diff --git a/packages/core/src/__tests__/agent-run-event-contract.test.ts b/packages/core/src/__tests__/agent-run-event-contract.test.ts new file mode 100644 index 0000000000..efcc6c790b --- /dev/null +++ b/packages/core/src/__tests__/agent-run-event-contract.test.ts @@ -0,0 +1,60 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; + +import { decodeAgentRunEvent } from '../agent-run.js'; +import type { AgentRunEvent, AgentRunStore, EmittedAgentRunEvent } from '../agent-run.js'; + +function ledgerRecord(overrides: Record = {}): Record { + return { + type: 'run_started', + id: 'event-1', + runId: 'run-1', + sessionId: 'session-1', + turnId: 'turn-1', + ts: 1, + ...overrides, + }; +} + +test('AgentRun reads an event type this build does not write', () => { + // The ledger outlives the build that wrote it, so a reader meets types whose writer was retired + // and types that have not shipped yet. Rejecting either one bricks startup on real data (#1942). + const decoded = decodeAgentRunEvent( + ledgerRecord({ type: 'written_by_another_version', data: { inputTokens: 7 } }), + ); + + assert.equal(decoded.type, 'written_by_another_version'); + assert.equal(decoded.data?.inputTokens, 7); +}); + +test('AgentRun still rejects a record whose envelope is damaged', () => { + // Tolerating an unknown `type` is not tolerating an unreadable record: everything around `type` + // stays exact, so real corruption is still caught rather than carried forward as a live event. + for (const record of [ + ledgerRecord({ type: '' }), + ledgerRecord({ type: ' ' }), + ledgerRecord({ type: 42 }), + ledgerRecord({ unexpectedField: 'present' }), + ledgerRecord({ ts: 'not-a-number' }), + ledgerRecord({ id: undefined }), + ]) { + assert.throws(() => decodeAgentRunEvent(record), /Invalid AgentRun event schema/); + } +}); + +test('AgentRun closes its write contract against a type this build does not emit', () => { + // The assertion here is the compiler: `@ts-expect-error` itself fails to build if the call ever + // type-checks again, which is what widening `appendEvent` back to `AgentRunEvent` would do. The + // call is only declared, never made, so the contract is checked without a store. + const retired: AgentRunEvent = ledgerRecord({ + type: 'written_by_another_version', + }) as unknown as AgentRunEvent; + const appendRetired = (store: AgentRunStore) => + // @ts-expect-error A ledger is read with any type but appended to only with an emitted one. + store.appendEvent('session-1', 'run-1', retired); + assert.equal(typeof appendRetired, 'function'); + + const emitted: EmittedAgentRunEvent = { ...retired, type: 'run_started' }; + const appendEmitted = (store: AgentRunStore) => store.appendEvent('session-1', 'run-1', emitted); + assert.equal(typeof appendEmitted, 'function'); +}); diff --git a/packages/core/src/agent-run.ts b/packages/core/src/agent-run.ts index 86d73b9d65..076dfaf0f1 100644 --- a/packages/core/src/agent-run.ts +++ b/packages/core/src/agent-run.ts @@ -359,8 +359,6 @@ export const AGENT_RUN_EVENT_TYPES = [ 'sandbox_denial_detected', 'provider_request_captured', 'provider_request_attempt_recorded', - // No current writer; shipped ledgers still carry it and strict reads must not reject them (#1942). - 'usage_recorded', 'model_call_attempt_recorded', 'history_compact_checkpoint_recorded', 'active_full_compact_block_recorded', @@ -376,8 +374,14 @@ export const AGENT_RUN_EVENT_TYPES = [ export type AgentRunEventType = (typeof AGENT_RUN_EVENT_TYPES)[number]; +/** + * A decoded ledger record. The ledger is append-only and outlives any single build, so `type` is + * an open string: a reader must accept a type another version wrote, whether that version retired + * the writer or has not shipped yet (#1942). The envelope around `type` is still validated, so + * this tolerance does not extend to a record that gained or lost a field. + */ export interface AgentRunEvent { - type: AgentRunEventType; + type: string; id: string; runId: string; sessionId: string; @@ -387,6 +391,22 @@ export interface AgentRunEvent { data?: Record; } +/** + * What this build may append. `AGENT_RUN_EVENT_TYPES` is the emitted catalogue, not the readable + * one, so it stays free to shrink when a writer retires while a misspelled or retired type fails + * to compile at the append that would persist it. + */ +export interface EmittedAgentRunEvent extends AgentRunEvent { + type: AgentRunEventType; +} + +const EMITTED_AGENT_RUN_EVENT_TYPES: ReadonlySet = new Set(AGENT_RUN_EVENT_TYPES); + +/** Whether this build emits `type`, and so knows what its record means. */ +export function isEmittedAgentRunEventType(type: string): type is AgentRunEventType { + return EMITTED_AGENT_RUN_EVENT_TYPES.has(type); +} + const AGENT_RUN_HEADER_SHAPE = defineObjectShape()( [ 'runId', @@ -532,7 +552,8 @@ export function decodeAgentRunEvent(value: unknown): AgentRunEvent { if ( !isRecord(value) || !hasExactShape(value, AGENT_RUN_EVENT_SHAPE) || - !(AGENT_RUN_EVENT_TYPES as readonly unknown[]).includes(value.type) || + typeof value.type !== 'string' || + value.type.trim().length === 0 || typeof value.id !== 'string' || typeof value.runId !== 'string' || typeof value.sessionId !== 'string' || @@ -563,7 +584,7 @@ export interface AgentRunStore { appendEvent( sessionId: string, runId: string, - event: AgentRunEvent, + event: EmittedAgentRunEvent, options?: { durable?: boolean }, ): Promise; readEvents(sessionId: string, runId: string): Promise; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0fe7afaae2..557ba1d96e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -404,12 +404,14 @@ export type { AgentRunInputSummary, AgentRunStatus, AgentRunStore, + EmittedAgentRunEvent, RootExecutionDescriptor, } from './agent-run.js'; export { AGENT_RUN_STATUSES, decodeAgentRunEvent, decodeAgentRunHeader, + isEmittedAgentRunEventType, isSessionInlineRun, } from './agent-run.js'; diff --git a/packages/headless/src/__tests__/provider-request-trace.test.ts b/packages/headless/src/__tests__/provider-request-trace.test.ts index d8e021b827..70660b15e7 100644 --- a/packages/headless/src/__tests__/provider-request-trace.test.ts +++ b/packages/headless/src/__tests__/provider-request-trace.test.ts @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { test } from 'node:test'; import assert from 'node:assert/strict'; -import type { AgentRunEvent, AgentRunHeader } from '@maka/core'; +import type { AgentRunHeader, EmittedAgentRunEvent } from '@maka/core'; import type { InvocationResult } from '@maka/runtime'; import { acquireOperationalStateDatabase } from '@maka/storage'; @@ -262,8 +262,8 @@ test('exports a torn AgentRun tail as incomplete provider-request evidence', asy const storage = await openHeadlessStorageForWrite(storageRoot); const runStore = storage.executionStores.agentRunStore; await runStore.createRun(header); - await runStore.appendEvent(identity.sessionId, identity.runId, capture as AgentRunEvent); - await runStore.appendEvent(identity.sessionId, identity.runId, attempt as AgentRunEvent); + await runStore.appendEvent(identity.sessionId, identity.runId, capture as EmittedAgentRunEvent); + await runStore.appendEvent(identity.sessionId, identity.runId, attempt as EmittedAgentRunEvent); corruptAgentRunEvent(storageRoot, identity.sessionId, identity.runId, 1); const traceEventsPath = await writeHarborTaskRunTrace({ @@ -336,7 +336,7 @@ test('also diagnoses missing provider evidence when the only run event is corrup const exportedEvents = (await readFile(traceEventsPath, 'utf8')) .trim() .split('\n') - .map((line) => JSON.parse(line) as AgentRunEvent); + .map((line) => JSON.parse(line) as EmittedAgentRunEvent); assert.deepEqual( exportedEvents.map((event) => event.type), @@ -415,12 +415,12 @@ test('exports missing provider-request evidence for every continuation invocatio await runStore.appendEvent( completeIdentity.sessionId, completeIdentity.runId, - capture as AgentRunEvent, + capture as EmittedAgentRunEvent, ); await runStore.appendEvent( completeIdentity.sessionId, completeIdentity.runId, - attempt as AgentRunEvent, + attempt as EmittedAgentRunEvent, ); const traceEventsPath = await writeHarborTaskRunTrace({ @@ -489,7 +489,7 @@ test('preserves existing run events when exporting a missing-evidence diagnostic const exportedEvents = (await readFile(traceEventsPath, 'utf8')) .trim() .split('\n') - .map((line) => JSON.parse(line) as AgentRunEvent); + .map((line) => JSON.parse(line) as EmittedAgentRunEvent); assert.deepEqual( exportedEvents.map((event) => event.type), diff --git a/packages/headless/src/__tests__/task-run-inspect.test.ts b/packages/headless/src/__tests__/task-run-inspect.test.ts index ee52509644..657f690c29 100644 --- a/packages/headless/src/__tests__/task-run-inspect.test.ts +++ b/packages/headless/src/__tests__/task-run-inspect.test.ts @@ -3,7 +3,12 @@ import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { describe, test } from 'node:test'; -import type { AgentRunEvent, AgentRunHeader, RuntimeEvent } from '@maka/core'; +import type { + AgentRunEventType, + AgentRunHeader, + EmittedAgentRunEvent, + RuntimeEvent, +} from '@maka/core'; import { buildHistoryCompactCheckpoint } from '@maka/runtime'; import { createSqliteAgentRunStore, createWorkspaceRuntimeStore } from '@maka/storage'; import type { HeavyTaskSemanticSelfCheckState, TaskEvent } from '../task-contracts.js'; @@ -385,7 +390,7 @@ function runHeader(overrides: Partial = {}): AgentRunHeader { }; } -function runEvent(id: string, type: AgentRunEvent['type']): AgentRunEvent { +function runEvent(id: string, type: AgentRunEventType): EmittedAgentRunEvent { return { id, type, runId: RUN_ID, sessionId: SESSION_ID, turnId: TURN_ID, ts: 10 }; } diff --git a/packages/headless/src/harbor-cell.ts b/packages/headless/src/harbor-cell.ts index 92f157db98..5a9bf03649 100644 --- a/packages/headless/src/harbor-cell.ts +++ b/packages/headless/src/harbor-cell.ts @@ -5,6 +5,7 @@ import type { AgentRunEvent, AgentRunHeader, BackendKind, + EmittedAgentRunEvent, PricingConfig, ProviderType, RuntimeEvent, @@ -694,7 +695,7 @@ export async function writeHarborTaskRunTrace(input: { turnId: header.turnId, ts: header.updatedAt, message: header.traceWriteError, - } satisfies AgentRunEvent, + } satisfies EmittedAgentRunEvent, ] : events; if (header.backendKind !== 'ai-sdk' || evidenceEvents.some(isProviderRequestTraceEvidence)) { @@ -714,7 +715,7 @@ export async function writeHarborTaskRunTrace(input: { reason: 'missing_provider_request_evidence', invocationId: invocation.invocationId, }, - } satisfies AgentRunEvent, + } satisfies EmittedAgentRunEvent, ]; }), ); diff --git a/packages/runtime-host/src/__tests__/execution-inspect-coordinator.test.ts b/packages/runtime-host/src/__tests__/execution-inspect-coordinator.test.ts index 71ff48996c..26da7138db 100644 --- a/packages/runtime-host/src/__tests__/execution-inspect-coordinator.test.ts +++ b/packages/runtime-host/src/__tests__/execution-inspect-coordinator.test.ts @@ -3,7 +3,7 @@ import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { describe, test } from 'node:test'; -import type { AgentRunEvent, AgentRunHeader } from '@maka/core'; +import type { AgentRunHeader, EmittedAgentRunEvent } from '@maka/core'; import { openInteractiveExecutionStoresForWrite } from '@maka/storage/execution-stores'; import { resolveStorageRoot, tryAcquireInteractiveRootOwner } from '@maka/storage/root-authority'; import { @@ -141,7 +141,7 @@ describe('HostExecutionInspectCoordinator', () => { await withCoordinator(async ({ stores, coordinator }) => { const session = await stores.sessionStore.create(sessionInput('Exact evidence budget')); await stores.agentRunStore.createRun(runHeader(session.id, 'exact-run', 1)); - const baseEvent: AgentRunEvent = { + const baseEvent: EmittedAgentRunEvent = { type: 'run_started', id: 'exact-event', sessionId: session.id, @@ -152,7 +152,7 @@ describe('HostExecutionInspectCoordinator', () => { }; const baseBytes = Buffer.byteLength(JSON.stringify(baseEvent), 'utf8'); assert.ok(baseBytes < EXECUTION_INSPECT_EVIDENCE_MAX_BYTES); - const event: AgentRunEvent = { + const event = { ...baseEvent, data: { payload: 'x'.repeat(EXECUTION_INSPECT_EVIDENCE_MAX_BYTES - baseBytes), diff --git a/packages/runtime/src/__tests__/context-diagnostics.test.ts b/packages/runtime/src/__tests__/context-diagnostics.test.ts index a9cae07406..f8a5c438e1 100644 --- a/packages/runtime/src/__tests__/context-diagnostics.test.ts +++ b/packages/runtime/src/__tests__/context-diagnostics.test.ts @@ -3,7 +3,12 @@ import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { test } from 'node:test'; -import type { AgentRunEvent, AgentRunHeader, AgentRunStore } from '@maka/core'; +import type { + AgentRunEvent, + AgentRunHeader, + AgentRunStore, + EmittedAgentRunEvent, +} from '@maka/core'; import { createSqliteAgentRunStore } from '@maka/storage'; import { readLatestContextDiagnostics } from '../context-diagnostics.js'; @@ -217,7 +222,7 @@ function attemptEvent( inputTokens: number | undefined, contextWindow: number, segments: Array> = [], -): AgentRunEvent { +): EmittedAgentRunEvent { const turnId = `turn-${runId}`; return { type: 'provider_request_attempt_recorded', @@ -255,7 +260,7 @@ function checkpointEvent( eventCount: number, turnCount: number, estimatedTokens: number, -): AgentRunEvent { +): EmittedAgentRunEvent { return { type: 'history_compact_checkpoint_recorded', id: `checkpoint-${ts}`, diff --git a/packages/runtime/src/__tests__/conversation-copy.test.ts b/packages/runtime/src/__tests__/conversation-copy.test.ts index 497035d87a..c2bcf615b8 100644 --- a/packages/runtime/src/__tests__/conversation-copy.test.ts +++ b/packages/runtime/src/__tests__/conversation-copy.test.ts @@ -6,6 +6,7 @@ import { test } from 'node:test'; import type { AgentRunHeader, AgentRunStore, + EmittedAgentRunEvent, RuntimeEvent, RuntimeEventStore, StoredMessage, @@ -970,6 +971,24 @@ test('conversation copy clones one terminal Runtime ledger with new owned identi turnId: 'turn-1', ts: 3, }); + // A record left by a build whose writer this one no longer has. The cast is the point: the + // write contract forbids producing this type, and only another version could have put it in + // the source ledger. The rewriters cannot check an unknown payload for source-owned ids, so + // the copy must drop it rather than carry those ids into the target (#1942). + await runStore.appendEvent('session-source', 'run-source', { + type: 'written_by_another_version', + id: 'foreign-source', + runId: 'run-source', + sessionId: 'session-source', + turnId: 'turn-1', + ts: 3.5, + data: { runtimeEventId: 'event-source-1' }, + } as unknown as EmittedAgentRunEvent); + assert.ok( + (await runStore.readEvents('session-source', 'run-source')).some( + (event) => event.type === 'written_by_another_version', + ), + ); const source = await new RuntimeReadModel({ runStore, runtimeEventStore, diff --git a/packages/runtime/src/__tests__/execution-inspect.test.ts b/packages/runtime/src/__tests__/execution-inspect.test.ts index a9a791643c..3838bcaf02 100644 --- a/packages/runtime/src/__tests__/execution-inspect.test.ts +++ b/packages/runtime/src/__tests__/execution-inspect.test.ts @@ -3,7 +3,13 @@ import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { describe, test } from 'node:test'; -import type { AgentRunEvent, AgentRunHeader, RuntimeEvent } from '@maka/core'; +import type { + AgentRunEvent, + AgentRunEventType, + AgentRunHeader, + EmittedAgentRunEvent, + RuntimeEvent, +} from '@maka/core'; import { createSessionStore } from '@maka/storage'; import { createSqliteAgentRunStore, createWorkspaceRuntimeStore } from '@maka/storage'; import { @@ -156,7 +162,7 @@ function runHeader(sessionId: string): AgentRunHeader { }; } -function runEvent(sessionId: string, type: AgentRunEvent['type']): AgentRunEvent { +function runEvent(sessionId: string, type: AgentRunEventType): EmittedAgentRunEvent { return { id: `op-${type}`, type, runId: RUN_ID, sessionId, turnId: TURN_ID, ts: TS + 1 }; } diff --git a/packages/runtime/src/__tests__/sandbox-boundary-restart-recovery.test.ts b/packages/runtime/src/__tests__/sandbox-boundary-restart-recovery.test.ts index fc0a4288cc..35653f19c9 100644 --- a/packages/runtime/src/__tests__/sandbox-boundary-restart-recovery.test.ts +++ b/packages/runtime/src/__tests__/sandbox-boundary-restart-recovery.test.ts @@ -5,6 +5,7 @@ import { join } from 'node:path'; import { describe, it } from 'node:test'; import type { AgentRunEvent, + EmittedAgentRunEvent, AgentRunHeader, CreateSessionInput, SessionHeader, @@ -222,7 +223,7 @@ function runHeader(sessionId: string): AgentRunHeader { }; } -function runEvent(sessionId: string): AgentRunEvent { +function runEvent(sessionId: string): EmittedAgentRunEvent { return { type: 'run_started', id: 'run-1-run_started-11', diff --git a/packages/runtime/src/__tests__/session-manager.test.ts b/packages/runtime/src/__tests__/session-manager.test.ts index c3f110b7d3..5782d0ab9f 100644 --- a/packages/runtime/src/__tests__/session-manager.test.ts +++ b/packages/runtime/src/__tests__/session-manager.test.ts @@ -31,6 +31,7 @@ import type { AgentGraphOperatorProvisionRequest, AgentGraphOperatorProvisionResult, AgentRunEvent, + EmittedAgentRunEvent, AgentRunHeader, AgentRunStore, ArtifactRecord, @@ -22392,7 +22393,7 @@ function makeRunHeader(overrides: Partial = {}): AgentRunHeader }; } -function makeRunEvent(overrides: Partial = {}): AgentRunEvent { +function makeRunEvent(overrides: Partial = {}): EmittedAgentRunEvent { return { type: 'run_started', id: `${overrides.runId ?? 'run-1'}-${overrides.type ?? 'run_started'}-${overrides.ts ?? 10}`, @@ -22626,7 +22627,7 @@ async function seedRuntimeReadTurnWithHeader(input: { async function seedRun( runStore: AgentRunStore, header: AgentRunHeader, - events: AgentRunEvent[], + events: EmittedAgentRunEvent[], ): Promise { await runStore.createRun(header); for (const event of events) { diff --git a/packages/runtime/src/agent-run.ts b/packages/runtime/src/agent-run.ts index d238399fad..6d8f155b3c 100644 --- a/packages/runtime/src/agent-run.ts +++ b/packages/runtime/src/agent-run.ts @@ -2,6 +2,7 @@ import type { AgentRunEvent, AgentRunHeader, AgentRunStore, + EmittedAgentRunEvent, RuntimeEvent, RuntimeEventStore, ToolBoundaryProtocol, @@ -1567,7 +1568,7 @@ export class AgentRun { } } -function traceToRunEvent(event: RunTraceEvent, runId: string): AgentRunEvent { +function traceToRunEvent(event: RunTraceEvent, runId: string): EmittedAgentRunEvent { return { type: event.type, id: event.id, diff --git a/packages/runtime/src/conversation-copy.ts b/packages/runtime/src/conversation-copy.ts index 7b3cc6986d..e56c2efe8b 100644 --- a/packages/runtime/src/conversation-copy.ts +++ b/packages/runtime/src/conversation-copy.ts @@ -2,13 +2,18 @@ import type { AgentRunEvent, AgentRunHeader, AgentRunStore, + EmittedAgentRunEvent, RuntimeEvent, RuntimeEventStore, StorageRef, StoredMessage, ToolResultContent, } from '@maka/core'; -import { decodeCanonicalToolResultContent, isSessionInlineRun } from '@maka/core'; +import { + decodeCanonicalToolResultContent, + isEmittedAgentRunEventType, + isSessionInlineRun, +} from '@maka/core'; import { TOOL_RECOVERY_DECISION_FACT_KIND } from '@maka/core/tool-recovery-fact'; import { buildHistoryCompactCheckpoint, @@ -475,7 +480,7 @@ function cloneAgentRunEvent( checkpointIds: Map, operationalEventIds: ReadonlyMap, providerTraceIds: ReadonlyMap, -): AgentRunEvent | null { +): EmittedAgentRunEvent | null { if (event.type === 'event_corrupt') { throw new Error(`Cannot copy corrupt AgentRun event ${event.id}`); } @@ -703,7 +708,12 @@ function toolOperationIdMap( return result; } -function isCopiedAgentRunEvent(event: AgentRunEvent): boolean { +function isCopiedAgentRunEvent(event: AgentRunEvent): event is EmittedAgentRunEvent { + // The rewriters below know which of this build's payloads carry source-owned references. A type + // this build does not emit cannot even be checked for them, so it is dropped rather than carried + // into the target with source identities intact. The ledger's `type` is open, so such an event + // may predate a retired writer or postdate this build entirely (#1942). + if (!isEmittedAgentRunEventType(event.type)) return false; // Active/semantic blocks hash the exact provider-visible source. Rewriting // target-owned RuntimeEvent and Artifact references invalidates that // evidence, so a copied Session starts without these derived diagnostics. diff --git a/packages/runtime/src/terminal-run-commit.ts b/packages/runtime/src/terminal-run-commit.ts index eadd80f50f..95864321bc 100644 --- a/packages/runtime/src/terminal-run-commit.ts +++ b/packages/runtime/src/terminal-run-commit.ts @@ -2,6 +2,7 @@ import { isPartialRuntimeEvent, isTerminalRuntimeEvent } from '@maka/core'; import type { AgentRunEvent, AgentRunHeader, + AgentRunEventType, AgentRunStore, RuntimeEvent, RuntimeEventStore, @@ -329,7 +330,7 @@ export function hasTerminalAgentRunEvent(events: readonly Pick { }); }); + test('reads an AgentRun event type this build does not write', async () => { + await withRoot(async (root) => { + const store = createSqliteAgentRunStore(root); + await store.createRun(runHeader()); + await store.appendEvent('session-1', 'run-1', runEvent()); + store.close?.(); + + // Rewrite the stored row into what a build that still had this writer would have left + // behind. Going through the database rather than appendEvent is the point: this build + // must be able to read a record it is no longer allowed to produce (#1942). + const db = new DatabaseSync(join(root, 'runtime.sqlite')); + try { + const record = { + ...runEvent(), + type: 'written_by_another_version', + data: { inputTokens: 7 }, + }; + db.prepare( + `UPDATE core_agent_run_events SET event_type = ?, record_json = ? WHERE event_id = ?`, + ).run('written_by_another_version', JSON.stringify(record), 'event-1'); + } finally { + db.close(); + } + + const reopened = createSqliteAgentRunStore(root); + try { + const events = await reopened.readEvents('session-1', 'run-1'); + assert.deepEqual( + events.map((event) => event.type), + ['written_by_another_version'], + ); + assert.equal(events[0]?.data?.inputTokens, 7); + + const recovered = await reopened.readEventsForRecovery('session-1', 'run-1'); + assert.deepEqual( + recovered.map((event) => event.type), + ['written_by_another_version'], + ); + } finally { + reopened.close?.(); + } + }); + }); + test('persists ShellRun records', async () => { await withRoot(async (root) => { const store = createSqliteShellRunStore(root); @@ -133,7 +178,7 @@ function runHeader(): AgentRunHeader { }; } -function runEvent(): AgentRunEvent { +function runEvent(): EmittedAgentRunEvent { return { type: 'run_started', id: 'event-1', diff --git a/packages/storage/src/agent-run-store.ts b/packages/storage/src/agent-run-store.ts index 57d75c51d0..49afb5f254 100644 --- a/packages/storage/src/agent-run-store.ts +++ b/packages/storage/src/agent-run-store.ts @@ -36,6 +36,7 @@ import { type AgentRunEventType, type AgentRunHeader, type AgentRunStore, + type EmittedAgentRunEvent, type AttachmentRef, type MessageContent, type RootExecutionDescriptor, @@ -350,7 +351,7 @@ class SqliteAgentRunStore implements DurableAgentRunStore { async appendEvent( sessionId: string, runId: string, - event: AgentRunEvent, + event: EmittedAgentRunEvent, _options: { durable?: boolean } = {}, ): Promise { assertSafeId(sessionId, 'Invalid session id');