diff --git a/apps/cli/tests/github-webhook-real.e2e.ts b/apps/cli/tests/github-webhook-real.e2e.ts index fd465714d3..b02a9a1f54 100644 --- a/apps/cli/tests/github-webhook-real.e2e.ts +++ b/apps/cli/tests/github-webhook-real.e2e.ts @@ -11,6 +11,7 @@ import { tmpdir } from 'node:os' import { join } from 'node:path' import { setTimeout as delay } from 'node:timers/promises' import { fileURLToPath } from 'node:url' +import { decodeStorageRecord } from '@deepseek-ai/dsh-session/chunk-rows' import { describe, expect, it } from 'vitest' import WebSocket from 'ws' @@ -59,15 +60,15 @@ interface WorkspaceBaseline { } interface HistoryPage { - events: Array<{ - event: { - type: string - data: unknown - } - }> + records: Array<{ event: HistoryEvent } | { chunks: unknown }> hasMore: boolean } +interface HistoryEvent { + type: string + data: unknown +} + interface ProcessObservation { readonly ready: Promise readonly text: () => string @@ -255,10 +256,10 @@ async function history(baseUrl: string, sessionId: string): Promise { request: { address: { kind: 'session', sessionId }, maxMessages: 100 } }, value => isRecord(value) && value.type === 'snapshot' - && Array.isArray(value.events) + && Array.isArray(value.records) && typeof value.hasMore === 'boolean', ) - return { events: frame.events as HistoryPage['events'], hasMore: frame.hasMore as boolean } + return { records: frame.records as HistoryPage['records'], hasMore: frame.hasMore as boolean } } /** Poll a public observation until it satisfies the test's behavior predicate. */ @@ -294,7 +295,7 @@ async function eventually( /** Return every text block from durable assistant messages. */ function assistantText(page: HistoryPage): string { const text: string[] = [] - for (const { event } of page.events) { + for (const event of historyEvents(page)) { if (event.type !== 'assistant/message' || !isRecord(event.data) || !isRecord(event.data.message)) continue const content = event.data.message.content if (!Array.isArray(content)) continue @@ -305,6 +306,11 @@ function assistantText(page: HistoryPage): string { return text.join('\n') } +/** Expand lossless history records for assertions over the public event stream. */ +function historyEvents(page: HistoryPage): HistoryEvent[] { + return page.records.flatMap(record => 'event' in record ? [record.event] : decodeStorageRecord(record.chunks)) +} + /** Stop the spawned CLI through its normal signal path, escalating only on a stuck teardown. */ async function stop(child: ChildProcess): Promise { if (child.exitCode !== null) return @@ -410,7 +416,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('GitHub webhook through the real 'webhook provenance, title, and permission events', async () => await history(baseUrl, sessionId), (page) => { - const events = page.events.map(item => item.event) + const events = historyEvents(page) const title = events.find(event => event.type === 'session/title') const permission = events.find(event => event.type === 'permission/preset' @@ -429,7 +435,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('GitHub webhook through the real }, 30_000, ) - const webhookMessage = admitted.events.map(item => item.event) + const webhookMessage = historyEvents(admitted) .find(event => event.type === 'user/message' && isRecord(event.data) && isRecord(event.data.source) diff --git a/docs/event-producer-consumer.i18n.yaml b/docs/event-producer-consumer.i18n.yaml index f89d450815..934d20fd94 100644 --- a/docs/event-producer-consumer.i18n.yaml +++ b/docs/event-producer-consumer.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/event-producer-consumer.md -event-producer-consumer.md: 6f971f5470c34093dd3774650ad191f9a3516df7 +event-producer-consumer.md: ce914f90821adc09c59dca15f202831a51655565 event-producer-consumer.zh.md: ca375c98b6c0552f255e5d2604c9ad0c1d968aad diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 6f971f5470..ce914f9082 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -21,11 +21,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `agent/session-start` | `emit` | [`packages/core/agent/src/runtime-types.ts:224`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | `agent-team`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:185`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`schedule`](../packages/schedule/schedule), `server`, `session-controller` | | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:285`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) | -| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:482`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:462`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:489`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:468`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:475`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:491`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:471`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:498`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:477`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:484`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:85`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes` | | `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | [`authorization`](../packages/credentials/authorization) | | `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:80`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` | diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index 04ad9a33d7..36b89eabc3 100644 --- a/docs/persistence-catalog.i18n.yaml +++ b/docs/persistence-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/persistence-catalog.md -persistence-catalog.md: 12558eeadc009b498c9a178cfcc79116bf1b7c2b +persistence-catalog.md: 7c63cd8dfdb181fac09cf3ce2e4bcec96d2bd59c persistence-catalog.zh.md: f855d6969aa2dcade159ac8d6549e5f0350a7f0f diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 12558eeadc..7c63cd8dfd 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -512,7 +512,7 @@ Source: [`packages/llm/llm-retry/src/types.ts:11`](../packages/llm/llm-retry/src 'model/selection': ModelSelection ``` -Source: [`packages/api/session-controller/src/types.ts:39`](../packages/api/session-controller/src/types.ts) +Source: [`packages/api/session-controller/src/types.ts:40`](../packages/api/session-controller/src/types.ts) ### `permission/*`