diff --git a/package.json b/package.json index 6236daf..35cd9e1 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "test:watch": "vitest" }, "dependencies": { - "@ellipsis-dev/sdk": "^0.8.1", + "@ellipsis-dev/sdk": "^0.10.0", "chalk": "^5.6.2", "cli-table3": "^0.6.5", "commander": "^12.1.0", diff --git a/src/commands/connect.ts b/src/commands/connect.ts index aaab961..ec72f6a 100644 --- a/src/commands/connect.ts +++ b/src/commands/connect.ts @@ -154,8 +154,8 @@ export async function runConnect( minRenderFeedSeq: showRecords ? 0 : store.cursor, sessionUrl: url, initialNotice: notice, - // The session's one model, fixed at creation (backend tokens_model). - model: typeof session.tokens_model === 'string' ? session.tokens_model : null, + // The session's one model, fixed at creation. + model: session.tokens?.model || null, configName: config, exitState, }), diff --git a/src/commands/session.tsx b/src/commands/session.tsx index c5dc81b..08de068 100644 --- a/src/commands/session.tsx +++ b/src/commands/session.tsx @@ -390,9 +390,7 @@ export function registerSession(program: Command): void { s.status, s.source ?? '-', formatTs(s.created_at), - usdFromMillicents( - s.cost_tokens + s.cost_sandbox_cpu + s.cost_sandbox_memory + s.cost_fee, - ), + usdFromMillicents(s.cost?.total ?? 0), ]), ) }) @@ -494,7 +492,7 @@ export function registerSession(program: Command): void { } } console.log( - '\nInspect one: agent session get . Full log: agent session log ', + '\nInspect one: agent session get . Full history: agent session export ', ) }) }, @@ -531,11 +529,12 @@ export function registerSession(program: Command): void { apiRoutes( alsoKnownAs( session - .command('log ') - .description("Download a session's complete archived log to stdout or a file"), + .command('export ') + .description("Download a session's complete archived history to stdout or a file"), + 'log', 'logs', ), - 'GET /sessions/{id}/log', + 'GET /sessions/{id}/export', ) .option('-o, --output ', 'write to a file instead of stdout') .option('--gzip', 'keep the concatenated .jsonl.gz bytes as-is (skip gunzip)') @@ -550,7 +549,7 @@ export function registerSession(program: Command): void { }, ) => { await runAction(async () => { - const manifest = await api().sessions.log(sessionId) + const manifest = await api().sessions.export(sessionId) if (opts.json) { printJson(manifest) return @@ -1057,12 +1056,8 @@ function printSessionSummary(s: AgentSession): void { if (s.config_id) console.log(`config: ${s.config_id}`) console.log(`created: ${s.created_at}`) console.log(`updated: ${s.updated_at}`) - console.log(`tokens: ${s.tokens_total.toLocaleString()}`) - console.log( - `cost: ${usdFromMillicents( - s.cost_tokens + s.cost_sandbox_cpu + s.cost_sandbox_memory + s.cost_fee, - )}`, - ) + console.log(`tokens: ${(s.tokens?.total ?? 0).toLocaleString()}`) + console.log(`cost: ${usdFromMillicents(s.cost?.total ?? 0)}`) const keys = Object.keys(s.metadata ?? {}) if (keys.length) { console.log('metadata:') @@ -1230,7 +1225,7 @@ export function formatSearchResult( now: Date = new Date(), ): string[] { const s = result.session - const author = s.attribution_id ? users[String(s.attribution_id)]?.login : undefined + const author = s.attribution?.id ? users[String(s.attribution.id)]?.login : undefined const header = [ s.id, s.status, diff --git a/src/lib/sessions.ts b/src/lib/sessions.ts index 05c39cd..16e1323 100644 --- a/src/lib/sessions.ts +++ b/src/lib/sessions.ts @@ -127,15 +127,15 @@ function trimZero(s: string): string { } // The nav row's right-hand metadata: how much work the agent did (tokens, -// spend) and when it last moved. Spend is the sum of the four millicent cost -// columns, the same total the chat footer shows. A just-started session drops -// the empty bits rather than showing "0 · $0.00". No source tag: the nav lists -// cloud sessions only, so it would read the same on every row. +// spend) and when it last moved. Spend is the server's millicent total, the +// same total the chat footer shows. A just-started session drops the empty +// bits rather than showing "0 · $0.00". No source tag: the nav lists cloud +// sessions only, so it would read the same on every row. export function rowMeta(session: AgentSession, now: Date = new Date()): string { const bits: string[] = [] - if (session.tokens_total > 0) bits.push(compactTokens(session.tokens_total)) - const millicents = - session.cost_tokens + session.cost_sandbox_cpu + session.cost_sandbox_memory + session.cost_fee + const tokens = session.tokens?.total ?? 0 + if (tokens > 0) bits.push(compactTokens(tokens)) + const millicents = session.cost?.total ?? 0 if (millicents > 0) bits.push(`$${(millicents / 100_000).toFixed(2)}`) bits.push(shortAge(lastEventAt(session), now)) return bits.join(' · ') diff --git a/src/lib/types.ts b/src/lib/types.ts index 8beee11..dcfae0f 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -19,8 +19,8 @@ type S = components['schemas'] // --------------------------- sessions & records --------------------------- export type AgentSession = S['Session'] -export type AgentSessionSource = S['AgentSessionSource'] -export type AgentSessionStatus = S['AgentSessionStatus'] +export type AgentSessionSource = S['SessionSource'] +export type AgentSessionStatus = S['SessionStatus'] export type SessionState = S['SessionState'] export type SessionSurface = S['SessionSurface'] export type SessionPrompting = S['SessionPrompting'] diff --git a/src/ui/ConnectApp.tsx b/src/ui/ConnectApp.tsx index f4dc8f3..72e6a18 100644 --- a/src/ui/ConnectApp.tsx +++ b/src/ui/ConnectApp.tsx @@ -382,12 +382,7 @@ export function ConnectApp(props: ConnectAppProps): React.ReactElement { [snapshot.records], ) const serverCostUsd = snapshot.session - ? usdNumberFromMillicents( - snapshot.session.cost_tokens + - snapshot.session.cost_sandbox_cpu + - snapshot.session.cost_sandbox_memory + - snapshot.session.cost_fee, - ) + ? usdNumberFromMillicents(snapshot.session.cost?.total ?? 0) : null // The sandbox startup timeline, derived from the lifecycle records of the diff --git a/src/ui/SessionsApp.tsx b/src/ui/SessionsApp.tsx index c87e886..1a1a81a 100644 --- a/src/ui/SessionsApp.tsx +++ b/src/ui/SessionsApp.tsx @@ -299,7 +299,7 @@ export function SessionsApp(props: SessionsAppProps): React.ReactElement { store, canSend: c.canSend, notice: [notice, c.reason].filter(Boolean).join(' · ') || null, - model: typeof session.tokens_model === 'string' ? session.tokens_model : null, + model: session.tokens?.model || null, configName: configName ?? session.config_id ?? null, url: sessionUrl(appBase, customerLogin, sessionId), } @@ -758,15 +758,8 @@ function useHeaderMeta( ) if (mainPane.type !== 'chat' || !entry) return null const session = snapshot?.session as FrameSession | undefined | null - const costUsd = session - ? usdNumberFromMillicents( - session.cost_tokens + - session.cost_sandbox_cpu + - session.cost_sandbox_memory + - session.cost_fee, - ) - : 0 - const tokens = session?.tokens_total ?? 0 + const costUsd = session ? usdNumberFromMillicents(session.cost?.total ?? 0) : 0 + const tokens = session?.tokens?.total ?? 0 const id = mainPane.sessionId const line = (idText: string, model: string | null | undefined): string => [ diff --git a/test/connect-render.test.ts b/test/connect-render.test.ts index d0c9237..7a4da19 100644 --- a/test/connect-render.test.ts +++ b/test/connect-render.test.ts @@ -62,12 +62,15 @@ function costTick(store: SessionTranscriptStore, cents: number): void { session: { id: 'session_render', status: 'waiting', - cost_tokens: cents, - cost_sandbox_cpu: 0, - cost_sandbox_memory: 0, - cost_fee: 0, - tokens_total: cents, - tokens_model: 'claude-fable-5', + cost: { llm: cents, sandbox_cpu: 0, sandbox_memory: 0, fee: 0, total: cents }, + tokens: { + input: 0, + output: 0, + cache_read: 0, + cache_creation: 0, + total: cents, + model: 'claude-fable-5', + }, }, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any) @@ -108,12 +111,15 @@ function seededStore(records: Record[], status: string) { const session = { id: 'session_render', status, - cost_tokens: 0, - cost_sandbox_cpu: 0, - cost_sandbox_memory: 0, - cost_fee: 0, - tokens_total: 0, - tokens_model: 'claude-fable-5', + cost: { llm: 0, sandbox_cpu: 0, sandbox_memory: 0, fee: 0, total: 0 }, + tokens: { + input: 0, + output: 0, + cache_read: 0, + cache_creation: 0, + total: 0, + model: 'claude-fable-5', + }, } store.ingest({ type: 'snapshot', diff --git a/test/search.test.ts b/test/search.test.ts index f32e5d3..38a1170 100644 --- a/test/search.test.ts +++ b/test/search.test.ts @@ -24,18 +24,9 @@ function session(overrides: Partial = {}): AgentSession { source: 'api', harness: 'claude_code', prompting: { enabled: true }, - resolved_budget_cents: 0, - resolved_budget_source: 'system', - cost_tokens: 0, - cost_sandbox_cpu: 0, - cost_sandbox_memory: 0, - cost_fee: 0, - tokens_total: 0, - tokens_input: 0, - tokens_output: 0, - tokens_cache_read: 0, - tokens_cache_creation: 0, - tokens_model: '', + budget: { cents: 0, source: 'system' }, + cost: { llm: 0, sandbox_cpu: 0, sandbox_memory: 0, fee: 0, total: 0 }, + tokens: { input: 0, output: 0, cache_read: 0, cache_creation: 0, total: 0, model: '' }, metadata: {}, ...overrides, } @@ -144,7 +135,7 @@ describe('formatSearchResult', () => { it('renders header, author, age, matched arms, and the recap snippet', () => { const result: SessionSearchResult = { - session: session({ attribution_id: '5201153' }), + session: session({ attribution: { id: '5201153', type: 'github_user' } }), matched: ['recap', 'similar'], recap_snippet: 'looked into the shift trade webhook retries', record_hits: [], diff --git a/test/sessions.test.ts b/test/sessions.test.ts index e47d788..7a84f7c 100644 --- a/test/sessions.test.ts +++ b/test/sessions.test.ts @@ -36,18 +36,9 @@ function session(overrides: Partial): AgentSession { source: 'api', harness: 'claude_code', prompting: { enabled: true }, - resolved_budget_cents: 0, - resolved_budget_source: 'system', - cost_tokens: 0, - cost_sandbox_cpu: 0, - cost_sandbox_memory: 0, - cost_fee: 0, - tokens_total: 0, - tokens_input: 0, - tokens_output: 0, - tokens_cache_read: 0, - tokens_cache_creation: 0, - tokens_model: '', + budget: { cents: 0, source: 'system' }, + cost: { llm: 0, sandbox_cpu: 0, sandbox_memory: 0, fee: 0, total: 0 }, + tokens: { input: 0, output: 0, cache_read: 0, cache_creation: 0, total: 0, model: '' }, metadata: {}, ...overrides, } @@ -173,11 +164,8 @@ describe('rowMeta', () => { it('reads tokens, spend, and age', () => { const s = session({ - tokens_total: 84_200, - cost_tokens: 30_000, - cost_sandbox_cpu: 10_000, - cost_sandbox_memory: 2_000, - cost_fee: 0, + tokens: { input: 0, output: 0, cache_read: 0, cache_creation: 0, total: 84_200, model: '' }, + cost: { llm: 30_000, sandbox_cpu: 10_000, sandbox_memory: 2_000, fee: 0, total: 42_000 }, updated_at: '2026-07-23T11:58:00Z', } as never) expect(rowMeta(s, now)).toBe('84.2k · $0.42 · 2m ago')