Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions packages/cli/src/types/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* conversation spans returned by the Sentry Explore agent conversations endpoints.
*/

import { vRetrieveOrganizationAiConversationResponse } from "@sentry/api/valibot";
import {
array,
boolean,
Expand Down Expand Up @@ -97,13 +98,23 @@ export type AgentConversationSpan = InferOutput<
typeof AgentConversationSpanSchema
>;

const sdkConversation = vRetrieveOrganizationAiConversationResponse.entries;
const sdkStats = sdkConversation.stats.wrapped.entries;

/**
* Conversation stats the CLI reads.
*
* Built from the `@sentry/api` schema. Only these fields are required: the
* server added the others (token and cost breakdowns, `usageByModel`) one at
* a time, and older self-hosted servers don't send them.
*/
export const ConversationStatsSchema = looseObject({
errors: number(),
llmCalls: number(),
toolCalls: number(),
toolErrors: number(),
totalCost: number(),
totalTokens: number(),
errors: sdkStats.errors,
llmCalls: sdkStats.llmCalls,
toolCalls: sdkStats.toolCalls,
toolErrors: sdkStats.toolErrors,
totalCost: sdkStats.totalCost,
totalTokens: sdkStats.totalTokens,
});

export type ConversationStats = InferOutput<typeof ConversationStatsSchema>;
Expand All @@ -116,14 +127,18 @@ export type ConversationStats = InferOutput<typeof ConversationStatsSchema>;
* (conversation-level metadata + a page of spans) instead of a bare span
* array. Pagination still uses the `Link` header; each page is an envelope
* whose `spans` field holds that page's rows.
*
* Built from the `@sentry/api` schema. The spec types `spans` as plain
* records, so the CLI checks them with its own span schema. `projects` and
* `webUrl` are not checked because the CLI doesn't read them.
*/
export const AgentConversationDetailsSchema = looseObject({
conversationId: string(),
title: nullable(string()),
conversationId: sdkConversation.conversationId,
title: sdkConversation.title,
spans: array(AgentConversationSpanSchema),
/**
* Added after the original envelope; missing on older self-hosted servers.
* The server sends `null` on every page after the first.
* The server sends `null` on every page after the first, and older
* self-hosted servers leave it out.
*/
stats: nullish(ConversationStatsSchema),
});
Expand Down
Loading