From 5e4cfe670f330c4d219e43aed416094a59195b52 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 16 Sep 2026 12:16:01 +0800 Subject: [PATCH 001/279] chore(session): initialize V4 release integration PR From 669b724a7837129d4a1fbd0cab7509f6b4e9a01f Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 16 Sep 2026 12:50:34 +0800 Subject: [PATCH 002/279] feat(session): add the V4 integration format and retain V3 replay inputs --- ...leased-session-format-migrations.i18n.yaml | 4 +- ...8-31-released-session-format-migrations.md | 3 + ...1-released-session-format-migrations.zh.md | 3 + apps/web/tests/chat-scroll-contract.e2e.ts | 5 +- apps/web/tests/preset-migration.snapshot.ts | 12 +- docs/config-catalog.i18n.yaml | 4 +- docs/config-catalog.md | 1 + docs/config-catalog.zh.md | 1 + .../adding-a-session-format-version.i18n.yaml | 4 +- .../adding-a-session-format-version.md | 4 +- .../adding-a-session-format-version.zh.md | 4 +- docs/module-graph.i18n.yaml | 4 +- docs/module-graph.md | 2 + docs/module-graph.zh.md | 2 + docs/persistence-catalog.i18n.yaml | 4 +- docs/persistence-catalog.md | 14 +- docs/persistence-catalog.zh.md | 14 +- .../2026-09-16-session-format-v4.i18n.yaml | 6 + .../2026-09-16-session-format-v4.md | 48 + .../2026-09-16-session-format-v4.schema.json | 87 + .../2026-09-16-session-format-v4.zh.md | 48 + .../historical-formats/README.i18n.yaml | 4 +- .../historical-formats/README.md | 5 +- .../historical-formats/README.zh.md | 5 +- .../historical-formats/v3.i18n.yaml | 6 + .../historical-formats/v3.md | 5634 ++ .../historical-formats/v3.schema.json | 61307 ++++++++++++++++ .../historical-formats/v3.zh.md | 5634 ++ docs/persistence-schema.json | 202 +- packages/core/session/README.i18n.yaml | 4 +- packages/core/session/README.md | 2 +- packages/core/session/README.zh.md | 2 +- packages/core/session/src/types.ts | 2 +- .../tests/vfs-example-fixture.spec.ts | 36 +- packages/session/README.i18n.yaml | 4 +- packages/session/README.md | 2 + packages/session/README.zh.md | 2 + .../session-format-catalog/README.i18n.yaml | 4 +- .../session/session-format-catalog/README.md | 1 + .../session-format-catalog/README.zh.md | 1 + .../session-format-catalog/package.json | 1 + .../session-format-catalog/src/generated.ts | 28 +- .../tests/catalog.spec.ts | 22 +- .../tests/current.spec.ts | 7 +- .../tests/preset-migration.spec.ts | 5 +- .../session-format-catalog/tsconfig.json | 3 + .../session-format-v2-to-v3/tests/catalog.ts | 21 + .../tests/combined-migration.spec.ts | 2 +- .../tests/content-admission.spec.ts | 2 +- .../session-format-v3-to-v4/README.i18n.yaml | 6 + .../session/session-format-v3-to-v4/README.md | 111 + .../session-format-v3-to-v4/README.zh.md | 111 + .../session-format-v3-to-v4/package.json | 51 + .../session-format-v3-to-v4/src/codec.ts | 38 + .../session-format-v3-to-v4/src/index.ts | 6 + .../session-format-v3-to-v4/src/migration.ts | 63 + .../session-format-v3-to-v4/src/validation.ts | 55 + .../tests/codec.spec.ts | 116 + .../tests/migration.spec.ts | 154 + .../session-format-v3-to-v4/tsconfig.json | 13 + .../session-persistence-jsonl/package.json | 2 +- .../session-persistence-jsonl/src/format.ts | 6 +- .../tests/built-migration-worker.e2e.ts | 6 +- .../tests/content-admission.spec.ts | 8 +- ...pec.ts => current-event-admission.spec.ts} | 12 +- .../tests/generation.spec.ts | 119 +- .../tests/jsonl.spec.ts | 35 +- .../tests/migration-refusal.spec.ts | 73 +- .../tests/multi-edge-publication.spec.ts | 10 +- .../tests/v2-ptc-migration.spec.ts | 12 +- .../tests/v2-system-migration.spec.ts | 14 +- .../session-persistence-jsonl/tsconfig.json | 2 +- .../llm-replay/tests/llm-replay.spec.ts | 4 +- .../session-snapshot/README.i18n.yaml | 4 +- .../test-support/session-snapshot/README.md | 4 +- .../session-snapshot/README.zh.md | 4 +- .../session-snapshot/src/normalize.ts | 45 +- .../session-snapshot/src/suite.ts | 4 +- .../session-snapshot/tests/normalize.spec.ts | 57 +- pnpm-lock.yaml | 20 +- python/sdk/tests/test_smoke_model.py | 35 +- scripts/doc-standard.spec.ts | 1 + scripts/gen-session-format-catalog.ts | 8 +- .../session-snapshot-corpus-policy.spec.ts | 49 +- scripts/session-snapshot-corpus-policy.ts | 31 +- scripts/session-snapshot-corpus.corpus.ts | 6 +- snapshots/AGENTS.md | 2 +- snapshots/sdk/sdk.snapshot.ts | 21 +- snapshots/session/headless.snapshot.ts | 6 +- tsconfig.base.json | 1 + tsconfig.host.json | 1 + 91 files changed, 74142 insertions(+), 406 deletions(-) create mode 100644 docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml create mode 100644 docs/persistence-changes/2026-09-16-session-format-v4.md create mode 100644 docs/persistence-changes/2026-09-16-session-format-v4.schema.json create mode 100644 docs/persistence-changes/2026-09-16-session-format-v4.zh.md create mode 100644 docs/persistence-changes/historical-formats/v3.i18n.yaml create mode 100644 docs/persistence-changes/historical-formats/v3.md create mode 100644 docs/persistence-changes/historical-formats/v3.schema.json create mode 100644 docs/persistence-changes/historical-formats/v3.zh.md create mode 100644 packages/session/session-format-v2-to-v3/tests/catalog.ts create mode 100644 packages/session/session-format-v3-to-v4/README.i18n.yaml create mode 100644 packages/session/session-format-v3-to-v4/README.md create mode 100644 packages/session/session-format-v3-to-v4/README.zh.md create mode 100644 packages/session/session-format-v3-to-v4/package.json create mode 100644 packages/session/session-format-v3-to-v4/src/codec.ts create mode 100644 packages/session/session-format-v3-to-v4/src/index.ts create mode 100644 packages/session/session-format-v3-to-v4/src/migration.ts create mode 100644 packages/session/session-format-v3-to-v4/src/validation.ts create mode 100644 packages/session/session-format-v3-to-v4/tests/codec.spec.ts create mode 100644 packages/session/session-format-v3-to-v4/tests/migration.spec.ts create mode 100644 packages/session/session-format-v3-to-v4/tsconfig.json rename packages/session/session-persistence-jsonl/tests/{v3-event-admission.spec.ts => current-event-admission.spec.ts} (93%) diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml index 759741d3f1..d75ac2da5f 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.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 .agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md -2026-08-31-released-session-format-migrations.md: d566459af64f4177ed0135813e75aaf77480823c -2026-08-31-released-session-format-migrations.zh.md: f82b406117691197d808111f1c8aa4c722d4bab2 +2026-08-31-released-session-format-migrations.md: 6c236431a69a004d969b321f896041b791b2900a +2026-08-31-released-session-format-migrations.zh.md: 3c0e242770a5056c621e971befb023869926bf6f diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md index d566459af6..6c236431a6 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md @@ -59,6 +59,7 @@ JSONL record → v0-to-v1 stage → v1-to-v2 stage → v2-to-v3 stage + → v3-to-v4 stage → current event collector ``` @@ -66,6 +67,8 @@ The chain contains no `flatMap`, spread expansion, intermediate event array, or ### Adjacent version ownership +The [V3-to-V4 specification](../../../../packages/session/session-format-v3-to-v4/README.md#v3-to-v4-specification) owns an identity body conversion: it advances the header version while preserving admitted events and inherited cuts. It reuses the frozen V3 codec from V2→V3. Generation-aware delivery validation prevents a historical acknowledgement from acquiring a current watermark meaning solely through the header change; earlier edges retain their own source-admission policies. + The [V2-to-V3 delivery guards](../../../../packages/session/session-format-v2-to-v3/README.md#delivery-guards) prevent a marker ignored in the source generation from becoming an active upload watermark merely because the header changes. Python release smoke checks generated logs against the source `SESSION_FORMAT_VERSION` independently of generation-neutral golden comparison, so coherent filenames and headers cannot conceal an outdated writer. The [V2-to-V3 README](../../../../packages/session/session-format-v2-to-v3/README.md#v2-to-v3-specification) is the single specification for that edge's transformations, preservation, and refusal; its separate [native admission section](../../../../packages/session/session-format-v2-to-v3/README.md#native-v3-admission) prevents current-only capabilities from being mistaken for historical transformations. The released V2 codec remains owned by V1→V2 and is reused, not copied. The [system-prompt](2026-09-02-system-prompt-as-surface-node.md), [PTC](../feature/2026-06-15-ptc.md), and [canonical-envelope](2026-09-06-v3-canonical-session-envelopes.md) notes retain their independent rationale, not duplicate conversion specifications. The [format-version cookbook](../../../../docs/cookbook/adding-a-session-format-version.md) owns package wiring, current consumers, snapshot successors, and validation commands. diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md index f82b406117..3c0e242770 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md @@ -59,6 +59,7 @@ JSONL record → v0-to-v1 stage → v1-to-v2 stage → v2-to-v3 stage + → v3-to-v4 stage → current event collector ``` @@ -66,6 +67,8 @@ Chain 中不存在 `flatMap`、spread expansion、中间 event array 或 schedul ### 相邻版本所有权 +[V3 到 V4 规范](../../../../packages/session/session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)负责 body 的恒等转换:它推进 header 版本,同时保留已接纳的事件与继承切点。它复用 V2→V3 中冻结的 V3 codec。按 generation 校验 delivery 可防止历史确认仅因 header 变化而获得当前水位含义;更早的 migration edge 保留各自的来源准入策略。 + [V2 到 V3 投递保护](../../../../packages/session/session-format-v2-to-v3/README.zh.md#delivery-guards)防止源代中被忽略的标记仅因头部变化就成为有效上传水位。Python 发布冒烟测试独立于跨代 golden 比较,按源代码中的 `SESSION_FORMAT_VERSION` 检查生成日志,因此文件名与 header 自洽不能掩盖过期 writer。 [V2 到 V3 README](../../../../packages/session/session-format-v2-to-v3/README.zh.md#v2-to-v3-specification)是该迁移边转换、保留与拒绝规则的单一规范真源;单列的[原生准入章节](../../../../packages/session/session-format-v2-to-v3/README.zh.md#native-v3-admission)避免将仅当前版本支持的能力误认为历史转换。已发布 V2 codec 仍归 V1→V2 所有,并被复用而非复制。[系统提示词](2026-09-02-system-prompt-as-surface-node.zh.md)、[PTC](../feature/2026-06-15-ptc.zh.md)和[规范信封](2026-09-06-v3-canonical-session-envelopes.zh.md)记录保留各自独立依据,而非重复转换规范。[格式版本实操手册](../../../../docs/cookbook/adding-a-session-format-version.zh.md)负责包接线、当前消费方、快照后继代际与验证命令。 diff --git a/apps/web/tests/chat-scroll-contract.e2e.ts b/apps/web/tests/chat-scroll-contract.e2e.ts index 4299bf542c..e66b583852 100644 --- a/apps/web/tests/chat-scroll-contract.e2e.ts +++ b/apps/web/tests/chat-scroll-contract.e2e.ts @@ -13,6 +13,7 @@ import { ToolCallId } from '@deepseek-ai/dsh-llm' import type { AssistantStreamFrame } from '@deepseek-ai/dsh-agent' import type { ReplayEntry, ReplayOverrideDoc } from '@deepseek-ai/dsh-llm-replay' import type { SessionEvent } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import { createChatScrollFixture, type ChatScrollFixture } from './chat-scroll-fixture.ts' import { launchWebScaffold, @@ -472,9 +473,9 @@ function assertClean(world: ScrollWorld): void { expect(world.tripwire.warnings).toEqual([]) } -it('generates a native V3 scroll seed with a protected system head and intact references', () => { +it('generates a current-format scroll seed with a protected system head and intact references', () => { const { header, events } = parseSeedFixture(HISTORY_FIXTURE.log) - expect(header.version).toBe(3) + expect(header.version).toBe(SESSION_FORMAT_VERSION) expect(events.slice(0, 5).map(event => event.type)).toEqual([ 'turn/start', 'step/start', 'system/message', 'user/message', 'session/title', ]) diff --git a/apps/web/tests/preset-migration.snapshot.ts b/apps/web/tests/preset-migration.snapshot.ts index 7fb3d881d2..d8fccb3271 100644 --- a/apps/web/tests/preset-migration.snapshot.ts +++ b/apps/web/tests/preset-migration.snapshot.ts @@ -1,11 +1,11 @@ -/** Cold V2 restoration mounts the shipped PTC preset and publishes only a V3 successor. */ +/** Cold V2 restoration mounts the shipped PTC preset and publishes only the current successor. */ import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises' -import { dirname, join } from 'node:path' +import { dirname } from 'node:path' import { fileURLToPath } from 'node:url' import { zstdCompressSync, zstdDecompressSync } from 'node:zlib' import { describe, expect, it } from 'vitest' -import { SessionId } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' import { generationLogPath } from '../../../packages/session/session-persistence-jsonl/src/format.ts' import { scanZstdFrames } from '../../../packages/session/session-persistence-jsonl/src/zstd.ts' import type {} from '@deepseek-ai/dsh-agent-presets' @@ -28,7 +28,7 @@ describe.skipIf(webSnapshotMode() === 'record')('historical preset restoration t const rows: Record[] = events.map((event, seq) => ({ ...event, seq, time: seq + 2 })) const source = Buffer.concat([header, ...rows].map(row => zstdCompressSync(Buffer.from(JSON.stringify(row) + '\n')))) const predecessor = generationLogPath(scaffold.persistenceRoot, scaffold.workspaceCwd, id, 2, 'zstd') - const successor = join(dirname(predecessor), 'session.v3.jsonl.zstd') + const successor = generationLogPath(scaffold.persistenceRoot, scaffold.workspaceCwd, id, SESSION_FORMAT_VERSION, 'zstd') await mkdir(dirname(predecessor), { recursive: true }) await writeFile(predecessor, source) @@ -53,7 +53,7 @@ describe.skipIf(webSnapshotMode() === 'record')('historical preset restoration t const published = Buffer.concat(scanZstdFrames(publishedBytes).frames .map(({ start, end }) => zstdDecompressSync(publishedBytes.subarray(start, end)))).toString('utf8') const expected = [ - { ...header, version: 3, agentPreset: 'ptc' }, + { ...header, version: SESSION_FORMAT_VERSION, agentPreset: 'ptc' }, ...rows.map(row => row['type'] === 'agent-preset/selected' && (row['data'] as { agentPreset: string }).agentPreset === 'code' ? { ...row, data: { agentPreset: 'ptc' } } @@ -65,7 +65,7 @@ describe.skipIf(webSnapshotMode() === 'record')('historical preset restoration t expect(normalizeSessionSnapshots([published], context)).toEqual(normalizeSessionSnapshots([expected], context)) expect(await readFile(predecessor)).toEqual(source) expect((await readdir(dirname(predecessor))).filter(name => name.endsWith('.jsonl.zstd')).sort()) - .toEqual(['session.v2.jsonl.zstd', 'session.v3.jsonl.zstd']) + .toEqual(['session.v2.jsonl.zstd', `session.v${SESSION_FORMAT_VERSION}.jsonl.zstd`]) } finally { await scaffold.close() } diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index 6d95b62184..e65792e703 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-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/config-catalog.md -config-catalog.md: ba691e83e0e81bf608f090c56cca6b797074116b -config-catalog.zh.md: 78d39e6e85329d797699b0a6e9e151e13d48fa5e +config-catalog.md: baf3ba3930f441652d772de825a55c32fe7af7bc +config-catalog.zh.md: 3edfb7038ac531a8255a42067e7c69d7f7a20b58 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index ba691e83e0..baf3ba3930 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -3798,6 +3798,7 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them. - `@deepseek-ai/dsh-session-format-v0-to-v1` ([`packages/session/session-format-v0-to-v1/src/index.ts`](../packages/session/session-format-v0-to-v1/src/index.ts)) - `@deepseek-ai/dsh-session-format-v1-to-v2` ([`packages/session/session-format-v1-to-v2/src/index.ts`](../packages/session/session-format-v1-to-v2/src/index.ts)) - `@deepseek-ai/dsh-session-format-v2-to-v3` ([`packages/session/session-format-v2-to-v3/src/index.ts`](../packages/session/session-format-v2-to-v3/src/index.ts)) +- `@deepseek-ai/dsh-session-format-v3-to-v4` ([`packages/session/session-format-v3-to-v4/src/index.ts`](../packages/session/session-format-v3-to-v4/src/index.ts)) - `@deepseek-ai/dsh-session-snapshot` ([`packages/test-support/session-snapshot/src/index.ts`](../packages/test-support/session-snapshot/src/index.ts)) - `@deepseek-ai/dsh-session-telemetry` ([`packages/session/session-telemetry/src/index.ts`](../packages/session/session-telemetry/src/index.ts)) - `@deepseek-ai/dsh-session-title-llm` ([`packages/session/session-title-llm/src/index.ts`](../packages/session/session-title-llm/src/index.ts)) diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 78d39e6e85..3edfb7038a 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -3799,6 +3799,7 @@ export interface Config { - `@deepseek-ai/dsh-session-format-v0-to-v1`([`packages/session/session-format-v0-to-v1/src/index.ts`](../packages/session/session-format-v0-to-v1/src/index.ts)) - `@deepseek-ai/dsh-session-format-v1-to-v2`([`packages/session/session-format-v1-to-v2/src/index.ts`](../packages/session/session-format-v1-to-v2/src/index.ts)) - `@deepseek-ai/dsh-session-format-v2-to-v3`([`packages/session/session-format-v2-to-v3/src/index.ts`](../packages/session/session-format-v2-to-v3/src/index.ts)) +- `@deepseek-ai/dsh-session-format-v3-to-v4`([`packages/session/session-format-v3-to-v4/src/index.ts`](../packages/session/session-format-v3-to-v4/src/index.ts)) - `@deepseek-ai/dsh-session-snapshot`([`packages/test-support/session-snapshot/src/index.ts`](../packages/test-support/session-snapshot/src/index.ts)) - `@deepseek-ai/dsh-session-telemetry`([`packages/session/session-telemetry/src/index.ts`](../packages/session/session-telemetry/src/index.ts)) - `@deepseek-ai/dsh-session-title-llm`([`packages/session/session-title-llm/src/index.ts`](../packages/session/session-title-llm/src/index.ts)) diff --git a/docs/cookbook/adding-a-session-format-version.i18n.yaml b/docs/cookbook/adding-a-session-format-version.i18n.yaml index f66eda7447..0daad832a8 100644 --- a/docs/cookbook/adding-a-session-format-version.i18n.yaml +++ b/docs/cookbook/adding-a-session-format-version.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/cookbook/adding-a-session-format-version.md -adding-a-session-format-version.md: 6ebc6bd2062acd88dab953bc227bc1046b13f083 -adding-a-session-format-version.zh.md: c66a045303f96c2ef237cf3b1c1dc598e9c8f5f6 +adding-a-session-format-version.md: 84dab0f385d8eaae9da952e54a148060437ca285 +adding-a-session-format-version.zh.md: 11c918fb0a4ce839363cc9f4e7f4341a60bbbd77 diff --git a/docs/cookbook/adding-a-session-format-version.md b/docs/cookbook/adding-a-session-format-version.md index 6ebc6bd206..84dab0f385 100644 --- a/docs/cookbook/adding-a-session-format-version.md +++ b/docs/cookbook/adding-a-session-format-version.md @@ -69,7 +69,7 @@ Verify both read and write paths. Header-only listing must not read bodies or pu ## 5. Create snapshot successors -Read [snapshot ownership](../../snapshots/AGENTS.md) and the [snapshot library](../../packages/test-support/session-snapshot/README.md). Select the owning scenario, not an adapter that only references it. After implementing N+1, keep each historical file and generate its successor using the target version’s canonical parent and child filenames. Never rename a predecessor to the target filename or change only its header. +Read [snapshot ownership](../../snapshots/AGENTS.md) and the [snapshot library](../../packages/test-support/session-snapshot/README.md). The [corpus policy](../../scripts/session-snapshot-corpus-policy.ts) keeps its declared baseline as replay input so upgrades exercise the adjacent chain; a writer bump does not require refreshing that corpus. Select the owning scenario when a current-generation successor is needed, keep each historical file, and use the target version’s canonical parent and child filenames. Never rename a predecessor to the target filename or change only its header. For unchanged replay input, use keyless refresh on the owner, then replay without write-back. These SDK commands use `text-turn` and the checkout's writer version. Implement and wire N+1 before using them to generate that version, and select the actual affected owner for a feature: @@ -80,7 +80,7 @@ pnpm run test:snapshot snapshots/sdk/sdk.snapshot.ts -t text-turn Review the new generation, request sidecars, and protocol output together. Verify every predecessor remains byte-identical and that parent/child roles remain contiguous. Selection uses the numerically highest generation, so update shared references to the owner's selected parent. Do not use the packed-layout migrator as a version upgrader. If the model transcript must change, the scenario owner uses live recording under the [testing policy](../testing.md), with its required provider key. -Keep deliberate historical cases explicit through `snapshot.yml`'s `sessionFormat.version` and supported `coverage` names; record and refresh leave their Session fixtures untouched. Update the [corpus policy](../../scripts/session-snapshot-corpus-policy.ts) for the current generation while retaining focused direct-edge, multi-hop, packed-row, retry/failure, and shipped-profile coverage. Check the corpus and both SDK projections; do not mass-refresh unrelated scenarios merely to silence a validation failure. +Keep cases older than the retained baseline explicit through `snapshot.yml`'s `sessionFormat.version` and supported `coverage` names; record and refresh leave pinned Session fixtures untouched. Update the [corpus policy](../../scripts/session-snapshot-corpus-policy.ts) for the current generation while retaining focused direct-edge, multi-hop, packed-row, retry/failure, and shipped-profile coverage. Check the corpus and both SDK projections; do not mass-refresh unrelated scenarios merely to silence a validation failure. ## 6. Validate the integrated result diff --git a/docs/cookbook/adding-a-session-format-version.zh.md b/docs/cookbook/adding-a-session-format-version.zh.md index c66a045303..11c918fb0a 100644 --- a/docs/cookbook/adding-a-session-format-version.zh.md +++ b/docs/cookbook/adding-a-session-format-version.zh.md @@ -69,7 +69,7 @@ pnpm run gen-session-format-catalog ## 5. 创建快照后继代际 -阅读[快照所有权](../../snapshots/AGENTS.md)和[快照库](../../packages/test-support/session-snapshot/README.zh.md)。选择拥有数据的场景,而非仅引用它的适配器。实现 N+1 后,保留每份历史文件,并按目标版本的规范父子文件名生成后继文件。绝不将前代重命名为目标文件名,或仅修改其 header。 +阅读[快照所有权](../../snapshots/AGENTS.md)和[快照库](../../packages/test-support/session-snapshot/README.zh.md)。[语料策略](../../scripts/session-snapshot-corpus-policy.ts)保留其声明的 baseline 作为回放输入,让升级实际经过相邻迁移链;提高 writer 版本不要求 refresh 该语料。需要当前代际后继时,选择拥有数据的场景,保留每份历史文件,并使用目标版本的规范父子文件名。绝不将前代重命名为目标文件名,或仅修改其 header。 如果回放输入不变,在所有者上执行无密钥 refresh,再执行不写回的 replay。以下 SDK 命令使用 `text-turn` 和工作区的写入器版本。先实现并接入 N+1,才能用它们生成该版本;功能变更应选择实际受影响的所有者: @@ -80,7 +80,7 @@ pnpm run test:snapshot snapshots/sdk/sdk.snapshot.ts -t text-turn 一起审查新代际、请求伴随文件与协议输出。验证每个前代的字节保持相同,且父子角色连续。选择规则采用数值最高的代际,因此应将共享引用更新为所有者选中的父代际。不要把 packed 布局迁移器当作版本升级器。如果模型 transcript(文本记录)必须变化,由场景所有者按照[测试策略](../testing.zh.md)使用所需提供方密钥进行实时录制。 -通过 `snapshot.yml` 的 `sessionFormat.version` 与受支持的 `coverage` 名称显式保留历史案例;record 和 refresh 不改动这些 Session fixture。更新[语料策略](../../scripts/session-snapshot-corpus-policy.ts)以采用当前代际,同时保留聚焦的直接迁移边、多跳、packed row、重试/失败及交付 profile 覆盖。检查语料和两个 SDK 投影;不要仅为消除校验失败而批量 refresh 无关场景。 +通过 `snapshot.yml` 的 `sessionFormat.version` 与受支持的 `coverage` 名称显式保留早于 baseline 的案例;record 和 refresh 不改动已 pin 的 Session fixture。更新[语料策略](../../scripts/session-snapshot-corpus-policy.ts)以采用当前代际,同时保留聚焦的直接迁移边、多跳、packed row、重试/失败及交付 profile 覆盖。检查语料和两个 SDK 投影;不要仅为消除校验失败而批量 refresh 无关场景。 ## 6. 验证集成结果 diff --git a/docs/module-graph.i18n.yaml b/docs/module-graph.i18n.yaml index 21ea52cffa..b143df3c3d 100644 --- a/docs/module-graph.i18n.yaml +++ b/docs/module-graph.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/module-graph.md -module-graph.md: 719273c14784fcf5dd98b2fddabfb7666c666139 -module-graph.zh.md: b1098cc39fdc1d44f9d7edc3555d18a2f2c26bc5 +module-graph.md: b0f35fda6446f32ffd9d68fceda82484f8fe208f +module-graph.zh.md: 5a8d81a8fc46e38dbd8379e9dc7e71d202b6ca08 diff --git a/docs/module-graph.md b/docs/module-graph.md index 719273c147..b0f35fda64 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -318,6 +318,7 @@ flowchart TD pkg_session_format_v0_to_v1["session-format-v0-to-v1"] pkg_session_format_v1_to_v2["session-format-v1-to-v2"] pkg_session_format_v2_to_v3["session-format-v2-to-v3"] + pkg_session_format_v3_to_v4["session-format-v3-to-v4"] pkg_session_log_deepseek["session-log-deepseek"] pkg_session_persistence["session-persistence"] pkg_session_persistence_jsonl["session-persistence-jsonl"] @@ -1378,6 +1379,7 @@ flowchart TD | [`session-format-v0-to-v1`](../packages/session/session-format-v0-to-v1) | `session` | — | | [`session-format-v1-to-v2`](../packages/session/session-format-v1-to-v2) | `session` | — | | [`session-format-v2-to-v3`](../packages/session/session-format-v2-to-v3) | `session` | — | +| [`session-format-v3-to-v4`](../packages/session/session-format-v3-to-v4) | `session` | — | | [`storage`](../packages/storage/storage) | `storage` | — | | [`win32-process`](../packages/subprocess/win32-process) | `subprocess` | — | | [`llm-mock-server`](../packages/test-support/llm-mock-server) | `test-support` | — | diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md index b1098cc39f..5a8d81a8fc 100644 --- a/docs/module-graph.zh.md +++ b/docs/module-graph.zh.md @@ -320,6 +320,7 @@ flowchart TD pkg_session_format_v0_to_v1["session-format-v0-to-v1"] pkg_session_format_v1_to_v2["session-format-v1-to-v2"] pkg_session_format_v2_to_v3["session-format-v2-to-v3"] + pkg_session_format_v3_to_v4["session-format-v3-to-v4"] pkg_session_log_deepseek["session-log-deepseek"] pkg_session_persistence["session-persistence"] pkg_session_persistence_jsonl["session-persistence-jsonl"] @@ -1380,6 +1381,7 @@ flowchart TD | [`session-format-v0-to-v1`](../packages/session/session-format-v0-to-v1) | `session` | — | | [`session-format-v1-to-v2`](../packages/session/session-format-v1-to-v2) | `session` | — | | [`session-format-v2-to-v3`](../packages/session/session-format-v2-to-v3) | `session` | — | +| [`session-format-v3-to-v4`](../packages/session/session-format-v3-to-v4) | `session` | — | | [`storage`](../packages/storage/storage) | `storage` | — | | [`win32-process`](../packages/subprocess/win32-process) | `subprocess` | — | | [`llm-mock-server`](../packages/test-support/llm-mock-server) | `test-support` | — | diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index 197b13291c..209d3d1edf 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: 99c24562c178b35944e5616729076d015eb3f4c6 -persistence-catalog.zh.md: a2c9590a799a1bd63745afaaad989be051015ae0 +persistence-catalog.md: 1f28ccf7178ce6c51b6fb2d00a43d1365760945a +persistence-catalog.zh.md: 73bd6df4edd8427910d1e1c1da0c039a0a9732b4 diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 99c24562c1..1f28ccf717 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -17,7 +17,7 @@ The [format references](persistence-changes/historical-formats/README.md) cover | Root | Kind | SHA-256 | Resolved type | |---|---|---|---| -| `SessionHeader` | header | `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` | [`packages/core/session/src/types.ts#SessionHeader`](#persistence-type-packagescoresessionsrctypestssessionheader) | +| `SessionHeader` | header | `1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445` | [`packages/core/session/src/types.ts#SessionHeader`](#persistence-type-packagescoresessionsrctypestssessionheader) | | `JsonlHeaderLine` | header | `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` | [`packages/session/session-persistence-jsonl/src/format.ts#HeaderLine`](#persistence-type-packagessessionsession-persistence-jsonlsrcformattsheaderline) | | `SessionEventEnvelope` | envelope | `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` | [`SessionEventEnvelope`](#persistence-type-sessioneventenvelope) | | `event:agent-preset/selected` | event | `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | [`event:agent-preset/selected`](#persistence-type-eventagent-presetselected) | @@ -1268,13 +1268,13 @@ SHA-256: `a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80` `2` - + -### `3` +### `4` -SHA-256: `137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e` +SHA-256: `af6e173f7be819bcd0a5c8d77918649c10ce761d8a184ff472f2e01ce64eb2e0` -`3` +`4` @@ -4560,7 +4560,7 @@ One of: ### `packages/core/session/src/types.ts#SessionHeader` -SHA-256: `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` +SHA-256: `1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445` Sources: [`packages/core/session/src/types.ts:93`](../packages/core/session/src/types.ts) @@ -4574,7 +4574,7 @@ Sources: [`packages/core/session/src/types.ts:93`](../packages/core/session/src/ | `isSeeded` | required | `boolean` | | `origin` | optional | `"subagent"` | | `parentSession` | optional | `string` | -| `version` | required | `3` | +| `version` | required | `4` | diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index a2c9590a79..73bd6df4ed 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -19,7 +19,7 @@ | 根类型 | 类别 | SHA-256 | 已解析类型 | |---|---|---|---| -| `SessionHeader` | header | `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` | [`packages/core/session/src/types.ts#SessionHeader`](#persistence-type-packagescoresessionsrctypestssessionheader) | +| `SessionHeader` | header | `1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445` | [`packages/core/session/src/types.ts#SessionHeader`](#persistence-type-packagescoresessionsrctypestssessionheader) | | `JsonlHeaderLine` | header | `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` | [`packages/session/session-persistence-jsonl/src/format.ts#HeaderLine`](#persistence-type-packagessessionsession-persistence-jsonlsrcformattsheaderline) | | `SessionEventEnvelope` | envelope | `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` | [`SessionEventEnvelope`](#persistence-type-sessioneventenvelope) | | `event:agent-preset/selected` | event | `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | [`event:agent-preset/selected`](#persistence-type-eventagent-presetselected) | @@ -1270,13 +1270,13 @@ SHA-256: `a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80` `2` - + -### `3` +### `4` -SHA-256: `137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e` +SHA-256: `af6e173f7be819bcd0a5c8d77918649c10ce761d8a184ff472f2e01ce64eb2e0` -`3` +`4` @@ -4562,7 +4562,7 @@ SHA-256: `530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6` ### `packages/core/session/src/types.ts#SessionHeader` -SHA-256: `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` +SHA-256: `1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445` 来源:[`packages/core/session/src/types.ts:93`](../packages/core/session/src/types.ts) @@ -4576,7 +4576,7 @@ SHA-256: `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` | `isSeeded` | 必需 | `boolean` | | `origin` | 可选 | `"subagent"` | | `parentSession` | 可选 | `string` | -| `version` | 必需 | `3` | +| `version` | 必需 | `4` | diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml b/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml new file mode 100644 index 0000000000..abb5bc3e7f --- /dev/null +++ b/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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-changes/2026-09-16-session-format-v4.md +2026-09-16-session-format-v4.md: 57273fba4d45ff77537a4d5777f182eef406e156 +2026-09-16-session-format-v4.zh.md: 26c15f688b0f68974ed07c720b1e4c1b168f1a6c diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.md b/docs/persistence-changes/2026-09-16-session-format-v4.md new file mode 100644 index 0000000000..57273fba4d --- /dev/null +++ b/docs/persistence-changes/2026-09-16-session-format-v4.md @@ -0,0 +1,48 @@ +--- +description: "Records a persistence type transition and its compatibility acknowledgement." +kind: persistence-change +--- + +# 2026-09-16-session-format-v4 + +English | [中文](2026-09-16-session-format-v4.zh.md) + +## Summary + +Advances the declared SessionHeader.version from 3 to 4 for the V4 integration writer. No declared event payload or envelope type changes. + +## Table of Contents + +- [Declaration](#declaration) +- [Compatibility](#compatibility) +- [Verification](#verification) +- [Dev Note](#dev-note) + + +## Declaration + +```yaml persistence-change +schemaVersion: 1 +id: 2026-09-16-session-format-v4 +baseline: false +changes: + - root: "SessionHeader" + previous: "2026-09-11-initial" + after: "1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445" + decision: version-bump +``` + + +## Compatibility + +The [V3-to-V4 migration](../../packages/session/session-format-v3-to-v4/README.md#v3-to-v4-specification) advances the header and preserves every admitted event and inherited cut. Its generation-aware delivery checks prevent historical acknowledgements from becoming active V4 watermarks. V3 readers refuse the newer generation; the catalog restores supported older inputs through the complete adjacent chain. The [V3 schema reference](historical-formats/v3.md) preserves the outgoing declarations, and persistence retains committed predecessor bytes while publishing only the current successor. + + +## Verification + +`pnpm exec vitest run packages/session/session-format-v3-to-v4/tests` passed 22 tests across two files, covering identity preservation, inherited cuts, admission, and delivery-generation refusal. `pnpm run verify-persistence-formats` passed for all five references from V0 through V4. Before the writer change, `pnpm run verify-persistence-catalog` passed and `pnpm run verify-persistence-formats --archive 3` captured the V3 schema. + + +## Dev Note + +None. diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.schema.json b/docs/persistence-changes/2026-09-16-session-format-v4.schema.json new file mode 100644 index 0000000000..6568960cda --- /dev/null +++ b/docs/persistence-changes/2026-09-16-session-format-v4.schema.json @@ -0,0 +1,87 @@ +{ + "formatVersion": 1, + "roots": [ + { + "key": "SessionHeader", + "kind": "header", + "digest": "1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 2, + "optional": false + }, + { + "name": "cwd", + "type": 1, + "optional": true + }, + { + "name": "delegationDepth", + "type": 2, + "optional": true + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "isSeeded", + "type": 3, + "optional": false + }, + { + "name": "origin", + "type": 4, + "optional": true + }, + { + "name": "parentSession", + "type": 1, + "optional": true + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "subagent" + }, + { + "kind": "literal", + "value": 4 + } + ] + } + } + ], + "types": [] +} diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.zh.md b/docs/persistence-changes/2026-09-16-session-format-v4.zh.md new file mode 100644 index 0000000000..26c15f688b --- /dev/null +++ b/docs/persistence-changes/2026-09-16-session-format-v4.zh.md @@ -0,0 +1,48 @@ +--- +description: "记录持久化类型更改及其兼容性确认。" +kind: persistence-change +--- + +# 2026-09-16-session-format-v4 + +[English](2026-09-16-session-format-v4.md) | 中文 + +## 概述 + +将声明的 SessionHeader.version 从 3 推进到 4,用于 V4 集成写入器。事件载荷与信封的声明类型均未变化。 + +## 目录 + +- [声明](#declaration) +- [兼容性](#compatibility) +- [验证](#verification) +- [开发备注](#dev-note) + + +## 声明 + +```yaml persistence-change +schemaVersion: 1 +id: 2026-09-16-session-format-v4 +baseline: false +changes: + - root: "SessionHeader" + previous: "2026-09-11-initial" + after: "1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445" + decision: version-bump +``` + + +## 兼容性 + +[V3 到 V4 迁移](../../packages/session/session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)推进 header,并保留每个已接纳事件与继承切点。其按 generation 校验 delivery 的规则可防止历史确认成为有效的 V4 水位。V3 读取方拒绝更新的 generation;目录通过完整的相邻迁移链恢复受支持的旧输入。[V3 schema 参考](historical-formats/v3.zh.md)保留原声明,持久化在只发布当前后继代的同时保留已提交前代的字节。 + + +## 验证 + +`pnpm exec vitest run packages/session/session-format-v3-to-v4/tests` 的两个文件共 22 个测试通过,覆盖恒等保留、继承切点、准入与 delivery generation 拒绝。`pnpm run verify-persistence-formats` 对从 V0 到 V4 的全部五个参考均验证通过。写入器变更前,`pnpm run verify-persistence-catalog` 通过,且 `pnpm run verify-persistence-formats --archive 3` 已捕获 V3 schema。 + + +## 开发备注 + +无。 diff --git a/docs/persistence-changes/historical-formats/README.i18n.yaml b/docs/persistence-changes/historical-formats/README.i18n.yaml index 1e25621ff8..f583fa9de3 100644 --- a/docs/persistence-changes/historical-formats/README.i18n.yaml +++ b/docs/persistence-changes/historical-formats/README.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-changes/historical-formats/README.md -README.md: 35fa4cec9c960e8d0e047c42e35dad83992ac8d0 -README.zh.md: 7dd2af55d1d68c108d678e6e0849f7d679da929d +README.md: 35b09b11b41f80bfe138829099ceff98123ca4bc +README.zh.md: 409bfe99922b5689321072c75cfd599f75ad96f3 diff --git a/docs/persistence-changes/historical-formats/README.md b/docs/persistence-changes/historical-formats/README.md index 35fa4cec9c..35b09b11b4 100644 --- a/docs/persistence-changes/historical-formats/README.md +++ b/docs/persistence-changes/historical-formats/README.md @@ -31,7 +31,8 @@ The index is generated from validated snapshots and the current writer constant. | 0 | `dsh-v0.1.2-rc.1` | [V0](v0.md) | [JSON](v0.schema.json) | 54 / 415 | | 1 | PR #3349 | [V1](v1.md) | [JSON](v1.schema.json) | 54 / 415 | | 2 | `dsh-v0.1.3-alpha.2` | [V2](v2.md) | [JSON](v2.schema.json) | 56 / 435 | -| 3 | Current checkout | [Current catalog](../../persistence-catalog.md) | [JSON](../../persistence-schema.json) | 60 / 468 | +| 3 | PR #4320 | [V3](v3.md) | [JSON](v3.schema.json) | 60 / 467 | +| 4 | Current checkout | [Current catalog](../../persistence-catalog.md) | [JSON](../../persistence-schema.json) | 60 / 468 | @@ -40,7 +41,7 @@ The index is generated from validated snapshots and the current writer constant. Each `vN.md` / `vN.zh.md` pair has `kind: persistence-format`, an identical `yaml persistence-format` declaration binding every root key to its captured digest, a pairing sidecar, and a complete `vN.schema.json`. The [template](../../../.agents/skills/dsh-doc/templates/persistence-format.md) defines these records. Roots cover the logical Session header, physical JSONL header, event envelope, and all first-party events at the selected checkpoint; each root includes every reachable declared type. Packed physical body records have separate codec owners linked from each page. -V0 and V2 use the latest matching tags in the [captured prerelease archive](../releases/README.md). V1 uses an intermediate source tree identified in its reference because the captured tags contain no V1 writer. Historical sources retain file paths without line numbers. Snapshots preserve historical optional fields and opaque values; they do not substitute current types into older formats. Historical identifiers remain intact only in schema JSON and the verified generated schema regions; authored prose follows current terminology rules. +V0 and V2 use the latest matching tags in the [captured prerelease archive](../releases/README.md). V1 uses an intermediate source tree identified in its reference because the captured tags contain no V1 writer. V3 captures the verified inventory before the V4 writer change in PR #4320. Historical sources retain file paths without line numbers. Snapshots preserve historical optional fields and opaque values; they do not substitute current types into older formats. Historical identifiers remain intact only in schema JSON and the verified generated schema regions; authored prose follows current terminology rules. These references describe selected schemas, not historical application replay or migration safety. Same-version event additions and optional payload changes can produce other valid inventories. The prerelease archive retains tag-by-tag differences; [change records](../README.md) retain current compatibility acknowledgements. Neither history is replaced by these format snapshots. diff --git a/docs/persistence-changes/historical-formats/README.zh.md b/docs/persistence-changes/historical-formats/README.zh.md index 7dd2af55d1..409bfe9992 100644 --- a/docs/persistence-changes/historical-formats/README.zh.md +++ b/docs/persistence-changes/historical-formats/README.zh.md @@ -31,7 +31,8 @@ description: "查找从 V0 到工作区写入器版本的每个 Session 格式 | 0 | `dsh-v0.1.2-rc.1` | [V0](v0.zh.md) | [JSON](v0.schema.json) | 54 / 415 | | 1 | PR #3349 | [V1](v1.zh.md) | [JSON](v1.schema.json) | 54 / 415 | | 2 | `dsh-v0.1.3-alpha.2` | [V2](v2.zh.md) | [JSON](v2.schema.json) | 56 / 435 | -| 3 | 当前工作树 | [当前目录](../../persistence-catalog.zh.md) | [JSON](../../persistence-schema.json) | 60 / 468 | +| 3 | PR #4320 | [V3](v3.zh.md) | [JSON](v3.schema.json) | 60 / 467 | +| 4 | 当前工作树 | [当前目录](../../persistence-catalog.zh.md) | [JSON](../../persistence-schema.json) | 60 / 468 | @@ -40,7 +41,7 @@ description: "查找从 V0 到工作区写入器版本的每个 Session 格式 每组 `vN.md` / `vN.zh.md` 文档包含 `kind: persistence-format`、将每个根类型键绑定到已记录摘要的相同 `yaml persistence-format` 声明、配对记录及完整的 `vN.schema.json`。[模板](../../../.agents/skills/dsh-doc/templates/persistence-format.md)定义这些记录。根类型覆盖所选检查点的逻辑 Session header、物理 JSONL header、事件信封与所有第一方事件;每个根包含所有可达的声明类型。打包的物理 body 记录由每页链接的独立 codec 负责。 -V0 与 V2 使用[已收录预发布归档](../releases/README.zh.md)中最后一个对应 tag。由于收录的 tag 没有 V1 写入器,V1 使用其参考文档中标识的中间源码树。历史来源保留文件路径,不包含行号。快照保留历史可选字段与不透明值,不会将当前类型替换到旧格式中。历史标识符仅在 schema JSON 与已验证的生成 schema 区间中原样保留;人工说明遵循当前术语规则。 +V0 与 V2 使用[已收录预发布归档](../releases/README.zh.md)中最后一个对应 tag。由于收录的 tag 没有 V1 写入器,V1 使用其参考文档中标识的中间源码树。V3 捕获 PR #4320 中 V4 写入器变更前已验证的目录。历史来源保留文件路径,不包含行号。快照保留历史可选字段与不透明值,不会将当前类型替换到旧格式中。历史标识符仅在 schema JSON 与已验证的生成 schema 区间中原样保留;人工说明遵循当前术语规则。 这些参考描述选定的 schema,不表示历史应用回放结果或迁移安全性。同版本内新增事件与可选载荷变更可以产生其他有效目录。预发布归档保留逐 tag 差异;[变更记录](../README.zh.md)保留当前兼容性确认。这些格式快照不替代任何一种历史。 diff --git a/docs/persistence-changes/historical-formats/v3.i18n.yaml b/docs/persistence-changes/historical-formats/v3.i18n.yaml new file mode 100644 index 0000000000..d8b64d6969 --- /dev/null +++ b/docs/persistence-changes/historical-formats/v3.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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-changes/historical-formats/v3.md +v3.md: cf9d6d64b08e4e861bdb20e244e1e5d75e297323 +v3.zh.md: b49cbf23a9c66fbe2804e1f2a28ac4e5cfcd7441 diff --git a/docs/persistence-changes/historical-formats/v3.md b/docs/persistence-changes/historical-formats/v3.md new file mode 100644 index 0000000000..cf9d6d64b0 --- /dev/null +++ b/docs/persistence-changes/historical-formats/v3.md @@ -0,0 +1,5634 @@ +--- +description: "Complete Session V3 persistence types, source evidence, and physical encoding references." +kind: persistence-format +--- + +# Session V3 persistence format + +English | [中文](v3.zh.md) + +## Summary + +Inspect the V3 persistence types captured before the V4 writer change in PR #4320. System prompts use surface messages, replacement endpoints use `startSeq` / `endSeq`, and surface events have explicit placement. This snapshot preserves the complete declared inventory at that V3 checkpoint. + +## Table of Contents + +- [Source evidence](#evidence) +- [Format characteristics](#characteristics) +- [Declaration](#declaration) +- [Complete schemas](#schema) +- [Verification and limitations](#verification) +- [Dev Note](#dev-note) + +----- + + +## Source evidence + +The source is the initial tree of PR #4320 on `release/session-log-v4`, recorded by the empty commit dated 2026-09-16 and titled `chore(session): initialize V4 release integration PR`. It contains the master tree with writer version 3, before the V4 source changes. The catalog freshness check passed and the V3 archive command captured the inventory before the writer advanced. This checkpoint is neither the final PR tree nor a new product release; the [release-status reference](../../session-format-status.md) owns publication evidence. + +The extracted declarations come from `packages/core/session/src/types.ts`, `packages/session/session-persistence-jsonl/src/format.ts`, and every first-party `SessionEventMap` merge and its reachable types. Source locations below refer to that captured tree, without line numbers. + + +## Format characteristics + +These facts describe the selected checkpoint. The generated tables below preserve the exact field types and optionality. + +- `SessionHeader.version` resolves to the literal 3. Logical and physical headers require `isSeeded`; the physical header has no `seedLength`. +- `system/message`, `user/message`, `assistant/message`, and `tool/result` require `surfaceOp`. Replacement endpoints are `startSeq` and `endSeq`; Assistant messages do not carry `sourceEventSeqs`. +- Assistant streams remain embedded in message or attempt events. System prompt text belongs to `system/message`, and PTC dispatch events use `tool/ptc-dispatch-start` and `tool/ptc-dispatch`. + +The [V3 codec](../../../packages/session/session-format-v2-to-v3/src/codec.ts) owns canonical event framing and source-event range encoding. The [V2-to-V3 specification](../../../packages/session/session-format-v2-to-v3/README.md#v2-to-v3-specification) defines historical conversion, while its [native V3 admission rules](../../../packages/session/session-format-v2-to-v3/README.md#native-v3-admission) distinguish extension handling from historical source validation. + +For a seeded V3 Session, the last `session/end-seed` event carrying `data.inherited: true` identifies the inherited cut by its sequence position. Physical `sourceEventSeqs` may use encoded ranges; the logical schemas retain expanded number arrays. + + +## Declaration + +[Schema inventory](v3.schema.json). + +```yaml persistence-format +schemaVersion: 1 +sessionFormatVersion: 3 +source: + pullRequest: 4320 +roots: + "SessionHeader": 2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03 + "JsonlHeaderLine": 18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f + "SessionEventEnvelope": 5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc + "event:agent-preset/selected": a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b + "event:agent/inbox/spliced": 646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f + "event:approval/asked": 3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1 + "event:approval/decided": bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3 + "event:approval/policy": 26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78 + "event:assistant/attempt": c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e + "event:assistant/message": 1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d + "event:command/done": 15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff + "event:command/run": 37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006 + "event:compaction/end": b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d + "event:compaction/prune": 7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04 + "event:compaction/start": db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965 + "event:compaction/summary": f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59 + "event:deliverables/presented": 13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176 + "event:feedback/message-delete": 3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796 + "event:feedback/message-put": b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf + "event:feedback/record": b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8 + "event:goal/change": 763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d + "event:hook/invoked": 8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0 + "event:hook/result": e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4 + "event:image/offload": b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e + "event:llm/retry": 525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336 + "event:llm/retry-started": 48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3 + "event:model/selection": 35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc + "event:permission/preset": 5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b + "event:plan/mode": a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f + "event:request/context": 37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf + "event:request/header": 8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489 + "event:sandbox/mode": 516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415 + "event:schedule/change": 2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42 + "event:session-log-deepseek/delivery-accepted": d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9 + "event:session/end-seed": 5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e + "event:session/title": 1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5 + "event:session/title-llm-request": e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d + "event:step/end": e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05 + "event:step/start": 4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986 + "event:subagent/catalog": ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871 + "event:subagent/descriptor": b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5 + "event:subagent/model-selection-policy": a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc + "event:system/message": 69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae + "event:team/member": 4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc + "event:team/message/delivered": 48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb + "event:team/message/queued": 443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4 + "event:team/task": d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a + "event:todo/write": b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26 + "event:tool-workflow/agent-end": babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7 + "event:tool-workflow/agent-start": 5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627 + "event:tool-workflow/run-end": 42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f + "event:tool-workflow/run-start": c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058 + "event:tool/call": 3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48 + "event:tool/ptc-dispatch": b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c + "event:tool/ptc-dispatch-start": ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93 + "event:tool/result": 29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2 + "event:turn/end": bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b + "event:turn/start": aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8 + "event:user/message": 314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578 + "event:web/deepseek-search-llm-request": cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331 +``` + + + + +## Complete schemas + +The [complete machine inventory](v3.schema.json) contains 60 roots and 467 reachable types. Digests include all referenced fields; source names and paths describe the selected historical tree. + +### Persistence type fingerprints + +| Root | Kind | SHA-256 | Resolved type | +|---|---|---|---| +| `SessionHeader` | header | `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` | [`packages/core/session/src/types.ts#SessionHeader`](#persistence-type-packagescoresessionsrctypestssessionheader) | +| `JsonlHeaderLine` | header | `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` | [`packages/session/session-persistence-jsonl/src/format.ts#HeaderLine`](#persistence-type-packagessessionsession-persistence-jsonlsrcformattsheaderline) | +| `SessionEventEnvelope` | envelope | `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` | [`SessionEventEnvelope`](#persistence-type-sessioneventenvelope) | +| `event:agent-preset/selected` | event | `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | [`event:agent-preset/selected`](#persistence-type-eventagent-presetselected) | +| `event:agent/inbox/spliced` | event | `646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f` | [`event:agent/inbox/spliced`](#persistence-type-eventagentinboxspliced) | +| `event:approval/asked` | event | `3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1` | [`event:approval/asked`](#persistence-type-eventapprovalasked) | +| `event:approval/decided` | event | `bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3` | [`event:approval/decided`](#persistence-type-eventapprovaldecided) | +| `event:approval/policy` | event | `26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78` | [`event:approval/policy`](#persistence-type-eventapprovalpolicy) | +| `event:assistant/attempt` | event | `c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e` | [`event:assistant/attempt`](#persistence-type-eventassistantattempt) | +| `event:assistant/message` | event | `1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d` | [`event:assistant/message`](#persistence-type-eventassistantmessage) | +| `event:command/done` | event | `15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff` | [`event:command/done`](#persistence-type-eventcommanddone) | +| `event:command/run` | event | `37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006` | [`event:command/run`](#persistence-type-eventcommandrun) | +| `event:compaction/end` | event | `b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d` | [`event:compaction/end`](#persistence-type-eventcompactionend) | +| `event:compaction/prune` | event | `7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04` | [`event:compaction/prune`](#persistence-type-eventcompactionprune) | +| `event:compaction/start` | event | `db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965` | [`event:compaction/start`](#persistence-type-eventcompactionstart) | +| `event:compaction/summary` | event | `f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59` | [`event:compaction/summary`](#persistence-type-eventcompactionsummary) | +| `event:deliverables/presented` | event | `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` | [`event:deliverables/presented`](#persistence-type-eventdeliverablespresented) | +| `event:feedback/message-delete` | event | `3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796` | [`event:feedback/message-delete`](#persistence-type-eventfeedbackmessage-delete) | +| `event:feedback/message-put` | event | `b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf` | [`event:feedback/message-put`](#persistence-type-eventfeedbackmessage-put) | +| `event:feedback/record` | event | `b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8` | [`event:feedback/record`](#persistence-type-eventfeedbackrecord) | +| `event:goal/change` | event | `763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d` | [`event:goal/change`](#persistence-type-eventgoalchange) | +| `event:hook/invoked` | event | `8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0` | [`event:hook/invoked`](#persistence-type-eventhookinvoked) | +| `event:hook/result` | event | `e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4` | [`event:hook/result`](#persistence-type-eventhookresult) | +| `event:image/offload` | event | `b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e` | [`event:image/offload`](#persistence-type-eventimageoffload) | +| `event:llm/retry` | event | `525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336` | [`event:llm/retry`](#persistence-type-eventllmretry) | +| `event:llm/retry-started` | event | `48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3` | [`event:llm/retry-started`](#persistence-type-eventllmretry-started) | +| `event:model/selection` | event | `35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc` | [`event:model/selection`](#persistence-type-eventmodelselection) | +| `event:permission/preset` | event | `5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b` | [`event:permission/preset`](#persistence-type-eventpermissionpreset) | +| `event:plan/mode` | event | `a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f` | [`event:plan/mode`](#persistence-type-eventplanmode) | +| `event:request/context` | event | `37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf` | [`event:request/context`](#persistence-type-eventrequestcontext) | +| `event:request/header` | event | `8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489` | [`event:request/header`](#persistence-type-eventrequestheader) | +| `event:sandbox/mode` | event | `516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415` | [`event:sandbox/mode`](#persistence-type-eventsandboxmode) | +| `event:schedule/change` | event | `2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42` | [`event:schedule/change`](#persistence-type-eventschedulechange) | +| `event:session-log-deepseek/delivery-accepted` | event | `d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9` | [`event:session-log-deepseek/delivery-accepted`](#persistence-type-eventsession-log-deepseekdelivery-accepted) | +| `event:session/end-seed` | event | `5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e` | [`event:session/end-seed`](#persistence-type-eventsessionend-seed) | +| `event:session/title` | event | `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` | [`event:session/title`](#persistence-type-eventsessiontitle) | +| `event:session/title-llm-request` | event | `e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d` | [`event:session/title-llm-request`](#persistence-type-eventsessiontitle-llm-request) | +| `event:step/end` | event | `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` | [`event:step/end`](#persistence-type-eventstepend) | +| `event:step/start` | event | `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | [`event:step/start`](#persistence-type-eventstepstart) | +| `event:subagent/catalog` | event | `ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871` | [`event:subagent/catalog`](#persistence-type-eventsubagentcatalog) | +| `event:subagent/descriptor` | event | `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` | [`event:subagent/descriptor`](#persistence-type-eventsubagentdescriptor) | +| `event:subagent/model-selection-policy` | event | `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` | [`event:subagent/model-selection-policy`](#persistence-type-eventsubagentmodel-selection-policy) | +| `event:system/message` | event | `69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae` | [`event:system/message`](#persistence-type-eventsystemmessage) | +| `event:team/member` | event | `4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc` | [`event:team/member`](#persistence-type-eventteammember) | +| `event:team/message/delivered` | event | `48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb` | [`event:team/message/delivered`](#persistence-type-eventteammessagedelivered) | +| `event:team/message/queued` | event | `443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4` | [`event:team/message/queued`](#persistence-type-eventteammessagequeued) | +| `event:team/task` | event | `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` | [`event:team/task`](#persistence-type-eventteamtask) | +| `event:todo/write` | event | `b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26` | [`event:todo/write`](#persistence-type-eventtodowrite) | +| `event:tool-workflow/agent-end` | event | `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` | [`event:tool-workflow/agent-end`](#persistence-type-eventtool-workflowagent-end) | +| `event:tool-workflow/agent-start` | event | `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` | [`event:tool-workflow/agent-start`](#persistence-type-eventtool-workflowagent-start) | +| `event:tool-workflow/run-end` | event | `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` | [`event:tool-workflow/run-end`](#persistence-type-eventtool-workflowrun-end) | +| `event:tool-workflow/run-start` | event | `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` | [`event:tool-workflow/run-start`](#persistence-type-eventtool-workflowrun-start) | +| `event:tool/call` | event | `3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48` | [`event:tool/call`](#persistence-type-eventtoolcall) | +| `event:tool/ptc-dispatch` | event | `b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c` | [`event:tool/ptc-dispatch`](#persistence-type-eventtoolptc-dispatch) | +| `event:tool/ptc-dispatch-start` | event | `ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93` | [`event:tool/ptc-dispatch-start`](#persistence-type-eventtoolptc-dispatch-start) | +| `event:tool/result` | event | `29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2` | [`event:tool/result`](#persistence-type-eventtoolresult) | +| `event:turn/end` | event | `bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b` | [`event:turn/end`](#persistence-type-eventturnend) | +| `event:turn/start` | event | `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` | [`event:turn/start`](#persistence-type-eventturnstart) | +| `event:user/message` | event | `314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578` | [`event:user/message`](#persistence-type-eventusermessage) | +| `event:web/deepseek-search-llm-request` | event | `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331` | [`event:web/deepseek-search-llm-request`](#persistence-type-eventwebdeepseek-search-llm-request) | + +
+Complete resolved types + +### Resolved persistence types + +Each definition appears once. References preserve sharing and recursion; the digest beside a definition includes its complete reachable structure. Source names and locations identify its declarations but are excluded from its digest. + + + +#### `0` + +SHA-256: `93d38436347f67c9022aacbc4472e283d722bcab8eb73fc376aaf7b6a6b9fb35` + +`0` + + + +#### `1` + +SHA-256: `f88f1b7b6bb733f685f5fb6a8744a5db9199fa53c90463ea1a33bad51153671d` + +`1` + + + +#### `2` + +SHA-256: `a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80` + +`2` + + + +#### `3` + +SHA-256: `137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e` + +`3` + + + +#### `"aborted"` + +SHA-256: `1e0b0b66b6f0c53fc72e52289d06b4708d776f1ca9df4c86a22bff621d403cf0` + +`"aborted"` + + + +#### `"active"` + +SHA-256: `c8e6f48878cc2a2f0dc59682280d81f407943fb503f32c64bf9ff3d9393c3eff` + +`"active"` + + + +#### `"after"` + +SHA-256: `5b232a9b9bfcc0fc6794dab7865bcf203a65785c5de5aa647a51228bff628413` + +`"after"` + + + +#### `"agent-instructions"` + +SHA-256: `fbd2c74b346a1595b376139c587fadd23e4a21acc9c0abce342975b6cfc60986` + +`"agent-instructions"` + + + +#### `"agent-message"` + +SHA-256: `82470020b5bfcb1a843e2aa05602af7d37df99e82d01f015c7c589ba054fd89d` + +`"agent-message"` + + + +#### `"agent-preset/selected"` + +SHA-256: `557e148d30b79ee48645850832b30c717d7c3b64641deb5d6133b8b4e91ee0b8` + +`"agent-preset/selected"` + + + +#### `"agent/inbox/spliced"` + +SHA-256: `829a2fb3be6efd4ba36aef8ed2d381a4c6fb2a0aaf50c823a6f3f8290786b809` + +`"agent/inbox/spliced"` + + + +#### `"allowed-once"` + +SHA-256: `811229eedcec57979dbadca7dbea832a59f8580cff30cb217fca5e2da16314bd` + +`"allowed-once"` + + + +#### `"always"` + +SHA-256: `142c37d302aa22a0a57915b5255939d3ca91c1811ca13fddcf84cf76ea00758a` + +`"always"` + + + +#### `"append"` + +SHA-256: `e438a9d4fb883b3e4a8d9fc8913aa1550ed50eb384bfbf943100a5605b537498` + +`"append"` + + + +#### `"approval/asked"` + +SHA-256: `cd186c309e2bef305705e1d324139240f5e681f4f6a957d6a25b0225f65560df` + +`"approval/asked"` + + + +#### `"approval/decided"` + +SHA-256: `378f90f9f6022a0991928a1eaf7991094ea1920fe89a9248358a1da106e1a970` + +`"approval/decided"` + + + +#### `"approval/policy"` + +SHA-256: `36d6a9a871d949ea4f3edd919d81d66aa69218bebef38899d2a1282c39420a1f` + +`"approval/policy"` + + + +#### `"ask"` + +SHA-256: `9e07693fd7cd9babe0688c22c986e4d519ae1c0e40eeea13b2dc583bed2abc86` + +`"ask"` + + + +#### `"assistant"` + +SHA-256: `95c0e88fcf0bafb2087f912ad9e2369de6ae6530cc0c4c2772c96205b57f7f60` + +`"assistant"` + + + +#### `"assistant/attempt"` + +SHA-256: `e95f957154b2b1b58692af53d4131180b6dd19e2264869f876dbaa959991494e` + +`"assistant/attempt"` + + + +#### `"assistant/message"` + +SHA-256: `6ab45ac76839722df912f3ba50f1c6b41f2d614bde11f1aabfae04117ccdc80d` + +`"assistant/message"` + + + +#### `"at"` + +SHA-256: `17aae616ef020b8b9f011ec398ec935450fb06d3e2a0722c456f63aeaf5ff728` + +`"at"` + + + +#### `"block"` + +SHA-256: `1e346446e183ee76f48d7994c97ecb302bddc682abb60b8a10ea0bb26223a69c` + +`"block"` + + + +#### `"block-end"` + +SHA-256: `eefbea819caeeea91ccb02dfafc16c68dd7f961cf9c1b2be25a2084509cf5c5a` + +`"block-end"` + + + +#### `"block-start"` + +SHA-256: `cbca49bde16b656d5b8fbe4a8a507769f7b594c6287782b809c03814941bc5e3` + +`"block-start"` + + + +#### `"blocked"` + +SHA-256: `254dce209e735f9cb6f6b7aec0354712b1611759ec02af4d35a96f2081e666f6` + +`"blocked"` + + + +#### `boolean` + +SHA-256: `aa93010d0e521ad7c42273f58d5c9b8bf1dfc94edf1b805a3971b364a35c1877` + +`boolean` + + + +#### `"canceled"` + +SHA-256: `d4e4d575abeb4b72d616dc65c17ac0eaa943cc135609395044c38d5afcb10e31` + +`"canceled"` + + + +#### `"cancelled"` + +SHA-256: `2142e391b9ccb60d487afcf373ce74db98d952f69e8289eddb352a7e16e996c5` + +`"cancelled"` + + + +#### `"catalog"` + +SHA-256: `aec150797b655c5f15ebb7a501454b0c208fbaccec9ace49d7de2171fc02f47d` + +`"catalog"` + + + +#### `"change"` + +SHA-256: `f789af5ab844827eb5a4f357c0afae1eeed108c6c22d8ca1a56e586b349a7c85` + +`"change"` + + + +#### `"chunk"` + +SHA-256: `14230f9b8b5797bb7e8c621fa636531cfbde2ffba1ef5f1fd058216ff21952a0` + +`"chunk"` + + + +#### `"claude-code"` + +SHA-256: `aff60ef947c18b012644852bdd0d5bfe72065e061dd563787c76c646b4a10f6b` + +`"claude-code"` + + + +#### `"clear"` + +SHA-256: `e7e154d47d5fbc5366330fb4dade1f108c6dfe4335044d21ded14b7bf1dce084` + +`"clear"` + + + +#### `"codex"` + +SHA-256: `15495614ccfa9cbdeefb0ec2abd76406435f4c6ff3dae42acae8e09ef42025c9` + +`"codex"` + + + +#### `"command/done"` + +SHA-256: `8cdd3fdd295cee53035de16a1b23411716f75e9f994fe9510cac5d7fef605c76` + +`"command/done"` + + + +#### `"command/run"` + +SHA-256: `f1996af2602e6f62b5ab179ca5c4af00d8753938b74cc6ef102de09e99e74a7e` + +`"command/run"` + + + +#### `"compaction/end"` + +SHA-256: `1986c2664009c99155e44795676c887fa67f7c55cd2d5e6b648ff763e0ab033a` + +`"compaction/end"` + + + +#### `"compaction/prune"` + +SHA-256: `10e386801903f9d424602c31d3ff837a94aef623c8b391376d8d9e253525fabe` + +`"compaction/prune"` + + + +#### `"compaction/start"` + +SHA-256: `e2d0367e5716bc188435e51718ebff8ce873190625fa93b1c5331102d98758fa` + +`"compaction/start"` + + + +#### `"compaction/summary"` + +SHA-256: `ef4f00923b9edbae15c7ef05320280bf61147ca17146cf59690359bfd5e5da45` + +`"compaction/summary"` + + + +#### `"complete"` + +SHA-256: `d9196086e41e4dd5c2ce87f5c25529c8112a1731d258cf0728747d41a9ee3241` + +`"complete"` + + + +#### `"completed"` + +SHA-256: `1ebc6f9ff3aa9e3a38f8695f49bacdab1f8b7a3832741853ca46f40af56ccd01` + +`"completed"` + + + +#### `"continuable"` + +SHA-256: `e5d3828df1ec3e2a66879de0659e0f4866d9cfffc00825ee731a66f8a0c03d98` + +`"continuable"` + + + +#### `"create"` + +SHA-256: `7624ca28c61ca0eaa4f015140f3cea6e0c16cce2f2960fab5f531203d253903e` + +`"create"` + + + +#### `"danger-full-access"` + +SHA-256: `18fce9540bb20897a66275499faee6b8296c97e9901fa1ff45a191772448ad1a` + +`"danger-full-access"` + + + +#### `"delegation"` + +SHA-256: `76632533f67879dcb346fcae640540dbc89b2472b0bce88c59f7e48fc5c0e668` + +`"delegation"` + + + +#### `"delete"` + +SHA-256: `d0fbb0ca1bbba059830826f33f801da1aced35a2504376d61e020bdfec8d50c0` + +`"delete"` + + + +#### `"deleted"` + +SHA-256: `e7e8f1318170b8284f16ab45a557afd4675c96071c0f2a456636481dab20b427` + +`"deleted"` + + + +#### `"deliverables/presented"` + +SHA-256: `1a2718b00937b236a0d0910ef5dab2f9f8b65e4bde410cc21f15fbbf29f584d3` + +`"deliverables/presented"` + + + +#### `"dispatch"` + +SHA-256: `26c879bdd130e8b8683a6ce588414fad2244783d6573ca399fa0de184a2b0bb1` + +`"dispatch"` + + + +#### `"disposed"` + +SHA-256: `b38f206d59bad891fa58c89f97a0036987b3defe7685acbd318fa55eb85f9751` + +`"disposed"` + + + +#### `"edit"` + +SHA-256: `ad22a5ca5bbaab2e1440779cd3648e85ddfc6f73b5207394eda699555cf31430` + +`"edit"` + + + +#### `"error"` + +SHA-256: `a2be0f0cb59f0d4a06557d45847d1938aced238baa77a6da416e590b8b958553` + +`"error"` + + + +#### `event:agent-preset/selected` + +SHA-256: `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:agent-preset/selected.data`](#persistence-type-eventagent-presetselecteddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"agent-preset/selected"` | + + + +#### `event:agent-preset/selected.data` + +SHA-256: `6e52dd55a1d48954ed5464ec46fe34d9eb65f709baabc9561e7a279910b0c406` + +Sources: `packages/preset/agent-presets/src/session.ts` + +| Property | Presence | Type | +|---|---|---| +| `agentPreset` | required | `string` | + + + +#### `event:agent/inbox/spliced` + +SHA-256: `646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:agent/inbox/spliced.data`](#persistence-type-eventagentinboxspliceddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"agent/inbox/spliced"` | + + + +#### `event:agent/inbox/spliced.data` + +SHA-256: `a6a195c1b4a906d953d24ab5864c9f1881d545460e080a51144adfc9cb058cfe` + +Sources: `packages/core/agent/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `inserted` | required | [`event:agent/inbox/spliced.data.inserted`](#persistence-type-eventagentinboxspliceddatainserted) | +| `outcome` | optional | `"canceled"` | +| `removedCount` | optional | `number` | +| `start` | required | `number` | +| `target` | required | [`packages/core/agent/src/types.ts#InboxTarget`](#persistence-type-packagescoreagentsrctypestsinboxtarget) | + + + +#### `event:agent/inbox/spliced.data.inserted` + +SHA-256: `300341f890f7b9506a1749fff4fa5239d16ea1c63ff6b15851acb03c20f3b48d` + +Array of [`packages/llm/llm/src/message.ts#UserMessage`](#persistence-type-packagesllmllmsrcmessagetsusermessage). + + + +#### `event:agent/inbox/spliced.data.inserted[0].content` + +SHA-256: `bb72d86bc9ef0b3908bfa57ef98ccccae24d67d945c9f6869ca3cb8577889e75` + +Array of [`packages/llm/llm/src/types.ts#ContentBlock`](#persistence-type-packagesllmllmsrctypestscontentblock). + + + +#### `event:agent/inbox/spliced.data.inserted[0].content[0][2].attachment.originalDimensions` + +SHA-256: `0f46153645c297846a3fad3911636659ca4717a5e7d71c9f50bffacd312115ef` + +Sources: `packages/attachment/attachment/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `height` | required | `number` | +| `width` | required | `number` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[0]` + +SHA-256: `ada310bf0bdb8fed51f3b56ea63f6ea6b18bbd587f04fccb63a14ab0b2a24e05` + +Sources: `packages/core/session/src/types.ts` · `packages/interaction/commands/src/types.ts` · `packages/llm/llm/src/message.ts` · `packages/session/session-title/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"user"` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[1]` + +SHA-256: `0ddab4577db37a3e0d9e3a91761735c8ef6f5629d526ab8ecaeeea19c097c8f8` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[10]` + +SHA-256: `6a4f72e2e179e17b922f2a9392c0e1c8f8c707f32494372454850a3eb184a6e7` + +Sources: `packages/api/session-controller/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `clientTimeZone` | optional | `string` | +| `kind` | required | `"user"` | +| `rpcId` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[15].references` + +SHA-256: `df843efd87c78cf8de98f8e0d0216956cd568d0d0e56a22c853663e274aa1a18` + +Array of [`event:agent/inbox/spliced.data.inserted[0].source[15].references[0]`](#persistence-type-eventagentinboxspliceddatainserted0source15references0). + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[15].references[0]` + +SHA-256: `4f91f187baeabef5c7950c4780d31bbe39f3345dff591a6cf26ac7e135ac1cf4` + +Sources: `packages/context/session-reference/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `capturedFormatVersion` | optional | `number` | +| `capturedThroughSeq` | required | [`event:compaction/end.data.turn`](#persistence-type-eventcompactionenddataturn) | +| `compacted` | required | `boolean` | +| `inputIndex` | required | `number` | +| `label` | required | `string` | +| `omittedBytes` | required | `number` | +| `omittedMessages` | required | `number` | +| `originalMessages` | required | `number` | +| `retainedMessages` | required | `number` | +| `sessionId` | required | `string` | +| `truncated` | required | `boolean` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[16].changes` + +SHA-256: `2ab12a0e345658f9342816d773fe610f049982bcad82631f43b9205abe43e5ee` + +Array of [`packages/context/agent-instructions/src/render.ts#AgentInstructionChange`](#persistence-type-packagescontextagent-instructionssrcrendertsagentinstructionchange). + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[16].changes[0].action` + +SHA-256: `904bf499d98be4a3a5f836fcac533b6c4899569b018071e6604e1d32657d00fd` + +One of: + +- `"remove"` +- `"replace"` +- `"set"` + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[17].entries` + +SHA-256: `aba175fb20ffc71112c55efe70458ff5d7dbfb83501892b4ba8d077f0ea5d7ba` + +Array of [`event:agent/inbox/spliced.data.inserted[0].source[17].entries[0]`](#persistence-type-eventagentinboxspliceddatainserted0source17entries0). + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[17].entries[0]` + +SHA-256: `83079c8a3f733ac3fa603eefa0fbb4737ca4d8b69e7e2e7298b60f9ac4098693` + +Sources: `packages/skill/tool-skill/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `description` | required | `string` | +| `name` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[19]` + +SHA-256: `9edc162949abf93bd5ff049191b345454ba104f583937ce5580fb50f067d2b94` + +Sources: `packages/webhook/webhook/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `deliveryId` | required | `string` | +| `form` | required | `"notice"` | +| `kind` | required | `"webhook"` | +| `provider` | required | `string` | +| `ruleId` | required | `string` | +| `source` | required | `string` | +| `summary` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[2]` + +SHA-256: `dda6e111a8ccfc12f6e742e977a1a4e3549e8c03732a5ff6c8d7c3d4bcb7a412` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"instructions"` | +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[3]` + +SHA-256: `2f90a7b3646fea3e677bd7b4000aa96f3b8964f107b614e204e11ad4051c24fc` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"catalog"` | +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[4]` + +SHA-256: `e8d26e6993445743e6c4342c31b284c7d8f5574369abdd6021183af1a6b3538f` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"snapshot"` | +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | +| `sections` | required | [`event:agent/inbox/spliced.data.inserted[0].source[4].sections`](#persistence-type-eventagentinboxspliceddatainserted0source4sections) | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[4].sections` + +SHA-256: `c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262` + +Array of [`packages/llm/llm/src/message.ts#ContextSnapshotSection`](#persistence-type-packagesllmllmsrcmessagetscontextsnapshotsection). + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[5]` + +SHA-256: `b4d298d90c798fa4d1f5b030ce3ce8031c4c41beafdb05323bec8b2a06903b43` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"notice"` | +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | +| `summary` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[6]` + +SHA-256: `2ce7ef3b3daebf95815c7ae454a751d3e67ca7a22e2e0734fe2942df393bb66c` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"relay"` | +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[7]` + +SHA-256: `85e1bd563d6c80c1f377f99f91103fec4e315148a7330f3b3dae7c2d04e33b01` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"recall"` | +| `kind` | required | `"plugin"` | +| `plugin` | required | `string` | + + + +#### `event:approval/asked` + +SHA-256: `3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:approval/asked.data`](#persistence-type-eventapprovalaskeddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"approval/asked"` | + + + +#### `event:approval/asked.data` + +SHA-256: `45f2a07ea94573123b6ae14db787a40062dec3834f36d8be92c523d40ba28448` + +Sources: `packages/interaction/user-approval/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `callId` | optional | `string` | +| `id` | required | `string` | +| `reason` | optional | `string` | +| `toolName` | required | `string` | + + + +#### `event:approval/decided` + +SHA-256: `bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:approval/decided.data`](#persistence-type-eventapprovaldecideddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"approval/decided"` | + + + +#### `event:approval/decided.data` + +SHA-256: `93cbbc5a7fd0b1aa1ff1b9a6bb5ec52b073f48e5a5200365c45c0cd54059e1b9` + +Sources: `packages/interaction/user-approval/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `id` | required | `string` | +| `outcome` | required | [`packages/interaction/user-approval/src/types.ts#ApprovalOutcome`](#persistence-type-packagesinteractionuser-approvalsrctypestsapprovaloutcome) | + + + +#### `event:approval/policy` + +SHA-256: `26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:approval/policy.data`](#persistence-type-eventapprovalpolicydata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"approval/policy"` | + + + +#### `event:approval/policy.data` + +SHA-256: `11f70b595aa76897fc4e25a352bfa718c659f44b799e5aa14e84e5a38fe72912` + +Sources: `packages/interaction/user-approval/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `policy` | required | [`packages/interaction/user-approval/src/index.ts#ApprovalPolicy`](#persistence-type-packagesinteractionuser-approvalsrcindextsapprovalpolicy) | +| `source` | optional | `"delegation"` | + + + +#### `event:assistant/attempt` + +SHA-256: `c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:assistant/attempt.data`](#persistence-type-eventassistantattemptdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"assistant/attempt"` | + + + +#### `event:assistant/attempt.data` + +SHA-256: `0c6412d3ba5e41adfaa6929c7d4093f2d52d8598c03f35844fc0d55e3070a3b1` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `step` | required | `number` | +| `stream` | required | [`event:assistant/attempt.data.stream`](#persistence-type-eventassistantattemptdatastream) | +| `turn` | required | `number` | + + + +#### `event:assistant/attempt.data.stream` + +SHA-256: `26f3bb7529cfce1e3a0f1ededa365d8b426758ca0feeb0beabeee805f8bb8346` + +Array of [`packages/llm/llm/src/assistant-stream.ts#AssistantStreamRecord`](#persistence-type-packagesllmllmsrcassistant-streamtsassistantstreamrecord). + + + +#### `event:assistant/attempt.data.stream[0][0]` + +SHA-256: `e72269f931559e901e5e8fe1cfcbd0669fb795f43cc038ff39fba62f60403c33` + +Sources: `packages/llm/llm/src/assistant-stream.ts` + +| Property | Presence | Type | +|---|---|---| +| `dt` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `index` | required | `number` | +| `texts` | required | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `time0` | required | `number` | +| `type` | required | `"text-chunks"` | + + + +#### `event:assistant/attempt.data.stream[0][0].texts` + +SHA-256: `93c33d9687613293f8c95d46c4d922fe9ceae83b84c384beff5c3315abe005f2` + +Array of `string`. + + + +#### `event:assistant/attempt.data.stream[0][1]` + +SHA-256: `71bb3254ec8f1e491ce63b762a7b5f18709de23aa4e8abcc8b886f4b6ce051dd` + +Sources: `packages/llm/llm/src/assistant-stream.ts` + +| Property | Presence | Type | +|---|---|---| +| `dt` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `index` | required | `number` | +| `texts` | required | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `time0` | required | `number` | +| `type` | required | `"reasoning-chunks"` | + + + +#### `event:assistant/attempt.data.stream[0][2]` + +SHA-256: `3860b4757d512a2869be833acb0faf834335b1b056bf3f83df5474dce95f8fa6` + +Sources: `packages/llm/llm/src/assistant-stream.ts` + +| Property | Presence | Type | +|---|---|---| +| `args` | required | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `dt` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `id` | required | `string` | +| `index` | required | `number` | +| `name` | optional | `string` | +| `time0` | required | `number` | +| `type` | required | `"tool-call-chunks"` | + + + +#### `event:assistant/attempt.data.stream[0][3]` + +SHA-256: `c93b6f51b399607349b4bcc66b58e848a44250ffc1e2537207bd092dfff94192` + +Sources: `packages/llm/llm/src/assistant-stream.ts` + +| Property | Presence | Type | +|---|---|---| +| `chunk` | required | [`packages/llm/llm/src/types.ts#StreamChunk`](#persistence-type-packagesllmllmsrctypestsstreamchunk) | +| `time` | required | `number` | +| `type` | required | `"chunk"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[0]` + +SHA-256: `647cb2e3aeb58e27d1d4d60011f208bb66dce257e8654193c533b47c4c22c253` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `blockType` | required | [`packages/llm/llm/src/types.ts#ContentBlockType`](#persistence-type-packagesllmllmsrctypestscontentblocktype) | +| `index` | required | `number` | +| `type` | required | `"block-start"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[1]` + +SHA-256: `95080295115fbd83544520ba247b68a03790131f6a2eac323d388758cb542f65` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `index` | required | `number` | +| `text` | required | `string` | +| `type` | required | `"text-delta"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[2]` + +SHA-256: `2abb711460e6238d851c30f3e4bdd87a2aa1887ee70575b3d3b7b25610673095` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `index` | required | `number` | +| `text` | required | `string` | +| `type` | required | `"reasoning-delta"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[3]` + +SHA-256: `88a610b831be6d92612a464be5c7d0b88ec24d97bd299837bf74bf7672183c9a` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `argumentsDelta` | required | `string` | +| `id` | required | `string` | +| `index` | required | `number` | +| `name` | optional | `string` | +| `type` | required | `"tool-call-delta"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[4]` + +SHA-256: `90c811b8c2668898515e69a24e82caffeb08517f9c7aa193867ff0380f3b535d` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `block` | required | [`packages/llm/llm/src/types.ts#ContentBlock`](#persistence-type-packagesllmllmsrctypestscontentblock) | +| `index` | required | `number` | +| `type` | required | `"block-end"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[5]` + +SHA-256: `f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `type` | required | `"usage"` | +| `usage` | required | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6]` + +SHA-256: `a2b49331716ba0a7078b026d145306a70eae64b7313c3e6204bd931e75ec3bb1` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `reason` | required | [`packages/llm/llm/src/types.ts#FinishReason`](#persistence-type-packagesllmllmsrctypestsfinishreason) | +| `replayState` | optional | [`packages/llm/llm/src/types.ts#ReplayEnvelope`](#persistence-type-packagesllmllmsrctypestsreplayenvelope) | +| `type` | required | `"finish"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[0]` + +SHA-256: `8e31bb958e9b015e6f8407eaade32217068159e816f3cc99c3ad76eb889732e0` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `failure` | required | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `kind` | required | `"aborted"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[1]` + +SHA-256: `693f4952fb5565da96c06bace8924b098ac2fbc915fde0ff8019701183abc057` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `failure` | required | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `kind` | required | `"error"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]` + +SHA-256: `ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7` + +Sources: `packages/core/session/src/types.ts` · `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"max-tokens"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[3]` + +SHA-256: `1d76406cbb2ddadb0dbbb51e9d8bc6cf678fed455cf8eb512f36f7c86d37a62f` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"stop"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[4]` + +SHA-256: `287211846beea1eccb5f9acee00d20388a38fcb2e95858fa2332d6f58529379a` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"tool-calls"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].replayState.blocks` + +SHA-256: `b1664fa89f8eab49a14e7e3168d8bc4da4aa9fd76332f6c4a053d839e5276ae7` + +Array of `unknown` (opaque). + + + +#### `event:assistant/message` + +SHA-256: `1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:assistant/message.data`](#persistence-type-eventassistantmessagedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `surfaceOp` | required | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | required | `number` | +| `type` | required | `"assistant/message"` | + + + +#### `event:assistant/message.data` + +SHA-256: `77b8491f946edfc8cc77ebae3ba49183759da31ba2dfa83d4c9e9e618c4b91d2` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `interrupted` | optional | `true` | +| `message` | required | [`packages/llm/llm/src/message.ts#AssistantMessage`](#persistence-type-packagesllmllmsrcmessagetsassistantmessage) | +| `step` | required | `number` | +| `stream` | required | [`event:assistant/attempt.data.stream`](#persistence-type-eventassistantattemptdatastream) | +| `turn` | required | `number` | +| `usage` | optional | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:command/done` + +SHA-256: `15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:command/done.data`](#persistence-type-eventcommanddonedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"command/done"` | + + + +#### `event:command/done.data` + +SHA-256: `5b6fb1f226ff56402db08a6aae82af76100b14056271875f69ec526a1ae05d51` + +Sources: `packages/interaction/commands/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `commandId` | required | `string` | +| `kind` | required | [`event:command/done.data.kind`](#persistence-type-eventcommanddonedatakind) | +| `sourceEventSeq` | optional | `number` | +| `text` | optional | `string` | + + + +#### `event:command/done.data.kind` + +SHA-256: `1ab2ef1296f157ba96998f179bb5daa9d21a82480da2901127aeab2730797c92` + +One of: + +- `"error"` +- `"success"` + + + +#### `event:command/run` + +SHA-256: `37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:command/run.data`](#persistence-type-eventcommandrundata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"command/run"` | + + + +#### `event:command/run.data` + +SHA-256: `a853902cfab417b8f08aa51ad6855fea46f34ed4588a74e47403035111d0fb86` + +Sources: `packages/interaction/commands/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `args` | optional | `string` | +| `commandId` | required | `string` | +| `name` | required | `string` | +| `source` | required | [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) | + + + +#### `event:compaction/end` + +SHA-256: `b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:compaction/end.data`](#persistence-type-eventcompactionenddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"compaction/end"` | + + + +#### `event:compaction/end.data` + +SHA-256: `ca59530d1a4f3e191b4032bc4a20eded0d827db8b5a7efb27b3af9e9b456c6f2` + +Sources: `packages/compaction/compaction/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `compactionId` | required | `string` | +| `error` | optional | `string` | +| `sourceCommandId` | optional | `string` | +| `turn` | required | [`event:compaction/end.data.turn`](#persistence-type-eventcompactionenddataturn) | + + + +#### `event:compaction/end.data.turn` + +SHA-256: `3bd652ebfa8726b3ce3937a4f1bd2759e02f86b3a08a20f9e41a8513656fbc5f` + +Sources: `packages/core/session/src/types.ts` + +One of: + +- `null` +- `number` + + + +#### `event:compaction/prune` + +SHA-256: `7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:compaction/prune.data`](#persistence-type-eventcompactionprunedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"compaction/prune"` | + + + +#### `event:compaction/prune.data` + +SHA-256: `5dd766ccd1702a1142ad8b4bd44f2242f8e8a6752669ad3de0a5d224329b1438` + +Sources: `packages/compaction/compaction/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `shadowedRange` | required | [`event:compaction/prune.data.shadowedRange`](#persistence-type-eventcompactionprunedatashadowedrange) | +| `shadowedSeqs` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `shadowedTokenCount` | required | `number` | + + + +#### `event:compaction/prune.data.shadowedRange` + +SHA-256: `9e41386b3a0c9572b0d63078492ebb3997da7d3a830d44e0259418bd02f4bcb2` + +Sources: `packages/compaction/compaction/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `end` | required | `number` | +| `start` | required | `number` | + + + +#### `event:compaction/start` + +SHA-256: `db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:compaction/start.data`](#persistence-type-eventcompactionstartdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"compaction/start"` | + + + +#### `event:compaction/start.data` + +SHA-256: `3e4e7683b0192c9f0e6a75c59076108f017892cdb302a98032c2632fd79c356f` + +Sources: `packages/compaction/compaction/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `compactionId` | required | `string` | +| `sourceCommandId` | optional | `string` | +| `turn` | required | [`event:compaction/end.data.turn`](#persistence-type-eventcompactionenddataturn) | + + + +#### `event:compaction/summary` + +SHA-256: `f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:compaction/summary.data`](#persistence-type-eventcompactionsummarydata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"compaction/summary"` | + + + +#### `event:compaction/summary.data` + +SHA-256: `feb329074f0206ecc06d8a1aa0a0b3e2f47fd27524ba020fbc849ba63e938896` + +One of: + +- [`event:compaction/summary.data[0]`](#persistence-type-eventcompactionsummarydata0) +- [`event:compaction/summary.data[1]`](#persistence-type-eventcompactionsummarydata1) + + + +#### `event:compaction/summary.data[0]` + +SHA-256: `9ff2ad8dddb836f75e8f6197fff2371323dfc396c3c6fb667e6e0b42fda79a5c` + +| Property | Presence | Type | +|---|---|---| +| `compactionId` | required | `string` | +| `llmStreamCall` | required | `true` | +| `maxTokens` | optional | `number` | +| `model` | required | `string` | +| `provider` | required | `string` | +| `rawOutput` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `shadowedRange` | required | [`event:compaction/prune.data.shadowedRange`](#persistence-type-eventcompactionprunedatashadowedrange) | +| `shadowedSeqs` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `shadowedTokenCount` | required | `number` | +| `sourceCommandId` | optional | `string` | +| `summary` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `usage` | optional | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:compaction/summary.data[1]` + +SHA-256: `3aa261c8516b5c955ed12080e6257a56cbe513f6c9f0ac9274c12e96c196ebca` + +| Property | Presence | Type | +|---|---|---| +| `compactionId` | required | `string` | +| `maxTokens` | optional | `number` | +| `model` | required | `string` | +| `provider` | required | `string` | +| `rawOutput` | optional | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `shadowedRange` | required | [`event:compaction/prune.data.shadowedRange`](#persistence-type-eventcompactionprunedatashadowedrange) | +| `shadowedSeqs` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `shadowedTokenCount` | required | `number` | +| `sourceCommandId` | optional | `string` | +| `summary` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `usage` | optional | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:deliverables/presented` + +SHA-256: `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:deliverables/presented.data`](#persistence-type-eventdeliverablespresenteddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"deliverables/presented"` | + + + +#### `event:deliverables/presented.data` + +SHA-256: `1528539c63db8b23506f0209a99ce77d8ad138adfbfcee3d4769b7382d93756c` + +Sources: `packages/fs/tool-present/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `callId` | required | `string` | +| `files` | required | [`event:deliverables/presented.data.files`](#persistence-type-eventdeliverablespresenteddatafiles) | +| `turn` | required | `number` | + + + +#### `event:deliverables/presented.data.files` + +SHA-256: `1d9cb3caa96100b18b1911fa3ff8c751ef6992971a03c5f4d9aefc1a0004a345` + +Array of [`packages/fs/tool-present/src/types.ts#PresentedFile`](#persistence-type-packagesfstool-presentsrctypestspresentedfile). + + + +#### `event:feedback/message-delete` + +SHA-256: `3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackDelete`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackdelete) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"feedback/message-delete"` | + + + +#### `event:feedback/message-put` + +SHA-256: `b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackPut`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackput) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"feedback/message-put"` | + + + +#### `event:feedback/message-put.data.item.category` + +SHA-256: `3305a4bb6b6c29b482ba91d59c60b47e8f98282d3dacc8c29e4a4c2712209bdd` + +One of: + +- `"instruction-following"` +- `"other"` +- `"product-interaction"` +- `"resource-cost"` +- `"security-privacy-permission"` +- `"service-stability"` +- `"task-result"` + + + +#### `event:feedback/record` + +SHA-256: `b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/feedback/command-feedback/src/types.ts#FeedbackRecord`](#persistence-type-packagesfeedbackcommand-feedbacksrctypestsfeedbackrecord) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"feedback/record"` | + + + +#### `event:goal/change` + +SHA-256: `763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/goal/goal/src/domain.ts#GoalChangeMeta`](#persistence-type-packagesgoalgoalsrcdomaintsgoalchangemeta) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"goal/change"` | + + + +#### `event:goal/change.data[0].operation` + +SHA-256: `62e6a429ff3f390a46ac39fb468692032f42936ca0db19b53454184189401379` + +One of: + +- `"block"` +- `"complete"` +- `"create"` +- `"edit"` +- `"pause"` +- `"resume"` + + + +#### `event:hook/invoked` + +SHA-256: `8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:hook/invoked.data`](#persistence-type-eventhookinvokeddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"hook/invoked"` | + + + +#### `event:hook/invoked.data` + +SHA-256: `119abe2b9c0b2f46ecb31d82b9acba4d4b30e049f655e2475e8b4ae12d5a9e25` + +Sources: `packages/hooks/hook-protocol/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `dialect` | required | [`packages/hooks/hook-protocol/src/types.ts#HookDialect`](#persistence-type-packageshookshook-protocolsrctypestshookdialect) | +| `handlerId` | required | `string` | +| `matcher` | optional | `string` | +| `point` | required | `string` | +| `turn` | required | `number` | + + + +#### `event:hook/result` + +SHA-256: `e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:hook/result.data`](#persistence-type-eventhookresultdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"hook/result"` | + + + +#### `event:hook/result.data` + +SHA-256: `8ad45ad053b4d89f8865c17cc9ff3b8748e86045f3f0fb816269a34af2619141` + +Sources: `packages/hooks/hook-protocol/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `decision` | required | `string` | +| `durationMs` | required | `number` | +| `exitCode` | optional | `number` | +| `handlerId` | required | `string` | +| `point` | required | `string` | +| `stderrSummary` | optional | `string` | +| `turn` | required | `number` | + + + +#### `event:image/offload` + +SHA-256: `b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:image/offload.data`](#persistence-type-eventimageoffloaddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"image/offload"` | + + + +#### `event:image/offload.data` + +SHA-256: `477614bca595a9e7adb5a1870be446b9a8684f3ba8950259d6289f2d3b74f028` + +Sources: `packages/compaction/compaction-image-offload/src/projection.ts` + +| Property | Presence | Type | +|---|---|---| +| `targets` | required | [`event:image/offload.data.targets`](#persistence-type-eventimageoffloaddatatargets) | + + + +#### `event:image/offload.data.targets` + +SHA-256: `9e2c06d8653585b33d72d5c1a80da79c8a24a88c284409bca15cc0f0ead5ebfb` + +Array of [`packages/compaction/compaction-image-offload/src/projection.ts#ImageOffloadTarget`](#persistence-type-packagescompactioncompaction-image-offloadsrcprojectiontsimageoffloadtarget). + + + +#### `event:llm/retry` + +SHA-256: `525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/llm/llm-retry/src/types.ts#LlmRetryEventData`](#persistence-type-packagesllmllm-retrysrctypestsllmretryeventdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"llm/retry"` | + + + +#### `event:llm/retry-started` + +SHA-256: `48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/llm/llm-retry/src/types.ts#LlmRetryStartedEventData`](#persistence-type-packagesllmllm-retrysrctypestsllmretrystartedeventdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"llm/retry-started"` | + + + +#### `event:llm/retry.data[0]` + +SHA-256: `cdee10e87dbed8440d8b6935888624884878efc7af95402e94171b29f173dced` + +Sources: `packages/llm/llm-retry/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `delayMs` | required | `number` | +| `failure` | required | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `maxRetries` | required | `number` | +| `mode` | required | `"normal"` | +| `policyKey` | required | `string` | +| `provider` | required | `string` | +| `retry` | required | `number` | +| `retryId` | required | `string` | +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `event:llm/retry.data[1]` + +SHA-256: `374fdd68aee5ff844e378c0cbdd961d247a0f22e4ade0bb03d800cd2a46a2b8b` + +Sources: `packages/llm/llm-retry/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `delayMs` | required | `number` | +| `failure` | required | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `mode` | required | `"always"` | +| `policyKey` | required | `string` | +| `provider` | required | `string` | +| `retry` | required | `number` | +| `retryId` | required | `string` | +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `event:model/selection` + +SHA-256: `35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/api/session-controller/src/types.ts#ModelSelection`](#persistence-type-packagesapisession-controllersrctypestsmodelselection) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"model/selection"` | + + + +#### `event:permission/preset` + +SHA-256: `5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:permission/preset.data`](#persistence-type-eventpermissionpresetdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"permission/preset"` | + + + +#### `event:permission/preset.data` + +SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` + +Sources: `packages/interaction/permission-presets/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `preset` | required | `string` | + + + +#### `event:plan/mode` + +SHA-256: `a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:plan/mode.data`](#persistence-type-eventplanmodedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"plan/mode"` | + + + +#### `event:plan/mode.data` + +SHA-256: `20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5` + +Sources: `packages/plan/plan-mode/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `active` | required | `boolean` | + + + +#### `event:request/context` + +SHA-256: `37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/core/session/src/types.ts#RequestContext`](#persistence-type-packagescoresessionsrctypestsrequestcontext) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"request/context"` | + + + +#### `event:request/header` + +SHA-256: `8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:request/header.data`](#persistence-type-eventrequestheaderdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"request/header"` | + + + +#### `event:request/header.data` + +SHA-256: `2f0aefb72ab453c4bf21a6687f436775d359dc6f8f10410fd4c0615b20bd9d76` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `header` | required | [`packages/core/session/src/types.ts#EpochHeader`](#persistence-type-packagescoresessionsrctypestsepochheader) | +| `reason` | required | [`packages/core/session/src/types.ts#RequestHeaderReason`](#persistence-type-packagescoresessionsrctypestsrequestheaderreason) | +| `startsSeries` | optional | `true` | + + + +#### `event:request/header.data.header.tools` + +SHA-256: `6d63f25a28b70801937a46b1058be5f52d4efbaf3516141470463ae469b59c23` + +Array of [`packages/llm/llm/src/types.ts#ToolSchema`](#persistence-type-packagesllmllmsrctypeststoolschema). + + + +#### `event:request/header.data.header.tools[0].parameters` + +SHA-256: `0aa62ab51b36c0e64b134bd03ba8725d758744180a1a447da49beaad194f219f` + +| Property | Presence | Type | +|---|---|---| +| [`string`] | index signature | `unknown` (opaque) | + + + +#### `event:sandbox/mode` + +SHA-256: `516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:sandbox/mode.data`](#persistence-type-eventsandboxmodedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"sandbox/mode"` | + + + +#### `event:sandbox/mode.data` + +SHA-256: `9890113e97dd3541787bfe6704f2b223d3a890b5325ca0acae2b0398909b413e` + +Sources: `packages/sandbox/sandbox-policy/src/session-mode.ts` + +| Property | Presence | Type | +|---|---|---| +| `mode` | required | [`packages/sandbox/sandbox/src/index.ts#SandboxMode`](#persistence-type-packagessandboxsandboxsrcindextssandboxmode) | +| `source` | optional | `"delegation"` | + + + +#### `event:schedule/change` + +SHA-256: `2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/schedule/schedule/src/types.ts#ScheduleChange`](#persistence-type-packagesscheduleschedulesrctypestsschedulechange) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"schedule/change"` | + + + +#### `event:session-log-deepseek/delivery-accepted` + +SHA-256: `d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:session-log-deepseek/delivery-accepted.data`](#persistence-type-eventsession-log-deepseekdelivery-accepteddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"session-log-deepseek/delivery-accepted"` | + + + +#### `event:session-log-deepseek/delivery-accepted.data` + +SHA-256: `8bb8c3751a6ce64b61aba1ec7ae798c00a5803c4d868a0430873216c6569ed52` + +Sources: `packages/session/session-log-deepseek/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `sessionFormatVersion` | optional | `number` | +| `sessionId` | required | `string` | +| `throughSeq` | required | `number` | + + + +#### `event:session/end-seed` + +SHA-256: `5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:session/end-seed.data`](#persistence-type-eventsessionend-seeddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"session/end-seed"` | + + + +#### `event:session/end-seed.data` + +SHA-256: `17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `inherited` | optional | `true` | + + + +#### `event:session/title` + +SHA-256: `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/session/session-title/src/types.ts#SessionTitleEventData`](#persistence-type-packagessessionsession-titlesrctypestssessiontitleeventdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"session/title"` | + + + +#### `event:session/title-llm-request` + +SHA-256: `e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData`](#persistence-type-packagessessionsession-title-llmsrcindextssessiontitlellmrequesteventdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"session/title-llm-request"` | + + + +#### `event:session/title-llm-request.data.messages` + +SHA-256: `478738df7e7d2b103b09fb937817a9302c81076809f2b341169e00a9419c5665` + +Array of [`packages/llm/llm/src/message.ts#Message`](#persistence-type-packagesllmllmsrcmessagetsmessage). + + + +#### `event:session/title-llm-request.data.messages[0].role` + +SHA-256: `acd36e1717d2b4ef9e98a8e6fac17ca1203f3f448e5bca51677f129a8f4999e2` + +One of: + +- `"assistant"` +- `"system"` +- `"user"` + + + +#### `event:session/title.data.source[0]` + +SHA-256: `1b5649238876e28811e80f10ec67a00c197ad3babd4ecc61a22b09064b88c597` + +Sources: `packages/session/session-title/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"fallback"` | + + + +#### `event:session/title.data.source[1]` + +SHA-256: `b81e9de81a481b24e1e1f9adf038bfc59e57b4f35ce62f8f1e45284186f4f812` + +Sources: `packages/session/session-title/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"provider"` | +| `model` | optional | [`packages/session/session-title/src/types.ts#SessionTitleModelIdentity`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlemodelidentity) | +| `provider` | required | `string` | + + + +#### `event:step/end` + +SHA-256: `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:step/end.data`](#persistence-type-eventstependdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"step/end"` | + + + +#### `event:step/end.data` + +SHA-256: `ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `event:step/start` + +SHA-256: `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:step/end.data`](#persistence-type-eventstependdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"step/start"` | + + + +#### `event:subagent/catalog` + +SHA-256: `ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent`](#persistence-type-packagessubagentsubagentsrccatalogtssubagentcatalogevent) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"subagent/catalog"` | + + + +#### `event:subagent/catalog.data[0]` + +SHA-256: `5d542ac7bdf13310c46e1a884dec9fb18ad8c6e153cff207e639cd7bf9d7e694` + +| Property | Presence | Type | +|---|---|---| +| `childCreatedAt` | required | `number` | +| `childId` | required | `string` | +| `label` | optional | `string` | +| `mode` | required | `"one-shot"` | +| `version` | required | `0` | + + + +#### `event:subagent/catalog.data[1]` + +SHA-256: `0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd` + +| Property | Presence | Type | +|---|---|---| +| `childCreatedAt` | required | `number` | +| `childId` | required | `string` | +| `label` | required | `string` | +| `mode` | required | `"continuable"` | +| `version` | required | `0` | + + + +#### `event:subagent/descriptor` + +SHA-256: `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/subagent/subagent/src/descriptor.ts#SubagentDescriptorData`](#persistence-type-packagessubagentsubagentsrcdescriptortssubagentdescriptordata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"subagent/descriptor"` | + + + +#### `event:subagent/model-selection-policy` + +SHA-256: `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:subagent/model-selection-policy.data`](#persistence-type-eventsubagentmodel-selection-policydata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"subagent/model-selection-policy"` | + + + +#### `event:subagent/model-selection-policy.data` + +SHA-256: `0d47a8f3d847243c4488e755ad4cab7a04ac5d4621b9c81865524cf3f4d8536f` + +Sources: `packages/subagent/tool-subagent/src/model-selection-state.ts` + +| Property | Presence | Type | +|---|---|---| +| `allowedModels` | required | [`event:subagent/model-selection-policy.data.allowedModels`](#persistence-type-eventsubagentmodel-selection-policydataallowedmodels) | + + + +#### `event:subagent/model-selection-policy.data.allowedModels` + +SHA-256: `ba77b58995e36f14bb13886b0493d0a1a63d5db10b1a6cd9f6ac65a72cf832ec` + +Array of [`packages/session/session-title/src/types.ts#SessionTitleModelIdentity`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlemodelidentity). + + + +#### `event:system/message` + +SHA-256: `69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:system/message.data`](#persistence-type-eventsystemmessagedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `sourceEventSeqs` | optional | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | required | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | required | `number` | +| `type` | required | `"system/message"` | + + + +#### `event:system/message.data` + +SHA-256: `2074f40221b76c75fd314246db558965dc3477dfb440bcc952b1eedc9778e366` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `message` | required | [`packages/llm/llm/src/message.ts#SystemMessage`](#persistence-type-packagesllmllmsrcmessagetssystemmessage) | +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `event:system/message.data.message.source` + +SHA-256: `23cf7e0cf3fec1283b60fa15713506169bc9c079a08e124d1cb9733baca80b40` + +One of: + +- [`event:agent/inbox/spliced.data.inserted[0].source[4]`](#persistence-type-eventagentinboxspliceddatainserted0source4) +- [`event:agent/inbox/spliced.data.inserted[0].source[5]`](#persistence-type-eventagentinboxspliceddatainserted0source5) +- [`event:agent/inbox/spliced.data.inserted[0].source[3]`](#persistence-type-eventagentinboxspliceddatainserted0source3) +- [`event:agent/inbox/spliced.data.inserted[0].source[2]`](#persistence-type-eventagentinboxspliceddatainserted0source2) +- [`event:agent/inbox/spliced.data.inserted[0].source[7]`](#persistence-type-eventagentinboxspliceddatainserted0source7) +- [`event:agent/inbox/spliced.data.inserted[0].source[6]`](#persistence-type-eventagentinboxspliceddatainserted0source6) +- [`event:agent/inbox/spliced.data.inserted[0].source[1]`](#persistence-type-eventagentinboxspliceddatainserted0source1) + + + +#### `event:team/member` + +SHA-256: `4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:team/member.data`](#persistence-type-eventteammemberdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"team/member"` | + + + +#### `event:team/member.data` + +SHA-256: `b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `member` | required | [`packages/experimental/agent-team/src/types.ts#TeamMemberSnapshot`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammembersnapshot) | +| `teamId` | required | `string` | +| `version` | required | `2` | + + + +#### `event:team/member.data.member.context` + +SHA-256: `50cf02d875f8a1f1411f4a6fbcffab9120ccef5f74a47331fbf29480e5f68f48` + +One of: + +- `"fork"` +- `"fresh"` + + + +#### `event:team/message/delivered` + +SHA-256: `48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:team/message/delivered.data`](#persistence-type-eventteammessagedelivereddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"team/message/delivered"` | + + + +#### `event:team/message/delivered.data` + +SHA-256: `0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `messageId` | required | `string` | +| `targetId` | required | `string` | +| `teamId` | required | `string` | +| `version` | required | `2` | + + + +#### `event:team/message/queued` + +SHA-256: `443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:team/message/queued.data`](#persistence-type-eventteammessagequeueddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"team/message/queued"` | + + + +#### `event:team/message/queued.data` + +SHA-256: `0c3f4d2248d9bc9700e2d7253fa71aa9935f5c39af6f11de5727f08cccaf8383` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `message` | required | [`packages/experimental/agent-team/src/types.ts#TeamMessageSnapshot`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammessagesnapshot) | +| `teamId` | required | `string` | +| `version` | required | `2` | + + + +#### `event:team/task` + +SHA-256: `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:team/task.data`](#persistence-type-eventteamtaskdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"team/task"` | + + + +#### `event:team/task.data` + +SHA-256: `a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `task` | required | [`packages/experimental/agent-team/src/types.ts#TeamTaskSnapshot`](#persistence-type-packagesexperimentalagent-teamsrctypeststeamtasksnapshot) | +| `teamId` | required | `string` | +| `version` | required | `2` | + + + +#### `event:todo/write` + +SHA-256: `b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:todo/write.data`](#persistence-type-eventtodowritedata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"todo/write"` | + + + +#### `event:todo/write.data` + +SHA-256: `79ddc907312f97cf9553d4841e8b3fc937097bd8d97900a790efad3c05255e99` + +Sources: `packages/todo/tool-todo/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `todos` | required | [`event:todo/write.data.todos`](#persistence-type-eventtodowritedatatodos) | + + + +#### `event:todo/write.data.todos` + +SHA-256: `4b7ddaf3710b88ff9b8df66304f5f97bf03688fd19730eedc2e9535203c820ea` + +Array of [`packages/todo/tool-todo/src/types.ts#TodoItem`](#persistence-type-packagestodotool-todosrctypeststodoitem). + + + +#### `event:todo/write.data.todos[0].status` + +SHA-256: `fd0d91a1f9dd2efb8959bdf5e07f8f0a98b1cdfa38ce8d4732ebde0b44c3abd4` + +One of: + +- `"completed"` +- `"in_progress"` +- `"pending"` + + + +#### `event:tool-workflow/agent-end` + +SHA-256: `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowagentenddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool-workflow/agent-end"` | + + + +#### `event:tool-workflow/agent-start` + +SHA-256: `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowagentstartdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool-workflow/agent-start"` | + + + +#### `event:tool-workflow/run-end` + +SHA-256: `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunEndData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowrunenddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool-workflow/run-end"` | + + + +#### `event:tool-workflow/run-start` + +SHA-256: `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowrunstartdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool-workflow/run-start"` | + + + +#### `event:tool/call` + +SHA-256: `3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:tool/call.data`](#persistence-type-eventtoolcalldata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool/call"` | + + + +#### `event:tool/call.data` + +SHA-256: `e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `arguments` | required | `string` | +| `callId` | required | `string` | +| `name` | required | `string` | +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `event:tool/ptc-dispatch` + +SHA-256: `b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/core/tools/src/types.ts#PtcDispatchEventData`](#persistence-type-packagescoretoolssrctypestsptcdispatcheventdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool/ptc-dispatch"` | + + + +#### `event:tool/ptc-dispatch-start` + +SHA-256: `ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/core/tools/src/types.ts#PtcDispatchStartEventData`](#persistence-type-packagescoretoolssrctypestsptcdispatchstarteventdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"tool/ptc-dispatch-start"` | + + + +#### `event:tool/ptc-dispatch.data.error` + +SHA-256: `a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735` + +Sources: `packages/core/session/src/types.ts` · `packages/core/tools/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `code` | required | `string` | +| `name` | required | `string` | +| `reason` | optional | `string` | + + + +#### `event:tool/result` + +SHA-256: `29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:tool/result.data`](#persistence-type-eventtoolresultdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `sourceEventSeqs` | optional | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | required | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | required | `number` | +| `type` | required | `"tool/result"` | + + + +#### `event:tool/result.data` + +SHA-256: `356aad27134a0e31af67c994ff8b9e4b91acfb6c4917b3bc1f7a62bbf82794d5` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `error` | optional | [`event:tool/ptc-dispatch.data.error`](#persistence-type-eventtoolptc-dispatchdataerror) | +| `message` | required | [`packages/llm/llm/src/message.ts#ToolResultMessage`](#persistence-type-packagesllmllmsrcmessagetstoolresultmessage) | +| `meta` | optional | [`event:tool/result.data.meta`](#persistence-type-eventtoolresultdatameta) | +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `event:tool/result.data.message.content` + +SHA-256: `8d6a011f3ef7096a4a922ef420458419ff6b20e1eaeece5d331db7585d2f08d6` + +| Position | Presence | Type | +|---|---|---| +| 0 | required | [`packages/llm/llm/src/types.ts#ToolResultBlock`](#persistence-type-packagesllmllmsrctypeststoolresultblock) | + + + +#### `event:tool/result.data.meta` + +SHA-256: `c592ce75aab73fcab19c1d7845684c72cf402b78d2e1f2833a58ecf9f3598ed6` + +Sources: `packages/util/values/src/index.ts` + +One of: + +- [`event:tool/result.data.meta[5]`](#persistence-type-eventtoolresultdatameta5) +- [`event:tool/result.data.meta[5][0][6]`](#persistence-type-eventtoolresultdatameta506) +- `string` +- `boolean` +- `null` +- `number` + + + +#### `event:tool/result.data.meta[5]` + +SHA-256: `72ec79127a9c0d0241b1106a74cc2b24c81ce467170f1c3c93f7b71a9496d227` + +Array of [`event:tool/result.data.meta`](#persistence-type-eventtoolresultdatameta). + + + +#### `event:tool/result.data.meta[5][0][6]` + +SHA-256: `529e0ccd0e34079ab4ff21ed87f810cee0388246263bf22e8aba5986b56fae05` + +Sources: `packages/util/values/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| [`string`] | index signature | [`event:tool/result.data.meta`](#persistence-type-eventtoolresultdatameta) | + + + +#### `event:turn/end` + +SHA-256: `bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:turn/end.data`](#persistence-type-eventturnenddata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"turn/end"` | + + + +#### `event:turn/end.data` + +SHA-256: `d3e447062a2847dad847dad5168a9508d92c484363dfc76fd82605aa7bd46285` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `reason` | required | [`packages/core/session/src/types.ts#TurnEndReason`](#persistence-type-packagescoresessionsrctypeststurnendreason) | +| `turn` | required | `number` | + + + +#### `event:turn/end.data.reason[0]` + +SHA-256: `b6ef9c6210be8350cd465f485cf520031fffa6bf3809c61a1e713e834c5982d0` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"completed"` | + + + +#### `event:turn/end.data.reason[1]` + +SHA-256: `0a30c3be336cdd4f8f34e66543a3d46d611c43986edd9b3ce6cbb9b721d3b5d3` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"aborted"` | +| `reason` | required | [`packages/core/session/src/types.ts#TurnEndCancelCause`](#persistence-type-packagescoresessionsrctypeststurnendcancelcause) | + + + +#### `event:turn/end.data.reason[1].reason[1]` + +SHA-256: `6c03546143cdf6ae88f1745ac98c5139efa1588d1415249bbc5f3104d32ab800` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"parent"` | + + + +#### `event:turn/end.data.reason[1].reason[2]` + +SHA-256: `6c5a37d42ebdb12db4410699259335f1e149e3a0260425684c00b153afc8990d` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"hook"` | +| `reason` | required | `string` | + + + +#### `event:turn/end.data.reason[1].reason[3]` + +SHA-256: `4bb451330ff699f36b45539ceb0eb2606ead72084e2c5bb637c36cc80e2252db` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"disposed"` | + + + +#### `event:turn/end.data.reason[1].reason[4]` + +SHA-256: `eaa71be0fbf0f702df8ea6c11d0aa2f9782263d45a10d0fb14eda662f4bfe04c` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"legacy"` | + + + +#### `event:turn/end.data.reason[2]` + +SHA-256: `023a355b2be0d688fb6e4df8388dadb942761d46cfe96d0f499aae9631a159d4` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"blocked"` | + + + +#### `event:turn/end.data.reason[3]` + +SHA-256: `79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `error` | required | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `kind` | required | `"error"` | + + + +#### `event:turn/end.data.reason[5]` + +SHA-256: `56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"interrupted"` | + + + +#### `event:turn/start` + +SHA-256: `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`event:turn/start.data`](#persistence-type-eventturnstartdata) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"turn/start"` | + + + +#### `event:turn/start.data` + +SHA-256: `f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `turn` | required | `number` | + + + +#### `event:user/message` + +SHA-256: `314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/llm/llm/src/message.ts#UserMessage`](#persistence-type-packagesllmllmsrcmessagetsusermessage) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `sourceEventSeqs` | optional | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | required | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | required | `number` | +| `type` | required | `"user/message"` | + + + +#### `event:web/deepseek-search-llm-request` + +SHA-256: `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331` + +| Property | Presence | Type | +|---|---|---| +| `data` | required | [`packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest`](#persistence-type-packageswebweb-search-deepseeksrcprovidertsdeepseeksearchllmrequest) | +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `"web/deepseek-search-llm-request"` | + + + +#### `event:web/deepseek-search-llm-request.data.body` + +SHA-256: `930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731` + +Sources: `packages/web/web-search-deepseek/src/provider.ts` + +| Property | Presence | Type | +|---|---|---| +| `max_tokens` | required | `number` | +| `messages` | required | [`event:web/deepseek-search-llm-request.data.body.messages`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages) | +| `model` | required | `string` | +| `tools` | required | [`event:web/deepseek-search-llm-request.data.body.tools`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodytools) | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages` + +SHA-256: `b993441f8ce7d27b80e619e113e232ae8e62d3d5a8340f6bfe12d8c4c018e62f` + +| Position | Presence | Type | +|---|---|---| +| 0 | required | [`event:web/deepseek-search-llm-request.data.body.messages[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0) | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages[0]` + +SHA-256: `9a2a9029f8d7ede05336980d8342737557f487b913bfd28853d0ab5214600ab5` + +Sources: `packages/web/web-search-deepseek/src/provider.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:web/deepseek-search-llm-request.data.body.messages[0].content`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0content) | +| `role` | required | `"user"` | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages[0].content` + +SHA-256: `8f6d609794bf5afc01d7ccf3e03811d32f4b8047f58a2c9a98db0154c2ad7cb9` + +| Position | Presence | Type | +|---|---|---| +| 0 | required | [`event:web/deepseek-search-llm-request.data.body.messages[0].content[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0content0) | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages[0].content[0]` + +SHA-256: `4e887768586528565381dadbddee6cef555874148089f4579e0b4b1ad096fc9c` + +Sources: `packages/llm/llm/src/types.ts` · `packages/web/web-search-deepseek/src/provider.ts` + +| Property | Presence | Type | +|---|---|---| +| `text` | required | `string` | +| `type` | required | `"text"` | + + + +#### `event:web/deepseek-search-llm-request.data.body.tools` + +SHA-256: `4aed17ec726b5397c29f6cb4bcd7905dc1a12bb6140f1657f073cd24380f2af8` + +| Position | Presence | Type | +|---|---|---| +| 0 | required | [`event:web/deepseek-search-llm-request.data.body.tools[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodytools0) | + + + +#### `event:web/deepseek-search-llm-request.data.body.tools[0]` + +SHA-256: `2d11ca7b0d4493e244b74eba093227866b33249841e59a1e9bf56afed38604c3` + +Sources: `packages/web/web-search-deepseek/src/provider.ts` + +| Property | Presence | Type | +|---|---|---| +| `max_uses` | required | `number` | +| `name` | required | `"web_search"` | +| `type` | required | `"web_search_20250305"` | + + + +#### `"every"` + +SHA-256: `e42b0f40b5d0b628c6e1c44a8fb9eda0780037a81959e1b93d2dfb47b46b0e87` + +`"every"` + + + +#### `"failed"` + +SHA-256: `b57a2889408de36e4516807194c73bdecd51a92f633ccd05db81bf049200f420` + +`"failed"` + + + +#### `"fallback"` + +SHA-256: `d6e654b88b584fcdf290a56802b1730bc7b9847ae86baa4265ab7769eb48990c` + +`"fallback"` + + + +#### `"feedback/message-delete"` + +SHA-256: `44818000e56acb97afdb5045ce235eb55e3fb1ccabc9fc7d0750bb38f36a7f8e` + +`"feedback/message-delete"` + + + +#### `"feedback/message-put"` + +SHA-256: `6cda0d6d3b4336d83998fe580628426df81c2afbab5d768b8813b56d569120e8` + +`"feedback/message-put"` + + + +#### `"feedback/record"` + +SHA-256: `c99e20441bf15341e9db54385e558e5c03d21dff2eb1ac08ccbf47c2d8747954` + +`"feedback/record"` + + + +#### `"file"` + +SHA-256: `277b61f9c6f8170425fa6ffe06cfa14376757a896a4749cb82a687d7364c4fc9` + +`"file"` + + + +#### `"finish"` + +SHA-256: `bd499eac047efe091a4df7382eadd06d25cf0cb31fee3981e8b24d85762841cd` + +`"finish"` + + + +#### `"fork"` + +SHA-256: `2da725e554cd89301d829ed9dc45a572c3cd1b93b5e91d0d71f007976d8a0863` + +`"fork"` + + + +#### `"fresh"` + +SHA-256: `dd2780e7e07684332f7a9ab047237798d260e7eaffb1321cb38eca695d184c3d` + +`"fresh"` + + + +#### `"goal"` + +SHA-256: `b815d7b91cdd9fc6ccc7dcba05cfc5ce1d55fab5fc0c0801803cd3630cedb602` + +`"goal"` + + + +#### `"goal/change"` + +SHA-256: `237c004c73b6b288246816e0d7fde16e09c63a47aa3b1227383d7afe58666163` + +`"goal/change"` + + + +#### `"hook"` + +SHA-256: `dbdafceb9a900183cccc80596498d386f3bf7bddead2b8cfde68453aa4739edc` + +`"hook"` + + + +#### `"hook/invoked"` + +SHA-256: `b9305f0ea75ccd6a6061c27fde19f2ab85534f9f3c1a717b573b077ebae0f611` + +`"hook/invoked"` + + + +#### `"hook/result"` + +SHA-256: `a3a259a1aa5401af786ce08c4a8419681d3000d73467991b5fc563389bc4ebd2` + +`"hook/result"` + + + +#### `"image"` + +SHA-256: `fb8b6a2e53cb9cf44c551176de0fb77d1ddc60037b99a891ff8a860b6d5c29a0` + +`"image"` + + + +#### `"image/gif"` + +SHA-256: `de30b1fa12c75f81df6aa4096e1595296d2d04e2be14a7c29849cf8028b79048` + +`"image/gif"` + + + +#### `"image/jpeg"` + +SHA-256: `3f74ba74acd10644c1ed6947a411d8088bd2cfac74f61bb8540f96d68e31f004` + +`"image/jpeg"` + + + +#### `"image/offload"` + +SHA-256: `9acbe713f3f641921dd3333b240aa72e176d795327c24e8d9db9b68b16771b49` + +`"image/offload"` + + + +#### `"image/png"` + +SHA-256: `58f94390b982f8a5ac1f4f235ba612557f4a1dc4a995d8b1cec63ce7639decb0` + +`"image/png"` + + + +#### `"image/webp"` + +SHA-256: `ebb768d85ec87fb68e42fc14fd7d8535b5ac11791b14d04c6770180f0a719bf8` + +`"image/webp"` + + + +#### `"in-history"` + +SHA-256: `f311671e07bc7fa645a0b6597de9966b97147956565296ba76a36543801b66c5` + +Sources: `packages/llm/llm/src/types.ts` + +`"in-history"` + + + +#### `"in_progress"` + +SHA-256: `94c56aeb1564ad735eb773d88636b40761d063efa1610f1308004d32923f5378` + +`"in_progress"` + + + +#### `"initial"` + +SHA-256: `e7ce49f12953583fad217bf80fb9f1463acff2c3e9471a823782661675fb124c` + +`"initial"` + + + +#### `"instruction-following"` + +SHA-256: `e4cac694f8b6e1d52e48c699464f1c4c26111ef87e558f7931040d00fdc8d486` + +`"instruction-following"` + + + +#### `"instructions"` + +SHA-256: `fee1caf8ab6a65c1bc981f5a1730164490f22a2a89ffa3d0b76f1f432c44c8b5` + +`"instructions"` + + + +#### `"interrupted"` + +SHA-256: `69d238a6e9b08d67f601b1825962963d8d3523cb69ebf6208c697dc5d058c199` + +`"interrupted"` + + + +#### `"legacy"` + +SHA-256: `ad3b56aa2fc1ad4250e7399295d34a8eae592e1907e85852e2291b2e498a30bc` + +`"legacy"` + + + +#### `"llm/retry"` + +SHA-256: `611cae9a3539733aa0c42f66035a7d90f19dcbbdfb5d9e3b628b13705253942d` + +`"llm/retry"` + + + +#### `"llm/retry-started"` + +SHA-256: `4ae007ed190a72c92138b22d059b83208079c7551ca13fb59ae8cf5e23693964` + +`"llm/retry-started"` + + + +#### `"max-tokens"` + +SHA-256: `68141cbe3994a5ffcd064c07c75996538437fd9dbf77ce8a2927e89ec577fabe` + +`"max-tokens"` + + + +#### `"model"` + +SHA-256: `2765e9119edf5816ac1ab4c95c5ee32c90403f3742962eff11544f7752d59d2e` + +`"model"` + + + +#### `"model/selection"` + +SHA-256: `1d5f04a03ea75fc8eeece544129eba0f49f0c82046e9c404461920390135c7b2` + +`"model/selection"` + + + +#### `"negative"` + +SHA-256: `b1f62380f6746fedd629e71065e3583cef83334875b499ac9665c2eb87acfbf5` + +`"negative"` + + + +#### `"never"` + +SHA-256: `1571525adc95a24e5d25b5a6440df401cd7cdd881b745178e85f5a333435cd1b` + +`"never"` + + + +#### `"next-step"` + +SHA-256: `3e2ece4967cfebe95f450a93f45523dff99d6749f6269f2f60f84dfecfcf3693` + +`"next-step"` + + + +#### `"next-turn"` + +SHA-256: `62ecb62dc0fe1b5e70217f8a80c39256a40ee3a1917be14e5ca899d20c35f7fd` + +`"next-turn"` + + + +#### `"normal"` + +SHA-256: `3bc287e765d58dc3a22672a0495a6cfd561220dd38fbaecef80aa95b96caed79` + +`"normal"` + + + +#### `"notice"` + +SHA-256: `e8de0f457fed5b9ff94dc4950b59ef75fd8ba8af665cc7899485924a62653367` + +`"notice"` + + + +#### `null` + +SHA-256: `938f7c7357bc403ea3b281a9dd016939df7a0880fc8db12612585be574d0d615` + +`null` + + + +#### `number` + +SHA-256: `0657d3ca5ac4e7bf79b00bcf860b1c7159d01a9da137497221ec2f1776e365f7` + +Sources: `packages/core/session/src/types.ts` + +`number` + + + +#### `"one-shot"` + +SHA-256: `d28765f87d6b6ab408e0b2f3e7e297791b004b806d8e302c49903ebae815feb2` + +`"one-shot"` + + + +#### `"other"` + +SHA-256: `9d80129e13edfb6feb03ed327e6085c6ef60b97ad074244b2f5fd4667424a6a4` + +`"other"` + + + +#### `packages/api/session-controller/src/types.ts#ModelSelection` + +SHA-256: `f09e5e7acf5ff5ccd193ff2eeec015fa2ff7c29d98bc465f8c3302058d47e29b` + +Sources: `packages/api/session-controller/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `model` | required | `string` | +| `provider` | required | `string` | +| `reasoningEffort` | optional | `string` | + + + +#### `packages/attachment/attachment/src/types.ts#FileAttachmentRef` + +SHA-256: `f19bee84bf3d20904553cdcd57465232bc1c2a194f54c4d195292ba0487223a6` + +Sources: `packages/attachment/attachment/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `attachmentId` | required | `string` | +| `bytes` | required | `number` | +| `name` | required | `string` | + + + +#### `packages/attachment/attachment/src/types.ts#ImageAttachmentRef` + +SHA-256: `b0b0eb1b16490f6bee135b2377e8f8c39227974c799ad7d49ff418af23ecbc35` + +Sources: `packages/attachment/attachment/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `attachmentId` | required | `string` | +| `bytes` | required | `number` | +| `height` | required | `number` | +| `mediaType` | required | [`packages/attachment/attachment/src/types.ts#ImageMediaType`](#persistence-type-packagesattachmentattachmentsrctypestsimagemediatype) | +| `name` | optional | `string` | +| `originalDimensions` | optional | [`event:agent/inbox/spliced.data.inserted[0].content[0][2].attachment.originalDimensions`](#persistence-type-eventagentinboxspliceddatainserted0content02attachmentoriginaldimensions) | +| `width` | required | `number` | + + + +#### `packages/attachment/attachment/src/types.ts#ImageMediaType` + +SHA-256: `2f1e6a7ebace43d727ae138ddcd352eb3813960009e5805b8c5ac84300c97716` + +Sources: `packages/attachment/attachment/src/types.ts` + +One of: + +- `"image/gif"` +- `"image/jpeg"` +- `"image/png"` +- `"image/webp"` + + + +#### `packages/compaction/compaction-image-offload/src/projection.ts#ImageOffloadTarget` + +SHA-256: `1cde1bedde79c5e8a56aee9c05c8e0a579cf5bc611deb85b93fa331a16ca978f` + +Sources: `packages/compaction/compaction-image-offload/src/projection.ts` + +| Property | Presence | Type | +|---|---|---| +| `imageIndexes` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `seq` | required | `number` | + + + +#### `packages/context/agent-instructions/src/render.ts#AgentInstructionChange` + +SHA-256: `83da72c6857601c75da11212ef847f57d457b9c99f0a82246dcdff3e26700239` + +Sources: `packages/context/agent-instructions/src/render.ts` + +| Property | Presence | Type | +|---|---|---| +| `action` | required | [`event:agent/inbox/spliced.data.inserted[0].source[16].changes[0].action`](#persistence-type-eventagentinboxspliceddatainserted0source16changes0action) | +| `digest` | optional | `string` | +| `path` | required | `string` | +| `scope` | required | `string` | + + + +#### `packages/context/agent-instructions/src/state.ts#AgentInstructionSource` + +SHA-256: `6f22a9d02b9a1f1157f3b0e7bdccd7e7b12b085c4efdb709dfc74a465cd4e590` + +Sources: `packages/context/agent-instructions/src/state.ts` + +| Property | Presence | Type | +|---|---|---| +| `baseline` | optional | `true` | +| `baselineIdentity` | optional | `string` | +| `changes` | required | [`event:agent/inbox/spliced.data.inserted[0].source[16].changes`](#persistence-type-eventagentinboxspliceddatainserted0source16changes) | +| `form` | required | `"instructions"` | +| `kind` | required | `"agent-instructions"` | + + + +#### `packages/context/session-reference/src/types.ts#SessionReferenceSource` + +SHA-256: `f56c5b59ca0161310c338d31dd16cf14287ccd602ff4181058df178c1c286d7f` + +Sources: `packages/context/session-reference/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"recall"` | +| `kind` | required | `"session-reference"` | +| `references` | required | [`event:agent/inbox/spliced.data.inserted[0].source[15].references`](#persistence-type-eventagentinboxspliceddatainserted0source15references) | +| `version` | required | `1` | + + + +#### `packages/core/agent/src/types.ts#InboxTarget` + +SHA-256: `96f4a9c81fc0f940ef71528a8cc66731ae4cf1f40d79680c5fe3c39f96d7723c` + +Sources: `packages/core/agent/src/types.ts` + +One of: + +- `"next-step"` +- `"next-turn"` + + + +#### `packages/core/session/src/types.ts#EpochHeader` + +SHA-256: `c55a891c7aac496de6ee64c91c1fb65728c977314013033e42c863428aada854` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `adapterDefaults` | optional | [`packages/llm/llm/src/call-config.ts#LlmCallConfigAdapterDefaults`](#persistence-type-packagesllmllmsrccall-configtsllmcallconfigadapterdefaults) | +| `config` | required | [`packages/llm/llm/src/call-config.ts#LlmCallConfig`](#persistence-type-packagesllmllmsrccall-configtsllmcallconfig) | +| `tools` | optional | [`event:request/header.data.header.tools`](#persistence-type-eventrequestheaderdataheadertools) | + + + +#### `packages/core/session/src/types.ts#RequestContext` + +SHA-256: `b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `contextWindow` | optional | `number` | +| `model` | required | `string` | +| `provider` | required | `string` | +| `systemPromptUpdate` | optional | `"in-history"` | + + + +#### `packages/core/session/src/types.ts#RequestHeaderReason` + +SHA-256: `530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6` + +Sources: `packages/core/session/src/types.ts` + +One of: + +- `"change"` +- `"initial"` +- `"resume"` +- `"series"` + + + +#### `packages/core/session/src/types.ts#SessionHeader` + +SHA-256: `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `agentPreset` | optional | `string` | +| `createdAt` | required | `number` | +| `cwd` | optional | `string` | +| `delegationDepth` | optional | `number` | +| `id` | required | `string` | +| `isSeeded` | required | `boolean` | +| `origin` | optional | `"subagent"` | +| `parentSession` | optional | `string` | +| `version` | required | `3` | + + + +#### `packages/core/session/src/types.ts#SurfaceOp` + +SHA-256: `335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5` + +Sources: `packages/core/session/src/types.ts` + +One of: + +- `"append"` +- [`SessionEventEnvelope[6].surfaceOp[1]`](#persistence-type-sessioneventenvelope6surfaceop1) + + + +#### `packages/core/session/src/types.ts#TurnEndCancelCause` + +SHA-256: `1f8c126cfab3df812cd115cfc23e3256f0fa2383400f4ce91ecad313577e59b0` + +Sources: `packages/core/session/src/types.ts` + +One of: + +- [`event:turn/end.data.reason[1].reason[2]`](#persistence-type-eventturnenddatareason1reason2) +- [`event:turn/end.data.reason[1].reason[3]`](#persistence-type-eventturnenddatareason1reason3) +- [`event:turn/end.data.reason[1].reason[4]`](#persistence-type-eventturnenddatareason1reason4) +- [`event:turn/end.data.reason[1].reason[1]`](#persistence-type-eventturnenddatareason1reason1) +- [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) + + + +#### `packages/core/session/src/types.ts#TurnEndReason` + +SHA-256: `a5a8c15f08af1b0f26f40906e0797b6b0920fd01069e660becce35ab7fc48d77` + +Sources: `packages/core/session/src/types.ts` + +One of: + +- [`event:turn/end.data.reason[5]`](#persistence-type-eventturnenddatareason5) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]`](#persistence-type-eventassistantattemptdatastream03chunk6reason2) +- [`event:turn/end.data.reason[3]`](#persistence-type-eventturnenddatareason3) +- [`event:turn/end.data.reason[1]`](#persistence-type-eventturnenddatareason1) +- [`event:turn/end.data.reason[2]`](#persistence-type-eventturnenddatareason2) +- [`event:turn/end.data.reason[0]`](#persistence-type-eventturnenddatareason0) + + + +#### `packages/core/tools/src/index.ts#ToolRestriction` + +SHA-256: `3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f` + +Sources: `packages/core/tools/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `allow` | optional | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `deny` | optional | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | + + + +#### `packages/core/tools/src/types.ts#PtcDispatchEventData` + +SHA-256: `8d2e5a3c4230e6ea6c0b5151f02241d0db02cd2551f2df1b6b9700cddcc0dca3` + +Sources: `packages/core/tools/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `arguments` | required | `unknown` (opaque) | +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `error` | optional | [`event:tool/ptc-dispatch.data.error`](#persistence-type-eventtoolptc-dispatchdataerror) | +| `isError` | required | `boolean` | +| `name` | required | `string` | +| `parentCallId` | required | `string` | +| `rootCallId` | required | `string` | +| `subCallId` | required | `string` | + + + +#### `packages/core/tools/src/types.ts#PtcDispatchStartEventData` + +SHA-256: `2fe5026daf14bd4ff2b7bfb7cf9791c302d9cbba06802178b6dfec00b892698f` + +Sources: `packages/core/tools/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `arguments` | required | `unknown` (opaque) | +| `name` | required | `string` | +| `parentCallId` | required | `string` | +| `rootCallId` | required | `string` | +| `subCallId` | required | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMemberPhase` + +SHA-256: `dfce5db4aa42b7ebe0bb79eca92553587287e18c06b9eba85cbfb9d332e26acd` + +Sources: `packages/experimental/agent-team/src/types.ts` + +One of: + +- `"active"` +- `"failed"` +- `"provisioning"` + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMemberSnapshot` + +SHA-256: `6598cd6da253948d6b207c6374a45335804c79b576866d6215649c2d1bc85e25` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `context` | required | [`event:team/member.data.member.context`](#persistence-type-eventteammemberdatamembercontext) | +| `description` | required | `string` | +| `error` | optional | `string` | +| `id` | required | `string` | +| `name` | required | `string` | +| `phase` | required | [`packages/experimental/agent-team/src/types.ts#TeamMemberPhase`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammemberphase) | +| `provider` | required | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMessageSnapshot` + +SHA-256: `5b694f394d5e11609887a3ccfa82844935d49806c37e336b30be2186d649ab94` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | required | `string` | +| `senderId` | required | `string` | +| `senderName` | required | `string` | +| `targetId` | required | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMessageSource` + +SHA-256: `2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"team-message"` | +| `messageId` | required | `string` | +| `senderId` | required | `string` | +| `senderName` | required | `string` | +| `teamId` | required | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamTaskSnapshot` + +SHA-256: `51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357` + +Sources: `packages/experimental/agent-team/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `blockedBy` | required | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `description` | required | `string` | +| `id` | required | `string` | +| `ownerId` | optional | `string` | +| `revision` | required | `number` | +| `status` | required | [`packages/experimental/agent-team/src/types.ts#TeamTaskStatus`](#persistence-type-packagesexperimentalagent-teamsrctypeststeamtaskstatus) | +| `subject` | required | `string` | +| `writeScopes` | required | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamTaskStatus` + +SHA-256: `b2d2a01e51341a3bfec809198952c8c830a7899f4cb6ecd3c1dc0b5d9a2af943` + +Sources: `packages/experimental/agent-team/src/types.ts` + +One of: + +- `"completed"` +- `"deleted"` +- `"in_progress"` +- `"pending"` + + + +#### `packages/feedback/command-feedback/src/types.ts#FeedbackRecord` + +SHA-256: `7d54a5a5e629e2e7783bfac72683bcc5e969e9f43426b9289826aaf294ff6344` + +Sources: `packages/feedback/command-feedback/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `category` | optional | [`event:feedback/message-put.data.item.category`](#persistence-type-eventfeedbackmessage-putdataitemcategory) | +| `text` | optional | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackDelete` + +SHA-256: `7c6129b6961cf4b2a030f36c78d2b0a5be38617651a9b81322e054ee512bee06` + +Sources: `packages/feedback/message-feedback/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `messageId` | required | `string` | +| `sessionId` | required | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackItem` + +SHA-256: `3d7d07060a7be77984feb651ea2bf1925d3e0477911d9d3ed86330d1e8ca6182` + +Sources: `packages/feedback/message-feedback/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `category` | optional | [`event:feedback/message-put.data.item.category`](#persistence-type-eventfeedbackmessage-putdataitemcategory) | +| `createdAt` | required | `number` | +| `messageId` | required | `string` | +| `note` | optional | `string` | +| `rating` | required | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackRating`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackrating) | +| `updatedAt` | required | `number` | +| `version` | required | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackPut` + +SHA-256: `aa7bc2817014ca6c45719b1c193c5c131be718a0921f34345098ff250f444626` + +Sources: `packages/feedback/message-feedback/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `item` | required | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackItem`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackitem) | +| `sessionId` | required | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackRating` + +SHA-256: `390eed1028aba02774f14408647acec10ec5516e97d4f15ecde2b9989d5a69f2` + +Sources: `packages/feedback/message-feedback/src/types.ts` + +One of: + +- `"negative"` +- `"positive"` + + + +#### `packages/fs/tool-present/src/types.ts#PresentedFile` + +SHA-256: `b8fc636a2121df9d8423c242e03c9d23b7ab7c6fdce00e45746932c60b730f97` + +Sources: `packages/fs/tool-present/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `description` | optional | `string` | +| `path` | required | `string` | + + + +#### `packages/goal/goal/src/domain.ts#GoalChangeMeta` + +SHA-256: `7d226b9fd95b4ba213d4237c22e930a91c3c769c95ca7f92977b9d625ba13438` + +Sources: `packages/goal/goal/src/domain.ts` + +One of: + +- [`packages/goal/goal/src/domain.ts#GoalClearChangeMeta`](#persistence-type-packagesgoalgoalsrcdomaintsgoalclearchangemeta) +- [`packages/goal/goal/src/domain.ts#GoalSnapshotChangeMeta`](#persistence-type-packagesgoalgoalsrcdomaintsgoalsnapshotchangemeta) + + + +#### `packages/goal/goal/src/domain.ts#GoalClearChangeMeta` + +SHA-256: `cffcdc19881ab61ec0a9ce18743996f7ac44ac8889f34dfac36ae745574aa22f` + +Sources: `packages/goal/goal/src/domain.ts` + +| Property | Presence | Type | +|---|---|---| +| `cleared` | required | [`packages/goal/goal/src/types.ts#GoalRef`](#persistence-type-packagesgoalgoalsrctypestsgoalref) | +| `clearedAt` | required | `number` | +| `kind` | required | `"goal/change"` | +| `operation` | required | `"clear"` | +| `version` | required | `1` | + + + +#### `packages/goal/goal/src/domain.ts#GoalMessageSource` + +SHA-256: `7f959241c24128b4983b559984811861dc59774b85905c8fa57c6cb0148a3dbc` + +Sources: `packages/goal/goal/src/domain.ts` + +| Property | Presence | Type | +|---|---|---| +| `goalId` | required | `string` | +| `kind` | required | `"goal"` | +| `revision` | required | `number` | +| `round` | required | `number` | + + + +#### `packages/goal/goal/src/domain.ts#GoalSnapshotChangeMeta` + +SHA-256: `1df34a6c086866ffdc2dd9e8e5c581c3751a010cdf6b8538a7327f7a3237f0b4` + +Sources: `packages/goal/goal/src/domain.ts` + +| Property | Presence | Type | +|---|---|---| +| `createdAt` | required | `number` | +| `goal` | required | [`packages/goal/goal/src/types.ts#GoalSnapshot`](#persistence-type-packagesgoalgoalsrctypestsgoalsnapshot) | +| `kind` | required | `"goal/change"` | +| `operation` | required | [`event:goal/change.data[0].operation`](#persistence-type-eventgoalchangedata0operation) | +| `roundsStarted` | required | `number` | +| `updatedAt` | required | `number` | +| `version` | required | `1` | + + + +#### `packages/goal/goal/src/types.ts#GoalBlockReason` + +SHA-256: `84ac8c1a66ffc697262e181f42e851259eae14038c113ca329fb4700ccdb1f7c` + +Sources: `packages/goal/goal/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `code` | required | `string` | +| `message` | required | `string` | + + + +#### `packages/goal/goal/src/types.ts#GoalPhase` + +SHA-256: `b8327af7ee5767952d1300cb4f03b7fc04197ae5ba275e13981c689ff7506172` + +Sources: `packages/goal/goal/src/types.ts` + +One of: + +- `"active"` +- `"blocked"` +- `"complete"` +- `"paused"` + + + +#### `packages/goal/goal/src/types.ts#GoalRef` + +SHA-256: `0b6d718c693fdf7f06dcccb0bcbbabe78cc63514eafc62d6b2a3899735279d6f` + +Sources: `packages/goal/goal/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `id` | required | `string` | +| `revision` | required | `number` | + + + +#### `packages/goal/goal/src/types.ts#GoalSnapshot` + +SHA-256: `6bbe793f6a93dc8d50a4d4d3fbb6f8ed15650bcb7e151d28669628f7b7c3fc25` + +Sources: `packages/goal/goal/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `blockedReason` | optional | [`packages/goal/goal/src/types.ts#GoalBlockReason`](#persistence-type-packagesgoalgoalsrctypestsgoalblockreason) | +| `id` | required | `string` | +| `maxGoalRounds` | required | `number` | +| `objective` | required | `string` | +| `phase` | required | [`packages/goal/goal/src/types.ts#GoalPhase`](#persistence-type-packagesgoalgoalsrctypestsgoalphase) | +| `revision` | required | `number` | + + + +#### `packages/hooks/hook-protocol/src/types.ts#HookDialect` + +SHA-256: `a6b41f5bede8094d7bf635be5d69b1bd7a25e006ca9cf9415bceb9322f1a7feb` + +Sources: `packages/hooks/hook-protocol/src/types.ts` + +One of: + +- `"claude-code"` +- `"codex"` + + + +#### `packages/interaction/user-approval/src/index.ts#ApprovalPolicy` + +SHA-256: `05d2ae1e0c7f8770f83f9a09047afb39a335d8ac986df3193659aa1e581472cf` + +Sources: `packages/interaction/user-approval/src/index.ts` + +One of: + +- `"ask"` +- `"never"` + + + +#### `packages/interaction/user-approval/src/types.ts#ApprovalOutcome` + +SHA-256: `930c1cd289def119d443e19dd90008916bf035f0a4d23e07241e7f050f2b89b7` + +Sources: `packages/interaction/user-approval/src/types.ts` + +One of: + +- `"allowed-once"` +- `"cancelled"` +- `"rejected"` +- `"unavailable"` + + + +#### `packages/llm/llm-retry/src/types.ts#LlmRetryEventData` + +SHA-256: `c170da8ab7c37635b10867b2571811d9e317ac3ec394e8ff8efe53f902fc41c1` + +Sources: `packages/llm/llm-retry/src/types.ts` + +One of: + +- [`event:llm/retry.data[0]`](#persistence-type-eventllmretrydata0) +- [`event:llm/retry.data[1]`](#persistence-type-eventllmretrydata1) + + + +#### `packages/llm/llm-retry/src/types.ts#LlmRetryStartedEventData` + +SHA-256: `6f72ece8f317cd080c4f20a93f1bf709965f5b81ac4669528f5a023191cfcf20` + +Sources: `packages/llm/llm-retry/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `retry` | required | `number` | +| `retryId` | required | `string` | +| `step` | required | `number` | +| `turn` | required | `number` | + + + +#### `packages/llm/llm/src/assistant-stream.ts#AssistantStreamRecord` + +SHA-256: `86cf1e44038cb8b11659863dd0efafe682e41b9c782265c1d50e0a687debfc60` + +Sources: `packages/llm/llm/src/assistant-stream.ts` + +One of: + +- [`event:assistant/attempt.data.stream[0][2]`](#persistence-type-eventassistantattemptdatastream02) +- [`event:assistant/attempt.data.stream[0][3]`](#persistence-type-eventassistantattemptdatastream03) +- [`event:assistant/attempt.data.stream[0][1]`](#persistence-type-eventassistantattemptdatastream01) +- [`event:assistant/attempt.data.stream[0][0]`](#persistence-type-eventassistantattemptdatastream00) + + + +#### `packages/llm/llm/src/call-config.ts#LlmCallConfig` + +SHA-256: `67d5f73ceae82f5265258142ad6cf172de2c1fef93ba551b7f0454e0a93bffe0` + +Sources: `packages/llm/llm/src/call-config.ts` + +| Property | Presence | Type | +|---|---|---| +| `maxTokens` | optional | `number` | +| `model` | required | `string` | +| `provider` | required | `string` | +| `reasoningEffort` | optional | `string` | +| `stop` | optional | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `temperature` | optional | `number` | + + + +#### `packages/llm/llm/src/call-config.ts#LlmCallConfigAdapterDefaults` + +SHA-256: `326a9bfda27dda5882fb3cbe6e715df41dae2298fdae3d66437457268a665693` + +Sources: `packages/llm/llm/src/call-config.ts` + +| Property | Presence | Type | +|---|---|---| +| `maxTokens` | optional | `true` | +| `reasoningEffort` | optional | `true` | + + + +#### `packages/llm/llm/src/message.ts#AssistantMessage` + +SHA-256: `e50b0a3ed8e6c80b672e4f855c91984f03b5c3fdd5d475bf171171f391a86c83` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | required | `string` | +| `role` | required | `"assistant"` | +| `source` | required | [`packages/llm/llm/src/message.ts#ModelMessageSource`](#persistence-type-packagesllmllmsrcmessagetsmodelmessagesource) | + + + +#### `packages/llm/llm/src/message.ts#ContextSnapshotSection` + +SHA-256: `86e1e384495ee09ac2d60c9db3610f1f1fddac2d248f6f1d6000e78054680219` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `name` | required | `string` | +| `text` | required | `string` | + + + +#### `packages/llm/llm/src/message.ts#Message` + +SHA-256: `23c7cce57d20589897f4e2bd5898affc6fc611b87cd0cc8b95be1cfdd8b3a7eb` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | required | `string` | +| `role` | required | [`event:session/title-llm-request.data.messages[0].role`](#persistence-type-eventsessiontitle-llm-requestdatamessages0role) | +| `source` | required | [`packages/llm/llm/src/message.ts#MessageSource`](#persistence-type-packagesllmllmsrcmessagetsmessagesource) | + + + +#### `packages/llm/llm/src/message.ts#MessageSource` + +SHA-256: `4c965666d5b42116945bc356087cd5e1fd549e6dece560785ed60511059a8283` + +Sources: `packages/llm/llm/src/message.ts` + +One of: + +- [`packages/context/agent-instructions/src/state.ts#AgentInstructionSource`](#persistence-type-packagescontextagent-instructionssrcstatetsagentinstructionsource) +- [`packages/llm/llm/src/message.ts#ToolMessageSource`](#persistence-type-packagesllmllmsrcmessagetstoolmessagesource) +- [`event:agent/inbox/spliced.data.inserted[0].source[10]`](#persistence-type-eventagentinboxspliceddatainserted0source10) +- [`event:agent/inbox/spliced.data.inserted[0].source[19]`](#persistence-type-eventagentinboxspliceddatainserted0source19) +- [`packages/skill/tool-skill/src/index.ts#SkillCatalogSource`](#persistence-type-packagesskilltool-skillsrcindextsskillcatalogsource) +- [`packages/skill/skill/src/index.ts#SkillInvocationSource`](#persistence-type-packagesskillskillsrcindextsskillinvocationsource) +- [`event:agent/inbox/spliced.data.inserted[0].source[4]`](#persistence-type-eventagentinboxspliceddatainserted0source4) +- [`event:agent/inbox/spliced.data.inserted[0].source[5]`](#persistence-type-eventagentinboxspliceddatainserted0source5) +- [`event:agent/inbox/spliced.data.inserted[0].source[6]`](#persistence-type-eventagentinboxspliceddatainserted0source6) +- [`event:agent/inbox/spliced.data.inserted[0].source[3]`](#persistence-type-eventagentinboxspliceddatainserted0source3) +- [`event:agent/inbox/spliced.data.inserted[0].source[2]`](#persistence-type-eventagentinboxspliceddatainserted0source2) +- [`event:agent/inbox/spliced.data.inserted[0].source[7]`](#persistence-type-eventagentinboxspliceddatainserted0source7) +- [`packages/context/session-reference/src/types.ts#SessionReferenceSource`](#persistence-type-packagescontextsession-referencesrctypestssessionreferencesource) +- [`packages/subagent/subagent/src/continuation-messages.ts#SubagentSettledMessageSource`](#persistence-type-packagessubagentsubagentsrccontinuation-messagestssubagentsettledmessagesource) +- [`packages/subagent/subagent/src/continuation-messages.ts#AgentMessageSource`](#persistence-type-packagessubagentsubagentsrccontinuation-messagestsagentmessagesource) +- [`packages/goal/goal/src/domain.ts#GoalMessageSource`](#persistence-type-packagesgoalgoalsrcdomaintsgoalmessagesource) +- [`packages/experimental/agent-team/src/types.ts#TeamMessageSource`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammessagesource) +- [`packages/llm/llm/src/message.ts#ModelMessageSource`](#persistence-type-packagesllmllmsrcmessagetsmodelmessagesource) +- [`event:agent/inbox/spliced.data.inserted[0].source[1]`](#persistence-type-eventagentinboxspliceddatainserted0source1) +- [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) + + + +#### `packages/llm/llm/src/message.ts#ModelMessageSource` + +SHA-256: `719c51f67074f97034a6c94297fe1f4b5d3c8d392c57586dab732aa5398c7a91` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `kind` | required | `"model"` | +| `model` | required | `string` | +| `provider` | required | `string` | +| `replayState` | optional | `unknown` (opaque) | + + + +#### `packages/llm/llm/src/message.ts#SystemMessage` + +SHA-256: `302b01ddddcbb3b16cfa3fba2a5d99f5082a55fbd9dc5c83a179a228b8a6a0ca` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | required | `string` | +| `role` | required | `"system"` | +| `source` | required | [`event:system/message.data.message.source`](#persistence-type-eventsystemmessagedatamessagesource) | + + + +#### `packages/llm/llm/src/message.ts#ToolMessageSource` + +SHA-256: `d9c462b9f62fdd3efc76a44b9524dc8781f6b91cd9c7e584b17d971defafebab` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `callId` | required | `string` | +| `kind` | required | `"tool"` | + + + +#### `packages/llm/llm/src/message.ts#ToolResultMessage` + +SHA-256: `1b573e2d5c094fa87e2a8bf409ddd4ac5ba92a123085e168de44b9ccdbd5244c` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:tool/result.data.message.content`](#persistence-type-eventtoolresultdatamessagecontent) | +| `id` | required | `string` | +| `role` | required | `"user"` | +| `source` | required | [`packages/llm/llm/src/message.ts#ToolMessageSource`](#persistence-type-packagesllmllmsrcmessagetstoolmessagesource) | + + + +#### `packages/llm/llm/src/message.ts#UserMessage` + +SHA-256: `4de5e7644130ed715ef6b5a4d86a87b30dca4096d1a6683c66acf6f7809379c7` + +Sources: `packages/llm/llm/src/message.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | required | `string` | +| `role` | required | `"user"` | +| `source` | required | [`packages/llm/llm/src/message.ts#MessageSource`](#persistence-type-packagesllmllmsrcmessagetsmessagesource) | + + + +#### `packages/llm/llm/src/types.ts#ContentBlock` + +SHA-256: `c7b24be059d34d08929593049a1a81eaa3855166aacfe9d7603c0bc8bb728d56` + +Sources: `packages/llm/llm/src/types.ts` + +One of: + +- [`packages/llm/llm/src/types.ts#ReasoningBlock`](#persistence-type-packagesllmllmsrctypestsreasoningblock) +- [`event:web/deepseek-search-llm-request.data.body.messages[0].content[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0content0) +- [`packages/llm/llm/src/types.ts#ToolCallBlock`](#persistence-type-packagesllmllmsrctypeststoolcallblock) +- [`packages/llm/llm/src/types.ts#ImageBlock`](#persistence-type-packagesllmllmsrctypestsimageblock) +- [`packages/llm/llm/src/types.ts#FileBlock`](#persistence-type-packagesllmllmsrctypestsfileblock) +- [`packages/llm/llm/src/types.ts#ToolResultBlock`](#persistence-type-packagesllmllmsrctypeststoolresultblock) + + + +#### `packages/llm/llm/src/types.ts#ContentBlockType` + +SHA-256: `757013fff5879d73d5753d8d1120faab56110e88ac3932485ab7e034d9e9ce61` + +Sources: `packages/llm/llm/src/types.ts` + +One of: + +- `"file"` +- `"image"` +- `"reasoning"` +- `"text"` +- `"tool-call"` +- `"tool-result"` + + + +#### `packages/llm/llm/src/types.ts#FileBlock` + +SHA-256: `f2da0f27c1e6add59982c37b15e4a4912c5b33466859cce3b13d503600e24aef` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `attachment` | required | [`packages/attachment/attachment/src/types.ts#FileAttachmentRef`](#persistence-type-packagesattachmentattachmentsrctypestsfileattachmentref) | +| `type` | required | `"file"` | + + + +#### `packages/llm/llm/src/types.ts#FinishReason` + +SHA-256: `5808e36c95355f0e745201b5db1b6bcec4ebf5adb75d3e82d7d59cc89635ab80` + +Sources: `packages/llm/llm/src/types.ts` + +One of: + +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[3]`](#persistence-type-eventassistantattemptdatastream03chunk6reason3) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[4]`](#persistence-type-eventassistantattemptdatastream03chunk6reason4) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[0]`](#persistence-type-eventassistantattemptdatastream03chunk6reason0) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[1]`](#persistence-type-eventassistantattemptdatastream03chunk6reason1) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]`](#persistence-type-eventassistantattemptdatastream03chunk6reason2) + + + +#### `packages/llm/llm/src/types.ts#ImageBlock` + +SHA-256: `12d5808fac1996b9b3c2afa806e03022252ba2d7b88f835862ae1896591f60c7` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `attachment` | required | [`packages/attachment/attachment/src/types.ts#ImageAttachmentRef`](#persistence-type-packagesattachmentattachmentsrctypestsimageattachmentref) | +| `offloaded` | optional | `true` | +| `type` | required | `"image"` | + + + +#### `packages/llm/llm/src/types.ts#LlmFailure` + +SHA-256: `5f2117d1856a5ab43c28371faa978ebfaa48f8c7d734ea3fc94842210df83dca` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `code` | required | `string` | +| `message` | required | `string` | +| `offloadImages` | optional | `number` | +| `providerRetryAfterMs` | optional | `number` | +| `requestId` | optional | `string` | +| `status` | optional | `number` | + + + +#### `packages/llm/llm/src/types.ts#ReasoningBlock` + +SHA-256: `814d9434e1ddf9078612b3b34322f26e9363b469213335007f7e9ba7fee9464e` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `text` | required | `string` | +| `type` | required | `"reasoning"` | + + + +#### `packages/llm/llm/src/types.ts#ReplayEnvelope` + +SHA-256: `0acd94fe8794574c9ae72c7855ee16d29c546096d4af760d16d1225385764555` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `blocks` | optional | [`event:assistant/attempt.data.stream[0][3].chunk[6].replayState.blocks`](#persistence-type-eventassistantattemptdatastream03chunk6replaystateblocks) | +| `response` | required | `unknown` (opaque) | + + + +#### `packages/llm/llm/src/types.ts#StreamChunk` + +SHA-256: `071d92b9dac661fcc826c678cf64d188f26fb93aab79c627b11a03acdd34dfca` + +Sources: `packages/llm/llm/src/types.ts` + +One of: + +- [`event:assistant/attempt.data.stream[0][3].chunk[3]`](#persistence-type-eventassistantattemptdatastream03chunk3) +- [`event:assistant/attempt.data.stream[0][3].chunk[4]`](#persistence-type-eventassistantattemptdatastream03chunk4) +- [`event:assistant/attempt.data.stream[0][3].chunk[0]`](#persistence-type-eventassistantattemptdatastream03chunk0) +- [`event:assistant/attempt.data.stream[0][3].chunk[2]`](#persistence-type-eventassistantattemptdatastream03chunk2) +- [`event:assistant/attempt.data.stream[0][3].chunk[1]`](#persistence-type-eventassistantattemptdatastream03chunk1) +- [`event:assistant/attempt.data.stream[0][3].chunk[6]`](#persistence-type-eventassistantattemptdatastream03chunk6) +- [`event:assistant/attempt.data.stream[0][3].chunk[5]`](#persistence-type-eventassistantattemptdatastream03chunk5) + + + +#### `packages/llm/llm/src/types.ts#TokenUsage` + +SHA-256: `fec5442b9ee4122e10514d81d5a43648003fe8bfb7ee2ba50c0cdbdd383ed394` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `cacheReadTokens` | optional | `number` | +| `cacheWriteTokens` | optional | `number` | +| `inputTokens` | required | `number` | +| `outputTokens` | required | `number` | +| `reasoningTokens` | optional | `number` | +| `totalTokens` | optional | `number` | + + + +#### `packages/llm/llm/src/types.ts#ToolCallBlock` + +SHA-256: `c1f0f17b6493b85db6453bb30e01b208d703731b25bc1e68e5d4fc72eea9cdea` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `arguments` | required | `string` | +| `id` | required | `string` | +| `name` | required | `string` | +| `type` | required | `"tool-call"` | + + + +#### `packages/llm/llm/src/types.ts#ToolResultBlock` + +SHA-256: `d61574d68558c5a184429e70b04da393dd5460bf5cc3ddef814546e659bd5127` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `isError` | optional | `boolean` | +| `toolCallId` | required | `string` | +| `type` | required | `"tool-result"` | + + + +#### `packages/llm/llm/src/types.ts#ToolSchema` + +SHA-256: `7f5f2a8618c2ece530a18b1358b890fb57fb8c35705e47b66bff2296f8c6e889` + +Sources: `packages/llm/llm/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `description` | required | `string` | +| `name` | required | `string` | +| `parameters` | required | [`event:request/header.data.header.tools[0].parameters`](#persistence-type-eventrequestheaderdataheadertools0parameters) | + + + +#### `packages/sandbox/sandbox/src/index.ts#SandboxMode` + +SHA-256: `fab2bb09bc5e3b9db0685e8f5500b029af1a2b33e70bc703c1d5d0f596fbc1fd` + +Sources: `packages/sandbox/sandbox/src/index.ts` + +One of: + +- `"danger-full-access"` +- `"read-only"` +- `"workspace-write"` + + + +#### `packages/schedule/schedule/src/types.ts#AfterScheduleRecord` + +SHA-256: `27e337d3d6b402b221e50c247a3f518a70d0c474cc60beee15fac3e9c5cbfcbe` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `afterSeconds` | required | `number` | +| `id` | required | `string` | +| `kind` | required | `"after"` | +| `prompt` | required | `string` | +| `scheduledAt` | required | `string` | + + + +#### `packages/schedule/schedule/src/types.ts#AtScheduleRecord` + +SHA-256: `658d895d187b26d83f3b53109a3bf77bbfba9f6f9a6d4bc4ee4315b4eb36239e` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `id` | required | `string` | +| `kind` | required | `"at"` | +| `prompt` | required | `string` | +| `scheduledAt` | required | `string` | + + + +#### `packages/schedule/schedule/src/types.ts#EveryScheduleDispatchChange` + +SHA-256: `e6063d0451dc02026fd9b54ad3f77c7b1b6392ad3e872a7737ac84e13ca72344` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `acceptedAt` | required | `string` | +| `id` | required | `string` | +| `operation` | required | `"dispatch"` | +| `version` | required | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#EveryScheduleRecord` + +SHA-256: `66ece68282d8c06330fb83329a24ae54c386d5ccfab296bbf18369da8beb7d14` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `everySeconds` | required | `number` | +| `id` | required | `string` | +| `kind` | required | `"every"` | +| `prompt` | required | `string` | +| `scheduledAt` | required | `string` | + + + +#### `packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange` + +SHA-256: `8e8e91646a5cae3fc78f7532a0013ff2088ae47077642c2edd507a508209b8af` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `id` | required | `string` | +| `operation` | required | `"dispatch"` | +| `version` | required | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleChange` + +SHA-256: `e1d0e52dcd1855ffb803efc18f8f7b776c48d1c25757e8a75c0281fa298c02e1` + +Sources: `packages/schedule/schedule/src/types.ts` + +One of: + +- [`packages/schedule/schedule/src/types.ts#EveryScheduleDispatchChange`](#persistence-type-packagesscheduleschedulesrctypestseveryscheduledispatchchange) +- [`packages/schedule/schedule/src/types.ts#ScheduleDeleteChange`](#persistence-type-packagesscheduleschedulesrctypestsscheduledeletechange) +- [`packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange`](#persistence-type-packagesscheduleschedulesrctypestsoneshotscheduledispatchchange) +- [`packages/schedule/schedule/src/types.ts#ScheduleCreateChange`](#persistence-type-packagesscheduleschedulesrctypestsschedulecreatechange) + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleCreateChange` + +SHA-256: `ca6425edd20afe34d0cedc6ad1abad1ad7b32e2fbc4c1d24db53939e80bf887f` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `operation` | required | `"create"` | +| `schedule` | required | [`packages/schedule/schedule/src/types.ts#ScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestsschedulerecord) | +| `version` | required | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleDeleteChange` + +SHA-256: `18dc21f12bbac8ade8377e6fbb54179e20c3d955d73fba3244c57fb6bf001df0` + +Sources: `packages/schedule/schedule/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `id` | required | `string` | +| `operation` | required | `"delete"` | +| `version` | required | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleRecord` + +SHA-256: `d8f868c6b3e7189de6c1ffe2ea04794ea2aa31315b6347d12536e46020afac87` + +Sources: `packages/schedule/schedule/src/types.ts` + +One of: + +- [`packages/schedule/schedule/src/types.ts#AfterScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestsafterschedulerecord) +- [`packages/schedule/schedule/src/types.ts#EveryScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestseveryschedulerecord) +- [`packages/schedule/schedule/src/types.ts#AtScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestsatschedulerecord) + + + +#### `packages/session/session-persistence-jsonl/src/format.ts#HeaderLine` + +SHA-256: `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` + +Sources: `packages/session/session-persistence-jsonl/src/format.ts` + +| Property | Presence | Type | +|---|---|---| +| `agentPreset` | optional | `string` | +| `createdAt` | required | `number` | +| `cwd` | optional | `string` | +| `delegationDepth` | required | `number` | +| `id` | required | `string` | +| `isSeeded` | required | `boolean` | +| `origin` | optional | `"subagent"` | +| `parentSession` | optional | `string` | +| `type` | required | `"session"` | +| `version` | required | `number` | + + + +#### `packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData` + +SHA-256: `9fe0e77a7816b7fdb4b953ec0e2f0cd7bbd22c5de5c3567e612d1b20eb0992e6` + +Sources: `packages/session/session-title-llm/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `maxTokens` | required | `number` | +| `messageSeqs` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `messages` | required | [`event:session/title-llm-request.data.messages`](#persistence-type-eventsessiontitle-llm-requestdatamessages) | +| `route` | required | [`packages/session/session-title/src/types.ts#SessionTitleModelIdentity`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlemodelidentity) | +| `system` | required | `string` | +| `titleProvider` | required | `string` | + + + +#### `packages/session/session-title/src/types.ts#SessionTitleEventData` + +SHA-256: `b56f6a885da3dc394c69a3e3cc5c0cfc4da15601b63fda4989eee8f40efc5be4` + +Sources: `packages/session/session-title/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `messageSeqs` | required | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `source` | required | [`packages/session/session-title/src/types.ts#SessionTitleSource`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlesource) | +| `title` | required | `string` | + + + +#### `packages/session/session-title/src/types.ts#SessionTitleModelIdentity` + +SHA-256: `07e1a58c58b593f507b8e7f25723bb0aa42baae6e00f5ecfddf28cb1e64d3235` + +Sources: `packages/session/session-title/src/types.ts` · `packages/subagent/tool-subagent/src/model-selection.ts` + +| Property | Presence | Type | +|---|---|---| +| `model` | required | `string` | +| `provider` | required | `string` | + + + +#### `packages/session/session-title/src/types.ts#SessionTitleSource` + +SHA-256: `30d5a537b296685770b1241c4b4bbde19d5a31ff81aa23df73fab5e90b8fc65f` + +Sources: `packages/session/session-title/src/types.ts` + +One of: + +- [`event:session/title.data.source[1]`](#persistence-type-eventsessiontitledatasource1) +- [`event:session/title.data.source[0]`](#persistence-type-eventsessiontitledatasource0) +- [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) + + + +#### `packages/skill/skill/src/index.ts#SkillInvocationSource` + +SHA-256: `672c4aa2a9b736e3d6e5da6346d2e2ed5e3573f2d0baafa18e7407c9f3fee3db` + +Sources: `packages/skill/skill/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"instructions"` | +| `kind` | required | `"skill-invocation"` | +| `name` | required | `string` | + + + +#### `packages/skill/tool-skill/src/index.ts#SkillCatalogSource` + +SHA-256: `fc2ae6962f9f8801c2b1e414668e1e17cbb7544c4f39381198977a38bd10c093` + +Sources: `packages/skill/tool-skill/src/index.ts` + +| Property | Presence | Type | +|---|---|---| +| `entries` | required | [`event:agent/inbox/spliced.data.inserted[0].source[17].entries`](#persistence-type-eventagentinboxspliceddatainserted0source17entries) | +| `form` | required | `"catalog"` | +| `kind` | required | `"skill-catalog"` | +| `update` | optional | `true` | + + + +#### `packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent` + +SHA-256: `3ac1196f59d5e9e0e9345122c8c403b102478b526404a2e591a38f613483321e` + +Sources: `packages/subagent/subagent/src/catalog.ts` + +One of: + +- [`event:subagent/catalog.data[1]`](#persistence-type-eventsubagentcatalogdata1) +- [`event:subagent/catalog.data[0]`](#persistence-type-eventsubagentcatalogdata0) + + + +#### `packages/subagent/subagent/src/continuation-messages.ts#AgentMessageSource` + +SHA-256: `4a9bef9f27a942520cc2279ca7dd3082556e4bff543f66b5c0333e1bbed1cd86` + +Sources: `packages/subagent/subagent/src/continuation-messages.ts` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"relay"` | +| `kind` | required | `"agent-message"` | +| `senderSessionId` | required | `string` | + + + +#### `packages/subagent/subagent/src/continuation-messages.ts#SubagentSettledMessageSource` + +SHA-256: `4e97c3d85c0fc817ee58873c38c25a2474abaaa0af4839311b50b68db3b8cf1a` + +Sources: `packages/subagent/subagent/src/continuation-messages.ts` + +| Property | Presence | Type | +|---|---|---| +| `form` | required | `"notice"` | +| `kind` | required | `"subagent-settled"` | +| `senderSessionId` | required | `string` | +| `summary` | required | `string` | + + + +#### `packages/subagent/subagent/src/descriptor.ts#ContinuableSubagentDescriptorData` + +SHA-256: `6487b10ba7542f3c447b1e41a1c6a590b7bfafe0b9b66b49f34028da85bb970f` + +Sources: `packages/subagent/subagent/src/descriptor.ts` + +| Property | Presence | Type | +|---|---|---| +| `agentModel` | optional | `string` | +| `agentProvider` | optional | `string` | +| `agentReasoningEffort` | optional | `string` | +| `label` | required | `string` | +| `mode` | required | `"continuable"` | +| `persona` | optional | `string` | +| `provider` | required | `string` | +| `toolFilter` | optional | [`packages/core/tools/src/index.ts#ToolRestriction`](#persistence-type-packagescoretoolssrcindextstoolrestriction) | +| `version` | required | `number` | + + + +#### `packages/subagent/subagent/src/descriptor.ts#OneShotSubagentDescriptorData` + +SHA-256: `5f758f3de5f00c18968a7c6d347083aac5c9ae13f6a79c78f6611b23c4973564` + +Sources: `packages/subagent/subagent/src/descriptor.ts` + +| Property | Presence | Type | +|---|---|---| +| `label` | optional | `string` | +| `mode` | required | `"one-shot"` | +| `provider` | required | `string` | +| `version` | required | `number` | + + + +#### `packages/subagent/subagent/src/descriptor.ts#SubagentDescriptorData` + +SHA-256: `86d1d0e9cfebb240421187e3dc37fb71cc38a1501885cf32f8f9adef7b0a2bde` + +Sources: `packages/subagent/subagent/src/descriptor.ts` + +One of: + +- [`packages/subagent/subagent/src/descriptor.ts#ContinuableSubagentDescriptorData`](#persistence-type-packagessubagentsubagentsrcdescriptortscontinuablesubagentdescriptordata) +- [`packages/subagent/subagent/src/descriptor.ts#OneShotSubagentDescriptorData`](#persistence-type-packagessubagentsubagentsrcdescriptortsoneshotsubagentdescriptordata) + + + +#### `packages/todo/tool-todo/src/types.ts#TodoItem` + +SHA-256: `a99f76fd149051c363f960bfeeb5b9509587ecaf7591a42797e4bfe810d8987a` + +Sources: `packages/todo/tool-todo/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `content` | required | `string` | +| `status` | required | [`event:todo/write.data.todos[0].status`](#persistence-type-eventtodowritedatatodos0status) | + + + +#### `packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest` + +SHA-256: `2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9` + +Sources: `packages/web/web-search-deepseek/src/provider.ts` + +| Property | Presence | Type | +|---|---|---| +| `apiVersion` | required | `string` | +| `body` | required | [`event:web/deepseek-search-llm-request.data.body`](#persistence-type-eventwebdeepseek-search-llm-requestdatabody) | +| `endpoint` | required | `string` | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData` + +SHA-256: `c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7` + +Sources: `packages/workflow/tool-workflow/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `outcome` | required | [`packages/workflow/workflow/src/types.ts#WorkflowAgentOutcome`](#persistence-type-packagesworkflowworkflowsrctypestsworkflowagentoutcome) | +| `runId` | required | `string` | +| `seq` | required | `number` | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData` + +SHA-256: `9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc` + +Sources: `packages/workflow/tool-workflow/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `childId` | required | `string` | +| `label` | required | `string` | +| `phase` | optional | `string` | +| `runId` | required | `string` | +| `seq` | required | `number` | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunEndData` + +SHA-256: `7f9365bae9fcb73e1e34061a1acfe0422c1a5fd351848cace9bebbe806f28462` + +Sources: `packages/workflow/tool-workflow/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `runId` | required | `string` | +| `stopReason` | required | [`packages/workflow/workflow/src/types.ts#WorkflowStopReason`](#persistence-type-packagesworkflowworkflowsrctypestsworkflowstopreason) | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData` + +SHA-256: `a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c` + +Sources: `packages/workflow/tool-workflow/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `name` | required | `string` | +| `runId` | required | `string` | + + + +#### `packages/workflow/workflow/src/types.ts#WorkflowAgentOutcome` + +SHA-256: `c2deb7c9183735d4e0fffddf5c623f4e34daa1c8e96b111982e957dfcbbcf896` + +Sources: `packages/workflow/workflow/src/types.ts` + +One of: + +- `"cancelled"` +- `"completed"` +- `"failed"` + + + +#### `packages/workflow/workflow/src/types.ts#WorkflowStopReason` + +SHA-256: `8465ece5e9d9007c038b357015d849c15262cb0bc25abc59e47692d87ee01a15` + +Sources: `packages/workflow/workflow/src/types.ts` + +One of: + +- `"cancelled"` +- `"completed"` +- `"error"` + + + +#### `"parent"` + +SHA-256: `e6411b09c1d982f789bf741ca74e2bea69df56029847f86a6148e722039ee732` + +`"parent"` + + + +#### `"pause"` + +SHA-256: `1d8798b1a5e8c545ee4dcd2b4e75c0b4c9ffd985e4744c6d1a1aab992f859721` + +`"pause"` + + + +#### `"paused"` + +SHA-256: `c43b119ce579b3e9983a0d3adc4ba402ebb9ba773d89738a2dab01ecf5813943` + +`"paused"` + + + +#### `"pending"` + +SHA-256: `234142ee4f996f38cc9fa3b8b3e3de29b03c9aefe5ebf6c224eddd564505aa85` + +`"pending"` + + + +#### `"permission/preset"` + +SHA-256: `ae63d9d1080ed8945031594d93f8d96651d7101b848719cc3e1475875cd3d649` + +`"permission/preset"` + + + +#### `"plan/mode"` + +SHA-256: `f634871d1e18b1eb199497ac8ab72d3964f48d03fbf611dc7521a1970cf429d9` + +`"plan/mode"` + + + +#### `"plugin"` + +SHA-256: `e654d28d1e6c471147310d2fba396d00969cfe6ed9022626d3f2c2312e0b1cbb` + +`"plugin"` + + + +#### `"positive"` + +SHA-256: `df5d9709b7db2a72510dc52052a23f0c38f39730af1504bab8bccabc14fae528` + +`"positive"` + + + +#### `"product-interaction"` + +SHA-256: `0341d4c3dfcd53253cdc1e789d9130d3cd848b6f8b0706bf92f313a68b39ff23` + +`"product-interaction"` + + + +#### `"provider"` + +SHA-256: `e31572180d6b28b73f073ad30ae19d5d82982d3daf984723984e23da1e7c459a` + +`"provider"` + + + +#### `"provisioning"` + +SHA-256: `871bfd6f7bb91061246768d3377f3fd58d6b8ea7c31f44c714ae7ab215650d62` + +`"provisioning"` + + + +#### `"read-only"` + +SHA-256: `12a0cfa619ac4a5fc6c3e8e359c8dae15769edc61497a575935c78d5842f8e42` + +`"read-only"` + + + +#### `"reasoning"` + +SHA-256: `3c2535ca0a2062f172f15344f8040755002b5ac506cf94fc4ebaa822b15feb8c` + +`"reasoning"` + + + +#### `"reasoning-chunks"` + +SHA-256: `688e853dc149f0d30b31765c12ec7e3be74169bdf1a4c6463a10b945d50cc1b8` + +`"reasoning-chunks"` + + + +#### `"reasoning-delta"` + +SHA-256: `6f091fe32ab24407236090ca9d710bbaf59bb57466e9f3b8f1f6e4862bc863c6` + +`"reasoning-delta"` + + + +#### `"recall"` + +SHA-256: `383cf73ae4748e5beb281ae74857ba1ffb92ae01075b9fbf51af78b666007a8f` + +`"recall"` + + + +#### `"rejected"` + +SHA-256: `fab35c4520883c0d69e42d079c9f543fc5ac7a2d15b537b5572fcd99059c7018` + +`"rejected"` + + + +#### `"relay"` + +SHA-256: `16d0507cb94b4cfc84a87446b1ba7652d6ec1d65ee1684789e747e30d542800e` + +`"relay"` + + + +#### `"remove"` + +SHA-256: `7382c4fc95fe8c5db65ca4d9da572b115d0dbb818b7f32c22ab040318ffbb4bc` + +`"remove"` + + + +#### `"replace"` + +SHA-256: `f6cb462f808309e315fea634f1ed86268b8346bbcee6774d9097ca6eed7ac1f8` + +`"replace"` + + + +#### `"request/context"` + +SHA-256: `70b082fe78991edf13cf66e1b4d06cd2dcff9cacfd76f8cfb996bfb61939e7b2` + +`"request/context"` + + + +#### `"request/header"` + +SHA-256: `3e0eff5946255ff05d88a10839c60305135801f97794ea48d409f8503303317e` + +`"request/header"` + + + +#### `"resource-cost"` + +SHA-256: `5bd310104cfe448e530beb11422d2f791e2e32e8e95fdc528a15f9ca693dae75` + +`"resource-cost"` + + + +#### `"resume"` + +SHA-256: `34d1ab5c5df378186d6054b1a1beea9a41e41965d6f336f0bc0025c441a82e66` + +`"resume"` + + + +#### `"sandbox/mode"` + +SHA-256: `ca085dba2c877feceebf3c62f9d39c6c2a4d2314d97b94b3927a780fe8fe2bb2` + +`"sandbox/mode"` + + + +#### `"schedule/change"` + +SHA-256: `0e7b2a97f54f1afdb8cdfad1635abe9145327db539bfb69b4045c19d8c17755d` + +`"schedule/change"` + + + +#### `"security-privacy-permission"` + +SHA-256: `07eccc9ea2f9b5439d76cc77d5e062936677d43f07a23da749819b0a22ee36b7` + +`"security-privacy-permission"` + + + +#### `"series"` + +SHA-256: `4f507598cf476214aa7646ce7841a7064a9dcb05d0a1eaaefaf79c2b738f160f` + +`"series"` + + + +#### `"service-stability"` + +SHA-256: `7180844e1066230c5e891f1b9ccd942423b0fe48aac6ded7eef2a285b288a732` + +`"service-stability"` + + + +#### `"session"` + +SHA-256: `e41bdebe246abe17154de7e7a1d81035437eee8d20e7f1edff0d91e2598ad828` + +`"session"` + + + +#### `"session-log-deepseek/delivery-accepted"` + +SHA-256: `47e5d84f1a93450a78c7f3954b43990d0f629af7c034a56313e5deb63e772c1b` + +`"session-log-deepseek/delivery-accepted"` + + + +#### `"session-reference"` + +SHA-256: `7f13860ee89a2d35ce09f958e85a04566cd59cb1de1d73a9619a9b631961dc71` + +`"session-reference"` + + + +#### `"session/end-seed"` + +SHA-256: `1c2686c0682e7bc51d61117b2652bd4a80707e331aa276d6ef915ae32534a330` + +`"session/end-seed"` + + + +#### `SessionEventEnvelope` + +SHA-256: `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` + +One of: + +- [`SessionEventEnvelope[39]`](#persistence-type-sessioneventenvelope39) +- [`SessionEventEnvelope[6]`](#persistence-type-sessioneventenvelope6) +- [`SessionEventEnvelope[0]`](#persistence-type-sessioneventenvelope0) + + + +#### `SessionEventEnvelope[0]` + +SHA-256: `e3e77b26f0148755a505f5b8ea843a3be117827d4703bb5754d9dc8ddbef521f` + +| Property | Presence | Type | +|---|---|---| +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `time` | required | `number` | +| `type` | required | `string` | + + + +#### `SessionEventEnvelope[39]` + +SHA-256: `998f22585a5d73ec005365e203f07fc3b3a029e82323fdda3fd7f13b0a9639d0` + +| Property | Presence | Type | +|---|---|---| +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `sourceEventSeqs` | optional | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | required | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | required | `number` | +| `type` | required | `string` | + + + +#### `SessionEventEnvelope[39].sourceEventSeqs` + +SHA-256: `5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78` + +Array of `number`. + + + +#### `SessionEventEnvelope[6]` + +SHA-256: `7af85bf70d4eafce63e739adae38ea85501e68df3a0e22f97f3a0be90fd9e4cb` + +| Property | Presence | Type | +|---|---|---| +| `ignorable` | optional | `true` | +| `seq` | required | `number` | +| `surfaceOp` | required | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | required | `number` | +| `type` | required | `string` | + + + +#### `SessionEventEnvelope[6].surfaceOp[1]` + +SHA-256: `bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825` + +Sources: `packages/core/session/src/types.ts` + +| Property | Presence | Type | +|---|---|---| +| `endSeq` | required | `number` | +| `op` | required | `"replace"` | +| `startSeq` | required | `number` | + + + +#### `"session/title"` + +SHA-256: `7a651f3b672c52fb615f22c0ce9cb3cc5b22aad92e6bbeefb0808fd7b9233a50` + +`"session/title"` + + + +#### `"session/title-llm-request"` + +SHA-256: `587bb11da730e06aa52b62c087d217d6f8f22459b25f31cb9e1e1baf17944e5e` + +`"session/title-llm-request"` + + + +#### `"set"` + +SHA-256: `b765ee31033cea463863faf3fc6a0a1b85c47c6a2f13fe1ce833abe56105114b` + +`"set"` + + + +#### `"skill-catalog"` + +SHA-256: `6ebcc2dbec9f2dabca9f668ae6d39e877899b180740570f453409db339221df3` + +`"skill-catalog"` + + + +#### `"skill-invocation"` + +SHA-256: `1922cd79a70806c17758185a6ef0458bc1fb3900363906733421c16414da2509` + +`"skill-invocation"` + + + +#### `"snapshot"` + +SHA-256: `6f9e00383836275e46c0a9915767f9bb561be5fc30aae490174908a93e99a912` + +`"snapshot"` + + + +#### `"step/end"` + +SHA-256: `c219efbdfd53b836786202ab4532913d555798f0a8615a4e9629736e3799fb70` + +`"step/end"` + + + +#### `"step/start"` + +SHA-256: `2c64d4bc7264fd3f8bed47e96ab8a593bce05a1e4e1c436dcd244a3b7e0c2a9d` + +`"step/start"` + + + +#### `"stop"` + +SHA-256: `57f3f606ff8b6c84d9c443faace9d1dd10cca0354f37a4f515ef075f7c351b90` + +`"stop"` + + + +#### `string` + +SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` + +Sources: `packages/api/session-controller/src/types.ts` · `packages/attachment/attachment/src/brand.ts` · `packages/compaction/compaction/src/brand.ts` · `packages/core/session/src/types.ts` · `packages/experimental/agent-team/src/types.ts` · `packages/feedback/message-feedback/src/types.ts` · `packages/goal/goal/src/types.ts` · `packages/interaction/commands/src/brand.ts` · `packages/interaction/user-approval/src/types.ts` · `packages/llm/llm-retry/src/brand.ts` · `packages/llm/llm/src/brand.ts` · `packages/schedule/schedule/src/types.ts` · `packages/session/session-title/src/index.ts` · `packages/session/session-title/src/types.ts` · `packages/webhook/webhook/src/brand.ts` · `packages/workflow/workflow/src/types.ts` + +`string` + + + +#### `"subagent"` + +SHA-256: `aacda84a69739238aa782eea902d3073017d9d74b9808de2bf5a83c9738cbdc6` + +`"subagent"` + + + +#### `"subagent-settled"` + +SHA-256: `bf16d2e98a7f13894ded2cffe5ce857bf473954a0e3c0ed9bc7739e2e1c7b78a` + +`"subagent-settled"` + + + +#### `"subagent/catalog"` + +SHA-256: `44c8c77aa9aa100b0d74d2deee85474b29faa6eee0ac0f662f7abe9931ddd7f2` + +`"subagent/catalog"` + + + +#### `"subagent/descriptor"` + +SHA-256: `5ebce1317eacd2c148456627a09668e927ee15c204f0643f5ea76b46b54a2647` + +`"subagent/descriptor"` + + + +#### `"subagent/model-selection-policy"` + +SHA-256: `0a8a062bc9c3c0d97fd97742262f2ea53dd32297f834e81114870d38ac3dc6da` + +`"subagent/model-selection-policy"` + + + +#### `"success"` + +SHA-256: `511801b0a6470d98566e8385d3dffddb2b67f79fcf73ed6056f46c3cc0a245a7` + +`"success"` + + + +#### `"system"` + +SHA-256: `8af841fc9b265ade3441caf9fe40dd24db24226befba48150e6d0eeccc1389c3` + +`"system"` + + + +#### `"system/message"` + +SHA-256: `1c5a58f4599bd4a9711712551ffe2442a5e5fcd0758bafe630cc4ead850bdaa7` + +`"system/message"` + + + +#### `"task-result"` + +SHA-256: `f05fb85e715af4ab4de0b6ba111166dd0435bd8bb74a0fa0f32b9d174113fc7c` + +`"task-result"` + + + +#### `"team-message"` + +SHA-256: `2e4debca12f2c449f96dc6574f3fbf2fb346193443114a241d01a236362ec48c` + +`"team-message"` + + + +#### `"team/member"` + +SHA-256: `18fcdd273a2f2f9d813a3be5e71df5903a963a5c88e46b90b14de6e2db890da0` + +`"team/member"` + + + +#### `"team/message/delivered"` + +SHA-256: `a8a2b9011fc067862df7ce40748868467e5778283d7ac193c13f77684a914c57` + +`"team/message/delivered"` + + + +#### `"team/message/queued"` + +SHA-256: `4e011753f8263f436efaabfbb3b4db53a98fc55342c5ded2daf7208b217be159` + +`"team/message/queued"` + + + +#### `"team/task"` + +SHA-256: `b57ae1b37e52bee0a21cbdace168dc6a15582bcda8c306dad962c5dcc8a8e28b` + +`"team/task"` + + + +#### `"text"` + +SHA-256: `4e44c9118152f6829634bfd508e47669ab0497caffa380c94b4be91f9390d35d` + +`"text"` + + + +#### `"text-chunks"` + +SHA-256: `f9cfc89e8fe085b4fcc9cd32b74b6f103608c54d7d8cd97b47c01de34f252ba3` + +`"text-chunks"` + + + +#### `"text-delta"` + +SHA-256: `5abab3a27fd2736660ecddd94b28d6bbf114986dd894880153bd1be3ccacb563` + +`"text-delta"` + + + +#### `"todo/write"` + +SHA-256: `af0750d32d97d47b12b7361a587db41894b17e04c9a805fe212f0114aa2248c7` + +`"todo/write"` + + + +#### `"tool"` + +SHA-256: `a13d8f379222ece8a02a86efe4c8334af4f108ecb3034b38c0a42bb3046e6847` + +`"tool"` + + + +#### `"tool-call"` + +SHA-256: `1f0133217eeeffd8d387baf1ec8ed9856e719bcd999dc08e48624cba96d75fd7` + +`"tool-call"` + + + +#### `"tool-call-chunks"` + +SHA-256: `616f93a5047de668e1c30d57b1786abd76beeb4123599637ec1dc5290320ede5` + +`"tool-call-chunks"` + + + +#### `"tool-call-delta"` + +SHA-256: `9b4fd974c124c83743efe030ba4e1250e087505f3f74588716a521fb8d453267` + +`"tool-call-delta"` + + + +#### `"tool-calls"` + +SHA-256: `6c1cccb433ddc153facb380c7dda956237ba5c31f8a532a69142dc277890cc9b` + +`"tool-calls"` + + + +#### `"tool-result"` + +SHA-256: `e5244812c495a80c2e78ba2c2690dca5f6b58ea8d3fe5531ff94a6f9ac5e5d66` + +`"tool-result"` + + + +#### `"tool-workflow/agent-end"` + +SHA-256: `5d17f27a1ef9f7026c0232714adf7573961536d75f3303ca97973975f5af170e` + +`"tool-workflow/agent-end"` + + + +#### `"tool-workflow/agent-start"` + +SHA-256: `ad92f473a03ae72599ff26c86e897c25e16269519ad2a87340f0bea946517af8` + +`"tool-workflow/agent-start"` + + + +#### `"tool-workflow/run-end"` + +SHA-256: `fe792a6cd430494503837e21e79f91677704ccdd9e870c679aabd7d43ed47ddd` + +`"tool-workflow/run-end"` + + + +#### `"tool-workflow/run-start"` + +SHA-256: `cdca80b8dad24d4e7b1d5a288a8475ba8d8d46be385bd2da85f122ee836f1670` + +`"tool-workflow/run-start"` + + + +#### `"tool/call"` + +SHA-256: `c589e938cc0e4989df8b82abef6339de621f0dc4fe62c230d145b94996af7f92` + +`"tool/call"` + + + +#### `"tool/ptc-dispatch"` + +SHA-256: `fb5e0517050d2c6d40e5b8145db1f7c5ca7044d5d50fada6ff80e0b22c6ca973` + +`"tool/ptc-dispatch"` + + + +#### `"tool/ptc-dispatch-start"` + +SHA-256: `2aed07493b1c65b6d00de5586da1e743cf501684b9ad43a1765fb4007d4ea456` + +`"tool/ptc-dispatch-start"` + + + +#### `"tool/result"` + +SHA-256: `570e85022434613394418ad33e77e9f1f7a05699b33d0b62eae0677a638c3833` + +`"tool/result"` + + + +#### `true` + +SHA-256: `dacf3d5f3e4ff619c1320e64a48dec5e7ecd7870bece65fbd449a0e63adfa521` + +`true` + + + +#### `"turn/end"` + +SHA-256: `4312134fc6f9cad507c31390bd3d147535492dd77621ec517c5e85f853d53a03` + +`"turn/end"` + + + +#### `"turn/start"` + +SHA-256: `0af3ecfb8c60d416fc40a7cc4fb2c4851a8e46608b2b38ab9e510670c971aa1f` + +`"turn/start"` + + + +#### `"unavailable"` + +SHA-256: `2c4c21f19f426a58f2dac914e34313aa43f8408972de857a486d1f086d5adb6c` + +`"unavailable"` + + + +#### `unknown` + +SHA-256: `bbc5696e3f13c758237b316e3cf08cda0b9fd51ffe672539883457769faa185d` + +`unknown`: the declaration does not expose the stored value's internal fields. + + + +#### `"usage"` + +SHA-256: `0bdaf9cb63594be4ef034b68901fffe792fe09d6d5f6bac42d7f56f6e7834fb9` + +`"usage"` + + + +#### `"user"` + +SHA-256: `68f44f59e91c41395076cb77265981a601680ec8a381bbbeb6ab754ffdc94573` + +`"user"` + + + +#### `"user/message"` + +SHA-256: `de25352d2dc4196309bd84b5bac6319f6d5c898ea0e82bb5ae66c5738d0d426f` + +`"user/message"` + + + +#### `"web_search"` + +SHA-256: `935c8d486292b13c87b57ca280eb8c58b5b2f5239be86fcd4334c33fdeb87682` + +`"web_search"` + + + +#### `"web_search_20250305"` + +SHA-256: `0116b1f89c05221d56b0ba35c83d302bf4857bc7277d247e9bbaf74b27d2c66e` + +`"web_search_20250305"` + + + +#### `"web/deepseek-search-llm-request"` + +SHA-256: `6f611bed14b2106542480c4a230b4a83baf76dc0d8ac0cd13319a7cb8dae7675` + +`"web/deepseek-search-llm-request"` + + + +#### `"webhook"` + +SHA-256: `db6c5246911d47a7969f6b4cb47c7d0dbbde75c402710b22ace3672fa97bebe0` + +`"webhook"` + + + +#### `"workspace-write"` + +SHA-256: `a3edd1efd1fef21b72c55e213c8a8b24196b091abde2b89db52be0b2aaae3cfa` + +`"workspace-write"` + +
+ + + + +## Verification and limitations + +`pnpm run verify-persistence-catalog` passed before `pnpm run verify-persistence-formats --archive 3` created the schema from the current V3 inventory. Archival retains every root and its reachable declared types, preserves root digests and opaque declarations, and removes source line numbers. Earlier format records remain unchanged. + +The inventory records declared fields and optionality, not every codec or restoration invariant. External plugin payloads, physical range encoding, and runtime relationships need their owning validators; schema completeness alone does not establish migration safety. + +```sh +pnpm run verify-persistence-formats +``` + +The check validates every format through the current writer, schema completeness, bilingual declarations, and generated tables using only this checkout. It does not replay historical applications. See the [format index](README.md) for maintenance rules and the [current catalog](../../persistence-catalog.md) for today's declarations. + + +## Dev Note + +None. diff --git a/docs/persistence-changes/historical-formats/v3.schema.json b/docs/persistence-changes/historical-formats/v3.schema.json new file mode 100644 index 0000000000..8667e6ae90 --- /dev/null +++ b/docs/persistence-changes/historical-formats/v3.schema.json @@ -0,0 +1,61307 @@ +{ + "formatVersion": 1, + "roots": [ + { + "key": "SessionHeader", + "kind": "header", + "digest": "2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 2, + "optional": false + }, + { + "name": "cwd", + "type": 1, + "optional": true + }, + { + "name": "delegationDepth", + "type": 2, + "optional": true + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "isSeeded", + "type": 3, + "optional": false + }, + { + "name": "origin", + "type": 4, + "optional": true + }, + { + "name": "parentSession", + "type": 1, + "optional": true + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "subagent" + }, + { + "kind": "literal", + "value": 3 + } + ] + } + }, + { + "key": "JsonlHeaderLine", + "kind": "header", + "digest": "18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 2, + "optional": false + }, + { + "name": "cwd", + "type": 1, + "optional": true + }, + { + "name": "delegationDepth", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "isSeeded", + "type": 3, + "optional": false + }, + { + "name": "origin", + "type": 4, + "optional": true + }, + { + "name": "parentSession", + "type": 1, + "optional": true + }, + { + "name": "type", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "subagent" + }, + { + "kind": "literal", + "value": "session" + } + ] + } + }, + { + "key": "SessionEventEnvelope", + "kind": "envelope", + "digest": "5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 10, + 11 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 4, + "optional": true + }, + { + "name": "surfaceOp", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 3, + "optional": false + }, + { + "name": "op", + "type": 8, + "optional": false + }, + { + "name": "startSeq", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "surfaceOp", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + } + ] + } + }, + { + "key": "event:agent-preset/selected", + "kind": "event", + "event": "agent-preset/selected", + "surface": false, + "digest": "a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "agent-preset/selected" + } + ] + } + }, + { + "key": "event:agent/inbox/spliced", + "kind": "event", + "event": "agent/inbox/spliced", + "surface": false, + "digest": "646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 18, + "optional": true + }, + { + "name": "seq", + "type": 11, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 90, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "inserted", + "type": 2, + "optional": false + }, + { + "name": "outcome", + "type": 86, + "optional": true + }, + { + "name": "removedCount", + "type": 11, + "optional": true + }, + { + "name": "start", + "type": 11, + "optional": false + }, + { + "name": "target", + "type": 87, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "role", + "type": 30, + "optional": false + }, + { + "name": "source", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 20, + 23, + 26, + 28 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 10, + "optional": false + }, + { + "name": "offloaded", + "type": 18, + "optional": true + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 21, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 32, + 41, + 43, + 44, + 47, + 52, + 54, + 59, + 60, + 61, + 63, + 65, + 66, + 73, + 75, + 77, + 79, + 81, + 84, + 85 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 18, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 7, + "optional": true + }, + { + "name": "changes", + "type": 33, + "optional": false + }, + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 35, + "optional": false + }, + { + "name": "digest", + "type": 7, + "optional": true + }, + { + "name": "path", + "type": 7, + "optional": false + }, + { + "name": "scope", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 36, + 37, + 38 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 7, + "optional": false + }, + { + "name": "kind", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 7, + "optional": true + }, + { + "name": "kind", + "type": 30, + "optional": false + }, + { + "name": "rpcId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 7, + "optional": false + }, + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 46, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "ruleId", + "type": 7, + "optional": false + }, + { + "name": "source", + "type": 7, + "optional": false + }, + { + "name": "summary", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 48, + "optional": false + }, + { + "name": "form", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + }, + { + "name": "update", + "type": 18, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 49 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + }, + { + "name": "sections", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 58 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + }, + { + "name": "summary", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 64, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 67, + "optional": false + }, + { + "name": "references", + "type": 68, + "optional": false + }, + { + "name": "version", + "type": 72, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 69 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 11, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 70, + "optional": false + }, + { + "name": "compacted", + "type": 24, + "optional": false + }, + { + "name": "inputIndex", + "type": 11, + "optional": false + }, + { + "name": "label", + "type": 7, + "optional": false + }, + { + "name": "omittedBytes", + "type": 11, + "optional": false + }, + { + "name": "omittedMessages", + "type": 11, + "optional": false + }, + { + "name": "originalMessages", + "type": 11, + "optional": false + }, + { + "name": "retainedMessages", + "type": 11, + "optional": false + }, + { + "name": "sessionId", + "type": 7, + "optional": false + }, + { + "name": "truncated", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 11, + 71 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 74, + "optional": false + }, + { + "name": "senderSessionId", + "type": 7, + "optional": false + }, + { + "name": "summary", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 64, + "optional": false + }, + { + "name": "kind", + "type": 76, + "optional": false + }, + { + "name": "senderSessionId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 7, + "optional": false + }, + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "revision", + "type": 11, + "optional": false + }, + { + "name": "round", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "messageId", + "type": 7, + "optional": false + }, + { + "name": "senderId", + "type": 7, + "optional": false + }, + { + "name": "senderName", + "type": 7, + "optional": false + }, + { + "name": "teamId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 82, + "optional": false + }, + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "replayState", + "type": 83, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "canceled" + }, + { + "kind": "union", + "types": [ + 88, + 89 + ] + }, + { + "kind": "literal", + "value": "next-step" + }, + { + "kind": "literal", + "value": "next-turn" + }, + { + "kind": "literal", + "value": "agent/inbox/spliced" + } + ] + } + }, + { + "key": "event:approval/asked", + "kind": "event", + "event": "approval/asked", + "surface": false, + "digest": "3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 2, + "optional": true + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "reason", + "type": 2, + "optional": true + }, + { + "name": "toolName", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "approval/asked" + } + ] + } + }, + { + "key": "event:approval/decided", + "kind": "event", + "event": "approval/decided", + "surface": false, + "digest": "bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 8, + "optional": true + }, + { + "name": "seq", + "type": 9, + "optional": false + }, + { + "name": "time", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "outcome", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "allowed-once" + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "rejected" + }, + { + "kind": "literal", + "value": "unavailable" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "approval/decided" + } + ] + } + }, + { + "key": "event:approval/policy", + "kind": "event", + "event": "approval/policy", + "surface": false, + "digest": "26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 7, + "optional": false + }, + { + "name": "time", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "policy", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "ask" + }, + { + "kind": "literal", + "value": "never" + }, + { + "kind": "literal", + "value": "delegation" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "approval/policy" + } + ] + } + }, + { + "key": "event:assistant/attempt", + "kind": "event", + "event": "assistant/attempt", + "surface": false, + "digest": "c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 26, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 72, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "stream", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 10, + 68, + 70 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 6, + "optional": false + }, + { + "name": "dt", + "type": 8, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 11, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 67, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 12, + 14, + 40, + 43, + 45, + 47, + 64 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 15, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 39, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 16, + 18, + 28, + 31, + 35, + 37 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "offloaded", + "type": 26, + "optional": true + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "mediaType", + "type": 20, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 25, + "optional": true + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 21, + 22, + 23, + 24 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 29, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 32, + "optional": false + }, + { + "name": "isError", + "type": 33, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 15 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 36, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 41, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 17, + 27, + 30, + 34, + 36, + 38 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 48, + "optional": false + }, + { + "name": "replayState", + "type": 60, + "optional": true + }, + { + "name": "type", + "type": 63, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 49, + 52, + 54, + 56, + 58 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "message", + "type": 7, + "optional": false + }, + { + "name": "offloadImages", + "type": 2, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 2, + "optional": true + }, + { + "name": "requestId", + "type": 7, + "optional": true + }, + { + "name": "status", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 59, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 61, + "optional": true + }, + { + "name": "response", + "type": 62, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 62 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 65, + "optional": false + }, + { + "name": "usage", + "type": 66, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 2, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 2, + "optional": true + }, + { + "name": "inputTokens", + "type": 2, + "optional": false + }, + { + "name": "outputTokens", + "type": 2, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 2, + "optional": true + }, + { + "name": "totalTokens", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 8, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "texts", + "type": 6, + "optional": false + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 69, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 8, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "texts", + "type": 6, + "optional": false + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 71, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + }, + { + "kind": "literal", + "value": "assistant/attempt" + } + ] + } + }, + { + "key": "event:assistant/message", + "kind": "event", + "event": "assistant/message", + "surface": true, + "digest": "1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 11, + "optional": false + }, + { + "name": "surfaceOp", + "type": 76, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 80, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "interrupted", + "type": 2, + "optional": true + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "step", + "type": 11, + "optional": false + }, + { + "name": "stream", + "type": 33, + "optional": false + }, + { + "name": "turn", + "type": 11, + "optional": false + }, + { + "name": "usage", + "type": 70, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "role", + "type": 29, + "optional": false + }, + { + "name": "source", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 19, + 22, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 10, + "optional": false + }, + { + "name": "offloaded", + "type": 2, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "isError", + "type": 23, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "replayState", + "type": 32, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "union", + "types": [ + 35, + 39, + 72, + 74 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 36, + "optional": false + }, + { + "name": "dt", + "type": 37, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "time0", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "array", + "element": 11 + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 40, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 71, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 41, + 43, + 45, + 48, + 50, + 52, + 68 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "type", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 5, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 46, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 47, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 8, + 18, + 21, + 24, + 26, + 28 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 49, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 51, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 53, + "optional": false + }, + { + "name": "replayState", + "type": 65, + "optional": true + }, + { + "name": "type", + "type": 67, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 54, + 57, + 59, + 61, + 63 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "message", + "type": 7, + "optional": false + }, + { + "name": "offloadImages", + "type": 11, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 11, + "optional": true + }, + { + "name": "requestId", + "type": 7, + "optional": true + }, + { + "name": "status", + "type": 11, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 58, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 60, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 62, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 64, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 66, + "optional": true + }, + { + "name": "response", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 32 + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 69, + "optional": false + }, + { + "name": "usage", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 11, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 11, + "optional": true + }, + { + "name": "inputTokens", + "type": 11, + "optional": false + }, + { + "name": "outputTokens", + "type": 11, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 11, + "optional": true + }, + { + "name": "totalTokens", + "type": 11, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 37, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "texts", + "type": 36, + "optional": false + }, + { + "name": "time0", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 73, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 37, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "texts", + "type": 36, + "optional": false + }, + { + "name": "time0", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 75, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + }, + { + "kind": "union", + "types": [ + 77, + 79 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 11, + "optional": false + }, + { + "name": "op", + "type": 78, + "optional": false + }, + { + "name": "startSeq", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "literal", + "value": "assistant/message" + } + ] + } + }, + { + "key": "event:command/done", + "kind": "event", + "event": "command/done", + "surface": false, + "digest": "15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "commandId", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "sourceEventSeq", + "type": 6, + "optional": true + }, + { + "name": "text", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "literal", + "value": "success" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "command/done" + } + ] + } + }, + { + "key": "event:command/run", + "kind": "event", + "event": "command/run", + "surface": false, + "digest": "37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 2, + "optional": true + }, + { + "name": "commandId", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "command/run" + } + ] + } + }, + { + "key": "event:compaction/end", + "kind": "event", + "event": "compaction/end", + "surface": false, + "digest": "b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 2, + "optional": false + }, + { + "name": "error", + "type": 2, + "optional": true + }, + { + "name": "sourceCommandId", + "type": 2, + "optional": true + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "compaction/end" + } + ] + } + }, + { + "key": "event:compaction/prune", + "kind": "event", + "event": "compaction/prune", + "surface": false, + "digest": "7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "shadowedRange", + "type": 2, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 4, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 3, + "optional": false + }, + { + "name": "start", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "compaction/prune" + } + ] + } + }, + { + "key": "event:compaction/start", + "kind": "event", + "event": "compaction/start", + "surface": false, + "digest": "db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 2, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 2, + "optional": true + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "compaction/start" + } + ] + } + }, + { + "key": "event:compaction/summary", + "kind": "event", + "event": "compaction/summary", + "surface": false, + "digest": "f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 32 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 3, + "optional": false + }, + { + "name": "llmStreamCall", + "type": 4, + "optional": false + }, + { + "name": "maxTokens", + "type": 5, + "optional": true + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "rawOutput", + "type": 6, + "optional": false + }, + { + "name": "shadowedRange", + "type": 29, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 30, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 5, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 3, + "optional": true + }, + { + "name": "summary", + "type": 6, + "optional": false + }, + { + "name": "usage", + "type": 31, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "union", + "types": [ + 8, + 11, + 13, + 15, + 17, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "isError", + "type": 9, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 18, + "optional": false + }, + { + "name": "offloaded", + "type": 4, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 5, + "optional": false + }, + { + "name": "height", + "type": 5, + "optional": false + }, + { + "name": "mediaType", + "type": 19, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 24, + "optional": true + }, + { + "name": "width", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 20, + 21, + 22, + 23 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 5, + "optional": false + }, + { + "name": "width", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 5, + "optional": false + }, + { + "name": "start", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 5, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 5, + "optional": true + }, + { + "name": "inputTokens", + "type": 5, + "optional": false + }, + { + "name": "outputTokens", + "type": 5, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 5, + "optional": true + }, + { + "name": "totalTokens", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 3, + "optional": false + }, + { + "name": "maxTokens", + "type": 5, + "optional": true + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "rawOutput", + "type": 6, + "optional": true + }, + { + "name": "shadowedRange", + "type": 29, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 30, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 5, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 3, + "optional": true + }, + { + "name": "summary", + "type": 6, + "optional": false + }, + { + "name": "usage", + "type": 31, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "compaction/summary" + } + ] + } + }, + { + "key": "event:deliverables/presented", + "kind": "event", + "event": "deliverables/presented", + "surface": false, + "digest": "13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 2, + "optional": false + }, + { + "name": "files", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 2, + "optional": true + }, + { + "name": "path", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "deliverables/presented" + } + ] + } + }, + { + "key": "event:feedback/message-delete", + "kind": "event", + "event": "feedback/message-delete", + "surface": false, + "digest": "3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "messageId", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "feedback/message-delete" + } + ] + } + }, + { + "key": "event:feedback/message-put", + "kind": "event", + "event": "feedback/message-put", + "surface": false, + "digest": "b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 16, + "optional": true + }, + { + "name": "seq", + "type": 11, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "item", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 3, + "optional": true + }, + { + "name": "createdAt", + "type": 11, + "optional": false + }, + { + "name": "messageId", + "type": 12, + "optional": false + }, + { + "name": "note", + "type": 12, + "optional": true + }, + { + "name": "rating", + "type": 13, + "optional": false + }, + { + "name": "updatedAt", + "type": 11, + "optional": false + }, + { + "name": "version", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "negative" + }, + { + "kind": "literal", + "value": "positive" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "feedback/message-put" + } + ] + } + }, + { + "key": "event:feedback/record", + "kind": "event", + "event": "feedback/record", + "surface": false, + "digest": "b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 11, + "optional": true + }, + { + "name": "seq", + "type": 12, + "optional": false + }, + { + "name": "time", + "type": 12, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 2, + "optional": true + }, + { + "name": "text", + "type": 10, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "feedback/record" + } + ] + } + }, + { + "key": "event:goal/change", + "kind": "event", + "event": "goal/change", + "surface": false, + "digest": "763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 23, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 9 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "cleared", + "type": 3, + "optional": false + }, + { + "name": "clearedAt", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "operation", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "revision", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "goal/change" + }, + { + "kind": "literal", + "value": "clear" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "createdAt", + "type": 5, + "optional": false + }, + { + "name": "goal", + "type": 10, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "operation", + "type": 17, + "optional": false + }, + { + "name": "roundsStarted", + "type": 5, + "optional": false + }, + { + "name": "updatedAt", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedReason", + "type": 11, + "optional": true + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "maxGoalRounds", + "type": 5, + "optional": false + }, + { + "name": "objective", + "type": 4, + "optional": false + }, + { + "name": "phase", + "type": 12, + "optional": false + }, + { + "name": "revision", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 4, + "optional": false + }, + { + "name": "message", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "paused" + }, + { + "kind": "union", + "types": [ + 15, + 18, + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "block" + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "edit" + }, + { + "kind": "literal", + "value": "pause" + }, + { + "kind": "literal", + "value": true + } + ] + } + }, + { + "key": "event:hook/invoked", + "kind": "event", + "event": "hook/invoked", + "surface": false, + "digest": "8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "dialect", + "type": 2, + "optional": false + }, + { + "name": "handlerId", + "type": 5, + "optional": false + }, + { + "name": "matcher", + "type": 5, + "optional": true + }, + { + "name": "point", + "type": 5, + "optional": false + }, + { + "name": "turn", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "claude-code" + }, + { + "kind": "literal", + "value": "codex" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "hook/invoked" + } + ] + } + }, + { + "key": "event:hook/result", + "kind": "event", + "event": "hook/result", + "surface": false, + "digest": "e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "decision", + "type": 2, + "optional": false + }, + { + "name": "durationMs", + "type": 3, + "optional": false + }, + { + "name": "exitCode", + "type": 3, + "optional": true + }, + { + "name": "handlerId", + "type": 2, + "optional": false + }, + { + "name": "point", + "type": 2, + "optional": false + }, + { + "name": "stderrSummary", + "type": 2, + "optional": true + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "hook/result" + } + ] + } + }, + { + "key": "event:image/offload", + "kind": "event", + "event": "image/offload", + "surface": false, + "digest": "b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "targets", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "imageIndexes", + "type": 4, + "optional": false + }, + { + "name": "seq", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image/offload" + } + ] + } + }, + { + "key": "event:llm/retry", + "kind": "event", + "event": "llm/retry", + "surface": false, + "digest": "525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 9, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 3, + "optional": false + }, + { + "name": "failure", + "type": 4, + "optional": false + }, + { + "name": "maxRetries", + "type": 3, + "optional": false + }, + { + "name": "mode", + "type": 6, + "optional": false + }, + { + "name": "policyKey", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "retry", + "type": 3, + "optional": false + }, + { + "name": "retryId", + "type": 5, + "optional": false + }, + { + "name": "step", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 5, + "optional": false + }, + { + "name": "message", + "type": 5, + "optional": false + }, + { + "name": "offloadImages", + "type": 3, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 3, + "optional": true + }, + { + "name": "requestId", + "type": 5, + "optional": true + }, + { + "name": "status", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "normal" + }, + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 3, + "optional": false + }, + { + "name": "failure", + "type": 4, + "optional": false + }, + { + "name": "mode", + "type": 8, + "optional": false + }, + { + "name": "policyKey", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "retry", + "type": 3, + "optional": false + }, + { + "name": "retryId", + "type": 5, + "optional": false + }, + { + "name": "step", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "always" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "llm/retry" + } + ] + } + }, + { + "key": "event:llm/retry-started", + "kind": "event", + "event": "llm/retry-started", + "surface": false, + "digest": "48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "retry", + "type": 2, + "optional": false + }, + { + "name": "retryId", + "type": 3, + "optional": false + }, + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "llm/retry-started" + } + ] + } + }, + { + "key": "event:model/selection", + "kind": "event", + "event": "model/selection", + "surface": false, + "digest": "35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "model/selection" + } + ] + } + }, + { + "key": "event:permission/preset", + "kind": "event", + "event": "permission/preset", + "surface": false, + "digest": "5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "preset", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "permission/preset" + } + ] + } + }, + { + "key": "event:plan/mode", + "kind": "event", + "event": "plan/mode", + "surface": false, + "digest": "a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "active", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "plan/mode" + } + ] + } + }, + { + "key": "event:request/context", + "kind": "event", + "event": "request/context", + "surface": false, + "digest": "37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "contextWindow", + "type": 2, + "optional": true + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "systemPromptUpdate", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "in-history" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "request/context" + } + ] + } + }, + { + "key": "event:request/header", + "kind": "event", + "event": "request/header", + "surface": false, + "digest": "8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "header", + "type": 2, + "optional": false + }, + { + "name": "reason", + "type": 13, + "optional": false + }, + { + "name": "startsSeries", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "adapterDefaults", + "type": 3, + "optional": true + }, + { + "name": "config", + "type": 5, + "optional": false + }, + { + "name": "tools", + "type": 9, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 4, + "optional": true + }, + { + "name": "reasoningEffort", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 6, + "optional": true + }, + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 7, + "optional": true + }, + { + "name": "stop", + "type": 8, + "optional": true + }, + { + "name": "temperature", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "array", + "element": 10 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "parameters", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 7, + "value": 12 + } + ] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "union", + "types": [ + 14, + 15, + 16, + 17 + ] + }, + { + "kind": "literal", + "value": "initial" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "series" + }, + { + "kind": "literal", + "value": "change" + }, + { + "kind": "literal", + "value": "request/header" + } + ] + } + }, + { + "key": "event:sandbox/mode", + "kind": "event", + "event": "sandbox/mode", + "surface": false, + "digest": "516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 8, + "optional": false + }, + { + "name": "time", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "mode", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "danger-full-access" + }, + { + "kind": "literal", + "value": "read-only" + }, + { + "kind": "literal", + "value": "workspace-write" + }, + { + "kind": "literal", + "value": "delegation" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "sandbox/mode" + } + ] + } + }, + { + "key": "event:schedule/change", + "kind": "event", + "event": "schedule/change", + "surface": false, + "digest": "2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 19, + "optional": true + }, + { + "name": "seq", + "type": 13, + "optional": false + }, + { + "name": "time", + "type": 13, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 6, + 8, + 9 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "acceptedAt", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "operation", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "dispatch" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "operation", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "delete" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "operation", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "operation", + "type": 10, + "optional": false + }, + { + "name": "schedule", + "type": 11, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "union", + "types": [ + 12, + 15, + 17 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "afterSeconds", + "type": 13, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 14, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "after" + }, + { + "kind": "object", + "properties": [ + { + "name": "everySeconds", + "type": 13, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 16, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "every" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 18, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "at" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "schedule/change" + } + ] + } + }, + { + "key": "event:session-log-deepseek/delivery-accepted", + "kind": "event", + "event": "session-log-deepseek/delivery-accepted", + "surface": false, + "digest": "d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "sessionFormatVersion", + "type": 2, + "optional": true + }, + { + "name": "sessionId", + "type": 3, + "optional": false + }, + { + "name": "throughSeq", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "session-log-deepseek/delivery-accepted" + } + ] + } + }, + { + "key": "event:session/end-seed", + "kind": "event", + "event": "session/end-seed", + "surface": false, + "digest": "5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "inherited", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "session/end-seed" + } + ] + } + }, + { + "key": "event:session/title", + "kind": "event", + "event": "session/title", + "surface": false, + "digest": "1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 13, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "messageSeqs", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 4, + "optional": false + }, + { + "name": "title", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 5, + 9, + 11 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "model", + "type": 7, + "optional": true + }, + { + "name": "provider", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "provider" + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 8, + "optional": false + }, + { + "name": "provider", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "fallback" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "session/title" + } + ] + } + }, + { + "key": "event:session/title-llm-request", + "kind": "event", + "event": "session/title-llm-request", + "surface": false, + "digest": "e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 19, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 91, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 2, + "optional": false + }, + { + "name": "messageSeqs", + "type": 3, + "optional": false + }, + { + "name": "messages", + "type": 4, + "optional": false + }, + { + "name": "route", + "type": 90, + "optional": false + }, + { + "name": "system", + "type": 9, + "optional": false + }, + { + "name": "titleProvider", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 9, + "optional": false + }, + { + "name": "role", + "type": 31, + "optional": false + }, + { + "name": "source", + "type": 35, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "union", + "types": [ + 8, + 11, + 21, + 24, + 27, + 29 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 9, + "optional": false + }, + { + "name": "id", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 12, + "optional": false + }, + { + "name": "offloaded", + "type": 19, + "optional": true + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 9, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "mediaType", + "type": 13, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": true + }, + { + "name": "originalDimensions", + "type": 18, + "optional": true + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 14, + 15, + 16, + 17 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 22, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 9, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "isError", + "type": 25, + "optional": true + }, + { + "name": "toolCallId", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "union", + "types": [ + 32, + 33, + 34 + ] + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 36, + 45, + 47, + 48, + 51, + 56, + 58, + 63, + 64, + 65, + 67, + 69, + 70, + 77, + 79, + 81, + 83, + 85, + 88, + 89 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 19, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 9, + "optional": true + }, + { + "name": "changes", + "type": 37, + "optional": false + }, + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 38 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 39, + "optional": false + }, + { + "name": "digest", + "type": 9, + "optional": true + }, + { + "name": "path", + "type": 9, + "optional": false + }, + { + "name": "scope", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 40, + 41, + 42 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 9, + "optional": false + }, + { + "name": "kind", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 9, + "optional": true + }, + { + "name": "kind", + "type": 34, + "optional": false + }, + { + "name": "rpcId", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 9, + "optional": false + }, + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + }, + { + "name": "provider", + "type": 9, + "optional": false + }, + { + "name": "ruleId", + "type": 9, + "optional": false + }, + { + "name": "source", + "type": 9, + "optional": false + }, + { + "name": "summary", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 52, + "optional": false + }, + { + "name": "form", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "update", + "type": 19, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 53 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 59, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + }, + { + "name": "sections", + "type": 61, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 62 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 9, + "optional": false + }, + { + "name": "text", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + }, + { + "name": "summary", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 66, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 68, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 66, + "optional": false + }, + { + "name": "kind", + "type": 71, + "optional": false + }, + { + "name": "references", + "type": 72, + "optional": false + }, + { + "name": "version", + "type": 76, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 73 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 2, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 74, + "optional": false + }, + { + "name": "compacted", + "type": 25, + "optional": false + }, + { + "name": "inputIndex", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 9, + "optional": false + }, + { + "name": "omittedBytes", + "type": 2, + "optional": false + }, + { + "name": "omittedMessages", + "type": 2, + "optional": false + }, + { + "name": "originalMessages", + "type": 2, + "optional": false + }, + { + "name": "retainedMessages", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 9, + "optional": false + }, + { + "name": "truncated", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 75 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "senderSessionId", + "type": 9, + "optional": false + }, + { + "name": "summary", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 68, + "optional": false + }, + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "senderSessionId", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 9, + "optional": false + }, + { + "name": "kind", + "type": 82, + "optional": false + }, + { + "name": "revision", + "type": 2, + "optional": false + }, + { + "name": "round", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 84, + "optional": false + }, + { + "name": "messageId", + "type": 9, + "optional": false + }, + { + "name": "senderId", + "type": 9, + "optional": false + }, + { + "name": "senderName", + "type": 9, + "optional": false + }, + { + "name": "teamId", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 86, + "optional": false + }, + { + "name": "model", + "type": 9, + "optional": false + }, + { + "name": "provider", + "type": 9, + "optional": false + }, + { + "name": "replayState", + "type": 87, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 9, + "optional": false + }, + { + "name": "provider", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session/title-llm-request" + } + ] + } + }, + { + "key": "event:step/end", + "kind": "event", + "event": "step/end", + "surface": false, + "digest": "e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "step/end" + } + ] + } + }, + { + "key": "event:step/start", + "kind": "event", + "event": "step/start", + "surface": false, + "digest": "4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "step/start" + } + ] + } + }, + { + "key": "event:subagent/catalog", + "kind": "event", + "event": "subagent/catalog", + "surface": false, + "digest": "ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 9, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 3, + "optional": false + }, + { + "name": "childId", + "type": 4, + "optional": false + }, + { + "name": "label", + "type": 4, + "optional": false + }, + { + "name": "mode", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "literal", + "value": 0 + }, + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 3, + "optional": false + }, + { + "name": "childId", + "type": 4, + "optional": false + }, + { + "name": "label", + "type": 4, + "optional": true + }, + { + "name": "mode", + "type": 8, + "optional": false + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "one-shot" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "subagent/catalog" + } + ] + } + }, + { + "key": "event:subagent/descriptor", + "kind": "event", + "event": "subagent/descriptor", + "surface": false, + "digest": "b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 10, + "optional": true + }, + { + "name": "seq", + "type": 7, + "optional": false + }, + { + "name": "time", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 8 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "agentModel", + "type": 3, + "optional": true + }, + { + "name": "agentProvider", + "type": 3, + "optional": true + }, + { + "name": "agentReasoningEffort", + "type": 3, + "optional": true + }, + { + "name": "label", + "type": 3, + "optional": false + }, + { + "name": "mode", + "type": 4, + "optional": false + }, + { + "name": "persona", + "type": 3, + "optional": true + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "toolFilter", + "type": 5, + "optional": true + }, + { + "name": "version", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "object", + "properties": [ + { + "name": "allow", + "type": 6, + "optional": true + }, + { + "name": "deny", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "label", + "type": 3, + "optional": true + }, + { + "name": "mode", + "type": 9, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "one-shot" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "subagent/descriptor" + } + ] + } + }, + { + "key": "event:subagent/model-selection-policy", + "kind": "event", + "event": "subagent/model-selection-policy", + "surface": false, + "digest": "a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "allowedModels", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "subagent/model-selection-policy" + } + ] + } + }, + { + "key": "event:system/message", + "kind": "event", + "event": "system/message", + "surface": true, + "digest": "69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 17, + "optional": true + }, + { + "name": "seq", + "type": 10, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 47, + "optional": true + }, + { + "name": "surfaceOp", + "type": 48, + "optional": false + }, + { + "name": "time", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 52, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "step", + "type": 10, + "optional": false + }, + { + "name": "turn", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "role", + "type": 29, + "optional": false + }, + { + "name": "source", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 8, + 19, + 22, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 9, + "optional": false + }, + { + "name": "offloaded", + "type": 17, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "mediaType", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 16, + "optional": true + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 23, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "union", + "types": [ + 31, + 36, + 38, + 40, + 42, + 44, + 46 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 32, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + }, + { + "name": "sections", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 35 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + }, + { + "name": "summary", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 41, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 10 + }, + { + "kind": "union", + "types": [ + 49, + 51 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 10, + "optional": false + }, + { + "name": "op", + "type": 50, + "optional": false + }, + { + "name": "startSeq", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "literal", + "value": "system/message" + } + ] + } + }, + { + "key": "event:team/member", + "kind": "event", + "event": "team/member", + "surface": false, + "digest": "4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 12, + "optional": true + }, + { + "name": "seq", + "type": 13, + "optional": false + }, + { + "name": "time", + "type": 13, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "member", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 6, + "optional": false + }, + { + "name": "version", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "context", + "type": 3, + "optional": false + }, + { + "name": "description", + "type": 6, + "optional": false + }, + { + "name": "error", + "type": 6, + "optional": true + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "phase", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "fork" + }, + { + "kind": "literal", + "value": "fresh" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 8, + 9, + 10 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "literal", + "value": "provisioning" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "team/member" + } + ] + } + }, + { + "key": "event:team/message/delivered", + "kind": "event", + "event": "team/message/delivered", + "surface": false, + "digest": "48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "messageId", + "type": 2, + "optional": false + }, + { + "name": "targetId", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "team/message/delivered" + } + ] + } + }, + { + "key": "event:team/message/queued", + "kind": "event", + "event": "team/message/queued", + "surface": false, + "digest": "443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 24, + "optional": true + }, + { + "name": "seq", + "type": 17, + "optional": false + }, + { + "name": "time", + "type": 17, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "senderId", + "type": 7, + "optional": false + }, + { + "name": "senderName", + "type": 7, + "optional": false + }, + { + "name": "targetId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 9, + 11, + 13, + 15, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 6, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": "team/message/queued" + } + ] + } + }, + { + "key": "event:team/task", + "kind": "event", + "event": "team/task", + "surface": false, + "digest": "d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 12, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "task", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedBy", + "type": 3, + "optional": false + }, + { + "name": "description", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "ownerId", + "type": 4, + "optional": true + }, + { + "name": "revision", + "type": 5, + "optional": false + }, + { + "name": "status", + "type": 6, + "optional": false + }, + { + "name": "subject", + "type": 4, + "optional": false + }, + { + "name": "writeScopes", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 7, + 8, + 9, + 10 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "deleted" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "team/task" + } + ] + } + }, + { + "key": "event:todo/write", + "kind": "event", + "event": "todo/write", + "surface": false, + "digest": "b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 9, + "optional": true + }, + { + "name": "seq", + "type": 10, + "optional": false + }, + { + "name": "time", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "todos", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "status", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "todo/write" + } + ] + } + }, + { + "key": "event:tool-workflow/agent-end", + "kind": "event", + "event": "tool-workflow/agent-end", + "surface": false, + "digest": "babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 8, + "optional": true + }, + { + "name": "seq", + "type": 7, + "optional": false + }, + { + "name": "time", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "outcome", + "type": 2, + "optional": false + }, + { + "name": "runId", + "type": 6, + "optional": false + }, + { + "name": "seq", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "tool-workflow/agent-end" + } + ] + } + }, + { + "key": "event:tool-workflow/agent-start", + "kind": "event", + "event": "tool-workflow/agent-start", + "surface": false, + "digest": "5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "childId", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 2, + "optional": false + }, + { + "name": "phase", + "type": 2, + "optional": true + }, + { + "name": "runId", + "type": 2, + "optional": false + }, + { + "name": "seq", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "tool-workflow/agent-start" + } + ] + } + }, + { + "key": "event:tool-workflow/run-end", + "kind": "event", + "event": "tool-workflow/run-end", + "surface": false, + "digest": "42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 8, + "optional": false + }, + { + "name": "time", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "runId", + "type": 2, + "optional": false + }, + { + "name": "stopReason", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-workflow/run-end" + } + ] + } + }, + { + "key": "event:tool-workflow/run-start", + "kind": "event", + "event": "tool-workflow/run-start", + "surface": false, + "digest": "c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "runId", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-workflow/run-start" + } + ] + } + }, + { + "key": "event:tool/call", + "kind": "event", + "event": "tool/call", + "surface": false, + "digest": "3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "callId", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "step", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "tool/call" + } + ] + } + }, + { + "key": "event:tool/ptc-dispatch", + "kind": "event", + "event": "tool/ptc-dispatch", + "surface": false, + "digest": "b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 24, + "optional": true + }, + { + "name": "seq", + "type": 17, + "optional": false + }, + { + "name": "time", + "type": 17, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "error", + "type": 29, + "optional": true + }, + { + "name": "isError", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "parentCallId", + "type": 7, + "optional": false + }, + { + "name": "rootCallId", + "type": 7, + "optional": false + }, + { + "name": "subCallId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 9, + 11, + 13, + 15, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 6, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "reason", + "type": 7, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool/ptc-dispatch" + } + ] + } + }, + { + "key": "event:tool/ptc-dispatch-start", + "kind": "event", + "event": "tool/ptc-dispatch-start", + "surface": false, + "digest": "ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "parentCallId", + "type": 3, + "optional": false + }, + { + "name": "rootCallId", + "type": 3, + "optional": false + }, + { + "name": "subCallId", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool/ptc-dispatch-start" + } + ] + } + }, + { + "key": "event:tool/result", + "kind": "event", + "event": "tool/result", + "surface": true, + "digest": "29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 24, + "optional": true + }, + { + "name": "seq", + "type": 17, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 38, + "optional": true + }, + { + "name": "surfaceOp", + "type": 39, + "optional": false + }, + { + "name": "time", + "type": 17, + "optional": false + }, + { + "name": "type", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 2, + "optional": true + }, + { + "name": "message", + "type": 4, + "optional": false + }, + { + "name": "meta", + "type": 34, + "optional": true + }, + { + "name": "step", + "type": 17, + "optional": false + }, + { + "name": "turn", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "reason", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "role", + "type": 31, + "optional": false + }, + { + "name": "source", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 6, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 7, + "optional": false + }, + { + "name": "isError", + "type": 29, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 8 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 11, + 13, + 15, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "union", + "types": [ + 3, + 17, + 29, + 35, + 36, + 37 + ] + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 3, + "value": 34 + } + ] + }, + { + "kind": "array", + "element": 17 + }, + { + "kind": "union", + "types": [ + 40, + 41 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 17, + "optional": false + }, + { + "name": "op", + "type": 42, + "optional": false + }, + { + "name": "startSeq", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "tool/result" + } + ] + } + }, + { + "key": "event:turn/end", + "kind": "event", + "event": "turn/end", + "surface": false, + "digest": "bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 29, + "optional": true + }, + { + "name": "seq", + "type": 14, + "optional": false + }, + { + "name": "time", + "type": 14, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 5, + 7, + 9, + 11, + 16 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "interrupted" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 12, + "optional": false + }, + { + "name": "kind", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 13, + "optional": false + }, + { + "name": "message", + "type": 13, + "optional": false + }, + { + "name": "offloadImages", + "type": 14, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 14, + "optional": true + }, + { + "name": "requestId", + "type": 13, + "optional": true + }, + { + "name": "status", + "type": 14, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 17, + "optional": false + }, + { + "name": "reason", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "union", + "types": [ + 19, + 21, + 23, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "reason", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "turn/end" + } + ] + } + }, + { + "key": "event:turn/start", + "kind": "event", + "event": "turn/start", + "surface": false, + "digest": "aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "turn/start" + } + ] + } + }, + { + "key": "event:user/message", + "kind": "event", + "event": "user/message", + "surface": true, + "digest": "314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 16, + "optional": true + }, + { + "name": "seq", + "type": 9, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 84, + "optional": true + }, + { + "name": "surfaceOp", + "type": 85, + "optional": false + }, + { + "name": "time", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 88, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 7, + 18, + 21, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 8, + "optional": false + }, + { + "name": "offloaded", + "type": 16, + "optional": true + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "mediaType", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 15, + "optional": true + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 11, + 12, + 13, + 14 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 22, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 30, + 39, + 41, + 42, + 45, + 50, + 52, + 57, + 58, + 59, + 61, + 63, + 64, + 71, + 73, + 75, + 77, + 79, + 82, + 83 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 16, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 5, + "optional": true + }, + { + "name": "changes", + "type": 31, + "optional": false + }, + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 32 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 33, + "optional": false + }, + { + "name": "digest", + "type": 5, + "optional": true + }, + { + "name": "path", + "type": 5, + "optional": false + }, + { + "name": "scope", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 34, + 35, + 36 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 5, + "optional": true + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "rpcId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 5, + "optional": false + }, + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 44, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "ruleId", + "type": 5, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 46, + "optional": false + }, + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 49, + "optional": false + }, + { + "name": "update", + "type": 16, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 47 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 53, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "sections", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 56 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 60, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 60, + "optional": false + }, + { + "name": "kind", + "type": 65, + "optional": false + }, + { + "name": "references", + "type": 66, + "optional": false + }, + { + "name": "version", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 67 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 9, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 68, + "optional": false + }, + { + "name": "compacted", + "type": 22, + "optional": false + }, + { + "name": "inputIndex", + "type": 9, + "optional": false + }, + { + "name": "label", + "type": 5, + "optional": false + }, + { + "name": "omittedBytes", + "type": 9, + "optional": false + }, + { + "name": "omittedMessages", + "type": 9, + "optional": false + }, + { + "name": "originalMessages", + "type": 9, + "optional": false + }, + { + "name": "retainedMessages", + "type": 9, + "optional": false + }, + { + "name": "sessionId", + "type": 5, + "optional": false + }, + { + "name": "truncated", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 9, + 69 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 72, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 74, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 76, + "optional": false + }, + { + "name": "revision", + "type": 9, + "optional": false + }, + { + "name": "round", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "messageId", + "type": 5, + "optional": false + }, + { + "name": "senderId", + "type": 5, + "optional": false + }, + { + "name": "senderName", + "type": 5, + "optional": false + }, + { + "name": "teamId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "model", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "replayState", + "type": 81, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 9 + }, + { + "kind": "union", + "types": [ + 86, + 87 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 9, + "optional": false + }, + { + "name": "op", + "type": 35, + "optional": false + }, + { + "name": "startSeq", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user/message" + } + ] + } + }, + { + "key": "event:web/deepseek-search-llm-request", + "kind": "event", + "event": "web/deepseek-search-llm-request", + "surface": false, + "digest": "cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 15, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "apiVersion", + "type": 2, + "optional": false + }, + { + "name": "body", + "type": 3, + "optional": false + }, + { + "name": "endpoint", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "max_tokens", + "type": 4, + "optional": false + }, + { + "name": "messages", + "type": 5, + "optional": false + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "tools", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 6, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 7, + "optional": false + }, + { + "name": "role", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 8, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 12, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "max_uses", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 13, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "web_search" + }, + { + "kind": "literal", + "value": "web_search_20250305" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "web/deepseek-search-llm-request" + } + ] + } + } + ], + "types": [ + { + "digest": "0116b1f89c05221d56b0ba35c83d302bf4857bc7277d247e9bbaf74b27d2c66e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "web_search_20250305" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "023a355b2be0d688fb6e4df8388dadb942761d46cfe96d0f499aae9631a159d4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "blocked" + } + ] + }, + "names": [ + "event:turn/end.data.reason[2]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "0341d4c3dfcd53253cdc1e789d9130d3cd848b6f8b0706bf92f313a68b39ff23", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "product-interaction" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "05d2ae1e0c7f8770f83f9a09047afb39a335d8ac986df3193659aa1e581472cf", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "ask" + }, + { + "kind": "literal", + "value": "never" + } + ] + }, + "names": [ + "packages/interaction/user-approval/src/index.ts#ApprovalPolicy" + ], + "sources": [ + "packages/interaction/user-approval/src/index.ts" + ] + }, + { + "digest": "0657d3ca5ac4e7bf79b00bcf860b1c7159d01a9da137497221ec2f1776e365f7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#SessionSeq" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "071d92b9dac661fcc826c678cf64d188f26fb93aab79c627b11a03acdd34dfca", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 5, + 31, + 34, + 36, + 38, + 55 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "index", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 6, + "optional": false + }, + { + "name": "index", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 7, + 9, + 19, + 22, + 26, + 28 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 10, + "optional": false + }, + { + "name": "offloaded", + "type": 17, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 3, + "optional": false + }, + { + "name": "height", + "type": 3, + "optional": false + }, + { + "name": "mediaType", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "originalDimensions", + "type": 16, + "optional": true + }, + { + "name": "width", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 3, + "optional": false + }, + { + "name": "width", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 23, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 32, + "optional": false + }, + { + "name": "index", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 8, + 18, + 21, + 25, + 27, + 29 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 3, + "optional": false + }, + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 35, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 3, + "optional": false + }, + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 37, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 39, + "optional": false + }, + { + "name": "replayState", + "type": 51, + "optional": true + }, + { + "name": "type", + "type": 54, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 40, + 43, + 45, + 47, + 49 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 41, + "optional": false + }, + { + "name": "kind", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 2, + "optional": false + }, + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "offloadImages", + "type": 3, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 3, + "optional": true + }, + { + "name": "requestId", + "type": 2, + "optional": true + }, + { + "name": "status", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 41, + "optional": false + }, + { + "name": "kind", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 48, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 50, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 52, + "optional": true + }, + { + "name": "response", + "type": 53, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 53 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 56, + "optional": false + }, + { + "name": "usage", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 3, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 3, + "optional": true + }, + { + "name": "inputTokens", + "type": 3, + "optional": false + }, + { + "name": "outputTokens", + "type": 3, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 3, + "optional": true + }, + { + "name": "totalTokens", + "type": 3, + "optional": true + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#StreamChunk" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "07e1a58c58b593f507b8e7f25723bb0aa42baae6e00f5ecfddf28cb1e64d3235", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 1, + "optional": false + }, + { + "name": "provider", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/session/session-title/src/types.ts#SessionTitleModelIdentity", + "packages/subagent/tool-subagent/src/model-selection.ts#AllowedModelRoute" + ], + "sources": [ + "packages/session/session-title/src/types.ts", + "packages/subagent/tool-subagent/src/model-selection.ts" + ] + }, + { + "digest": "07eccc9ea2f9b5439d76cc77d5e062936677d43f07a23da749819b0a22ee36b7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "security-privacy-permission" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "0a30c3be336cdd4f8f34e66543a3d46d611c43986edd9b3ce6cbb9b721d3b5d3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + }, + { + "name": "reason", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "union", + "types": [ + 3, + 5, + 7, + 10, + 12 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 8, + "optional": false + }, + { + "name": "reason", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + } + ] + }, + "names": [ + "event:turn/end.data.reason[1]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "0a8a062bc9c3c0d97fd97742262f2ea53dd32297f834e81114870d38ac3dc6da", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "subagent/model-selection-policy" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "0aa62ab51b36c0e64b134bd03ba8725d758744180a1a447da49beaad194f219f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 1, + "value": 2 + } + ] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "event:request/header.data.header.tools[0].parameters" + ], + "sources": [] + }, + { + "digest": "0acd94fe8794574c9ae72c7855ee16d29c546096d4af760d16d1225385764555", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 1, + "optional": true + }, + { + "name": "response", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ReplayEnvelope" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "0af3ecfb8c60d416fc40a7cc4fb2c4851a8e46608b2b38ab9e510670c971aa1f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "turn/start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "0b6d718c693fdf7f06dcccb0bcbbabe78cc63514eafc62d6b2a3899735279d6f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "revision", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/goal/goal/src/types.ts#GoalRef" + ], + "sources": [ + "packages/goal/goal/src/types.ts" + ] + }, + { + "digest": "0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "messageId", + "type": 1, + "optional": false + }, + { + "name": "targetId", + "type": 1, + "optional": false + }, + { + "name": "teamId", + "type": 1, + "optional": false + }, + { + "name": "version", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": 2 + } + ] + }, + "names": [ + "event:team/message/delivered.data" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "0bdaf9cb63594be4ef034b68901fffe792fe09d6d5f6bac42d7f56f6e7834fb9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "usage" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "0c3f4d2248d9bc9700e2d7253fa71aa9935f5c39af6f11de5727f08cccaf8383", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "message", + "type": 1, + "optional": false + }, + { + "name": "teamId", + "type": 6, + "optional": false + }, + { + "name": "version", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "senderId", + "type": 6, + "optional": false + }, + { + "name": "senderName", + "type": 6, + "optional": false + }, + { + "name": "targetId", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 8, + 10, + 12, + 14, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 5, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 15, + "optional": false + }, + { + "name": "offloaded", + "type": 23, + "optional": true + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 16, + "optional": false + }, + { + "name": "height", + "type": 16, + "optional": false + }, + { + "name": "mediaType", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 22, + "optional": true + }, + { + "name": "width", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 18, + 19, + 20, + 21 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 16, + "optional": false + }, + { + "name": "width", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 26, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": 2 + } + ] + }, + "names": [ + "event:team/message/queued.data" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "0c6412d3ba5e41adfaa6929c7d4093f2d52d8598c03f35844fc0d55e3070a3b1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 1, + "optional": false + }, + { + "name": "stream", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 9, + 67, + 69 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 5, + "optional": false + }, + { + "name": "dt", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "time0", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 1 + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 10, + "optional": false + }, + { + "name": "time", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 66, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 11, + 13, + 39, + 42, + 44, + 46, + 63 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 14, + "optional": false + }, + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 15, + 17, + 27, + 30, + 34, + 36 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 18, + "optional": false + }, + { + "name": "offloaded", + "type": 25, + "optional": true + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 1, + "optional": false + }, + { + "name": "height", + "type": 1, + "optional": false + }, + { + "name": "mediaType", + "type": 19, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 24, + "optional": true + }, + { + "name": "width", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 20, + 21, + 22, + 23 + ] + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 1, + "optional": false + }, + { + "name": "width", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 28, + "optional": false + }, + { + "name": "type", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 31, + "optional": false + }, + { + "name": "isError", + "type": 32, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 14 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 35, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 37, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 40, + "optional": false + }, + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 41, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 16, + 26, + 29, + 33, + 35, + 37 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 45, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 47, + "optional": false + }, + { + "name": "replayState", + "type": 59, + "optional": true + }, + { + "name": "type", + "type": 62, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 48, + 51, + 53, + 55, + 57 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 6, + "optional": false + }, + { + "name": "message", + "type": 6, + "optional": false + }, + { + "name": "offloadImages", + "type": 1, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 1, + "optional": true + }, + { + "name": "requestId", + "type": 6, + "optional": true + }, + { + "name": "status", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 52, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 54, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 56, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 58, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 60, + "optional": true + }, + { + "name": "response", + "type": 61, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 61 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 64, + "optional": false + }, + { + "name": "usage", + "type": 65, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 1, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 1, + "optional": true + }, + { + "name": "inputTokens", + "type": 1, + "optional": false + }, + { + "name": "outputTokens", + "type": 1, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 1, + "optional": true + }, + { + "name": "totalTokens", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "texts", + "type": 5, + "optional": false + }, + { + "name": "time0", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 68, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "texts", + "type": 5, + "optional": false + }, + { + "name": "time0", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + } + ] + }, + "names": [ + "event:assistant/attempt.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "0d47a8f3d847243c4488e755ad4cab7a04ac5d4621b9c81865524cf3f4d8536f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "allowedModels", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:subagent/model-selection-policy.data" + ], + "sources": [ + "packages/subagent/tool-subagent/src/model-selection-state.ts" + ] + }, + { + "digest": "0ddab4577db37a3e0d9e3a91761735c8ef6f5629d526ab8ecaeeea19c097c8f8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + }, + { + "name": "plugin", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[1]", + "event:system/message.data.message.source[0]" + ], + "sources": [] + }, + { + "digest": "0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 1, + "optional": false + }, + { + "name": "childId", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 2, + "optional": false + }, + { + "name": "mode", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "literal", + "value": 0 + } + ] + }, + "names": [ + "event:subagent/catalog.data[1]" + ], + "sources": [] + }, + { + "digest": "0e7b2a97f54f1afdb8cdfad1635abe9145327db539bfb69b4045c19d8c17755d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "schedule/change" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "0f46153645c297846a3fad3911636659ca4717a5e7d71c9f50bffacd312115ef", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 1, + "optional": false + }, + { + "name": "width", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].content[0][2].attachment.originalDimensions" + ], + "sources": [ + "packages/attachment/attachment/src/types.ts" + ] + }, + { + "digest": "10e386801903f9d424602c31d3ff837a94aef623c8b391376d8d9e253525fabe", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "compaction/prune" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 11, + "optional": false + }, + { + "name": "surfaceOp", + "type": 76, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 80, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "interrupted", + "type": 2, + "optional": true + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "step", + "type": 11, + "optional": false + }, + { + "name": "stream", + "type": 33, + "optional": false + }, + { + "name": "turn", + "type": 11, + "optional": false + }, + { + "name": "usage", + "type": 70, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "role", + "type": 29, + "optional": false + }, + { + "name": "source", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 19, + 22, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 10, + "optional": false + }, + { + "name": "offloaded", + "type": 2, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "isError", + "type": 23, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "replayState", + "type": 32, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "union", + "types": [ + 35, + 39, + 72, + 74 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 36, + "optional": false + }, + { + "name": "dt", + "type": 37, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "time0", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "array", + "element": 11 + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 40, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 71, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 41, + 43, + 45, + 48, + 50, + 52, + 68 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "type", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 5, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 46, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 47, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 8, + 18, + 21, + 24, + 26, + 28 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 49, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 51, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 53, + "optional": false + }, + { + "name": "replayState", + "type": 65, + "optional": true + }, + { + "name": "type", + "type": 67, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 54, + 57, + 59, + 61, + 63 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "message", + "type": 7, + "optional": false + }, + { + "name": "offloadImages", + "type": 11, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 11, + "optional": true + }, + { + "name": "requestId", + "type": 7, + "optional": true + }, + { + "name": "status", + "type": 11, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 58, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 60, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 62, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 64, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 66, + "optional": true + }, + { + "name": "response", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 32 + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 69, + "optional": false + }, + { + "name": "usage", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 11, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 11, + "optional": true + }, + { + "name": "inputTokens", + "type": 11, + "optional": false + }, + { + "name": "outputTokens", + "type": 11, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 11, + "optional": true + }, + { + "name": "totalTokens", + "type": 11, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 37, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "texts", + "type": 36, + "optional": false + }, + { + "name": "time0", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 73, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 37, + "optional": false + }, + { + "name": "index", + "type": 11, + "optional": false + }, + { + "name": "texts", + "type": 36, + "optional": false + }, + { + "name": "time0", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 75, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + }, + { + "kind": "union", + "types": [ + 77, + 79 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 11, + "optional": false + }, + { + "name": "op", + "type": 78, + "optional": false + }, + { + "name": "startSeq", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "literal", + "value": "assistant/message" + } + ] + }, + "names": [ + "event:assistant/message" + ], + "sources": [] + }, + { + "digest": "119abe2b9c0b2f46ecb31d82b9acba4d4b30e049f655e2475e8b4ae12d5a9e25", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "dialect", + "type": 1, + "optional": false + }, + { + "name": "handlerId", + "type": 4, + "optional": false + }, + { + "name": "matcher", + "type": 4, + "optional": true + }, + { + "name": "point", + "type": 4, + "optional": false + }, + { + "name": "turn", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "claude-code" + }, + { + "kind": "literal", + "value": "codex" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:hook/invoked.data" + ], + "sources": [ + "packages/hooks/hook-protocol/src/types.ts" + ] + }, + { + "digest": "11f70b595aa76897fc4e25a352bfa718c659f44b799e5aa14e84e5a38fe72912", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "policy", + "type": 1, + "optional": false + }, + { + "name": "source", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "ask" + }, + { + "kind": "literal", + "value": "never" + }, + { + "kind": "literal", + "value": "delegation" + } + ] + }, + "names": [ + "event:approval/policy.data" + ], + "sources": [ + "packages/interaction/user-approval/src/index.ts" + ] + }, + { + "digest": "12a0cfa619ac4a5fc6c3e8e359c8dae15769edc61497a575935c78d5842f8e42", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "read-only" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "12d5808fac1996b9b3c2afa806e03022252ba2d7b88f835862ae1896591f60c7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 1, + "optional": false + }, + { + "name": "offloaded", + "type": 10, + "optional": true + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 3, + "optional": false + }, + { + "name": "height", + "type": 3, + "optional": false + }, + { + "name": "mediaType", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "originalDimensions", + "type": 9, + "optional": true + }, + { + "name": "width", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 5, + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 3, + "optional": false + }, + { + "name": "width", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ImageBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": 3 + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 2, + "optional": false + }, + { + "name": "files", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 2, + "optional": true + }, + { + "name": "path", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "deliverables/presented" + } + ] + }, + "names": [ + "event:deliverables/presented" + ], + "sources": [] + }, + { + "digest": "14230f9b8b5797bb7e8c621fa636531cfbde2ffba1ef5f1fd058216ff21952a0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "chunk" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "142c37d302aa22a0a57915b5255939d3ca91c1811ca13fddcf84cf76ea00758a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "always" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "commandId", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "sourceEventSeq", + "type": 6, + "optional": true + }, + { + "name": "text", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "literal", + "value": "success" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "command/done" + } + ] + }, + "names": [ + "event:command/done" + ], + "sources": [] + }, + { + "digest": "1528539c63db8b23506f0209a99ce77d8ad138adfbfcee3d4769b7382d93756c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 1, + "optional": false + }, + { + "name": "files", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 1, + "optional": true + }, + { + "name": "path", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:deliverables/presented.data" + ], + "sources": [ + "packages/fs/tool-present/src/types.ts" + ] + }, + { + "digest": "15495614ccfa9cbdeefb0ec2abd76406435f4c6ff3dae42acae8e09ef42025c9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "codex" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1571525adc95a24e5d25b5a6440df401cd7cdd881b745178e85f5a333435cd1b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "never" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "16d0507cb94b4cfc84a87446b1ba7652d6ec1d65ee1684789e747e30d542800e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "relay" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "17aae616ef020b8b9f011ec398ec935450fb06d3e2a0722c456f63aeaf5ff728", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "at" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "inherited", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + } + ] + }, + "names": [ + "event:session/end-seed.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "18dc21f12bbac8ade8377e6fbb54179e20c3d955d73fba3244c57fb6bf001df0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "operation", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "delete" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#ScheduleDeleteChange" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 2, + "optional": false + }, + { + "name": "cwd", + "type": 1, + "optional": true + }, + { + "name": "delegationDepth", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "isSeeded", + "type": 3, + "optional": false + }, + { + "name": "origin", + "type": 4, + "optional": true + }, + { + "name": "parentSession", + "type": 1, + "optional": true + }, + { + "name": "type", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "subagent" + }, + { + "kind": "literal", + "value": "session" + } + ] + }, + "names": [ + "packages/session/session-persistence-jsonl/src/format.ts#HeaderLine" + ], + "sources": [ + "packages/session/session-persistence-jsonl/src/format.ts" + ] + }, + { + "digest": "18fcdd273a2f2f9d813a3be5e71df5903a963a5c88e46b90b14de6e2db890da0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "team/member" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "18fce9540bb20897a66275499faee6b8296c97e9901fa1ff45a191772448ad1a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "danger-full-access" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1922cd79a70806c17758185a6ef0458bc1fb3900363906733421c16414da2509", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "skill-invocation" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1986c2664009c99155e44795676c887fa67f7c55cd2d5e6b648ff763e0ab033a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "compaction/end" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1a2718b00937b236a0d0910ef5dab2f9f8b65e4bde410cc21f15fbbf29f584d3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "deliverables/presented" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1ab2ef1296f157ba96998f179bb5daa9d21a82480da2901127aeab2730797c92", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "literal", + "value": "success" + } + ] + }, + "names": [ + "event:command/done.data.kind" + ], + "sources": [] + }, + { + "digest": "1b5649238876e28811e80f10ec67a00c197ad3babd4ecc61a22b09064b88c597", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "fallback" + } + ] + }, + "names": [ + "event:session/title.data.source[0]" + ], + "sources": [ + "packages/session/session-title/src/types.ts" + ] + }, + { + "digest": "1b573e2d5c094fa87e2a8bf409ddd4ac5ba92a123085e168de44b9ccdbd5244c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 2, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 26, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 2, + 5, + 8, + 10, + 12, + 23 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 13, + "optional": false + }, + { + "name": "offloaded", + "type": 21, + "optional": true + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 14, + "optional": false + }, + { + "name": "height", + "type": 14, + "optional": false + }, + { + "name": "mediaType", + "type": 15, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 20, + "optional": true + }, + { + "name": "width", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 16, + 17, + 18, + 19 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 14, + "optional": false + }, + { + "name": "width", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 24, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 14, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 6, + "optional": false + }, + { + "name": "kind", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#ToolResultMessage" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 13, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "messageSeqs", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 4, + "optional": false + }, + { + "name": "title", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 5, + 9, + 11 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "model", + "type": 7, + "optional": true + }, + { + "name": "provider", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "provider" + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 8, + "optional": false + }, + { + "name": "provider", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "fallback" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "session/title" + } + ] + }, + "names": [ + "event:session/title" + ], + "sources": [] + }, + { + "digest": "1c2686c0682e7bc51d61117b2652bd4a80707e331aa276d6ef915ae32534a330", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "session/end-seed" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1c5a58f4599bd4a9711712551ffe2442a5e5fcd0758bafe630cc4ead850bdaa7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "system/message" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1cde1bedde79c5e8a56aee9c05c8e0a579cf5bc611deb85b93fa331a16ca978f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "imageIndexes", + "type": 1, + "optional": false + }, + { + "name": "seq", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/compaction/compaction-image-offload/src/projection.ts#ImageOffloadTarget" + ], + "sources": [ + "packages/compaction/compaction-image-offload/src/projection.ts" + ] + }, + { + "digest": "1d5f04a03ea75fc8eeece544129eba0f49f0c82046e9c404461920390135c7b2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "model/selection" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1d76406cbb2ddadb0dbbb51e9d8bc6cf678fed455cf8eb512f36f7c86d37a62f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6].reason[3]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "1d8798b1a5e8c545ee4dcd2b4e75c0b4c9ffd985e4744c6d1a1aab992f859721", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "pause" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1d9cb3caa96100b18b1911fa3ff8c751ef6992971a03c5f4d9aefc1a0004a345", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 2, + "optional": true + }, + { + "name": "path", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:deliverables/presented.data.files" + ], + "sources": [] + }, + { + "digest": "1df34a6c086866ffdc2dd9e8e5c581c3751a010cdf6b8538a7327f7a3237f0b4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "createdAt", + "type": 1, + "optional": false + }, + { + "name": "goal", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 10, + "optional": false + }, + { + "name": "operation", + "type": 11, + "optional": false + }, + { + "name": "roundsStarted", + "type": 1, + "optional": false + }, + { + "name": "updatedAt", + "type": 1, + "optional": false + }, + { + "name": "version", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedReason", + "type": 3, + "optional": true + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "maxGoalRounds", + "type": 1, + "optional": false + }, + { + "name": "objective", + "type": 4, + "optional": false + }, + { + "name": "phase", + "type": 5, + "optional": false + }, + { + "name": "revision", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 4, + "optional": false + }, + { + "name": "message", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 6, + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "paused" + }, + { + "kind": "literal", + "value": "goal/change" + }, + { + "kind": "union", + "types": [ + 8, + 12, + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "block" + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "literal", + "value": "edit" + }, + { + "kind": "literal", + "value": "pause" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/goal/goal/src/domain.ts#GoalSnapshotChangeMeta" + ], + "sources": [ + "packages/goal/goal/src/domain.ts" + ] + }, + { + "digest": "1e0b0b66b6f0c53fc72e52289d06b4708d776f1ca9df4c86a22bff621d403cf0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "aborted" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1e346446e183ee76f48d7994c97ecb302bddc682abb60b8a10ea0bb26223a69c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "block" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1ebc6f9ff3aa9e3a38f8695f49bacdab1f8b7a3832741853ca46f40af56ccd01", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "completed" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1f0133217eeeffd8d387baf1ec8ed9856e719bcd999dc08e48624cba96d75fd7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-call" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "1f8c126cfab3df812cd115cfc23e3256f0fa2383400f4ce91ecad313577e59b0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 4, + 6, + 8, + 10 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "reason", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#TurnEndCancelCause" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "2074f40221b76c75fd314246db558965dc3477dfb440bcc952b1eedc9778e366", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "message", + "type": 1, + "optional": false + }, + { + "name": "step", + "type": 9, + "optional": false + }, + { + "name": "turn", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 7, + 18, + 21, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 8, + "optional": false + }, + { + "name": "offloaded", + "type": 16, + "optional": true + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "mediaType", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 15, + "optional": true + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 11, + 12, + 13, + 14 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 22, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "union", + "types": [ + 30, + 35, + 37, + 39, + 41, + 43, + 45 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 31, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "sections", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 36, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 38, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 40, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 44, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 32, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:system/message.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "active", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + } + ] + }, + "names": [ + "event:plan/mode.data" + ], + "sources": [ + "packages/plan/plan-mode/src/index.ts" + ] + }, + { + "digest": "2142e391b9ccb60d487afcf373ce74db98d952f69e8289eddb352a7e16e996c5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "cancelled" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + }, + { + "name": "messageId", + "type": 2, + "optional": false + }, + { + "name": "senderId", + "type": 2, + "optional": false + }, + { + "name": "senderName", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/experimental/agent-team/src/types.ts#TeamMessageSource" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "234142ee4f996f38cc9fa3b8b3e3de29b03c9aefe5ebf6c224eddd564505aa85", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "237c004c73b6b288246816e0d7fde16e09c63a47aa3b1227383d7afe58666163", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "goal/change" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "23c7cce57d20589897f4e2bd5898affc6fc611b87cd0cc8b95be1cfdd8b3a7eb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "role", + "type": 27, + "optional": false + }, + { + "name": "source", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 3, + 6, + 17, + 20, + 23, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 7, + "optional": false + }, + { + "name": "offloaded", + "type": 15, + "optional": true + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 8, + "optional": false + }, + { + "name": "height", + "type": 8, + "optional": false + }, + { + "name": "mediaType", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "originalDimensions", + "type": 14, + "optional": true + }, + { + "name": "width", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 10, + 11, + 12, + 13 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 8, + "optional": false + }, + { + "name": "width", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 18, + "optional": false + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 8, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "isError", + "type": 21, + "optional": true + }, + { + "name": "toolCallId", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "union", + "types": [ + 28, + 29, + 30 + ] + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 32, + 41, + 43, + 44, + 47, + 52, + 54, + 59, + 60, + 61, + 63, + 65, + 66, + 73, + 75, + 77, + 79, + 81, + 84, + 85 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 15, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 4, + "optional": true + }, + { + "name": "changes", + "type": 33, + "optional": false + }, + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 35, + "optional": false + }, + { + "name": "digest", + "type": 4, + "optional": true + }, + { + "name": "path", + "type": 4, + "optional": false + }, + { + "name": "scope", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 36, + 37, + 38 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 4, + "optional": false + }, + { + "name": "kind", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 4, + "optional": true + }, + { + "name": "kind", + "type": 30, + "optional": false + }, + { + "name": "rpcId", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 4, + "optional": false + }, + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 46, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + }, + { + "name": "ruleId", + "type": 4, + "optional": false + }, + { + "name": "source", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 48, + "optional": false + }, + { + "name": "form", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + }, + { + "name": "update", + "type": 15, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 49 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "sections", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 58 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "text", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 64, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 67, + "optional": false + }, + { + "name": "references", + "type": 68, + "optional": false + }, + { + "name": "version", + "type": 72, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 69 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 8, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 70, + "optional": false + }, + { + "name": "compacted", + "type": 21, + "optional": false + }, + { + "name": "inputIndex", + "type": 8, + "optional": false + }, + { + "name": "label", + "type": 4, + "optional": false + }, + { + "name": "omittedBytes", + "type": 8, + "optional": false + }, + { + "name": "omittedMessages", + "type": 8, + "optional": false + }, + { + "name": "originalMessages", + "type": 8, + "optional": false + }, + { + "name": "retainedMessages", + "type": 8, + "optional": false + }, + { + "name": "sessionId", + "type": 4, + "optional": false + }, + { + "name": "truncated", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 8, + 71 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 74, + "optional": false + }, + { + "name": "senderSessionId", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 64, + "optional": false + }, + { + "name": "kind", + "type": 76, + "optional": false + }, + { + "name": "senderSessionId", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 4, + "optional": false + }, + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "revision", + "type": 8, + "optional": false + }, + { + "name": "round", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "messageId", + "type": 4, + "optional": false + }, + { + "name": "senderId", + "type": 4, + "optional": false + }, + { + "name": "senderName", + "type": 4, + "optional": false + }, + { + "name": "teamId", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 82, + "optional": false + }, + { + "name": "model", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + }, + { + "name": "replayState", + "type": 83, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 30, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#Message" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "23cf7e0cf3fec1283b60fa15713506169bc9c079a08e124d1cb9733baca80b40", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 7, + 9, + 11, + 13, + 15, + 17 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "sections", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "text", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 8, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 10, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 12, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 14, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 16, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:system/message.data.message.source" + ], + "sources": [] + }, + { + "digest": "2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "apiVersion", + "type": 1, + "optional": false + }, + { + "name": "body", + "type": 2, + "optional": false + }, + { + "name": "endpoint", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "max_tokens", + "type": 3, + "optional": false + }, + { + "name": "messages", + "type": 4, + "optional": false + }, + { + "name": "model", + "type": 1, + "optional": false + }, + { + "name": "tools", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 5, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "role", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 7, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 11, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "max_uses", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 12, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "web_search" + }, + { + "kind": "literal", + "value": "web_search_20250305" + } + ] + }, + "names": [ + "packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest" + ], + "sources": [ + "packages/web/web-search-deepseek/src/provider.ts" + ] + }, + { + "digest": "254dce209e735f9cb6f6b7aec0354712b1611759ec02af4d35a96f2081e666f6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "blocked" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 7, + "optional": false + }, + { + "name": "time", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "policy", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "ask" + }, + { + "kind": "literal", + "value": "never" + }, + { + "kind": "literal", + "value": "delegation" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "approval/policy" + } + ] + }, + "names": [ + "event:approval/policy" + ], + "sources": [] + }, + { + "digest": "26c879bdd130e8b8683a6ce588414fad2244783d6573ca399fa0de184a2b0bb1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "dispatch" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "26f3bb7529cfce1e3a0f1ededa365d8b426758ca0feeb0beabeee805f8bb8346", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "union", + "types": [ + 2, + 8, + 66, + 68 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 3, + "optional": false + }, + { + "name": "dt", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "time0", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 9, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 65, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 10, + 12, + 38, + 41, + 43, + 45, + 62 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 13, + "optional": false + }, + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 37, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 14, + 16, + 26, + 29, + 33, + 35 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 17, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 6, + "optional": false + }, + { + "name": "height", + "type": 6, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 6, + "optional": false + }, + { + "name": "width", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 30, + "optional": false + }, + { + "name": "isError", + "type": 31, + "optional": true + }, + { + "name": "toolCallId", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 13 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 36, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 39, + "optional": false + }, + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 15, + 25, + 28, + 32, + 34, + 36 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 46, + "optional": false + }, + { + "name": "replayState", + "type": 58, + "optional": true + }, + { + "name": "type", + "type": 61, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 47, + 50, + 52, + 54, + 56 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 49, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 4, + "optional": false + }, + { + "name": "message", + "type": 4, + "optional": false + }, + { + "name": "offloadImages", + "type": 6, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 6, + "optional": true + }, + { + "name": "requestId", + "type": 4, + "optional": true + }, + { + "name": "status", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 53, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 59, + "optional": true + }, + { + "name": "response", + "type": 60, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 60 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 63, + "optional": false + }, + { + "name": "usage", + "type": 64, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 6, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 6, + "optional": true + }, + { + "name": "inputTokens", + "type": 6, + "optional": false + }, + { + "name": "outputTokens", + "type": 6, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 6, + "optional": true + }, + { + "name": "totalTokens", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 5, + "optional": false + }, + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "texts", + "type": 3, + "optional": false + }, + { + "name": "time0", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 67, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 5, + "optional": false + }, + { + "name": "index", + "type": 6, + "optional": false + }, + { + "name": "texts", + "type": 3, + "optional": false + }, + { + "name": "time0", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 69, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream", + "event:assistant/message.data.stream" + ], + "sources": [] + }, + { + "digest": "2765e9119edf5816ac1ab4c95c5ee32c90403f3742962eff11544f7752d59d2e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "model" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "277b61f9c6f8170425fa6ffe06cfa14376757a896a4749cb82a687d7364c4fc9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "file" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "27e337d3d6b402b221e50c247a3f518a70d0c474cc60beee15fac3e9c5cbfcbe", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "afterSeconds", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "prompt", + "type": 2, + "optional": false + }, + { + "name": "scheduledAt", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "after" + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#AfterScheduleRecord" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "287211846beea1eccb5f9acee00d20388a38fcb2e95858fa2332d6f58529379a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6].reason[4]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 24, + "optional": true + }, + { + "name": "seq", + "type": 17, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 38, + "optional": true + }, + { + "name": "surfaceOp", + "type": 39, + "optional": false + }, + { + "name": "time", + "type": 17, + "optional": false + }, + { + "name": "type", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 2, + "optional": true + }, + { + "name": "message", + "type": 4, + "optional": false + }, + { + "name": "meta", + "type": 34, + "optional": true + }, + { + "name": "step", + "type": 17, + "optional": false + }, + { + "name": "turn", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "reason", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "role", + "type": 31, + "optional": false + }, + { + "name": "source", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 6, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 7, + "optional": false + }, + { + "name": "isError", + "type": 29, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 8 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 11, + 13, + 15, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "union", + "types": [ + 3, + 17, + 29, + 35, + 36, + 37 + ] + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 3, + "value": 34 + } + ] + }, + { + "kind": "array", + "element": 17 + }, + { + "kind": "union", + "types": [ + 40, + 41 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 17, + "optional": false + }, + { + "name": "op", + "type": 42, + "optional": false + }, + { + "name": "startSeq", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "tool/result" + } + ] + }, + "names": [ + "event:tool/result" + ], + "sources": [] + }, + { + "digest": "2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 19, + "optional": true + }, + { + "name": "seq", + "type": 13, + "optional": false + }, + { + "name": "time", + "type": 13, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 6, + 8, + 9 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "acceptedAt", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "operation", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "dispatch" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "operation", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "delete" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "operation", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "operation", + "type": 10, + "optional": false + }, + { + "name": "schedule", + "type": 11, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "union", + "types": [ + 12, + 15, + 17 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "afterSeconds", + "type": 13, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 14, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "after" + }, + { + "kind": "object", + "properties": [ + { + "name": "everySeconds", + "type": 13, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 16, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "every" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 18, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "at" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "schedule/change" + } + ] + }, + "names": [ + "event:schedule/change" + ], + "sources": [] + }, + { + "digest": "2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 2, + "optional": false + }, + { + "name": "cwd", + "type": 1, + "optional": true + }, + { + "name": "delegationDepth", + "type": 2, + "optional": true + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "isSeeded", + "type": 3, + "optional": false + }, + { + "name": "origin", + "type": 4, + "optional": true + }, + { + "name": "parentSession", + "type": 1, + "optional": true + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "subagent" + }, + { + "kind": "literal", + "value": 3 + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#SessionHeader" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "2ab12a0e345658f9342816d773fe610f049982bcad82631f43b9205abe43e5ee", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 2, + "optional": false + }, + { + "name": "digest", + "type": 6, + "optional": true + }, + { + "name": "path", + "type": 6, + "optional": false + }, + { + "name": "scope", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[16].changes" + ], + "sources": [] + }, + { + "digest": "2abb711460e6238d851c30f3e4bdd87a2aa1887ee70575b3d3b7b25610673095", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning-delta" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[2]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "2aed07493b1c65b6d00de5586da1e743cf501684b9ad43a1765fb4007d4ea456", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool/ptc-dispatch-start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "2c4c21f19f426a58f2dac914e34313aa43f8408972de857a486d1f086d5adb6c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "unavailable" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "2c64d4bc7264fd3f8bed47e96ab8a593bce05a1e4e1c436dcd244a3b7e0c2a9d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "step/start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "2ce7ef3b3daebf95815c7ae454a751d3e67ca7a22e2e0734fe2942df393bb66c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[6]", + "event:system/message.data.message.source[5]" + ], + "sources": [] + }, + { + "digest": "2d11ca7b0d4493e244b74eba093227866b33249841e59a1e9bf56afed38604c3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "max_uses", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "web_search" + }, + { + "kind": "literal", + "value": "web_search_20250305" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body.tools[0]" + ], + "sources": [ + "packages/web/web-search-deepseek/src/provider.ts" + ] + }, + { + "digest": "2da725e554cd89301d829ed9dc45a572c3cd1b93b5e91d0d71f007976d8a0863", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "fork" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "2e4debca12f2c449f96dc6574f3fbf2fb346193443114a241d01a236362ec48c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "team-message" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "2f0aefb72ab453c4bf21a6687f436775d359dc6f8f10410fd4c0615b20bd9d76", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "header", + "type": 1, + "optional": false + }, + { + "name": "reason", + "type": 12, + "optional": false + }, + { + "name": "startsSeries", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "adapterDefaults", + "type": 2, + "optional": true + }, + { + "name": "config", + "type": 4, + "optional": false + }, + { + "name": "tools", + "type": 8, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 3, + "optional": true + }, + { + "name": "reasoningEffort", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 5, + "optional": true + }, + { + "name": "model", + "type": 6, + "optional": false + }, + { + "name": "provider", + "type": 6, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 6, + "optional": true + }, + { + "name": "stop", + "type": 7, + "optional": true + }, + { + "name": "temperature", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "array", + "element": 9 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "parameters", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 6, + "value": 11 + } + ] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "series" + }, + { + "kind": "literal", + "value": "change" + }, + { + "kind": "literal", + "value": "initial" + } + ] + }, + "names": [ + "event:request/header.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "2f1e6a7ebace43d727ae138ddcd352eb3813960009e5805b8c5ac84300c97716", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + } + ] + }, + "names": [ + "packages/attachment/attachment/src/types.ts#ImageMediaType" + ], + "sources": [ + "packages/attachment/attachment/src/types.ts" + ] + }, + { + "digest": "2f90a7b3646fea3e677bd7b4000aa96f3b8964f107b614e204e11ad4051c24fc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[3]", + "event:system/message.data.message.source[2]" + ], + "sources": [] + }, + { + "digest": "2fe5026daf14bd4ff2b7bfb7cf9791c302d9cbba06802178b6dfec00b892698f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "parentCallId", + "type": 2, + "optional": false + }, + { + "name": "rootCallId", + "type": 2, + "optional": false + }, + { + "name": "subCallId", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/core/tools/src/types.ts#PtcDispatchStartEventData" + ], + "sources": [ + "packages/core/tools/src/types.ts" + ] + }, + { + "digest": "300341f890f7b9506a1749fff4fa5239d16ea1c63ff6b15851acb03c20f3b48d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 7, + 18, + 21, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 8, + "optional": false + }, + { + "name": "offloaded", + "type": 16, + "optional": true + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "mediaType", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 15, + "optional": true + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 11, + 12, + 13, + 14 + ] + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 22, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 30, + 39, + 41, + 42, + 45, + 50, + 52, + 57, + 58, + 59, + 61, + 63, + 64, + 71, + 73, + 75, + 77, + 79, + 82, + 83 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 16, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 5, + "optional": true + }, + { + "name": "changes", + "type": 31, + "optional": false + }, + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 32 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 33, + "optional": false + }, + { + "name": "digest", + "type": 5, + "optional": true + }, + { + "name": "path", + "type": 5, + "optional": false + }, + { + "name": "scope", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 34, + 35, + 36 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 5, + "optional": true + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "rpcId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 5, + "optional": false + }, + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 44, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "ruleId", + "type": 5, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 46, + "optional": false + }, + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 49, + "optional": false + }, + { + "name": "update", + "type": 16, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 47 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 53, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "sections", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 56 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 60, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 60, + "optional": false + }, + { + "name": "kind", + "type": 65, + "optional": false + }, + { + "name": "references", + "type": 66, + "optional": false + }, + { + "name": "version", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 67 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 9, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 68, + "optional": false + }, + { + "name": "compacted", + "type": 22, + "optional": false + }, + { + "name": "inputIndex", + "type": 9, + "optional": false + }, + { + "name": "label", + "type": 5, + "optional": false + }, + { + "name": "omittedBytes", + "type": 9, + "optional": false + }, + { + "name": "omittedMessages", + "type": 9, + "optional": false + }, + { + "name": "originalMessages", + "type": 9, + "optional": false + }, + { + "name": "retainedMessages", + "type": 9, + "optional": false + }, + { + "name": "sessionId", + "type": 5, + "optional": false + }, + { + "name": "truncated", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 9, + 69 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 72, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 74, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 76, + "optional": false + }, + { + "name": "revision", + "type": 9, + "optional": false + }, + { + "name": "round", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "messageId", + "type": 5, + "optional": false + }, + { + "name": "senderId", + "type": 5, + "optional": false + }, + { + "name": "senderName", + "type": 5, + "optional": false + }, + { + "name": "teamId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "model", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "replayState", + "type": 81, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 28, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted" + ], + "sources": [] + }, + { + "digest": "302b01ddddcbb3b16cfa3fba2a5d99f5082a55fbd9dc5c83a179a228b8a6a0ca", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "role", + "type": 27, + "optional": false + }, + { + "name": "source", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 3, + 6, + 17, + 20, + 23, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 7, + "optional": false + }, + { + "name": "offloaded", + "type": 15, + "optional": true + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 8, + "optional": false + }, + { + "name": "height", + "type": 8, + "optional": false + }, + { + "name": "mediaType", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "originalDimensions", + "type": 14, + "optional": true + }, + { + "name": "width", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 10, + 11, + 12, + 13 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 8, + "optional": false + }, + { + "name": "width", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 18, + "optional": false + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 8, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "isError", + "type": 21, + "optional": true + }, + { + "name": "toolCallId", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "union", + "types": [ + 29, + 34, + 36, + 38, + 40, + 42, + 44 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 30, + "optional": false + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "sections", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 33 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "text", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 35, + "optional": false + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 41, + "optional": false + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#SystemMessage" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "30d5a537b296685770b1241c4b4bbde19d5a31ff81aa23df73fab5e90b8fc65f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 5, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "model", + "type": 3, + "optional": true + }, + { + "name": "provider", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "provider" + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "fallback" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "packages/session/session-title/src/types.ts#SessionTitleSource" + ], + "sources": [ + "packages/session/session-title/src/types.ts" + ] + }, + { + "digest": "314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 16, + "optional": true + }, + { + "name": "seq", + "type": 9, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 84, + "optional": true + }, + { + "name": "surfaceOp", + "type": 85, + "optional": false + }, + { + "name": "time", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 88, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 7, + 18, + 21, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 8, + "optional": false + }, + { + "name": "offloaded", + "type": 16, + "optional": true + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "mediaType", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 15, + "optional": true + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 11, + 12, + 13, + 14 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 22, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 30, + 39, + 41, + 42, + 45, + 50, + 52, + 57, + 58, + 59, + 61, + 63, + 64, + 71, + 73, + 75, + 77, + 79, + 82, + 83 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 16, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 5, + "optional": true + }, + { + "name": "changes", + "type": 31, + "optional": false + }, + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 32 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 33, + "optional": false + }, + { + "name": "digest", + "type": 5, + "optional": true + }, + { + "name": "path", + "type": 5, + "optional": false + }, + { + "name": "scope", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 34, + 35, + 36 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 5, + "optional": true + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "rpcId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 5, + "optional": false + }, + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 44, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "ruleId", + "type": 5, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 46, + "optional": false + }, + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 49, + "optional": false + }, + { + "name": "update", + "type": 16, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 47 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 53, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "sections", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 56 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 60, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 60, + "optional": false + }, + { + "name": "kind", + "type": 65, + "optional": false + }, + { + "name": "references", + "type": 66, + "optional": false + }, + { + "name": "version", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 67 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 9, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 68, + "optional": false + }, + { + "name": "compacted", + "type": 22, + "optional": false + }, + { + "name": "inputIndex", + "type": 9, + "optional": false + }, + { + "name": "label", + "type": 5, + "optional": false + }, + { + "name": "omittedBytes", + "type": 9, + "optional": false + }, + { + "name": "omittedMessages", + "type": 9, + "optional": false + }, + { + "name": "originalMessages", + "type": 9, + "optional": false + }, + { + "name": "retainedMessages", + "type": 9, + "optional": false + }, + { + "name": "sessionId", + "type": 5, + "optional": false + }, + { + "name": "truncated", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 9, + 69 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 72, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 74, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 76, + "optional": false + }, + { + "name": "revision", + "type": 9, + "optional": false + }, + { + "name": "round", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "messageId", + "type": 5, + "optional": false + }, + { + "name": "senderId", + "type": 5, + "optional": false + }, + { + "name": "senderName", + "type": 5, + "optional": false + }, + { + "name": "teamId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "model", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "replayState", + "type": 81, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 9 + }, + { + "kind": "union", + "types": [ + 86, + 87 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 9, + "optional": false + }, + { + "name": "op", + "type": 35, + "optional": false + }, + { + "name": "startSeq", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user/message" + } + ] + }, + "names": [ + "event:user/message" + ], + "sources": [] + }, + { + "digest": "326a9bfda27dda5882fb3cbe6e715df41dae2298fdae3d66437457268a665693", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 1, + "optional": true + }, + { + "name": "reasoningEffort", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + } + ] + }, + "names": [ + "packages/llm/llm/src/call-config.ts#LlmCallConfigAdapterDefaults" + ], + "sources": [ + "packages/llm/llm/src/call-config.ts" + ] + }, + { + "digest": "3305a4bb6b6c29b482ba91d59c60b47e8f98282d3dacc8c29e4a4c2712209bdd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + } + ] + }, + "names": [ + "event:feedback/message-put.data.item.category", + "event:feedback/record.data.category" + ], + "sources": [] + }, + { + "digest": "335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 3, + "optional": false + }, + { + "name": "op", + "type": 4, + "optional": false + }, + { + "name": "startSeq", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "replace" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#SurfaceOp" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "34d1ab5c5df378186d6054b1a1beea9a41e41965d6f336f0bc0025c441a82e66", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "resume" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "model/selection" + } + ] + }, + "names": [ + "event:model/selection" + ], + "sources": [] + }, + { + "digest": "356aad27134a0e31af67c994ff8b9e4b91acfb6c4917b3bc1f7a62bbf82794d5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 1, + "optional": true + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "meta", + "type": 33, + "optional": true + }, + { + "name": "step", + "type": 16, + "optional": false + }, + { + "name": "turn", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "reason", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "role", + "type": 30, + "optional": false + }, + { + "name": "source", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 5, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "isError", + "type": 28, + "optional": true + }, + { + "name": "toolCallId", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "union", + "types": [ + 5, + 8, + 10, + 12, + 14, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 15, + "optional": false + }, + { + "name": "offloaded", + "type": 23, + "optional": true + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 16, + "optional": false + }, + { + "name": "height", + "type": 16, + "optional": false + }, + { + "name": "mediaType", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "originalDimensions", + "type": 22, + "optional": true + }, + { + "name": "width", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 18, + 19, + 20, + 21 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 16, + "optional": false + }, + { + "name": "width", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 26, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "union", + "types": [ + 2, + 16, + 28, + 34, + 35, + 36 + ] + }, + { + "kind": "array", + "element": 33 + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 2, + "value": 33 + } + ] + } + ] + }, + "names": [ + "event:tool/result.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "36d6a9a871d949ea4f3edd919d81d66aa69218bebef38899d2a1282c39420a1f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "approval/policy" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 2, + "optional": true + }, + { + "name": "commandId", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "command/run" + } + ] + }, + "names": [ + "event:command/run" + ], + "sources": [] + }, + { + "digest": "374fdd68aee5ff844e378c0cbdd961d247a0f22e4ade0bb03d800cd2a46a2b8b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 1, + "optional": false + }, + { + "name": "failure", + "type": 2, + "optional": false + }, + { + "name": "mode", + "type": 4, + "optional": false + }, + { + "name": "policyKey", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "retry", + "type": 1, + "optional": false + }, + { + "name": "retryId", + "type": 3, + "optional": false + }, + { + "name": "step", + "type": 1, + "optional": false + }, + { + "name": "turn", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "offloadImages", + "type": 1, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 1, + "optional": true + }, + { + "name": "requestId", + "type": 3, + "optional": true + }, + { + "name": "status", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "always" + } + ] + }, + "names": [ + "event:llm/retry.data[1]" + ], + "sources": [ + "packages/llm/llm-retry/src/types.ts" + ] + }, + { + "digest": "378f90f9f6022a0991928a1eaf7991094ea1920fe89a9248358a1da106e1a970", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "approval/decided" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "contextWindow", + "type": 2, + "optional": true + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "systemPromptUpdate", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "in-history" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "request/context" + } + ] + }, + "names": [ + "event:request/context" + ], + "sources": [] + }, + { + "digest": "383cf73ae4748e5beb281ae74857ba1ffb92ae01075b9fbf51af78b666007a8f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "recall" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "3860b4757d512a2869be833acb0faf834335b1b056bf3f83df5474dce95f8fa6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 1, + "optional": false + }, + { + "name": "dt", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "index", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "time0", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-call-chunks" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][2]" + ], + "sources": [ + "packages/llm/llm/src/assistant-stream.ts" + ] + }, + { + "digest": "390eed1028aba02774f14408647acec10ec5516e97d4f15ecde2b9989d5a69f2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "negative" + }, + { + "kind": "literal", + "value": "positive" + } + ] + }, + "names": [ + "packages/feedback/message-feedback/src/types.ts#MessageFeedbackRating" + ], + "sources": [ + "packages/feedback/message-feedback/src/types.ts" + ] + }, + { + "digest": "3aa261c8516b5c955ed12080e6257a56cbe513f6c9f0ac9274c12e96c196ebca", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 1, + "optional": false + }, + { + "name": "maxTokens", + "type": 2, + "optional": true + }, + { + "name": "model", + "type": 1, + "optional": false + }, + { + "name": "provider", + "type": 1, + "optional": false + }, + { + "name": "rawOutput", + "type": 3, + "optional": true + }, + { + "name": "shadowedRange", + "type": 27, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 28, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 2, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 1, + "optional": true + }, + { + "name": "summary", + "type": 3, + "optional": false + }, + { + "name": "usage", + "type": 29, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 8, + 10, + 12, + 14, + 24 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 6, + "optional": true + }, + { + "name": "toolCallId", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 15, + "optional": false + }, + { + "name": "offloaded", + "type": 22, + "optional": true + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 1, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "mediaType", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": true + }, + { + "name": "originalDimensions", + "type": 21, + "optional": true + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 17, + 18, + 19, + 20 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 25, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 1, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 2, + "optional": false + }, + { + "name": "start", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 2, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 2, + "optional": true + }, + { + "name": "inputTokens", + "type": 2, + "optional": false + }, + { + "name": "outputTokens", + "type": 2, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 2, + "optional": true + }, + { + "name": "totalTokens", + "type": 2, + "optional": true + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:compaction/summary.data[1]" + ], + "sources": [] + }, + { + "digest": "3ac1196f59d5e9e0e9345122c8c403b102478b526404a2e591a38f613483321e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 6 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 2, + "optional": false + }, + { + "name": "childId", + "type": 3, + "optional": false + }, + { + "name": "label", + "type": 3, + "optional": false + }, + { + "name": "mode", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "literal", + "value": 0 + }, + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 2, + "optional": false + }, + { + "name": "childId", + "type": 3, + "optional": false + }, + { + "name": "label", + "type": 3, + "optional": true + }, + { + "name": "mode", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "one-shot" + } + ] + }, + "names": [ + "packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent" + ], + "sources": [ + "packages/subagent/subagent/src/catalog.ts" + ] + }, + { + "digest": "3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "callId", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "step", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "tool/call" + } + ] + }, + "names": [ + "event:tool/call" + ], + "sources": [] + }, + { + "digest": "3bc287e765d58dc3a22672a0495a6cfd561220dd38fbaecef80aa95b96caed79", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "normal" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "3bd652ebfa8726b3ce3937a4f1bd2759e02f86b3a08a20f9e41a8513656fbc5f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:compaction/end.data.turn", + "event:compaction/start.data.turn", + "packages/core/session/src/types.ts#OptionalSessionSeq" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 2, + "optional": true + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "reason", + "type": 2, + "optional": true + }, + { + "name": "toolName", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "approval/asked" + } + ] + }, + "names": [ + "event:approval/asked" + ], + "sources": [] + }, + { + "digest": "3c2535ca0a2062f172f15344f8040755002b5ac506cf94fc4ebaa822b15feb8c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "reasoning" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "allow", + "type": 1, + "optional": true + }, + { + "name": "deny", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/core/tools/src/index.ts#ToolRestriction" + ], + "sources": [ + "packages/core/tools/src/index.ts" + ] + }, + { + "digest": "3d7d07060a7be77984feb651ea2bf1925d3e0477911d9d3ed86330d1e8ca6182", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 9, + "optional": false + }, + { + "name": "messageId", + "type": 10, + "optional": false + }, + { + "name": "note", + "type": 10, + "optional": true + }, + { + "name": "rating", + "type": 11, + "optional": false + }, + { + "name": "updatedAt", + "type": 9, + "optional": false + }, + { + "name": "version", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 12, + 13 + ] + }, + { + "kind": "literal", + "value": "negative" + }, + { + "kind": "literal", + "value": "positive" + } + ] + }, + "names": [ + "packages/feedback/message-feedback/src/types.ts#MessageFeedbackItem" + ], + "sources": [ + "packages/feedback/message-feedback/src/types.ts" + ] + }, + { + "digest": "3e0eff5946255ff05d88a10839c60305135801f97794ea48d409f8503303317e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "request/header" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "3e2ece4967cfebe95f450a93f45523dff99d6749f6269f2f60f84dfecfcf3693", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "next-step" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "3e4e7683b0192c9f0e6a75c59076108f017892cdb302a98032c2632fd79c356f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 1, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 1, + "optional": true + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:compaction/start.data" + ], + "sources": [ + "packages/compaction/compaction/src/types.ts" + ] + }, + { + "digest": "3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "messageId", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "feedback/message-delete" + } + ] + }, + "names": [ + "event:feedback/message-delete" + ], + "sources": [] + }, + { + "digest": "3f74ba74acd10644c1ed6947a411d8088bd2cfac74f61bb8540f96d68e31f004", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "image/jpeg" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 8, + "optional": false + }, + { + "name": "time", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "runId", + "type": 2, + "optional": false + }, + { + "name": "stopReason", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-workflow/run-end" + } + ] + }, + "names": [ + "event:tool-workflow/run-end" + ], + "sources": [] + }, + { + "digest": "4312134fc6f9cad507c31390bd3d147535492dd77621ec517c5e85f853d53a03", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "turn/end" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 24, + "optional": true + }, + { + "name": "seq", + "type": 17, + "optional": false + }, + { + "name": "time", + "type": 17, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "senderId", + "type": 7, + "optional": false + }, + { + "name": "senderName", + "type": 7, + "optional": false + }, + { + "name": "targetId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 9, + 11, + 13, + 15, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 6, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": "team/message/queued" + } + ] + }, + "names": [ + "event:team/message/queued" + ], + "sources": [] + }, + { + "digest": "44818000e56acb97afdb5045ce235eb55e3fb1ccabc9fc7d0750bb38f36a7f8e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "feedback/message-delete" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "44c8c77aa9aa100b0d74d2deee85474b29faa6eee0ac0f662f7abe9931ddd7f2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "subagent/catalog" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "step/start" + } + ] + }, + "names": [ + "event:step/start" + ], + "sources": [] + }, + { + "digest": "45f2a07ea94573123b6ae14db787a40062dec3834f36d8be92c523d40ba28448", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 1, + "optional": true + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "reason", + "type": 1, + "optional": true + }, + { + "name": "toolName", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:approval/asked.data" + ], + "sources": [ + "packages/interaction/user-approval/src/types.ts" + ] + }, + { + "digest": "477614bca595a9e7adb5a1870be446b9a8684f3ba8950259d6289f2d3b74f028", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "targets", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "object", + "properties": [ + { + "name": "imageIndexes", + "type": 3, + "optional": false + }, + { + "name": "seq", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:image/offload.data" + ], + "sources": [ + "packages/compaction/compaction-image-offload/src/projection.ts" + ] + }, + { + "digest": "478738df7e7d2b103b09fb937817a9302c81076809f2b341169e00a9419c5665", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 32, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 7, + 18, + 21, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 8, + "optional": false + }, + { + "name": "offloaded", + "type": 16, + "optional": true + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "mediaType", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 15, + "optional": true + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 11, + 12, + 13, + 14 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 9, + "optional": false + }, + { + "name": "width", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 22, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "union", + "types": [ + 29, + 30, + 31 + ] + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 33, + 42, + 44, + 45, + 48, + 53, + 55, + 60, + 61, + 62, + 64, + 66, + 67, + 74, + 76, + 78, + 80, + 82, + 85, + 86 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 16, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 5, + "optional": true + }, + { + "name": "changes", + "type": 34, + "optional": false + }, + { + "name": "form", + "type": 40, + "optional": false + }, + { + "name": "kind", + "type": 41, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 35 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 36, + "optional": false + }, + { + "name": "digest", + "type": 5, + "optional": true + }, + { + "name": "path", + "type": 5, + "optional": false + }, + { + "name": "scope", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 37, + 38, + 39 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 5, + "optional": true + }, + { + "name": "kind", + "type": 31, + "optional": false + }, + { + "name": "rpcId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 5, + "optional": false + }, + { + "name": "form", + "type": 46, + "optional": false + }, + { + "name": "kind", + "type": 47, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "ruleId", + "type": 5, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 49, + "optional": false + }, + { + "name": "form", + "type": 51, + "optional": false + }, + { + "name": "kind", + "type": 52, + "optional": false + }, + { + "name": "update", + "type": 16, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 50 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 40, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 56, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "sections", + "type": 58, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 59 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 46, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 40, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 63, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 65, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 51, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 63, + "optional": false + }, + { + "name": "kind", + "type": 68, + "optional": false + }, + { + "name": "references", + "type": 69, + "optional": false + }, + { + "name": "version", + "type": 73, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 70 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 9, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 71, + "optional": false + }, + { + "name": "compacted", + "type": 22, + "optional": false + }, + { + "name": "inputIndex", + "type": 9, + "optional": false + }, + { + "name": "label", + "type": 5, + "optional": false + }, + { + "name": "omittedBytes", + "type": 9, + "optional": false + }, + { + "name": "omittedMessages", + "type": 9, + "optional": false + }, + { + "name": "originalMessages", + "type": 9, + "optional": false + }, + { + "name": "retainedMessages", + "type": 9, + "optional": false + }, + { + "name": "sessionId", + "type": 5, + "optional": false + }, + { + "name": "truncated", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 9, + 72 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 46, + "optional": false + }, + { + "name": "kind", + "type": 75, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + }, + { + "name": "summary", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 65, + "optional": false + }, + { + "name": "kind", + "type": 77, + "optional": false + }, + { + "name": "senderSessionId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 79, + "optional": false + }, + { + "name": "revision", + "type": 9, + "optional": false + }, + { + "name": "round", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 81, + "optional": false + }, + { + "name": "messageId", + "type": 5, + "optional": false + }, + { + "name": "senderId", + "type": 5, + "optional": false + }, + { + "name": "senderName", + "type": 5, + "optional": false + }, + { + "name": "teamId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 83, + "optional": false + }, + { + "name": "model", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "replayState", + "type": 84, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "plugin", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 31, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:session/title-llm-request.data.messages" + ], + "sources": [] + }, + { + "digest": "47e5d84f1a93450a78c7f3954b43990d0f629af7c034a56313e5deb63e772c1b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "session-log-deepseek/delivery-accepted" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "retry", + "type": 2, + "optional": false + }, + { + "name": "retryId", + "type": 3, + "optional": false + }, + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "llm/retry-started" + } + ] + }, + "names": [ + "event:llm/retry-started" + ], + "sources": [] + }, + { + "digest": "48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "messageId", + "type": 2, + "optional": false + }, + { + "name": "targetId", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "team/message/delivered" + } + ] + }, + "names": [ + "event:team/message/delivered" + ], + "sources": [] + }, + { + "digest": "4a9bef9f27a942520cc2279ca7dd3082556e4bff543f66b5c0333e1bbed1cd86", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "senderSessionId", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/subagent/subagent/src/continuation-messages.ts#AgentMessageSource" + ], + "sources": [ + "packages/subagent/subagent/src/continuation-messages.ts" + ] + }, + { + "digest": "4ae007ed190a72c92138b22d059b83208079c7551ca13fb59ae8cf5e23693964", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "llm/retry-started" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "4aed17ec726b5397c29f6cb4bcd7905dc1a12bb6140f1657f073cd24380f2af8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "tuple", + "elements": [ + { + "type": 1, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "max_uses", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "web_search" + }, + { + "kind": "literal", + "value": "web_search_20250305" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body.tools" + ], + "sources": [] + }, + { + "digest": "4b7ddaf3710b88ff9b8df66304f5f97bf03688fd19730eedc2e9535203c820ea", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "status", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [ + "event:todo/write.data.todos" + ], + "sources": [] + }, + { + "digest": "4bb451330ff699f36b45539ceb0eb2606ead72084e2c5bb637c36cc80e2252db", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + } + ] + }, + "names": [ + "event:turn/end.data.reason[1].reason[3]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "4c965666d5b42116945bc356087cd5e1fd549e6dece560785ed60511059a8283", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 12, + 14, + 16, + 19, + 24, + 26, + 31, + 32, + 34, + 35, + 36, + 38, + 47, + 49, + 51, + 53, + 55, + 58, + 59 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 2, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 3, + "optional": true + }, + { + "name": "changes", + "type": 4, + "optional": false + }, + { + "name": "form", + "type": 10, + "optional": false + }, + { + "name": "kind", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 6, + "optional": false + }, + { + "name": "digest", + "type": 3, + "optional": true + }, + { + "name": "path", + "type": 3, + "optional": false + }, + { + "name": "scope", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 3, + "optional": true + }, + { + "name": "kind", + "type": 15, + "optional": false + }, + { + "name": "rpcId", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 3, + "optional": false + }, + { + "name": "form", + "type": 17, + "optional": false + }, + { + "name": "kind", + "type": 18, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "ruleId", + "type": 3, + "optional": false + }, + { + "name": "source", + "type": 3, + "optional": false + }, + { + "name": "summary", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 20, + "optional": false + }, + { + "name": "form", + "type": 22, + "optional": false + }, + { + "name": "kind", + "type": 23, + "optional": false + }, + { + "name": "update", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 21 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 10, + "optional": false + }, + { + "name": "kind", + "type": 25, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 27, + "optional": false + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + }, + { + "name": "sections", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 30 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "text", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 17, + "optional": false + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + }, + { + "name": "summary", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 33, + "optional": false + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 22, + "optional": false + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 10, + "optional": false + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 39, + "optional": false + }, + { + "name": "references", + "type": 40, + "optional": false + }, + { + "name": "version", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 41 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 42, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 43, + "optional": false + }, + { + "name": "compacted", + "type": 45, + "optional": false + }, + { + "name": "inputIndex", + "type": 42, + "optional": false + }, + { + "name": "label", + "type": 3, + "optional": false + }, + { + "name": "omittedBytes", + "type": 42, + "optional": false + }, + { + "name": "omittedMessages", + "type": 42, + "optional": false + }, + { + "name": "originalMessages", + "type": 42, + "optional": false + }, + { + "name": "retainedMessages", + "type": 42, + "optional": false + }, + { + "name": "sessionId", + "type": 3, + "optional": false + }, + { + "name": "truncated", + "type": 45, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 42, + 44 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 17, + "optional": false + }, + { + "name": "kind", + "type": 48, + "optional": false + }, + { + "name": "senderSessionId", + "type": 3, + "optional": false + }, + { + "name": "summary", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 33, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + }, + { + "name": "senderSessionId", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 52, + "optional": false + }, + { + "name": "revision", + "type": 42, + "optional": false + }, + { + "name": "round", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "messageId", + "type": 3, + "optional": false + }, + { + "name": "senderId", + "type": 3, + "optional": false + }, + { + "name": "senderName", + "type": 3, + "optional": false + }, + { + "name": "teamId", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "replayState", + "type": 57, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 15, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#MessageSource" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/api/session-controller/src/types.ts#SessionRequestId", + "packages/attachment/attachment/src/brand.ts#AttachmentId", + "packages/compaction/compaction/src/brand.ts#CompactionId", + "packages/core/session/src/types.ts#SessionId", + "packages/experimental/agent-team/src/types.ts#TeamId", + "packages/experimental/agent-team/src/types.ts#TeamMessageId", + "packages/experimental/agent-team/src/types.ts#TeamTaskId", + "packages/feedback/message-feedback/src/types.ts#MessageFeedbackVersion", + "packages/goal/goal/src/types.ts#GoalId", + "packages/interaction/commands/src/brand.ts#CommandId", + "packages/interaction/user-approval/src/types.ts#ApprovalRequestId", + "packages/llm/llm-retry/src/brand.ts#RetryId", + "packages/llm/llm/src/brand.ts#MessageId", + "packages/llm/llm/src/brand.ts#ProviderRequestId", + "packages/llm/llm/src/brand.ts#ReasoningEffortId", + "packages/llm/llm/src/brand.ts#ToolCallId", + "packages/schedule/schedule/src/types.ts#ScheduleId", + "packages/session/session-title/src/index.ts#SessionTitleProviderId", + "packages/session/session-title/src/types.ts#SessionTitleProviderId", + "packages/webhook/webhook/src/brand.ts#WebhookDeliveryId", + "packages/webhook/webhook/src/brand.ts#WebhookRuleId", + "packages/webhook/webhook/src/brand.ts#WebhookSourceId", + "packages/workflow/workflow/src/types.ts#WorkflowRunId" + ], + "sources": [ + "packages/api/session-controller/src/types.ts", + "packages/attachment/attachment/src/brand.ts", + "packages/compaction/compaction/src/brand.ts", + "packages/core/session/src/types.ts", + "packages/experimental/agent-team/src/types.ts", + "packages/feedback/message-feedback/src/types.ts", + "packages/goal/goal/src/types.ts", + "packages/interaction/commands/src/brand.ts", + "packages/interaction/user-approval/src/types.ts", + "packages/llm/llm-retry/src/brand.ts", + "packages/llm/llm/src/brand.ts", + "packages/schedule/schedule/src/types.ts", + "packages/session/session-title/src/index.ts", + "packages/session/session-title/src/types.ts", + "packages/webhook/webhook/src/brand.ts", + "packages/workflow/workflow/src/types.ts" + ] + }, + { + "digest": "4de5e7644130ed715ef6b5a4d86a87b30dca4096d1a6683c66acf6f7809379c7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "role", + "type": 27, + "optional": false + }, + { + "name": "source", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 3, + 6, + 17, + 20, + 23, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 7, + "optional": false + }, + { + "name": "offloaded", + "type": 15, + "optional": true + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 8, + "optional": false + }, + { + "name": "height", + "type": 8, + "optional": false + }, + { + "name": "mediaType", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "originalDimensions", + "type": 14, + "optional": true + }, + { + "name": "width", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 10, + 11, + 12, + 13 + ] + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 8, + "optional": false + }, + { + "name": "width", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 18, + "optional": false + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 8, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "isError", + "type": 21, + "optional": true + }, + { + "name": "toolCallId", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 29, + 38, + 40, + 41, + 44, + 49, + 51, + 56, + 57, + 58, + 60, + 62, + 63, + 70, + 72, + 74, + 76, + 78, + 81, + 82 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 15, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 4, + "optional": true + }, + { + "name": "changes", + "type": 30, + "optional": false + }, + { + "name": "form", + "type": 36, + "optional": false + }, + { + "name": "kind", + "type": 37, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 31 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 32, + "optional": false + }, + { + "name": "digest", + "type": 4, + "optional": true + }, + { + "name": "path", + "type": 4, + "optional": false + }, + { + "name": "scope", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 33, + 34, + 35 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 4, + "optional": false + }, + { + "name": "kind", + "type": 39, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 4, + "optional": true + }, + { + "name": "kind", + "type": 27, + "optional": false + }, + { + "name": "rpcId", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 4, + "optional": false + }, + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 43, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + }, + { + "name": "ruleId", + "type": 4, + "optional": false + }, + { + "name": "source", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 45, + "optional": false + }, + { + "name": "form", + "type": 47, + "optional": false + }, + { + "name": "kind", + "type": 48, + "optional": false + }, + { + "name": "update", + "type": 15, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 46 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 36, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 52, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "sections", + "type": 54, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 55 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "text", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 36, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 59, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 61, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 47, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 59, + "optional": false + }, + { + "name": "kind", + "type": 64, + "optional": false + }, + { + "name": "references", + "type": 65, + "optional": false + }, + { + "name": "version", + "type": 69, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 66 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 8, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 67, + "optional": false + }, + { + "name": "compacted", + "type": 21, + "optional": false + }, + { + "name": "inputIndex", + "type": 8, + "optional": false + }, + { + "name": "label", + "type": 4, + "optional": false + }, + { + "name": "omittedBytes", + "type": 8, + "optional": false + }, + { + "name": "omittedMessages", + "type": 8, + "optional": false + }, + { + "name": "originalMessages", + "type": 8, + "optional": false + }, + { + "name": "retainedMessages", + "type": 8, + "optional": false + }, + { + "name": "sessionId", + "type": 4, + "optional": false + }, + { + "name": "truncated", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 8, + 68 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 71, + "optional": false + }, + { + "name": "senderSessionId", + "type": 4, + "optional": false + }, + { + "name": "summary", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 61, + "optional": false + }, + { + "name": "kind", + "type": 73, + "optional": false + }, + { + "name": "senderSessionId", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 4, + "optional": false + }, + { + "name": "kind", + "type": 75, + "optional": false + }, + { + "name": "revision", + "type": 8, + "optional": false + }, + { + "name": "round", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 77, + "optional": false + }, + { + "name": "messageId", + "type": 4, + "optional": false + }, + { + "name": "senderId", + "type": 4, + "optional": false + }, + { + "name": "senderName", + "type": 4, + "optional": false + }, + { + "name": "teamId", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 79, + "optional": false + }, + { + "name": "model", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + }, + { + "name": "replayState", + "type": 80, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "plugin", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 27, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#UserMessage" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "4e011753f8263f436efaabfbb3b4db53a98fc55342c5ded2daf7208b217be159", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "team/message/queued" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "4e44c9118152f6829634bfd508e47669ab0497caffa380c94b4be91f9390d35d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "text" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "4e887768586528565381dadbddee6cef555874148089f4579e0b4b1ad096fc9c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body.messages[0].content[0]", + "packages/llm/llm/src/types.ts#TextBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts", + "packages/web/web-search-deepseek/src/provider.ts" + ] + }, + { + "digest": "4e97c3d85c0fc817ee58873c38c25a2474abaaa0af4839311b50b68db3b8cf1a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "senderSessionId", + "type": 3, + "optional": false + }, + { + "name": "summary", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/subagent/subagent/src/continuation-messages.ts#SubagentSettledMessageSource" + ], + "sources": [ + "packages/subagent/subagent/src/continuation-messages.ts" + ] + }, + { + "digest": "4f507598cf476214aa7646ce7841a7064a9dcb05d0a1eaaefaf79c2b738f160f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "series" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "4f91f187baeabef5c7950c4780d31bbe39f3345dff591a6cf26ac7e135ac1cf4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 1, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 2, + "optional": false + }, + { + "name": "compacted", + "type": 4, + "optional": false + }, + { + "name": "inputIndex", + "type": 1, + "optional": false + }, + { + "name": "label", + "type": 5, + "optional": false + }, + { + "name": "omittedBytes", + "type": 1, + "optional": false + }, + { + "name": "omittedMessages", + "type": 1, + "optional": false + }, + { + "name": "originalMessages", + "type": 1, + "optional": false + }, + { + "name": "retainedMessages", + "type": 1, + "optional": false + }, + { + "name": "sessionId", + "type": 5, + "optional": false + }, + { + "name": "truncated", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 1, + 3 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[15].references[0]" + ], + "sources": [ + "packages/context/session-reference/src/types.ts" + ] + }, + { + "digest": "4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 12, + "optional": true + }, + { + "name": "seq", + "type": 13, + "optional": false + }, + { + "name": "time", + "type": 13, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "member", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 6, + "optional": false + }, + { + "name": "version", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "context", + "type": 3, + "optional": false + }, + { + "name": "description", + "type": 6, + "optional": false + }, + { + "name": "error", + "type": 6, + "optional": true + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "phase", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "fork" + }, + { + "kind": "literal", + "value": "fresh" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 8, + 9, + 10 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "literal", + "value": "provisioning" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "team/member" + } + ] + }, + "names": [ + "event:team/member" + ], + "sources": [] + }, + { + "digest": "50cf02d875f8a1f1411f4a6fbcffab9120ccef5f74a47331fbf29480e5f68f48", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "fork" + }, + { + "kind": "literal", + "value": "fresh" + } + ] + }, + "names": [ + "event:team/member.data.member.context" + ], + "sources": [] + }, + { + "digest": "511801b0a6470d98566e8385d3dffddb2b67f79fcf73ed6056f46c3cc0a245a7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "success" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 8, + "optional": false + }, + { + "name": "time", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "mode", + "type": 2, + "optional": false + }, + { + "name": "source", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "danger-full-access" + }, + { + "kind": "literal", + "value": "read-only" + }, + { + "kind": "literal", + "value": "workspace-write" + }, + { + "kind": "literal", + "value": "delegation" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "sandbox/mode" + } + ] + }, + "names": [ + "event:sandbox/mode" + ], + "sources": [] + }, + { + "digest": "51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "blockedBy", + "type": 1, + "optional": false + }, + { + "name": "description", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "ownerId", + "type": 2, + "optional": true + }, + { + "name": "revision", + "type": 3, + "optional": false + }, + { + "name": "status", + "type": 4, + "optional": false + }, + { + "name": "subject", + "type": 2, + "optional": false + }, + { + "name": "writeScopes", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 5, + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "deleted" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [ + "packages/experimental/agent-team/src/types.ts#TeamTaskSnapshot" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 9, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 3, + "optional": false + }, + { + "name": "failure", + "type": 4, + "optional": false + }, + { + "name": "maxRetries", + "type": 3, + "optional": false + }, + { + "name": "mode", + "type": 6, + "optional": false + }, + { + "name": "policyKey", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "retry", + "type": 3, + "optional": false + }, + { + "name": "retryId", + "type": 5, + "optional": false + }, + { + "name": "step", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 5, + "optional": false + }, + { + "name": "message", + "type": 5, + "optional": false + }, + { + "name": "offloadImages", + "type": 3, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 3, + "optional": true + }, + { + "name": "requestId", + "type": 5, + "optional": true + }, + { + "name": "status", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "normal" + }, + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 3, + "optional": false + }, + { + "name": "failure", + "type": 4, + "optional": false + }, + { + "name": "mode", + "type": 8, + "optional": false + }, + { + "name": "policyKey", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "retry", + "type": 3, + "optional": false + }, + { + "name": "retryId", + "type": 5, + "optional": false + }, + { + "name": "step", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "always" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "llm/retry" + } + ] + }, + "names": [ + "event:llm/retry" + ], + "sources": [] + }, + { + "digest": "529e0ccd0e34079ab4ff21ed87f810cee0388246263bf22e8aba5986b56fae05", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 1, + "value": 2 + } + ] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 0, + 1, + 3, + 4, + 5, + 6 + ] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:tool/result.data.meta[5][0][6]", + "event:tool/result.data.meta[6]" + ], + "sources": [ + "packages/util/values/src/index.ts" + ] + }, + { + "digest": "530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "change" + }, + { + "kind": "literal", + "value": "initial" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "series" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#RequestHeaderReason" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "557e148d30b79ee48645850832b30c717d7c3b64641deb5d6133b8b4e91ee0b8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "agent-preset/selected" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "interrupted" + } + ] + }, + "names": [ + "event:turn/end.data.reason[5]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "570e85022434613394418ad33e77e9f1f7a05699b33d0b62eae0677a638c3833", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool/result" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 10, + 11 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 4, + "optional": true + }, + { + "name": "surfaceOp", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 3, + "optional": false + }, + { + "name": "op", + "type": 8, + "optional": false + }, + { + "name": "startSeq", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "surfaceOp", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "SessionEventEnvelope" + ], + "sources": [] + }, + { + "digest": "57f3f606ff8b6c84d9c443faace9d1dd10cca0354f37a4f515ef075f7c351b90", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "stop" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5808e36c95355f0e745201b5db1b6bcec4ebf5adb75d3e82d7d59cc89635ab80", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 3, + 5, + 10, + 12 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 6, + "optional": false + }, + { + "name": "kind", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "message", + "type": 7, + "optional": false + }, + { + "name": "offloadImages", + "type": 8, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 8, + "optional": true + }, + { + "name": "requestId", + "type": 7, + "optional": true + }, + { + "name": "status", + "type": 8, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 6, + "optional": false + }, + { + "name": "kind", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#FinishReason" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "587bb11da730e06aa52b62c087d217d6f8f22459b25f31cb9e1e1baf17944e5e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "session/title-llm-request" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "58f94390b982f8a5ac1f4f235ba612557f4a1dc4a995d8b1cec63ce7639decb0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "image/png" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5abab3a27fd2736660ecddd94b28d6bbf114986dd894880153bd1be3ccacb563", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "text-delta" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5b232a9b9bfcc0fc6794dab7865bcf203a65785c5de5aa647a51228bff628413", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "after" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5b694f394d5e11609887a3ccfa82844935d49806c37e336b30be2186d649ab94", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "senderId", + "type": 5, + "optional": false + }, + { + "name": "senderName", + "type": 5, + "optional": false + }, + { + "name": "targetId", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 3, + 7, + 9, + 11, + 13, + 24 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "isError", + "type": 4, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 14, + "optional": false + }, + { + "name": "offloaded", + "type": 22, + "optional": true + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 15, + "optional": false + }, + { + "name": "height", + "type": 15, + "optional": false + }, + { + "name": "mediaType", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 21, + "optional": true + }, + { + "name": "width", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 17, + 18, + 19, + 20 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 15, + "optional": false + }, + { + "name": "width", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 25, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 15, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + } + ] + }, + "names": [ + "packages/experimental/agent-team/src/types.ts#TeamMessageSnapshot" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "5b6fb1f226ff56402db08a6aae82af76100b14056271875f69ec526a1ae05d51", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "commandId", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "sourceEventSeq", + "type": 5, + "optional": true + }, + { + "name": "text", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "literal", + "value": "success" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:command/done.data" + ], + "sources": [ + "packages/interaction/commands/src/types.ts" + ] + }, + { + "digest": "5bd310104cfe448e530beb11422d2f791e2e32e8e95fdc528a15f9ca693dae75", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "resource-cost" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "preset", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "permission/preset" + } + ] + }, + "names": [ + "event:permission/preset" + ], + "sources": [] + }, + { + "digest": "5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "SessionEventEnvelope[39].sourceEventSeqs", + "SessionEventEnvelope[52].sourceEventSeqs", + "SessionEventEnvelope[55].sourceEventSeqs", + "event:assistant/attempt.data.stream[0][0].dt", + "event:assistant/attempt.data.stream[0][1].dt", + "event:assistant/attempt.data.stream[0][2].dt", + "event:compaction/prune.data.shadowedSeqs", + "event:compaction/summary.data[0].shadowedSeqs", + "event:compaction/summary.data[1].shadowedSeqs", + "event:image/offload.data.targets[0].imageIndexes", + "event:session/title-llm-request.data.messageSeqs", + "event:session/title.data.messageSeqs", + "event:system/message.sourceEventSeqs", + "event:tool/result.sourceEventSeqs", + "event:user/message.sourceEventSeqs" + ], + "sources": [] + }, + { + "digest": "5d17f27a1ef9f7026c0232714adf7573961536d75f3303ca97973975f5af170e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-workflow/agent-end" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5d542ac7bdf13310c46e1a884dec9fb18ad8c6e153cff207e639cd7bf9d7e694", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 1, + "optional": false + }, + { + "name": "childId", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 2, + "optional": true + }, + { + "name": "mode", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "one-shot" + }, + { + "kind": "literal", + "value": 0 + } + ] + }, + "names": [ + "event:subagent/catalog.data[0]" + ], + "sources": [] + }, + { + "digest": "5dd766ccd1702a1142ad8b4bd44f2242f8e8a6752669ad3de0a5d224329b1438", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "shadowedRange", + "type": 1, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 3, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 2, + "optional": false + }, + { + "name": "start", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 2 + } + ] + }, + "names": [ + "event:compaction/prune.data" + ], + "sources": [ + "packages/compaction/compaction/src/types.ts" + ] + }, + { + "digest": "5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 2, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "inherited", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "session/end-seed" + } + ] + }, + "names": [ + "event:session/end-seed" + ], + "sources": [] + }, + { + "digest": "5ebce1317eacd2c148456627a09668e927ee15c204f0643f5ea76b46b54a2647", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "subagent/descriptor" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "5f2117d1856a5ab43c28371faa978ebfaa48f8c7d734ea3fc94842210df83dca", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 1, + "optional": false + }, + { + "name": "message", + "type": 1, + "optional": false + }, + { + "name": "offloadImages", + "type": 2, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 2, + "optional": true + }, + { + "name": "requestId", + "type": 1, + "optional": true + }, + { + "name": "status", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#LlmFailure" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "childId", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 2, + "optional": false + }, + { + "name": "phase", + "type": 2, + "optional": true + }, + { + "name": "runId", + "type": 2, + "optional": false + }, + { + "name": "seq", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "tool-workflow/agent-start" + } + ] + }, + "names": [ + "event:tool-workflow/agent-start" + ], + "sources": [] + }, + { + "digest": "5f758f3de5f00c18968a7c6d347083aac5c9ae13f6a79c78f6611b23c4973564", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "label", + "type": 1, + "optional": true + }, + { + "name": "mode", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 1, + "optional": false + }, + { + "name": "version", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "one-shot" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/subagent/subagent/src/descriptor.ts#OneShotSubagentDescriptorData" + ], + "sources": [ + "packages/subagent/subagent/src/descriptor.ts" + ] + }, + { + "digest": "611cae9a3539733aa0c42f66035a7d90f19dcbbdfb5d9e3b628b13705253942d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "llm/retry" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "616f93a5047de668e1c30d57b1786abd76beeb4123599637ec1dc5290320ede5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-call-chunks" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "62e6a429ff3f390a46ac39fb468692032f42936ca0db19b53454184189401379", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "block" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "literal", + "value": "edit" + }, + { + "kind": "literal", + "value": "pause" + }, + { + "kind": "literal", + "value": "resume" + } + ] + }, + "names": [ + "event:goal/change.data[0].operation" + ], + "sources": [] + }, + { + "digest": "62ecb62dc0fe1b5e70217f8a80c39256a40ee3a1917be14e5ca899d20c35f7fd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "next-turn" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 18, + "optional": true + }, + { + "name": "seq", + "type": 11, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 90, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "inserted", + "type": 2, + "optional": false + }, + { + "name": "outcome", + "type": 86, + "optional": true + }, + { + "name": "removedCount", + "type": 11, + "optional": true + }, + { + "name": "start", + "type": 11, + "optional": false + }, + { + "name": "target", + "type": 87, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "role", + "type": 30, + "optional": false + }, + { + "name": "source", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 20, + 23, + 26, + 28 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 10, + "optional": false + }, + { + "name": "offloaded", + "type": 18, + "optional": true + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 21, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 32, + 41, + 43, + 44, + 47, + 52, + 54, + 59, + 60, + 61, + 63, + 65, + 66, + 73, + 75, + 77, + 79, + 81, + 84, + 85 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 18, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 7, + "optional": true + }, + { + "name": "changes", + "type": 33, + "optional": false + }, + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 40, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 34 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 35, + "optional": false + }, + { + "name": "digest", + "type": 7, + "optional": true + }, + { + "name": "path", + "type": 7, + "optional": false + }, + { + "name": "scope", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 36, + 37, + 38 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 7, + "optional": false + }, + { + "name": "kind", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 7, + "optional": true + }, + { + "name": "kind", + "type": 30, + "optional": false + }, + { + "name": "rpcId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 7, + "optional": false + }, + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 46, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "ruleId", + "type": 7, + "optional": false + }, + { + "name": "source", + "type": 7, + "optional": false + }, + { + "name": "summary", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 48, + "optional": false + }, + { + "name": "form", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + }, + { + "name": "update", + "type": 18, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 49 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 55, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + }, + { + "name": "sections", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 58 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + }, + { + "name": "summary", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 64, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 62, + "optional": false + }, + { + "name": "kind", + "type": 67, + "optional": false + }, + { + "name": "references", + "type": 68, + "optional": false + }, + { + "name": "version", + "type": 72, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 69 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 11, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 70, + "optional": false + }, + { + "name": "compacted", + "type": 24, + "optional": false + }, + { + "name": "inputIndex", + "type": 11, + "optional": false + }, + { + "name": "label", + "type": 7, + "optional": false + }, + { + "name": "omittedBytes", + "type": 11, + "optional": false + }, + { + "name": "omittedMessages", + "type": 11, + "optional": false + }, + { + "name": "originalMessages", + "type": 11, + "optional": false + }, + { + "name": "retainedMessages", + "type": 11, + "optional": false + }, + { + "name": "sessionId", + "type": 7, + "optional": false + }, + { + "name": "truncated", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 11, + 71 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 74, + "optional": false + }, + { + "name": "senderSessionId", + "type": 7, + "optional": false + }, + { + "name": "summary", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 64, + "optional": false + }, + { + "name": "kind", + "type": 76, + "optional": false + }, + { + "name": "senderSessionId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 7, + "optional": false + }, + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "revision", + "type": 11, + "optional": false + }, + { + "name": "round", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "messageId", + "type": 7, + "optional": false + }, + { + "name": "senderId", + "type": 7, + "optional": false + }, + { + "name": "senderName", + "type": 7, + "optional": false + }, + { + "name": "teamId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 82, + "optional": false + }, + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "replayState", + "type": 83, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "plugin", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "canceled" + }, + { + "kind": "union", + "types": [ + 88, + 89 + ] + }, + { + "kind": "literal", + "value": "next-step" + }, + { + "kind": "literal", + "value": "next-turn" + }, + { + "kind": "literal", + "value": "agent/inbox/spliced" + } + ] + }, + "names": [ + "event:agent/inbox/spliced" + ], + "sources": [] + }, + { + "digest": "647cb2e3aeb58e27d1d4d60011f208bb66dce257e8654193c533b47c4c22c253", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 1, + "optional": false + }, + { + "name": "index", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3, + 4, + 5, + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "block-start" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[0]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "6487b10ba7542f3c447b1e41a1c6a590b7bfafe0b9b66b49f34028da85bb970f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentModel", + "type": 1, + "optional": true + }, + { + "name": "agentProvider", + "type": 1, + "optional": true + }, + { + "name": "agentReasoningEffort", + "type": 1, + "optional": true + }, + { + "name": "label", + "type": 1, + "optional": false + }, + { + "name": "mode", + "type": 2, + "optional": false + }, + { + "name": "persona", + "type": 1, + "optional": true + }, + { + "name": "provider", + "type": 1, + "optional": false + }, + { + "name": "toolFilter", + "type": 3, + "optional": true + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "object", + "properties": [ + { + "name": "allow", + "type": 4, + "optional": true + }, + { + "name": "deny", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 1 + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/subagent/subagent/src/descriptor.ts#ContinuableSubagentDescriptorData" + ], + "sources": [ + "packages/subagent/subagent/src/descriptor.ts" + ] + }, + { + "digest": "658d895d187b26d83f3b53109a3bf77bbfba9f6f9a6d4bc4ee4315b4eb36239e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "prompt", + "type": 1, + "optional": false + }, + { + "name": "scheduledAt", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "at" + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#AtScheduleRecord" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "6598cd6da253948d6b207c6374a45335804c79b576866d6215649c2d1bc85e25", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "context", + "type": 1, + "optional": false + }, + { + "name": "description", + "type": 4, + "optional": false + }, + { + "name": "error", + "type": 4, + "optional": true + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "phase", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "fork" + }, + { + "kind": "literal", + "value": "fresh" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "literal", + "value": "provisioning" + } + ] + }, + "names": [ + "packages/experimental/agent-team/src/types.ts#TeamMemberSnapshot" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "66ece68282d8c06330fb83329a24ae54c386d5ccfab296bbf18369da8beb7d14", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "everySeconds", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "prompt", + "type": 2, + "optional": false + }, + { + "name": "scheduledAt", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "every" + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#EveryScheduleRecord" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "672c4aa2a9b736e3d6e5da6346d2e2ed5e3573f2d0baafa18e7407c9f3fee3db", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/skill/skill/src/index.ts#SkillInvocationSource" + ], + "sources": [ + "packages/skill/skill/src/index.ts" + ] + }, + { + "digest": "67d5f73ceae82f5265258142ad6cf172de2c1fef93ba551b7f0454e0a93bffe0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 1, + "optional": true + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 2, + "optional": true + }, + { + "name": "stop", + "type": 3, + "optional": true + }, + { + "name": "temperature", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 2 + } + ] + }, + "names": [ + "packages/llm/llm/src/call-config.ts#LlmCallConfig" + ], + "sources": [ + "packages/llm/llm/src/call-config.ts" + ] + }, + { + "digest": "68141cbe3994a5ffcd064c07c75996538437fd9dbf77ce8a2927e89ec577fabe", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "max-tokens" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "688e853dc149f0d30b31765c12ec7e3be74169bdf1a4c6463a10b945d50cc1b8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "reasoning-chunks" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "68f44f59e91c41395076cb77265981a601680ec8a381bbbeb6ab754ffdc94573", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "693f4952fb5565da96c06bace8924b098ac2fbc915fde0ff8019701183abc057", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 2, + "optional": false + }, + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "offloadImages", + "type": 3, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 3, + "optional": true + }, + { + "name": "requestId", + "type": 2, + "optional": true + }, + { + "name": "status", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "error" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6].reason[1]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 17, + "optional": true + }, + { + "name": "seq", + "type": 10, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 47, + "optional": true + }, + { + "name": "surfaceOp", + "type": 48, + "optional": false + }, + { + "name": "time", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 52, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "step", + "type": 10, + "optional": false + }, + { + "name": "turn", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "role", + "type": 29, + "optional": false + }, + { + "name": "source", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 8, + 19, + 22, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 9, + "optional": false + }, + { + "name": "offloaded", + "type": 17, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "mediaType", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 16, + "optional": true + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 23, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "union", + "types": [ + 31, + 36, + 38, + 40, + 42, + 44, + 46 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 32, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + }, + { + "name": "sections", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 35 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 37, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + }, + { + "name": "summary", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 39, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 41, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 45, + "optional": false + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 10 + }, + { + "kind": "union", + "types": [ + 49, + 51 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 10, + "optional": false + }, + { + "name": "op", + "type": 50, + "optional": false + }, + { + "name": "startSeq", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "literal", + "value": "system/message" + } + ] + }, + "names": [ + "event:system/message" + ], + "sources": [] + }, + { + "digest": "69d238a6e9b08d67f601b1825962963d8d3523cb69ebf6208c697dc5d058c199", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "interrupted" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6a4f72e2e179e17b922f2a9392c0e1c8f8c707f32494372454850a3eb184a6e7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 1, + "optional": true + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "rpcId", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[10]" + ], + "sources": [ + "packages/api/session-controller/src/types.ts" + ] + }, + { + "digest": "6ab45ac76839722df912f3ba50f1c6b41f2d614bde11f1aabfae04117ccdc80d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "assistant/message" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6bbe793f6a93dc8d50a4d4d3fbb6f8ed15650bcb7e151d28669628f7b7c3fc25", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "blockedReason", + "type": 1, + "optional": true + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "maxGoalRounds", + "type": 3, + "optional": false + }, + { + "name": "objective", + "type": 2, + "optional": false + }, + { + "name": "phase", + "type": 4, + "optional": false + }, + { + "name": "revision", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 2, + "optional": false + }, + { + "name": "message", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 5, + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "paused" + } + ] + }, + "names": [ + "packages/goal/goal/src/types.ts#GoalSnapshot" + ], + "sources": [ + "packages/goal/goal/src/types.ts" + ] + }, + { + "digest": "6c03546143cdf6ae88f1745ac98c5139efa1588d1415249bbc5f3104d32ab800", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + } + ] + }, + "names": [ + "event:turn/end.data.reason[1].reason[1]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "6c1cccb433ddc153facb380c7dda956237ba5c31f8a532a69142dc277890cc9b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-calls" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6c5a37d42ebdb12db4410699259335f1e149e3a0260425684c00b153afc8990d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + }, + { + "name": "reason", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:turn/end.data.reason[1].reason[2]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "6cda0d6d3b4336d83998fe580628426df81c2afbab5d768b8813b56d569120e8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "feedback/message-put" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6d63f25a28b70801937a46b1058be5f52d4efbaf3516141470463ae469b59c23", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "parameters", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 2, + "value": 4 + } + ] + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "event:request/header.data.header.tools" + ], + "sources": [] + }, + { + "digest": "6e52dd55a1d48954ed5464ec46fe34d9eb65f709baabc9561e7a279910b0c406", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent-preset/selected.data" + ], + "sources": [ + "packages/preset/agent-presets/src/session.ts" + ] + }, + { + "digest": "6ebcc2dbec9f2dabca9f668ae6d39e877899b180740570f453409db339221df3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "skill-catalog" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6f091fe32ab24407236090ca9d710bbaf59bb57466e9f3b8f1f6e4862bc863c6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "reasoning-delta" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6f22a9d02b9a1f1157f3b0e7bdccd7e7b12b085c4efdb709dfc74a465cd4e590", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 1, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 2, + "optional": true + }, + { + "name": "changes", + "type": 3, + "optional": false + }, + { + "name": "form", + "type": 9, + "optional": false + }, + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 5, + "optional": false + }, + { + "name": "digest", + "type": 2, + "optional": true + }, + { + "name": "path", + "type": 2, + "optional": false + }, + { + "name": "scope", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + } + ] + }, + "names": [ + "packages/context/agent-instructions/src/state.ts#AgentInstructionSource" + ], + "sources": [ + "packages/context/agent-instructions/src/state.ts" + ] + }, + { + "digest": "6f611bed14b2106542480c4a230b4a83baf76dc0d8ac0cd13319a7cb8dae7675", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "web/deepseek-search-llm-request" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "6f72ece8f317cd080c4f20a93f1bf709965f5b81ac4669528f5a023191cfcf20", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "retry", + "type": 1, + "optional": false + }, + { + "name": "retryId", + "type": 2, + "optional": false + }, + { + "name": "step", + "type": 1, + "optional": false + }, + { + "name": "turn", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/llm/llm-retry/src/types.ts#LlmRetryStartedEventData" + ], + "sources": [ + "packages/llm/llm-retry/src/types.ts" + ] + }, + { + "digest": "6f9e00383836275e46c0a9915767f9bb561be5fc30aae490174908a93e99a912", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "snapshot" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "70b082fe78991edf13cf66e1b4d06cd2dcff9cacfd76f8cfb996bfb61939e7b2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "request/context" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "7180844e1066230c5e891f1b9ccd942423b0fe48aac6ded7eef2a285b288a732", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "service-stability" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "719c51f67074f97034a6c94297fe1f4b5d3c8d392c57586dab732aa5398c7a91", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "replayState", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#ModelMessageSource" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "71bb3254ec8f1e491ce63b762a7b5f18709de23aa4e8abcc8b886f4b6ce051dd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 1, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "texts", + "type": 3, + "optional": false + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning-chunks" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][1]" + ], + "sources": [ + "packages/llm/llm/src/assistant-stream.ts" + ] + }, + { + "digest": "72ec79127a9c0d0241b1106a74cc2b24c81ce467170f1c3c93f7b71a9496d227", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "union", + "types": [ + 0, + 2, + 3, + 4, + 5, + 6 + ] + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 3, + "value": 1 + } + ] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:tool/result.data.meta[5]", + "event:tool/result.data.meta[5][0][5]" + ], + "sources": [] + }, + { + "digest": "7382c4fc95fe8c5db65ca4d9da572b115d0dbb818b7f32c22ab040318ffbb4bc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "remove" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "757013fff5879d73d5753d8d1120faab56110e88ac3932485ab7e034d9e9ce61", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "literal", + "value": "tool-result" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ContentBlockType" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "7624ca28c61ca0eaa4f015140f3cea6e0c16cce2f2960fab5f531203d253903e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "create" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 23, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 9 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "cleared", + "type": 3, + "optional": false + }, + { + "name": "clearedAt", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "operation", + "type": 7, + "optional": false + }, + { + "name": "version", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "revision", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "goal/change" + }, + { + "kind": "literal", + "value": "clear" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "createdAt", + "type": 5, + "optional": false + }, + { + "name": "goal", + "type": 10, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "operation", + "type": 17, + "optional": false + }, + { + "name": "roundsStarted", + "type": 5, + "optional": false + }, + { + "name": "updatedAt", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedReason", + "type": 11, + "optional": true + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "maxGoalRounds", + "type": 5, + "optional": false + }, + { + "name": "objective", + "type": 4, + "optional": false + }, + { + "name": "phase", + "type": 12, + "optional": false + }, + { + "name": "revision", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 4, + "optional": false + }, + { + "name": "message", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "paused" + }, + { + "kind": "union", + "types": [ + 15, + 18, + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "block" + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "edit" + }, + { + "kind": "literal", + "value": "pause" + }, + { + "kind": "literal", + "value": true + } + ] + }, + "names": [ + "event:goal/change" + ], + "sources": [] + }, + { + "digest": "76632533f67879dcb346fcae640540dbc89b2472b0bce88c59f7e48fc5c0e668", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "delegation" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "77b8491f946edfc8cc77ebae3ba49183759da31ba2dfa83d4c9e9e618c4b91d2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "interrupted", + "type": 1, + "optional": true + }, + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "step", + "type": 10, + "optional": false + }, + { + "name": "stream", + "type": 32, + "optional": false + }, + { + "name": "turn", + "type": 10, + "optional": false + }, + { + "name": "usage", + "type": 69, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "role", + "type": 28, + "optional": false + }, + { + "name": "source", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 8, + 18, + 21, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 9, + "optional": false + }, + { + "name": "offloaded", + "type": 1, + "optional": true + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "mediaType", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 16, + "optional": true + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 22, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 30, + "optional": false + }, + { + "name": "model", + "type": 6, + "optional": false + }, + { + "name": "provider", + "type": 6, + "optional": false + }, + { + "name": "replayState", + "type": 31, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "array", + "element": 33 + }, + { + "kind": "union", + "types": [ + 34, + 38, + 71, + 73 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 35, + "optional": false + }, + { + "name": "dt", + "type": 36, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "time0", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 37, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "array", + "element": 10 + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 39, + "optional": false + }, + { + "name": "time", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 70, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 40, + 42, + 44, + 47, + 49, + 51, + 67 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "type", + "type": 41, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 4, + "optional": false + }, + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 45, + "optional": false + }, + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 7, + 17, + 20, + 23, + 25, + 27 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 48, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 50, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 52, + "optional": false + }, + { + "name": "replayState", + "type": 64, + "optional": true + }, + { + "name": "type", + "type": 66, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 53, + 56, + 58, + 60, + 62 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 6, + "optional": false + }, + { + "name": "message", + "type": 6, + "optional": false + }, + { + "name": "offloadImages", + "type": 10, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 10, + "optional": true + }, + { + "name": "requestId", + "type": 6, + "optional": true + }, + { + "name": "status", + "type": 10, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 59, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 61, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 63, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 65, + "optional": true + }, + { + "name": "response", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 31 + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 68, + "optional": false + }, + { + "name": "usage", + "type": 69, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 10, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 10, + "optional": true + }, + { + "name": "inputTokens", + "type": 10, + "optional": false + }, + { + "name": "outputTokens", + "type": 10, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 10, + "optional": true + }, + { + "name": "totalTokens", + "type": 10, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 36, + "optional": false + }, + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "texts", + "type": 35, + "optional": false + }, + { + "name": "time0", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 72, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 36, + "optional": false + }, + { + "name": "index", + "type": 10, + "optional": false + }, + { + "name": "texts", + "type": 35, + "optional": false + }, + { + "name": "time0", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 74, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + } + ] + }, + "names": [ + "event:assistant/message.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 2, + "optional": false + }, + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "offloadImages", + "type": 3, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 3, + "optional": true + }, + { + "name": "requestId", + "type": 2, + "optional": true + }, + { + "name": "status", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "error" + } + ] + }, + "names": [ + "event:turn/end.data.reason[3]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "79ddc907312f97cf9553d4841e8b3fc937097bd8d97900a790efad3c05255e99", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "todos", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "status", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 5, + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [ + "event:todo/write.data" + ], + "sources": [ + "packages/todo/tool-todo/src/types.ts" + ] + }, + { + "digest": "7a651f3b672c52fb615f22c0ce9cb3cc5b22aad92e6bbeefb0808fd7b9233a50", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "session/title" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "7af85bf70d4eafce63e739adae38ea85501e68df3a0e22f97f3a0be90fd9e4cb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 1, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "surfaceOp", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 2, + "optional": false + }, + { + "name": "op", + "type": 6, + "optional": false + }, + { + "name": "startSeq", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "SessionEventEnvelope[6]" + ], + "sources": [] + }, + { + "digest": "7c6129b6961cf4b2a030f36c78d2b0a5be38617651a9b81322e054ee512bee06", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "messageId", + "type": 1, + "optional": false + }, + { + "name": "sessionId", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/feedback/message-feedback/src/types.ts#MessageFeedbackDelete" + ], + "sources": [ + "packages/feedback/message-feedback/src/types.ts" + ] + }, + { + "digest": "7d226b9fd95b4ba213d4237c22e930a91c3c769c95ca7f92977b9d625ba13438", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 8 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "cleared", + "type": 2, + "optional": false + }, + { + "name": "clearedAt", + "type": 4, + "optional": false + }, + { + "name": "kind", + "type": 5, + "optional": false + }, + { + "name": "operation", + "type": 6, + "optional": false + }, + { + "name": "version", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "revision", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "goal/change" + }, + { + "kind": "literal", + "value": "clear" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "createdAt", + "type": 4, + "optional": false + }, + { + "name": "goal", + "type": 9, + "optional": false + }, + { + "name": "kind", + "type": 5, + "optional": false + }, + { + "name": "operation", + "type": 16, + "optional": false + }, + { + "name": "roundsStarted", + "type": 4, + "optional": false + }, + { + "name": "updatedAt", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedReason", + "type": 10, + "optional": true + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "maxGoalRounds", + "type": 4, + "optional": false + }, + { + "name": "objective", + "type": 3, + "optional": false + }, + { + "name": "phase", + "type": 11, + "optional": false + }, + { + "name": "revision", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "message", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "paused" + }, + { + "kind": "union", + "types": [ + 14, + 17, + 18, + 19, + 20, + 21 + ] + }, + { + "kind": "literal", + "value": "block" + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "literal", + "value": "edit" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "pause" + } + ] + }, + "names": [ + "packages/goal/goal/src/domain.ts#GoalChangeMeta" + ], + "sources": [ + "packages/goal/goal/src/domain.ts" + ] + }, + { + "digest": "7d54a5a5e629e2e7783bfac72683bcc5e969e9f43426b9289826aaf294ff6344", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 1, + "optional": true + }, + { + "name": "text", + "type": 9, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/feedback/command-feedback/src/types.ts#FeedbackRecord" + ], + "sources": [ + "packages/feedback/command-feedback/src/types.ts" + ] + }, + { + "digest": "7f13860ee89a2d35ce09f958e85a04566cd59cb1de1d73a9619a9b631961dc71", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "session-reference" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "7f5f2a8618c2ece530a18b1358b890fb57fb8c35705e47b66bff2296f8c6e889", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "parameters", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 1, + "value": 3 + } + ] + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ToolSchema" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "shadowedRange", + "type": 2, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 4, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 3, + "optional": false + }, + { + "name": "start", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "compaction/prune" + } + ] + }, + "names": [ + "event:compaction/prune" + ], + "sources": [] + }, + { + "digest": "7f9365bae9fcb73e1e34061a1acfe0422c1a5fd351848cace9bebbe806f28462", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "runId", + "type": 1, + "optional": false + }, + { + "name": "stopReason", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "error" + } + ] + }, + "names": [ + "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunEndData" + ], + "sources": [ + "packages/workflow/tool-workflow/src/types.ts" + ] + }, + { + "digest": "7f959241c24128b4983b559984811861dc59774b85905c8fa57c6cb0148a3dbc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "revision", + "type": 3, + "optional": false + }, + { + "name": "round", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/goal/goal/src/domain.ts#GoalMessageSource" + ], + "sources": [ + "packages/goal/goal/src/domain.ts" + ] + }, + { + "digest": "811229eedcec57979dbadca7dbea832a59f8580cff30cb217fca5e2da16314bd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "allowed-once" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "814d9434e1ddf9078612b3b34322f26e9363b469213335007f7e9ba7fee9464e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ReasoningBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "82470020b5bfcb1a843e2aa05602af7d37df99e82d01f015c7c589ba054fd89d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "agent-message" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "829a2fb3be6efd4ba36aef8ed2d381a4c6fb2a0aaf50c823a6f3f8290786b809", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "agent/inbox/spliced" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "83079c8a3f733ac3fa603eefa0fbb4737ca4d8b69e7e2e7298b60f9ac4098693", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[17].entries[0]" + ], + "sources": [ + "packages/skill/tool-skill/src/index.ts" + ] + }, + { + "digest": "83da72c6857601c75da11212ef847f57d457b9c99f0a82246dcdff3e26700239", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 1, + "optional": false + }, + { + "name": "digest", + "type": 5, + "optional": true + }, + { + "name": "path", + "type": 5, + "optional": false + }, + { + "name": "scope", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/context/agent-instructions/src/render.ts#AgentInstructionChange" + ], + "sources": [ + "packages/context/agent-instructions/src/render.ts" + ] + }, + { + "digest": "8465ece5e9d9007c038b357015d849c15262cb0bc25abc59e47692d87ee01a15", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "error" + } + ] + }, + "names": [ + "packages/workflow/workflow/src/types.ts#WorkflowStopReason" + ], + "sources": [ + "packages/workflow/workflow/src/types.ts" + ] + }, + { + "digest": "84ac8c1a66ffc697262e181f42e851259eae14038c113ca329fb4700ccdb1f7c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 1, + "optional": false + }, + { + "name": "message", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/goal/goal/src/types.ts#GoalBlockReason" + ], + "sources": [ + "packages/goal/goal/src/types.ts" + ] + }, + { + "digest": "85e1bd563d6c80c1f377f99f91103fec4e315148a7330f3b3dae7c2d04e33b01", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[7]", + "event:system/message.data.message.source[6]" + ], + "sources": [] + }, + { + "digest": "86cf1e44038cb8b11659863dd0efafe682e41b9c782265c1d50e0a687debfc60", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 7, + 65, + 67 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 2, + "optional": false + }, + { + "name": "dt", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "time0", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 8, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 64, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 9, + 11, + 37, + 40, + 42, + 44, + 61 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 12, + "optional": false + }, + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 36, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 13, + 15, + 25, + 28, + 32, + 34 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 23, + "optional": true + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 5, + "optional": false + }, + { + "name": "height", + "type": 5, + "optional": false + }, + { + "name": "mediaType", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 22, + "optional": true + }, + { + "name": "width", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 18, + 19, + 20, + 21 + ] + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 5, + "optional": false + }, + { + "name": "width", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 26, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 29, + "optional": false + }, + { + "name": "isError", + "type": 30, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 12 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 35, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 38, + "optional": false + }, + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 39, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 14, + 24, + 27, + 31, + 33, + 35 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 41, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 45, + "optional": false + }, + { + "name": "replayState", + "type": 57, + "optional": true + }, + { + "name": "type", + "type": 60, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 46, + 49, + 51, + 53, + 55 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 47, + "optional": false + }, + { + "name": "kind", + "type": 48, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "offloadImages", + "type": 5, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 5, + "optional": true + }, + { + "name": "requestId", + "type": 3, + "optional": true + }, + { + "name": "status", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 47, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 52, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 54, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 56, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 58, + "optional": true + }, + { + "name": "response", + "type": 59, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 59 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 62, + "optional": false + }, + { + "name": "usage", + "type": 63, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 5, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 5, + "optional": true + }, + { + "name": "inputTokens", + "type": 5, + "optional": false + }, + { + "name": "outputTokens", + "type": 5, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 5, + "optional": true + }, + { + "name": "totalTokens", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 4, + "optional": false + }, + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "texts", + "type": 2, + "optional": false + }, + { + "name": "time0", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 66, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 4, + "optional": false + }, + { + "name": "index", + "type": 5, + "optional": false + }, + { + "name": "texts", + "type": 2, + "optional": false + }, + { + "name": "time0", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 68, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + } + ] + }, + "names": [ + "packages/llm/llm/src/assistant-stream.ts#AssistantStreamRecord" + ], + "sources": [ + "packages/llm/llm/src/assistant-stream.ts" + ] + }, + { + "digest": "86d1d0e9cfebb240421187e3dc37fb71cc38a1501885cf32f8f9adef7b0a2bde", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "agentModel", + "type": 2, + "optional": true + }, + { + "name": "agentProvider", + "type": 2, + "optional": true + }, + { + "name": "agentReasoningEffort", + "type": 2, + "optional": true + }, + { + "name": "label", + "type": 2, + "optional": false + }, + { + "name": "mode", + "type": 3, + "optional": false + }, + { + "name": "persona", + "type": 2, + "optional": true + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "toolFilter", + "type": 4, + "optional": true + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "object", + "properties": [ + { + "name": "allow", + "type": 5, + "optional": true + }, + { + "name": "deny", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "label", + "type": 2, + "optional": true + }, + { + "name": "mode", + "type": 8, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "one-shot" + } + ] + }, + "names": [ + "packages/subagent/subagent/src/descriptor.ts#SubagentDescriptorData" + ], + "sources": [ + "packages/subagent/subagent/src/descriptor.ts" + ] + }, + { + "digest": "86e1e384495ee09ac2d60c9db3610f1f1fddac2d248f6f1d6000e78054680219", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "text", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#ContextSnapshotSection" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "871bfd6f7bb91061246768d3377f3fd58d6b8ea7c31f44c714ae7ab215650d62", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "provisioning" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "88a610b831be6d92612a464be5c7d0b88ec24d97bd299837bf74bf7672183c9a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": true + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-call-delta" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[3]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 7, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "dialect", + "type": 2, + "optional": false + }, + { + "name": "handlerId", + "type": 5, + "optional": false + }, + { + "name": "matcher", + "type": 5, + "optional": true + }, + { + "name": "point", + "type": 5, + "optional": false + }, + { + "name": "turn", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "claude-code" + }, + { + "kind": "literal", + "value": "codex" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "hook/invoked" + } + ] + }, + "names": [ + "event:hook/invoked" + ], + "sources": [] + }, + { + "digest": "8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "preset", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:permission/preset.data" + ], + "sources": [ + "packages/interaction/permission-presets/src/index.ts" + ] + }, + { + "digest": "8ad45ad053b4d89f8865c17cc9ff3b8748e86045f3f0fb816269a34af2619141", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "decision", + "type": 1, + "optional": false + }, + { + "name": "durationMs", + "type": 2, + "optional": false + }, + { + "name": "exitCode", + "type": 2, + "optional": true + }, + { + "name": "handlerId", + "type": 1, + "optional": false + }, + { + "name": "point", + "type": 1, + "optional": false + }, + { + "name": "stderrSummary", + "type": 1, + "optional": true + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:hook/result.data" + ], + "sources": [ + "packages/hooks/hook-protocol/src/types.ts" + ] + }, + { + "digest": "8af841fc9b265ade3441caf9fe40dd24db24226befba48150e6d0eeccc1389c3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "system" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "8bb8c3751a6ce64b61aba1ec7ae798c00a5803c4d868a0430873216c6569ed52", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "sessionFormatVersion", + "type": 1, + "optional": true + }, + { + "name": "sessionId", + "type": 2, + "optional": false + }, + { + "name": "throughSeq", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:session-log-deepseek/delivery-accepted.data" + ], + "sources": [ + "packages/session/session-log-deepseek/src/types.ts" + ] + }, + { + "digest": "8cdd3fdd295cee53035de16a1b23411716f75e9f994fe9510cac5d7fef605c76", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "command/done" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "8d2e5a3c4230e6ea6c0b5151f02241d0db02cd2551f2df1b6b9700cddcc0dca3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 1, + "optional": false + }, + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "error", + "type": 28, + "optional": true + }, + { + "name": "isError", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "parentCallId", + "type": 6, + "optional": false + }, + { + "name": "rootCallId", + "type": 6, + "optional": false + }, + { + "name": "subCallId", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 4, + 8, + 10, + 12, + 14, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 5, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 15, + "optional": false + }, + { + "name": "offloaded", + "type": 23, + "optional": true + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 16, + "optional": false + }, + { + "name": "height", + "type": 16, + "optional": false + }, + { + "name": "mediaType", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 22, + "optional": true + }, + { + "name": "width", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 18, + 19, + 20, + 21 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 16, + "optional": false + }, + { + "name": "width", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 26, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "reason", + "type": 6, + "optional": true + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/core/tools/src/types.ts#PtcDispatchEventData" + ], + "sources": [ + "packages/core/tools/src/types.ts" + ] + }, + { + "digest": "8d6a011f3ef7096a4a922ef420458419ff6b20e1eaeece5d331db7585d2f08d6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "tuple", + "elements": [ + { + "type": 1, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "isError", + "type": 25, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "union", + "types": [ + 1, + 4, + 7, + 9, + 11, + 22 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 12, + "optional": false + }, + { + "name": "offloaded", + "type": 20, + "optional": true + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 13, + "optional": false + }, + { + "name": "height", + "type": 13, + "optional": false + }, + { + "name": "mediaType", + "type": 14, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 19, + "optional": true + }, + { + "name": "width", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 15, + 16, + 17, + 18 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 13, + "optional": false + }, + { + "name": "width", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 23, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 13, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + } + ] + }, + "names": [ + "event:tool/result.data.message.content" + ], + "sources": [] + }, + { + "digest": "8e31bb958e9b015e6f8407eaade32217068159e816f3cc99c3ad76eb889732e0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 2, + "optional": false + }, + { + "name": "message", + "type": 2, + "optional": false + }, + { + "name": "offloadImages", + "type": 3, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 3, + "optional": true + }, + { + "name": "requestId", + "type": 2, + "optional": true + }, + { + "name": "status", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "aborted" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6].reason[0]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "8e8e91646a5cae3fc78f7532a0013ff2088ae47077642c2edd507a508209b8af", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "operation", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "dispatch" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "header", + "type": 2, + "optional": false + }, + { + "name": "reason", + "type": 13, + "optional": false + }, + { + "name": "startsSeries", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "adapterDefaults", + "type": 3, + "optional": true + }, + { + "name": "config", + "type": 5, + "optional": false + }, + { + "name": "tools", + "type": 9, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 4, + "optional": true + }, + { + "name": "reasoningEffort", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 6, + "optional": true + }, + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 7, + "optional": true + }, + { + "name": "stop", + "type": 8, + "optional": true + }, + { + "name": "temperature", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "array", + "element": 10 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "parameters", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 7, + "value": 12 + } + ] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "union", + "types": [ + 14, + 15, + 16, + 17 + ] + }, + { + "kind": "literal", + "value": "initial" + }, + { + "kind": "literal", + "value": "resume" + }, + { + "kind": "literal", + "value": "series" + }, + { + "kind": "literal", + "value": "change" + }, + { + "kind": "literal", + "value": "request/header" + } + ] + }, + "names": [ + "event:request/header" + ], + "sources": [] + }, + { + "digest": "8f6d609794bf5afc01d7ccf3e03811d32f4b8047f58a2c9a98db0154c2ad7cb9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "tuple", + "elements": [ + { + "type": 1, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body.messages[0].content" + ], + "sources": [] + }, + { + "digest": "904bf499d98be4a3a5f836fcac533b6c4899569b018071e6604e1d32657d00fd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[16].changes[0].action" + ], + "sources": [] + }, + { + "digest": "90c811b8c2668898515e69a24e82caffeb08517f9c7aa193867ff0380f3b535d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 1, + "optional": false + }, + { + "name": "index", + "type": 15, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 7, + 9, + 11, + 13, + 24 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 4, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 1 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 14, + "optional": false + }, + { + "name": "offloaded", + "type": 22, + "optional": true + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 15, + "optional": false + }, + { + "name": "height", + "type": 15, + "optional": false + }, + { + "name": "mediaType", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 21, + "optional": true + }, + { + "name": "width", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 17, + 18, + 19, + 20 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 15, + "optional": false + }, + { + "name": "width", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 25, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 15, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": "block-end" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[4]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "max_tokens", + "type": 1, + "optional": false + }, + { + "name": "messages", + "type": 2, + "optional": false + }, + { + "name": "model", + "type": 6, + "optional": false + }, + { + "name": "tools", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 3, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "role", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 5, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 10, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "max_uses", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "web_search" + }, + { + "kind": "literal", + "value": "web_search_20250305" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body" + ], + "sources": [ + "packages/web/web-search-deepseek/src/provider.ts" + ] + }, + { + "digest": "930c1cd289def119d443e19dd90008916bf035f0a4d23e07241e7f050f2b89b7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "allowed-once" + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "rejected" + }, + { + "kind": "literal", + "value": "unavailable" + } + ] + }, + "names": [ + "packages/interaction/user-approval/src/types.ts#ApprovalOutcome" + ], + "sources": [ + "packages/interaction/user-approval/src/types.ts" + ] + }, + { + "digest": "935c8d486292b13c87b57ca280eb8c58b5b2f5239be86fcd4334c33fdeb87682", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "web_search" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "938f7c7357bc403ea3b281a9dd016939df7a0880fc8db12612585be574d0d615", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "primitive", + "type": "null" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "93c33d9687613293f8c95d46c4d922fe9ceae83b84c384beff5c3315abe005f2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][0].texts", + "event:assistant/attempt.data.stream[0][1].texts", + "event:assistant/attempt.data.stream[0][2].args", + "event:request/header.data.header.config.stop", + "event:subagent/descriptor.data[1].toolFilter.allow", + "event:subagent/descriptor.data[1].toolFilter.deny", + "event:team/task.data.task.blockedBy", + "event:team/task.data.task.writeScopes" + ], + "sources": [] + }, + { + "digest": "93cbbc5a7fd0b1aa1ff1b9a6bb5ec52b073f48e5a5200365c45c0cd54059e1b9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "outcome", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "allowed-once" + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "rejected" + }, + { + "kind": "literal", + "value": "unavailable" + } + ] + }, + "names": [ + "event:approval/decided.data" + ], + "sources": [ + "packages/interaction/user-approval/src/types.ts" + ] + }, + { + "digest": "93d38436347f67c9022aacbc4472e283d722bcab8eb73fc376aaf7b6a6b9fb35", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": 0 + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "94c56aeb1564ad735eb773d88636b40761d063efa1610f1308004d32923f5378", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "in_progress" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "95080295115fbd83544520ba247b68a03790131f6a2eac323d388758cb542f65", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 1, + "optional": false + }, + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text-delta" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[1]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "95c0e88fcf0bafb2087f912ad9e2369de6ae6530cc0c4c2772c96205b57f7f60", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "assistant" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "96f4a9c81fc0f940ef71528a8cc66731ae4cf1f40d79680c5fe3c39f96d7723c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "next-step" + }, + { + "kind": "literal", + "value": "next-turn" + } + ] + }, + "names": [ + "packages/core/agent/src/types.ts#InboxTarget" + ], + "sources": [ + "packages/core/agent/src/types.ts" + ] + }, + { + "digest": "9890113e97dd3541787bfe6704f2b223d3a890b5325ca0acae2b0398909b413e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "mode", + "type": 1, + "optional": false + }, + { + "name": "source", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "danger-full-access" + }, + { + "kind": "literal", + "value": "read-only" + }, + { + "kind": "literal", + "value": "workspace-write" + }, + { + "kind": "literal", + "value": "delegation" + } + ] + }, + "names": [ + "event:sandbox/mode.data" + ], + "sources": [ + "packages/sandbox/sandbox-policy/src/session-mode.ts" + ] + }, + { + "digest": "998f22585a5d73ec005365e203f07fc3b3a029e82323fdda3fd7f13b0a9639d0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 1, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "sourceEventSeqs", + "type": 3, + "optional": true + }, + { + "name": "surfaceOp", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 5, + 6 + ] + }, + { + "kind": "literal", + "value": "append" + }, + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 2, + "optional": false + }, + { + "name": "op", + "type": 7, + "optional": false + }, + { + "name": "startSeq", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "SessionEventEnvelope[39]", + "SessionEventEnvelope[52]", + "SessionEventEnvelope[55]" + ], + "sources": [] + }, + { + "digest": "9a2a9029f8d7ede05336980d8342737557f487b913bfd28853d0ab5214600ab5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "role", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 2, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body.messages[0]" + ], + "sources": [ + "packages/web/web-search-deepseek/src/provider.ts" + ] + }, + { + "digest": "9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "childId", + "type": 1, + "optional": false + }, + { + "name": "label", + "type": 1, + "optional": false + }, + { + "name": "phase", + "type": 1, + "optional": true + }, + { + "name": "runId", + "type": 1, + "optional": false + }, + { + "name": "seq", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData" + ], + "sources": [ + "packages/workflow/tool-workflow/src/types.ts" + ] + }, + { + "digest": "9acbe713f3f641921dd3333b240aa72e176d795327c24e8d9db9b68b16771b49", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "image/offload" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "9b4fd974c124c83743efe030ba4e1250e087505f3f74588716a521fb8d453267", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-call-delta" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "9d80129e13edfb6feb03ed327e6085c6ef60b97ad074244b2f5fd4667424a6a4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "other" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "9e07693fd7cd9babe0688c22c986e4d519ae1c0e40eeea13b2dc583bed2abc86", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "ask" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "9e2c06d8653585b33d72d5c1a80da79c8a24a88c284409bca15cc0f0ead5ebfb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "imageIndexes", + "type": 2, + "optional": false + }, + { + "name": "seq", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:image/offload.data.targets" + ], + "sources": [] + }, + { + "digest": "9e41386b3a0c9572b0d63078492ebb3997da7d3a830d44e0259418bd02f4bcb2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 1, + "optional": false + }, + { + "name": "start", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:compaction/prune.data.shadowedRange", + "event:compaction/summary.data[0].shadowedRange", + "event:compaction/summary.data[1].shadowedRange" + ], + "sources": [ + "packages/compaction/compaction/src/types.ts" + ] + }, + { + "digest": "9edc162949abf93bd5ff049191b345454ba104f583937ce5580fb50f067d2b94", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 1, + "optional": false + }, + { + "name": "form", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 1, + "optional": false + }, + { + "name": "ruleId", + "type": 1, + "optional": false + }, + { + "name": "source", + "type": 1, + "optional": false + }, + { + "name": "summary", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[19]" + ], + "sources": [ + "packages/webhook/webhook/src/types.ts" + ] + }, + { + "digest": "9fe0e77a7816b7fdb4b953ec0e2f0cd7bbd22c5de5c3567e612d1b20eb0992e6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 1, + "optional": false + }, + { + "name": "messageSeqs", + "type": 2, + "optional": false + }, + { + "name": "messages", + "type": 3, + "optional": false + }, + { + "name": "route", + "type": 89, + "optional": false + }, + { + "name": "system", + "type": 8, + "optional": false + }, + { + "name": "titleProvider", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 1 + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 8, + "optional": false + }, + { + "name": "role", + "type": 30, + "optional": false + }, + { + "name": "source", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "union", + "types": [ + 7, + 10, + 20, + 23, + 26, + 28 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 8, + "optional": false + }, + { + "name": "id", + "type": 8, + "optional": false + }, + { + "name": "name", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 11, + "optional": false + }, + { + "name": "offloaded", + "type": 18, + "optional": true + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 8, + "optional": false + }, + { + "name": "bytes", + "type": 1, + "optional": false + }, + { + "name": "height", + "type": 1, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 8, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 1, + "optional": false + }, + { + "name": "width", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 21, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 8, + "optional": false + }, + { + "name": "bytes", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 5, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 8, + "optional": false + }, + { + "name": "type", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "union", + "types": [ + 31, + 32, + 33 + ] + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 35, + 44, + 46, + 47, + 50, + 55, + 57, + 62, + 63, + 64, + 66, + 68, + 69, + 76, + 78, + 80, + 82, + 84, + 87, + 88 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 18, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 8, + "optional": true + }, + { + "name": "changes", + "type": 36, + "optional": false + }, + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 37 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 38, + "optional": false + }, + { + "name": "digest", + "type": 8, + "optional": true + }, + { + "name": "path", + "type": 8, + "optional": false + }, + { + "name": "scope", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 39, + 40, + 41 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 8, + "optional": false + }, + { + "name": "kind", + "type": 45, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 8, + "optional": true + }, + { + "name": "kind", + "type": 33, + "optional": false + }, + { + "name": "rpcId", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 8, + "optional": false + }, + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 49, + "optional": false + }, + { + "name": "provider", + "type": 8, + "optional": false + }, + { + "name": "ruleId", + "type": 8, + "optional": false + }, + { + "name": "source", + "type": 8, + "optional": false + }, + { + "name": "summary", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 51, + "optional": false + }, + { + "name": "form", + "type": 53, + "optional": false + }, + { + "name": "kind", + "type": 54, + "optional": false + }, + { + "name": "update", + "type": 18, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 52 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 8, + "optional": false + }, + { + "name": "name", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 56, + "optional": false + }, + { + "name": "name", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 58, + "optional": false + }, + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + }, + { + "name": "sections", + "type": 60, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 61 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 8, + "optional": false + }, + { + "name": "text", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + }, + { + "name": "summary", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 65, + "optional": false + }, + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 67, + "optional": false + }, + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 53, + "optional": false + }, + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 65, + "optional": false + }, + { + "name": "kind", + "type": 70, + "optional": false + }, + { + "name": "references", + "type": 71, + "optional": false + }, + { + "name": "version", + "type": 75, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 72 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 1, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 73, + "optional": false + }, + { + "name": "compacted", + "type": 24, + "optional": false + }, + { + "name": "inputIndex", + "type": 1, + "optional": false + }, + { + "name": "label", + "type": 8, + "optional": false + }, + { + "name": "omittedBytes", + "type": 1, + "optional": false + }, + { + "name": "omittedMessages", + "type": 1, + "optional": false + }, + { + "name": "originalMessages", + "type": 1, + "optional": false + }, + { + "name": "retainedMessages", + "type": 1, + "optional": false + }, + { + "name": "sessionId", + "type": 8, + "optional": false + }, + { + "name": "truncated", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 1, + 74 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 48, + "optional": false + }, + { + "name": "kind", + "type": 77, + "optional": false + }, + { + "name": "senderSessionId", + "type": 8, + "optional": false + }, + { + "name": "summary", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 67, + "optional": false + }, + { + "name": "kind", + "type": 79, + "optional": false + }, + { + "name": "senderSessionId", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 8, + "optional": false + }, + { + "name": "kind", + "type": 81, + "optional": false + }, + { + "name": "revision", + "type": 1, + "optional": false + }, + { + "name": "round", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 83, + "optional": false + }, + { + "name": "messageId", + "type": 8, + "optional": false + }, + { + "name": "senderId", + "type": 8, + "optional": false + }, + { + "name": "senderName", + "type": 8, + "optional": false + }, + { + "name": "teamId", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 85, + "optional": false + }, + { + "name": "model", + "type": 8, + "optional": false + }, + { + "name": "provider", + "type": 8, + "optional": false + }, + { + "name": "replayState", + "type": 86, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 59, + "optional": false + }, + { + "name": "plugin", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 8, + "optional": false + }, + { + "name": "provider", + "type": 8, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData" + ], + "sources": [ + "packages/session/session-title-llm/src/index.ts" + ] + }, + { + "digest": "9ff2ad8dddb836f75e8f6197fff2371323dfc396c3c6fb667e6e0b42fda79a5c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 1, + "optional": false + }, + { + "name": "llmStreamCall", + "type": 2, + "optional": false + }, + { + "name": "maxTokens", + "type": 3, + "optional": true + }, + { + "name": "model", + "type": 1, + "optional": false + }, + { + "name": "provider", + "type": 1, + "optional": false + }, + { + "name": "rawOutput", + "type": 4, + "optional": false + }, + { + "name": "shadowedRange", + "type": 27, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 28, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 3, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 1, + "optional": true + }, + { + "name": "summary", + "type": 4, + "optional": false + }, + { + "name": "usage", + "type": 29, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "union", + "types": [ + 6, + 9, + 11, + 13, + 15, + 24 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "isError", + "type": 7, + "optional": true + }, + { + "name": "toolCallId", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 2, + "optional": true + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 1, + "optional": false + }, + { + "name": "bytes", + "type": 3, + "optional": false + }, + { + "name": "height", + "type": 3, + "optional": false + }, + { + "name": "mediaType", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": true + }, + { + "name": "originalDimensions", + "type": 22, + "optional": true + }, + { + "name": "width", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 18, + 19, + 20, + 21 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 3, + "optional": false + }, + { + "name": "width", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 25, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 1, + "optional": false + }, + { + "name": "bytes", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 3, + "optional": false + }, + { + "name": "start", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 3, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 3, + "optional": true + }, + { + "name": "inputTokens", + "type": 3, + "optional": false + }, + { + "name": "outputTokens", + "type": 3, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 3, + "optional": true + }, + { + "name": "totalTokens", + "type": 3, + "optional": true + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:compaction/summary.data[0]" + ], + "sources": [] + }, + { + "digest": "a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": 2 + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "agent-preset/selected" + } + ] + }, + "names": [ + "event:agent-preset/selected" + ], + "sources": [] + }, + { + "digest": "a13d8f379222ece8a02a86efe4c8334af4f108ecb3034b38c0a42bb3046e6847", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "a2b49331716ba0a7078b026d145306a70eae64b7313c3e6204bd931e75ec3bb1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 1, + "optional": false + }, + { + "name": "replayState", + "type": 15, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 7, + 9, + 11, + 13 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 4, + "optional": false + }, + { + "name": "message", + "type": 4, + "optional": false + }, + { + "name": "offloadImages", + "type": 5, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 5, + "optional": true + }, + { + "name": "requestId", + "type": 4, + "optional": true + }, + { + "name": "status", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 16, + "optional": true + }, + { + "name": "response", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 17 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "a2be0f0cb59f0d4a06557d45847d1938aced238baa77a6da416e590b8b958553", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "error" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "a3a259a1aa5401af786ce08c4a8419681d3000d73467991b5fc563389bc4ebd2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "hook/result" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "a3edd1efd1fef21b72c55e213c8a8b24196b091abde2b89db52be0b2aaae3cfa", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "workspace-write" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "task", + "type": 1, + "optional": false + }, + { + "name": "teamId", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedBy", + "type": 2, + "optional": false + }, + { + "name": "description", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "ownerId", + "type": 3, + "optional": true + }, + { + "name": "revision", + "type": 4, + "optional": false + }, + { + "name": "status", + "type": 5, + "optional": false + }, + { + "name": "subject", + "type": 3, + "optional": false + }, + { + "name": "writeScopes", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 6, + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "deleted" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + }, + { + "kind": "literal", + "value": 2 + } + ] + }, + "names": [ + "event:team/task.data" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "a5a8c15f08af1b0f26f40906e0797b6b0920fd01069e660becce35ab7fc48d77", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 3, + 5, + 10, + 23, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "interrupted" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 6, + "optional": false + }, + { + "name": "kind", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "message", + "type": 7, + "optional": false + }, + { + "name": "offloadImages", + "type": 8, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 8, + "optional": true + }, + { + "name": "requestId", + "type": 7, + "optional": true + }, + { + "name": "status", + "type": 8, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 11, + "optional": false + }, + { + "name": "reason", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "union", + "types": [ + 13, + 15, + 17, + 19, + 21 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 20, + "optional": false + }, + { + "name": "reason", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "completed" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#TurnEndReason" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 5, + "optional": true + }, + { + "name": "seq", + "type": 6, + "optional": false + }, + { + "name": "time", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "allowedModels", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "subagent/model-selection-policy" + } + ] + }, + "names": [ + "event:subagent/model-selection-policy" + ], + "sources": [] + }, + { + "digest": "a6a195c1b4a906d953d24ab5864c9f1881d545460e080a51144adfc9cb058cfe", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "inserted", + "type": 1, + "optional": false + }, + { + "name": "outcome", + "type": 85, + "optional": true + }, + { + "name": "removedCount", + "type": 10, + "optional": true + }, + { + "name": "start", + "type": 10, + "optional": false + }, + { + "name": "target", + "type": 86, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "role", + "type": 29, + "optional": false + }, + { + "name": "source", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 8, + 19, + 22, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 9, + "optional": false + }, + { + "name": "offloaded", + "type": 17, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "mediaType", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": true + }, + { + "name": "originalDimensions", + "type": 16, + "optional": true + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 6, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 23, + "optional": true + }, + { + "name": "toolCallId", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 6, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 31, + 40, + 42, + 43, + 46, + 51, + 53, + 58, + 59, + 60, + 62, + 64, + 65, + 72, + 74, + 76, + 78, + 80, + 83, + 84 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 17, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 6, + "optional": true + }, + { + "name": "changes", + "type": 32, + "optional": false + }, + { + "name": "form", + "type": 38, + "optional": false + }, + { + "name": "kind", + "type": 39, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 33 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 34, + "optional": false + }, + { + "name": "digest", + "type": 6, + "optional": true + }, + { + "name": "path", + "type": 6, + "optional": false + }, + { + "name": "scope", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 35, + 36, + 37 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 6, + "optional": false + }, + { + "name": "kind", + "type": 41, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 6, + "optional": true + }, + { + "name": "kind", + "type": 29, + "optional": false + }, + { + "name": "rpcId", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 6, + "optional": false + }, + { + "name": "form", + "type": 44, + "optional": false + }, + { + "name": "kind", + "type": 45, + "optional": false + }, + { + "name": "provider", + "type": 6, + "optional": false + }, + { + "name": "ruleId", + "type": 6, + "optional": false + }, + { + "name": "source", + "type": 6, + "optional": false + }, + { + "name": "summary", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 47, + "optional": false + }, + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + }, + { + "name": "update", + "type": 17, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 48 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 38, + "optional": false + }, + { + "name": "kind", + "type": 52, + "optional": false + }, + { + "name": "name", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + }, + { + "name": "sections", + "type": 56, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 57 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 6, + "optional": false + }, + { + "name": "text", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 44, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + }, + { + "name": "summary", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 38, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 61, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 63, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 61, + "optional": false + }, + { + "name": "kind", + "type": 66, + "optional": false + }, + { + "name": "references", + "type": 67, + "optional": false + }, + { + "name": "version", + "type": 71, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 68 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 10, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 69, + "optional": false + }, + { + "name": "compacted", + "type": 23, + "optional": false + }, + { + "name": "inputIndex", + "type": 10, + "optional": false + }, + { + "name": "label", + "type": 6, + "optional": false + }, + { + "name": "omittedBytes", + "type": 10, + "optional": false + }, + { + "name": "omittedMessages", + "type": 10, + "optional": false + }, + { + "name": "originalMessages", + "type": 10, + "optional": false + }, + { + "name": "retainedMessages", + "type": 10, + "optional": false + }, + { + "name": "sessionId", + "type": 6, + "optional": false + }, + { + "name": "truncated", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 10, + 70 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 44, + "optional": false + }, + { + "name": "kind", + "type": 73, + "optional": false + }, + { + "name": "senderSessionId", + "type": 6, + "optional": false + }, + { + "name": "summary", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 63, + "optional": false + }, + { + "name": "kind", + "type": 75, + "optional": false + }, + { + "name": "senderSessionId", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 6, + "optional": false + }, + { + "name": "kind", + "type": 77, + "optional": false + }, + { + "name": "revision", + "type": 10, + "optional": false + }, + { + "name": "round", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 79, + "optional": false + }, + { + "name": "messageId", + "type": 6, + "optional": false + }, + { + "name": "senderId", + "type": 6, + "optional": false + }, + { + "name": "senderName", + "type": 6, + "optional": false + }, + { + "name": "teamId", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 81, + "optional": false + }, + { + "name": "model", + "type": 6, + "optional": false + }, + { + "name": "provider", + "type": 6, + "optional": false + }, + { + "name": "replayState", + "type": 82, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "plugin", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 29, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "canceled" + }, + { + "kind": "union", + "types": [ + 87, + 88 + ] + }, + { + "kind": "literal", + "value": "next-step" + }, + { + "kind": "literal", + "value": "next-turn" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data" + ], + "sources": [ + "packages/core/agent/src/types.ts" + ] + }, + { + "digest": "a6b41f5bede8094d7bf635be5d69b1bd7a25e006ca9cf9415bceb9322f1a7feb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2 + ] + }, + { + "kind": "literal", + "value": "claude-code" + }, + { + "kind": "literal", + "value": "codex" + } + ] + }, + "names": [ + "packages/hooks/hook-protocol/src/types.ts#HookDialect" + ], + "sources": [ + "packages/hooks/hook-protocol/src/types.ts" + ] + }, + { + "digest": "a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "runId", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData" + ], + "sources": [ + "packages/workflow/tool-workflow/src/types.ts" + ] + }, + { + "digest": "a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "active", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "plan/mode" + } + ] + }, + "names": [ + "event:plan/mode" + ], + "sources": [] + }, + { + "digest": "a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "reason", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:tool/ptc-dispatch.data.error", + "event:tool/result.data.error" + ], + "sources": [ + "packages/core/session/src/types.ts", + "packages/core/tools/src/types.ts" + ] + }, + { + "digest": "a853902cfab417b8f08aa51ad6855fea46f34ed4588a74e47403035111d0fb86", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 1, + "optional": true + }, + { + "name": "commandId", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "source", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "event:command/run.data" + ], + "sources": [ + "packages/interaction/commands/src/types.ts" + ] + }, + { + "digest": "a8a2b9011fc067862df7ce40748868467e5778283d7ac193c13f77684a914c57", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "team/message/delivered" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "a99f76fd149051c363f960bfeeb5b9509587ecaf7591a42797e4bfe810d8987a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "status", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [ + "packages/todo/tool-todo/src/types.ts#TodoItem" + ], + "sources": [ + "packages/todo/tool-todo/src/types.ts" + ] + }, + { + "digest": "aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "turn/start" + } + ] + }, + "names": [ + "event:turn/start" + ], + "sources": [] + }, + { + "digest": "aa7bc2817014ca6c45719b1c193c5c131be718a0921f34345098ff250f444626", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "item", + "type": 1, + "optional": false + }, + { + "name": "sessionId", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 2, + "optional": true + }, + { + "name": "createdAt", + "type": 10, + "optional": false + }, + { + "name": "messageId", + "type": 11, + "optional": false + }, + { + "name": "note", + "type": 11, + "optional": true + }, + { + "name": "rating", + "type": 12, + "optional": false + }, + { + "name": "updatedAt", + "type": 10, + "optional": false + }, + { + "name": "version", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 13, + 14 + ] + }, + { + "kind": "literal", + "value": "negative" + }, + { + "kind": "literal", + "value": "positive" + } + ] + }, + "names": [ + "packages/feedback/message-feedback/src/types.ts#MessageFeedbackPut" + ], + "sources": [ + "packages/feedback/message-feedback/src/types.ts" + ] + }, + { + "digest": "aa93010d0e521ad7c42273f58d5c9b8bf1dfc94edf1b805a3971b364a35c1877", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "primitive", + "type": "boolean" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "aacda84a69739238aa782eea902d3073017d9d74b9808de2bf5a83c9738cbdc6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "subagent" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]", + "event:turn/end.data.reason[4]" + ], + "sources": [ + "packages/core/session/src/types.ts", + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "aba175fb20ffc71112c55efe70458ff5d7dbfb83501892b4ba8d077f0ea5d7ba", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[17].entries" + ], + "sources": [] + }, + { + "digest": "acd36e1717d2b4ef9e98a8e6fac17ca1203f3f448e5bca51677f129a8f4999e2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "event:session/title-llm-request.data.messages[0].role" + ], + "sources": [] + }, + { + "digest": "ad22a5ca5bbaab2e1440779cd3648e85ddfc6f73b5207394eda699555cf31430", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "edit" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ad3b56aa2fc1ad4250e7399295d34a8eae592e1907e85852e2291b2e498a30bc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "legacy" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ad92f473a03ae72599ff26c86e897c25e16269519ad2a87340f0bea946517af8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-workflow/agent-start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ada310bf0bdb8fed51f3b56ea63f6ea6b18bbd587f04fccb63a14ab0b2a24e05", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[0]", + "event:session/title.data.source[2]", + "event:turn/end.data.reason[1].reason[0]", + "packages/interaction/commands/src/types.ts#CommandSource" + ], + "sources": [ + "packages/core/session/src/types.ts", + "packages/interaction/commands/src/types.ts", + "packages/llm/llm/src/message.ts", + "packages/session/session-title/src/types.ts" + ] + }, + { + "digest": "ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 9, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 3, + "optional": false + }, + { + "name": "childId", + "type": 4, + "optional": false + }, + { + "name": "label", + "type": 4, + "optional": false + }, + { + "name": "mode", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "literal", + "value": 0 + }, + { + "kind": "object", + "properties": [ + { + "name": "childCreatedAt", + "type": 3, + "optional": false + }, + { + "name": "childId", + "type": 4, + "optional": false + }, + { + "name": "label", + "type": 4, + "optional": true + }, + { + "name": "mode", + "type": 8, + "optional": false + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "one-shot" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "subagent/catalog" + } + ] + }, + "names": [ + "event:subagent/catalog" + ], + "sources": [] + }, + { + "digest": "ae63d9d1080ed8945031594d93f8d96651d7101b848719cc3e1475875cd3d649", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "permission/preset" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "aec150797b655c5f15ebb7a501454b0c208fbaccec9ace49d7de2171fc02f47d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "catalog" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "af0750d32d97d47b12b7361a587db41894b17e04c9a805fe212f0114aa2248c7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "todo/write" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "aff60ef947c18b012644852bdd0d5bfe72065e061dd563787c76c646b4a10f6b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "claude-code" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 2, + "optional": false + }, + { + "name": "error", + "type": 2, + "optional": true + }, + { + "name": "sourceCommandId", + "type": 2, + "optional": true + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "compaction/end" + } + ] + }, + "names": [ + "event:compaction/end" + ], + "sources": [] + }, + { + "digest": "b0b0eb1b16490f6bee135b2377e8f8c39227974c799ad7d49ff418af23ecbc35", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 1, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "mediaType", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": true + }, + { + "name": "originalDimensions", + "type": 8, + "optional": true + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "packages/attachment/attachment/src/types.ts#ImageAttachmentRef" + ], + "sources": [ + "packages/attachment/attachment/src/types.ts" + ] + }, + { + "digest": "b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "contextWindow", + "type": 1, + "optional": true + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "systemPromptUpdate", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "in-history" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#RequestContext" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "b1664fa89f8eab49a14e7e3168d8bc4da4aa9fd76332f6c4a053d839e5276ae7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[6].replayState.blocks" + ], + "sources": [] + }, + { + "digest": "b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "member", + "type": 1, + "optional": false + }, + { + "name": "teamId", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "context", + "type": 2, + "optional": false + }, + { + "name": "description", + "type": 5, + "optional": false + }, + { + "name": "error", + "type": 5, + "optional": true + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "phase", + "type": 6, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "fork" + }, + { + "kind": "literal", + "value": "fresh" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "literal", + "value": "provisioning" + }, + { + "kind": "literal", + "value": 2 + } + ] + }, + "names": [ + "event:team/member.data" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "b1f62380f6746fedd629e71065e3583cef83334875b499ac9665c2eb87acfbf5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "negative" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "targets", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "imageIndexes", + "type": 4, + "optional": false + }, + { + "name": "seq", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image/offload" + } + ] + }, + "names": [ + "event:image/offload" + ], + "sources": [] + }, + { + "digest": "b2d2a01e51341a3bfec809198952c8c830a7899f4cb6ecd3c1dc0b5d9a2af943", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "deleted" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [ + "packages/experimental/agent-team/src/types.ts#TeamTaskStatus" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 24, + "optional": true + }, + { + "name": "seq", + "type": 17, + "optional": false + }, + { + "name": "time", + "type": 17, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "error", + "type": 29, + "optional": true + }, + { + "name": "isError", + "type": 6, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "parentCallId", + "type": 7, + "optional": false + }, + { + "name": "rootCallId", + "type": 7, + "optional": false + }, + { + "name": "subCallId", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 9, + 11, + 13, + 15, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 3, + "optional": false + }, + { + "name": "isError", + "type": 6, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 16, + "optional": false + }, + { + "name": "offloaded", + "type": 24, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 17, + "optional": false + }, + { + "name": "width", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 17, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "reason", + "type": 7, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool/ptc-dispatch" + } + ] + }, + "names": [ + "event:tool/ptc-dispatch" + ], + "sources": [] + }, + { + "digest": "b38f206d59bad891fa58c89f97a0036987b3defe7685acbd318fa55eb85f9751", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "disposed" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b4d298d90c798fa4d1f5b030ce3ce8031c4c41beafdb05323bec8b2a06903b43", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + }, + { + "name": "summary", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[5]", + "event:system/message.data.message.source[4]" + ], + "sources": [] + }, + { + "digest": "b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 16, + "optional": true + }, + { + "name": "seq", + "type": 11, + "optional": false + }, + { + "name": "time", + "type": 11, + "optional": false + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "item", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 3, + "optional": true + }, + { + "name": "createdAt", + "type": 11, + "optional": false + }, + { + "name": "messageId", + "type": 12, + "optional": false + }, + { + "name": "note", + "type": 12, + "optional": true + }, + { + "name": "rating", + "type": 13, + "optional": false + }, + { + "name": "updatedAt", + "type": 11, + "optional": false + }, + { + "name": "version", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "negative" + }, + { + "kind": "literal", + "value": "positive" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "feedback/message-put" + } + ] + }, + "names": [ + "event:feedback/message-put" + ], + "sources": [] + }, + { + "digest": "b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 11, + "optional": true + }, + { + "name": "seq", + "type": 12, + "optional": false + }, + { + "name": "time", + "type": 12, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "category", + "type": 2, + "optional": true + }, + { + "name": "text", + "type": 10, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ] + }, + { + "kind": "literal", + "value": "instruction-following" + }, + { + "kind": "literal", + "value": "other" + }, + { + "kind": "literal", + "value": "product-interaction" + }, + { + "kind": "literal", + "value": "resource-cost" + }, + { + "kind": "literal", + "value": "security-privacy-permission" + }, + { + "kind": "literal", + "value": "service-stability" + }, + { + "kind": "literal", + "value": "task-result" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "feedback/record" + } + ] + }, + "names": [ + "event:feedback/record" + ], + "sources": [] + }, + { + "digest": "b56f6a885da3dc394c69a3e3cc5c0cfc4da15601b63fda4989eee8f40efc5be4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "messageSeqs", + "type": 1, + "optional": false + }, + { + "name": "source", + "type": 3, + "optional": false + }, + { + "name": "title", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 4, + 8, + 10 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 5, + "optional": false + }, + { + "name": "model", + "type": 6, + "optional": true + }, + { + "name": "provider", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "provider" + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 7, + "optional": false + }, + { + "name": "provider", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "fallback" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "packages/session/session-title/src/types.ts#SessionTitleEventData" + ], + "sources": [ + "packages/session/session-title/src/types.ts" + ] + }, + { + "digest": "b57a2889408de36e4516807194c73bdecd51a92f633ccd05db81bf049200f420", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "failed" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b57ae1b37e52bee0a21cbdace168dc6a15582bcda8c306dad962c5dcc8a8e28b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "team/task" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b6ef9c6210be8350cd465f485cf520031fffa6bf3809c61a1e713e834c5982d0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "completed" + } + ] + }, + "names": [ + "event:turn/end.data.reason[0]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "b765ee31033cea463863faf3fc6a0a1b85c47c6a2f13fe1ce833abe56105114b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "set" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 10, + "optional": true + }, + { + "name": "seq", + "type": 7, + "optional": false + }, + { + "name": "time", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 8 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "agentModel", + "type": 3, + "optional": true + }, + { + "name": "agentProvider", + "type": 3, + "optional": true + }, + { + "name": "agentReasoningEffort", + "type": 3, + "optional": true + }, + { + "name": "label", + "type": 3, + "optional": false + }, + { + "name": "mode", + "type": 4, + "optional": false + }, + { + "name": "persona", + "type": 3, + "optional": true + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "toolFilter", + "type": 5, + "optional": true + }, + { + "name": "version", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "continuable" + }, + { + "kind": "object", + "properties": [ + { + "name": "allow", + "type": 6, + "optional": true + }, + { + "name": "deny", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "label", + "type": 3, + "optional": true + }, + { + "name": "mode", + "type": 9, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "one-shot" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "subagent/descriptor" + } + ] + }, + "names": [ + "event:subagent/descriptor" + ], + "sources": [] + }, + { + "digest": "b815d7b91cdd9fc6ccc7dcba05cfc5ce1d55fab5fc0c0801803cd3630cedb602", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "goal" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b81e9de81a481b24e1e1f9adf038bfc59e57b4f35ce62f8f1e45284186f4f812", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + }, + { + "name": "model", + "type": 2, + "optional": true + }, + { + "name": "provider", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "provider" + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:session/title.data.source[1]" + ], + "sources": [ + "packages/session/session-title/src/types.ts" + ] + }, + { + "digest": "b8327af7ee5767952d1300cb4f03b7fc04197ae5ba275e13981c689ff7506172", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "literal", + "value": "complete" + }, + { + "kind": "literal", + "value": "paused" + } + ] + }, + "names": [ + "packages/goal/goal/src/types.ts#GoalPhase" + ], + "sources": [ + "packages/goal/goal/src/types.ts" + ] + }, + { + "digest": "b8fc636a2121df9d8423c242e03c9d23b7ab7c6fdce00e45746932c60b730f97", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 1, + "optional": true + }, + { + "name": "path", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/fs/tool-present/src/types.ts#PresentedFile" + ], + "sources": [ + "packages/fs/tool-present/src/types.ts" + ] + }, + { + "digest": "b9305f0ea75ccd6a6061c27fde19f2ab85534f9f3c1a717b573b077ebae0f611", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "hook/invoked" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 9, + "optional": true + }, + { + "name": "seq", + "type": 10, + "optional": false + }, + { + "name": "time", + "type": 10, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "todos", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 3 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 4, + "optional": false + }, + { + "name": "status", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 6, + 7, + 8 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "todo/write" + } + ] + }, + "names": [ + "event:todo/write" + ], + "sources": [] + }, + { + "digest": "b993441f8ce7d27b80e619e113e232ae8e62d3d5a8340f6bfe12d8c4c018e62f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "tuple", + "elements": [ + { + "type": 1, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 2, + "optional": false + }, + { + "name": "role", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 3, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request.data.body.messages" + ], + "sources": [] + }, + { + "digest": "ba77b58995e36f14bb13886b0493d0a1a63d5db10b1a6cd9f6ac65a72cf832ec", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:subagent/model-selection-policy.data.allowedModels" + ], + "sources": [] + }, + { + "digest": "bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 29, + "optional": true + }, + { + "name": "seq", + "type": 14, + "optional": false + }, + { + "name": "time", + "type": 14, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 5, + 7, + 9, + 11, + 16 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "interrupted" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 12, + "optional": false + }, + { + "name": "kind", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 13, + "optional": false + }, + { + "name": "message", + "type": 13, + "optional": false + }, + { + "name": "offloadImages", + "type": 14, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 14, + "optional": true + }, + { + "name": "requestId", + "type": 13, + "optional": true + }, + { + "name": "status", + "type": 14, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 17, + "optional": false + }, + { + "name": "reason", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "union", + "types": [ + 19, + 21, + 23, + 25, + 27 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 28, + "optional": false + }, + { + "name": "reason", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "turn/end" + } + ] + }, + "names": [ + "event:turn/end" + ], + "sources": [] + }, + { + "digest": "babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 8, + "optional": true + }, + { + "name": "seq", + "type": 7, + "optional": false + }, + { + "name": "time", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "outcome", + "type": 2, + "optional": false + }, + { + "name": "runId", + "type": 6, + "optional": false + }, + { + "name": "seq", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 3, + 4, + 5 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "tool-workflow/agent-end" + } + ] + }, + "names": [ + "event:tool-workflow/agent-end" + ], + "sources": [] + }, + { + "digest": "bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 8, + "optional": true + }, + { + "name": "seq", + "type": 9, + "optional": false + }, + { + "name": "time", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "outcome", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5, + 6, + 7 + ] + }, + { + "kind": "literal", + "value": "allowed-once" + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "rejected" + }, + { + "kind": "literal", + "value": "unavailable" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "approval/decided" + } + ] + }, + "names": [ + "event:approval/decided" + ], + "sources": [] + }, + { + "digest": "bb72d86bc9ef0b3908bfa57ef98ccccae24d67d945c9f6869ca3cb8577889e75", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "union", + "types": [ + 2, + 5, + 7, + 9, + 20, + 23 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 10, + "optional": false + }, + { + "name": "offloaded", + "type": 18, + "optional": true + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 11, + "optional": false + }, + { + "name": "width", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 21, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 0, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].content", + "event:agent/inbox/spliced.data.inserted[0].content[0][5].content", + "event:assistant/message.data.message.content", + "event:compaction/summary.data[0].rawOutput", + "event:compaction/summary.data[0].summary", + "event:compaction/summary.data[1].rawOutput", + "event:compaction/summary.data[1].summary", + "event:session/title-llm-request.data.messages[0].content", + "event:system/message.data.message.content", + "event:team/message/queued.data.message.content", + "event:tool/ptc-dispatch.data.content" + ], + "sources": [] + }, + { + "digest": "bbc5696e3f13c758237b316e3cf08cda0b9fd51ffe672539883457769faa185d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[8].replayState", + "event:assistant/attempt.data.stream[0][3].chunk[6].replayState.blocks[0]", + "event:assistant/attempt.data.stream[0][3].chunk[6].replayState.response", + "event:request/header.data.header.tools[0].parameters.[value]", + "event:tool/ptc-dispatch-start.data.arguments", + "event:tool/ptc-dispatch.data.arguments" + ], + "sources": [] + }, + { + "digest": "bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "endSeq", + "type": 1, + "optional": false + }, + { + "name": "op", + "type": 2, + "optional": false + }, + { + "name": "startSeq", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "replace" + } + ] + }, + "names": [ + "SessionEventEnvelope[6].surfaceOp[1]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "bd499eac047efe091a4df7382eadd06d25cf0cb31fee3981e8b24d85762841cd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "finish" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "bf16d2e98a7f13894ded2cffe5ce857bf473954a0e3c0ed9bc7739e2e1c7b78a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "subagent-settled" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "outcome", + "type": 1, + "optional": false + }, + { + "name": "runId", + "type": 5, + "optional": false + }, + { + "name": "seq", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 3, + 4 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData" + ], + "sources": [ + "packages/workflow/tool-workflow/src/types.ts" + ] + }, + { + "digest": "c170da8ab7c37635b10867b2571811d9e317ac3ec394e8ff8efe53f902fc41c1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 6 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 2, + "optional": false + }, + { + "name": "failure", + "type": 3, + "optional": false + }, + { + "name": "maxRetries", + "type": 2, + "optional": false + }, + { + "name": "mode", + "type": 5, + "optional": false + }, + { + "name": "policyKey", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + }, + { + "name": "retry", + "type": 2, + "optional": false + }, + { + "name": "retryId", + "type": 4, + "optional": false + }, + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 4, + "optional": false + }, + { + "name": "message", + "type": 4, + "optional": false + }, + { + "name": "offloadImages", + "type": 2, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 2, + "optional": true + }, + { + "name": "requestId", + "type": 4, + "optional": true + }, + { + "name": "status", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "normal" + }, + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 2, + "optional": false + }, + { + "name": "failure", + "type": 3, + "optional": false + }, + { + "name": "mode", + "type": 7, + "optional": false + }, + { + "name": "policyKey", + "type": 4, + "optional": false + }, + { + "name": "provider", + "type": 4, + "optional": false + }, + { + "name": "retry", + "type": 2, + "optional": false + }, + { + "name": "retryId", + "type": 4, + "optional": false + }, + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "always" + } + ] + }, + "names": [ + "packages/llm/llm-retry/src/types.ts#LlmRetryEventData" + ], + "sources": [ + "packages/llm/llm-retry/src/types.ts" + ] + }, + { + "digest": "c1f0f17b6493b85db6453bb30e01b208d703731b25bc1e68e5d4fc72eea9cdea", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ToolCallBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "runId", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-workflow/run-start" + } + ] + }, + "names": [ + "event:tool-workflow/run-start" + ], + "sources": [] + }, + { + "digest": "c219efbdfd53b836786202ab4532913d555798f0a8615a4e9629736e3799fb70", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "step/end" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "c2deb7c9183735d4e0fffddf5c623f4e34daa1c8e96b111982e957dfcbbcf896", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "cancelled" + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "failed" + } + ] + }, + "names": [ + "packages/workflow/workflow/src/types.ts#WorkflowAgentOutcome" + ], + "sources": [ + "packages/workflow/workflow/src/types.ts" + ] + }, + { + "digest": "c43b119ce579b3e9983a0d3adc4ba402ebb9ba773d89738a2dab01ecf5813943", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "paused" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "c55a891c7aac496de6ee64c91c1fb65728c977314013033e42c863428aada854", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "adapterDefaults", + "type": 1, + "optional": true + }, + { + "name": "config", + "type": 3, + "optional": false + }, + { + "name": "tools", + "type": 7, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 2, + "optional": true + }, + { + "name": "reasoningEffort", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 4, + "optional": true + }, + { + "name": "model", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 5, + "optional": true + }, + { + "name": "stop", + "type": 6, + "optional": true + }, + { + "name": "temperature", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "array", + "element": 8 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "parameters", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 5, + "value": 10 + } + ] + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#EpochHeader" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "c589e938cc0e4989df8b82abef6339de621f0dc4fe62c230d145b94996af7f92", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool/call" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "c592ce75aab73fcab19c1d7845684c72cf402b78d2e1f2833a58ecf9f3598ed6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + { + "kind": "array", + "element": 0 + }, + { + "kind": "object", + "properties": [], + "indices": [ + { + "key": 3, + "value": 0 + } + ] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:tool/result.data.meta", + "packages/util/values/src/index.ts#JsonValue" + ], + "sources": [ + "packages/util/values/src/index.ts" + ] + }, + { + "digest": "c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "text", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[4].sections" + ], + "sources": [] + }, + { + "digest": "c7b24be059d34d08929593049a1a81eaa3855166aacfe9d7603c0bc8bb728d56", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 4, + 6, + 8, + 19, + 22 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 9, + "optional": false + }, + { + "name": "offloaded", + "type": 17, + "optional": true + }, + { + "name": "type", + "type": 18, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "mediaType", + "type": 11, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "originalDimensions", + "type": 16, + "optional": true + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 12, + 13, + 14, + 15 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 10, + "optional": false + }, + { + "name": "width", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 20, + "optional": false + }, + { + "name": "type", + "type": 21, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 10, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 23, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 0 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ContentBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 26, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 72, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "stream", + "type": 3, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "union", + "types": [ + 5, + 10, + 68, + 70 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "args", + "type": 6, + "optional": false + }, + { + "name": "dt", + "type": 8, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "literal", + "value": "tool-call-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 11, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 67, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 12, + 14, + 40, + 43, + 45, + 47, + 64 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 15, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 39, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 16, + 18, + 28, + 31, + 35, + 37 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 7, + "optional": false + }, + { + "name": "id", + "type": 7, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 19, + "optional": false + }, + { + "name": "offloaded", + "type": 26, + "optional": true + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "mediaType", + "type": 20, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": true + }, + { + "name": "originalDimensions", + "type": 25, + "optional": true + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 21, + 22, + 23, + 24 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 29, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 7, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 32, + "optional": false + }, + { + "name": "isError", + "type": 33, + "optional": true + }, + { + "name": "toolCallId", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 15 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 36, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 41, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 42, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 17, + 27, + 30, + 34, + 36, + 38 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "text", + "type": 7, + "optional": false + }, + { + "name": "type", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 48, + "optional": false + }, + { + "name": "replayState", + "type": 60, + "optional": true + }, + { + "name": "type", + "type": 63, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 49, + 52, + 54, + 56, + 58 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 51, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 7, + "optional": false + }, + { + "name": "message", + "type": 7, + "optional": false + }, + { + "name": "offloadImages", + "type": 2, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 2, + "optional": true + }, + { + "name": "requestId", + "type": 7, + "optional": true + }, + { + "name": "status", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 50, + "optional": false + }, + { + "name": "kind", + "type": 53, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 57, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 59, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 61, + "optional": true + }, + { + "name": "response", + "type": 62, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 62 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 65, + "optional": false + }, + { + "name": "usage", + "type": 66, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 2, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 2, + "optional": true + }, + { + "name": "inputTokens", + "type": 2, + "optional": false + }, + { + "name": "outputTokens", + "type": 2, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 2, + "optional": true + }, + { + "name": "totalTokens", + "type": 2, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 8, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "texts", + "type": 6, + "optional": false + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 69, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-chunks" + }, + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 8, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "texts", + "type": 6, + "optional": false + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 71, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-chunks" + }, + { + "kind": "literal", + "value": "assistant/attempt" + } + ] + }, + "names": [ + "event:assistant/attempt" + ], + "sources": [] + }, + { + "digest": "c8e6f48878cc2a2f0dc59682280d81f407943fb503f32c64bf9ff3d9393c3eff", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "active" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "c93b6f51b399607349b4bcc66b58e848a44250ffc1e2537207bd092dfff94192", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "chunk", + "type": 1, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 59, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 6, + 32, + 35, + 37, + 39, + 56 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "argumentsDelta", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "index", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool-call-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "block", + "type": 7, + "optional": false + }, + { + "name": "index", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 31, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 8, + 10, + 20, + 23, + 27, + 29 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 11, + "optional": false + }, + { + "name": "offloaded", + "type": 18, + "optional": true + }, + { + "name": "type", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 4, + "optional": false + }, + { + "name": "height", + "type": 4, + "optional": false + }, + { + "name": "mediaType", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 17, + "optional": true + }, + { + "name": "width", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 13, + 14, + 15, + 16 + ] + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 4, + "optional": false + }, + { + "name": "width", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 21, + "optional": false + }, + { + "name": "type", + "type": 22, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 24, + "optional": false + }, + { + "name": "isError", + "type": 25, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "block-end" + }, + { + "kind": "object", + "properties": [ + { + "name": "blockType", + "type": 33, + "optional": false + }, + { + "name": "index", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 9, + 19, + 22, + 26, + 28, + 30 + ] + }, + { + "kind": "literal", + "value": "block-start" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 4, + "optional": false + }, + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 36, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "index", + "type": 4, + "optional": false + }, + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 38, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text-delta" + }, + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 40, + "optional": false + }, + { + "name": "replayState", + "type": 52, + "optional": true + }, + { + "name": "type", + "type": 55, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 41, + 44, + 46, + 48, + 50 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 43, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "offloadImages", + "type": 4, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 4, + "optional": true + }, + { + "name": "requestId", + "type": 3, + "optional": true + }, + { + "name": "status", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "object", + "properties": [ + { + "name": "failure", + "type": 42, + "optional": false + }, + { + "name": "kind", + "type": 45, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 47, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 49, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "stop" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 51, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-calls" + }, + { + "kind": "object", + "properties": [ + { + "name": "blocks", + "type": 53, + "optional": true + }, + { + "name": "response", + "type": 54, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 54 + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "literal", + "value": "finish" + }, + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 57, + "optional": false + }, + { + "name": "usage", + "type": 58, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 4, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 4, + "optional": true + }, + { + "name": "inputTokens", + "type": 4, + "optional": false + }, + { + "name": "outputTokens", + "type": 4, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 4, + "optional": true + }, + { + "name": "totalTokens", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "chunk" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3]" + ], + "sources": [ + "packages/llm/llm/src/assistant-stream.ts" + ] + }, + { + "digest": "c99e20441bf15341e9db54385e558e5c03d21dff2eb1ac08ccbf47c2d8747954", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "feedback/record" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ca085dba2c877feceebf3c62f9d39c6c2a4d2314d97b94b3927a780fe8fe2bb2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "sandbox/mode" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ca59530d1a4f3e191b4032bc4a20eded0d827db8b5a7efb27b3af9e9b456c6f2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 1, + "optional": false + }, + { + "name": "error", + "type": 1, + "optional": true + }, + { + "name": "sourceCommandId", + "type": 1, + "optional": true + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 3, + 4 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:compaction/end.data" + ], + "sources": [ + "packages/compaction/compaction/src/types.ts" + ] + }, + { + "digest": "ca6425edd20afe34d0cedc6ad1abad1ad7b32e2fbc4c1d24db53939e80bf887f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "operation", + "type": 1, + "optional": false + }, + { + "name": "schedule", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "union", + "types": [ + 3, + 7, + 9 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "afterSeconds", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "prompt", + "type": 5, + "optional": false + }, + { + "name": "scheduledAt", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "after" + }, + { + "kind": "object", + "properties": [ + { + "name": "everySeconds", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 8, + "optional": false + }, + { + "name": "prompt", + "type": 5, + "optional": false + }, + { + "name": "scheduledAt", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "every" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "kind", + "type": 10, + "optional": false + }, + { + "name": "prompt", + "type": 5, + "optional": false + }, + { + "name": "scheduledAt", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "at" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#ScheduleCreateChange" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "cbca49bde16b656d5b8fbe4a8a507769f7b594c6287782b809c03814941bc5e3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "block-start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "cd186c309e2bef305705e1d324139240f5e681f4f6a957d6a25b0225f65560df", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "approval/asked" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "cdca80b8dad24d4e7b1d5a288a8475ba8d8d46be385bd2da85f122ee836f1670", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-workflow/run-start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "cdee10e87dbed8440d8b6935888624884878efc7af95402e94171b29f173dced", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "delayMs", + "type": 1, + "optional": false + }, + { + "name": "failure", + "type": 2, + "optional": false + }, + { + "name": "maxRetries", + "type": 1, + "optional": false + }, + { + "name": "mode", + "type": 4, + "optional": false + }, + { + "name": "policyKey", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "retry", + "type": 1, + "optional": false + }, + { + "name": "retryId", + "type": 3, + "optional": false + }, + { + "name": "step", + "type": 1, + "optional": false + }, + { + "name": "turn", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 3, + "optional": false + }, + { + "name": "message", + "type": 3, + "optional": false + }, + { + "name": "offloadImages", + "type": 1, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 1, + "optional": true + }, + { + "name": "requestId", + "type": 3, + "optional": true + }, + { + "name": "status", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "normal" + } + ] + }, + "names": [ + "event:llm/retry.data[0]" + ], + "sources": [ + "packages/llm/llm-retry/src/types.ts" + ] + }, + { + "digest": "cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 15, + "optional": true + }, + { + "name": "seq", + "type": 4, + "optional": false + }, + { + "name": "time", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "apiVersion", + "type": 2, + "optional": false + }, + { + "name": "body", + "type": 3, + "optional": false + }, + { + "name": "endpoint", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "object", + "properties": [ + { + "name": "max_tokens", + "type": 4, + "optional": false + }, + { + "name": "messages", + "type": 5, + "optional": false + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "tools", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 6, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 7, + "optional": false + }, + { + "name": "role", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "tuple", + "elements": [ + { + "type": 8, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "tuple", + "elements": [ + { + "type": 12, + "optional": false, + "rest": false + } + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "max_uses", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 13, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "web_search" + }, + { + "kind": "literal", + "value": "web_search_20250305" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "web/deepseek-search-llm-request" + } + ] + }, + "names": [ + "event:web/deepseek-search-llm-request" + ], + "sources": [] + }, + { + "digest": "cffcdc19881ab61ec0a9ce18743996f7ac44ac8889f34dfac36ae745574aa22f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "cleared", + "type": 1, + "optional": false + }, + { + "name": "clearedAt", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 4, + "optional": false + }, + { + "name": "operation", + "type": 5, + "optional": false + }, + { + "name": "version", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "revision", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "goal/change" + }, + { + "kind": "literal", + "value": "clear" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/goal/goal/src/domain.ts#GoalClearChangeMeta" + ], + "sources": [ + "packages/goal/goal/src/domain.ts" + ] + }, + { + "digest": "d0fbb0ca1bbba059830826f33f801da1aced35a2504376d61e020bdfec8d50c0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "delete" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "d28765f87d6b6ab408e0b2f3e7e297791b004b806d8e302c49903ebae815feb2", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "one-shot" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "d3e447062a2847dad847dad5168a9508d92c484363dfc76fd82605aa7bd46285", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "reason", + "type": 1, + "optional": false + }, + { + "name": "turn", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 4, + 6, + 11, + 24, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "interrupted" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "max-tokens" + }, + { + "kind": "object", + "properties": [ + { + "name": "error", + "type": 7, + "optional": false + }, + { + "name": "kind", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "code", + "type": 8, + "optional": false + }, + { + "name": "message", + "type": 8, + "optional": false + }, + { + "name": "offloadImages", + "type": 9, + "optional": true + }, + { + "name": "providerRetryAfterMs", + "type": 9, + "optional": true + }, + { + "name": "requestId", + "type": 8, + "optional": true + }, + { + "name": "status", + "type": 9, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "error" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 12, + "optional": false + }, + { + "name": "reason", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "aborted" + }, + { + "kind": "union", + "types": [ + 14, + 16, + 18, + 20, + 22 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "disposed" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 17, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 19, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "parent" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 21, + "optional": false + }, + { + "name": "reason", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "hook" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "blocked" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "completed" + } + ] + }, + "names": [ + "event:turn/end.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "d4e4d575abeb4b72d616dc65c17ac0eaa943cc135609395044c38d5afcb10e31", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "canceled" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 12, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "task", + "type": 2, + "optional": false + }, + { + "name": "teamId", + "type": 4, + "optional": false + }, + { + "name": "version", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "blockedBy", + "type": 3, + "optional": false + }, + { + "name": "description", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "ownerId", + "type": 4, + "optional": true + }, + { + "name": "revision", + "type": 5, + "optional": false + }, + { + "name": "status", + "type": 6, + "optional": false + }, + { + "name": "subject", + "type": 4, + "optional": false + }, + { + "name": "writeScopes", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 7, + 8, + 9, + 10 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "deleted" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + }, + { + "kind": "literal", + "value": 2 + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "team/task" + } + ] + }, + "names": [ + "event:team/task" + ], + "sources": [] + }, + { + "digest": "d61574d68558c5a184429e70b04da393dd5460bf5cc3ddef814546e659bd5127", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "isError", + "type": 24, + "optional": true + }, + { + "name": "toolCallId", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 0, + 3, + 6, + 8, + 10, + 21 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 4, + "optional": false + }, + { + "name": "id", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 11, + "optional": false + }, + { + "name": "offloaded", + "type": 19, + "optional": true + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 12, + "optional": false + }, + { + "name": "height", + "type": 12, + "optional": false + }, + { + "name": "mediaType", + "type": 13, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": true + }, + { + "name": "originalDimensions", + "type": 18, + "optional": true + }, + { + "name": "width", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 14, + 15, + 16, + 17 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 12, + "optional": false + }, + { + "name": "width", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 22, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 4, + "optional": false + }, + { + "name": "bytes", + "type": 12, + "optional": false + }, + { + "name": "name", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#ToolResultBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "sessionFormatVersion", + "type": 2, + "optional": true + }, + { + "name": "sessionId", + "type": 3, + "optional": false + }, + { + "name": "throughSeq", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "session-log-deepseek/delivery-accepted" + } + ] + }, + "names": [ + "event:session-log-deepseek/delivery-accepted" + ], + "sources": [] + }, + { + "digest": "d6e654b88b584fcdf290a56802b1730bc7b9847ae86baa4265ab7769eb48990c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "fallback" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "d8f868c6b3e7189de6c1ffe2ea04794ea2aa31315b6347d12536e46020afac87", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 5, + 7 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "afterSeconds", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 4, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "after" + }, + { + "kind": "object", + "properties": [ + { + "name": "everySeconds", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 6, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "every" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "kind", + "type": 8, + "optional": false + }, + { + "name": "prompt", + "type": 3, + "optional": false + }, + { + "name": "scheduledAt", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "at" + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#ScheduleRecord" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "d9196086e41e4dd5c2ce87f5c25529c8112a1731d258cf0728747d41a9ee3241", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "complete" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "d9c462b9f62fdd3efc76a44b9524dc8781f6b91cd9c7e584b17d971defafebab", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool" + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#ToolMessageSource" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "dacf3d5f3e4ff619c1320e64a48dec5e7ecd7870bece65fbd449a0e63adfa521", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": true + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "db6c5246911d47a7969f6b4cb47c7d0dbbde75c402710b22ace3672fa97bebe0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "webhook" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 6, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 7, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 2, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 2, + "optional": true + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "union", + "types": [ + 4, + 5 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "compaction/start" + } + ] + }, + "names": [ + "event:compaction/start" + ], + "sources": [] + }, + { + "digest": "dbdafceb9a900183cccc80596498d386f3bf7bddead2b8cfde68453aa4739edc", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "hook" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "dd2780e7e07684332f7a9ab047237798d260e7eaffb1321cb38eca695d184c3d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "fresh" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "dda6e111a8ccfc12f6e742e977a1a4e3549e8c03732a5ff6c8d7c3d4bcb7a412", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[2]", + "event:system/message.data.message.source[1]" + ], + "sources": [] + }, + { + "digest": "de25352d2dc4196309bd84b5bac6319f6d5c898ea0e82bb5ae66c5738d0d426f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "user/message" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "de30b1fa12c75f81df6aa4096e1595296d2d04e2be14a7c29849cf8028b79048", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "image/gif" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "df5d9709b7db2a72510dc52052a23f0c38f39730af1504bab8bccabc14fae528", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "positive" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "df843efd87c78cf8de98f8e0d0216956cd568d0d0e56a22c853663e274aa1a18", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "array", + "element": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 2, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 3, + "optional": false + }, + { + "name": "compacted", + "type": 5, + "optional": false + }, + { + "name": "inputIndex", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 6, + "optional": false + }, + { + "name": "omittedBytes", + "type": 2, + "optional": false + }, + { + "name": "omittedMessages", + "type": 2, + "optional": false + }, + { + "name": "originalMessages", + "type": 2, + "optional": false + }, + { + "name": "retainedMessages", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 6, + "optional": false + }, + { + "name": "truncated", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 2, + 4 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[15].references" + ], + "sources": [] + }, + { + "digest": "dfce5db4aa42b7ebe0bb79eca92553587287e18c06b9eba85cbfb9d332e26acd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "active" + }, + { + "kind": "literal", + "value": "failed" + }, + { + "kind": "literal", + "value": "provisioning" + } + ] + }, + "names": [ + "packages/experimental/agent-team/src/types.ts#TeamMemberPhase" + ], + "sources": [ + "packages/experimental/agent-team/src/types.ts" + ] + }, + { + "digest": "e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 3, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "step/end" + } + ] + }, + "names": [ + "event:step/end" + ], + "sources": [] + }, + { + "digest": "e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 19, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 91, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "maxTokens", + "type": 2, + "optional": false + }, + { + "name": "messageSeqs", + "type": 3, + "optional": false + }, + { + "name": "messages", + "type": 4, + "optional": false + }, + { + "name": "route", + "type": 90, + "optional": false + }, + { + "name": "system", + "type": 9, + "optional": false + }, + { + "name": "titleProvider", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "id", + "type": 9, + "optional": false + }, + { + "name": "role", + "type": 31, + "optional": false + }, + { + "name": "source", + "type": 35, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "union", + "types": [ + 8, + 11, + 21, + 24, + 27, + 29 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 9, + "optional": false + }, + { + "name": "id", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 12, + "optional": false + }, + { + "name": "offloaded", + "type": 19, + "optional": true + }, + { + "name": "type", + "type": 20, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 9, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "mediaType", + "type": 13, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": true + }, + { + "name": "originalDimensions", + "type": 18, + "optional": true + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 14, + 15, + 16, + 17 + ] + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 2, + "optional": false + }, + { + "name": "width", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 22, + "optional": false + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 9, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "isError", + "type": 25, + "optional": true + }, + { + "name": "toolCallId", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 9, + "optional": false + }, + { + "name": "type", + "type": 30, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "union", + "types": [ + 32, + 33, + 34 + ] + }, + { + "kind": "literal", + "value": "system" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "literal", + "value": "user" + }, + { + "kind": "union", + "types": [ + 36, + 45, + 47, + 48, + 51, + 56, + 58, + 63, + 64, + 65, + 67, + 69, + 70, + 77, + 79, + 81, + 83, + 85, + 88, + 89 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "baseline", + "type": 19, + "optional": true + }, + { + "name": "baselineIdentity", + "type": 9, + "optional": true + }, + { + "name": "changes", + "type": 37, + "optional": false + }, + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 44, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 38 + }, + { + "kind": "object", + "properties": [ + { + "name": "action", + "type": 39, + "optional": false + }, + { + "name": "digest", + "type": 9, + "optional": true + }, + { + "name": "path", + "type": 9, + "optional": false + }, + { + "name": "scope", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 40, + 41, + 42 + ] + }, + { + "kind": "literal", + "value": "remove" + }, + { + "kind": "literal", + "value": "replace" + }, + { + "kind": "literal", + "value": "set" + }, + { + "kind": "literal", + "value": "instructions" + }, + { + "kind": "literal", + "value": "agent-instructions" + }, + { + "kind": "object", + "properties": [ + { + "name": "callId", + "type": 9, + "optional": false + }, + { + "name": "kind", + "type": 46, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool" + }, + { + "kind": "object", + "properties": [ + { + "name": "clientTimeZone", + "type": 9, + "optional": true + }, + { + "name": "kind", + "type": 34, + "optional": false + }, + { + "name": "rpcId", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "deliveryId", + "type": 9, + "optional": false + }, + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 50, + "optional": false + }, + { + "name": "provider", + "type": 9, + "optional": false + }, + { + "name": "ruleId", + "type": 9, + "optional": false + }, + { + "name": "source", + "type": 9, + "optional": false + }, + { + "name": "summary", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "notice" + }, + { + "kind": "literal", + "value": "webhook" + }, + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 52, + "optional": false + }, + { + "name": "form", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 55, + "optional": false + }, + { + "name": "update", + "type": 19, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 53 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 9, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 57, + "optional": false + }, + { + "name": "name", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "skill-invocation" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 59, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + }, + { + "name": "sections", + "type": 61, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "array", + "element": 62 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 9, + "optional": false + }, + { + "name": "text", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + }, + { + "name": "summary", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 43, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 66, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 68, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "relay" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 54, + "optional": false + }, + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 66, + "optional": false + }, + { + "name": "kind", + "type": 71, + "optional": false + }, + { + "name": "references", + "type": 72, + "optional": false + }, + { + "name": "version", + "type": 76, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 73 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 2, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 74, + "optional": false + }, + { + "name": "compacted", + "type": 25, + "optional": false + }, + { + "name": "inputIndex", + "type": 2, + "optional": false + }, + { + "name": "label", + "type": 9, + "optional": false + }, + { + "name": "omittedBytes", + "type": 2, + "optional": false + }, + { + "name": "omittedMessages", + "type": 2, + "optional": false + }, + { + "name": "originalMessages", + "type": 2, + "optional": false + }, + { + "name": "retainedMessages", + "type": 2, + "optional": false + }, + { + "name": "sessionId", + "type": 9, + "optional": false + }, + { + "name": "truncated", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 75 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 49, + "optional": false + }, + { + "name": "kind", + "type": 78, + "optional": false + }, + { + "name": "senderSessionId", + "type": 9, + "optional": false + }, + { + "name": "summary", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "subagent-settled" + }, + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 68, + "optional": false + }, + { + "name": "kind", + "type": 80, + "optional": false + }, + { + "name": "senderSessionId", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "agent-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "goalId", + "type": 9, + "optional": false + }, + { + "name": "kind", + "type": 82, + "optional": false + }, + { + "name": "revision", + "type": 2, + "optional": false + }, + { + "name": "round", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "goal" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 84, + "optional": false + }, + { + "name": "messageId", + "type": 9, + "optional": false + }, + { + "name": "senderId", + "type": 9, + "optional": false + }, + { + "name": "senderName", + "type": 9, + "optional": false + }, + { + "name": "teamId", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "team-message" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 86, + "optional": false + }, + { + "name": "model", + "type": 9, + "optional": false + }, + { + "name": "provider", + "type": 9, + "optional": false + }, + { + "name": "replayState", + "type": 87, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 60, + "optional": false + }, + { + "name": "plugin", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 34, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 9, + "optional": false + }, + { + "name": "provider", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "session/title-llm-request" + } + ] + }, + "names": [ + "event:session/title-llm-request" + ], + "sources": [] + }, + { + "digest": "e1d0e52dcd1855ffb803efc18f8f7b776c48d1c25757e8a75c0281fa298c02e1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 5, + 7, + 8 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "acceptedAt", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "operation", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "dispatch" + }, + { + "kind": "literal", + "value": 1 + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "operation", + "type": 6, + "optional": false + }, + { + "name": "version", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "delete" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "operation", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "operation", + "type": 9, + "optional": false + }, + { + "name": "schedule", + "type": 10, + "optional": false + }, + { + "name": "version", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "create" + }, + { + "kind": "union", + "types": [ + 11, + 14, + 16 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "afterSeconds", + "type": 12, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 13, + "optional": false + }, + { + "name": "prompt", + "type": 2, + "optional": false + }, + { + "name": "scheduledAt", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "after" + }, + { + "kind": "object", + "properties": [ + { + "name": "everySeconds", + "type": 12, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 15, + "optional": false + }, + { + "name": "prompt", + "type": 2, + "optional": false + }, + { + "name": "scheduledAt", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "every" + }, + { + "kind": "object", + "properties": [ + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "kind", + "type": 17, + "optional": false + }, + { + "name": "prompt", + "type": 2, + "optional": false + }, + { + "name": "scheduledAt", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "at" + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#ScheduleChange" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "e2d0367e5716bc188435e51718ebff8ce873190625fa93b1c5331102d98758fa", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "compaction/start" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e31572180d6b28b73f073ad30ae19d5d82982d3daf984723984e23da1e7c459a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "provider" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e3e77b26f0148755a505f5b8ea843a3be117827d4703bb5754d9dc8ddbef521f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "ignorable", + "type": 1, + "optional": true + }, + { + "name": "seq", + "type": 2, + "optional": false + }, + { + "name": "time", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "SessionEventEnvelope[0]", + "SessionEventEnvelope[10]", + "SessionEventEnvelope[11]", + "SessionEventEnvelope[12]", + "SessionEventEnvelope[13]", + "SessionEventEnvelope[14]", + "SessionEventEnvelope[15]", + "SessionEventEnvelope[16]", + "SessionEventEnvelope[17]", + "SessionEventEnvelope[18]", + "SessionEventEnvelope[19]", + "SessionEventEnvelope[1]", + "SessionEventEnvelope[20]", + "SessionEventEnvelope[21]", + "SessionEventEnvelope[22]", + "SessionEventEnvelope[23]", + "SessionEventEnvelope[24]", + "SessionEventEnvelope[25]", + "SessionEventEnvelope[26]", + "SessionEventEnvelope[27]", + "SessionEventEnvelope[28]", + "SessionEventEnvelope[29]", + "SessionEventEnvelope[2]", + "SessionEventEnvelope[30]", + "SessionEventEnvelope[31]", + "SessionEventEnvelope[32]", + "SessionEventEnvelope[33]", + "SessionEventEnvelope[34]", + "SessionEventEnvelope[35]", + "SessionEventEnvelope[36]", + "SessionEventEnvelope[37]", + "SessionEventEnvelope[38]", + "SessionEventEnvelope[3]", + "SessionEventEnvelope[40]", + "SessionEventEnvelope[41]", + "SessionEventEnvelope[42]", + "SessionEventEnvelope[43]", + "SessionEventEnvelope[44]", + "SessionEventEnvelope[45]", + "SessionEventEnvelope[46]", + "SessionEventEnvelope[47]", + "SessionEventEnvelope[48]", + "SessionEventEnvelope[49]", + "SessionEventEnvelope[4]", + "SessionEventEnvelope[50]", + "SessionEventEnvelope[51]", + "SessionEventEnvelope[53]", + "SessionEventEnvelope[54]", + "SessionEventEnvelope[56]", + "SessionEventEnvelope[5]", + "SessionEventEnvelope[7]", + "SessionEventEnvelope[8]", + "SessionEventEnvelope[9]" + ], + "sources": [] + }, + { + "digest": "e41bdebe246abe17154de7e7a1d81035437eee8d20e7f1edff0d91e2598ad828", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "session" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e42b0f40b5d0b628c6e1c44a8fb9eda0780037a81959e1b93d2dfb47b46b0e87", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "every" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e438a9d4fb883b3e4a8d9fc8913aa1550ed50eb384bfbf943100a5605b537498", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "append" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 1, + "optional": false + }, + { + "name": "callId", + "type": 1, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + }, + { + "name": "step", + "type": 2, + "optional": false + }, + { + "name": "turn", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:tool/call.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "e4cac694f8b6e1d52e48c699464f1c4c26111ef87e558f7931040d00fdc8d486", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "instruction-following" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e50b0a3ed8e6c80b672e4f855c91984f03b5c3fdd5d475bf171171f391a86c83", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "role", + "type": 27, + "optional": false + }, + { + "name": "source", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "union", + "types": [ + 3, + 7, + 9, + 11, + 13, + 24 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 1, + "optional": false + }, + { + "name": "isError", + "type": 4, + "optional": true + }, + { + "name": "toolCallId", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 5, + "optional": false + }, + { + "name": "id", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 14, + "optional": false + }, + { + "name": "offloaded", + "type": 22, + "optional": true + }, + { + "name": "type", + "type": 23, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 15, + "optional": false + }, + { + "name": "height", + "type": 15, + "optional": false + }, + { + "name": "mediaType", + "type": 16, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": true + }, + { + "name": "originalDimensions", + "type": 21, + "optional": true + }, + { + "name": "width", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 17, + 18, + 19, + 20 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 15, + "optional": false + }, + { + "name": "width", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 25, + "optional": false + }, + { + "name": "type", + "type": 26, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 5, + "optional": false + }, + { + "name": "bytes", + "type": 15, + "optional": false + }, + { + "name": "name", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "literal", + "value": "assistant" + }, + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 29, + "optional": false + }, + { + "name": "model", + "type": 5, + "optional": false + }, + { + "name": "provider", + "type": 5, + "optional": false + }, + { + "name": "replayState", + "type": 30, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "model" + }, + { + "kind": "opaque", + "reason": "unknown" + } + ] + }, + "names": [ + "packages/llm/llm/src/message.ts#AssistantMessage" + ], + "sources": [ + "packages/llm/llm/src/message.ts" + ] + }, + { + "digest": "e5244812c495a80c2e78ba2c2690dca5f6b58ea8d3fe5531ff94a6f9ac5e5d66", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-result" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e5d3828df1ec3e2a66879de0659e0f4866d9cfffc00825ee731a66f8a0c03d98", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "continuable" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e6063d0451dc02026fd9b54ad3f77c7b1b6392ad3e872a7737ac84e13ca72344", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "acceptedAt", + "type": 1, + "optional": false + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "operation", + "type": 2, + "optional": false + }, + { + "name": "version", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "dispatch" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/schedule/schedule/src/types.ts#EveryScheduleDispatchChange" + ], + "sources": [ + "packages/schedule/schedule/src/types.ts" + ] + }, + { + "digest": "e6411b09c1d982f789bf741ca74e2bea69df56029847f86a6148e722039ee732", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "parent" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e654d28d1e6c471147310d2fba396d00969cfe6ed9022626d3f2c2312e0b1cbb", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "plugin" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e72269f931559e901e5e8fe1cfcbd0669fb795f43cc038ff39fba62f60403c33", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "dt", + "type": 1, + "optional": false + }, + { + "name": "index", + "type": 2, + "optional": false + }, + { + "name": "texts", + "type": 3, + "optional": false + }, + { + "name": "time0", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "text-chunks" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][0]" + ], + "sources": [ + "packages/llm/llm/src/assistant-stream.ts" + ] + }, + { + "digest": "e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 3, + "optional": false + }, + { + "name": "time", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "decision", + "type": 2, + "optional": false + }, + { + "name": "durationMs", + "type": 3, + "optional": false + }, + { + "name": "exitCode", + "type": 3, + "optional": true + }, + { + "name": "handlerId", + "type": 2, + "optional": false + }, + { + "name": "point", + "type": 2, + "optional": false + }, + { + "name": "stderrSummary", + "type": 2, + "optional": true + }, + { + "name": "turn", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "literal", + "value": "hook/result" + } + ] + }, + "names": [ + "event:hook/result" + ], + "sources": [] + }, + { + "digest": "e7ce49f12953583fad217bf80fb9f1463acff2c3e9471a823782661675fb124c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "initial" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e7e154d47d5fbc5366330fb4dade1f108c6dfe4335044d21ded14b7bf1dce084", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "clear" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e7e8f1318170b8284f16ab45a557afd4675c96071c0f2a456636481dab20b427", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "deleted" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e8d26e6993445743e6c4342c31b284c7d8f5574369abdd6021183af1a6b3538f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "plugin", + "type": 3, + "optional": false + }, + { + "name": "sections", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "snapshot" + }, + { + "kind": "literal", + "value": "plugin" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "object", + "properties": [ + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "text", + "type": 3, + "optional": false + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:agent/inbox/spliced.data.inserted[0].source[4]", + "event:system/message.data.message.source[3]" + ], + "sources": [] + }, + { + "digest": "e8de0f457fed5b9ff94dc4950b59ef75fd8ba8af665cc7899485924a62653367", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "notice" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "e95f957154b2b1b58692af53d4131180b6dd19e2264869f876dbaa959991494e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "assistant/attempt" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "eaa71be0fbf0f702df8ea6c11d0aa2f9782263d45a10d0fb14eda662f4bfe04c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "kind", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "legacy" + } + ] + }, + "names": [ + "event:turn/end.data.reason[1].reason[4]" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "ebb768d85ec87fb68e42fc14fd7d8535b5ac11791b14d04c6770180f0a719bf8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "image/webp" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 6, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "parentCallId", + "type": 3, + "optional": false + }, + { + "name": "rootCallId", + "type": 3, + "optional": false + }, + { + "name": "subCallId", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "opaque", + "reason": "unknown" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "tool/ptc-dispatch-start" + } + ] + }, + "names": [ + "event:tool/ptc-dispatch-start" + ], + "sources": [] + }, + { + "digest": "eefbea819caeeea91ccb02dfafc16c68dd7f961cf9c1b2be25a2084509cf5c5a", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "block-end" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "step", + "type": 1, + "optional": false + }, + { + "name": "turn", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:step/end.data", + "event:step/start.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "ef4f00923b9edbae15c7ef05320280bf61147ca17146cf59690359bfd5e5da45", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "compaction/summary" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f05fb85e715af4ab4de0b6ba111166dd0435bd8bb74a0fa0f32b9d174113fc7c", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "task-result" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f09e5e7acf5ff5ccd193ff2eeec015fa2ff7c29d98bc465f8c3302058d47e29b", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "model", + "type": 1, + "optional": false + }, + { + "name": "provider", + "type": 1, + "optional": false + }, + { + "name": "reasoningEffort", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + } + ] + }, + "names": [ + "packages/api/session-controller/src/types.ts#ModelSelection" + ], + "sources": [ + "packages/api/session-controller/src/types.ts" + ] + }, + { + "digest": "f1996af2602e6f62b5ab179ca5c4af00d8753938b74cc6ef102de09e99e74a7e", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "command/run" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f19bee84bf3d20904553cdcd57465232bc1c2a194f54c4d195292ba0487223a6", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 1, + "optional": false + }, + { + "name": "bytes", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/attachment/attachment/src/types.ts#FileAttachmentRef" + ], + "sources": [ + "packages/attachment/attachment/src/types.ts" + ] + }, + { + "digest": "f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "type", + "type": 1, + "optional": false + }, + { + "name": "usage", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "usage" + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 3, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 3, + "optional": true + }, + { + "name": "inputTokens", + "type": 3, + "optional": false + }, + { + "name": "outputTokens", + "type": 3, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 3, + "optional": true + }, + { + "name": "totalTokens", + "type": 3, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:assistant/attempt.data.stream[0][3].chunk[5]" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "f2da0f27c1e6add59982c37b15e4a4912c5b33466859cce3b13d503600e24aef", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 1, + "optional": false + }, + { + "name": "type", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "literal", + "value": "file" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#FileBlock" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "f311671e07bc7fa645a0b6597de9966b97147956565296ba76a36543801b66c5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "in-history" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#SystemPromptUpdate" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "f56c5b59ca0161310c338d31dd16cf14287ccd602ff4181058df178c1c286d7f", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "form", + "type": 1, + "optional": false + }, + { + "name": "kind", + "type": 2, + "optional": false + }, + { + "name": "references", + "type": 3, + "optional": false + }, + { + "name": "version", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "recall" + }, + { + "kind": "literal", + "value": "session-reference" + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "object", + "properties": [ + { + "name": "capturedFormatVersion", + "type": 5, + "optional": true + }, + { + "name": "capturedThroughSeq", + "type": 6, + "optional": false + }, + { + "name": "compacted", + "type": 8, + "optional": false + }, + { + "name": "inputIndex", + "type": 5, + "optional": false + }, + { + "name": "label", + "type": 9, + "optional": false + }, + { + "name": "omittedBytes", + "type": 5, + "optional": false + }, + { + "name": "omittedMessages", + "type": 5, + "optional": false + }, + { + "name": "originalMessages", + "type": 5, + "optional": false + }, + { + "name": "retainedMessages", + "type": 5, + "optional": false + }, + { + "name": "sessionId", + "type": 9, + "optional": false + }, + { + "name": "truncated", + "type": 8, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "union", + "types": [ + 5, + 7 + ] + }, + { + "kind": "primitive", + "type": "null" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [ + "packages/context/session-reference/src/types.ts#SessionReferenceSource" + ], + "sources": [ + "packages/context/session-reference/src/types.ts" + ] + }, + { + "digest": "f634871d1e18b1eb199497ac8ab72d3964f48d03fbf611dc7521a1970cf429d9", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "plan/mode" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f6cb462f808309e315fea634f1ed86268b8346bbcee6774d9097ca6eed7ac1f8", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "replace" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "data", + "type": 1, + "optional": false + }, + { + "name": "ignorable", + "type": 4, + "optional": true + }, + { + "name": "seq", + "type": 5, + "optional": false + }, + { + "name": "time", + "type": 5, + "optional": false + }, + { + "name": "type", + "type": 33, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 2, + 32 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 3, + "optional": false + }, + { + "name": "llmStreamCall", + "type": 4, + "optional": false + }, + { + "name": "maxTokens", + "type": 5, + "optional": true + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "rawOutput", + "type": 6, + "optional": false + }, + { + "name": "shadowedRange", + "type": 29, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 30, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 5, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 3, + "optional": true + }, + { + "name": "summary", + "type": 6, + "optional": false + }, + { + "name": "usage", + "type": 31, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 7 + }, + { + "kind": "union", + "types": [ + 8, + 11, + 13, + 15, + 17, + 26 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 6, + "optional": false + }, + { + "name": "isError", + "type": 9, + "optional": true + }, + { + "name": "toolCallId", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 10, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 12, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 14, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 3, + "optional": false + }, + { + "name": "id", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + }, + { + "name": "type", + "type": 16, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 18, + "optional": false + }, + { + "name": "offloaded", + "type": 4, + "optional": true + }, + { + "name": "type", + "type": 25, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 5, + "optional": false + }, + { + "name": "height", + "type": 5, + "optional": false + }, + { + "name": "mediaType", + "type": 19, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": true + }, + { + "name": "originalDimensions", + "type": 24, + "optional": true + }, + { + "name": "width", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 20, + 21, + 22, + 23 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 5, + "optional": false + }, + { + "name": "width", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 27, + "optional": false + }, + { + "name": "type", + "type": 28, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 3, + "optional": false + }, + { + "name": "bytes", + "type": 5, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 5, + "optional": false + }, + { + "name": "start", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 5 + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 5, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 5, + "optional": true + }, + { + "name": "inputTokens", + "type": 5, + "optional": false + }, + { + "name": "outputTokens", + "type": 5, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 5, + "optional": true + }, + { + "name": "totalTokens", + "type": 5, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 3, + "optional": false + }, + { + "name": "maxTokens", + "type": 5, + "optional": true + }, + { + "name": "model", + "type": 3, + "optional": false + }, + { + "name": "provider", + "type": 3, + "optional": false + }, + { + "name": "rawOutput", + "type": 6, + "optional": true + }, + { + "name": "shadowedRange", + "type": 29, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 30, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 5, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 3, + "optional": true + }, + { + "name": "summary", + "type": 6, + "optional": false + }, + { + "name": "usage", + "type": 31, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "compaction/summary" + } + ] + }, + "names": [ + "event:compaction/summary" + ], + "sources": [] + }, + { + "digest": "f789af5ab844827eb5a4f357c0afae1eeed108c6c22d8ca1a56e586b349a7c85", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "change" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f88f1b7b6bb733f685f5fb6a8744a5db9199fa53c90463ea1a33bad51153671d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": 1 + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "turn", + "type": 1, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "event:turn/start.data" + ], + "sources": [ + "packages/core/session/src/types.ts" + ] + }, + { + "digest": "f9cfc89e8fe085b4fcc9cd32b74b6f103608c54d7d8cd97b47c01de34f252ba3", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "text-chunks" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "fab2bb09bc5e3b9db0685e8f5500b029af1a2b33e70bc703c1d5d0f596fbc1fd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "danger-full-access" + }, + { + "kind": "literal", + "value": "read-only" + }, + { + "kind": "literal", + "value": "workspace-write" + } + ] + }, + "names": [ + "packages/sandbox/sandbox/src/index.ts#SandboxMode" + ], + "sources": [ + "packages/sandbox/sandbox/src/index.ts" + ] + }, + { + "digest": "fab35c4520883c0d69e42d079c9f543fc5ac7a2d15b537b5572fcd99059c7018", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "rejected" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "fb5e0517050d2c6d40e5b8145db1f7c5ca7044d5d50fada6ff80e0b22c6ca973", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool/ptc-dispatch" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "fb8b6a2e53cb9cf44c551176de0fb77d1ddc60037b99a891ff8a860b6d5c29a0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "image" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "fbd2c74b346a1595b376139c587fadd23e4a21acc9c0abce342975b6cfc60986", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "agent-instructions" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "fc2ae6962f9f8801c2b1e414668e1e17cbb7544c4f39381198977a38bd10c093", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "entries", + "type": 1, + "optional": false + }, + { + "name": "form", + "type": 4, + "optional": false + }, + { + "name": "kind", + "type": 5, + "optional": false + }, + { + "name": "update", + "type": 6, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 2 + }, + { + "kind": "object", + "properties": [ + { + "name": "description", + "type": 3, + "optional": false + }, + { + "name": "name", + "type": 3, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": "catalog" + }, + { + "kind": "literal", + "value": "skill-catalog" + }, + { + "kind": "literal", + "value": true + } + ] + }, + "names": [ + "packages/skill/tool-skill/src/index.ts#SkillCatalogSource" + ], + "sources": [ + "packages/skill/tool-skill/src/index.ts" + ] + }, + { + "digest": "fd0d91a1f9dd2efb8959bdf5e07f8f0a98b1cdfa38ce8d4732ebde0b44c3abd4", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 2, + 3 + ] + }, + { + "kind": "literal", + "value": "completed" + }, + { + "kind": "literal", + "value": "in_progress" + }, + { + "kind": "literal", + "value": "pending" + } + ] + }, + "names": [ + "event:todo/write.data.todos[0].status" + ], + "sources": [] + }, + { + "digest": "fe792a6cd430494503837e21e79f91677704ccdd9e870c679aabd7d43ed47ddd", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "tool-workflow/run-end" + } + ] + }, + "names": [], + "sources": [] + }, + { + "digest": "feb329074f0206ecc06d8a1aa0a0b3e2f47fd27524ba020fbc849ba63e938896", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "union", + "types": [ + 1, + 31 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 2, + "optional": false + }, + { + "name": "llmStreamCall", + "type": 3, + "optional": false + }, + { + "name": "maxTokens", + "type": 4, + "optional": true + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "rawOutput", + "type": 5, + "optional": false + }, + { + "name": "shadowedRange", + "type": 28, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 29, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 4, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 2, + "optional": true + }, + { + "name": "summary", + "type": 5, + "optional": false + }, + { + "name": "usage", + "type": 30, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "literal", + "value": true + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "array", + "element": 6 + }, + { + "kind": "union", + "types": [ + 7, + 10, + 12, + 14, + 16, + 25 + ] + }, + { + "kind": "object", + "properties": [ + { + "name": "content", + "type": 5, + "optional": false + }, + { + "name": "isError", + "type": 8, + "optional": true + }, + { + "name": "toolCallId", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 9, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "tool-result" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 11, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "reasoning" + }, + { + "kind": "object", + "properties": [ + { + "name": "text", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 13, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "text" + }, + { + "kind": "object", + "properties": [ + { + "name": "arguments", + "type": 2, + "optional": false + }, + { + "name": "id", + "type": 2, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + }, + { + "name": "type", + "type": 15, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "tool-call" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 17, + "optional": false + }, + { + "name": "offloaded", + "type": 3, + "optional": true + }, + { + "name": "type", + "type": 24, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 4, + "optional": false + }, + { + "name": "height", + "type": 4, + "optional": false + }, + { + "name": "mediaType", + "type": 18, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": true + }, + { + "name": "originalDimensions", + "type": 23, + "optional": true + }, + { + "name": "width", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "union", + "types": [ + 19, + 20, + 21, + 22 + ] + }, + { + "kind": "literal", + "value": "image/gif" + }, + { + "kind": "literal", + "value": "image/jpeg" + }, + { + "kind": "literal", + "value": "image/png" + }, + { + "kind": "literal", + "value": "image/webp" + }, + { + "kind": "object", + "properties": [ + { + "name": "height", + "type": 4, + "optional": false + }, + { + "name": "width", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "image" + }, + { + "kind": "object", + "properties": [ + { + "name": "attachment", + "type": 26, + "optional": false + }, + { + "name": "type", + "type": 27, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "attachmentId", + "type": 2, + "optional": false + }, + { + "name": "bytes", + "type": 4, + "optional": false + }, + { + "name": "name", + "type": 2, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "literal", + "value": "file" + }, + { + "kind": "object", + "properties": [ + { + "name": "end", + "type": 4, + "optional": false + }, + { + "name": "start", + "type": 4, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "array", + "element": 4 + }, + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 4, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 4, + "optional": true + }, + { + "name": "inputTokens", + "type": 4, + "optional": false + }, + { + "name": "outputTokens", + "type": 4, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 4, + "optional": true + }, + { + "name": "totalTokens", + "type": 4, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "object", + "properties": [ + { + "name": "compactionId", + "type": 2, + "optional": false + }, + { + "name": "maxTokens", + "type": 4, + "optional": true + }, + { + "name": "model", + "type": 2, + "optional": false + }, + { + "name": "provider", + "type": 2, + "optional": false + }, + { + "name": "rawOutput", + "type": 5, + "optional": true + }, + { + "name": "shadowedRange", + "type": 28, + "optional": false + }, + { + "name": "shadowedSeqs", + "type": 29, + "optional": false + }, + { + "name": "shadowedTokenCount", + "type": 4, + "optional": false + }, + { + "name": "sourceCommandId", + "type": 2, + "optional": true + }, + { + "name": "summary", + "type": 5, + "optional": false + }, + { + "name": "usage", + "type": 30, + "optional": true + } + ], + "indices": [] + } + ] + }, + "names": [ + "event:compaction/summary.data" + ], + "sources": [] + }, + { + "digest": "fec5442b9ee4122e10514d81d5a43648003fe8bfb7ee2ba50c0cdbdd383ed394", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "cacheReadTokens", + "type": 1, + "optional": true + }, + { + "name": "cacheWriteTokens", + "type": 1, + "optional": true + }, + { + "name": "inputTokens", + "type": 1, + "optional": false + }, + { + "name": "outputTokens", + "type": 1, + "optional": false + }, + { + "name": "reasoningTokens", + "type": 1, + "optional": true + }, + { + "name": "totalTokens", + "type": 1, + "optional": true + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "number" + } + ] + }, + "names": [ + "packages/llm/llm/src/types.ts#TokenUsage" + ], + "sources": [ + "packages/llm/llm/src/types.ts" + ] + }, + { + "digest": "fee1caf8ab6a65c1bc981f5a1730164490f22a2a89ffa3d0b76f1f432c44c8b5", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": "instructions" + } + ] + }, + "names": [], + "sources": [] + } + ] +} diff --git a/docs/persistence-changes/historical-formats/v3.zh.md b/docs/persistence-changes/historical-formats/v3.zh.md new file mode 100644 index 0000000000..b49cbf23a9 --- /dev/null +++ b/docs/persistence-changes/historical-formats/v3.zh.md @@ -0,0 +1,5634 @@ +--- +description: "完整的 Session V3 持久化类型、来源证据与物理编码参考。" +kind: persistence-format +--- + +# Session V3 持久化格式 + +[English](v3.md) | 中文 + +## 概述 + +查阅 PR #4320 中 V4 写入器变更之前捕获的 V3 持久化类型。系统提示词使用 surface 消息,替换端点使用 `startSeq` / `endSeq`,surface 事件具有显式位置。本快照保留该 V3 检查点的完整声明目录。 + +## 目录 + +- [来源证据](#evidence) +- [格式特征](#characteristics) +- [机器声明](#declaration) +- [完整 schema](#schema) +- [验证与限制](#verification) +- [开发备注](#dev-note) + +----- + + +## 来源证据 + +来源为 `release/session-log-v4` 上 PR #4320 的初始源码树,由日期为 2026-09-16、标题为 `chore(session): initialize V4 release integration PR` 的空提交记录。它包含写入器版本为 3 的 master 源码树,尚未包含 V4 源码变更。目录新鲜度检查通过后,V3 归档命令在写入器推进前捕获了该目录。此检查点既不是 PR 最终源码树,也不是新的产品发布;[发布状态参考](../../session-format-status.zh.md)负责发布证据。 + +提取的声明来自 `packages/core/session/src/types.ts`、`packages/session/session-persistence-jsonl/src/format.ts`,以及所有第一方 `SessionEventMap` 声明合并及其可达类型。下方源码位置指向该捕获的源码树,不包含行号。 + + +## 格式特征 + +以下事实描述所选检查点。下方生成的表格保留精确的字段类型与可选性。 + +- `SessionHeader.version` 解析为字面量 3。逻辑与物理 header 均要求 `isSeeded`;物理 header 没有 `seedLength`。 +- `system/message`、`user/message`、`assistant/message` 和 `tool/result` 要求 `surfaceOp`。替换端点为 `startSeq` 与 `endSeq`;Assistant 消息不携带 `sourceEventSeqs`。 +- Assistant 流仍内嵌在 message 或 attempt 事件中。系统提示词文本属于 `system/message`,PTC 分派事件使用 `tool/ptc-dispatch-start` 和 `tool/ptc-dispatch`。 + +[V3 codec](../../../packages/session/session-format-v2-to-v3/src/codec.ts)负责规范事件编码与来源事件范围编码。[V2 到 V3 规范](../../../packages/session/session-format-v2-to-v3/README.zh.md#v2-to-v3-specification)定义历史转换,其[原生 V3 准入规则](../../../packages/session/session-format-v2-to-v3/README.zh.md#native-v3-admission)区分扩展处理与历史来源验证。 + +对于已继承的 V3 Session,最后一个携带 `data.inherited: true` 的 `session/end-seed` 事件以其序号位置标识继承切点。物理 `sourceEventSeqs` 可以使用范围编码;逻辑 schema 保留展开后的数值数组。 + + +## 机器声明 + +[Schema 目录](v3.schema.json)。 + +```yaml persistence-format +schemaVersion: 1 +sessionFormatVersion: 3 +source: + pullRequest: 4320 +roots: + "SessionHeader": 2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03 + "JsonlHeaderLine": 18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f + "SessionEventEnvelope": 5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc + "event:agent-preset/selected": a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b + "event:agent/inbox/spliced": 646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f + "event:approval/asked": 3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1 + "event:approval/decided": bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3 + "event:approval/policy": 26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78 + "event:assistant/attempt": c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e + "event:assistant/message": 1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d + "event:command/done": 15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff + "event:command/run": 37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006 + "event:compaction/end": b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d + "event:compaction/prune": 7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04 + "event:compaction/start": db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965 + "event:compaction/summary": f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59 + "event:deliverables/presented": 13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176 + "event:feedback/message-delete": 3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796 + "event:feedback/message-put": b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf + "event:feedback/record": b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8 + "event:goal/change": 763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d + "event:hook/invoked": 8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0 + "event:hook/result": e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4 + "event:image/offload": b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e + "event:llm/retry": 525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336 + "event:llm/retry-started": 48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3 + "event:model/selection": 35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc + "event:permission/preset": 5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b + "event:plan/mode": a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f + "event:request/context": 37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf + "event:request/header": 8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489 + "event:sandbox/mode": 516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415 + "event:schedule/change": 2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42 + "event:session-log-deepseek/delivery-accepted": d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9 + "event:session/end-seed": 5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e + "event:session/title": 1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5 + "event:session/title-llm-request": e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d + "event:step/end": e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05 + "event:step/start": 4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986 + "event:subagent/catalog": ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871 + "event:subagent/descriptor": b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5 + "event:subagent/model-selection-policy": a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc + "event:system/message": 69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae + "event:team/member": 4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc + "event:team/message/delivered": 48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb + "event:team/message/queued": 443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4 + "event:team/task": d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a + "event:todo/write": b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26 + "event:tool-workflow/agent-end": babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7 + "event:tool-workflow/agent-start": 5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627 + "event:tool-workflow/run-end": 42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f + "event:tool-workflow/run-start": c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058 + "event:tool/call": 3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48 + "event:tool/ptc-dispatch": b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c + "event:tool/ptc-dispatch-start": ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93 + "event:tool/result": 29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2 + "event:turn/end": bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b + "event:turn/start": aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8 + "event:user/message": 314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578 + "event:web/deepseek-search-llm-request": cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331 +``` + + + + +## 完整 schema + +[完整机器目录](v3.schema.json)包含 60 个根类型和 467 种可达类型。摘要包含所有引用字段;源码名称和路径描述所选的历史源码树。 + +### 持久化类型指纹 + +| 根类型 | 类别 | SHA-256 | 已解析类型 | +|---|---|---|---| +| `SessionHeader` | header | `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` | [`packages/core/session/src/types.ts#SessionHeader`](#persistence-type-packagescoresessionsrctypestssessionheader) | +| `JsonlHeaderLine` | header | `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` | [`packages/session/session-persistence-jsonl/src/format.ts#HeaderLine`](#persistence-type-packagessessionsession-persistence-jsonlsrcformattsheaderline) | +| `SessionEventEnvelope` | envelope | `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` | [`SessionEventEnvelope`](#persistence-type-sessioneventenvelope) | +| `event:agent-preset/selected` | event | `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | [`event:agent-preset/selected`](#persistence-type-eventagent-presetselected) | +| `event:agent/inbox/spliced` | event | `646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f` | [`event:agent/inbox/spliced`](#persistence-type-eventagentinboxspliced) | +| `event:approval/asked` | event | `3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1` | [`event:approval/asked`](#persistence-type-eventapprovalasked) | +| `event:approval/decided` | event | `bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3` | [`event:approval/decided`](#persistence-type-eventapprovaldecided) | +| `event:approval/policy` | event | `26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78` | [`event:approval/policy`](#persistence-type-eventapprovalpolicy) | +| `event:assistant/attempt` | event | `c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e` | [`event:assistant/attempt`](#persistence-type-eventassistantattempt) | +| `event:assistant/message` | event | `1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d` | [`event:assistant/message`](#persistence-type-eventassistantmessage) | +| `event:command/done` | event | `15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff` | [`event:command/done`](#persistence-type-eventcommanddone) | +| `event:command/run` | event | `37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006` | [`event:command/run`](#persistence-type-eventcommandrun) | +| `event:compaction/end` | event | `b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d` | [`event:compaction/end`](#persistence-type-eventcompactionend) | +| `event:compaction/prune` | event | `7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04` | [`event:compaction/prune`](#persistence-type-eventcompactionprune) | +| `event:compaction/start` | event | `db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965` | [`event:compaction/start`](#persistence-type-eventcompactionstart) | +| `event:compaction/summary` | event | `f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59` | [`event:compaction/summary`](#persistence-type-eventcompactionsummary) | +| `event:deliverables/presented` | event | `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` | [`event:deliverables/presented`](#persistence-type-eventdeliverablespresented) | +| `event:feedback/message-delete` | event | `3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796` | [`event:feedback/message-delete`](#persistence-type-eventfeedbackmessage-delete) | +| `event:feedback/message-put` | event | `b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf` | [`event:feedback/message-put`](#persistence-type-eventfeedbackmessage-put) | +| `event:feedback/record` | event | `b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8` | [`event:feedback/record`](#persistence-type-eventfeedbackrecord) | +| `event:goal/change` | event | `763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d` | [`event:goal/change`](#persistence-type-eventgoalchange) | +| `event:hook/invoked` | event | `8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0` | [`event:hook/invoked`](#persistence-type-eventhookinvoked) | +| `event:hook/result` | event | `e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4` | [`event:hook/result`](#persistence-type-eventhookresult) | +| `event:image/offload` | event | `b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e` | [`event:image/offload`](#persistence-type-eventimageoffload) | +| `event:llm/retry` | event | `525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336` | [`event:llm/retry`](#persistence-type-eventllmretry) | +| `event:llm/retry-started` | event | `48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3` | [`event:llm/retry-started`](#persistence-type-eventllmretry-started) | +| `event:model/selection` | event | `35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc` | [`event:model/selection`](#persistence-type-eventmodelselection) | +| `event:permission/preset` | event | `5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b` | [`event:permission/preset`](#persistence-type-eventpermissionpreset) | +| `event:plan/mode` | event | `a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f` | [`event:plan/mode`](#persistence-type-eventplanmode) | +| `event:request/context` | event | `37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf` | [`event:request/context`](#persistence-type-eventrequestcontext) | +| `event:request/header` | event | `8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489` | [`event:request/header`](#persistence-type-eventrequestheader) | +| `event:sandbox/mode` | event | `516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415` | [`event:sandbox/mode`](#persistence-type-eventsandboxmode) | +| `event:schedule/change` | event | `2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42` | [`event:schedule/change`](#persistence-type-eventschedulechange) | +| `event:session-log-deepseek/delivery-accepted` | event | `d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9` | [`event:session-log-deepseek/delivery-accepted`](#persistence-type-eventsession-log-deepseekdelivery-accepted) | +| `event:session/end-seed` | event | `5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e` | [`event:session/end-seed`](#persistence-type-eventsessionend-seed) | +| `event:session/title` | event | `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` | [`event:session/title`](#persistence-type-eventsessiontitle) | +| `event:session/title-llm-request` | event | `e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d` | [`event:session/title-llm-request`](#persistence-type-eventsessiontitle-llm-request) | +| `event:step/end` | event | `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` | [`event:step/end`](#persistence-type-eventstepend) | +| `event:step/start` | event | `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | [`event:step/start`](#persistence-type-eventstepstart) | +| `event:subagent/catalog` | event | `ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871` | [`event:subagent/catalog`](#persistence-type-eventsubagentcatalog) | +| `event:subagent/descriptor` | event | `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` | [`event:subagent/descriptor`](#persistence-type-eventsubagentdescriptor) | +| `event:subagent/model-selection-policy` | event | `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` | [`event:subagent/model-selection-policy`](#persistence-type-eventsubagentmodel-selection-policy) | +| `event:system/message` | event | `69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae` | [`event:system/message`](#persistence-type-eventsystemmessage) | +| `event:team/member` | event | `4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc` | [`event:team/member`](#persistence-type-eventteammember) | +| `event:team/message/delivered` | event | `48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb` | [`event:team/message/delivered`](#persistence-type-eventteammessagedelivered) | +| `event:team/message/queued` | event | `443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4` | [`event:team/message/queued`](#persistence-type-eventteammessagequeued) | +| `event:team/task` | event | `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` | [`event:team/task`](#persistence-type-eventteamtask) | +| `event:todo/write` | event | `b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26` | [`event:todo/write`](#persistence-type-eventtodowrite) | +| `event:tool-workflow/agent-end` | event | `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` | [`event:tool-workflow/agent-end`](#persistence-type-eventtool-workflowagent-end) | +| `event:tool-workflow/agent-start` | event | `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` | [`event:tool-workflow/agent-start`](#persistence-type-eventtool-workflowagent-start) | +| `event:tool-workflow/run-end` | event | `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` | [`event:tool-workflow/run-end`](#persistence-type-eventtool-workflowrun-end) | +| `event:tool-workflow/run-start` | event | `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` | [`event:tool-workflow/run-start`](#persistence-type-eventtool-workflowrun-start) | +| `event:tool/call` | event | `3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48` | [`event:tool/call`](#persistence-type-eventtoolcall) | +| `event:tool/ptc-dispatch` | event | `b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c` | [`event:tool/ptc-dispatch`](#persistence-type-eventtoolptc-dispatch) | +| `event:tool/ptc-dispatch-start` | event | `ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93` | [`event:tool/ptc-dispatch-start`](#persistence-type-eventtoolptc-dispatch-start) | +| `event:tool/result` | event | `29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2` | [`event:tool/result`](#persistence-type-eventtoolresult) | +| `event:turn/end` | event | `bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b` | [`event:turn/end`](#persistence-type-eventturnend) | +| `event:turn/start` | event | `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` | [`event:turn/start`](#persistence-type-eventturnstart) | +| `event:user/message` | event | `314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578` | [`event:user/message`](#persistence-type-eventusermessage) | +| `event:web/deepseek-search-llm-request` | event | `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331` | [`event:web/deepseek-search-llm-request`](#persistence-type-eventwebdeepseek-search-llm-request) | + +
+完整解析类型 + +### 已解析的持久化类型 + +每个类型定义仅列出一次。引用保留共享和递归关系;定义旁的摘要涵盖其完整可达结构。源码名称和位置标识声明来源,但不参与摘要计算。 + + + +#### `0` + +SHA-256: `93d38436347f67c9022aacbc4472e283d722bcab8eb73fc376aaf7b6a6b9fb35` + +`0` + + + +#### `1` + +SHA-256: `f88f1b7b6bb733f685f5fb6a8744a5db9199fa53c90463ea1a33bad51153671d` + +`1` + + + +#### `2` + +SHA-256: `a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80` + +`2` + + + +#### `3` + +SHA-256: `137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e` + +`3` + + + +#### `"aborted"` + +SHA-256: `1e0b0b66b6f0c53fc72e52289d06b4708d776f1ca9df4c86a22bff621d403cf0` + +`"aborted"` + + + +#### `"active"` + +SHA-256: `c8e6f48878cc2a2f0dc59682280d81f407943fb503f32c64bf9ff3d9393c3eff` + +`"active"` + + + +#### `"after"` + +SHA-256: `5b232a9b9bfcc0fc6794dab7865bcf203a65785c5de5aa647a51228bff628413` + +`"after"` + + + +#### `"agent-instructions"` + +SHA-256: `fbd2c74b346a1595b376139c587fadd23e4a21acc9c0abce342975b6cfc60986` + +`"agent-instructions"` + + + +#### `"agent-message"` + +SHA-256: `82470020b5bfcb1a843e2aa05602af7d37df99e82d01f015c7c589ba054fd89d` + +`"agent-message"` + + + +#### `"agent-preset/selected"` + +SHA-256: `557e148d30b79ee48645850832b30c717d7c3b64641deb5d6133b8b4e91ee0b8` + +`"agent-preset/selected"` + + + +#### `"agent/inbox/spliced"` + +SHA-256: `829a2fb3be6efd4ba36aef8ed2d381a4c6fb2a0aaf50c823a6f3f8290786b809` + +`"agent/inbox/spliced"` + + + +#### `"allowed-once"` + +SHA-256: `811229eedcec57979dbadca7dbea832a59f8580cff30cb217fca5e2da16314bd` + +`"allowed-once"` + + + +#### `"always"` + +SHA-256: `142c37d302aa22a0a57915b5255939d3ca91c1811ca13fddcf84cf76ea00758a` + +`"always"` + + + +#### `"append"` + +SHA-256: `e438a9d4fb883b3e4a8d9fc8913aa1550ed50eb384bfbf943100a5605b537498` + +`"append"` + + + +#### `"approval/asked"` + +SHA-256: `cd186c309e2bef305705e1d324139240f5e681f4f6a957d6a25b0225f65560df` + +`"approval/asked"` + + + +#### `"approval/decided"` + +SHA-256: `378f90f9f6022a0991928a1eaf7991094ea1920fe89a9248358a1da106e1a970` + +`"approval/decided"` + + + +#### `"approval/policy"` + +SHA-256: `36d6a9a871d949ea4f3edd919d81d66aa69218bebef38899d2a1282c39420a1f` + +`"approval/policy"` + + + +#### `"ask"` + +SHA-256: `9e07693fd7cd9babe0688c22c986e4d519ae1c0e40eeea13b2dc583bed2abc86` + +`"ask"` + + + +#### `"assistant"` + +SHA-256: `95c0e88fcf0bafb2087f912ad9e2369de6ae6530cc0c4c2772c96205b57f7f60` + +`"assistant"` + + + +#### `"assistant/attempt"` + +SHA-256: `e95f957154b2b1b58692af53d4131180b6dd19e2264869f876dbaa959991494e` + +`"assistant/attempt"` + + + +#### `"assistant/message"` + +SHA-256: `6ab45ac76839722df912f3ba50f1c6b41f2d614bde11f1aabfae04117ccdc80d` + +`"assistant/message"` + + + +#### `"at"` + +SHA-256: `17aae616ef020b8b9f011ec398ec935450fb06d3e2a0722c456f63aeaf5ff728` + +`"at"` + + + +#### `"block"` + +SHA-256: `1e346446e183ee76f48d7994c97ecb302bddc682abb60b8a10ea0bb26223a69c` + +`"block"` + + + +#### `"block-end"` + +SHA-256: `eefbea819caeeea91ccb02dfafc16c68dd7f961cf9c1b2be25a2084509cf5c5a` + +`"block-end"` + + + +#### `"block-start"` + +SHA-256: `cbca49bde16b656d5b8fbe4a8a507769f7b594c6287782b809c03814941bc5e3` + +`"block-start"` + + + +#### `"blocked"` + +SHA-256: `254dce209e735f9cb6f6b7aec0354712b1611759ec02af4d35a96f2081e666f6` + +`"blocked"` + + + +#### `boolean` + +SHA-256: `aa93010d0e521ad7c42273f58d5c9b8bf1dfc94edf1b805a3971b364a35c1877` + +`boolean` + + + +#### `"canceled"` + +SHA-256: `d4e4d575abeb4b72d616dc65c17ac0eaa943cc135609395044c38d5afcb10e31` + +`"canceled"` + + + +#### `"cancelled"` + +SHA-256: `2142e391b9ccb60d487afcf373ce74db98d952f69e8289eddb352a7e16e996c5` + +`"cancelled"` + + + +#### `"catalog"` + +SHA-256: `aec150797b655c5f15ebb7a501454b0c208fbaccec9ace49d7de2171fc02f47d` + +`"catalog"` + + + +#### `"change"` + +SHA-256: `f789af5ab844827eb5a4f357c0afae1eeed108c6c22d8ca1a56e586b349a7c85` + +`"change"` + + + +#### `"chunk"` + +SHA-256: `14230f9b8b5797bb7e8c621fa636531cfbde2ffba1ef5f1fd058216ff21952a0` + +`"chunk"` + + + +#### `"claude-code"` + +SHA-256: `aff60ef947c18b012644852bdd0d5bfe72065e061dd563787c76c646b4a10f6b` + +`"claude-code"` + + + +#### `"clear"` + +SHA-256: `e7e154d47d5fbc5366330fb4dade1f108c6dfe4335044d21ded14b7bf1dce084` + +`"clear"` + + + +#### `"codex"` + +SHA-256: `15495614ccfa9cbdeefb0ec2abd76406435f4c6ff3dae42acae8e09ef42025c9` + +`"codex"` + + + +#### `"command/done"` + +SHA-256: `8cdd3fdd295cee53035de16a1b23411716f75e9f994fe9510cac5d7fef605c76` + +`"command/done"` + + + +#### `"command/run"` + +SHA-256: `f1996af2602e6f62b5ab179ca5c4af00d8753938b74cc6ef102de09e99e74a7e` + +`"command/run"` + + + +#### `"compaction/end"` + +SHA-256: `1986c2664009c99155e44795676c887fa67f7c55cd2d5e6b648ff763e0ab033a` + +`"compaction/end"` + + + +#### `"compaction/prune"` + +SHA-256: `10e386801903f9d424602c31d3ff837a94aef623c8b391376d8d9e253525fabe` + +`"compaction/prune"` + + + +#### `"compaction/start"` + +SHA-256: `e2d0367e5716bc188435e51718ebff8ce873190625fa93b1c5331102d98758fa` + +`"compaction/start"` + + + +#### `"compaction/summary"` + +SHA-256: `ef4f00923b9edbae15c7ef05320280bf61147ca17146cf59690359bfd5e5da45` + +`"compaction/summary"` + + + +#### `"complete"` + +SHA-256: `d9196086e41e4dd5c2ce87f5c25529c8112a1731d258cf0728747d41a9ee3241` + +`"complete"` + + + +#### `"completed"` + +SHA-256: `1ebc6f9ff3aa9e3a38f8695f49bacdab1f8b7a3832741853ca46f40af56ccd01` + +`"completed"` + + + +#### `"continuable"` + +SHA-256: `e5d3828df1ec3e2a66879de0659e0f4866d9cfffc00825ee731a66f8a0c03d98` + +`"continuable"` + + + +#### `"create"` + +SHA-256: `7624ca28c61ca0eaa4f015140f3cea6e0c16cce2f2960fab5f531203d253903e` + +`"create"` + + + +#### `"danger-full-access"` + +SHA-256: `18fce9540bb20897a66275499faee6b8296c97e9901fa1ff45a191772448ad1a` + +`"danger-full-access"` + + + +#### `"delegation"` + +SHA-256: `76632533f67879dcb346fcae640540dbc89b2472b0bce88c59f7e48fc5c0e668` + +`"delegation"` + + + +#### `"delete"` + +SHA-256: `d0fbb0ca1bbba059830826f33f801da1aced35a2504376d61e020bdfec8d50c0` + +`"delete"` + + + +#### `"deleted"` + +SHA-256: `e7e8f1318170b8284f16ab45a557afd4675c96071c0f2a456636481dab20b427` + +`"deleted"` + + + +#### `"deliverables/presented"` + +SHA-256: `1a2718b00937b236a0d0910ef5dab2f9f8b65e4bde410cc21f15fbbf29f584d3` + +`"deliverables/presented"` + + + +#### `"dispatch"` + +SHA-256: `26c879bdd130e8b8683a6ce588414fad2244783d6573ca399fa0de184a2b0bb1` + +`"dispatch"` + + + +#### `"disposed"` + +SHA-256: `b38f206d59bad891fa58c89f97a0036987b3defe7685acbd318fa55eb85f9751` + +`"disposed"` + + + +#### `"edit"` + +SHA-256: `ad22a5ca5bbaab2e1440779cd3648e85ddfc6f73b5207394eda699555cf31430` + +`"edit"` + + + +#### `"error"` + +SHA-256: `a2be0f0cb59f0d4a06557d45847d1938aced238baa77a6da416e590b8b958553` + +`"error"` + + + +#### `event:agent-preset/selected` + +SHA-256: `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:agent-preset/selected.data`](#persistence-type-eventagent-presetselecteddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"agent-preset/selected"` | + + + +#### `event:agent-preset/selected.data` + +SHA-256: `6e52dd55a1d48954ed5464ec46fe34d9eb65f709baabc9561e7a279910b0c406` + +来源:`packages/preset/agent-presets/src/session.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `agentPreset` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced` + +SHA-256: `646c2f1d243d3a78c5bc9305786fb340f5209c48a97e65f2a186cc5195491f3f` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:agent/inbox/spliced.data`](#persistence-type-eventagentinboxspliceddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"agent/inbox/spliced"` | + + + +#### `event:agent/inbox/spliced.data` + +SHA-256: `a6a195c1b4a906d953d24ab5864c9f1881d545460e080a51144adfc9cb058cfe` + +来源:`packages/core/agent/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `inserted` | 必需 | [`event:agent/inbox/spliced.data.inserted`](#persistence-type-eventagentinboxspliceddatainserted) | +| `outcome` | 可选 | `"canceled"` | +| `removedCount` | 可选 | `number` | +| `start` | 必需 | `number` | +| `target` | 必需 | [`packages/core/agent/src/types.ts#InboxTarget`](#persistence-type-packagescoreagentsrctypestsinboxtarget) | + + + +#### `event:agent/inbox/spliced.data.inserted` + +SHA-256: `300341f890f7b9506a1749fff4fa5239d16ea1c63ff6b15851acb03c20f3b48d` + +[`packages/llm/llm/src/message.ts#UserMessage`](#persistence-type-packagesllmllmsrcmessagetsusermessage) 的数组。 + + + +#### `event:agent/inbox/spliced.data.inserted[0].content` + +SHA-256: `bb72d86bc9ef0b3908bfa57ef98ccccae24d67d945c9f6869ca3cb8577889e75` + +[`packages/llm/llm/src/types.ts#ContentBlock`](#persistence-type-packagesllmllmsrctypestscontentblock) 的数组。 + + + +#### `event:agent/inbox/spliced.data.inserted[0].content[0][2].attachment.originalDimensions` + +SHA-256: `0f46153645c297846a3fad3911636659ca4717a5e7d71c9f50bffacd312115ef` + +来源:`packages/attachment/attachment/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `height` | 必需 | `number` | +| `width` | 必需 | `number` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[0]` + +SHA-256: `ada310bf0bdb8fed51f3b56ea63f6ea6b18bbd587f04fccb63a14ab0b2a24e05` + +来源:`packages/core/session/src/types.ts` · `packages/interaction/commands/src/types.ts` · `packages/llm/llm/src/message.ts` · `packages/session/session-title/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"user"` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[1]` + +SHA-256: `0ddab4577db37a3e0d9e3a91761735c8ef6f5629d526ab8ecaeeea19c097c8f8` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[10]` + +SHA-256: `6a4f72e2e179e17b922f2a9392c0e1c8f8c707f32494372454850a3eb184a6e7` + +来源:`packages/api/session-controller/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `clientTimeZone` | 可选 | `string` | +| `kind` | 必需 | `"user"` | +| `rpcId` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[15].references` + +SHA-256: `df843efd87c78cf8de98f8e0d0216956cd568d0d0e56a22c853663e274aa1a18` + +[`event:agent/inbox/spliced.data.inserted[0].source[15].references[0]`](#persistence-type-eventagentinboxspliceddatainserted0source15references0) 的数组。 + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[15].references[0]` + +SHA-256: `4f91f187baeabef5c7950c4780d31bbe39f3345dff591a6cf26ac7e135ac1cf4` + +来源:`packages/context/session-reference/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `capturedFormatVersion` | 可选 | `number` | +| `capturedThroughSeq` | 必需 | [`event:compaction/end.data.turn`](#persistence-type-eventcompactionenddataturn) | +| `compacted` | 必需 | `boolean` | +| `inputIndex` | 必需 | `number` | +| `label` | 必需 | `string` | +| `omittedBytes` | 必需 | `number` | +| `omittedMessages` | 必需 | `number` | +| `originalMessages` | 必需 | `number` | +| `retainedMessages` | 必需 | `number` | +| `sessionId` | 必需 | `string` | +| `truncated` | 必需 | `boolean` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[16].changes` + +SHA-256: `2ab12a0e345658f9342816d773fe610f049982bcad82631f43b9205abe43e5ee` + +[`packages/context/agent-instructions/src/render.ts#AgentInstructionChange`](#persistence-type-packagescontextagent-instructionssrcrendertsagentinstructionchange) 的数组。 + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[16].changes[0].action` + +SHA-256: `904bf499d98be4a3a5f836fcac533b6c4899569b018071e6604e1d32657d00fd` + +以下类型之一: + +- `"remove"` +- `"replace"` +- `"set"` + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[17].entries` + +SHA-256: `aba175fb20ffc71112c55efe70458ff5d7dbfb83501892b4ba8d077f0ea5d7ba` + +[`event:agent/inbox/spliced.data.inserted[0].source[17].entries[0]`](#persistence-type-eventagentinboxspliceddatainserted0source17entries0) 的数组。 + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[17].entries[0]` + +SHA-256: `83079c8a3f733ac3fa603eefa0fbb4737ca4d8b69e7e2e7298b60f9ac4098693` + +来源:`packages/skill/tool-skill/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `description` | 必需 | `string` | +| `name` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[19]` + +SHA-256: `9edc162949abf93bd5ff049191b345454ba104f583937ce5580fb50f067d2b94` + +来源:`packages/webhook/webhook/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `deliveryId` | 必需 | `string` | +| `form` | 必需 | `"notice"` | +| `kind` | 必需 | `"webhook"` | +| `provider` | 必需 | `string` | +| `ruleId` | 必需 | `string` | +| `source` | 必需 | `string` | +| `summary` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[2]` + +SHA-256: `dda6e111a8ccfc12f6e742e977a1a4e3549e8c03732a5ff6c8d7c3d4bcb7a412` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"instructions"` | +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[3]` + +SHA-256: `2f90a7b3646fea3e677bd7b4000aa96f3b8964f107b614e204e11ad4051c24fc` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"catalog"` | +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[4]` + +SHA-256: `e8d26e6993445743e6c4342c31b284c7d8f5574369abdd6021183af1a6b3538f` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"snapshot"` | +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | +| `sections` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].source[4].sections`](#persistence-type-eventagentinboxspliceddatainserted0source4sections) | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[4].sections` + +SHA-256: `c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262` + +[`packages/llm/llm/src/message.ts#ContextSnapshotSection`](#persistence-type-packagesllmllmsrcmessagetscontextsnapshotsection) 的数组。 + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[5]` + +SHA-256: `b4d298d90c798fa4d1f5b030ce3ce8031c4c41beafdb05323bec8b2a06903b43` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"notice"` | +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | +| `summary` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[6]` + +SHA-256: `2ce7ef3b3daebf95815c7ae454a751d3e67ca7a22e2e0734fe2942df393bb66c` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"relay"` | +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | + + + +#### `event:agent/inbox/spliced.data.inserted[0].source[7]` + +SHA-256: `85e1bd563d6c80c1f377f99f91103fec4e315148a7330f3b3dae7c2d04e33b01` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"recall"` | +| `kind` | 必需 | `"plugin"` | +| `plugin` | 必需 | `string` | + + + +#### `event:approval/asked` + +SHA-256: `3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:approval/asked.data`](#persistence-type-eventapprovalaskeddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"approval/asked"` | + + + +#### `event:approval/asked.data` + +SHA-256: `45f2a07ea94573123b6ae14db787a40062dec3834f36d8be92c523d40ba28448` + +来源:`packages/interaction/user-approval/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `callId` | 可选 | `string` | +| `id` | 必需 | `string` | +| `reason` | 可选 | `string` | +| `toolName` | 必需 | `string` | + + + +#### `event:approval/decided` + +SHA-256: `bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:approval/decided.data`](#persistence-type-eventapprovaldecideddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"approval/decided"` | + + + +#### `event:approval/decided.data` + +SHA-256: `93cbbc5a7fd0b1aa1ff1b9a6bb5ec52b073f48e5a5200365c45c0cd54059e1b9` + +来源:`packages/interaction/user-approval/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `id` | 必需 | `string` | +| `outcome` | 必需 | [`packages/interaction/user-approval/src/types.ts#ApprovalOutcome`](#persistence-type-packagesinteractionuser-approvalsrctypestsapprovaloutcome) | + + + +#### `event:approval/policy` + +SHA-256: `26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:approval/policy.data`](#persistence-type-eventapprovalpolicydata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"approval/policy"` | + + + +#### `event:approval/policy.data` + +SHA-256: `11f70b595aa76897fc4e25a352bfa718c659f44b799e5aa14e84e5a38fe72912` + +来源:`packages/interaction/user-approval/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `policy` | 必需 | [`packages/interaction/user-approval/src/index.ts#ApprovalPolicy`](#persistence-type-packagesinteractionuser-approvalsrcindextsapprovalpolicy) | +| `source` | 可选 | `"delegation"` | + + + +#### `event:assistant/attempt` + +SHA-256: `c80c89da83c46db7a454f034c10f969e03cfb574859c7316e5bff683f5a14b0e` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:assistant/attempt.data`](#persistence-type-eventassistantattemptdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"assistant/attempt"` | + + + +#### `event:assistant/attempt.data` + +SHA-256: `0c6412d3ba5e41adfaa6929c7d4093f2d52d8598c03f35844fc0d55e3070a3b1` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `step` | 必需 | `number` | +| `stream` | 必需 | [`event:assistant/attempt.data.stream`](#persistence-type-eventassistantattemptdatastream) | +| `turn` | 必需 | `number` | + + + +#### `event:assistant/attempt.data.stream` + +SHA-256: `26f3bb7529cfce1e3a0f1ededa365d8b426758ca0feeb0beabeee805f8bb8346` + +[`packages/llm/llm/src/assistant-stream.ts#AssistantStreamRecord`](#persistence-type-packagesllmllmsrcassistant-streamtsassistantstreamrecord) 的数组。 + + + +#### `event:assistant/attempt.data.stream[0][0]` + +SHA-256: `e72269f931559e901e5e8fe1cfcbd0669fb795f43cc038ff39fba62f60403c33` + +来源:`packages/llm/llm/src/assistant-stream.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `dt` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `index` | 必需 | `number` | +| `texts` | 必需 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `time0` | 必需 | `number` | +| `type` | 必需 | `"text-chunks"` | + + + +#### `event:assistant/attempt.data.stream[0][0].texts` + +SHA-256: `93c33d9687613293f8c95d46c4d922fe9ceae83b84c384beff5c3315abe005f2` + +`string` 的数组。 + + + +#### `event:assistant/attempt.data.stream[0][1]` + +SHA-256: `71bb3254ec8f1e491ce63b762a7b5f18709de23aa4e8abcc8b886f4b6ce051dd` + +来源:`packages/llm/llm/src/assistant-stream.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `dt` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `index` | 必需 | `number` | +| `texts` | 必需 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `time0` | 必需 | `number` | +| `type` | 必需 | `"reasoning-chunks"` | + + + +#### `event:assistant/attempt.data.stream[0][2]` + +SHA-256: `3860b4757d512a2869be833acb0faf834335b1b056bf3f83df5474dce95f8fa6` + +来源:`packages/llm/llm/src/assistant-stream.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `args` | 必需 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `dt` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `id` | 必需 | `string` | +| `index` | 必需 | `number` | +| `name` | 可选 | `string` | +| `time0` | 必需 | `number` | +| `type` | 必需 | `"tool-call-chunks"` | + + + +#### `event:assistant/attempt.data.stream[0][3]` + +SHA-256: `c93b6f51b399607349b4bcc66b58e848a44250ffc1e2537207bd092dfff94192` + +来源:`packages/llm/llm/src/assistant-stream.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `chunk` | 必需 | [`packages/llm/llm/src/types.ts#StreamChunk`](#persistence-type-packagesllmllmsrctypestsstreamchunk) | +| `time` | 必需 | `number` | +| `type` | 必需 | `"chunk"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[0]` + +SHA-256: `647cb2e3aeb58e27d1d4d60011f208bb66dce257e8654193c533b47c4c22c253` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `blockType` | 必需 | [`packages/llm/llm/src/types.ts#ContentBlockType`](#persistence-type-packagesllmllmsrctypestscontentblocktype) | +| `index` | 必需 | `number` | +| `type` | 必需 | `"block-start"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[1]` + +SHA-256: `95080295115fbd83544520ba247b68a03790131f6a2eac323d388758cb542f65` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `index` | 必需 | `number` | +| `text` | 必需 | `string` | +| `type` | 必需 | `"text-delta"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[2]` + +SHA-256: `2abb711460e6238d851c30f3e4bdd87a2aa1887ee70575b3d3b7b25610673095` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `index` | 必需 | `number` | +| `text` | 必需 | `string` | +| `type` | 必需 | `"reasoning-delta"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[3]` + +SHA-256: `88a610b831be6d92612a464be5c7d0b88ec24d97bd299837bf74bf7672183c9a` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `argumentsDelta` | 必需 | `string` | +| `id` | 必需 | `string` | +| `index` | 必需 | `number` | +| `name` | 可选 | `string` | +| `type` | 必需 | `"tool-call-delta"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[4]` + +SHA-256: `90c811b8c2668898515e69a24e82caffeb08517f9c7aa193867ff0380f3b535d` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `block` | 必需 | [`packages/llm/llm/src/types.ts#ContentBlock`](#persistence-type-packagesllmllmsrctypestscontentblock) | +| `index` | 必需 | `number` | +| `type` | 必需 | `"block-end"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[5]` + +SHA-256: `f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `type` | 必需 | `"usage"` | +| `usage` | 必需 | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6]` + +SHA-256: `a2b49331716ba0a7078b026d145306a70eae64b7313c3e6204bd931e75ec3bb1` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `reason` | 必需 | [`packages/llm/llm/src/types.ts#FinishReason`](#persistence-type-packagesllmllmsrctypestsfinishreason) | +| `replayState` | 可选 | [`packages/llm/llm/src/types.ts#ReplayEnvelope`](#persistence-type-packagesllmllmsrctypestsreplayenvelope) | +| `type` | 必需 | `"finish"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[0]` + +SHA-256: `8e31bb958e9b015e6f8407eaade32217068159e816f3cc99c3ad76eb889732e0` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `failure` | 必需 | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `kind` | 必需 | `"aborted"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[1]` + +SHA-256: `693f4952fb5565da96c06bace8924b098ac2fbc915fde0ff8019701183abc057` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `failure` | 必需 | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `kind` | 必需 | `"error"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]` + +SHA-256: `ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7` + +来源:`packages/core/session/src/types.ts` · `packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"max-tokens"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[3]` + +SHA-256: `1d76406cbb2ddadb0dbbb51e9d8bc6cf678fed455cf8eb512f36f7c86d37a62f` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"stop"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].reason[4]` + +SHA-256: `287211846beea1eccb5f9acee00d20388a38fcb2e95858fa2332d6f58529379a` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"tool-calls"` | + + + +#### `event:assistant/attempt.data.stream[0][3].chunk[6].replayState.blocks` + +SHA-256: `b1664fa89f8eab49a14e7e3168d8bc4da4aa9fd76332f6c4a053d839e5276ae7` + +`unknown`(不透明) 的数组。 + + + +#### `event:assistant/message` + +SHA-256: `1169b301aaabcd992657b93ec93750c43175dda81ada5cac086f14f2eaaeed6d` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:assistant/message.data`](#persistence-type-eventassistantmessagedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `surfaceOp` | 必需 | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | 必需 | `number` | +| `type` | 必需 | `"assistant/message"` | + + + +#### `event:assistant/message.data` + +SHA-256: `77b8491f946edfc8cc77ebae3ba49183759da31ba2dfa83d4c9e9e618c4b91d2` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `interrupted` | 可选 | `true` | +| `message` | 必需 | [`packages/llm/llm/src/message.ts#AssistantMessage`](#persistence-type-packagesllmllmsrcmessagetsassistantmessage) | +| `step` | 必需 | `number` | +| `stream` | 必需 | [`event:assistant/attempt.data.stream`](#persistence-type-eventassistantattemptdatastream) | +| `turn` | 必需 | `number` | +| `usage` | 可选 | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:command/done` + +SHA-256: `15196447222782e773eb943c92b18316ce96b9af0f0cfddb6e57ba8274ecc5ff` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:command/done.data`](#persistence-type-eventcommanddonedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"command/done"` | + + + +#### `event:command/done.data` + +SHA-256: `5b6fb1f226ff56402db08a6aae82af76100b14056271875f69ec526a1ae05d51` + +来源:`packages/interaction/commands/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `commandId` | 必需 | `string` | +| `kind` | 必需 | [`event:command/done.data.kind`](#persistence-type-eventcommanddonedatakind) | +| `sourceEventSeq` | 可选 | `number` | +| `text` | 可选 | `string` | + + + +#### `event:command/done.data.kind` + +SHA-256: `1ab2ef1296f157ba96998f179bb5daa9d21a82480da2901127aeab2730797c92` + +以下类型之一: + +- `"error"` +- `"success"` + + + +#### `event:command/run` + +SHA-256: `37184378c6439257d105c4e2022d80fc9c3a3f7c7f6ac661b00bc9f18d871006` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:command/run.data`](#persistence-type-eventcommandrundata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"command/run"` | + + + +#### `event:command/run.data` + +SHA-256: `a853902cfab417b8f08aa51ad6855fea46f34ed4588a74e47403035111d0fb86` + +来源:`packages/interaction/commands/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `args` | 可选 | `string` | +| `commandId` | 必需 | `string` | +| `name` | 必需 | `string` | +| `source` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) | + + + +#### `event:compaction/end` + +SHA-256: `b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:compaction/end.data`](#persistence-type-eventcompactionenddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"compaction/end"` | + + + +#### `event:compaction/end.data` + +SHA-256: `ca59530d1a4f3e191b4032bc4a20eded0d827db8b5a7efb27b3af9e9b456c6f2` + +来源:`packages/compaction/compaction/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `compactionId` | 必需 | `string` | +| `error` | 可选 | `string` | +| `sourceCommandId` | 可选 | `string` | +| `turn` | 必需 | [`event:compaction/end.data.turn`](#persistence-type-eventcompactionenddataturn) | + + + +#### `event:compaction/end.data.turn` + +SHA-256: `3bd652ebfa8726b3ce3937a4f1bd2759e02f86b3a08a20f9e41a8513656fbc5f` + +来源:`packages/core/session/src/types.ts` + +以下类型之一: + +- `null` +- `number` + + + +#### `event:compaction/prune` + +SHA-256: `7f7fd5a6b0064f597534b29ff62ef26e786dffccf5e14f654a7d4fcea2c35f04` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:compaction/prune.data`](#persistence-type-eventcompactionprunedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"compaction/prune"` | + + + +#### `event:compaction/prune.data` + +SHA-256: `5dd766ccd1702a1142ad8b4bd44f2242f8e8a6752669ad3de0a5d224329b1438` + +来源:`packages/compaction/compaction/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `shadowedRange` | 必需 | [`event:compaction/prune.data.shadowedRange`](#persistence-type-eventcompactionprunedatashadowedrange) | +| `shadowedSeqs` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `shadowedTokenCount` | 必需 | `number` | + + + +#### `event:compaction/prune.data.shadowedRange` + +SHA-256: `9e41386b3a0c9572b0d63078492ebb3997da7d3a830d44e0259418bd02f4bcb2` + +来源:`packages/compaction/compaction/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `end` | 必需 | `number` | +| `start` | 必需 | `number` | + + + +#### `event:compaction/start` + +SHA-256: `db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:compaction/start.data`](#persistence-type-eventcompactionstartdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"compaction/start"` | + + + +#### `event:compaction/start.data` + +SHA-256: `3e4e7683b0192c9f0e6a75c59076108f017892cdb302a98032c2632fd79c356f` + +来源:`packages/compaction/compaction/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `compactionId` | 必需 | `string` | +| `sourceCommandId` | 可选 | `string` | +| `turn` | 必需 | [`event:compaction/end.data.turn`](#persistence-type-eventcompactionenddataturn) | + + + +#### `event:compaction/summary` + +SHA-256: `f6f3f30109e9008fccf7da2a3268a63da8646b59dd7cf7b75bcd9cf08ac08a59` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:compaction/summary.data`](#persistence-type-eventcompactionsummarydata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"compaction/summary"` | + + + +#### `event:compaction/summary.data` + +SHA-256: `feb329074f0206ecc06d8a1aa0a0b3e2f47fd27524ba020fbc849ba63e938896` + +以下类型之一: + +- [`event:compaction/summary.data[0]`](#persistence-type-eventcompactionsummarydata0) +- [`event:compaction/summary.data[1]`](#persistence-type-eventcompactionsummarydata1) + + + +#### `event:compaction/summary.data[0]` + +SHA-256: `9ff2ad8dddb836f75e8f6197fff2371323dfc396c3c6fb667e6e0b42fda79a5c` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `compactionId` | 必需 | `string` | +| `llmStreamCall` | 必需 | `true` | +| `maxTokens` | 可选 | `number` | +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `rawOutput` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `shadowedRange` | 必需 | [`event:compaction/prune.data.shadowedRange`](#persistence-type-eventcompactionprunedatashadowedrange) | +| `shadowedSeqs` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `shadowedTokenCount` | 必需 | `number` | +| `sourceCommandId` | 可选 | `string` | +| `summary` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `usage` | 可选 | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:compaction/summary.data[1]` + +SHA-256: `3aa261c8516b5c955ed12080e6257a56cbe513f6c9f0ac9274c12e96c196ebca` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `compactionId` | 必需 | `string` | +| `maxTokens` | 可选 | `number` | +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `rawOutput` | 可选 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `shadowedRange` | 必需 | [`event:compaction/prune.data.shadowedRange`](#persistence-type-eventcompactionprunedatashadowedrange) | +| `shadowedSeqs` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `shadowedTokenCount` | 必需 | `number` | +| `sourceCommandId` | 可选 | `string` | +| `summary` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `usage` | 可选 | [`packages/llm/llm/src/types.ts#TokenUsage`](#persistence-type-packagesllmllmsrctypeststokenusage) | + + + +#### `event:deliverables/presented` + +SHA-256: `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:deliverables/presented.data`](#persistence-type-eventdeliverablespresenteddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"deliverables/presented"` | + + + +#### `event:deliverables/presented.data` + +SHA-256: `1528539c63db8b23506f0209a99ce77d8ad138adfbfcee3d4769b7382d93756c` + +来源:`packages/fs/tool-present/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `callId` | 必需 | `string` | +| `files` | 必需 | [`event:deliverables/presented.data.files`](#persistence-type-eventdeliverablespresenteddatafiles) | +| `turn` | 必需 | `number` | + + + +#### `event:deliverables/presented.data.files` + +SHA-256: `1d9cb3caa96100b18b1911fa3ff8c751ef6992971a03c5f4d9aefc1a0004a345` + +[`packages/fs/tool-present/src/types.ts#PresentedFile`](#persistence-type-packagesfstool-presentsrctypestspresentedfile) 的数组。 + + + +#### `event:feedback/message-delete` + +SHA-256: `3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackDelete`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackdelete) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"feedback/message-delete"` | + + + +#### `event:feedback/message-put` + +SHA-256: `b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackPut`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackput) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"feedback/message-put"` | + + + +#### `event:feedback/message-put.data.item.category` + +SHA-256: `3305a4bb6b6c29b482ba91d59c60b47e8f98282d3dacc8c29e4a4c2712209bdd` + +以下类型之一: + +- `"instruction-following"` +- `"other"` +- `"product-interaction"` +- `"resource-cost"` +- `"security-privacy-permission"` +- `"service-stability"` +- `"task-result"` + + + +#### `event:feedback/record` + +SHA-256: `b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/feedback/command-feedback/src/types.ts#FeedbackRecord`](#persistence-type-packagesfeedbackcommand-feedbacksrctypestsfeedbackrecord) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"feedback/record"` | + + + +#### `event:goal/change` + +SHA-256: `763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/goal/goal/src/domain.ts#GoalChangeMeta`](#persistence-type-packagesgoalgoalsrcdomaintsgoalchangemeta) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"goal/change"` | + + + +#### `event:goal/change.data[0].operation` + +SHA-256: `62e6a429ff3f390a46ac39fb468692032f42936ca0db19b53454184189401379` + +以下类型之一: + +- `"block"` +- `"complete"` +- `"create"` +- `"edit"` +- `"pause"` +- `"resume"` + + + +#### `event:hook/invoked` + +SHA-256: `8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:hook/invoked.data`](#persistence-type-eventhookinvokeddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"hook/invoked"` | + + + +#### `event:hook/invoked.data` + +SHA-256: `119abe2b9c0b2f46ecb31d82b9acba4d4b30e049f655e2475e8b4ae12d5a9e25` + +来源:`packages/hooks/hook-protocol/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `dialect` | 必需 | [`packages/hooks/hook-protocol/src/types.ts#HookDialect`](#persistence-type-packageshookshook-protocolsrctypestshookdialect) | +| `handlerId` | 必需 | `string` | +| `matcher` | 可选 | `string` | +| `point` | 必需 | `string` | +| `turn` | 必需 | `number` | + + + +#### `event:hook/result` + +SHA-256: `e75916628f3f10c2d50658bd143052a46285fbf1a9a700ba54947614603d26b4` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:hook/result.data`](#persistence-type-eventhookresultdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"hook/result"` | + + + +#### `event:hook/result.data` + +SHA-256: `8ad45ad053b4d89f8865c17cc9ff3b8748e86045f3f0fb816269a34af2619141` + +来源:`packages/hooks/hook-protocol/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `decision` | 必需 | `string` | +| `durationMs` | 必需 | `number` | +| `exitCode` | 可选 | `number` | +| `handlerId` | 必需 | `string` | +| `point` | 必需 | `string` | +| `stderrSummary` | 可选 | `string` | +| `turn` | 必需 | `number` | + + + +#### `event:image/offload` + +SHA-256: `b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:image/offload.data`](#persistence-type-eventimageoffloaddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"image/offload"` | + + + +#### `event:image/offload.data` + +SHA-256: `477614bca595a9e7adb5a1870be446b9a8684f3ba8950259d6289f2d3b74f028` + +来源:`packages/compaction/compaction-image-offload/src/projection.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `targets` | 必需 | [`event:image/offload.data.targets`](#persistence-type-eventimageoffloaddatatargets) | + + + +#### `event:image/offload.data.targets` + +SHA-256: `9e2c06d8653585b33d72d5c1a80da79c8a24a88c284409bca15cc0f0ead5ebfb` + +[`packages/compaction/compaction-image-offload/src/projection.ts#ImageOffloadTarget`](#persistence-type-packagescompactioncompaction-image-offloadsrcprojectiontsimageoffloadtarget) 的数组。 + + + +#### `event:llm/retry` + +SHA-256: `525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/llm/llm-retry/src/types.ts#LlmRetryEventData`](#persistence-type-packagesllmllm-retrysrctypestsllmretryeventdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"llm/retry"` | + + + +#### `event:llm/retry-started` + +SHA-256: `48e5c9861f16ac07e78cb7b5ae9dabdf7bb85c58baed5a51b4ad275050ea58e3` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/llm/llm-retry/src/types.ts#LlmRetryStartedEventData`](#persistence-type-packagesllmllm-retrysrctypestsllmretrystartedeventdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"llm/retry-started"` | + + + +#### `event:llm/retry.data[0]` + +SHA-256: `cdee10e87dbed8440d8b6935888624884878efc7af95402e94171b29f173dced` + +来源:`packages/llm/llm-retry/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `delayMs` | 必需 | `number` | +| `failure` | 必需 | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `maxRetries` | 必需 | `number` | +| `mode` | 必需 | `"normal"` | +| `policyKey` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `retry` | 必需 | `number` | +| `retryId` | 必需 | `string` | +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `event:llm/retry.data[1]` + +SHA-256: `374fdd68aee5ff844e378c0cbdd961d247a0f22e4ade0bb03d800cd2a46a2b8b` + +来源:`packages/llm/llm-retry/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `delayMs` | 必需 | `number` | +| `failure` | 必需 | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `mode` | 必需 | `"always"` | +| `policyKey` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `retry` | 必需 | `number` | +| `retryId` | 必需 | `string` | +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `event:model/selection` + +SHA-256: `35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/api/session-controller/src/types.ts#ModelSelection`](#persistence-type-packagesapisession-controllersrctypestsmodelselection) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"model/selection"` | + + + +#### `event:permission/preset` + +SHA-256: `5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:permission/preset.data`](#persistence-type-eventpermissionpresetdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"permission/preset"` | + + + +#### `event:permission/preset.data` + +SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` + +来源:`packages/interaction/permission-presets/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `preset` | 必需 | `string` | + + + +#### `event:plan/mode` + +SHA-256: `a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:plan/mode.data`](#persistence-type-eventplanmodedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"plan/mode"` | + + + +#### `event:plan/mode.data` + +SHA-256: `20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5` + +来源:`packages/plan/plan-mode/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `active` | 必需 | `boolean` | + + + +#### `event:request/context` + +SHA-256: `37cbc9cf06d494cfe5c67f078af1605eacb8e4c2c853e9e26455b73de0ee7ccf` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/core/session/src/types.ts#RequestContext`](#persistence-type-packagescoresessionsrctypestsrequestcontext) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"request/context"` | + + + +#### `event:request/header` + +SHA-256: `8ea13bcd983eab596dbfd41c5c2b62a0b318b71cd2a987a6fd752c6ced7e4489` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:request/header.data`](#persistence-type-eventrequestheaderdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"request/header"` | + + + +#### `event:request/header.data` + +SHA-256: `2f0aefb72ab453c4bf21a6687f436775d359dc6f8f10410fd4c0615b20bd9d76` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `header` | 必需 | [`packages/core/session/src/types.ts#EpochHeader`](#persistence-type-packagescoresessionsrctypestsepochheader) | +| `reason` | 必需 | [`packages/core/session/src/types.ts#RequestHeaderReason`](#persistence-type-packagescoresessionsrctypestsrequestheaderreason) | +| `startsSeries` | 可选 | `true` | + + + +#### `event:request/header.data.header.tools` + +SHA-256: `6d63f25a28b70801937a46b1058be5f52d4efbaf3516141470463ae469b59c23` + +[`packages/llm/llm/src/types.ts#ToolSchema`](#persistence-type-packagesllmllmsrctypeststoolschema) 的数组。 + + + +#### `event:request/header.data.header.tools[0].parameters` + +SHA-256: `0aa62ab51b36c0e64b134bd03ba8725d758744180a1a447da49beaad194f219f` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| [`string`] | 索引签名 | `unknown`(不透明) | + + + +#### `event:sandbox/mode` + +SHA-256: `516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:sandbox/mode.data`](#persistence-type-eventsandboxmodedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"sandbox/mode"` | + + + +#### `event:sandbox/mode.data` + +SHA-256: `9890113e97dd3541787bfe6704f2b223d3a890b5325ca0acae2b0398909b413e` + +来源:`packages/sandbox/sandbox-policy/src/session-mode.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `mode` | 必需 | [`packages/sandbox/sandbox/src/index.ts#SandboxMode`](#persistence-type-packagessandboxsandboxsrcindextssandboxmode) | +| `source` | 可选 | `"delegation"` | + + + +#### `event:schedule/change` + +SHA-256: `2a7f86849ae54b3398ee49661a757c4fcb59a6192b7036ee2ff514617e13fb42` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/schedule/schedule/src/types.ts#ScheduleChange`](#persistence-type-packagesscheduleschedulesrctypestsschedulechange) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"schedule/change"` | + + + +#### `event:session-log-deepseek/delivery-accepted` + +SHA-256: `d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:session-log-deepseek/delivery-accepted.data`](#persistence-type-eventsession-log-deepseekdelivery-accepteddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"session-log-deepseek/delivery-accepted"` | + + + +#### `event:session-log-deepseek/delivery-accepted.data` + +SHA-256: `8bb8c3751a6ce64b61aba1ec7ae798c00a5803c4d868a0430873216c6569ed52` + +来源:`packages/session/session-log-deepseek/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `sessionFormatVersion` | 可选 | `number` | +| `sessionId` | 必需 | `string` | +| `throughSeq` | 必需 | `number` | + + + +#### `event:session/end-seed` + +SHA-256: `5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:session/end-seed.data`](#persistence-type-eventsessionend-seeddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"session/end-seed"` | + + + +#### `event:session/end-seed.data` + +SHA-256: `17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `inherited` | 可选 | `true` | + + + +#### `event:session/title` + +SHA-256: `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/session/session-title/src/types.ts#SessionTitleEventData`](#persistence-type-packagessessionsession-titlesrctypestssessiontitleeventdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"session/title"` | + + + +#### `event:session/title-llm-request` + +SHA-256: `e0b5bf44c27bbfc6ab144239e3e4169c4d21146645e0e3121bbb359c3bc8591d` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData`](#persistence-type-packagessessionsession-title-llmsrcindextssessiontitlellmrequesteventdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"session/title-llm-request"` | + + + +#### `event:session/title-llm-request.data.messages` + +SHA-256: `478738df7e7d2b103b09fb937817a9302c81076809f2b341169e00a9419c5665` + +[`packages/llm/llm/src/message.ts#Message`](#persistence-type-packagesllmllmsrcmessagetsmessage) 的数组。 + + + +#### `event:session/title-llm-request.data.messages[0].role` + +SHA-256: `acd36e1717d2b4ef9e98a8e6fac17ca1203f3f448e5bca51677f129a8f4999e2` + +以下类型之一: + +- `"assistant"` +- `"system"` +- `"user"` + + + +#### `event:session/title.data.source[0]` + +SHA-256: `1b5649238876e28811e80f10ec67a00c197ad3babd4ecc61a22b09064b88c597` + +来源:`packages/session/session-title/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"fallback"` | + + + +#### `event:session/title.data.source[1]` + +SHA-256: `b81e9de81a481b24e1e1f9adf038bfc59e57b4f35ce62f8f1e45284186f4f812` + +来源:`packages/session/session-title/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"provider"` | +| `model` | 可选 | [`packages/session/session-title/src/types.ts#SessionTitleModelIdentity`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlemodelidentity) | +| `provider` | 必需 | `string` | + + + +#### `event:step/end` + +SHA-256: `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:step/end.data`](#persistence-type-eventstependdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"step/end"` | + + + +#### `event:step/end.data` + +SHA-256: `ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `event:step/start` + +SHA-256: `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:step/end.data`](#persistence-type-eventstependdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"step/start"` | + + + +#### `event:subagent/catalog` + +SHA-256: `ae1f7110feeec697b8cab42b68f7709aa7b3279764099dfb53c25890d2e5c871` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent`](#persistence-type-packagessubagentsubagentsrccatalogtssubagentcatalogevent) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"subagent/catalog"` | + + + +#### `event:subagent/catalog.data[0]` + +SHA-256: `5d542ac7bdf13310c46e1a884dec9fb18ad8c6e153cff207e639cd7bf9d7e694` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `childCreatedAt` | 必需 | `number` | +| `childId` | 必需 | `string` | +| `label` | 可选 | `string` | +| `mode` | 必需 | `"one-shot"` | +| `version` | 必需 | `0` | + + + +#### `event:subagent/catalog.data[1]` + +SHA-256: `0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `childCreatedAt` | 必需 | `number` | +| `childId` | 必需 | `string` | +| `label` | 必需 | `string` | +| `mode` | 必需 | `"continuable"` | +| `version` | 必需 | `0` | + + + +#### `event:subagent/descriptor` + +SHA-256: `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/subagent/subagent/src/descriptor.ts#SubagentDescriptorData`](#persistence-type-packagessubagentsubagentsrcdescriptortssubagentdescriptordata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"subagent/descriptor"` | + + + +#### `event:subagent/model-selection-policy` + +SHA-256: `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:subagent/model-selection-policy.data`](#persistence-type-eventsubagentmodel-selection-policydata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"subagent/model-selection-policy"` | + + + +#### `event:subagent/model-selection-policy.data` + +SHA-256: `0d47a8f3d847243c4488e755ad4cab7a04ac5d4621b9c81865524cf3f4d8536f` + +来源:`packages/subagent/tool-subagent/src/model-selection-state.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `allowedModels` | 必需 | [`event:subagent/model-selection-policy.data.allowedModels`](#persistence-type-eventsubagentmodel-selection-policydataallowedmodels) | + + + +#### `event:subagent/model-selection-policy.data.allowedModels` + +SHA-256: `ba77b58995e36f14bb13886b0493d0a1a63d5db10b1a6cd9f6ac65a72cf832ec` + +[`packages/session/session-title/src/types.ts#SessionTitleModelIdentity`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlemodelidentity) 的数组。 + + + +#### `event:system/message` + +SHA-256: `69becfb6b2d3fd5da91518089454cae8ef33f1835637ec44dde35dd077fd4bae` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:system/message.data`](#persistence-type-eventsystemmessagedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `sourceEventSeqs` | 可选 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | 必需 | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | 必需 | `number` | +| `type` | 必需 | `"system/message"` | + + + +#### `event:system/message.data` + +SHA-256: `2074f40221b76c75fd314246db558965dc3477dfb440bcc952b1eedc9778e366` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `message` | 必需 | [`packages/llm/llm/src/message.ts#SystemMessage`](#persistence-type-packagesllmllmsrcmessagetssystemmessage) | +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `event:system/message.data.message.source` + +SHA-256: `23cf7e0cf3fec1283b60fa15713506169bc9c079a08e124d1cb9733baca80b40` + +以下类型之一: + +- [`event:agent/inbox/spliced.data.inserted[0].source[4]`](#persistence-type-eventagentinboxspliceddatainserted0source4) +- [`event:agent/inbox/spliced.data.inserted[0].source[5]`](#persistence-type-eventagentinboxspliceddatainserted0source5) +- [`event:agent/inbox/spliced.data.inserted[0].source[3]`](#persistence-type-eventagentinboxspliceddatainserted0source3) +- [`event:agent/inbox/spliced.data.inserted[0].source[2]`](#persistence-type-eventagentinboxspliceddatainserted0source2) +- [`event:agent/inbox/spliced.data.inserted[0].source[7]`](#persistence-type-eventagentinboxspliceddatainserted0source7) +- [`event:agent/inbox/spliced.data.inserted[0].source[6]`](#persistence-type-eventagentinboxspliceddatainserted0source6) +- [`event:agent/inbox/spliced.data.inserted[0].source[1]`](#persistence-type-eventagentinboxspliceddatainserted0source1) + + + +#### `event:team/member` + +SHA-256: `4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:team/member.data`](#persistence-type-eventteammemberdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"team/member"` | + + + +#### `event:team/member.data` + +SHA-256: `b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `member` | 必需 | [`packages/experimental/agent-team/src/types.ts#TeamMemberSnapshot`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammembersnapshot) | +| `teamId` | 必需 | `string` | +| `version` | 必需 | `2` | + + + +#### `event:team/member.data.member.context` + +SHA-256: `50cf02d875f8a1f1411f4a6fbcffab9120ccef5f74a47331fbf29480e5f68f48` + +以下类型之一: + +- `"fork"` +- `"fresh"` + + + +#### `event:team/message/delivered` + +SHA-256: `48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:team/message/delivered.data`](#persistence-type-eventteammessagedelivereddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"team/message/delivered"` | + + + +#### `event:team/message/delivered.data` + +SHA-256: `0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `messageId` | 必需 | `string` | +| `targetId` | 必需 | `string` | +| `teamId` | 必需 | `string` | +| `version` | 必需 | `2` | + + + +#### `event:team/message/queued` + +SHA-256: `443371ec07a03a82a0e93d93abca3e70b03bca55ba5b01d507030fcb66e8fbb4` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:team/message/queued.data`](#persistence-type-eventteammessagequeueddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"team/message/queued"` | + + + +#### `event:team/message/queued.data` + +SHA-256: `0c3f4d2248d9bc9700e2d7253fa71aa9935f5c39af6f11de5727f08cccaf8383` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `message` | 必需 | [`packages/experimental/agent-team/src/types.ts#TeamMessageSnapshot`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammessagesnapshot) | +| `teamId` | 必需 | `string` | +| `version` | 必需 | `2` | + + + +#### `event:team/task` + +SHA-256: `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:team/task.data`](#persistence-type-eventteamtaskdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"team/task"` | + + + +#### `event:team/task.data` + +SHA-256: `a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `task` | 必需 | [`packages/experimental/agent-team/src/types.ts#TeamTaskSnapshot`](#persistence-type-packagesexperimentalagent-teamsrctypeststeamtasksnapshot) | +| `teamId` | 必需 | `string` | +| `version` | 必需 | `2` | + + + +#### `event:todo/write` + +SHA-256: `b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:todo/write.data`](#persistence-type-eventtodowritedata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"todo/write"` | + + + +#### `event:todo/write.data` + +SHA-256: `79ddc907312f97cf9553d4841e8b3fc937097bd8d97900a790efad3c05255e99` + +来源:`packages/todo/tool-todo/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `todos` | 必需 | [`event:todo/write.data.todos`](#persistence-type-eventtodowritedatatodos) | + + + +#### `event:todo/write.data.todos` + +SHA-256: `4b7ddaf3710b88ff9b8df66304f5f97bf03688fd19730eedc2e9535203c820ea` + +[`packages/todo/tool-todo/src/types.ts#TodoItem`](#persistence-type-packagestodotool-todosrctypeststodoitem) 的数组。 + + + +#### `event:todo/write.data.todos[0].status` + +SHA-256: `fd0d91a1f9dd2efb8959bdf5e07f8f0a98b1cdfa38ce8d4732ebde0b44c3abd4` + +以下类型之一: + +- `"completed"` +- `"in_progress"` +- `"pending"` + + + +#### `event:tool-workflow/agent-end` + +SHA-256: `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowagentenddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool-workflow/agent-end"` | + + + +#### `event:tool-workflow/agent-start` + +SHA-256: `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowagentstartdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool-workflow/agent-start"` | + + + +#### `event:tool-workflow/run-end` + +SHA-256: `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunEndData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowrunenddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool-workflow/run-end"` | + + + +#### `event:tool-workflow/run-start` + +SHA-256: `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData`](#persistence-type-packagesworkflowtool-workflowsrctypeststoolworkflowrunstartdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool-workflow/run-start"` | + + + +#### `event:tool/call` + +SHA-256: `3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:tool/call.data`](#persistence-type-eventtoolcalldata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool/call"` | + + + +#### `event:tool/call.data` + +SHA-256: `e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `arguments` | 必需 | `string` | +| `callId` | 必需 | `string` | +| `name` | 必需 | `string` | +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `event:tool/ptc-dispatch` + +SHA-256: `b33142af8176323ffbb20762541be81c1d51b60a60887803836e0b146e5bef0c` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/core/tools/src/types.ts#PtcDispatchEventData`](#persistence-type-packagescoretoolssrctypestsptcdispatcheventdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool/ptc-dispatch"` | + + + +#### `event:tool/ptc-dispatch-start` + +SHA-256: `ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/core/tools/src/types.ts#PtcDispatchStartEventData`](#persistence-type-packagescoretoolssrctypestsptcdispatchstarteventdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool/ptc-dispatch-start"` | + + + +#### `event:tool/ptc-dispatch.data.error` + +SHA-256: `a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735` + +来源:`packages/core/session/src/types.ts` · `packages/core/tools/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `code` | 必需 | `string` | +| `name` | 必需 | `string` | +| `reason` | 可选 | `string` | + + + +#### `event:tool/result` + +SHA-256: `29af48b840d0cd9e48b6f50bf3b354f8f6340607c5b99220a48e74f60beac9e2` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:tool/result.data`](#persistence-type-eventtoolresultdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `sourceEventSeqs` | 可选 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | 必需 | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | 必需 | `number` | +| `type` | 必需 | `"tool/result"` | + + + +#### `event:tool/result.data` + +SHA-256: `356aad27134a0e31af67c994ff8b9e4b91acfb6c4917b3bc1f7a62bbf82794d5` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `error` | 可选 | [`event:tool/ptc-dispatch.data.error`](#persistence-type-eventtoolptc-dispatchdataerror) | +| `message` | 必需 | [`packages/llm/llm/src/message.ts#ToolResultMessage`](#persistence-type-packagesllmllmsrcmessagetstoolresultmessage) | +| `meta` | 可选 | [`event:tool/result.data.meta`](#persistence-type-eventtoolresultdatameta) | +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `event:tool/result.data.message.content` + +SHA-256: `8d6a011f3ef7096a4a922ef420458419ff6b20e1eaeece5d331db7585d2f08d6` + +| 位置 | 存在性 | 类型 | +|---|---|---| +| 0 | 必需 | [`packages/llm/llm/src/types.ts#ToolResultBlock`](#persistence-type-packagesllmllmsrctypeststoolresultblock) | + + + +#### `event:tool/result.data.meta` + +SHA-256: `c592ce75aab73fcab19c1d7845684c72cf402b78d2e1f2833a58ecf9f3598ed6` + +来源:`packages/util/values/src/index.ts` + +以下类型之一: + +- [`event:tool/result.data.meta[5]`](#persistence-type-eventtoolresultdatameta5) +- [`event:tool/result.data.meta[5][0][6]`](#persistence-type-eventtoolresultdatameta506) +- `string` +- `boolean` +- `null` +- `number` + + + +#### `event:tool/result.data.meta[5]` + +SHA-256: `72ec79127a9c0d0241b1106a74cc2b24c81ce467170f1c3c93f7b71a9496d227` + +[`event:tool/result.data.meta`](#persistence-type-eventtoolresultdatameta) 的数组。 + + + +#### `event:tool/result.data.meta[5][0][6]` + +SHA-256: `529e0ccd0e34079ab4ff21ed87f810cee0388246263bf22e8aba5986b56fae05` + +来源:`packages/util/values/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| [`string`] | 索引签名 | [`event:tool/result.data.meta`](#persistence-type-eventtoolresultdatameta) | + + + +#### `event:turn/end` + +SHA-256: `bab768260853e13a7cf2e22e65af572a1e76a5b2c01f3cdc2ce09d39b87fb70b` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:turn/end.data`](#persistence-type-eventturnenddata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"turn/end"` | + + + +#### `event:turn/end.data` + +SHA-256: `d3e447062a2847dad847dad5168a9508d92c484363dfc76fd82605aa7bd46285` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `reason` | 必需 | [`packages/core/session/src/types.ts#TurnEndReason`](#persistence-type-packagescoresessionsrctypeststurnendreason) | +| `turn` | 必需 | `number` | + + + +#### `event:turn/end.data.reason[0]` + +SHA-256: `b6ef9c6210be8350cd465f485cf520031fffa6bf3809c61a1e713e834c5982d0` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"completed"` | + + + +#### `event:turn/end.data.reason[1]` + +SHA-256: `0a30c3be336cdd4f8f34e66543a3d46d611c43986edd9b3ce6cbb9b721d3b5d3` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"aborted"` | +| `reason` | 必需 | [`packages/core/session/src/types.ts#TurnEndCancelCause`](#persistence-type-packagescoresessionsrctypeststurnendcancelcause) | + + + +#### `event:turn/end.data.reason[1].reason[1]` + +SHA-256: `6c03546143cdf6ae88f1745ac98c5139efa1588d1415249bbc5f3104d32ab800` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"parent"` | + + + +#### `event:turn/end.data.reason[1].reason[2]` + +SHA-256: `6c5a37d42ebdb12db4410699259335f1e149e3a0260425684c00b153afc8990d` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"hook"` | +| `reason` | 必需 | `string` | + + + +#### `event:turn/end.data.reason[1].reason[3]` + +SHA-256: `4bb451330ff699f36b45539ceb0eb2606ead72084e2c5bb637c36cc80e2252db` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"disposed"` | + + + +#### `event:turn/end.data.reason[1].reason[4]` + +SHA-256: `eaa71be0fbf0f702df8ea6c11d0aa2f9782263d45a10d0fb14eda662f4bfe04c` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"legacy"` | + + + +#### `event:turn/end.data.reason[2]` + +SHA-256: `023a355b2be0d688fb6e4df8388dadb942761d46cfe96d0f499aae9631a159d4` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"blocked"` | + + + +#### `event:turn/end.data.reason[3]` + +SHA-256: `79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `error` | 必需 | [`packages/llm/llm/src/types.ts#LlmFailure`](#persistence-type-packagesllmllmsrctypestsllmfailure) | +| `kind` | 必需 | `"error"` | + + + +#### `event:turn/end.data.reason[5]` + +SHA-256: `56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"interrupted"` | + + + +#### `event:turn/start` + +SHA-256: `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`event:turn/start.data`](#persistence-type-eventturnstartdata) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"turn/start"` | + + + +#### `event:turn/start.data` + +SHA-256: `f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `turn` | 必需 | `number` | + + + +#### `event:user/message` + +SHA-256: `314765bdff29c7862fb6ce820f1773563ba3094a680d163ea21180a2591b8578` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/llm/llm/src/message.ts#UserMessage`](#persistence-type-packagesllmllmsrcmessagetsusermessage) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `sourceEventSeqs` | 可选 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | 必需 | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | 必需 | `number` | +| `type` | 必需 | `"user/message"` | + + + +#### `event:web/deepseek-search-llm-request` + +SHA-256: `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `data` | 必需 | [`packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest`](#persistence-type-packageswebweb-search-deepseeksrcprovidertsdeepseeksearchllmrequest) | +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `"web/deepseek-search-llm-request"` | + + + +#### `event:web/deepseek-search-llm-request.data.body` + +SHA-256: `930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731` + +来源:`packages/web/web-search-deepseek/src/provider.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `max_tokens` | 必需 | `number` | +| `messages` | 必需 | [`event:web/deepseek-search-llm-request.data.body.messages`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages) | +| `model` | 必需 | `string` | +| `tools` | 必需 | [`event:web/deepseek-search-llm-request.data.body.tools`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodytools) | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages` + +SHA-256: `b993441f8ce7d27b80e619e113e232ae8e62d3d5a8340f6bfe12d8c4c018e62f` + +| 位置 | 存在性 | 类型 | +|---|---|---| +| 0 | 必需 | [`event:web/deepseek-search-llm-request.data.body.messages[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0) | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages[0]` + +SHA-256: `9a2a9029f8d7ede05336980d8342737557f487b913bfd28853d0ab5214600ab5` + +来源:`packages/web/web-search-deepseek/src/provider.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:web/deepseek-search-llm-request.data.body.messages[0].content`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0content) | +| `role` | 必需 | `"user"` | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages[0].content` + +SHA-256: `8f6d609794bf5afc01d7ccf3e03811d32f4b8047f58a2c9a98db0154c2ad7cb9` + +| 位置 | 存在性 | 类型 | +|---|---|---| +| 0 | 必需 | [`event:web/deepseek-search-llm-request.data.body.messages[0].content[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0content0) | + + + +#### `event:web/deepseek-search-llm-request.data.body.messages[0].content[0]` + +SHA-256: `4e887768586528565381dadbddee6cef555874148089f4579e0b4b1ad096fc9c` + +来源:`packages/llm/llm/src/types.ts` · `packages/web/web-search-deepseek/src/provider.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `text` | 必需 | `string` | +| `type` | 必需 | `"text"` | + + + +#### `event:web/deepseek-search-llm-request.data.body.tools` + +SHA-256: `4aed17ec726b5397c29f6cb4bcd7905dc1a12bb6140f1657f073cd24380f2af8` + +| 位置 | 存在性 | 类型 | +|---|---|---| +| 0 | 必需 | [`event:web/deepseek-search-llm-request.data.body.tools[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodytools0) | + + + +#### `event:web/deepseek-search-llm-request.data.body.tools[0]` + +SHA-256: `2d11ca7b0d4493e244b74eba093227866b33249841e59a1e9bf56afed38604c3` + +来源:`packages/web/web-search-deepseek/src/provider.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `max_uses` | 必需 | `number` | +| `name` | 必需 | `"web_search"` | +| `type` | 必需 | `"web_search_20250305"` | + + + +#### `"every"` + +SHA-256: `e42b0f40b5d0b628c6e1c44a8fb9eda0780037a81959e1b93d2dfb47b46b0e87` + +`"every"` + + + +#### `"failed"` + +SHA-256: `b57a2889408de36e4516807194c73bdecd51a92f633ccd05db81bf049200f420` + +`"failed"` + + + +#### `"fallback"` + +SHA-256: `d6e654b88b584fcdf290a56802b1730bc7b9847ae86baa4265ab7769eb48990c` + +`"fallback"` + + + +#### `"feedback/message-delete"` + +SHA-256: `44818000e56acb97afdb5045ce235eb55e3fb1ccabc9fc7d0750bb38f36a7f8e` + +`"feedback/message-delete"` + + + +#### `"feedback/message-put"` + +SHA-256: `6cda0d6d3b4336d83998fe580628426df81c2afbab5d768b8813b56d569120e8` + +`"feedback/message-put"` + + + +#### `"feedback/record"` + +SHA-256: `c99e20441bf15341e9db54385e558e5c03d21dff2eb1ac08ccbf47c2d8747954` + +`"feedback/record"` + + + +#### `"file"` + +SHA-256: `277b61f9c6f8170425fa6ffe06cfa14376757a896a4749cb82a687d7364c4fc9` + +`"file"` + + + +#### `"finish"` + +SHA-256: `bd499eac047efe091a4df7382eadd06d25cf0cb31fee3981e8b24d85762841cd` + +`"finish"` + + + +#### `"fork"` + +SHA-256: `2da725e554cd89301d829ed9dc45a572c3cd1b93b5e91d0d71f007976d8a0863` + +`"fork"` + + + +#### `"fresh"` + +SHA-256: `dd2780e7e07684332f7a9ab047237798d260e7eaffb1321cb38eca695d184c3d` + +`"fresh"` + + + +#### `"goal"` + +SHA-256: `b815d7b91cdd9fc6ccc7dcba05cfc5ce1d55fab5fc0c0801803cd3630cedb602` + +`"goal"` + + + +#### `"goal/change"` + +SHA-256: `237c004c73b6b288246816e0d7fde16e09c63a47aa3b1227383d7afe58666163` + +`"goal/change"` + + + +#### `"hook"` + +SHA-256: `dbdafceb9a900183cccc80596498d386f3bf7bddead2b8cfde68453aa4739edc` + +`"hook"` + + + +#### `"hook/invoked"` + +SHA-256: `b9305f0ea75ccd6a6061c27fde19f2ab85534f9f3c1a717b573b077ebae0f611` + +`"hook/invoked"` + + + +#### `"hook/result"` + +SHA-256: `a3a259a1aa5401af786ce08c4a8419681d3000d73467991b5fc563389bc4ebd2` + +`"hook/result"` + + + +#### `"image"` + +SHA-256: `fb8b6a2e53cb9cf44c551176de0fb77d1ddc60037b99a891ff8a860b6d5c29a0` + +`"image"` + + + +#### `"image/gif"` + +SHA-256: `de30b1fa12c75f81df6aa4096e1595296d2d04e2be14a7c29849cf8028b79048` + +`"image/gif"` + + + +#### `"image/jpeg"` + +SHA-256: `3f74ba74acd10644c1ed6947a411d8088bd2cfac74f61bb8540f96d68e31f004` + +`"image/jpeg"` + + + +#### `"image/offload"` + +SHA-256: `9acbe713f3f641921dd3333b240aa72e176d795327c24e8d9db9b68b16771b49` + +`"image/offload"` + + + +#### `"image/png"` + +SHA-256: `58f94390b982f8a5ac1f4f235ba612557f4a1dc4a995d8b1cec63ce7639decb0` + +`"image/png"` + + + +#### `"image/webp"` + +SHA-256: `ebb768d85ec87fb68e42fc14fd7d8535b5ac11791b14d04c6770180f0a719bf8` + +`"image/webp"` + + + +#### `"in-history"` + +SHA-256: `f311671e07bc7fa645a0b6597de9966b97147956565296ba76a36543801b66c5` + +来源:`packages/llm/llm/src/types.ts` + +`"in-history"` + + + +#### `"in_progress"` + +SHA-256: `94c56aeb1564ad735eb773d88636b40761d063efa1610f1308004d32923f5378` + +`"in_progress"` + + + +#### `"initial"` + +SHA-256: `e7ce49f12953583fad217bf80fb9f1463acff2c3e9471a823782661675fb124c` + +`"initial"` + + + +#### `"instruction-following"` + +SHA-256: `e4cac694f8b6e1d52e48c699464f1c4c26111ef87e558f7931040d00fdc8d486` + +`"instruction-following"` + + + +#### `"instructions"` + +SHA-256: `fee1caf8ab6a65c1bc981f5a1730164490f22a2a89ffa3d0b76f1f432c44c8b5` + +`"instructions"` + + + +#### `"interrupted"` + +SHA-256: `69d238a6e9b08d67f601b1825962963d8d3523cb69ebf6208c697dc5d058c199` + +`"interrupted"` + + + +#### `"legacy"` + +SHA-256: `ad3b56aa2fc1ad4250e7399295d34a8eae592e1907e85852e2291b2e498a30bc` + +`"legacy"` + + + +#### `"llm/retry"` + +SHA-256: `611cae9a3539733aa0c42f66035a7d90f19dcbbdfb5d9e3b628b13705253942d` + +`"llm/retry"` + + + +#### `"llm/retry-started"` + +SHA-256: `4ae007ed190a72c92138b22d059b83208079c7551ca13fb59ae8cf5e23693964` + +`"llm/retry-started"` + + + +#### `"max-tokens"` + +SHA-256: `68141cbe3994a5ffcd064c07c75996538437fd9dbf77ce8a2927e89ec577fabe` + +`"max-tokens"` + + + +#### `"model"` + +SHA-256: `2765e9119edf5816ac1ab4c95c5ee32c90403f3742962eff11544f7752d59d2e` + +`"model"` + + + +#### `"model/selection"` + +SHA-256: `1d5f04a03ea75fc8eeece544129eba0f49f0c82046e9c404461920390135c7b2` + +`"model/selection"` + + + +#### `"negative"` + +SHA-256: `b1f62380f6746fedd629e71065e3583cef83334875b499ac9665c2eb87acfbf5` + +`"negative"` + + + +#### `"never"` + +SHA-256: `1571525adc95a24e5d25b5a6440df401cd7cdd881b745178e85f5a333435cd1b` + +`"never"` + + + +#### `"next-step"` + +SHA-256: `3e2ece4967cfebe95f450a93f45523dff99d6749f6269f2f60f84dfecfcf3693` + +`"next-step"` + + + +#### `"next-turn"` + +SHA-256: `62ecb62dc0fe1b5e70217f8a80c39256a40ee3a1917be14e5ca899d20c35f7fd` + +`"next-turn"` + + + +#### `"normal"` + +SHA-256: `3bc287e765d58dc3a22672a0495a6cfd561220dd38fbaecef80aa95b96caed79` + +`"normal"` + + + +#### `"notice"` + +SHA-256: `e8de0f457fed5b9ff94dc4950b59ef75fd8ba8af665cc7899485924a62653367` + +`"notice"` + + + +#### `null` + +SHA-256: `938f7c7357bc403ea3b281a9dd016939df7a0880fc8db12612585be574d0d615` + +`null` + + + +#### `number` + +SHA-256: `0657d3ca5ac4e7bf79b00bcf860b1c7159d01a9da137497221ec2f1776e365f7` + +来源:`packages/core/session/src/types.ts` + +`number` + + + +#### `"one-shot"` + +SHA-256: `d28765f87d6b6ab408e0b2f3e7e297791b004b806d8e302c49903ebae815feb2` + +`"one-shot"` + + + +#### `"other"` + +SHA-256: `9d80129e13edfb6feb03ed327e6085c6ef60b97ad074244b2f5fd4667424a6a4` + +`"other"` + + + +#### `packages/api/session-controller/src/types.ts#ModelSelection` + +SHA-256: `f09e5e7acf5ff5ccd193ff2eeec015fa2ff7c29d98bc465f8c3302058d47e29b` + +来源:`packages/api/session-controller/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `reasoningEffort` | 可选 | `string` | + + + +#### `packages/attachment/attachment/src/types.ts#FileAttachmentRef` + +SHA-256: `f19bee84bf3d20904553cdcd57465232bc1c2a194f54c4d195292ba0487223a6` + +来源:`packages/attachment/attachment/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `attachmentId` | 必需 | `string` | +| `bytes` | 必需 | `number` | +| `name` | 必需 | `string` | + + + +#### `packages/attachment/attachment/src/types.ts#ImageAttachmentRef` + +SHA-256: `b0b0eb1b16490f6bee135b2377e8f8c39227974c799ad7d49ff418af23ecbc35` + +来源:`packages/attachment/attachment/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `attachmentId` | 必需 | `string` | +| `bytes` | 必需 | `number` | +| `height` | 必需 | `number` | +| `mediaType` | 必需 | [`packages/attachment/attachment/src/types.ts#ImageMediaType`](#persistence-type-packagesattachmentattachmentsrctypestsimagemediatype) | +| `name` | 可选 | `string` | +| `originalDimensions` | 可选 | [`event:agent/inbox/spliced.data.inserted[0].content[0][2].attachment.originalDimensions`](#persistence-type-eventagentinboxspliceddatainserted0content02attachmentoriginaldimensions) | +| `width` | 必需 | `number` | + + + +#### `packages/attachment/attachment/src/types.ts#ImageMediaType` + +SHA-256: `2f1e6a7ebace43d727ae138ddcd352eb3813960009e5805b8c5ac84300c97716` + +来源:`packages/attachment/attachment/src/types.ts` + +以下类型之一: + +- `"image/gif"` +- `"image/jpeg"` +- `"image/png"` +- `"image/webp"` + + + +#### `packages/compaction/compaction-image-offload/src/projection.ts#ImageOffloadTarget` + +SHA-256: `1cde1bedde79c5e8a56aee9c05c8e0a579cf5bc611deb85b93fa331a16ca978f` + +来源:`packages/compaction/compaction-image-offload/src/projection.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `imageIndexes` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `seq` | 必需 | `number` | + + + +#### `packages/context/agent-instructions/src/render.ts#AgentInstructionChange` + +SHA-256: `83da72c6857601c75da11212ef847f57d457b9c99f0a82246dcdff3e26700239` + +来源:`packages/context/agent-instructions/src/render.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `action` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].source[16].changes[0].action`](#persistence-type-eventagentinboxspliceddatainserted0source16changes0action) | +| `digest` | 可选 | `string` | +| `path` | 必需 | `string` | +| `scope` | 必需 | `string` | + + + +#### `packages/context/agent-instructions/src/state.ts#AgentInstructionSource` + +SHA-256: `6f22a9d02b9a1f1157f3b0e7bdccd7e7b12b085c4efdb709dfc74a465cd4e590` + +来源:`packages/context/agent-instructions/src/state.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `baseline` | 可选 | `true` | +| `baselineIdentity` | 可选 | `string` | +| `changes` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].source[16].changes`](#persistence-type-eventagentinboxspliceddatainserted0source16changes) | +| `form` | 必需 | `"instructions"` | +| `kind` | 必需 | `"agent-instructions"` | + + + +#### `packages/context/session-reference/src/types.ts#SessionReferenceSource` + +SHA-256: `f56c5b59ca0161310c338d31dd16cf14287ccd602ff4181058df178c1c286d7f` + +来源:`packages/context/session-reference/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"recall"` | +| `kind` | 必需 | `"session-reference"` | +| `references` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].source[15].references`](#persistence-type-eventagentinboxspliceddatainserted0source15references) | +| `version` | 必需 | `1` | + + + +#### `packages/core/agent/src/types.ts#InboxTarget` + +SHA-256: `96f4a9c81fc0f940ef71528a8cc66731ae4cf1f40d79680c5fe3c39f96d7723c` + +来源:`packages/core/agent/src/types.ts` + +以下类型之一: + +- `"next-step"` +- `"next-turn"` + + + +#### `packages/core/session/src/types.ts#EpochHeader` + +SHA-256: `c55a891c7aac496de6ee64c91c1fb65728c977314013033e42c863428aada854` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `adapterDefaults` | 可选 | [`packages/llm/llm/src/call-config.ts#LlmCallConfigAdapterDefaults`](#persistence-type-packagesllmllmsrccall-configtsllmcallconfigadapterdefaults) | +| `config` | 必需 | [`packages/llm/llm/src/call-config.ts#LlmCallConfig`](#persistence-type-packagesllmllmsrccall-configtsllmcallconfig) | +| `tools` | 可选 | [`event:request/header.data.header.tools`](#persistence-type-eventrequestheaderdataheadertools) | + + + +#### `packages/core/session/src/types.ts#RequestContext` + +SHA-256: `b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `contextWindow` | 可选 | `number` | +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `systemPromptUpdate` | 可选 | `"in-history"` | + + + +#### `packages/core/session/src/types.ts#RequestHeaderReason` + +SHA-256: `530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6` + +来源:`packages/core/session/src/types.ts` + +以下类型之一: + +- `"change"` +- `"initial"` +- `"resume"` +- `"series"` + + + +#### `packages/core/session/src/types.ts#SessionHeader` + +SHA-256: `2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `agentPreset` | 可选 | `string` | +| `createdAt` | 必需 | `number` | +| `cwd` | 可选 | `string` | +| `delegationDepth` | 可选 | `number` | +| `id` | 必需 | `string` | +| `isSeeded` | 必需 | `boolean` | +| `origin` | 可选 | `"subagent"` | +| `parentSession` | 可选 | `string` | +| `version` | 必需 | `3` | + + + +#### `packages/core/session/src/types.ts#SurfaceOp` + +SHA-256: `335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5` + +来源:`packages/core/session/src/types.ts` + +以下类型之一: + +- `"append"` +- [`SessionEventEnvelope[6].surfaceOp[1]`](#persistence-type-sessioneventenvelope6surfaceop1) + + + +#### `packages/core/session/src/types.ts#TurnEndCancelCause` + +SHA-256: `1f8c126cfab3df812cd115cfc23e3256f0fa2383400f4ce91ecad313577e59b0` + +来源:`packages/core/session/src/types.ts` + +以下类型之一: + +- [`event:turn/end.data.reason[1].reason[2]`](#persistence-type-eventturnenddatareason1reason2) +- [`event:turn/end.data.reason[1].reason[3]`](#persistence-type-eventturnenddatareason1reason3) +- [`event:turn/end.data.reason[1].reason[4]`](#persistence-type-eventturnenddatareason1reason4) +- [`event:turn/end.data.reason[1].reason[1]`](#persistence-type-eventturnenddatareason1reason1) +- [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) + + + +#### `packages/core/session/src/types.ts#TurnEndReason` + +SHA-256: `a5a8c15f08af1b0f26f40906e0797b6b0920fd01069e660becce35ab7fc48d77` + +来源:`packages/core/session/src/types.ts` + +以下类型之一: + +- [`event:turn/end.data.reason[5]`](#persistence-type-eventturnenddatareason5) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]`](#persistence-type-eventassistantattemptdatastream03chunk6reason2) +- [`event:turn/end.data.reason[3]`](#persistence-type-eventturnenddatareason3) +- [`event:turn/end.data.reason[1]`](#persistence-type-eventturnenddatareason1) +- [`event:turn/end.data.reason[2]`](#persistence-type-eventturnenddatareason2) +- [`event:turn/end.data.reason[0]`](#persistence-type-eventturnenddatareason0) + + + +#### `packages/core/tools/src/index.ts#ToolRestriction` + +SHA-256: `3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f` + +来源:`packages/core/tools/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `allow` | 可选 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `deny` | 可选 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | + + + +#### `packages/core/tools/src/types.ts#PtcDispatchEventData` + +SHA-256: `8d2e5a3c4230e6ea6c0b5151f02241d0db02cd2551f2df1b6b9700cddcc0dca3` + +来源:`packages/core/tools/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `arguments` | 必需 | `unknown`(不透明) | +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `error` | 可选 | [`event:tool/ptc-dispatch.data.error`](#persistence-type-eventtoolptc-dispatchdataerror) | +| `isError` | 必需 | `boolean` | +| `name` | 必需 | `string` | +| `parentCallId` | 必需 | `string` | +| `rootCallId` | 必需 | `string` | +| `subCallId` | 必需 | `string` | + + + +#### `packages/core/tools/src/types.ts#PtcDispatchStartEventData` + +SHA-256: `2fe5026daf14bd4ff2b7bfb7cf9791c302d9cbba06802178b6dfec00b892698f` + +来源:`packages/core/tools/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `arguments` | 必需 | `unknown`(不透明) | +| `name` | 必需 | `string` | +| `parentCallId` | 必需 | `string` | +| `rootCallId` | 必需 | `string` | +| `subCallId` | 必需 | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMemberPhase` + +SHA-256: `dfce5db4aa42b7ebe0bb79eca92553587287e18c06b9eba85cbfb9d332e26acd` + +来源:`packages/experimental/agent-team/src/types.ts` + +以下类型之一: + +- `"active"` +- `"failed"` +- `"provisioning"` + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMemberSnapshot` + +SHA-256: `6598cd6da253948d6b207c6374a45335804c79b576866d6215649c2d1bc85e25` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `context` | 必需 | [`event:team/member.data.member.context`](#persistence-type-eventteammemberdatamembercontext) | +| `description` | 必需 | `string` | +| `error` | 可选 | `string` | +| `id` | 必需 | `string` | +| `name` | 必需 | `string` | +| `phase` | 必需 | [`packages/experimental/agent-team/src/types.ts#TeamMemberPhase`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammemberphase) | +| `provider` | 必需 | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMessageSnapshot` + +SHA-256: `5b694f394d5e11609887a3ccfa82844935d49806c37e336b30be2186d649ab94` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | 必需 | `string` | +| `senderId` | 必需 | `string` | +| `senderName` | 必需 | `string` | +| `targetId` | 必需 | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamMessageSource` + +SHA-256: `2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"team-message"` | +| `messageId` | 必需 | `string` | +| `senderId` | 必需 | `string` | +| `senderName` | 必需 | `string` | +| `teamId` | 必需 | `string` | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamTaskSnapshot` + +SHA-256: `51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357` + +来源:`packages/experimental/agent-team/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `blockedBy` | 必需 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `description` | 必需 | `string` | +| `id` | 必需 | `string` | +| `ownerId` | 可选 | `string` | +| `revision` | 必需 | `number` | +| `status` | 必需 | [`packages/experimental/agent-team/src/types.ts#TeamTaskStatus`](#persistence-type-packagesexperimentalagent-teamsrctypeststeamtaskstatus) | +| `subject` | 必需 | `string` | +| `writeScopes` | 必需 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | + + + +#### `packages/experimental/agent-team/src/types.ts#TeamTaskStatus` + +SHA-256: `b2d2a01e51341a3bfec809198952c8c830a7899f4cb6ecd3c1dc0b5d9a2af943` + +来源:`packages/experimental/agent-team/src/types.ts` + +以下类型之一: + +- `"completed"` +- `"deleted"` +- `"in_progress"` +- `"pending"` + + + +#### `packages/feedback/command-feedback/src/types.ts#FeedbackRecord` + +SHA-256: `7d54a5a5e629e2e7783bfac72683bcc5e969e9f43426b9289826aaf294ff6344` + +来源:`packages/feedback/command-feedback/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `category` | 可选 | [`event:feedback/message-put.data.item.category`](#persistence-type-eventfeedbackmessage-putdataitemcategory) | +| `text` | 可选 | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackDelete` + +SHA-256: `7c6129b6961cf4b2a030f36c78d2b0a5be38617651a9b81322e054ee512bee06` + +来源:`packages/feedback/message-feedback/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `messageId` | 必需 | `string` | +| `sessionId` | 必需 | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackItem` + +SHA-256: `3d7d07060a7be77984feb651ea2bf1925d3e0477911d9d3ed86330d1e8ca6182` + +来源:`packages/feedback/message-feedback/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `category` | 可选 | [`event:feedback/message-put.data.item.category`](#persistence-type-eventfeedbackmessage-putdataitemcategory) | +| `createdAt` | 必需 | `number` | +| `messageId` | 必需 | `string` | +| `note` | 可选 | `string` | +| `rating` | 必需 | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackRating`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackrating) | +| `updatedAt` | 必需 | `number` | +| `version` | 必需 | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackPut` + +SHA-256: `aa7bc2817014ca6c45719b1c193c5c131be718a0921f34345098ff250f444626` + +来源:`packages/feedback/message-feedback/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `item` | 必需 | [`packages/feedback/message-feedback/src/types.ts#MessageFeedbackItem`](#persistence-type-packagesfeedbackmessage-feedbacksrctypestsmessagefeedbackitem) | +| `sessionId` | 必需 | `string` | + + + +#### `packages/feedback/message-feedback/src/types.ts#MessageFeedbackRating` + +SHA-256: `390eed1028aba02774f14408647acec10ec5516e97d4f15ecde2b9989d5a69f2` + +来源:`packages/feedback/message-feedback/src/types.ts` + +以下类型之一: + +- `"negative"` +- `"positive"` + + + +#### `packages/fs/tool-present/src/types.ts#PresentedFile` + +SHA-256: `b8fc636a2121df9d8423c242e03c9d23b7ab7c6fdce00e45746932c60b730f97` + +来源:`packages/fs/tool-present/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `description` | 可选 | `string` | +| `path` | 必需 | `string` | + + + +#### `packages/goal/goal/src/domain.ts#GoalChangeMeta` + +SHA-256: `7d226b9fd95b4ba213d4237c22e930a91c3c769c95ca7f92977b9d625ba13438` + +来源:`packages/goal/goal/src/domain.ts` + +以下类型之一: + +- [`packages/goal/goal/src/domain.ts#GoalClearChangeMeta`](#persistence-type-packagesgoalgoalsrcdomaintsgoalclearchangemeta) +- [`packages/goal/goal/src/domain.ts#GoalSnapshotChangeMeta`](#persistence-type-packagesgoalgoalsrcdomaintsgoalsnapshotchangemeta) + + + +#### `packages/goal/goal/src/domain.ts#GoalClearChangeMeta` + +SHA-256: `cffcdc19881ab61ec0a9ce18743996f7ac44ac8889f34dfac36ae745574aa22f` + +来源:`packages/goal/goal/src/domain.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `cleared` | 必需 | [`packages/goal/goal/src/types.ts#GoalRef`](#persistence-type-packagesgoalgoalsrctypestsgoalref) | +| `clearedAt` | 必需 | `number` | +| `kind` | 必需 | `"goal/change"` | +| `operation` | 必需 | `"clear"` | +| `version` | 必需 | `1` | + + + +#### `packages/goal/goal/src/domain.ts#GoalMessageSource` + +SHA-256: `7f959241c24128b4983b559984811861dc59774b85905c8fa57c6cb0148a3dbc` + +来源:`packages/goal/goal/src/domain.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `goalId` | 必需 | `string` | +| `kind` | 必需 | `"goal"` | +| `revision` | 必需 | `number` | +| `round` | 必需 | `number` | + + + +#### `packages/goal/goal/src/domain.ts#GoalSnapshotChangeMeta` + +SHA-256: `1df34a6c086866ffdc2dd9e8e5c581c3751a010cdf6b8538a7327f7a3237f0b4` + +来源:`packages/goal/goal/src/domain.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `createdAt` | 必需 | `number` | +| `goal` | 必需 | [`packages/goal/goal/src/types.ts#GoalSnapshot`](#persistence-type-packagesgoalgoalsrctypestsgoalsnapshot) | +| `kind` | 必需 | `"goal/change"` | +| `operation` | 必需 | [`event:goal/change.data[0].operation`](#persistence-type-eventgoalchangedata0operation) | +| `roundsStarted` | 必需 | `number` | +| `updatedAt` | 必需 | `number` | +| `version` | 必需 | `1` | + + + +#### `packages/goal/goal/src/types.ts#GoalBlockReason` + +SHA-256: `84ac8c1a66ffc697262e181f42e851259eae14038c113ca329fb4700ccdb1f7c` + +来源:`packages/goal/goal/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `code` | 必需 | `string` | +| `message` | 必需 | `string` | + + + +#### `packages/goal/goal/src/types.ts#GoalPhase` + +SHA-256: `b8327af7ee5767952d1300cb4f03b7fc04197ae5ba275e13981c689ff7506172` + +来源:`packages/goal/goal/src/types.ts` + +以下类型之一: + +- `"active"` +- `"blocked"` +- `"complete"` +- `"paused"` + + + +#### `packages/goal/goal/src/types.ts#GoalRef` + +SHA-256: `0b6d718c693fdf7f06dcccb0bcbbabe78cc63514eafc62d6b2a3899735279d6f` + +来源:`packages/goal/goal/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `id` | 必需 | `string` | +| `revision` | 必需 | `number` | + + + +#### `packages/goal/goal/src/types.ts#GoalSnapshot` + +SHA-256: `6bbe793f6a93dc8d50a4d4d3fbb6f8ed15650bcb7e151d28669628f7b7c3fc25` + +来源:`packages/goal/goal/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `blockedReason` | 可选 | [`packages/goal/goal/src/types.ts#GoalBlockReason`](#persistence-type-packagesgoalgoalsrctypestsgoalblockreason) | +| `id` | 必需 | `string` | +| `maxGoalRounds` | 必需 | `number` | +| `objective` | 必需 | `string` | +| `phase` | 必需 | [`packages/goal/goal/src/types.ts#GoalPhase`](#persistence-type-packagesgoalgoalsrctypestsgoalphase) | +| `revision` | 必需 | `number` | + + + +#### `packages/hooks/hook-protocol/src/types.ts#HookDialect` + +SHA-256: `a6b41f5bede8094d7bf635be5d69b1bd7a25e006ca9cf9415bceb9322f1a7feb` + +来源:`packages/hooks/hook-protocol/src/types.ts` + +以下类型之一: + +- `"claude-code"` +- `"codex"` + + + +#### `packages/interaction/user-approval/src/index.ts#ApprovalPolicy` + +SHA-256: `05d2ae1e0c7f8770f83f9a09047afb39a335d8ac986df3193659aa1e581472cf` + +来源:`packages/interaction/user-approval/src/index.ts` + +以下类型之一: + +- `"ask"` +- `"never"` + + + +#### `packages/interaction/user-approval/src/types.ts#ApprovalOutcome` + +SHA-256: `930c1cd289def119d443e19dd90008916bf035f0a4d23e07241e7f050f2b89b7` + +来源:`packages/interaction/user-approval/src/types.ts` + +以下类型之一: + +- `"allowed-once"` +- `"cancelled"` +- `"rejected"` +- `"unavailable"` + + + +#### `packages/llm/llm-retry/src/types.ts#LlmRetryEventData` + +SHA-256: `c170da8ab7c37635b10867b2571811d9e317ac3ec394e8ff8efe53f902fc41c1` + +来源:`packages/llm/llm-retry/src/types.ts` + +以下类型之一: + +- [`event:llm/retry.data[0]`](#persistence-type-eventllmretrydata0) +- [`event:llm/retry.data[1]`](#persistence-type-eventllmretrydata1) + + + +#### `packages/llm/llm-retry/src/types.ts#LlmRetryStartedEventData` + +SHA-256: `6f72ece8f317cd080c4f20a93f1bf709965f5b81ac4669528f5a023191cfcf20` + +来源:`packages/llm/llm-retry/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `retry` | 必需 | `number` | +| `retryId` | 必需 | `string` | +| `step` | 必需 | `number` | +| `turn` | 必需 | `number` | + + + +#### `packages/llm/llm/src/assistant-stream.ts#AssistantStreamRecord` + +SHA-256: `86cf1e44038cb8b11659863dd0efafe682e41b9c782265c1d50e0a687debfc60` + +来源:`packages/llm/llm/src/assistant-stream.ts` + +以下类型之一: + +- [`event:assistant/attempt.data.stream[0][2]`](#persistence-type-eventassistantattemptdatastream02) +- [`event:assistant/attempt.data.stream[0][3]`](#persistence-type-eventassistantattemptdatastream03) +- [`event:assistant/attempt.data.stream[0][1]`](#persistence-type-eventassistantattemptdatastream01) +- [`event:assistant/attempt.data.stream[0][0]`](#persistence-type-eventassistantattemptdatastream00) + + + +#### `packages/llm/llm/src/call-config.ts#LlmCallConfig` + +SHA-256: `67d5f73ceae82f5265258142ad6cf172de2c1fef93ba551b7f0454e0a93bffe0` + +来源:`packages/llm/llm/src/call-config.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `maxTokens` | 可选 | `number` | +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `reasoningEffort` | 可选 | `string` | +| `stop` | 可选 | [`event:assistant/attempt.data.stream[0][0].texts`](#persistence-type-eventassistantattemptdatastream00texts) | +| `temperature` | 可选 | `number` | + + + +#### `packages/llm/llm/src/call-config.ts#LlmCallConfigAdapterDefaults` + +SHA-256: `326a9bfda27dda5882fb3cbe6e715df41dae2298fdae3d66437457268a665693` + +来源:`packages/llm/llm/src/call-config.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `maxTokens` | 可选 | `true` | +| `reasoningEffort` | 可选 | `true` | + + + +#### `packages/llm/llm/src/message.ts#AssistantMessage` + +SHA-256: `e50b0a3ed8e6c80b672e4f855c91984f03b5c3fdd5d475bf171171f391a86c83` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | 必需 | `string` | +| `role` | 必需 | `"assistant"` | +| `source` | 必需 | [`packages/llm/llm/src/message.ts#ModelMessageSource`](#persistence-type-packagesllmllmsrcmessagetsmodelmessagesource) | + + + +#### `packages/llm/llm/src/message.ts#ContextSnapshotSection` + +SHA-256: `86e1e384495ee09ac2d60c9db3610f1f1fddac2d248f6f1d6000e78054680219` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `name` | 必需 | `string` | +| `text` | 必需 | `string` | + + + +#### `packages/llm/llm/src/message.ts#Message` + +SHA-256: `23c7cce57d20589897f4e2bd5898affc6fc611b87cd0cc8b95be1cfdd8b3a7eb` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | 必需 | `string` | +| `role` | 必需 | [`event:session/title-llm-request.data.messages[0].role`](#persistence-type-eventsessiontitle-llm-requestdatamessages0role) | +| `source` | 必需 | [`packages/llm/llm/src/message.ts#MessageSource`](#persistence-type-packagesllmllmsrcmessagetsmessagesource) | + + + +#### `packages/llm/llm/src/message.ts#MessageSource` + +SHA-256: `4c965666d5b42116945bc356087cd5e1fd549e6dece560785ed60511059a8283` + +来源:`packages/llm/llm/src/message.ts` + +以下类型之一: + +- [`packages/context/agent-instructions/src/state.ts#AgentInstructionSource`](#persistence-type-packagescontextagent-instructionssrcstatetsagentinstructionsource) +- [`packages/llm/llm/src/message.ts#ToolMessageSource`](#persistence-type-packagesllmllmsrcmessagetstoolmessagesource) +- [`event:agent/inbox/spliced.data.inserted[0].source[10]`](#persistence-type-eventagentinboxspliceddatainserted0source10) +- [`event:agent/inbox/spliced.data.inserted[0].source[19]`](#persistence-type-eventagentinboxspliceddatainserted0source19) +- [`packages/skill/tool-skill/src/index.ts#SkillCatalogSource`](#persistence-type-packagesskilltool-skillsrcindextsskillcatalogsource) +- [`packages/skill/skill/src/index.ts#SkillInvocationSource`](#persistence-type-packagesskillskillsrcindextsskillinvocationsource) +- [`event:agent/inbox/spliced.data.inserted[0].source[4]`](#persistence-type-eventagentinboxspliceddatainserted0source4) +- [`event:agent/inbox/spliced.data.inserted[0].source[5]`](#persistence-type-eventagentinboxspliceddatainserted0source5) +- [`event:agent/inbox/spliced.data.inserted[0].source[6]`](#persistence-type-eventagentinboxspliceddatainserted0source6) +- [`event:agent/inbox/spliced.data.inserted[0].source[3]`](#persistence-type-eventagentinboxspliceddatainserted0source3) +- [`event:agent/inbox/spliced.data.inserted[0].source[2]`](#persistence-type-eventagentinboxspliceddatainserted0source2) +- [`event:agent/inbox/spliced.data.inserted[0].source[7]`](#persistence-type-eventagentinboxspliceddatainserted0source7) +- [`packages/context/session-reference/src/types.ts#SessionReferenceSource`](#persistence-type-packagescontextsession-referencesrctypestssessionreferencesource) +- [`packages/subagent/subagent/src/continuation-messages.ts#SubagentSettledMessageSource`](#persistence-type-packagessubagentsubagentsrccontinuation-messagestssubagentsettledmessagesource) +- [`packages/subagent/subagent/src/continuation-messages.ts#AgentMessageSource`](#persistence-type-packagessubagentsubagentsrccontinuation-messagestsagentmessagesource) +- [`packages/goal/goal/src/domain.ts#GoalMessageSource`](#persistence-type-packagesgoalgoalsrcdomaintsgoalmessagesource) +- [`packages/experimental/agent-team/src/types.ts#TeamMessageSource`](#persistence-type-packagesexperimentalagent-teamsrctypeststeammessagesource) +- [`packages/llm/llm/src/message.ts#ModelMessageSource`](#persistence-type-packagesllmllmsrcmessagetsmodelmessagesource) +- [`event:agent/inbox/spliced.data.inserted[0].source[1]`](#persistence-type-eventagentinboxspliceddatainserted0source1) +- [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) + + + +#### `packages/llm/llm/src/message.ts#ModelMessageSource` + +SHA-256: `719c51f67074f97034a6c94297fe1f4b5d3c8d392c57586dab732aa5398c7a91` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `kind` | 必需 | `"model"` | +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | +| `replayState` | 可选 | `unknown`(不透明) | + + + +#### `packages/llm/llm/src/message.ts#SystemMessage` + +SHA-256: `302b01ddddcbb3b16cfa3fba2a5d99f5082a55fbd9dc5c83a179a228b8a6a0ca` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | 必需 | `string` | +| `role` | 必需 | `"system"` | +| `source` | 必需 | [`event:system/message.data.message.source`](#persistence-type-eventsystemmessagedatamessagesource) | + + + +#### `packages/llm/llm/src/message.ts#ToolMessageSource` + +SHA-256: `d9c462b9f62fdd3efc76a44b9524dc8781f6b91cd9c7e584b17d971defafebab` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `callId` | 必需 | `string` | +| `kind` | 必需 | `"tool"` | + + + +#### `packages/llm/llm/src/message.ts#ToolResultMessage` + +SHA-256: `1b573e2d5c094fa87e2a8bf409ddd4ac5ba92a123085e168de44b9ccdbd5244c` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:tool/result.data.message.content`](#persistence-type-eventtoolresultdatamessagecontent) | +| `id` | 必需 | `string` | +| `role` | 必需 | `"user"` | +| `source` | 必需 | [`packages/llm/llm/src/message.ts#ToolMessageSource`](#persistence-type-packagesllmllmsrcmessagetstoolmessagesource) | + + + +#### `packages/llm/llm/src/message.ts#UserMessage` + +SHA-256: `4de5e7644130ed715ef6b5a4d86a87b30dca4096d1a6683c66acf6f7809379c7` + +来源:`packages/llm/llm/src/message.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `id` | 必需 | `string` | +| `role` | 必需 | `"user"` | +| `source` | 必需 | [`packages/llm/llm/src/message.ts#MessageSource`](#persistence-type-packagesllmllmsrcmessagetsmessagesource) | + + + +#### `packages/llm/llm/src/types.ts#ContentBlock` + +SHA-256: `c7b24be059d34d08929593049a1a81eaa3855166aacfe9d7603c0bc8bb728d56` + +来源:`packages/llm/llm/src/types.ts` + +以下类型之一: + +- [`packages/llm/llm/src/types.ts#ReasoningBlock`](#persistence-type-packagesllmllmsrctypestsreasoningblock) +- [`event:web/deepseek-search-llm-request.data.body.messages[0].content[0]`](#persistence-type-eventwebdeepseek-search-llm-requestdatabodymessages0content0) +- [`packages/llm/llm/src/types.ts#ToolCallBlock`](#persistence-type-packagesllmllmsrctypeststoolcallblock) +- [`packages/llm/llm/src/types.ts#ImageBlock`](#persistence-type-packagesllmllmsrctypestsimageblock) +- [`packages/llm/llm/src/types.ts#FileBlock`](#persistence-type-packagesllmllmsrctypestsfileblock) +- [`packages/llm/llm/src/types.ts#ToolResultBlock`](#persistence-type-packagesllmllmsrctypeststoolresultblock) + + + +#### `packages/llm/llm/src/types.ts#ContentBlockType` + +SHA-256: `757013fff5879d73d5753d8d1120faab56110e88ac3932485ab7e034d9e9ce61` + +来源:`packages/llm/llm/src/types.ts` + +以下类型之一: + +- `"file"` +- `"image"` +- `"reasoning"` +- `"text"` +- `"tool-call"` +- `"tool-result"` + + + +#### `packages/llm/llm/src/types.ts#FileBlock` + +SHA-256: `f2da0f27c1e6add59982c37b15e4a4912c5b33466859cce3b13d503600e24aef` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `attachment` | 必需 | [`packages/attachment/attachment/src/types.ts#FileAttachmentRef`](#persistence-type-packagesattachmentattachmentsrctypestsfileattachmentref) | +| `type` | 必需 | `"file"` | + + + +#### `packages/llm/llm/src/types.ts#FinishReason` + +SHA-256: `5808e36c95355f0e745201b5db1b6bcec4ebf5adb75d3e82d7d59cc89635ab80` + +来源:`packages/llm/llm/src/types.ts` + +以下类型之一: + +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[3]`](#persistence-type-eventassistantattemptdatastream03chunk6reason3) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[4]`](#persistence-type-eventassistantattemptdatastream03chunk6reason4) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[0]`](#persistence-type-eventassistantattemptdatastream03chunk6reason0) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[1]`](#persistence-type-eventassistantattemptdatastream03chunk6reason1) +- [`event:assistant/attempt.data.stream[0][3].chunk[6].reason[2]`](#persistence-type-eventassistantattemptdatastream03chunk6reason2) + + + +#### `packages/llm/llm/src/types.ts#ImageBlock` + +SHA-256: `12d5808fac1996b9b3c2afa806e03022252ba2d7b88f835862ae1896591f60c7` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `attachment` | 必需 | [`packages/attachment/attachment/src/types.ts#ImageAttachmentRef`](#persistence-type-packagesattachmentattachmentsrctypestsimageattachmentref) | +| `offloaded` | 可选 | `true` | +| `type` | 必需 | `"image"` | + + + +#### `packages/llm/llm/src/types.ts#LlmFailure` + +SHA-256: `5f2117d1856a5ab43c28371faa978ebfaa48f8c7d734ea3fc94842210df83dca` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `code` | 必需 | `string` | +| `message` | 必需 | `string` | +| `offloadImages` | 可选 | `number` | +| `providerRetryAfterMs` | 可选 | `number` | +| `requestId` | 可选 | `string` | +| `status` | 可选 | `number` | + + + +#### `packages/llm/llm/src/types.ts#ReasoningBlock` + +SHA-256: `814d9434e1ddf9078612b3b34322f26e9363b469213335007f7e9ba7fee9464e` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `text` | 必需 | `string` | +| `type` | 必需 | `"reasoning"` | + + + +#### `packages/llm/llm/src/types.ts#ReplayEnvelope` + +SHA-256: `0acd94fe8794574c9ae72c7855ee16d29c546096d4af760d16d1225385764555` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `blocks` | 可选 | [`event:assistant/attempt.data.stream[0][3].chunk[6].replayState.blocks`](#persistence-type-eventassistantattemptdatastream03chunk6replaystateblocks) | +| `response` | 必需 | `unknown`(不透明) | + + + +#### `packages/llm/llm/src/types.ts#StreamChunk` + +SHA-256: `071d92b9dac661fcc826c678cf64d188f26fb93aab79c627b11a03acdd34dfca` + +来源:`packages/llm/llm/src/types.ts` + +以下类型之一: + +- [`event:assistant/attempt.data.stream[0][3].chunk[3]`](#persistence-type-eventassistantattemptdatastream03chunk3) +- [`event:assistant/attempt.data.stream[0][3].chunk[4]`](#persistence-type-eventassistantattemptdatastream03chunk4) +- [`event:assistant/attempt.data.stream[0][3].chunk[0]`](#persistence-type-eventassistantattemptdatastream03chunk0) +- [`event:assistant/attempt.data.stream[0][3].chunk[2]`](#persistence-type-eventassistantattemptdatastream03chunk2) +- [`event:assistant/attempt.data.stream[0][3].chunk[1]`](#persistence-type-eventassistantattemptdatastream03chunk1) +- [`event:assistant/attempt.data.stream[0][3].chunk[6]`](#persistence-type-eventassistantattemptdatastream03chunk6) +- [`event:assistant/attempt.data.stream[0][3].chunk[5]`](#persistence-type-eventassistantattemptdatastream03chunk5) + + + +#### `packages/llm/llm/src/types.ts#TokenUsage` + +SHA-256: `fec5442b9ee4122e10514d81d5a43648003fe8bfb7ee2ba50c0cdbdd383ed394` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `cacheReadTokens` | 可选 | `number` | +| `cacheWriteTokens` | 可选 | `number` | +| `inputTokens` | 必需 | `number` | +| `outputTokens` | 必需 | `number` | +| `reasoningTokens` | 可选 | `number` | +| `totalTokens` | 可选 | `number` | + + + +#### `packages/llm/llm/src/types.ts#ToolCallBlock` + +SHA-256: `c1f0f17b6493b85db6453bb30e01b208d703731b25bc1e68e5d4fc72eea9cdea` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `arguments` | 必需 | `string` | +| `id` | 必需 | `string` | +| `name` | 必需 | `string` | +| `type` | 必需 | `"tool-call"` | + + + +#### `packages/llm/llm/src/types.ts#ToolResultBlock` + +SHA-256: `d61574d68558c5a184429e70b04da393dd5460bf5cc3ddef814546e659bd5127` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].content`](#persistence-type-eventagentinboxspliceddatainserted0content) | +| `isError` | 可选 | `boolean` | +| `toolCallId` | 必需 | `string` | +| `type` | 必需 | `"tool-result"` | + + + +#### `packages/llm/llm/src/types.ts#ToolSchema` + +SHA-256: `7f5f2a8618c2ece530a18b1358b890fb57fb8c35705e47b66bff2296f8c6e889` + +来源:`packages/llm/llm/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `description` | 必需 | `string` | +| `name` | 必需 | `string` | +| `parameters` | 必需 | [`event:request/header.data.header.tools[0].parameters`](#persistence-type-eventrequestheaderdataheadertools0parameters) | + + + +#### `packages/sandbox/sandbox/src/index.ts#SandboxMode` + +SHA-256: `fab2bb09bc5e3b9db0685e8f5500b029af1a2b33e70bc703c1d5d0f596fbc1fd` + +来源:`packages/sandbox/sandbox/src/index.ts` + +以下类型之一: + +- `"danger-full-access"` +- `"read-only"` +- `"workspace-write"` + + + +#### `packages/schedule/schedule/src/types.ts#AfterScheduleRecord` + +SHA-256: `27e337d3d6b402b221e50c247a3f518a70d0c474cc60beee15fac3e9c5cbfcbe` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `afterSeconds` | 必需 | `number` | +| `id` | 必需 | `string` | +| `kind` | 必需 | `"after"` | +| `prompt` | 必需 | `string` | +| `scheduledAt` | 必需 | `string` | + + + +#### `packages/schedule/schedule/src/types.ts#AtScheduleRecord` + +SHA-256: `658d895d187b26d83f3b53109a3bf77bbfba9f6f9a6d4bc4ee4315b4eb36239e` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `id` | 必需 | `string` | +| `kind` | 必需 | `"at"` | +| `prompt` | 必需 | `string` | +| `scheduledAt` | 必需 | `string` | + + + +#### `packages/schedule/schedule/src/types.ts#EveryScheduleDispatchChange` + +SHA-256: `e6063d0451dc02026fd9b54ad3f77c7b1b6392ad3e872a7737ac84e13ca72344` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `acceptedAt` | 必需 | `string` | +| `id` | 必需 | `string` | +| `operation` | 必需 | `"dispatch"` | +| `version` | 必需 | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#EveryScheduleRecord` + +SHA-256: `66ece68282d8c06330fb83329a24ae54c386d5ccfab296bbf18369da8beb7d14` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `everySeconds` | 必需 | `number` | +| `id` | 必需 | `string` | +| `kind` | 必需 | `"every"` | +| `prompt` | 必需 | `string` | +| `scheduledAt` | 必需 | `string` | + + + +#### `packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange` + +SHA-256: `8e8e91646a5cae3fc78f7532a0013ff2088ae47077642c2edd507a508209b8af` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `id` | 必需 | `string` | +| `operation` | 必需 | `"dispatch"` | +| `version` | 必需 | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleChange` + +SHA-256: `e1d0e52dcd1855ffb803efc18f8f7b776c48d1c25757e8a75c0281fa298c02e1` + +来源:`packages/schedule/schedule/src/types.ts` + +以下类型之一: + +- [`packages/schedule/schedule/src/types.ts#EveryScheduleDispatchChange`](#persistence-type-packagesscheduleschedulesrctypestseveryscheduledispatchchange) +- [`packages/schedule/schedule/src/types.ts#ScheduleDeleteChange`](#persistence-type-packagesscheduleschedulesrctypestsscheduledeletechange) +- [`packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange`](#persistence-type-packagesscheduleschedulesrctypestsoneshotscheduledispatchchange) +- [`packages/schedule/schedule/src/types.ts#ScheduleCreateChange`](#persistence-type-packagesscheduleschedulesrctypestsschedulecreatechange) + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleCreateChange` + +SHA-256: `ca6425edd20afe34d0cedc6ad1abad1ad7b32e2fbc4c1d24db53939e80bf887f` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `operation` | 必需 | `"create"` | +| `schedule` | 必需 | [`packages/schedule/schedule/src/types.ts#ScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestsschedulerecord) | +| `version` | 必需 | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleDeleteChange` + +SHA-256: `18dc21f12bbac8ade8377e6fbb54179e20c3d955d73fba3244c57fb6bf001df0` + +来源:`packages/schedule/schedule/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `id` | 必需 | `string` | +| `operation` | 必需 | `"delete"` | +| `version` | 必需 | `1` | + + + +#### `packages/schedule/schedule/src/types.ts#ScheduleRecord` + +SHA-256: `d8f868c6b3e7189de6c1ffe2ea04794ea2aa31315b6347d12536e46020afac87` + +来源:`packages/schedule/schedule/src/types.ts` + +以下类型之一: + +- [`packages/schedule/schedule/src/types.ts#AfterScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestsafterschedulerecord) +- [`packages/schedule/schedule/src/types.ts#EveryScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestseveryschedulerecord) +- [`packages/schedule/schedule/src/types.ts#AtScheduleRecord`](#persistence-type-packagesscheduleschedulesrctypestsatschedulerecord) + + + +#### `packages/session/session-persistence-jsonl/src/format.ts#HeaderLine` + +SHA-256: `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` + +来源:`packages/session/session-persistence-jsonl/src/format.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `agentPreset` | 可选 | `string` | +| `createdAt` | 必需 | `number` | +| `cwd` | 可选 | `string` | +| `delegationDepth` | 必需 | `number` | +| `id` | 必需 | `string` | +| `isSeeded` | 必需 | `boolean` | +| `origin` | 可选 | `"subagent"` | +| `parentSession` | 可选 | `string` | +| `type` | 必需 | `"session"` | +| `version` | 必需 | `number` | + + + +#### `packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData` + +SHA-256: `9fe0e77a7816b7fdb4b953ec0e2f0cd7bbd22c5de5c3567e612d1b20eb0992e6` + +来源:`packages/session/session-title-llm/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `maxTokens` | 必需 | `number` | +| `messageSeqs` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `messages` | 必需 | [`event:session/title-llm-request.data.messages`](#persistence-type-eventsessiontitle-llm-requestdatamessages) | +| `route` | 必需 | [`packages/session/session-title/src/types.ts#SessionTitleModelIdentity`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlemodelidentity) | +| `system` | 必需 | `string` | +| `titleProvider` | 必需 | `string` | + + + +#### `packages/session/session-title/src/types.ts#SessionTitleEventData` + +SHA-256: `b56f6a885da3dc394c69a3e3cc5c0cfc4da15601b63fda4989eee8f40efc5be4` + +来源:`packages/session/session-title/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `messageSeqs` | 必需 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `source` | 必需 | [`packages/session/session-title/src/types.ts#SessionTitleSource`](#persistence-type-packagessessionsession-titlesrctypestssessiontitlesource) | +| `title` | 必需 | `string` | + + + +#### `packages/session/session-title/src/types.ts#SessionTitleModelIdentity` + +SHA-256: `07e1a58c58b593f507b8e7f25723bb0aa42baae6e00f5ecfddf28cb1e64d3235` + +来源:`packages/session/session-title/src/types.ts` · `packages/subagent/tool-subagent/src/model-selection.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `model` | 必需 | `string` | +| `provider` | 必需 | `string` | + + + +#### `packages/session/session-title/src/types.ts#SessionTitleSource` + +SHA-256: `30d5a537b296685770b1241c4b4bbde19d5a31ff81aa23df73fab5e90b8fc65f` + +来源:`packages/session/session-title/src/types.ts` + +以下类型之一: + +- [`event:session/title.data.source[1]`](#persistence-type-eventsessiontitledatasource1) +- [`event:session/title.data.source[0]`](#persistence-type-eventsessiontitledatasource0) +- [`event:agent/inbox/spliced.data.inserted[0].source[0]`](#persistence-type-eventagentinboxspliceddatainserted0source0) + + + +#### `packages/skill/skill/src/index.ts#SkillInvocationSource` + +SHA-256: `672c4aa2a9b736e3d6e5da6346d2e2ed5e3573f2d0baafa18e7407c9f3fee3db` + +来源:`packages/skill/skill/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"instructions"` | +| `kind` | 必需 | `"skill-invocation"` | +| `name` | 必需 | `string` | + + + +#### `packages/skill/tool-skill/src/index.ts#SkillCatalogSource` + +SHA-256: `fc2ae6962f9f8801c2b1e414668e1e17cbb7544c4f39381198977a38bd10c093` + +来源:`packages/skill/tool-skill/src/index.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `entries` | 必需 | [`event:agent/inbox/spliced.data.inserted[0].source[17].entries`](#persistence-type-eventagentinboxspliceddatainserted0source17entries) | +| `form` | 必需 | `"catalog"` | +| `kind` | 必需 | `"skill-catalog"` | +| `update` | 可选 | `true` | + + + +#### `packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent` + +SHA-256: `3ac1196f59d5e9e0e9345122c8c403b102478b526404a2e591a38f613483321e` + +来源:`packages/subagent/subagent/src/catalog.ts` + +以下类型之一: + +- [`event:subagent/catalog.data[1]`](#persistence-type-eventsubagentcatalogdata1) +- [`event:subagent/catalog.data[0]`](#persistence-type-eventsubagentcatalogdata0) + + + +#### `packages/subagent/subagent/src/continuation-messages.ts#AgentMessageSource` + +SHA-256: `4a9bef9f27a942520cc2279ca7dd3082556e4bff543f66b5c0333e1bbed1cd86` + +来源:`packages/subagent/subagent/src/continuation-messages.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"relay"` | +| `kind` | 必需 | `"agent-message"` | +| `senderSessionId` | 必需 | `string` | + + + +#### `packages/subagent/subagent/src/continuation-messages.ts#SubagentSettledMessageSource` + +SHA-256: `4e97c3d85c0fc817ee58873c38c25a2474abaaa0af4839311b50b68db3b8cf1a` + +来源:`packages/subagent/subagent/src/continuation-messages.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `form` | 必需 | `"notice"` | +| `kind` | 必需 | `"subagent-settled"` | +| `senderSessionId` | 必需 | `string` | +| `summary` | 必需 | `string` | + + + +#### `packages/subagent/subagent/src/descriptor.ts#ContinuableSubagentDescriptorData` + +SHA-256: `6487b10ba7542f3c447b1e41a1c6a590b7bfafe0b9b66b49f34028da85bb970f` + +来源:`packages/subagent/subagent/src/descriptor.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `agentModel` | 可选 | `string` | +| `agentProvider` | 可选 | `string` | +| `agentReasoningEffort` | 可选 | `string` | +| `label` | 必需 | `string` | +| `mode` | 必需 | `"continuable"` | +| `persona` | 可选 | `string` | +| `provider` | 必需 | `string` | +| `toolFilter` | 可选 | [`packages/core/tools/src/index.ts#ToolRestriction`](#persistence-type-packagescoretoolssrcindextstoolrestriction) | +| `version` | 必需 | `number` | + + + +#### `packages/subagent/subagent/src/descriptor.ts#OneShotSubagentDescriptorData` + +SHA-256: `5f758f3de5f00c18968a7c6d347083aac5c9ae13f6a79c78f6611b23c4973564` + +来源:`packages/subagent/subagent/src/descriptor.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `label` | 可选 | `string` | +| `mode` | 必需 | `"one-shot"` | +| `provider` | 必需 | `string` | +| `version` | 必需 | `number` | + + + +#### `packages/subagent/subagent/src/descriptor.ts#SubagentDescriptorData` + +SHA-256: `86d1d0e9cfebb240421187e3dc37fb71cc38a1501885cf32f8f9adef7b0a2bde` + +来源:`packages/subagent/subagent/src/descriptor.ts` + +以下类型之一: + +- [`packages/subagent/subagent/src/descriptor.ts#ContinuableSubagentDescriptorData`](#persistence-type-packagessubagentsubagentsrcdescriptortscontinuablesubagentdescriptordata) +- [`packages/subagent/subagent/src/descriptor.ts#OneShotSubagentDescriptorData`](#persistence-type-packagessubagentsubagentsrcdescriptortsoneshotsubagentdescriptordata) + + + +#### `packages/todo/tool-todo/src/types.ts#TodoItem` + +SHA-256: `a99f76fd149051c363f960bfeeb5b9509587ecaf7591a42797e4bfe810d8987a` + +来源:`packages/todo/tool-todo/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `content` | 必需 | `string` | +| `status` | 必需 | [`event:todo/write.data.todos[0].status`](#persistence-type-eventtodowritedatatodos0status) | + + + +#### `packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest` + +SHA-256: `2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9` + +来源:`packages/web/web-search-deepseek/src/provider.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `apiVersion` | 必需 | `string` | +| `body` | 必需 | [`event:web/deepseek-search-llm-request.data.body`](#persistence-type-eventwebdeepseek-search-llm-requestdatabody) | +| `endpoint` | 必需 | `string` | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData` + +SHA-256: `c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7` + +来源:`packages/workflow/tool-workflow/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `outcome` | 必需 | [`packages/workflow/workflow/src/types.ts#WorkflowAgentOutcome`](#persistence-type-packagesworkflowworkflowsrctypestsworkflowagentoutcome) | +| `runId` | 必需 | `string` | +| `seq` | 必需 | `number` | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData` + +SHA-256: `9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc` + +来源:`packages/workflow/tool-workflow/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `childId` | 必需 | `string` | +| `label` | 必需 | `string` | +| `phase` | 可选 | `string` | +| `runId` | 必需 | `string` | +| `seq` | 必需 | `number` | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunEndData` + +SHA-256: `7f9365bae9fcb73e1e34061a1acfe0422c1a5fd351848cace9bebbe806f28462` + +来源:`packages/workflow/tool-workflow/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `runId` | 必需 | `string` | +| `stopReason` | 必需 | [`packages/workflow/workflow/src/types.ts#WorkflowStopReason`](#persistence-type-packagesworkflowworkflowsrctypestsworkflowstopreason) | + + + +#### `packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData` + +SHA-256: `a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c` + +来源:`packages/workflow/tool-workflow/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `name` | 必需 | `string` | +| `runId` | 必需 | `string` | + + + +#### `packages/workflow/workflow/src/types.ts#WorkflowAgentOutcome` + +SHA-256: `c2deb7c9183735d4e0fffddf5c623f4e34daa1c8e96b111982e957dfcbbcf896` + +来源:`packages/workflow/workflow/src/types.ts` + +以下类型之一: + +- `"cancelled"` +- `"completed"` +- `"failed"` + + + +#### `packages/workflow/workflow/src/types.ts#WorkflowStopReason` + +SHA-256: `8465ece5e9d9007c038b357015d849c15262cb0bc25abc59e47692d87ee01a15` + +来源:`packages/workflow/workflow/src/types.ts` + +以下类型之一: + +- `"cancelled"` +- `"completed"` +- `"error"` + + + +#### `"parent"` + +SHA-256: `e6411b09c1d982f789bf741ca74e2bea69df56029847f86a6148e722039ee732` + +`"parent"` + + + +#### `"pause"` + +SHA-256: `1d8798b1a5e8c545ee4dcd2b4e75c0b4c9ffd985e4744c6d1a1aab992f859721` + +`"pause"` + + + +#### `"paused"` + +SHA-256: `c43b119ce579b3e9983a0d3adc4ba402ebb9ba773d89738a2dab01ecf5813943` + +`"paused"` + + + +#### `"pending"` + +SHA-256: `234142ee4f996f38cc9fa3b8b3e3de29b03c9aefe5ebf6c224eddd564505aa85` + +`"pending"` + + + +#### `"permission/preset"` + +SHA-256: `ae63d9d1080ed8945031594d93f8d96651d7101b848719cc3e1475875cd3d649` + +`"permission/preset"` + + + +#### `"plan/mode"` + +SHA-256: `f634871d1e18b1eb199497ac8ab72d3964f48d03fbf611dc7521a1970cf429d9` + +`"plan/mode"` + + + +#### `"plugin"` + +SHA-256: `e654d28d1e6c471147310d2fba396d00969cfe6ed9022626d3f2c2312e0b1cbb` + +`"plugin"` + + + +#### `"positive"` + +SHA-256: `df5d9709b7db2a72510dc52052a23f0c38f39730af1504bab8bccabc14fae528` + +`"positive"` + + + +#### `"product-interaction"` + +SHA-256: `0341d4c3dfcd53253cdc1e789d9130d3cd848b6f8b0706bf92f313a68b39ff23` + +`"product-interaction"` + + + +#### `"provider"` + +SHA-256: `e31572180d6b28b73f073ad30ae19d5d82982d3daf984723984e23da1e7c459a` + +`"provider"` + + + +#### `"provisioning"` + +SHA-256: `871bfd6f7bb91061246768d3377f3fd58d6b8ea7c31f44c714ae7ab215650d62` + +`"provisioning"` + + + +#### `"read-only"` + +SHA-256: `12a0cfa619ac4a5fc6c3e8e359c8dae15769edc61497a575935c78d5842f8e42` + +`"read-only"` + + + +#### `"reasoning"` + +SHA-256: `3c2535ca0a2062f172f15344f8040755002b5ac506cf94fc4ebaa822b15feb8c` + +`"reasoning"` + + + +#### `"reasoning-chunks"` + +SHA-256: `688e853dc149f0d30b31765c12ec7e3be74169bdf1a4c6463a10b945d50cc1b8` + +`"reasoning-chunks"` + + + +#### `"reasoning-delta"` + +SHA-256: `6f091fe32ab24407236090ca9d710bbaf59bb57466e9f3b8f1f6e4862bc863c6` + +`"reasoning-delta"` + + + +#### `"recall"` + +SHA-256: `383cf73ae4748e5beb281ae74857ba1ffb92ae01075b9fbf51af78b666007a8f` + +`"recall"` + + + +#### `"rejected"` + +SHA-256: `fab35c4520883c0d69e42d079c9f543fc5ac7a2d15b537b5572fcd99059c7018` + +`"rejected"` + + + +#### `"relay"` + +SHA-256: `16d0507cb94b4cfc84a87446b1ba7652d6ec1d65ee1684789e747e30d542800e` + +`"relay"` + + + +#### `"remove"` + +SHA-256: `7382c4fc95fe8c5db65ca4d9da572b115d0dbb818b7f32c22ab040318ffbb4bc` + +`"remove"` + + + +#### `"replace"` + +SHA-256: `f6cb462f808309e315fea634f1ed86268b8346bbcee6774d9097ca6eed7ac1f8` + +`"replace"` + + + +#### `"request/context"` + +SHA-256: `70b082fe78991edf13cf66e1b4d06cd2dcff9cacfd76f8cfb996bfb61939e7b2` + +`"request/context"` + + + +#### `"request/header"` + +SHA-256: `3e0eff5946255ff05d88a10839c60305135801f97794ea48d409f8503303317e` + +`"request/header"` + + + +#### `"resource-cost"` + +SHA-256: `5bd310104cfe448e530beb11422d2f791e2e32e8e95fdc528a15f9ca693dae75` + +`"resource-cost"` + + + +#### `"resume"` + +SHA-256: `34d1ab5c5df378186d6054b1a1beea9a41e41965d6f336f0bc0025c441a82e66` + +`"resume"` + + + +#### `"sandbox/mode"` + +SHA-256: `ca085dba2c877feceebf3c62f9d39c6c2a4d2314d97b94b3927a780fe8fe2bb2` + +`"sandbox/mode"` + + + +#### `"schedule/change"` + +SHA-256: `0e7b2a97f54f1afdb8cdfad1635abe9145327db539bfb69b4045c19d8c17755d` + +`"schedule/change"` + + + +#### `"security-privacy-permission"` + +SHA-256: `07eccc9ea2f9b5439d76cc77d5e062936677d43f07a23da749819b0a22ee36b7` + +`"security-privacy-permission"` + + + +#### `"series"` + +SHA-256: `4f507598cf476214aa7646ce7841a7064a9dcb05d0a1eaaefaf79c2b738f160f` + +`"series"` + + + +#### `"service-stability"` + +SHA-256: `7180844e1066230c5e891f1b9ccd942423b0fe48aac6ded7eef2a285b288a732` + +`"service-stability"` + + + +#### `"session"` + +SHA-256: `e41bdebe246abe17154de7e7a1d81035437eee8d20e7f1edff0d91e2598ad828` + +`"session"` + + + +#### `"session-log-deepseek/delivery-accepted"` + +SHA-256: `47e5d84f1a93450a78c7f3954b43990d0f629af7c034a56313e5deb63e772c1b` + +`"session-log-deepseek/delivery-accepted"` + + + +#### `"session-reference"` + +SHA-256: `7f13860ee89a2d35ce09f958e85a04566cd59cb1de1d73a9619a9b631961dc71` + +`"session-reference"` + + + +#### `"session/end-seed"` + +SHA-256: `1c2686c0682e7bc51d61117b2652bd4a80707e331aa276d6ef915ae32534a330` + +`"session/end-seed"` + + + +#### `SessionEventEnvelope` + +SHA-256: `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` + +以下类型之一: + +- [`SessionEventEnvelope[39]`](#persistence-type-sessioneventenvelope39) +- [`SessionEventEnvelope[6]`](#persistence-type-sessioneventenvelope6) +- [`SessionEventEnvelope[0]`](#persistence-type-sessioneventenvelope0) + + + +#### `SessionEventEnvelope[0]` + +SHA-256: `e3e77b26f0148755a505f5b8ea843a3be117827d4703bb5754d9dc8ddbef521f` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `time` | 必需 | `number` | +| `type` | 必需 | `string` | + + + +#### `SessionEventEnvelope[39]` + +SHA-256: `998f22585a5d73ec005365e203f07fc3b3a029e82323fdda3fd7f13b0a9639d0` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `sourceEventSeqs` | 可选 | [`SessionEventEnvelope[39].sourceEventSeqs`](#persistence-type-sessioneventenvelope39sourceeventseqs) | +| `surfaceOp` | 必需 | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | 必需 | `number` | +| `type` | 必需 | `string` | + + + +#### `SessionEventEnvelope[39].sourceEventSeqs` + +SHA-256: `5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78` + +`number` 的数组。 + + + +#### `SessionEventEnvelope[6]` + +SHA-256: `7af85bf70d4eafce63e739adae38ea85501e68df3a0e22f97f3a0be90fd9e4cb` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `ignorable` | 可选 | `true` | +| `seq` | 必需 | `number` | +| `surfaceOp` | 必需 | [`packages/core/session/src/types.ts#SurfaceOp`](#persistence-type-packagescoresessionsrctypestssurfaceop) | +| `time` | 必需 | `number` | +| `type` | 必需 | `string` | + + + +#### `SessionEventEnvelope[6].surfaceOp[1]` + +SHA-256: `bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825` + +来源:`packages/core/session/src/types.ts` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `endSeq` | 必需 | `number` | +| `op` | 必需 | `"replace"` | +| `startSeq` | 必需 | `number` | + + + +#### `"session/title"` + +SHA-256: `7a651f3b672c52fb615f22c0ce9cb3cc5b22aad92e6bbeefb0808fd7b9233a50` + +`"session/title"` + + + +#### `"session/title-llm-request"` + +SHA-256: `587bb11da730e06aa52b62c087d217d6f8f22459b25f31cb9e1e1baf17944e5e` + +`"session/title-llm-request"` + + + +#### `"set"` + +SHA-256: `b765ee31033cea463863faf3fc6a0a1b85c47c6a2f13fe1ce833abe56105114b` + +`"set"` + + + +#### `"skill-catalog"` + +SHA-256: `6ebcc2dbec9f2dabca9f668ae6d39e877899b180740570f453409db339221df3` + +`"skill-catalog"` + + + +#### `"skill-invocation"` + +SHA-256: `1922cd79a70806c17758185a6ef0458bc1fb3900363906733421c16414da2509` + +`"skill-invocation"` + + + +#### `"snapshot"` + +SHA-256: `6f9e00383836275e46c0a9915767f9bb561be5fc30aae490174908a93e99a912` + +`"snapshot"` + + + +#### `"step/end"` + +SHA-256: `c219efbdfd53b836786202ab4532913d555798f0a8615a4e9629736e3799fb70` + +`"step/end"` + + + +#### `"step/start"` + +SHA-256: `2c64d4bc7264fd3f8bed47e96ab8a593bce05a1e4e1c436dcd244a3b7e0c2a9d` + +`"step/start"` + + + +#### `"stop"` + +SHA-256: `57f3f606ff8b6c84d9c443faace9d1dd10cca0354f37a4f515ef075f7c351b90` + +`"stop"` + + + +#### `string` + +SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` + +来源:`packages/api/session-controller/src/types.ts` · `packages/attachment/attachment/src/brand.ts` · `packages/compaction/compaction/src/brand.ts` · `packages/core/session/src/types.ts` · `packages/experimental/agent-team/src/types.ts` · `packages/feedback/message-feedback/src/types.ts` · `packages/goal/goal/src/types.ts` · `packages/interaction/commands/src/brand.ts` · `packages/interaction/user-approval/src/types.ts` · `packages/llm/llm-retry/src/brand.ts` · `packages/llm/llm/src/brand.ts` · `packages/schedule/schedule/src/types.ts` · `packages/session/session-title/src/index.ts` · `packages/session/session-title/src/types.ts` · `packages/webhook/webhook/src/brand.ts` · `packages/workflow/workflow/src/types.ts` + +`string` + + + +#### `"subagent"` + +SHA-256: `aacda84a69739238aa782eea902d3073017d9d74b9808de2bf5a83c9738cbdc6` + +`"subagent"` + + + +#### `"subagent-settled"` + +SHA-256: `bf16d2e98a7f13894ded2cffe5ce857bf473954a0e3c0ed9bc7739e2e1c7b78a` + +`"subagent-settled"` + + + +#### `"subagent/catalog"` + +SHA-256: `44c8c77aa9aa100b0d74d2deee85474b29faa6eee0ac0f662f7abe9931ddd7f2` + +`"subagent/catalog"` + + + +#### `"subagent/descriptor"` + +SHA-256: `5ebce1317eacd2c148456627a09668e927ee15c204f0643f5ea76b46b54a2647` + +`"subagent/descriptor"` + + + +#### `"subagent/model-selection-policy"` + +SHA-256: `0a8a062bc9c3c0d97fd97742262f2ea53dd32297f834e81114870d38ac3dc6da` + +`"subagent/model-selection-policy"` + + + +#### `"success"` + +SHA-256: `511801b0a6470d98566e8385d3dffddb2b67f79fcf73ed6056f46c3cc0a245a7` + +`"success"` + + + +#### `"system"` + +SHA-256: `8af841fc9b265ade3441caf9fe40dd24db24226befba48150e6d0eeccc1389c3` + +`"system"` + + + +#### `"system/message"` + +SHA-256: `1c5a58f4599bd4a9711712551ffe2442a5e5fcd0758bafe630cc4ead850bdaa7` + +`"system/message"` + + + +#### `"task-result"` + +SHA-256: `f05fb85e715af4ab4de0b6ba111166dd0435bd8bb74a0fa0f32b9d174113fc7c` + +`"task-result"` + + + +#### `"team-message"` + +SHA-256: `2e4debca12f2c449f96dc6574f3fbf2fb346193443114a241d01a236362ec48c` + +`"team-message"` + + + +#### `"team/member"` + +SHA-256: `18fcdd273a2f2f9d813a3be5e71df5903a963a5c88e46b90b14de6e2db890da0` + +`"team/member"` + + + +#### `"team/message/delivered"` + +SHA-256: `a8a2b9011fc067862df7ce40748868467e5778283d7ac193c13f77684a914c57` + +`"team/message/delivered"` + + + +#### `"team/message/queued"` + +SHA-256: `4e011753f8263f436efaabfbb3b4db53a98fc55342c5ded2daf7208b217be159` + +`"team/message/queued"` + + + +#### `"team/task"` + +SHA-256: `b57ae1b37e52bee0a21cbdace168dc6a15582bcda8c306dad962c5dcc8a8e28b` + +`"team/task"` + + + +#### `"text"` + +SHA-256: `4e44c9118152f6829634bfd508e47669ab0497caffa380c94b4be91f9390d35d` + +`"text"` + + + +#### `"text-chunks"` + +SHA-256: `f9cfc89e8fe085b4fcc9cd32b74b6f103608c54d7d8cd97b47c01de34f252ba3` + +`"text-chunks"` + + + +#### `"text-delta"` + +SHA-256: `5abab3a27fd2736660ecddd94b28d6bbf114986dd894880153bd1be3ccacb563` + +`"text-delta"` + + + +#### `"todo/write"` + +SHA-256: `af0750d32d97d47b12b7361a587db41894b17e04c9a805fe212f0114aa2248c7` + +`"todo/write"` + + + +#### `"tool"` + +SHA-256: `a13d8f379222ece8a02a86efe4c8334af4f108ecb3034b38c0a42bb3046e6847` + +`"tool"` + + + +#### `"tool-call"` + +SHA-256: `1f0133217eeeffd8d387baf1ec8ed9856e719bcd999dc08e48624cba96d75fd7` + +`"tool-call"` + + + +#### `"tool-call-chunks"` + +SHA-256: `616f93a5047de668e1c30d57b1786abd76beeb4123599637ec1dc5290320ede5` + +`"tool-call-chunks"` + + + +#### `"tool-call-delta"` + +SHA-256: `9b4fd974c124c83743efe030ba4e1250e087505f3f74588716a521fb8d453267` + +`"tool-call-delta"` + + + +#### `"tool-calls"` + +SHA-256: `6c1cccb433ddc153facb380c7dda956237ba5c31f8a532a69142dc277890cc9b` + +`"tool-calls"` + + + +#### `"tool-result"` + +SHA-256: `e5244812c495a80c2e78ba2c2690dca5f6b58ea8d3fe5531ff94a6f9ac5e5d66` + +`"tool-result"` + + + +#### `"tool-workflow/agent-end"` + +SHA-256: `5d17f27a1ef9f7026c0232714adf7573961536d75f3303ca97973975f5af170e` + +`"tool-workflow/agent-end"` + + + +#### `"tool-workflow/agent-start"` + +SHA-256: `ad92f473a03ae72599ff26c86e897c25e16269519ad2a87340f0bea946517af8` + +`"tool-workflow/agent-start"` + + + +#### `"tool-workflow/run-end"` + +SHA-256: `fe792a6cd430494503837e21e79f91677704ccdd9e870c679aabd7d43ed47ddd` + +`"tool-workflow/run-end"` + + + +#### `"tool-workflow/run-start"` + +SHA-256: `cdca80b8dad24d4e7b1d5a288a8475ba8d8d46be385bd2da85f122ee836f1670` + +`"tool-workflow/run-start"` + + + +#### `"tool/call"` + +SHA-256: `c589e938cc0e4989df8b82abef6339de621f0dc4fe62c230d145b94996af7f92` + +`"tool/call"` + + + +#### `"tool/ptc-dispatch"` + +SHA-256: `fb5e0517050d2c6d40e5b8145db1f7c5ca7044d5d50fada6ff80e0b22c6ca973` + +`"tool/ptc-dispatch"` + + + +#### `"tool/ptc-dispatch-start"` + +SHA-256: `2aed07493b1c65b6d00de5586da1e743cf501684b9ad43a1765fb4007d4ea456` + +`"tool/ptc-dispatch-start"` + + + +#### `"tool/result"` + +SHA-256: `570e85022434613394418ad33e77e9f1f7a05699b33d0b62eae0677a638c3833` + +`"tool/result"` + + + +#### `true` + +SHA-256: `dacf3d5f3e4ff619c1320e64a48dec5e7ecd7870bece65fbd449a0e63adfa521` + +`true` + + + +#### `"turn/end"` + +SHA-256: `4312134fc6f9cad507c31390bd3d147535492dd77621ec517c5e85f853d53a03` + +`"turn/end"` + + + +#### `"turn/start"` + +SHA-256: `0af3ecfb8c60d416fc40a7cc4fb2c4851a8e46608b2b38ab9e510670c971aa1f` + +`"turn/start"` + + + +#### `"unavailable"` + +SHA-256: `2c4c21f19f426a58f2dac914e34313aa43f8408972de857a486d1f086d5adb6c` + +`"unavailable"` + + + +#### `unknown` + +SHA-256: `bbc5696e3f13c758237b316e3cf08cda0b9fd51ffe672539883457769faa185d` + +`unknown`:此声明未暴露存储值的内部字段。 + + + +#### `"usage"` + +SHA-256: `0bdaf9cb63594be4ef034b68901fffe792fe09d6d5f6bac42d7f56f6e7834fb9` + +`"usage"` + + + +#### `"user"` + +SHA-256: `68f44f59e91c41395076cb77265981a601680ec8a381bbbeb6ab754ffdc94573` + +`"user"` + + + +#### `"user/message"` + +SHA-256: `de25352d2dc4196309bd84b5bac6319f6d5c898ea0e82bb5ae66c5738d0d426f` + +`"user/message"` + + + +#### `"web_search"` + +SHA-256: `935c8d486292b13c87b57ca280eb8c58b5b2f5239be86fcd4334c33fdeb87682` + +`"web_search"` + + + +#### `"web_search_20250305"` + +SHA-256: `0116b1f89c05221d56b0ba35c83d302bf4857bc7277d247e9bbaf74b27d2c66e` + +`"web_search_20250305"` + + + +#### `"web/deepseek-search-llm-request"` + +SHA-256: `6f611bed14b2106542480c4a230b4a83baf76dc0d8ac0cd13319a7cb8dae7675` + +`"web/deepseek-search-llm-request"` + + + +#### `"webhook"` + +SHA-256: `db6c5246911d47a7969f6b4cb47c7d0dbbde75c402710b22ace3672fa97bebe0` + +`"webhook"` + + + +#### `"workspace-write"` + +SHA-256: `a3edd1efd1fef21b72c55e213c8a8b24196b091abde2b89db52be0b2aaae3cfa` + +`"workspace-write"` + +
+ + + + +## 验证与限制 + +`pnpm run verify-persistence-catalog` 通过后,`pnpm run verify-persistence-formats --archive 3` 从当前 V3 目录创建了 schema。归档保留每个根及其可达的声明类型、根摘要与不透明声明,并移除源码行号。更早的格式记录保持不变。 + +目录记录声明字段与可选性,并不覆盖每项 codec 或恢复不变量。外部插件载荷、物理范围编码与运行时关系需要各自的验证器;schema 完整性本身不能确立迁移安全性。 + +```sh +pnpm run verify-persistence-formats +``` + +该检查仅使用本工作树验证直到当前写入器的每个格式、schema 完整性、双语声明与生成表格。它不会回放历史应用。维护规则参见[格式索引](README.zh.md),当前声明参见[当前目录](../../persistence-catalog.zh.md)。 + + +## 开发备注 + +无。 diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json index a3f1565668..6535d07366 100644 --- a/docs/persistence-schema.json +++ b/docs/persistence-schema.json @@ -4,7 +4,7 @@ { "key": "SessionHeader", "kind": "header", - "digest": "2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03", + "digest": "1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445", "schema": { "root": 0, "nodes": [ @@ -77,7 +77,7 @@ }, { "kind": "literal", - "value": 3 + "value": 4 } ] } @@ -17631,20 +17631,6 @@ "packages/llm/llm/src/types.ts:78" ] }, - { - "digest": "137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e", - "schema": { - "root": 0, - "nodes": [ - { - "kind": "literal", - "value": 3 - } - ] - }, - "names": [], - "sources": [] - }, { "digest": "13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176", "schema": { @@ -18228,6 +18214,91 @@ "names": [], "sources": [] }, + { + "digest": "1a3440e3577382704d42a6263aa463504eb74c566734a55e9503a63efcd02445", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "object", + "properties": [ + { + "name": "agentPreset", + "type": 1, + "optional": true + }, + { + "name": "createdAt", + "type": 2, + "optional": false + }, + { + "name": "cwd", + "type": 1, + "optional": true + }, + { + "name": "delegationDepth", + "type": 2, + "optional": true + }, + { + "name": "id", + "type": 1, + "optional": false + }, + { + "name": "isSeeded", + "type": 3, + "optional": false + }, + { + "name": "origin", + "type": 4, + "optional": true + }, + { + "name": "parentSession", + "type": 1, + "optional": true + }, + { + "name": "version", + "type": 5, + "optional": false + } + ], + "indices": [] + }, + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "primitive", + "type": "number" + }, + { + "kind": "primitive", + "type": "boolean" + }, + { + "kind": "literal", + "value": "subagent" + }, + { + "kind": "literal", + "value": 4 + } + ] + }, + "names": [ + "packages/core/session/src/types.ts#SessionHeader" + ], + "sources": [ + "packages/core/session/src/types.ts:93" + ] + }, { "digest": "1ab2ef1296f157ba96998f179bb5daa9d21a82480da2901127aeab2730797c92", "schema": { @@ -23340,91 +23411,6 @@ ], "sources": [] }, - { - "digest": "2a8b114637e66faab5fae1c6e2fba65320db6224c80f5f36c5bf32f937154d03", - "schema": { - "root": 0, - "nodes": [ - { - "kind": "object", - "properties": [ - { - "name": "agentPreset", - "type": 1, - "optional": true - }, - { - "name": "createdAt", - "type": 2, - "optional": false - }, - { - "name": "cwd", - "type": 1, - "optional": true - }, - { - "name": "delegationDepth", - "type": 2, - "optional": true - }, - { - "name": "id", - "type": 1, - "optional": false - }, - { - "name": "isSeeded", - "type": 3, - "optional": false - }, - { - "name": "origin", - "type": 4, - "optional": true - }, - { - "name": "parentSession", - "type": 1, - "optional": true - }, - { - "name": "version", - "type": 5, - "optional": false - } - ], - "indices": [] - }, - { - "kind": "primitive", - "type": "string" - }, - { - "kind": "primitive", - "type": "number" - }, - { - "kind": "primitive", - "type": "boolean" - }, - { - "kind": "literal", - "value": "subagent" - }, - { - "kind": "literal", - "value": 3 - } - ] - }, - "names": [ - "packages/core/session/src/types.ts#SessionHeader" - ], - "sources": [ - "packages/core/session/src/types.ts:93" - ] - }, { "digest": "2ab12a0e345658f9342816d773fe610f049982bcad82631f43b9205abe43e5ee", "schema": { @@ -49188,6 +49174,20 @@ "names": [], "sources": [] }, + { + "digest": "af6e173f7be819bcd0a5c8d77918649c10ce761d8a184ff472f2e01ce64eb2e0", + "schema": { + "root": 0, + "nodes": [ + { + "kind": "literal", + "value": 4 + } + ] + }, + "names": [], + "sources": [] + }, { "digest": "aff60ef947c18b012644852bdd0d5bfe72065e061dd563787c76c646b4a10f6b", "schema": { diff --git a/packages/core/session/README.i18n.yaml b/packages/core/session/README.i18n.yaml index 583c52a88c..122a740004 100644 --- a/packages/core/session/README.i18n.yaml +++ b/packages/core/session/README.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 packages/core/session/README.md -README.md: 8d07292287d7300b562751ad74de77397bd5b5db -README.zh.md: 28b6f1f02838420861a76409046c0e9a12bac1b5 +README.md: 3e120780c711a3e35088291ea33b883c9a3653c6 +README.zh.md: 6dbb593e04a9e153693bf32533747a163c71d7cf diff --git a/packages/core/session/README.md b/packages/core/session/README.md index 8d07292287..3e120780c7 100644 --- a/packages/core/session/README.md +++ b/packages/core/session/README.md @@ -183,7 +183,7 @@ Logging causes no invalidation, and exact reconstruction preserves request-prefi These limits define when the session store needs special care. They are current package constraints, not a task backlog. - **`fork()` cuts only at stable boundaries of live sessions** — the selected prefix must end outside an open turn and the source must be in the store; forking a persisted-but-unloaded session is excluded from the fork API. -- **`SESSION_FORMAT_VERSION` names the [current logical representation](../../../docs/session-format-status.md)** — the current reader rejects retired `header.system` and validates `system/message` payloads and protected-head rewrites. Historical headers and events belong to adjacent format packages; the adjacent migration chain converts supported history before constructing `Session`, and the write-open path publishes only the current-format successor. Equal-version unknown events require the envelope's explicit `ignorable` marker, which does not promise safe structural migration ([mechanism](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md)). +- **`SESSION_FORMAT_VERSION` names the [current logical representation](../../../docs/session-format-status.md)** — the current reader rejects retired `header.system` and validates `system/message` payloads and protected-head rewrites. Historical headers and events belong to adjacent format packages; the [adjacent migration chain](../../session/session-format-catalog/README.md) converts supported history before constructing `Session`, and the write-open path publishes only the current-format successor. Equal-version unknown events require the envelope's explicit `ignorable` marker, which does not promise safe structural migration ([mechanism](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md)). - **`TurnEndReasonMap` omits the ACP-named `refusal` / `max_turn_requests` variants** — producer-gated: they land when an adapter or the loop first emits them. - **No session tree beyond fork** — a pi-style entry tree over branched sessions is deferred unless a consumer needs more than boundary-based forking. diff --git a/packages/core/session/README.zh.md b/packages/core/session/README.zh.md index 28b6f1f028..6dbb593e04 100644 --- a/packages/core/session/README.zh.md +++ b/packages/core/session/README.zh.md @@ -183,7 +183,7 @@ session.deriveMessages() // the derived model history 这些限制说明会话存储何时需要特别留意。它们是当前包约束,不是任务积压。 - **`fork()` 仅在实时会话的稳定边界处切分**:所选前缀结束时不得有开放轮次,且源会话必须位于存储中;fork API 不支持对已持久化但未加载的会话进行 fork。 -- **`SESSION_FORMAT_VERSION` 命名[当前逻辑表示](../../../docs/session-format-status.zh.md)**——当前读取器拒绝已退役的 `header.system`,并校验 `system/message` 载荷与受保护头节点的重写。历史 header 与事件归相邻格式包所有;相邻迁移链在构造 `Session` 前转换受支持的历史,写打开只发布当前格式的后继代际。同版本未知事件要求信封显式带有 `ignorable` 标记,但这不保证结构迁移的安全性([机制](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md))。 +- **`SESSION_FORMAT_VERSION` 命名[当前逻辑表示](../../../docs/session-format-status.zh.md)**——当前读取器拒绝已退役的 `header.system`,并校验 `system/message` 载荷与受保护头节点的重写。历史 header 与事件归相邻格式包所有;[相邻迁移链](../../session/session-format-catalog/README.zh.md)在构造 `Session` 前转换受支持的历史,写打开只发布当前格式的后继代际。同版本未知事件要求信封显式带有 `ignorable` 标记,但这不保证结构迁移的安全性([机制](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md))。 - **`TurnEndReasonMap` 不含 ACP(Agent Client Protocol)命名的 `refusal`/`max_turn_requests` 变体**:受生产方约束;只有当适配器或循环首次产生这些变体时才加入。 - **fork 之外没有会话树**:基于分支会话的 pi 风格条目树被推迟,除非消费方需要超越基于边界的 forking 的能力。 diff --git a/packages/core/session/src/types.ts b/packages/core/session/src/types.ts index 0b946bd17a..09e6016a95 100644 --- a/packages/core/session/src/types.ts +++ b/packages/core/session/src/types.ts @@ -85,7 +85,7 @@ export type OptionalSessionSeq = SessionSeq | null * immutable prior-generation, and current fast-path rules are recorded in * `.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md`. */ -export const SESSION_FORMAT_VERSION = 3 +export const SESSION_FORMAT_VERSION = 4 /** * Immutable validated storage metadata, kept outside the conversation event log. diff --git a/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts b/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts index 9ea467ea14..91e0880e2d 100644 --- a/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts +++ b/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts @@ -2,6 +2,7 @@ import { readFileSync, readdirSync } from 'node:fs' import { join, relative } from 'node:path' import { describe, expect, it } from 'vitest' import { SESSION_FORMAT_VERSION, Session, SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' +import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' import { generationLogFilename, scanLog, @@ -37,6 +38,14 @@ function readSession(id: string): ReturnType { return scanLog(Buffer.from(generated)) } +function restoreSession(content: string, version: number) { + const [header, ...events] = content.trimEnd().split('\n').map(line => JSON.parse(line) as unknown) + expect(header).toMatchObject({ type: 'session', version }) + const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + for (const event of events) restore.decodeRow(event) + return restore.finish() +} + function textOf(event: SessionEvent): string { if (event.type === 'user/message') { return event.data.content.flatMap(block => block.type === 'text' ? [block.text] : []).join('\n') @@ -48,17 +57,27 @@ function textOf(event: SessionEvent): string { } describe('WebWorker preview VFS example', () => { - it('matches its deterministic source byte for byte', () => { + it('retains V3 inputs that strictly restore to the deterministic current output', () => { const expected = buildVfsExampleFiles() + const currentName = generationLogFilename(SESSION_FORMAT_VERSION, 'none') + const committedPath = (path: string): string => path.endsWith(`/${currentName}`) + ? `${path.slice(0, -currentName.length)}session.v3.jsonl` + : path const predecessors = Object.values(VFS_EXAMPLE_SESSION_IDS) .map(id => `home/sessions/--dsh-workspace--/${id}/session.v2.jsonl`) - expect(filesUnder(VFS_EXAMPLE_ROOT)).toEqual([...expected.keys(), ...predecessors].sort()) + expect(filesUnder(VFS_EXAMPLE_ROOT)).toEqual([...expected.keys()].map(committedPath).concat(predecessors).sort()) for (const [path, content] of expected) { - expect(readFileSync(join(VFS_EXAMPLE_ROOT, path), 'utf8'), path).toBe(content) + if (path === 'home/storages/session_projcache.json') continue + const committed = readFileSync(join(VFS_EXAMPLE_ROOT, committedPath(path)), 'utf8') + if (path.endsWith(`/${currentName}`)) { + expect(restoreSession(committed, 3), path).toEqual(restoreSession(content, SESSION_FORMAT_VERSION)) + } else { + expect(committed, path).toBe(content) + } } }) - it('keeps the committed cache on the current generated projection', () => { + it('retains V3 cache identity while the generated cache uses the current writer', () => { const committed = JSON.parse(readFileSync( join(VFS_EXAMPLE_ROOT, 'home/storages/session_projcache.json'), 'utf8', @@ -80,9 +99,12 @@ describe('WebWorker preview VFS example', () => { const generatedText = buildVfsExampleFiles().get('home/storages/session_projcache.json') if (generatedText === undefined) throw new Error('missing generated VFS example projection cache') const generated = JSON.parse(generatedText) as typeof committed - expect(committed).toEqual(generated) - expect(committed.tables.sessions[VFS_EXAMPLE_SESSION_IDS.main]?.identity.formatVersion) - .toBe(SESSION_FORMAT_VERSION) + const expectedCurrent = structuredClone(committed) + for (const session of Object.values(expectedCurrent.tables.sessions)) { + expect(session.identity.formatVersion).toBe(3) + session.identity.formatVersion = SESSION_FORMAT_VERSION + } + expect(generated).toEqual(expectedCurrent) expect(generated.unit).toEqual({ name: projectionCacheDomainSpec.name, version: projectionCacheDomainSpec.version, diff --git a/packages/session/README.i18n.yaml b/packages/session/README.i18n.yaml index d7a451cf3c..a8c4662bfd 100644 --- a/packages/session/README.i18n.yaml +++ b/packages/session/README.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 packages/session/README.md -README.md: 86d3c2ce9467fda0cdc6cc2ee255be75960e7a45 -README.zh.md: f7b0ea006e2cba24e727bd6f2860583778a9d6ab +README.md: 989a98f4b89ebf9ef66a05499e003bd13b6532ee +README.zh.md: 4f9a553188b6f49e0bafc6222581e147d8132a2d diff --git a/packages/session/README.md b/packages/session/README.md index 86d3c2ce94..989a98f4b8 100644 --- a/packages/session/README.md +++ b/packages/session/README.md @@ -31,6 +31,8 @@ The group splits into four families: durable storage (persistence seam, backends | [`session-format/`](session-format/README.md) | Pure adjacent-format chain and artifact validation library | library — no ctx key | | [`session-format-v0-to-v1/`](session-format-v0-to-v1/README.md) | Frozen released-v0 decoder and identity migration into released v1 | library — no ctx key | | [`session-format-v1-to-v2/`](session-format-v1-to-v2/README.md) | Frozen released-v1 decoder and cardinality-changing Assistant-stream migration into released v2 | library — no ctx key | +| [`session-format-v2-to-v3/`](session-format-v2-to-v3/README.md) | Frozen V2 decoder and system-prompt, envelope, and PTC migration into V3 | library — no ctx key | +| [`session-format-v3-to-v4/`](session-format-v3-to-v4/README.md) | V3 identity migration and V4 codec with generation-aware delivery validation | library — no ctx key | | [`session-format-catalog/`](session-format-catalog/README.md) | Generated static catalog of shipped adjacent migrations | library — no ctx key | | [`session-persistence/`](session-persistence/README.md) | Defines the durable session-storage service and the shared write coordination every backend composes | `ctx.sessionPersistence` | | [`session-persistence-jsonl/`](session-persistence-jsonl/README.md) | Shipped backend: immutable canonical generation filenames per Session with exclusive successor publication, optionally Zstandard-compressed | registers on `ctx.sessionPersistence` | diff --git a/packages/session/README.zh.md b/packages/session/README.zh.md index f7b0ea006e..4f9a553188 100644 --- a/packages/session/README.zh.md +++ b/packages/session/README.zh.md @@ -31,6 +31,8 @@ session 组让对话持久保存,恢复已发布的日志格式,并使已提 | [`session-format/`](session-format/README.zh.md) | 纯相邻格式链与产物校验库 | 库,不使用 ctx key | | [`session-format-v0-to-v1/`](session-format-v0-to-v1/README.zh.md) | 冻结的 released-v0 解码器,以及到 released v1 的恒等迁移 | 库,不使用 ctx key | | [`session-format-v1-to-v2/`](session-format-v1-to-v2/README.zh.md) | 冻结的 released-v1 解码器,以及迁移到 released v2 时会改变基数的 Assistant 流迁移 | 库,不使用 ctx key | +| [`session-format-v2-to-v3/`](session-format-v2-to-v3/README.zh.md) | 冻结的 V2 解码器,以及迁入 V3 的系统提示词、信封与 PTC 转换 | 库——无 ctx 键 | +| [`session-format-v3-to-v4/`](session-format-v3-to-v4/README.zh.md) | V3 恒等迁移与 V4 编解码器,按 generation 校验 delivery | 库——无 ctx 键 | | [`session-format-catalog/`](session-format-catalog/README.zh.md) | 自动生成的已交付相邻迁移静态目录 | 库,不使用 ctx key | | [`session-persistence/`](session-persistence/README.zh.md) | 定义持久会话存储服务,以及每个后端组合的共享写入协调机制 | `ctx.sessionPersistence` | | [`session-persistence-jsonl/`](session-persistence-jsonl/README.zh.md) | 随产品交付的后端:逐 Session 使用不可变规范 generation 文件名并排他发布后继;可选 Zstandard 压缩 | 注册到 `ctx.sessionPersistence` | diff --git a/packages/session/session-format-catalog/README.i18n.yaml b/packages/session/session-format-catalog/README.i18n.yaml index 523dc45f64..c48bbbc3b9 100644 --- a/packages/session/session-format-catalog/README.i18n.yaml +++ b/packages/session/session-format-catalog/README.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 packages/session/session-format-catalog/README.md -README.md: 8232a28b2c2c31c0176adb62e07ed16a804791e8 -README.zh.md: 2c4c86da50640f672842d98e6cc254dca08a3470 +README.md: 5ebfa82486873810f64d2f7bd3f83957bd995ed9 +README.zh.md: 6e8d674b0dfd2e69c2ff2d0857afd04ab91734b5 diff --git a/packages/session/session-format-catalog/README.md b/packages/session/session-format-catalog/README.md index 8232a28b2c..5ebfa82486 100644 --- a/packages/session/session-format-catalog/README.md +++ b/packages/session/session-format-catalog/README.md @@ -67,6 +67,7 @@ The catalog contains all supported historical readers directly. A profile cannot - [Released v0 to v1 edge](../session-format-v0-to-v1/README.md) — codec and validator ownership. - [Released v1 to v2 edge](../session-format-v1-to-v2/README.md) — Assistant stream embedding and cardinality-changing reference remapping. - [Released V2 to V3 specification](../session-format-v2-to-v3/README.md#v2-to-v3-specification) — transformations, preservation, and refusal. +- [V3 to V4 specification](../session-format-v3-to-v4/README.md#v3-to-v4-specification) — identity conversion and delivery-generation validation. - [JSONL persistence](../session-persistence-jsonl/README.md) — immutable generation naming and exclusive publication. ----- diff --git a/packages/session/session-format-catalog/README.zh.md b/packages/session/session-format-catalog/README.zh.md index 2c4c86da50..6e8d674b0d 100644 --- a/packages/session/session-format-catalog/README.zh.md +++ b/packages/session/session-format-catalog/README.zh.md @@ -67,6 +67,7 @@ Production 历史读取使用 `{ recovery: 'recoverable', validation: 'transform - [已发布 v0 到 v1 迁移边](../session-format-v0-to-v1/README.zh.md)——编解码器与校验器所有权。 - [已发布 v1 到 v2 迁移边](../session-format-v1-to-v2/README.zh.md)——Assistant 流嵌入与基数变化引用重映射。 - [已发布 V2 到 V3 规范](../session-format-v2-to-v3/README.zh.md#v2-to-v3-specification)——转换、保留与拒绝。 +- [V3 到 V4 规范](../session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)——恒等转换与 delivery generation 校验。 - [JSONL 持久化](../session-persistence-jsonl/README.zh.md)——不可变 generation 命名与排他发布。 ----- diff --git a/packages/session/session-format-catalog/package.json b/packages/session/session-format-catalog/package.json index 05574cd6b5..388c41e8b6 100644 --- a/packages/session/session-format-catalog/package.json +++ b/packages/session/session-format-catalog/package.json @@ -36,6 +36,7 @@ "@deepseek-ai/dsh-session-format-v0-to-v1": "workspace:^", "@deepseek-ai/dsh-session-format-v1-to-v2": "workspace:^", "@deepseek-ai/dsh-session-format-v2-to-v3": "workspace:^", + "@deepseek-ai/dsh-session-format-v3-to-v4": "workspace:^", "@deepseek-ai/dsh-compaction-image-offload": "workspace:^" }, "peerDependencies": { diff --git a/packages/session/session-format-catalog/src/generated.ts b/packages/session/session-format-catalog/src/generated.ts index f726d954d9..2296efe207 100644 --- a/packages/session/session-format-catalog/src/generated.ts +++ b/packages/session/session-format-catalog/src/generated.ts @@ -8,24 +8,36 @@ import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format' import { validateInstalledCurrentSessionArtifact, validateInstalledCurrentSessionHeader } from './current.ts' import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, sessionFormatV0ToV1 } from '@deepseek-ai/dsh-session-format-v0-to-v1' import { releasedV2SessionFormatCodec, sessionFormatV1ToV2 } from '@deepseek-ai/dsh-session-format-v1-to-v2' -import { assertReleasedV3Header, releasedV3SessionFormatCodec, restoreReleasedV3Artifact, sessionFormatV2ToV3 } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { releasedV3SessionFormatCodec, sessionFormatV2ToV3 } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { assertReleasedV4Header, releasedV4SessionFormatCodec, restoreReleasedV4Artifact, sessionFormatV3ToV4 } from '@deepseek-ai/dsh-session-format-v3-to-v4' /** Physical codec dispatch and complete adjacent chain, independent of mounted plugins. */ export const sessionFormatCatalog = createSessionFormatCatalog({ - currentVersion: 3, - codecs: [releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, releasedV2SessionFormatCodec, releasedV3SessionFormatCodec], - currentEncoder: releasedV3SessionFormatCodec, - migrations: [sessionFormatV0ToV1, sessionFormatV1ToV2, sessionFormatV2ToV3], + currentVersion: 4, + codecs: [ + releasedV0SessionFormatCodec, + releasedV1SessionFormatCodec, + releasedV2SessionFormatCodec, + releasedV3SessionFormatCodec, + releasedV4SessionFormatCodec, + ], + currentEncoder: releasedV4SessionFormatCodec, + migrations: [ + sessionFormatV0ToV1, + sessionFormatV1ToV2, + sessionFormatV2ToV3, + sessionFormatV3ToV4, + ], restoreCurrent(artifact) { - const restored = restoreReleasedV3Artifact(artifact, KNOWN_SESSION_EVENT_TYPES) + const restored = restoreReleasedV4Artifact(artifact, KNOWN_SESSION_EVENT_TYPES) validateInstalledCurrentSessionArtifact(restored) return restored }, restoreTransformedCurrent(artifact) { - return restoreReleasedV3Artifact(artifact, KNOWN_SESSION_EVENT_TYPES) + return restoreReleasedV4Artifact(artifact, KNOWN_SESSION_EVENT_TYPES) }, restoreCurrentHeader(header) { - assertReleasedV3Header(header) + assertReleasedV4Header(header) validateInstalledCurrentSessionHeader(header) return header }, diff --git a/packages/session/session-format-catalog/tests/catalog.spec.ts b/packages/session/session-format-catalog/tests/catalog.spec.ts index 335f406e89..6ada05de30 100644 --- a/packages/session/session-format-catalog/tests/catalog.spec.ts +++ b/packages/session/session-format-catalog/tests/catalog.spec.ts @@ -4,7 +4,7 @@ import { sessionFormatCatalog } from '../src/index.ts' import { currentSessionMessageProjections } from '../src/message-projections.ts' import { MESSAGE_PROJECTION_EVENT_TYPES } from '@deepseek-ai/dsh-session/src/known-event-types.ts' import { validateInstalledCurrentSessionArtifact } from '../src/current.ts' -import { Session, SessionId } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, Session, SessionId } from '@deepseek-ai/dsh-session' import { createUserMessage } from '@deepseek-ai/dsh-llm' function deepFreeze(value: T): T { @@ -27,7 +27,7 @@ describe('first-party Session format catalog', () => { } expect(() => { validateInstalledCurrentSessionArtifact(artifact) }).toThrow(/image index 0 does not exist/) }) - it('statically owns the complete adjacent v0 to v3 chain', () => { + it('statically owns every adjacent edge through the current writer', () => { const header = { type: 'session', version: 0, @@ -37,13 +37,13 @@ describe('first-party Session format catalog', () => { delegationDepth: 0, } - expect(sessionFormatCatalog.currentVersion).toBe(3) + expect(sessionFormatCatalog.currentVersion).toBe(SESSION_FORMAT_VERSION) expect(sessionFormatCatalog.readHeader(header)).toEqual({ status: 'migration-required', storedVersion: 0, - targetVersion: 3, + targetVersion: SESSION_FORMAT_VERSION, header: { - version: 3, + version: SESSION_FORMAT_VERSION, id: 'catalog', createdAt: 1, isSeeded: true, @@ -57,13 +57,13 @@ describe('first-party Session format catalog', () => { }) restore.decodeRow({ type: 'turn/start', seq: 0, time: 2, data: { turn: 1 } }) expect(restore.finish()).toMatchObject({ - header: { version: 3, id: 'catalog' }, + header: { version: SESSION_FORMAT_VERSION, id: 'catalog' }, }) }) it('restores the installed current vocabulary without freezing ordinary payload additions', () => { const header = { - type: 'session', version: 3, id: 'current-growth', createdAt: 1, isSeeded: false, delegationDepth: 0, + type: 'session', version: SESSION_FORMAT_VERSION, id: 'current-growth', createdAt: 1, isSeeded: false, delegationDepth: 0, } const restore = (rows: readonly unknown[]) => { const current = sessionFormatCatalog.createRestore(header, { @@ -102,7 +102,7 @@ describe('first-party Session format catalog', () => { restore.decodeRow({ type: 'feedback/record', seq: 0, time: 1, data: { text: 'inherited' } }) } const artifact = restore.finish() - expect(artifact.header.version).toBe(3) + expect(artifact.header.version).toBe(SESSION_FORMAT_VERSION) expect(artifact.inheritedEventCount).toBe(seedLength) expect(artifact.events.at(-1)).toEqual({ type: 'session/end-seed', seq: seedLength, time: 1, data: { inherited: true }, @@ -123,7 +123,7 @@ describe('first-party Session format catalog', () => { const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) for (const row of rows) restore.decodeRow(row) expect(restore.finish()).toEqual({ - header: { version: 3, id: 'v2-identity', createdAt: 1, isSeeded, delegationDepth: 0 }, + header: { version: SESSION_FORMAT_VERSION, id: 'v2-identity', createdAt: 1, isSeeded, delegationDepth: 0 }, inheritedEventCount: isSeeded ? 4 : 0, events: [ { type: 'turn/start', seq: 0, time: 1, data: { turn: 1 } }, @@ -200,7 +200,7 @@ describe('first-party Session format catalog', () => { { ...rows[8], seq: 9 }, { ...rows[9], seq: 10 }, ] expect(artifact).toEqual({ - header: { version: 3, id: sourceHeader.id, createdAt: 1, isSeeded: false, delegationDepth: 0 }, + header: { version: SESSION_FORMAT_VERSION, id: sourceHeader.id, createdAt: 1, isSeeded: false, delegationDepth: 0 }, inheritedEventCount: 0, events: expected, }) const currentHeader = deepFreeze(sessionFormatCatalog.encodeCurrentHeader(artifact.header, artifact.inheritedEventCount)) @@ -213,7 +213,7 @@ describe('first-party Session format catalog', () => { expect(JSON.stringify({ currentHeader, currentRows })).toBe(encodedBefore) }) - it.each(['current', 'transformed'] as const)('rejects native v3 obsolete required tags with %s validation and retains ignorable tags', (validation) => { + it.each(['current', 'transformed'] as const)('rejects obsolete required tags in V3 input with %s validation and retains ignorable tags', (validation) => { const header = deepFreeze({ type: 'session', version: 3, id: 'native-ptc', createdAt: 1, isSeeded: false, delegationDepth: 0 }) for (const type of ['tool/code-dispatch-start', 'tool/code-dispatch']) { const required = deepFreeze({ type, seq: 0, time: 1, data: null }) diff --git a/packages/session/session-format-catalog/tests/current.spec.ts b/packages/session/session-format-catalog/tests/current.spec.ts index 283f2a1029..ea1180a3be 100644 --- a/packages/session/session-format-catalog/tests/current.spec.ts +++ b/packages/session/session-format-catalog/tests/current.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest' +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import type { SessionFormatArtifact, SessionFormatHeader } from '@deepseek-ai/dsh-session-format' import { validateInstalledCurrentSessionArtifact, @@ -6,7 +7,7 @@ import { } from '../src/current.ts' const currentHeader: SessionFormatHeader = { - version: 3, + version: SESSION_FORMAT_VERSION, id: 'installed-current', createdAt: 1, isSeeded: false, @@ -16,14 +17,14 @@ const currentHeader: SessionFormatHeader = { describe('installed current Session restoration', () => { it('rejects version skew before entering current Session validation', () => { expect(() => { validateInstalledCurrentSessionHeader({ ...currentHeader, version: 0 }) }) - .toThrow(/installed Session format is v3, got v0/) + .toThrow(`installed Session format is v${SESSION_FORMAT_VERSION}, got v0`) const artifact: SessionFormatArtifact = { header: { ...currentHeader, version: 0 }, inheritedEventCount: 0, events: [], } expect(() => { validateInstalledCurrentSessionArtifact(artifact) }) - .toThrow(/installed Session format is v3, got v0/) + .toThrow(`installed Session format is v${SESSION_FORMAT_VERSION}, got v0`) }) it('accepts only current request-header reasons and the true starts-series marker', () => { diff --git a/packages/session/session-format-catalog/tests/preset-migration.spec.ts b/packages/session/session-format-catalog/tests/preset-migration.spec.ts index 74896f7837..a7f6b19c67 100644 --- a/packages/session/session-format-catalog/tests/preset-migration.spec.ts +++ b/packages/session/session-format-catalog/tests/preset-migration.spec.ts @@ -1,6 +1,7 @@ /** Every historical entry generation migrates all preset selections before projection or fork. */ import { describe, expect, it } from 'vitest' +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import { sessionFormatCatalog } from '../src/index.ts' describe('catalog preset migration', () => { @@ -21,7 +22,7 @@ describe('catalog preset migration', () => { const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) for (const row of source) restore.decodeRow(row) const artifact = restore.finish() - expect(artifact.header).toMatchObject({ version: 3, id: 'code', agentPreset: 'ptc', isSeeded: true }) + expect(artifact.header).toMatchObject({ version: SESSION_FORMAT_VERSION, id: 'code', agentPreset: 'ptc', isSeeded: true }) expect(artifact.inheritedEventCount).toBe(2) expect(artifact.events.map(event => event.seq)).toEqual([0, 1, 2, 3, 4, 5]) expect(artifact.events.filter(event => event.type === 'agent-preset/selected').map(event => event.data)) @@ -30,7 +31,7 @@ describe('catalog preset migration', () => { expect(JSON.stringify({ header, source })).toBe(before) }) - it('does not reinterpret a native v3 custom preset named code', () => { + it('does not reinterpret a V3 custom preset named code', () => { const header = { type: 'session', version: 3, id: 'native', createdAt: 1, isSeeded: false, delegationDepth: 0, agentPreset: 'code', diff --git a/packages/session/session-format-catalog/tsconfig.json b/packages/session/session-format-catalog/tsconfig.json index 42a9cc2ff3..0dc8e0c9e9 100644 --- a/packages/session/session-format-catalog/tsconfig.json +++ b/packages/session/session-format-catalog/tsconfig.json @@ -29,6 +29,9 @@ { "path": "../session-format-v2-to-v3" }, + { + "path": "../session-format-v3-to-v4" + }, { "path": "../../compaction/compaction-image-offload" } diff --git a/packages/session/session-format-v2-to-v3/tests/catalog.ts b/packages/session/session-format-v2-to-v3/tests/catalog.ts new file mode 100644 index 0000000000..7541a5d094 --- /dev/null +++ b/packages/session/session-format-v2-to-v3/tests/catalog.ts @@ -0,0 +1,21 @@ +/** Fixed V0–V3 composition for released-edge tests, independent of the current writer. */ + +import { KNOWN_SESSION_EVENT_TYPES } from '@deepseek-ai/dsh-session' +import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format' +import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, sessionFormatV0ToV1 } from '@deepseek-ai/dsh-session-format-v0-to-v1' +import { releasedV2SessionFormatCodec, sessionFormatV1ToV2 } from '@deepseek-ai/dsh-session-format-v1-to-v2' +import { assertReleasedV3Header, releasedV3SessionFormatCodec, restoreReleasedV3Artifact, sessionFormatV2ToV3 } from '../src/index.ts' + +/** Restore the released V3 result through its complete predecessor chain. */ +export const v3Catalog = createSessionFormatCatalog({ + currentVersion: 3, + codecs: [releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, releasedV2SessionFormatCodec, releasedV3SessionFormatCodec], + currentEncoder: releasedV3SessionFormatCodec, + migrations: [sessionFormatV0ToV1, sessionFormatV1ToV2, sessionFormatV2ToV3], + restoreCurrent: artifact => restoreReleasedV3Artifact(artifact, KNOWN_SESSION_EVENT_TYPES), + restoreTransformedCurrent: artifact => restoreReleasedV3Artifact(artifact, KNOWN_SESSION_EVENT_TYPES), + restoreCurrentHeader(header) { + assertReleasedV3Header(header) + return header + }, +}) diff --git a/packages/session/session-format-v2-to-v3/tests/combined-migration.spec.ts b/packages/session/session-format-v2-to-v3/tests/combined-migration.spec.ts index 42fc9965cf..fbb8db6e84 100644 --- a/packages/session/session-format-v2-to-v3/tests/combined-migration.spec.ts +++ b/packages/session/session-format-v2-to-v3/tests/combined-migration.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { v3Catalog as sessionFormatCatalog } from './catalog.ts' import { SessionFormatEventCollector, SessionFormatUnsupportedMigrationError } from '@deepseek-ai/dsh-session-format' import type { SessionFormatEvent, SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' import { releasedV3SessionFormatCodec, restoreReleasedV3Artifact } from '../src/index.ts' diff --git a/packages/session/session-format-v2-to-v3/tests/content-admission.spec.ts b/packages/session/session-format-v2-to-v3/tests/content-admission.spec.ts index d448b449d1..ac6a67a213 100644 --- a/packages/session/session-format-v2-to-v3/tests/content-admission.spec.ts +++ b/packages/session/session-format-v2-to-v3/tests/content-admission.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { SessionFormatEventCollector } from '@deepseek-ai/dsh-session-format' import type { SessionFormatEvent, SessionFormatJsonObject, SessionFormatJsonValue } from '@deepseek-ai/dsh-session-format' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { v3Catalog as sessionFormatCatalog } from './catalog.ts' import { restoreReleasedV3Artifact, sessionFormatV2ToV3 } from '../src/index.ts' const header = { version: 2, id: 'content-admission', createdAt: 1, isSeeded: false, delegationDepth: 0 } diff --git a/packages/session/session-format-v3-to-v4/README.i18n.yaml b/packages/session/session-format-v3-to-v4/README.i18n.yaml new file mode 100644 index 0000000000..0d1d297559 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 packages/session/session-format-v3-to-v4/README.md +README.md: 97befb074bd6b756905368a88b621e4871d1ed0f +README.zh.md: 169ba020026d63e5d79bd2ac362968fff08cccfa diff --git a/packages/session/session-format-v3-to-v4/README.md b/packages/session/session-format-v3-to-v4/README.md new file mode 100644 index 0000000000..97befb074b --- /dev/null +++ b/packages/session/session-format-v3-to-v4/README.md @@ -0,0 +1,111 @@ +--- +description: "Restore V3 Sessions as V4 while preserving events, inherited cuts, and recorded delivery generations." +kind: "package-library" +--- + +# @deepseek-ai/dsh-session-format-v3-to-v4 + +English | [中文](README.zh.md) + +## Summary + +Restore supported V3 Sessions as V4 without changing their events or historical requests. The library advances the header version, retains event coordinates and inherited cuts, and prevents historical delivery markers from becoming active V4 watermarks. Persistence consumes it through the static catalog; the library does not read or publish files. + +## Table of Contents + +- [Use this package](#use-this-package) +- [V3-to-V4 specification](#v3-to-v4-specification) +- [Understand the implementation](#understand-the-implementation) +- [Further Exploration](#further-exploration) +- [Model Experience](#model-experience) +- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work) +- [Dev Note](#dev-note) + +----- + + +## Use this package + +Use the [catalog](../session-format-catalog/README.md) for complete restoration. Direct imports serve catalog assembly and tests; this library has no Cordis mount configuration. Its [public exports](src/index.ts) provide the adjacent migration, the exact released V3 codec, the V4 codec, and target validators. + +The header-only operation advances validated metadata without reading the body: + +```text +const targetHeader = sessionFormatV3ToV4.migrateHeader(sourceHeader) +``` + +Complete restoration decodes rows, passes them through a fresh stage, and validates the target artifact. Partial stage emissions do not establish success: a later event or `finish()` can refuse the artifact. Strict catalog restoration uses `{ recovery: 'strict', validation: 'current' }`; the [format protocol](../session-format/README.md) owns scheduling and error handling. + +----- + + +## V3-to-V4 specification + +The logical header changes only `version: 3` to `version: 4`. Every admitted event retains its type, payload, timestamp, sequence, message identity, surface operation, and references. The stage emits the original event object. It adds, removes, and reorders no events. The released V3 codec remains owned by [V2-to-V3](../session-format-v2-to-v3/README.md); this package reuses it without changing earlier migration semantics. + +Source events must be dense from zero. A seeded Session's last `session/end-seed` carrying `inherited: true` determines its inherited event count, excluding the marker. A supplied source cut must agree. Missing seeded markers and inherited markers in unseeded Sessions are refused. Each stage owns its counters and cut; seeded stages leave the cut unknown before EOF, including when preceding migrations change event count. + +Complete restoration applies [native V3 admission](../session-format-v2-to-v3/README.md#native-v3-admission) to the unchanged representation: malformed canonical events and invalid relationships are refused; unknown required event types require installed vocabulary; unknown ignorable events retain their opaque values. This identity edge changes no coordinates or payload meaning, so retaining opaque data does not require interpreting it. The separate source-audit policies of earlier edges remain unchanged. + +A `session-log-deepseek/delivery-accepted` event must identify a nonnegative safe-integer generation; omission identifies V0. A source marker claiming V4 is refused because advancing the header would activate it. Source V3 markers require a nonempty Session id and a `throughSeq` that names an earlier event. A foreign V3 marker is permitted only inside the inherited prefix of a Session with `parentSession`. Other generations retain their recorded coordinates and ids. No delivery payload is rewritten. + +V4 restoration validates V4 delivery coordinates and ownership under the same rules. V3 deliveries are historical in V4 and do not become V4 watermarks. The V4 codec preserves V3 framing and pre-recovery structural refusal; complete vocabulary, delivery, and relationship checks require the target restorer or catalog `validation: 'current'`. Recoverable codec reads alone do not establish strict restoration. + +----- + + +## Understand the implementation + +
+Implementation internals — click to expand + +The migration declaration creates independent streaming stages. Compact runs expand as iterables without an intermediate event array. The V4 codec translates only the physical header version while delegating released V3 event framing and recovery. JSONL scanners call `assertV4RowAdmission` before suppressing recoverable rows. + +The target restorer uses a private V3 relationship view to distinguish V4 deliveries from historical V3 deliveries, then returns the original artifact. Its temporary generation substitutions never escape. No runtime invariant companion is published because this pure library owns no independently maintained runtime observations. + +
+ +----- + + +## Further Exploration + +- [Format version and release status](../../../docs/session-format-status.md) — checkout writer and published format authority. +- [Adding a Session format version](../../../docs/cookbook/adding-a-session-format-version.md) — adjacent-edge integration and validation. +- [JSONL persistence](../session-persistence-jsonl/README.md) — immutable generation selection and publication. + +----- + + +## Model Experience + +### Historical restoration + +#### What the model sees + +Historical requests retain their recorded messages and model configuration because the [identity stage](src/migration.ts) preserves `SessionFormatEvent.data`. This edge adds no model-visible content. + +#### Token effect + +The identity conversion changes no request text or token-bearing data. + +#### KV Cache effect + +The edge preserves the recorded request prefix. Provider cache availability and eviction remain outside this library. + +## Known Limitations and Deferred Work + + + +- **Existing V4 data skips this edge** — later edits to the unreleased migration do not transform an already-written V4 generation. Integration tests need fresh disposable homes populated from unchanged historical input. +- **No file publication** — the library returns validated logical events; persistence owns publishing a successor beside unchanged committed generations. + + +### Dev Note + +
+Working context for maintainers — click to expand + +None. + +
diff --git a/packages/session/session-format-v3-to-v4/README.zh.md b/packages/session/session-format-v3-to-v4/README.zh.md new file mode 100644 index 0000000000..169ba02002 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/README.zh.md @@ -0,0 +1,111 @@ +--- +description: "将 V3 Session 恢复为 V4,保留事件、继承切分点和已记录的投递代际。" +kind: "package-library" +--- + +# @deepseek-ai/dsh-session-format-v3-to-v4 + +[English](README.md) | 中文 + +## 概述 + +将受支持的 V3 Session 恢复为 V4,不改变其中的事件或历史请求。该库推进头部版本,保留事件坐标和继承切分点,并防止历史投递标记成为生效的 V4 水位。持久化通过静态目录使用本库;本库不读取或发布文件。 + +## 目录 + +- [使用本包](#use-this-package) +- [V3 到 V4 规范](#v3-to-v4-specification) +- [理解实现](#understand-the-implementation) +- [进一步探索](#further-exploration) +- [模型体验](#model-experience) +- [已知限制与待办工作](#known-limitations-and-deferred-work) +- [开发备注](#dev-note) + +----- + + +## 使用本包 + +完整恢复应使用[目录](../session-format-catalog/README.zh.md)。直接导入用于组装目录和测试;本库没有 Cordis 挂载配置。[公开导出](src/index.ts)提供相邻迁移、原样复用的已发布 V3 编解码器、V4 编解码器和目标校验器。 + +仅头部操作推进已校验的元数据,不读取正文: + +```text +const targetHeader = sessionFormatV3ToV4.migrateHeader(sourceHeader) +``` + +完整恢复解码行、通过新的 Stage 处理行,并校验目标产物。Stage 的部分输出不代表恢复成功:后续事件或 `finish()` 仍可能拒绝该产物。严格的目录恢复使用 `{ recovery: 'strict', validation: 'current' }`;[格式协议](../session-format/README.zh.md)负责调度和错误处理。 + +----- + + +## V3 到 V4 规范 + +逻辑头部只将 `version: 3` 改为 `version: 4`。每个获准事件都保留其类型、载荷、时间戳、序号、消息身份、surface 操作和引用。Stage 输出原始事件对象,不增删或重排事件。已发布 V3 编解码器仍由 [V2 到 V3](../session-format-v2-to-v3/README.zh.md)拥有;本包复用它,不改变较早迁移的语义。 + +源事件必须从零开始连续编号。带种子的 Session 中,最后一个携带 `inherited: true` 的 `session/end-seed` 决定继承事件数,不包含该标记本身。传入的源切分点必须与之相符。带种子却缺少标记,或不带种子却出现继承标记的 Session 均被拒绝。每个 Stage 独立拥有计数器和切分点;带种子的 Stage 在 EOF 前保持切分点未知,包括前序迁移改变事件数的情况。 + +完整恢复对未改变的表示应用[原生 V3 准入规则](../session-format-v2-to-v3/README.zh.md#native-v3-admission):拒绝格式错误的规范事件和无效关系;未知必需事件类型要求已安装的事件词表支持;未知可忽略事件保留其不透明值。该恒等迁移不改变坐标或载荷含义,因此保留不透明数据不需要解释其内容。较早迁移边各自的源审计策略保持不变。 + +`session-log-deepseek/delivery-accepted` 事件必须标识非负安全整数代际;省略时表示 V0。声称属于 V4 的源标记会被拒绝,因为推进头部会使它生效。源 V3 标记要求非空 Session id,以及指向较早事件的 `throughSeq`。属于其他 Session 的 V3 标记只允许出现在带有 `parentSession` 的 Session 的继承前缀中。其他代际保留记录的坐标和 id。任何投递载荷都不会被重写。 + +V4 恢复按相同规则校验 V4 投递坐标和归属。V3 投递在 V4 中属于历史数据,不会成为 V4 水位。V4 编解码器保留 V3 行格式和恢复前的结构性拒绝规则;完整的词表、投递和关系校验需要目标恢复器或目录的 `validation: 'current'`。仅执行可恢复编解码读取不能证明严格恢复成功。 + +----- + + +## 理解实现 + +
+实现内部机制 — 点击展开 + +迁移声明创建相互独立的流式 Stage。紧凑事件段通过迭代器展开,不生成中间事件数组。V4 编解码器只转换物理头部版本,将已发布 V3 事件行格式和恢复行为委托给原编解码器。JSONL 扫描器在抑制可恢复行之前调用 `assertV4RowAdmission`。 + +目标恢复器通过私有 V3 关系视图区分 V4 投递和历史 V3 投递,然后返回原始产物。临时的代际替换不会离开该视图。本包不发布运行时不变量伴随插件,因为这个纯函数库不拥有独立维护的运行时观测。 + +
+ +----- + + +## 进一步探索 + +- [格式版本与发布状态](../../../docs/session-format-status.zh.md) — 当前检出写入版本与已发布格式的权威记录。 +- [添加 Session 格式版本](../../../docs/cookbook/adding-a-session-format-version.zh.md) — 相邻迁移边的集成与校验。 +- [JSONL 持久化](../session-persistence-jsonl/README.zh.md) — 不可变代际选择与发布。 + +----- + + +## 模型体验 + +### 历史恢复 + +#### 模型看到什么 + +历史请求保留记录的消息与模型配置,因为[恒等迁移 Stage](src/migration.ts)保留 `SessionFormatEvent.data`。该迁移边不添加模型可见内容。 + +#### Token 影响 + +恒等转换不改变请求文本或承载 token 的数据。 + +#### KV Cache 影响 + +该迁移边保留记录的请求前缀。提供方缓存的可用性和淘汰策略不属于本库职责。 + +## 已知限制与待办工作 + + + +- **现有 V4 数据跳过此迁移边** — 对尚未发布迁移的后续修改不会转换已经写出的 V4 代际。集成测试需要使用新的临时 home,并从未改变的历史输入初始化。 +- **不发布文件** — 本库返回已校验的逻辑事件;持久化负责在不改变已提交代际的前提下发布后继文件。 + + +### 开发备注 + +
+维护者工作上下文 — 点击展开 + +无。 + +
diff --git a/packages/session/session-format-v3-to-v4/package.json b/packages/session/session-format-v3-to-v4/package.json new file mode 100644 index 0000000000..f1d2d49179 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/package.json @@ -0,0 +1,51 @@ +{ + "name": "@deepseek-ai/dsh-session-format-v3-to-v4", + "description": "Streaming identity migration and delivery validation from Session V3 to V4", + "version": "0.1.6-alpha.1", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", + "directory": "packages/session/session-format-v3-to-v4" + }, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/types/**/*.d.ts" + ], + "license": "MIT", + "dsh": { + "sessionFormatMigration": { + "from": 3, + "to": 4, + "export": ".", + "migration": "sessionFormatV3ToV4", + "sourceCodec": "releasedV3SessionFormatCodec", + "targetCodec": "releasedV4SessionFormatCodec", + "targetHeaderValidator": "assertReleasedV4Header", + "targetRestorer": "restoreReleasedV4Artifact" + } + }, + "dependencies": { + "@deepseek-ai/dsh-session-format": "workspace:^", + "@deepseek-ai/dsh-session-format-v2-to-v3": "workspace:^" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "workspace:^" + }, + "devDependencies": { + "@deepseek-ai/cordis": "workspace:^" + } +} diff --git a/packages/session/session-format-v3-to-v4/src/codec.ts b/packages/session/session-format-v3-to-v4/src/codec.ts new file mode 100644 index 0000000000..0a0df00539 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/src/codec.ts @@ -0,0 +1,38 @@ +/** V4 framing retains released V3 event encoding and structural admission. */ + +import { SessionFormatError, isSessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatCodec, SessionFormatCurrentEncoder, SessionFormatHeader } from '@deepseek-ai/dsh-session-format' +import { assertV3RowAdmission, releasedV3SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { assertReleasedV4Header } from './validation.ts' + +/** V4 codec preserves the released V3 physical event representation. */ +export const releasedV4SessionFormatCodec = Object.freeze({ + version: 4, + decodeHeader(value: unknown) { + return { ...releasedV3SessionFormatCodec.decodeHeader(physicalV3(value)), version: 4 } + }, + createDecoder(value, recovery) { + const decoder = releasedV3SessionFormatCodec.createDecoder(physicalV3(value), recovery) + return { ...decoder, header: { ...decoder.header, version: 4 } } + }, + encodeHeader(header, inheritedEventCount) { + assertReleasedV4Header(header) + return { ...releasedV3SessionFormatCodec.encodeHeader({ ...header, version: 3 }, inheritedEventCount), version: 4 } + }, + encodeEvent: releasedV3SessionFormatCodec.encodeEvent, +} satisfies SessionFormatCodec & SessionFormatCurrentEncoder) + +/** + * Apply V4 structural admission before a scanner discards a recoverable suffix. + * @param row - parsed physical row before framing and source-event range decoding. + */ +export function assertV4RowAdmission(row: unknown): void { + assertV3RowAdmission(row) +} + +function physicalV3(value: unknown): SessionFormatHeader { + if (!isSessionFormatJsonObject(value) || value['version'] !== 4) { + throw new SessionFormatError('expected format v4 physical Session header') + } + return { ...value, version: 3 } as SessionFormatHeader +} diff --git a/packages/session/session-format-v3-to-v4/src/index.ts b/packages/session/session-format-v3-to-v4/src/index.ts new file mode 100644 index 0000000000..a440a78ee2 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/src/index.ts @@ -0,0 +1,6 @@ +/** Identity V3-to-V4 migration with frozen V3 framing and generation-aware delivery validation. */ + +export { releasedV3SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v2-to-v3' +export * from './codec.ts' +export * from './migration.ts' +export { assertReleasedV4Header, restoreReleasedV4Artifact } from './validation.ts' diff --git a/packages/session/session-format-v3-to-v4/src/migration.ts b/packages/session/session-format-v3-to-v4/src/migration.ts new file mode 100644 index 0000000000..6f6497367e --- /dev/null +++ b/packages/session/session-format-v3-to-v4/src/migration.ts @@ -0,0 +1,63 @@ +/** Streaming V3-to-V4 identity conversion with inherited cuts and delivery activation guards. */ + +import { SessionFormatError, SessionFormatUnsupportedMigrationError, defineSessionFormatMigration, sessionFormatCount } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatEvent, SessionFormatEventRun, SessionFormatJsonObject, SessionFormatMigrationContext, SessionFormatMigrationStage, SessionFormatMigrationStageInput } from '@deepseek-ai/dsh-session-format' +import { assertReleasedV3Header } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { assertReleasedV4Header, validateDeliveryAccepted } from './validation.ts' + +/** Adjacent migration preserves admitted V3 event values and coordinates. */ +export const sessionFormatV3ToV4 = defineSessionFormatMigration({ + name: '@deepseek-ai/dsh-session-format-v3-to-v4', + fromVersion: 3, + toVersion: 4, + migrateHeader(header) { + assertReleasedV3Header(header) + return { ...header, version: 4 } + }, + createStage(input) { return new ReleasedV3ToV4Stage(input) }, + validateTargetHeader: assertReleasedV4Header, +}) + +class ReleasedV3ToV4Stage implements SessionFormatMigrationStage { + readonly headerInheritedEventCount?: number + private cut: number | undefined + private nextSeq = 0 + private foreignDeliverySeq: number | undefined + + constructor(private readonly input: SessionFormatMigrationStageInput) { + this.cut = input.sourceHeader.isSeeded ? undefined : 0 + if (!input.sourceHeader.isSeeded) this.headerInheritedEventCount = 0 + } + + transformEvent(event: SessionFormatEvent, context: SessionFormatMigrationContext): void { + if (event.seq !== this.nextSeq++) throw new SessionFormatError('format v3 source events must be dense') + if (event.type === 'session/end-seed' && (event.data as SessionFormatJsonObject)['inherited'] === true) { + if (!this.input.sourceHeader.isSeeded) throw new SessionFormatError('unseeded format v3 Session contains an inherited end-seed marker') + this.cut = event.seq + } + const deliveryId = validateDeliveryAccepted(event, 3) + if (event.type === 'session-log-deepseek/delivery-accepted') { + if ((event.data as SessionFormatJsonObject)['sessionFormatVersion'] === 4) { + throw new SessionFormatUnsupportedMigrationError('format v3 delivery marker claims target format v4') + } + if (deliveryId !== undefined && deliveryId !== this.input.sourceHeader.id) this.foreignDeliverySeq = event.seq + } + context.emitEvent(event) + } + + transformRun(run: SessionFormatEventRun, context: SessionFormatMigrationContext): void { + for (const event of run.expand()) this.transformEvent(event, context) + } + + finish(_context: SessionFormatMigrationContext): number { + const cut = sessionFormatCount(this.cut, 'format v3 inherited event count') + if (this.input.sourceInheritedEventCount !== undefined && cut !== this.input.sourceInheritedEventCount) { + throw new SessionFormatError('format v3 inherited cut disagrees with its source marker') + } + if (this.foreignDeliverySeq !== undefined + && (this.input.sourceHeader.parentSession === undefined || this.foreignDeliverySeq >= cut)) { + throw new SessionFormatError('current-generation delivery marker names the wrong Session') + } + return cut + } +} diff --git a/packages/session/session-format-v3-to-v4/src/validation.ts b/packages/session/session-format-v3-to-v4/src/validation.ts new file mode 100644 index 0000000000..a68e3542c5 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/src/validation.ts @@ -0,0 +1,55 @@ +/** V4 metadata and relationship validation without changing recorded delivery generations. */ + +import { SessionFormatError, isSessionFormatJsonObject, sessionFormatCount } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatArtifact, SessionFormatEvent, SessionFormatHeader, SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' +import { assertReleasedV3Header, restoreReleasedV3Artifact } from '@deepseek-ai/dsh-session-format-v2-to-v3' + +/** + * Validate V4 metadata with the unchanged released V3 header fields. + * @param header - decoded V4 Session header. + */ +export function assertReleasedV4Header(header: SessionFormatHeader): void { + if (header.version !== 4) throw new SessionFormatError('expected format v4 header') + assertReleasedV3Header({ ...header, version: 3 }) +} + +/** + * Validate V4 relationships and delivery coordinates while retaining the original artifact. + * @param artifact - complete detached V4 artifact. + * @param knownEventTypes - event types understood by the installed Session package. + * @returns the same validated artifact and event objects. + */ +export function restoreReleasedV4Artifact(artifact: SessionFormatArtifact, knownEventTypes: ReadonlySet): SessionFormatArtifact { + assertReleasedV4Header(artifact.header) + const events = artifact.events.map((event): SessionFormatEvent => { + validateDeliveryAccepted(event, 4) + if (event.type !== 'session-log-deepseek/delivery-accepted') return event + const data = event.data as SessionFormatJsonObject + const version = data['sessionFormatVersion'] + // Only this private relationship view substitutes generations; recorded delivery identities stay unchanged. + return version === 4 || version === 3 + ? { ...event, data: { ...data, sessionFormatVersion: version === 4 ? 3 : 2 } } + : event + }) + restoreReleasedV3Artifact({ ...artifact, header: { ...artifact.header, version: 3 }, events }, knownEventTypes) + return artifact +} + +/** + * Validate delivery generation and active-generation coordinates before evaluating ownership. + * @param event - decoded event whose delivery payload may be inspected. + * @param currentVersion - generation whose watermark coordinates are active. + * @returns the active delivery's nonempty Session id, or undefined for other events and generations. + */ +export function validateDeliveryAccepted(event: SessionFormatEvent, currentVersion: 3 | 4): string | undefined { + if (event.type !== 'session-log-deepseek/delivery-accepted') return undefined + const data = event.data + if (!isSessionFormatJsonObject(data)) throw new SessionFormatError('delivery-accepted data must be an object') + const version = sessionFormatCount(data['sessionFormatVersion'] === undefined ? 0 : data['sessionFormatVersion'], 'delivery sessionFormatVersion') + if (version !== currentVersion) return undefined + const throughSeq = sessionFormatCount(data['throughSeq'], 'delivery throughSeq') + if (throughSeq >= event.seq) throw new SessionFormatError('delivery throughSeq must precede its marker') + const id = data['sessionId'] + if (typeof id !== 'string' || id.length === 0) throw new SessionFormatError('delivery requires a nonempty Session id') + return id +} diff --git a/packages/session/session-format-v3-to-v4/tests/codec.spec.ts b/packages/session/session-format-v3-to-v4/tests/codec.spec.ts new file mode 100644 index 0000000000..e4e6905d92 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/tests/codec.spec.ts @@ -0,0 +1,116 @@ +import { describe, expect, it } from 'vitest' +import { SessionFormatEventCollector } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatEvent, SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' +import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { releasedV3SessionFormatCodec as previousCodec } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { assertReleasedV4Header, assertV4RowAdmission, releasedV3SessionFormatCodec, releasedV4SessionFormatCodec, restoreReleasedV4Artifact } from '../src/index.ts' + +const header = { version: 4, id: 'parent', createdAt: 1, isSeeded: false, delegationDepth: 0 } +const fact: SessionFormatEvent = { type: 'feedback/record', seq: 0, time: 1, data: { text: 'retained' } } +const types = new Set(['feedback/record', 'session-log-deepseek/delivery-accepted', 'session/end-seed']) +const delivery = (version: number | undefined, sessionId = header.id): SessionFormatEvent => ({ + type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 2, + data: { sessionId, throughSeq: 0, ...(version === undefined ? {} : { sessionFormatVersion: version }) }, +}) + +function restore(events: readonly SessionFormatEvent[], sourceHeader = header) { + return restoreReleasedV4Artifact({ header: sourceHeader, events, inheritedEventCount: 0 }, types) +} + +describe('V4 framing and restoration', () => { + it('reuses the released V3 codec and round trips unchanged V3 event encoding', () => { + expect(releasedV3SessionFormatCodec).toBe(previousCodec) + const physical = releasedV4SessionFormatCodec.encodeHeader(header, 0) + expect(physical).toEqual({ type: 'session', ...header }) + expect(releasedV4SessionFormatCodec.decodeHeader(physical)).toEqual(header) + const decoder = releasedV4SessionFormatCodec.createDecoder(physical, 'strict') + const output = new SessionFormatEventCollector() + expect(decoder.header).toEqual(header) + const row = releasedV4SessionFormatCodec.encodeEvent(fact) + expect(row).toEqual(releasedV3SessionFormatCodec.encodeEvent(fact)) + decoder.decodeRow(row, output) + expect(decoder.finish(output)).toBe(0) + expect(output.values).toEqual([fact]) + const artifact = { header, events: output.values, inheritedEventCount: 0 } + expect(restoreReleasedV4Artifact(artifact, types)).toBe(artifact) + }) + + it('rejects mismatched versions and malformed logical and physical metadata', () => { + expect(() => { assertReleasedV4Header({ ...header, version: 3 }) }).toThrow('v4 header') + expect(() => { assertReleasedV4Header({ ...header, createdAt: -1 }) }).toThrow('createdAt') + expect(() => releasedV4SessionFormatCodec.decodeHeader(null)).toThrow('v4 physical') + expect(() => releasedV4SessionFormatCodec.createDecoder({ ...header, version: 3 }, 'strict')).toThrow('v4 physical') + expect(() => releasedV4SessionFormatCodec.decodeHeader({ type: 'session', ...header, extra: 1 })).toThrow(/field|member/) + }) + + it('retains predecessor and future delivery generations without activating their watermarks', () => { + for (const version of [undefined, 0, 1, 2, 3, 5]) { + const marker = { ...delivery(version, 'foreign'), data: { ...delivery(version).data as SessionFormatJsonObject, sessionId: 'foreign', throughSeq: 500 } } + expect(restore([fact, marker]).events[1]).toBe(marker) + } + const current = delivery(4) + expect(restore([fact, current]).events[1]).toBe(current) + expect(() => restore([fact, delivery(4, 'foreign')])).toThrow('wrong Session') + }) + + it('rejects malformed active delivery coordinates and malformed generation identifiers', () => { + const marker = delivery(4) + const data = marker.data as SessionFormatJsonObject + for (const throughSeq of [-1, 1, 1.5]) { + expect(() => restore([fact, { ...marker, data: { ...data, throughSeq } }])).toThrow('throughSeq') + } + for (const sessionId of ['', null, 3]) { + expect(() => restore([fact, { ...marker, data: { ...data, sessionId } }])).toThrow('nonempty') + } + for (const sessionFormatVersion of [-1, -0, 1.5, '4', null]) { + expect(() => restore([fact, { ...marker, data: { ...data, sessionFormatVersion } }])).toThrow('sessionFormatVersion') + } + expect(() => restore([fact, { ...marker, data: null }])).toThrow('data must be an object') + const reader = sessionFormatCatalog.createRestore({ type: 'session', ...header }, { recovery: 'strict', validation: 'current' }) + reader.decodeRow(fact) + reader.decodeRow({ ...marker, data: { ...data, throughSeq: 1 } }) + expect(() => reader.finish()).toThrow('throughSeq') + }) + + it('preserves inherited and local events and admits foreign active deliveries inside the seed only', () => { + const inherited = delivery(4, 'ancestor') + const artifact = { + header: { ...header, isSeeded: true, parentSession: 'ancestor' }, inheritedEventCount: 2, + events: [fact, inherited, { type: 'session/end-seed', seq: 2, time: 3, data: { inherited: true } }, { ...fact, seq: 3 }], + } + expect(restoreReleasedV4Artifact(artifact, types)).toBe(artifact) + expect(() => restoreReleasedV4Artifact({ ...artifact, inheritedEventCount: 1 }, types)).toThrow('marker') + }) + + it('preserves unknown ignorable values and requires installed vocabulary for unknown required events', () => { + const opaque = { type: 'external/opaque', seq: 0, time: 1, data: { untouched: ['a', 3] }, ignorable: true } + expect(restore([opaque]).events[0]).toBe(opaque) + const required = { type: 'external/required', seq: 0, time: 1, data: null } + expect(() => restore([required])).toThrow('unknown event type') + const artifact = { header, events: [required], inheritedEventCount: 0 } + expect(restoreReleasedV4Artifact(artifact, new Set([required.type]))).toBe(artifact) + }) + + it.each([ + { type: 'request/header', seq: 0, time: 1, data: { header: { system: '' } } }, + { type: 'system/message', seq: 0, time: 1, data: {} }, + { type: 'tool/code-dispatch', seq: 0, time: 1, data: null }, + ])('refuses structural $type violations even after recoverable corruption', (row) => { + expect(() => { assertV4RowAdmission(row) }).toThrow() + const decoder = releasedV4SessionFormatCodec.createDecoder({ type: 'session', ...header }, 'recoverable') + const output = new SessionFormatEventCollector() + decoder.decodeRow(null, output) + expect(() => { decoder.decodeRow(row, output) }).toThrow() + }) + + it('leaves ordinary framing recovery to the released decoder', () => { + expect(() => { assertV4RowAdmission(null) }).not.toThrow() + expect(() => { assertV4RowAdmission(fact) }).not.toThrow() + const decoder = releasedV4SessionFormatCodec.createDecoder({ type: 'session', ...header }, 'recoverable') + const output = new SessionFormatEventCollector() + decoder.decodeRow(fact, output) + decoder.decodeRow(null, output) + expect(decoder.finish(output)).toBe(0) + expect(output.values).toEqual([fact]) + }) +}) diff --git a/packages/session/session-format-v3-to-v4/tests/migration.spec.ts b/packages/session/session-format-v3-to-v4/tests/migration.spec.ts new file mode 100644 index 0000000000..f9e87ee791 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/tests/migration.spec.ts @@ -0,0 +1,154 @@ +import { describe, expect, it } from 'vitest' +import { SessionFormatEventCollector } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatEvent, SessionFormatHeader, SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' +import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { releasedV3SessionFormatCodec, sessionFormatV3ToV4 } from '../src/index.ts' + +const header: SessionFormatHeader = { version: 3, id: 'identity', createdAt: 1, isSeeded: false, delegationDepth: 0 } +const fact: SessionFormatEvent = { type: 'feedback/record', seq: 0, time: 2, data: { text: 'retained' } } +const seed: SessionFormatEvent = { type: 'session/end-seed', seq: 1, time: 3, data: { inherited: true } } +const delivery = (version: number | undefined, sessionId = header.id): SessionFormatEvent => ({ + type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 3, + data: { sessionId, throughSeq: 0, ...(version === undefined ? {} : { sessionFormatVersion: version }) }, +}) + +function stage(sourceHeader = header, sourceInheritedEventCount?: number) { + return sessionFormatV3ToV4.createStage({ + sourceHeader, targetHeader: sessionFormatV3ToV4.migrateHeader(sourceHeader), + sourceInheritedEventCount, sourceKind: 'decoded', + }) +} + +function migrate(events: readonly SessionFormatEvent[], sourceHeader = header, cut?: number) { + const current = stage(sourceHeader, cut) + const output = new SessionFormatEventCollector() + for (const event of events) current.transformEvent(event, output) + return { events: output.values, cut: current.finish(output) } +} + +function restore(events: readonly SessionFormatEvent[], sourceHeader = header) { + const reader = sessionFormatCatalog.createRestore({ type: 'session', ...sourceHeader }, { recovery: 'strict', validation: 'current' }) + for (const event of events) reader.decodeRow(event) + return reader.finish() +} + +describe('V3 to V4 identity migration', () => { + it('changes only the header version and retains event objects, payloads, timestamps, and coordinates', () => { + const rows = [fact, delivery(3)] + const before = JSON.stringify({ header, rows }) + expect(sessionFormatV3ToV4.migrateHeader(header)).toEqual({ ...header, version: 4 }) + expect(migrate(rows)).toEqual({ events: rows, cut: 0 }) + expect(migrate(rows).events[0]).toBe(fact) + expect(migrate(rows).events[1]).toBe(rows[1]) + expect(JSON.stringify({ header, rows })).toBe(before) + expect(stage().headerInheritedEventCount).toBe(0) + expect(migrate([])).toEqual({ events: [], cut: 0 }) + expect(restore(rows)).toEqual({ header: { ...header, version: 4 }, inheritedEventCount: 0, events: rows }) + expect(restore(rows)).toEqual(restore(rows)) + }) + + it('keeps interleaved stage state independent and derives an inherited cut unavailable before EOF', () => { + const inherited = stage({ ...header, isSeeded: true, parentSession: 'ancestor' }) + const local = stage() + const a = new SessionFormatEventCollector() + const b = new SessionFormatEventCollector() + expect(inherited.headerInheritedEventCount).toBeUndefined() + inherited.transformEvent(fact, a) + local.transformEvent(fact, b) + inherited.transformEvent(seed, a) + expect(local.finish(b)).toBe(0) + expect(inherited.finish(a)).toBe(1) + expect(a.values).toEqual([fact, seed]) + expect(b.values).toEqual([fact]) + expect(migrate([fact, seed], { ...header, isSeeded: true }, 1).cut).toBe(1) + }) + + it('consumes compact runs without changing their event values', () => { + const current = stage() + const output = new SessionFormatEventCollector() + current.transformRun({ runType: 'identity', eventCount: 1, firstSeq: 0, *expand() { yield fact } }, output) + expect(current.finish(output)).toBe(0) + expect(output.values[0]).toBe(fact) + }) + + it('rejects sparse sequences and inconsistent inheritance', () => { + expect(() => migrate([{ ...fact, seq: 1 }])).toThrow('dense') + expect(() => migrate([fact, seed])).toThrow('unseeded') + expect(() => migrate([fact], { ...header, isSeeded: true })).toThrow('inherited event count') + expect(() => migrate([fact, seed], { ...header, isSeeded: true }, 0)).toThrow('disagrees') + expect(() => migrate([fact, { ...seed, data: {} }], { ...header, isSeeded: true })).toThrow('inherited event count') + }) + + it('refuses a target-generation delivery without changing predecessor or future delivery values', () => { + expect(() => migrate([fact, delivery(4)])).toThrow('claims target format v4') + expect(() => restore([fact, delivery(4)])).toThrow('claims target format v4') + for (const version of [undefined, 0, 1, 2, 3, 5]) { + const marker = delivery(version) + expect(migrate([fact, marker]).events[1]).toBe(marker) + } + }) + + it('checks active V3 coordinates before the delivery becomes historical', () => { + const marker = delivery(3) + const data = marker.data as SessionFormatJsonObject + for (const throughSeq of [-1, 1, 1.5]) { + expect(() => migrate([fact, { ...marker, data: { ...data, throughSeq } }])).toThrow('throughSeq') + } + expect(() => migrate([fact, { ...marker, data: { ...data, sessionId: '' } }])).toThrow('nonempty') + expect(() => restore([fact, { ...marker, data: { ...data, throughSeq: 1 } }])).toThrow('throughSeq') + const historical = { ...marker, data: { sessionId: 'ancestor', throughSeq: 500, sessionFormatVersion: 2 } } + expect(restore([fact, historical]).events[1]).toEqual(historical) + }) + + it('permits foreign active deliveries only inside a parent seed', () => { + const foreign = delivery(3, 'ancestor') + expect(() => migrate([fact, foreign])).toThrow('wrong Session') + expect(() => migrate([fact, foreign], { ...header, parentSession: 'ancestor' })).toThrow('wrong Session') + const rows = [fact, foreign, { ...seed, seq: 2 }] + expect(migrate(rows, { ...header, isSeeded: true, parentSession: 'ancestor' }).cut).toBe(2) + expect(() => migrate(rows, { ...header, isSeeded: true })).toThrow('wrong Session') + expect(() => migrate([fact, seed, { ...foreign, seq: 2 }], { ...header, isSeeded: true, parentSession: 'ancestor' })).toThrow('wrong Session') + }) + + it('retains unknown ignorable values and refuses unknown required events during strict catalog restoration', () => { + const opaque: SessionFormatEvent = { + type: 'external/opaque', seq: 0, time: -5, ignorable: true, + data: { nested: { seq: 40 }, content: ['opaque'] }, surfaceOp: { future: { ref: 9 } }, + } + expect(restore([opaque]).events).toEqual([opaque]) + const { ignorable: _ignorable, ...required } = opaque + expect(() => restore([required])).toThrow('unknown event type') + expect(() => restore([{ ...fact, time: 1.5 }])).toThrow('time') + expect(() => restore([{ ...fact, extra: 1 }])).toThrow(/field|member/) + }) + + it.each([0, 1, 2, 3])('restores a seeded V%i chain, including upstream cardinality changes, and reopens V4', (version) => { + const rows = [ + { type: 'turn/start', data: { turn: 1 } }, + { type: 'step/start', data: { turn: 1, step: 1 } }, + { type: 'user/message', data: { id: 'user', role: 'user', source: { kind: 'user' }, content: [{ type: 'text', text: 'input' }] }, surfaceOp: 'append' }, + { type: 'request/header', data: { header: { config: { provider: 'mock', model: 'mock' }, system: 'seed prompt' }, reason: 'initial' } }, + { type: 'step/end', data: { turn: 1, step: 1 } }, + { type: 'turn/end', data: { turn: 1, reason: { kind: 'completed' } } }, + { type: 'session/end-seed', data: version < 2 ? {} : { inherited: true } }, + ].map((event, seq): SessionFormatEvent => ({ ...event, seq, time: seq + 1 })) + const source = version === 3 ? restore(rows, { ...header, version: 2, isSeeded: true }).events : rows + const physical = version < 2 + ? { type: 'session', version, id: header.id, createdAt: 1, delegationDepth: 0, parentSession: 'ancestor', seedLength: 6 } + : { type: 'session', ...header, version, isSeeded: true, parentSession: 'ancestor' } + const before = JSON.stringify({ physical, source }) + const reader = sessionFormatCatalog.createRestore(physical, { recovery: 'strict', validation: 'current' }) + for (const row of source) reader.decodeRow(version === 3 ? releasedV3SessionFormatCodec.encodeEvent(row) : row) + const artifact = reader.finish() + expect(artifact.header.version).toBe(4) + expect(artifact.inheritedEventCount).toBe(8) + expect(artifact.events.filter(event => event.type === 'system/message')).toHaveLength(2) + expect(artifact.events.at(-1)?.seq).toBe(8) + const reopened = sessionFormatCatalog.createRestore(sessionFormatCatalog.encodeCurrentHeader(artifact.header, 8), { + recovery: 'strict', validation: 'current', + }) + for (const event of artifact.events) reopened.decodeRow(sessionFormatCatalog.encodeCurrentEvent(event)) + expect(reopened.finish()).toEqual(artifact) + expect(JSON.stringify({ physical, source })).toBe(before) + }) +}) diff --git a/packages/session/session-format-v3-to-v4/tsconfig.json b/packages/session/session-format-v3-to-v4/tsconfig.json new file mode 100644 index 0000000000..373e4c24f6 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types" + }, + "include": ["src"], + "references": [ + { "path": "../../../vendor/cordis" }, + { "path": "../session-format" }, + { "path": "../session-format-v2-to-v3" } + ] +} diff --git a/packages/session/session-persistence-jsonl/package.json b/packages/session/session-persistence-jsonl/package.json index d5fad6d730..dbb621c842 100644 --- a/packages/session/session-persistence-jsonl/package.json +++ b/packages/session/session-persistence-jsonl/package.json @@ -36,7 +36,7 @@ "@deepseek-ai/dsh-llm": "workspace:^", "@deepseek-ai/dsh-session-format": "workspace:^", "@deepseek-ai/dsh-session-format-catalog": "workspace:^", - "@deepseek-ai/dsh-session-format-v2-to-v3": "workspace:^", + "@deepseek-ai/dsh-session-format-v3-to-v4": "workspace:^", "@deepseek-ai/node-addon-system": "workspace:^", "koffi": "^3.1.0", "@deepseek-ai/schemastery": "workspace:^" diff --git a/packages/session/session-persistence-jsonl/src/format.ts b/packages/session/session-persistence-jsonl/src/format.ts index 4129207ece..71177b9727 100644 --- a/packages/session/session-persistence-jsonl/src/format.ts +++ b/packages/session/session-persistence-jsonl/src/format.ts @@ -23,7 +23,7 @@ import { parseSessionFormatLogFilename, sessionFormatLogFilename, SessionFormatU import type { SessionFormatEvent } from '@deepseek-ai/dsh-session-format' import type { SessionFormatRecovery, SessionFormatRestore } from '@deepseek-ai/dsh-session-format' import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' -import { assertV3RowAdmission } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { assertV4RowAdmission } from '@deepseek-ai/dsh-session-format-v3-to-v4' import { SessionFormatUnsupportedError, sessionFormatVersionRefusal, @@ -488,7 +488,7 @@ export class SessionLogScanner { // This scanner accepts only current-generation files. Owned structural refusal must // precede its recoverable-tail suppression, independently of the strict decoder state. try { - assertV3RowAdmission(decoded) + assertV4RowAdmission(decoded) } catch (error: unknown) { if (error instanceof SessionFormatUnsupportedMigrationError) throw new SessionFormatUnsupportedError(error.message) throw error @@ -502,7 +502,7 @@ export class SessionLogScanner { try { this.restore.decodeRow(decoded) } catch (error: unknown) { - // Unsupported V3 rows have already been refused before recovery. + // Unsupported current-format rows have already been refused before recovery. /* v8 ignore next -- every production Session format decoder rejects with Error. */ const detail = error instanceof Error ? error.message : String(error) const issue = new Error(`corrupt session log: invalid committed event at line ${this.eventLine}: ${detail}`, { diff --git a/packages/session/session-persistence-jsonl/tests/built-migration-worker.e2e.ts b/packages/session/session-persistence-jsonl/tests/built-migration-worker.e2e.ts index a75a9496ef..9d130a40a9 100644 --- a/packages/session/session-persistence-jsonl/tests/built-migration-worker.e2e.ts +++ b/packages/session/session-persistence-jsonl/tests/built-migration-worker.e2e.ts @@ -2,6 +2,7 @@ import { existsSync } from 'node:fs' import { join } from 'node:path' import { fileURLToPath } from 'node:url' import { execa } from 'execa' +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import { describe, expect, it } from 'vitest' const packageRoot = fileURLToPath(new URL('..', import.meta.url)) @@ -16,6 +17,7 @@ describe.skipIf(!built)('built migration verifier (plain node)', () => { import { join } from 'node:path' import { Worker } from 'node:worker_threads' import { Context } from '@deepseek-ai/cordis' + import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' const root = await mkdtemp(join(tmpdir(), 'dsh-built-migration-')) @@ -31,7 +33,7 @@ describe.skipIf(!built)('built migration verifier (plain node)', () => { const handle = await ctx.sessionPersistence.open(id, 'write') await handle.close() await ctx.sessionPersistence.flush() - const currentPath = join(directory, 'session.v3.jsonl') + const currentPath = join(directory, 'session.v' + SESSION_FORMAT_VERSION + '.jsonl') const header = JSON.parse((await readFile(currentPath, 'utf8')).trim()) await mkdir(join(root, 'lib')) await copyFile('package.json', join(root, 'package.json')) @@ -71,7 +73,7 @@ describe.skipIf(!built)('built migration verifier (plain node)', () => { expect(exitCode, `stderr:\n${stderr}`).toBe(0) expect(JSON.parse(stdout.trim())).toEqual({ - id: 'built-migration-worker', version: 3, verified: true, refused: false, + id: 'built-migration-worker', version: SESSION_FORMAT_VERSION, verified: true, refused: false, refusal: 'current session generation contains 0 events, expected 1', }) }) diff --git a/packages/session/session-persistence-jsonl/tests/content-admission.spec.ts b/packages/session/session-persistence-jsonl/tests/content-admission.spec.ts index 2b27defcf4..e8e088220c 100644 --- a/packages/session/session-persistence-jsonl/tests/content-admission.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/content-admission.spec.ts @@ -1,7 +1,7 @@ /** V2 content admission refuses entire generations without publishing a valid prefix. */ import { Context } from '@deepseek-ai/cordis' -import { SessionId } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' import type { SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' import { SessionFormatUnsupportedError } from '@deepseek-ai/dsh-session-persistence' import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' @@ -198,7 +198,7 @@ describe.each(['none', 'zstd'] as const)('V2 admitted content publication (%s)', const reader = await ctx.sessionPersistence.open(id, 'read') const restored = await (async () => { try { - expect(reader.header.version).toBe(3) + expect(reader.header.version).toBe(SESSION_FORMAT_VERSION) return await reader.read() } finally { await reader.close() } })() @@ -219,7 +219,7 @@ describe.each(['none', 'zstd'] as const)('V2 admitted content publication (%s)', expect((await writer.read()).events).toEqual(restored.events) await writer.flush() } finally { await writer.close() } - const successor = generationLogPath(root!, undefined, id, 3, compression) + const successor = generationLogPath(root!, undefined, id, SESSION_FORMAT_VERSION, compression) const published = await readFile(successor) let decoded = published if (compression === 'zstd') { @@ -237,7 +237,7 @@ describe.each(['none', 'zstd'] as const)('V2 admitted content publication (%s)', const fresh = await mount(compression) const reopened = await fresh.sessionPersistence.open(id, 'read') try { - expect(reopened.header.version).toBe(3) + expect(reopened.header.version).toBe(SESSION_FORMAT_VERSION) expect((await reopened.read()).events).toEqual(restored.events) } finally { await reopened.close() } expect(await observe(path)).toEqual(original) diff --git a/packages/session/session-persistence-jsonl/tests/v3-event-admission.spec.ts b/packages/session/session-persistence-jsonl/tests/current-event-admission.spec.ts similarity index 93% rename from packages/session/session-persistence-jsonl/tests/v3-event-admission.spec.ts rename to packages/session/session-persistence-jsonl/tests/current-event-admission.spec.ts index 02e9d8aef7..36f5ef40b7 100644 --- a/packages/session/session-persistence-jsonl/tests/v3-event-admission.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/current-event-admission.spec.ts @@ -1,5 +1,5 @@ import { Context } from '@deepseek-ai/cordis' -import { SessionId, SessionSeq } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, SessionId, SessionSeq } from '@deepseek-ai/dsh-session' import { SessionFormatUnsupportedError } from '@deepseek-ai/dsh-session-persistence' import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises' @@ -8,8 +8,8 @@ import { dirname, join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { generationLogPath, scanLog } from '../src/format.ts' -const id = SessionId('v3-admission') -const header = { type: 'session', version: 3, id, createdAt: 1000, isSeeded: false, delegationDepth: 0 } +const id = SessionId('current-admission') +const header = { type: 'session', version: SESSION_FORMAT_VERSION, id, createdAt: 1000, isSeeded: false, delegationDepth: 0 } const start = { type: 'turn/start', seq: 0, time: 1, data: { turn: 1 } } const prefix = [header, start].map(row => JSON.stringify(row)).join('\n') + '\n' const obsoleteTypes = ['tool/code-dispatch-start', 'tool/code-dispatch'] as const @@ -22,12 +22,12 @@ function obsoleteEvent(type: string, ignorable?: true) { } } -describe('native V3 event admission at EOF', () => { +describe('current event admission at EOF', () => { let root: string let ctx: Context beforeEach(async () => { - root = await mkdtemp(join(tmpdir(), 'dsh-v3-admission-')) + root = await mkdtemp(join(tmpdir(), 'dsh-current-admission-')) ctx = new Context() await ctx.plugin(JsonlSessionPersistence, { root, compression: 'none' }) }) @@ -41,7 +41,7 @@ describe('native V3 event admission at EOF', () => { }) async function store(bytes: Buffer): Promise { - const path = generationLogPath(root, undefined, id, 3, 'none') + const path = generationLogPath(root, undefined, id, SESSION_FORMAT_VERSION, 'none') await mkdir(dirname(path), { recursive: true }) await writeFile(path, bytes) return path diff --git a/packages/session/session-persistence-jsonl/tests/generation.spec.ts b/packages/session/session-persistence-jsonl/tests/generation.spec.ts index 41db8b8ea0..71f05baa1a 100644 --- a/packages/session/session-persistence-jsonl/tests/generation.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/generation.spec.ts @@ -1,3 +1,4 @@ +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import { afterEach, describe, expect, it, vi } from 'vitest' import { createHash } from 'node:crypto' import { @@ -145,7 +146,7 @@ interface TestGenerationFormatAdapter extends JsonlGenerationFormatAdapter { } function adapter(overrides: Partial = {}): TestGenerationFormatAdapter { - const currentVersion = overrides.currentVersion ?? 3 + const currentVersion = overrides.currentVersion ?? SESSION_FORMAT_VERSION return { currentVersion, createRestore(headerValue) { @@ -287,7 +288,7 @@ async function decodeZstdJsonl(path: string): Promise { } describe('JSONL immutable generation publication', () => { - it('refuses V2 messages without surface markers before writing a V3 successor', async () => { + it('refuses V2 messages without surface markers before writing a current successor', async () => { const root = await tempRoot() const request = options(root, 'none', catalogAdapter(), 2) const events = assistantLifecycle('assistant/message', assistantData()) @@ -332,7 +333,7 @@ describe('JSONL immutable generation publication', () => { expect(await readdir(root)).toEqual(['session.v2.jsonl']) }) - it('publishes canonical V3 replacements and headers while retaining exact V2 bytes', async () => { + it('publishes canonical replacements and current headers while retaining exact V2 bytes', async () => { const root = await tempRoot() const request = options(root, 'none', catalogAdapter(), 2) const config = { provider: 'mock', model: 'mock' } @@ -370,8 +371,8 @@ describe('JSONL immutable generation publication', () => { expect(await readFile(request.sourcePath)).toEqual(source) const written = (await readFile(request.currentPath, 'utf8')).trimEnd().split('\n') .map(row => JSON.parse(row) as unknown) - expect(written).toEqual([header(3), ...canonical]) - expect((await readdir(root)).sort()).toEqual(['session.v2.jsonl', 'session.v3.jsonl']) + expect(written).toEqual([header(SESSION_FORMAT_VERSION), ...canonical]) + expect((await readdir(root)).sort()).toEqual(['session.v2.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) }) it('returns migrated events while publication is still waiting for verification', async () => { @@ -407,7 +408,7 @@ describe('JSONL immutable generation publication', () => { release.resolve(undefined) await publication const [writtenHeader, ...writtenEvents] = (await readFile(request.currentPath, 'utf8')).trimEnd().split('\n') - expect(JSON.parse(writtenHeader as string)).toEqual({ ...header(3), isSeeded: false }) + expect(JSON.parse(writtenHeader as string)).toEqual({ ...header(SESSION_FORMAT_VERSION), isSeeded: false }) expect(writtenEvents.map(row => JSON.parse(row) as unknown)).toEqual([boundaryEvent, largeEvent, finalEvent]) }) @@ -487,14 +488,14 @@ describe('JSONL immutable generation publication', () => { it('verifies exact current identity, completeness, and event count', async () => { const root = await tempRoot() - const path = generationPath(root, 3, 'none') - await writeFile(path, line({ ...header(3), isSeeded: false }) + line(event0)) + const path = generationPath(root, SESSION_FORMAT_VERSION, 'none') + await writeFile(path, line({ ...header(SESSION_FORMAT_VERSION), isSeeded: false }) + line(event0)) await expect(verifyJsonlCurrentGeneration(path, 'none', 'other', 1)) .rejects.toThrow('expected "other"') await expect(verifyJsonlCurrentGeneration(path, 'none', 'generation-test', 2)) .rejects.toThrow('contains 1 events') - await writeFile(path, line({ ...header(3), isSeeded: false }) + JSON.stringify(event0)) + await writeFile(path, line({ ...header(SESSION_FORMAT_VERSION), isSeeded: false }) + JSON.stringify(event0)) await expect(verifyJsonlCurrentGeneration(path, 'none', 'generation-test', 1)) .rejects.toThrow('torn physical tail') @@ -503,7 +504,7 @@ describe('JSONL immutable generation publication', () => { .rejects.toThrow('empty or header-less') await expect(verifyJsonlCurrentGeneration(path, 'zstd', 'generation-test', 0)) .rejects.toThrow('empty or header-less Zstandard') - const headerFrame = await compressZstdFrame(line({ ...header(3), isSeeded: false })) + const headerFrame = await compressZstdFrame(line({ ...header(SESSION_FORMAT_VERSION), isSeeded: false })) await writeFile(path, Buffer.concat([headerFrame, await compressZstdFrame(JSON.stringify(event0))])) await expect(verifyJsonlCurrentGeneration(path, 'zstd', 'generation-test', 1)) .rejects.toThrow('torn physical tail') @@ -517,9 +518,9 @@ describe('JSONL immutable generation publication', () => { it('keeps complete Assistant stream checks in current-generation verification', async () => { const root = await tempRoot() - const path = generationPath(root, 3, 'none') + const path = generationPath(root, SESSION_FORMAT_VERSION, 'none') const verify = async (events: readonly SessionFormatEvent[]) => { - await writeFile(path, line(header(3)) + events.map(line).join('')) + await writeFile(path, line(header(SESSION_FORMAT_VERSION)) + events.map(line).join('')) return verifyJsonlCurrentGeneration(path, 'none', 'generation-test', events.length) } @@ -573,7 +574,7 @@ describe('JSONL immutable generation publication', () => { const differentRoot = await tempRoot() const different = options(differentRoot, 'none', streamingAdapter()) await writeFile(different.sourcePath, line(header(0)) + line(event0)) - await writeFile(different.currentPath, line({ ...header(3), isSeeded: false }) + line({ ...event0, time: 99 })) + await writeFile(different.currentPath, line({ ...header(SESSION_FORMAT_VERSION), isSeeded: false }) + line({ ...event0, time: 99 })) const conflicted = await prepareJsonlMigration({ ...different, verifyCurrentFile: verifier(), @@ -585,7 +586,7 @@ describe('JSONL immutable generation publication', () => { await writeFile(unchecked.sourcePath, line(header(0)) + line(event0)) await writeFile( unchecked.currentPath, - line({ ...header(3), isSeeded: false }) + line({ ...event0, time: 99 }), + line({ ...header(SESSION_FORMAT_VERSION), isSeeded: false }) + line({ ...event0, time: 99 }), ) const uncheckedPublication = await prepareJsonlMigration({ ...unchecked, @@ -641,8 +642,8 @@ describe('JSONL immutable generation publication', () => { it('checks migration and verification identities exactly', async () => { const verifyRoot = await tempRoot() - const currentPath = generationPath(verifyRoot, 3, 'none') - await writeFile(currentPath, line(header(3))) + const currentPath = generationPath(verifyRoot, SESSION_FORMAT_VERSION, 'none') + await writeFile(currentPath, line(header(SESSION_FORMAT_VERSION))) let statCount = 0 await expect(createJsonlGenerationTestRuntime({ fs: { stat: async path => ({ ...await stat(path, { bigint: true }), ctimeNs: BigInt(++statCount) }) }, @@ -665,7 +666,7 @@ describe('JSONL immutable generation publication', () => { }) await expect(mismatched.publish()).rejects.toThrow('changed during verification') - const current = options(await tempRoot(), 'none', streamingAdapter(), 3) + const current = options(await tempRoot(), 'none', streamingAdapter(), SESSION_FORMAT_VERSION) await expect(prepareJsonlMigration({ ...current, verifyCurrentFile: vi.fn() })) .rejects.toThrow('requires a historical source') @@ -735,10 +736,10 @@ describe('JSONL immutable generation publication', () => { verifyCurrentFile: verifier(), }) await winPrepared.publish() - expect(await readFile(win.currentPath, 'utf8')).toContain('"version":3') + expect(await readFile(win.currentPath, 'utf8')).toContain(`"version":${SESSION_FORMAT_VERSION}`) }) - it('publishes v3 beside an immutable suffixless v0 source', async () => { + it('publishes the current generation beside an immutable suffixless v0 source', async () => { const root = await tempRoot() const request = { ...options(root), signal: new AbortController().signal } const source = Buffer.from(line(header(0)) + line(event0)) @@ -749,13 +750,13 @@ describe('JSONL immutable generation publication', () => { expect(result).toMatchObject({ status: 'migrated', fromVersion: 0, - toVersion: 3, + toVersion: SESSION_FORMAT_VERSION, path: request.currentPath, sourcePath: request.sourcePath, }) expect(await readFile(request.sourcePath)).toEqual(source) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) - expect((await readdir(root)).sort()).toEqual(['session.jsonl', 'session.v3.jsonl']) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) + expect((await readdir(root)).sort()).toEqual(['session.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) }) it.each(['none', 'zstd'] as const)( @@ -884,15 +885,15 @@ describe('JSONL immutable generation publication', () => { createRestore: (value) => { const restore = wrongBase.createRestore(value) return { - header: { ...restore.header, version: 4 }, + header: { ...restore.header, version: SESSION_FORMAT_VERSION + 1 }, decodeRow: (row) => { restore.decodeRow(row) }, finish: () => { const artifact = restore.finish() - return { ...artifact, header: { ...artifact.header, version: 4 } } + return { ...artifact, header: { ...artifact.header, version: SESSION_FORMAT_VERSION + 1 } } }, } }, - })))).rejects.toThrow('format migration returned v4, expected v3') + })))).rejects.toThrow(`format migration returned v${SESSION_FORMAT_VERSION + 1}, expected v${SESSION_FORMAT_VERSION}`) expect(await readdir(blockedRoot)).toEqual(['session.jsonl']) expect(await readdir(ordinaryRoot)).toEqual(['session.jsonl']) expect(await readdir(wrongRoot)).toEqual(['session.jsonl']) @@ -933,8 +934,8 @@ describe('JSONL immutable generation publication', () => { expect(await readFile(request.sourcePath)).toEqual(source) const sourceAfter = await stat(request.sourcePath, { bigint: true }) expect([sourceAfter.dev, sourceAfter.ino]).toEqual([sourceBefore.dev, sourceBefore.ino]) - expect(await readFile(request.currentPath, 'utf8')).toBe(line({ ...header(3), isSeeded: false }) + line(event0)) - expect((await readdir(root)).sort()).toEqual(['session.jsonl', 'session.v3.jsonl']) + expect(await readFile(request.currentPath, 'utf8')).toBe(line({ ...header(SESSION_FORMAT_VERSION), isSeeded: false }) + line(event0)) + expect((await readdir(root)).sort()).toEqual(['session.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) }) it.each(['none', 'zstd'] as const)( @@ -958,7 +959,7 @@ describe('JSONL immutable generation publication', () => { const currentText = compression === 'zstd' ? await decodeZstdJsonl(request.currentPath) : await readFile(request.currentPath, 'utf8') - expect(currentText).toBe(line(header(3)) + line(event0)) + expect(currentText).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }, ) @@ -984,9 +985,9 @@ describe('JSONL immutable generation publication', () => { await ensureJsonlGenerationCurrent(emptyTailRequest) await ensureJsonlGenerationCurrent(tornRequest) - expect(await decodeZstdJsonl(headerRequest.currentPath)).toBe(line(header(3))) - expect(await decodeZstdJsonl(emptyTailRequest.currentPath)).toBe(line(header(3))) - expect(await decodeZstdJsonl(tornRequest.currentPath)).toBe(line(header(3)) + line(event0) + line(event1)) + expect(await decodeZstdJsonl(headerRequest.currentPath)).toBe(line(header(SESSION_FORMAT_VERSION))) + expect(await decodeZstdJsonl(emptyTailRequest.currentPath)).toBe(line(header(SESSION_FORMAT_VERSION))) + expect(await decodeZstdJsonl(tornRequest.currentPath)).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0) + line(event1)) }) it('rejects header-less raw and Zstandard sources and a non-independent Zstandard header frame', async () => { @@ -1044,7 +1045,7 @@ describe('JSONL immutable generation publication', () => { await expect(ensureJsonlGenerationCurrent(refused)).rejects.toThrow('row 2 is not valid JSON') expect(await readFile(dropped.sourcePath, 'utf8')).toBe(incomplete) - expect(await readFile(dropped.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(dropped.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) expect(await readFile(refused.sourcePath, 'utf8')).toBe(committed) expect(await readdir(refusedRoot)).toEqual(['session.jsonl']) }) @@ -1058,7 +1059,7 @@ describe('JSONL immutable generation publication', () => { await ensureJsonlGenerationCurrent(request) expect(await readFile(request.sourcePath)).toEqual(source) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('validates canonical lowercase generation filenames and one shared directory', async () => { @@ -1072,11 +1073,11 @@ describe('JSONL immutable generation publication', () => { message: 'source path must end with "session.jsonl"', }, { - request: { ...options(root), currentPath: join(root, 'session.V3.jsonl') }, - message: 'current JSONL generation path must end with "session.v3.jsonl"', + request: { ...options(root), currentPath: join(root, `session.V${SESSION_FORMAT_VERSION}.jsonl`) }, + message: `current JSONL generation path must end with "session.v${SESSION_FORMAT_VERSION}.jsonl"`, }, { - request: { ...options(root), currentPath: generationPath(other, 3, 'none') }, + request: { ...options(root), currentPath: generationPath(other, SESSION_FORMAT_VERSION, 'none') }, message: 'must share one Session directory', }, ] @@ -1160,7 +1161,7 @@ describe('JSONL immutable generation publication', () => { expect((await readdir(root)).sort()).toEqual([ 'session.jsonl', 'session.migration.collision.jsonl.tmp', - 'session.v3.jsonl', + `session.v${SESSION_FORMAT_VERSION}.jsonl`, ]) }) @@ -1168,7 +1169,7 @@ describe('JSONL immutable generation publication', () => { const root = await tempRoot() const request = options(root) const source = Buffer.from(line(header(0)) + line(event0)) - const current = Buffer.from(line(header(3)) + line(event0)) + const current = Buffer.from(line(header(SESSION_FORMAT_VERSION)) + line(event0)) await writeFile(request.sourcePath, source) await writeFile(request.currentPath, current) @@ -1177,7 +1178,7 @@ describe('JSONL immutable generation publication', () => { expect(result).toMatchObject({ status: 'migrated', path: request.currentPath }) expect(await readFile(request.sourcePath)).toEqual(source) expect(await readFile(request.currentPath)).toEqual(current) - expect((await readdir(root)).sort()).toEqual(['session.jsonl', 'session.v3.jsonl']) + expect((await readdir(root)).sort()).toEqual(['session.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) }) it.each(['none', 'zstd'] as const)( @@ -1189,8 +1190,8 @@ describe('JSONL immutable generation publication', () => { ? await encodeZstd(0, [event0]) : Buffer.from(line(header(0)) + line(event0)) const expected = compression === 'zstd' - ? await encodeZstd(3, [event0]) - : Buffer.from(line(header(3)) + line(event0)) + ? await encodeZstd(SESSION_FORMAT_VERSION, [event0]) + : Buffer.from(line(header(SESSION_FORMAT_VERSION)) + line(event0)) const appended = compression === 'zstd' ? await compressZstdFrame(line(event1)) : Buffer.from(line(event1)) @@ -1211,11 +1212,11 @@ describe('JSONL immutable generation publication', () => { const request = options(root) const expected = join(root, 'expected.jsonl') await writeFile(request.sourcePath, line(header(0)) + line(event0)) - await writeFile(expected, line(header(3)) + line(event0)) + await writeFile(expected, line(header(SESSION_FORMAT_VERSION)) + line(event0)) await link(expected, request.currentPath) await expect(ensureJsonlGenerationCurrent(request)).resolves.toMatchObject({ path: request.currentPath }) - expect(await readFile(expected, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(expected, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it.each(['different', 'malformed', 'symlink', 'directory'] as const)( @@ -1225,7 +1226,7 @@ describe('JSONL immutable generation publication', () => { const request = options(root) const source = Buffer.from(line(header(0)) + line(event0)) await writeFile(request.sourcePath, source) - if (kind === 'different') await writeFile(request.currentPath, line(header(3)) + line(event1)) + if (kind === 'different') await writeFile(request.currentPath, line(header(SESSION_FORMAT_VERSION)) + line(event1)) if (kind === 'malformed') await writeFile(request.currentPath, '{not-json}\n') if (kind === 'symlink') await symlink(request.sourcePath, request.currentPath) if (kind === 'directory') await mkdir(request.currentPath) @@ -1252,7 +1253,7 @@ describe('JSONL immutable generation publication', () => { }, } await writeFile(request.sourcePath, line(header(0)) + line(event0)) - await writeFile(request.currentPath, line(header(3)) + line(event0)) + await writeFile(request.currentPath, line(header(SESSION_FORMAT_VERSION)) + line(event0)) const failure = await ensureJsonlGenerationCurrent(request).then( () => undefined, @@ -1281,10 +1282,10 @@ describe('JSONL immutable generation publication', () => { request, { platform: 'darwin', fs: { open: openFile } }, )).rejects.toBe(directorySyncFailure) - expect((await readdir(root)).sort()).toEqual(['session.jsonl', 'session.v3.jsonl']) + expect((await readdir(root)).sort()).toEqual(['session.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) await expect(ensureJsonlGenerationCurrent(request)).resolves.toMatchObject({ path: request.currentPath }) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('retains a committed generation when its post-publication stat fails', async () => { @@ -1302,7 +1303,7 @@ describe('JSONL immutable generation publication', () => { }, }, })).rejects.toBe(statFailure) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) expect((await readdir(root)).every(name => !name.includes('.tmp'))).toBe(true) }) @@ -1318,7 +1319,7 @@ describe('JSONL immutable generation publication', () => { if (phase === 'after-publication') controller.abort(reason) }, })).resolves.toMatchObject({ status: 'migrated', path: request.currentPath }) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('rejects a noncanonical case-insensitive collision instead of accepting its bytes', async () => { @@ -1330,12 +1331,12 @@ describe('JSONL immutable generation publication', () => { platform: 'darwin', fs: posixSimulationFs({ link: async () => { throw fsError('EEXIST') }, - readdir: async () => ['session.V3.jsonl'], + readdir: async () => [`session.V${SESSION_FORMAT_VERSION}.jsonl`], }), }).then(() => undefined, (error: unknown) => error) if (!(failure instanceof JsonlGenerationTargetConflictError)) throw new Error('expected target conflict') - expect(failure.reason.message).toContain('noncanonical directory entry "session.V3.jsonl"') + expect(failure.reason.message).toContain(`noncanonical directory entry "session.V${SESSION_FORMAT_VERSION}.jsonl"`) expect((await readdir(root)).every(name => !name.includes('.tmp'))).toBe(true) }) @@ -1365,7 +1366,7 @@ describe('JSONL immutable generation publication', () => { }, })).resolves.toMatchObject({ status: 'migrated', path: request.currentPath }) expect(reads).not.toContain(request.currentPath) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('leaves a crash-style staging file inert', async () => { @@ -1378,7 +1379,7 @@ describe('JSONL immutable generation publication', () => { await ensureJsonlGenerationCurrent(request) expect(await readFile(crashStage, 'utf8')).toBe(line(header(99))) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('removes an exclusively created stage when writing or syncing it fails', async () => { @@ -1499,7 +1500,7 @@ describe('JSONL immutable generation publication', () => { }), })).resolves.toMatchObject({ status: 'migrated', path: request.currentPath }) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('surfaces candidate validation errors and cleanup errors without publishing', async () => { @@ -1534,7 +1535,7 @@ describe('JSONL immutable generation publication', () => { if (!path.includes('.tmp')) return bytes if (mode === 'torn') return bytes.subarray(0, -1) if (mode === 'old') return Buffer.from(line(header(0)) + line(event0)) - return Buffer.from(line(header(3)) + '{not-json}\n') + return Buffer.from(line(header(SESSION_FORMAT_VERSION)) + '{not-json}\n') } await expect(ensureWithOverrides( @@ -1544,7 +1545,7 @@ describe('JSONL immutable generation publication', () => { mode === 'torn' ? 'current session generation has a torn physical tail' : mode === 'old' - ? 'uses log format v0, older than the supported v3' + ? `uses log format v0, older than the supported v${SESSION_FORMAT_VERSION}` : 'unparsable committed event at line 1', ) expect(await readdir(root)).toEqual(['session.jsonl']) @@ -1563,7 +1564,7 @@ describe('JSONL immutable generation publication', () => { expect(publishNewWin32).toHaveBeenCalledOnce() expect(publishNewWin32.mock.calls[0]?.[1]).toBe(request.currentPath) expect(await readFile(request.sourcePath)).toEqual(source) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('accepts an identical target that wins Windows publication', async () => { @@ -1571,7 +1572,7 @@ describe('JSONL immutable generation publication', () => { const request = options(root) await writeFile(request.sourcePath, line(header(0)) + line(event0)) const publishNewWin32 = vi.fn(async (_from: string, to: string) => { - await writeFile(to, line(header(3)) + line(event0)) + await writeFile(to, line(header(SESSION_FORMAT_VERSION)) + line(event0)) throw fsError('EEXIST') }) @@ -1614,7 +1615,7 @@ describe('JSONL immutable generation publication', () => { ) expect(raced).toBe(true) - expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(3)) + line(event0)) + expect(await readFile(request.currentPath, 'utf8')).toBe(line(header(SESSION_FORMAT_VERSION)) + line(event0)) }) it('honors cancellation before reading a generation', async () => { diff --git a/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts index 854aa5226b..9e3493edb9 100644 --- a/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts @@ -439,7 +439,7 @@ describe('JsonlSessionPersistence: format helpers', () => { ['unseeded', false, 0], ['empty-seed', true, 0], ['nonempty-seed', true, 3], - ] as const)('round-trips v3 lineage markers for %s', (_case, isSeeded, inheritedEventCount) => { + ] as const)('round-trips current lineage markers for %s', (_case, isSeeded, inheritedEventCount) => { const events = isSeeded ? [ ...Array.from({ length: inheritedEventCount }, (_, seq) => ({ @@ -470,7 +470,7 @@ describe('JsonlSessionPersistence: format helpers', () => { expect(toHeaderLine(scanned.meta, scanned.inheritedEventCount)).toStrictEqual(line) }) - it('rejects a v3 physical header without explicit isSeeded', () => { + it('rejects a current physical header without explicit isSeeded', () => { const { isSeeded: _isSeeded, ...line } = toHeaderLine(meta('missing-is-seeded')) expect(() => scanLog(Buffer.from(`${JSON.stringify(line)}\n`))).toThrow(/session header/) }) @@ -698,7 +698,6 @@ describe('JsonlSessionPersistence: immutable format generations', () => { afterEach(async () => { await ctx.fiber.dispose() }) it('projects a released v0 header through stat and list without reading or mutating its body', async () => { - expect(SESSION_FORMAT_VERSION).toBe(3) const header = meta('released-v0-metadata', '/work') const sourcePath = historicalLogPath(root, header.cwd, header.id) const currentPath = rawLogPath(root, header.cwd, header.id) @@ -972,12 +971,12 @@ describe('JsonlSessionPersistence: immutable format generations', () => { .toEqual(['session.v1.jsonl']) }) - it('selects v1 from a v0/v1 directory, then v3 from the retained three-generation set', async () => { + it('selects v1 from a v0/v1 directory, then the current generation from the retained three-generation set', async () => { const header = meta('mixed-generation-read', '/work') const directory = sessionDir(root, header.cwd, header.id) const v0Path = historicalLogPath(root, header.cwd, header.id) const v1Path = generationLogPath(root, header.cwd, header.id, 1, 'none') - const v3Path = rawLogPath(root, header.cwd, header.id) + const currentPath = rawLogPath(root, header.cwd, header.id) await mkdir(directory, { recursive: true }) await writeFile(v0Path, `${JSON.stringify(releasedV0Header(header))}\n`) await writeFile(v1Path, releasedV1PackedPhysicalLog(header)) @@ -988,13 +987,13 @@ describe('JsonlSessionPersistence: immutable format generations', () => { await writer.close() expect((await readdir(directory)).filter(name => name.startsWith('session')).sort()) .toEqual(process.platform === 'win32' - ? ['session.jsonl', 'session.v1.jsonl', 'session.v3.jsonl'] - : ['session.jsonl', 'session.lock', 'session.v1.jsonl', 'session.v3.jsonl']) + ? ['session.jsonl', 'session.v1.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`] + : ['session.jsonl', 'session.lock', 'session.v1.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) await writeFile(v0Path, 'corrupt lower v0\n') await writeFile(v1Path, 'corrupt lower v1\n') await expect(readAll(ctx.sessionPersistence, header.id)).resolves.toEqual(migrated) - expect(await readFile(v3Path, 'utf8')).toContain('"version":3') + expect(await readFile(currentPath, 'utf8')).toContain(`"version":${SESSION_FORMAT_VERSION}`) }) it('does not publish a historical generation through handle storage resolution', async () => { @@ -1073,7 +1072,7 @@ describe('JsonlSessionPersistence: immutable format generations', () => { const writer = await ctx.sessionPersistence.open(header.id, 'write') await writer.close() expect(await readFile(sourcePath, 'utf8')).toBe(`${source}\n`) - expect(await readFile(currentPath, 'utf8')).toContain('"version":3') + expect(await readFile(currentPath, 'utf8')).toContain(`"version":${SESSION_FORMAT_VERSION}`) }) it('finishes publication before rejecting a write open cancelled during publication', async () => { @@ -1089,7 +1088,7 @@ describe('JsonlSessionPersistence: immutable format generations', () => { await expect(ctx.sessionPersistence.open(header.id, 'write', { signal: controller.signal })) .rejects.toBe(reason) - expect(await readFile(currentPath, 'utf8')).toContain('"version":3') + expect(await readFile(currentPath, 'utf8')).toContain(`"version":${SESSION_FORMAT_VERSION}`) const writer = await ctx.sessionPersistence.open(header.id, 'write') await writer.close() }) @@ -2012,7 +2011,7 @@ describe('JsonlSessionPersistence: scanLog unit', () => { expect(restored).toMatchObject({ type: 'user/message', surfaceOp: 'append', sourceEventSeqs: [0, 1] }) }) - it('requires the tagged inherited cut to agree with the v3 header lineage', () => { + it('requires the tagged inherited cut to agree with the current header lineage', () => { const seeded = { ...meta('scanner-seeded-cut'), isSeeded: true } const seededHeader = JSON.stringify(toHeaderLine(seeded, SessionLogOffset(0))) expect(() => scanLog(Buffer.from(`${seededHeader}\n`))) @@ -2234,7 +2233,7 @@ describe('JsonlSessionPersistence: scanLog unit', () => { }) }) -describe('JsonlSessionPersistence: nested v3 Assistant streams', () => { +describe('JsonlSessionPersistence: nested Assistant streams', () => { let ctx: Context beforeEach(async () => { root = await freshRoot() @@ -2287,7 +2286,7 @@ describe('JsonlSessionPersistence: nested v3 Assistant streams', () => { expect(loaded.events).toEqual(log) }) - it.each([2, 3])('reads v%s rows and appends a v3 turn without changing predecessor bytes', async (version) => { + it.each([2, 3])('reads v%s rows and appends a current turn without changing predecessor bytes', async (version) => { const m = meta('mixed', '/work') const log = chunkRunLog() const sourcePath = generationLogPath(root, '/work', m.id, version, 'none') @@ -2304,10 +2303,10 @@ describe('JsonlSessionPersistence: nested v3 Assistant streams', () => { const expected = version === 2 ? withMigratedEmptyHead(log) : log const restored = await readAll(ctx.sessionPersistence, m.id) - expect(restored.meta.version).toBe(3) + expect(restored.meta.version).toBe(SESSION_FORMAT_VERSION) expect(restored.events).toEqual(expected) expect(await readFile(sourcePath)).toEqual(source) - if (version === 2) await expect(readFile(currentPath)).rejects.toMatchObject({ code: 'ENOENT' }) + await expect(readFile(currentPath)).rejects.toMatchObject({ code: 'ENOENT' }) const secondTurn: SessionEvent[] = JSON.parse(JSON.stringify(log)) as SessionEvent[] for (const [k, e] of secondTurn.entries()) { ;(e as { seq: number }).seq = expected.length + k @@ -2317,11 +2316,11 @@ describe('JsonlSessionPersistence: nested v3 Assistant streams', () => { const loaded = await readAll(ctx.sessionPersistence, m.id) expect(loaded.events).toEqual([...expected, ...secondTurn]) - expect(currentPath).toBe(join(dirname(sourcePath), 'session.v3.jsonl')) + expect(currentPath).toBe(join(dirname(sourcePath), `session.v${SESSION_FORMAT_VERSION}.jsonl`)) const successor = (await readFile(currentPath, 'utf8')).trimEnd().split('\n') - expect(JSON.parse(successor[0] as string)).toMatchObject({ version: 3 }) + expect(JSON.parse(successor[0] as string)).toMatchObject({ version: SESSION_FORMAT_VERSION }) expect(successor.slice(1).map(row => JSON.parse(row) as unknown)).toEqual([...expected, ...secondTurn]) - if (version === 2) expect(await readFile(sourcePath)).toEqual(source) + expect(await readFile(sourcePath)).toEqual(source) // Compact tags stay nested; physical rows contain only current event tags. const tags = (await readFile(rawLogPath(root, '/work', m.id), 'utf8')).split('\n').filter(Boolean) .map(line => (JSON.parse(line) as { type: string }).type) diff --git a/packages/session/session-persistence-jsonl/tests/migration-refusal.spec.ts b/packages/session/session-persistence-jsonl/tests/migration-refusal.spec.ts index b8d4bb5542..24f3844a62 100644 --- a/packages/session/session-persistence-jsonl/tests/migration-refusal.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/migration-refusal.spec.ts @@ -1,7 +1,7 @@ -/** Durable EOF refusals preserve historical generations and never fall back from native V3. */ +/** Durable EOF refusals preserve historical generations and never fall back from the selected generation. */ import { Context } from '@deepseek-ai/cordis' -import { SessionId } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' import type { SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' import { SessionFormatUnsupportedError } from '@deepseek-ai/dsh-session-persistence' import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' @@ -116,7 +116,11 @@ function line(value: unknown): string { return JSON.stringify(value) + '\n' } -async function store(version: 2 | 3, compression: JsonlCompression, rows: readonly SessionFormatJsonObject[]) { +async function store( + version: 2 | 3 | typeof SESSION_FORMAT_VERSION, + compression: JsonlCompression, + rows: readonly SessionFormatJsonObject[], +) { const path = generationLogPath(root, undefined, id, version, compression) const header = { type: 'session', version, id, createdAt: 1000, isSeeded: false, delegationDepth: 0 } const events = rows.map((row, seq) => ({ ...row, seq, time: 1001 + seq })) @@ -162,38 +166,43 @@ describe.each(modes)('EOF migration refusal ($compression, $access)', ({ compres expect(await observe(path)).toEqual(original) await expectOnlyGenerations([path]) for (const targetCompression of ['none', 'zstd'] as const) { - await expect(stat(generationLogPath(root, undefined, id, 3, targetCompression))) - .rejects.toMatchObject({ code: 'ENOENT' }) + for (const targetVersion of [3, SESSION_FORMAT_VERSION]) { + await expect(stat(generationLogPath(root, undefined, id, targetVersion, targetCompression))) + .rejects.toMatchObject({ code: 'ENOENT' }) + } } } }) - it.each(nativeRefusals)('refuses native V3 $name instead of falling back to readable V2', async ({ tail, diagnostic }) => { - const lowerPath = await store(2, compression, prefix) - const lower = await observe(lowerPath) - const ctx = await mount(compression) - const reader = await ctx.sessionPersistence.open(id, 'read') - try { - expect(reader.header.version).toBe(3) - const restored = await reader.read() - expect(restored.events.map(event => event.type)).toEqual([ - 'turn/start', 'step/start', 'system/message', 'user/message', 'system/message', 'request/header', - ]) - expect(restored.events.find(event => event.type === 'user/message')?.data).toEqual(question) - } finally { - await reader.close() - } - expect(await observe(lowerPath)).toEqual(lower) - await expectOnlyGenerations([lowerPath]) - - const path = await store(3, compression, [...nativePrefix, tail]) - const original = await observe(path) - const message = diagnostic + ' (raw log: ' + path + ')' - for (let attempt = 0; attempt < 2; attempt += 1) { - await expectRefusal(ctx, access, path, message) - expect(await observe(path)).toEqual(original) + it.each(nativeRefusals.flatMap(refusal => ([3, SESSION_FORMAT_VERSION] as const).map(version => ({ ...refusal, version }))))( + 'refuses V$version $name instead of falling back to readable V2', async ({ tail, diagnostic, version }) => { + const lowerPath = await store(2, compression, prefix) + const lower = await observe(lowerPath) + const ctx = await mount(compression) + const reader = await ctx.sessionPersistence.open(id, 'read') + try { + expect(reader.header.version).toBe(SESSION_FORMAT_VERSION) + const restored = await reader.read() + expect(restored.events.map(event => event.type)).toEqual([ + 'turn/start', 'step/start', 'system/message', 'user/message', 'system/message', 'request/header', + ]) + expect(restored.events.find(event => event.type === 'user/message')?.data).toEqual(question) + } finally { + await reader.close() + } expect(await observe(lowerPath)).toEqual(lower) - await expectOnlyGenerations([lowerPath, path]) - } - }) + await expectOnlyGenerations([lowerPath]) + + const path = await store(version, compression, [...nativePrefix, tail]) + const original = await observe(path) + const message = diagnostic + (version < SESSION_FORMAT_VERSION ? `; source v${version} artifact remains unchanged` : '') + + ' (raw log: ' + path + ')' + for (let attempt = 0; attempt < 2; attempt += 1) { + await expectRefusal(ctx, access, path, message) + expect(await observe(path)).toEqual(original) + expect(await observe(lowerPath)).toEqual(lower) + await expectOnlyGenerations([lowerPath, path]) + } + }, + ) }) diff --git a/packages/session/session-persistence-jsonl/tests/multi-edge-publication.spec.ts b/packages/session/session-persistence-jsonl/tests/multi-edge-publication.spec.ts index 9be35ec1bf..b081b39d73 100644 --- a/packages/session/session-persistence-jsonl/tests/multi-edge-publication.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/multi-edge-publication.spec.ts @@ -1,7 +1,7 @@ /** Durable composition of historical chunk collapse and V3 system/reference migration. */ import { Context } from '@deepseek-ai/cordis' -import { Session, SessionId, SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, Session, SessionId, SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session' import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session' import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format' import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, sessionFormatV0ToV1 } from '@deepseek-ai/dsh-session-format-v0-to-v1' @@ -150,7 +150,7 @@ function assertRequests(events: readonly SessionEvent[], header: SessionHeader) function assertMigrated(result: Awaited>) { const { events, header, cut, session } = result - expect(header).toEqual({ version: 3, id, createdAt: 1, parentSession: 'parent', delegationDepth: 0, isSeeded: true }) + expect(header).toEqual({ version: SESSION_FORMAT_VERSION, id, createdAt: 1, parentSession: 'parent', delegationDepth: 0, isSeeded: true }) expect(events.map(event => event.seq)).toEqual(Array.from({ length: 23 }, (_, seq) => seq)) expect(events.filter(event => event.type.startsWith('assistant/'))).toEqual([{ type: 'assistant/message', seq: 6, time: 108, surfaceOp: 'append', @@ -200,7 +200,7 @@ async function publishedRows(path: string, compression: JsonlCompression) { } describe.each([0, 1] as const)('V%s multi-edge durable publication', (version) => { - it.each(['none', 'zstd'] as const)('publishes only V3 after chunk collapse, system changes, and reference remapping (%s)', async (compression) => { + it.each(['none', 'zstd'] as const)('publishes only the current generation after chunk collapse, system changes, and reference remapping (%s)', async (compression) => { const { root, path } = await seed(version, compression) const source = await observe(path) const ctx = await mount(root, compression) @@ -215,7 +215,7 @@ describe.each([0, 1] as const)('V%s multi-edge durable publication', (version) = expect(written.events).toEqual(prepared.events) await ctx.fiber.dispose() contexts.splice(contexts.indexOf(ctx), 1) - const successor = generationLogPath(root, undefined, id, 3, compression) + const successor = generationLogPath(root, undefined, id, SESSION_FORMAT_VERSION, compression) expect((await readdir(dirname(path))).filter(name => name !== 'session.lock').sort()) .toEqual([basename(path), basename(successor)].sort()) expect(await publishedRows(successor, compression)).toEqual([{ type: 'session', ...prepared.header }, ...prepared.events]) @@ -263,7 +263,7 @@ describe.each([0, 1] as const)('V%s multi-edge durable publication', (version) = expect(retried.events).toEqual(expected) expect(retried.cut).toBe(prepared.cut) assertRequests(retried.events, retried.header) - const successor = generationLogPath(root, undefined, id, 3, compression) + const successor = generationLogPath(root, undefined, id, SESSION_FORMAT_VERSION, compression) expect(await publishedRows(successor, compression)).toEqual([{ type: 'session', ...prepared.header }, ...expected]) expect((await readdir(dirname(path))).filter(name => name !== 'session.lock').sort()) .toEqual([basename(path), basename(successor)].sort()) diff --git a/packages/session/session-persistence-jsonl/tests/v2-ptc-migration.spec.ts b/packages/session/session-persistence-jsonl/tests/v2-ptc-migration.spec.ts index e22acf4aef..e53e646f23 100644 --- a/packages/session/session-persistence-jsonl/tests/v2-ptc-migration.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/v2-ptc-migration.spec.ts @@ -1,7 +1,7 @@ /** Real JSONL publication and provider-neutral message preservation across the V2 PTC rename. */ import { Context } from '@deepseek-ai/cordis' -import { Session, SessionId } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, Session, SessionId } from '@deepseek-ai/dsh-session' import type { SessionFormatEvent } from '@deepseek-ai/dsh-session-format' import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' import { createHash } from 'node:crypto' @@ -117,21 +117,21 @@ describe('JSONL V2 PTC publication and restore', () => { } }) - it('publishes V3 without changing V2 bytes and preserves restored IDs, roles, content, and replay state', async () => { + it('publishes the current generation without changing V2 bytes and preserves restored IDs, roles, content, and replay state', async () => { if (root === undefined || ctx === undefined) throw new Error('persistence fixture is not initialized') const id = SessionId('tools-code-mode:session') const header = { type: 'session', version: 2, id, createdAt: 1000, isSeeded: false, delegationDepth: 0 } const events = releasedV2Events() const source = Buffer.from([header, ...events].map(row => JSON.stringify(row)).join('\n') + '\n') const predecessor = generationLogPath(root, undefined, id, 2, 'none') - const successor = join(dirname(predecessor), 'session.v3.jsonl') + const successor = join(dirname(predecessor), `session.v${SESSION_FORMAT_VERSION}.jsonl`) await mkdir(dirname(predecessor), { recursive: true }) await writeFile(predecessor, source) const sourceStat = await stat(predecessor) const reader = await ctx.sessionPersistence.open(id, 'read') try { - expect(reader.header).toEqual({ version: 3, id, createdAt: 1000, isSeeded: false, delegationDepth: 0 }) + expect(reader.header).toEqual({ version: SESSION_FORMAT_VERSION, id, createdAt: 1000, isSeeded: false, delegationDepth: 0 }) expect((await reader.read()).events.map(event => event.type)).toEqual([ 'turn/start', 'step/start', 'system/message', 'user/message', 'assistant/message', 'tool/call', 'tool/ptc-dispatch-start', 'tool/ptc-dispatch', 'tool/result', 'agent/inbox/spliced', @@ -153,7 +153,7 @@ describe('JSONL V2 PTC publication and restore', () => { const published = await readFile(successor) const [publishedHeader, ...publishedEvents] = published.toString('utf8').trimEnd().split('\n') .map((row): unknown => JSON.parse(row)) - expect(publishedHeader).toEqual({ ...header, version: 3 }) + expect(publishedHeader).toEqual({ ...header, version: SESSION_FORMAT_VERSION }) const expectedEvents: SessionFormatEvent[] = events.map(event => ({ ...event, seq: event.seq < 2 ? event.seq : event.seq + 1 })) expectedEvents[5] = { ...expectedEvents[5], type: 'tool/ptc-dispatch-start' } as SessionFormatEvent expectedEvents[6] = { ...expectedEvents[6], type: 'tool/ptc-dispatch' } as SessionFormatEvent @@ -201,6 +201,6 @@ describe('JSONL V2 PTC publication and restore', () => { expect(await stat(predecessor)).toMatchObject({ dev: sourceStat.dev, ino: sourceStat.ino }) expect(await readFile(successor)).toEqual(published) expect((await readdir(dirname(predecessor))).filter(name => name.endsWith('.jsonl')).sort()) - .toEqual(['session.v2.jsonl', 'session.v3.jsonl']) + .toEqual(['session.v2.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) }) }) diff --git a/packages/session/session-persistence-jsonl/tests/v2-system-migration.spec.ts b/packages/session/session-persistence-jsonl/tests/v2-system-migration.spec.ts index b8a7fad132..300eee0a76 100644 --- a/packages/session/session-persistence-jsonl/tests/v2-system-migration.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/v2-system-migration.spec.ts @@ -1,6 +1,6 @@ import { freezeMessage, MessageId } from '@deepseek-ai/dsh-llm' import { Context } from '@deepseek-ai/cordis' -import { Session, SessionId, SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session' +import { SESSION_FORMAT_VERSION, Session, SessionId, SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session' import type { SessionEvent } from '@deepseek-ai/dsh-session' import { SessionFormatUnsupportedError } from '@deepseek-ai/dsh-session-persistence' import type { SessionHandle } from '@deepseek-ai/dsh-session-persistence' @@ -95,7 +95,7 @@ function assertRequestHistory(events: readonly SessionEvent[], handle: SessionHa } describe('V2 system prompts through current Session and JSONL persistence', () => { - it.each([undefined, ''])('prepares prompts and clear (%j) read-only, then publishes V3 without replacing V2', async (clear) => { + it.each([undefined, ''])('prepares prompts and clear (%j) read-only, then publishes the current generation without replacing V2', async (clear) => { const sourcePath = await writeV2([ { type: 'turn/start', data: { turn: 1 } }, { type: 'step/start', data: { turn: 1, step: 1 } }, @@ -110,7 +110,7 @@ describe('V2 system prompts through current Session and JSONL persistence', () = const reader = await ctx.sessionPersistence.open(id, 'read') let prepared: readonly SessionEvent[] try { - expect(reader.header.version).toBe(3) + expect(reader.header.version).toBe(SESSION_FORMAT_VERSION) prepared = (await reader.read()).events expect(prepared.map(event => event.seq)).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) expect(prepared.filter(event => event.type !== 'system/message').map(event => [event.type, event.time])).toEqual([ @@ -156,10 +156,10 @@ describe('V2 system prompts through current Session and JSONL persistence', () = } expect(await observeFile(sourcePath)).toEqual(original) expect((await readdir(directory)).filter(name => name.endsWith('.jsonl')).sort()) - .toEqual(['session.v2.jsonl', 'session.v3.jsonl']) - const publishedPath = generationLogPath(root, undefined, id, 3, 'none') + .toEqual(['session.v2.jsonl', `session.v${SESSION_FORMAT_VERSION}.jsonl`]) + const publishedPath = generationLogPath(root, undefined, id, SESSION_FORMAT_VERSION, 'none') const published = (await readFile(publishedPath, 'utf8')).trimEnd().split('\n').map(line => JSON.parse(line) as unknown) - expect(published[0]).toMatchObject({ type: 'session', version: 3, id }) + expect(published[0]).toMatchObject({ type: 'session', version: SESSION_FORMAT_VERSION, id }) expect(published.slice(1)).toEqual(prepared) const reopened = await mount() @@ -268,7 +268,7 @@ describe('V2 system prompts through current Session and JSONL persistence', () = .toEqual(['session.v1.jsonl', 'session.v2.jsonl']) }) - it('persists native V3 system appends after the protected head without converting them to user messages', async () => { + it('persists current system appends after the protected head without converting them to user messages', async () => { const ctx = await mount() const session = Session.create(id) const writer = await ctx.sessionPersistence.create(session.header) diff --git a/packages/session/session-persistence-jsonl/tsconfig.json b/packages/session/session-persistence-jsonl/tsconfig.json index 393ada381f..d3484120a6 100644 --- a/packages/session/session-persistence-jsonl/tsconfig.json +++ b/packages/session/session-persistence-jsonl/tsconfig.json @@ -36,7 +36,7 @@ "path": "../session-format-catalog" }, { - "path": "../session-format-v2-to-v3" + "path": "../session-format-v3-to-v4" } ] } diff --git a/packages/test-support/llm-replay/tests/llm-replay.spec.ts b/packages/test-support/llm-replay/tests/llm-replay.spec.ts index 816d9c30a6..251ce14062 100644 --- a/packages/test-support/llm-replay/tests/llm-replay.spec.ts +++ b/packages/test-support/llm-replay/tests/llm-replay.spec.ts @@ -61,7 +61,7 @@ const COMPACTION_ID = CompactionId('replay-compaction') /** Build a minimal session-JSONL string: a header line + the given events. */ function sessionJsonl( events: SessionEvent[], - header?: { id?: string; createdAt?: number; seedLength?: number; version?: 0 | 1 | 2 | 3 }, + header?: { id?: string; createdAt?: number; seedLength?: number; version?: 0 | 1 | 2 | 3 | 4 }, ): string { const version = header?.version ?? 0 const headerLine = JSON.stringify({ @@ -79,7 +79,7 @@ function sessionJsonl( /** Build a valid one-turn Session around recorded model calls. */ function replaySessionJsonl( calls: readonly StreamChunk[][], - header?: { id?: string; createdAt?: number; seedLength?: number; version?: 0 | 1 | 2 | 3 }, + header?: { id?: string; createdAt?: number; seedLength?: number; version?: 0 | 1 | 2 | 3 | 4 }, ): string { const version = header?.version ?? SESSION_FORMAT_VERSION const events: SessionEvent[] = [] diff --git a/packages/test-support/session-snapshot/README.i18n.yaml b/packages/test-support/session-snapshot/README.i18n.yaml index 9c31a25c34..6e47c654a5 100644 --- a/packages/test-support/session-snapshot/README.i18n.yaml +++ b/packages/test-support/session-snapshot/README.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 packages/test-support/session-snapshot/README.md -README.md: 51aaff9af7dfce83ed032b42ce0bb471aa384002 -README.zh.md: ad136b19a75170c130bbb872ba02bb88e010bb02 +README.md: 14305a6a27de79690537895a632f9796b4b7d17b +README.zh.md: 7e3d8db31f67a670b026bc4e95eb8e481a2f95eb diff --git a/packages/test-support/session-snapshot/README.md b/packages/test-support/session-snapshot/README.md index 51aaff9af7..14305a6a27 100644 --- a/packages/test-support/session-snapshot/README.md +++ b/packages/test-support/session-snapshot/README.md @@ -68,13 +68,13 @@ defineAcpSnapshotSuite({ }) ``` -Each recorded-session directory carries a closed `snapshot.yml` manifest plus canonical parent and contiguous child roles. Parent filenames are `session[.vN].jsonl`; children are `session.[.vN].jsonl`; v0 omits `.v0`, positive versions use lowercase `.vN`, and every filename agrees with its header. A role may retain older generations, but the harness selects the numerically highest one. An owning manifest may declare `sessionFormat.version` plus one or more closed `coverage` names to keep that historical generation as an explicit migration fixture; absence tracks the current writer. The manifest also names the scenario, shipped profile, composition/header class, recording source, and only the replay, platform, permission, environment, workspace, or input facts the completed Session cannot reconstruct. Storage guards check tool results and portable paths in every selected parent and child role. Prompt/schema scrubbing, message identity, and prompt-before-request ordering apply to current generations; retained predecessors keep their historical representation. The adapter registers expected-output, Session-log, and optional `workspace.expected/` comparisons; guards reject orphan directories, missing roles, noncanonical names, absolute paths, malformed manifests, and platform-specific separators. +Each recorded-session directory carries a closed `snapshot.yml` manifest plus canonical parent and contiguous child roles. Parent filenames are `session[.vN].jsonl`; children are `session.[.vN].jsonl`; v0 omits `.v0`, positive versions use lowercase `.vN`, and every filename agrees with its header. A role may retain older generations, but the harness selects the numerically highest one. An owning manifest may declare `sessionFormat.version` plus one or more closed `coverage` names to keep that historical generation as an explicit migration fixture. Without that declaration, record and refresh write the current generation; replay also accepts the retained V3 baseline under the [corpus policy](../../../snapshots/AGENTS.md). The manifest also names the scenario, shipped profile, composition/header class, recording source, and only the replay, platform, permission, environment, workspace, or input facts the completed Session cannot reconstruct. Storage guards check tool results and portable paths in every selected parent and child role. Prompt/schema scrubbing, message identity, and prompt-before-request ordering apply to current generations; retained predecessors keep their historical representation. The adapter registers expected-output, Session-log, and optional `workspace.expected/` comparisons; guards reject orphan directories, missing roles, noncanonical names, absolute paths, malformed manifests, and platform-specific separators. `normalizeSessionSnapshot` retains the complete Session header and event payloads but omits top-level `seq`/`time` envelopes from committed fixtures after normalizing paths and scrubbing system-prompt text and tool schemas; it also normalizes embedded stream clocks and historical packed-row `seq0`/`time0` envelopes, and catalog child-creation clocks. Event order and source-event references are preserved. Replay synthesizes the top-level envelopes in memory, while runtime persistence continues to write complete logs. Multi-session comparison validates expected and harvested logs through the strict build-static Session format catalog before identity redaction and normalization; source filenames cannot alter format validation. A retained historical replay input is not the native current-format writer-output oracle: structural migration preserves request meaning but can produce a different event layout. Normalization preserves unexpected request-header fields, including `system`, so regressions remain visible. Versionless protocol-adapter unit fixtures remain outside the released Session format corpus. Fixtures in the [current writer format](../../../docs/session-format-status.md) use one row per event; retained v0/v1 fixtures may use canonical packed rows. The [temporary repository migrator](../../../scripts/migrate-packed-session-fixtures.ts) (`pnpm run migrate:packed-session-fixtures`) rewrites older historical layouts, and its [removal proposal](../../../.agents/notes/proposed/process/2026-07-26-remove-packed-session-fixture-migrator.md) owns its deletion. Spill scenarios save through the real local provider under a private temporary root. Their fixture adapter exposes fixed-length logical locators and maps only this run’s saved locators back to real files for retrieval, preserving preview budgets without writing into a shared logical path. Known snapshot spill paths normalize to stable locator tokens, including paths quoted inside JSON omission notices with JSON-escaped Windows separators. Refresh extraction preserves the matched serialized path spelling for literal replacement. Normalization changes only the locator: saved byte lengths and omission counts remain comparison evidence. -Retained historical scenarios keep their canonical Session files unchanged and selected for replay, with no newer canonical sibling in the pinned directory. Their exact normalized native current-format output is recorded separately in `writer.expected.jsonl` for the parent and `writer..expected.jsonl` for children; these are output oracles, not replay generations. Retained SDK scenarios use `notifications.current.expected.jsonl` for current protocol output. Comparisons neither project current events back into a historical format nor strip structural differences. Independent migration tests verify the official transform rather than treating native writer layout as its expected event sequence. +Retained historical scenarios keep their canonical Session files unchanged and selected for replay, with no newer canonical sibling in the pinned directory. Their exact normalized native writer output is recorded separately in `writer.expected.jsonl` for the parent and `writer..expected.jsonl` for children; these are output oracles, not replay generations. Output oracles may retain an older supported generation: comparison restores them through the strict catalog, while harvested logs must use the checkout writer. Fresh-writer golden comparisons select `nativeWriterOutput` to tokenize only delivery markers qualified by each input’s original writer generation after strict restoration. Other delivery generations and captured-source fields remain numeric; source-versus-migrated-artifact comparisons preserve exact generations by default. Recording and refresh never store these comparison tokens. Retained SDK scenarios use `notifications.current.expected.jsonl` for current protocol output. Comparisons neither project current events back into a historical format nor strip structural differences. Independent migration tests verify the official transform rather than treating native writer layout as its expected event sequence. ### Record, replay, and refresh diff --git a/packages/test-support/session-snapshot/README.zh.md b/packages/test-support/session-snapshot/README.zh.md index ad136b19a7..7e3d8db31f 100644 --- a/packages/test-support/session-snapshot/README.zh.md +++ b/packages/test-support/session-snapshot/README.zh.md @@ -68,13 +68,13 @@ defineAcpSnapshotSuite({ }) ``` -每个已记录 Session 目录携带封闭的 `snapshot.yml` manifest,以及规范 parent 与连续 child 角色。parent 文件名是 `session[.vN].jsonl`;child 是 `session.[.vN].jsonl`;v0 省略 `.v0`,正版本使用小写 `.vN`,且每个文件名与其 header 一致。一个角色可以保留旧 generation,但 harness 会选择数值最高的一项。拥有 fixture 的 manifest 可以声明 `sessionFormat.version` 与一个或多个封闭 `coverage` 名称,把该历史 generation 保留为显式迁移 fixture;省略此字段时跟随当前 writer。manifest 还会指名场景、随附 profile、组合/header 类别、录制来源,以及已完成 Session 无法重建的 replay、平台、权限、环境、workspace 或输入事实。存储保护检查每个选定 parent 与 child 角色的工具结果和可移植路径。提示词/schema 擦除、消息身份及提示词先于请求的顺序检查适用于当前 generation;保留的前代维持其历史表示。适配器注册预期输出、Session 日志与可选 `workspace.expected/` 比较;保护会拒绝遗留目录、缺失角色、非规范名称、绝对路径、格式错误的 manifest 与平台专用分隔符。 +每个已记录 Session 目录携带封闭的 `snapshot.yml` manifest,以及规范 parent 与连续 child 角色。parent 文件名是 `session[.vN].jsonl`;child 是 `session.[.vN].jsonl`;v0 省略 `.v0`,正版本使用小写 `.vN`,且每个文件名与其 header 一致。一个角色可以保留旧 generation,但 harness 会选择数值最高的一项。拥有 fixture 的 manifest 可以声明 `sessionFormat.version` 与一个或多个封闭 `coverage` 名称,把该历史 generation 保留为显式迁移 fixture。未声明时,record 与 refresh 写入当前 generation;replay 也按[语料策略](../../../snapshots/AGENTS.md)接受保留的 V3 基线。manifest 还会指名场景、随附 profile、组合/header 类别、录制来源,以及已完成 Session 无法重建的 replay、平台、权限、环境、workspace 或输入事实。存储保护检查每个选定 parent 与 child 角色的工具结果和可移植路径。提示词/schema 擦除、消息身份及提示词先于请求的顺序检查适用于当前 generation;保留的前代维持其历史表示。适配器注册预期输出、Session 日志与可选 `workspace.expected/` 比较;保护会拒绝遗留目录、缺失角色、非规范名称、绝对路径、格式错误的 manifest 与平台专用分隔符。 `normalizeSessionSnapshot` 在规范化路径并擦除系统提示文本与工具 schema 后,会保留完整 Session header 与事件 payload,但从已提交 fixture 中省略顶层 `seq`/`time` envelope;它还会规范化嵌入式 stream clock 与历史 packed-row 的 `seq0`/`time0` envelope 与 catalog child 创建时钟。事件顺序与来源事件引用保持不变。Replay 只在内存中合成顶层 envelope,而运行时持久化仍写入完整日志。多 Session 比较会先通过严格的构建期静态 Session 格式目录校验预期日志与收集日志,再进行身份脱敏与规范化;来源文件名不能改变格式校验。保留的历史 replay 输入不是原生当前格式 writer 输出的比较基准:结构迁移保留请求含义,但可以产生不同的事件布局。归一化保留意外的 request-header 字段(包括 `system`),使回归保持可见。无版本的协议适配器单元测试 fixture 不属于已发布 Session 格式语料。[当前写入器格式](../../../docs/session-format-status.zh.md)的 fixture 每个事件占一行;保留的 v0/v1 fixture 可以使用规范 packed row。[临时仓库迁移器](../../../scripts/migrate-packed-session-fixtures.ts)(`pnpm run migrate:packed-session-fixtures`)会改写更旧的历史布局,由其[移除提案](../../../.agents/notes/proposed/process/2026-07-26-remove-packed-session-fixture-migrator.zh.md)负责删除该迁移器。 spill 场景通过真实本地提供方保存到私有临时根目录。fixture 适配器提供固定长度的逻辑定位符,并仅将本次运行已保存的定位符映射回实际文件以供检索,在不写入共享逻辑路径的情况下保留预览预算。已知的快照 spill 路径会规范化为稳定的定位符 token,包括 JSON 省略通知中带引号、使用 JSON 转义 Windows 分隔符的路径。刷新提取会保留匹配路径的序列化写法,以便进行字面替换。规范化只改变定位符:保存字节数与省略计数仍作为比较证据。 -保留历史输入的场景保持规范 Session 文件不变,并继续选择它们进行回放;固定历史版本的目录中没有更新的规范同角色文件。其精确的规范化原生当前格式输出单独记录在父会话的 `writer.expected.jsonl` 和子会话的 `writer..expected.jsonl` 中;这些是输出比较基准,而非 replay 代际。保留历史输入的 SDK 场景使用 `notifications.current.expected.jsonl` 记录当前协议输出。比较既不将当前事件反向投影为历史格式,也不剥除结构差异。独立迁移测试验证正式转换,而不把原生 writer 布局当作其预期事件序列。 +保留历史输入的场景保持规范 Session 文件不变,并继续选择它们进行回放;固定历史版本的目录中没有更新的规范同角色文件。其精确的规范化原生 writer 输出单独记录在父会话的 `writer.expected.jsonl` 和子会话的 `writer..expected.jsonl` 中;这些是输出比较基准,而非 replay 代际。输出比较基准可以保留较旧的受支持代际:比较通过严格 catalog 恢复它们,而收集的日志必须使用当前检出版本的 writer。新 writer 输出的 golden 比较选择 `nativeWriterOutput`,仅在严格恢复后,将版本限定为各输入原始 writer 代际的 delivery 标记转换为 token。其他 delivery 代际与 captured-source 字段保持数值;源文件与已迁移产物的比较默认保留精确代际。record 与 refresh 从不存储这些比较 token。保留历史输入的 SDK 场景使用 `notifications.current.expected.jsonl` 记录当前协议输出。比较既不将当前事件反向投影为历史格式,也不剥除结构差异。独立迁移测试验证正式转换,而不把原生 writer 布局当作其预期事件序列。 ### 录制、回放与刷新 diff --git a/packages/test-support/session-snapshot/src/normalize.ts b/packages/test-support/session-snapshot/src/normalize.ts index 0201030f6d..ec5702a696 100644 --- a/packages/test-support/session-snapshot/src/normalize.ts +++ b/packages/test-support/session-snapshot/src/normalize.ts @@ -11,6 +11,7 @@ import { } from '@deepseek-ai/dsh-session' import { prepareSessionSnapshotFixtureForComparison } from '@deepseek-ai/dsh-llm-replay' import { redactSessionSnapshotIds } from './identity.ts' +import { sessionHeaderVersion } from './session-files.ts' const SESSION_ID = '{{sessionId}}' const MESSAGE_ID = '{{messageId}}' @@ -20,6 +21,7 @@ const SYSTEM = '{{system}}' const TOOLS = '{{tools}}' const EVENT_TIME = '{{eventTime}}' const EVENT_OMITTED_BYTES = '{{eventOmittedBytes}}' +const SOURCE_SESSION_FORMAT = '{{sourceSessionFormatVersion}}' const PACKED_CHUNK_ROW_TYPES = new Set(['text-chunks', 'reasoning-chunks', 'tool-call-chunks']) function isPackedFixtureRow(record: Record): boolean { @@ -105,6 +107,12 @@ export interface NormalizeOptions { identityMode?: 'legacy' | 'preserve' } +/** Comparison controls for complete primary and child Session logs. */ +export interface SessionSnapshotComparisonOptions extends Omit { + /** Inputs are captured native writer output, rather than source-versus-migrated-artifact comparisons. */ + nativeWriterOutput?: true +} + /** Return every known spelling of the generated cwd, most specific first. */ function cwdSpellings(ctx: NormalizeContext): string[] { const spellings = [...new Set([ctx.cwd, ...ctx.cwdAliases ?? []])] @@ -432,41 +440,52 @@ export function normalizeSessionSnapshot( /** * Normalize one scenario's primary and child logs with shared typed identity redaction. + * Native-writer comparison strictly restores each input before tokenizing its own delivery generation. * @param rawLogs - primary-first persisted or projected session JSONL. * @param ctx - generated cwd spellings and other volatile run facts. - * @param options - separator controls; relationship-preserving identity mode is mandatory. - * @returns normalized session fixtures in input order. + * @param options - separator and native-writer comparison controls; identity relationships are preserved. + * @returns comparison-only Session records in input order; not persistence or fixture write-back input. */ export function normalizeSessionSnapshots( rawLogs: readonly string[], ctx: NormalizeContext, - options: Omit = {}, + options: SessionSnapshotComparisonOptions = {}, ): string[] { - const currentLogs = rawLogs.map(log => hasSessionFormatVersion(log) - ? prepareSessionSnapshotFixtureForComparison(log) - : log) - const comparableLogs = currentLogs.map(normalizeSessionFormatMetadata) + const { nativeWriterOutput, ...normalizeOptions } = options + const comparableLogs = rawLogs.map((log) => { + if (!hasSessionFormatVersion(log)) return normalizeSessionFormatMetadata(log) + const currentLog = prepareSessionSnapshotFixtureForComparison(log) + return normalizeSessionFormatMetadata(currentLog, nativeWriterOutput + ? sessionHeaderVersion(log, 'source Session snapshot') : undefined) + }) return redactSessionSnapshotIds(comparableLogs).map(log => projectSessionSnapshot( scrubSessionSnapshot(normalizeSessionLog( log, { ...ctx, sessionIds: [] }, - { ...options, identityMode: 'preserve' }, + { ...normalizeOptions, identityMode: 'preserve' }, )), )) } /** * Omit the artifact header generation after official migration for comparison. - * Delivery and captured-source generations retain their opaque recorded values. + * An explicit source version tokenizes only delivery markers for that original input generation. + * Other delivery generations and every captured-source generation retain their recorded values. * @param rawLog - Session records or events as compact JSON lines. - * @returns the same records with only the Session header version omitted. + * @param sourceVersion - original generation of strictly validated native writer output; otherwise omit. + * @returns comparison-only records with the Session header version omitted and native delivery qualifiers tokenized. */ -export function normalizeSessionFormatMetadata(rawLog: string): string { +export function normalizeSessionFormatMetadata(rawLog: string, sourceVersion?: number): string { return rawLog.split('\n').map((line) => { if (line.trim().length === 0) return line const record = JSON.parse(line) as Record - if (record.type !== 'session' || !Object.hasOwn(record, 'version')) return line - delete record.version + if (record.type === 'session' && Object.hasOwn(record, 'version')) { + delete record.version + } else if (sourceVersion !== undefined && record.type === 'session-log-deepseek/delivery-accepted') { + const data = record.data as Record | undefined + if (data?.sessionFormatVersion !== sourceVersion) return line + data.sessionFormatVersion = SOURCE_SESSION_FORMAT + } else return line return JSON.stringify(record) }).join('\n') } diff --git a/packages/test-support/session-snapshot/src/suite.ts b/packages/test-support/session-snapshot/src/suite.ts index dff7c45819..30f10dc213 100644 --- a/packages/test-support/session-snapshot/src/suite.ts +++ b/packages/test-support/session-snapshot/src/suite.ts @@ -1439,8 +1439,8 @@ export function defineAcpSnapshotSuite(options: SnapshotSuiteOptions): void { sessionIds: fixtureContexts.flatMap(context => context.sessionIds), cwd: (fixtureContexts[0] as NormalizeContext).cwd, } - const actualSnapshots = normalizeSessionSnapshots(harvested, ctx) - const expectedSnapshots = normalizeSessionSnapshots(fixtures, fixtureCtx) + const actualSnapshots = normalizeSessionSnapshots(harvested, ctx, { nativeWriterOutput: true }) + const expectedSnapshots = normalizeSessionSnapshots(fixtures, fixtureCtx, { nativeWriterOutput: true }) for (const [index, actual] of actualSnapshots.entries()) { expect(actual, `${fixtureFiles[index]} mismatch`).toEqual(expectedSnapshots[index]) } diff --git a/packages/test-support/session-snapshot/tests/normalize.spec.ts b/packages/test-support/session-snapshot/tests/normalize.spec.ts index be8bcb7ff4..13dd684ea3 100644 --- a/packages/test-support/session-snapshot/tests/normalize.spec.ts +++ b/packages/test-support/session-snapshot/tests/normalize.spec.ts @@ -1,4 +1,6 @@ import { describe, expect, it } from 'vitest' +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' +import { prepareSessionSnapshotFixtureForComparison } from '@deepseek-ai/dsh-llm-replay' import { type NormalizeContext, extractSnapshotSpillPaths, @@ -753,7 +755,60 @@ describe('normalizeSessionSnapshot', () => { .toThrow('session snapshot must start with a session header') }) - it('preserves delivery and captured-source generations after artifact migration', () => { + function deliveryLog(version: number, deliveryVersion = version): string { + return [ + { type: 'session', version, id: 'delivery', createdAt: 1, isSeeded: false, delegationDepth: 0 }, + { type: 'turn/start', seq: 0, time: 1, data: { turn: 1 } }, + { + type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 2, + data: { sessionId: 'delivery', throughSeq: 0, sessionFormatVersion: deliveryVersion }, + }, + ].map(record => JSON.stringify(record)).join('\n') + '\n' + } + + it('compares each strictly restored input using its own native delivery generation', () => { + const [historical, current] = normalizeSessionSnapshots( + [deliveryLog(3), deliveryLog(SESSION_FORMAT_VERSION)], ctx, { nativeWriterOutput: true }, + ) + expect(historical).toBe(current) + expect(current).toContain('"sessionFormatVersion":"{{sourceSessionFormatVersion}}"') + expect(normalizeSessionSnapshot(deliveryLog(SESSION_FORMAT_VERSION), ctx)) + .toContain(`"sessionFormatVersion":${SESSION_FORMAT_VERSION}`) + }) + + it('keeps source-versus-migrated-artifact delivery comparison generation-exact by default', () => { + const source = deliveryLog(3) + const target = prepareSessionSnapshotFixtureForComparison(source) + const [historical, migrated] = normalizeSessionSnapshots([source, target], ctx) + expect(historical).toBe(migrated) + expect(migrated).toContain('"sessionFormatVersion":3') + }) + + it('keeps a wrong native delivery generation distinguishable from historical writer output', () => { + const [historical, staleCurrent] = normalizeSessionSnapshots( + [deliveryLog(3), deliveryLog(SESSION_FORMAT_VERSION, 3)], ctx, { nativeWriterOutput: true }, + ) + expect(staleCurrent).not.toBe(historical) + expect(staleCurrent).toContain('"sessionFormatVersion":3') + }) + + it('refuses a source marker claiming the migration target before creating comparison tokens', () => { + expect(() => normalizeSessionSnapshots([deliveryLog(3, 4)], ctx, { nativeWriterOutput: true })) + .toThrow('format v3 delivery marker claims target format v4') + }) + + it('keeps captured generations and delivery lookalikes numeric in versioned inputs', () => { + const log = deliveryLog(SESSION_FORMAT_VERSION) + JSON.stringify({ + type: 'custom/event', seq: 2, time: 3, ignorable: true, + data: { capturedFormatVersion: SESSION_FORMAT_VERSION, sessionFormatVersion: SESSION_FORMAT_VERSION }, + }) + '\n' + const [normalized] = normalizeSessionSnapshots([log], ctx, { nativeWriterOutput: true }) + expect(normalized).toContain(JSON.stringify({ + capturedFormatVersion: SESSION_FORMAT_VERSION, sessionFormatVersion: SESSION_FORMAT_VERSION, + })) + }) + + it('preserves delivery and captured-source generations without a validated source generation', () => { const event = (version: number): string => JSON.stringify({ type: 'session-log-deepseek/delivery-accepted', data: { sessionId: 's', throughSeq: 4, sessionFormatVersion: version }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 015fc0c1a2..1da5093b1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9030,6 +9030,9 @@ importers: '@deepseek-ai/dsh-session-format-v2-to-v3': specifier: workspace:^ version: link:../session-format-v2-to-v3 + '@deepseek-ai/dsh-session-format-v3-to-v4': + specifier: workspace:^ + version: link:../session-format-v3-to-v4 devDependencies: '@deepseek-ai/cordis': specifier: workspace:^ @@ -9092,6 +9095,19 @@ importers: specifier: workspace:^ version: link:../../../vendor/cordis + packages/session/session-format-v3-to-v4: + dependencies: + '@deepseek-ai/dsh-session-format': + specifier: workspace:^ + version: link:../session-format + '@deepseek-ai/dsh-session-format-v2-to-v3': + specifier: workspace:^ + version: link:../session-format-v2-to-v3 + devDependencies: + '@deepseek-ai/cordis': + specifier: workspace:^ + version: link:../../../vendor/cordis + packages/session/session-log-deepseek: dependencies: '@deepseek-ai/dsh-brand': @@ -9174,9 +9190,9 @@ importers: '@deepseek-ai/dsh-session-format-catalog': specifier: workspace:^ version: link:../session-format-catalog - '@deepseek-ai/dsh-session-format-v2-to-v3': + '@deepseek-ai/dsh-session-format-v3-to-v4': specifier: workspace:^ - version: link:../session-format-v2-to-v3 + version: link:../session-format-v3-to-v4 '@deepseek-ai/node-addon-system': specifier: workspace:^ version: link:../../../native/system/packages/entry diff --git a/python/sdk/tests/test_smoke_model.py b/python/sdk/tests/test_smoke_model.py index 580114cdae..12402c01e3 100644 --- a/python/sdk/tests/test_smoke_model.py +++ b/python/sdk/tests/test_smoke_model.py @@ -14,6 +14,10 @@ from deepseek_harness import RunResult ROOT = Path(__file__).resolve().parents[3] SMOKE = runpy.run_path(ROOT / "scripts" / "smoke-python-runtime.py") +SESSION_FORMAT_VERSION = int( + (ROOT / "packages/core/session/src/types.ts").read_text(encoding="utf-8") + .split("export const SESSION_FORMAT_VERSION = ", 1)[1].splitlines()[0] +) def live_result(**overrides: object) -> RunResult: @@ -460,21 +464,22 @@ def test_snapshot_generation_names_select_highest_role_without_double_counting( } -def test_snapshot_comparison_accepts_v3_output_against_v2_without_rewriting(tmp_path: Path) -> None: +def test_snapshot_comparison_accepts_current_output_against_v2_without_rewriting(tmp_path: Path) -> None: predecessor = '{"type":"session","version":2}\n' - successor = '{"type":"session","version":3}\n' + successor = json.dumps({"type": "session", "version": SESSION_FORMAT_VERSION}) + "\n" + successor_name = f"session.v{SESSION_FORMAT_VERSION}.jsonl" old_path = tmp_path / "session.v2.jsonl" old_path.write_text(predecessor, encoding="utf-8") - files = {"session.v3.jsonl": successor} + files = {successor_name: successor} SMOKE["compare_snapshot_files"](files, False, tmp_path, ("session.v2.jsonl",)) assert old_path.read_text(encoding="utf-8") == predecessor - assert not (tmp_path / "session.v3.jsonl").exists() + assert not (tmp_path / successor_name).exists() SMOKE["compare_snapshot_files"](files, True, tmp_path, ("session.v2.jsonl",)) assert old_path.read_text(encoding="utf-8") == predecessor - assert (tmp_path / "session.v3.jsonl").read_text(encoding="utf-8") == successor - assert SMOKE["selected_snapshot_session_files"](tmp_path) == {0: tmp_path / "session.v3.jsonl"} + assert (tmp_path / successor_name).read_text(encoding="utf-8") == successor + assert SMOKE["selected_snapshot_session_files"](tmp_path) == {0: tmp_path / successor_name} @pytest.mark.parametrize("filenames", [ @@ -485,7 +490,7 @@ def test_snapshot_comparison_accepts_v3_output_against_v2_without_rewriting(tmp_ def test_snapshot_builder_checks_role_order_and_count_across_generations( tmp_path: Path, filenames: tuple[str, ...], ) -> None: - files = {"session.v3.jsonl": "", "session.1.v3.jsonl": ""} + files = {f"session.v{SESSION_FORMAT_VERSION}.jsonl": "", f"session.1.v{SESSION_FORMAT_VERSION}.jsonl": ""} with pytest.raises(AssertionError, match="snapshot builder produced"): SMOKE["compare_snapshot_files"](files, False, tmp_path, filenames) @@ -496,12 +501,14 @@ def test_snapshot_generation_comparison_rejects_changed_payload(tmp_path: Path) ) with pytest.raises(AssertionError, match="executable snapshot mismatch"): SMOKE["compare_snapshot_files"]( - {"session.v3.jsonl": '{"type":"session","version":3,"id":"changed"}\n'}, + {f"session.v{SESSION_FORMAT_VERSION}.jsonl": json.dumps({ + "type": "session", "version": SESSION_FORMAT_VERSION, "id": "changed", + }) + "\n"}, False, tmp_path, ("session.v2.jsonl",), ) -@pytest.mark.parametrize("version", [2, 4]) +@pytest.mark.parametrize("version", [SESSION_FORMAT_VERSION - 1, SESSION_FORMAT_VERSION + 1]) @pytest.mark.parametrize("update", [False, True]) def test_snapshot_comparison_rejects_noncurrent_writer( tmp_path: Path, version: int, update: bool, @@ -509,22 +516,22 @@ def test_snapshot_comparison_rejects_noncurrent_writer( golden = '{"type":"session","version":2}\n' (tmp_path / "session.v2.jsonl").write_text(golden, encoding="utf-8") content = json.dumps({"type": "session", "version": version}) + "\n" - with pytest.raises(AssertionError, match="expected current Session format v3"): + with pytest.raises(AssertionError, match=f"expected current Session format v{SESSION_FORMAT_VERSION}"): SMOKE["compare_snapshot_files"]( {f"session.v{version}.jsonl": content}, update, tmp_path, ("session.v2.jsonl",), ) assert (tmp_path / "session.v2.jsonl").read_text(encoding="utf-8") == golden - assert not (tmp_path / "session.v4.jsonl").exists() + assert not (tmp_path / f"session.v{SESSION_FORMAT_VERSION}.jsonl").exists() -@pytest.mark.parametrize("version", [2, 3, 4]) +@pytest.mark.parametrize("version", [SESSION_FORMAT_VERSION - 1, SESSION_FORMAT_VERSION, SESSION_FORMAT_VERSION + 1]) def test_persisted_session_requires_current_writer(version: int) -> None: content = json.dumps({"type": "session", "version": version}) + "\n" path = Path(f"session.v{version}.jsonl") - if version == 3: + if version == SESSION_FORMAT_VERSION: assert SMOKE["assert_persisted_session_version"](path, content) == version else: - with pytest.raises(AssertionError, match="expected current Session format v3"): + with pytest.raises(AssertionError, match=f"expected current Session format v{SESSION_FORMAT_VERSION}"): SMOKE["assert_persisted_session_version"](path, content) diff --git a/scripts/doc-standard.spec.ts b/scripts/doc-standard.spec.ts index df3f98f2ca..6c6663f286 100644 --- a/scripts/doc-standard.spec.ts +++ b/scripts/doc-standard.spec.ts @@ -73,6 +73,7 @@ const PACKAGE_LIBRARIES: Readonly> = { 'packages/session/session-format-catalog': 'Generated build-static Session format inventory with no plugin registration.', 'packages/session/session-format-v0-to-v1': 'Pure released-v0 codec and adjacent migration library.', 'packages/session/session-format-v2-to-v3': 'Pure released-v2 codec and adjacent migration library.', + 'packages/session/session-format-v3-to-v4': 'Released V3 codec reuse and adjacent migration library.', 'packages/session/session-telemetry': 'Telemetry Service Definition and capture library; providers mount the backend.', 'packages/session/session-title-llm': 'Shared LLM title-provider registration and request policy.', 'packages/subagent/subagent-in-process-driver': 'Shared one-shot child-agent driver used by provider plugins.', diff --git a/scripts/gen-session-format-catalog.ts b/scripts/gen-session-format-catalog.ts index 0ea9e151e7..7c3ca85b51 100644 --- a/scripts/gen-session-format-catalog.ts +++ b/scripts/gen-session-format-catalog.ts @@ -209,9 +209,13 @@ export function renderSessionFormatCatalog( '/** Physical codec dispatch and complete adjacent chain, independent of mounted plugins. */', 'export const sessionFormatCatalog = createSessionFormatCatalog({', ` currentVersion: ${currentVersion},`, - ` codecs: [${codecs.join(', ')}],`, + ' codecs: [', + ...codecs.map(codec => ` ${codec},`), + ' ],', ` currentEncoder: ${currentCodec},`, - ` migrations: [${declarations.map(item => item.migration).join(', ')}],`, + ' migrations: [', + ...declarations.map(item => ` ${item.migration},`), + ' ],', ' restoreCurrent(artifact) {', ` const restored = ${restorer}(artifact, KNOWN_SESSION_EVENT_TYPES)`, ' validateInstalledCurrentSessionArtifact(restored)', diff --git a/scripts/session-snapshot-corpus-policy.spec.ts b/scripts/session-snapshot-corpus-policy.spec.ts index 5b52419ecc..0b31c0262a 100644 --- a/scripts/session-snapshot-corpus-policy.spec.ts +++ b/scripts/session-snapshot-corpus-policy.spec.ts @@ -11,17 +11,18 @@ const completeV0 = { }, } as const -const adjacent = Array.from({ length: SESSION_FORMAT_VERSION - 1 }, (_, index) => ({ - key: `sdk/v${index + 1}`, - selectedVersions: [index + 1], - retained: { version: index + 1, coverage: ['adjacent-migration'] as const }, +const adjacent = [1, 2].map(version => ({ + key: `sdk/v${version}`, + selectedVersions: [version], + retained: { version, coverage: ['adjacent-migration'] as const }, })) +const baseline = { key: 'session/v3', selectedVersions: Array(8).fill(3) } const current = { key: 'session/current', selectedVersions: Array(8).fill(SESSION_FORMAT_VERSION) } describe('recorded-session corpus policy', () => { - it('accepts a current majority and complete bounded migration coverage', () => { + it('keeps a V3 majority as migration input without requiring current-generation successors', () => { expect(assertSnapshotCorpusPolicy([ - current, + baseline, { key: 'session/multi-hop', selectedVersions: [0, 0, 0], @@ -30,23 +31,33 @@ describe('recorded-session corpus policy', () => { { key: 'session/packed', selectedVersions: [0], retained: { version: 0, coverage: ['packed-row'] } }, { key: 'session/retry', selectedVersions: [0], retained: { version: 0, coverage: ['retry-failure'] } }, ...adjacent, - ])).toEqual({ currentRoles: 8, retainedRoles: 5 + adjacent.length, retainedScenarios: 3 + adjacent.length }) + ])).toEqual({ currentRoles: 0, baselineRoles: 8, retainedRoles: 5 + adjacent.length, retainedScenarios: 3 + adjacent.length }) + }) + + it('accepts current-writer owners alongside retained V3 replay input', () => { + expect(assertSnapshotCorpusPolicy([baseline, current, completeV0, ...adjacent])) + .toEqual({ currentRoles: 8, baselineRoles: 8, retainedRoles: 3, retainedScenarios: 3 }) + }) + + it('rejects refreshing away every direct V3 migration input', () => { + expect(() => assertSnapshotCorpusPolicy([current, completeV0, ...adjacent])) + .toThrow('Session corpus lacks v3 coverage: adjacent-migration') }) it('requires v0 coverage from v0 fixtures', () => { - expect(() => assertSnapshotCorpusPolicy([current, ...adjacent])) + expect(() => assertSnapshotCorpusPolicy([baseline, ...adjacent])) .toThrow('Session corpus lacks v0 coverage') }) it.each(adjacent)('requires direct coverage from $key', (fixture) => { expect(() => assertSnapshotCorpusPolicy([ - current, completeV0, ...adjacent.filter(other => other !== fixture), + baseline, completeV0, ...adjacent.filter(other => other !== fixture), ])).toThrow(`Session corpus lacks v${fixture.retained.version} coverage: adjacent-migration`) }) it('does not let one retained generation claim another edge\'s coverage', () => { expect(() => assertSnapshotCorpusPolicy([ - current, + baseline, completeV0, { key: 'sdk/adjacent', @@ -63,9 +74,16 @@ describe('recorded-session corpus policy', () => { expect(() => assertSnapshotCorpusPolicy([{ key: 'session/empty', selectedVersions: [] }])) .toThrow('session/empty: scenario owns no selected Session role') expect(() => assertSnapshotCorpusPolicy([{ key: 'session/old', selectedVersions: [1] }])) - .toThrow(`session/old: selected Session generation v1 does not match expected v${SESSION_FORMAT_VERSION}`) + .toThrow(`session/old: selected Session generation v1 must be retained baseline v3 or current v${SESSION_FORMAT_VERSION}`) expect(() => assertSnapshotCorpusPolicy([{ ...completeV0, selectedVersions: [0, SESSION_FORMAT_VERSION] }])) .toThrow(`session/v0: selected Session generation v${SESSION_FORMAT_VERSION} does not match expected v0`) + expect(() => assertSnapshotCorpusPolicy([{ ...baseline, selectedVersions: [3, SESSION_FORMAT_VERSION] }])) + .toThrow(`session/v3: selected Session generation v${SESSION_FORMAT_VERSION} does not match expected v3`) + }) + + it('rejects future unpinned generations', () => { + expect(() => assertSnapshotCorpusPolicy([{ key: 'session/future', selectedVersions: [SESSION_FORMAT_VERSION + 1] }])) + .toThrow(`session/future: selected Session generation v${SESSION_FORMAT_VERSION + 1} must be retained baseline v3 or current v${SESSION_FORMAT_VERSION}`) }) it.each([SESSION_FORMAT_VERSION, SESSION_FORMAT_VERSION + 1, -1, 0.5])( @@ -77,14 +95,15 @@ describe('recorded-session corpus policy', () => { }, ) - it('bounds historical roles and requires a current majority', () => { + it('bounds explicitly retained roles and requires a baseline/current majority', () => { expect(() => assertSnapshotCorpusPolicy([ - { ...current, selectedVersions: Array(20).fill(SESSION_FORMAT_VERSION) }, + baseline, + current, { ...completeV0, selectedVersions: Array(11).fill(0) }, ...adjacent, ])).toThrow(`Session corpus retains ${11 + adjacent.length} historical roles; maximum is 10`) expect(() => assertSnapshotCorpusPolicy([ - { ...current, selectedVersions: [SESSION_FORMAT_VERSION] }, completeV0, ...adjacent, - ])).toThrow(`Session corpus requires a current majority; current=1, retained=${1 + adjacent.length}`) + { ...baseline, selectedVersions: [3] }, completeV0, ...adjacent, + ])).toThrow(`Session corpus requires a baseline/current majority; baseline=1, current=0, retained=${1 + adjacent.length}`) }) }) diff --git a/scripts/session-snapshot-corpus-policy.ts b/scripts/session-snapshot-corpus-policy.ts index e294d98b1c..0ca43d308d 100644 --- a/scripts/session-snapshot-corpus-policy.ts +++ b/scripts/session-snapshot-corpus-policy.ts @@ -1,4 +1,4 @@ -/** Enforced current-writer majority and retained migration coverage. */ +/** Retained V3 replay inputs, current-writer fixtures, and bounded older migration coverage. */ import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import type { SnapshotSessionFormatManifest } from '@deepseek-ai/dsh-session-snapshot' @@ -16,10 +16,12 @@ export interface SnapshotCorpusScenarioGenerations { /** Counts returned after the corpus policy accepts the inventory. */ export interface SnapshotCorpusGenerationSummary { readonly currentRoles: number + readonly baselineRoles: number readonly retainedRoles: number readonly retainedScenarios: number } +const RETAINED_BASELINE_VERSION = 3 const MAX_RETAINED_ROLES = 10 const REQUIRED_V0_COVERAGE = new Set([ 'multi-hop', @@ -30,24 +32,26 @@ const REQUIRED_V0_COVERAGE = new Set([ const REQUIRED_ADJACENT_COVERAGE = new Set(['adjacent-migration']) /** - * Require a current-writer majority and bounded coverage of each released migration source. + * Require a baseline/current majority and direct coverage of each historical migration source. * * @param scenarios - Every owning top-level recorded-session scenario. - * @returns Accepted current and retained role counts. + * @returns Accepted current, baseline, and explicitly retained role counts. */ export function assertSnapshotCorpusPolicy( scenarios: readonly SnapshotCorpusScenarioGenerations[], ): SnapshotCorpusGenerationSummary { let currentRoles = 0 + let baselineRoles = 0 let retainedRoles = 0 let retainedScenarios = 0 const coverageByVersion = new Map>() for (const scenario of scenarios) { - if (scenario.selectedVersions.length === 0) { + const selectedVersion = scenario.selectedVersions[0] + if (selectedVersion === undefined) { throw new Error(`${scenario.key}: scenario owns no selected Session role`) } - const expectedVersion = scenario.retained?.version ?? SESSION_FORMAT_VERSION + const expectedVersion = scenario.retained?.version ?? selectedVersion const mismatched = scenario.selectedVersions.find(version => version !== expectedVersion) if (mismatched !== undefined) { throw new Error( @@ -55,7 +59,15 @@ export function assertSnapshotCorpusPolicy( ) } if (scenario.retained === undefined) { - currentRoles += scenario.selectedVersions.length + if (selectedVersion === RETAINED_BASELINE_VERSION) { + baselineRoles += scenario.selectedVersions.length + } else if (selectedVersion === SESSION_FORMAT_VERSION) { + currentRoles += scenario.selectedVersions.length + } else { + throw new Error( + `${scenario.key}: selected Session generation v${selectedVersion} must be retained baseline v${RETAINED_BASELINE_VERSION} or current v${SESSION_FORMAT_VERSION}`, + ) + } continue } if (!Number.isSafeInteger(scenario.retained.version) @@ -77,6 +89,7 @@ export function assertSnapshotCorpusPolicy( for (const item of scenario.retained.coverage) coverage.add(item) } + if (baselineRoles > 0) coverageByVersion.set(RETAINED_BASELINE_VERSION, new Set(REQUIRED_ADJACENT_COVERAGE)) for (let version = 0; version < SESSION_FORMAT_VERSION; version += 1) { const required = version === 0 ? REQUIRED_V0_COVERAGE : REQUIRED_ADJACENT_COVERAGE const coverage = coverageByVersion.get(version) @@ -88,10 +101,10 @@ export function assertSnapshotCorpusPolicy( if (retainedRoles > MAX_RETAINED_ROLES) { throw new Error(`Session corpus retains ${retainedRoles} historical roles; maximum is ${MAX_RETAINED_ROLES}`) } - if (currentRoles <= retainedRoles) { + if (baselineRoles + currentRoles <= retainedRoles) { throw new Error( - `Session corpus requires a current majority; current=${currentRoles}, retained=${retainedRoles}`, + `Session corpus requires a baseline/current majority; baseline=${baselineRoles}, current=${currentRoles}, retained=${retainedRoles}`, ) } - return { currentRoles, retainedRoles, retainedScenarios } + return { currentRoles, baselineRoles, retainedRoles, retainedScenarios } } diff --git a/scripts/session-snapshot-corpus.corpus.ts b/scripts/session-snapshot-corpus.corpus.ts index 13a20ae364..438a644731 100644 --- a/scripts/session-snapshot-corpus.corpus.ts +++ b/scripts/session-snapshot-corpus.corpus.ts @@ -191,7 +191,7 @@ it('keeps every recorded session owned, pinned, redacted, and header-scrubbed', } }) -it('keeps a current-writer majority plus bounded declared historical migration coverage', async () => { +it('keeps V3 replay input plus bounded declared historical migration coverage', async () => { const owners = (await scenarios()).filter(scenario => scenario.manifest.session === undefined) const inventory = await Promise.all(owners.map(async scenario => ({ key: scenario.key, @@ -201,7 +201,9 @@ it('keeps a current-writer majority plus bounded declared historical migration c : { retained: scenario.manifest.sessionFormat }), }))) - expect(assertSnapshotCorpusPolicy(inventory)).toMatchObject({ + const summary = assertSnapshotCorpusPolicy(inventory) + expect(summary.baselineRoles).toBeGreaterThan(0) + expect(summary).toMatchObject({ retainedRoles: 9, retainedScenarios: 7, }) diff --git a/snapshots/AGENTS.md b/snapshots/AGENTS.md index 5b72efe92d..0d2071e25b 100644 --- a/snapshots/AGENTS.md +++ b/snapshots/AGENTS.md @@ -6,7 +6,7 @@ Every process under test starts through the `dsh` CLI with a shipped profile and Each scenario owns or explicitly references one primary Session role plus contiguous child roles. Canonical parent filenames are `session[.vN].jsonl`; children are `session.[.vN].jsonl`; v0 omits `.v0`, positive versions use lowercase `.vN`, and every filename agrees with its header. A directory may retain several generations of one role, but replay, record, and refresh select the numerically highest. Record and refresh write version-named outputs without renaming or deleting a committed generation; reviewed source-tree curation is separate. The owner alone records or refreshes the selected role. For an ordinary one-shot case, derive the user task and replay script from that selected JSONL; do not duplicate them in an `input.json`. Shared references are read-only, acyclic, point to the owner's selected parent generation, and are used only when another interface intentionally renders the same recorded behavior. -An owner that must keep a historical generation declares its exact `sessionFormat.version` and closed migration `coverage` names in `snapshot.yml`; record and refresh never rewrite that Session fixture. Owners without this declaration track current-writer output. +An owner that must keep a historical generation declares its exact `sessionFormat.version` and closed migration `coverage` names in `snapshot.yml`; record and refresh never rewrite that Session fixture. Owners without this declaration write current-writer output during record and refresh; replay accepts the retained V3 baseline or the current generation, with one selected generation per owner. The [corpus policy](../scripts/session-snapshot-corpus-policy.ts) requires V3 inputs for direct upgrade coverage and explicit V0–V2 migration coverage; a writer bump alone does not refresh fixtures. Committed sessions are normalization fixed points. Replace volatile identities with typed relationship-preserving tokens, replace request system prompts and tool schemas with tokens, and keep exactly one readable sidecar owner per header class. Never redact arbitrary user or tool text merely because it resembles an identifier. diff --git a/snapshots/sdk/sdk.snapshot.ts b/snapshots/sdk/sdk.snapshot.ts index 159dc328fb..3405411e43 100644 --- a/snapshots/sdk/sdk.snapshot.ts +++ b/snapshots/sdk/sdk.snapshot.ts @@ -408,6 +408,17 @@ function records(log: string): JsonObject[] { .map(line => JSON.parse(line) as JsonObject) } +function notificationComparisonRecords(log: string, sourceLogs: readonly string[]): JsonObject[] { + const versions = sourceLogs.map((source, index) => sessionHeaderVersion(source, `notification Session ${index}`)) + expect(new Set(versions).size, 'wire golden Session roles share one native writer generation').toBe(1) + return records(log).map((record) => { + if (record.method !== 'session.event') return record + const params = record.params as JsonObject + const event = JSON.parse(normalizeSessionFormatMetadata(JSON.stringify(params.event), versions[0])) as unknown + return { ...record, params: { ...params, event } } + }) +} + function modelFromSession(log: string): { provider: string; model: string } { for (const record of records(log)) { if (record.type !== 'request/header') continue @@ -885,14 +896,14 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => { expect(await Promise.all((await fixtureFiles(scenario)).map(file => readFile(file, 'utf8'))), 'historical replay input remains unchanged').toEqual(replayContents) for (const [index, content] of expectedContents.entries()) { - expect(sessionHeaderVersion(content, writerSnapshotName(index))).toBe(SESSION_FORMAT_VERSION) + expect(sessionHeaderVersion(content, writerSnapshotName(index))).toBeLessThanOrEqual(SESSION_FORMAT_VERSION) } } // Persisted transcripts match the committed fixtures. const expectedContext = contextOfContents(expectedContents) - const actualSnapshots = normalizeSessionSnapshots(ordered.map(log => log.content), actualContext) - const expectedSnapshots = normalizeSessionSnapshots(expectedContents, expectedContext) + const actualSnapshots = normalizeSessionSnapshots(ordered.map(log => log.content), actualContext, { nativeWriterOutput: true }) + const expectedSnapshots = normalizeSessionSnapshots(expectedContents, expectedContext, { nativeWriterOutput: true }) expect(actualSnapshots.map(records), `${scenario.name}: sessions`).toEqual(expectedSnapshots.map(records)) await verifyHeaders(scenario, ordered, actualContext, assertions.dshSdkChild?.agentConfig) @@ -908,10 +919,10 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => { } const expectedNotifications = await readFile(notificationsExpectedPath, 'utf8') expect( - records(normalizedNotifications), + notificationComparisonRecords(normalizedNotifications, ordered.map(log => log.content)), `${scenario.name}: notifications`, ) - .toEqual(records(expectedNotifications)) + .toEqual(notificationComparisonRecords(expectedNotifications, expectedContents)) expect(normalizedResult).toBe(await readFile(resultExpectedPath, 'utf8')) } diff --git a/snapshots/session/headless.snapshot.ts b/snapshots/session/headless.snapshot.ts index f072ebc1fa..bcd2ad2564 100644 --- a/snapshots/session/headless.snapshot.ts +++ b/snapshots/session/headless.snapshot.ts @@ -1153,12 +1153,12 @@ describe('headless recorded-session snapshots', () => { if (mode === 'refresh') await writeSessionFixtures(scenario, actualLogs, fixtures, actualContext) expected = await Promise.all(fixtures.map((_, index) => readFile(join(scenario.dir, writerSnapshotName(index)), 'utf8'))) for (const [index, content] of expected.entries()) { - expect(sessionHeaderVersion(content, writerSnapshotName(index))).toBe(SESSION_FORMAT_VERSION) + expect(sessionHeaderVersion(content, writerSnapshotName(index))).toBeLessThanOrEqual(SESSION_FORMAT_VERSION) } expect(await fixtureSessions(scenario), 'historical replay input remains unchanged').toEqual(fixtures) } - const actualSnapshots = normalizeSessionSnapshots(actualLogs.map(log => log.content), actualContext) - const expectedSnapshots = normalizeSessionSnapshots(expected, contextOf(expected)) + const actualSnapshots = normalizeSessionSnapshots(actualLogs.map(log => log.content), actualContext, { nativeWriterOutput: true }) + const expectedSnapshots = normalizeSessionSnapshots(expected, contextOf(expected), { nativeWriterOutput: true }) for (const [index, actual] of actualSnapshots.entries()) { expect(records(actual), `${scenario.name}: session ${index}`).toEqual(records(expectedSnapshots[index] as string)) } diff --git a/tsconfig.base.json b/tsconfig.base.json index b55a3f3e6e..922e38ed64 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -394,6 +394,7 @@ "@deepseek-ai/dsh-session-format-v0-to-v1": ["./packages/session/session-format-v0-to-v1/src"], "@deepseek-ai/dsh-session-format-v1-to-v2": ["./packages/session/session-format-v1-to-v2/src"], "@deepseek-ai/dsh-session-format-v2-to-v3": ["./packages/session/session-format-v2-to-v3/src"], + "@deepseek-ai/dsh-session-format-v3-to-v4": ["./packages/session/session-format-v3-to-v4/src"], "@deepseek-ai/dsh-session-log-deepseek": ["./packages/session/session-log-deepseek/src"], "@deepseek-ai/dsh-session-log-deepseek/invariant": ["./packages/session/session-log-deepseek/src/invariant.ts"], "@deepseek-ai/dsh-session-log-export": ["./packages/session-query/session-log-export/src"], diff --git a/tsconfig.host.json b/tsconfig.host.json index cf53223326..9c4ea65562 100644 --- a/tsconfig.host.json +++ b/tsconfig.host.json @@ -207,6 +207,7 @@ { "path": "./packages/session/session-format-v0-to-v1" }, { "path": "./packages/session/session-format-v1-to-v2" }, { "path": "./packages/session/session-format-v2-to-v3" }, + { "path": "./packages/session/session-format-v3-to-v4" }, { "path": "./packages/session/session-format-catalog" }, { "path": "./packages/session/session-checkpoint-policy" }, { "path": "./packages/session/session-log-deepseek" }, From 9c10de50a65e25023104eb9815718d95dd309ff6 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 16 Sep 2026 13:02:13 +0800 Subject: [PATCH 003/279] fix(test): compare native Python delivery generations without rewriting goldens --- python/development.i18n.yaml | 4 +- python/development.md | 2 + python/development.zh.md | 2 + python/sdk/tests/test_smoke_model.py | 137 +++++++++++++++++++++++++++ scripts/smoke-python-runtime.py | 63 +++++++++++- 5 files changed, 201 insertions(+), 7 deletions(-) diff --git a/python/development.i18n.yaml b/python/development.i18n.yaml index 097ae91c3c..f568fedc82 100644 --- a/python/development.i18n.yaml +++ b/python/development.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 python/development.md -development.md: 8e7608ada715e5a0acc6eb597ae9d06ebef3ecbf -development.zh.md: 3f6c1f92632d216e540b0dff5c4b72cdf90ae7d1 +development.md: b36a26b08631ae02532d6f190bab968c1ec24720 +development.zh.md: 81e8015bbcf45424dfb595154bab0ffe1e501251 diff --git a/python/development.md b/python/development.md index 8e7608ada7..b36a26b086 100644 --- a/python/development.md +++ b/python/development.md @@ -36,6 +36,8 @@ uv run --project python/sdk python scripts/smoke-python-runtime.py \ Four scenarios compare committed expected output under `scripts/snapshots/python-sdk-single-exe/`. `minimal/model-visible.json` pins the Linux/macOS `sdk-minimal` profile's assembled system prompts, advertised tool schemas, and model-visible messages; `minimal/win-x64/model-visible.json` pins its PowerShell counterpart. A plugin that contributes an unintended system section or user message therefore fails the job, and every message the profile emits is compared. `advanced/` pins one complex process's SDK result and parent/child session logs across every target. `restart/` launches two complete SDK runtime processes against one persistence root and snapshots their isolated model histories, high-level results, and separate durable logs across every target. `sdk-minimal-in-history` reuses the persistent-shell and editor scenario with a section that changes after the first successful shell call. `minimal-in-history/prompt-history.json` pins both prompt versions, the unchanged leading prompt in later requests, appended SDK system-message events, and `request/context.systemPromptUpdate`; tool schemas stay fixed and the editor file is checked independently. Rerun the owning scenario with `--update-snapshots` and review that diff before committing it. +The `advanced` and `restart` comparisons match native delivery qualifiers against each input's own Session generation, including SDK events and notifications. Captured and other delivery generations retain their numeric values. Each side must use one generation across its Session roles, and fresh logs must identify the current writer. Comparison never rewrites committed recordings. + Trusted pull requests and master pushes also run `--scenario sdk-live --installed-wheel` on each selected native target. That scenario performs two tool-using turns against `https://api.deepseek.com`: it checks the created file immediately, replaces its content with a host-only random challenge, and requires the second turn to copy the changed content into a fresh receipt without modifying the source. Both turns must complete with the exact sentinel answer and a model-requested tool call; external byte comparisons check the files. Missing repository secrets fail instead of self-skipping. Fork and Dependabot pull requests run the complete keyless installed-wheel path but receive no key. An interactive smoke test needs `DEEPSEEK_API_KEY` in the environment or repository-root `.env`: diff --git a/python/development.zh.md b/python/development.zh.md index 3f6c1f9263..81e8015bbc 100644 --- a/python/development.zh.md +++ b/python/development.zh.md @@ -36,6 +36,8 @@ uv run --project python/sdk python scripts/smoke-python-runtime.py \ 其中四个场景会比对 `scripts/snapshots/python-sdk-single-exe/` 下已提交的期望输出。`minimal/model-visible.json` 固定 Linux/macOS `sdk-minimal` profile 所组装的系统提示词、对外公布的工具 schema 与模型可见消息;`minimal/win-x64/model-visible.json` 固定对应的 PowerShell 版本。因此,插件一旦贡献出计划外的系统分段或 user 消息,该任务即失败,且该 profile 发出的每条消息都会参与比对。`advanced/` 跨所有目标固定一个复杂进程的 SDK 结果及父/子会话日志。`restart/` 针对同一持久化根目录启动两个完整 SDK 运行时进程,并跨所有目标固定其彼此隔离的模型历史、高层结果与独立持久日志。`sdk-minimal-in-history` 复用持久 shell 与编辑器场景,并在首次 shell 调用成功后更改一个分段。`minimal-in-history/prompt-history.json` 固定两个提示词版本、后续请求中不变的首条提示词、追加的 SDK system-message 事件及 `request/context.systemPromptUpdate`;工具 schema 保持不变,并独立检查编辑器创建的文件。重新运行对应场景时加上 `--update-snapshots`,并在提交前审阅该差异。 +`advanced` 与 `restart` 的比较按每份输入自身的 Session 代际匹配原生 delivery 限定值,包括 SDK 事件与通知。捕获的代际及其他 delivery 代际保留数值。每一侧的 Session 角色必须使用同一个代际,新日志必须标识当前写入器。比较绝不重写已提交的记录。 + 可信拉取请求与 master 推送还会在各自选定的原生目标上运行 `--scenario sdk-live --installed-wheel`。该场景面向 `https://api.deepseek.com` 执行两个使用工具的轮次:立即检查已创建文件,将其内容替换为仅宿主知道的随机挑战值,并要求第二轮将变更后的内容复制到全新的回执文件,且不修改源文件。两个轮次都必须完成、返回精确的哨兵答案并由模型请求调用工具;文件通过外部逐字节比较验证。仓库密钥缺失时失败,而不是自行 skip。Fork 与 Dependabot 拉取请求会运行完整的 keyless 安装后 wheel 路径,但不会获得密钥。 交互式冒烟测试需要环境变量或仓库根目录 `.env` 中存在 `DEEPSEEK_API_KEY`: diff --git a/python/sdk/tests/test_smoke_model.py b/python/sdk/tests/test_smoke_model.py index 12402c01e3..e972365779 100644 --- a/python/sdk/tests/test_smoke_model.py +++ b/python/sdk/tests/test_smoke_model.py @@ -482,6 +482,143 @@ def test_snapshot_comparison_accepts_current_output_against_v2_without_rewriting assert SMOKE["selected_snapshot_session_files"](tmp_path) == {0: tmp_path / successor_name} +def native_delivery_snapshot(version: int) -> dict[str, str]: + event = { + "type": "session-log-deepseek/delivery-accepted", + "data": {"sessionId": "s", "throughSeq": 0, "sessionFormatVersion": version}, + } + return { + "result.json": json.dumps({ + "events": [event], + "notifications": [{"method": "session.event", "payload": {"sessionId": "s", "event": event}}], + }) + "\n", + f"session.v{version}.jsonl": SMOKE["render_jsonl"]([ + {"type": "session", "version": version, "id": "s"}, + {"type": "turn/start", "data": {"turn": 1}}, + event, + ]), + } + + +def test_native_writer_comparison_requires_opt_in_and_preserves_written_generations(tmp_path: Path) -> None: + golden = native_delivery_snapshot(3) + fresh = native_delivery_snapshot(SESSION_FORMAT_VERSION) + for name, content in golden.items(): + (tmp_path / name).write_text(content, encoding="utf-8") + compare = SMOKE["compare_snapshot_files"] + with pytest.raises(AssertionError, match="executable snapshot mismatch"): + compare(fresh, False, tmp_path, tuple(golden)) + compare(fresh, False, tmp_path, tuple(golden), native_writer_output=True) + assert {path.name: path.read_text(encoding="utf-8") for path in tmp_path.iterdir()} == golden + compare(fresh, True, tmp_path, tuple(golden), native_writer_output=True) + assert (tmp_path / "session.v3.jsonl").read_text(encoding="utf-8") == golden["session.v3.jsonl"] + for name, content in fresh.items(): + assert (tmp_path / name).read_text(encoding="utf-8") == content + assert "{{sourceSessionFormatVersion}}" not in content + + +@pytest.mark.parametrize("surface", ["session", "events", "notifications"]) +def test_native_writer_comparison_rejects_stale_current_delivery(tmp_path: Path, surface: str) -> None: + golden = native_delivery_snapshot(3) + fresh = native_delivery_snapshot(SESSION_FORMAT_VERSION) + for name, content in golden.items(): + (tmp_path / name).write_text(content, encoding="utf-8") + if surface == "session": + name = f"session.v{SESSION_FORMAT_VERSION}.jsonl" + records = [json.loads(line) for line in fresh[name].splitlines()] + records[-1]["data"]["sessionFormatVersion"] = 3 + fresh[name] = SMOKE["render_jsonl"](records) + else: + result = json.loads(fresh["result.json"]) + event = result["events"][0] if surface == "events" else result["notifications"][0]["payload"]["event"] + event["data"]["sessionFormatVersion"] = 3 + fresh["result.json"] = json.dumps(result) + "\n" + with pytest.raises(AssertionError, match="executable snapshot mismatch"): + SMOKE["compare_snapshot_files"](fresh, False, tmp_path, tuple(golden), native_writer_output=True) + + +def test_native_writer_comparison_preserves_captured_and_nested_delivery_values() -> None: + delivery = { + "type": "session-log-deepseek/delivery-accepted", + "data": {"sessionId": "s", "throughSeq": 0, "sessionFormatVersion": 3}, + } + captured = {"type": "custom/event", "data": { + "capturedFormatVersion": 3, "sessionFormatVersion": 3, "nested": delivery, + }} + value = { + "events": [delivery, captured, {**delivery, "data": {**delivery["data"], "sessionFormatVersion": 2}}], + "notifications": [ + {"method": "session.event", "params": {"event": delivery}}, + {"method": "other.event", "payload": {"event": delivery}}, + ], + } + normalized = json.loads(SMOKE["normalize_snapshot_comparison_text"]("result.json", json.dumps(value), 3)) + assert normalized["events"][0]["data"]["sessionFormatVersion"] == "{{sourceSessionFormatVersion}}" + assert normalized["events"][1] == captured + assert normalized["events"][2]["data"]["sessionFormatVersion"] == 2 + assert normalized["notifications"][0]["params"]["event"]["data"]["sessionFormatVersion"] == "{{sourceSessionFormatVersion}}" + assert normalized["notifications"][1] == value["notifications"][1] + assert SMOKE["normalize_session_format_comparison"](delivery) == delivery + + +def test_default_comparison_keeps_a_migrated_delivery_generation_exact() -> None: + source = native_delivery_snapshot(3)["session.v3.jsonl"] + target_records = [json.loads(line) for line in source.splitlines()] + target_records[0]["version"] = SESSION_FORMAT_VERSION + target = SMOKE["render_jsonl"](target_records) + normalize = SMOKE["normalize_snapshot_comparison_text"] + assert normalize("session.v3.jsonl", source) == normalize(f"session.v{SESSION_FORMAT_VERSION}.jsonl", target) + assert '"sessionFormatVersion":3' in normalize(f"session.v{SESSION_FORMAT_VERSION}.jsonl", target) + + +def test_native_writer_comparison_rejects_mixed_expected_role_generations(tmp_path: Path) -> None: + golden = {"session.v2.jsonl": 2, "session.1.v3.jsonl": 3} + fresh = {} + for index, (name, version) in enumerate(golden.items()): + (tmp_path / name).write_text(SMOKE["render_jsonl"]([ + {"type": "session", "version": version}, + ]), encoding="utf-8") + fresh[SMOKE["snapshot_session_filename"](index, SESSION_FORMAT_VERSION)] = SMOKE["render_jsonl"]([ + {"type": "session", "version": SESSION_FORMAT_VERSION}, + ]) + with pytest.raises(AssertionError, match="requires one Session generation across all roles"): + SMOKE["compare_snapshot_files"](fresh, False, tmp_path, tuple(golden), native_writer_output=True) + + +@pytest.mark.parametrize("scenario", ["ADVANCED", "RESTART"]) +def test_committed_python_native_goldens_compare_current_output_without_rewriting(scenario: str) -> None: + directory = SMOKE[f"{scenario}_SNAPSHOT_DIRECTORY"] + filenames = SMOKE[f"{scenario}_SNAPSHOT_FILENAMES"] + before = {path.name: path.read_bytes() for path in directory.iterdir() if path.is_file()} + + def current_writer(value: object) -> object: + if isinstance(value, list): + return [current_writer(item) for item in value] + if not isinstance(value, dict): + return value + result = {key: current_writer(item) for key, item in value.items()} + if result.get("type") == "session": + assert result["version"] == 3 + result["version"] = SESSION_FORMAT_VERSION + if result.get("type") == "session-log-deepseek/delivery-accepted": + assert result["data"]["sessionFormatVersion"] == 3 + result["data"]["sessionFormatVersion"] = SESSION_FORMAT_VERSION + return result + + fresh = {} + for name in filenames: + content = before[name].decode("utf-8") + if name.endswith(".jsonl"): + parsed = SMOKE["parse_snapshot_session_filename"](name) + fresh[SMOKE["snapshot_session_filename"](parsed[0], SESSION_FORMAT_VERSION)] = SMOKE["render_jsonl"]([ + current_writer(json.loads(line)) for line in content.splitlines() if line + ]) + else: + fresh[name] = json.dumps(current_writer(json.loads(content)), indent=2, ensure_ascii=False) + "\n" + SMOKE["compare_snapshot_files"](fresh, False, directory, filenames, native_writer_output=True) + assert {path.name: path.read_bytes() for path in directory.iterdir() if path.is_file()} == before + + @pytest.mark.parametrize("filenames", [ ("session.1.v2.jsonl", "session.v2.jsonl"), ("session.v2.jsonl",), diff --git a/scripts/smoke-python-runtime.py b/scripts/smoke-python-runtime.py index afd1cc4cb7..baec977d4b 100644 --- a/scripts/smoke-python-runtime.py +++ b/scripts/smoke-python-runtime.py @@ -1413,6 +1413,7 @@ def smoke_sdk_snapshot(base_url: str, executable: Path, update_snapshots: bool) files = build_snapshot_files(result, logs, child_ids, root) compare_snapshot_files( files, update_snapshots, ADVANCED_SNAPSHOT_DIRECTORY, ADVANCED_SNAPSHOT_FILENAMES, + native_writer_output=True, ) @@ -1479,6 +1480,7 @@ def smoke_sdk_restart_snapshot(base_url: str, executable: Path, update_snapshots ) compare_snapshot_files( files, update_snapshots, RESTART_SNAPSHOT_DIRECTORY, RESTART_SNAPSHOT_FILENAMES, + native_writer_output=True, ) @@ -2282,6 +2284,7 @@ def project_session_snapshot(records: list[dict[str, object]]) -> list[dict[str, SESSION_FORMAT_TOKEN = "{{sessionFormatVersion}}" +NATIVE_DELIVERY_FORMAT_TOKEN = "{{sourceSessionFormatVersion}}" def expand_snapshot_stream_member(member: object) -> list[dict[str, object]]: @@ -2404,7 +2407,31 @@ def normalize_session_format_comparison( return normalized -def normalize_snapshot_comparison_text(name: str, content: str) -> str: +def normalize_native_delivery_record(value: object, source_version: int) -> object: + """Tokenize a native delivery qualifier in one Session event or SDK notification.""" + if not isinstance(value, dict): + return value + if value.get("method") == "session.event": + for key in ("payload", "params"): + wrapper = value.get(key) + if isinstance(wrapper, dict) and "event" in wrapper: + return {**value, key: { + **wrapper, + "event": normalize_native_delivery_record(wrapper["event"], source_version), + }} + data = value.get("data") + if value.get("type") != "session-log-deepseek/delivery-accepted" or not isinstance(data, dict): + return value + if data.get("sessionFormatVersion") != source_version: + return value + return {**value, "data": {**data, "sessionFormatVersion": NATIVE_DELIVERY_FORMAT_TOKEN}} + + +def normalize_snapshot_comparison_text( + name: str, + content: str, + native_writer_version: int | None = None, +) -> str: """Normalize Session generation metadata only while comparing committed expected outputs.""" if name.startswith("session") and name.endswith(".jsonl"): parsed = [json.loads(line) for line in content.splitlines() if line] @@ -2412,6 +2439,8 @@ def normalize_snapshot_comparison_text(name: str, content: str) -> str: source_version = header.get("version") if isinstance(header, dict) else None if not isinstance(source_version, int): raise AssertionError(f"{name}: snapshot Session header has no integer format version") + if native_writer_version is not None: + parsed = [normalize_native_delivery_record(record, native_writer_version) for record in parsed] records = [ normalize_session_format_comparison(expanded, source_version) for record in parsed @@ -2419,8 +2448,18 @@ def normalize_snapshot_comparison_text(name: str, content: str) -> str: ] return render_jsonl(records) if name.endswith(".json"): + value = json.loads(content) + if name == "result.json" and native_writer_version is not None and isinstance(value, dict): + value = { + **value, + **{ + key: [normalize_native_delivery_record(record, native_writer_version) for record in value[key]] + for key in ("events", "notifications") + if isinstance(value.get(key), list) + }, + } return json.dumps( - normalize_session_format_comparison(json.loads(content)), + normalize_session_format_comparison(value), indent=2, ensure_ascii=False, ) + "\n" @@ -2432,8 +2471,10 @@ def compare_snapshot_files( update: bool, directory: Path, filenames: tuple[str, ...], + *, + native_writer_output: bool = False, ) -> None: - """Compare ordered artifact roles and Session content across generations, or write generated filenames.""" + """Compare artifact roles and content, optionally matching each side's native delivery generation.""" scenario = directory.name def role_name(name: str) -> str: @@ -2485,12 +2526,24 @@ def compare_snapshot_files( f"{scenario} snapshot Session roles differ: " f"expected={sorted(selected_expected)}, actual={sorted(actual_sessions)}", ) + actual_native_version = expected_native_version = None + if native_writer_output: + def common_generation(contents: list[tuple[str, str]]) -> int: + versions = {session_header_version(content, name) for name, content in contents} + if len(versions) != 1: + raise AssertionError(f"{scenario}: native writer comparison requires one Session generation across all roles") + return versions.pop() + + actual_native_version = common_generation(list(actual_sessions.values())) + expected_native_version = common_generation([ + (path.name, path.read_text(encoding="utf-8")) for path in selected_expected.values() + ]) for name, actual in files.items(): parsed = parse_snapshot_session_filename(name) expected_path = directory / name if parsed is None else selected_expected[parsed[0]] expected_text = expected_path.read_text(encoding="utf-8") - compared_actual = normalize_snapshot_comparison_text(name, actual) - compared_expected = normalize_snapshot_comparison_text(expected_path.name, expected_text) + compared_actual = normalize_snapshot_comparison_text(name, actual, actual_native_version) + compared_expected = normalize_snapshot_comparison_text(expected_path.name, expected_text, expected_native_version) if compared_actual == compared_expected: continue diff = "".join(difflib.unified_diff( From 8a461495772b29bf80bc6208396a0debf0acdb22 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 16 Sep 2026 13:21:19 +0800 Subject: [PATCH 004/279] fix(test): validate retained V3 layouts and current reference captures --- .../adding-a-session-format-version.i18n.yaml | 4 +- .../adding-a-session-format-version.md | 2 +- .../adding-a-session-format-version.zh.md | 2 +- scripts/session-fixture-layout.spec.ts | 13 ++--- scripts/session-fixture-layout.ts | 2 + snapshots/session/headless.snapshot.ts | 52 ++++++++++++++++++- 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/docs/cookbook/adding-a-session-format-version.i18n.yaml b/docs/cookbook/adding-a-session-format-version.i18n.yaml index 0daad832a8..a24ca7e1ea 100644 --- a/docs/cookbook/adding-a-session-format-version.i18n.yaml +++ b/docs/cookbook/adding-a-session-format-version.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/cookbook/adding-a-session-format-version.md -adding-a-session-format-version.md: 84dab0f385d8eaae9da952e54a148060437ca285 -adding-a-session-format-version.zh.md: 11c918fb0a4ce839363cc9f4e7f4341a60bbbd77 +adding-a-session-format-version.md: 577a344c8f4341f93fc718cd71f786c35b601477 +adding-a-session-format-version.zh.md: bdd1b741c1c5342c70e0567d4daea553b1663609 diff --git a/docs/cookbook/adding-a-session-format-version.md b/docs/cookbook/adding-a-session-format-version.md index 84dab0f385..577a344c8f 100644 --- a/docs/cookbook/adding-a-session-format-version.md +++ b/docs/cookbook/adding-a-session-format-version.md @@ -60,7 +60,7 @@ Prove strict restoration through `sessionFormatCatalog.createRestore(header, { r ## 4. Update current-version consumers -Trace each current-version consumer, including Session creation/restoration, JSONL filename selection and publication, the catalog's current encoder/restorer, projection-cache generation identity, replay and snapshot normalization, and TypeScript/Python SDK recordings. Use the writer constant where a value means current; keep literal historical versions in released codecs and historical fixtures. Update current documentation and generated references through their owners. +Trace each current-version consumer, including Session creation/restoration, JSONL filename selection and publication, the catalog's current encoder/restorer, projection-cache generation identity, replay and snapshot normalization, [physical fixture-layout validation](../../scripts/session-fixture-layout.ts), and TypeScript/Python SDK recordings. Use the writer constant where a value means current; keep literal historical versions in released codecs and historical fixtures. Update current documentation and generated references through their owners. Do not bump unrelated versions automatically. A request wrapper's `sessionFormatVersion` identifies its embedded Session generation; its outer schema version has its own meaning. Projection-unit state versions likewise do not replace the cache's Session-generation identity. diff --git a/docs/cookbook/adding-a-session-format-version.zh.md b/docs/cookbook/adding-a-session-format-version.zh.md index 11c918fb0a..bdd1b741c1 100644 --- a/docs/cookbook/adding-a-session-format-version.zh.md +++ b/docs/cookbook/adding-a-session-format-version.zh.md @@ -60,7 +60,7 @@ pnpm run gen-session-format-catalog ## 4. 更新当前版本消费方 -追踪每个当前版本消费方,包括 Session 创建与恢复、JSONL 文件名选择与发布、catalog 的当前编码器与恢复器、投影缓存的代际身份、回放与快照归一化,以及 TypeScript/Python SDK 录制。当值表示当前版本时使用写入器常量;在已发布 codec 和历史 fixture 中保留字面历史版本。通过各自所有者更新当前文档与生成参考。 +追踪每个当前版本消费方,包括 Session 创建与恢复、JSONL 文件名选择与发布、catalog 的当前编码器与恢复器、投影缓存的代际身份、回放与快照归一化、[物理 fixture 布局校验](../../scripts/session-fixture-layout.ts),以及 TypeScript/Python SDK 录制。当值表示当前版本时使用写入器常量;在已发布 codec 和历史 fixture 中保留字面历史版本。通过各自所有者更新当前文档与生成参考。 不要自动提升无关版本。请求包装层的 `sessionFormatVersion` 标识嵌入的 Session 代际;外层 schema 版本有自己的含义。投影单元状态版本同样不能替代缓存的 Session 代际身份。 diff --git a/scripts/session-fixture-layout.spec.ts b/scripts/session-fixture-layout.spec.ts index 37908f4dda..9f654962b4 100644 --- a/scripts/session-fixture-layout.spec.ts +++ b/scripts/session-fixture-layout.spec.ts @@ -11,6 +11,7 @@ import { const HEADER = ` {"type":"session","version":${SESSION_FORMAT_VERSION},"id":"fixture","createdAt":1,"isSeeded":false,"delegationDepth":0} ` const root = resolve(import.meta.dirname, '..') +const historicalVersions = Array.from({ length: SESSION_FORMAT_VERSION }, (_, version) => version) const FIXTURE_MESSAGE = createAssistantMessage({ content: [{ type: 'text', text: 'part-0part-1part-2part-3' }], source: { provider: 'mock', model: 'mock' }, @@ -133,8 +134,8 @@ describe('canonicalSessionFixture', () => { expect(() => decodedBody(canonical!)).toThrow(/session snapshot line 3:.*empty optional header fields must be omitted/) }) - it.each([0, 1, 2])('preserves physically valid v%i bytes without requiring migration to current', (version) => { - const header = { type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version === 2 ? { isSeeded: false } : {}) } + it.each(historicalVersions)('preserves physically valid v%i bytes without requiring migration to current', (version) => { + const header = { type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version >= 2 ? { isSeeded: false } : {}) } const content = [ JSON.stringify(header), JSON.stringify({ type: 'user/message', data: { role: 'user', id: 'historical-user', source: { kind: 'user' }, content: [] }, surfaceOp: 'append' }), @@ -143,16 +144,16 @@ describe('canonicalSessionFixture', () => { expect(canonicalSessionFixture(content)).toBe(content) }) - it.each([0, 1, 2])('rejects v%i sequence gaps and invalid source-event ranges with source line diagnostics', (version) => { - const header = JSON.stringify({ type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version === 2 ? { isSeeded: false } : {}) }) + it.each(historicalVersions)('rejects v%i sequence gaps and invalid source-event ranges with source line diagnostics', (version) => { + const header = JSON.stringify({ type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version >= 2 ? { isSeeded: false } : {}) }) expect(() => canonicalSessionFixture(`${header}\n{"type":"feedback/record","seq":3,"data":{"text":"gap"}}\n`, 'gap.jsonl')) .toThrow(/gap\.jsonl: session snapshot line 2:.*seq/) expect(() => canonicalSessionFixture(`${header}\n{"type":"feedback/record","data":{},"sourceEventSeqs":[[2,0]]}\n`, 'range.jsonl')) .toThrow(/range\.jsonl: session snapshot line 2:/) }) - it.each([0, 1, 2])('finalizes the v%i source inherited cut', (version) => { - const header = { type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version === 2 ? { isSeeded: true } : { seedLength: 1 }) } + it.each(historicalVersions)('finalizes the v%i source inherited cut', (version) => { + const header = { type: 'session', version, id: 'historical', createdAt: 1, delegationDepth: 0, ...(version >= 2 ? { isSeeded: true } : { seedLength: 1 }) } expect(() => canonicalSessionFixture(`${JSON.stringify(header)}\n`, 'cut.jsonl')) .toThrow(/cut\.jsonl: session snapshot line 1:.*(?:inherited|seed)/) }) diff --git a/scripts/session-fixture-layout.ts b/scripts/session-fixture-layout.ts index 9feac22ba5..e181666840 100644 --- a/scripts/session-fixture-layout.ts +++ b/scripts/session-fixture-layout.ts @@ -14,9 +14,11 @@ import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' import { SessionFormatEventCollector, type SessionFormatArtifactDecoder, type SessionFormatCodec } from '@deepseek-ai/dsh-session-format' import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v0-to-v1' import { releasedV2SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v1-to-v2' +import { releasedV3SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v2-to-v3' const historicalCodecs: readonly SessionFormatCodec[] = [ releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, releasedV2SessionFormatCodec, + releasedV3SessionFormatCodec, ] /** Physical persistence artifacts validated by the WebWorker runtime fixture spec. */ diff --git a/snapshots/session/headless.snapshot.ts b/snapshots/session/headless.snapshot.ts index bcd2ad2564..d8f366718e 100644 --- a/snapshots/session/headless.snapshot.ts +++ b/snapshots/session/headless.snapshot.ts @@ -550,6 +550,31 @@ function pinOf(scenario: HeadlessScenario): HeadlessScenario { return pin } +function spillReferenceSource(events: readonly JsonObject[], label: string): JsonObject { + const messages = events.filter((event) => { + const source = (event.data as JsonObject | undefined)?.source as JsonObject | undefined + return event.type === 'user/message' && source?.kind === 'session-reference' + }) + expect(messages, `${label}: reference message count`).toHaveLength(1) + const source = (messages[0]!.data as JsonObject).source as JsonObject + expect(source).toMatchObject({ kind: 'session-reference', form: 'recall', version: 1 }) + const references = source.references as JsonObject[] + expect(references, `${label}: referenced Session count`).toHaveLength(1) + expect(references[0]?.sessionId, `${label}: referenced Session id`).toBe('reference-source') + return references[0]! +} + +function sessionReferenceSpillExpected(actual: readonly JsonObject[], expectedLog: string, recordedVersion: number): JsonObject[] { + const expected = records(expectedLog) + const actualReference = spillReferenceSource(actual, 'actual session-reference-spill') + const expectedReference = spillReferenceSource(expected, 'expected session-reference-spill') + // source-session.ts creates reference-source anew with Session.create() for each run. + expect(actualReference.capturedFormatVersion, 'fresh reference-source generation').toBe(SESSION_FORMAT_VERSION) + expect(expectedReference.capturedFormatVersion, 'recorded reference-source generation').toBe(recordedVersion) + expectedReference.capturedFormatVersion = SESSION_FORMAT_VERSION + return expected +} + /** Require successful verification and the complete canonical event before refresh can write a fixture. */ async function verifySessionQuerySpill(log: string, spillRoot: string, locatorRoot: string): Promise { const events = parseSessionLog(log) @@ -999,6 +1024,23 @@ describe('headless recorded-session snapshots', () => { } }) + it('session-reference-spill validates captured generations before adapting its fresh source expectation', async () => { + const fixture = await readFile(join(snapshotsRoot, 'session-reference-spill/session.v3.jsonl'), 'utf8') + const recordedVersion = sessionHeaderVersion(fixture, 'session-reference-spill fixture') + expect(recordedVersion).toBe(3) + const normalized = normalizeSessionSnapshots([fixture], contextOf([fixture]))[0]! + const actual = records(normalized) + spillReferenceSource(actual, 'fresh source').capturedFormatVersion = SESSION_FORMAT_VERSION + + expect(sessionReferenceSpillExpected(actual, normalized, recordedVersion)).toEqual(actual) + expect(() => sessionReferenceSpillExpected(records(normalized), normalized, recordedVersion)) + .toThrow('fresh reference-source generation') + expect(() => sessionReferenceSpillExpected(actual, normalized, SESSION_FORMAT_VERSION)) + .toThrow('recorded reference-source generation') + expect(spillReferenceSource(records(normalized), 'unchanged fixture').capturedFormatVersion).toBe(3) + expect(await readFile(join(snapshotsRoot, 'session-reference-spill/session.v3.jsonl'), 'utf8')).toBe(fixture) + }) + for (const scenario of scenarios) { const skipped = scenario.manifest.platform === 'posix' && process.platform === 'win32' || scenario.manifest.platform === 'pwsh' && !hasPwsh @@ -1160,7 +1202,15 @@ describe('headless recorded-session snapshots', () => { const actualSnapshots = normalizeSessionSnapshots(actualLogs.map(log => log.content), actualContext, { nativeWriterOutput: true }) const expectedSnapshots = normalizeSessionSnapshots(expected, contextOf(expected), { nativeWriterOutput: true }) for (const [index, actual] of actualSnapshots.entries()) { - expect(records(actual), `${scenario.name}: session ${index}`).toEqual(records(expectedSnapshots[index] as string)) + const actualRecords = records(actual) + const expectedRecords = scenario.name === 'session-reference-spill' && index === 0 + ? sessionReferenceSpillExpected( + actualRecords, + expectedSnapshots[index] as string, + sessionHeaderVersion(expected[index] as string, 'session-reference-spill fixture'), + ) + : records(expectedSnapshots[index] as string) + expect(actualRecords, `${scenario.name}: session ${index}`).toEqual(expectedRecords) } await verifyHeaders(scenario, actualLogs, actualContext) From 3bde1a56e3ffec9c0fd72a8580da2afb3e2f1d37 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 16 Sep 2026 13:46:05 +0800 Subject: [PATCH 005/279] fix(test): prepare preview generations and preserve embedded stream timing --- ...leased-session-format-migrations.i18n.yaml | 4 +- ...8-31-released-session-format-migrations.md | 2 + ...1-released-session-format-migrations.zh.md | 2 + apps/web/tests/preview-boot.e2e.ts | 10 +- apps/web/tests/scaffold-generation.spec.ts | 31 +++++- apps/web/tests/scaffold.ts | 15 +-- .../webworker-packer/README.i18n.yaml | 4 +- .../experimental/webworker-packer/README.md | 5 +- .../webworker-packer/README.zh.md | 5 +- .../webworker-packer/package.json | 2 + .../experimental/webworker-packer/src/bin.ts | 6 +- .../webworker-packer/src/index.ts | 2 +- .../webworker-packer/src/preview.ts | 79 ++++++++++++++ .../webworker-packer/src/repository.ts | 2 + .../webworker-packer/tests/built-lib.e2e.ts | 9 ++ .../webworker-packer/tests/preview.spec.ts | 102 ++++++++++++++++++ .../webworker-packer/tsconfig.json | 6 ++ .../webworker-runtime/README.i18n.yaml | 4 +- .../experimental/webworker-runtime/README.md | 2 +- .../webworker-runtime/README.zh.md | 2 +- pnpm-lock.yaml | 6 ++ 21 files changed, 273 insertions(+), 27 deletions(-) create mode 100644 packages/experimental/webworker-packer/src/preview.ts create mode 100644 packages/experimental/webworker-packer/tests/preview.spec.ts diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml index d75ac2da5f..13d5415c62 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.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 .agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md -2026-08-31-released-session-format-migrations.md: 6c236431a69a004d969b321f896041b791b2900a -2026-08-31-released-session-format-migrations.zh.md: 3c0e242770a5056c621e971befb023869926bf6f +2026-08-31-released-session-format-migrations.md: 8d7b8cbc06b77fbe3587593df65f454cf7752518 +2026-08-31-released-session-format-migrations.zh.md: 0443740ff1b724cd4f27dd636cd3dff381824f5a diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md index 6c236431a6..8d7b8cbc06 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md @@ -99,6 +99,8 @@ Current encoding is record based. The provider serializes about 1 MiB of plainte The shipped `lib/worker.cjs` bundles its JavaScript workspace dependencies so each fresh verifier avoids resolving and compiling their runtime module graph. This is safe because the Worker communicates through plain request/result messages and shares no service or class identity with its host. The Host build applies the existing TypeScript and Typert transforms; the Client pass skips this Node-only package instead of replacing its worker with untransformed source. Native add-ons remain external. Verification, scheduler admission, termination, and durable publication still complete before writable open returns. The built-worker smoke copies the package manifest and worker into an isolated temporary package with ambient module paths removed, accepts a valid generation, and rejects an incorrect event count. +The [browser preview packer](../../../../packages/experimental/webworker-packer/README.md) prepares current successors for bundled Session data in Node. The browser host does not implement `node:worker_threads`, so this preparation preserves both immutable fixture generations and runtime JSONL’s Worker verification requirement. + Preparation forwards cancellation through source reads and observes it at the existing approximately 500 ms Decode yield boundary. Once `publish()` starts, encode, Worker verification, and publication do not receive caller cancellation and run to settlement; write open checks its caller signal again afterward. A published generation is never rolled back. The Stage pipeline ends at one prepared current artifact. [Historical Session read preparation](2026-09-05-read-only-session-migration-preparation.md) defines how read open consumes that artifact immediately while write open performs encode, verification, and publication before returning append access. diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md index 3c0e242770..0443740ff1 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md @@ -99,6 +99,8 @@ Current encode 以单条 record 为单位。Provider 在主线程每个 slice 发布的 `lib/worker.cjs` 将 JavaScript workspace 依赖一起打包,使每个新 verifier 无需解析并编译它们的运行时模块图。Worker 只通过普通 request/result 消息通信,与 host 不共享 service 或 class identity,因此可以这样处理。Host build 应用现有 TypeScript 与 Typert 转换;Client pass 跳过这个 Node-only package,不会用未经转换的源代码覆盖 worker。Native add-on 保持 external。Verification、scheduler admission、termination 与 durable publication 仍在 writable open 返回前完成。Built-worker 冒烟测试把 package manifest 与 worker 复制到隔离的临时 package,移除环境中的模块搜索路径,接受有效 generation,并拒绝错误的 event count。 +[浏览器 preview 打包器](../../../../packages/experimental/webworker-packer/README.zh.md)在 Node 中为随包 Session 数据准备当前代际后继。浏览器 host 未实现 `node:worker_threads`,因此打包阶段的准备同时保留不可变 fixture 代际与运行时 JSONL 的 Worker 校验要求。 + Preparation 会把 cancellation 传给 source read,并在现有的约 500 ms Decode yield 边界观察它。`publish()` 一旦开始,encode、Worker verification 与 publication 不接收 caller cancellation,并运行到终态;write open 会在之后再次检查 caller signal。已经发布的 generation 绝不会回滚。 Stage pipeline 终止于一份 prepared current artifact。[历史 Session 只读迁移准备](2026-09-05-read-only-session-migration-preparation.zh.md)定义 read open 如何立即消费该 artifact,以及 write open 如何在返回 append 权限前完成 encode、verification 与 publication。 diff --git a/apps/web/tests/preview-boot.e2e.ts b/apps/web/tests/preview-boot.e2e.ts index 0819e0e8ce..d94ef6d366 100644 --- a/apps/web/tests/preview-boot.e2e.ts +++ b/apps/web/tests/preview-boot.e2e.ts @@ -27,7 +27,7 @@ import { chromium } from 'playwright' import type { Browser } from 'playwright' import { expect, it } from 'vitest' import { - composeProfile, configTrees, indexWorkspacePackages, packVfsImage, packVfsOverlay, + composeProfile, configTrees, indexWorkspacePackages, packVfsImage, packPreviewFixture, previewFixtures, WRAPPER_CONTRACT, } from '@deepseek-ai/dsh-experimental-webworker-packer' import { @@ -118,9 +118,9 @@ function requirePreviewPages(): void { * The base image, fixture manifest, and overlays to serve. `pnpm run build` * emits the pages but only `build:preview` packs the image, so this lane packs * a missing image rather than skipping the deployment it accepts. The example - * overlay pairs its committed Session generations with the generator-owned - * current projection cache. The worker therefore exercises historical reads - * without relying on a stale cache schema. Generated files land in a temp + * overlay retains its committed Session generations, prepares current successors + * through the Node catalog, and supplies the generator-owned current projection cache. + * Generated files land in a temp * directory, never in `dist/`: the * client-artifact digest record treats `dist/` as build-owned, so a test write * there fails the record check for every later consumer. @@ -161,7 +161,7 @@ function requireVfsAssets(): PreviewAssets { const trees = fixture.id === 'vfs-example' ? [...fixture.trees, { mount: 'home/storages', directory: cacheDirectory }] : fixture.trees - writeAsset(relativePath, packVfsOverlay(trees).image) + writeAsset(relativePath, packPreviewFixture(trees).image) return { id: fixture.id, label: fixture.label, diff --git a/apps/web/tests/scaffold-generation.spec.ts b/apps/web/tests/scaffold-generation.spec.ts index 198268c9f1..f6d735b1d8 100644 --- a/apps/web/tests/scaffold-generation.spec.ts +++ b/apps/web/tests/scaffold-generation.spec.ts @@ -1,9 +1,11 @@ import { afterEach, describe, expect, it } from 'vitest' -import { mkdtemp, rm, writeFile } from 'node:fs/promises' +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { parseSessionLog, prepareSessionSnapshotFixtureForComparison } from '@deepseek-ai/dsh-llm-replay' import { assertFixtureInventory, + parseSeedFixture, recordedSessionFixturePath, selectedSessionFixture, } from './scaffold.ts' @@ -14,6 +16,33 @@ afterEach(async () => { for (const root of roots.splice(0)) await rm(root, { recursive: true, force: true }) }) +describe('Web seed stream timing', () => { + it.each([2, 3])('preserves embedded timestamps from format v%i and its current projection', async (version) => { + const fixture = await readFile(new URL(`../../../snapshots/session/skill-load/session.v${version}.jsonl`, import.meta.url), 'utf8') + const current = prepareSessionSnapshotFixtureForComparison(fixture) + const expected = parseSessionLog(current) + + expect(parseSeedFixture(fixture).events).toEqual(expected) + expect(parseSeedFixture(current).events).toEqual(expected) + }) + + it.each(['session.jsonl', 'session.v1.jsonl'])('reconstructs positive stream intervals from %s', async (filename) => { + const fixture = await readFile(new URL(`../../../snapshots/session/text-turn/${filename}`, import.meta.url), 'utf8') + const messages = parseSeedFixture(fixture).events.filter(event => event.type === 'assistant/message') + expect(messages).toHaveLength(1) + const stream = messages[0]!.data.stream + expect(stream.length).toBeGreaterThan(1) + + let previousEnd = -1 + for (const record of stream) { + const start = 'time' in record ? record.time : record.time0 + expect(start).toBeGreaterThan(previousEnd) + previousEnd = 'time' in record ? record.time : record.time0 + record.dt.reduce((total, delta) => total + delta, 0) + } + expect(previousEnd).toBeGreaterThan(0) + }) +}) + describe('Web snapshot generation filenames', () => { it('selects the highest parent and child generations without counting retained inputs twice', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-web-fixture-generations-')) diff --git a/apps/web/tests/scaffold.ts b/apps/web/tests/scaffold.ts index 7e3d6276df..473090bdd4 100644 --- a/apps/web/tests/scaffold.ts +++ b/apps/web/tests/scaffold.ts @@ -1255,12 +1255,7 @@ export function realizeSeedFixture(scaffold: WebScaffold, fixtureText: string, i }).join('\n') } -/** - * Parse a committed web seed fixture through the replay reader. - * @param fixtureText - session JSONL fixture contents. - * @returns the current header line, parsed header, and logical events. - */ -/** Give a migrated fixture stream positive relative timing before its final wall-clock rebase. */ +/** Give reconstructed V0/V1 chunk streams positive intervals before the final wall-clock rebase. */ function spreadMigratedSeedStream( stream: SessionEvent<'assistant/message'>['data']['stream'], ): SessionEvent<'assistant/message'>['data']['stream'] { @@ -1277,6 +1272,12 @@ function spreadMigratedSeedStream( }) } +/** + * Parse a committed web seed fixture through the replay reader. + * Embedded streams retain their recorded timing; V0/V1 chunk streams receive positive relative intervals. + * @param fixtureText - session JSONL fixture contents. + * @returns the current header line, parsed header, and logical events. + */ export function parseSeedFixture(fixtureText: string): { headerLine: string header: Record @@ -1291,7 +1292,7 @@ export function parseSeedFixture(fixtureText: string): { const header = JSON.parse(headerLine) as Record if (header.type !== 'session') throw new Error('seed fixture must start with a session header') const events = parseSessionLog(current).map((event) => { - if (sourceHeader.version === SESSION_FORMAT_VERSION) return event + if (sourceHeader.version !== 0 && sourceHeader.version !== 1) return event if (event.type === 'assistant/message') { return { ...event, data: { ...event.data, stream: spreadMigratedSeedStream(event.data.stream) } } } diff --git a/packages/experimental/webworker-packer/README.i18n.yaml b/packages/experimental/webworker-packer/README.i18n.yaml index 2707041400..e6443c0a41 100644 --- a/packages/experimental/webworker-packer/README.i18n.yaml +++ b/packages/experimental/webworker-packer/README.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 packages/experimental/webworker-packer/README.md -README.md: 90723b7718393ed32005bd6146764044a8ec80b1 -README.zh.md: 9d7df43bf2b49d7b4a0438fcdb96fdbe44cc326a +README.md: 65a428cb82ec490cb1ff64432c372f912cc529de +README.zh.md: 8d3335dafb448fa6d2cd27395bb92dd97a4fb6c0 diff --git a/packages/experimental/webworker-packer/README.md b/packages/experimental/webworker-packer/README.md index 90723b7718..65a428cb82 100644 --- a/packages/experimental/webworker-packer/README.md +++ b/packages/experimental/webworker-packer/README.md @@ -35,7 +35,9 @@ The pack is a three-layer standard stack: `repository.ts` owns the repo-shaped inputs (workspace scan of `vendor/`, `packages/`, `native/system/packages/`, and `apps/`; profile composition through the real CLI dump path); `pack.ts` owns none of them, so the same library packs a different tree by being called differently. The native scan makes the Landlock entry package an ordinary published-view dependency while its executable remains a Worker platform implementation. The CLI is `dsh-pack-vfs-image --out [--profile web]`; `apps/web`'s `build:preview` runs it after the preview shell build. -The repository adapter also declares the preview-only fixture trees under `webworker-runtime/tests/fixtures/`. The CLI packs each named fixture into a separate deterministic overlay archive plus a browser-readable manifest. Overlay files bypass npm publish-view and module-reachability exclusions, so dot directories and example source files remain intact; their mounts are limited to `home/` and `workspace/`. `pack.ts` treats them as opaque bytes, and Session and Workspace interpretation stays in the runtime packages that own those formats. +The repository adapter also declares the preview-only fixture trees under `webworker-runtime/tests/fixtures/`. The CLI packs each named fixture into a separate deterministic overlay archive plus a browser-readable manifest. Overlay files bypass npm publish-view and module-reachability exclusions, so dot directories and example source files remain intact; their mounts are limited to `home/` and `workspace/`. `packVfsOverlay` treats all files as opaque bytes. + +`packPreviewFixture` prepares the newest canonical raw Session generation in each fixture directory through the [Session format catalog](../../session/session-format-catalog/README.md) in Node. It strictly restores the source, encodes and strictly validates the current successor, and packs that successor beside unchanged source files. A malformed, unsupported, or future selected generation refuses the build without falling back. Temporary successors are removed after packing. Browser write-open then uses current data without invoking Node's migration-verification Worker. Projection caches remain owner-validated; an older generation cannot supply a current fold checkpoint. ----- @@ -57,6 +59,7 @@ None; this package neither assembles nor sends a provider request. - **Vendored package sources (`src/*.ts`) are excluded** — nothing resolves them at runtime; a future in-worker source-inspection feature would need a dedicated include rule. - **The packer assumes built `lib/` artifacts are current**: it never compiles, so a stale workspace build packs stale bytes. Run the repository build first. - **The CLI requires its original repository location**: `dsh-pack-vfs-image` finds the checkout relative to its own installed file and reads the source CLI, configuration trees, and preview fixtures there. An npm installation supports the parameterized library API; the CLI and repository helpers require a complete, built DeepSeek Harness checkout. +- **Preview Session inputs use raw JSONL** — `packPreviewFixture` rejects compressed and noncanonical Session generation filenames. Generic overlays remain byte-preserving. diff --git a/packages/experimental/webworker-packer/README.zh.md b/packages/experimental/webworker-packer/README.zh.md index 9d7df43bf2..8d3335dafb 100644 --- a/packages/experimental/webworker-packer/README.zh.md +++ b/packages/experimental/webworker-packer/README.zh.md @@ -35,7 +35,9 @@ VFS 镜像打包器:把一份合成 profile 变成浏览器 worker 挂载为 `repository.ts` 拥有仓库形态输入(`vendor/`、`packages/`、`native/system/packages/` 与 `apps/` 的 workspace 扫描;经真 CLI dump 路径合成 profile);`pack.ts` 一概不拥有,同一库换参即可打另一棵树。Native 扫描使 Landlock 入口包成为普通发布视图依赖,其可执行文件仍由 Worker 平台实现。CLI 为 `dsh-pack-vfs-image --out [--profile web]`;`apps/web` 的 `build:preview` 在预览壳构建后运行它。 -仓库适配器还声明 `webworker-runtime/tests/fixtures/` 下仅用于 preview 的 fixture(测试前置数据) tree。CLI 会把每套具名 fixture 打成一份独立的确定性 overlay 归档,并写出浏览器可读的 manifest(元数据清单)。Overlay 文件绕过 npm 发布视图和模块可达性排除规则,因此点目录与示例源码会完整保留;其挂载位置仅限 `home/` 与 `workspace/`。`pack.ts` 把它们视为不透明字节;会话与 Workspace 的解释仍归拥有这些格式的运行时包。 +仓库适配器还声明 `webworker-runtime/tests/fixtures/` 下仅用于 preview 的 fixture(测试前置数据) tree。CLI 会把每套具名 fixture 打成一份独立的确定性 overlay 归档,并写出浏览器可读的 manifest(元数据清单)。Overlay 文件绕过 npm 发布视图和模块可达性排除规则,因此点目录与示例源码会完整保留;其挂载位置仅限 `home/` 与 `workspace/`。`packVfsOverlay` 将所有文件视为不透明字节。 + +`packPreviewFixture` 在 Node 中通过 [Session 格式目录](../../session/session-format-catalog/README.zh.md)准备每个 fixture 目录里最新的规范原始 Session 代际。它严格恢复源文件、编码并严格校验当前后继文件,然后将后继文件与未改变的源文件一同打包。如果选中的代际格式错误、不受支持或属于未来版本,构建会拒绝,不回退。临时后继文件在打包后删除。浏览器以写模式打开时即可使用当前数据,无需调用 Node 的迁移校验 Worker。投影缓存仍由其所属包校验;较早代际不能提供当前折叠检查点。 ----- @@ -57,6 +59,7 @@ VFS 镜像打包器:把一份合成 profile 变成浏览器 worker 挂载为 - **vendored 包源码(`src/*.ts`)被排除**——运行时无人解析它们;未来若有 worker 内源码巡检功能需要专门的 include 规则。 - **打包器假定构建产物 `lib/` 是新鲜的**:它从不编译,工作区构建陈旧就会打包陈旧字节。先跑仓库构建。 - **CLI 必须位于原有仓库位置**:`dsh-pack-vfs-image` 相对于自身安装文件定位检出目录,并从中读取源码 CLI、配置树和预览 fixture。npm 安装支持参数化的库 API;CLI 和仓库辅助函数需要完整且已构建的 DeepSeek Harness 检出目录。 +- **Preview Session 输入使用原始 JSONL** — `packPreviewFixture` 拒绝压缩文件与不规范的 Session 代际文件名。通用 overlay 仍逐字节保留输入。 diff --git a/packages/experimental/webworker-packer/package.json b/packages/experimental/webworker-packer/package.json index e62ace335a..280291fd67 100644 --- a/packages/experimental/webworker-packer/package.json +++ b/packages/experimental/webworker-packer/package.json @@ -36,6 +36,8 @@ "@deepseek-ai/cordis-plugin-include": "workspace:^", "@deepseek-ai/dsh-experimental-webworker-runtime": "workspace:^", "@deepseek-ai/dsh-home-paths": "workspace:^", + "@deepseek-ai/dsh-session-format": "workspace:^", + "@deepseek-ai/dsh-session-format-catalog": "workspace:^", "js-yaml": "^4.2.0", "picomatch": "^4.0.4" }, diff --git a/packages/experimental/webworker-packer/src/bin.ts b/packages/experimental/webworker-packer/src/bin.ts index 093fac23d5..629fa2a761 100644 --- a/packages/experimental/webworker-packer/src/bin.ts +++ b/packages/experimental/webworker-packer/src/bin.ts @@ -14,9 +14,9 @@ import { PREVIEW_FIXTURE_MANIFEST_FILE, PREVIEW_FIXTURE_MANIFEST_VERSION, type PreviewFixtureManifest, } from '@deepseek-ai/dsh-experimental-webworker-runtime' -import { packVfsImage, packVfsOverlay } from './pack.ts' +import { packVfsImage } from './pack.ts' import { - composeProfile, configTrees, describePack, indexWorkspacePackages, previewFixtures, + composeProfile, configTrees, describePack, indexWorkspacePackages, packPreviewFixture, previewFixtures, } from './repository.ts' /** @@ -66,7 +66,7 @@ const fixtureDirectory = join(dirname(outputFile), 'fixtures') mkdirSync(fixtureDirectory, { recursive: true }) const fixtureLines: string[] = [] const fixtures = fixtureDefinitions.map((fixture) => { - const packed = packVfsOverlay(fixture.trees) + const packed = packPreviewFixture(fixture.trees) const file = `fixtures/${fixture.id}.tar.gz` writeFileSync(join(dirname(outputFile), file), packed.image) fixtureLines.push(` fixture overlay ${fixture.id} (${String(packed.image.byteLength)} B compressed)`) diff --git a/packages/experimental/webworker-packer/src/index.ts b/packages/experimental/webworker-packer/src/index.ts index ea203a6f7a..5ebf1f260e 100644 --- a/packages/experimental/webworker-packer/src/index.ts +++ b/packages/experimental/webworker-packer/src/index.ts @@ -11,6 +11,6 @@ export { type ConfigTree, type ImageTree, type PackOptions, type PackOverlayResult, type PackResult, } from './pack.ts' export { - composeProfile, configTrees, describePack, indexWorkspacePackages, previewFixtures, + composeProfile, configTrees, describePack, indexWorkspacePackages, packPreviewFixture, previewFixtures, type PreviewFixture, } from './repository.ts' diff --git a/packages/experimental/webworker-packer/src/preview.ts b/packages/experimental/webworker-packer/src/preview.ts new file mode 100644 index 0000000000..cca1bb9824 --- /dev/null +++ b/packages/experimental/webworker-packer/src/preview.ts @@ -0,0 +1,79 @@ +/** Node-side Session preparation for browser Preview data overlays. */ + +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { dirname, join, posix } from 'node:path' +import { isSessionFormatJsonObject, parseSessionFormatLogFilename, sessionFormatLogFilename } from '@deepseek-ai/dsh-session-format' +import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { packVfsOverlay, type ImageTree, type PackOverlayResult } from './pack.ts' +import type { ImageFiles } from './transform-image.ts' + +interface PreviewSession { + readonly path: string + readonly directory: string + readonly id: string + readonly version: number + readonly bytes: Uint8Array +} + +/** + * Pack Preview data with strictly validated current Session successors prepared in Node. + * Committed source bytes remain in the overlay; only the newest canonical raw generation + * of each Session is restored. Future, malformed, and unsupported selected data refuse the pack. + * @param trees - Ordered source trees under the Preview's home and workspace mounts. + * @returns Deterministic overlay containing unchanged inputs and final current successors. + */ +export function packPreviewFixture(trees: readonly ImageTree[]): PackOverlayResult { + const original = packVfsOverlay(trees) + const successors = new Map() + for (const source of selectedSessions(original.files)) { + const text = new TextDecoder('utf-8', { fatal: true }).decode(source.bytes) + if (!text.endsWith('\n')) throw new Error(`preview fixture: ${source.path} has a torn physical tail`) + const [headerLine = '', ...rows] = text.slice(0, -1).split('\n') + const header: unknown = JSON.parse(headerLine) + if (!isSessionFormatJsonObject(header) || header['version'] !== source.version || header['id'] !== source.id) { + throw new Error(`preview fixture: ${source.path} disagrees with its Session header`) + } + const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + for (const row of rows) restore.decodeRow(JSON.parse(row)) + const artifact = restore.finish() + if (source.version === sessionFormatCatalog.currentVersion) continue + const encodedHeader = sessionFormatCatalog.encodeCurrentHeader(artifact.header, artifact.inheritedEventCount) + const encodedEvents = artifact.events.map(event => sessionFormatCatalog.encodeCurrentEvent(event)) + const verification = sessionFormatCatalog.createRestore(encodedHeader, { recovery: 'strict', validation: 'current' }) + for (const event of encodedEvents) verification.decodeRow(event) + verification.finish() + successors.set( + posix.join(source.directory, sessionFormatLogFilename(sessionFormatCatalog.currentVersion)), + [encodedHeader, ...encodedEvents].map(row => JSON.stringify(row) + '\n').join(''), + ) + } + if (successors.size === 0) return original + const directory = mkdtempSync(join(tmpdir(), 'dsh-preview-sessions-')) + try { + for (const [imagePath, content] of successors) { + const path = join(directory, imagePath.slice('home/sessions/'.length)) + mkdirSync(dirname(path), { recursive: true }) + writeFileSync(path, content, { flag: 'wx' }) + } + return packVfsOverlay([...trees, { mount: 'home/sessions', directory }]) + } finally { + rmSync(directory, { recursive: true, force: true }) + } +} + +function selectedSessions(files: ImageFiles): readonly PreviewSession[] { + const selected = new Map() + for (const [path, bytes] of Object.entries(files)) { + const match = /^home\/sessions\/[^/]+\/([^/]+)\/(session(?:\..*)?\.jsonl(?:\.zstd)?)$/u.exec(path) + if (match === null) continue + const version = parseSessionFormatLogFilename(match[2] as string) + if (version === undefined) throw new Error(`preview fixture: ${path} must name a canonical raw Session generation`) + const directory = posix.dirname(path) + const previous = selected.get(directory) + if (previous === undefined || previous.version < version) { + selected.set(directory, { path, directory, id: match[1] as string, version, bytes }) + } + } + return [...selected.values()] +} diff --git a/packages/experimental/webworker-packer/src/repository.ts b/packages/experimental/webworker-packer/src/repository.ts index dd012ba7c7..7314b4d612 100644 --- a/packages/experimental/webworker-packer/src/repository.ts +++ b/packages/experimental/webworker-packer/src/repository.ts @@ -14,6 +14,8 @@ import { join, relative } from 'node:path' import { DSH_HOME_ENV } from '@deepseek-ai/dsh-home-paths' import type { ConfigTree, ImageTree, PackResult } from './pack.ts' +export { packPreviewFixture } from './preview.ts' + /** * Repository directories scanned for workspace and vendored packages. The * image only ever materializes runtime packages, which live here. The Landlock diff --git a/packages/experimental/webworker-packer/tests/built-lib.e2e.ts b/packages/experimental/webworker-packer/tests/built-lib.e2e.ts index 9d74a12682..87ed0e83f1 100644 --- a/packages/experimental/webworker-packer/tests/built-lib.e2e.ts +++ b/packages/experimental/webworker-packer/tests/built-lib.e2e.ts @@ -76,6 +76,7 @@ it('loads both tarballs through plain Node and mounts their base image and overl import * as packer from '@deepseek-ai/dsh-experimental-webworker-packer' import * as runtime from '@deepseek-ai/dsh-experimental-webworker-runtime' import * as client from '@deepseek-ai/dsh-experimental-webworker-runtime/client' + import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' for (const name of ['webworker-packer', 'webworker-runtime']) { assert.equal(import.meta.resolve('@deepseek-ai/dsh-experimental-' + name), new URL('./node_modules/@deepseek-ai/dsh-experimental-' + name + '/lib/index.js', import.meta.url).href) @@ -93,6 +94,14 @@ it('loads both tarballs through plain Node and mounts their base image and overl const overlay = packer.packVfsOverlay([{ mount: 'workspace', directory: fileURLToPath(new URL('./overlay', import.meta.url)) }]) runtime.loadVfsOverlay(await runtime.inflateImage(overlay.image, 'packed overlay'), '/dsh', vfs) assert.equal(vfs.readFileSync('/dsh/workspace/hello.txt', 'utf8'), 'packed worker pair\\n') + mkdirSync('home/sessions/project/preview', { recursive: true }) + const historical = JSON.stringify({ type: 'session', version: 3, id: 'preview', createdAt: 1, isSeeded: false, delegationDepth: 0 }) + '\\n' + writeFileSync('home/sessions/project/preview/session.v3.jsonl', historical) + const prepared = packer.packPreviewFixture([{ mount: 'home', directory: fileURLToPath(new URL('./home', import.meta.url)) }]) + runtime.loadVfsOverlay(await runtime.inflateImage(prepared.image, 'prepared preview'), '/dsh', vfs) + assert.equal(vfs.readFileSync('/dsh/home/sessions/project/preview/session.v3.jsonl', 'utf8'), historical) + const current = JSON.parse(vfs.readFileSync('/dsh/home/sessions/project/preview/session.v' + sessionFormatCatalog.currentVersion + '.jsonl', 'utf8')) + assert.equal(current.version, sessionFormatCatalog.currentVersion) console.log('packed image and overlay mounted') ` await writeFile(join(root, 'consumer.mjs'), script) diff --git a/packages/experimental/webworker-packer/tests/preview.spec.ts b/packages/experimental/webworker-packer/tests/preview.spec.ts new file mode 100644 index 0000000000..2b03798032 --- /dev/null +++ b/packages/experimental/webworker-packer/tests/preview.spec.ts @@ -0,0 +1,102 @@ +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' +import { afterEach, describe, expect, it } from 'vitest' +import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { sessionFormatLogFilename } from '@deepseek-ai/dsh-session-format' +import { packPreviewFixture } from '../src/preview.ts' +import { packVfsOverlay } from '../src/pack.ts' +import { previewFixtures } from '../src/repository.ts' + +const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url)) +const roots: string[] = [] +const currentVersion = sessionFormatCatalog.currentVersion +const text = (bytes: Uint8Array | undefined): string => new TextDecoder().decode(bytes) + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }) +}) + +function source() { + const root = mkdtempSync(join(tmpdir(), 'dsh-preview-source-')) + roots.push(root) + const session = join(root, 'sessions', 'project', 'example') + mkdirSync(session, { recursive: true }) + return { + trees: [{ mount: 'home', directory: root }], + put(version: number, body = '', overrides: Record = {}) { + const path = join(session, sessionFormatLogFilename(version)) + const header = { type: 'session', version, id: 'example', createdAt: 1, isSeeded: false, delegationDepth: 0, ...overrides } + writeFileSync(path, JSON.stringify(header) + '\n' + body) + return path + }, + } +} + +function restore(bytes: Uint8Array | undefined) { + const [header, ...rows] = text(bytes).trimEnd().split('\n').map(row => JSON.parse(row) as unknown) + const reader = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + for (const row of rows) reader.decodeRow(row) + return reader.finish() +} + +describe('Node preparation of Preview Session data', () => { + it('packs strictly migrated current successors beside every unchanged example file', () => { + const fixture = previewFixtures(repoRoot)[0]! + const original = packVfsOverlay(fixture.trees) + const projected = packPreviewFixture(fixture.trees) + const currentFiles = Object.keys(projected.files).filter(path => path.endsWith('/' + sessionFormatLogFilename(currentVersion))) + expect(currentFiles).toHaveLength(3) + for (const [path, bytes] of Object.entries(original.files)) expect(projected.files[path], path).toEqual(bytes) + for (const path of currentFiles) { + const sourcePath = path.replace(/\/session\.v\d+\.jsonl$/u, '/session.v3.jsonl') + expect(restore(projected.files[path])).toEqual(restore(original.files[sourcePath])) + expect(JSON.parse(text(projected.files[path]).split('\n')[0]!)).toMatchObject({ version: currentVersion }) + } + expect(packPreviewFixture(fixture.trees).image).toEqual(projected.image) + expect(packVfsOverlay(fixture.trees).files).toEqual(original.files) + }) + + it('uses the highest generation and leaves an already-current image byte-identical', () => { + const fixture = source() + const older = fixture.put(3, '{invalid historical data}\n') + fixture.put(currentVersion) + const original = packVfsOverlay(fixture.trees) + expect(packPreviewFixture(fixture.trees).image).toEqual(original.image) + expect(text(original.files['home/sessions/project/example/session.v3.jsonl'])).toBe(readFileSync(older, 'utf8')) + }) + + it('keeps an overlay without Sessions opaque', () => { + const fixture = source() + expect(packPreviewFixture(fixture.trees)).toEqual(packVfsOverlay(fixture.trees)) + }) + + it.each(['future', 'corrupt', 'unknown-required'] as const)('refuses selected %s data without falling back or changing inputs', (mode) => { + const fixture = source() + fixture.put(3) + const path = fixture.put(mode === 'future' ? currentVersion + 1 : currentVersion, + mode === 'corrupt' ? '{invalid JSON}\n' + : mode === 'unknown-required' ? JSON.stringify({ type: 'external/required', seq: 0, time: 1, data: null }) + '\n' : '') + const before = readFileSync(path) + expect(() => packPreviewFixture(fixture.trees)).toThrow() + expect(readFileSync(path)).toEqual(before) + }) + + it.each([{ version: 2 }, { id: 'other' }])('refuses selected metadata that disagrees with its location: %j', (overrides) => { + const fixture = source() + fixture.put(3, '', overrides) + expect(() => packPreviewFixture(fixture.trees)).toThrow('disagrees with its Session header') + }) + + it('refuses a torn physical tail and compressed Session generations', () => { + const fixture = source() + const path = fixture.put(3) + const bytes = readFileSync(path) + writeFileSync(path, bytes.subarray(0, -1)) + expect(() => packPreviewFixture(fixture.trees)).toThrow('torn physical tail') + writeFileSync(path, bytes) + writeFileSync(join(dirname(path), sessionFormatLogFilename(currentVersion) + '.zstd'), 'compressed data') + expect(() => packPreviewFixture(fixture.trees)).toThrow('canonical raw Session generation') + }) +}) diff --git a/packages/experimental/webworker-packer/tsconfig.json b/packages/experimental/webworker-packer/tsconfig.json index 152b9ad8c2..d7021210ec 100644 --- a/packages/experimental/webworker-packer/tsconfig.json +++ b/packages/experimental/webworker-packer/tsconfig.json @@ -19,6 +19,12 @@ }, { "path": "../../util/home-paths" + }, + { + "path": "../../session/session-format" + }, + { + "path": "../../session/session-format-catalog" } ] } diff --git a/packages/experimental/webworker-runtime/README.i18n.yaml b/packages/experimental/webworker-runtime/README.i18n.yaml index 1b815a3e4a..5a5a2d00a7 100644 --- a/packages/experimental/webworker-runtime/README.i18n.yaml +++ b/packages/experimental/webworker-runtime/README.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 packages/experimental/webworker-runtime/README.md -README.md: 724e47a004fac83fe0f19a588faf0c227d843232 -README.zh.md: 4e88b3cf10f98a423268c60b69269d2550d2c1f9 +README.md: de423c3606f1fd24582b6db1d3ffd011bfd4e632 +README.zh.md: ca5ca793e7c56b1b1fccb65b356f3c98c03cac2b diff --git a/packages/experimental/webworker-runtime/README.md b/packages/experimental/webworker-runtime/README.md index 724e47a004..de423c3606 100644 --- a/packages/experimental/webworker-runtime/README.md +++ b/packages/experimental/webworker-runtime/README.md @@ -32,7 +32,7 @@ Three build artifacts and one source-owned process layer: - **`src/shell/` (the worker's own process layer)** — a browser worker cannot fork, so `node:child_process` is not a stub but an implementation: `spawn` starts the command in its own Web Worker — this same bundle, told by its first frame to be a shell process — and reports it through the `ChildProcess` surface the subprocess service consumes. The command runs off the host's thread, `SIGKILL` terminates it whatever it is doing, and it reaches the VFS only by message (the host serves those frames). Worker platform executables preserve native-package protocols such as Landlock without replacing their JavaScript packages or coupling their implementations to `node:child_process`; ordinary commands use the package's evaluator and coreutils command table. The grammar is `@yarnpkg/parsers`' `parseShell`, while `execSync`/`fork` still refuse because they need a real process. - **`lib/client.js` (page half)** — startup has two independent stages. `chooseWorkerHostSource({ image?, fixtureManifest? })` optionally owns the boot barrier and fixture manifest: without `preview-fixture` it waits at the source chooser, while a valid query selects directly; either path returns ordered overlays. `connectWorkerHost(worker, { image?, overlays? })` remains the public base-runtime connector; callers that skip the chooser get an empty overlay list. `apps/web` invokes both and supplies its statically bundled Worker. The opening `init` frame carries the base and ordered overlay URLs, the boot payload delivers the structured index-injection table, and `applyIndexInjections` executes it before the shell entry runs. Script preload rows are advisory and skipped because `/plugins` resources resolve only through the tunnel; `loadBundle` fetches each combo on first demand, embeds its tunnel-only source map as a Base64 data URL, and executes the script as a Blob. The tunnel also exposes fetch-shaped transport, the independent file-upload carrier, and the API client. Request frames preserve Blob bodies through structured clone and transfer `ReadableStream` ownership. The Host Worker streams both forms into the route, so neither browser thread creates a complete byte array for a generic-file upload. -Acceptance lives in `apps/web/tests/preview-boot.e2e.ts`, which serves the real built pages and drives the pre-boot chooser plus Worker activation in headless Chromium. The empty selection exercises first-run startup. The `vfs-example` overlay supplies ordinary workspace files and plaintext persistence artifacts for cold Workspace/Session discovery, tool presentation, subagent navigation, and history paging without a model request. The fixture generator owns current-generation logs and the projection cache; committed predecessor logs remain byte-identical alongside them. The chooser reserves WebFS as a separate user-authorized source; that provider does not read the built-in fixture. +Acceptance lives in `apps/web/tests/preview-boot.e2e.ts`, which serves the real built pages and drives the pre-boot chooser plus Worker activation in headless Chromium. The empty selection exercises first-run startup. The `vfs-example` overlay supplies ordinary workspace files and plaintext persistence artifacts for cold Workspace/Session discovery, tool presentation, subagent navigation, and history paging without a model request. The [packer](../webworker-packer/README.md) prepares current-generation successors from committed historical logs in Node; those source logs remain byte-identical in the overlay. The fixture generator owns the acceptance test's current projection cache. The chooser reserves WebFS as a separate user-authorized source; that provider does not read the built-in fixture. The [built-bundle import sweep](tests/compile/transform-corpus-check.ts) checks bare Node imports after the library build. Its Dockkit exception accepts Node’s unknown-`.css`-extension refusal for any stylesheet rather than one pinned path; another extension, error code, or message, and an unexpectedly successful exempt import, remain errors. See the [stylesheet exemption decision](../../../.agents/notes/implemented/bug-fix/2026-09-10-built-bundle-css-exemption.md). diff --git a/packages/experimental/webworker-runtime/README.zh.md b/packages/experimental/webworker-runtime/README.zh.md index 4e88b3cf10..ca5ca793e7 100644 --- a/packages/experimental/webworker-runtime/README.zh.md +++ b/packages/experimental/webworker-runtime/README.zh.md @@ -32,7 +32,7 @@ kind: "package-library" - **`src/shell/`(worker 自己的进程层)**——浏览器 worker 无法 fork,所以 `node:child_process` 不是 stub 而是实现:`spawn` 把命令放进它自己的 Web Worker——就是这同一个束,由首帧告诉它「你是 shell 进程」——并以 subprocess 服务消费的 `ChildProcess` 面报告结果。命令不占宿主线程,`SIGKILL` 不管它在干什么都能终止它,而它只能靠消息触达 VFS(由宿主应答这些帧)。Worker 平台 executable 在不替换 JavaScript 包、也不把具体实现耦合进 `node:child_process` 的情况下保持 Landlock 等 native 包协议;普通命令使用本包的求值器与 coreutils 命令表。语法来自 `@yarnpkg/parsers` 的 `parseShell`,而 `execSync`/`fork` 依然拒绝,因为它们需要真进程。 - **`lib/client.js`(页面半)**——启动分为相互独立的两段。`chooseWorkerHostSource({ image?, fixtureManifest? })` 可选地拥有 boot barrier 与 fixture manifest:没有 `preview-fixture` 时停在来源选择面板,合法 query 则直接选择;两条路径都返回按序排列的 overlays。`connectWorkerHost(worker, { image?, overlays? })` 仍是公开的基础运行态连接器;调用方跳过选择器时 overlay 列表为空。`apps/web` 调用这两段并提供静态打包的 Worker。开局 `init` 帧携带基础镜像与按序排列的 overlay URL,boot 载荷送达结构化 index 注入表,`applyIndexInjections` 在壳入口运行前逐行执行。脚本 preload 行只是提示,因此会被跳过:`/plugins` 资源只能经 tunnel 解析,`loadBundle` 会在首次需要时获取 combo、把仅 tunnel 可达的 sourcemap 内嵌为 Base64 data URL,再以 Blob 执行脚本。Tunnel 还暴露 fetch 形式的传输、独立文件上传载体和 API 客户端。请求帧通过结构化克隆保留 Blob 请求体,并转移 `ReadableStream` 的所有权。Host Worker 将两种请求体都逐块送入路由,因此通用文件上传不会在任何浏览器线程创建完整字节数组。 -验收在 `apps/web/tests/preview-boot.e2e.ts`:静态服务真实构建页面,在 headless Chromium 里驱动 pre-boot 选择面板与 Worker 激活。空白选择验证首次启动;`vfs-example` overlay 提供普通 workspace 文件与明文 persistence 产物,无需模型请求即可验证 Workspace/Session 冷发现、工具呈现、subagent 导航和历史分页。fixture 生成器负责当前代日志与投影缓存;已提交的前代日志逐字节保持不变,与它们并存。选择面板为 WebFS 保留独立的用户授权来源;该 provider 不读取内置 fixture。 +验收在 `apps/web/tests/preview-boot.e2e.ts`:静态服务真实构建页面,在 headless Chromium 里驱动 pre-boot 选择面板与 Worker 激活。空白选择验证首次启动;`vfs-example` overlay 提供普通 workspace 文件与明文 persistence 产物,无需模型请求即可验证 Workspace/Session 冷发现、工具呈现、subagent 导航和历史分页。[打包器](../webworker-packer/README.zh.md)在 Node 中根据已提交的历史日志准备当前代后继文件;这些源日志在 overlay 中逐字节保持不变。fixture 生成器负责验收测试的当前投影缓存。选择面板为 WebFS 保留独立的用户授权来源;该 provider 不读取内置 fixture。 [已构建 bundle 导入检查](tests/compile/transform-corpus-check.ts)在库构建后检查裸 Node 导入。Dockkit 例外接受 Node 针对任意样式表报告的未知 `.css` 扩展名错误,而不限定某一固定路径;其他扩展名、错误码或消息,以及意外成功的豁免导入,仍然报错。参见 [样式表豁免决策](../../../.agents/notes/implemented/bug-fix/2026-09-10-built-bundle-css-exemption.zh.md)。 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1da5093b1e..aa704b0458 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6495,6 +6495,12 @@ importers: '@deepseek-ai/dsh-home-paths': specifier: workspace:^ version: link:../../util/home-paths + '@deepseek-ai/dsh-session-format': + specifier: workspace:^ + version: link:../../session/session-format + '@deepseek-ai/dsh-session-format-catalog': + specifier: workspace:^ + version: link:../../session/session-format-catalog js-yaml: specifier: ^4.2.0 version: 4.3.1 From 1d1ae1a5afbfb05bdb97f039a3e1cdcb1f6f4d97 Mon Sep 17 00:00:00 2001 From: Dudu-0223 Date: Wed, 16 Sep 2026 10:36:23 +0800 Subject: [PATCH 006/279] fix(session): migrate historical subagent catalogs to V4 --- ...leased-session-format-migrations.i18n.yaml | 4 +- ...8-31-released-session-format-migrations.md | 42 +- ...1-released-session-format-migrations.zh.md | 42 +- docs/config-catalog.i18n.yaml | 4 +- docs/config-catalog.md | 4 +- docs/config-catalog.zh.md | 4 +- .../2026-09-16-session-format-v4.i18n.yaml | 4 +- .../2026-09-16-session-format-v4.md | 8 +- .../2026-09-16-session-format-v4.zh.md | 8 +- .../webworker-packer/README.i18n.yaml | 4 +- .../experimental/webworker-packer/README.md | 2 +- .../webworker-packer/README.zh.md | 2 +- .../webworker-packer/package.json | 1 + .../webworker-packer/src/preview.ts | 21 +- .../webworker-packer/tests/preview.spec.ts | 37 +- .../webworker-packer/tsconfig.json | 3 + .../tests/vfs-example-fixture.spec.ts | 4 +- .../session-format-catalog/README.i18n.yaml | 4 +- .../session/session-format-catalog/README.md | 5 +- .../session-format-catalog/README.zh.md | 5 +- .../session-format-catalog/src/children.ts | 19 + .../session-format-catalog/src/generated.ts | 10 +- .../session-format-catalog/src/historical.ts | 21 + .../session-format-catalog/src/index.ts | 2 + .../tests/catalog.spec.ts | 38 +- .../tests/children.spec.ts | 38 ++ .../tests/preset-migration.spec.ts | 6 +- .../session-format-v3-to-v4/README.i18n.yaml | 4 +- .../session/session-format-v3-to-v4/README.md | 32 +- .../session-format-v3-to-v4/README.zh.md | 32 +- .../session-format-v3-to-v4/src/facts.ts | 88 +++++ .../session-format-v3-to-v4/src/index.ts | 5 +- .../session-format-v3-to-v4/src/migration.ts | 71 +++- .../session-format-v3-to-v4/src/validation.ts | 25 +- .../tests/catalog-completion.spec.ts | 150 ++++++++ .../tests/codec.spec.ts | 12 +- .../tests/corpus.spec.ts | 103 +++++ .../tests/migration.spec.ts | 38 +- .../session-log-deepseek/tests/upload.spec.ts | 32 ++ .../README.i18n.yaml | 4 +- .../session-persistence-jsonl/README.md | 8 +- .../session-persistence-jsonl/README.zh.md | 8 +- .../src/catalog-migration.ts | 82 ++++ .../session-persistence-jsonl/src/format.ts | 3 +- .../src/generation.ts | 37 +- .../session-persistence-jsonl/src/index.ts | 149 +++++-- .../tests/catalog-migration.perf.ts | 77 ++++ .../tests/catalog-migration.spec.ts | 364 ++++++++++++++++++ .../tests/generation.spec.ts | 19 +- .../tests/jsonl.spec.ts | 19 + .../test-support/llm-replay/README.i18n.yaml | 4 +- packages/test-support/llm-replay/README.md | 2 + packages/test-support/llm-replay/README.zh.md | 2 + packages/test-support/llm-replay/src/index.ts | 3 +- .../llm-replay/tests/llm-replay.spec.ts | 30 +- .../session-snapshot/README.i18n.yaml | 4 +- .../test-support/session-snapshot/README.md | 2 + .../session-snapshot/README.zh.md | 2 + .../session-snapshot/src/index.ts | 1 + .../session-snapshot/src/suite.ts | 31 +- .../session-snapshot/tests/suite.spec.ts | 27 ++ pnpm-lock.yaml | 3 + scripts/gen-session-format-catalog.ts | 10 +- snapshots/sdk/sdk.snapshot.ts | 4 +- 64 files changed, 1668 insertions(+), 161 deletions(-) create mode 100644 packages/session/session-format-catalog/src/children.ts create mode 100644 packages/session/session-format-catalog/src/historical.ts create mode 100644 packages/session/session-format-catalog/tests/children.spec.ts create mode 100644 packages/session/session-format-v3-to-v4/src/facts.ts create mode 100644 packages/session/session-format-v3-to-v4/tests/catalog-completion.spec.ts create mode 100644 packages/session/session-format-v3-to-v4/tests/corpus.spec.ts create mode 100644 packages/session/session-persistence-jsonl/src/catalog-migration.ts create mode 100644 packages/session/session-persistence-jsonl/tests/catalog-migration.perf.ts create mode 100644 packages/session/session-persistence-jsonl/tests/catalog-migration.spec.ts diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml index 13d5415c62..ce6cf70bb0 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.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 .agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md -2026-08-31-released-session-format-migrations.md: 8d7b8cbc06b77fbe3587593df65f454cf7752518 -2026-08-31-released-session-format-migrations.zh.md: 0443740ff1b724cd4f27dd636cd3dff381824f5a +2026-08-31-released-session-format-migrations.md: 379b4b735e1aaacb664faac57831b842de82c743 +2026-08-31-released-session-format-migrations.zh.md: 0a2790f81987deb145845295064b1ef5a3bbcba7 diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md index 8d7b8cbc06..379b4b735e 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md @@ -67,7 +67,7 @@ The chain contains no `flatMap`, spread expansion, intermediate event array, or ### Adjacent version ownership -The [V3-to-V4 specification](../../../../packages/session/session-format-v3-to-v4/README.md#v3-to-v4-specification) owns an identity body conversion: it advances the header version while preserving admitted events and inherited cuts. It reuses the frozen V3 codec from V2→V3. Generation-aware delivery validation prevents a historical acknowledgement from acquiring a current watermark meaning solely through the header change; earlier edges retain their own source-admission policies. +The [V3-to-V4 specification](../../../../packages/session/session-format-v3-to-v4/README.md#v3-to-v4-specification) specifies parent catalog completion: it advances the header version, preserves admitted events and inherited cuts, and appends missing own catalog entries from child evidence. It reuses the frozen V3 codec from V2→V3. Generation-aware delivery validation prevents a historical acknowledgement from acquiring a current watermark meaning solely through the header change; earlier edges retain their own source-admission policies. The [V2-to-V3 delivery guards](../../../../packages/session/session-format-v2-to-v3/README.md#delivery-guards) prevent a marker ignored in the source generation from becoming an active upload watermark merely because the header changes. Python release smoke checks generated logs against the source `SESSION_FORMAT_VERSION` independently of generation-neutral golden comparison, so coherent filenames and headers cannot conceal an outdated writer. @@ -99,7 +99,7 @@ Current encoding is record based. The provider serializes about 1 MiB of plainte The shipped `lib/worker.cjs` bundles its JavaScript workspace dependencies so each fresh verifier avoids resolving and compiling their runtime module graph. This is safe because the Worker communicates through plain request/result messages and shares no service or class identity with its host. The Host build applies the existing TypeScript and Typert transforms; the Client pass skips this Node-only package instead of replacing its worker with untransformed source. Native add-ons remain external. Verification, scheduler admission, termination, and durable publication still complete before writable open returns. The built-worker smoke copies the package manifest and worker into an isolated temporary package with ambient module paths removed, accepts a valid generation, and rejects an incorrect event count. -The [browser preview packer](../../../../packages/experimental/webworker-packer/README.md) prepares current successors for bundled Session data in Node. The browser host does not implement `node:worker_threads`, so this preparation preserves both immutable fixture generations and runtime JSONL’s Worker verification requirement. +The [browser preview packer](../../../../packages/experimental/webworker-packer/README.md) prepares current successors for bundled Session data in Node, using same-root direct-child descriptors as parent catalog evidence. The browser host does not implement `node:worker_threads`, so this preparation preserves both immutable fixture generations and runtime JSONL’s Worker verification requirement. Preparation forwards cancellation through source reads and observes it at the existing approximately 500 ms Decode yield boundary. Once `publish()` starts, encode, Worker verification, and publication do not receive caller cancellation and run to settlement; write open checks its caller signal again afterward. A published generation is never rolled back. @@ -127,6 +127,44 @@ Existing write handles retain the process-local claim and kernel-backed cross-pr | Verification repeats on the main thread | At most two complete-generation Workers | Keeps verification CPU off the main thread | | Production and fixture migration use different APIs | Catalog `createRestore()` with explicit policies | One decoder/chain implementation | +### Parent catalog prerequisites + +V3→V4 completes parent child discovery from retained direct-child headers and own descriptors. Storage supplies compact descriptor evidence to the catalog assembly, which binds it into the V3→V4 stage factory; the Stage waits for the parent's final inherited cut before validating catalog payloads and requiring complete own discovery facts. Nested seed markers discard inherited catalog candidates without interpreting their payloads. An existing catalog entry survives an unavailable descriptor, including a child that failed before its first step. Descriptor v1 denotes continuable mode; v2/v3 explicitly record mode. Available discovery fields must agree with the parent; absent entries require a supported descriptor. Missing evidence refuses migration rather than reporting parent corruption. JSONL rechecks related membership and source revisions when preparing, reusing, and publishing. An unsupported generation or unreadable header elsewhere in that scan refuses migration because it cannot prove unrelatedness. Source drift invalidates preparation; read open retries once automatically, while write open refuses publication. Diagnostics retain the offending child path and distinguish unsupported migration evidence from malformed child data. The storage decoder classifies physical JSON and compression failures before the collector adds child context; filesystem reads and cancellation keep their original errors. The V0–V3-only catalog avoids recursive child migration. Current V4 reads skip that scan but apply the same own-catalog field, uniqueness, and current delivery ownership checks as strict restoration. See the [format specification](../../../../packages/session/session-format-v3-to-v4/README.md). + +Raw parent/child migration tests retain 24 historical creation-time conflicts as rejection evidence. Detached controls align only the child creation time and prove event-preserving restoration, including a published child without a descriptor. Headless/ACP and SDK snapshot adapters validate live parent/child clocks before normalization and preserve their equality during refresh; committed predecessor generations remain unchanged. + +Historical public revisions combine the parent’s physical revision with a fingerprint of every selected canonical path and its filesystem revision. Parent-only tokens cannot identify catalog changes supplied by children; a root fingerprint preserves metadata-only `stat`/`list` and includes unreadable or unsupported members without a new persistent index. Unrelated changes also invalidate historical caches, and obtaining the token costs a root scan. Current tokens stay file-local. The preparation memo keeps physical parent revisions and separately validates child membership and revisions. + +The generic format interfaces carry only the artifact being restored. Parent-specific catalog assembly replaces the V3→V4 declaration with a closure over the collected child evidence; it reuses the generated codec, migration, and validation inventory. The assembly compiles one short migration chain per parent preparation, with independent stage state per restore. Binding at assembly keeps child evidence out of generic restore options and stage inputs without moving discovery or source revalidation into the migration. Static header and native current reads need no child evidence; an unbound historical body restore refuses rather than assuming an empty child set. + + +### Catalog scan measurements + +The package-local [diagnostic](../../../../packages/session/session-persistence-jsonl/tests/catalog-migration.perf.ts) measures one raw V3 parent, four direct children with 1,000 events each, and 0/100/1,000 unrelated header-only V3 Sessions. Each sample creates its own temporary corpus and Cordis context in a fresh process, runs stat → cold read → memo read → write publication → current warm read, and disposes the context and files. It uses built workspace exports under plain Node; fixture creation is outside the measured intervals. These are filesystem-cache-warm observations after fixture creation, not disk-cold latency or a performance gate. + +On macOS arm64 with Node v26.0.0, all three samples per size are below in milliseconds. Read-only opens do not publish: membership scanning remains proportional to corpus size even when decoding is memoized. The 1,000-unrelated medians are 84.14 ms for stat, 237.97 ms for cold read, 110.98 ms for memo read, 268.46 ms for publication, and 0.41 ms for the same-process current read. These measurements document the cost; they establish no speedup claim or cross-host threshold. + +| Unrelated Sessions | Historical stat | Cold read | Memo read | Publish | Current warm read | +|---:|---:|---:|---:|---:|---:| +| 0 | 5.17 | 19.00 | 1.36 | 42.88 | 0.47 | +| 0 | 3.30 | 14.87 | 1.45 | 35.75 | 0.41 | +| 0 | 3.18 | 16.71 | 1.50 | 34.51 | 0.47 | +| 100 | 29.44 | 77.48 | 17.01 | 60.66 | 0.43 | +| 100 | 12.42 | 42.71 | 13.69 | 60.19 | 0.43 | +| 100 | 11.19 | 41.06 | 12.61 | 57.18 | 0.39 | +| 1000 | 84.14 | 237.97 | 109.86 | 284.96 | 0.48 | +| 1000 | 99.41 | 259.88 | 123.50 | 268.46 | 0.41 | +| 1000 | 75.40 | 236.64 | 110.98 | 247.69 | 0.39 | + +Run from the repository root after building the runtime: + +```sh +pnpm run build:lib:host +cd packages/session/session-persistence-jsonl +node --input-type=module -e 'import { build } from "tsdown"; await build({ config: false, entry: ["tests/catalog-migration.perf.ts"], outDir: ".artifacts/perf", tsconfig: false, dts: false, deps: { neverBundle: [/^@deepseek-ai\//], onlyBundle: false } })' +node .artifacts/perf/catalog-migration.perf.mjs +``` + ## Verification The migration specification requires evidence for transformations, preservation, and refusal separately. Direct-edge and native V3 tests cannot establish seeded multi-hop publication: preceding assistant-stream folding changes source coordinates before V3 inserts system events. Tests through the real catalog and JSONL provider therefore need raw and compressed V0/V1 inputs, mapped references and inherited cuts, publish/reopen equivalence, unchanged predecessor bytes, and no intermediate generations. Coverage percentages alone cannot prove those cross-stage relationships; combined assertions must compare the resulting history and refusal effects. diff --git a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md index 0443740ff1..0a2790f819 100644 --- a/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md @@ -67,7 +67,7 @@ Chain 中不存在 `flatMap`、spread expansion、中间 event array 或 schedul ### 相邻版本所有权 -[V3 到 V4 规范](../../../../packages/session/session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)负责 body 的恒等转换:它推进 header 版本,同时保留已接纳的事件与继承切点。它复用 V2→V3 中冻结的 V3 codec。按 generation 校验 delivery 可防止历史确认仅因 header 变化而获得当前水位含义;更早的 migration edge 保留各自的来源准入策略。 +[V3 到 V4 规范](../../../../packages/session/session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)规定父目录补全:它推进 header 版本,保留已接纳的事件与继承切点,并根据子 Session 证据追加缺失的自身目录记录。它复用 V2→V3 中冻结的 V3 codec。按 generation 校验 delivery 可防止历史确认仅因 header 变化而获得当前水位含义;更早的 migration edge 保留各自的来源准入策略。 [V2 到 V3 投递保护](../../../../packages/session/session-format-v2-to-v3/README.zh.md#delivery-guards)防止源代中被忽略的标记仅因头部变化就成为有效上传水位。Python 发布冒烟测试独立于跨代 golden 比较,按源代码中的 `SESSION_FORMAT_VERSION` 检查生成日志,因此文件名与 header 自洽不能掩盖过期 writer。 @@ -99,7 +99,7 @@ Current encode 以单条 record 为单位。Provider 在主线程每个 slice 发布的 `lib/worker.cjs` 将 JavaScript workspace 依赖一起打包,使每个新 verifier 无需解析并编译它们的运行时模块图。Worker 只通过普通 request/result 消息通信,与 host 不共享 service 或 class identity,因此可以这样处理。Host build 应用现有 TypeScript 与 Typert 转换;Client pass 跳过这个 Node-only package,不会用未经转换的源代码覆盖 worker。Native add-on 保持 external。Verification、scheduler admission、termination 与 durable publication 仍在 writable open 返回前完成。Built-worker 冒烟测试把 package manifest 与 worker 复制到隔离的临时 package,移除环境中的模块搜索路径,接受有效 generation,并拒绝错误的 event count。 -[浏览器 preview 打包器](../../../../packages/experimental/webworker-packer/README.zh.md)在 Node 中为随包 Session 数据准备当前代际后继。浏览器 host 未实现 `node:worker_threads`,因此打包阶段的准备同时保留不可变 fixture 代际与运行时 JSONL 的 Worker 校验要求。 +[浏览器 preview 打包器](../../../../packages/experimental/webworker-packer/README.zh.md)在 Node 中为随包 Session 数据准备当前代际后继,并使用同一根目录中直属子 Session 的 descriptor 作为父目录证据。浏览器 host 未实现 `node:worker_threads`,因此打包阶段的准备同时保留不可变 fixture 代际与运行时 JSONL 的 Worker 校验要求。 Preparation 会把 cancellation 传给 source read,并在现有的约 500 ms Decode yield 边界观察它。`publish()` 一旦开始,encode、Worker verification 与 publication 不接收 caller cancellation,并运行到终态;write open 会在之后再次检查 caller signal。已经发布的 generation 绝不会回滚。 @@ -127,6 +127,44 @@ POSIX publication 使用 hard-link creation 加目录 sync;Windows 使用 no-o | 主线程重复执行完整 verification | 最多两个 complete-generation Worker | Verification CPU 不占用主线程 | | Production 与 fixture 使用不同 migration API | Catalog `createRestore()` 加显式 policy | 只保留一套 decoder/chain 实现 | +### 父目录前置事实 + +V3→V4 使用保留的直属子 Session header 和自身 descriptor 补齐父 Session 的子代理发现记录。存储将紧凑的 descriptor 证据提供给 catalog 组装处,由其绑定到 V3→V4 stage 工厂;Stage 等待父 Session 的最终继承截点确定后,才校验目录 payload 并要求完整的自身发现事实。嵌套的 seed 标记丢弃继承目录候选,不解释其 payload。已有目录记录允许 descriptor 不可用,包括在首次 step 之前失败的子 Session。Descriptor v1 表示 continuable 模式;v2/v3 显式记录模式。可获得的发现字段必须与父目录一致;缺失记录要求受支持的 descriptor。证据不足会拒绝迁移,而不是报告父日志损坏。JSONL 在准备、复用和发布时重新检查关联成员与来源修订。扫描中其他任何不支持代际或不可读 header 都会拒绝迁移,因为无法证明它与父 Session 无关。来源变化使准备缓存失效;只读打开自动重试一次,写打开则拒绝发布。诊断保留出错子日志的路径,并区分不支持的迁移证据与畸形子数据。存储解码器先将物理 JSON 与压缩错误归类,再由收集器补充子日志信息;文件系统读取与取消保留原始错误。仅支持 V0–V3 的目录避免递归迁移子 Session。当前 V4 读取跳过该扫描,但会执行与严格恢复相同的自身目录字段、唯一性及当前投递归属检查。见[格式规范](../../../../packages/session/session-format-v3-to-v4/README.zh.md)。 + +原始父子迁移测试保留 24 个历史创建时间冲突作为拒绝证据。独立的内存对照只对齐子创建时间,证明恢复保留事件,包括已发布但没有 descriptor 的子 Session。Headless/ACP 与 SDK 快照适配器在规范化之前校验实时父子时钟,并在刷新时保持两者相等;已提交的前代文件保持不变。 + +历史格式的公开修订号组合父日志物理修订号与每个所选规范路径及其文件系统修订号的指纹。仅父日志令牌无法标识子日志提供的目录变化;全库指纹让 `stat`/`list` 保持只读元数据,也纳入不可读或不支持的成员,无需新增持久化索引。无关变化也会使历史缓存失效,获取令牌需要扫描根目录。当前格式令牌仍只取决于自身文件。准备缓存保留父日志物理修订号,并独立校验子成员集合与修订。 + +通用格式接口只传递正在恢复的 artifact。每个父 Session 的 catalog 组装将 V3→V4 声明替换为捕获已收集子 Session 证据的闭包,并复用生成的 codec、迁移与校验清单。每次父 Session 准备只编译一条短迁移链,每次恢复拥有独立的 stage 状态。在组装处绑定证据,使通用恢复选项和 stage 输入不必携带子 Session 证据,同时保留存储对发现与来源重验的所有权。静态 header 和原生当前格式读取不需要子 Session 证据;未绑定的历史正文恢复会拒绝,不会假定子 Session 集合为空。 + + +### 目录扫描测量 + +包内[诊断脚本](../../../../packages/session/session-persistence-jsonl/tests/catalog-migration.perf.ts)测量一个原始 V3 父日志、四个各有 1,000 条事件的直属子日志,以及 0/100/1,000 个只有 header 的无关 V3 Session。每个样本在新进程中创建独立临时日志库与 Cordis 上下文,按 stat → 冷读 → 缓存读取 → 写入发布 → 当前格式热读顺序执行,最后释放上下文并删除文件。脚本在普通 Node 下使用已构建的工作区导出;创建夹具不计入测量区间。这些结果是夹具创建后的文件系统缓存热态观察,不代表磁盘冷读延迟,也不是性能门禁。 + +以下为 macOS arm64、Node v26.0.0 下各规模的全部三个样本,单位为毫秒。只读打开不发布后继:即使解码结果已缓存,成员扫描仍与日志库规模成正比。1,000 个无关日志时,中位数分别为 stat 84.14 ms、冷读 237.97 ms、缓存读取 110.98 ms、发布 268.46 ms,以及同进程当前格式读取 0.41 ms。这些测量记录成本,不证明性能提升,也不设跨主机阈值。 + +| 无关 Session | 历史 stat | 冷读 | 缓存读取 | 发布 | 当前格式热读 | +|---:|---:|---:|---:|---:|---:| +| 0 | 5.17 | 19.00 | 1.36 | 42.88 | 0.47 | +| 0 | 3.30 | 14.87 | 1.45 | 35.75 | 0.41 | +| 0 | 3.18 | 16.71 | 1.50 | 34.51 | 0.47 | +| 100 | 29.44 | 77.48 | 17.01 | 60.66 | 0.43 | +| 100 | 12.42 | 42.71 | 13.69 | 60.19 | 0.43 | +| 100 | 11.19 | 41.06 | 12.61 | 57.18 | 0.39 | +| 1000 | 84.14 | 237.97 | 109.86 | 284.96 | 0.48 | +| 1000 | 99.41 | 259.88 | 123.50 | 268.46 | 0.41 | +| 1000 | 75.40 | 236.64 | 110.98 | 247.69 | 0.39 | + +在仓库根目录构建运行时后执行: + +```sh +pnpm run build:lib:host +cd packages/session/session-persistence-jsonl +node --input-type=module -e 'import { build } from "tsdown"; await build({ config: false, entry: ["tests/catalog-migration.perf.ts"], outDir: ".artifacts/perf", tsconfig: false, dts: false, deps: { neverBundle: [/^@deepseek-ai\//], onlyBundle: false } })' +node .artifacts/perf/catalog-migration.perf.mjs +``` + ## 验证 迁移规范要求分别提供转换、保留与拒绝的证据。直接迁移边和原生 V3 测试不能证明有种子的多跳发布:前代 assistant 流折叠会在 V3 插入系统事件前改变源坐标。因此,经过真实目录与 JSONL 提供方的测试需要原始及压缩的 V0/V1 输入、映射后的引用和继承切点、发布/重新打开等价性、前代字节不变,以及不产生中间代。覆盖率百分比本身不能证明这些跨阶段关系;组合断言必须比较结果历史与拒绝效果。 diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index 1a1fac5a78..48edcc4999 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-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/config-catalog.md -config-catalog.md: 5bcb6b4f1ef6d8d78c57beddd0c44e7c370d682a -config-catalog.zh.md: 868a9626081e2945c5075f350fd618dced87f725 +config-catalog.md: 31f75d5dbc1569d759b8fbcde56dcc7ac3e85bc1 +config-catalog.zh.md: e1d3064c1134443d0a3dc17011f068a84560a7d3 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 5bcb6b4f1e..31f75d5dbc 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1568,7 +1568,7 @@ export interface ReplayModelConfig { Depends on: [`ModelModality`](../packages/llm/llm/src/index.ts) · [`RetryPolicyConfig`](../packages/llm/llm/src/index.ts) · [`SystemPromptUpdate`](../packages/llm/llm/src/index.ts) -Source: [`packages/test-support/llm-replay/src/index.ts:1122`](../packages/test-support/llm-replay/src/index.ts) +Source: [`packages/test-support/llm-replay/src/index.ts:1123`](../packages/test-support/llm-replay/src/index.ts) @@ -2125,7 +2125,7 @@ export interface Config { export type JsonlCompression = 'zstd' | 'none' ``` -Source: [`packages/session/session-persistence-jsonl/src/index.ts:88`](../packages/session/session-persistence-jsonl/src/index.ts) +Source: [`packages/session/session-persistence-jsonl/src/index.ts:90`](../packages/session/session-persistence-jsonl/src/index.ts) diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 868a962608..e1d3064c11 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -1570,7 +1570,7 @@ export interface ReplayModelConfig { Depends on: [`ModelModality`](../packages/llm/llm/src/index.ts) · [`RetryPolicyConfig`](../packages/llm/llm/src/index.ts) · [`SystemPromptUpdate`](../packages/llm/llm/src/index.ts) -来源:[`packages/test-support/llm-replay/src/index.ts:1122`](../packages/test-support/llm-replay/src/index.ts) +来源:[`packages/test-support/llm-replay/src/index.ts:1123`](../packages/test-support/llm-replay/src/index.ts) @@ -2127,7 +2127,7 @@ export interface Config { export type JsonlCompression = 'zstd' | 'none' ``` -来源:[`packages/session/session-persistence-jsonl/src/index.ts:88`](../packages/session/session-persistence-jsonl/src/index.ts) +来源:[`packages/session/session-persistence-jsonl/src/index.ts:90`](../packages/session/session-persistence-jsonl/src/index.ts) diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml b/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml index abb5bc3e7f..c44c0591ef 100644 --- a/docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml +++ b/docs/persistence-changes/2026-09-16-session-format-v4.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-changes/2026-09-16-session-format-v4.md -2026-09-16-session-format-v4.md: 57273fba4d45ff77537a4d5777f182eef406e156 -2026-09-16-session-format-v4.zh.md: 26c15f688b0f68974ed07c720b1e4c1b168f1a6c +2026-09-16-session-format-v4.md: 1148545e767802b6f6c275b1df3e3f323ea92609 +2026-09-16-session-format-v4.zh.md: 47d4564610da2185ecba55fbc25225abc7c75ede diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.md b/docs/persistence-changes/2026-09-16-session-format-v4.md index 57273fba4d..1148545e76 100644 --- a/docs/persistence-changes/2026-09-16-session-format-v4.md +++ b/docs/persistence-changes/2026-09-16-session-format-v4.md @@ -35,12 +35,16 @@ changes: ## Compatibility -The [V3-to-V4 migration](../../packages/session/session-format-v3-to-v4/README.md#v3-to-v4-specification) advances the header and preserves every admitted event and inherited cut. Its generation-aware delivery checks prevent historical acknowledgements from becoming active V4 watermarks. V3 readers refuse the newer generation; the catalog restores supported older inputs through the complete adjacent chain. The [V3 schema reference](historical-formats/v3.md) preserves the outgoing declarations, and persistence retains committed predecessor bytes while publishing only the current successor. +The [V3-to-V4 migration](../../packages/session/session-format-v3-to-v4/README.md#v3-to-v4-specification) advances the header, preserves every admitted source event and inherited cut, and appends missing parent `subagent/catalog` records from retained direct-child logs in the same persistence root. Historical body restoration requires an explicit child-evidence set, including an empty set when no children are available to backfill. Missing required descriptors or conflicting identities refuse migration without publication; existing catalog facts remain. The linked specification owns descriptor admission and deterministic append order. + +Historical read opens prepare the result in memory. Write opens revalidate child membership and revisions before publishing the current successor beside unchanged predecessor files. Already-written V4 files do not rerun this incoming edge, so unreleased integration uses disposable homes. Delivery-generation checks keep historical acknowledgements from becoming active V4 watermarks. V3 readers refuse the newer generation; the [V3 schema reference](historical-formats/v3.md) preserves the outgoing declarations. ## Verification -`pnpm exec vitest run packages/session/session-format-v3-to-v4/tests` passed 22 tests across two files, covering identity preservation, inherited cuts, admission, and delivery-generation refusal. `pnpm run verify-persistence-formats` passed for all five references from V0 through V4. Before the writer change, `pnpm run verify-persistence-catalog` passed and `pnpm run verify-persistence-formats --archive 3` captured the V3 schema. +`pnpm exec vitest run packages/session/session-format-v3-to-v4/tests packages/session/session-format-catalog/tests packages/session/session-persistence-jsonl/tests/catalog-migration.spec.ts` passed 140 tests across nine files, with one skipped test. The suites cover catalog completion, inherited cuts, child-evidence refusal, and JSONL preparation/publication. + +Before the writer change, `pnpm run verify-persistence-catalog` passed and `pnpm run verify-persistence-formats --archive 3` captured the V3 schema. The V4 header schema digest and its generated companion remain unchanged. ## Dev Note diff --git a/docs/persistence-changes/2026-09-16-session-format-v4.zh.md b/docs/persistence-changes/2026-09-16-session-format-v4.zh.md index 26c15f688b..47d4564610 100644 --- a/docs/persistence-changes/2026-09-16-session-format-v4.zh.md +++ b/docs/persistence-changes/2026-09-16-session-format-v4.zh.md @@ -35,12 +35,16 @@ changes: ## 兼容性 -[V3 到 V4 迁移](../../packages/session/session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)推进 header,并保留每个已接纳事件与继承切点。其按 generation 校验 delivery 的规则可防止历史确认成为有效的 V4 水位。V3 读取方拒绝更新的 generation;目录通过完整的相邻迁移链恢复受支持的旧输入。[V3 schema 参考](historical-formats/v3.zh.md)保留原声明,持久化在只发布当前后继代的同时保留已提交前代的字节。 +[V3 到 V4 迁移](../../packages/session/session-format-v3-to-v4/README.zh.md#v3-to-v4-specification)推进 header,保留每个已接纳源事件与继承切点,并根据同一持久化根目录中保留的直接子 Session 日志追加缺失的父级 `subagent/catalog` 记录。历史正文恢复要求显式提供子日志证据集合;没有可供补全的子日志时也须传入空集合。缺少必需的 descriptor 或身份冲突会拒绝迁移,且不发布后继;已有 catalog 事实保持不变。链接中的规范负责 descriptor 准入与确定性追加顺序。 + +历史读取打开在内存中准备结果。写入打开在重新校验子项成员与修订后,将当前后继发布到未修改的前代文件旁。已写入的 V4 文件不会重新运行该迁入边,因此未发布集成使用可丢弃的 home。Delivery generation 校验防止历史确认成为有效的 V4 水位。V3 读取方拒绝更新的 generation;[V3 schema 参考](historical-formats/v3.zh.md)保留原声明。 ## 验证 -`pnpm exec vitest run packages/session/session-format-v3-to-v4/tests` 的两个文件共 22 个测试通过,覆盖恒等保留、继承切点、准入与 delivery generation 拒绝。`pnpm run verify-persistence-formats` 对从 V0 到 V4 的全部五个参考均验证通过。写入器变更前,`pnpm run verify-persistence-catalog` 通过,且 `pnpm run verify-persistence-formats --archive 3` 已捕获 V3 schema。 +`pnpm exec vitest run packages/session/session-format-v3-to-v4/tests packages/session/session-format-catalog/tests packages/session/session-persistence-jsonl/tests/catalog-migration.spec.ts` 的九个文件共 140 个测试通过,一个测试跳过。这些测试覆盖 catalog 补全、继承切点、子日志证据拒绝,以及 JSONL 准备与发布。 + +写入器变更前,`pnpm run verify-persistence-catalog` 通过,且 `pnpm run verify-persistence-formats --archive 3` 已捕获 V3 schema。V4 header schema digest 及其生成的配套文件保持不变。 ## 开发备注 diff --git a/packages/experimental/webworker-packer/README.i18n.yaml b/packages/experimental/webworker-packer/README.i18n.yaml index e6443c0a41..0d9d1a565a 100644 --- a/packages/experimental/webworker-packer/README.i18n.yaml +++ b/packages/experimental/webworker-packer/README.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 packages/experimental/webworker-packer/README.md -README.md: 65a428cb82ec490cb1ff64432c372f912cc529de -README.zh.md: 8d3335dafb448fa6d2cd27395bb92dd97a4fb6c0 +README.md: c927fd2f4b3bef3078a263f7b65bb0130898ef5b +README.zh.md: 2a10a8c0f51f7596d27b8c2ad92a1eeea6715ca8 diff --git a/packages/experimental/webworker-packer/README.md b/packages/experimental/webworker-packer/README.md index 65a428cb82..c927fd2f4b 100644 --- a/packages/experimental/webworker-packer/README.md +++ b/packages/experimental/webworker-packer/README.md @@ -37,7 +37,7 @@ The pack is a three-layer standard stack: The repository adapter also declares the preview-only fixture trees under `webworker-runtime/tests/fixtures/`. The CLI packs each named fixture into a separate deterministic overlay archive plus a browser-readable manifest. Overlay files bypass npm publish-view and module-reachability exclusions, so dot directories and example source files remain intact; their mounts are limited to `home/` and `workspace/`. `packVfsOverlay` treats all files as opaque bytes. -`packPreviewFixture` prepares the newest canonical raw Session generation in each fixture directory through the [Session format catalog](../../session/session-format-catalog/README.md) in Node. It strictly restores the source, encodes and strictly validates the current successor, and packs that successor beside unchanged source files. A malformed, unsupported, or future selected generation refuses the build without falling back. Temporary successors are removed after packing. Browser write-open then uses current data without invoking Node's migration-verification Worker. Projection caches remain owner-validated; an older generation cannot supply a current fold checkpoint. +`packPreviewFixture` prepares the newest canonical raw Session generation in each fixture directory through the [Session format catalog](../../session/session-format-catalog/README.md) in Node. It collects direct-child discovery evidence from the same fixture root before completing historical parent catalogs. It strictly restores the source, encodes and strictly validates the current successor, and packs that successor beside unchanged source files. A malformed, unsupported, or future selected generation refuses the build without falling back. Temporary successors are removed after packing. Browser write-open then uses current data without invoking Node's migration-verification Worker. Projection caches remain owner-validated; an older generation cannot supply a current fold checkpoint. ----- diff --git a/packages/experimental/webworker-packer/README.zh.md b/packages/experimental/webworker-packer/README.zh.md index 8d3335dafb..2a10a8c0f5 100644 --- a/packages/experimental/webworker-packer/README.zh.md +++ b/packages/experimental/webworker-packer/README.zh.md @@ -37,7 +37,7 @@ VFS 镜像打包器:把一份合成 profile 变成浏览器 worker 挂载为 仓库适配器还声明 `webworker-runtime/tests/fixtures/` 下仅用于 preview 的 fixture(测试前置数据) tree。CLI 会把每套具名 fixture 打成一份独立的确定性 overlay 归档,并写出浏览器可读的 manifest(元数据清单)。Overlay 文件绕过 npm 发布视图和模块可达性排除规则,因此点目录与示例源码会完整保留;其挂载位置仅限 `home/` 与 `workspace/`。`packVfsOverlay` 将所有文件视为不透明字节。 -`packPreviewFixture` 在 Node 中通过 [Session 格式目录](../../session/session-format-catalog/README.zh.md)准备每个 fixture 目录里最新的规范原始 Session 代际。它严格恢复源文件、编码并严格校验当前后继文件,然后将后继文件与未改变的源文件一同打包。如果选中的代际格式错误、不受支持或属于未来版本,构建会拒绝,不回退。临时后继文件在打包后删除。浏览器以写模式打开时即可使用当前数据,无需调用 Node 的迁移校验 Worker。投影缓存仍由其所属包校验;较早代际不能提供当前折叠检查点。 +`packPreviewFixture` 在 Node 中通过 [Session 格式目录](../../session/session-format-catalog/README.zh.md)准备每个 fixture 目录里最新的规范原始 Session 代际。它从同一 fixture 根目录收集直属子 Session 的发现证据,再补全历史父目录。它严格恢复源文件、编码并严格校验当前后继文件,然后将后继文件与未改变的源文件一同打包。如果选中的代际格式错误、不受支持或属于未来版本,构建会拒绝,不回退。临时后继文件在打包后删除。浏览器以写模式打开时即可使用当前数据,无需调用 Node 的迁移校验 Worker。投影缓存仍由其所属包校验;较早代际不能提供当前折叠检查点。 ----- diff --git a/packages/experimental/webworker-packer/package.json b/packages/experimental/webworker-packer/package.json index 280291fd67..406fd468ab 100644 --- a/packages/experimental/webworker-packer/package.json +++ b/packages/experimental/webworker-packer/package.json @@ -38,6 +38,7 @@ "@deepseek-ai/dsh-home-paths": "workspace:^", "@deepseek-ai/dsh-session-format": "workspace:^", "@deepseek-ai/dsh-session-format-catalog": "workspace:^", + "@deepseek-ai/dsh-session-format-v3-to-v4": "workspace:^", "js-yaml": "^4.2.0", "picomatch": "^4.0.4" }, diff --git a/packages/experimental/webworker-packer/src/preview.ts b/packages/experimental/webworker-packer/src/preview.ts index cca1bb9824..76f9d86cf2 100644 --- a/packages/experimental/webworker-packer/src/preview.ts +++ b/packages/experimental/webworker-packer/src/preview.ts @@ -4,7 +4,8 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { dirname, join, posix } from 'node:path' import { isSessionFormatJsonObject, parseSessionFormatLogFilename, sessionFormatLogFilename } from '@deepseek-ai/dsh-session-format' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { createSessionFormatCatalogWithChildren, historicalSessionFormatCatalog, sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { historicalChildCatalogSource } from '@deepseek-ai/dsh-session-format-v3-to-v4' import { packVfsOverlay, type ImageTree, type PackOverlayResult } from './pack.ts' import type { ImageFiles } from './transform-image.ts' @@ -26,7 +27,7 @@ interface PreviewSession { export function packPreviewFixture(trees: readonly ImageTree[]): PackOverlayResult { const original = packVfsOverlay(trees) const successors = new Map() - for (const source of selectedSessions(original.files)) { + const sources = selectedSessions(original.files).map((source) => { const text = new TextDecoder('utf-8', { fatal: true }).decode(source.bytes) if (!text.endsWith('\n')) throw new Error(`preview fixture: ${source.path} has a torn physical tail`) const [headerLine = '', ...rows] = text.slice(0, -1).split('\n') @@ -34,10 +35,20 @@ export function packPreviewFixture(trees: readonly ImageTree[]): PackOverlayResu if (!isSessionFormatJsonObject(header) || header['version'] !== source.version || header['id'] !== source.id) { throw new Error(`preview fixture: ${source.path} disagrees with its Session header`) } - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) - for (const row of rows) restore.decodeRow(JSON.parse(row)) - const artifact = restore.finish() + const catalog = source.version <= 3 ? historicalSessionFormatCatalog : sessionFormatCatalog + const restore = catalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + const events: unknown[] = rows.map(row => JSON.parse(row) as unknown) + for (const event of events) restore.decodeRow(event) + return { ...source, header, events, artifact: restore.finish() } + }) + for (const source of sources) { if (source.version === sessionFormatCatalog.currentVersion) continue + const children = sources.filter(child => posix.dirname(child.directory) === posix.dirname(source.directory) + && child.artifact.header.parentSession === source.id && child.artifact.header.origin === 'subagent') + .map(child => ({ ...historicalChildCatalogSource(child.artifact), sourcePath: child.path })) + const restore = createSessionFormatCatalogWithChildren(children).createRestore(source.header, { recovery: 'strict', validation: 'current' }) + for (const event of source.events) restore.decodeRow(event) + const artifact = restore.finish() const encodedHeader = sessionFormatCatalog.encodeCurrentHeader(artifact.header, artifact.inheritedEventCount) const encodedEvents = artifact.events.map(event => sessionFormatCatalog.encodeCurrentEvent(event)) const verification = sessionFormatCatalog.createRestore(encodedHeader, { recovery: 'strict', validation: 'current' }) diff --git a/packages/experimental/webworker-packer/tests/preview.spec.ts b/packages/experimental/webworker-packer/tests/preview.spec.ts index 2b03798032..443b7736d0 100644 --- a/packages/experimental/webworker-packer/tests/preview.spec.ts +++ b/packages/experimental/webworker-packer/tests/preview.spec.ts @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { afterEach, describe, expect, it } from 'vitest' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { createSessionFormatCatalogWithChildren, sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' import { sessionFormatLogFilename } from '@deepseek-ai/dsh-session-format' import { packPreviewFixture } from '../src/preview.ts' import { packVfsOverlay } from '../src/pack.ts' @@ -36,7 +36,7 @@ function source() { function restore(bytes: Uint8Array | undefined) { const [header, ...rows] = text(bytes).trimEnd().split('\n').map(row => JSON.parse(row) as unknown) - const reader = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + const reader = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation: 'current' }) for (const row of rows) reader.decodeRow(row) return reader.finish() } @@ -51,13 +51,44 @@ describe('Node preparation of Preview Session data', () => { for (const [path, bytes] of Object.entries(original.files)) expect(projected.files[path], path).toEqual(bytes) for (const path of currentFiles) { const sourcePath = path.replace(/\/session\.v\d+\.jsonl$/u, '/session.v3.jsonl') - expect(restore(projected.files[path])).toEqual(restore(original.files[sourcePath])) + const historical = restore(original.files[sourcePath]) + const current = restore(projected.files[path]) + const appended = path.includes('/preview-showcase/') ? [ + { version: 0, childId: 'preview-architecture-review', childCreatedAt: 1787472100000, mode: 'one-shot', label: 'Review preview architecture' }, + { version: 0, childId: 'preview-follow-up-builder', childCreatedAt: 1787472200000, mode: 'continuable', label: 'Continue preview verification' }, + ].map((data, index) => ({ type: 'subagent/catalog', seq: historical.events.length + index, + time: historical.events.at(-1)!.time, data })) : [] + expect(current).toEqual({ ...historical, events: [...historical.events, ...appended] }) expect(JSON.parse(text(projected.files[path]).split('\n')[0]!)).toMatchObject({ version: currentVersion }) } expect(packPreviewFixture(fixture.trees).image).toEqual(projected.image) expect(packVfsOverlay(fixture.trees).files).toEqual(original.files) }) + it.each(['missing-descriptor', 'other-root', 'other-origin', 'current-child'] as const)('collects only direct subagent children in the same root: %s', (mode) => { + const fixture = source() + const parent = fixture.put(3) + const childDirectory = join(fixture.trees[0]!.directory, 'sessions', mode === 'other-root' ? 'other' : 'project', 'child') + mkdirSync(childDirectory, { recursive: true }) + const version = mode === 'current-child' ? currentVersion : 3 + const child = { type: 'session', version, id: 'child', createdAt: 2, isSeeded: false, + delegationDepth: 1, parentSession: 'example', ...(mode === 'other-origin' ? {} : { origin: 'subagent' }) } + const descriptor = { type: 'subagent/descriptor', seq: 0, time: 3, + data: { version: 3, mode: 'one-shot', provider: 'spawn' } } + writeFileSync(join(childDirectory, sessionFormatLogFilename(version)), + JSON.stringify(child) + '\n' + (mode === 'current-child' ? JSON.stringify(descriptor) + '\n' : '')) + const before = readFileSync(parent) + if (mode === 'missing-descriptor') { + expect(() => packPreviewFixture(fixture.trees)).toThrow('requires exactly one own supported subagent descriptor') + } else { + const packed = packPreviewFixture(fixture.trees) + expect(restore(packed.files[`home/sessions/project/example/${sessionFormatLogFilename(currentVersion)}`]).events) + .toEqual(mode === 'current-child' ? [{ type: 'subagent/catalog', seq: 0, time: 1, + data: { version: 0, childId: 'child', childCreatedAt: 2, mode: 'one-shot' } }] : []) + } + expect(readFileSync(parent)).toEqual(before) + }) + it('uses the highest generation and leaves an already-current image byte-identical', () => { const fixture = source() const older = fixture.put(3, '{invalid historical data}\n') diff --git a/packages/experimental/webworker-packer/tsconfig.json b/packages/experimental/webworker-packer/tsconfig.json index d7021210ec..9d99bdf7b1 100644 --- a/packages/experimental/webworker-packer/tsconfig.json +++ b/packages/experimental/webworker-packer/tsconfig.json @@ -25,6 +25,9 @@ }, { "path": "../../session/session-format-catalog" + }, + { + "path": "../../session/session-format-v3-to-v4" } ] } diff --git a/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts b/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts index 91e0880e2d..aaa2448d0f 100644 --- a/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts +++ b/packages/experimental/webworker-runtime/tests/vfs-example-fixture.spec.ts @@ -2,7 +2,7 @@ import { readFileSync, readdirSync } from 'node:fs' import { join, relative } from 'node:path' import { describe, expect, it } from 'vitest' import { SESSION_FORMAT_VERSION, Session, SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { createSessionFormatCatalogWithChildren } from '@deepseek-ai/dsh-session-format-catalog' import { generationLogFilename, scanLog, @@ -41,7 +41,7 @@ function readSession(id: string): ReturnType { function restoreSession(content: string, version: number) { const [header, ...events] = content.trimEnd().split('\n').map(line => JSON.parse(line) as unknown) expect(header).toMatchObject({ type: 'session', version }) - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation: 'current' }) for (const event of events) restore.decodeRow(event) return restore.finish() } diff --git a/packages/session/session-format-catalog/README.i18n.yaml b/packages/session/session-format-catalog/README.i18n.yaml index c48bbbc3b9..129dc4e8af 100644 --- a/packages/session/session-format-catalog/README.i18n.yaml +++ b/packages/session/session-format-catalog/README.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 packages/session/session-format-catalog/README.md -README.md: 5ebfa82486873810f64d2f7bd3f83957bd995ed9 -README.zh.md: 6e8d674b0dfd2e69c2ff2d0857afd04ab91734b5 +README.md: 0666f13cef0a7f019ddd741666ee8c95f78af2b8 +README.zh.md: b0132d2543f7f5a3a1d9ca5958e5c0593f3320e1 diff --git a/packages/session/session-format-catalog/README.md b/packages/session/session-format-catalog/README.md index 5ebfa82486..0666f13cef 100644 --- a/packages/session/session-format-catalog/README.md +++ b/packages/session/session-format-catalog/README.md @@ -33,7 +33,8 @@ Import this library from persistence and test-support readers that need the comp ```text const descriptor = sessionFormatCatalog.readHeader(physicalHeader) -const restore = sessionFormatCatalog.createRestore(physicalHeader, { recovery: 'recoverable', validation: 'transformed' }) +const catalog = createSessionFormatCatalogWithChildren(childFacts) +const restore = catalog.createRestore(physicalHeader, { recovery: 'recoverable', validation: 'transformed' }) for (const row of physicalRows) restore.decodeRow(row) const current = restore.finish() const headerRecord = sessionFormatCatalog.encodeCurrentHeader(current.header, current.inheritedEventCount) @@ -46,6 +47,8 @@ Production historical reads select `{ recovery: 'recoverable', validation: 'tran The catalog contains all supported historical readers directly. A profile cannot add, remove, or reorder an edge by mounting a feature plugin. Its peer dependency on `dsh-session` supplies the installed current event vocabulary and current restoration rules, while historical edge validators remain frozen. The browser-safe `./message-projections` export assembles current plugin-owned interpreters for detached constructors and surface folds; it does not mount recovery listeners. +`createSessionFormatCatalogWithChildren(childFacts)` binds explicit child evidence to V3→V4 during assembly; see the [catalog-completion specification](../session-format-v3-to-v4/README.md). `historicalSessionFormatCatalog` restores V0–V3 only for collecting child prerequisites without recursively completing their catalogs. Isolated transcript replay explicitly supplies an empty array; persistence must collect the complete available direct-child set. Keep the supplied evidence unchanged for the catalog’s lifetime. Each restore owns independent stage state. The static `sessionFormatCatalog` supports header and native current-format reads; historical body reads require the child-bound catalog. + ----- diff --git a/packages/session/session-format-catalog/README.zh.md b/packages/session/session-format-catalog/README.zh.md index 6e8d674b0d..b0132d2543 100644 --- a/packages/session/session-format-catalog/README.zh.md +++ b/packages/session/session-format-catalog/README.zh.md @@ -33,7 +33,8 @@ kind: "package-library" ```text const descriptor = sessionFormatCatalog.readHeader(physicalHeader) -const restore = sessionFormatCatalog.createRestore(physicalHeader, { recovery: 'recoverable', validation: 'transformed' }) +const catalog = createSessionFormatCatalogWithChildren(childFacts) +const restore = catalog.createRestore(physicalHeader, { recovery: 'recoverable', validation: 'transformed' }) for (const row of physicalRows) restore.decodeRow(row) const current = restore.finish() const headerRecord = sessionFormatCatalog.encodeCurrentHeader(current.header, current.inheritedEventCount) @@ -46,6 +47,8 @@ Production 历史读取使用 `{ recovery: 'recoverable', validation: 'transform 该目录直接包含所有受支持的历史读取器。Profile 无法通过挂载功能插件来添加、移除或重新排列迁移边。它通过对 `dsh-session` 的对等依赖(peer dependency)获得已安装的当前事件词表与当前还原规则,而历史迁移边校验器保持冻结。浏览器安全的 `./message-projections` 导出为独立构造函数和 surface 折叠装配当前插件拥有的处理器,不挂载恢复监听器。 +`createSessionFormatCatalogWithChildren(childFacts)` 在组装时将显式的子 Session 证据绑定到 V3→V4,见[目录补齐规范](../session-format-v3-to-v4/README.zh.md)。`historicalSessionFormatCatalog` 仅还原 V0–V3,用于收集子 Session 前置事实,避免递归补齐其目录。独立转录回放显式提供空数组;持久化必须收集完整的可用直属子 Session 集合。在 catalog 的生命周期内保持传入证据不变。每次恢复各自拥有独立的 stage 状态。静态 `sessionFormatCatalog` 支持 header 和原生当前格式读取;历史正文读取必须使用已绑定子 Session 的 catalog。 + ----- diff --git a/packages/session/session-format-catalog/src/children.ts b/packages/session/session-format-catalog/src/children.ts new file mode 100644 index 0000000000..580e46d2ae --- /dev/null +++ b/packages/session/session-format-catalog/src/children.ts @@ -0,0 +1,19 @@ +/** Bind parent-specific child evidence into the static first-party migration inventory. */ + +import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatCatalog, SessionFormatJsonValue } from '@deepseek-ai/dsh-session-format' +import { createSessionFormatV3ToV4, sessionFormatV3ToV4 } from '@deepseek-ai/dsh-session-format-v3-to-v4' +import { sessionFormatCatalogOptions } from './generated.ts' + +/** + * Assemble a catalog whose V3→V4 edge knows one parent's historical children. + * @param children - complete child evidence retained unchanged for the catalog's lifetime; an empty array declares no children. + * @returns a catalog with independent restore state per artifact and unchanged current-format readers. + */ +export function createSessionFormatCatalogWithChildren(children: readonly SessionFormatJsonValue[]): SessionFormatCatalog { + const migration = createSessionFormatV3ToV4(children) + return createSessionFormatCatalog({ + ...sessionFormatCatalogOptions, + migrations: sessionFormatCatalogOptions.migrations.map(edge => edge === sessionFormatV3ToV4 ? migration : edge), + }) +} diff --git a/packages/session/session-format-catalog/src/generated.ts b/packages/session/session-format-catalog/src/generated.ts index 2296efe207..eab9d91456 100644 --- a/packages/session/session-format-catalog/src/generated.ts +++ b/packages/session/session-format-catalog/src/generated.ts @@ -5,14 +5,15 @@ import { KNOWN_SESSION_EVENT_TYPES } from '@deepseek-ai/dsh-session' import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatCatalogOptions } from '@deepseek-ai/dsh-session-format' import { validateInstalledCurrentSessionArtifact, validateInstalledCurrentSessionHeader } from './current.ts' import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, sessionFormatV0ToV1 } from '@deepseek-ai/dsh-session-format-v0-to-v1' import { releasedV2SessionFormatCodec, sessionFormatV1ToV2 } from '@deepseek-ai/dsh-session-format-v1-to-v2' import { releasedV3SessionFormatCodec, sessionFormatV2ToV3 } from '@deepseek-ai/dsh-session-format-v2-to-v3' import { assertReleasedV4Header, releasedV4SessionFormatCodec, restoreReleasedV4Artifact, sessionFormatV3ToV4 } from '@deepseek-ai/dsh-session-format-v3-to-v4' -/** Physical codec dispatch and complete adjacent chain, independent of mounted plugins. */ -export const sessionFormatCatalog = createSessionFormatCatalog({ +/** Static assembly shared by current reads and parent-specific historical restoration. */ +export const sessionFormatCatalogOptions: SessionFormatCatalogOptions = { currentVersion: 4, codecs: [ releasedV0SessionFormatCodec, @@ -41,4 +42,7 @@ export const sessionFormatCatalog = createSessionFormatCatalog({ validateInstalledCurrentSessionHeader(header) return header }, -}) +} + +/** Physical codec dispatch and complete adjacent chain, independent of mounted plugins. */ +export const sessionFormatCatalog = createSessionFormatCatalog(sessionFormatCatalogOptions) diff --git a/packages/session/session-format-catalog/src/historical.ts b/packages/session/session-format-catalog/src/historical.ts new file mode 100644 index 0000000000..9a29c06df6 --- /dev/null +++ b/packages/session/session-format-catalog/src/historical.ts @@ -0,0 +1,21 @@ +/** Historical restoration for collecting migration prerequisites without recursively opening current Sessions. */ + +import { KNOWN_SESSION_EVENT_TYPES } from '@deepseek-ai/dsh-session' +import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format' +import { releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, sessionFormatV0ToV1 } from '@deepseek-ai/dsh-session-format-v0-to-v1' +import { releasedV2SessionFormatCodec, sessionFormatV1ToV2 } from '@deepseek-ai/dsh-session-format-v1-to-v2' +import { assertReleasedV3Header, releasedV3SessionFormatCodec, restoreReleasedV3Artifact, sessionFormatV2ToV3 } from '@deepseek-ai/dsh-session-format-v2-to-v3' + +/** V0–V3 decoding for historical child identity; never publishes or completes parent catalogs. */ +export const historicalSessionFormatCatalog = createSessionFormatCatalog({ + currentVersion: 3, + codecs: [releasedV0SessionFormatCodec, releasedV1SessionFormatCodec, releasedV2SessionFormatCodec, releasedV3SessionFormatCodec], + currentEncoder: releasedV3SessionFormatCodec, + migrations: [sessionFormatV0ToV1, sessionFormatV1ToV2, sessionFormatV2ToV3], + restoreCurrent: artifact => restoreReleasedV3Artifact(artifact, KNOWN_SESSION_EVENT_TYPES), + restoreTransformedCurrent: artifact => restoreReleasedV3Artifact(artifact, KNOWN_SESSION_EVENT_TYPES), + restoreCurrentHeader(header) { + assertReleasedV3Header(header) + return header + }, +}) diff --git a/packages/session/session-format-catalog/src/index.ts b/packages/session/session-format-catalog/src/index.ts index 095ce7bf84..854a9c89b6 100644 --- a/packages/session/session-format-catalog/src/index.ts +++ b/packages/session/session-format-catalog/src/index.ts @@ -1,4 +1,6 @@ /** Build-static first-party Session format migration catalog. */ export { sessionFormatCatalog } from './generated.ts' +export { createSessionFormatCatalogWithChildren } from './children.ts' +export { historicalSessionFormatCatalog } from './historical.ts' export { SessionFormatUnsupportedMigrationError } from '@deepseek-ai/dsh-session-format' diff --git a/packages/session/session-format-catalog/tests/catalog.spec.ts b/packages/session/session-format-catalog/tests/catalog.spec.ts index 6ada05de30..45a26e7ccb 100644 --- a/packages/session/session-format-catalog/tests/catalog.spec.ts +++ b/packages/session/session-format-catalog/tests/catalog.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import type { SessionFormatEvent } from '@deepseek-ai/dsh-session-format' -import { sessionFormatCatalog } from '../src/index.ts' +import { createSessionFormatCatalogWithChildren, historicalSessionFormatCatalog, sessionFormatCatalog } from '../src/index.ts' import { currentSessionMessageProjections } from '../src/message-projections.ts' import { MESSAGE_PROJECTION_EVENT_TYPES } from '@deepseek-ai/dsh-session/src/known-event-types.ts' import { validateInstalledCurrentSessionArtifact } from '../src/current.ts' @@ -52,7 +52,7 @@ describe('first-party Session format catalog', () => { }) const v1Header = { ...header, version: 1 } - const restore = sessionFormatCatalog.createRestore(v1Header, { + const restore = createSessionFormatCatalogWithChildren([]).createRestore(v1Header, { recovery: 'strict', validation: 'current', }) restore.decodeRow({ type: 'turn/start', seq: 0, time: 2, data: { turn: 1 } }) @@ -66,7 +66,7 @@ describe('first-party Session format catalog', () => { type: 'session', version: SESSION_FORMAT_VERSION, id: 'current-growth', createdAt: 1, isSeeded: false, delegationDepth: 0, } const restore = (rows: readonly unknown[]) => { - const current = sessionFormatCatalog.createRestore(header, { + const current = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation: 'current', }) for (const row of rows) current.decodeRow(row) @@ -97,7 +97,7 @@ describe('first-party Session format catalog', () => { type: 'session', version, id: 'seed-chain', createdAt: 1, parentSession: 'parent', seedLength, delegationDepth: 0, } - const restore = sessionFormatCatalog.createRestore(sourceHeader, { recovery: 'strict', validation: 'current' }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(sourceHeader, { recovery: 'strict', validation: 'current' }) if (seedLength > 0) { restore.decodeRow({ type: 'feedback/record', seq: 0, time: 1, data: { text: 'inherited' } }) } @@ -120,7 +120,7 @@ describe('first-party Session format catalog', () => { ...(isSeeded ? [{ type: 'session/end-seed', seq: 3, time: 4, data: { inherited: true } }] : []), ] const before = JSON.stringify({ header, rows }) - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation: 'current' }) for (const row of rows) restore.decodeRow(row) expect(restore.finish()).toEqual({ header: { version: SESSION_FORMAT_VERSION, id: 'v2-identity', createdAt: 1, isSeeded, delegationDepth: 0 }, @@ -149,7 +149,7 @@ describe('first-party Session format catalog', () => { const header = { type: 'session', version: 2, id: 'v2-unknown', createdAt: 1, isSeeded: false, delegationDepth: 0 } const row = { type: 'external/event', seq: 0, time: 1, data: { extra: ['unchanged'] }, ignorable: true } const before = JSON.stringify({ header, row }) - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation }) expect(() => { restore.decodeRow(row) }).toThrow(/cannot safely transform unclassified event external\/event/) expect(JSON.stringify({ header, row })).toBe(before) }) @@ -184,7 +184,7 @@ describe('first-party Session format catalog', () => { { type: 'turn/end', seq: 9, time: 17, data: { turn: 1, reason: { kind: 'completed' } } }, ]) const before = JSON.stringify({ sourceHeader, rows }) - const restore = sessionFormatCatalog.createRestore(sourceHeader, { recovery: 'strict', validation: 'current' }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(sourceHeader, { recovery: 'strict', validation: 'current' }) for (const row of rows) restore.decodeRow(row) const artifact = restore.finish() const renamedMessage = (id: string) => ({ ...message(id), source: { kind: 'plugin', plugin: 'tools-ptc' } }) @@ -217,10 +217,10 @@ describe('first-party Session format catalog', () => { const header = deepFreeze({ type: 'session', version: 3, id: 'native-ptc', createdAt: 1, isSeeded: false, delegationDepth: 0 }) for (const type of ['tool/code-dispatch-start', 'tool/code-dispatch']) { const required = deepFreeze({ type, seq: 0, time: 1, data: null }) - const rejected = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }) + const rejected = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation }) expect(() => { rejected.decodeRow(required) }).toThrow(/unknown event type/) const ignorable = deepFreeze({ ...required, ignorable: true, data: { text: 'tools-code-mode', source: { kind: 'plugin', plugin: 'tools-code-mode' } } }) - const accepted = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }) + const accepted = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation }) accepted.decodeRow(ignorable) expect(accepted.finish().events).toEqual([ignorable]) } @@ -230,7 +230,7 @@ describe('first-party Session format catalog', () => { const header = deepFreeze({ type: 'session', version: 2, id: 'v2-collision', createdAt: 1, isSeeded: false, delegationDepth: 0 }) for (const type of ['tool/ptc-dispatch-start', 'tool/ptc-dispatch']) { for (const ignorable of [false, true]) { - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation }) const row = deepFreeze({ type, seq: 0, time: 1, data: null, ...(ignorable ? { ignorable: true } : {}) }) expect(() => { restore.decodeRow(row) }).toThrow(/format v2.*ptc-dispatch/) } @@ -245,7 +245,7 @@ describe('first-party Session format catalog', () => { { type: 'tool/code-dispatch-start', seq: 1, time: 2, data, ignorable: true }, { type: 'tool/code-dispatch', seq: 2, time: 3, data: { ...data, isError: false, content: [] }, ignorable: true }, ]) - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation }) for (const row of rows) restore.decodeRow(row) expect(restore.finish().events).toEqual([ rows[0], { ...rows[1], type: 'tool/ptc-dispatch-start' }, { ...rows[2], type: 'tool/ptc-dispatch' }, @@ -254,7 +254,7 @@ describe('first-party Session format catalog', () => { it.each(['current', 'transformed'] as const)('refuses a v3 delivery marker in v2 input (%s)', (validation) => { const header = { type: 'session', version: 2, id: 'future-delivery', createdAt: 1, isSeeded: false, delegationDepth: 0 } - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation }) restore.decodeRow({ type: 'feedback/record', seq: 0, time: 1, data: { text: 'unaccepted' } }) expect(() => { restore.decodeRow({ type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 2, @@ -264,7 +264,7 @@ describe('first-party Session format catalog', () => { }) it('validates complete relationships after streaming migration', () => { - const stream = sessionFormatCatalog.createRestore({ + const stream = createSessionFormatCatalogWithChildren([]).createRestore({ type: 'session', version: 1, id: 'invalid-stream', createdAt: 1, delegationDepth: 0, }, { recovery: 'strict', validation: 'current' }) stream.decodeRow({ type: 'step/start', seq: 0, time: 2, data: { turn: 1, step: 1 } }) @@ -272,3 +272,15 @@ describe('first-party Session format catalog', () => { expect(() => stream.finish()).toThrow(/open turn/) }) }) + +describe('historical child prerequisite catalog', () => { + it('restores V3 and preceding versions without the incoming catalog-completion edge', () => { + const header = { type: 'session', version: 2, id: 'historical', createdAt: 1, isSeeded: false, delegationDepth: 0 } + expect(historicalSessionFormatCatalog.readHeader(header)).toMatchObject({ status: 'migration-required' }) + for (const validation of ['current', 'transformed'] as const) { + const restored = historicalSessionFormatCatalog.createRestore(header, { recovery: 'strict', validation }).finish() + expect(restored.header.version).toBe(3) + expect(historicalSessionFormatCatalog.createRestore({ ...header, version: 3 }, { recovery: 'strict', validation }).finish()).toEqual(restored) + } + }) +}) diff --git a/packages/session/session-format-catalog/tests/children.spec.ts b/packages/session/session-format-catalog/tests/children.spec.ts new file mode 100644 index 0000000000..4b2d465e93 --- /dev/null +++ b/packages/session/session-format-catalog/tests/children.spec.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from 'vitest' +import { createSessionFormatCatalogWithChildren, sessionFormatCatalog } from '../src/index.ts' + +const header = { type: 'session', version: 3, id: 'parent', createdAt: 1, isSeeded: false, delegationDepth: 0 } +const policy = { recovery: 'strict', validation: 'current' } as const +const child = (id: string) => ({ childId: id, childCreatedAt: 2, descriptorCount: 1, + descriptor: { version: 3, provider: 'spawn', mode: 'one-shot' } }) + +describe('parent-specific catalog assembly', () => { + it('requires explicit children for historical bodies while retaining header and native V4 reads', () => { + expect(sessionFormatCatalog.readHeader(header).status).toBe('migration-required') + expect(() => sessionFormatCatalog.createRestore(header, policy)).toThrow('explicit historical child facts') + expect(createSessionFormatCatalogWithChildren([]).createRestore(header, policy).finish().events).toEqual([]) + expect(sessionFormatCatalog.createRestore({ ...header, version: 4 }, policy).finish().events).toEqual([]) + }) + + it('isolates interleaved restores and child evidence across parent catalogs', () => { + const left = createSessionFormatCatalogWithChildren([child('left-child')]) + const first = left.createRestore(header, policy) + const second = createSessionFormatCatalogWithChildren([child('right-child')]) + .createRestore({ ...header, id: 'other-parent' }, policy) + const repeated = left.createRestore(header, policy) + const row = { type: 'feedback/record', seq: 0, time: 5, data: { text: 'retained' } } + first.decodeRow(row) + second.decodeRow(row) + repeated.decodeRow(row) + const right = second.finish() + const result = first.finish() + expect(result.events).toEqual([row, { type: 'subagent/catalog', seq: 1, time: 5, + data: { version: 0, childId: 'left-child', childCreatedAt: 2, mode: 'one-shot' } }]) + expect(right.events[1]?.data).toMatchObject({ childId: 'right-child' }) + expect(repeated.finish()).toEqual(result) + const physical = sessionFormatCatalog.encodeCurrentHeader(result.header, result.inheritedEventCount) + const reopened = sessionFormatCatalog.createRestore(physical, policy) + for (const event of result.events) reopened.decodeRow(sessionFormatCatalog.encodeCurrentEvent(event)) + expect(reopened.finish()).toEqual(result) + }) +}) diff --git a/packages/session/session-format-catalog/tests/preset-migration.spec.ts b/packages/session/session-format-catalog/tests/preset-migration.spec.ts index a7f6b19c67..08cef8b978 100644 --- a/packages/session/session-format-catalog/tests/preset-migration.spec.ts +++ b/packages/session/session-format-catalog/tests/preset-migration.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' -import { sessionFormatCatalog } from '../src/index.ts' +import { createSessionFormatCatalogWithChildren } from '../src/index.ts' describe('catalog preset migration', () => { it.each([0, 1, 2])('migrates a seeded v%i header and every inherited/local selection', (version) => { @@ -19,7 +19,7 @@ describe('catalog preset migration', () => { ? [...rows.slice(0, 2), { type: 'session/end-seed', seq: 2, time: 2, data: { inherited: true } }, ...rows.slice(2)] : rows const before = JSON.stringify({ header, source }) - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation: 'current' }) for (const row of source) restore.decodeRow(row) const artifact = restore.finish() expect(artifact.header).toMatchObject({ version: SESSION_FORMAT_VERSION, id: 'code', agentPreset: 'ptc', isSeeded: true }) @@ -37,7 +37,7 @@ describe('catalog preset migration', () => { delegationDepth: 0, agentPreset: 'code', } const row = { type: 'agent-preset/selected', seq: 0, time: 1, data: { agentPreset: 'code' } } - const restore = sessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + const restore = createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'strict', validation: 'current' }) restore.decodeRow(row) expect(restore.finish()).toMatchObject({ header: { agentPreset: 'code' }, events: [row] }) }) diff --git a/packages/session/session-format-v3-to-v4/README.i18n.yaml b/packages/session/session-format-v3-to-v4/README.i18n.yaml index 0d1d297559..2bc9892f2b 100644 --- a/packages/session/session-format-v3-to-v4/README.i18n.yaml +++ b/packages/session/session-format-v3-to-v4/README.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 packages/session/session-format-v3-to-v4/README.md -README.md: 97befb074bd6b756905368a88b621e4871d1ed0f -README.zh.md: 169ba020026d63e5d79bd2ac362968fff08cccfa +README.md: 4eada9da45fdd241b315feeee959705818c169b9 +README.zh.md: 72c47cf5c1448275cc2eeb02a4d9baae00b47d2c diff --git a/packages/session/session-format-v3-to-v4/README.md b/packages/session/session-format-v3-to-v4/README.md index 97befb074b..4eada9da45 100644 --- a/packages/session/session-format-v3-to-v4/README.md +++ b/packages/session/session-format-v3-to-v4/README.md @@ -9,7 +9,7 @@ English | [中文](README.zh.md) ## Summary -Restore supported V3 Sessions as V4 without changing their events or historical requests. The library advances the header version, retains event coordinates and inherited cuts, and prevents historical delivery markers from becoming active V4 watermarks. Persistence consumes it through the static catalog; the library does not read or publish files. +`dsh-session-format-v3-to-v4` restores released V3 Sessions into the unreleased V4 integration format. The incoming edge preserves admitted events, appends missing parent catalog records, and inherits V3 framing and relationship validation. The static format catalog consumes this library; JSONL persistence owns source reads and successor publication. ## Table of Contents @@ -41,11 +41,11 @@ Complete restoration decodes rows, passes them through a fresh stage, and valida ## V3-to-V4 specification -The logical header changes only `version: 3` to `version: 4`. Every admitted event retains its type, payload, timestamp, sequence, message identity, surface operation, and references. The stage emits the original event object. It adds, removes, and reorders no events. The released V3 codec remains owned by [V2-to-V3](../session-format-v2-to-v3/README.md); this package reuses it without changing earlier migration semantics. +The logical header changes only `version: 3` to `version: 4`. Every admitted event retains its type, payload, timestamp, sequence, message identity, surface operation, and references. The stage emits the original event object. It appends missing own parent catalog records after the unchanged source events. The released V3 codec remains owned by [V2-to-V3](../session-format-v2-to-v3/README.md); this package reuses it without changing earlier migration semantics. Source events must be dense from zero. A seeded Session's last `session/end-seed` carrying `inherited: true` determines its inherited event count, excluding the marker. A supplied source cut must agree. Missing seeded markers and inherited markers in unseeded Sessions are refused. Each stage owns its counters and cut; seeded stages leave the cut unknown before EOF, including when preceding migrations change event count. -Complete restoration applies [native V3 admission](../session-format-v2-to-v3/README.md#native-v3-admission) to the unchanged representation: malformed canonical events and invalid relationships are refused; unknown required event types require installed vocabulary; unknown ignorable events retain their opaque values. This identity edge changes no coordinates or payload meaning, so retaining opaque data does not require interpreting it. The separate source-audit policies of earlier edges remain unchanged. +Complete restoration applies [native V3 admission](../session-format-v2-to-v3/README.md#native-v3-admission) to the unchanged representation: malformed canonical events and invalid relationships are refused; unknown required event types require installed vocabulary; unknown ignorable events retain their opaque values. This edge changes no source coordinates or payload meaning, so retaining opaque data does not require interpreting it. The separate source-audit policies of earlier edges remain unchanged. A `session-log-deepseek/delivery-accepted` event must identify a nonnegative safe-integer generation; omission identifies V0. A source marker claiming V4 is refused because advancing the header would activate it. Source V3 markers require a nonempty Session id and a `throughSeq` that names an earlier event. A foreign V3 marker is permitted only inside the inherited prefix of a Session with `parentSession`. Other generations retain their recorded coordinates and ids. No delivery payload is rewritten. @@ -53,6 +53,23 @@ V4 restoration validates V4 delivery coordinates and ownership under the same ru ----- +### Entry point + +```text +const catalog = createSessionFormatCatalogWithChildren(childFacts) +const restore = catalog.createRestore(physicalHeader, { + recovery: 'strict', validation: 'current', +}) +for (const row of rows) restore.decodeRow(row) +const artifact = restore.finish() +``` + +`childFacts` is required explicitly; an empty array declares no children to backfill. The catalog uses `createSessionFormatV3ToV4(childFacts)` to bind this evidence in the stage factory; the generic migration interfaces carry no child data. Keep the evidence unchanged for the lifetime of the bound migration. `historicalChildCatalogSource()` collects a direct subagent child's id, creation time, own descriptor count, and descriptor payload after the inherited prefix. Collection permits absent or unknown descriptors. The Stage interprets descriptor v1 as continuable with a required label, and v2/v3 through their mode and label fields; it does not restore historical continuation composition. + +An existing own parent catalog entry does not require an available child descriptor. Its extensions remain intact; creation time and available supported discovery fields must agree with the child. Duplicate own descriptors are refused. A missing catalog entry requires exactly one supported descriptor with complete discovery fields; missing or unknown descriptors refuse migration without publication. Native V4 reads also validate own catalog fields and uniqueness; malformed catalog data reports a format error rather than an incoming-migration failure. Catalog payload version 0 is the admitted schema; future payload evolution must update the codec’s admission and the repository’s persistence-change records together. + +Migration retains every source event, order, sequence, timestamp, and payload, appending missing own catalog records sorted by creation time then child id. Appended records use the last source event time, or header creation time for an empty log. Catalog field and uniqueness checks apply only after the final inherited cut; inherited payloads remain opaque and do not establish own membership. Existing catalog extensions remain intact. + ## Understand the implementation @@ -83,11 +100,11 @@ The target restorer uses a private V3 relationship view to distinguish V4 delive #### What the model sees -Historical requests retain their recorded messages and model configuration because the [identity stage](src/migration.ts) preserves `SessionFormatEvent.data`. This edge adds no model-visible content. +Historical requests retain their recorded messages and model configuration because the [migration stage](src/migration.ts) preserves `SessionFormatEvent.data`. This edge adds no model-visible content. #### Token effect -The identity conversion changes no request text or token-bearing data. +Catalog records do not enter model messages directly; subsequent subagent listing can discover the historical children. #### KV Cache effect @@ -97,8 +114,9 @@ The edge preserves the recorded request prefix. Provider cache availability and -- **Existing V4 data skips this edge** — later edits to the unreleased migration do not transform an already-written V4 generation. Integration tests need fresh disposable homes populated from unchanged historical input. -- **No file publication** — the library returns validated logical events; persistence owns publishing a successor beside unchanged committed generations. +- **Unreleased integration format** — integrate and validate the selected structural changes before releasing V4; already-written V4 files do not rerun this incoming edge. Use disposable integration homes and retain the original historical inputs. +- **Retained child logs required** — a parent alone cannot recover unrecorded child ids, creation times, or descriptors. Deleted children cannot be reconstructed from tool arguments; existing parent catalog records remain. +- **Storage scope** — facts cover recognizable children within the same persistence root. Cross-root import and corrupt-log repair are outside this migration. ### Dev Note diff --git a/packages/session/session-format-v3-to-v4/README.zh.md b/packages/session/session-format-v3-to-v4/README.zh.md index 169ba02002..72c47cf5c1 100644 --- a/packages/session/session-format-v3-to-v4/README.zh.md +++ b/packages/session/session-format-v3-to-v4/README.zh.md @@ -9,7 +9,7 @@ kind: "package-library" ## 概述 -将受支持的 V3 Session 恢复为 V4,不改变其中的事件或历史请求。该库推进头部版本,保留事件坐标和继承切分点,并防止历史投递标记成为生效的 V4 水位。持久化通过静态目录使用本库;本库不读取或发布文件。 +`dsh-session-format-v3-to-v4` 将已发布的 V3 Session 恢复为尚未发布的 V4 集成格式。入边保留已接纳事件,追加缺失的父目录记录,并继承 V3 分帧与关系校验。静态格式目录使用本库;JSONL 持久化负责源读取和后继代发布。 ## 目录 @@ -41,11 +41,11 @@ const targetHeader = sessionFormatV3ToV4.migrateHeader(sourceHeader) ## V3 到 V4 规范 -逻辑头部只将 `version: 3` 改为 `version: 4`。每个获准事件都保留其类型、载荷、时间戳、序号、消息身份、surface 操作和引用。Stage 输出原始事件对象,不增删或重排事件。已发布 V3 编解码器仍由 [V2 到 V3](../session-format-v2-to-v3/README.zh.md)拥有;本包复用它,不改变较早迁移的语义。 +逻辑头部只将 `version: 3` 改为 `version: 4`。每个获准事件都保留其类型、载荷、时间戳、序号、消息身份、surface 操作和引用。Stage 输出原始事件对象,并在未改变的源事件之后追加缺失的自身父目录记录。已发布 V3 编解码器仍由 [V2 到 V3](../session-format-v2-to-v3/README.zh.md)拥有;本包复用它,不改变较早迁移的语义。 源事件必须从零开始连续编号。带种子的 Session 中,最后一个携带 `inherited: true` 的 `session/end-seed` 决定继承事件数,不包含该标记本身。传入的源切分点必须与之相符。带种子却缺少标记,或不带种子却出现继承标记的 Session 均被拒绝。每个 Stage 独立拥有计数器和切分点;带种子的 Stage 在 EOF 前保持切分点未知,包括前序迁移改变事件数的情况。 -完整恢复对未改变的表示应用[原生 V3 准入规则](../session-format-v2-to-v3/README.zh.md#native-v3-admission):拒绝格式错误的规范事件和无效关系;未知必需事件类型要求已安装的事件词表支持;未知可忽略事件保留其不透明值。该恒等迁移不改变坐标或载荷含义,因此保留不透明数据不需要解释其内容。较早迁移边各自的源审计策略保持不变。 +完整恢复对未改变的表示应用[原生 V3 准入规则](../session-format-v2-to-v3/README.zh.md#native-v3-admission):拒绝格式错误的规范事件和无效关系;未知必需事件类型要求已安装的事件词表支持;未知可忽略事件保留其不透明值。该迁移不改变源坐标或载荷含义,因此保留不透明数据不需要解释其内容。较早迁移边各自的源审计策略保持不变。 `session-log-deepseek/delivery-accepted` 事件必须标识非负安全整数代际;省略时表示 V0。声称属于 V4 的源标记会被拒绝,因为推进头部会使它生效。源 V3 标记要求非空 Session id,以及指向较早事件的 `throughSeq`。属于其他 Session 的 V3 标记只允许出现在带有 `parentSession` 的 Session 的继承前缀中。其他代际保留记录的坐标和 id。任何投递载荷都不会被重写。 @@ -53,6 +53,23 @@ V4 恢复按相同规则校验 V4 投递坐标和归属。V3 投递在 V4 中属 ----- +### 入口 + +```text +const catalog = createSessionFormatCatalogWithChildren(childFacts) +const restore = catalog.createRestore(physicalHeader, { + recovery: 'strict', validation: 'current', +}) +for (const row of rows) restore.decodeRow(row) +const artifact = restore.finish() +``` + +`childFacts` 必须显式提供;空数组声明没有可补齐的子 Session。catalog 使用 `createSessionFormatV3ToV4(childFacts)` 在 stage 工厂中绑定这些证据;通用迁移接口不传递子 Session 数据。在已绑定迁移的生命周期内保持证据不变。`historicalChildCatalogSource()` 收集直属 subagent 子 Session 的 id、创建时间、继承前缀之后的自身 descriptor 数量及载荷。收集阶段允许 descriptor 缺失或版本未知。Stage 将 descriptor v1 解释为必须带 label 的 continuable,按 v2/v3 的 mode 与 label 字段解释这两个版本;它不恢复历史 continuation composition。 + +父 Session 已有的自身目录记录不要求子 descriptor 可用。记录中的扩展字段保持不变;创建时间与可获得的受支持发现字段必须与子 Session 一致。重复的自身 descriptor 会被拒绝。缺失的目录记录要求恰好一个受支持且发现字段完整的 descriptor;descriptor 缺失或版本未知会拒绝迁移且不发布后继版本。原生 V4 读取也检查自身目录字段及唯一性;畸形目录数据报告格式错误,而不是入边迁移失败。目录载荷版本 0 是准入模式;后续载荷演进必须同时更新编解码器准入规则与仓库的持久化变更记录。 + +迁移保留每个来源事件及其顺序、序号、时间和 payload,仅按创建时间、子 id 排序追加缺失的自身目录记录。追加时间使用来源最后一个事件的时间,空日志使用 header 创建时间。目录字段与唯一性检查仅作用于最终继承截点之后的记录;继承的 payload 保持不透明,也不计入自身成员关系。已有目录的扩展字段原样保留。 + ## 理解实现 @@ -83,11 +100,11 @@ V4 恢复按相同规则校验 V4 投递坐标和归属。V3 投递在 V4 中属 #### 模型看到什么 -历史请求保留记录的消息与模型配置,因为[恒等迁移 Stage](src/migration.ts)保留 `SessionFormatEvent.data`。该迁移边不添加模型可见内容。 +历史请求保留记录的消息与模型配置,因为[迁移 Stage](src/migration.ts)保留 `SessionFormatEvent.data`。该迁移边不添加模型可见内容。 #### Token 影响 -恒等转换不改变请求文本或承载 token 的数据。 +目录记录不直接进入模型消息;后续子代理列举可以发现历史子 Session。 #### KV Cache 影响 @@ -97,8 +114,9 @@ V4 恢复按相同规则校验 V4 投递坐标和归属。V3 投递在 V4 中属 -- **现有 V4 数据跳过此迁移边** — 对尚未发布迁移的后续修改不会转换已经写出的 V4 代际。集成测试需要使用新的临时 home,并从未改变的历史输入初始化。 -- **不发布文件** — 本库返回已校验的逻辑事件;持久化负责在不改变已提交代际的前提下发布后继文件。 +- **尚未发布的集成格式**——发布 V4 前须集成并验证选定的结构变更;已写入的 V4 文件不会重跑此入边。使用可丢弃的集成 home,并保留原始历史输入。 +- **依赖保留的子日志**——仅凭父日志无法恢复未记录的子 id、创建时间或 descriptor。删除的子 Session 无法从工具参数恢复;已存在的父目录记录仍保留。 +- **存储范围**——事实只覆盖同一持久化根目录内可识别的子 Session。跨根目录导入和损坏日志修复不属于此迁移。 ### 开发备注 diff --git a/packages/session/session-format-v3-to-v4/src/facts.ts b/packages/session/session-format-v3-to-v4/src/facts.ts new file mode 100644 index 0000000000..029eae5794 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/src/facts.ts @@ -0,0 +1,88 @@ +/** Historical child identity reduced to the fields required by a parent's catalog. */ + +import { SessionFormatError, SessionFormatUnsupportedMigrationError, isSessionFormatJsonObject, sessionFormatCount } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatArtifact, SessionFormatJsonObject, SessionFormatJsonValue } from '@deepseek-ai/dsh-session-format' + +/** + * Collect a child's own descriptor without requiring one before its parent catalog is read. + * @param artifact - validated historical child artifact with its exact inherited cut. + * @returns compact child identity and descriptor evidence for catalog completion. + */ +export function historicalChildCatalogSource(artifact: SessionFormatArtifact): SessionFormatJsonObject { + const header = artifact.header + if (header.origin !== 'subagent' || header.parentSession === undefined) { + throw new SessionFormatUnsupportedMigrationError('catalog migration requires a subagent child with a direct parent') + } + const descriptors = artifact.events.filter(event => event.type === 'subagent/descriptor' && event.seq >= artifact.inheritedEventCount) + return { + childId: header.id, childCreatedAt: header.createdAt, + descriptorCount: descriptors.length, descriptor: descriptors[0]?.data ?? null, + } +} + +/** + * Validate supplemental child evidence supplied across the migration JSON interface. + * @param value - collected child identity and optional descriptor. + * @returns validated evidence; descriptor interpretation is deferred until parent membership is known. + */ +export function childCatalogSource(value: SessionFormatJsonValue): SessionFormatJsonObject { + if (!isSessionFormatJsonObject(value) || typeof value['childId'] !== 'string' + || !Object.hasOwn(value, 'descriptor')) { + throw new SessionFormatUnsupportedMigrationError('catalog migration requires historical child identity and descriptor evidence') + } + sessionFormatCount(value['childCreatedAt'], 'catalog child creation time') + sessionFormatCount(value['descriptorCount'], 'child descriptor count') + return value +} + +/** + * Interpret only the discovery fields of known historical descriptors. + * @param source - validated child evidence. + * @returns a catalog fact, or undefined when an existing entry needs no unavailable descriptor. + */ +export function childCatalogFact(source: SessionFormatJsonObject): SessionFormatJsonObject | undefined { + const id = source['childId'] as string + const descriptor = source['descriptor'] + const count = source['descriptorCount'] as number + const known = isSessionFormatJsonObject(descriptor) && [1, 2, 3].includes(descriptor['version'] as number) + if (count > 1) { + throw new SessionFormatUnsupportedMigrationError(`${childCatalogSubject(source)} requires exactly one own supported subagent descriptor to complete its parent catalog`) + } + if (count === 0 || !known) return undefined + if (typeof descriptor['provider'] !== 'string') { + throw new SessionFormatUnsupportedMigrationError(`${childCatalogSubject(source)} has an invalid subagent descriptor provider`) + } + return catalogFact({ + version: 0, childId: id, childCreatedAt: source['childCreatedAt'] as number, + // V1 described only continuable children and carried no mode field. + mode: descriptor['version'] === 1 ? 'continuable' : descriptor['mode'] as SessionFormatJsonValue, + ...(descriptor['label'] === undefined ? {} : { label: descriptor['label'] }), + }, childCatalogSubject(source)) +} + +/** + * Validate the historical fields used for catalog membership without interpreting extensions. + * @param value - catalog payload or prepared historical discovery fact. + * @param subject - event type or child identity used in rejection diagnostics. + * @returns validated catalog payload. + */ +export function catalogFact(value: SessionFormatJsonValue, subject = 'subagent/catalog'): SessionFormatJsonObject { + if (!isSessionFormatJsonObject(value) || value['version'] !== 0 + || typeof value['childId'] !== 'string' + || (value['mode'] !== 'continuable' && value['mode'] !== 'one-shot') + || (value['mode'] === 'continuable' && typeof value['label'] !== 'string') + || (value['label'] !== undefined && typeof value['label'] !== 'string')) { + throw new SessionFormatError(`${subject} requires a complete version 0 catalog fact`) + } + sessionFormatCount(value['childCreatedAt'], 'catalog child creation time') + return value +} + +/** + * Name the child and its optional storage-owned location in a migration diagnostic. + * @param source - validated supplemental child evidence. + * @returns a child identity with its source path when persistence supplied one. + */ +export function childCatalogSubject(source: SessionFormatJsonObject): string { + return `Session ${source['childId'] as string}${typeof source['sourcePath'] === 'string' ? ` (raw log: ${source['sourcePath']})` : ''}` +} diff --git a/packages/session/session-format-v3-to-v4/src/index.ts b/packages/session/session-format-v3-to-v4/src/index.ts index a440a78ee2..439ea404cf 100644 --- a/packages/session/session-format-v3-to-v4/src/index.ts +++ b/packages/session/session-format-v3-to-v4/src/index.ts @@ -1,6 +1,7 @@ -/** Identity V3-to-V4 migration with frozen V3 framing and generation-aware delivery validation. */ +/** V3 framing and adjacent historical parent-catalog migration into V4. */ export { releasedV3SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v2-to-v3' export * from './codec.ts' export * from './migration.ts' -export { assertReleasedV4Header, restoreReleasedV4Artifact } from './validation.ts' +export { assertReleasedV4Header, assertReleasedV4Relationships, restoreReleasedV4Artifact } from './validation.ts' +export { historicalChildCatalogSource } from './facts.ts' diff --git a/packages/session/session-format-v3-to-v4/src/migration.ts b/packages/session/session-format-v3-to-v4/src/migration.ts index 6f6497367e..228715d53a 100644 --- a/packages/session/session-format-v3-to-v4/src/migration.ts +++ b/packages/session/session-format-v3-to-v4/src/migration.ts @@ -1,11 +1,12 @@ -/** Streaming V3-to-V4 identity conversion with inherited cuts and delivery activation guards. */ +/** Append historical child facts after the unchanged V3 source suffix. */ -import { SessionFormatError, SessionFormatUnsupportedMigrationError, defineSessionFormatMigration, sessionFormatCount } from '@deepseek-ai/dsh-session-format' -import type { SessionFormatEvent, SessionFormatEventRun, SessionFormatJsonObject, SessionFormatMigrationContext, SessionFormatMigrationStage, SessionFormatMigrationStageInput } from '@deepseek-ai/dsh-session-format' +import { defineSessionFormatMigration, SessionFormatError, SessionFormatUnsupportedMigrationError, isSessionFormatJsonObject, sessionFormatCount } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatEvent, SessionFormatEventRun, SessionFormatJsonObject, SessionFormatJsonValue, SessionFormatMigration, SessionFormatMigrationContext, SessionFormatMigrationStage, SessionFormatMigrationStageInput } from '@deepseek-ai/dsh-session-format' import { assertReleasedV3Header } from '@deepseek-ai/dsh-session-format-v2-to-v3' import { assertReleasedV4Header, validateDeliveryAccepted } from './validation.ts' +import { catalogFact, childCatalogSource, childCatalogFact, childCatalogSubject } from './facts.ts' -/** Adjacent migration preserves admitted V3 event values and coordinates. */ +/** Header-only migration declaration; body restoration requires explicit child evidence. */ export const sessionFormatV3ToV4 = defineSessionFormatMigration({ name: '@deepseek-ai/dsh-session-format-v3-to-v4', fromVersion: 3, @@ -14,26 +15,51 @@ export const sessionFormatV3ToV4 = defineSessionFormatMigration({ assertReleasedV3Header(header) return { ...header, version: 4 } }, - createStage(input) { return new ReleasedV3ToV4Stage(input) }, + createStage() { + throw new SessionFormatUnsupportedMigrationError('V3 catalog migration requires explicit historical child facts, including an empty array for a parent without children') + }, validateTargetHeader: assertReleasedV4Header, }) +/** + * Bind one parent's historical child evidence to its V3→V4 migration. + * @param children - complete child evidence retained unchanged for the lifetime of this declaration; an empty array declares no children. + * @returns an adjacent migration that creates independent stages with the supplied evidence. + */ +export function createSessionFormatV3ToV4(children: readonly SessionFormatJsonValue[]): SessionFormatMigration { + return defineSessionFormatMigration({ + ...sessionFormatV3ToV4, + createStage: input => new ReleasedV3ToV4Stage(input, children), + }) +} + class ReleasedV3ToV4Stage implements SessionFormatMigrationStage { readonly headerInheritedEventCount?: number + private readonly candidates: readonly SessionFormatJsonObject[] + private readonly catalogs: SessionFormatJsonValue[] = [] private cut: number | undefined private nextSeq = 0 + private time: number private foreignDeliverySeq: number | undefined - constructor(private readonly input: SessionFormatMigrationStageInput) { + constructor(private readonly input: SessionFormatMigrationStageInput, children: readonly SessionFormatJsonValue[]) { + this.candidates = children.map(childCatalogSource).sort((left, right) => + (left['childCreatedAt'] as number) - (right['childCreatedAt'] as number) + || (left['childId'] === right['childId'] ? 0 : (left['childId'] as string) < (right['childId'] as string) ? -1 : 1)) this.cut = input.sourceHeader.isSeeded ? undefined : 0 if (!input.sourceHeader.isSeeded) this.headerInheritedEventCount = 0 + this.time = input.sourceHeader.createdAt } transformEvent(event: SessionFormatEvent, context: SessionFormatMigrationContext): void { - if (event.seq !== this.nextSeq++) throw new SessionFormatError('format v3 source events must be dense') - if (event.type === 'session/end-seed' && (event.data as SessionFormatJsonObject)['inherited'] === true) { + if (event.seq !== this.nextSeq++) throw new SessionFormatError('V3 source events must be dense') + this.time = event.time + if (event.type === 'session/end-seed' && isSessionFormatJsonObject(event.data) && event.data['inherited'] === true) { if (!this.input.sourceHeader.isSeeded) throw new SessionFormatError('unseeded format v3 Session contains an inherited end-seed marker') this.cut = event.seq + this.catalogs.length = 0 + } else if (event.type === 'subagent/catalog') { + this.catalogs.push(event.data) } const deliveryId = validateDeliveryAccepted(event, 3) if (event.type === 'session-log-deepseek/delivery-accepted') { @@ -49,8 +75,16 @@ class ReleasedV3ToV4Stage implements SessionFormatMigrationStage { for (const event of run.expand()) this.transformEvent(event, context) } - finish(_context: SessionFormatMigrationContext): number { - const cut = sessionFormatCount(this.cut, 'format v3 inherited event count') + finish(context: SessionFormatMigrationContext): number { + const cut = sessionFormatCount(this.cut, 'V3 inherited event count') + // Catalog payloads belong to this Session only after the final inherited cut. + const existingCatalogs = new Map() + for (const data of this.catalogs) { + const fact = catalogFact(data) + const id = fact['childId'] as string + if (existingCatalogs.has(id)) throw new SessionFormatUnsupportedMigrationError(`duplicate catalog child ${id}`) + existingCatalogs.set(id, fact) + } if (this.input.sourceInheritedEventCount !== undefined && cut !== this.input.sourceInheritedEventCount) { throw new SessionFormatError('format v3 inherited cut disagrees with its source marker') } @@ -58,6 +92,23 @@ class ReleasedV3ToV4Stage implements SessionFormatMigrationStage { && (this.input.sourceHeader.parentSession === undefined || this.foreignDeliverySeq >= cut)) { throw new SessionFormatError('current-generation delivery marker names the wrong Session') } + for (const source of this.candidates) { + const id = source['childId'] as string + const existing = existingCatalogs.get(id) + const fact = childCatalogFact(source) + if (existing !== undefined) { + if (existing['childCreatedAt'] !== source['childCreatedAt']) { + throw new SessionFormatUnsupportedMigrationError(`${childCatalogSubject(source)} conflicts with its parent catalog`) + } + if (fact !== undefined && ['mode', 'label'].some(key => existing[key] !== fact[key])) { + throw new SessionFormatUnsupportedMigrationError(`${childCatalogSubject(source)} conflicts with its parent catalog`) + } + continue + } + if (fact === undefined) throw new SessionFormatUnsupportedMigrationError(`${childCatalogSubject(source)} requires exactly one own supported subagent descriptor to complete its parent catalog`) + existingCatalogs.set(id, fact) + context.emitEvent({ type: 'subagent/catalog', seq: this.nextSeq++, time: this.time, data: fact }) + } return cut } } diff --git a/packages/session/session-format-v3-to-v4/src/validation.ts b/packages/session/session-format-v3-to-v4/src/validation.ts index a68e3542c5..4793bdcff6 100644 --- a/packages/session/session-format-v3-to-v4/src/validation.ts +++ b/packages/session/session-format-v3-to-v4/src/validation.ts @@ -3,6 +3,7 @@ import { SessionFormatError, isSessionFormatJsonObject, sessionFormatCount } from '@deepseek-ai/dsh-session-format' import type { SessionFormatArtifact, SessionFormatEvent, SessionFormatHeader, SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' import { assertReleasedV3Header, restoreReleasedV3Artifact } from '@deepseek-ai/dsh-session-format-v2-to-v3' +import { catalogFact } from './facts.ts' /** * Validate V4 metadata with the unchanged released V3 header fields. @@ -21,8 +22,8 @@ export function assertReleasedV4Header(header: SessionFormatHeader): void { */ export function restoreReleasedV4Artifact(artifact: SessionFormatArtifact, knownEventTypes: ReadonlySet): SessionFormatArtifact { assertReleasedV4Header(artifact.header) + assertReleasedV4Relationships(artifact) const events = artifact.events.map((event): SessionFormatEvent => { - validateDeliveryAccepted(event, 4) if (event.type !== 'session-log-deepseek/delivery-accepted') return event const data = event.data as SessionFormatJsonObject const version = data['sessionFormatVersion'] @@ -53,3 +54,25 @@ export function validateDeliveryAccepted(event: SessionFormatEvent, currentVersi if (typeof id !== 'string' || id.length === 0) throw new SessionFormatError('delivery requires a nonempty Session id') return id } + +/** + * Validate V4 catalog membership and delivery ownership without changing vocabulary or turn recovery policies. + * @param artifact - decoded artifact with its final inherited cut. + */ +export function assertReleasedV4Relationships(artifact: SessionFormatArtifact): void { + const ids = new Set() + for (const event of artifact.events) { + const deliveryId = validateDeliveryAccepted(event, 4) + if (deliveryId !== undefined + && !(artifact.header.parentSession !== undefined && event.seq < artifact.inheritedEventCount) + && deliveryId !== artifact.header.id) { + throw new SessionFormatError('current-generation delivery marker names the wrong Session') + } + if (event.type === 'subagent/catalog' && event.seq >= artifact.inheritedEventCount) { + const fact = catalogFact(event.data) + const id = fact['childId'] as string + if (ids.has(id)) throw new SessionFormatError(`duplicate catalog child ${id}`) + ids.add(id) + } + } +} diff --git a/packages/session/session-format-v3-to-v4/tests/catalog-completion.spec.ts b/packages/session/session-format-v3-to-v4/tests/catalog-completion.spec.ts new file mode 100644 index 0000000000..a0b52938e2 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/tests/catalog-completion.spec.ts @@ -0,0 +1,150 @@ +import { describe, expect, it } from 'vitest' +import { isSessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' +import { catalogFact, childCatalogFact } from '../src/facts.ts' +import type { SessionFormatEvent, SessionFormatJsonValue } from '@deepseek-ai/dsh-session-format' +import { createSessionFormatV3ToV4, historicalChildCatalogSource, sessionFormatV3ToV4 } from '../src/index.ts' + +const header = { version: 3, id: 'parent', createdAt: 1, isSeeded: false, delegationDepth: 0 } +const child = { version: 0, childId: 'child', childCreatedAt: 2, mode: 'continuable', label: 'child task' } + +function migrate(events: SessionFormatEvent[], facts: readonly SessionFormatJsonValue[], seeded = false, cut?: number, run = false) { + const migration = createSessionFormatV3ToV4(facts.map((value) => { + if (!isSessionFormatJsonObject(value) || !('version' in value)) return value + const fact = catalogFact(value) + return { childId: fact['childId']!, childCreatedAt: fact['childCreatedAt']!, descriptorCount: 1, + descriptor: { version: 3, provider: 'spawn', mode: fact['mode']!, ...(fact['label'] === undefined ? {} : { label: fact['label'] }) } } + })) + const stage = migration.createStage({ + sourceHeader: { ...header, isSeeded: seeded, ...(seeded ? { parentSession: 'ancestor' } : {}) }, targetHeader: { ...header, version: 4, isSeeded: seeded }, + sourceKind: 'decoded', sourceInheritedEventCount: cut ?? (seeded ? undefined : 0), + }) + const output: SessionFormatEvent[] = [] + const context = { emitEvent: (event: SessionFormatEvent) => { output.push(event) }, emitRun: () => { throw new Error('unexpected run') } } + if (run) stage.transformRun({ runType: 'test', firstSeq: 0, eventCount: events.length, *expand() { yield* events } }, context) + else for (const event of events) stage.transformEvent(event, context) + return { cut: stage.finish(context), events: output } +} + +describe('V3 parent catalog completion', () => { + it('appends deterministic child facts without changing source events', () => { + const source = [{ type: 'feedback/record', seq: 0, time: 10, data: { text: 'retained' } }] + const result = migrate(source, [child]) + expect(result.events[0]).toBe(source[0]) + expect(result.events[1]).toEqual({ type: 'subagent/catalog', seq: 1, time: 10, data: child }) + expect(migrate(source, [child])).toEqual(result) + expect(source).toHaveLength(1) + }) + + it('preserves existing facts and adds only missing children', () => { + const source = [{ type: 'subagent/catalog', seq: 0, time: 5, data: child }] + expect(migrate(source, [child, child]).events).toEqual(source) + expect(migrate(source, [child, { ...child, childId: 'second' }]).events).toHaveLength(2) + }) + + it('does not treat inherited catalog membership as owned', () => { + const source = [ + { type: 'subagent/catalog', seq: 0, time: 1, data: child }, + { type: 'session/end-seed', seq: 1, time: 2, data: { inherited: true } }, + ] + const result = migrate(source, [child], true) + expect(result.cut).toBe(1) + expect(result.events[2]).toMatchObject({ type: 'subagent/catalog', seq: 2, data: child }) + }) + + it('validates catalog payloads only after the final inherited seed marker', () => { + const opaque = { type: 'subagent/catalog', seq: 0, time: 1, data: { version: 99 } } + const seed = { type: 'session/end-seed', seq: 1, time: 2, data: { inherited: true } } + const source = [opaque, seed, { ...opaque, seq: 2 }, { ...seed, seq: 3 }] + expect(migrate(source, [child], true).events).toEqual([ + ...source, { type: 'subagent/catalog', seq: 4, time: 2, data: child }, + ]) + expect(() => migrate([...source, { ...opaque, seq: 4 }], [], true)).toThrow('complete version 0') + expect(() => migrate([opaque], [])).toThrow('complete version 0') + }) + + it('requires explicit corpus facts and refuses conflicting identities', () => { + expect(() => sessionFormatV3ToV4.createStage({ sourceHeader: header, targetHeader: { ...header, version: 4 }, + sourceKind: 'decoded', sourceInheritedEventCount: 0 })).toThrow('explicit historical child facts') + expect(() => migrate([], [{ ...child, mode: 'unknown' }])).toThrow('complete version 0') + expect(() => migrate([{ type: 'subagent/catalog', seq: 0, time: 2, data: child }], [{ ...child, childCreatedAt: 3 }])).toThrow('conflicts') + }) + + it('extracts the own descriptor after a fork prefix', () => { + const artifact = { + header: { ...header, id: 'child', createdAt: 2, origin: 'subagent' as const, parentSession: 'parent', isSeeded: true }, + inheritedEventCount: 1, + events: [ + { type: 'subagent/descriptor', seq: 0, time: 1, data: { version: 3, mode: 'one-shot', provider: 'fork' } }, + { type: 'subagent/descriptor', seq: 1, time: 2, data: { version: 3, mode: 'continuable', provider: 'fork', label: 'child task' } }, + ], + } + expect(childCatalogFact(historicalChildCatalogSource(artifact))).toEqual(child) + expect(() => migrate([], [historicalChildCatalogSource({ ...artifact, inheritedEventCount: 0 })])).toThrow('exactly one') + expect(() => migrate([], [historicalChildCatalogSource({ ...artifact, events: [] })])).toThrow('exactly one') + }) + it('orders tied and differently dated children independently of directory enumeration', () => { + const children = [{ ...child, childId: 'z' }, { ...child, childId: 'a' }, { ...child, childId: 'first', childCreatedAt: 1 }] + expect(migrate([], children).events.map(event => event.data)).toEqual([children[2], children[1], children[0]]) + expect(migrate([], children).events[0]?.time).toBe(1) + }) + + it('rejects duplicates, sparse events, and missing or inconsistent seed cuts', () => { + const catalog = { type: 'subagent/catalog', seq: 0, time: 1, data: child } + expect(() => migrate([catalog, { ...catalog, seq: 1 }], [])).toThrow('duplicate') + expect(() => migrate([{ ...catalog, seq: 1 }], [])).toThrow('dense') + expect(() => migrate([], [], true)).toThrow('inherited event count') + expect(() => migrate([], [], false, 1)).toThrow('disagrees') + expect(migrate([catalog], [], false, undefined, true).events).toEqual([catalog]) + }) + + it('rejects target delivery activation and invalid current delivery ownership', () => { + const preceding = { type: 'feedback/record', seq: 0, time: 1, data: { text: 'prior' } } + const delivery = { type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 1, + data: { sessionId: 'other', throughSeq: 0, sessionFormatVersion: 4 } } + expect(() => migrate([preceding, delivery], [])).toThrow('claims target format v4') + expect(() => migrate([preceding, { ...delivery, data: { ...delivery.data, sessionFormatVersion: 3 } }], [])).toThrow('wrong Session') + }) + + it('requires supported descriptors and complete discovery fields', () => { + const artifact = { header: { ...header, origin: 'subagent' as const, parentSession: 'parent' }, inheritedEventCount: 0, events: [] } + expect(() => historicalChildCatalogSource({ ...artifact, header })).toThrow('direct parent') + for (const data of [null, {}, { version: 4, mode: 'one-shot', provider: 'spawn' }]) { + expect(() => migrate([], [historicalChildCatalogSource({ ...artifact, events: [{ type: 'subagent/descriptor', seq: 0, time: 1, data }] })])).toThrow('supported subagent descriptor') + } + for (const value of [null, { ...child, version: 1 }, { ...child, childId: null }, + { ...child, label: null }, { ...child, childCreatedAt: -1 }]) { + expect(() => migrate([], [value])).toThrow() + } + expect(migrate([], [{ version: 0, childId: 'one-shot', childCreatedAt: 2, mode: 'one-shot' }]).events).toHaveLength(1) + }) + + it.each([null, { version: 99 }])('retains existing catalog extensions without interpreting unavailable descriptors: %j', (descriptor) => { + const data = { ...child, extension: 'retained' } + const source = [{ type: 'subagent/catalog', seq: 0, time: 1, data }] + expect(migrate(source, [{ childId: 'child', childCreatedAt: 2, descriptorCount: descriptor === null ? 0 : 1, descriptor }]).events).toEqual(source) + }) + + it('refuses malformed supplemental evidence and known descriptor conflicts', () => { + for (const source of [null, {}, { childId: 'child', childCreatedAt: 2, descriptor: null, descriptorCount: -1 }]) { + expect(() => migrate([], [source])).toThrow() + } + const source = { childId: 'child', childCreatedAt: 2, descriptorCount: 1, + descriptor: { version: 3, mode: 'continuable', label: 'child task' } } + expect(() => migrate([], [source])).toThrow('invalid subagent descriptor provider') + const existing = [{ type: 'subagent/catalog', seq: 0, time: 1, data: child }] + expect(() => migrate(existing, [{ ...source, descriptor: { ...source.descriptor, provider: 'spawn', label: 'different' } }])).toThrow('conflicts') + }) + + it('validates predecessor delivery before preserving its generation identity', () => { + const prior = { type: 'feedback/record', seq: 0, time: 1, data: { text: 'prior' } } + const marker = { type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 1, + data: { sessionId: 'ancestor', throughSeq: 0, sessionFormatVersion: 3 } } + const seed = { type: 'session/end-seed', seq: 2, time: 2, data: { inherited: true } } + expect(migrate([prior, marker, seed], [], true).events).toEqual([prior, marker, seed]) + expect(() => migrate([prior, { ...seed, seq: 1 }, { ...marker, seq: 2 }], [], true)).toThrow('wrong Session') + expect(migrate([prior, { ...marker, data: { ...marker.data, sessionFormatVersion: 2 } }], []).events).toHaveLength(2) + expect(migrate([prior, { ...marker, data: { ...marker.data, sessionId: 'parent' } }], []).events).toHaveLength(2) + expect(childCatalogFact(historicalChildCatalogSource({ header: { ...header, origin: 'subagent', parentSession: 'ancestor' }, inheritedEventCount: 0, + events: [{ type: 'subagent/descriptor', seq: 0, time: 1, data: { version: 3, mode: 'one-shot', provider: 'spawn' } }] }))).toEqual({ version: 0, childId: 'parent', childCreatedAt: 1, mode: 'one-shot' }) + }) +}) diff --git a/packages/session/session-format-v3-to-v4/tests/codec.spec.ts b/packages/session/session-format-v3-to-v4/tests/codec.spec.ts index e4e6905d92..c89e62db65 100644 --- a/packages/session/session-format-v3-to-v4/tests/codec.spec.ts +++ b/packages/session/session-format-v3-to-v4/tests/codec.spec.ts @@ -7,7 +7,8 @@ import { assertReleasedV4Header, assertV4RowAdmission, releasedV3SessionFormatCo const header = { version: 4, id: 'parent', createdAt: 1, isSeeded: false, delegationDepth: 0 } const fact: SessionFormatEvent = { type: 'feedback/record', seq: 0, time: 1, data: { text: 'retained' } } -const types = new Set(['feedback/record', 'session-log-deepseek/delivery-accepted', 'session/end-seed']) +const catalog: SessionFormatEvent = { type: 'subagent/catalog', seq: 0, time: 1, data: { version: 0, childId: 'child', childCreatedAt: 2, mode: 'one-shot' } } +const types = new Set(['subagent/catalog', 'feedback/record', 'session-log-deepseek/delivery-accepted', 'session/end-seed']) const delivery = (version: number | undefined, sessionId = header.id): SessionFormatEvent => ({ type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 2, data: { sessionId, throughSeq: 0, ...(version === undefined ? {} : { sessionFormatVersion: version }) }, @@ -113,4 +114,13 @@ describe('V4 framing and restoration', () => { expect(decoder.finish(output)).toBe(0) expect(output.values).toEqual([fact]) }) + it('rejects duplicate own catalog membership', () => { + expect(() => restore([catalog, { ...catalog, seq: 1 }])).toThrow('duplicate catalog child') + }) + + it('keeps inherited catalog entries outside own uniqueness checks', () => { + const artifact = { header: { ...header, isSeeded: true, parentSession: 'ancestor' }, inheritedEventCount: 1, + events: [catalog, { type: 'session/end-seed', seq: 1, time: 2, data: { inherited: true } }, { ...catalog, seq: 2 }] } + expect(restoreReleasedV4Artifact(artifact, types)).toBe(artifact) + }) }) diff --git a/packages/session/session-format-v3-to-v4/tests/corpus.spec.ts b/packages/session/session-format-v3-to-v4/tests/corpus.spec.ts new file mode 100644 index 0000000000..4f5ff88777 --- /dev/null +++ b/packages/session/session-format-v3-to-v4/tests/corpus.spec.ts @@ -0,0 +1,103 @@ +import { readFileSync, readdirSync } from 'node:fs' +import { join, resolve } from 'node:path' +import { expect, it } from 'vitest' +import { createSessionFormatCatalogWithChildren, historicalSessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { isSessionFormatJsonObject, type SessionFormatArtifact, type SessionFormatJsonObject, type SessionFormatJsonValue } from '@deepseek-ai/dsh-session-format' +import { historicalChildCatalogSource } from '../src/index.ts' + +const root = resolve(import.meta.dirname, '../../../..') + +function restoreFixture(path: string): SessionFormatArtifact { + const records = readFileSync(join(root, path), 'utf8').trim().split('\n').map(line => JSON.parse(line) as Record) + const header = records.shift()! + if (typeof header['cwd'] === 'string' && header['cwd'].startsWith('{{cwd}}')) header['cwd'] = resolve('snapshot-cwd') + const restore = historicalSessionFormatCatalog.createRestore(header, { recovery: 'strict', validation: 'current' }) + for (const [seq, record] of records.entries()) { + if (record['type'] === 'request/header' && isSessionFormatJsonObject(record['data']) && isSessionFormatJsonObject(record['data']['header'])) { + const request = { ...record['data']['header'] } + record['data'] = { ...record['data'], header: request } + if (request['tools'] === '{{tools}}') delete request['tools'] + else if (Array.isArray(request['tools']) && request['tools'].every(tool => typeof tool === 'string')) { + request['tools'] = request['tools'].map(name => ({ name, description: '', parameters: {} })) + } + } + restore.decodeRow({ ...record, seq: record['seq'] ?? seq, time: record['time'] ?? 0 }) + } + return restore.finish() +} + +function migrate(parent: SessionFormatArtifact, children: SessionFormatArtifact[]) { + const restore = createSessionFormatCatalogWithChildren(children.map(historicalChildCatalogSource)).createRestore({ type: 'session', ...parent.header }, { + recovery: 'strict', validation: 'current', + }) + for (const event of parent.events) restore.decodeRow(event) + return restore.finish() +} + +it('refuses recorded parent/child clock conflicts and migrates consistent copies including failed startup', () => { + const conflicts: string[] = [] + let pairs = 0 + let withoutDescriptor = 0 + for (const profile of ['sdk', 'session']) { + const base = `snapshots/${profile}` + for (const dir of readdirSync(join(root, base), { withFileTypes: true })) { + if (!dir.isDirectory()) continue + const names = readdirSync(join(root, base, dir.name)).filter(name => /^session(?:\.\d+)?\.v3\.jsonl$/.test(name)) + if (names.length < 2) continue + const logs = names.map(name => ({ path: `${base}/${dir.name}/${name}`, artifact: restoreFixture(`${base}/${dir.name}/${name}`) })) + for (const parent of logs) { + const children = logs.filter(child => child.artifact.header.origin === 'subagent' && child.artifact.header.parentSession === parent.artifact.header.id) + if (children.length === 0) continue + pairs += children.length + const catalogs = parent.artifact.events.filter(event => event.type === 'subagent/catalog' && event.seq >= parent.artifact.inheritedEventCount) + const aligned = children.map((child) => { + const catalog = catalogs.find(event => isSessionFormatJsonObject(event.data) && event.data['childId'] === child.artifact.header.id)?.data + expect(isSessionFormatJsonObject(catalog), child.path).toBe(true) + const createdAt = (catalog as SessionFormatJsonObject)['childCreatedAt'] as number + if (createdAt !== child.artifact.header.createdAt) conflicts.push(child.path) + if (historicalChildCatalogSource(child.artifact)['descriptorCount'] === 0) withoutDescriptor++ + // Only this detached control changes a clock; committed generations are immutable rejection evidence. + return { ...child.artifact, header: { ...child.artifact.header, createdAt } } + }) + if (children.some(child => conflicts.includes(child.path))) { + expect(() => migrate(parent.artifact, children.map(child => child.artifact)), parent.path).toThrow('conflicts with its parent catalog') + } else { + expect(migrate(parent.artifact, children.map(child => child.artifact)).events, parent.path).toEqual(parent.artifact.events) + } + expect(migrate(parent.artifact, aligned), parent.path).toEqual({ + ...parent.artifact, header: { ...parent.artifact.header, version: 4 }, + }) + } + } + } + expect(pairs).toBe(24) + expect(withoutDescriptor).toBe(1) + expect(conflicts.sort()).toEqual(EXPECTED_CONFLICTS) +}) + +const EXPECTED_CONFLICTS = [ + 'snapshots/sdk/subagent-continuable-inheritance/session.1.v3.jsonl', + 'snapshots/sdk/subagent-continuable/session.1.v3.jsonl', + 'snapshots/sdk/subagent-fork-in-process/session.1.v3.jsonl', + 'snapshots/sdk/subagent-list-agents/session.1.v3.jsonl', + 'snapshots/sdk/subagent-mixed/session.1.v3.jsonl', + 'snapshots/sdk/subagent-mixed/session.2.v3.jsonl', + 'snapshots/sdk/subagent-send-message/session.1.v3.jsonl', + 'snapshots/sdk/subagent-spawn-in-process/session.1.v3.jsonl', + 'snapshots/session/advanced-toolchain-runtime/session.1.v3.jsonl', + 'snapshots/session/advanced-toolchain-runtime/session.2.v3.jsonl', + 'snapshots/session/advanced-toolchain/session.1.v3.jsonl', + 'snapshots/session/advanced-toolchain/session.2.v3.jsonl', + 'snapshots/session/ralph-loop/session.1.v3.jsonl', + 'snapshots/session/ralph-loop/session.2.v3.jsonl', + 'snapshots/session/subagent-child-question-rejection/session.1.v3.jsonl', + 'snapshots/session/subagent-depth-two-rejection/session.1.v3.jsonl', + 'snapshots/session/subagent-depth-two-rejection/session.2.v3.jsonl', + 'snapshots/session/subagent-max-tokens-partial/session.1.v3.jsonl', + 'snapshots/session/subagent-parallel/session.1.v3.jsonl', + 'snapshots/session/subagent-parallel/session.2.v3.jsonl', + 'snapshots/session/subagent-published-run-failure/session.1.v3.jsonl', + 'snapshots/session/subagent-spawn-in-process/session.1.v3.jsonl', + 'snapshots/session/subagent-tool-filter/session.1.v3.jsonl', + 'snapshots/session/workflow-run/session.1.v3.jsonl', +] diff --git a/packages/session/session-format-v3-to-v4/tests/migration.spec.ts b/packages/session/session-format-v3-to-v4/tests/migration.spec.ts index f9e87ee791..53ee1435f9 100644 --- a/packages/session/session-format-v3-to-v4/tests/migration.spec.ts +++ b/packages/session/session-format-v3-to-v4/tests/migration.spec.ts @@ -1,8 +1,9 @@ import { describe, expect, it } from 'vitest' +import { restoreReleasedV3Artifact } from '@deepseek-ai/dsh-session-format-v2-to-v3' import { SessionFormatEventCollector } from '@deepseek-ai/dsh-session-format' import type { SessionFormatEvent, SessionFormatHeader, SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' -import { releasedV3SessionFormatCodec, sessionFormatV3ToV4 } from '../src/index.ts' +import { createSessionFormatCatalogWithChildren, sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { releasedV3SessionFormatCodec, createSessionFormatV3ToV4, sessionFormatV3ToV4 } from '../src/index.ts' const header: SessionFormatHeader = { version: 3, id: 'identity', createdAt: 1, isSeeded: false, delegationDepth: 0 } const fact: SessionFormatEvent = { type: 'feedback/record', seq: 0, time: 2, data: { text: 'retained' } } @@ -13,7 +14,7 @@ const delivery = (version: number | undefined, sessionId = header.id): SessionFo }) function stage(sourceHeader = header, sourceInheritedEventCount?: number) { - return sessionFormatV3ToV4.createStage({ + return createSessionFormatV3ToV4([]).createStage({ sourceHeader, targetHeader: sessionFormatV3ToV4.migrateHeader(sourceHeader), sourceInheritedEventCount, sourceKind: 'decoded', }) @@ -27,12 +28,12 @@ function migrate(events: readonly SessionFormatEvent[], sourceHeader = header, c } function restore(events: readonly SessionFormatEvent[], sourceHeader = header) { - const reader = sessionFormatCatalog.createRestore({ type: 'session', ...sourceHeader }, { recovery: 'strict', validation: 'current' }) + const reader = createSessionFormatCatalogWithChildren([]).createRestore({ type: 'session', ...sourceHeader }, { recovery: 'strict', validation: 'current' }) for (const event of events) reader.decodeRow(event) return reader.finish() } -describe('V3 to V4 identity migration', () => { +describe('V3 to V4 source preservation', () => { it('changes only the header version and retains event objects, payloads, timestamps, and coordinates', () => { const rows = [fact, delivery(3)] const before = JSON.stringify({ header, rows }) @@ -137,7 +138,7 @@ describe('V3 to V4 identity migration', () => { ? { type: 'session', version, id: header.id, createdAt: 1, delegationDepth: 0, parentSession: 'ancestor', seedLength: 6 } : { type: 'session', ...header, version, isSeeded: true, parentSession: 'ancestor' } const before = JSON.stringify({ physical, source }) - const reader = sessionFormatCatalog.createRestore(physical, { recovery: 'strict', validation: 'current' }) + const reader = createSessionFormatCatalogWithChildren([]).createRestore(physical, { recovery: 'strict', validation: 'current' }) for (const row of source) reader.decodeRow(version === 3 ? releasedV3SessionFormatCodec.encodeEvent(row) : row) const artifact = reader.finish() expect(artifact.header.version).toBe(4) @@ -151,4 +152,29 @@ describe('V3 to V4 identity migration', () => { expect(reopened.finish()).toEqual(artifact) expect(JSON.stringify({ physical, source })).toBe(before) }) + + it.each(['strict', 'recoverable'] as const)('retains delivery inside a nested inherited prefix during %s restoration', (recovery) => { + const physical = { type: 'session', ...header, isSeeded: true, parentSession: 'ancestor' } + const rows = [fact, seed, { ...delivery(3, 'ancestor'), seq: 2 }, { ...seed, seq: 3 }] + const decoder = releasedV3SessionFormatCodec.createDecoder(physical, 'strict') + const source = new SessionFormatEventCollector() + for (const row of rows) decoder.decodeRow(row, source) + const artifact = restoreReleasedV3Artifact({ header: decoder.header, events: source.values, + inheritedEventCount: decoder.finish(source) }, new Set(rows.map(row => row.type))) + expect(artifact.inheritedEventCount).toBe(3) + + const reader = createSessionFormatCatalogWithChildren([]).createRestore(physical, { recovery, validation: 'current' }) + for (const row of rows) reader.decodeRow(row) + expect(reader.finish()).toEqual({ ...artifact, header: { ...artifact.header, version: 4 } }) + }) + + it.each(['strict', 'recoverable'] as const)('refuses foreign delivery after the final inherited cut during %s restoration', (recovery) => { + const reader = createSessionFormatCatalogWithChildren([]).createRestore({ type: 'session', ...header, isSeeded: true, parentSession: 'ancestor' }, { + recovery, validation: 'current', + }) + for (const row of [fact, seed, { ...delivery(3, 'ancestor'), seq: 2 }, { ...seed, seq: 3 }, { ...delivery(3, 'ancestor'), seq: 4 }]) { + reader.decodeRow(row) + } + expect(() => reader.finish()).toThrow('wrong Session') + }) }) diff --git a/packages/session/session-log-deepseek/tests/upload.spec.ts b/packages/session/session-log-deepseek/tests/upload.spec.ts index abd4fafc67..25e58bb5f2 100644 --- a/packages/session/session-log-deepseek/tests/upload.spec.ts +++ b/packages/session/session-log-deepseek/tests/upload.spec.ts @@ -8,7 +8,9 @@ import SessionStore, { SessionSeq, type CreateSessionOptions, type SessionEvent, + type SessionHeader, } from '@deepseek-ai/dsh-session' +import { createSessionFormatCatalogWithChildren } from '@deepseek-ai/dsh-session-format-catalog' import DeepSeekLlmApiExtensionRegistry from '@deepseek-ai/dsh-deepseek-llm-api-extensions' import { createAssistantMessage, createSystemMessage, createUserMessage } from '@deepseek-ai/dsh-llm' import type { JsonValue } from '@deepseek-ai/dsh-util-values' @@ -215,6 +217,36 @@ describe('incremental DeepSeek session-log upload', () => { expect(forkPayload.fields.dsh_session_log).toMatchObject({ afterSeq: -1, throughSeq: fork.session.seq - 1 }) }) + it('uploads a migrated V3 log from the beginning before resuming current-generation acknowledgements', async () => { + const id = SessionId('migrated-v3-delivery') + const reader = createSessionFormatCatalogWithChildren([]).createRestore({ + type: 'session', version: 3, id, createdAt: 1, isSeeded: false, delegationDepth: 0, + }, { recovery: 'strict', validation: 'current' }) + reader.decodeRow({ type: 'feedback/record', seq: 0, time: 2, data: { text: 'retained' } }) + reader.decodeRow({ + type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 3, + data: { sessionId: id, throughSeq: 0, sessionFormatVersion: 3 }, + }) + const artifact = reader.finish() + const session = Session.fromRestore(id, artifact.events as SessionEvent[], + artifact.header as unknown as SessionHeader, SessionLogOffset(artifact.inheritedEventCount), 'detached') + const { ctx } = await harness('delivery-migration-owner') + ctx.effect(() => ctx.sessions.enter(session)) + + const first = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: id }) + expect(first.fields.dsh_session_log).toMatchObject({ sessionFormatVersion: SESSION_FORMAT_VERSION, afterSeq: -1 }) + expect(first.fields.dsh_session_log?.events[0]?.seq).toBe(0) + expect(first.fields.dsh_session_log?.events[1]).toMatchObject({ data: { sessionFormatVersion: 3, throughSeq: 0 } }) + const throughSeq = session.seq - 1 + await first.accept() + expect(session.snapshotEvents().at(-1)?.data).toEqual({ sessionId: id, sessionFormatVersion: SESSION_FORMAT_VERSION, throughSeq }) + + const second = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: id }) + expect(second.fields.dsh_session_log?.afterSeq).toBe(throughSeq) + expect(second.fields.dsh_session_log?.events.map(event => event.seq)).toEqual([throughSeq + 1]) + expect(session.eventAt(SessionSeq(1))?.data).toMatchObject({ sessionFormatVersion: 3, throughSeq: 0 }) + }) + it('takes the maximum watermark when concurrent acceptances settle out of order', async () => { const { ctx, session } = await harness('concurrent') session.append('turn/start', { turn: 1 }) diff --git a/packages/session/session-persistence-jsonl/README.i18n.yaml b/packages/session/session-persistence-jsonl/README.i18n.yaml index b0af7efebf..97101e98da 100644 --- a/packages/session/session-persistence-jsonl/README.i18n.yaml +++ b/packages/session/session-persistence-jsonl/README.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 packages/session/session-persistence-jsonl/README.md -README.md: fc431ff27bcd236c4d44b8d3e7b20d4291b936d4 -README.zh.md: 3b265bf43f058d4c0711568df156825febed4d24 +README.md: 9b2464e6330cfb5c256f18060814330c7637635e +README.zh.md: 22c0adb2d78efc3fee077ec68f8d43de422aa1a9 diff --git a/packages/session/session-persistence-jsonl/README.md b/packages/session/session-persistence-jsonl/README.md index fc431ff27b..9b2464e633 100644 --- a/packages/session/session-persistence-jsonl/README.md +++ b/packages/session/session-persistence-jsonl/README.md @@ -79,7 +79,11 @@ The current-generation scanner applies the current codec owner’s structural ad ### Reading the logs -`open(id, 'read'|'write')` selects the highest canonical generation. Current input follows the ordinary fast path. For historical input, a read open decodes and migrates the source once, validates the current logical result, and returns it without publishing a successor. A write open reuses that revision-keyed preparation when available, or performs the same preparation, then encodes a same-directory temporary file in bounded chunks, verifies it in a Worker Thread, rechecks the source revision, and publishes the current successor without overwrite before returning. The source remains byte-identical. Source drift after preparation rejects that write open without replacing the logical history already returned to readers; a later write open prepares the new revision. The backend marks decoded event graphs `shared-frozen` when it freezes them before memoization; handle reads and slices preserve that state, including empty slices. Only an unmaterialized pending log reports `detached`. `stat(id)` and `list()` select and translate only the highest generation header without reading event rows or starting migration; snapshots carry `sizeBytes` and a best-effort stat-derived revision for the selected file. With `compression: 'none'`, the log is newline-delimited text an external reader can consume directly; the compressed default must be read through the backend. +`open(id, 'read'|'write')` selects the highest canonical generation. Current input follows the ordinary fast path. For historical input, a read open decodes and migrates the source once, validates the current logical result, and returns it without publishing a successor. A write open reuses that revision-keyed preparation when available, or performs the same preparation, then encodes a same-directory temporary file in bounded chunks, verifies it in a Worker Thread, rechecks the source revision, and publishes the current successor without overwrite before returning. The source remains byte-identical. Source drift after preparation rejects that write open without replacing the logical history already returned to readers; a later write open prepares the new revision. The backend marks decoded event graphs `shared-frozen` when it freezes them before memoization; handle reads and slices preserve that state, including empty slices. Only an unmaterialized pending log reports `detached`. `stat(id)` and `list()` select and translate only the highest generation header without reading event rows or starting migration; snapshots carry the selected file’s `sizeBytes` and a best-effort revision. Current revisions identify that file; historical revisions also fingerprint the selected files across the persistence root, so child changes invalidate cached logical events. Fingerprinting reads filesystem metadata only; unrelated changes conservatively invalidate historical revisions. One `list()` call shares a corpus fingerprint across its historical entries. With `compression: 'none'`, the log is newline-delimited text an external reader can consume directly; the compressed default must be read through the backend. + +Historical body preparation completes the parent catalog through [V3→V4](../session-format-v3-to-v4/README.md). It scans headers, decodes only direct children one at a time, and retains compact descriptor evidence plus source revisions. It rechecks membership and revisions before returning preparation, reusing it, and publishing. Source drift invalidates preparation: read open retries preparation once automatically, while write open refuses publication. Diagnostics name the changed, added, removed, or unreadable child path. An unsupported selected generation or unreadable header anywhere else in the scan refuses migration because it cannot establish complete membership. Ordinary listing still skips those files. Unavailable migration facts report an unsupported format; malformed child events, JSON records, and compressed data report corruption at the child path. Filesystem errors and cancellation retain their original errors. Current V4 opens bypass this scan and validate catalog fields, uniqueness, and current delivery ownership before exposing events. + +Historical `stat` and `list` revisions require metadata work proportional to the root’s Session count. Fresh body preparation scans all selected headers and decodes direct-child bodies; memo reuse still scans membership and checks revisions. Read-only access never publishes an upgrade, so cold processes and evicted preparations repeat that work. Current V4 body reads and revisions avoid the historical corpus scan. See the [measured costs and diagnostic command](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md#catalog-scan-measurements). ----- @@ -93,7 +97,7 @@ This section explains the physical encoding and write path; the observable contr ### Design concept -The backend owns its complete storage runtime (`src/storage.ts`): `JsonlSessionHandle` carries the per-handle mutation chain, the routed live-event buffer with its fixed batching window and single-flight drain, monotonic reads, and idempotent close; a tracker holds the in-process single-writer claims, the open-handle set teardown sweeps, and the created-but-unmaterialized pending sessions the backend's own session listeners route into. Historical body reads share one per-session Decode/Migrate preparation, and a bounded revision-keyed memo lets an immediate observe-to-resume handoff reuse that parse; the backend deep-freezes each event graph once before memoization, so later handle reads reuse it without copying or freezing. Only a write open publishes the prepared successor. The package deliberately exposes only its default plugin export plus configuration types — the concrete class is not a named export, so consumers couple to `ctx.sessionPersistence`, and the shared seam suites (`runPersistenceContract`/`runLiveWritePathContract`) pin its observable behavior. Its change token is a best-effort file revision: device, inode, size, and nanosecond timestamps identify one log for `stat`/`list`, for the stable-read loop that retries a read torn by a concurrent append, and for the pre-publication source check. +The backend owns its complete storage runtime (`src/storage.ts`): `JsonlSessionHandle` carries the per-handle mutation chain, the routed live-event buffer with its fixed batching window and single-flight drain, monotonic reads, and idempotent close; a tracker holds the in-process single-writer claims, the open-handle set teardown sweeps, and the created-but-unmaterialized pending sessions the backend's own session listeners route into. Historical body reads share one per-session Decode/Migrate preparation, and a bounded revision-keyed memo lets an immediate observe-to-resume handoff reuse that parse; the backend deep-freezes each event graph once before memoization, so later handle reads reuse it without copying or freezing. Only a write open publishes the prepared successor. The package deliberately exposes only its default plugin export plus configuration types — the concrete class is not a named export, so consumers couple to `ctx.sessionPersistence`, and the shared seam suites (`runPersistenceContract`/`runLiveWritePathContract`) pin its observable behavior. Physical revisions combine device, inode, size, and nanosecond timestamps for the preparation memo, stable-read retries, and publication checks. Historical public revisions add a SHA-256 fingerprint of sorted selected paths and their physical revisions; lock files and retained unselected generations do not contribute. ### Physical encoding diff --git a/packages/session/session-persistence-jsonl/README.zh.md b/packages/session/session-persistence-jsonl/README.zh.md index 3b265bf43f..22c0adb2d7 100644 --- a/packages/session/session-persistence-jsonl/README.zh.md +++ b/packages/session/session-persistence-jsonl/README.zh.md @@ -79,7 +79,11 @@ kind: "package-reference" ### 读取日志 -`open(id, 'read'|'write')` 选择最高规范 generation。当前格式输入走普通快速路径。对于历史输入,只读 open 会单遍解码并迁移源、校验当前逻辑结果,然后在不发布后继的情况下返回。写 open 会在可用时复用按 revision 为键的 preparation,否则执行同一套 preparation,再按有界分片编码同目录临时文件、在 Worker Thread 中校验、复查源修订,并在返回前以不覆盖方式发布当前后继。源保持逐字节不变。如果源在 preparation 后发生变化,该次写 open 会失败,已经返回给读方的逻辑历史不会被替换;后续写 open 会针对新的 revision 重新执行 preparation。后端在 memo 化前冻结已解码的 event graph,并在此时将其标记为 `shared-frozen`;句柄读取和 slice 即使为空也保留该状态。只有尚未实体化的 pending 空日志报告 `detached`。`stat(id)` 与 `list()` 只选择并转换最高 generation 的 header,不读取事件行,也不启动迁移;快照携带所选文件的 `sizeBytes` 与尽力而为的 stat 派生修订号。选择 `compression: 'none'` 后,日志是外部读取方可直接消费的换行分隔文本;压缩默认值必须经后端读取。 +`open(id, 'read'|'write')` 选择最高规范 generation。当前格式输入走普通快速路径。对于历史输入,只读 open 会单遍解码并迁移源、校验当前逻辑结果,然后在不发布后继的情况下返回。写 open 会在可用时复用按 revision 为键的 preparation,否则执行同一套 preparation,再按有界分片编码同目录临时文件、在 Worker Thread 中校验、复查源修订,并在返回前以不覆盖方式发布当前后继。源保持逐字节不变。如果源在 preparation 后发生变化,该次写 open 会失败,已经返回给读方的逻辑历史不会被替换;后续写 open 会针对新的 revision 重新执行 preparation。后端在 memo 化前冻结已解码的 event graph,并在此时将其标记为 `shared-frozen`;句柄读取和 slice 即使为空也保留该状态。只有尚未实体化的 pending 空日志报告 `detached`。`stat(id)` 与 `list()` 只选择并转换最高 generation 的 header,不读取事件行,也不启动迁移;快照携带所选文件的 `sizeBytes` 与尽力而为的修订号。当前格式修订号标识该文件;历史格式修订号还包含持久化根目录中所选文件的指纹,因此子日志变化会使缓存的逻辑事件失效。指纹只读取文件系统元数据;无关变化也会保守地使历史修订号失效。一次 `list()` 为其历史条目共用一个全库指纹。选择 `compression: 'none'` 后,日志是外部读取方可直接消费的换行分隔文本;压缩默认值必须经后端读取。 + +历史正文准备通过 [V3→V4](../session-format-v3-to-v4/README.zh.md) 补齐父目录:扫描 header,仅逐个解码直属子 Session,保留紧凑的 descriptor 证据及来源修订。在准备返回、复用和发布前重新检查成员集合与修订。来源变化会使准备缓存失效:只读打开自动重新准备一次,写打开则拒绝发布。诊断指出发生变化、新增、删除或无法读取的子日志路径。扫描中其他任何被选中的不支持代际或不可读 header 都会拒绝迁移,因为无法确认成员集合完整。普通列举仍跳过这些文件。迁移事实不足会报告格式不支持;子事件、JSON 记录或压缩数据畸形会在子日志路径报告损坏。文件系统错误与取消保留原始错误。当前 V4 打开跳过此扫描,并在暴露事件之前检查目录字段、唯一性及当前投递归属。 + +历史格式的 `stat` 与 `list` 修订号需要与根目录 Session 数量成正比的元数据工作。首次正文准备扫描所有所选 header 并解码直属子正文;复用准备缓存仍扫描成员集合并检查修订。只读访问从不发布升级,因此冷进程与被淘汰的准备缓存会重复这些工作。当前 V4 正文读取和修订号避开历史全库扫描。见[实测成本与诊断命令](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md#catalog-scan-measurements)。 ----- @@ -93,7 +97,7 @@ kind: "package-reference" ### 设计理念 -该后端拥有自己完整的存储运行时(`src/storage.ts`):`JsonlSessionHandle` 承载逐句柄修改链、带固定批处理窗口与 single-flight 排空的已路由实时事件缓冲、单调读取与幂等 close;一个 tracker 持有进程内单写者认领、teardown 清扫所遍历的打开句柄集合,以及后端自己的会话监听器所路由进的已创建但未实体化待定会话。历史正文读取共享每个 Session 唯一的一次 Decode/Migrate preparation,按 revision 为键的有界 memo 让紧接的观察到恢复交接复用该解析;backend 在 memo 化前只对每个 event graph 深度冻结一次,因此后续 handle read 无需复制或再次冻结。只有写 open 才发布准备好的后继。本包有意只暴露默认插件导出与配置类型——具体类不是具名导出,因此消费方只耦合 `ctx.sessionPersistence`,其可观察行为由共享 seam 测试套件(`runPersistenceContract`/`runLiveWritePathContract`)钉住。其变更令牌是尽力而为的文件修订值:device、inode、size 与纳秒时间戳标识一份日志,供 `stat`/`list`、在并发 append 撕裂读取时重试的稳定读取循环,以及发布前源检查使用。 +该后端拥有自己完整的存储运行时(`src/storage.ts`):`JsonlSessionHandle` 承载逐句柄修改链、带固定批处理窗口与 single-flight 排空的已路由实时事件缓冲、单调读取与幂等 close;一个 tracker 持有进程内单写者认领、teardown 清扫所遍历的打开句柄集合,以及后端自己的会话监听器所路由进的已创建但未实体化待定会话。历史正文读取共享每个 Session 唯一的一次 Decode/Migrate preparation,按 revision 为键的有界 memo 让紧接的观察到恢复交接复用该解析;backend 在 memo 化前只对每个 event graph 深度冻结一次,因此后续 handle read 无需复制或再次冻结。只有写 open 才发布准备好的后继。本包有意只暴露默认插件导出与配置类型——具体类不是具名导出,因此消费方只耦合 `ctx.sessionPersistence`,其可观察行为由共享 seam 测试套件(`runPersistenceContract`/`runLiveWritePathContract`)钉住。物理修订号组合 device、inode、size 与纳秒时间戳,供准备缓存、稳定读取重试及发布检查使用。历史格式的公开修订号还加入所选路径排序后及其物理修订号的 SHA-256 指纹;锁文件与保留但未被选中的代际不参与计算。 ### 物理编码 diff --git a/packages/session/session-persistence-jsonl/src/catalog-migration.ts b/packages/session/session-persistence-jsonl/src/catalog-migration.ts new file mode 100644 index 0000000000..77e3d8b43e --- /dev/null +++ b/packages/session/session-persistence-jsonl/src/catalog-migration.ts @@ -0,0 +1,82 @@ +/** Collect historical discovery facts without recursively preparing related current generations. */ + +import { stat } from 'node:fs/promises' +import { basename } from 'node:path' +import { historicalSessionFormatCatalog, sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { historicalChildCatalogSource } from '@deepseek-ai/dsh-session-format-v3-to-v4' +import { SessionFormatUnsupportedError, SessionPersistenceCorruptionError } from '@deepseek-ai/dsh-session-persistence' +import { SessionFormatError, SessionFormatUnsupportedMigrationError } from '@deepseek-ai/dsh-session-format' +import type { SessionFormatJsonObject } from '@deepseek-ai/dsh-session-format' +import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session' +import { parseGenerationLogFilename } from './format.ts' +import type { JsonlCompression } from './format.ts' +import { JsonlGenerationSourceChangedError, readDecodedJsonlSource } from './generation.ts' +import type { JsonlPhysicalIdentity } from './generation.ts' + +/** Per-parent supplemental facts and the source checks required before serving or publishing them. */ +interface PreparedCatalogFacts { + readonly facts: readonly SessionFormatJsonObject[] + /** @returns resolves while every decoded child still has the captured physical revision. */ + validate(): Promise +} + +/** + * Collect each related child's own descriptor through existing historical codecs. + * @param parentId - parent whose incoming migration consumes these facts. + * @param sources - header-indexed direct children in the selected source corpus. + * @param compression - configured source encoding. + * @param signal - cancellation forwarded through each source read. + * @returns compact facts; complete child event arrays are released after extraction. + */ +export async function prepareCatalogFacts( + parentId: SessionId, + sources: readonly { readonly header: SessionHeader; readonly path: string }[], + compression: JsonlCompression, + signal: AbortSignal, +): Promise { + const facts: SessionFormatJsonObject[] = [] + const witnesses: { path: string; identity: JsonlPhysicalIdentity }[] = [] + for (const source of sources) { + signal.throwIfAborted() + const version = parseGenerationLogFilename(basename(source.path), compression) + if (version === undefined) throw new SessionFormatUnsupportedMigrationError(`unrecognized historical child generation ${source.path}`) + let restored: Awaited> + try { + restored = await readDecodedJsonlSource(source.path, version, compression, { + createRestore: header => (version <= 3 ? historicalSessionFormatCatalog : sessionFormatCatalog).createRestore(header, { + recovery: 'recoverable', validation: 'current', + }), + }, signal) + } catch (error: unknown) { + if (error instanceof SessionFormatUnsupportedMigrationError) { + throw new SessionFormatUnsupportedError( + `child Session ${source.header.id}: ${error.message} (raw log: ${source.path})`, + { kind: 'jsonl', path: source.path }, + ) + } + if (error instanceof SessionFormatError) { + throw new SessionPersistenceCorruptionError(`child Session ${source.header.id}: ${error.message} (raw log: ${source.path})`, { cause: error }) + } + throw error + } + const header = restored.artifact.header + if (header.id !== source.header.id || header.createdAt !== source.header.createdAt + || header.parentSession !== parentId || header.origin !== 'subagent' + || ['cwd', 'isSeeded', 'delegationDepth', 'agentPreset'].some(key => header[key] !== source.header[key as keyof SessionHeader])) { + throw new JsonlGenerationSourceChangedError(source.path) + } + facts.push({ ...historicalChildCatalogSource(restored.artifact), sourcePath: source.path }) + witnesses.push({ path: source.path, identity: restored.identity }) + } + return { + facts, + async validate() { + for (const witness of witnesses) { + const current = await stat(witness.path, { bigint: true }) + if (current.dev !== witness.identity.dev || current.ino !== witness.identity.ino + || current.size !== witness.identity.size || current.mtimeNs !== witness.identity.mtimeNs + || current.ctimeNs !== witness.identity.ctimeNs) throw new JsonlGenerationSourceChangedError(witness.path) + } + }, + } +} diff --git a/packages/session/session-persistence-jsonl/src/format.ts b/packages/session/session-persistence-jsonl/src/format.ts index 71177b9727..0c9df5b05e 100644 --- a/packages/session/session-persistence-jsonl/src/format.ts +++ b/packages/session/session-persistence-jsonl/src/format.ts @@ -23,7 +23,7 @@ import { parseSessionFormatLogFilename, sessionFormatLogFilename, SessionFormatU import type { SessionFormatEvent } from '@deepseek-ai/dsh-session-format' import type { SessionFormatRecovery, SessionFormatRestore } from '@deepseek-ai/dsh-session-format' import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' -import { assertV4RowAdmission } from '@deepseek-ai/dsh-session-format-v3-to-v4' +import { assertV4RowAdmission, assertReleasedV4Relationships } from '@deepseek-ai/dsh-session-format-v3-to-v4' import { SessionFormatUnsupportedError, sessionFormatVersionRefusal, @@ -464,6 +464,7 @@ export class SessionLogScanner { finish(): SessionLogScan { this.finished = true const artifact = this.restore.finish() + assertReleasedV4Relationships(artifact) return { meta: this.meta, inheritedEventCount: SessionLogOffset(artifact.inheritedEventCount), diff --git a/packages/session/session-persistence-jsonl/src/generation.ts b/packages/session/session-persistence-jsonl/src/generation.ts index 1e5ded6771..ff01e9a038 100644 --- a/packages/session/session-persistence-jsonl/src/generation.ts +++ b/packages/session/session-persistence-jsonl/src/generation.ts @@ -28,6 +28,7 @@ import { constants, createZstdCompress } from 'node:zlib' import { Session } from '@deepseek-ai/dsh-session' import type { SessionEvent } from '@deepseek-ai/dsh-session' import { BlockAssembler, expandAssistantStream } from '@deepseek-ai/dsh-llm' +import { SessionFormatError } from '@deepseek-ai/dsh-session-format' import type { SessionFormatArtifact, SessionFormatJsonValue, @@ -68,6 +69,8 @@ export interface JsonlGenerationFormatAdapter { /** Inputs for preparing one historical generation and publishing its current successor later. */ export interface PrepareJsonlMigrationOptions { + /** Revalidate related source facts before preparation returns and immediately before publication. */ + readonly validateRelatedSources?: () => Promise /** Immutable generation selected by the backend resolver. */ readonly sourcePath: string /** Version selected from the source filename and independently checked against its header. */ @@ -372,7 +375,7 @@ interface StartedMigrationStream { async function startMigrationStream( headerRecord: Buffer, sourceVersion: number, - format: JsonlGenerationFormatAdapter, + format: Pick, validateHistoricalHeader?: PrepareJsonlMigrationOptions['validateHistoricalHeader'], ): Promise { const value = parseJson(headerRecord.subarray(0, -1).toString('utf8'), 'header line') @@ -409,7 +412,7 @@ async function decodeStreamingMigration( bytes: Buffer, compression: JsonlCompression, sourceVersion: number, - format: JsonlGenerationFormatAdapter, + format: Pick, validateHistoricalHeader: PrepareJsonlMigrationOptions['validateHistoricalHeader'], signal?: AbortSignal, ): Promise { @@ -900,6 +903,7 @@ async function publishPreparedMigration( throw new Error('staged session generation changed during verification') } await internals.barrier('before-source-check', 1) + await options.validateRelatedSources?.() const beforePublish = await internals.fs.stat(sourcePath) if (identity(beforePublish) !== identity(sourceIdentity)) { throw new JsonlGenerationSourceChangedError(sourcePath) @@ -974,6 +978,7 @@ async function prepareMigration( if (artifact.header.version !== format.currentVersion) { throw new Error(`format migration returned v${artifact.header.version}, expected v${format.currentVersion}`) } + await options.validateRelatedSources?.() const sourceIdentity = source.identity let publication: Promise | undefined return { @@ -1024,3 +1029,31 @@ export function createJsonlGenerationRuntime( } const defaultGenerationRuntime = createJsonlGenerationRuntime() + +/** + * Read one stable source through the shared streaming parser without publishing a generation. + * @param path - selected source generation path. + * @param version - physical source version identified by its filename. + * @param compression - source encoding. + * @param format - codec/restore factory, independent of current-generation publication. + * @param signal - cancellation observed during source reads and decode yields. + * @returns decoded artifact and physical source identity for later revalidation. + * @throws SessionFormatError for physical decoding failures; storage, cancellation, and unsupported migration errors retain their category. + */ +export async function readDecodedJsonlSource( + path: string, + version: number, + compression: JsonlCompression, + format: Pick, + signal?: AbortSignal, +): Promise<{ artifact: SessionFormatArtifact; identity: JsonlPhysicalIdentity }> { + const source = await readStableJsonlFile(path, signal) + let artifact: SessionFormatArtifact + try { + artifact = await decodeStreamingMigration(source.bytes, compression, version, format, undefined, signal) + } catch (error: unknown) { + if (signal?.aborted || error instanceof SessionFormatError) throw error + throw new SessionFormatError(String(error), { cause: error }) + } + return { artifact, identity: source.identity } +} diff --git a/packages/session/session-persistence-jsonl/src/index.ts b/packages/session/session-persistence-jsonl/src/index.ts index ba4f8996f0..771393b73c 100644 --- a/packages/session/session-persistence-jsonl/src/index.ts +++ b/packages/session/session-persistence-jsonl/src/index.ts @@ -9,6 +9,7 @@ import { Context } from '@deepseek-ai/cordis' import z from '@deepseek-ai/schemastery' import { + createSessionFormatCatalogWithChildren, SessionFormatUnsupportedMigrationError, sessionFormatCatalog, } from '@deepseek-ai/dsh-session-format-catalog' @@ -17,7 +18,7 @@ import { open, mkdir, readdir, realpath, link, rm, stat, truncate } from 'node:f import { dirname, join, resolve } from 'node:path' import { performance } from 'node:perf_hooks' import { scheduler } from 'node:timers/promises' -import { randomBytes } from 'node:crypto' +import { createHash, randomBytes } from 'node:crypto' import { SessionPersistence, SessionPersistenceRevision, SessionFormatUnsupportedError, SessionPersistenceCorruptionError, @@ -44,6 +45,7 @@ import { } from './zstd.ts' import { ensureDurableDirectoryWin32, publishNewFileWin32 } from './win32.ts' import { verifyCurrentGenerationInWorker } from './migration-verifier.ts' +import { prepareCatalogFacts } from './catalog-migration.ts' import { JsonlGenerationSourceChangedError, JsonlGenerationUnsupportedMigrationError, @@ -122,6 +124,7 @@ interface CurrentStoredLog extends StoredLogBase { /** A migrated historical generation retained until an explicit write open publishes it. */ interface PreparedStoredLog extends StoredLogBase { readonly status: 'prepared' + readonly validateRelatedSources: () => Promise readonly publication: { readonly source: ResolvedJsonlGeneration readonly value: PreparedJsonlMigration @@ -245,7 +248,7 @@ class JsonlSessionPersistence extends SessionPersistence { private compression: JsonlCompression private rootEncodingCheck: Promise | undefined private readonly tracker = new JsonlBackendTracker(this.name) - private readonly generationFormat: JsonlGenerationFormatAdapter + private readonly generationFormat: Omit /** * Bounded LRU of parsed, validated stored logs keyed by session id and * guarded by the stat-derived revision, so an immediate cold-read handoff @@ -271,10 +274,6 @@ class JsonlSessionPersistence extends SessionPersistence { this.compression = config.compression ?? DEFAULT_COMPRESSION this.generationFormat = { currentVersion: sessionFormatCatalog.currentVersion, - createRestore: header => sessionFormatCatalog.createRestore(header, { - recovery: 'recoverable', - validation: 'transformed', - }), encodeHeader: (header, inheritedEventCount) => sessionFormatCatalog.encodeCurrentHeader(header, inheritedEventCount), encodeEvent: event => sessionFormatCatalog.encodeCurrentEvent(event), @@ -342,7 +341,13 @@ class JsonlSessionPersistence extends SessionPersistence { if (pending !== undefined) { return this.tracker.adopt(new JsonlSessionHandle(this, id, pending.header, 'read', { cursor: 0, materialized: false, inheritedEventCount: pending.inheritedEventCount })) } - const stored = await this.requireStoredLog(id, options?.signal) + let stored: StoredLog + try { + stored = await this.requireStoredLog(id, options?.signal) + } catch (error: unknown) { + if (!(error instanceof JsonlGenerationSourceChangedError)) throw error + stored = await this.requireStoredLog(id, options?.signal) + } let state: StorageHandleState if (stored.status === 'prepared') { state = { @@ -442,7 +447,9 @@ class JsonlSessionPersistence extends SessionPersistence { options?.signal?.throwIfAborted() return { header, - revision: fileRevision(identity), + revision: selected.sourceVersion < SESSION_FORMAT_VERSION + ? SessionPersistenceRevision(`${fileRevision(identity)}:${await this.historicalCorpusRevision(options?.signal)}`) + : fileRevision(identity), sizeBytes: Number(identity.size), } } catch (error: unknown) { @@ -466,7 +473,10 @@ class JsonlSessionPersistence extends SessionPersistence { // append lands mid-scan is then still in this snapshot (its artifact may // predate the scan), so create-to-list visibility never has a hole. const pending = [...this.tracker.pendingEntries()] - for (const artifact of await this.listArtifacts(signal)) { + const artifacts = await this.listArtifacts(signal) + const corpusRevision = artifacts.some(artifact => artifact.sourceVersion < SESSION_FORMAT_VERSION) + ? await this.historicalCorpusRevision(signal) : undefined + for (const artifact of artifacts) { signal?.throwIfAborted() try { const identity = await stat(artifact.path, { bigint: true }) @@ -474,7 +484,9 @@ class JsonlSessionPersistence extends SessionPersistence { listed.add(artifact.header.id) snapshots.push({ header: artifact.header, - revision: fileRevision(identity), + revision: artifact.sourceVersion < SESSION_FORMAT_VERSION + ? SessionPersistenceRevision(`${fileRevision(identity)}:${corpusRevision}`) + : fileRevision(identity), sizeBytes: Number(identity.size), }) } catch (error: unknown) { @@ -567,6 +579,12 @@ class JsonlSessionPersistence extends SessionPersistence { signal.throwIfAborted() const memoized = this.coldLogMemo.get(id) if (memoized?.status === 'prepared' && memoized.revision === sourceRevision) { + try { + await memoized.validateRelatedSources() + } catch (error: unknown) { + this.coldLogMemo.delete(id) + throw this.generationFailure(id, selected, error) + } this.coldLogMemo.delete(id) this.coldLogMemo.set(id, memoized) return memoized @@ -602,13 +620,33 @@ class JsonlSessionPersistence extends SessionPersistence { signal: AbortSignal, ): Promise { let prepared: Awaited> + let validateRelatedSources: () => Promise try { + const children = async () => (await this.listArtifacts(signal, selected.sourcePath)) + .filter(source => source.header.origin === 'subagent' && source.header.parentSession === id) + const sources = await children() + const related = await prepareCatalogFacts(id, sources, this.compression, signal) + const membership = sources.map(source => source.path).sort() + validateRelatedSources = async () => { + const current = (await children()).map(source => source.path).sort() + const before = new Set(membership) + const after = new Set(current) + const changed = current.find(path => !before.has(path)) ?? membership.find(path => !after.has(path)) + if (changed !== undefined) throw new JsonlGenerationSourceChangedError(changed) + await related.validate() + } prepared = await prepareJsonlMigration({ sourcePath: selected.sourcePath, sourceVersion: selected.sourceVersion, currentPath: selected.currentPath, compression: this.compression, - format: this.generationFormat, + format: { + ...this.generationFormat, + createRestore: header => createSessionFormatCatalogWithChildren(related.facts).createRestore(header, { + recovery: 'recoverable', validation: 'transformed', + }), + }, + validateRelatedSources, verifyCurrentFile: verifyCurrentGenerationInWorker, validateHistoricalHeader: headerValue => this.validateSourceIdentity( selected, @@ -627,6 +665,7 @@ class JsonlSessionPersistence extends SessionPersistence { validateStoredEvents(meta, events, { kind: 'jsonl', path: selected.sourcePath }) const stored: PreparedStoredLog = { status: 'prepared', + validateRelatedSources, meta, ...freezeStoredEvents(events), tornTruncateTo: undefined, @@ -972,35 +1011,77 @@ class JsonlSessionPersistence extends SessionPersistence { } } - private async listArtifacts(signal?: AbortSignal): Promise> { - signal?.throwIfAborted() - await this.ensureRootEncoding() - signal?.throwIfAborted() - const artifacts: Array<{ header: SessionHeader; path: string }> = [] - const ids = new Set() + /** Enumerate selected physical generations without interpreting their headers or bodies. */ + private async listGenerations(signal?: AbortSignal): Promise { + const sources: ResolvedJsonlGeneration[] = [] for (const project of await this.listProjectDirs(signal)) { - signal?.throwIfAborted() for (const dir of await this.listSessionDirs(project, signal)) { signal?.throwIfAborted() const selected = await this.resolveGenerationInDirectory(dir, signal) - if (selected === undefined) continue - let header: SessionHeader | undefined - try { - header = await this.readGenerationHeader(selected, undefined, signal) - } catch (error: unknown) { - // Listing skips a foreign format while opening its id still refuses - // with the selected physical location. - if (error instanceof SessionFormatUnsupportedError) continue - throw error - } - if (header === undefined) continue - if (ids.has(header.id)) { - throw new Error(`duplicate JSONL session id "${header.id}" appears in multiple project directories`) - } - ids.add(header.id) - artifacts.push({ header, path: selected.sourcePath }) + if (selected !== undefined) sources.push(selected) } } + return sources + } + + /** Historical logical events depend on the corpus, including members with unreadable headers. */ + private async historicalCorpusRevision(signal?: AbortSignal): Promise { + const paths = (await this.listGenerations(signal)).map(source => source.sourcePath).sort() + const hash = createHash('sha256') + for (const path of paths) { + signal?.throwIfAborted() + let revision: string + try { + revision = fileRevision(await stat(path, { bigint: true })) + } catch (error: unknown) { + if (!isENOENT(error)) throw error + revision = 'missing' + } + hash.update(JSON.stringify([path, revision])) + } + signal?.throwIfAborted() + return hash.digest('hex') + } + + private async listArtifacts( + signal?: AbortSignal, + migrationSource?: string, + ): Promise> { + signal?.throwIfAborted() + await this.ensureRootEncoding() + signal?.throwIfAborted() + const artifacts: Array<{ header: SessionHeader; path: string; sourceVersion: number }> = [] + const ids = new Set() + for (const selected of await this.listGenerations(signal)) { + signal?.throwIfAborted() + if (migrationSource !== undefined && selected.sourceVersion > SESSION_FORMAT_VERSION) { + throw new SessionFormatUnsupportedError( + `catalog migration cannot inspect Session format v${selected.sourceVersion}; upgrade the harness (raw log: ${selected.sourcePath})`, + { kind: 'jsonl', path: selected.sourcePath }, + ) + } + let header: SessionHeader | undefined + try { + header = await this.readGenerationHeader(selected, undefined, signal) + } catch (error: unknown) { + if (error instanceof SessionFormatUnsupportedError && migrationSource === undefined) continue + throw error + } + if (header === undefined) { + if (migrationSource !== undefined && selected.sourcePath !== migrationSource) { + throw new SessionFormatUnsupportedError( + `cannot establish complete catalog membership from an unreadable Session header (raw log: ${selected.sourcePath})`, + { kind: 'jsonl', path: selected.sourcePath }, + ) + } + continue + } + if (ids.has(header.id)) { + throw new Error(`duplicate JSONL session id "${header.id}" appears in multiple project directories`) + } + ids.add(header.id) + artifacts.push({ header, path: selected.sourcePath, sourceVersion: selected.sourceVersion }) + } signal?.throwIfAborted() return artifacts } diff --git a/packages/session/session-persistence-jsonl/tests/catalog-migration.perf.ts b/packages/session/session-persistence-jsonl/tests/catalog-migration.perf.ts new file mode 100644 index 0000000000..a866354449 --- /dev/null +++ b/packages/session/session-persistence-jsonl/tests/catalog-migration.perf.ts @@ -0,0 +1,77 @@ +/** Threshold-free, built-runtime measurements of historical catalog reads as the corpus grows. */ + +import { Context } from '@deepseek-ai/cordis' +import { SessionId } from '@deepseek-ai/dsh-session' +import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' +import { spawnSync } from 'node:child_process' +import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { performance } from 'node:perf_hooks' +import { fileURLToPath } from 'node:url' + +const CHILDREN = 4 +const CHILD_EVENTS = 1_000 +const SAMPLES = 3 + +async function measure(unrelated: number) { + const root = await mkdtemp(join(tmpdir(), 'dsh-catalog-perf-')) + const ctx = new Context() + try { + for (let i = 0; i < unrelated + CHILDREN + 1; i++) { + const id = i === 0 ? 'parent' : `session-${i}` + const child = i > 0 && i <= CHILDREN + const directory = join(root, '_no-cwd', id) + await mkdir(directory, { recursive: true }) + const header = { type: 'session', version: 3, id, createdAt: i + 1, isSeeded: false, delegationDepth: child ? 1 : 0, + ...(child ? { origin: 'subagent', parentSession: 'parent' } : {}) } + const events = child ? [ + { type: 'subagent/descriptor', seq: 0, time: 1, data: { version: 3, mode: 'one-shot', provider: 'spawn' } }, + ...Array.from({ length: CHILD_EVENTS - 1 }, (_, seq) => ({ + type: 'feedback/record', seq: seq + 1, time: 2, data: { text: 'Synthetic migration observation. '.repeat(4) }, + })), + ] : [] + await writeFile(join(directory, 'session.v3.jsonl'), [header, ...events].map(row => JSON.stringify(row) + '\n').join('')) + } + await ctx.plugin(JsonlSessionPersistence, { root, compression: 'none' }) + const parent = SessionId('parent') + const timed = async (operation: () => Promise): Promise => { + const start = performance.now() + await operation() + return performance.now() - start + } + const read = async (): Promise => { + const handle = await ctx.sessionPersistence.open(parent, 'read') + try { await handle.read() } finally { await handle.close() } + } + const statMs = await timed(() => ctx.sessionPersistence.stat(parent)) + const coldReadMs = await timed(read) + const memoReadMs = await timed(read) + const publishMs = await timed(async () => { + const handle = await ctx.sessionPersistence.open(parent, 'write') + await handle.close() + }) + const currentReadMs = await timed(read) + return { unrelated, children: CHILDREN, childEvents: CHILD_EVENTS, statMs, coldReadMs, memoReadMs, publishMs, currentReadMs } + } finally { + await ctx.fiber.dispose() + await rm(root, { recursive: true, force: true }) + } +} + +if (process.argv[2] === '--sample') { + process.stdout.write(JSON.stringify(await measure(Number(process.argv[3]))) + '\n') +} else { + const samples = [] + for (const size of [0, 100, 1_000]) { + for (let sample = 0; sample < SAMPLES; sample++) { + const result = spawnSync(process.execPath, [fileURLToPath(import.meta.url), '--sample', String(size)], { + encoding: 'utf8', timeout: 60_000, + }) + if (result.error !== undefined) throw result.error + if (result.signal !== null || result.status !== 0) throw new Error(`measurement failed: ${result.signal ?? result.status}: ${result.stderr}`) + samples.push(JSON.parse(result.stdout) as Record) + } + } + process.stdout.write(JSON.stringify({ node: process.version, platform: process.platform, arch: process.arch, samples }, null, 2) + '\n') +} diff --git a/packages/session/session-persistence-jsonl/tests/catalog-migration.spec.ts b/packages/session/session-persistence-jsonl/tests/catalog-migration.spec.ts new file mode 100644 index 0000000000..96cf6cae50 --- /dev/null +++ b/packages/session/session-persistence-jsonl/tests/catalog-migration.spec.ts @@ -0,0 +1,364 @@ +import { Context } from '@deepseek-ai/cordis' +import { SessionId, type SessionHeader } from '@deepseek-ai/dsh-session' +import { SessionFormatUnsupportedError, SessionPersistenceCorruptionError } from '@deepseek-ai/dsh-session-persistence' +import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' +import { afterEach, describe, expect, it } from 'vitest' +import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { dirname, join } from 'node:path' +import { generationLogPath } from '../src/format.ts' +import { prepareCatalogFacts } from '../src/catalog-migration.ts' +import { compressZstdFrame } from '../src/zstd.ts' + +const roots: string[] = [] +const contexts: Context[] = [] + +afterEach(async () => { + await Promise.all(contexts.splice(0).map(ctx => ctx.fiber.dispose())) + await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true }))) +}) + +describe.each(['none', 'zstd'] as const)('historical catalog publication (%s)', (compression) => { + async function fixture() { + const root = await mkdtemp(join(tmpdir(), 'dsh-catalog-migration-')) + roots.push(root) + const ctx = new Context() + contexts.push(ctx) + await ctx.plugin(JsonlSessionPersistence, { root, compression }) + const parent = SessionId('parent') + const header = { type: 'session', version: 3, id: parent, createdAt: 1, isSeeded: false, delegationDepth: 0 } + async function write(id: string, events: unknown[], child = false, version = 3) { + const path = generationLogPath(root, undefined, SessionId(id), version, compression) + await mkdir(dirname(path), { recursive: true }) + const meta: Record = { ...header, id, version, ...(child ? { origin: 'subagent', parentSession: parent, createdAt: 2, delegationDepth: 1 } : {}) } + if (version < 2) delete meta['isSeeded'] + const first = JSON.stringify(meta) + '\n' + const body = events.map(row => JSON.stringify(row) + '\n').join('') + await writeFile(path, compression === 'none' ? first + body + : Buffer.concat([await compressZstdFrame(first), ...(body.length === 0 ? [] : [await compressZstdFrame(body)])])) + return path + } + await write(parent, []) + const descriptor = { type: 'subagent/descriptor', seq: 0, time: 2, data: { version: 3, mode: 'continuable', provider: 'spawn', label: 'old child' } } + async function read() { + const handle = await ctx.sessionPersistence.open(parent, 'read') + try { return (await handle.read()).events } finally { await handle.close() } + } + return { root, ctx, parent, header, descriptor, write, read } + } + + it.each(['read', 'write'] as const)('refuses foreign native V4 delivery through %s access', async (access) => { + const f = await fixture() + await f.write(f.parent, [ + { type: 'feedback/record', seq: 0, time: 1, data: {} }, + { type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 2, + data: { sessionId: 'other', sessionFormatVersion: 4, throughSeq: 0 } }, + ], false, 4) + await expect(f.ctx.sessionPersistence.open(f.parent, access)).rejects.toThrow('wrong Session') + }) + + it('does not publish incomplete membership after a child header becomes unreadable', async () => { + const f = await fixture() + const path = await f.write('child', [], true) + const broken = '{broken header\n' + await writeFile(path, compression === 'none' ? broken : await compressZstdFrame(broken)) + await expect(f.read()).rejects.toThrow(path) + await expect(f.ctx.sessionPersistence.open(f.parent, 'write')).rejects.toThrow(path) + expect((await readdir(dirname(generationLogPath(f.root, undefined, f.parent, 3, compression)))).filter(name => name !== 'session.lock')) + .toEqual([compression === 'none' ? 'session.v3.jsonl' : 'session.v3.jsonl.zstd']) + }) + + it('invalidates lightweight revisions on child membership and contents while retaining stable tokens', async () => { + const f = await fixture() + const revision = async () => (await f.ctx.sessionPersistence.stat(f.parent))!.revision + const first = await revision() + expect(await revision()).toBe(first) + await f.write('child', [f.descriptor], true) + const added = await revision() + expect(added).not.toBe(first) + expect((await f.ctx.sessionPersistence.list()).find(row => row.header.id === f.parent)?.revision).toBe(added) + await f.write('child', [f.descriptor, { type: 'feedback/record', seq: 1, time: 3, data: {} }], true) + expect(await revision()).not.toBe(added) + }) + + it('reports malformed native catalog data without migration terminology', async () => { + const f = await fixture() + await f.write(f.parent, [{ type: 'subagent/catalog', seq: 0, time: 1, + data: { version: 0, childId: 'child', childCreatedAt: 2, mode: 'invalid' } }], false, 4) + const error = await f.read().catch((error: unknown) => error) + expect(error).toBeInstanceOf(SessionPersistenceCorruptionError) + expect((error as Error).message).not.toContain('migration requires') + }) + + it('keeps current revisions independent of unrelated historical logs and write ownership', async () => { + const f = await fixture() + await f.write(f.parent, [], false, 4) + const first = (await f.ctx.sessionPersistence.stat(f.parent))!.revision + await f.write('child', [f.descriptor], true) + expect((await f.ctx.sessionPersistence.stat(f.parent))!.revision).toBe(first) + expect((await f.ctx.sessionPersistence.list()).find(row => row.header.id === f.parent)?.revision).toBe(first) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + await writer.close() + expect((await f.ctx.sessionPersistence.stat(f.parent))!.revision).toBe(first) + }) + + it('invalidates historical revisions when selected children disappear or gain an opaque successor', async () => { + const f = await fixture() + const path = await f.write('child', [f.descriptor], true) + const first = (await f.ctx.sessionPersistence.stat(f.parent))!.revision + await rm(path) + const removed = (await f.ctx.sessionPersistence.stat(f.parent))!.revision + expect(removed).not.toBe(first) + await f.write('child', [], true, 5) + expect((await f.ctx.sessionPersistence.stat(f.parent))!.revision).not.toBe(removed) + expect((await f.ctx.sessionPersistence.list()).find(row => row.header.id === f.parent)?.revision).not.toBe(removed) + }) + + it('reports a corrupt child body at the child location', async () => { + const f = await fixture() + const catalog = { type: 'subagent/catalog', seq: 0, time: 1, + data: { version: 0, childId: 'grandchild', childCreatedAt: 3, mode: 'one-shot' } } + const path = await f.write('child', [catalog, { ...catalog, seq: 1 }], true, 4) + await expect(f.read()).rejects.toBeInstanceOf(SessionPersistenceCorruptionError) + await expect(f.read()).rejects.toThrow(path) + }) + + it.each(['read', 'write'] as const)('locates physical child JSON corruption during %s access', async (access) => { + const f = await fixture() + const childPath = await f.write('child', [], true) + const first = JSON.stringify({ ...f.header, id: 'child', origin: 'subagent', parentSession: f.parent, delegationDepth: 1 }) + '\n' + // A sealed turn makes the malformed row corruption rather than a recoverable tail. + const body = '{broken\n' + JSON.stringify({ type: 'turn/end', seq: 1, time: 2, + data: { turn: 1, reason: { kind: 'completed' } } }) + '\n' + await writeFile(childPath, compression === 'none' ? first + body + : Buffer.concat([await compressZstdFrame(first), await compressZstdFrame(body)])) + const parentPath = generationLogPath(f.root, undefined, f.parent, 3, compression) + const original = await Promise.all([readFile(parentPath), readFile(childPath)]) + const error: unknown = await f.ctx.sessionPersistence.open(f.parent, access).catch((error: unknown) => error) + expect(error).toBeInstanceOf(SessionPersistenceCorruptionError) + expect((error as Error).message).toContain(childPath) + expect((error as Error).message).not.toContain(parentPath) + expect((error as Error).message).toContain('row 1 is not valid JSON') + expect(await Promise.all([readFile(parentPath), readFile(childPath)])).toEqual(original) + expect((await readdir(dirname(parentPath))).filter(name => name !== 'session.lock')) + .toEqual([compression === 'none' ? 'session.v3.jsonl' : 'session.v3.jsonl.zstd']) + }) + + it('preserves opaque inherited catalogs through read preparation and write publication', async () => { + const f = await fixture() + const parentPath = generationLogPath(f.root, undefined, f.parent, 3, compression) + const first = JSON.stringify({ ...f.header, isSeeded: true, parentSession: 'ancestor' }) + '\n' + const events = [ + { type: 'subagent/catalog', seq: 0, time: 1, data: { version: 99 } }, + { type: 'session/end-seed', seq: 1, time: 2, data: { inherited: true } }, + { type: 'subagent/catalog', seq: 2, time: 3, data: null }, + { type: 'session/end-seed', seq: 3, time: 4, data: { inherited: true } }, + ] + const body = events.map(event => JSON.stringify(event) + '\n').join('') + await writeFile(parentPath, compression === 'none' ? first + body + : Buffer.concat([await compressZstdFrame(first), await compressZstdFrame(body)])) + const original = await readFile(parentPath) + expect(await f.read()).toEqual(events) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + try { expect((await writer.read()).events).toEqual(events) } finally { await writer.close() } + expect(await f.read()).toEqual(events) + expect(await readFile(parentPath)).toEqual(original) + }) + + it.skipIf(compression !== 'zstd')('locates invalid compressed child frames at the child path', async () => { + const f = await fixture() + const childPath = await f.write('child', [], true) + await writeFile(childPath, Buffer.concat([await readFile(childPath), Buffer.alloc(8)])) + const error: unknown = await f.read().catch((error: unknown) => error) + expect(error).toBeInstanceOf(SessionPersistenceCorruptionError) + expect((error as Error).message).toContain(childPath) + }) + + it('keeps a complete parent catalog when a published child never writes a descriptor', async () => { + const f = await fixture() + const catalog = { type: 'subagent/catalog', seq: 0, time: 2, + data: { version: 0, childId: 'child', childCreatedAt: 2, mode: 'one-shot', label: 'failed startup' } } + const parentPath = await f.write(f.parent, [catalog]) + const childPath = await f.write('child', [], true) + const original = await Promise.all([readFile(parentPath), readFile(childPath)]) + expect(await f.read()).toEqual([catalog]) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + await writer.close() + expect(await f.read()).toEqual([catalog]) + expect(await Promise.all([readFile(parentPath), readFile(childPath)])).toEqual(original) + }) + + it.each([1, 2, 3])('backfills a missing catalog from descriptor v%i', async (version) => { + const f = await fixture() + const data = version === 1 ? { version, provider: 'spawn', label: 'old child' } + : { ...f.descriptor.data, version } + await f.write('child', [{ ...f.descriptor, data }], true) + expect(await f.read()).toMatchObject([{ type: 'subagent/catalog', data: { + childId: 'child', childCreatedAt: 2, mode: 'continuable', label: 'old child', + } }]) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + await writer.close() + }) + + it('classifies missing discovery information as unsupported migration', async () => { + const f = await fixture() + await f.write('child', [], true) + await expect(f.read()).rejects.toBeInstanceOf(SessionFormatUnsupportedError) + await expect(f.ctx.sessionPersistence.open(f.parent, 'write')).rejects.toBeInstanceOf(SessionFormatUnsupportedError) + expect((await readdir(dirname(generationLogPath(f.root, undefined, f.parent, 3, compression)))).filter(name => name !== 'session.lock')) + .toEqual([compression === 'none' ? 'session.v3.jsonl' : 'session.v3.jsonl.zstd']) + }) + + it.each([false, true])('refuses an opaque future generation before publishing membership (prepared=%s)', async (prepared) => { + const f = await fixture() + await f.write('child', [f.descriptor], true) + if (prepared) expect(await f.read()).toHaveLength(1) + await f.write('child', [], true, 5) + await expect(f.ctx.sessionPersistence.open(f.parent, 'write')).rejects.toBeInstanceOf(SessionFormatUnsupportedError) + expect((await readdir(dirname(generationLogPath(f.root, undefined, f.parent, 3, compression)))).filter(name => name !== 'session.lock')) + .toEqual([compression === 'none' ? 'session.v3.jsonl' : 'session.v3.jsonl.zstd']) + }) + + it('requires a readable corpus even when an unknown header cannot identify its parent', async () => { + const f = await fixture() + await f.write('future-root', [], false, 5) + expect((await f.ctx.sessionPersistence.list()).map(row => row.header.id)).toEqual([f.parent]) + await expect(f.read()).rejects.toBeInstanceOf(SessionFormatUnsupportedError) + }) + + it('preserves unsupported child decoding errors instead of reporting parent corruption', async () => { + const f = await fixture() + const path = await f.write('child', [{ type: 'future/required', seq: 0, time: 2, data: {} }], true) + await expect(f.read()).rejects.toBeInstanceOf(SessionFormatUnsupportedError) + await expect(f.read()).rejects.toThrow(path) + }) + + it('locates incomplete historical descriptor fields at their child source', async () => { + const f = await fixture() + const path = await f.write('child', [{ ...f.descriptor, data: { version: 2, provider: 'spawn', mode: 'unknown' } }], true) + await expect(f.read()).rejects.toBeInstanceOf(SessionFormatUnsupportedError) + await expect(f.read()).rejects.toThrow(path) + }) + + it.each(['read', 'write'] as const)('rejects duplicate own catalogs through a current %s open', async (access) => { + const f = await fixture() + const catalog = { type: 'subagent/catalog', seq: 0, time: 2, + data: { version: 0, childId: 'child', childCreatedAt: 2, mode: 'one-shot' } } + await f.write(f.parent, [catalog, { ...catalog, seq: 1 }], false, 4) + await expect(f.ctx.sessionPersistence.open(f.parent, access)).rejects.toThrow('duplicate catalog child') + }) + + it('recollects a changed child within the same read open', async () => { + const f = await fixture() + await f.write('child', [f.descriptor], true) + expect(await f.read()).toHaveLength(1) + await f.write('child', [f.descriptor, { type: 'feedback/record', seq: 1, time: 3, data: { text: 'appended' } }], true) + expect(await f.read()).toHaveLength(1) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + await writer.close() + }) + + it('detects children added after preparation instead of publishing incomplete membership', async () => { + const f = await fixture() + expect(await f.read()).toEqual([]) + await f.write('child', [f.descriptor], true) + await expect(f.ctx.sessionPersistence.open(f.parent, 'write')).rejects.toThrow(generationLogPath(f.root, undefined, SessionId('child'), 3, compression)) + expect(await f.read()).toHaveLength(1) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + await writer.close() + }) + + it('refuses an unavailable descriptor without writing a successor', async () => { + const f = await fixture() + await f.write('child', [], true) + await expect(f.read()).rejects.toThrow('supported subagent descriptor') + const parentPath = generationLogPath(f.root, undefined, f.parent, 3, compression) + expect(await readdir(dirname(parentPath))).toEqual([compression === 'none' ? 'session.v3.jsonl' : 'session.v3.jsonl.zstd']) + }) + + it('reads current children without recursive migration and preserves current parent fast reads', async () => { + const f = await fixture() + await f.write('child', [f.descriptor], true, 4) + expect(await f.read()).toHaveLength(1) + await f.write(f.parent, [], false, 4) + await f.write('child', [], true, 4) + expect(await f.read()).toEqual([]) + }) + + it('refuses publication when a related child disappears', async () => { + const f = await fixture() + const path = await f.write('child', [f.descriptor], true) + const header = { ...f.header, id: SessionId('child'), origin: 'subagent', parentSession: f.parent, createdAt: 2, delegationDepth: 1 } as SessionHeader + const prepare = () => prepareCatalogFacts(f.parent, [{ path, header }], compression, new AbortController().signal) + const prepared = await prepare() + await rm(path) + await expect(prepared.validate()).rejects.toMatchObject({ code: 'ENOENT' }) + await expect(prepare()).rejects.toMatchObject({ code: 'ENOENT' }) + }) + + it('rejects changed header identities and invalid source selection', async () => { + const f = await fixture() + const path = await f.write('child', [f.descriptor], true) + const header = { ...f.header, id: SessionId('wrong-child'), origin: 'subagent', parentSession: f.parent } as SessionHeader + const signal = new AbortController().signal + await expect(prepareCatalogFacts(f.parent, [{ path, header }], compression, signal)).rejects.toThrow('changed') + await expect(prepareCatalogFacts(f.parent, [{ path: path + '.foreign', header }], compression, signal)).rejects.toThrow('unrecognized historical child generation') + const controller = new AbortController() + controller.abort(new Error('cancelled child collection')) + await expect(prepareCatalogFacts(f.parent, [{ path, header }], compression, controller.signal)).rejects.toThrow('cancelled child collection') + }) + + it.each([0, 1, 2])('composes a V%i parent and child through all preceding edges', async (version) => { + const f = await fixture() + const initial = generationLogPath(f.root, undefined, f.parent, 3, compression) + await rm(initial) + const parentPath = await f.write(f.parent, [], false, version) + const childPath = await f.write('child', [f.descriptor], true, version) + const before = await Promise.all([readFile(parentPath), readFile(childPath)]) + expect(await f.read()).toMatchObject([{ type: 'subagent/catalog', seq: 0, data: { childId: 'child', mode: 'continuable', label: 'old child' } }]) + const writer = await f.ctx.sessionPersistence.open(f.parent, 'write') + await writer.close() + expect(await Promise.all([readFile(parentPath), readFile(childPath)])).toEqual(before) + expect((await readdir(dirname(parentPath))).filter(name => name !== 'session.lock')).toHaveLength(2) + }) + + it('lists historical headers, prepares read-only membership, and publishes an unchanged-prefix successor', async () => { + const root = await mkdtemp(join(tmpdir(), 'dsh-catalog-migration-')) + roots.push(root) + const parent = SessionId('parent') + const child = SessionId('child') + const header = { type: 'session', version: 3, id: parent, createdAt: 1, isSeeded: false, delegationDepth: 0 } + const childHeader = { ...header, id: child, createdAt: 2, origin: 'subagent', parentSession: parent, delegationDepth: 1 } + const descriptor = { type: 'subagent/descriptor', seq: 0, time: 2, data: { version: 3, mode: 'one-shot', provider: 'spawn', label: 'old child' } } + const sourcePaths: string[] = [] + for (const [meta, events] of [[header, []], [childHeader, [descriptor]]] as const) { + const path = generationLogPath(root, undefined, meta.id, 3, compression) + sourcePaths.push(path) + await mkdir(dirname(path), { recursive: true }) + const first = Buffer.from(JSON.stringify(meta) + '\n') + const body = Buffer.from(events.map(event => JSON.stringify(event) + '\n').join('')) + await writeFile(path, compression === 'none' ? Buffer.concat([first, body]) + : Buffer.concat([await compressZstdFrame(first), ...(body.length === 0 ? [] : [await compressZstdFrame(body)])])) + } + const original = await Promise.all(sourcePaths.map(path => readFile(path))) + const ctx = new Context() + contexts.push(ctx) + await ctx.plugin(JsonlSessionPersistence, { root, compression }) + expect((await ctx.sessionPersistence.list()).map(row => row.header.id).sort()).toEqual([child, parent]) + const reader = await ctx.sessionPersistence.open(parent, 'read') + let expected + try { + expect(reader.header.version).toBe(4) + expected = (await reader.read()).events + expect(expected).toEqual([{ type: 'subagent/catalog', seq: 0, time: 1, data: { + version: 0, childId: child, childCreatedAt: 2, mode: 'one-shot', label: 'old child', + } }]) + expect(await readdir(dirname(sourcePaths[0]!))).toEqual([compression === 'none' ? 'session.v3.jsonl' : 'session.v3.jsonl.zstd']) + } finally { await reader.close() } + const writer = await ctx.sessionPersistence.open(parent, 'write') + try { expect((await writer.read()).events).toEqual(expected) } finally { await writer.close() } + expect(await Promise.all(sourcePaths.map(path => readFile(path)))).toEqual(original) + const reopened = await ctx.sessionPersistence.open(parent, 'read') + try { expect((await reopened.read()).events).toEqual(expected) } finally { await reopened.close() } + }) +}) diff --git a/packages/session/session-persistence-jsonl/tests/generation.spec.ts b/packages/session/session-persistence-jsonl/tests/generation.spec.ts index 71f05baa1a..664f66b2ba 100644 --- a/packages/session/session-persistence-jsonl/tests/generation.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/generation.spec.ts @@ -23,6 +23,7 @@ import { JsonlGenerationTargetConflictError, JsonlGenerationUnsupportedMigrationError, prepareJsonlMigration, + readDecodedJsonlSource, verifyJsonlCurrentGeneration, type JsonlGenerationFormatAdapter, type PrepareJsonlMigrationOptions, @@ -30,7 +31,7 @@ import { import { createJsonlGenerationTestRuntime } from '../src/testing/generation.ts' import { compressZstdFrame, decompressZstdFrame, scanZstdFrames } from '../src/zstd.ts' import type { JsonlCompression } from '../src/format.ts' -import { sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' +import { createSessionFormatCatalogWithChildren, sessionFormatCatalog } from '@deepseek-ai/dsh-session-format-catalog' import type { SessionFormatArtifact, SessionFormatEvent, @@ -85,6 +86,20 @@ function header(version: number, id = 'generation-test'): Record { + const path = join(await tempRoot(), 'session.v3.jsonl') + await writeFile(path, line(header(3))) + const controller = new AbortController() + const reason = new Error('child decoding cancelled') + await expect(readDecodedJsonlSource(path, 3, 'none', { + createRestore() { + controller.abort(reason) + throw reason + }, + }, controller.signal)).rejects.toBe(reason) +}) + const assistantUsage = { inputTokens: 3, outputTokens: 2 } const assistantReplayState = { response: { id: 'response' } } @@ -179,7 +194,7 @@ function adapter(overrides: Partial = {}): TestGene function catalogAdapter(): JsonlGenerationFormatAdapter { return { currentVersion: sessionFormatCatalog.currentVersion, - createRestore: header => sessionFormatCatalog.createRestore(header, { + createRestore: header => createSessionFormatCatalogWithChildren([]).createRestore(header, { recovery: 'recoverable', validation: 'transformed', }), encodeHeader: (header, inheritedEventCount) => diff --git a/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts index 9e3493edb9..02a494368f 100644 --- a/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session/session-persistence-jsonl/tests/jsonl.spec.ts @@ -1165,6 +1165,25 @@ describe('JsonlSessionPersistence: immutable format generations', () => { .rejects.toThrow(/released v0 physical header lacks required member "type"/) }) + it('tracks a disappearing corpus member and propagates its storage faults in historical revisions', async () => { + const parent = meta('corpus-revision-parent', '/work') + const child = meta('corpus-revision-child', '/work') + for (const header of [parent, child]) { + const path = historicalLogPath(root, header.cwd, header.id) + await mkdir(dirname(path), { recursive: true }) + await writeFile(path, `${JSON.stringify(releasedV0Header(header))}\n`) + } + const present = await ctx.sessionPersistence.stat(parent.id) + statFailure.path = historicalLogPath(root, child.cwd, child.id) + statFailure.error = Object.assign(new Error('member disappeared'), { code: 'ENOENT' }) + const missing = await ctx.sessionPersistence.stat(parent.id) + expect(missing).toBeDefined() + expect(missing?.revision).not.toBe(present?.revision) + expect((await ctx.sessionPersistence.stat(parent.id))?.revision).toBe(missing?.revision) + statFailure.error = Object.assign(new Error('member denied'), { code: 'EACCES' }) + await expect(ctx.sessionPersistence.stat(parent.id)).rejects.toBe(statFailure.error) + }) + it('surfaces source-read storage faults and aborts unwrapped during migration', async () => { const header = meta('source-read-fault', '/work') const sourcePath = historicalLogPath(root, header.cwd, header.id) diff --git a/packages/test-support/llm-replay/README.i18n.yaml b/packages/test-support/llm-replay/README.i18n.yaml index 28c2b4ef5e..125108504b 100644 --- a/packages/test-support/llm-replay/README.i18n.yaml +++ b/packages/test-support/llm-replay/README.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 packages/test-support/llm-replay/README.md -README.md: 5877db20babb07523e870d6f3041e1c35f076130 -README.zh.md: dc2c015ff4f1347da41f49608452702c9c90a67a +README.md: 1124572ce28375a1d67b474c23dbe29000124f01 +README.zh.md: ee7f75509687da17867adbb5e414b74b8775addf diff --git a/packages/test-support/llm-replay/README.md b/packages/test-support/llm-replay/README.md index 5877db20ba..1124572ce2 100644 --- a/packages/test-support/llm-replay/README.md +++ b/packages/test-support/llm-replay/README.md @@ -83,6 +83,8 @@ Two failure modes are not reconstructable from a durable Assistant settlement al - **An unrecorded session makes a call** — replay fails loud and tells you to re-record the scenario. - **A scripted placeholder matches nothing** — `{{fromRequest:}}` resolution validates the pattern and the request corpus and fails loud on no match, an invalid pattern, or an unterminated placeholder. +Isolated transcript extraction supplies an explicit empty child-fact set to V3→V4. It retains recorded catalog entries but does not discover related files. Complete historical parent catalog migration belongs to JSONL persistence. + ----- diff --git a/packages/test-support/llm-replay/README.zh.md b/packages/test-support/llm-replay/README.zh.md index dc2c015ff4..ee7f755096 100644 --- a/packages/test-support/llm-replay/README.zh.md +++ b/packages/test-support/llm-replay/README.zh.md @@ -83,6 +83,8 @@ parent agent 委托给进程内 subagent 的场景会为每个 Session 记录一 - **未记录的会话发起调用**——回放会明确报错,并提示你重新录制场景。 - **脚本占位符匹配不到内容**——`{{fromRequest:}}` 解析会校验模式与请求语料,匹配不到、模式非法或占位符未闭合都会明确报错。 +独立转录提取向 V3→V4 显式提供空的子 Session 事实集合;保留已有目录记录,但不发现关联文件。完整的历史父目录迁移由 JSONL 持久化负责。 + ----- diff --git a/packages/test-support/llm-replay/src/index.ts b/packages/test-support/llm-replay/src/index.ts index 14d1a5764a..16f0d32a5a 100644 --- a/packages/test-support/llm-replay/src/index.ts +++ b/packages/test-support/llm-replay/src/index.ts @@ -15,6 +15,7 @@ import type {} from '@deepseek-ai/dsh-deepseek-llm-api-extensions' import { SESSION_FORMAT_VERSION, SessionLogOffset, type SessionEvent } from '@deepseek-ai/dsh-session' import type { SessionLogOffset as SessionLogOffsetType } from '@deepseek-ai/dsh-session' import { + createSessionFormatCatalogWithChildren, SessionFormatUnsupportedMigrationError, sessionFormatCatalog, } from '@deepseek-ai/dsh-session-format-catalog' @@ -232,7 +233,7 @@ function parseSessionFixture(text: string): ParsedSessionFixture { headerLineNumber = lineNumber sourceHeader = recordValue try { - restore = sessionFormatCatalog.createRestore(normalizeProjectedHeader(recordValue), { + restore = createSessionFormatCatalogWithChildren([]).createRestore(normalizeProjectedHeader(recordValue), { recovery: 'strict', validation: 'current', }) diff --git a/packages/test-support/llm-replay/tests/llm-replay.spec.ts b/packages/test-support/llm-replay/tests/llm-replay.spec.ts index 251ce14062..49ae763ef7 100644 --- a/packages/test-support/llm-replay/tests/llm-replay.spec.ts +++ b/packages/test-support/llm-replay/tests/llm-replay.spec.ts @@ -240,13 +240,13 @@ describe('fixture format diagnostics', () => { const actual = await importOriginal() return { ...actual, - sessionFormatCatalog: { - ...actual.sessionFormatCatalog, + createSessionFormatCatalogWithChildren: () => ({ + ...actual.createSessionFormatCatalogWithChildren([]), createRestore(): never { const failure: unknown = 'decoder exploded' throw failure }, - }, + }), } }) try { @@ -266,8 +266,8 @@ describe('fixture format diagnostics', () => { const actual = await importOriginal() return { ...actual, - sessionFormatCatalog: { - ...actual.sessionFormatCatalog, + createSessionFormatCatalogWithChildren: () => ({ + ...actual.createSessionFormatCatalogWithChildren([]), createRestore() { return { header: { version: SESSION_FORMAT_VERSION, id: 'fixture', createdAt: 0, isSeeded: false, delegationDepth: 0 }, @@ -277,7 +277,7 @@ describe('fixture format diagnostics', () => { }, } }, - }, + }), } }) try { @@ -297,8 +297,8 @@ describe('fixture format diagnostics', () => { const actual = await importOriginal() return { ...actual, - sessionFormatCatalog: { - ...actual.sessionFormatCatalog, + createSessionFormatCatalogWithChildren: () => ({ + ...actual.createSessionFormatCatalogWithChildren([]), createRestore() { return { header: { version: SESSION_FORMAT_VERSION, id: 'fixture', createdAt: 0, isSeeded: false, delegationDepth: 0 }, @@ -308,7 +308,7 @@ describe('fixture format diagnostics', () => { }, } }, - }, + }), } }) try { @@ -329,8 +329,8 @@ describe('fixture format diagnostics', () => { let row = 0 return { ...actual, - sessionFormatCatalog: { - ...actual.sessionFormatCatalog, + createSessionFormatCatalogWithChildren: () => ({ + ...actual.createSessionFormatCatalogWithChildren([]), createRestore() { return { header: { version: SESSION_FORMAT_VERSION, id: 'fixture', createdAt: 0, isSeeded: false, delegationDepth: 0 }, @@ -341,7 +341,7 @@ describe('fixture format diagnostics', () => { finish(): never { throw new Error('unexpected finish') }, } }, - }, + }), } }) try { @@ -372,8 +372,8 @@ describe('fixture format diagnostics', () => { const actual = await importOriginal() return { ...actual, - sessionFormatCatalog: { - ...actual.sessionFormatCatalog, + createSessionFormatCatalogWithChildren: () => ({ + ...actual.createSessionFormatCatalogWithChildren([]), createRestore() { return { header: { version: SESSION_FORMAT_VERSION, id: 'fixture', createdAt: 0, isSeeded: false, delegationDepth: 0 }, @@ -381,7 +381,7 @@ describe('fixture format diagnostics', () => { finish(): never { throw new Error(message) }, } }, - }, + }), } }) try { diff --git a/packages/test-support/session-snapshot/README.i18n.yaml b/packages/test-support/session-snapshot/README.i18n.yaml index 6e47c654a5..f86d7f18b9 100644 --- a/packages/test-support/session-snapshot/README.i18n.yaml +++ b/packages/test-support/session-snapshot/README.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 packages/test-support/session-snapshot/README.md -README.md: 14305a6a27de79690537895a632f9796b4b7d17b -README.zh.md: 7e3d8db31f67a670b026bc4e95eb8e481a2f95eb +README.md: 22f091a45d7b445b615a8a6f60b3426500f7f849 +README.zh.md: 526de9b371ec4f07761f46d497fed202ff0dfb8d diff --git a/packages/test-support/session-snapshot/README.md b/packages/test-support/session-snapshot/README.md index 14305a6a27..22f091a45d 100644 --- a/packages/test-support/session-snapshot/README.md +++ b/packages/test-support/session-snapshot/README.md @@ -76,6 +76,8 @@ Spill scenarios save through the real local provider under a private temporary r Retained historical scenarios keep their canonical Session files unchanged and selected for replay, with no newer canonical sibling in the pinned directory. Their exact normalized native writer output is recorded separately in `writer.expected.jsonl` for the parent and `writer..expected.jsonl` for children; these are output oracles, not replay generations. Output oracles may retain an older supported generation: comparison restores them through the strict catalog, while harvested logs must use the checkout writer. Fresh-writer golden comparisons select `nativeWriterOutput` to tokenize only delivery markers qualified by each input’s original writer generation after strict restoration. Other delivery generations and captured-source fields remain numeric; source-versus-migrated-artifact comparisons preserve exact generations by default. Recording and refresh never store these comparison tokens. Retained SDK scenarios use `notifications.current.expected.jsonl` for current protocol output. Comparisons neither project current events back into a historical format nor strip structural differences. Independent migration tests verify the official transform rather than treating native writer layout as its expected event sequence. +Headless/ACP and SDK adapters compare raw catalog child-creation times with harvested child headers before normalization. Refresh preserves the chosen child header time in every matching catalog entry, including inherited copies, so retained header clocks cannot diverge from freshly written catalog clocks. Committed historical inconsistencies remain unchanged migration-refusal evidence; normalizing their clocks does not establish successful migration. + ### Record, replay, and refresh `pnpm run test:snapshot:record` calls the live LLM and writes the harvested current generation under its canonical versioned filename. Record and refresh never rename or delete a completed generation, including generations of a child role absent from a later run; reviewed source-tree curation removes a predecessor only after the same role has a verified current replacement. Scenarios with an explicit `sessionFormat` remain read-only in record mode. `pnpm run test:snapshot:refresh` stays keyless, runs the selected highest replay input, and writes stdout, owned prompt and tool-schema sidecars, and a fresh current-generation comparable Session output; retained historical scenarios write the separate writer-output oracles instead of a canonical current-format replay generation. Each composition owner keeps its replay patch beside its live patch; top-level `snapshots/` owns Session-driven scenarios, while other expected outputs stay beside their owning package. [`dsh-llm-replay`](../llm-replay/README.md) serves the recorded streams selected through `DSH_SNAPSHOT_*` environment values. diff --git a/packages/test-support/session-snapshot/README.zh.md b/packages/test-support/session-snapshot/README.zh.md index 7e3d8db31f..526de9b371 100644 --- a/packages/test-support/session-snapshot/README.zh.md +++ b/packages/test-support/session-snapshot/README.zh.md @@ -76,6 +76,8 @@ spill 场景通过真实本地提供方保存到私有临时根目录。fixture 保留历史输入的场景保持规范 Session 文件不变,并继续选择它们进行回放;固定历史版本的目录中没有更新的规范同角色文件。其精确的规范化原生 writer 输出单独记录在父会话的 `writer.expected.jsonl` 和子会话的 `writer..expected.jsonl` 中;这些是输出比较基准,而非 replay 代际。输出比较基准可以保留较旧的受支持代际:比较通过严格 catalog 恢复它们,而收集的日志必须使用当前检出版本的 writer。新 writer 输出的 golden 比较选择 `nativeWriterOutput`,仅在严格恢复后,将版本限定为各输入原始 writer 代际的 delivery 标记转换为 token。其他 delivery 代际与 captured-source 字段保持数值;源文件与已迁移产物的比较默认保留精确代际。record 与 refresh 从不存储这些比较 token。保留历史输入的 SDK 场景使用 `notifications.current.expected.jsonl` 记录当前协议输出。比较既不将当前事件反向投影为历史格式,也不剥除结构差异。独立迁移测试验证正式转换,而不把原生 writer 布局当作其预期事件序列。 +Headless/ACP 与 SDK 适配器在规范化之前,将原始目录中的子创建时间与采集到的子 header 比较。刷新会在每条匹配的目录记录中保留选定的子 header 时间,包括继承副本,防止保留的 header 时钟与新写入的目录时钟分歧。已提交的历史不一致数据保持不变,作为迁移拒绝证据;将其时钟规范化不能证明迁移成功。 + ### 录制、回放与刷新 `pnpm run test:snapshot:record` 调用在线 LLM(大语言模型),并在规范具名版本文件下写入收集到的当前 generation。record 与 refresh 绝不重命名或删除已完成的 generation,即使后续运行不再产生某个 child 角色也一样;受审阅的源树整理只有在同角色存在已验证的当前替代文件后才移除前代。显式声明 `sessionFormat` 的场景在录制模式下保持只读。`pnpm run test:snapshot:refresh` 保持无密钥,运行选定的最高 replay 输入,并写入 stdout、各 pin 自有的提示词与工具 schema 伴随文件,以及新鲜当前 generation 的可比较 Session 输出;保留历史输入的场景写入单独的 writer 输出比较基准,而非规范当前格式 replay 代际。每个组合 owner 把 replay patch 放在 live patch 旁;顶层 `snapshots/` 拥有 Session 驱动场景,其他预期输出留在其 package owner 旁。[`dsh-llm-replay`](../llm-replay/README.zh.md) 提供通过 `DSH_SNAPSHOT_*` 环境值选择的已记录流。 diff --git a/packages/test-support/session-snapshot/src/index.ts b/packages/test-support/session-snapshot/src/index.ts index 04a9ccd5d7..386940f23c 100644 --- a/packages/test-support/session-snapshot/src/index.ts +++ b/packages/test-support/session-snapshot/src/index.ts @@ -98,6 +98,7 @@ export { parseSystemPromptSnapshot, parseToolSchemasSnapshot, refreshFixtureReplacements, + reconcileCatalogCreationTimes, restorePinnedToolSchemas, stabilizeFixtureMessageIds, stabilizeRefreshLog, diff --git a/packages/test-support/session-snapshot/src/suite.ts b/packages/test-support/session-snapshot/src/suite.ts index 30f10dc213..578526b1f1 100644 --- a/packages/test-support/session-snapshot/src/suite.ts +++ b/packages/test-support/session-snapshot/src/suite.ts @@ -837,6 +837,32 @@ export function refreshFixtureReplacements(logs: HarvestedLog[], fixtures: strin return replacements } +/** + * Check raw parent/child clocks before normalization, or preserve their equality during refresh. + * @param logs - one scenario's parent and child logs with shared Session ids. + * @param policy - validate live output, or align refreshed catalogs to the retained child headers. + * @returns logs with only conflicting catalog creation times replaced under preserve-headers. + */ +export function reconcileCatalogCreationTimes(logs: readonly string[], policy: 'validate' | 'preserve-headers'): string[] { + const headers = new Map(logs.map((log) => { + const header = parseJsonlRecords(log)[0] + return [header?.['id'], header] as const + })) + return logs.map(log => log.split('\n').map((line) => { + if (line.length === 0) return line + const record = JSON.parse(line) as Record + if (record.type !== 'subagent/catalog' || !isRecord(record.data)) return line + const child = headers.get(record.data.childId) + // Partial harvested corpora need not retain every cataloged child log. + if (child === undefined || record.data.childCreatedAt === child.createdAt) return line + if (policy === 'validate') { + throw new Error(`catalog child ${String(record.data.childId)} creation time ${String(record.data.childCreatedAt)} disagrees with child header ${String(child.createdAt)}`) + } + record.data.childCreatedAt = child.createdAt + return JSON.stringify(record) + }).join('\n')) +} + function preserveFixtureVolatiles(record: Record, existing: Record | undefined): void { if (existing === undefined || existing.type !== record.type) return if (record.type === 'session') { @@ -1308,6 +1334,7 @@ export function defineAcpSnapshotSuite(options: SnapshotSuiteOptions): void { ...scenario.configPath !== undefined ? { configPath: scenario.configPath } : {}, }) + reconcileCatalogCreationTimes(result.sessionLogs.map(log => log.content), 'validate') for (const log of result.sessionLogs) { expect(unknownToolCallIds(log.content), `session ${log.id}: snapshot scenarios must not accept UNKNOWN_TOOL`) .toEqual([]) @@ -1361,7 +1388,9 @@ export function defineAcpSnapshotSuite(options: SnapshotSuiteOptions): void { ctx, )))) : result.sessionLogs.map(log => scrubSessionSnapshot(portableFixture(log.content))) - const outputFixtures = redactSessionSnapshotIds(stabilizeFixtureMessageIds(freshFixtures, existingFixtures)) + const outputFixtures = redactSessionSnapshotIds(stabilizeFixtureMessageIds( + reconcileCatalogCreationTimes(freshFixtures, 'preserve-headers'), existingFixtures, + )) await Promise.all(outputFixtures.map((fixture, index) => writeFile(join(dir, outputFixtureFiles[index] as string), fixture))) fixtureFiles = outputFixtureFiles diff --git a/packages/test-support/session-snapshot/tests/suite.spec.ts b/packages/test-support/session-snapshot/tests/suite.spec.ts index 30054581dc..31a2c1b219 100644 --- a/packages/test-support/session-snapshot/tests/suite.spec.ts +++ b/packages/test-support/session-snapshot/tests/suite.spec.ts @@ -35,6 +35,7 @@ import { parseSystemPromptSnapshot, parseToolSchemasSnapshot, refreshFixtureReplacements, + reconcileCatalogCreationTimes, scenarioSkipped, restorePinnedToolSchemas, type SharedSnapshotClaim, @@ -1569,3 +1570,29 @@ describe('stabilizeRefreshLog', () => { expect(outputIds).toEqual(freshNames.map(name => ids[name as keyof typeof ids])) }) }) + + +describe('raw parent and child catalog clocks', () => { + const child = '{"type":"session","id":"child","createdAt":100}\n' + const parent = (time: number) => [ + { type: 'session', id: 'parent', createdAt: 1 }, + { type: 'subagent/catalog', seq: 0, time: 2, data: { version: 0, childId: 'child', childCreatedAt: time, mode: 'one-shot' } }, + ].map(row => JSON.stringify(row) + '\n').join('') + + it('rejects mismatched raw clocks before normalization can erase them', () => { + expect(() => reconcileCatalogCreationTimes([parent(200), child], 'validate')).toThrow('creation time 200 disagrees with child header 100') + expect(reconcileCatalogCreationTimes([parent(100), child], 'validate')).toEqual([parent(100), child]) + }) + + it('keeps retained child clocks in newly generated catalog fixtures', () => { + const output = reconcileCatalogCreationTimes([parent(200), child], 'preserve-headers') + expect(output).toEqual([parent(100), child]) + expect(reconcileCatalogCreationTimes(output, 'validate')).toEqual(output) + expect(reconcileCatalogCreationTimes(output, 'preserve-headers')).toEqual(output) + }) + + it('preserves partial corpora and unrelated rows verbatim', () => { + const partial = parent(200) + '{"type":"feedback/record","data":null}\n' + expect(reconcileCatalogCreationTimes([partial], 'validate')).toEqual([partial]) + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa704b0458..e86365e2e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6501,6 +6501,9 @@ importers: '@deepseek-ai/dsh-session-format-catalog': specifier: workspace:^ version: link:../../session/session-format-catalog + '@deepseek-ai/dsh-session-format-v3-to-v4': + specifier: workspace:^ + version: link:../../session/session-format-v3-to-v4 js-yaml: specifier: ^4.2.0 version: 4.3.1 diff --git a/scripts/gen-session-format-catalog.ts b/scripts/gen-session-format-catalog.ts index 7c3ca85b51..b913442dc0 100644 --- a/scripts/gen-session-format-catalog.ts +++ b/scripts/gen-session-format-catalog.ts @@ -203,11 +203,12 @@ export function renderSessionFormatCatalog( '', "import { KNOWN_SESSION_EVENT_TYPES } from '@deepseek-ai/dsh-session'", "import { createSessionFormatCatalog } from '@deepseek-ai/dsh-session-format'", + "import type { SessionFormatCatalogOptions } from '@deepseek-ai/dsh-session-format'", "import { validateInstalledCurrentSessionArtifact, validateInstalledCurrentSessionHeader } from './current.ts'", ...imports, '', - '/** Physical codec dispatch and complete adjacent chain, independent of mounted plugins. */', - 'export const sessionFormatCatalog = createSessionFormatCatalog({', + '/** Static assembly shared by current reads and parent-specific historical restoration. */', + 'export const sessionFormatCatalogOptions: SessionFormatCatalogOptions = {', ` currentVersion: ${currentVersion},`, ' codecs: [', ...codecs.map(codec => ` ${codec},`), @@ -229,7 +230,10 @@ export function renderSessionFormatCatalog( ' validateInstalledCurrentSessionHeader(header)', ' return header', ' },', - '})', + '}', + '', + '/** Physical codec dispatch and complete adjacent chain, independent of mounted plugins. */', + 'export const sessionFormatCatalog = createSessionFormatCatalog(sessionFormatCatalogOptions)', '', ].join('\n') } diff --git a/snapshots/sdk/sdk.snapshot.ts b/snapshots/sdk/sdk.snapshot.ts index 3405411e43..e314c68f4f 100644 --- a/snapshots/sdk/sdk.snapshot.ts +++ b/snapshots/sdk/sdk.snapshot.ts @@ -31,6 +31,7 @@ import { parseToolSchemasSnapshot, redactSessionSnapshotIds, refreshFixtureReplacements, + reconcileCatalogCreationTimes, restorePinnedToolSchemas, scrubModelRequestBulk, scrubSessionSnapshot, @@ -822,6 +823,7 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => { recording ? logs.length : files.length, assertions.dshSdkChild !== undefined, ) + reconcileCatalogCreationTimes(ordered.map(log => log.content), 'validate') const actualContext = contextOf(ordered, cwd) if (scenario.name === 'tool-error-details') { const events = results.flatMap(result => result.events) @@ -873,7 +875,7 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => { stabilizeRefreshLog(log.content, existing, replacements, actualContext), )) }) - expectedContents = redactSessionSnapshotIds(stabilizeFixtureMessageIds(refreshed, expectedContents)) + expectedContents = redactSessionSnapshotIds(stabilizeFixtureMessageIds(reconcileCatalogCreationTimes(refreshed, 'preserve-headers'), expectedContents)) } if (writesSessionFixtures || refreshing && retained) { From e55093b47d6cfc7db94d703ee6b04fdf39d925aa Mon Sep 17 00:00:00 2001 From: Dudu-0223 Date: Wed, 16 Sep 2026 11:13:15 +0800 Subject: [PATCH 007/279] feat(subagent): migrate direct catalog consumers to parent projections --- ...01-parent-owned-subagent-catalog.i18n.yaml | 4 +- ...026-09-01-parent-owned-subagent-catalog.md | 4 +- ...-09-01-parent-owned-subagent-catalog.zh.md | 4 +- ...07-27-web-subagent-conversations.i18n.yaml | 4 +- .../2026-07-27-web-subagent-conversations.md | 38 +- ...026-07-27-web-subagent-conversations.zh.md | 38 +- ...web-subagent-catalog-projections.i18n.yaml | 6 + ...-09-08-web-subagent-catalog-projections.md | 31 + ...-08-web-subagent-catalog-projections.zh.md | 31 + ...subagent-catalog-membership-only.i18n.yaml | 6 + ...-09-16-subagent-catalog-membership-only.md | 25 + ...-16-subagent-catalog-membership-only.zh.md | 25 + ...backend-continuation-performance.i18n.yaml | 4 +- ...-09-06-backend-continuation-performance.md | 8 +- ...-06-backend-continuation-performance.zh.md | 8 +- .../subagent-diagnostic/parent.expected.jsonl | 5 +- .../subagent-diagnostic/replay.override.json | 2 +- .../tests/subagent-diagnostic.expected.e2e.ts | 39 +- apps/web/tests/agent-preset-selection.e2e.ts | 34 +- apps/web/tests/assembled-remote.ts | 6 +- apps/web/tests/subagent-conversation.e2e.ts | 159 +- apps/web/tests/subagent-interrupt-ui.e2e.ts | 25 +- .../child-catalog.worker.ts | 26 +- docs/config-catalog.i18n.yaml | 4 +- docs/config-catalog.md | 2 +- docs/config-catalog.zh.md | 2 +- docs/event-producer-consumer.i18n.yaml | 4 +- docs/event-producer-consumer.md | 20 +- docs/event-producer-consumer.zh.md | 20 +- docs/persistence-catalog.i18n.yaml | 4 +- docs/persistence-catalog.md | 4 +- docs/persistence-catalog.zh.md | 4 +- docs/persistence-schema.json | 4 +- docs/subsystems/session.i18n.yaml | 4 +- docs/subsystems/session.md | 15 +- docs/subsystems/session.zh.md | 15 +- docs/subsystems/subagent.i18n.yaml | 4 +- docs/subsystems/subagent.md | 51 +- docs/subsystems/subagent.zh.md | 51 +- docs/tool-catalog.i18n.yaml | 4 +- docs/tool-catalog.md | 2 +- docs/tool-catalog.zh.md | 2 +- .../api/session-controller/README.i18n.yaml | 4 +- packages/api/session-controller/README.md | 6 +- packages/api/session-controller/README.zh.md | 6 +- .../src/client/contract/sessions.ts | 15 +- .../session-controller/src/client/index.ts | 2 +- .../src/client/sessions/lineage.ts | 3 +- .../src/client/sessions/manager.ts | 367 ++--- .../src/client/sessions/remotes.ts | 3 +- .../src/client/sessions/service.ts | 44 +- .../src/client/sessions/session.ts | 2 +- packages/api/session-controller/src/index.ts | 43 +- packages/api/session-controller/src/list.ts | 2 + packages/api/session-controller/src/types.ts | 16 +- .../tests/client-apply.client.spec.ts | 6 +- .../tests/inbox-projection.client.spec.ts | 6 +- .../tests/lineage.client.spec.ts | 2 +- .../tests/manager.client.spec.ts | 542 ++++--- .../tests/projection-store.client.spec.ts | 13 +- .../tests/remote/session.client.ts | 2 +- .../tests/sessions-service.client.spec.ts | 121 +- .../tests/subagent-catalog.host.spec.ts | 216 +++ .../session-controller/tests/test-remote.ts | 7 + .../tests/transport.client.spec.ts | 1 - .../tests/transport.host.spec.ts | 28 +- .../locale/tests/language-row.client.spec.tsx | 2 +- .../ui-chat/tests/chat-view.client.spec.tsx | 2 +- .../tests/transcript-view-row.client.spec.tsx | 2 +- .../client/skeleton/ConversationMainPanel.tsx | 4 +- .../conversation-registry.client.spec.ts | 5 +- .../tests/enter-behavior-row.client.spec.tsx | 2 +- .../tests/input-bar.client.spec.tsx | 2 +- .../tests/input-matrix.client.spec.tsx | 2 +- .../tests/input-scenarios.client.spec.tsx | 2 +- .../tests/skeleton.client.spec.tsx | 2 +- .../tests/produced-files.client.spec.tsx | 2 +- .../tests/job-list-action.client.spec.tsx | 2 +- .../ui-layout/tests/app-frame.client.spec.tsx | 2 +- .../tests/document-title.client.spec.tsx | 2 +- .../tests/open-in-app-action.client.spec.tsx | 2 +- .../tests/ui-session.client.spec.ts | 2 +- .../tests/components.client.spec.tsx | 2 +- packages/client/ui-subagent/README.i18n.yaml | 4 +- packages/client/ui-subagent/README.md | 10 +- packages/client/ui-subagent/README.zh.md | 10 +- .../client/SubagentHeaderLineage.module.css | 13 - .../src/client/SubagentHeaderLineage.tsx | 251 +--- .../client/ui-subagent/src/client/index.ts | 10 +- .../client/ui-subagent/src/client/locales.ts | 8 - .../src/client/subagent-lineage.ts | 46 - .../tests/browser-plugin.client.spec.ts | 19 +- .../tests/conversation-ui.client.spec.tsx | 310 ++-- .../tests/subagent-lineage.client.spec.ts | 31 - .../tests/appearance-row.client.spec.tsx | 2 +- .../tests/font-size-row.client.spec.tsx | 2 +- .../tests/coverage-tails.client.spec.tsx | 2 +- .../ui-tool/tests/diff-card.client.spec.tsx | 2 +- .../ui-tool/tests/image-card.client.spec.tsx | 2 +- .../ui-tool/tests/read-card.client.spec.tsx | 2 +- .../tests/terminal-card.client.spec.tsx | 2 +- .../ui-trajectory/tests/views.client.spec.tsx | 2 +- .../tests/plan-review-panel.client.spec.tsx | 2 +- .../user-questions-composer.client.spec.tsx | 2 +- .../client/ui-workflow-run/README.i18n.yaml | 4 +- packages/client/ui-workflow-run/README.md | 2 +- packages/client/ui-workflow-run/README.zh.md | 2 +- .../src/client/WorkflowRunPanel.tsx | 9 +- .../tests/workflow-run.client.spec.tsx | 34 +- packages/client/ui-workspace/README.i18n.yaml | 4 +- packages/client/ui-workspace/README.md | 2 +- packages/client/ui-workspace/README.zh.md | 2 +- .../src/client/subagent-lineage.ts | 46 - .../client/ui-workspace/src/client/tree.ts | 27 +- .../ui-workspace/tests/apply.client.spec.ts | 2 +- .../tests/subagent-lineage.client.spec.ts | 30 - .../ui-workspace/tests/tree.client.spec.ts | 34 +- .../tests/workspace-browser.client.spec.tsx | 2 +- .../tests/workspace-picker.client.spec.tsx | 2 +- .../tests/workspaces-service.client.spec.ts | 2 +- .../client-ui-agent-team/src/client/mount.ts | 5 +- .../tests/browser-plugin.client.spec.ts | 36 +- .../tool-agent-team/tests/tool-team.spec.ts | 13 +- .../src/client/api-catalog.ts | 11 +- .../extensions/tool-cordis/src/api-catalog.ts | 55 +- packages/subagent/subagent/README.i18n.yaml | 4 +- packages/subagent/subagent/README.md | 7 +- packages/subagent/subagent/README.zh.md | 9 +- .../subagent/subagent/src/control-types.ts | 58 +- packages/subagent/subagent/src/control.ts | 55 +- packages/subagent/subagent/src/index.ts | 73 +- .../subagent/subagent/src/list-children.ts | 76 +- .../subagent/subagent/tests/control.spec.ts | 129 +- .../subagent/tests/list-children.spec.ts | 1309 +++++------------ .../subagent/subagent/tests/service.spec.ts | 2 +- .../tool-subagent-control/README.i18n.yaml | 4 +- .../subagent/tool-subagent-control/README.md | 4 +- .../tool-subagent-control/README.zh.md | 4 +- .../tool-subagent-control/src/list-agents.ts | 18 +- .../tests/list-agents.spec.ts | 38 +- .../tests/tool-subagent-control.spec.ts | 6 +- .../client-runtime/README.i18n.yaml | 4 +- .../test-support/client-runtime/README.md | 2 + .../test-support/client-runtime/README.zh.md | 2 + .../client-runtime/src/sessions.ts | 28 +- .../tests/runtime.client.spec.tsx | 26 +- scripts/gen-cordis-catalog.ts | 5 +- scripts/gen-cordis-inspect-catalog.ts | 2 +- .../sdk/bash-tool/tool-schemas.expected.json | 2 +- .../tool-schemas.1.expected.json | 2 +- .../tool-schemas.1.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.1.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.1.expected.json | 2 +- .../tool-schemas.1.expected.json | 2 +- .../sdk/text-turn/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 4 +- .../tool-schemas.expected.json | 2 +- .../both-mode-turn/system-prompt.expected.md | 2 +- .../both-mode-turn/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 4 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../system-prompt.expected.md | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../lsp-definition/tool-schemas.expected.json | 2 +- .../system-prompt.expected.md | 2 +- .../mcp-resources/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../plugin-manager/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../provider-cwd/tool-schemas.expected.json | 2 +- .../system-prompt.expected.md | 2 +- .../system-prompt.expected.md | 2 +- .../ptc-python-turn/system-prompt.expected.md | 2 +- .../ptc-read-image/system-prompt.expected.md | 2 +- .../ptc-turn/system-prompt.expected.md | 2 +- .../tool-schemas.expected.json | 2 +- .../pwsh-tool-turn/tool-schemas.expected.json | 2 +- .../ralph-loop/tool-schemas.1.expected.json | 2 +- .../ralph-loop/tool-schemas.2.expected.json | 2 +- .../ralph-loop/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.1.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../text-turn/tool-schemas.expected.json | 2 +- .../web-fetch/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- .../web/ptc-round/system-prompt.expected.md | 2 +- .../tool-schemas.expected.json | 2 +- .../catalog-push.expected.md | 3 + .../stale-catalog.expected.md | 3 - .../subagent-conversation/tree.expected.md | 2 +- 208 files changed, 2378 insertions(+), 2913 deletions(-) create mode 100644 .agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.i18n.yaml create mode 100644 .agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.md create mode 100644 .agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.zh.md create mode 100644 .agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.i18n.yaml create mode 100644 .agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.md create mode 100644 .agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.zh.md create mode 100644 packages/api/session-controller/tests/subagent-catalog.host.spec.ts delete mode 100644 packages/client/ui-subagent/src/client/subagent-lineage.ts delete mode 100644 packages/client/ui-subagent/tests/subagent-lineage.client.spec.ts delete mode 100644 packages/client/ui-workspace/src/client/subagent-lineage.ts delete mode 100644 packages/client/ui-workspace/tests/subagent-lineage.client.spec.ts create mode 100644 snapshots/web/subagent-conversation/catalog-push.expected.md delete mode 100644 snapshots/web/subagent-conversation/stale-catalog.expected.md diff --git a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml index c09aaa9dcb..59e3f84862 100644 --- a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-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 .agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md -2026-09-01-parent-owned-subagent-catalog.md: 20e2dd035b41612592e7baeb55f89322dff02848 -2026-09-01-parent-owned-subagent-catalog.zh.md: 6ec33e8be8d4373ba98a9934178a67e207ffb0bb +2026-09-01-parent-owned-subagent-catalog.md: 536ec33148bd675a974622b98ee23de812691dc0 +2026-09-01-parent-owned-subagent-catalog.zh.md: ec78ff9e4b7d54a7309baf21c383ec5ff83a19c8 diff --git a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md index 20e2dd035b..536ec33148 100644 --- a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md +++ b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md @@ -44,6 +44,6 @@ Current-writer snapshot expectations include catalog facts even when replay inpu ## Consequences -Session observations and client snapshots expose the direct-child list through `projections.values.subagentCatalog`. The projection change feed publishes a complete list when catalog state changes. Each view costs O(D), so D creations can incur O(D²) cumulative view work; this follows the existing projection mechanism. Direct-child and descendant listing still use the Session corpus and child identity projection. +Session observations and client snapshots expose the direct-child list through `projections.values.subagentCatalog`. The projection change feed publishes a complete list when catalog state changes. Each view costs O(D), so D creations can incur O(D²) cumulative view work; this follows the existing projection mechanism. `listChildren()` reads the parent projection through one live-preferred Session observation; descendant listing uses the Session corpus and child identity projection. [Web projection consumption](../simplification/2026-09-08-web-subagent-catalog-projections.md) owns browser loading and synchronization. -Backends that do not know the required event refuse the log under the existing Session event mechanism. Catalog projection does not reconstruct missing parent facts by scanning old child logs. +[Creation metadata exclusion](../simplification/2026-09-16-subagent-catalog-membership-only.md) records why model configuration is absent from catalog facts. diff --git a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md index 6ec33e8be8..ec78ff9e4b 100644 --- a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md +++ b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md @@ -44,6 +44,6 @@ snapshot normalizer 会把 `childCreatedAt` 归零,因为它来自 process clo ## 后果 -Session 观察和客户端快照通过 `projections.values.subagentCatalog` 暴露直接子级列表。目录状态变化时,projection 变更通知发布完整列表。每次视图计算成本为 O(D),因此 D 次创建的累计视图工作量可能为 O(D²);这沿用既有 projection 机制。直接子级和后代列表仍使用 Session 语料库与子级身份 projection。 +Session observation 与 client snapshot 通过 `projections.values.subagentCatalog` 暴露直接子级列表。目录状态变化时,projection change feed 发布完整列表。每次 view 的成本为 O(D),因此 D 次创建可能累计产生 O(D²) 的 view 工作量;这沿用现有 projection 机制。`listChildren()` 通过一次 live-preferred Session observation 读取父 projection;后代枚举使用 Session 语料库与子身份 projection。[Web projection 消费决策](../simplification/2026-09-08-web-subagent-catalog-projections.zh.md) 说明浏览器加载与同步。 -不认识该 required event 的 backend 会按既有 Session event 机制拒绝日志。目录投影不通过扫描旧子级日志来重建缺失的父级事实。 +[创建元数据排除决策](../simplification/2026-09-16-subagent-catalog-membership-only.zh.md) 说明目录事实为何不包含模型配置。 diff --git a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml index cd51630220..7cfba02779 100644 --- a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.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 .agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md -2026-07-27-web-subagent-conversations.md: d0713731de86df639a426ee56c39857c50af6bc7 -2026-07-27-web-subagent-conversations.zh.md: 0f4f6467484ee1caa3cdf28f44e016ff674ac1dc +2026-07-27-web-subagent-conversations.md: 84839dc94b9e4aa0d2511339af1fa17486a953cf +2026-07-27-web-subagent-conversations.zh.md: 4ffdd4fa2fa9da6c622c19b650a12bba85850448 diff --git a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md index d0713731de..84839dc94b 100644 --- a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md +++ b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md @@ -10,7 +10,7 @@ Session-backed subagents have durable identities, persisted transcripts, and a d The browser must preserve the [continuable subagent contract](../../implemented/feature/2026-07-28-continuable-subagent-conversations.md): a continuable child has at most one process-local Activation, accepts later work only through the exact live direct parent, and uses the Agent inbox as its sole FIFO. Viewing history must not create an Activation. Once an inbox message is accepted, the HTTP caller neither owns its execution nor gains a cancellation handle. -The UI must also preserve the membership, modes, and diagnostics of the [durable catalog](../../archived/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md). The shared service reports live-preferred corpus activity, while the Web projection replaces it with the exact child Agent driver's `running` or `inactive` state. Neither activity is a durable outcome or a promise that continuation will succeed. +The UI must also preserve the membership and modes of the [durable catalog](../architecture/2026-09-01-parent-owned-subagent-catalog.md). The Web projection adds the exact child Agent driver's `running` or `inactive` state. Neither activity is a durable outcome or a promise that continuation will succeed. ## Decision @@ -30,16 +30,16 @@ The Figma [subagent list](https://www.figma.com/design/jRBBK7zBgcszdVWQ0Fh5J8/Ha | Design intent | Shipped contract | | --- | --- | -| The session header opens a compact child list. | The trigger aggregates the complete subagent-only descendant lineage; the tree shows every direct catalog entry in service order, including disabled diagnostics. | +| The session header opens a compact child list. | The trigger counts healthy direct entries returned by the parent catalog service. | | Selecting a row reuses the conversation UI. | Addressed history never activates the child; only a continuable row with a live parent retains the ordinary composer. | -| Nested agents expand progressively. | Each row carries a one-level `hasChildren` snapshot; disclosure reserves known direct-descendant rows immediately, then loads only that row's direct catalog and retains its own parent address. | +| Nested agents expand progressively. | A row remains expandable until its own catalog has loaded empty; expansion loads only that direct catalog and retains the row's parent address. | | Rows show labels, state, usage, and active duration without duplicating sidebar rows. | Mode and `running`/`inactive` activity are textual as well as visual; optional title, durable token usage, and active-turn duration come from the list's retained projection values. Compact duration loses smaller units above one day, while hover and accessible naming retain exact whole seconds. `SessionHeader.origin` removes duplicate navigation rows but grants no capability. | ## Product contract -The descendant-count control is absent only when a complete empty direct-catalog response agrees with the session-summary projection that no subagent descendants are known. On an ordinary session, a slash separates the current title from that count control. Every subagent breadcrumb combines its compact 12px title with a fixed double chevron: the current breadcrumb uses primary color and weight 500, while ancestors use tertiary color and weight 400. Hovering a combined control for 150ms opens its direct-parent catalog, with a short crossing grace for the portaled menu; ArrowDown remains the keyboard entry path. Clicking an ancestor cancels pending hover, closes an open catalog, and only navigates upward. Each direct-parent catalog enables sibling switching and bolds its selected row; its label overrides the session-summary title, and every missing switcher catalog refreshes automatically. Only the current subagent appends its own descendant-count control. Long titles truncate before the fixed chevron. The count trigger counts every known session-summary descendant reached through an uninterrupted `origin: 'subagent'` lineage, stops at ordinary forks, and shows ongoing activity when any counted descendant is running. Because ordinary sidebar rows hide subagent-origin sessions, the Workspace browser indexes the same uninterrupted lineage onto each visible ordinary row: any running descendant supplies its blue activity indicator and exact count in hover and assistive text without describing an idle parent as running. An ordinary fork starts a separate aggregation subtree. Pending interaction outranks parent running; either remains primary while descendant activity becomes a second hover and assistive status. With neither present, descendant activity outranks an unviewed completion reminder, which returns after the last running descendant stops. Every healthy direct-catalog row carries a read-time `hasChildren` hint derived only from direct lineage headers with durable `origin: 'subagent'`; normal healthy and diagnostic subagent candidates carry that marker, while ordinary forks do not. This lookahead reads no descendant event log, and the descriptor-backed catalog loaded after disclosure remains authoritative. When summaries establish descendants before that catalog exists or after a stale empty response, the action stays visible and exposes only disabled loading rows until opening it refreshes the catalog; summary-only rows never grant navigation. The UI omits disclosure for a known leaf before interaction; the hint does not promise that the child will remain a leaf. While an expanded direct catalog is loading, known lineage reserves one disabled loading row per direct descendant without recursively fetching descendant catalogs. The tree then presents continuable and one-shot rows, falling back to the session id when an optional one-shot label is absent. Corrupt, unsupported, and unavailable candidates remain visible as disabled diagnostic rows. +The child-count control appears when the direct catalog contains entries or its read fails; it stays hidden while an empty catalog is absent or loading, and after a successful empty read. On an ordinary session, a slash separates the current title from that control. Every subagent breadcrumb combines its compact 12px title with a fixed double chevron: the current breadcrumb uses primary color and weight 500, while ancestors use tertiary color and weight 400. Hovering a combined control for 150ms opens its direct-parent catalog, with a short crossing grace for the portaled menu; ArrowDown remains the keyboard entry path. Clicking an ancestor cancels pending hover, closes an open catalog, and only navigates upward. Each direct-parent catalog enables sibling switching and bolds its selected row; its label overrides the optional session-summary title, and a missing switcher catalog loads on interaction. Only the current subagent appends its own direct-child count control. Long titles truncate before the fixed chevron. The trigger reports the direct catalog's total and running counts. Ordinary sidebar rows hide subagent-origin Sessions and read their direct running-child count from the same loaded catalog map; Session summaries supply activity but never create membership. Pending interaction outranks parent running; either remains primary while direct-child activity becomes a second hover and assistive status. With neither present, direct-child activity outranks an unviewed completion reminder, which returns after the last running direct child stops. A tree row remains expandable while its child catalog is absent, loading, or failed, and becomes a known leaf only after that catalog loads empty. Loading shows a generic notice rather than summary-derived placeholder rows. The tree presents continuable and one-shot rows, falling back to the Session id when an optional one-shot label is absent. -`running` means the exact child Agent driver is draining work at the Host sampling boundary; `inactive` means that driver is idle or absent. The UI does not translate either value into success, failure, cancellation, completeness, or resumability. `subagent.list` supplies the current driver-status baseline, `host/session-status` updates known activity in place, request-local replay prevents an older in-flight list response from overwriting a newer transition, and `host/session-removed` returns a known row to `inactive`; reconnect reads a fresh baseline. A `host/session-added` frame for a direct subagent immediately flips any loaded parent row to `hasChildren: true`, and that positive hint survives an older in-flight catalog response; membership, labels, mode, diagnostics, and the authoritative snapshot still require a debounced `subagent.list` refresh while the affected branch is open. A prompt response remains delivery-time authority. +`running` means the child Agent driver is draining work; `inactive` means that driver is idle or absent. Session-list baselines and status events supply activity, and removal marks completed subagents inactive while retaining their display projections. The shared parent `subagentCatalog` projection supplies membership. Initial reads and pushed values meet in one projection store; a newer sequence wins. [The projection-consumer decision](../simplification/2026-09-08-web-subagent-catalog-projections.md) owns loading, reconnect, and synchronization tradeoffs. A prompt response remains delivery-time authority. Healthy rows reuse the standard session projections retained in the list mirror. The token figure sums the four disjoint `tokenUsage` buckets across the durable log. `subagentTiming` resets at every descriptor so an inherited fork seed cannot enter the child's total, accumulates completed `turn/start` → `turn/end` spans, and carries same-cut `active.since` and `active.through` bounds for an open turn. Existing session events advance `active.through` while that turn remains open; the menu adds no separate timer or log read and advances its local clock only while a known descendant is running. Below one day it formats whole seconds; longer visual values retain at most two adjacent units, using approximate 30-day months and 365-day years, while hover and accessible naming preserve the exact day/hour/minute/second duration. An inactive row bounds an interrupted open turn with `active.through`, so a stale projection never borrows newer session metadata and reopening the menu never restarts completed work. Neither metric implies a durable outcome. @@ -51,17 +51,17 @@ Agent-bound auxiliary controls are unavailable in addressed child views. In part ## Host adapter and wire contract -`@deepseek-ai/dsh-subagent` owns the browser-safe generated `subagent` Remote namespace: +The Session Controller owns catalog and history reads; `@deepseek-ai/dsh-subagent` owns continuation controls: -- `subagent.list` takes `parentSessionId`, calls `ctx.subagents.listChildren(parentSessionId, signal)`, returns the complete ordered entries with each healthy row's boolean `hasChildren` snapshot, replaces each healthy row's corpus activity with whether its exact Agent driver is running, and includes whether the exact parent currently resolves from `ctx.agents`. -- `subagent.history` takes the full mode-bearing address plus ordinary page arguments. It verifies the child and mode against the direct catalog, reads through `ctx.sessionQuery.readSession()`, rechecks direct lineage, and returns the ordinary raw-event, render-intent, pagination, and host-computed session-projection baseline without publishing an Agent. +- `session.projections` takes `sessionId` and returns one live-preferred Session observation’s complete projection baseline without activating an Agent. The Client seeds the standard projection store; subagent consumers select `subagentCatalog`. Parent Agent availability comes from Session-list summaries and lifecycle events. +- `session.page` and `session.follow` take the full mode-bearing address. They validate the child header, direct parent, descriptor identity, and mode at the observed cut, then return ordinary raw events, pagination, live reconciliation, and Host projection baselines without publishing an Agent. - `subagent.prompt` accepts only a `mode: 'continuable'` address, `delivery: 'queue' | 'steer'`, and upload-shaped `PromptContentPart[]`; the Host admits and persists image parts into durable references before delivery ([image delivery](../../archived/bug-fix/2026-08-27-steer-followup-image-delivery.md)). It requires the exact live parent, revalidates the catalog address, uses the continuation manager's shared human-delivery admission, and returns the accepted `MessageId`. -The gateway maps missing parent, missing or diagnostic catalog entries, not-resumable and unauthorized children, request cancellation, image admission and image-capability refusals (`subagent/attachment-invalid`), and temporarily unavailable continuation admission to typed RPC errors. It does not expose descriptor or provider details. A list/prompt race is normal: the prompt result, not the earlier availability or activity snapshot, is authoritative. +The gateway maps missing parents or catalog entries, not-resumable and unauthorized children, request cancellation, image admission and image-capability refusals (`subagent/attachment-invalid`), and temporarily unavailable continuation admission to typed RPC errors. It does not expose descriptor or provider details. A list/prompt race is normal: the prompt result, not the earlier availability or activity snapshot, is authoritative. -Viewing persisted history creates no mux subscription by itself. When a follow-up materializes a cold child Activation, the existing Host and mux streams publish its lifecycle and events. Reconnect rebuilds the addressed window through `subagent.history`. +Viewing persisted history creates no Agent by itself. When a follow-up materializes a cold child Activation, the existing Host and Session journal streams publish its lifecycle and events. Reconnect rebuilds the addressed window through `session.follow`. -The ordinary `session.history` route is likewise observation-only for both ordinary and subagent sessions, but it does not carry the catalog address or grant continuation authority. Every ordinary route that needs an Agent resolves through the shared ownership fence before cold resume; `session.cancel` retains that fence. `session.updateQueue` has one target-local exception for a live child whose current projected identity is continuable and comes from its own non-seed suffix; one-shot, missing, unknown, corrupt, seed-only, or cold children remain fenced. +The ordinary `session.page` and `session.follow` address is likewise observation-only for both ordinary and subagent sessions, but it does not carry the catalog address or grant continuation authority. Every ordinary route that needs an Agent resolves through the shared ownership fence before cold resume; `session.cancel` retains that fence. `session.updateQueue` has one target-local exception for a live child whose current projected identity is continuable and comes from its own non-seed suffix; one-shot, missing, unknown, corrupt, seed-only, or cold children remain fenced. The adapter stays behind the generated Remote namespace; `dsh-host-webserver` remains a carrier. Browser code imports the contract through the existing connection package and never reaches host `ctx`, preserving the [archived GUI RPC layering decision](../../archived/architecture/2026-07-19-gui-layering-and-rpc-protocol.md). @@ -71,7 +71,7 @@ The React-free runtime owns catalogs, single-flight refreshes, retained addresse Catalogs ride the standard `useSessions` snapshot. Component-local state owns menu visibility, expanded branches, focus, and hover timers. `ui-conversation` declares a lineage slot for the current ordinary title and every subagent breadcrumb, passes plain breadcrumb identity and display text plus an upward-navigation callback for ancestors, and retains the ordinary title as the render fallback. `@deepseek-ai/dsh-client-ui-subagent` occupies each lineage slot with direct-parent catalog navigation and elects a reason-specific read-only composer from ordinary owner props. Components receive derived props and callbacks, never `ctx`. -Every in-process subagent child stamps `SessionHeader.origin: 'subagent'` before publication. Session list summaries and incremental Host frames project it so grouped and flat sidebars omit duplicate child rows while preserving ordinary forks. The same existing `host/session-added` frame marks a loaded direct parent row expandable without introducing a catalog event stream. Descriptor mode and catalog verification remain the authority for navigation, continuation, and authorization. +Every in-process subagent child stamps `SessionHeader.origin: 'subagent'` before publication. Session list summaries and incremental Host frames project it so grouped and flat sidebars omit duplicate child rows while preserving ordinary forks. Parent catalog projection owns membership and tree structure; descriptor identity and exact-parent checks own addressed history and continuation validation. The package's existing `@label` source remains separate plain-text model input. It does not resolve labels to addresses or acquire continuation semantics. @@ -95,23 +95,23 @@ The shipped Web composition mounts SQLite session query beside JSONL persistence **Infer mode or sidebar filtering from lineage.** Rejected because ordinary forks share `parentSession`. The descriptor-backed catalog owns mode; the separate `origin` marker is only a cheap navigation classifier. -**Build an eager recursive tree or dedicated catalog stream.** Rejected for the current scale. Header-only one-level expandability lookahead preserves pre-click stability without reading descendant events, while disclosure remains a lazy authoritative direct-child read; existing Host frames update activity, restore expandable parent rows, and trigger bounded membership refreshes. +**Build an eager recursive tree or dedicated catalog stream.** Rejected for the current scale. Disclosure loads missing catalogs lazily, and existing control frames carry complete projection updates. **Let a child remain independently interactive after its parent disappears.** Rejected because independent lifetime and user ownership require side-session semantics. ## Testing -- Host protocol tests pin schemas including required boolean expandability, id echoing, mode verification, non-activating history, exact-parent enforcement, FIFO admission receipts, cancellation, and sanitized failure mapping. +- Host protocol tests pin healthy direct catalog schemas, id echoing, mode verification, non-activating history, exact-parent enforcement, FIFO admission receipts, cancellation, and sanitized failure mapping. - Generic Host tests pin attached and cold history and forks without Agent publication, cold projection folding, descriptor/origin/runtime-owner denial, explicit-id adoption denial, and the direct queue-control fence. -- Client object tests pin retained and restored addresses, one-shot read-only and cancel rejection, history routing, continuable prompt and interrupt routing, suppression of Agent-bound model controls, live activity flips including in-flight response replay and detach fallback, subagent-parent expandability flips, and membership refresh. -- jsdom tests pin the ordinary-title separator, per-level combined subagent-title switchers, 12px nested titles, current and ancestor styling, selected-row weight, catalog-label precedence, hover delay, upward-click suppression, truncation with a retained chevron, the aggregate descendant count and activity, sidebar propagation across nested lineage and ordinary-fork boundaries, row-status precedence, token totals, second-precision running and frozen inactive durations, adaptive long-duration units with exact accessible text, the summary-backed root action across absent and stale-empty catalogs, known loading-row shape, mixed-mode rows, pre-click leaf disclosure, diagnostics, lazy descendant disclosure, direct-parent addresses, keyboard behavior, and both read-only reasons. -- The keyless assembled Web snapshot contains an inactive continuable child with durable usage, an inactive one-shot sibling with a deterministic long duration, and a persisted grandchild; it pins the three-descendant trigger across a stale empty catalog response, usage and timing rows, adaptive long-duration presentation, and the aggregate running transition, expands without activation, opens persisted history, admits a human FIFO follow-up, reconciles child mux events, and proves one-shot history remains read-only. A separate assembled scenario holds a real child Agent turn at the LLM seam while it pins the aggregate running state in both the header and visible idle owner row, then cancels the turn during teardown. +- Client object tests pin retained and restored addresses, one-shot read-only and cancel rejection, history routing, continuable prompt and interrupt routing, suppression of Agent-bound model controls, live activity from Session summaries and Agent disposal, authoritative catalog membership, and membership refresh. +- jsdom tests pin the ordinary-title separator, per-level combined subagent-title switchers, 12px nested titles, current and ancestor styling, selected-row weight, catalog-label precedence, hover delay, upward-click suppression, truncation with a retained chevron, direct counts and activity from catalogs, sidebar direct-child activity, row-status precedence, token totals, second-precision running and frozen inactive durations, adaptive long-duration units with exact accessible text, generic loading, mixed-mode rows, ready-empty leaf detection, lazy descendant disclosure, direct-parent addresses, keyboard behavior, and both read-only reasons. +- The keyless assembled Web snapshot contains an inactive continuable child with durable usage, an inactive one-shot sibling with a deterministic long duration, and a persisted grandchild; it pins direct catalog counts, usage and timing rows, adaptive long-duration presentation, and lazy nested expansion, opens persisted history without activation, admits a human FIFO follow-up, reconciles child mux events, and proves one-shot history remains read-only. A separate assembled scenario holds a real child Agent turn at the LLM seam while it pins the direct running state in both the header and visible idle owner row, then cancels the turn during teardown. - Navigation tests pin subagent-only breadcrumbs, workspace placement for forks created from subagents, and `origin: 'subagent'` sidebar filtering without hiding ordinary forks. ## Consequences -- Catalog reads may rescan persisted lineage and each direct candidate's descriptor log, but expandability reuses only descendant headers already present in that trace; the Web activity baseline adds one Agent-registry lookup per healthy row and then uses existing live frames, while usage and duration reuse projection baselines and pushes with no per-row log read, and membership refresh stays debounced and single-flight. -- Parent availability, child activity, and `hasChildren` are snapshots. Publication, disposal, another sender, or another process may win after listing; typed prompt failure remains expected. +- Catalog reads fold only the selected parent's catalog projection. Web activity comes from Session summaries, while usage and duration reuse projection baselines and pushes with no per-row log read; projection reads remain single-flight. +- Parent availability and child activity are snapshots. Publication, disposal, another sender, or another process may win after listing; typed prompt failure remains expected. - A child may publish between history fetch and mux subscription, so the existing sequence reconciliation also covers the cold-to-live addressed path. - Persisted origin adds one deliberately weak product-classification field to child headers and list projections; it cannot become an authorization shortcut. - Beyond the current-turn Stop of a running continuable child ([interrupt contract](2026-08-06-continuable-subagent-interrupt.md)), the UI has no child cancellation, durable outcome, Activation identity, deletion, or independently interactive offline mode, and its text must not imply those capabilities. Active-turn duration measures logged work rather than Activation residency. diff --git a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md index 0f4f646748..4ffdd4fa2f 100644 --- a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md +++ b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md @@ -10,7 +10,7 @@ Status: implemented 浏览器必须遵守[可继续 subagent 约定](../../implemented/feature/2026-07-28-continuable-subagent-conversations.zh.md):一个可继续 child 在进程内最多只能有一项 Activation,只能通过确切的存活直接 parent 接受后续工作,并将 agent inbox 用作唯一的 FIFO。查看历史不得创建 Activation。inbox 消息一经接受,HTTP 调用方既不拥有其执行过程,也不会获得取消句柄。 -UI 还必须保留[持久化目录](../../archived/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)的成员、mode 与 diagnostic。共享服务报告采用实时优先规则的语料活动状态,而 Web 投影会将其替换为确切 child Agent driver 的 `running` 或 `inactive` 状态。这两种活动状态都不是持久化结果,也不承诺继续执行会成功。 +UI 还必须保留[持久化目录](../architecture/2026-09-01-parent-owned-subagent-catalog.zh.md)的成员与 mode。Web 投影会添加确切 child Agent driver 的 `running` 或 `inactive` 状态。这两种活动状态都不是持久化结果,也不承诺继续执行会成功。 ## 决策 @@ -30,16 +30,16 @@ Figma 中的 [subagent 列表](https://www.figma.com/design/jRBBK7zBgcszdVWQ0Fh5 | 设计意图 | 已交付约定 | | --- | --- | -| 会话页头可打开紧凑的 child 列表。 | 触发器会汇总仅含 subagent 的完整后代谱系;树按服务顺序显示每个直接目录条目,包括已禁用的 diagnostic。 | +| 会话页头可打开紧凑的 child 列表。 | 触发器统计 parent catalog service 返回的健康直接条目。 | | 选择一行会复用对话 UI。 | 已寻址历史绝不激活 child;只有 parent 存活的可继续行才保留普通输入框。 | -| 嵌套 agent 会逐层展开。 | 每行携带一层 `hasChildren` 快照;展开时会立即预留已知直接后代行,随后仍只加载该行的直接目录,并保留其自身的 parent 地址。 | +| 嵌套 agent 会逐层展开。 | row 在自身 catalog 成功加载为空前保持可展开;展开时只加载该直接 catalog,并保留 row 的 parent 地址。 | | 条目显示 label、状态、token 用量与活跃耗时,同时避免侧边栏条目重复。 | mode 与 `running`/`inactive` 活动状态会同时以文字和视觉呈现;可选 title、持久化 token 用量与活跃轮次耗时来自列表保留的投影值。紧凑耗时从一天起省略更小的单位,而悬停和无障碍名称仍保留精确的整秒数。`SessionHeader.origin` 会移除重复的导航条目,但不授予任何能力。 | ## 产品约定 -只有当完整的直接目录空响应与会话摘要投影相符,二者均表明没有已知的 subagent 后代时,才不显示后代数量控件。普通会话会用斜杠分隔当前 title 和该数量控件。每一级 subagent 面包屑都将紧凑的 12px title 与固定显示的双向箭头组合成一个控件:当前面包屑使用主标签颜色和 500 字重,祖先则使用三级标签颜色和 400 字重。悬停组合控件 150ms 后会打开其直接 parent 目录;浮层菜单具有短暂的跨越宽限时间,ArrowDown 保留为键盘入口。点击祖先会取消待触发的悬停、关闭已打开的目录,并且只向上导航。每个直接 parent 目录都可切换 sibling,并会加粗其选中行;目录 label 优先于会话摘要 title,缺失的每个切换器目录都会自动刷新。只有当前 subagent 会追加自己的后代数量控件。过长的 title 会在固定箭头之前截断。数量触发器会统计经不间断的 `origin: 'subagent'` 谱系可达的每个已知会话摘要后代,在普通 fork 处停止,并在任一计入统计的后代处于 `running` 时显示活动仍在进行。由于普通侧边栏行会隐藏 origin 为 subagent 的会话,Workspace 浏览器会在每个可见的普通行上索引同一条不间断谱系:任何运行中的后代都会让该行显示蓝色活动指示器,并在悬停与无障碍文本中给出确切数量,同时不会把空闲 parent 描述为正在运行。普通 fork 会开启单独的聚合子树。待处理交互优先于 parent 的运行中状态;二者无论哪一项存在都会保持为主要状态,而后代活动则成为悬停与无障碍状态中的第二项。两者均不存在时,后代活动优先于未查看的完成提醒;最后一个运行中的后代停止后,该提醒会恢复。每个健康的直接目录行都携带读取时的 `hasChildren` 提示,该值只根据持久化 `origin: 'subagent'` 的直接谱系 header 派生;正常的健康与 diagnostic subagent 候选都会携带该标记,而普通 fork 不会。该预查不读取任何后代事件日志,展开后仍以描述符支撑的目录为权威依据。当摘要在该目录尚不存在时或在一次陈旧的空响应后确认已有后代时,该操作会保持可见,并且在打开它以刷新目录之前仅显示禁用的加载行;仅由摘要支撑的行绝不会提供导航能力。UI 会在交互前就省略已知叶子节点的展开控件;该提示不承诺 child 会一直是叶子。已展开的直接目录加载期间,已知谱系会为每个直接后代预留一行禁用的加载行,而不会递归获取后代目录。随后树会呈现可继续与 one-shot 行;one-shot 的可选 label 缺失时,回退到其会话 id。损坏、不受支持或不可用的候选仍以禁用的 diagnostic 行显示。 +直接 catalog 有子项或读取失败时显示 child 数量控件;空目录缺席、加载中或成功读取为空时均隐藏该控件。普通会话会用斜杠分隔当前 title 和该控件。每一级 subagent 面包屑都将紧凑的 12px title 与固定显示的双向箭头组合成一个控件:当前面包屑使用主标签颜色和 500 字重,祖先则使用三级标签颜色和 400 字重。悬停组合控件 150ms 后会打开其直接 parent 目录;浮层菜单具有短暂的跨越宽限时间,ArrowDown 保留为键盘入口。点击祖先会取消待触发的悬停、关闭已打开的目录,并且只向上导航。每个直接 parent 目录都可切换 sibling,并会加粗其选中行;目录 label 优先于可选的会话摘要 title,缺失的切换器目录在交互时加载。只有当前 subagent 会追加自己的直接 child 数量控件。过长的 title 会在固定箭头之前截断。触发器报告直接 catalog 的总数与运行数。普通侧边栏 row 隐藏 origin 为 subagent 的 Session,并从同一份已加载 catalog map 读取直接运行 child 数;Session summary 提供 activity,但绝不创建 membership。待处理交互优先于 parent 的运行中状态;二者无论哪一项存在都会保持为主要状态,而直接 child activity 则成为悬停与无障碍状态中的第二项。两者均不存在时,直接 child activity 优先于未查看的完成提醒;最后一个运行中的直接 child 停止后,该提醒会恢复。tree row 在 child catalog 缺席、加载中或失败时保持可展开,只有 catalog 成功加载为空后才成为已知叶子。加载时显示通用提示,不会从 summary 生成占位 row。tree 会呈现 continuable 与 one-shot row;one-shot 的可选 label 缺失时,回退到其 Session id。 -`running` 表示在 Host 采样边界,确切 child Agent driver 正在处理工作;`inactive` 表示该 driver 空闲或不存在。UI 不会把任一值解释为成功、失败、取消、完成状态或可恢复性。`subagent.list` 提供当前 driver 状态基线,`host/session-status` 会就地更新已知活动状态,请求内回放会阻止更早发起但尚未完成的列表响应覆盖较新的状态转换,`host/session-removed` 则会使已知行恢复为 `inactive`;重连时会读取新的基线。直接 subagent 的 `host/session-added` 帧会立即把任何已加载的 parent 行翻转为 `hasChildren: true`,并使这项正向提示不被更早发起但尚未完成的目录响应覆盖;受影响分支打开期间,成员、label、mode、diagnostic 与权威快照仍需要通过去抖动的 `subagent.list` 刷新来更新。消息投递时仍以提示词响应为权威依据。 +`running` 表示子 Agent driver 正在处理工作;`inactive` 表示该 driver 空闲或不存在。Session 列表基线与状态事件提供活动状态,移除事件将完成的子代理标为 inactive 并保留其展示 projection。共享的父 `subagentCatalog` projection 提供成员关系。初始读取与推送值进入同一个 projection store,较新序号优先。[projection 消费决策](../simplification/2026-09-08-web-subagent-catalog-projections.zh.md) 说明加载、重连与同步取舍。提示词响应仍是投递时的权威依据。 健康行会复用列表镜像中保留的标准会话投影。token 用量数值会汇总持久化日志中四个互不重叠的 `tokenUsage` 桶。`subagentTiming` 会在每个描述符处重置,使继承的 fork 种子不会计入 child 总量;它会累加已完成的 `turn/start` → `turn/end` 时段,并携带未结束轮次同一切面的 `active.since` 和 `active.through` 边界。该轮次保持未结束期间,现有会话事件会推进 `active.through`;菜单不会增加单独的计时器或日志读取,且仅在有已知后代处于运行状态时才推进其本地时钟。不足一天时,菜单会以整秒格式化时间;达到一天后的视觉值最多保留两个相邻单位,其中月份按近似 30 天计算,年份按近似 365 天计算,而悬停信息与无障碍名称会保留精确的天/小时/分钟/秒耗时。对 inactive 行,菜单以 `active.through` 为被中断未结束轮次的上界,因此陈旧投影绝不会借用更新的会话元数据,且重新打开菜单绝不会让已完成工作重新计时。这两项指标都不蕴含持久化结果语义。 @@ -51,17 +51,17 @@ one-shot 行始终会用文案替代输入框,说明执行记录为只读。 ## 宿主适配器与协议约定 -`@deepseek-ai/dsh-subagent` 拥有浏览器安全的生成 `subagent` Remote 命名空间: +Session Controller 负责 catalog 与 history read;`@deepseek-ai/dsh-subagent` 负责 continuation control: -- `subagent.list` 接受 `parentSessionId`,调用 `ctx.subagents.listChildren(parentSessionId, signal)`,返回完整有序的条目以及每个健康行的布尔 `hasChildren` 快照,把每个健康行的语料活动状态替换为其确切 Agent driver 是否正在运行,并说明当前能否从 `ctx.agents` 解析出确切 parent。 -- `subagent.history` 接受包含 mode 的完整地址与普通页参数。它对照直接目录校验 child 与 mode,通过 `ctx.sessionQuery.readSession()` 读取,再次检查直接谱系,并在不发布 agent 的情况下返回普通原始事件、渲染意图、分页与由 Host 计算的会话投影基线。 +- `session.projections` 接受 `sessionId`,返回一次 live-preferred Session observation 的完整 projection 基线,不激活 Agent。Client 将基线写入标准 projection store;subagent 消费者选择 `subagentCatalog`。父 Agent 可用性来自 Session 列表摘要与生命周期事件。 +- `session.page` 与 `session.follow` 接受包含 mode 的完整地址。它们在观察到的 cut 上校验 child header、直接 parent、descriptor identity 与 mode,随后在不发布 Agent 的情况下返回普通 raw event、pagination、live reconciliation 与 Host projection baseline。 - `subagent.prompt` 只接受 `mode: 'continuable'` 地址、`delivery: 'queue' | 'steer'` 与上传形态的 `PromptContentPart[]`;Host 在投递前把图片部分准入并持久化为持久引用([图片投递](../../archived/bug-fix/2026-08-27-steer-followup-image-delivery.md))。它要求确切的存活 parent,重新校验目录地址,使用 continuation manager 共享的人类投递准入,并返回已接受的 `MessageId`。 -网关会将 parent 缺失、目录条目缺失或为 diagnostic、child 不可恢复或未授权、请求取消、图片准入或图片能力拒绝(`subagent/attachment-invalid`)以及继续执行准入暂时不可用等失败映射为类型化 RPC 错误。它不会公开描述符或提供方细节。list/prompt 竞态属于正常情况:权威依据是提示词操作的结果,而不是更早的可用性或活动快照。 +网关会将 parent 或目录条目缺失、child 不可恢复或未授权、请求取消、图片准入或图片能力拒绝(`subagent/attachment-invalid`)以及继续执行准入暂时不可用等失败映射为类型化 RPC 错误。它不会公开描述符或提供方细节。list/prompt 竞态属于正常情况:权威依据是提示词操作的结果,而不是更早的可用性或活动快照。 -查看持久化历史本身不会创建 mux 订阅。当后续消息物化冷态 child Activation 时,现有 Host 与 mux 流会发布其生命周期与事件。重新连接时,系统通过 `subagent.history` 重建已寻址窗口。 +查看持久化历史本身不会创建 Agent。当后续消息物化冷态 child Activation 时,现有 Host 与 Session journal stream 会发布其生命周期与事件。重新连接时,系统通过 `session.follow` 重建已寻址窗口。 -普通 `session.history` 路由对于普通会话和 subagent 会话同样只执行观察,但它既不携带目录地址,也不授予继续执行权限。每条需要 Agent 的普通路由都会在恢复冷会话前经过共享所有权栅栏;`session.cancel` 保留该栅栏。`session.updateQueue` 只有一个目标本地例外:目标是在线 child,且其当前 projection identity 为 continuable 并来自自身的非 seed suffix;one-shot、缺失、未知、损坏、仅含 seed identity 或冷 child 仍受栅栏阻挡。 +普通 `session.page` 与 `session.follow` 地址对于普通会话和 subagent 会话同样只执行观察,但它既不携带目录地址,也不授予继续执行权限。每条需要 Agent 的普通路由都会在恢复冷会话前经过共享所有权栅栏;`session.cancel` 保留该栅栏。`session.updateQueue` 只有一个目标本地例外:目标是在线 child,且其当前 projection identity 为 continuable 并来自自身的非 seed suffix;one-shot、缺失、未知、损坏、仅含 seed identity 或冷 child 仍受栅栏阻挡。 适配器仍位于生成的 Remote 命名空间之后;`dsh-host-webserver` 仍作为载体。浏览器代码通过现有连接包导入约定,绝不直接访问宿主 `ctx`,从而保持[已归档的 GUI RPC 分层决策](../../archived/architecture/2026-07-19-gui-layering-and-rpc-protocol.md)。 @@ -71,7 +71,7 @@ one-shot 行始终会用文案替代输入框,说明执行记录为只读。 目录通过标准 `useSessions` 快照传递。组件局部状态负责菜单可见性、已展开分支、焦点与悬停计时器。`ui-conversation` 为当前普通 title 和每一级 subagent 面包屑声明谱系 slot,传入纯数据形式的面包屑身份与显示文本,并为祖先传入向上导航回调;普通 title 由 render site 保留为回退。`@deepseek-ai/dsh-client-ui-subagent` 以直接 parent 目录导航占用每个谱系 slot,并根据普通 owner props 选择按原因区分的只读编辑器。组件只接收派生 props 与回调,绝不接收 `ctx`。 -每个进程内 subagent child 都会在发布前写入 `SessionHeader.origin: 'subagent'`。会话列表摘要与增量 Host 帧会投影该字段,使分组和扁平侧边栏省略重复的 child 行,同时保留普通 fork。同一条现有的 `host/session-added` 帧还会把已加载的直接 parent 行标记为可展开,而无需引入目录事件流。描述符 mode 与目录校验仍然是导航、继续执行和授权的权威依据。 +每个进程内 subagent child 都会在发布前写入 `SessionHeader.origin: 'subagent'`。会话列表摘要与增量 Host 帧会投影该字段,使分组和扁平侧边栏省略重复的 child 行,同时保留普通 fork。parent catalog projection 拥有 membership 与 tree structure 权威;descriptor identity 与精确 parent check 拥有 addressed history 与 continuation validation 权威。 该包现有的 `@label` source 仍然是独立的面向模型纯文本输入。它不会将 label 解析为地址,也不会获得继续执行语义。 @@ -95,23 +95,23 @@ one-shot 行始终会用文案替代输入框,说明执行记录为只读。 **根据谱系推断 mode 或侧边栏过滤。** 不予采纳,因为普通 fork 共享 `parentSession`。由描述符支撑的目录负责提供 mode;单独的 `origin` 标记只是低成本的导航分类器。 -**构建预先加载的递归树或专用目录流。** 就当前规模而言不予采纳。仅用于页头的一层可展开性预查会在不读取后代事件的情况下保证点击前的稳定性,而展开仍是懒加载式权威直接 child 读取;现有 Host 帧会更新活动状态、恢复 parent 行的可展开性,并触发有界的成员刷新。 +**构建预先加载的递归树或专用目录流。** 就当前规模而言不予采纳。展开控件按需加载缺失目录,现有 control 帧传递完整 projection 更新。 **让 child 在 parent 消失后仍能独立交互。** 不予采纳,因为独立生命周期与用户所有权需要 side session 语义。 ## 测试 -- 宿主协议测试固定 schema(包括必需的布尔可展开性)、id 回显、mode 校验、非激活式历史、确切 parent 强制要求、FIFO 准入回执、取消与脱敏后的失败映射。 +- 宿主协议测试固定健康的直接 catalog schema、id 回显、mode 校验、非激活式历史、确切 parent 强制要求、FIFO 准入回执、取消与脱敏后的失败映射。 - 通用 Host 测试固定在不发布 Agent 的情况下读取已附加与冷态历史及执行 fork、冷态投影归并、按描述符/origin/运行时 owner 拒绝、拒绝显式 id 接纳,以及直接队列控制栅栏。 -- 客户端对象测试固定已保留与已恢复的地址、one-shot 只读与取消拒绝、历史路由、可继续提示词与中断路由、屏蔽绑定到 agent 的模型控件、实时活动状态翻转(包括在途响应回放与 detach 回退)、subagent parent 可展开性翻转与成员刷新。 -- jsdom 测试固定普通 title 分隔符、逐级合并的 subagent title 切换热区、嵌套 title 的 12px 字号、当前与祖先样式、选中行字重、目录 label 优先级、悬停延迟、向上点击抑制、保留箭头的截断、后代聚合计数与活动状态、侧边栏活动在嵌套谱系中的传播与普通 fork 边界、行状态优先级、token 用量总计、精确到秒的运行中耗时与冻结后 inactive 耗时、采用自适应单位的长耗时及其精确无障碍文本、目录缺失或为陈旧空目录时由摘要支撑的根操作、已知加载行的形态、混合 mode 行、点击前的叶子展开控件、diagnostic、后代懒加载展开、直接 parent 地址、键盘行为与两种只读原因。 -- 无密钥的组装 Web 快照包含一个具有持久化 token 用量的 inactive 可继续 child、一个具有确定性长耗时的 inactive one-shot sibling 和一个持久化 grandchild;它会固定触发器在一次陈旧的空目录响应后仍显示三个后代,并固定 token 用量与计时行、自适应长耗时呈现及聚合 `running` 状态转换,在不激活的情况下展开、打开持久化历史、准入一条用户 FIFO 后续消息、归并 child mux 事件,并证明 one-shot 历史仍然只读。另一个独立的组装场景会在 LLM seam 处保持一个真实的 child Agent 轮次进行中,同时固定页头和可见空闲 owner 行中的聚合运行状态,随后在 teardown 期间取消该轮次。 +- 客户端对象测试固定已保留与已恢复的地址、one-shot 只读与取消拒绝、历史路由、可继续提示词与中断路由、屏蔽绑定到 agent 的模型控件、来自 Session 摘要与 Agent 销毁的实时活动状态、权威 catalog membership 与成员刷新。 +- jsdom 测试固定普通 title 分隔符、逐级合并的 subagent title 切换热区、嵌套 title 的 12px 字号、当前与祖先样式、选中行字重、目录 label 优先级、悬停延迟、向上点击抑制、保留箭头的截断、catalog 直接计数与 activity、侧边栏直接 child activity、行状态优先级、token 用量总计、精确到秒的运行中耗时与冻结后 inactive 耗时、采用自适应单位的长耗时及其精确无障碍文本、通用加载提示、混合 mode row、ready-empty 叶子判定、descendant 懒加载展开、直接 parent 地址、键盘行为与两种只读原因。 +- 无密钥的组装 Web 快照包含一个具有持久化 token 用量的 inactive 可继续 child、一个具有确定性长耗时的 inactive one-shot sibling 和一个持久化 grandchild;它会固定直接 catalog 数量、token 用量与计时行、自适应长耗时呈现及嵌套懒加载,在不激活的情况下打开持久化历史、准入一条用户 FIFO 后续消息、归并 child mux 事件,并证明 one-shot 历史仍然只读。另一个独立的组装场景会在 LLM seam 处保持一个真实的 child Agent 轮次进行中,同时固定页头和可见空闲 owner row 中的直接运行状态,随后在 teardown 期间取消该轮次。 - 导航测试固定仅含 subagent 的面包屑导航、从 subagent 创建 fork 时的 Workspace 归属,以及 `origin: 'subagent'` 侧边栏过滤,同时不隐藏普通 fork。 ## 后果 -- 目录读取可能重新扫描持久化谱系与每个直接候选的描述符日志,但可展开性只复用该追踪中已有的后代 header;Web 活动基线会为每个健康行增加一次 Agent 注册表查找,随后使用现有实时帧,而 token 用量与耗时会复用投影基线和推送,无需按行读取日志,成员刷新则保持去抖动和单次并发。 -- parent 可用性、child 活动状态与 `hasChildren` 都是快照。列出之后,发布、dispose(资源释放)、其他发送方或其他进程都可能抢先改变状态;类型化提示词失败仍属预期行为。 +- catalog read 只 fold 所选 parent 的 catalog projection。Web activity 来自 Session 摘要;token 用量与耗时复用 projection baseline 和 push,无需按 row 读取日志,投影读取保持 single-flight。 +- parent 可用性与 child activity 都是快照。列出之后,发布、dispose(资源释放)、其他发送方或其他进程都可能抢先改变状态;类型化提示词失败仍属预期行为。 - child 可能在历史获取与 mux 订阅之间发布,因此现有序号归并也涵盖从冷态转为存活的已寻址路径。 - 持久化 origin 会为 child header 与列表投影添加一个有意保持弱约束的产品分类字段;它不能变成授权捷径。 - 除对正在运行的可继续 child 的当前轮次 Stop([中断约定](2026-08-06-continuable-subagent-interrupt.zh.md))之外,UI 不提供 child 取消、持久化结果、Activation 身份、删除或可独立交互的离线 mode,其文案不得暗示这些能力已经存在。活跃轮次耗时度量的是已记录工作,而非 Activation 驻留时间。 diff --git a/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.i18n.yaml b/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.i18n.yaml new file mode 100644 index 0000000000..d589324465 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 .agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.md +2026-09-08-web-subagent-catalog-projections.md: 766d33e581bcac53844b0836f23cda615858fc27 +2026-09-08-web-subagent-catalog-projections.zh.md: ef14db2530ed10a7aa34408c5a6fada6f0a28858 diff --git a/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.md b/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.md new file mode 100644 index 0000000000..766d33e581 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.md @@ -0,0 +1,31 @@ +# Agent Note: Web subagent catalogs consume shared projections + +Status: implemented + +English | [中文](2026-09-08-web-subagent-catalog-projections.zh.md) + +## Problem + +The parent catalog projection already publishes complete membership through the Session control stream. A separate catalog-change event, repeated RPC reads, and a second membership cache duplicate that delivery and require coordination between responses and later events. Historical Sessions still need initial loading when their projection is absent, and parent Agent availability remains independent of durable membership. + +## Decision + +The Client retains catalog membership only in its standard per-Session projection store. Initial `session.projections` reads return a complete projection baseline from one live-preferred Session observation. The endpoint accepts any Session id and has no catalog-specific dependency or validation. The same observation supplies the values and sequence cursor. Initial baselines and live control frames use the store's existing sequence ordering, so an older response cannot replace a newer value. The endpoint does not activate an Agent or sample child activity. Opening a conversation uses its follow baseline without scheduling a second projection read; unopened catalog branches still use explicit reads. + +Feature consumers select `subagentCatalog` from `projectionsBySession` and derive row activity from Session-list baselines and status events. Session summaries report Agent availability separately; Agent creation and disposal republish the existing summary event. Completed subagents retain their summaries and display projections after removal. Generic projection reads own loading and error state; parent availability comes from the Session list independently of membership. Opening a loaded catalog reuses its data; an initial failure can be retried. Reconnect cancels previous reads and starts fresh reads for requested catalogs. Session removal cancels its pending read and marks parent availability false; projection responses cannot change Agent availability. + +The [parent-catalog decision](../architecture/2026-09-01-parent-owned-subagent-catalog.md) owns durable creation facts and ordering. This decision supersedes the dedicated membership-refresh mechanism in [Web subagent conversations](../feature/2026-07-27-web-subagent-conversations.md); that note remains active for navigation, control, and presentation decisions. + +Host summaries replace running and availability state; local create/fork placeholders only enrich missing metadata. Sharing overwrite behavior would let a late local response erase a newer Host state and generate a false completion reminder. Removed ordinary Sessions retain stores only for nonempty child catalogs; empty catalogs carry no navigation that needs to survive removal. Breadcrumb selectors derive addresses from the Session-list snapshot so their subscriptions cover every dependency. + +## Alternatives considered + +**Keep notification-driven reads.** Rejected because the shared stream already delivers the changed value. Menu subscriptions, response-local activity replay, and trailing membership reads add no required delivery capability. + +**Remove the initial-read endpoint.** Deferred. Session-list projections are cache hints and may be absent; following a conversation also transfers history and retains observation state. A lightweight read preserves historical catalog access without establishing a conversation follow stream. Parent availability is a live delivery hint, not a durable projection fact. + +## Consequences + +Membership changes use the existing control stream without extra catalog notifications or reads. Whole-value projection publication still costs O(D) for D children; this change does not introduce delta transport. Initial reads return the observation's complete projection baseline, including values beyond the catalog, so they reuse standard baseline semantics at the cost of that additional initial payload. Session sequence ordering does not establish identity across reused Session ids. + +Manager tests cover pushed membership, stale initial responses, lazy loading, status composition, retained completion metadata, retry, removal of empty catalogs, late create/fork responses, and reconnect cancellation. Host tests exercise the shared control stream and cold observations. The persisted-subagent Web scenario covers nested historical navigation and continuation through the shipped application. diff --git a/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.zh.md b/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.zh.md new file mode 100644 index 0000000000..ef14db2530 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.zh.md @@ -0,0 +1,31 @@ +# Agent Note:Web 子代理目录消费共享 projection + +Status: implemented + +[English](2026-09-08-web-subagent-catalog-projections.md) | 中文 + +## 问题 + +父目录 projection 已通过 Session control stream 发布完整成员关系。独立的目录变化事件、重复 RPC 读取与第二份成员缓存重复传递同一数据,并要求协调响应与后续事件。历史 Session 的 projection 缺席时仍需初始加载,父 Agent 可用性也独立于持久成员关系。 + +## 决策 + +Client 仅在标准逐 Session projection store 中保留目录成员关系。初始 `session.projections` 读取通过一次 live-preferred Session observation 返回完整 projection 基线。endpoint 接受任意 Session id,不含目录专用依赖或校验。值与序号游标来自同一次 observation。初始基线与实时 control 帧使用 store 既有的序号排序,因此旧响应不能替换新值。该 endpoint 不激活 Agent,也不采样子代理活动状态。打开会话时使用其 follow baseline,不再额外调度一次投影读取;未打开的目录分支仍使用显式读取。 + +功能消费者从 `projectionsBySession` 中选择 `subagentCatalog`,并从 Session 列表基线与状态事件派生行活动状态。Session 摘要单独报告 Agent 可用性;Agent 创建与销毁重新发布已有摘要事件。完成的子代理在移除后保留摘要与展示 projection。通用 projection 读取拥有加载与错误状态;父 Agent 可用性来自 Session 列表,独立于成员关系。打开已加载目录会复用数据,初始失败可以重试。重连取消此前的读取,并为已请求的目录重新读取。Session 移除会取消其待完成读取并将父 Agent 可用性标为 false;projection 响应不能改变 Agent 可用性。 + +[父目录决策](../architecture/2026-09-01-parent-owned-subagent-catalog.zh.md) 说明持久创建事实与顺序。本决策取代 [Web 子代理会话](../feature/2026-07-27-web-subagent-conversations.zh.md) 中的专用成员刷新机制;该记录继续保留导航、控制与展示决策。 + +Host 摘要替换运行状态与可用性;本地 create/fork 占位摘要只补充缺失的元数据。若共用覆盖行为,晚到的本地响应会抹去较新的 Host 状态,并生成虚假的完成提醒。普通 Session 移除后,仅为非空子目录保留 store;空目录没有需要保留的导航关系。面包屑 selector 从 Session 列表快照推导地址,使订阅涵盖全部依赖。 + +## 考虑过的替代方案 + +**保留通知驱动的读取。** 不采用,因为共享流已经传递变化后的值。菜单订阅、请求内活动状态回放与尾随成员读取没有提供额外的必要传递能力。 + +**删除初始读取 endpoint。** 暂缓。Session 列表 projection 是可能缺席的缓存提示;跟随会话还会传输历史并保留 observation 状态。轻量读取保留历史目录访问能力,无需建立会话跟随流。父 Agent 可用性是实时投递提示,而非持久 projection 事实。 + +## 影响 + +成员变化使用既有 control stream,无需额外目录通知或读取。对 D 个子级发布完整 projection 值仍需 O(D);本变更不引入增量传输。初始读取返回 observation 的完整 projection 基线,其中包括目录以外的值,以额外初始载荷换取标准基线语义的复用。Session 序号排序不确立复用 Session id 之间的身份关系。 + +Manager 测试覆盖成员推送、过时初始响应、按需加载、状态组合、完成元数据保留、重试、空目录移除、晚到的 create/fork 响应与重连取消。Host 测试覆盖共享 control stream 与冷 observation。持久化子代理 Web 场景通过发布应用验证嵌套历史导航与续传。 diff --git a/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.i18n.yaml b/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.i18n.yaml new file mode 100644 index 0000000000..a6c46b0bbd --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 .agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.md +2026-09-16-subagent-catalog-membership-only.md: d1d0956380ef2b2ffd610e5a3d07c7988991e42e +2026-09-16-subagent-catalog-membership-only.zh.md: 4225a331a0b3c483349760cd805416a94c4b915a diff --git a/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.md b/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.md new file mode 100644 index 0000000000..d1d0956380 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.md @@ -0,0 +1,25 @@ +# Agent Note: Keep model configuration outside subagent catalogs + +Status: implemented + +English | [中文](2026-09-16-subagent-catalog-membership-only.zh.md) + +## Problem + +The parent catalog serves direct-child discovery. Recording a child's creation-time LLM provider and model would preserve immutable configuration without opening child histories, but discovery and navigation consumers do not read those values. Creation configuration also does not establish which model served a request. + +## Decision + +The catalog event and projection retain child identity, creation time, mode, and label. `establishCatalogChild(parent, childHeader, descriptor)` receives only the values needed to publish membership. Child composition and request history retain their own model configuration; catalog loading adds no child observation or model lookup. + +This decision supersedes only the creation-model metadata choice in the [parent-catalog decision](../architecture/2026-09-01-parent-owned-subagent-catalog.md). That note remains active for successful publication, event order, fork isolation, and projection ownership. The unreleased optional metadata declaration and its dedicated expectations are absent; existing historical Session generations from the migration base remain intact. + +## Alternatives considered + +**Keep optional creation metadata for future display.** Optional fields still require durable schemas, cache invalidation, producers, and replay expectations. A consumer requiring the immutable creation route could justify those costs; current consumers do not require it. + +**Read child histories during discovery.** This adds work proportional to child histories without helping membership. A display that needs the model used by a request can observe the child's existing `modelSelection` projection independently. + +## Consequences + +The catalog provides no historical creation-route record. Reintroducing one requires a consumer whose requirement cannot be met by the existing child composition or request projections. Initial reads, live updates, reconnect, and authorization keep their existing owners. Catalog and creation tests, recorded-session replay, and both SDK expectations verify that membership still publishes without the extra metadata. diff --git a/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.zh.md b/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.zh.md new file mode 100644 index 0000000000..4225a331a0 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-09-16-subagent-catalog-membership-only.zh.md @@ -0,0 +1,25 @@ +# Agent Note: 将模型配置保留在子代理目录之外 + +Status: implemented + +[English](2026-09-16-subagent-catalog-membership-only.md) | 中文 + +## 问题 + +父目录用于发现直接子级。记录子级创建时的 LLM provider 和 model,可以在不打开子级历史的情况下保留不可变配置,但发现与导航的消费者不读取这些值。创建配置也不能确定实际处理某次请求的模型。 + +## 决策 + +目录事件与投影保留子级身份、创建时间、模式和标签。`establishCatalogChild(parent, childHeader, descriptor)` 只接收发布成员关系所需的值。子级组合与请求历史各自保留模型配置;目录加载不增加子级观察或模型查询。 + +本决策仅替代[父目录决策](../architecture/2026-09-01-parent-owned-subagent-catalog.zh.md)中的创建模型元数据选择。该记录继续说明成功发布、事件顺序、fork 隔离和投影所有权。未发布的可选元数据声明及其专属预期输出不予保留;迁移基线中已有的历史 Session 世代保持完整。 + +## 考虑过的替代方案 + +**保留可选创建元数据,供未来展示使用。** 可选字段仍需要持久化 schema、缓存失效、写入方和回放预期输出。需要不可变创建路由的消费者可以证明这些成本合理,但当前消费者没有此需求。 + +**在发现过程中读取子级历史。** 这会增加与子级历史规模相关的工作,却不帮助确定成员关系。需要展示请求实际使用模型的功能,可以独立观察子级已有的 `modelSelection` 投影。 + +## 后果 + +目录不提供历史创建路由记录。重新引入此记录,需要存在无法通过已有子级组合或请求投影满足需求的消费者。初始读取、实时更新、重连和授权继续由现有模块负责。目录与创建测试、已记录 Session 回放以及两套 SDK 的预期输出验证了成员关系仍可在没有额外元数据的情况下发布。 diff --git a/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.i18n.yaml b/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.i18n.yaml index f63c4924fd..aeaed20365 100644 --- a/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.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 .agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.md -2026-09-06-backend-continuation-performance.md: a30c7a47a93f0a8827d1cb4d0857aeabe9dd2fee -2026-09-06-backend-continuation-performance.zh.md: c703ea70e496d279e5965295d308a2919ed2b445 +2026-09-06-backend-continuation-performance.md: a2423a404e23f6a4ccb6a4fb177ec6842b7bf584 +2026-09-06-backend-continuation-performance.zh.md: 942cfd37528d121bf482c48c5d75dd1f2de30887 diff --git a/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.md b/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.md index a30c7a47a9..a2423a404e 100644 --- a/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.md +++ b/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.md @@ -19,13 +19,13 @@ The shared history has 800 completed two-step turns, four tool calls per turn, a | Request history | After unmeasured cold resume, deliver 40 sequential text-only turns over the tool-heavy history, then flush | Idle Agent with all 40 model requests completed; reports turn and final-flush time separately | | Tool continuation | Cold resume, 20 sequential turns with eight parallel-safe synthetic tool calls and a final reply per turn, then flush | Idle Agent with 40 model requests and 160 completed tool executions; reports resume, turns, and final flush separately | | Shipped SDK workflow | Launch built dsh with the sdk-minimal profile, deliver 100 sequential turns with eight real file-view calls per turn, then close the SDK | SDK receives 200 assistant messages and 800 successful file results; includes Loader boot, stdio JSON-RPC, persistence, and shutdown | -| Child catalog | List 16 inactive seeded fork children twice through the real subagent and Session query services | Two complete healthy catalogs with observations released; each child inherits 80 tool-heavy turns and owns its descriptor after the exact fork cut | +| Child catalog | Observe one cold parent catalog twice through the real Session query and subagent services | Two complete 16-child catalogs with parent observations released; each stored fork child inherits 80 tool-heavy turns, and discovery reads only the parent facts | The tool execution pipeline, request preparation, Session projections required by those services, persistence, and catalog observations remain production code. Only the model adapter and bounded tool body are synthetic. The adapter retains a request counter, not request objects, so the fixture cannot manufacture a growing retention cost. Sequential input means each idle interval belongs to the one request delivered by this worker; it does not generalize idle to a per-message completion API under concurrent input. The SDK fixture explicitly inserts `fs-local` and `str_replace_editor` through its profile patch. This preserves the calibrated file-view workload independently of the [minimal profile's shell-only defaults](../simplification/2026-09-03-minimal-profiles-persistent-shell-only.md). File reads, timing endpoints, and budgets remain the same. -Five samples report raw wall time, CPU user/system time, peak RSS, endpoint counts, and the minimum, median, and maximum total wall time. Each aggregate report also records CPU models, available parallelism, platform, architecture, and Node/V8 versions after the timed workers exit. Budgets enforce the unrounded median. Continuation additionally measures retained heap against an initialized Host: two explicit GCs separated by an event-loop yield precede and follow the timed operation, while the idle Agent remains reachable. The measured delta therefore includes the resident historical Session and live additions, not just newly appended turns. GC and teardown are outside timing; flush is inside. Request-history retention starts after resume and is diagnostic only. Catalog peak RSS is diagnostic; no retained-heap budget claims to measure already-released child observations. +Five samples report raw wall time, CPU user/system time, peak RSS, endpoint counts, and the minimum, median, and maximum total wall time. Each aggregate report also records CPU models, available parallelism, platform, architecture, and Node/V8 versions after the timed workers exit. Budgets enforce the unrounded median. Continuation additionally measures retained heap against an initialized Host: two explicit GCs separated by an event-loop yield precede and follow the timed operation, while the idle Agent remains reachable. The measured delta therefore includes the resident historical Session and live additions, not just newly appended turns. GC and teardown are outside timing; flush is inside. Request-history retention starts after resume and is diagnostic only. Catalog peak RSS is diagnostic; no retained-heap budget claims to measure already-released parent observations. The parent bounds every child to 60 seconds, checks timeout, signal, exit, and report independently, awaits process close, and removes private roots after failures. Context and Agent teardown run in finally blocks. Seed processes cannot warm the measured process's caches. Filesystem caches are not forcibly evicted: cold means a fresh process, not cold physical storage. @@ -41,7 +41,7 @@ The implementation reference is the PR #3537 merge on Apple M4 Pro, macOS arm64, Continuation retains approximately 22.295 MiB; its source expectation is 23 MiB and its budget is 28.75 MiB. SDK time expectations use the existing [calibration helper](../../../../benchmarks/support/calibration.ts): 2× shared CI time scale and 1.25× variance headroom. Request history uses the direct hosted expectation in the [request-freeze calibration](../simplification/2026-09-06-agent-request-freeze-evidence.md), without the 2× scale. Memory uses only 1.25× headroom. The scale is inherited from the existing lane's calibration, not a new Linux measurement of these cases; CI evidence remains necessary when runner characteristics change. Baseline budgets protect the measured implementation; tighter budgets belong with a measured behavior-preserving fix. -A separate plain-Node request-history CPU profile attributes 132.876 ms of sampled self time to deepFreeze called by buildRequest during a 211.300 ms operation. This identifies repeated traversal of already-frozen history as a focused investigation target, not a proven optimization result. Catalog first/repeat timings remain separate because a second listing still reads body-bearing seeded children after observations are released. +A separate plain-Node request-history CPU profile attributes 132.876 ms of sampled self time to deepFreeze called by buildRequest during a 211.300 ms operation. This identifies repeated traversal of already-frozen history as a focused investigation target, not a proven optimization result. Catalog first/repeat timings separately report the first and second parent-catalog observations. The shipped SDK variant completes 100 turns, 200 requests, and 800 real file reads. Its five-sample smoke totals are 1,521.773, 1,463.465, 1,689.701, 1,365.485, and 1,417.106 ms (median 1,463.465 ms); a full-suite repeat reports 1,596.183, 1,784.536, 2,120.082, 1,405.365, and 1,355.894 ms (median 1,596.183 ms). Its 1,700 ms reference expectation yields a 4,250 ms CI budget. The repeat also slows the unchanged service cases, so it is validation under variable host load rather than evidence to relax their exclusive calibration. The SDK process receives an allowlisted environment and private home/workspace. A 40-second deadline starts SDK shutdown; every path awaits the same memoized close promise before the outer worker’s 60-second deadline. Profile timing includes boot, all turns, and shutdown, reported separately; no parent-process CPU or heap metric is presented as server memory. The adapter does not serialize requests for an external model provider. @@ -59,7 +59,7 @@ Baseline request history uses a 600 ms expected CI duration with 1.25× headroom **Measure only deriveMessages.** Rejected: its incremental cache does not include complete request freezing, adapter dispatch, live append, or persistence. Actual sequential requests protect the cost the Agent pays per step. -**Use only unseeded children with warm projection-cache rows.** Rejected: that path bypasses body observations and misses the exact inherited-cut requirement of fork children. The catalog intentionally omits the optional projection cache and reports the seeded fallback path; it does not characterize cache-hit discovery. +**Use only unseeded children with warm projection-cache rows.** Rejected: that path bypasses body observations and misses the exact inherited-cut requirement of fork children. The original calibration omits the optional projection cache and reports the seeded fallback path. Current catalog reads observe durable parent facts; the recorded child-body timings describe the calibration implementation. **Apply an optimization and its desired budget together with the first measurements.** Rejected: a baseline-only layer remains independently mergeable and records the current workload before attribution or implementation changes. Source constants cannot be overridden by environment variables. diff --git a/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.zh.md b/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.zh.md index c703ea70e4..942cfd3752 100644 --- a/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.zh.md +++ b/.agents/notes/implemented/testing/2026-09-06-backend-continuation-performance.zh.md @@ -19,13 +19,13 @@ Status: implemented | 请求历史 | 在不计时的冷恢复后,向工具密集历史顺序提交 40 个纯文本轮次,然后 flush | 空闲 Agent,已完成全部 40 次模型请求;分别报告轮次和最终 flush 时间 | | 工具续聊 | 冷恢复,顺序执行 20 个轮次,每轮八次可安全并行的合成工具调用和一条最终回复,然后 flush | 空闲 Agent,已完成 40 次模型请求和 160 次工具执行;分别报告恢复、轮次和最终 flush 时间 | | 已发布 SDK 工作流 | 使用 sdk-minimal profile 启动已构建 dsh,顺序提交 100 个轮次,每轮八次真实文件查看调用,然后关闭 SDK | SDK 收到 200 条助手消息和 800 个成功文件结果;包含 Loader 启动、stdio JSON-RPC、持久化和关闭 | -| 子会话目录 | 通过真实 subagent 和 Session 查询服务,两次列出 16 个非活动、带种子的 fork 子会话 | 两份完整健康目录,观察已释放;每个子会话继承 80 个工具密集轮次,并在精确 fork 切点后拥有自己的描述符 | +| 子会话目录 | 通过真实 Session 查询和 subagent 服务,两次观察一个冷 parent 目录 | 两份完整的 16 子级目录,parent 观察已释放;每个存储的 fork 子级继承 80 个工具密集轮次,发现只读取 parent fact | 工具执行管线、请求准备、这些服务所需的 Session 投影、持久化和目录观察均保留生产代码。只有模型适配器和有界工具体是合成的。适配器只保留请求计数,不保留请求对象,因此 fixture(测试前置数据)不会制造不断增长的保留成本。顺序输入使每个空闲区间对应此 worker 提交的唯一请求;这不代表并发输入时可以把空闲状态推广为逐消息完成 API。 SDK fixture 通过 profile patch 显式插入 `fs-local` 和 `str_replace_editor`。这使经校准的文件查看负载不依赖[极简 profile 只提供 shell 的默认组合](../simplification/2026-09-03-minimal-profiles-persistent-shell-only.zh.md)。文件读取、计时终点和预算保持不变。 -五个样本报告原始壁钟时间、CPU 用户态/内核态时间、峰值 RSS、终点计数及总壁钟时间的最小值、中位数和最大值。每份汇总报告还在计时 worker 退出后记录 CPU 型号、可用并行度、平台、架构以及 Node/V8 版本。预算约束未经舍入的中位数。续聊还相对已初始化 Host 测量保留堆内存:计时操作前后各执行两次显式 GC,中间让出一次事件循环,空闲 Agent 始终可达。因此该增量包含常驻历史 Session 和实时追加,而不只是新轮次。GC 与资源释放不计时;flush 计时。请求历史的内存基线从恢复后开始,只作诊断。目录峰值 RSS 仅作诊断;没有保留堆预算声称衡量已经释放的子会话观察。 +五个样本报告原始壁钟时间、CPU 用户态/内核态时间、峰值 RSS、终点计数及总壁钟时间的最小值、中位数和最大值。每份汇总报告还在计时 worker 退出后记录 CPU 型号、可用并行度、平台、架构以及 Node/V8 版本。预算约束未经舍入的中位数。续聊还相对已初始化 Host 测量保留堆内存:计时操作前后各执行两次显式 GC,中间让出一次事件循环,空闲 Agent 始终可达。因此该增量包含常驻历史 Session 和实时追加,而不只是新轮次。GC 与资源释放不计时;flush 计时。请求历史的内存基线从恢复后开始,只作诊断。目录峰值 RSS 仅作诊断;没有保留堆预算声称衡量已经释放的父会话观察。 父进程为每个子进程设置 60 秒上限,独立检查超时、信号、退出状态和报告,等待进程关闭,并在失败后删除私有根目录。Context 和 Agent 在 finally 中释放。播种进程无法预热被测进程的缓存。不强制清除文件系统缓存:冷指新进程,不指冷物理存储。 @@ -41,7 +41,7 @@ SDK fixture 通过 profile patch 显式插入 `fs-local` 和 `str_replace_editor 续聊保留约 22.295 MiB;源码期望值为 23 MiB,预算为 28.75 MiB。SDK 时间期望值使用现有[校准辅助函数](../../../../benchmarks/support/calibration.ts):2× 共享 CI 时间比例和 1.25× 波动余量。请求历史使用[请求冻结校准](../simplification/2026-09-06-agent-request-freeze-evidence.zh.md)中的直接托管期望值,不乘以 2× 比例。内存只使用 1.25× 余量。比例继承现有通道的校准,并非这些用例的新 Linux 实测值;runner 特征变化时仍需 CI 证据。基线预算保护实测实现;更紧预算属于有测量依据且保持行为的修复。 -独立的纯 Node 请求历史 CPU profile 在一次 211.300 ms 操作中,将 132.876 ms 采样自身时间归因于 buildRequest 调用的 deepFreeze。这把重复遍历已冻结历史定位为聚焦调查目标,不是已证实的优化结果。目录首次/重复时间分别保留,因为观察释放后第二次列举仍读取带种子子会话的正文。 +独立的纯 Node 请求历史 CPU profile 在一次 211.300 ms 操作中,将 132.876 ms 采样自身时间归因于 buildRequest 调用的 deepFreeze。这把重复遍历已冻结历史定位为聚焦调查目标,不是已证实的优化结果。目录首次/重复时间分别报告第一次和第二次 parent 目录观察。 已发布 SDK 变体完成 100 个轮次、200 次请求和 800 次真实文件读取。五样本 smoke 总时间为 1,521.773、1,463.465、1,689.701、1,365.485 和 1,417.106 ms(中位数 1,463.465 ms);完整套件重复运行报告 1,596.183、1,784.536、2,120.082、1,405.365 和 1,355.894 ms(中位数 1,596.183 ms)。1,700 ms 参考期望对应 4,250 ms CI 预算。重复运行中未改变的服务用例也变慢,因此这是可变主机负载下的验证,不是放宽其独占校准预算的依据。SDK 进程使用白名单环境和私有主目录/工作区。40 秒截止时间启动 SDK 关闭;所有路径等待同一个记忆化 close Promise,并早于外层 worker 的 60 秒截止时间。Profile 时间包含启动、全部轮次和关闭,分别报告;不把父进程 CPU 或堆指标当作服务端内存。适配器不为外部模型服务商序列化请求。 @@ -59,7 +59,7 @@ SDK fixture 通过 profile patch 显式插入 `fs-local` 和 `str_replace_editor **只测 deriveMessages。** 拒绝:它的增量缓存不包含完整请求冻结、适配器分发、实时追加或持久化。实际顺序请求保护 Agent 每一步支付的成本。 -**只使用投影缓存行已预热的无种子子会话。** 拒绝:该路径绕过正文观察,遗漏 fork 子会话的精确继承切点要求。目录用例有意不挂载可选投影缓存,报告带种子的回退路径;它不代表缓存命中的发现过程。 +**只使用投影缓存行已预热的无种子子会话。** 拒绝:该路径绕过正文观察,遗漏 fork 子会话的精确继承切点要求。原始校准有意不挂载可选投影缓存,报告带种子的回退路径。parent 自有目录的测量观察持久 parent fact;子级正文读取只属于已记录的校准实现。 **将优化及其目标预算与首次测量一起应用。** 拒绝:纯基线层可以独立合并,并在归因或实现改变前记录当前负载。环境变量不能覆盖源码常量。 diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl index ac7306cfdd..7b49cd5613 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl @@ -5,6 +5,7 @@ {"type":"user/message","data":{"content":[{"type":"text","text":"Start a background job."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"step/end","data":{"turn":1,"step":1}} {"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}} +{"type":"subagent/catalog","data":{"version":0,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"descriptorless child"}} {"type":"session/end-seed","data":{}} {"type":"permission/preset","data":{"preset":"workspace-write"}} {"type":"sandbox/mode","data":{"mode":"workspace-write"}} @@ -21,9 +22,9 @@ {"type":"session/title","data":{"title":"Start a background job.","messageSeqs":[3],"source":{"kind":"fallback"}}} {"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"list-once","name":"list_agents","arguments":"{}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"list-once","name":"list_agents","args":["{}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"list-once","name":"list_agents","arguments":"{}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"} {"type":"tool/call","data":{"turn":2,"step":1,"callId":"list-once","name":"list_agents","arguments":"{}"}} -{"type":"tool/result","data":{"turn":2,"step":1,"message":{"source":{"kind":"tool","callId":"list-once"},"content":[{"type":"tool-result","toolCallId":"list-once","content":[{"type":"text","text":"{{sessionId}} [diagnostic: corrupt]"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[21],"surfaceOp":"append"} +{"type":"tool/result","data":{"turn":2,"step":1,"message":{"source":{"kind":"tool","callId":"list-once"},"content":[{"type":"tool-result","toolCallId":"list-once","content":[{"type":"text","text":"{{sessionId}} [ready] — descriptorless child"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[22],"surfaceOp":"append"} {"type":"step/end","data":{"turn":2,"step":1}} {"type":"step/start","data":{"turn":2,"step":2}} -{"type":"assistant/message","data":{"turn":2,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"The stored subagent is unreadable. PARENT_DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["The stored subagent is unreadable. PARENT_DONE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The stored subagent is unreadable. PARENT_DONE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"} +{"type":"assistant/message","data":{"turn":2,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"The catalogued subagent is ready. PARENT_DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["The catalogued subagent is ready. PARENT_DONE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The catalogued subagent is ready. PARENT_DONE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"} {"type":"step/end","data":{"turn":2,"step":2}} {"type":"turn/end","data":{"turn":2,"reason":{"kind":"completed"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/replay.override.json b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/replay.override.json index 2b9facf71f..6d66bcf03d 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/replay.override.json +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/replay.override.json @@ -1 +1 @@ -[{"kind": "chunks", "chunks": [{"type": "block-start", "index": 0, "blockType": "tool-call"}, {"type": "tool-call-delta", "index": 0, "id": "list-once", "name": "list_agents", "argumentsDelta": "{}"}, {"type": "block-end", "index": 0, "block": {"type": "tool-call", "id": "list-once", "name": "list_agents", "arguments": "{}"}}, {"type": "usage", "usage": {"inputTokens": 10, "outputTokens": 5}}, {"type": "finish", "reason": {"kind": "tool-calls"}}]}, {"kind": "chunks", "chunks": [{"type": "block-start", "index": 0, "blockType": "text"}, {"type": "text-delta", "index": 0, "text": "The stored subagent is unreadable. PARENT_DONE"}, {"type": "block-end", "index": 0, "block": {"type": "text", "text": "The stored subagent is unreadable. PARENT_DONE"}}, {"type": "usage", "usage": {"inputTokens": 10, "outputTokens": 5}}, {"type": "finish", "reason": {"kind": "stop"}}]}] +[{"kind": "chunks", "chunks": [{"type": "block-start", "index": 0, "blockType": "tool-call"}, {"type": "tool-call-delta", "index": 0, "id": "list-once", "name": "list_agents", "argumentsDelta": "{}"}, {"type": "block-end", "index": 0, "block": {"type": "tool-call", "id": "list-once", "name": "list_agents", "arguments": "{}"}}, {"type": "usage", "usage": {"inputTokens": 10, "outputTokens": 5}}, {"type": "finish", "reason": {"kind": "tool-calls"}}]}, {"kind": "chunks", "chunks": [{"type": "block-start", "index": 0, "blockType": "text"}, {"type": "text-delta", "index": 0, "text": "The catalogued subagent is ready. PARENT_DONE"}, {"type": "block-end", "index": 0, "block": {"type": "text", "text": "The catalogued subagent is ready. PARENT_DONE"}}, {"type": "usage", "usage": {"inputTokens": 10, "outputTokens": 5}}, {"type": "finish", "reason": {"kind": "stop"}}]}] diff --git a/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts b/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts index 7cdb9a2e36..be58890d9d 100644 --- a/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts +++ b/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts @@ -1,7 +1,6 @@ /** - * Assembled-app regression: a persisted `origin: 'subagent'` child whose log - * carries no descriptor event is surfaced by `list_agents` as a - * `[diagnostic: corrupt]` row instead of being silently dropped. + * Assembled-app regression: a parent-owned catalog event remains sufficient + * for direct discovery when the persisted child has no descriptor event. */ import { readFile, readdir, writeFile } from 'node:fs/promises' @@ -42,11 +41,10 @@ async function expectSession(actual: string, expectedPath: string): Promise { +async function seedCataloguedDescriptorlessChild(root: string, cwd: string): Promise { const ctx = new Context() await ctx.plugin(JsonlSessionPersistence, { root, compression: 'none' }) const parentMeta: SessionHeader = { @@ -68,6 +66,18 @@ async function seedDescriptorlessChild(root: string, cwd: string): Promise { type: 'user/message', seq: SessionSeq(3), time: 13, data: createUserMessage({ content: [{ type: 'text', text: 'Start a background job.' }], source: { kind: 'user' } }), surfaceOp: 'append' }, { type: 'step/end', seq: SessionSeq(4), time: 14, data: { turn: 1, step: 1 } }, { type: 'turn/end', seq: SessionSeq(5), time: 15, data: { turn: 1, reason: { kind: 'completed' } } }, + { + type: 'subagent/catalog', + seq: SessionSeq(6), + time: 16, + data: { + version: 0, + childId, + childCreatedAt: 2, + mode: 'continuable', + label: 'descriptorless child', + }, + }, ] const childMeta: SessionHeader = { version: SESSION_FORMAT_VERSION, @@ -95,8 +105,8 @@ async function seedDescriptorlessChild(root: string, cwd: string): Promise } } -describe('descriptor-less cold child diagnostic snapshot', () => { - it('surfaces the unreadable child as a corrupt diagnostic through the assembled headless app', async () => { +describe('parent-owned cold child catalog snapshot', () => { + it('discovers a catalogued child without reading its descriptor through the assembled headless app', async () => { let cwd = '' const result = await runLoaderSmoke({ label: 'subagent diagnostic headless stream-json snapshot', @@ -112,7 +122,7 @@ describe('descriptor-less cold child diagnostic snapshot', () => { }, prepare: async (runCwd) => { cwd = runCwd - await seedDescriptorlessChild(join(runCwd, '.sessions'), runCwd) + await seedCataloguedDescriptorlessChild(join(runCwd, '.sessions'), runCwd) }, inspect: async (runCwd) => { const sessionsDir = join(runCwd, '.sessions') @@ -121,9 +131,10 @@ describe('descriptor-less cold child diagnostic snapshot', () => { const parent = logs.find(content => content.includes('"subagent-diagnostic-parent"')) if (parent === undefined) throw new Error('missing persisted parent log') - // THE model-visible fact: the descriptor-less child is reported, not - // silently dropped, and its reason is the corrupt classification. - expect(parent).toContain(`${childId} [diagnostic: corrupt]`) + // THE model-visible fact: the parent catalog supplies discovery even + // though consulting the descriptor-less child would classify it corrupt. + expect(parent).toContain(`${childId} [ready] — descriptorless child`) + expect(parent).not.toContain('[diagnostic: corrupt]') const context: NormalizeContext = { sessionIds: [parentId, childId], cwd } const normalizedParent = normalizeSessionSnapshot(parent, context) @@ -139,7 +150,7 @@ describe('descriptor-less cold child diagnostic snapshot', () => { expect(records.at(-1)).toMatchObject({ type: 'result', sessionId: parentId, - output: 'The stored subagent is unreadable. PARENT_DONE', + output: 'The catalogued subagent is ready. PARENT_DONE', }) }, LOADER_SMOKE_TEST_TIMEOUT_MS) }) diff --git a/apps/web/tests/agent-preset-selection.e2e.ts b/apps/web/tests/agent-preset-selection.e2e.ts index a06c0da136..8cd3070c64 100644 --- a/apps/web/tests/agent-preset-selection.e2e.ts +++ b/apps/web/tests/agent-preset-selection.e2e.ts @@ -34,6 +34,9 @@ const MENU_EXPECTED = join(SNAPSHOT_DIR, 'menu.expected.md') const HEADER_EXPECTED = join(SNAPSHOT_DIR, 'header.expected.md') const MODE = webSnapshotMode() const SEED_ID = 'agent-preset-selection-web-e2e' +const SEED_TIME = 1784974100000 +const SEEDED_CHILD_ID = sessionId('agent-preset-selection-child') +const SEEDED_CHILD_CREATED_AT = 1784974100100 /** A project skill only a preset that mounts `skill-filesystem` can discover. */ const SKILL_NAME = 'preset-catalog-demo' /** The preset whose rows resolve and then refuse to start. */ @@ -87,13 +90,12 @@ async function seedWorkspaceSkill(workspaceCwd: string): Promise { * @returns a tokenized session log ending on a closed turn. */ function seedLog(): string { - const time = 1784974100000 const at = (index: number, event: Record): string => - JSON.stringify({ ...event, seq: index, time: time + index }) + JSON.stringify({ ...event, seq: index, time: SEED_TIME + index }) return [ JSON.stringify({ type: 'session', version: SESSION_FORMAT_VERSION, id: '{{sessionId}}', - createdAt: time, cwd: '{{cwd}}/workspace', isSeeded: false, delegationDepth: 0, + createdAt: SEED_TIME, cwd: '{{cwd}}/workspace', isSeeded: false, delegationDepth: 0, }), at(0, { type: 'turn/start', data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user', rpcId: 'seed' } } } }), at(1, { type: 'step/start', data: { turn: 1, step: 1 } }), @@ -114,7 +116,17 @@ function seedLog(): string { }), at(4, { type: 'session/title', data: { title: 'Seeded turn', messageSeqs: [3], source: { kind: 'fallback' } } }), at(5, { type: 'step/end', data: { turn: 1, step: 1 } }), - at(6, { type: 'turn/end', data: { turn: 1, reason: { kind: 'completed' } } }), + at(6, { + type: 'subagent/catalog', + data: { + version: 0, + childId: SEEDED_CHILD_ID, + childCreatedAt: SEEDED_CHILD_CREATED_AT, + mode: 'one-shot', + label: 'header order probe', + }, + }), + at(7, { type: 'turn/end', data: { turn: 1, reason: { kind: 'completed' } } }), ].join('\n') } @@ -125,13 +137,11 @@ function seedLog(): string { * @param parentId - the seeded session whose header the browser opens. */ async function seedSubagent(scaffold: WebScaffold, parentId: SessionId): Promise { - const childId = sessionId('agent-preset-selection-child') - const createdAt = 1784974100100 const header: SessionHeader = { version: SESSION_FORMAT_VERSION, - id: childId, + id: SEEDED_CHILD_ID, isSeeded: false, - createdAt, + createdAt: SEEDED_CHILD_CREATED_AT, cwd: scaffold.workspaceCwd, parentSession: parentId, origin: 'subagent', @@ -143,13 +153,13 @@ async function seedSubagent(scaffold: WebScaffold, parentId: SessionId): Promise { type: 'turn/start', seq: 0, - time: createdAt, + time: SEEDED_CHILD_CREATED_AT, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }, }, { type: 'user/message', seq: 1, - time: createdAt + 1, + time: SEEDED_CHILD_CREATED_AT + 1, data: createUserMessage({ content: [{ type: 'text', text: 'Check the session-header action order.' }], source: { kind: 'user' }, @@ -159,7 +169,7 @@ async function seedSubagent(scaffold: WebScaffold, parentId: SessionId): Promise { type: 'subagent/descriptor', seq: 2, - time: createdAt + 2, + time: SEEDED_CHILD_CREATED_AT + 2, data: snapshotSubagentDescriptor({ mode: 'one-shot', provider: 'spawn', label: 'header order probe', }), @@ -167,7 +177,7 @@ async function seedSubagent(scaffold: WebScaffold, parentId: SessionId): Promise { type: 'turn/end', seq: 3, - time: createdAt + 3, + time: SEEDED_CHILD_CREATED_AT + 3, data: { turn: 1, reason: { kind: 'completed' } }, }, ] as SessionEvent[]) diff --git a/apps/web/tests/assembled-remote.ts b/apps/web/tests/assembled-remote.ts index 69739dc7a7..23c66da520 100644 --- a/apps/web/tests/assembled-remote.ts +++ b/apps/web/tests/assembled-remote.ts @@ -139,7 +139,6 @@ export function createAssembledRemote(options: AssembledRemoteOptions = {}): Ass 'settings/canOpenAgentPresetDirectory': ok(true), 'settings/openSettingsDocument': ok({ opened: true }), 'settings/openAgentPresetDirectory': ok({ opened: true }), - 'subagents/list': ok({ entries: [], parentAvailable: true }), 'terminal/list': ok([]), 'skills/list': ok({ skills: [] }), 'session/canOpenWorkspacePath': ok(true), @@ -204,6 +203,11 @@ export function createAssembledRemote(options: AssembledRemoteOptions = {}): Ass return ok(undefined) }) mock.unary('session/list', () => ok({ items: structuredClone(sessions) })) + mock.unary('session/projections', (request: unknown) => { + const sessionId = recordString(recordValue(request, 'request'), 'sessionId') + const summary = sessions.find(candidate => candidate.sessionId === sessionId) + return ok(structuredClone(summary?.projections ?? fixture.control.value.projections[sessionId] ?? null)) + }) mock.unary('workspace/create', (request: unknown) => { const path = recordString(recordValue(request, 'request'), 'path') const existing = workspaces.find(workspace => workspace.path === path) diff --git a/apps/web/tests/subagent-conversation.e2e.ts b/apps/web/tests/subagent-conversation.e2e.ts index e4a93fce77..cf20c40597 100644 --- a/apps/web/tests/subagent-conversation.e2e.ts +++ b/apps/web/tests/subagent-conversation.e2e.ts @@ -7,7 +7,8 @@ import { chromium } from 'playwright' import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest' import { prepareSessionSnapshotFixtureForComparison } from '@deepseek-ai/dsh-llm-replay' import { - SESSION_FORMAT_VERSION, SessionId as sessionId, SessionLogOffset, type SessionEvent, type SessionHeader, type SessionId, + SESSION_FORMAT_VERSION, SessionId as sessionId, SessionLogOffset, SessionSeq, + type SessionEvent, type SessionHeader, type SessionId, } from '@deepseek-ai/dsh-session' import type {} from '@deepseek-ai/dsh-agent' import { snapshotSubagentDescriptor } from '@deepseek-ai/dsh-subagent' @@ -24,9 +25,9 @@ const AVAILABLE_CHILD_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/s const AVAILABLE_CHILD_EXPANDED_EXPECTED = fileURLToPath( new URL('../../../snapshots/web/subagent-conversation/ui-expanded.expected.md', import.meta.url), ) +const CATALOG_PUSH_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/catalog-push.expected.md', import.meta.url)) const TREE_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/tree.expected.md', import.meta.url)) const BRANCHLESS_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/branchless.expected.md', import.meta.url)) -const STALE_CATALOG_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/stale-catalog.expected.md', import.meta.url)) const SIDEBAR_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/sidebar.expected.md', import.meta.url)) const UNAVAILABLE_GRANDCHILD_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/nested.expected.md', import.meta.url)) const FORK_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/fork.expected.md', import.meta.url)) @@ -197,6 +198,19 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await oneShotHandle.close() scaffold.ctx.sessionProjectionCache.coldSnapshot(oneShotHeader, SessionLogOffset(0), oneShotEvents) await waitForCacheRow(scaffold, oneShotHeader) + await page.getByRole('button', { name: '1 subagent', exact: true }).waitFor({ timeout: 15_000 }) + const catalogReads = apiCalls.filter(path => path === '/api/session/projections').length + parent.session.append('subagent/catalog', { + version: 0, + childId: oneShotId, + childCreatedAt: oneShotAt, + mode: 'one-shot', + label: ONE_SHOT_LABEL, + }) + const pushedCount = page.getByRole('button', { name: '2 subagents', exact: true }) + await pushedCount.waitFor({ timeout: 15_000 }) + expect(apiCalls.filter(path => path === '/api/session/projections')).toHaveLength(catalogReads) + await compareOrRefreshGolden(CATALOG_PUSH_EXPECTED, await pushedCount.ariaSnapshot(), MODE) grandchildId = sessionId('recorded-grandchild') const authoredAt = Date.now() const grandchildHeader: SessionHeader = { @@ -248,38 +262,65 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await grandchildHandle.close() scaffold.ctx.sessionProjectionCache.coldSnapshot(grandchildHeader, SessionLogOffset(0), grandchildEvents) await waitForCacheRow(scaffold, grandchildHeader) + const childHandle = await scaffold.ctx.sessionPersistence.open(childId, 'write') + const childHeader = childHandle.header + const childInheritedEventCount = childHandle.inheritedEventCount + const { events: childEvents } = await childHandle.read() + const grandchildCatalogEvent: SessionEvent<'subagent/catalog'> = { + type: 'subagent/catalog', + seq: SessionSeq((childEvents.at(-1)?.seq ?? -1) + 1), + time: authoredAt, + data: { + version: 0, + childId: grandchildId, + childCreatedAt: authoredAt, + mode: 'continuable', + label: NESTED_LABEL, + }, + } + await childHandle.append([grandchildCatalogEvent]) + await childHandle.close() + scaffold.ctx.sessionProjectionCache.coldSnapshot( + childHeader, + childInheritedEventCount, + [...childEvents, grandchildCatalogEvent], + ) expect(scaffold.ctx.agents.get(childId)).toBeUndefined() expect(scaffold.ctx.agents.get(oneShotId)).toBeUndefined() expect(scaffold.ctx.agents.get(grandchildId)).toBeUndefined() - await expect(scaffold.ctx.subagents.listChildren(parent.id)).resolves.toMatchObject([ + expect(await scaffold.ctx.subagents.listChildren(parent.id)).toMatchObject([ { - kind: 'child', id: oneShotId, mode: 'one-shot', - label: ONE_SHOT_LABEL, activity: 'inactive', hasChildren: false, + id: childId, mode: 'continuable', label: LABEL, }, { - kind: 'child', id: childId, mode: 'continuable', label: LABEL, - activity: 'inactive', hasChildren: true, - }, - ]) - await expect(scaffold.ctx.subagents.listChildren(childId)).resolves.toMatchObject([ - { - kind: 'child', id: grandchildId, mode: 'continuable', - label: NESTED_LABEL, activity: 'inactive', hasChildren: false, + id: oneShotId, mode: 'one-shot', label: ONE_SHOT_LABEL, }, ]) + { + using observed = await scaffold.ctx.sessionQuery.observeSession(childId) + expect(observed.source).toBe('prepared') + expect(observed.projections?.values.subagentCatalog).toEqual([ + { id: grandchildId, createdAt: authoredAt, mode: 'continuable', label: NESTED_LABEL }, + ]) + expect(await scaffold.ctx.subagents.listChildren(childId)).toMatchObject([ + { + id: grandchildId, mode: 'continuable', label: NESTED_LABEL, + }, + ]) + } // These two cold fixtures were authored after the page's initial // session.list and intentionally emitted no api-session/added event. Reload // to exercise the restart baseline that discovers their full lineage. const warningStart = tripwire.warnings.length await page.reload({ waitUntil: 'load' }) await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) - const catalogButton = page.getByRole('button', { name: '3 subagents', exact: true }) + const catalogButton = page.getByRole('button', { name: '2 subagents', exact: true }) await catalogButton.waitFor({ timeout: 15_000 }) await catalogButton.hover() const catalogTree = page.getByRole('tree', { name: 'Subagent sessions' }) await catalogTree.getByRole('treeitem').nth(1).waitFor({ timeout: 15_000 }) await catalogTree.press('Escape') - await page.getByRole('button', { name: '3 subagents' }).waitFor({ timeout: 15_000 }) + await page.getByRole('button', { name: '2 subagents' }).waitFor({ timeout: 15_000 }) acknowledgeReloadConnectionLoss(tripwire, warningStart) }, 120_000) @@ -295,71 +336,19 @@ describe('web e2e: persisted subagent conversation and human continuation', () = if (failures.length > 1) throw new AggregateError(failures, 'subagent Web teardown failed') }) - it('keeps known descendants reachable across a stale empty catalog response', async () => { - onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-stale-catalog')) - const pattern = '**/api/subagents/list' - let firstClaimed = false - let emptyDelivered = false - let trailingRequested = false - let releaseCatalog = (): void => {} - const catalogHeld = new Promise((resolve) => { releaseCatalog = resolve }) - await page.route(pattern, async (route) => { - if (firstClaimed) { - const response = await route.fetch() - trailingRequested = true - await catalogHeld - await route.fulfill({ response }) - return - } - firstClaimed = true - const response = await route.fetch() - const body = await response.json() as { - result: { ok: true; value: { entries: unknown[] } } | { ok: false } - } - if (body.result.ok) body.result.value.entries = [] - await route.fulfill({ response, json: body }) - emptyDelivered = true - }) - - const warningStart = tripwire.warnings.length - try { - await page.reload({ waitUntil: 'load' }) - await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) - await expect.poll(() => emptyDelivered, { timeout: 15_000 }).toBe(true) - await page.getByRole('button', { name: '3 subagents' }).waitFor({ timeout: 15_000 }) - acknowledgeReloadConnectionLoss(tripwire, warningStart) - - await page.getByRole('button', { name: '3 subagents' }).hover() - await expect.poll(() => trailingRequested, { timeout: 15_000 }).toBe(true) - const tree = page.getByRole('tree', { name: 'Subagent sessions' }) - await tree.getByRole('treeitem', { name: 'Loading subagents' }).first().waitFor() - expect(await tree.getByRole('treeitem', { name: 'Loading subagents' }).count()).toBe(2) - await compareOrRefreshGolden( - STALE_CATALOG_EXPECTED, - await captureStableAria(page, '[role="tree"][aria-label="Subagent sessions"]', scaffold.workspaceCwd), - MODE, - ) - releaseCatalog() - await tree.getByRole('treeitem', { name: new RegExp(LABEL) }).waitFor({ timeout: 15_000 }) - await tree.press('Escape') - } finally { - releaseCatalog() - await page.unroute(pattern) - } - }) - it('expands a persisted grandchild progressively without activating either level', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-tree')) - await page.getByRole('button', { name: '3 subagents' }).hover() + await page.getByRole('button', { name: '2 subagents' }).hover() const catalogTree = page.getByRole('tree', { name: 'Subagent sessions' }) expect(await catalogTree.evaluate((element) => { const rect = element.getBoundingClientRect() const hit = document.elementFromPoint(rect.left + 8, rect.top + 8) return hit !== null && element.contains(hit) })).toBe(true) - expect(await page.getByRole('button', { + const oneShotDisclosure = page.getByRole('button', { name: `Expand ${ONE_SHOT_LABEL} descendants`, - }).count()).toBe(0) + }) + expect(await oneShotDisclosure.count()).toBe(0) const oneShotRow = page.getByRole('treeitem', { name: new RegExp(ONE_SHOT_LABEL) }) expect(await oneShotRow.getByText('~6mo 12d', { exact: true }).count()).toBe(1) expect(await oneShotRow.getAttribute('aria-label')).toContain('192d 00h 00m 00s') @@ -377,12 +366,19 @@ describe('web e2e: persisted subagent conversation and human continuation', () = scaffold.workspaceCwd, ) await compareOrRefreshGolden(TREE_EXPECTED, snapshot, MODE) - await page.getByRole('tree', { name: 'Subagent sessions' }).press('Escape') + await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).click() + await page.getByText(NESTED_PROMPT).waitFor() + const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' }) + await hierarchy.getByRole('button', { name: `Switch subagent: ${LABEL}`, exact: true }).waitFor() + expect(scaffold.ctx.agents.get(childId)).toBeUndefined() + expect(scaffold.ctx.agents.get(grandchildId)).toBeUndefined() + await hierarchy.getByRole('button').first().click() + await page.getByRole('button', { name: '2 subagents', exact: true }).waitFor() }) it('opens the completed child from persistence without activating it', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-open')) - await page.getByRole('button', { name: '3 subagents' }).hover() + await page.getByRole('button', { name: '2 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await expect.poll( () => page.getByText(/^Explain event sourcing in one sentence\.Your parent agent id is /).count(), @@ -403,7 +399,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = it('keeps a restored child neutral until its parent availability arrives', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-restore')) - const pattern = '**/api/subagents/list' + const pattern = '**/api/session/list' let requested = false let releaseCatalog = (): void => {} const catalogHeld = new Promise((resolve) => { releaseCatalog = resolve }) @@ -481,6 +477,10 @@ describe('web e2e: persisted subagent conversation and human continuation', () = const tree = page.getByRole('tree', { name: 'Subagent sessions' }) const nestedRow = tree.locator('[role="treeitem"]').filter({ hasText: NESTED_LABEL }) await nestedRow.waitFor({ timeout: 15_000 }) + const nestedDisclosure = page.getByRole('button', { + name: `Expand ${NESTED_LABEL} descendants`, + }) + expect(await nestedDisclosure.count()).toBe(0) const clickArea = nestedRow.locator(':scope > div') expect(await clickArea.count()).toBe(1) const [treeBox, clickAreaBox] = await Promise.all([ @@ -521,10 +521,9 @@ describe('web e2e: persisted subagent conversation and human continuation', () = it('opens a one-shot child as permanently read-only history', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-one-shot')) const parentSession = page.getByRole('tree', { name: 'Sessions' }) - .getByRole('treeitem') - .last() + .getByRole('treeitem', { name: /Ask a research subagent to/ }) await parentSession.click() - await page.getByRole('button', { name: '3 subagents' }).hover() + await page.getByRole('button', { name: '2 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(ONE_SHOT_LABEL) }).click() await page.getByText('One-shot tasks do not accept follow-ups; review the full execution record here.').waitFor() expect(scaffold.ctx.agents.get(oneShotId)).toBeUndefined() @@ -535,7 +534,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await page.getByRole('tree', { name: 'Sessions' }) .getByRole('treeitem', { name: /Ask a research subagent to/ }) .click() - await page.getByRole('button', { name: '3 subagents' }).hover() + await page.getByRole('button', { name: '2 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('textbox', { name: 'Message or run a task, / commands, @ files or sessions' }).waitFor() const forkResponse = page.waitForResponse(response => @@ -561,7 +560,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-post-fork-followup')) const sessions = page.getByRole('tree', { name: 'Sessions' }) await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() - await page.getByRole('button', { name: '3 subagents' }).hover() + await page.getByRole('button', { name: '2 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.locator('[data-composer-input][contenteditable="true"]').first().waitFor() expect(scaffold.ctx.agents.get(childId)).toBeUndefined() @@ -578,7 +577,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await expect.poll(() => scaffold.ctx.agents.get(forkId)).not.toBeUndefined() await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() - await page.getByRole('button', { name: '3 subagents' }).press('ArrowDown') + await page.getByRole('button', { name: '2 subagents' }).press('ArrowDown') await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() const input = page.locator('[data-composer-input][contenteditable="true"]').first() await input.waitFor() diff --git a/apps/web/tests/subagent-interrupt-ui.e2e.ts b/apps/web/tests/subagent-interrupt-ui.e2e.ts index 11d96c63fd..7e71c1f8bb 100644 --- a/apps/web/tests/subagent-interrupt-ui.e2e.ts +++ b/apps/web/tests/subagent-interrupt-ui.e2e.ts @@ -185,20 +185,25 @@ describe.skipIf(MODE === 'record')('web e2e: composer interrupt for a running co it('interrupts the live child through the parent-offline composer', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-interrupt-offline')) - // Simulate a parent that went offline: the catalog delivers - // parentAvailable: false while the child Activation stays live (the - // interrupt RPC itself needs no live parent — covered host-side by - // subagent-interrupt.e2e.ts). - const pattern = '**/api/subagents/list' + // The parent is unavailable in the Session list while the child stays live. + const pattern = '**/api/session/list' await page.route(pattern, async (route) => { const response = await route.fetch() const body = await response.json() as { - result: { ok: true; value: { parentAvailable: boolean } } | { ok: false } + result: { ok: true; value: { items: { sessionId: SessionId; agentAvailable: boolean }[] } } | { ok: false } + } + if (body.result.ok) { + const summary = body.result.value.items.find(session => session.sessionId === parent.id) + if (summary === undefined) throw new Error('parent missing from Session list') + summary.agentAvailable = false } - if (body.result.ok) body.result.value.parentAvailable = false await route.fulfill({ response, json: body }) }) try { + const warningStart = tripwire.warnings.length + await page.reload({ waitUntil: 'load' }) + await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) + acknowledgeReloadConnectionLoss(tripwire, warningStart) await page.getByRole('button', { name: /1 subagent/ }).click() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() const input = page.getByRole('textbox', { @@ -264,7 +269,11 @@ describe.skipIf(MODE === 'record')('web e2e: composer interrupt for a running co it('interrupts through subagents/interruptByParent, parks the follow-up, and resumes it FIFO', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-interrupt-flow')) - // Reselect the child with the truthful catalog: parent available again. + // A new connection reloads the truthful parent-availability hint. + const warningStart = tripwire.warnings.length + await page.reload({ waitUntil: 'load' }) + await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) + acknowledgeReloadConnectionLoss(tripwire, warningStart) await page.getByRole('navigation', { name: 'Session hierarchy' }) .getByRole('button').first().click() await page.getByRole('button', { name: /1 subagent/ }).click() diff --git a/benchmarks/agent-continuation/child-catalog.worker.ts b/benchmarks/agent-continuation/child-catalog.worker.ts index e12cb97d2f..831a15c1b8 100644 --- a/benchmarks/agent-continuation/child-catalog.worker.ts +++ b/benchmarks/agent-continuation/child-catalog.worker.ts @@ -1,4 +1,4 @@ -/** Cold catalog observations of persisted fork children with tool-heavy inherited histories. */ +/** Cold parent-catalog observations beside fork children with tool-heavy inherited histories. */ import { performance } from 'node:perf_hooks' import { Context } from '@deepseek-ai/cordis' @@ -11,7 +11,7 @@ import SubagentRuntime, { SUBAGENT_DESCRIPTOR_VERSION } from '@deepseek-ai/dsh-s import { assertBuiltBenchmarkRuntime } from '../support/built-worker.ts' import { PARENT_ID, syntheticHistory, TIME_ZERO, WORKLOAD } from './workload.ts' -/** Two complete catalog reads in one fresh Host, with every child observation released. */ +/** Two complete catalog reads in one fresh Host, with each parent observation released. */ export interface CatalogReport { readonly totalMs: number readonly firstMs: number @@ -33,8 +33,14 @@ class CatalogQuery extends SessionQueryEngine { async function seed(ctx: Context): Promise { const inherited = syntheticHistory(WORKLOAD.childHistoryTurns) + const catalog: SessionEvent[] = [] for (let child = 0; child < WORKLOAD.children; child++) { const id = SessionId('bench-child-' + String(child)) + catalog.push({ + type: 'subagent/catalog', seq: SessionSeq(child), time: TIME_ZERO + child, + data: { version: 0, childId: id, childCreatedAt: TIME_ZERO + child, + mode: 'continuable', label: 'Synthetic child ' + String(child) }, + }) const events: SessionEvent[] = [ ...inherited, { type: 'session/end-seed', seq: SessionSeq(inherited.length), time: TIME_ZERO + inherited.length, data: { inherited: true } }, @@ -51,6 +57,14 @@ async function seed(ctx: Context): Promise { await handle.flush() } finally { await handle.close() } } + const parent = await ctx.sessionPersistence.create({ + version: SESSION_FORMAT_VERSION, id: PARENT_ID, createdAt: TIME_ZERO, cwd: '/bench', + isSeeded: false, + }) + try { + await parent.append(catalog) + await parent.flush() + } finally { await parent.close() } } async function run(root: string, mode: string): Promise { @@ -65,15 +79,15 @@ async function run(root: string, mode: string): Promise ctx.subagents.listChildren(PARENT_ID) const cpuStart = process.cpuUsage() const start = performance.now() - const first = await ctx.subagents.listChildren(PARENT_ID) + const first = await readCatalog() const firstDone = performance.now() - const repeated = await ctx.subagents.listChildren(PARENT_ID) + const repeated = await readCatalog() const end = performance.now() const cpu = process.cpuUsage(cpuStart) - if (first.length !== WORKLOAD.children || repeated.length !== WORKLOAD.children - || [...first, ...repeated].some(row => row.kind !== 'child')) { + if (first.length !== WORKLOAD.children || repeated.length !== WORKLOAD.children) { throw new Error('child-catalog benchmark did not reach the complete healthy catalog') } return { diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index 48edcc4999..65e61562bd 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-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/config-catalog.md -config-catalog.md: 31f75d5dbc1569d759b8fbcde56dcc7ac3e85bc1 -config-catalog.zh.md: e1d3064c1134443d0a3dc17011f068a84560a7d3 +config-catalog.md: d9c96b1fd4ab4a119dc95429649c933484da6b33 +config-catalog.zh.md: fbb2ef3fc7aa829fe083b0a3b4f16a51c3c9afca diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 31f75d5dbc..d9c96b1fd4 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -213,7 +213,7 @@ export interface Config { } ``` -Source: [`packages/api/session-controller/src/index.ts:71`](../packages/api/session-controller/src/index.ts) +Source: [`packages/api/session-controller/src/index.ts:75`](../packages/api/session-controller/src/index.ts) diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index e1d3064c11..fbb2ef3fc7 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -215,7 +215,7 @@ export interface Config { } ``` -来源:[`packages/api/session-controller/src/index.ts:71`](../packages/api/session-controller/src/index.ts) +来源:[`packages/api/session-controller/src/index.ts:75`](../packages/api/session-controller/src/index.ts) diff --git a/docs/event-producer-consumer.i18n.yaml b/docs/event-producer-consumer.i18n.yaml index 78b75271c4..1e70b0d5a0 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: db0f7d4bbe6a0e3a513863fb2d16f56cdeec0488 -event-producer-consumer.zh.md: e0f8db40dad9be12c0568e151dc0f40342f71b6d +event-producer-consumer.md: 43dad3cdab75f7569cde6884c7b8f5b6be750650 +event-producer-consumer.zh.md: ebd91068d3d8ea4ff3cd16c2fb3259e1e8d4036f diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index db0f7d4bbe..43dad3cdab 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -10,7 +10,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `agent-loop/config-start-failed` | `emit` | [`packages/core/agent-loop/src/index.ts:246`](../packages/core/agent-loop/src/index.ts) | [`agent-loop`](../packages/core/agent-loop) (`events.dispatch`) | - | | `agent-preset/selected` | `emit` | [`packages/preset/agent-presets/src/types.ts:82`](../packages/preset/agent-presets/src/types.ts) | [`agent-presets`](../packages/preset/agent-presets) (`emit`) | `remotes` | | `agent/assistant-stream` | `emit` | [`packages/core/agent/src/runtime-types.ts:363`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`headless`](../packages/bundle/headless), `session-controller` | -| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:261`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | [`agent-presets`](../packages/preset/agent-presets), `agent-team`, `browser-use-runtime`, [`file-reference-local`](../packages/context/file-reference-local), [`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), [`loader-smoke`](../packages/test-support/loader-smoke), [`schedule`](../packages/schedule/schedule), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | +| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:261`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | [`agent-presets`](../packages/preset/agent-presets), `agent-team`, `browser-use-runtime`, [`file-reference-local`](../packages/context/file-reference-local), [`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), [`loader-smoke`](../packages/test-support/loader-smoke), [`schedule`](../packages/schedule/schedule), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/disposed` | `emit` | [`packages/core/agent/src/runtime-types.ts:270`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), [`file-reference-local`](../packages/context/file-reference-local), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`subagent`](../packages/subagent/subagent), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/error` | `emit` | [`packages/core/agent/src/runtime-types.ts:393`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`session-telemetry`](../packages/session/session-telemetry) | | `agent/inbox/claimed` | `emit` | [`packages/core/agent/src/runtime-types.ts:299`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent), [`tool-jobs`](../packages/jobs/tool-jobs) | @@ -21,11 +21,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:353`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm-retry`](../packages/llm/llm-retry) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:280`](../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:381`](../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:586`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:566`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:593`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:572`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:579`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:598`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:578`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:605`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:584`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:591`](../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:89`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` | @@ -61,10 +61,10 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `settings/document-updated` | `emit` | [`packages/settings/settings/src/types.ts:105`](../packages/settings/settings/src/types.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | `remotes` | | `settings/updated` | `emit` | [`packages/settings/settings/src/types.ts:92`](../packages/settings/settings/src/types.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | [`settings`](../packages/settings/settings) | | `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:296`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | - | -| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:170`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), `server`, [`subagent`](../packages/subagent/subagent) | -| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:144`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | -| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:150`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | -| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:161`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`subagent`](../packages/subagent/subagent) | +| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:171`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), `server`, [`subagent`](../packages/subagent/subagent) | +| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:145`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | +| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:151`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | +| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:162`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`subagent`](../packages/subagent/subagent) | | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:31`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), `browser-use-runtime`, [`session-reference`](../packages/context/session-reference), [`system-prompt`](../packages/core/system-prompt) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:37`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `tools/change` | `emit` | [`packages/core/tools/src/index.ts:201`](../packages/core/tools/src/index.ts) | [`agent-presets`](../packages/preset/agent-presets) (`emit`), [`tools`](../packages/core/tools) (`emit`) | `browser-use-runtime`, [`tool-subagent`](../packages/subagent/tool-subagent) | diff --git a/docs/event-producer-consumer.zh.md b/docs/event-producer-consumer.zh.md index e0f8db40da..ebd91068d3 100644 --- a/docs/event-producer-consumer.zh.md +++ b/docs/event-producer-consumer.zh.md @@ -12,7 +12,7 @@ | `agent-loop/config-start-failed` | `emit` | [`packages/core/agent-loop/src/index.ts:246`](../packages/core/agent-loop/src/index.ts) | [`agent-loop`](../packages/core/agent-loop) (`events.dispatch`) | - | | `agent-preset/selected` | `emit` | [`packages/preset/agent-presets/src/types.ts:82`](../packages/preset/agent-presets/src/types.ts) | [`agent-presets`](../packages/preset/agent-presets) (`emit`) | `remotes` | | `agent/assistant-stream` | `emit` | [`packages/core/agent/src/runtime-types.ts:363`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`headless`](../packages/bundle/headless), `session-controller` | -| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:261`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | [`agent-presets`](../packages/preset/agent-presets), `agent-team`, `browser-use-runtime`, [`file-reference-local`](../packages/context/file-reference-local), [`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), [`loader-smoke`](../packages/test-support/loader-smoke), [`schedule`](../packages/schedule/schedule), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | +| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:261`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | [`agent-presets`](../packages/preset/agent-presets), `agent-team`, `browser-use-runtime`, [`file-reference-local`](../packages/context/file-reference-local), [`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), [`loader-smoke`](../packages/test-support/loader-smoke), [`schedule`](../packages/schedule/schedule), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/disposed` | `emit` | [`packages/core/agent/src/runtime-types.ts:270`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), [`file-reference-local`](../packages/context/file-reference-local), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`subagent`](../packages/subagent/subagent), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/error` | `emit` | [`packages/core/agent/src/runtime-types.ts:393`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`session-telemetry`](../packages/session/session-telemetry) | | `agent/inbox/claimed` | `emit` | [`packages/core/agent/src/runtime-types.ts:299`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent), [`tool-jobs`](../packages/jobs/tool-jobs) | @@ -23,11 +23,11 @@ | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:353`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm-retry`](../packages/llm/llm-retry) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:280`](../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:381`](../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:586`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:566`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:593`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:572`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:579`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:598`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:578`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:605`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:584`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:591`](../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:89`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` | @@ -63,10 +63,10 @@ | `settings/document-updated` | `emit` | [`packages/settings/settings/src/types.ts:105`](../packages/settings/settings/src/types.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | `remotes` | | `settings/updated` | `emit` | [`packages/settings/settings/src/types.ts:92`](../packages/settings/settings/src/types.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | [`settings`](../packages/settings/settings) | | `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:296`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | - | -| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:170`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), `server`, [`subagent`](../packages/subagent/subagent) | -| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:144`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | -| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:150`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | -| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:161`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`subagent`](../packages/subagent/subagent) | +| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:171`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), `server`, [`subagent`](../packages/subagent/subagent) | +| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:145`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | +| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:151`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) | +| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:162`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`subagent`](../packages/subagent/subagent) | | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:31`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), `browser-use-runtime`, [`session-reference`](../packages/context/session-reference), [`system-prompt`](../packages/core/system-prompt) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:37`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `tools/change` | `emit` | [`packages/core/tools/src/index.ts:201`](../packages/core/tools/src/index.ts) | [`agent-presets`](../packages/preset/agent-presets) (`emit`), [`tools`](../packages/core/tools) (`emit`) | `browser-use-runtime`, [`tool-subagent`](../packages/subagent/tool-subagent) | diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index 209d3d1edf..c398e85a7a 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: 1f28ccf7178ce6c51b6fb2d00a43d1365760945a -persistence-catalog.zh.md: 73bd6df4edd8427910d1e1c1da0c039a0a9732b4 +persistence-catalog.md: ff546fe1a7be96dce4026995b76ee3782df7e3ee +persistence-catalog.zh.md: 8b352447d2e8f2b37a85f108bd31c422dd0d3967 diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 1f28ccf717..ff546fe1a7 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -1790,7 +1790,7 @@ SHA-256: `0ddab4577db37a3e0d9e3a91761735c8ef6f5629d526ab8ecaeeea19c097c8f8` SHA-256: `6a4f72e2e179e17b922f2a9392c0e1c8f8c707f32494372454850a3eb184a6e7` -Sources: [`packages/api/session-controller/src/types.ts:380`](../packages/api/session-controller/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:383`](../packages/api/session-controller/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6305,7 +6305,7 @@ SHA-256: `57f3f606ff8b6c84d9c443faace9d1dd10cca0354f37a4f515ef075f7c351b90` SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -Sources: [`packages/api/session-controller/src/types.ts:375`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:19`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:20`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:32`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:8`](../packages/experimental/agent-team/src/types.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:10`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/webhook/webhook/src/brand.ts:12`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:6`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:9`](../packages/webhook/webhook/src/brand.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:378`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:19`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:20`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:32`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:8`](../packages/experimental/agent-team/src/types.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:10`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/webhook/webhook/src/brand.ts:12`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:6`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:9`](../packages/webhook/webhook/src/brand.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index 73bd6df4ed..8b352447d2 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -1792,7 +1792,7 @@ SHA-256: `0ddab4577db37a3e0d9e3a91761735c8ef6f5629d526ab8ecaeeea19c097c8f8` SHA-256: `6a4f72e2e179e17b922f2a9392c0e1c8f8c707f32494372454850a3eb184a6e7` -来源:[`packages/api/session-controller/src/types.ts:380`](../packages/api/session-controller/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:383`](../packages/api/session-controller/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6307,7 +6307,7 @@ SHA-256: `57f3f606ff8b6c84d9c443faace9d1dd10cca0354f37a4f515ef075f7c351b90` SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -来源:[`packages/api/session-controller/src/types.ts:375`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:19`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:20`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:32`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:8`](../packages/experimental/agent-team/src/types.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:10`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/webhook/webhook/src/brand.ts:12`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:6`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:9`](../packages/webhook/webhook/src/brand.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:378`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:19`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:20`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:32`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:8`](../packages/experimental/agent-team/src/types.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:10`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/webhook/webhook/src/brand.ts:12`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:6`](../packages/webhook/webhook/src/brand.ts) · [`packages/webhook/webhook/src/brand.ts:9`](../packages/webhook/webhook/src/brand.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json index 6535d07366..acf05e197f 100644 --- a/docs/persistence-schema.json +++ b/docs/persistence-schema.json @@ -32033,7 +32033,7 @@ "packages/workflow/workflow/src/types.ts#WorkflowRunId" ], "sources": [ - "packages/api/session-controller/src/types.ts:375", + "packages/api/session-controller/src/types.ts:378", "packages/attachment/attachment/src/brand.ts:6", "packages/compaction/compaction/src/brand.ts:4", "packages/core/session/src/types.ts:19", @@ -37967,7 +37967,7 @@ "event:agent/inbox/spliced.data.inserted[0].source[10]" ], "sources": [ - "packages/api/session-controller/src/types.ts:380" + "packages/api/session-controller/src/types.ts:383" ] }, { diff --git a/docs/subsystems/session.i18n.yaml b/docs/subsystems/session.i18n.yaml index 099313090b..7bdac8f860 100644 --- a/docs/subsystems/session.i18n.yaml +++ b/docs/subsystems/session.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/subsystems/session.md -session.md: 7c7e244bfca17c8e22cabe45fc69126113b685d6 -session.zh.md: fecae92809bdba93588e163447d372c7a42d0260 +session.md: b509cc87ebfb276687aa4eb0072718b7b578347f +session.zh.md: 5bf663ca1218c229584a17265b049dc6143283c6 diff --git a/docs/subsystems/session.md b/docs/subsystems/session.md index 7c7e244bfc..b509cc87eb 100644 --- a/docs/subsystems/session.md +++ b/docs/subsystems/session.md @@ -886,6 +886,14 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' | */ @Remote({ mode: 'stream' }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable +/** + * Read all registered projections without activating an Agent. + * @param request - Session whose current values are required. + * @param signal - cancellation for the Session observation. + * @returns complete baseline, or null when the Session does not exist. + */ +@Remote('projections') async projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise + /** * Stream a complete live-control baseline followed by replacement frames. * @param signal - cancellation owned by the Remote stream carrier. @@ -1070,13 +1078,14 @@ Source: [`packages/api/session-controller/src/types.ts`](../../packages/api/sess #### `api-session/added` — emit -A Session became visible to Session list consumers. +A Session became visible or its Agent was created or disposed. Consumers upsert the summary and replace its current running and availability state. ```ts cordis-catalog /** - * A Session became visible to Session list consumers. + * A Session became visible or its Agent was created or disposed. + * Consumers upsert the summary and replace its current running and availability state. * @mode emit - * @param summary - initial list row for the Session. + * @param summary - current list row for the Session. */ 'api-session/added'(summary: SessionSummary): void ``` diff --git a/docs/subsystems/session.zh.md b/docs/subsystems/session.zh.md index fecae92809..5bf663ca12 100644 --- a/docs/subsystems/session.zh.md +++ b/docs/subsystems/session.zh.md @@ -890,6 +890,14 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' | */ @Remote({ mode: 'stream' }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable +/** + * Read all registered projections without activating an Agent. + * @param request - Session whose current values are required. + * @param signal - cancellation for the Session observation. + * @returns complete baseline, or null when the Session does not exist. + */ +@Remote('projections') async projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise + /** * Stream a complete live-control baseline followed by replacement frames. * @param signal - cancellation owned by the Remote stream carrier. @@ -1074,13 +1082,14 @@ Source: [`packages/api/session-controller/src/types.ts`](../../packages/api/sess #### `api-session/added` — emit -A Session became visible to Session list consumers. +A Session became visible or its Agent was created or disposed. Consumers upsert the summary and replace its current running and availability state. ```ts cordis-catalog /** - * A Session became visible to Session list consumers. + * A Session became visible or its Agent was created or disposed. + * Consumers upsert the summary and replace its current running and availability state. * @mode emit - * @param summary - initial list row for the Session. + * @param summary - current list row for the Session. */ 'api-session/added'(summary: SessionSummary): void ``` diff --git a/docs/subsystems/subagent.i18n.yaml b/docs/subsystems/subagent.i18n.yaml index f9b7d9ae89..83bd6654e0 100644 --- a/docs/subsystems/subagent.i18n.yaml +++ b/docs/subsystems/subagent.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/subsystems/subagent.md -subagent.md: 21c75626158db666fd72bed2742b30e12f4cb719 -subagent.zh.md: ca4bb724b82f4f9e81f1e5b7653950ad8c2d3745 +subagent.md: dbb90805a236ee1e1ce0522ffdc17181f57e3722 +subagent.zh.md: 650bd023a60f4208c401f1124973f0fb6e5e18fe diff --git a/docs/subsystems/subagent.md b/docs/subsystems/subagent.md index 21c7562615..dbb90805a2 100644 --- a/docs/subsystems/subagent.md +++ b/docs/subsystems/subagent.md @@ -4,7 +4,7 @@ English | [中文](subagent.zh.md) The subagent seam lets an agent delegate work to a child agent. Like [bash](shell.md), it is **one optional capability**, not part of the agent loop, so its types live here rather than in [core.md](core.md). It differs from the other capability seams because **multiple provider implementations coexist** in one context, registered by name (`ctx.subagents`), while bash allows only one executor. Its registry follows the [LLM adapter registry](llm-streaming.md), not the single-service bash executor. -Service Definition: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `dsh-subagent-fork-in-process`, `dsh-subagent-acp`, `dsh-subagent-codex`, `dsh-subagent-claude-code`, `dsh-subagent-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](../../packages/subagent/tool-subagent) (per-provider delegation) and [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager and read-only child and descendant discovery straight from the session store and optional session persistence. Product-provider rationale lives in [the Codex and Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), and [the adjacent-Agent messaging Agent Note](../../.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md); [the archived list-identity-projection record](../../.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md) documents the original list-identity decision. +Service Definition: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `dsh-subagent-fork-in-process`, `dsh-subagent-acp`, `dsh-subagent-codex`, `dsh-subagent-claude-code`, `dsh-subagent-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](../../packages/subagent/tool-subagent) (per-provider delegation) and [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager, direct-child discovery through the parent catalog, and complete descendant discovery through the Session corpus. Product-provider rationale lives in [the Codex and Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), and [the adjacent-Agent messaging Agent Note](../../.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md); [the archived list-identity-projection record](../../.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md) documents the original list-identity decision. Sources: [`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts), [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts), and [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts) @@ -266,7 +266,7 @@ A local one-shot provider appends the descriptor inside the child's initial turn ## Durable enumeration: `listChildren()`, `listDescendants()`, and their entries -`SubagentRuntime.listChildren(parentSessionId)` enumerates the parent's direct session-backed subagents from the live-preferred merge of `ctx.sessions` and the session-query engine's `listSessions()` — no Agent is loaded or resumed. Candidates are the direct children whose durable header carries `origin: 'subagent'`; the marker classifies enumeration and coarse generic-route denial but cannot establish a valid descriptor, resumability, or authorization — the projection fold owns identity, and the Activation contract owns resume. Each row's `mode`/`label` is the registered `subagent` projection unit's value, served through a three-rung ladder: the registry's watermark cache for a live child (zero log reads); the optional projection checkpoint cache for a cold one (`cachedSnapshot` — an identity passing the own-suffix seq gate is final, because an own descriptor is immutable once appended); otherwise one `query.observeSession()` cold observation folded through the registry (bounded concurrency, recomputed per listing). The cache is a pure optional accelerator: absent, serving the `null` sentinel or missing the key, failing the seq gate, or faulting, it falls silently through to the authoritative refold. The fold is `subagent/descriptor` last-wins with no failure channel: the child's own descriptor overrides a fork-seeded ancestor's, and a malformed or unknown-version payload folds to a serializable `null` sentinel, treated as no value. The result is one `SubagentListEntry[]` in `createdAt`-then-id order: a served identity yields a `child` entry with `mode: 'one-shot' | 'continuable'` and `activity: 'running' | 'inactive'`; continuable entries always carry `label`, while one-shot entries carry it only when the start caller supplied presentation metadata. A settled candidate whose fold served no identity yields a `corrupt` diagnostic — missing, malformed, and unknown-version descriptors deliberately undistinguished (`unsupported` remains in the type but is never produced); a running candidate without an identity is omitted (the creation window before its descriptor lands); a failed cold inspection yields one `unavailable` diagnostic retried on the next listing, so one damaged sibling cannot hide healthy children. `hasChildren` marks a direct descendant with durable subagent origin, read from the same merged material. Activity snapshots only whether the logical record is live in `ctx.sessions`, not outcome or resumability. Absent persistence, enumeration is live-only rather than an error — a cold child cannot be resumed then either. `listChildren()` throws `SubagentError` with code `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` when the `ctx.sessionProjections` registry is absent and `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE` when the session store is, both checked before any read so a deployment with zero children still fails deterministically; the list tool requires `ctx.subagents` and `ctx.agents` at plugin load. A service consumer such as a UI can display both modes and choose an unlabeled one-shot fallback, while the model-facing `list_agents` adapter (the separately loadable `/list-agents` plugin of [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)) keeps only continuable entries and refines status through the live Agent registry into its own `running`/`idle`/`ready` vocabulary, whose `ready` names a storage-only child as resumable rather than terminal. Listing does not consult the continuation manager's Activation map, Agent registry, or provider availability; `send_message` remains the authoritative delivery-time operation, and a listed running continuable child may still reject delivery as an ownership conflict. [The archived list-identity-projection record](../../.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md) documents the original read-path decision. +`SubagentRuntime.listChildren(parentSessionId, signal?)` reads the parent's `subagentCatalog` view through a live-preferred Session observation and releases that observation on success or failure. It returns direct-child entries in parent event order without reading child logs or enumerating the Session corpus. Query failures propagate; a missing catalog projection fails explicitly. Browser rows derive membership from the shared projection store and add activity from Session status; the control stream pushes complete catalog updates. `listDescendants()` retains corpus traversal, child-identity diagnostics, and complete `hasChildren` computation. [The parent-catalog Agent Note](../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md) owns creation, fork isolation, ordering, and persistence costs. `SubagentRuntime.listDescendants(rootSessionId)` applies the same live-preferred corpus and projection-backed interpretation to the root's complete descendant tree in stable pre-order. Ordinary sessions and one-shot children remain traversal nodes, so continuable descendants below them are discovered; only `origin: 'subagent'` candidates produce rows. Each returned child or diagnostic adds its position from the enumerated durable header, while a cold inspection revalidates that complete lifecycle before serving identity: @@ -463,6 +463,8 @@ The spawn and fork backends create an ordinary one-shot agent through `parent.ct - **Delegation depth** is durable `SessionHeader.delegationDepth` plus the merge-extensible runtime field `AgentOptions.subagentDepth`; absence means top-level depth zero, and the greater present value is authoritative. The seam owns both fields — the loop neither sets nor reads them — so an in-process child persists parent depth + 1, cold resume cannot lower it, and every start rejects a derived depth outside the safe-integer domain or above a defined absolute `request.maxDepth` cap. - **Fork seeding** uses [`CreateAgentOptions.seed`](core.md#creation-and-ownership) (a `SessionEvent[]` prefix threaded through `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })`, the same primitive `ctx.agents.resume()` uses). The fork backend passes a *balanced completed-turn prefix* of the parent's log — the parent's events up to and including its last `turn/end` — so the seed is contiguous-from-0 and the [invariants](../../packages/runtime-diagnostics/invariants) replay accepts it (the in-flight, unbalanced turn is excluded). +`SubagentCatalogEntry` describes one successful direct-child creation fact; `SubagentCatalogState` is the host-only projection state. `listChildren()` owns a live-preferred parent observation without opening child logs. Browser consumers read `subagentCatalog` through the shared Session projection store and combine membership with Session-list activity. `SubagentCatalogRow` belongs to complete-descendant listing. [The parent-catalog decision](../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md) owns the persistent facts and read semantics. + @@ -563,23 +565,15 @@ async drainContinuableDescendants(parents: readonly Agent[]): Promise async drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise /** - * Enumerate the parent's direct session-backed subagents without loading or - * resuming an Agent. The Session query service supplies one live-preferred - * corpus and shared point observations; the projection cache supplies - * immutable descriptor hits without opening cold logs. The registered - * `subagent` projection remains the sole mode/label classifier. - * - * Every query receives `signal`, and the listing rechecks cancellation - * around each await. Read rejections that settle - * after an abort become a stable `SubagentError` with code `CANCELLED`. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - caller-owned cancellation forwarded to Session queries - * and observed around every read await. - * @returns children and per-child diagnostics ordered by `createdAt`, then id. - * @throws {@link SubagentError} when the projection registry or the session - * store is not mounted, or the caller cancels the listing. + * Read the parent's durable direct-child catalog without loading or resuming an Agent. + * The service owns and releases the live-preferred Session observation. + * @param parentSessionId - parent whose direct children are requested. + * @param signal - cancellation forwarded to the Session query. + * @returns catalog children in parent event order. + * @throws {@link SubagentError} when query or catalog projection is unavailable. + * @throws SessionQueryError when the parent cannot be read or the query is cancelled. */ -listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise +listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise /** * Enumerate the root's complete session-backed subagent tree in stable @@ -587,32 +581,17 @@ listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise -/** - * Remote face of {@link listChildren} for one browser: the durable listing - * plus live Agent activity and the delivery-time parent availability hint. - * Parent availability is a hint; {@link prompt} performs the authoritative - * check. Named apart from the provider-name {@link list}, which owns the - * member. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - carrier cancellation forwarded to Session queries. - * @returns the catalog view for that parent. - * @throws {RemoteError} `gateway/bad-request` for an empty parent id, - * `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when - * the deployment has no projection registry, otherwise `gateway/internal`. - */ -@Remote('list') async remoteExportList(parentSessionId: SessionId, signal: AbortSignal): Promise - /** * Deliver one browser-authored message to a continuable child through the * exact live direct parent, retaining the caller-minted request identity and diff --git a/docs/subsystems/subagent.zh.md b/docs/subsystems/subagent.zh.md index ca4bb724b8..650bd023a6 100644 --- a/docs/subsystems/subagent.zh.md +++ b/docs/subsystems/subagent.zh.md @@ -4,7 +4,7 @@ subagent seam 让一个 agent(智能体)将工作委派给子 agent。与 [bash](shell.zh.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环),因此其类型定义在此而非 [core.md](core.zh.md) 中。它不同于其他能力 seam,因为**同一上下文中可共存多个提供方实现**,并按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。该注册表遵循 [LLM(大语言模型)适配器注册表](llm-streaming.zh.md),而非单服务的 bash 执行器。 -Service Definition:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。Service Provider 是六个兄弟包:`dsh-subagent-spawn-in-process`、`dsh-subagent-fork-in-process`、`dsh-subagent-acp`、`dsh-subagent-codex`、`dsh-subagent-claude-code`、`dsh-subagent-dsh-sdk`;面向模型的 Consumer 包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)和 [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,并直接基于会话存储和可选的会话持久化提供只读的 child 与后代发现。产品提供方设计理由见 [Codex 与 Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.zh.md)和[相邻 Agent 消息 Agent Note](../../.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md);[已归档的列表身份投影记录](../../.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md)记录了最初的列表身份决策。 +Service Definition:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。Service Provider 是六个兄弟包:`dsh-subagent-spawn-in-process`、`dsh-subagent-fork-in-process`、`dsh-subagent-acp`、`dsh-subagent-codex`、`dsh-subagent-claude-code`、`dsh-subagent-dsh-sdk`;面向模型的 Consumer 包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)和 [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,通过 parent 目录发现直接 child,并通过 Session 语料库发现完整后代。产品提供方设计理由见 [Codex 与 Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.zh.md)和[相邻 Agent 消息 Agent Note](../../.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md);[已归档的列表身份投影记录](../../.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md)记录了最初的列表身份决策。 源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts)、[`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts)和 [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts) @@ -266,7 +266,7 @@ interface ContinuableCreateSpec { ## 持久化枚举:`listChildren()`、`listDescendants()` 与其条目 -`SubagentRuntime.listChildren(parentSessionId)` 从 `ctx.sessions` 与会话查询引擎 `listSessions()` 的实时优先合并中枚举 parent 直接且由会话支撑的 subagent——不会加载或恢复任何 Agent。候选是持久 header 携带 `origin: 'subagent'` 的直接 child;该标记只负责枚举分类与粗粒度的通用路由拒绝,不能证明描述符有效、child 可恢复或操作已获授权——身份由投影折叠负责,恢复由 Activation 约定负责。每行的 `mode`/`label` 是已注册 `subagent` projection unit 的值,经三级阶梯供值:存活 child 由注册表水位缓存供值(零日志读取);冷 child 先读可选的投影 checkpoint 缓存(`cachedSnapshot`——过 own-suffix seq 门的身份即定值,own descriptor 一经追加不可变);否则在一次 `query.observeSession()` 冷观察上经注册表折叠(有界并发,每次列表重新计算)。该缓存是纯可选加速层:服务缺席、行里是 `null` 哨兵或 key 缺席、seq 门不过、读取出错,都静默落到权威重折。折叠规则是 `subagent/descriptor` last-wins 且没有失败通道:子 agent 自己的描述符覆盖 fork seed 中祖先的描述符,格式错误或版本不认识的载荷折叠为可序列化的 `null` 哨兵,视同无值。结果是按 `createdAt`、再按 id 排序的 `SubagentListEntry[]`:取到身份即生成带有 `mode: 'one-shot' | 'continuable'` 和 `activity: 'running' | 'inactive'` 的 `child` 条目;可继续条目始终携带 `label`,一次性条目则只在启动调用方提供展示元数据时携带该字段。已定局而折叠无身份的候选生成 `corrupt` diagnostic——缺失、格式错误与版本不认识的描述符有意不再细分(`unsupported` 仍保留在类型中但从不产出);运行中而无身份的候选被省略(描述符落盘前的创建窗口);冷检查失败生成一条 `unavailable` diagnostic 并在下次列表自然重试,因此一个损坏的 sibling 不会隐藏健康 child。`hasChildren` 标记存在持久 subagent origin 的直接后代,读取自同一份合并材料。活动状态只表示逻辑记录是否在 `ctx.sessions` 中存活,而不表示结果或可恢复性。缺少持久化时,枚举退化为仅存活枚举而不是报错——此时冷 child 本就无法恢复。缺少 `ctx.sessionProjections` 注册表时,`listChildren()` 抛出携带错误码 `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` 的 `SubagentError`,缺少会话存储时则抛出 `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE`,两者都在任何读取之前检查,因此零 child 的部署同样确定失败;列表工具在插件加载时要求 `ctx.subagents` 与 `ctx.agents`。UI 等服务消费方可以展示两种模式,并为无标签的一次性 child 选择回退展示;面向模型的 `list_agents` 适配器([dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) 中可单独加载的 `/list-agents` 插件)则只保留可继续条目,并通过在线 Agent 注册表将状态细化为自己的 `running`/`idle`/`ready` 词汇,其中 `ready` 把仅存于存储的 child 命名为可恢复而非终态。枚举不会查询继续执行管理器的 Activation map、Agent 注册表或提供方可用性;`send_message` 仍是消息送达时的权威操作,列表中的运行中可继续 child 仍可能因所有权冲突而拒绝投递。[已归档的列表身份投影记录](../../.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md)记录了最初的读路径决策。 +`SubagentRuntime.listChildren(parentSessionId, signal?)` 通过优先使用在线 Session 的观察读取父会话的 `subagentCatalog` 视图,并在成功或失败时释放观察。它按父会话事件顺序返回直接子级条目,不读取子级日志,也不枚举 Session 语料库。查询失败直接传播;缺少目录投影时显式失败。浏览器条目从共享 projection store 派生成员关系,并从 Session 状态补充活动状态;control stream 推送完整目录更新。`listDescendants()` 保留语料库遍历、子级身份诊断和完整的 `hasChildren` 计算。[父目录 Agent Note](../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md) 说明创建、fork 隔离、排序和持久化成本。 `SubagentRuntime.listDescendants(rootSessionId)` 将同一份实时优先语料与基于投影的解释应用到根的完整后代树,并按稳定 pre-order 输出。普通会话和一次性 child 仍作为遍历节点,因此其下的可继续后代仍可发现;只有 `origin: 'subagent'` 的候选会生成条目。每个返回的 child 或 diagnostic 都从枚举所得的持久 header 附加树位置;冷检查在提供身份前还会重新校验完整生命周期: @@ -467,6 +467,8 @@ spawn 和 fork 后端通过 `parent.ctx` 创建一个普通的单次 agent,将 - **委派深度**由持久 `SessionHeader.delegationDepth` 与可合并扩展的运行时字段 `AgentOptions.subagentDepth` 共同表示;缺失表示顶层深度为零,存在的较大值具有权威性。两个字段都归该 seam 所有——循环既不设置也不读取它们——因此进程内子 agent 会持久保存 parent 深度 + 1,冷恢复无法降低深度,而且每次 start 都会拒绝超出安全整数域、或高于已定义绝对 `request.maxDepth` 上限的派生深度。 - **Fork 种子注入**使用 [`CreateAgentOptions.seed`](core.zh.md#creation-and-ownership)(一个 `SessionEvent[]` 前缀,经由 `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })` 传递,与 `ctx.agents.resume()` 使用的原语相同)。fork 后端传入父级日志的一段*平衡的已完成轮次前缀*——父级事件直到并包括其最后一个 `turn/end`——因此种子从 0 连续,[invariants](../../packages/runtime-diagnostics/invariants) 回放可以接受它(进行中的、未平衡的轮次被排除在外)。 +`SubagentCatalogEntry` 描述一条成功创建直接子级的事实;`SubagentCatalogState` 是仅 host 使用的 projection state。`listChildren()` 拥有一次 live-preferred 父 Session observation,不打开子级日志。浏览器消费者通过共享 Session projection store 读取 `subagentCatalog`,并将成员关系与 Session 列表活动状态组合。`SubagentCatalogRow` 属于完整后代列表。[父目录决策](../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md) 规定持久事实与读取语义。 + @@ -567,23 +569,15 @@ async drainContinuableDescendants(parents: readonly Agent[]): Promise async drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise /** - * Enumerate the parent's direct session-backed subagents without loading or - * resuming an Agent. The Session query service supplies one live-preferred - * corpus and shared point observations; the projection cache supplies - * immutable descriptor hits without opening cold logs. The registered - * `subagent` projection remains the sole mode/label classifier. - * - * Every query receives `signal`, and the listing rechecks cancellation - * around each await. Read rejections that settle - * after an abort become a stable `SubagentError` with code `CANCELLED`. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - caller-owned cancellation forwarded to Session queries - * and observed around every read await. - * @returns children and per-child diagnostics ordered by `createdAt`, then id. - * @throws {@link SubagentError} when the projection registry or the session - * store is not mounted, or the caller cancels the listing. + * Read the parent's durable direct-child catalog without loading or resuming an Agent. + * The service owns and releases the live-preferred Session observation. + * @param parentSessionId - parent whose direct children are requested. + * @param signal - cancellation forwarded to the Session query. + * @returns catalog children in parent event order. + * @throws {@link SubagentError} when query or catalog projection is unavailable. + * @throws SessionQueryError when the parent cannot be read or the query is cancelled. */ -listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise +listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise /** * Enumerate the root's complete session-backed subagent tree in stable @@ -591,32 +585,17 @@ listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise -/** - * Remote face of {@link listChildren} for one browser: the durable listing - * plus live Agent activity and the delivery-time parent availability hint. - * Parent availability is a hint; {@link prompt} performs the authoritative - * check. Named apart from the provider-name {@link list}, which owns the - * member. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - carrier cancellation forwarded to Session queries. - * @returns the catalog view for that parent. - * @throws {RemoteError} `gateway/bad-request` for an empty parent id, - * `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when - * the deployment has no projection registry, otherwise `gateway/internal`. - */ -@Remote('list') async remoteExportList(parentSessionId: SessionId, signal: AbortSignal): Promise - /** * Deliver one browser-authored message to a continuable child through the * exact live direct parent, retaining the caller-minted request identity and diff --git a/docs/tool-catalog.i18n.yaml b/docs/tool-catalog.i18n.yaml index 529831a2fb..89eb824e21 100644 --- a/docs/tool-catalog.i18n.yaml +++ b/docs/tool-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/tool-catalog.md -tool-catalog.md: 0166c7dd9829f0774c277508299726aac8426969 -tool-catalog.zh.md: 7722301c04febbd7b8d1c5509bfdb9e3881d0b76 +tool-catalog.md: 397e5aa402e9763bf3c5dc48ab95985292cc667a +tool-catalog.zh.md: 4ae7ebd2beb9376a4f6888e6bfc41fc9d278bfa8 diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index 0166c7dd98..397e5aa402 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -2063,7 +2063,7 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/sub ### `list_agents` -List your continuable background subagents by durable id and label. Use it to recall which ones you started, not to poll for completion — you are told when one finishes. Status comes from the live registry: running means the agent is working right now, idle means it is loaded but between turns (it may be waiting on agents it started), and ready means it exists only in storage — resumable, not terminal, and not a result waiting to be collected; a `send_message` steers a running child at its nearest step boundary or starts a turn for an idle or ready child, and a direct child remains a `send_message` candidate in every status. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped. Scope `descendants` walks the whole tree below you in stable pre-order, annotating each entry with its durable direct-parent session id and depth. You may use `send_message` only for depth-1 entries; deeper entries are candidates for `interrupt_agent` only. +List your continuable background subagents by durable id and label. Use it to recall which ones you started, not to poll for completion — you are told when one finishes. Status comes from the live registry: running means the agent is working right now, idle means it is loaded but between turns (it may be waiting on agents it started), and ready means it exists only in storage — resumable, not terminal, and not a result waiting to be collected; a `send_message` steers a running child at its nearest step boundary or starts a turn for an idle or ready child, and a direct child remains a `send_message` candidate in every status. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics only in `descendants` scope. Scope `descendants` walks the whole tree below you in stable pre-order, annotating each entry with its durable direct-parent session id and depth. You may use `send_message` only for depth-1 entries; deeper entries are candidates for `interrupt_agent` only. ```json { diff --git a/docs/tool-catalog.zh.md b/docs/tool-catalog.zh.md index 7722301c04..4ae7ebd2be 100644 --- a/docs/tool-catalog.zh.md +++ b/docs/tool-catalog.zh.md @@ -2069,7 +2069,7 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, ### `list_agents` -按持久 id 和标签列出你的可继续后台 subagent。用它回忆你启动过哪些 subagent,而不是轮询完成情况——subagent 完成时你会被告知。状态来自实时注册表:running 表示 agent 此刻正在工作;idle 表示已加载但处于轮次之间,可能正在等待它启动的 agent;ready 表示它只存在于存储中——可恢复而非终态,也不表示有结果等待收集;`send_message` 会在运行中 child 的最近 step 边界 steer 消息,或为 idle、ready child 启动轮次,且无论处于哪种状态,直接子级都仍可作为 `send_message` 的目标。该快照并非投递承诺;`send_message` 会执行权威检查,仍可能失败。无法读取的子级会作为诊断信息报告,而不会被静默丢弃。`descendants` 作用域会按稳定的前序顺序遍历你下方的整棵树,并为每个条目标注其持久的直接父会话 id 和深度。只有深度为 1 的条目可以使用 `send_message`;更深的条目只能作为 `interrupt_agent` 的候选目标。 +按持久 id 和标签列出你的可继续后台 subagent。用它回忆你启动过哪些 subagent,而不是轮询完成情况——subagent 完成时你会被告知。状态来自实时注册表:running 表示 agent 此刻正在工作;idle 表示已加载但处于轮次之间,可能正在等待它启动的 agent;ready 表示它只存在于存储中——可恢复而非终态,也不表示有结果等待收集;`send_message` 会在运行中 child 的最近 step 边界 steer 消息,或为 idle、ready child 启动轮次,且无论处于哪种状态,直接子级都仍可作为 `send_message` 的目标。该快照并非投递承诺;`send_message` 会执行权威检查,仍可能失败。无法读取的子级仅在 `descendants` 作用域中作为诊断信息报告。`descendants` 作用域会按稳定的前序顺序遍历你下方的整棵树,并为每个条目标注其持久的直接父会话 id 和深度。只有深度为 1 的条目可以使用 `send_message`;更深的条目只能作为 `interrupt_agent` 的候选目标。 ```json { diff --git a/packages/api/session-controller/README.i18n.yaml b/packages/api/session-controller/README.i18n.yaml index 54f3e511fd..57c8091841 100644 --- a/packages/api/session-controller/README.i18n.yaml +++ b/packages/api/session-controller/README.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 packages/api/session-controller/README.md -README.md: 772cec4f15da7150617b847824070b27749394ae -README.zh.md: 0f04e539d3eb389273b7b7950acf2dadcc5410bc +README.md: bc42c6520ddfb6af2bd68ab31d14caa424394c25 +README.zh.md: 0a79ebd6558d4a5d3e6e8342f88810ae59bf5f70 diff --git a/packages/api/session-controller/README.md b/packages/api/session-controller/README.md index 772cec4f15..bc42c6520d 100644 --- a/packages/api/session-controller/README.md +++ b/packages/api/session-controller/README.md @@ -28,9 +28,11 @@ History pages and follow opening snapshots carry one `{ type: 'event', event: Se The Client journal validates exact V3 event envelopes before publishing follow snapshots, live entries, or history pages. It reuses the browser-safe Session validators for required surface markers, exact replacement endpoints, earlier unique source seqs, embedded Assistant provider metadata, request-header omissions, and tool-error consistency. Invalid records fail without field stripping or normalization; range membership and source existence remain durable-log checks on the Host. -Each endpoint states its activation policy. List reads only stored headers and projection-cache rows: it never calls per-session stat or opens a cold Session body. A current-format cache identity may supply every list hint; a lifecycle-matching predecessor cache may supply only its version-compatible title as a stale display fact, never as an authoritative fold seed. Search, attachment, history pages, log following, skill discovery, and workspace-path opening can inspect persistence without activating an Agent; `canOpenWorkspacePath()` reports native-opening availability without addressing a Session. Cancellation requires live state; queue mutation, model, rename, prompt, and file-reference operations may resolve or resume an ordinary Session. Prompt rejects content with neither non-whitespace text nor an attachment before resolving the Agent or appending Session events; queue edits accept only non-empty text content. Prompt admission consumes opaque receipts from the injected [`fileUploads`](../../client/file-upload/README.md) Host service and resolves every same-Agent receipt before sending the complete ordered content list through `ctx.attachments`. Prompt retries whose `requestId` is already queued or logged return the original acceptance without inserting another message. Create and fork are the only operations that create a new Agent directly. The service applies one preset-aware resume policy and subagent ownership fence to its own methods and to the Typert Agent and Session lookups used by other Remote namespaces. Queue mutation has one narrow exception: a live child whose current projected identity is continuable and comes from its own non-seed suffix accepts the ordinary Edit, Remove, and QueueDock Steer actions across both inbox destinations. One-shot, missing, unknown, corrupt, seed-only, or cold children remain rejected without resume. The skill catalog uses a live Agent when present or the recorded preset's standing scope when cold, so listing never starts an Agent. The authenticated delivery routes use `workspaceDesktop()` for the serving Host name and file-manager behavior. `openWorkspacePath({ path, action: "reveal" })` delegates file-manager navigation to the native adapter; omitting `action` opens the default application. +Each endpoint states its activation policy. List reads only stored headers and projection-cache rows: it never calls per-session stat or opens a cold Session body. A current-format cache identity may supply every list hint; a lifecycle-matching predecessor cache may supply only its version-compatible title as a stale display fact, never as an authoritative fold seed. Search, attachment, history pages, log following, skill discovery, and workspace-path opening can inspect persistence without activating an Agent; `canOpenWorkspacePath()` reports native-opening availability without addressing a Session. Cancellation requires live state; queue mutation, model, rename, prompt, and file-reference operations may resolve or resume an ordinary Session. Prompt rejects content with neither non-whitespace text nor an attachment before resolving the Agent or appending Session events; queue edits accept only non-empty text content. Prompt admission consumes opaque receipts from the injected [`fileUploads`](../../client/file-upload/README.md) Host service and resolves every same-Agent receipt before sending the complete ordered content list through `ctx.attachments`. Prompt retries whose `requestId` is already queued or logged return the original acceptance without inserting another message. Create and fork are the only operations that create a new Agent directly. The service applies one preset-aware resume policy and subagent ownership fence to its own methods and to the Typert Agent and Session lookups used by other Remote namespaces. Queue mutation has one narrow exception: a live child whose current projected identity is continuable and comes from its own non-seed suffix accepts the ordinary Edit, Remove, and QueueDock Steer actions across both inbox destinations. One-shot, missing, unknown, corrupt, seed-only, or cold children remain rejected without resume. The skill catalog uses a live Agent when present or the recorded preset's standing scope when cold, so listing never starts an Agent. The authenticated delivery routes use `workspaceDesktop()` for the serving Host name and file-manager behavior. `openWorkspacePath({ path, action: "reveal" })` delegates file-manager navigation to the native adapter; omitting `action` opens the default application. `session.projections` reads one complete baseline through a live-preferred Session observation without activating an Agent. It returns null for a missing Session and serves any registered projection keys. The Client exposes shared values and explicit-read state through `projectionsBySession`; domains select their own keys. Session-list summaries carry `agentAvailable`, updated through existing summary and status events independently of durable projections. Initial reads and live projection frames use the same sequence ordering. -Client list refreshes retain unchanged row objects and reuse the items array when order and values match. Cache membership checks use a per-refresh ID set, so reconciliation grows linearly with the current list and retained cache sizes. +Client list refreshes retain unchanged row objects and reuse the items array when order and values match. Cache membership checks use a per-refresh ID set, so reconciliation grows linearly with the current list and retained cache sizes. Host summary updates replace running and Agent availability; local create/fork responses only fill missing metadata on existing rows. Removed ordinary Sessions retain projection stores only when their catalogs contain children. + +Projection reads retain loading and failure state independently of their values. Reconnect cancels reads from the previous connection and reloads previously requested projections; live membership updates arrive through the control stream. Parent availability comes from Host summaries and remains unknown until a summary or a successful list baseline establishes it. Address lookup resolves projected children without selecting them or creating scopes. The Client adapter exposes `SessionEventStream`, a Gateway `RemoteJournalStream` bound to one ordinary or direct-subagent address. It opens follow before the initial page, publishes only contiguous `replace`, `prepend`, `append`, and `settle-assistant` changes, and repairs reconnect or sequence gaps through a tail page. Backwards paging has two verbs: `loadOlder()` pulls one 50-message page, and `loadThrough(seq)` — the turn-jump loader — loops 200-message pages until the window covers the target seq, lowering a shared target on repeated calls, stopping on a page that makes no progress, and reporting busy through the same `loadingOlder` snapshot bit. The Web adapter explicitly opts into cursorless Assistant frames: each opening carries the active attempt's `startedAfterSeq`, `nextIndex`, and compact stream, and every stream member becomes a Client-only `assistant/live-chunk` entry ordered between durable cursors. The Host captures a follower-local arrival ordinal with that baseline and suppresses buffered frames at or before the cut; a replacement Agent may restart frame revision at one. A durable `assistant/message` or `assistant/attempt` arriving after an active opening stays staged only when its seq follows `startedAfterSeq` and its Turn and Step match; the matching end type, seq, and index publishes one named settlement delta that retires the attempt's transient rows and adds the durable entry while earlier same-step retries remain visible. Revision, dense-index, or settlement gaps for a known attempt reopen follow, while a controller that missed the start ignores unknown-attempt frames and publishes their durable settlement normally. An abandoned end publishes a settlement delta without a durable entry so its transient rows retire immediately. A durable gap-repair page has no Assistant baseline, so its held notification reopens follow once for a paired page and baseline. Every history record covers exactly its event seq. A business, persistence, or unresolved continuity failure terminates the stream, while only physical carrier loss selects automatic resumption. `SessionControlStream` is a Gateway `RemoteSnapshotStream`; every generation opens with a complete process-local baseline, so reconnect replaces jobs and projection state instead of treating transient values as durable events. At each ready Host generation, a synchronous Client subscription clears retained projection values and watermarks before refreshing queries and restarting the control stream, including Sessions absent from the control baseline. The first control stream waits for generation readiness, so its opening values cannot precede invalidation. Outstanding list responses from the previous generation cannot republish those values. Within a generation, a delayed control baseline cannot overwrite or clear newer list, history, or live values. The durable `inbox` projection carries both pending lists through the same cold-read and reconnect path as other projections. Client Agent contexts provide the identity used by the independent [`fileUpload`](../../client/file-upload/README.md) service; Session objects expose lifecycle, prompt, queue, and history operations rather than file transfer. diff --git a/packages/api/session-controller/README.zh.md b/packages/api/session-controller/README.zh.md index 0f04e539d3..0a79ebd655 100644 --- a/packages/api/session-controller/README.zh.md +++ b/packages/api/session-controller/README.zh.md @@ -28,9 +28,11 @@ kind: "package-reference" Client journal 在发布 follow 快照、live entry 或历史页之前验证精确的 V3 事件 envelope。它复用浏览器安全的 Session validator,检查必需的 surface marker、精确的 replacement endpoint、更早且唯一的 source seq、内嵌 Assistant 提供方元数据、request header 可选字段的省略规则以及工具错误一致性。无效 record 直接失败,不删除字段或归一化;范围成员与来源存在性仍由 Host 的持久日志检查。 -每个 endpoint 都声明自己的激活策略。列表只读取持久化 header 与 projection cache row,绝不调用逐 Session stat 或打开冷 Session body。当前格式 cache identity 可以提供全部列表 hint;生命周期匹配的 predecessor cache 只能提供版本兼容的 title,作为可能过时的展示事实,绝不能作为权威 fold seed。搜索、附件、历史页、日志跟随、skill 发现和工作区路径打开可以在不激活 Agent 的情况下检查 persistence;`canOpenWorkspacePath()` 无需指定 Session 即可报告原生打开能力。取消要求 live 状态;queue 变更、模型、重命名、prompt 和文件引用操作可以解析或恢复普通 Session。提示词会在解析 Agent 或追加 Session 事件前,拒绝既没有非空白文本也没有附件的 content;queue edit 只接受非空文本 content。prompt 准入从注入的 [`fileUploads`](../../client/file-upload/README.zh.md) Host 服务取得不透明凭证,在把完整有序内容列表交给 `ctx.attachments` 前解析每个属于同一 Agent 的凭证。`requestId` 已进入 queue 或日志时,prompt 重试直接返回原来的接受结果,不会重复插入消息。只有 create 与 fork 会直接创建新 Agent。该服务把同一套感知 preset 的恢复策略和 subagent ownership fence 同时用于自身方法,以及其他 Remote namespace 使用的 Typert Agent 与 Session lookup。Queue 变更只有一个狭窄例外:当前 projection identity 为 continuable 且来自自身非 seed suffix 的在线 child,可以在两个 inbox 目标上使用普通 Edit、Remove 与 QueueDock Steer action。One-shot、缺失、未知、损坏、仅含 seed identity 或冷 child 继续被拒绝,且不会恢复。skill 目录优先使用已有 live Agent,否则使用所记录 preset 的常驻 scope,因此列表查询绝不会启动 Agent。经过鉴权的文件交付路由通过 `workspaceDesktop()` 获取提供服务的 Host 名称和文件管理器行为。`openWorkspacePath({ path, action: "reveal" })` 将文件管理器导航委托给原生适配器;省略 `action` 时打开默认应用。 +每个 endpoint 都声明自己的激活策略。列表只读取持久化 header 与 projection cache row,绝不调用逐 Session stat 或打开冷 Session body。当前格式 cache identity 可以提供全部列表 hint;生命周期匹配的 predecessor cache 只能提供版本兼容的 title,作为可能过时的展示事实,绝不能作为权威 fold seed。搜索、附件、历史页、日志跟随、skill 发现和工作区路径打开可以在不激活 Agent 的情况下检查 persistence;`canOpenWorkspacePath()` 无需指定 Session 即可报告原生打开能力。取消要求 live 状态;queue 变更、模型、重命名、prompt 和文件引用操作可以解析或恢复普通 Session。提示词会在解析 Agent 或追加 Session 事件前,拒绝既没有非空白文本也没有附件的 content;queue edit 只接受非空文本 content。prompt 准入从注入的 [`fileUploads`](../../client/file-upload/README.zh.md) Host 服务取得不透明凭证,在把完整有序内容列表交给 `ctx.attachments` 前解析每个属于同一 Agent 的凭证。`requestId` 已进入 queue 或日志时,prompt 重试直接返回原来的接受结果,不会重复插入消息。只有 create 与 fork 会直接创建新 Agent。该服务把同一套感知 preset 的恢复策略和 subagent ownership fence 同时用于自身方法,以及其他 Remote namespace 使用的 Typert Agent 与 Session lookup。Queue 变更只有一个狭窄例外:当前 projection identity 为 continuable 且来自自身非 seed suffix 的在线 child,可以在两个 inbox 目标上使用普通 Edit、Remove 与 QueueDock Steer action。One-shot、缺失、未知、损坏、仅含 seed identity 或冷 child 继续被拒绝,且不会恢复。skill 目录优先使用已有 live Agent,否则使用所记录 preset 的常驻 scope,因此列表查询绝不会启动 Agent。经过鉴权的文件交付路由通过 `workspaceDesktop()` 获取提供服务的 Host 名称和文件管理器行为。`openWorkspacePath({ path, action: "reveal" })` 将文件管理器导航委托给原生适配器;省略 `action` 时打开默认应用。 `session.projections` 通过一次 live-preferred Session observation 读取完整基线,不激活 Agent。Session 不存在时返回 null,并可提供任意已注册的 projection key。Client 通过 `projectionsBySession` 暴露共享值和显式读取状态,由领域选择自身的 key。Session 列表摘要携带 `agentAvailable`,通过已有摘要与状态事件更新,与持久化 projection 相互独立。初始读取与实时 projection 帧使用相同的序号排序规则。 -Client 列表刷新保留未变化的行对象,并在顺序和值均相同时复用条目数组。缓存成员检查使用每次刷新构建的 ID 集合,因此对账成本随当前列表和保留缓存的规模线性增长。 +Client 列表刷新保留未变化的行对象,并在顺序和值均相同时复用条目数组。缓存成员检查使用每次刷新构建的 ID 集合,因此对账成本随当前列表和保留缓存的规模线性增长。 Host 摘要更新会替换运行状态与 Agent 可用性;本地 create/fork 响应只补充已有行缺失的元数据。普通 Session 被移除后,仅在目录仍有子项时保留其投影 store。 + +投影读取独立于其值保留加载与失败状态。重连会取消上一连接的读取,并重新加载已请求的投影;实时成员更新通过 control stream 到达。父 Agent 可用性来自 Host 摘要,在收到对应摘要或成功的列表 baseline 前保持未知。地址查找直接解析投影中的子项,不会选择它们或创建 scope。 Client 适配器提供 `SessionEventStream`,即绑定到一个普通 Session 或 direct subagent address 的 Gateway `RemoteJournalStream`。它在读取首个 page 前打开 follow,只发布连续的 `replace`、`prepend`、`append` 与 `settle-assistant` 变更,并通过 tail page 修复重连或 seq 缺口。向后分页有两个动词:`loadOlder()` 拉一页 50 条消息,而 `loadThrough(seq)`——轮次跳转加载器——按每页 200 条消息循环拉取直到窗口覆盖目标 seq,重复调用会下调共享目标,遇到无进展的页即停止,忙碌状态复用同一个 `loadingOlder` 快照位。Web 适配器显式选择接收无 cursor 的 Assistant frame:每个 opening 携带活跃 attempt 的 `startedAfterSeq`、`nextIndex` 与紧凑 stream,每个 stream member 都成为排在持久 cursor 之间的 Client-only `assistant/live-chunk` 条目。Host 会随该 baseline 捕获 follower 本地到达序号,并抑制该 cut 及之前的 buffered frame;replacement Agent 可以从 revision 一重新开始。活跃 opening 之后到达的持久 `assistant/message` 或 `assistant/attempt` 只有在其 seq 晚于 `startedAfterSeq` 且轮次与步骤匹配时才会保持暂存;匹配的 end type、seq 与 index 会发布一个具名 settlement delta,删除该 attempt 的瞬态 row、加入持久条目,并保留同一步骤中更早的 retry。已知 attempt 的 revision、密集 index 或 settlement 缺口会重新打开 follow;若 controller 错过 start,则忽略 unknown-attempt frame,并正常发布其持久 settlement。Abandoned end 会发布不含持久条目的 settlement delta,使瞬态 row 立即退出。持久缺口修复 page 不携带 Assistant baseline,因此 held notification 会重新打开 follow 一次,以取得配对的 page 与 baseline。每条历史 record 只覆盖自身的事件 seq。业务、persistence 或无法恢复的连续性错误会终止 stream,只有物理载体断开才触发自动恢复。`SessionControlStream` 是 Gateway `RemoteSnapshotStream`;每代都以完整的进程本地 baseline 开始,因此重连会替换 jobs 和 projection 状态,而不会把瞬态值当作 durable event。每次 Host generation 就绪时,同步的 Client 订阅会先清除保留的投影值及其水位,再刷新查询并重新打开 control stream,其中也包括 control baseline 中没有列出的 Session。首次 control stream 会等待 generation 就绪,确保其 opening 值不会先于旧状态清理到达。上一代尚未完成的 list 响应无法重新发布这些值。同一 generation 内,延迟到达的 control baseline 不能覆盖或清除较新的 list、history 或 live 值。持久 `inbox` 投影通过与其他投影相同的冷读取和重连路径传输两份待处理列表。Client Agent 上下文提供独立 [`fileUpload`](../../client/file-upload/README.zh.md) 服务使用的身份;Session 对象提供生命周期、prompt、queue 与历史操作,不提供文件传输。 diff --git a/packages/api/session-controller/src/client/contract/sessions.ts b/packages/api/session-controller/src/client/contract/sessions.ts index 08c13a208e..4918912887 100644 --- a/packages/api/session-controller/src/client/contract/sessions.ts +++ b/packages/api/session-controller/src/client/contract/sessions.ts @@ -50,21 +50,16 @@ export interface ISessions { /** * Resolve an already discovered direct-parent address without opening it. * @param id - possible addressed child id. - * @returns the retained address, when present. + * @returns a retained or loaded-catalog address, without retaining a new selection or scope. */ subagentAddress(id: SessionId): SubagentAddress | undefined + /** - * Mark whether a catalog menu is consuming live membership updates. - * @param parentSessionId - catalog owner. - * @param open - current menu state. - */ - setSubagentCatalogOpen(parentSessionId: SessionId, open: boolean): void - /** - * Refresh one direct-child catalog. - * @param parentSessionId - catalog owner. + * Load all Session projections once per connection; retry an unsuccessful initial read. + * @param sessionId - Session to inspect without opening its conversation. * @returns completion of the current or newly started refresh. */ - refreshSubagents(parentSessionId: SessionId): Promise + refreshProjections(sessionId: SessionId): Promise /** Clear the current selection into the no-session view state. */ clear(): void diff --git a/packages/api/session-controller/src/client/index.ts b/packages/api/session-controller/src/client/index.ts index 4f9c84ea4a..c7f75dfd3c 100644 --- a/packages/api/session-controller/src/client/index.ts +++ b/packages/api/session-controller/src/client/index.ts @@ -31,7 +31,7 @@ export type { SessionListPhase, SessionListSnapshot, SessionSearchResultItem, - SubagentCatalogSnapshot, + SessionProjectionSnapshot, } from './sessions/manager.ts' export type { Session } from './sessions/session.ts' export type { diff --git a/packages/api/session-controller/src/client/sessions/lineage.ts b/packages/api/session-controller/src/client/sessions/lineage.ts index 09551369b6..206628d2ab 100644 --- a/packages/api/session-controller/src/client/sessions/lineage.ts +++ b/packages/api/session-controller/src/client/sessions/lineage.ts @@ -68,8 +68,9 @@ export function flattenLineage( return } visited.add(s.sessionId) + const { agentAvailable: _agentAvailable, ...row } = s out.push({ - ...s, + ...row, completed: completed?.has(s.sessionId) ?? false, depth, }) diff --git a/packages/api/session-controller/src/client/sessions/manager.ts b/packages/api/session-controller/src/client/sessions/manager.ts index 4480402c4d..b8dbf6ddeb 100644 --- a/packages/api/session-controller/src/client/sessions/manager.ts +++ b/packages/api/session-controller/src/client/sessions/manager.ts @@ -2,7 +2,7 @@ // dispatch entry + list state, constructed and held by ClientSessions (one per browser client). // List data never enters zustand; React connects via subscribe/getListSnapshot. -import type { SubagentAddress, SubagentCatalog } from '@deepseek-ai/dsh-subagent/client' +import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client' import { SessionSeq, type SessionId, type SessionSeqCursor } from '@deepseek-ai/dsh-session/types' import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types' import type { @@ -21,6 +21,7 @@ import { flattenLineage } from './lineage.ts' // useProjection('title') consumer reads). Zero value imports by construction. import type {} from '@deepseek-ai/dsh-session-title/client' import { Notifier } from './notifier.ts' +import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types' import { ProjectionValueStore } from './projection-store.ts' import { Session } from './session.ts' import type { SessionRemotes } from './remotes.ts' @@ -54,38 +55,30 @@ export interface SessionListSnapshot { /** Arrival lifecycle (see {@link SessionListPhase}); `state` stays the pull-activity axis. */ phase: SessionListPhase error: RemoteFailure | null - subagentsByParent: Readonly> + projectionsBySession: Readonly> /** Background jobs per session; an absent key is an empty set. */ jobsBySession: Readonly> currentAddress: SubagentAddress | undefined } -/** One parent-addressed durable catalog projected through the sessions snapshot. */ -export type SubagentCatalogSnapshot = Omit & { - /** Absent until the first successful catalog read. */ - readonly parentAvailable?: boolean - state: 'loading' | 'ready' | 'error' - error: RemoteFailure | null +/** Shared projection values and the lifecycle of their explicit baseline read. */ +export interface SessionProjectionSnapshot { + readonly values: Readonly> + readonly state: 'idle' | 'loading' | 'ready' | 'error' + readonly error: RemoteFailure | null } -function catalogAvailability(parentAvailable: boolean | undefined): { - readonly parentAvailable?: boolean -} { - return parentAvailable === undefined ? {} : { parentAvailable } -} - -interface CatalogInflight { +interface ProjectionInflight { readonly promise: Promise - readonly expandableRows: Set - readonly activityRows: Map - /** Removal-time invalidation replayed over the response this request predates. */ - parentAvailableOverride: false | undefined + readonly controller: AbortController } +type ProjectionLoad = Omit + type SessionListMutation = - | { kind: 'upsert'; summary: SessionSummary } + | { kind: 'upsert' | 'placeholder'; summary: SessionSummary } | { kind: 'remove'; sessionId: SessionId } - | { kind: 'status'; sessionId: SessionId; running: boolean } + | { kind: 'status'; sessionId: SessionId; running: boolean; agentAvailable: boolean } | { kind: 'activity'; sessionId: SessionId; updatedAt: number } /** Local first-send flip: the sender clears blank without waiting for a host frame. */ | { kind: 'engaged'; sessionId: SessionId } @@ -117,12 +110,8 @@ export class SessionManager { /** Active list request's mutation log; its identity also fences completion after reconnect. */ private listMutations: SessionListMutation[] | null = null private readonly addresses = new Map() - private readonly catalogs = new Map() - private readonly catalogInflight = new Map() - /** Catalog owners whose membership changed while a pull was in flight: one trailing refresh after it settles. */ - private readonly catalogStale = new Set() - private readonly openCatalogs = new Set() - private readonly catalogDebounce = new Map>() + private readonly projectionLoads = new Map() + private readonly projectionInflight = new Map() /** * Background jobs per session, last-wins from Session Controller's control * stream. An empty set is stored as an absent key, so absence and `[]` are @@ -163,7 +152,7 @@ export class SessionManager { * @param sessionId - listed or catalog-addressed Session id. */ select(sessionId: SessionId): void { - const address = this.navigationAddress(sessionId) + const address = this.subagentAddress(sessionId) if (!this.summaries.some(summary => summary.sessionId === sessionId) && address === undefined) { throw new Error(`sessions.select: unknown session ${sessionId}`) } @@ -172,12 +161,11 @@ export class SessionManager { address, address === undefined ? undefined - : this.catalogs.get(address.parentSessionId)?.parentAvailable, + : this.agentAvailable(address.parentSessionId), ) this.selected = sessionId // Looking at the session consumes its completion reminder (dot clears). this.completedNotifications.delete(sessionId) - void this.refreshSubagents(sessionId) this.notifier.notifyNow() } @@ -186,16 +174,16 @@ export class SessionManager { * @param address - catalog-derived parent and child ids. */ selectSubagent(address: SubagentAddress): void { - const catalog = this.catalogs.get(address.parentSessionId) - const entry = catalog?.entries.find(candidate => candidate.id === address.childSessionId) - if (entry === undefined || entry.kind !== 'child' || entry.mode !== address.mode) { + const entries = this.projectionStores.get(address.parentSessionId)?.values().subagentCatalog + const entry = entries?.find(candidate => candidate.id === address.childSessionId) + if (entry === undefined + || entry.mode !== address.mode) { throw new Error(`sessions.selectSubagent: ${address.childSessionId} is not a healthy catalog child`) } this.addresses.set(address.childSessionId, address) - this.sessions.get(address.childSessionId)?.configureSubagent(address, catalog?.parentAvailable) + this.sessions.get(address.childSessionId)?.configureSubagent(address, this.agentAvailable(address.parentSessionId)) this.selected = address.childSessionId this.completedNotifications.delete(address.childSessionId) - void this.refreshSubagents(address.childSessionId) this.notifier.notifyNow() } @@ -205,27 +193,23 @@ export class SessionManager { this.notifier.notifyNow() } - /** - * Return the durable catalog address retained for one child. - * @param sessionId - possible addressed child id. - * @returns The direct-parent address, when navigation discovered one. - */ - subagentAddress(sessionId: SessionId): SubagentAddress | undefined { - return this.addresses.get(sessionId) - } - /** * Resolve an address for breadcrumb navigation without retaining transport authority. * @param sessionId - possible child id in an already-loaded catalog. * @returns A retained or catalog-derived direct-parent address. */ - navigationAddress(sessionId: SessionId): SubagentAddress | undefined { + subagentAddress(sessionId: SessionId): SubagentAddress | undefined { const retained = this.addresses.get(sessionId) if (retained !== undefined) return retained - for (const [parentSessionId, catalog] of this.catalogs) { - const child = catalog.entries.find(entry => entry.kind === 'child' && entry.id === sessionId) - if (child?.kind === 'child') { - return { parentSessionId, childSessionId: sessionId, mode: child.mode } + for (const parentSessionId of this.projectionStores.keys()) { + const child = this.projectionStores.get(parentSessionId)?.values().subagentCatalog + ?.find(entry => entry.id === sessionId) + if (child !== undefined) { + return { + parentSessionId, + childSessionId: sessionId, + mode: child.mode, + } } } return undefined @@ -250,10 +234,10 @@ export class SessionManager { * @returns when every Session Remote iterator has completed teardown. */ async dispose(): Promise { - for (const timer of this.catalogDebounce.values()) clearTimeout(timer) - this.catalogDebounce.clear() - this.catalogStale.clear() - this.openCatalogs.clear() + const reads = [...this.projectionInflight.values()] + for (const { controller } of reads) controller.abort() + this.projectionInflight.clear() + await Promise.all(reads.map(read => read.promise)) const sessions = [...this.sessions.values()] this.sessions.clear() for (const session of sessions) void this.startSessionDisposal(session) @@ -295,13 +279,13 @@ export class SessionManager { session.handleRunning(summary.running) } else { const address = this.addresses.get(sessionId) - const child = address === undefined ? undefined : this.catalogs.get(address.parentSessionId)?.entries - .find(entry => entry.kind === 'child' && entry.id === sessionId) - if (child?.kind === 'child') { + const child = address === undefined ? undefined : this.projectionStores.get(address.parentSessionId)?.values().subagentCatalog + ?.find(entry => entry.id === sessionId) + if (child !== undefined) { // A catalogued child exists only after its delegated session has // durable history, even though child rows do not carry `blank`. session.handleBlank(false) - session.handleRunning(child.activity === 'running') + session.handleRunning(false) } } } @@ -312,11 +296,11 @@ export class SessionManager { const address = this.addresses.get(sessionId) const parentAvailable = address === undefined ? undefined - : this.catalogs.get(address.parentSessionId)?.parentAvailable + : this.agentAvailable(address.parentSessionId) return new Session(sessionId, this.remote, { ...(address === undefined ? {} : { address, - ...catalogAvailability(parentAvailable), + ...parentAvailable === undefined ? {} : { parentAvailable }, }), // The sender's local first-send flip mirrors into the list row so the // session surfaces (lists filter on blank) before any host frame lands. @@ -341,101 +325,58 @@ export class SessionManager { } /** - * Refresh one direct-child catalog, reusing its in-flight request. - * @param parentSessionId - catalog owner. + * Load a complete projection baseline once per connection; retry unsuccessful reads. + * @param sessionId - Session to inspect without opening its conversation. + * @returns completion of the current or newly started read. */ - refreshSubagents(parentSessionId: SessionId): Promise { - const existing = this.catalogInflight.get(parentSessionId) + refreshProjections(sessionId: SessionId): Promise { + const existing = this.projectionInflight.get(sessionId) if (existing !== undefined) return existing.promise - const previous = this.catalogs.get(parentSessionId) - const expandableRows = new Set() - const activityRows = new Map() - this.catalogs.set(parentSessionId, { - entries: previous?.entries ?? [], - ...(previous?.parentAvailable === undefined - ? {} - : { parentAvailable: previous.parentAvailable }), - state: 'loading', - error: null, - }) + if (this.projectionLoads.get(sessionId)?.state === 'ready') return Promise.resolve() + const controller = new AbortController() + const store = this.projectionStore(sessionId) + const initialValues = store.values() + this.projectionLoads.set(sessionId, { state: 'loading', error: null }) this.notifier.markDirty() const operation = (async () => { try { - const result = await this.remote.subagents.list(parentSessionId) + const result = await this.remote.session.projections({ sessionId }, controller.signal) + if (controller.signal.aborted) return if (result.ok) { - const parentAvailable = this.catalogInflight.get(parentSessionId)?.parentAvailableOverride - ?? result.value.parentAvailable - this.catalogs.set(parentSessionId, { - ...result.value, - entries: this.withCatalogMutations(result.value.entries, expandableRows, activityRows), - parentAvailable, - state: 'ready', - error: null, - }) - for (const [childId, address] of this.addresses) { - if (address.parentSessionId !== parentSessionId) continue - this.sessions.get(childId)?.handleSubagentParentAvailable(parentAvailable) + if (result.value !== null) { + store.seed({ ...result.value, asOfSeq: sessionSeqCursor(result.value.asOfSeq) }) + } else if (store.values() === initialValues) { + // A later frame proves existence independently of an earlier missing read. + store.clear() } + this.projectionLoads.set(sessionId, { state: 'ready', error: null }) } else { - this.catalogs.set(parentSessionId, { - entries: this.withCatalogMutations( - previous?.entries ?? [], expandableRows, activityRows, - ), - ...catalogAvailability( - this.catalogInflight.get(parentSessionId)?.parentAvailableOverride - ?? previous?.parentAvailable, - ), - state: 'error', - error: result.error, - }) + this.projectionLoads.set(sessionId, { state: 'error', error: result.error }) } } catch (error: unknown) { + if (controller.signal.aborted) return if (!isRemoteFailure(error)) throw error - this.catalogs.set(parentSessionId, { - entries: this.withCatalogMutations( - previous?.entries ?? [], expandableRows, activityRows, - ), - ...catalogAvailability( - this.catalogInflight.get(parentSessionId)?.parentAvailableOverride - ?? previous?.parentAvailable, - ), - state: 'error', - error, - }) + this.projectionLoads.set(sessionId, { state: 'error', error }) } finally { - this.catalogInflight.delete(parentSessionId) - // Re-arm the trailing pull before the dirty notify: the response the - // caller observed predates the stale-marking change, so the follow-up - // refresh is the only carrier of that change. - if (this.catalogStale.delete(parentSessionId)) void this.refreshSubagents(parentSessionId) - this.notifier.markDirty() + if (!controller.signal.aborted) { + this.projectionInflight.delete(sessionId) + this.notifier.markDirty() + } } })() - this.catalogInflight.set(parentSessionId, { - promise: operation, - expandableRows, - activityRows, - parentAvailableOverride: undefined, - }) + this.projectionInflight.set(sessionId, { promise: operation, controller }) return operation } - /** - * Mark whether a catalog menu is consuming live membership updates. - * @param parentSessionId - catalog owner. - * @param open - current menu state. - */ - setSubagentCatalogOpen(parentSessionId: SessionId, open: boolean): void { - if (open) { - this.openCatalogs.add(parentSessionId) - void this.refreshSubagents(parentSessionId) - } else { - this.openCatalogs.delete(parentSessionId) - const timer = this.catalogDebounce.get(parentSessionId) - if (timer !== undefined) { - clearTimeout(timer) - this.catalogDebounce.delete(parentSessionId) - } + private agentAvailable(sessionId: SessionId): boolean | undefined { + return this.summaries.find(summary => summary.sessionId === sessionId)?.agentAvailable + ?? (this.listPhase === 'ready' ? false : undefined) + } + + private updateParentAvailability(): void { + for (const [childId, address] of this.addresses) { + const available = this.agentAvailable(address.parentSessionId) + if (available !== undefined) this.sessions.get(childId)?.handleSubagentParentAvailable(available) } } @@ -475,6 +416,7 @@ export class SessionManager { this.summaries = summaries this.listState = 'idle' this.listPhase = 'ready' + this.updateParentAvailability() // Covers the empty-mutations pull (a plain baseline carries no edge). this.syncCompletedNotifications() // Push running/blank bits down to instantiated Sessions (the list is the authoritative summary source). @@ -559,7 +501,7 @@ export class SessionManager { : { ...(opts.cwd === undefined ? {} : { cwd: opts.cwd }), ...shared } const result = await this.remote.session.create(payload) if (result.ok) { - this.recordMutation({ kind: 'upsert', summary: { + this.recordMutation({ kind: 'placeholder', summary: { agentAvailable: true, sessionId: result.value.sessionId, updatedAt: Date.now(), running: false, blank: true, ...(opts.cwd !== undefined ? { cwd: opts.cwd } : {}), } }) @@ -569,7 +511,7 @@ export class SessionManager { // so expose it immediately as Ungrouped while the caller keeps the // prompt buffer and decides whether to retry attachment. if (publishedSessionId !== undefined) { - this.recordMutation({ kind: 'upsert', summary: { + this.recordMutation({ kind: 'placeholder', summary: { agentAvailable: true, sessionId: publishedSessionId, updatedAt: Date.now(), running: false, @@ -601,7 +543,7 @@ export class SessionManager { ? result.value.sessionId : workspaceAttachSessionId(result.error) if (childId !== undefined) { - this.recordMutation({ kind: 'upsert', summary: { + this.recordMutation({ kind: 'placeholder', summary: { agentAvailable: true, sessionId: childId, updatedAt: Date.now(), running: false, blank: false, parentSessionId: opts.sessionId, ...(source?.cwd !== undefined ? { cwd: source.cwd } : {}), @@ -611,13 +553,12 @@ export class SessionManager { } /** - * Insert-or-enrich a locally synthesized summary: a new id prepends; an - * existing entry only gains fields it lacks (the session-added frame and the - * create() echo race — whichever lands second must fill the placeholder's - * missing cwd/parentSessionId, never overwrite list-refresh data). + * Merge a Host summary, replacing live state and filling missing metadata. + * Local create/fork placeholders only fill metadata on an existing row. */ private mergeSummary(summary: SessionSummary): void { this.recordMutation({ kind: 'upsert', summary }) + this.updateParentAvailability() } /** Apply immediately and retain for replay when a list response is in flight. */ @@ -698,13 +639,6 @@ export class SessionManager { store.apply(key, value, sessionSeqCursor(projections.asOfSeq)) } } - if (summary.origin === 'subagent' && summary.parentSessionId !== undefined) { - this.markCatalogParentExpandable(summary.parentSessionId) - } - if (summary.parentSessionId !== undefined - && (this.selected === summary.parentSessionId || this.openCatalogs.has(summary.parentSessionId))) { - this.scheduleCatalogRefresh(summary.parentSessionId) - } } /** @@ -712,25 +646,21 @@ export class SessionManager { * @param sessionId - removed Session identity. */ handleSessionRemoved(sessionId: SessionId): void { - const summary = this.summaries.find(candidate => candidate.sessionId === sessionId) - const durableSubagent = summary?.origin === 'subagent' || this.addresses.has(sessionId) + const durableSubagent = this.subagentAddress(sessionId) !== undefined + || this.summaries.some(summary => summary.sessionId === sessionId && summary.origin === 'subagent') this.recordMutation(durableSubagent - ? { kind: 'status', sessionId, running: false } + ? { kind: 'status', sessionId, running: false, agentAvailable: false } : { kind: 'remove', sessionId }) - this.updateCatalogActivity(sessionId, false) if (durableSubagent) this.sessions.get(sessionId)?.handleRunning(false) else this.sessions.get(sessionId)?.handleRemoved() this.jobsBySession.delete(sessionId) - if (!durableSubagent) this.projectionStores.delete(sessionId) - const inflightCatalog = this.catalogInflight.get(sessionId) - if (inflightCatalog !== undefined) { - inflightCatalog.parentAvailableOverride = false - this.catalogStale.add(sessionId) - } - const ownedCatalog = this.catalogs.get(sessionId) - if (ownedCatalog !== undefined && ownedCatalog.parentAvailable) { - this.catalogs.set(sessionId, { ...ownedCatalog, parentAvailable: false }) + const catalog = this.projectionStores.get(sessionId)?.values().subagentCatalog + if (!durableSubagent && (catalog === undefined || catalog.length === 0)) { + this.projectionStores.delete(sessionId) } + this.projectionInflight.get(sessionId)?.controller.abort() + this.projectionInflight.delete(sessionId) + this.projectionLoads.delete(sessionId) for (const [childId, address] of this.addresses) { if (address.parentSessionId === sessionId) { this.sessions.get(childId)?.handleSubagentParentAvailable(false) @@ -744,9 +674,9 @@ export class SessionManager { * @param running - current Agent running state. */ handleSessionStatus(sessionId: SessionId, running: boolean): void { - this.recordMutation({ kind: 'status', sessionId, running }) + this.recordMutation({ kind: 'status', sessionId, running, agentAvailable: true }) + this.updateParentAvailability() this.sessions.get(sessionId)?.handleRunning(running) - this.updateCatalogActivity(sessionId, running) } /** @@ -778,87 +708,14 @@ export class SessionManager { this.listMutations = null this.listInflight = null void this.refreshList() + const parents = new Set(this.projectionLoads.keys()) const selectedAddress = this.selected === undefined ? undefined : this.addresses.get(this.selected) - if (selectedAddress !== undefined) void this.refreshSubagents(selectedAddress.parentSessionId) - if (this.selected !== undefined) void this.refreshSubagents(this.selected) - for (const parentSessionId of this.openCatalogs) void this.refreshSubagents(parentSessionId) - } - - /** Debounce membership refetches while one parent catalog is selected or open. */ - private scheduleCatalogRefresh(parentSessionId: SessionId): void { - if (this.catalogDebounce.has(parentSessionId)) return - const timer = setTimeout(() => { - this.catalogDebounce.delete(parentSessionId) - // The in-flight response predates the membership frame that scheduled - // this callback. Queue one post-settlement pull instead of treating an - // ordinary overlapping read as evidence that catalog membership changed. - if (this.catalogInflight.has(parentSessionId)) { - this.catalogStale.add(parentSessionId) - return - } - void this.refreshSubagents(parentSessionId) - }, 50) - this.catalogDebounce.set(parentSessionId, timer) - } - - /** Apply one Agent-driver transition to loaded and in-flight catalogs. */ - private updateCatalogActivity(childSessionId: SessionId, running: boolean): void { - const activity = running ? 'running' as const : 'inactive' as const - for (const inflight of this.catalogInflight.values()) { - inflight.activityRows.set(childSessionId, activity) - } - let changed = false - for (const [parentSessionId, catalog] of this.catalogs) { - if (!catalog.entries.some(entry => - entry.kind === 'child' && entry.id === childSessionId && entry.activity !== activity)) continue - const entries = catalog.entries.map((entry) => { - if (entry.kind !== 'child' || entry.id !== childSessionId) return entry - return { ...entry, activity } - }) - changed = true - this.catalogs.set(parentSessionId, { ...catalog, entries }) - } - if (changed) this.notifier.markDirty() - } - - /** Preserve and project a positive expandability hint after one direct subagent publishes. */ - private markCatalogParentExpandable(parentSessionId: SessionId): void { - this.applyCatalogParentExpandable(parentSessionId) - for (const inflight of this.catalogInflight.values()) inflight.expandableRows.add(parentSessionId) - } - - /** Apply one positive expandability hint to every loaded catalog containing that unique row id. */ - private applyCatalogParentExpandable(parentSessionId: SessionId): void { - let changed = false - for (const [catalogParentId, catalog] of this.catalogs) { - if (!catalog.entries.some(entry => - entry.kind === 'child' && entry.id === parentSessionId && !entry.hasChildren)) continue - const entries = catalog.entries.map((entry) => { - if (entry.kind !== 'child' || entry.id !== parentSessionId || entry.hasChildren) return entry - return { ...entry, hasChildren: true } - }) - changed = true - this.catalogs.set(catalogParentId, { ...catalog, entries }) - } - if (changed) this.notifier.markDirty() - } - - /** Fold request-local row mutations into one catalog result before publication. */ - private withCatalogMutations( - entries: SubagentCatalog['entries'], - expandableRows: ReadonlySet, - activityRows: ReadonlyMap, - ): SubagentCatalog['entries'] { - return entries.map((entry) => { - if (entry.kind !== 'child') return entry - const activity = activityRows.get(entry.id) - if (!expandableRows.has(entry.id) && activity === undefined) return entry - return { - ...entry, - ...expandableRows.has(entry.id) ? { hasChildren: true } : {}, - ...activity === undefined ? {} : { activity }, - } - }) + if (selectedAddress !== undefined) parents.add(selectedAddress.parentSessionId) + if (this.selected !== undefined) parents.add(this.selected) + for (const { controller } of this.projectionInflight.values()) controller.abort() + this.projectionInflight.clear() + this.projectionLoads.clear() + for (const parentSessionId of parents) void this.refreshProjections(parentSessionId) } /** @@ -937,7 +794,10 @@ export class SessionManager { state: this.listState, phase: this.listPhase, error: this.listError, - subagentsByParent: Object.fromEntries(this.catalogs), + projectionsBySession: Object.fromEntries([...this.projectionStores].map(([sessionId, store]) => [ + sessionId, + { values: store.values(), state: 'idle', error: null, ...this.projectionLoads.get(sessionId) }, + ])), jobsBySession: Object.fromEntries(this.jobsBySession), currentAddress: current === undefined ? undefined : this.addresses.get(current), } @@ -947,7 +807,8 @@ export class SessionManager { /** Apply one list mutation without deriving display order. */ function applyMutation(summaries: readonly SessionSummary[], mutation: SessionListMutation): SessionSummary[] { switch (mutation.kind) { - case 'upsert': { + case 'upsert': + case 'placeholder': { const existing = summaries.find(summary => summary.sessionId === mutation.summary.sessionId) if (existing === undefined) return [mutation.summary, ...summaries] const filled: SessionSummary = { @@ -955,6 +816,10 @@ function applyMutation(summaries: readonly SessionSummary[], mutation: SessionLi // Blank only lowers: a stale true (session-added racing the local // first send) never re-hides an already-surfaced session. blank: existing.blank && mutation.summary.blank, + ...(mutation.kind === 'upsert' ? { + agentAvailable: mutation.summary.agentAvailable, + running: mutation.summary.running, + } : {}), ...(existing.cwd === undefined && mutation.summary.cwd !== undefined ? { cwd: mutation.summary.cwd } : {}), ...(existing.parentSessionId === undefined && mutation.summary.parentSessionId !== undefined ? { parentSessionId: mutation.summary.parentSessionId } : {}), @@ -963,6 +828,7 @@ function applyMutation(summaries: readonly SessionSummary[], mutation: SessionLi } if (filled.cwd === existing.cwd && filled.parentSessionId === existing.parentSessionId && filled.origin === existing.origin && filled.blank === existing.blank + && filled.agentAvailable === existing.agentAvailable && filled.running === existing.running ) return [...summaries] return summaries.map(summary => summary.sessionId === mutation.summary.sessionId ? filled : summary) } @@ -972,8 +838,9 @@ function applyMutation(summaries: readonly SessionSummary[], mutation: SessionLi // running:true doubles as the cross-client blank flip (a blank session // never runs, so the first running frame proves a message landed). return summaries.map(summary => summary.sessionId === mutation.sessionId - && (summary.running !== mutation.running || (mutation.running && summary.blank)) - ? { ...summary, running: mutation.running, blank: summary.blank && !mutation.running } + && (summary.running !== mutation.running + || summary.agentAvailable !== mutation.agentAvailable || (mutation.running && summary.blank)) + ? { ...summary, running: mutation.running, agentAvailable: mutation.agentAvailable, blank: summary.blank && !mutation.running } : summary) case 'activity': return summaries.map(summary => summary.sessionId === mutation.sessionId diff --git a/packages/api/session-controller/src/client/sessions/remotes.ts b/packages/api/session-controller/src/client/sessions/remotes.ts index c2e585514b..8e084384d4 100644 --- a/packages/api/session-controller/src/client/sessions/remotes.ts +++ b/packages/api/session-controller/src/client/sessions/remotes.ts @@ -9,7 +9,7 @@ import type { ClientRemote } from '@deepseek-ai/dsh-api-gateway/client' import type { CommandSubmitAttachment } from '@deepseek-ai/dsh-commands/types' import type { SessionId } from '@deepseek-ai/dsh-session/types' import type { - SubagentCatalog, SubagentInterruptReceipt, SubagentPromptReceipt, SubagentPromptRequest, + SubagentInterruptReceipt, SubagentPromptReceipt, SubagentPromptRequest, } from '@deepseek-ai/dsh-subagent/client' import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol' import type { SessionRemote } from '../transport.ts' @@ -26,7 +26,6 @@ export interface SessionCommandsRemote { /** Narrow subagent namespace consumed by a Client Session and its manager. */ export interface SessionSubagentsRemote { - list(parentSessionId: SessionId, signal?: AbortSignal): Promise> prompt( request: SubagentPromptRequest, signal?: AbortSignal, diff --git a/packages/api/session-controller/src/client/sessions/service.ts b/packages/api/session-controller/src/client/sessions/service.ts index d1d840c513..0f65e945cc 100644 --- a/packages/api/session-controller/src/client/sessions/service.ts +++ b/packages/api/session-controller/src/client/sessions/service.ts @@ -32,7 +32,7 @@ import type { AgentContext, ISessions } from '../contract/sessions.ts' import { createScope, scopeOf as scopeTagOf } from '../scope.ts' import { SessionManager } from './manager.ts' import type { SessionRemotes } from './remotes.ts' -import type { SessionListPhase, SessionSearchResultItem, SubagentCatalogSnapshot } from './manager.ts' +import type { SessionListPhase, SessionSearchResultItem, SessionProjectionSnapshot } from './manager.ts' import type { Session } from './session.ts' /** Session list row projected from the host list RPC plus live stream increments. */ @@ -74,8 +74,8 @@ export interface SessionListState { current: SessionId | undefined /** Arrival lifecycle projected 1:1 from the manager snapshot (see SessionListPhase): empty-with-ready means "truly no sessions". */ phase: SessionListPhase - /** Direct durable catalogs keyed by their selected parent address. */ - subagentsByParent: Readonly> + /** Shared projection values and explicit-read state, including unopened Sessions. */ + projectionsBySession: Readonly> /** * Background jobs each session can see, mirrored last-wins from Session * Controller's control baseline and `jobs` frames. A missing key is an empty @@ -233,7 +233,7 @@ export class ClientSessions implements ISessions { ) this.list = createSnapshotStore({ ids: [], byId: {}, current: undefined, phase: 'pending', - subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) // The manager owns wire truth; the store is its projection. Manager // notifications are already microtask-batched. @@ -283,27 +283,18 @@ export class ClientSessions implements ISessions { * Resolve an already discovered direct-parent address without opening it. * Feature plugins use this to avoid Agent-bound RPCs in persisted child views. * @param id - possible addressed child id. - * @returns The retained address, when present. + * @returns A retained or loaded-catalog address, without retaining a new selection or scope. */ subagentAddress(id: SessionId): SubagentAddress | undefined { return this.manager.subagentAddress(id) } /** - * Inform the Session Controller whether a catalog menu is consuming membership updates. - * @param parentSessionId - selected parent. - * @param open - menu state. + * Load all Session projections once per connection; retry an unsuccessful initial read. + * @param sessionId - Session to inspect without opening its conversation. */ - setSubagentCatalogOpen(parentSessionId: SessionId, open: boolean): void { - this.manager.setSubagentCatalogOpen(parentSessionId, open) - } - - /** - * Refresh one direct-child catalog. - * @param parentSessionId - catalog owner. - */ - refreshSubagents(parentSessionId: SessionId): Promise { - return this.manager.refreshSubagents(parentSessionId) + refreshProjections(sessionId: SessionId): Promise { + return this.manager.refreshProjections(sessionId) } /** @@ -532,7 +523,6 @@ export class ClientSessions implements ISessions { * cannot miss; kept so a future current writer cannot crash the notify. */ if (record !== undefined) { void record.session.open() - void this.manager.refreshSubagents(current) } } @@ -576,7 +566,7 @@ export class ClientSessions implements ISessions { /** Project the manager's list snapshot into the store (title derivation is display-only). */ private projectList(): void { const { - items, current, phase, subagentsByParent, jobsBySession, currentAddress, + items, current, phase, projectionsBySession, jobsBySession, currentAddress, } = this.manager.getListSnapshot() const ids: SessionId[] = [] const byId: Record = {} @@ -604,9 +594,9 @@ export class ClientSessions implements ISessions { while (address !== undefined && !seen.has(address.childSessionId)) { const childId = address.childSessionId seen.add(childId) - const child = subagentsByParent[address.parentSessionId]?.entries - .find(entry => entry.kind === 'child' && entry.id === childId) - if (child?.kind !== 'child') break + const child = projectionsBySession[address.parentSessionId]?.values.subagentCatalog + ?.find(entry => entry.id === childId) + if (child === undefined) break const displayTitle = child.label ?? childId const summary = byId[childId] if (summary === undefined) { @@ -615,16 +605,14 @@ export class ClientSessions implements ISessions { displayTitle, parentId: address.parentSessionId, origin: 'subagent', - running: child.activity === 'running', + running: false, blank: false, updatedAt: 0, } } else if (summary.displayTitle !== displayTitle) { byId[childId] = { ...summary, displayTitle } } - const parent = byId[address.parentSessionId] - if (parent !== undefined && parent.origin !== 'subagent') break - address = this.manager.navigationAddress(address.parentSessionId) + address = this.manager.subagentAddress(address.parentSessionId) } } const persisted = this.selection.getSnapshot().sessionId @@ -642,7 +630,7 @@ export class ClientSessions implements ISessions { ...(currentAddress === undefined ? {} : { subagentAddress: currentAddress }), }) } - this.list.set({ ids, byId, current, phase, subagentsByParent, jobsBySession, currentAddress }) + this.list.set({ ids, byId, current, phase, projectionsBySession, jobsBySession, currentAddress }) this.pruneScopes() } diff --git a/packages/api/session-controller/src/client/sessions/session.ts b/packages/api/session-controller/src/client/sessions/session.ts index 3c401cc3e7..1b23423061 100644 --- a/packages/api/session-controller/src/client/sessions/session.ts +++ b/packages/api/session-controller/src/client/sessions/session.ts @@ -57,7 +57,7 @@ export const JUMP_PAGE_MESSAGES = 200 export interface SessionOptions { /** Catalog-discovered address selecting non-activating subagent transport. */ address?: SubagentAddress - /** Whether the exact direct parent Agent was live at the latest catalog read; absent before that read. */ + /** Whether the exact direct parent Agent is available in Host summaries; absent until known. */ parentAvailable?: boolean /** * First ACCEPTED prompt on a blank session (fires at most once, on the diff --git a/packages/api/session-controller/src/index.ts b/packages/api/session-controller/src/index.ts index f13f24f7dc..0b06db2f51 100644 --- a/packages/api/session-controller/src/index.ts +++ b/packages/api/session-controller/src/index.ts @@ -1,6 +1,7 @@ /** Session Remote owner: cold reads, explicit Agent commands, and live control state. */ import { hostname } from 'node:os' +import type { Agent } from '@deepseek-ai/dsh-agent' import { Context } from '@deepseek-ai/cordis' import z from '@deepseek-ai/schemastery' import { errorChain } from '@deepseek-ai/dsh-llm' @@ -8,7 +9,7 @@ import type {} from '@deepseek-ai/dsh-client-file-upload' import { canOpenNativePath, nativeFileManager, openNativePath, revealNativePath } from '@deepseek-ai/dsh-native-command' import type { SessionId } from '@deepseek-ai/dsh-session' import type { SessionInspection } from '@deepseek-ai/dsh-session-persistence' -import type { SessionObservation } from '@deepseek-ai/dsh-session-query' +import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query' import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol' import { ApiSessionAgentController, @@ -51,6 +52,9 @@ import type { SessionSearchValue, SessionSelectModelRequest, SessionSelectModelValue, + SessionProjectionsRequest, + SessionProjectionsValue, + SessionProjectionValues, SessionUpdateQueueRequest, SessionUpdateQueueValue, } from './types.ts' @@ -149,6 +153,13 @@ export class SessionController extends TypertRemoteService { ctx.on('session/disposed', (session) => { ctx.emit('api-session/removed', session.id) }) + const publishAgentAvailability = ({ agent }: { agent: Agent }): undefined => { + if (ctx.sessions.get(agent.id) === agent.session) { + ctx.emit('api-session/added', this.listState.summaryFor(agent.session)) + } + } + ctx.on('agent/created', publishAgentAvailability) + ctx.on('agent/disposed', publishAgentAvailability) ctx.on('agent/status', ({ agent, status }) => { ctx.emit('api-session/status', agent.id, status === 'running') }) @@ -402,6 +413,36 @@ export class SessionController extends TypertRemoteService { return this.history.follow(request, signal) } + /** + * Read all registered projections without activating an Agent. + * @param request - Session whose current values are required. + * @param signal - cancellation for the Session observation. + * @returns complete baseline, or null when the Session does not exist. + */ + @Remote('projections') + async projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise { + const { sessionId } = request + if (sessionId.length === 0) { + throw new RemoteError('gateway/bad-request', 'sessionId must not be empty', {}) + } + try { + using observation = await this.ctx.sessionQuery.observeSession(sessionId, { signal }) + const projections = observation.projections + if (projections === undefined) { + throw new RemoteError('session/projections-unavailable', 'Session projections are unavailable', {}) + } + return { asOfSeq: projections.asOfSeq, values: projections.values as SessionProjectionValues } + } catch (error: unknown) { + if (error instanceof SessionQueryError && error.code === 'SESSION_QUERY_SESSION_NOT_FOUND') return null + if (signal.aborted + || (error instanceof SessionQueryError && error.code === 'SESSION_QUERY_ABORTED')) { + throw new RemoteError('gateway/cancelled', 'Session projection read was cancelled', {}, { cause: error }) + } + if (error instanceof RemoteError) throw error + throw new RemoteError('gateway/internal', 'Session projection read failed', {}, { cause: error }) + } + } + /** * Stream a complete live-control baseline followed by replacement frames. * @param signal - cancellation owned by the Remote stream carrier. diff --git a/packages/api/session-controller/src/list.ts b/packages/api/session-controller/src/list.ts index 4aa369c378..530414c52d 100644 --- a/packages/api/session-controller/src/list.ts +++ b/packages/api/session-controller/src/list.ts @@ -111,6 +111,7 @@ export class ApiSessionList { return { sessionId: session.id, updatedAt: updatedAt(session.header, metadata), + agentAvailable: this.ctx.agents.get(session.id)?.session === session, running: this.ctx.agents.get(session.id)?.status === 'running', blank: metadata?.blank ?? session.seq === 0, ...listFields(session.header), @@ -149,6 +150,7 @@ export class ApiSessionList { return { sessionId: header.id, updatedAt: updatedAt(header, metadata), + agentAvailable: false, running: false, // A large, metadata-less, or inaccessible cache miss remains unknown and visible. blank: metadata?.blank ?? false, diff --git a/packages/api/session-controller/src/types.ts b/packages/api/session-controller/src/types.ts index bc8af2514f..7457da533b 100644 --- a/packages/api/session-controller/src/types.ts +++ b/packages/api/session-controller/src/types.ts @@ -161,6 +161,8 @@ export type QueueAction = /** One Session list entry. */ export interface SessionSummary { + /** Whether this Session currently owns a live Agent. */ + readonly agentAvailable: boolean readonly sessionId: SessionId readonly updatedAt: number readonly running: boolean @@ -191,6 +193,7 @@ declare module '@deepseek-ai/dsh-typert-protocol' { readonly requestedCwd: string readonly existingCwd?: string } + 'session/projections-unavailable': Record 'session/agent-busy': { readonly reason: string } 'session/invalid-time-zone': { readonly value: string } 'session/workspace-attach-failed': { readonly sessionId: SessionId; readonly workspaceId: string } @@ -391,6 +394,14 @@ export type SessionAddress = readonly mode: 'one-shot' | 'continuable' } +/** One non-activating Session projection read. */ +export interface SessionProjectionsRequest { + readonly sessionId: SessionId +} + +/** Complete Session projection baseline; null when the Session does not exist. */ +export type SessionProjectionsValue = SessionProjectionBaseline | null + /** One raw Session event in the Remote journal. */ export interface SessionEventEntry { readonly type: 'event' @@ -559,9 +570,10 @@ export type SessionControlFrame = declare module '@deepseek-ai/cordis' { interface Events { /** - * A Session became visible to Session list consumers. + * A Session became visible or its Agent was created or disposed. + * Consumers upsert the summary and replace its current running and availability state. * @mode emit - * @param summary - initial list row for the Session. + * @param summary - current list row for the Session. */ 'api-session/added'(summary: SessionSummary): void /** diff --git a/packages/api/session-controller/tests/client-apply.client.spec.ts b/packages/api/session-controller/tests/client-apply.client.spec.ts index ee973fc05f..f7a0f98c03 100644 --- a/packages/api/session-controller/tests/client-apply.client.spec.ts +++ b/packages/api/session-controller/tests/client-apply.client.spec.ts @@ -51,7 +51,7 @@ describe('Session Controller Client apply', () => { // The first generation's `connection/reset` already ran it; apply itself saw no Host yet. await vi.waitFor(() => { expect(connected).toHaveBeenCalledOnce() }) - await emit(mock, 'api-session/added', { sessionId: sid('session-1'), updatedAt: 1, running: false, blank: true }) + await emit(mock, 'api-session/added', { agentAvailable: true, sessionId: sid('session-1'), updatedAt: 1, running: false, blank: true }) await vi.waitFor(() => { expect(sessions.list.getSnapshot().byId[sid('session-1')]).toMatchObject({ running: false, updatedAt: 1 }) }) @@ -84,7 +84,7 @@ describe('Session Controller Client apply', () => { const connected = vi.spyOn(ClientSessions.prototype, 'handleConnected') const sessionId = sid('immediate-baseline') mock.remote.session.list.mockResolvedValue(ok({ items: [{ - sessionId, updatedAt: 1, running: false, blank: false, + sessionId, updatedAt: 1, running: false, blank: false, agentAvailable: true, }] })) let projection = { asOfSeq: 20, values: { title: 'Before restart' } } mock.stream(CONTROL, (_args, stream) => { @@ -150,7 +150,7 @@ describe('Session Controller Client apply', () => { const { client, sessions } = await bench(start) await vi.waitFor(() => { expect(sessions.list.getSnapshot().phase).toBe('ready') }) - await emit(mock, 'api-session/added', { sessionId: sid('agent-1'), updatedAt: 1, running: false, blank: true }) + await emit(mock, 'api-session/added', { agentAvailable: true, sessionId: sid('agent-1'), updatedAt: 1, running: false, blank: true }) await vi.waitFor(() => { expect(sessions.scope(sid('agent-1'))).toBeDefined() }) const scoped = sessions.scope(sid('agent-1')) as Context const adapter = client.ctx.typert.contexts.getClient('agent') diff --git a/packages/api/session-controller/tests/inbox-projection.client.spec.ts b/packages/api/session-controller/tests/inbox-projection.client.spec.ts index 9f4ebfecda..589aa43d09 100644 --- a/packages/api/session-controller/tests/inbox-projection.client.spec.ts +++ b/packages/api/session-controller/tests/inbox-projection.client.spec.ts @@ -63,7 +63,7 @@ describe('Inbox projection intake', () => { const empty = { 'next-turn': [], 'next-step': [] } const stale = { ...empty, 'next-turn': [message('removed', 'already removed')] } const result = ok({ items: [{ - sessionId: SID, updatedAt: 1, running: false, blank: false, + sessionId: SID, updatedAt: 1, running: false, blank: false, agentAvailable: false, projections: { asOfSeq: 21, values: { inbox: empty } }, }] }) let refreshed: Promise | undefined @@ -108,9 +108,9 @@ describe('Inbox projection intake', () => { const face = manager.get(SID).projections.faceOf('inbox') const baseline = { type: 'baseline', value: { jobs: {}, projections: {} } } as const const result = ok({ items: [ - { sessionId: SID, updatedAt: 1, running: false, blank: false, + { sessionId: SID, updatedAt: 1, running: false, blank: false, agentAvailable: false, projections: { asOfSeq: 1, values: { inbox: empty } } }, - { sessionId: hiddenSessionId, updatedAt: 1, running: false, blank: false, + { sessionId: hiddenSessionId, updatedAt: 1, running: false, blank: false, agentAvailable: false, projections: { asOfSeq: 1, values: { inbox: restored } } }, ] }) let refreshed: Promise | undefined diff --git a/packages/api/session-controller/tests/lineage.client.spec.ts b/packages/api/session-controller/tests/lineage.client.spec.ts index b15b89e61b..bef0085962 100644 --- a/packages/api/session-controller/tests/lineage.client.spec.ts +++ b/packages/api/session-controller/tests/lineage.client.spec.ts @@ -7,7 +7,7 @@ import { describe, expect, it, vi } from 'vitest' import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-api-remotes/client' import { flattenLineage } from '../src/client/sessions/lineage.ts' -const s = (id: string, updatedAt: number, parent?: string): SessionSummary => ({ +const s = (id: string, updatedAt: number, parent?: string): SessionSummary => ({ agentAvailable: true, sessionId: id as SessionId, updatedAt, running: false, blank: false, ...(parent !== undefined ? { parentSessionId: parent as SessionId } : {}), }) diff --git a/packages/api/session-controller/tests/manager.client.spec.ts b/packages/api/session-controller/tests/manager.client.spec.ts index c33a4a28c0..75e2e30014 100644 --- a/packages/api/session-controller/tests/manager.client.spec.ts +++ b/packages/api/session-controller/tests/manager.client.spec.ts @@ -24,12 +24,11 @@ const S2 = 'fk-m2' as SessionId /** Gateway Client cone used by the subagent-catalog and connected-generation cases. */ const API_ROSTER = webApp.closure(['@deepseek-ai/dsh-api-gateway']) const it = createClientTest({ roster: API_ROSTER }) -/** The first client boot pays the cold module transform of the api cone. */ -const COLD_BOOT_TIMEOUT_MS = 60_000 type SummaryOver = Partial<{ updatedAt: number running: boolean + agentAvailable: boolean blank: boolean cwd: string parentSessionId: SessionId @@ -37,7 +36,7 @@ type SummaryOver = Partial<{ }> function summary(sessionId: SessionId, over: SummaryOver = {}) { - return { sessionId, updatedAt: 100, running: false, blank: false, ...over } + return { agentAvailable: true, sessionId, updatedAt: 100, running: false, blank: false, ...over } } function makeManager( @@ -263,29 +262,29 @@ describe('Host Remote event routing', () => { describe('subagent catalogs', () => { it('keeps a catalog-discovered child address across ordinary selection and status frames', async ({ mock, remote, start }) => { - remote.session.list.mockResolvedValue(ok({ items: [ + remote.session.list.mockImplementation(() => Promise.resolve(ok({ items: [ summary(S1), summary(S2, { parentSessionId: S1, origin: 'subagent' }), - ] as never[] })) - remote.subagents.list.mockResolvedValue(ok({ - entries: [{ - kind: 'child', id: S2, mode: 'continuable', label: 'worker', - activity: 'running', hasChildren: false, - }] as never[], - parentAvailable: true, - })) + ] as never[] }))) + remote.session.projections.mockImplementation(() => Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, + id: S2, mode: 'continuable', label: 'worker', + }] } }))) mock.load(sessionWorld) const client = await start() const manager = new SessionManager(client.ctx.remote) await manager.refreshList() - await manager.refreshSubagents(S1) - manager.selectSubagent({ parentSessionId: S1, childSessionId: S2, mode: 'continuable' }) + await manager.refreshProjections(S1) + manager.selectSubagent({ + parentSessionId: S1, childSessionId: S2, mode: 'continuable', + }) expect(manager.getListSnapshot().currentAddress).toEqual({ parentSessionId: S1, childSessionId: S2, mode: 'continuable', }) expect(manager.get(S2).getSnapshot().subagent).toEqual({ - address: { parentSessionId: S1, childSessionId: S2, mode: 'continuable' }, + address: { + parentSessionId: S1, childSessionId: S2, mode: 'continuable', + }, parentAvailable: true, }) // Clicking the same child through an ordinary list-selection path must not @@ -295,21 +294,26 @@ describe('subagent catalogs', () => { parentSessionId: S1, childSessionId: S2, mode: 'continuable', }) expect(manager.get(S2).getSnapshot().subagent).toEqual({ - address: { parentSessionId: S1, childSessionId: S2, mode: 'continuable' }, + address: { + parentSessionId: S1, childSessionId: S2, mode: 'continuable', + }, parentAvailable: true, }) await manager.get(S2).open() await manager.get(S2).prompt([{ type: 'text', text: 'continue' }], 'queue') - expect(remote.session.follow.mock.calls.map(([request]) => request)).toEqual([ + expect(mock.log.requests(FOLLOW)).toEqual([ { address: { - kind: 'subagent', parentSessionId: S1, childSessionId: S2, mode: 'continuable', + kind: 'subagent', + parentSessionId: S1, + childSessionId: S2, + mode: 'continuable', }, assistantStream: true, maxMessages: 50, }, ]) - expect(remote.session.page).not.toHaveBeenCalled() + expect(mock.log.requests('session/page')).toEqual([]) expect(remote.subagents.prompt.mock.calls.map(([request]) => request)).toEqual([ { requestId: expect.any(String) as unknown as string, @@ -320,13 +324,14 @@ describe('subagent catalogs', () => { clientTimeZone: new Intl.DateTimeFormat().resolvedOptions().timeZone, }, ]) - expect(remote.session.prompt).not.toHaveBeenCalled() - const listCalls = remote.subagents.list.mock.calls.length + expect(mock.log.requests('session/page')).toEqual([]) + expect(remote.session.prompt.mock.calls.map(([request]) => request)).toEqual([]) + const listCalls = remote.session.projections.mock.calls.map(([request]) => request).length manager.handleSessionStatus(S2, false) - expect(manager.getListSnapshot().subagentsByParent[S1]?.entries[0]).toMatchObject({ - kind: 'child', id: S2, activity: 'inactive', + expect(manager.getListSnapshot().projectionsBySession[S1]?.values.subagentCatalog?.[0]).toMatchObject({ + id: S2, }) - expect(remote.subagents.list).toHaveBeenCalledTimes(listCalls) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(listCalls) manager.handleSessionRemoved(S2) expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)).toMatchObject({ @@ -335,274 +340,170 @@ describe('subagent catalogs', () => { expect(manager.get(S2).getSnapshot()).toMatchObject({ removed: false, subagent: { - address: { parentSessionId: S1, childSessionId: S2, mode: 'continuable' }, + address: { + parentSessionId: S1, childSessionId: S2, mode: 'continuable', + }, }, }) - }, COLD_BOOT_TIMEOUT_MS) - - it('refetches debounced membership only while the parent catalog is open', async ({ mock, remote }) => { - vi.useFakeTimers() - try { - const manager = makeManager(mock, remote) - await manager.refreshSubagents(S1) - manager.setSubagentCatalogOpen(S1, true) - await Promise.resolve() - const baseline = remote.subagents.list.mock.calls.length - manager.handleSessionAdded(summary(S2, { parentSessionId: S1 })) - manager.handleSessionAdded(summary('fk-m3' as SessionId, { parentSessionId: S1 })) - await vi.advanceTimersByTimeAsync(50) - expect(remote.subagents.list).toHaveBeenCalledTimes(baseline + 1) - - manager.setSubagentCatalogOpen(S1, false) - manager.handleSessionAdded(summary('fk-m4' as SessionId, { parentSessionId: S1 })) - await vi.advanceTimersByTimeAsync(50) - expect(remote.subagents.list).toHaveBeenCalledTimes(baseline + 1) - } finally { - vi.useRealTimers() - } }) - it('marks a loaded parent row expandable only for a direct subagent publication', async ({ mock, remote }) => { - const root = 'fk-root' as SessionId - remote.subagents.list.mockResolvedValue(ok({ - entries: [ - { - kind: 'child', id: S1, mode: 'continuable', label: 'parent', - activity: 'inactive', hasChildren: false, - }, - { - kind: 'child', id: S2, mode: 'continuable', label: 'ordinary parent', - activity: 'inactive', hasChildren: false, - }, - ] as never[], - parentAvailable: true, - })) + it('publishes pushed membership without a catalog request or an instantiated parent', ({ mock, remote }) => { const manager = makeManager(mock, remote) - await manager.refreshSubagents(root) - - manager.handleSessionAdded(summary('fk-grandchild' as SessionId, { - parentSessionId: S1, origin: 'subagent', - })) - manager.handleSessionAdded(summary('fk-fork' as SessionId, { parentSessionId: S2 })) - - expect(manager.getListSnapshot().subagentsByParent[root]?.entries).toMatchObject([ - { kind: 'child', id: S1, hasChildren: true }, - { kind: 'child', id: S2, hasChildren: false }, + manager.handleSessionAdded(summary(S2, { origin: 'subagent', parentSessionId: S1, running: true })) + manager.handleControlFrame({ + type: 'projection', sessionId: S1, key: 'subagentCatalog', seq: 4, + value: [{ id: S2, createdAt: 1, mode: 'continuable', label: 'worker' }], + }) + expect(manager.getListSnapshot().projectionsBySession[S1]?.values.subagentCatalog).toEqual([ + { id: S2, createdAt: 1, mode: 'continuable', label: 'worker' }, ]) + expect(manager.subagentAddress(S2)).toEqual({ parentSessionId: S1, childSessionId: S2, mode: 'continuable' }) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toEqual([]) }) - it('preserves a live expandability hint across only the older in-flight catalog response', async ({ mock, remote }) => { - const root = 'fk-root' as SessionId - const response = Promise.withResolvers>>() - remote.subagents.list.mockReturnValue(response.promise) + it('keeps newer pushed membership when the initial read returns an older baseline', async ({ mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.projections.mockImplementation(() => response.promise) const manager = makeManager(mock, remote) - const refresh = manager.refreshSubagents(root) - - manager.handleSessionAdded(summary('fk-grandchild' as SessionId, { - parentSessionId: S1, origin: 'subagent', - })) - response.resolve(ok({ - entries: [{ - kind: 'child', id: S1, mode: 'continuable', label: 'parent', - activity: 'inactive', hasChildren: false, - }] as never[], - parentAvailable: true, - })) - await refresh - - expect(manager.getListSnapshot().subagentsByParent[root]?.entries).toMatchObject([ - { kind: 'child', id: S1, hasChildren: true }, - ]) - - remote.subagents.list.mockResolvedValue(ok({ - entries: [{ - kind: 'child', id: S1, mode: 'continuable', label: 'parent', - activity: 'inactive', hasChildren: false, - }] as never[], - parentAvailable: true, - })) - await manager.refreshSubagents(root) - expect(manager.getListSnapshot().subagentsByParent[root]?.entries).toMatchObject([ - { kind: 'child', id: S1, hasChildren: false }, - ]) + const read = manager.refreshProjections(S1) + manager.handleControlFrame({ + type: 'projection', sessionId: S1, key: 'subagentCatalog', seq: 5, + value: [{ id: S2, createdAt: 1, mode: 'continuable', label: 'pushed' }], + }) + response.resolve(ok({ asOfSeq: 3, values: { subagentCatalog: [] } })) + await read + expect(manager.getListSnapshot().projectionsBySession[S1]?.values.subagentCatalog?.[0]?.label).toBe('pushed') + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(1) }) - it('replays status frames over an older in-flight catalog response', async ({ mock, remote }) => { - const root = 'fk-root' as SessionId - const response = Promise.withResolvers>>() - remote.subagents.list.mockReturnValue(response.promise) - const manager = makeManager(mock, remote) - const refresh = manager.refreshSubagents(root) - + it.for([false, true])('keeps live parent availability when an earlier initial read settles (failure: %s)', async (failure, { mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.projections.mockImplementation(() => response.promise) + const manager = makeManager(mock, remote, S2, { parentSessionId: S1, childSessionId: S2, mode: 'continuable' }) + const child = manager.get(S2) + const read = manager.refreshProjections(S1) + manager.handleSessionAdded(summary(S1)) manager.handleSessionStatus(S1, false) + response.resolve(failure + ? err(new RemoteError('gateway/internal', 'offline', {})) + : ok({ asOfSeq: 0, values: { subagentCatalog: [] } })) + await read + expect(child.getSnapshot().subagent?.parentAvailable).toBe(true) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(1) + }) + + it('keeps parent availability unknown after list failure and accepts a later Host summary', async ({ mock, remote }) => { + const manager = makeManager(mock, remote, S2, { parentSessionId: S1, childSessionId: S2, mode: 'continuable' }) + const child = manager.get(S2) + remote.session.list.mockResolvedValue(err(new RemoteError('gateway/internal', 'offline', {}))) + await manager.refreshList() + expect(manager.getListSnapshot().state).toBe('error') + expect(child.getSnapshot().subagent?.parentAvailable).toBeUndefined() + manager.handleSessionAdded(summary(S1)) + expect(child.getSnapshot().subagent?.parentAvailable).toBe(true) + await manager.dispose() + }) + + it('keeps a pushed catalog when an earlier initial read reports the parent missing', async ({ mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.projections.mockImplementation(() => response.promise) + const manager = makeManager(mock, remote) + const read = manager.refreshProjections(S1) + manager.handleControlFrame({ type: 'projection', sessionId: S1, key: 'subagentCatalog', seq: 1, + value: [{ id: S2, createdAt: 1, mode: 'one-shot' }] }) + response.resolve(ok(null)) + await read + expect(manager.getListSnapshot().projectionsBySession[S1]?.values.subagentCatalog).toEqual([ + { id: S2, createdAt: 1, mode: 'one-shot' }, + ]) + }) + + it('shares cold initial loading and reuses the loaded catalog when reopened', async ({ mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.projections.mockImplementation(() => response.promise) + const manager = makeManager(mock, remote) + const read = manager.refreshProjections(S1) + expect(manager.refreshProjections(S1)).toBe(read) + expect(manager.getListSnapshot().projectionsBySession[S1]?.state).toBe('loading') + response.resolve(ok({ asOfSeq: 0, values: { + subagentCatalog: [{ id: S2, createdAt: 1, mode: 'one-shot' }], + title: 'cold parent', + } })) + await read + await manager.refreshProjections(S1) + manager.handleSessionAdded(summary(S1)) + expect(manager.getListSnapshot().items[0]?.title).toBe('cold parent') + expect(manager.getListSnapshot().projectionsBySession[S1]).toMatchObject({ + values: { subagentCatalog: [{ id: S2, createdAt: 1, mode: 'one-shot' }] }, state: 'ready', + }) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(1) + }) + + it('uses current Session status rather than the time an initial catalog read started', async ({ mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.projections.mockImplementation(() => response.promise) + const manager = makeManager(mock, remote) + const read = manager.refreshProjections(S1) + manager.handleSessionAdded(summary(S2, { origin: 'subagent', parentSessionId: S1 })) manager.handleSessionStatus(S2, true) - response.resolve(ok({ - entries: [ - { - kind: 'child', id: S1, mode: 'continuable', label: 'stopped', - activity: 'running', hasChildren: false, - }, - { - kind: 'child', id: S2, mode: 'continuable', label: 'started', - activity: 'inactive', hasChildren: false, - }, - ] as never[], - parentAvailable: true, - })) - await refresh - - expect(manager.getListSnapshot().subagentsByParent[root]?.entries).toMatchObject([ - { kind: 'child', id: S1, activity: 'inactive' }, - { kind: 'child', id: S2, activity: 'running' }, - ]) + response.resolve(ok({ asOfSeq: 0, values: { + subagentCatalog: [{ id: S2, createdAt: 1, mode: 'continuable', label: 'worker' }], + } })) + await read + expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)?.running).toBe(true) + manager.handleSessionStatus(S2, false) + expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)?.running).toBe(false) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(1) }) - it('marks a detached catalog child inactive without requiring a selected address', async ({ mock, remote }) => { - remote.subagents.list.mockResolvedValue(ok({ - entries: [{ - kind: 'child', id: S2, mode: 'continuable', label: 'worker', - activity: 'running', hasChildren: false, - }] as never[], - parentAvailable: true, - })) + it('keeps completed unselected child metadata with its durable catalog row', ({ mock, remote }) => { const manager = makeManager(mock, remote) - await manager.refreshSubagents(S1) - + manager.handleSessionAdded(summary(S2, { origin: 'subagent', parentSessionId: S1, running: true })) + manager.handleControlFrame({ type: 'projection', sessionId: S2, key: 'title', value: 'finished child', seq: 2 }) + manager.handleControlFrame({ type: 'projection', sessionId: S1, key: 'subagentCatalog', seq: 1, + value: [{ id: S2, createdAt: 1, mode: 'one-shot' }] }) manager.handleSessionRemoved(S2) - - expect(manager.getListSnapshot().subagentsByParent[S1]?.entries).toMatchObject([ - { kind: 'child', id: S2, activity: 'inactive' }, - ]) + expect(manager.getListSnapshot().items[0]).toMatchObject({ title: 'finished child', running: false }) + expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)?.running).toBe(false) }) - it('coalesces overlapping catalog reads without scheduling a trailing pull', async ({ mock, remote }) => { - const root = 'fk-root' as SessionId - const first = Promise.withResolvers>>() - remote.subagents.list.mockReturnValue(first.promise) + it('does not invent membership from Session summaries', ({ mock, remote }) => { const manager = makeManager(mock, remote) - - const refresh = manager.refreshSubagents(root) - expect(manager.refreshSubagents(root)).toBe(refresh) - remote.subagents.list.mockResolvedValue(ok({ entries: [], parentAvailable: true })) - first.resolve(ok({ entries: [], parentAvailable: true })) - await refresh - - expect(remote.subagents.list).toHaveBeenCalledOnce() + manager.handleSessionAdded(summary(S2, { origin: 'subagent', parentSessionId: S1 })) + expect(manager.getListSnapshot().projectionsBySession[S1]).toBeUndefined() }) - it('runs one trailing catalog refresh for a membership change coalesced into an in-flight pull', async ({ mock, remote }) => { - vi.useFakeTimers() - try { - const root = 'fk-root' as SessionId - const first = Promise.withResolvers>>() - const second = Promise.withResolvers>>() - remote.subagents.list.mockReturnValue(first.promise) - const manager = makeManager(mock, remote, root) - const refresh = manager.refreshSubagents(root) - manager.setSubagentCatalogOpen(root, true) - - // A membership frame arrives while the pull is in flight; the debounced - // refresh it schedules fires 50ms later and is coalesced into the pull — - // which was requested before the new child existed. The stale mark must - // queue one trailing pull carrying the change. - manager.handleSessionAdded(summary(S2, { parentSessionId: root })) - await vi.advanceTimersByTimeAsync(50) - remote.subagents.list.mockReturnValueOnce(second.promise) - first.resolve(ok({ - entries: [{ - kind: 'child', id: S1, mode: 'continuable', label: 'older', - activity: 'inactive', hasChildren: false, - }] as never[], - parentAvailable: true, - })) - await refresh - // The trailing pull is already in flight (kicked synchronously in finally). - second.resolve(ok({ - entries: [ - { - kind: 'child', id: S1, mode: 'continuable', label: 'older', - activity: 'inactive', hasChildren: false, - }, - { - kind: 'child', id: S2, mode: 'continuable', label: 'new child', - activity: 'inactive', hasChildren: false, - }, - ] as never[], - parentAvailable: true, - })) - await second.promise - // The Remote face resolves one microtask after the response settles. - await vi.advanceTimersByTimeAsync(0) - - expect(remote.subagents.list).toHaveBeenCalledTimes(2) - expect(manager.getListSnapshot().subagentsByParent[root]?.entries).toMatchObject([ - { kind: 'child', id: S1, label: 'older' }, - { kind: 'child', id: S2, label: 'new child' }, - ]) - } finally { - vi.useRealTimers() - } + it('retries a failed initial read without discarding pushed entries', async ({ mock, remote }) => { + remote.session.projections.mockImplementation(() => Promise.resolve(err(new RemoteError('gateway/internal', 'offline', {})))) + const manager = makeManager(mock, remote) + manager.handleControlFrame({ type: 'projection', sessionId: S1, key: 'subagentCatalog', seq: 2, + value: [{ id: S2, createdAt: 1, mode: 'one-shot' }] }) + await manager.refreshProjections(S1) + expect(manager.getListSnapshot().projectionsBySession[S1]).toMatchObject({ state: 'error', values: { subagentCatalog: [{ id: S2 }] } }) + remote.session.projections.mockImplementation(() => Promise.resolve(ok({ asOfSeq: 2, values: { subagentCatalog: [] } }))) + await manager.refreshProjections(S1) + expect(manager.getListSnapshot().projectionsBySession[S1]).toMatchObject({ state: 'ready', values: { subagentCatalog: [{ id: S2 }] } }) }) - it('keeps removal invalidation across a stale success and failed trailing pull', async ({ mock, remote }) => { - const root = 'fk-root' as SessionId - const child = () => ({ - kind: 'child' as const, id: S2, mode: 'continuable' as const, label: 'worker', - activity: 'inactive' as const, hasChildren: false, + it('ignores a late response after parent removal without a trailing request', async ({ mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.projections.mockImplementation(() => response.promise) + const manager = makeManager(mock, remote) + const read = manager.refreshProjections(S1) + manager.handleSessionRemoved(S1) + response.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [] } })) + await read + expect(manager.getListSnapshot().items.some(item => item.sessionId === S1)).toBe(false) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(1) + }) + + it('represents a missing parent as an empty unavailable catalog', async ({ mock, remote }) => { + remote.session.projections.mockImplementation(() => Promise.resolve(ok(null))) + const manager = makeManager(mock, remote) + await manager.refreshProjections(S1) + expect(manager.getListSnapshot().projectionsBySession[S1]).toEqual({ + values: {}, state: 'ready', error: null, }) - const first = Promise.withResolvers>>() - remote.subagents.list.mockReturnValue(first.promise) - const manager = makeManager(mock, remote) - const refresh = manager.refreshSubagents(root) - first.resolve(ok({ entries: [child()] as never[], parentAvailable: true })) - await refresh - manager.selectSubagent({ parentSessionId: root, childSessionId: S2, mode: 'continuable' }) - - // The removal lands while a second pull is in flight: the invalidation - // must survive the pre-removal ok response, so one trailing pull runs. - const mid = Promise.withResolvers>>() - remote.subagents.list.mockReturnValueOnce(mid.promise) - const midRefresh = manager.refreshSubagents(root) - manager.handleSessionRemoved(root) - const trailing = Promise.withResolvers>>() - remote.subagents.list.mockReturnValueOnce(trailing.promise) - mid.resolve(ok({ entries: [child()] as never[], parentAvailable: true })) - await midRefresh - expect(manager.getListSnapshot().subagentsByParent[root]?.parentAvailable).toBe(false) - expect(manager.get(S2).getSnapshot().subagent).toMatchObject({ parentAvailable: false }) - - trailing.resolve(err(new RemoteError('gateway/internal', 'trailing pull failed', {}))) - await vi.waitFor(() => { - expect(manager.getListSnapshot().subagentsByParent[root]).toMatchObject({ - state: 'error', - parentAvailable: false, - }) - }) - - const rootCalls = remote.subagents.list.mock.calls.filter(([call]) => call === root) - expect(rootCalls).toHaveLength(3) - expect(manager.getListSnapshot().subagentsByParent[root]?.parentAvailable).toBe(false) - expect(manager.get(S2).getSnapshot().subagent).toMatchObject({ parentAvailable: false }) - }) - - it('invalidates catalog availability when the owning parent is removed', async ({ mock, remote }) => { - const root = 'fk-root' as SessionId - remote.subagents.list.mockResolvedValue(ok({ - entries: [{ - kind: 'child', id: S2, mode: 'continuable', label: 'worker', - activity: 'inactive', hasChildren: false, - }] as never[], - parentAvailable: true, - })) - const manager = makeManager(mock, remote) - await manager.refreshSubagents(root) - manager.selectSubagent({ parentSessionId: root, childSessionId: S2, mode: 'continuable' }) - expect(manager.get(S2).getSnapshot().subagent).toMatchObject({ parentAvailable: true }) - - manager.handleSessionRemoved(root) - - expect(manager.getListSnapshot().subagentsByParent[root]?.parentAvailable).toBe(false) - expect(manager.get(S2).getSnapshot().subagent).toMatchObject({ parentAvailable: false }) }) }) @@ -636,6 +537,38 @@ describe('remaining branches', () => { expect(await manager.create()).toMatchObject({ ok: false }) }) + it.for(['create', 'fork'] as const)('preserves pushed running state when a %s response arrives later', async (operation, { mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session[operation].mockImplementation(() => response.promise) + const manager = makeManager(mock, remote) + const request = operation === 'create' ? manager.create() : manager.fork({ sessionId: S1 }) + manager.handleSessionAdded(summary(S2, { running: true })) + response.resolve(ok({ sessionId: S2 })) + await request + expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)) + .toMatchObject({ running: true, completed: false }) + manager.handleSessionAdded(summary(S2, { running: false, agentAvailable: false })) + expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)) + .toMatchObject({ running: false, completed: true }) + await manager.dispose() + }) + + it('preserves Host availability when a local create echo follows Agent disposal', async ({ mock, remote }) => { + const response = Promise.withResolvers>>() + remote.session.create.mockImplementation(() => response.promise) + const manager = makeManager(mock, remote, S2, { + parentSessionId: S1, childSessionId: S2, mode: 'continuable', + }) + const child = manager.get(S2) + const request = manager.create() + manager.handleSessionAdded(summary(S1, { agentAvailable: false })) + response.resolve(ok({ sessionId: S1 })) + await request + manager.select(S2) + expect(child.getSnapshot().subagent?.parentAvailable).toBe(false) + await manager.dispose() + }) + it('publishes a real Ungrouped summary from workspace-attach-failed', async ({ mock, remote }) => { remote.session.create.mockResolvedValue(err(new RemoteError('session/workspace-attach-failed', 'published but unattached', { sessionId: S1, workspaceId: 'w1', @@ -852,6 +785,55 @@ describe('connected generation', () => { } }) + it.for([false, true])('refreshes an unselected cached catalog after offline activity changes: %s', async (running, { mock, remote }) => { + let hostRunning = !running + remote.session.list.mockImplementation(() => Promise.resolve(ok({ items: [ + summary(S1), + summary(S2, { parentSessionId: S1, origin: 'subagent', running: hostRunning }), + ] as never[] }))) + remote.session.projections.mockImplementation(() => Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, id: S2, mode: 'continuable', label: 'worker' }] } }))) + const manager = makeManager(mock, remote) + try { + await manager.refreshList() + await manager.refreshProjections(S1) + const reads = remote.session.projections.mock.calls.map(([request]) => request).length + hostRunning = running + manager.handleConnected() + await manager.refreshList() + await vi.waitFor(() => { + expect(manager.getListSnapshot().items.find(item => item.sessionId === S2)?.running) + .toBe(running) + }) + expect(manager.getListSnapshot().current).toBeUndefined() + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(reads + 1) + } finally { + await manager.dispose() + } + }) + + it('starts a fresh catalog read on reconnect and ignores the previous response', async ({ mock, remote }) => { + const previous = Promise.withResolvers>>() + remote.session.projections + .mockReturnValueOnce(previous.promise) + .mockResolvedValue(ok({ asOfSeq: 0, values: { subagentCatalog: [] } })) + const manager = makeManager(mock, remote) + try { + const read = manager.refreshProjections(S1) + manager.handleConnected() + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(2) + previous.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, id: S2, mode: 'continuable', label: 'worker' }] } })) + await read + await vi.waitFor(() => { + expect(manager.getListSnapshot().projectionsBySession[S1]).toMatchObject({ + values: {}, state: 'ready', + }) + }) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toHaveLength(2) + } finally { + await manager.dispose() + } + }) + it('refreshes query baselines without rebuilding independently resumed Session sources', async ({ mock, remote, start }) => { mock.stream(FOLLOW, followScript(ok({ records: entries(plainTurn(SessionSeq(0), 0, 'a', 'b')) as never[], @@ -874,23 +856,33 @@ describe('connected generation', () => { it('retains the durable parent address and refreshes its catalogs across reconnect', async ({ mock, remote }) => { const address = { - parentSessionId: S1, childSessionId: S2, mode: 'continuable' as const, + parentSessionId: S1, + childSessionId: S2, + mode: 'continuable' as const, } - const parent = Promise.withResolvers>>() - const child = Promise.withResolvers>>() - remote.subagents.list.mockImplementation(payload => (payload === S1 ? parent.promise : child.promise)) + remote.session.list.mockImplementation(() => Promise.resolve(ok({ items: [summary(S1)] as never[] }))) + const parent = Promise.withResolvers>>() + const child = Promise.withResolvers>>() + remote.session.projections.mockImplementation(payload => ( + payload as { sessionId: SessionId } + ).sessionId === S1 ? parent.promise : child.promise) const manager = makeManager(mock, remote, S2, address) manager.handleConnected() expect(manager.get(S2).getSnapshot().subagent).toEqual({ address }) - parent.resolve(ok({ entries: [], parentAvailable: true })) - child.resolve(ok({ entries: [], parentAvailable: true })) + parent.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, + id: S2, mode: 'continuable', label: 'worker', + }] } })) + child.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [] } })) await vi.waitFor(() => { - expect(remote.session.list).toHaveBeenCalledOnce() + expect(remote.session.list.mock.calls.map(([request]) => request)).toHaveLength(1) }) await vi.waitFor(() => { - expect(remote.subagents.list.mock.calls.map(([parentSessionId]) => parentSessionId)).toEqual([S1, S2]) + expect(remote.session.projections.mock.calls.map(([request]) => request)).toEqual([ + { sessionId: S1 }, + { sessionId: S2 }, + ]) }) expect(manager.get(S2).getSnapshot().subagent).toEqual({ address, diff --git a/packages/api/session-controller/tests/projection-store.client.spec.ts b/packages/api/session-controller/tests/projection-store.client.spec.ts index b943557ca4..2ab2bbaec6 100644 --- a/packages/api/session-controller/tests/projection-store.client.spec.ts +++ b/packages/api/session-controller/tests/projection-store.client.spec.ts @@ -187,7 +187,7 @@ describe('manager frame routing', () => { it('preserves a newer title when the control baseline omits it', async ({ mock, remote }) => { const manager = makeManager(mock, remote) remote.session.list.mockResolvedValue(ok({ - items: [{ sessionId: sid('s1'), updatedAt: 1, running: false, blank: false }], + items: [{ agentAvailable: true, sessionId: sid('s1'), updatedAt: 1, running: false, blank: false }], })) await manager.refreshList() manager.handleControlFrame({ @@ -209,7 +209,7 @@ describe('manager frame routing', () => { it('projects every retained value into list rows with stable snapshot identity', async ({ mock, remote }) => { const manager = makeManager(mock, remote) remote.session.list.mockResolvedValue(ok({ - items: [{ + items: [{ agentAvailable: true, sessionId: sid('s1'), updatedAt: 1, running: false, blank: false, projections: { asOfSeq: 2, @@ -232,16 +232,21 @@ describe('manager frame routing', () => { expect(manager.getListSnapshot().items[0]?.projectionValues).not.toBe(baseline) }) - it('drops the projection store with the removed session', async ({ mock, remote }) => { + it.for([undefined, []])('drops the removed ordinary Session store with catalog %s', async (catalog, { mock, remote }) => { const manager = makeManager(mock, remote) remote.session.list.mockResolvedValue(ok({ - items: [{ sessionId: sid('s1'), updatedAt: 1, running: false, blank: false }], + items: [{ agentAvailable: true, sessionId: sid('s1'), updatedAt: 1, running: false, blank: false }], })) await manager.refreshList() manager.handleControlFrame({ type: 'projection', sessionId: sid('s1'), key: 'title', value: 'Doomed', seq: 4, }) + if (catalog !== undefined) { + manager.handleControlFrame({ type: 'projection', sessionId: sid('s1'), key: 'subagentCatalog', value: catalog, seq: 4 }) + } manager.handleSessionRemoved(sid('s1')) + expect(manager.getListSnapshot().projectionsBySession[sid('s1')]).toBeUndefined() expect(manager.get(sid('s1')).projections.get('title')).toBeUndefined() + await manager.dispose() }) }) diff --git a/packages/api/session-controller/tests/remote/session.client.ts b/packages/api/session-controller/tests/remote/session.client.ts index b4cd74676c..4d86abcf9e 100644 --- a/packages/api/session-controller/tests/remote/session.client.ts +++ b/packages/api/session-controller/tests/remote/session.client.ts @@ -145,7 +145,7 @@ export const sessionWorld: RemoteTable = { data: 'AA==', }), 'session/page': pageRule(ok({ records: [], hasMore: false })), - 'subagents/list': ok({ entries: [], parentAvailable: true }), + 'session/projections': ok({ asOfSeq: -1, values: { subagentCatalog: [] } }), 'subagents/prompt': ok({ messageId: 'fake-message' }), 'subagents/interruptByParent': ok({ accepted: true }), }, diff --git a/packages/api/session-controller/tests/sessions-service.client.spec.ts b/packages/api/session-controller/tests/sessions-service.client.spec.ts index e1acd28966..de1336c7e1 100644 --- a/packages/api/session-controller/tests/sessions-service.client.spec.ts +++ b/packages/api/session-controller/tests/sessions-service.client.spec.ts @@ -62,12 +62,12 @@ type FeedRow = { origin?: 'subagent' running?: boolean blank?: boolean - projections?: Record + projections?: import('../src/types.ts').SessionProjectionValues } async function feedList(b: Bench, rows: FeedRow[]): Promise { b.mock.remote.session.list.mockResolvedValue(ok({ - items: rows.map(r => ({ + items: rows.map(r => ({ agentAvailable: true, sessionId: sid(r.id), updatedAt: 1, running: r.running ?? false, blank: r.blank ?? false, ...(r.cwd !== undefined ? { cwd: r.cwd } : {}), ...(r.parentId !== undefined ? { parentSessionId: sid(r.parentId) } : {}), @@ -76,7 +76,7 @@ async function feedList(b: Bench, rows: FeedRow[]): Promise { ? {} : { projections: { asOfSeq: 0, values: r.projections } }), })), - }) as never) + })) await b.svc.refresh() await Promise.resolve() // manager notifier flush } @@ -116,7 +116,7 @@ describe('list store projection', () => { it('reflects live increments (host stream via manager) into the store', async ({ bench }) => { const b = bench() await feedList(b, [{ id: 's1' }]) - b.svc.handleSessionAdded({ + b.svc.handleSessionAdded({ agentAvailable: true, sessionId: sid('s2'), updatedAt: 2, running: false, blank: true, }) await Promise.resolve() @@ -149,6 +149,23 @@ describe('search', () => { }) describe('scope tree', () => { + it('opens a conversation from follow projections without a second projection request', async ({ bench }) => { + const b = bench() + b.mock.stream(FOLLOW, followScript(ok({ + records: [], hasMore: false, + projections: { asOfSeq: 0, values: { subagentCatalog: [{ + id: sid('child'), createdAt: 1, mode: 'one-shot', + }] } }, + }))) + await feedList(b, [{ id: 's1' }]) + b.svc.open(sid('s1')) + await vi.waitFor(() => { + expect(b.svc.list.getSnapshot().projectionsBySession[sid('s1')]?.values.subagentCatalog) + .toEqual([{ id: sid('child'), createdAt: 1, mode: 'one-shot' }]) + }) + expect(b.mock.remote.session.projections).not.toHaveBeenCalled() + }) + it('publishes transient Assistant chunks and the named durable v2 settlement through one event source', async ({ bench }) => { const b = bench() await feedList(b, [{ id: 's1' }]) @@ -544,7 +561,7 @@ describe('Agent scope disposal lifecycle', () => { const b = bench() const readiness = b.ctx.plugin(() => undefined) await readiness - b.svc.handleSessionAdded({ + b.svc.handleSessionAdded({ agentAvailable: true, sessionId: sid('live'), updatedAt: 1, running: false, blank: true, }) await Promise.resolve() @@ -834,72 +851,60 @@ describe('binding and stage lifecycle', () => { describe('catalog-addressed navigation', () => { it('uses catalog labels for a listed addressed route', async ({ bench }) => { const b = bench() - b.mock.remote.subagents.list.mockImplementation((payload) => { - const parentSessionId = payload - if (parentSessionId === sid('root')) { - return Promise.resolve(ok({ - entries: [{ - kind: 'child', id: sid('child'), mode: 'continuable', label: 'Child', - activity: 'inactive', hasChildren: true, - }] as never[], - parentAvailable: true, - })) + b.mock.remote.session.projections.mockImplementation((payload) => { + const { sessionId } = payload as { sessionId: SessionId } + if (sessionId === sid('root')) { + return Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, + id: sid('child'), mode: 'continuable', label: 'Child', + }] } })) } - if (parentSessionId === sid('child')) { - return Promise.resolve(ok({ - entries: [{ - kind: 'child', id: sid('grandchild'), mode: 'continuable', label: 'Grandchild', - activity: 'inactive', hasChildren: false, - }] as never[], - parentAvailable: false, - })) + if (sessionId === sid('child')) { + return Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, + id: sid('grandchild'), mode: 'continuable', label: 'Grandchild', + }] } })) } - return Promise.resolve(ok({ entries: [], parentAvailable: false })) + return Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [] } })) }) await feedList(b, [ { id: 'root' }, { id: 'child', cwd: '/summary-child', parentId: 'root', origin: 'subagent' }, { id: 'grandchild', cwd: '/summary-grandchild', parentId: 'child', origin: 'subagent' }, ]) - await b.svc.refreshSubagents(sid('root')) - await b.svc.refreshSubagents(sid('child')) + await b.svc.refreshProjections(sid('root')) + await b.svc.refreshProjections(sid('child')) b.svc.openSubagent({ - parentSessionId: sid('child'), childSessionId: sid('grandchild'), mode: 'continuable', + parentSessionId: sid('child'), + childSessionId: sid('grandchild'), + mode: 'continuable', }) expect(b.svc.list.getSnapshot().byId[sid('child')]?.displayTitle).toBe('Child') expect(b.svc.list.getSnapshot().byId[sid('grandchild')]?.displayTitle).toBe('Grandchild') }) - it('projects a directly opened descendant route without retaining ancestor scopes or addresses', async ({ bench }) => { + it('resolves catalog addresses for never-selected ancestors without opening their scopes', async ({ bench }) => { const b = bench() - b.mock.remote.subagents.list.mockImplementation((payload) => { - const parentSessionId = payload - if (parentSessionId === sid('root')) { - return Promise.resolve(ok({ - entries: [{ - kind: 'child', id: sid('child'), mode: 'continuable', label: 'Child', - activity: 'inactive', hasChildren: true, - }] as never[], - parentAvailable: true, - })) + b.mock.remote.session.projections.mockImplementation((payload) => { + const { sessionId } = payload as { sessionId: SessionId } + if (sessionId === sid('root')) { + return Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, + id: sid('child'), mode: 'continuable', label: 'Child', + }] } })) } - if (parentSessionId === sid('child')) { - return Promise.resolve(ok({ - entries: [{ - kind: 'child', id: sid('grandchild'), mode: 'continuable', label: 'Grandchild', - activity: 'inactive', hasChildren: false, - }] as never[], - parentAvailable: false, - })) + if (sessionId === sid('child')) { + return Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [{ createdAt: 1, + id: sid('grandchild'), mode: 'continuable', label: 'Grandchild', + }] } })) } - return Promise.resolve(ok({ entries: [], parentAvailable: false })) + return Promise.resolve(ok({ asOfSeq: 0, values: { subagentCatalog: [] } })) }) await feedList(b, [{ id: 'root' }]) - await b.svc.refreshSubagents(sid('root')) - await b.svc.refreshSubagents(sid('child')) + await b.svc.refreshProjections(sid('root')) + await b.svc.refreshProjections(sid('child')) b.svc.openSubagent({ - parentSessionId: sid('child'), childSessionId: sid('grandchild'), mode: 'continuable', + parentSessionId: sid('child'), + childSessionId: sid('grandchild'), + mode: 'continuable', }) const list = b.svc.list.getSnapshot() @@ -907,12 +912,20 @@ describe('catalog-addressed navigation', () => { expect(list.byId[sid('child')]).toMatchObject({ parentId: sid('root'), origin: 'subagent' }) expect(list.byId[sid('grandchild')]).toMatchObject({ parentId: sid('child'), origin: 'subagent' }) expect(b.svc.binding(sid('child'))).toBeUndefined() - expect(b.svc.subagentAddress(sid('child'))).toBeUndefined() + expect(b.svc.subagentAddress(sid('child'))).toEqual({ + parentSessionId: sid('root'), + childSessionId: sid('child'), + mode: 'continuable', + }) + expect(b.svc.binding(sid('child'))).toBeUndefined() + expect(b.svc.list.getSnapshot().currentAddress?.childSessionId).toBe(sid('grandchild')) b.svc.open(sid('child')) expect(b.svc.list.getSnapshot().current).toBe(sid('child')) expect(b.svc.subagentAddress(sid('child'))).toEqual({ - parentSessionId: sid('root'), childSessionId: sid('child'), mode: 'continuable', + parentSessionId: sid('root'), + childSessionId: sid('child'), + mode: 'continuable', }) }) }) @@ -1040,7 +1053,7 @@ describe('scope lifecycle rides the list mirror (entity parity: no client-side p const b = bench() await feedList(b, []) expect(b.svc.scope(sid('s-new'))).toBeUndefined() // not in view: no scope, no exceptions - b.svc.handleSessionAdded({ + b.svc.handleSessionAdded({ agentAvailable: true, sessionId: sid('s-new'), updatedAt: 2, running: false, blank: true, cwd: '/w/a', }) await Promise.resolve() @@ -1100,7 +1113,7 @@ describe('blank mirror', () => { it('takes session-added blank=true as the hidden birth and list blank as reconnect authority', async ({ bench }) => { const b = bench() await feedList(b, []) - b.svc.handleSessionAdded({ + b.svc.handleSessionAdded({ agentAvailable: true, sessionId: sid('s-new'), updatedAt: 2, running: false, blank: true, cwd: '/w/a', }) await Promise.resolve() diff --git a/packages/api/session-controller/tests/subagent-catalog.host.spec.ts b/packages/api/session-controller/tests/subagent-catalog.host.spec.ts new file mode 100644 index 0000000000..3c8cf0ca00 --- /dev/null +++ b/packages/api/session-controller/tests/subagent-catalog.host.spec.ts @@ -0,0 +1,216 @@ +import { Context } from '@deepseek-ai/cordis' +import AgentRegistry from '@deepseek-ai/dsh-agent' +import type { Agent } from '@deepseek-ai/dsh-agent' +import SessionStore, { SESSION_FORMAT_VERSION, SessionLogOffset, SessionSeq, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session' +import { SessionQueryError } from '@deepseek-ai/dsh-session-query' +import type { SessionObservation } from '@deepseek-ai/dsh-session-query' +import SubagentRuntime from '@deepseek-ai/dsh-subagent' +import { describe, expect, it, vi } from 'vitest' +import { + createSessionTestController, + installSessionReadTestServices, + testSessionPersistence, +} from './test-remote.ts' + +const defaults = { + defaultModelSelection: () => ({ provider: 'fixture', model: 'fixture-model' }), + cwd: '/tmp', +} + +const PARENT = SessionId('catalog-parent') +const CHILD = SessionId('catalog-child') +const header: SessionHeader = { + version: SESSION_FORMAT_VERSION, + id: PARENT, + createdAt: 1, + isSeeded: false, + cwd: '/workspace', +} +const events: SessionEvent[] = [{ + type: 'subagent/catalog', + seq: SessionSeq(0), + time: 1, + data: { + version: 0, + childId: CHILD, + childCreatedAt: 2, + mode: 'continuable', + label: 'worker', + }, +}] + +async function bench() { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(AgentRegistry) + ctx.provide('sessionPersistence', testSessionPersistence(ctx, { + list: () => Promise.resolve([header]), + inspect: (sessionId: SessionId) => Promise.resolve( + sessionId === PARENT ? { meta: header, events } : undefined, + ), + }) as never) + installSessionReadTestServices(ctx) + await ctx.plugin(SubagentRuntime) + const controller = createSessionTestController(ctx, defaults) + return { ctx, controller } +} + +describe('SessionController subagent catalog', () => { + it('pushes complete catalog values through the shared control stream', async () => { + const { ctx, controller } = await bench() + const signal = new AbortController() + const stream = controller.control(signal.signal)[Symbol.asyncIterator]() + try { + await stream.next() + const parent = ctx.sessions.create(PARENT, { meta: { createdAt: 7, cwd: '/workspace' } }) + parent.append('subagent/catalog', { + version: 0, childId: CHILD, childCreatedAt: 8, mode: 'continuable', label: 'worker', + }) + let frame = await stream.next() + while (!frame.done && !(frame.value.type === 'projection' && frame.value.key === 'subagentCatalog' + && Array.isArray(frame.value.value) && frame.value.value.length === 1)) { + frame = await stream.next() + } + expect(frame.value).toMatchObject({ type: 'projection', sessionId: PARENT, key: 'subagentCatalog', + value: [{ id: CHILD, createdAt: 8, mode: 'continuable', label: 'worker' }] }) + } finally { + signal.abort() + await stream.return?.() + } + }) + + it('requests a stored parent catalog by id without loading an Agent', async () => { + const { ctx, controller } = await bench() + const observe = vi.spyOn(ctx.sessionQuery, 'observeSession') + const signal = new AbortController().signal + + await expect(controller.projections({ sessionId: PARENT }, signal)).resolves.toMatchObject({ values: { subagentCatalog: [{ + id: CHILD, + mode: 'continuable', + label: 'worker', + }] } }) + expect(observe).toHaveBeenCalledOnce() + expect(observe).toHaveBeenCalledWith(PARENT, { + signal, + }) + }) + + it('serves a live parent from its maintained registry state without folding its log', async () => { + const { ctx, controller } = await bench() + const parent = ctx.sessions.create(PARENT, { meta: { createdAt: 7, cwd: '/workspace' } }) + parent.append('turn/start', { turn: 1 }) + parent.append('subagent/catalog', { + version: 0, + childId: CHILD, + childCreatedAt: 8, + mode: 'one-shot', + label: 'live worker', + }) + const snapshot = vi.spyOn(ctx.sessionProjections, 'snapshot') + const hydrate = vi.spyOn(ctx.sessionProjections, 'hydrate') + + const result = await controller.projections({ sessionId: PARENT }, new AbortController().signal) + expect(result).toMatchObject({ values: { subagentCatalog: [{ + id: CHILD, + mode: 'one-shot', + label: 'live worker', + }] } }) + expect(snapshot).toHaveBeenCalledWith(parent) + expect(hydrate).not.toHaveBeenCalled() + }) + + it('reports Agent availability through Session summaries independently of projections', async () => { + const { ctx, controller } = await bench() + const parent = ctx.sessions.create(PARENT, { meta: { createdAt: 1, cwd: '/workspace' } }) + parent.append('subagent/catalog', { + version: 0, childId: CHILD, childCreatedAt: 8, mode: 'one-shot', + }) + const summaries: boolean[] = [] + ctx.on('api-session/added', (summary) => { summaries.push(summary.agentAvailable) }) + const dispose = ctx.agents.register({ id: PARENT, session: parent, status: 'idle', ctx } as Agent) + await dispose + expect(summaries).toEqual([true]) + const available = await controller.list({}, new AbortController().signal) + expect(available.items.find(item => item.sessionId === PARENT)?.agentAvailable).toBe(true) + await dispose() + expect(summaries).toEqual([true, false]) + const unavailable = await controller.list({}, new AbortController().signal) + expect(unavailable.items.find(item => item.sessionId === PARENT)?.agentAvailable).toBe(false) + const result = await controller.projections({ sessionId: PARENT }, new AbortController().signal) + expect(result).toMatchObject({ asOfSeq: 0, values: { subagentCatalog: [{ id: CHILD, createdAt: 8, mode: 'one-shot' }] } }) + }) + + it('does not republish a Session when its Agent outlives the Session registration', async () => { + const { ctx } = await bench() + const session = ctx.sessions.prepare(SessionId('detached'), { meta: { cwd: '/workspace' } }) + const detach = ctx.sessions.enter(session) + const disposeAgent = ctx.agents.register({ id: session.id, session, status: 'idle', ctx } as Agent) + await disposeAgent + const added = vi.fn() + ctx.on('api-session/added', added) + detach() + await disposeAgent() + expect(added).not.toHaveBeenCalled() + }) + + it('reads registered projections without a subagent provider or catalog key', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(AgentRegistry) + installSessionReadTestServices(ctx) + const controller = createSessionTestController(ctx, defaults) + const session = ctx.sessions.create(PARENT, { meta: { cwd: '/workspace' } }) + const expected = ctx.sessionProjections.snapshot(session) + expect(expected.values.subagentCatalog).toBeUndefined() + await expect(controller.projections({ sessionId: PARENT }, new AbortController().signal)).resolves.toEqual(expected) + expect(ctx.agents.get(PARENT)).toBeUndefined() + }) + + it('validates the parent id and keeps not-found distinct from cancellation', async () => { + const { controller } = await bench() + const signal = new AbortController().signal + await expect(controller.projections({ sessionId: SessionId('') }, signal)).rejects.toMatchObject({ + code: 'gateway/bad-request', + }) + await expect(controller.projections({ sessionId: SessionId('missing') }, signal)).resolves.toEqual(null) + const aborted = new AbortController() + aborted.abort() + await expect(controller.projections({ sessionId: PARENT }, aborted.signal)).rejects.toMatchObject({ + code: 'gateway/cancelled', + }) + }) + + it('maps query cancellation, missing projections, and unexpected failures', async () => { + const { ctx, controller } = await bench() + const observe = vi.spyOn(ctx.sessionQuery, 'observeSession') + observe.mockRejectedValueOnce(new SessionQueryError( + 'query cancelled', + 'SESSION_QUERY_ABORTED', + )) + await expect(controller.projections({ sessionId: PARENT }, new AbortController().signal)).rejects.toMatchObject({ + code: 'gateway/cancelled', + }) + + observe.mockRestore() + // An observation without the catalog state means no registry served it. + const stateless: SessionObservation = { + source: 'prepared', + header, + inheritedEventCount: SessionLogOffset(0), + events, + cursor: SessionSeq(0), + retain: () => stateless, + [Symbol.dispose]: () => {}, + } + vi.spyOn(ctx.sessionQuery, 'observeSession').mockResolvedValueOnce(stateless) + await expect(controller.projections({ sessionId: PARENT }, new AbortController().signal)).rejects.toMatchObject({ + code: 'session/projections-unavailable', + }) + + vi.spyOn(ctx.sessionQuery, 'observeSession').mockRejectedValueOnce(new Error('storage offline')) + await expect(controller.projections({ sessionId: PARENT }, new AbortController().signal)).rejects.toMatchObject({ + code: 'gateway/internal', + }) + }) +}) diff --git a/packages/api/session-controller/tests/test-remote.ts b/packages/api/session-controller/tests/test-remote.ts index 721288f7dc..b4d3db8198 100644 --- a/packages/api/session-controller/tests/test-remote.ts +++ b/packages/api/session-controller/tests/test-remote.ts @@ -9,6 +9,7 @@ import type { ImageAttachmentLimits, } from '@deepseek-ai/dsh-attachment' import type { SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionProjectionsValue } from '../src/types.ts' import { SessionPersistenceNotFoundError, SessionPersistenceRevision, @@ -57,6 +58,7 @@ import type { SessionSearchValue, SessionSelectModelRequest, SessionSelectModelValue, + SessionProjectionsRequest, SessionUpdateQueueRequest, SessionUpdateQueueValue, } from '../src/types.ts' @@ -80,6 +82,7 @@ export interface TestSessionRemote { signal?: AbortSignal, ): Promise> page(request: SessionPageRequest, signal?: AbortSignal): Promise> + projections(request: SessionProjectionsRequest, signal?: AbortSignal): Promise> follow(request: SessionFollowRequest, signal?: AbortSignal): AsyncIterable control(signal?: AbortSignal): AsyncIterable } @@ -360,6 +363,10 @@ export function createSessionTestRemote( () => direct.page(request, signal), signal, ), + projections: (request, signal = new AbortController().signal) => remoteResult( + () => direct.projections(request, signal), + signal, + ), follow: (request, signal = new AbortController().signal) => direct.follow(request, signal), control: (signal = new AbortController().signal) => direct.control(signal), } diff --git a/packages/api/session-controller/tests/transport.client.spec.ts b/packages/api/session-controller/tests/transport.client.spec.ts index e83dac78fd..5038601759 100644 --- a/packages/api/session-controller/tests/transport.client.spec.ts +++ b/packages/api/session-controller/tests/transport.client.spec.ts @@ -81,7 +81,6 @@ function sessionClient(remote: SessionTransportRemote): SessionRemotes { ), commands: { execute: () => Promise.reject(new Error('stream tests never run commands')) }, subagents: { - list: () => Promise.reject(new Error('stream tests never read the subagent catalog')), prompt: () => Promise.reject(new Error('stream tests never prompt a subagent')), interruptByParent: () => Promise.reject(new Error('stream tests never interrupt a subagent')), }, diff --git a/packages/api/session-controller/tests/transport.host.spec.ts b/packages/api/session-controller/tests/transport.host.spec.ts index bac8a541d4..04b43972e9 100644 --- a/packages/api/session-controller/tests/transport.host.spec.ts +++ b/packages/api/session-controller/tests/transport.host.spec.ts @@ -441,7 +441,12 @@ describe('SessionHistoryController', () => { const signal = new AbortController().signal await expect(transport.page({ - address: { kind: 'subagent', parentSessionId, childSessionId, mode: 'continuable' }, + address: { + kind: 'subagent', + parentSessionId, + childSessionId, + mode: 'continuable', + }, throughSeq: 0, }, signal)).resolves.toMatchObject({ records: [{ type: 'event', event: { type: 'subagent/descriptor' } }], @@ -456,7 +461,12 @@ describe('SessionHistoryController', () => { throughSeq: 0, }, signal)).rejects.toMatchObject({ code: 'subagent/unauthorized' }) await expect(transport.page({ - address: { kind: 'subagent', parentSessionId, childSessionId, mode: 'one-shot' }, + address: { + kind: 'subagent', + parentSessionId, + childSessionId, + mode: 'one-shot', + }, throughSeq: 0, }, signal)).rejects.toMatchObject({ code: 'subagent/unauthorized' }) await expect(transport.page({ @@ -659,7 +669,12 @@ describe('SessionHistoryController', () => { const history = new SessionHistoryController(ctx, vi.fn()) await expect(history.page({ - address: { kind: 'subagent', parentSessionId, childSessionId, mode: 'continuable' }, + address: { + kind: 'subagent', + parentSessionId, + childSessionId, + mode: 'continuable', + }, throughSeq: -1, }, signal())).rejects.toMatchObject({ code: 'subagent/catalog-diagnostic', details: { reason: 'unsupported' }, @@ -690,7 +705,12 @@ describe('SessionHistoryController', () => { })) const childSnapshot = vi.spyOn(child.ctx.sessionProjections, 'snapshot') const page = await child.transport.page({ - address: { kind: 'subagent', parentSessionId, childSessionId, mode: 'continuable' }, + address: { + kind: 'subagent', + parentSessionId, + childSessionId, + mode: 'continuable', + }, throughSeq: 0, }, signal()) expect('projections' in page).toBe(false) diff --git a/packages/client/locale/tests/language-row.client.spec.tsx b/packages/client/locale/tests/language-row.client.spec.tsx index d65a1c82f0..23fe793268 100644 --- a/packages/client/locale/tests/language-row.client.spec.tsx +++ b/packages/client/locale/tests/language-row.client.spec.tsx @@ -20,7 +20,7 @@ const OPTIONS = [{ id: 'zh', label: '中文' }, { id: 'en', label: 'English' }] function emptySessions() { const store = createSnapshotStore( - { ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined }) + { ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined }) return bindSnapshotSelector(store) } function emptyWorkspaces() { diff --git a/packages/client/ui-chat/tests/chat-view.client.spec.tsx b/packages/client/ui-chat/tests/chat-view.client.spec.tsx index 55bf2dd537..c8e7cb0e91 100644 --- a/packages/client/ui-chat/tests/chat-view.client.spec.tsx +++ b/packages/client/ui-chat/tests/chat-view.client.spec.tsx @@ -203,7 +203,7 @@ const compaction = (over: Partial = {}): CompactionSummar /** Empty sessions-list hook for the global standard-kit seat. */ function emptySessions() { const store = createSnapshotStore( - { ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined }) + { ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined }) return bindSnapshotSelector(store) } diff --git a/packages/client/ui-chat/tests/transcript-view-row.client.spec.tsx b/packages/client/ui-chat/tests/transcript-view-row.client.spec.tsx index 288bdce31d..ea97188135 100644 --- a/packages/client/ui-chat/tests/transcript-view-row.client.spec.tsx +++ b/packages/client/ui-chat/tests/transcript-view-row.client.spec.tsx @@ -14,7 +14,7 @@ afterEach(cleanup) function emptySessions() { return bindSnapshotSelector(createSnapshotStore({ - ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, })) } diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationMainPanel.tsx b/packages/client/ui-conversation/src/client/skeleton/ConversationMainPanel.tsx index e6a91eff58..5a2fd9558a 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationMainPanel.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationMainPanel.tsx @@ -115,8 +115,8 @@ export function ConversationMainPanel(props: ConversationSlotProps) { // The exemption is deliberately open-state-wide, not loading-only: a // summary-blank session is the hero before its open starts (`cold`) and // after one fails (`error`) for the same reason — there is no history. - // A restored continuable subagent also stays settled until its eagerly - // loaded parent catalog establishes availability. This keeps the composer + // A restored continuable subagent waits for a Host summary to establish + // parent availability. This keeps the composer // hidden instead of briefly rendering the parent-offline takeover. const parentAvailabilityPending = session?.subagent?.address.mode === 'continuable' && session.subagent.parentAvailable === undefined diff --git a/packages/client/ui-conversation/tests/conversation-registry.client.spec.ts b/packages/client/ui-conversation/tests/conversation-registry.client.spec.ts index 22ca9a0fb3..6a54608185 100644 --- a/packages/client/ui-conversation/tests/conversation-registry.client.spec.ts +++ b/packages/client/ui-conversation/tests/conversation-registry.client.spec.ts @@ -72,7 +72,7 @@ function fakeSessions(ctx: Context): { sessions: ISessions; binding: SessionBind byId: {}, current: undefined, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) @@ -83,8 +83,7 @@ function fakeSessions(ctx: Context): { sessions: ISessions; binding: SessionBind open: () => {}, openSubagent: () => {}, subagentAddress: () => undefined, - setSubagentCatalogOpen: () => {}, - refreshSubagents: () => Promise.reject(new Error('unused fake Sessions operation')), + refreshProjections: () => Promise.reject(new Error('unused fake Sessions operation')), clear: () => {}, refresh: () => Promise.reject(new Error('unused fake Sessions operation')), search: () => Promise.reject(new Error('unused fake Sessions operation')), diff --git a/packages/client/ui-conversation/tests/enter-behavior-row.client.spec.tsx b/packages/client/ui-conversation/tests/enter-behavior-row.client.spec.tsx index 66011fc2b0..d642b412df 100644 --- a/packages/client/ui-conversation/tests/enter-behavior-row.client.spec.tsx +++ b/packages/client/ui-conversation/tests/enter-behavior-row.client.spec.tsx @@ -22,7 +22,7 @@ afterEach(() => { function emptySessions() { return bindSnapshotSelector(createSnapshotStore({ - ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, })) } diff --git a/packages/client/ui-conversation/tests/input-bar.client.spec.tsx b/packages/client/ui-conversation/tests/input-bar.client.spec.tsx index fc7089b423..d11188092f 100644 --- a/packages/client/ui-conversation/tests/input-bar.client.spec.tsx +++ b/packages/client/ui-conversation/tests/input-bar.client.spec.tsx @@ -174,7 +174,7 @@ function bench(over?: BenchOptions) { useResource, useSessions: bindSnapshotSelector(createSnapshotStore({ ids: [], byId: {}, current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, })), useWorkspaces: bindSnapshotSelector(createSnapshotStore({ items: [], archivedSessionIds: [], state: 'idle', phase: 'ready', error: null, diff --git a/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx b/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx index bf9bcd3940..009572b773 100644 --- a/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx +++ b/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx @@ -54,7 +54,7 @@ function mountBar(shell: SessionInputShell, over?: { running?: boolean; disabled useSession: bindSnapshotSelector(session), useSessions: bindSnapshotSelector(createSnapshotStore({ ids: [], byId: {}, current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, })), useSessionPendingInteraction: bindSnapshotSelector( createSnapshotStore(new Map()), diff --git a/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx b/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx index 9f8c9f6bf5..4d306e0e8f 100644 --- a/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx +++ b/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx @@ -145,7 +145,7 @@ async function scopedBench(register?: (inputTriggers: InputTriggerService) => vo useSession: bindSnapshotSelector(sessionStore), useSessions: bindSnapshotSelector(createSnapshotStore({ ids: [], byId: {}, current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, })), useSessionPendingInteraction: bindSnapshotSelector( createSnapshotStore(new Map()), diff --git a/packages/client/ui-conversation/tests/skeleton.client.spec.tsx b/packages/client/ui-conversation/tests/skeleton.client.spec.tsx index 31d811a9ee..dd18451680 100644 --- a/packages/client/ui-conversation/tests/skeleton.client.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.client.spec.tsx @@ -151,7 +151,7 @@ function mount( ...listed && { [SID]: childRow }, }, current: SID, - phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) const workspaces = createSnapshotStore(workspaceState(workspaceRows)) const session = createSnapshotStore(snapshot) diff --git a/packages/client/ui-deliverables/tests/produced-files.client.spec.tsx b/packages/client/ui-deliverables/tests/produced-files.client.spec.tsx index 1460c31415..5cb0b0b120 100644 --- a/packages/client/ui-deliverables/tests/produced-files.client.spec.tsx +++ b/packages/client/ui-deliverables/tests/produced-files.client.spec.tsx @@ -35,7 +35,7 @@ import type { SessionEvent } from '@deepseek-ai/dsh-session/types' function openProps(controller = new PresentedOpenController()) { controller.host.set({ name: 'desktop', available: true, fileManager: 'finder' }) - const sessions: SessionListState = { ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined } + const sessions: SessionListState = { ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined } return { useSessions: (select: (state: SessionListState) => T): T => select(sessions), reloadPresentedHost: vi.fn(() => controller.loadHost()), diff --git a/packages/client/ui-jobs/tests/job-list-action.client.spec.tsx b/packages/client/ui-jobs/tests/job-list-action.client.spec.tsx index c3f016d58e..ba8e23552c 100644 --- a/packages/client/ui-jobs/tests/job-list-action.client.spec.tsx +++ b/packages/client/ui-jobs/tests/job-list-action.client.spec.tsx @@ -41,7 +41,7 @@ function props(jobs: readonly JobView[] | undefined): JobListActionProps { byId: {}, current: SESSION, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: jobs === undefined ? {} : { [SESSION]: jobs }, currentAddress: undefined, } satisfies SessionListState diff --git a/packages/client/ui-layout/tests/app-frame.client.spec.tsx b/packages/client/ui-layout/tests/app-frame.client.spec.tsx index 2e525ae028..72c71aa366 100644 --- a/packages/client/ui-layout/tests/app-frame.client.spec.tsx +++ b/packages/client/ui-layout/tests/app-frame.client.spec.tsx @@ -78,7 +78,7 @@ function mountFrame(windowWidth = frameWidth) { }, current: selectedSession, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) diff --git a/packages/client/ui-layout/tests/document-title.client.spec.tsx b/packages/client/ui-layout/tests/document-title.client.spec.tsx index 5c3184970f..ed6acc0a9e 100644 --- a/packages/client/ui-layout/tests/document-title.client.spec.tsx +++ b/packages/client/ui-layout/tests/document-title.client.spec.tsx @@ -21,7 +21,7 @@ function titleSources() { byId: { [sessionId]: { id: sessionId, displayTitle: 'Test', running: false, blank: false, updatedAt: 1 } }, current: sessionId, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) diff --git a/packages/client/ui-open-in-app/tests/open-in-app-action.client.spec.tsx b/packages/client/ui-open-in-app/tests/open-in-app-action.client.spec.tsx index 42d6ee0a02..e9a19dc560 100644 --- a/packages/client/ui-open-in-app/tests/open-in-app-action.client.spec.tsx +++ b/packages/client/ui-open-in-app/tests/open-in-app-action.client.spec.tsx @@ -34,7 +34,7 @@ function bench(over: { byId: over.cwd === undefined ? {} : { [SESSION]: { cwd: over.cwd } }, current: SESSION, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } as unknown as SessionListState diff --git a/packages/client/ui-session/tests/ui-session.client.spec.ts b/packages/client/ui-session/tests/ui-session.client.spec.ts index 9560fdbf5e..2bbbdd88e7 100644 --- a/packages/client/ui-session/tests/ui-session.client.spec.ts +++ b/packages/client/ui-session/tests/ui-session.client.spec.ts @@ -39,7 +39,7 @@ function createSessionsBench(_ctx: Context): SessionsBench { byId: {}, current: undefined, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) diff --git a/packages/client/ui-settings-unarchive-sessions/tests/components.client.spec.tsx b/packages/client/ui-settings-unarchive-sessions/tests/components.client.spec.tsx index 6e947e912b..075d7231dc 100644 --- a/packages/client/ui-settings-unarchive-sessions/tests/components.client.spec.tsx +++ b/packages/client/ui-settings-unarchive-sessions/tests/components.client.spec.tsx @@ -29,7 +29,7 @@ function sessionState(sessions: readonly SessionSummary[], phase: SessionListSta byId: Object.fromEntries(sessions.map(session => [session.id, session])), current: undefined, phase, - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } diff --git a/packages/client/ui-subagent/README.i18n.yaml b/packages/client/ui-subagent/README.i18n.yaml index e9e00343e6..4d0114ad2c 100644 --- a/packages/client/ui-subagent/README.i18n.yaml +++ b/packages/client/ui-subagent/README.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 packages/client/ui-subagent/README.md -README.md: f4c6da14e5cf3788f2ea0c40902b2dc07558ec7c -README.zh.md: d96b6dfcaadd02514dc65d74a3a1f266a98f1f3c +README.md: 3e3da6d65af38cbd4d6dad69ec8d081e0185caa8 +README.zh.md: 5b41a44ec93f783d8dc19b459bbe206f62edaba5 diff --git a/packages/client/ui-subagent/README.md b/packages/client/ui-subagent/README.md index f4c6da14e5..3e3da6d65a 100644 --- a/packages/client/ui-subagent/README.md +++ b/packages/client/ui-subagent/README.md @@ -25,11 +25,11 @@ Use this package to browse every subagent conversation beneath a parent session, ## Use this package -The session header keeps the current session title as the lineage breadcrumb and, when the session has subagent descendants, appends a `/` count trigger before the header's action row; the trigger opens the descendant catalog, counts the complete subagent-only lineage, stops at ordinary forks, and shows ongoing activity when any counted descendant is running. Select any depth to open that child's conversation with its exact `{parentSessionId, childSessionId, mode}` address. +The session header keeps the current session title as the lineage breadcrumb and appends a `/` count trigger when its direct catalog has entries or a read has failed. An absent catalog, an empty loading catalog, or a successfully loaded empty catalog hides the count trigger. The trigger opens that direct catalog, reports its total and running counts, and loads nested catalogs only when their rows expand. Select any depth to open that child's conversation with its exact `{parentSessionId, childSessionId, mode}` address. ### Browsing the tree -Rows display mode plus `running`/`inactive` activity and an optional log-backed title; the trailing column stacks total durable provider usage above active-turn duration. Keyboard navigation works with ArrowRight/ArrowLeft to expand and collapse branches and ArrowUp/ArrowDown, Home, End, and Escape to navigate or close the tree. An unlabeled one-shot row falls back to its session id; corrupt, unsupported, or unavailable rows remain readable but disabled. +Rows display mode plus `running`/`inactive` activity and an optional log-backed title; the trailing column stacks total durable provider usage above active-turn duration. Keyboard navigation works with ArrowRight/ArrowLeft to expand and collapse branches and ArrowUp/ArrowDown, Home, End, and Escape to navigate or close the tree. An unlabeled one-shot row falls back to its session id. A row is a known leaf only after its own catalog loads empty. ### Continuing a conversation @@ -51,11 +51,13 @@ The catalog and composer behavior are specified by the [Web subagent conversatio ### Catalog derivation -The header lineage renderer reads `subagentsByParent` and session summaries through the standard `useSessions` hook. The compact tree remains direct-catalog authoritative: each healthy row's `hasChildren` hint determines disclosure before interaction, a catalog level reserves the disclosure column only when at least one healthy row is a branch, and expanding a branch immediately reserves one disabled loading row per known direct descendant before lazily replacing them with that child's authoritative catalog. Every visible branch is reported to the runtime so membership frames cause a debounced refresh only where the tree is being consumed. +The header lineage renderer reads `projectionsBySession` through the standard `useSessions` hook. The renderer selects `subagentCatalog` from each Session’s shared values for membership, disclosure, and counts; Session summaries supply activity, titles, and usage. Expanding a row loads its initial catalog when needed. Live projection frames update every loaded level without menu subscriptions or repeated membership queries. A row remains expandable while its catalog is absent, loading, or failed, and becomes a known leaf after a ready empty catalog. + +Breadcrumb addresses derive from the selected address and loaded catalogs in the Session-list snapshot, including never-selected ancestors. ### Duration and tokens -Token totals sum the four disjoint `tokenUsage` buckets. Duration sums completed `subagentTiming` turns, advances once per second only for an open turn on a running child, and freezes after the child becomes inactive; an interrupted open turn is bounded by its same-cut `active.through`, never by newer session metadata. +Each visible catalog level advances its own clock while it contains a running child; collapsing the level or closing the menu releases that clock. Token totals sum the four disjoint `tokenUsage` buckets. Duration sums completed `subagentTiming` turns, advances once per second only for an open turn on a running child, and freezes after the child becomes inactive; an interrupted open turn is bounded by its same-cut `active.through`, never by newer session metadata. ### Composer election diff --git a/packages/client/ui-subagent/README.zh.md b/packages/client/ui-subagent/README.zh.md index d96b6dfcaa..5b41a44ec9 100644 --- a/packages/client/ui-subagent/README.zh.md +++ b/packages/client/ui-subagent/README.zh.md @@ -25,11 +25,11 @@ kind: "package-reference" ## 使用本包 -会话页头保留当前会话 title 作为谱系面包屑,并在会话存在 subagent 后代时,于页头操作行之前追加 `/` 数量触发器;触发器打开后代目录,统计仅含 subagent 的完整谱系、在普通 fork 处停止,并在任一计入统计的后代处于 `running` 时显示活动仍在进行。选择任意深度,即可用该子会话的确切 `{parentSessionId, childSessionId, mode}` 地址打开其对话。 +会话页头保留当前会话 title 作为谱系面包屑,并在直接目录有子项或读取失败时追加 `/` 数量触发器。目录缺席、空目录加载中或成功加载为空时,均隐藏数量触发器。触发器打开该直接目录,报告总数与运行数,并且只在行展开时加载嵌套目录。选择任意深度,即可用该子会话的确切 `{parentSessionId, childSessionId, mode}` 地址打开其对话。 ### 浏览目录 -行显示 mode、`running`/`inactive` 活动状态与由日志支撑的可选 title;尾随列在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。键盘导航:ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树。没有 label 的 one-shot 行回退到其会话 id;损坏、不受支持或不可用的行仍保持可读但禁用。 +行显示 mode、`running`/`inactive` 活动状态与由日志支撑的可选 title;尾随列在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。键盘导航:ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树。没有 label 的 one-shot 行回退到其会话 id。只有一行自身的目录加载为空后,它才是已知叶子。 ### 续接对话 @@ -51,11 +51,13 @@ kind: "package-reference" ### 目录派生 -页头谱系 renderer 通过标准 `useSessions` 钩子读取 `subagentsByParent` 与会话摘要。紧凑树仍以直接目录为权威依据:每个健康行的 `hasChildren` 提示在交互前决定是否显示展开控件;每层目录仅在其中至少一个健康行是分支时才预留展开列;展开分支时会立即为每个已知直接后代预留一行禁用的加载行,随后再用该 child 的权威目录懒加载结果替换。每个可见分支都会上报给运行时,使成员帧只在树正被消费的位置触发去抖动刷新。 +页头谱系 renderer 通过标准 `useSessions` 钩子读取 `projectionsBySession`。renderer 从每个 Session 的共享值中选择 `subagentCatalog`,用于成员关系、展开控件与数量;Session 摘要提供活动状态、标题与用量。展开行会按需加载初始目录。实时 projection 帧更新所有已加载层级,无需菜单订阅或重复成员查询。行在目录缺席、加载中或失败时保持可展开,并在目录就绪且为空后成为已知叶子。 + +面包屑地址从 Session 列表快照中的当前选中地址和已加载目录推导,也包括从未选中过的祖先。 ### 耗时与 token -token 用量总计为四个互不重叠的 `tokenUsage` 桶之和。耗时会累加已完成的 `subagentTiming` 轮次,仅在运行中 child 存在未结束轮次时每秒递增一次,并在 child 变为 inactive 后冻结;被中断的未结束轮次以其同一切面的 `active.through` 为上界,绝不使用更新的会话元数据。 +每个可见目录层在包含运行中 child 时独立推进时钟;折叠该层或关闭菜单会释放时钟。token 用量总计为四个互不重叠的 `tokenUsage` 桶之和。耗时会累加已完成的 `subagentTiming` 轮次,仅在运行中 child 存在未结束轮次时每秒递增一次,并在 child 变为 inactive 后冻结;被中断的未结束轮次以其同一切面的 `active.through` 为上界,绝不使用更新的会话元数据。 ### 编辑器选举 diff --git a/packages/client/ui-subagent/src/client/SubagentHeaderLineage.module.css b/packages/client/ui-subagent/src/client/SubagentHeaderLineage.module.css index 5b8582c295..34ae40ddb9 100644 --- a/packages/client/ui-subagent/src/client/SubagentHeaderLineage.module.css +++ b/packages/client/ui-subagent/src/client/SubagentHeaderLineage.module.css @@ -162,19 +162,6 @@ margin-top: 4px; } -.disabled { - color: var(--dsw-alias-label-dimmed); - cursor: not-allowed; -} - -.disabled:hover { - background: transparent; -} - -.loadingRow { - cursor: default; -} - .disclosure, .disclosureSpace { flex: none; diff --git a/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx b/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx index 6fa3da23a1..77e99dd938 100644 --- a/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx +++ b/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx @@ -1,10 +1,8 @@ -import { - useEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type MouseEvent, -} from 'react' +import { useMemo, useEffect, useRef, useState, type CSSProperties, type KeyboardEvent, type MouseEvent } from 'react' import { createPortal } from 'react-dom' import { - type SessionListState, type SessionProjectionMap, type SessionSummary, - type SubagentCatalogSnapshot, + type SessionProjectionMap, type SessionSummary, + type SessionProjectionSnapshot, } from '@deepseek-ai/dsh-api-session-controller/client' import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client' import type { SessionId } from '@deepseek-ai/dsh-session/types' @@ -16,16 +14,17 @@ import { NS } from './locales.ts' import type {} from '@deepseek-ai/dsh-client-ui-conversation/client' import type {} from '@deepseek-ai/dsh-token-meter/client' import css from './SubagentHeaderLineage.module.css' -import { indexSubagentDescendants } from './subagent-lineage.ts' -type CatalogEntry = SubagentCatalogSnapshot['entries'][number] -type Catalogs = SessionListState['subagentsByParent'] +type SubagentCatalogSnapshot = Omit & { + state: 'loading' | 'ready' | 'error' + entries: (SessionProjectionMap['subagentCatalog'][number] & { activity: 'running' | 'inactive' })[] +} +type Catalogs = Readonly> /** Business actions supplied by the slot registration. */ export interface SubagentCatalogInjected { openChild: (address: SubagentAddress) => void refresh: (parentSessionId: SessionId) => void - setCatalogOpen: (parentSessionId: SessionId, open: boolean) => void } /** Full props for the session-header lineage renderer. */ @@ -40,24 +39,12 @@ interface CatalogRowsProps { summaries: Readonly> expanded: ReadonlySet level: number - now: number openChild: (address: SubagentAddress) => void refresh: (parentSessionId: SessionId) => void toggleBranch: (childSessionId: SessionId) => void closeCatalog: () => void } -function diagnosticReason( - entry: Extract, - t: TranslateNS, -): string { - switch (entry.reason) { - case 'corrupt': return t('diagnostic.corrupt') - case 'unsupported': return t('diagnostic.unsupported') - case 'unavailable': return t('diagnostic.unavailable') - } -} - function treeItems(root: HTMLDivElement | null): HTMLElement[] { return root === null ? [] @@ -175,8 +162,6 @@ function formatExactDuration(ms: number, t: TranslateNS): string { }) } -const NO_DESCENDANTS = { count: 0, runningCount: 0 } as const - function SubagentSwitcherIcon() { return ( > - level: number - t: TranslateNS -}) { - const children = Object.values(summaries).filter(summary => ( - summary.origin === 'subagent' && summary.parentId === parentSessionId - )) - if (children.length === 0) return
{t('loading.label')}
- return children.map(summary => ( -
-
- - - - {t('loading.label')} - -
-
- )) +/** Render catalog loading without inventing child membership. */ +function CatalogLoadingRows({ t }: { t: TranslateNS }) { + return
{t('loading.label')}
+} + +/** A child becomes a known leaf only after its own authoritative catalog loads empty. */ +function isKnownLeaf(catalog: SubagentCatalogSnapshot | undefined): boolean { + return catalog?.state === 'ready' && catalog.entries.length === 0 } /** Render one catalog level and recurse only through explicitly expanded rows. */ function CatalogRows({ - parentSessionId, currentSessionId, catalog, catalogs, summaries, expanded, level, now, + parentSessionId, currentSessionId, catalog, catalogs, summaries, expanded, level, openChild, refresh, toggleBranch, closeCatalog, t, }: CatalogRowsProps & { t: TranslateNS }) { + const [now, setNow] = useState(() => Date.now()) + const running = catalog.entries.some(entry => entry.activity === 'running') + useEffect(() => { + if (!running) return + const timer = setInterval(() => { setNow(Date.now()) }, 1_000) + return () => { clearInterval(timer) } + }, [running]) const emptyLoading = catalog.state === 'loading' && catalog.entries.length === 0 - const reserveDisclosure = catalog.entries.some( - entry => entry.kind === 'child' && entry.hasChildren, - ) + const reserveDisclosure = catalog.entries.some(entry => !isKnownLeaf(catalogs[entry.id])) return ( <> {emptyLoading && ( - + )} {catalog.state === 'error' && (
@@ -268,33 +228,10 @@ function CatalogRows({
)} {catalog.entries.map((entry) => { - if (entry.kind === 'diagnostic') { - const reason = diagnosticReason(entry, t) - return ( -
-
- {reserveDisclosure && } - - - {entry.id} - {reason} - -
-
- ) - } - const childCatalog = catalogs[entry.id] const isCurrent = entry.id === currentSessionId const isExpanded = expanded.has(entry.id) - const knownLeaf = !entry.hasChildren + const knownLeaf = isKnownLeaf(childCatalog) const childLoading = childCatalog === undefined || (childCatalog.state === 'loading' && childCatalog.entries.length === 0) const summary = summaries[entry.id] @@ -324,7 +261,11 @@ function CatalogRows({ .join(' · ') const open = (): void => { - openChild({ parentSessionId, childSessionId: entry.id, mode: entry.mode }) + openChild({ + parentSessionId, + childSessionId: entry.id, + mode: entry.mode, + }) closeCatalog() } const handleKey = (event: KeyboardEvent): void => { @@ -401,14 +342,7 @@ function CatalogRows({ aria-busy={childLoading || undefined} > {childCatalog === undefined - ? ( - - ) + ? : ( state.subagentsByParent) + const projections = useSessions(state => state.projectionsBySession) const summaries = useSessions(state => state.byId) + const catalogs = useMemo(() => Object.fromEntries(Object.entries(projections).map(([id, snapshot]) => [id, { + state: snapshot.state === 'idle' + ? snapshot.values.subagentCatalog === undefined ? 'loading' : 'ready' + : snapshot.state, + error: snapshot.error, + entries: (snapshot.values.subagentCatalog ?? []).map(entry => ({ + ...entry, activity: summaries[entry.id]?.running === true ? 'running' as const : 'inactive' as const, + })), + }])), [projections, summaries]) const catalog = catalogs[rootSessionId] const [open, setOpen] = useState(false) const [menuPosition, setMenuPosition] = useState() - const [now, setNow] = useState(() => Date.now()) const [expanded, setExpanded] = useState>(() => new Set()) const rootRef = useRef(null) const triggerRef = useRef(null) const menuRef = useRef(null) const hoverOpenTimer = useRef | undefined>(undefined) const hoverCloseTimer = useRef | undefined>(undefined) - const observedCatalogs = useRef(new Set()) - const setCatalogOpenRef = useRef(setCatalogOpen) - setCatalogOpenRef.current = setCatalogOpen const currentEntry = currentSessionId === undefined ? undefined - : catalog?.entries.find(entry => entry.kind === 'child' && entry.id === currentSessionId) - const switcherDisplayTitle = currentEntry?.kind === 'child' + : catalog?.entries.find(entry => entry.id === currentSessionId) + const switcherDisplayTitle = currentEntry !== undefined ? currentEntry.label ?? currentEntry.id : displayTitle - const healthy = catalog?.entries.filter(entry => entry.kind === 'child') ?? [] - const descendants = useMemo( - () => indexSubagentDescendants(summaries).get(rootSessionId) ?? NO_DESCENDANTS, - [rootSessionId, summaries], - ) - // The catalog can arrive before the session-list baseline; never undercount - // the already-visible direct rows during that short bootstrap window. - const descendantCount = Math.max(healthy.length, descendants.count) - const totalCountKey = descendantCount === 1 ? 'count.total.one' : 'count.total.other' - const runningCountKey = descendants.runningCount === 1 ? 'count.running.one' : 'count.running.other' - // Session summaries can announce membership before the descriptor-backed catalog catches up. - // Keep that entry point visible through disabled loading rows; only catalog rows are navigable. - const summaryBackedLoading = (descendants.count > 0 || variant === 'switcher') - && (catalog === undefined || (catalog.state === 'ready' && catalog.entries.length === 0)) - const presentedCatalog: SubagentCatalogSnapshot | undefined = summaryBackedLoading - ? { - entries: [], - parentAvailable: catalog?.parentAvailable ?? false, - state: 'loading', - error: null, - } - : catalog - - const observeCatalog = (parentSessionId: SessionId, next: boolean): void => { - if (next) observedCatalogs.current.add(parentSessionId) - else observedCatalogs.current.delete(parentSessionId) - setCatalogOpen(parentSessionId, next) - } - - const closeAllCatalogs = (): void => { - for (const parentSessionId of observedCatalogs.current) { - setCatalogOpen(parentSessionId, false) - } - observedCatalogs.current.clear() - setExpanded(new Set()) - } + const directChildren = catalog?.entries ?? [] + const directCount = directChildren.length + const runningCount = directChildren.filter(entry => entry.activity === 'running').length + const totalCountKey = directCount === 1 ? 'count.total.one' : 'count.total.other' + const runningCountKey = runningCount === 1 ? 'count.running.one' : 'count.running.other' + const presentedCatalog: SubagentCatalogSnapshot | undefined = catalog ?? (variant === 'switcher' + ? { entries: [], state: 'loading', error: null } + : undefined) const cancelHoverClose = (): void => { if (hoverCloseTimer.current === undefined) return @@ -564,13 +474,12 @@ function CatalogDropdown({ if (trigger === null) return setOpen(true) setMenuPosition(catalogMenuPosition(trigger)) - setNow(Date.now()) - observeCatalog(rootSessionId, true) + refresh(rootSessionId) } else { setOpen(false) setMenuPosition(undefined) - closeAllCatalogs() + setExpanded(new Set()) } if (restoreFocus) queueMicrotask(() => { triggerRef.current?.focus() }) } @@ -601,11 +510,10 @@ function CatalogDropdown({ closing.add(parentSessionId) const branch = catalogs[parentSessionId] for (const entry of branch?.entries ?? []) { - if (entry.kind === 'child') visit(entry.id) + visit(entry.id) } } visit(root) - for (const parentSessionId of closing) observeCatalog(parentSessionId, false) setExpanded(current => new Set([...current].filter(id => !closing.has(id)))) } @@ -615,7 +523,7 @@ function CatalogDropdown({ return } setExpanded(current => new Set(current).add(childSessionId)) - observeCatalog(childSessionId, true) + refresh(childSessionId) } useEffect(() => { @@ -649,37 +557,24 @@ function CatalogDropdown({ } }, [open]) - useEffect(() => { - if (!open || descendants.runningCount === 0) return - const timer = setInterval(() => { setNow(Date.now()) }, 1_000) - return () => { clearInterval(timer) } - }, [open, descendants.runningCount]) - useEffect(() => () => { cancelHoverOpen() cancelHoverClose() - for (const parentSessionId of observedCatalogs.current) { - setCatalogOpenRef.current(parentSessionId, false) - } - observedCatalogs.current.clear() }, []) - // Visibility needs evidence of children (entries, summary-known descendants, - // or a failed load worth retrying). A bare loading catalog is not evidence: - // selecting any session schedules a refresh whose loading snapshot would - // otherwise flash the action in and out on childless sessions. + // Visibility needs catalog evidence of children or a failed load worth retrying. + // An empty loading catalog is not evidence of children. const visible = presentedCatalog !== undefined && (variant === 'switcher' || presentedCatalog.state === 'error' - || presentedCatalog.entries.length > 0 - || descendantCount > 0) + || presentedCatalog.entries.length > 0) useEffect(() => { if (visible) return cancelHoverOpen() cancelHoverClose() if (!open) return setOpen(false) - closeAllCatalogs() + setExpanded(new Set()) }, [visible, open]) if (!visible) return null @@ -731,8 +626,8 @@ function CatalogDropdown({ aria-label={variant === 'switcher' ? t('switcher.aria', { title: switcherDisplayTitle }) : t( - descendants.runningCount > 0 ? runningCountKey : totalCountKey, - { count: descendants.runningCount > 0 ? descendants.runningCount : descendantCount }, + runningCount > 0 ? runningCountKey : totalCountKey, + { count: runningCount > 0 ? runningCount : directCount }, )} onClick={openTitle === undefined ? undefined @@ -752,12 +647,12 @@ function CatalogDropdown({ ? {switcherDisplayTitle} : ( <> - {descendants.runningCount > 0 && ( + {runningCount > 0 && ( )} - {t(totalCountKey, { count: descendantCount })} + {t(totalCountKey, { count: directCount })} )} {variant === 'switcher' @@ -782,7 +677,6 @@ function CatalogDropdown({ summaries={summaries} expanded={expanded} level={1} - now={now} openChild={openChild} refresh={refresh} toggleBranch={toggleBranch} @@ -798,17 +692,20 @@ function CatalogDropdown({ /** * Render one breadcrumb title together with its subagent navigation. * @param props - Breadcrumb title, session standard props, and catalog actions. - * @returns An ordinary-title descendant count, or a title-and-chevron sibling switcher. + * @returns An ordinary-title direct-child count, or a title-and-chevron sibling switcher. */ export function SubagentHeaderLineage({ lineageSessionId, displayTitle, openTitle, - useSessions, openChild, refresh, setCatalogOpen, t, + useSessions, openChild, refresh, t, }: SubagentHeaderLineageProps) { const parentId = useSessions((state) => { - const summary = state.byId[lineageSessionId] - return summary?.origin === 'subagent' ? summary.parentId : undefined + if (state.currentAddress?.childSessionId === lineageSessionId) return state.currentAddress.parentSessionId + for (const [parentId, snapshot] of Object.entries(state.projectionsBySession)) { + if (snapshot.values.subagentCatalog?.some(entry => entry.id === lineageSessionId)) return parentId as SessionId + } + return undefined }) - const shared = { useSessions, openChild, refresh, setCatalogOpen, t } + const shared = { useSessions, openChild, refresh, t } if (parentId === undefined) { return ( = { - 'diagnostic.corrupt': 'corrupted session record', - 'diagnostic.unsupported': 'unsupported subagent record version', - 'diagnostic.unavailable': 'session record temporarily unavailable', 'duration.seconds': '{seconds}s', 'duration.minutes': '{minutes}m {seconds}s', 'duration.hours': '{hours}h {minutes}m {seconds}s', @@ -64,7 +57,6 @@ export const en: Record = { 'tokens.million': '{value}M', 'tokens.total': '{value} tok', 'loading.label': 'Loading subagents…', - 'loading.aria': 'Loading subagents', 'load.error': 'Unable to load subagents', 'retry': 'Retry', 'mode.oneShot': 'one-shot', diff --git a/packages/client/ui-subagent/src/client/subagent-lineage.ts b/packages/client/ui-subagent/src/client/subagent-lineage.ts deleted file mode 100644 index d96ab4ff8a..0000000000 --- a/packages/client/ui-subagent/src/client/subagent-lineage.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** UI Subagent-owned projection of descendant counts from Session summaries. */ - -import type { SessionId } from '@deepseek-ai/dsh-session/types' - -interface LineageEntry { - readonly id: SessionId - readonly parentId?: SessionId - readonly origin?: 'subagent' - readonly running: boolean -} - -/** Descendant counts for one possible parent Session. */ -export interface SubagentDescendantSummary { - readonly count: number - readonly runningCount: number -} - -/* jscpd:ignore-start -- UI Subagent and UI Workspace independently project their own views. */ -/** - * Index uninterrupted subagent descendants under each ancestor. - * @param summaries - Session summaries keyed by id. - * @returns descendant totals keyed by possible parent id. - */ -export function indexSubagentDescendants( - summaries: Readonly>, -): ReadonlyMap { - const indexed = new Map() - for (const descendant of Object.values(summaries)) { - if (descendant.origin !== 'subagent') continue - const seen = new Set() - let current: LineageEntry | undefined = descendant - while (current?.origin === 'subagent' && current.parentId !== undefined && !seen.has(current.id)) { - seen.add(current.id) - const aggregate = indexed.get(current.parentId) - if (aggregate === undefined) { - indexed.set(current.parentId, { count: 1, runningCount: descendant.running ? 1 : 0 }) - } else { - aggregate.count += 1 - if (descendant.running) aggregate.runningCount += 1 - } - current = summaries[current.parentId] - } - } - return indexed -} -/* jscpd:ignore-end */ diff --git a/packages/client/ui-subagent/tests/browser-plugin.client.spec.ts b/packages/client/ui-subagent/tests/browser-plugin.client.spec.ts index 015b42c54d..100faa6f1d 100644 --- a/packages/client/ui-subagent/tests/browser-plugin.client.spec.ts +++ b/packages/client/ui-subagent/tests/browser-plugin.client.spec.ts @@ -35,22 +35,27 @@ function sessionsWith(sessions: SessionSummary[]) { for (const s of sessions) byId[s.id] = s const snapshot = { ids: sessions.map(s => s.id), byId, current: undefined } as unknown as SessionListState const actionCalls: { method: string; args: unknown[] }[] = [] + const address: SubagentAddress = { + parentSessionId: sid('parent'), + childSessionId: sid('c1'), + mode: 'continuable', + } return { list: { getSnapshot: () => snapshot, subscribe: () => () => {}, }, actionCalls, + subagentAddress: (childSessionId: SessionId) => childSessionId === address.childSessionId + ? address + : undefined, openSubagent: (address: SubagentAddress) => { actionCalls.push({ method: 'openSubagent', args: [address] }) }, - refreshSubagents: (parentSessionId: SessionId) => { - actionCalls.push({ method: 'refreshSubagents', args: [parentSessionId] }) + refreshProjections: (parentSessionId: SessionId) => { + actionCalls.push({ method: 'refreshProjections', args: [parentSessionId] }) return Promise.resolve() }, - setSubagentCatalogOpen: (parentSessionId: SessionId, open: boolean) => { - actionCalls.push({ method: 'setSubagentCatalogOpen', args: [parentSessionId, open] }) - }, } } @@ -105,11 +110,9 @@ describe('apply', () => { } actions.openChild(address) actions.refresh(sid('parent')) - actions.setCatalogOpen(sid('parent'), true) expect(face.actionCalls).toEqual([ { method: 'openSubagent', args: [address] }, - { method: 'refreshSubagents', args: [sid('parent')] }, - { method: 'setSubagentCatalogOpen', args: [sid('parent'), true] }, + { method: 'refreshProjections', args: [sid('parent')] }, ]) const composerEntry = ctx.slots.entries('conversation.composer') diff --git a/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx b/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx index e026945747..6734e07dbd 100644 --- a/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx +++ b/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx @@ -3,8 +3,9 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import { act, cleanup, fireEvent, render, screen, within } from '@testing-library/react' import { makeTranslate, RemoteError } from '@deepseek-ai/dsh-client-test-runtime' import type { - SessionListState, SessionSummary, SubagentCatalogSnapshot, + SessionListState, SessionSummary, } from '@deepseek-ai/dsh-api-session-controller/client' +import type { SubagentAddress, SubagentCatalogRow } from '@deepseek-ai/dsh-subagent/client' import type { SessionId } from '@deepseek-ai/dsh-session/types' import { SubagentHeaderLineage, type SubagentHeaderLineageProps, @@ -23,18 +24,19 @@ const CHILD = 'child' as SessionId const GRANDCHILD = 'grandchild' as SessionId const t: SubagentHeaderLineageProps['t'] = makeTranslate(zh) -function catalog(over: Partial = {}): SubagentCatalogSnapshot { +type CatalogFixture = { entries: readonly SubagentCatalogRow[]; parentAvailable: boolean; state: 'loading' | 'ready' | 'error'; error: SessionListState['projectionsBySession'][SessionId]['error'] } + +function catalog(over: Partial = {}): CatalogFixture { return { entries: [ { - kind: 'child', id: CHILD, mode: 'continuable', label: 'worker', - activity: 'running', hasChildren: true, + id: CHILD, mode: 'continuable', label: 'worker', + activity: 'running', }, { - kind: 'child', id: 'child-2' as SessionId, mode: 'one-shot', - label: 'reviewer', activity: 'inactive', hasChildren: false, + id: 'child-2' as SessionId, mode: 'one-shot', + label: 'reviewer', activity: 'inactive', }, - { kind: 'diagnostic', id: 'bad' as SessionId, reason: 'corrupt' }, ], parentAvailable: true, state: 'ready', @@ -44,26 +46,34 @@ function catalog(over: Partial = {}): SubagentCatalogSn } function props( - value: SubagentCatalogSnapshot | undefined, - nested: Readonly> = {}, + value: CatalogFixture | undefined, + nested: Readonly> = {}, summaries?: Readonly>, + currentAddress?: SubagentAddress, ) { + const catalogs = value === undefined ? nested : { [PARENT]: value, ...nested } const state = { ids: [CHILD], byId: summaries ?? { + ...Object.fromEntries(Object.values(catalogs).flatMap(catalog => catalog.entries.map(entry => [entry.id, { + id: entry.id, displayTitle: entry.label ?? entry.id, running: entry.activity === 'running', blank: false, updatedAt: 1, + }]))), [CHILD]: { id: CHILD, title: '正在扫描项目文件', displayTitle: 'worker', - running: true, + running: Object.values(catalogs).some(catalog => catalog.entries.some(entry => entry.id === CHILD && entry.activity === 'running')), blank: false, updatedAt: Date.now(), }, }, current: PARENT, phase: 'ready', - subagentsByParent: value === undefined ? nested : { [PARENT]: value, ...nested }, + projectionsBySession: Object.fromEntries(Object.entries(catalogs).map(([id, catalog]) => [id, { + state: catalog.state, error: catalog.error, + values: { subagentCatalog: catalog.entries.map(({ activity: _activity, ...entry }) => ({ ...entry, createdAt: 1 })) }, + }])) , jobsBySession: {}, - currentAddress: undefined, + currentAddress, } satisfies SessionListState function useSessions(select: (snapshot: SessionListState) => T): T { return select(state) @@ -73,7 +83,6 @@ function props( useSessions, openChild: vi.fn(), refresh: vi.fn(), - setCatalogOpen: vi.fn(), lineageSessionId: PARENT, displayTitle: 'Parent title', t, @@ -99,10 +108,32 @@ function hoverCatalog(trigger: HTMLElement): void { } describe('SubagentHeaderLineage', () => { - it('aggregates live descendant activity onto the closed trigger', () => { + it('shows retained children while an idle projection awaits refresh', () => { + const injected = props(catalog()) + const initial = injected.useSessions(state => state) + let projections: SessionListState['projectionsBySession'] = { + [PARENT]: { state: 'idle', error: null, values: {} }, + } + const current: SubagentHeaderLineageProps = { + ...injected, + useSessions: select => select({ ...initial, projectionsBySession: projections }), + } + const view = render() + expect(screen.queryByRole('button')).toBeNull() + + projections = { + [PARENT]: { ...initial.projectionsBySession[PARENT]!, state: 'idle' }, + } + view.rerender() + hoverCatalog(screen.getByRole('button')) + expect(screen.getByRole('treeitem', { name: /worker/ })).toBeTruthy() + expect(screen.getByRole('treeitem', { name: /reviewer/ })).toBeTruthy() + }) + + it('combines projected membership with Session activity on the closed trigger', () => { const summaries: Record = { [CHILD]: { - ...summary(CHILD, Date.now()), + ...summary(CHILD, Date.now()), running: true, parentId: PARENT, origin: 'subagent', }, @@ -124,17 +155,20 @@ describe('SubagentHeaderLineage', () => { expect(trigger.querySelector('[data-state="ongoing"]')).not.toBeNull() view.rerender() - const inactiveTrigger = screen.getByRole('button', { name: '3 个子代理' }) + const inactiveTrigger = screen.getByRole('button', { name: '2 个子代理' }) expect(inactiveTrigger.querySelector('[data-state="ongoing"]')).toBeNull() }) - it('does not aggregate subagents reached through an ordinary fork', () => { + it('does not count Sessions outside projected membership', () => { const fork = 'fork' as SessionId const forkChild = 'fork-child' as SessionId - render( { [forkChild]: { ...summary(forkChild, 1), parentId: fork, origin: 'subagent', running: true }, })} />) - const trigger = screen.getByRole('button', { name: '2 个子代理' }) + const trigger = screen.getByRole('button', { name: '1 个子代理' }) expect(trigger.querySelector('[data-state="ongoing"]')).toBeNull() }) - it('renders healthy counts, stable rows, diagnostics, and catalog-addressed navigation', () => { + it('renders stable rows and catalog-addressed navigation', () => { const input = props(catalog()) render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) hoverCatalog(trigger) - expect(input.setCatalogOpen).toHaveBeenCalledWith(PARENT, true) - expect(screen.getAllByRole('treeitem')).toHaveLength(3) + expect(input.refresh).toHaveBeenCalledWith(PARENT) + expect(screen.getAllByRole('treeitem')).toHaveLength(2) expect(screen.getByText('正在扫描项目文件 · 可继续 · 正在运行')).toBeTruthy() expect(screen.getByText('一次性 · 当前未运行')).toBeTruthy() - const diagnostic = screen.getByRole('treeitem', { name: /会话记录损坏/ }) - expect(diagnostic.getAttribute('aria-disabled')).toBe('true') expect(screen.getByRole('button', { name: '展开 worker 的下级子代理' })).toBeTruthy() - expect(screen.queryByRole('button', { name: '展开 reviewer 的下级子代理' })).toBeNull() - expect(screen.getByRole('treeitem', { name: /reviewer/ }).children).toHaveLength(2) + expect(screen.getByRole('button', { name: '展开 reviewer 的下级子代理' })).toBeTruthy() fireEvent.click(screen.getByRole('treeitem', { name: /worker/ })) expect(input.openChild).toHaveBeenCalledWith({ - parentSessionId: PARENT, childSessionId: CHILD, mode: 'continuable', + parentSessionId: PARENT, + childSessionId: CHILD, mode: 'continuable', }) - expect(input.setCatalogOpen).toHaveBeenLastCalledWith(PARENT, false) }) - it('selects singular count keys for one descendant', () => { + it('selects singular count keys for one direct child', () => { const base = props(catalog({ entries: [{ - kind: 'child', id: CHILD, mode: 'continuable', label: 'worker', - activity: 'running', hasChildren: false, + id: CHILD, mode: 'continuable', label: 'worker', + activity: 'running', }], }), {}, { [CHILD]: { @@ -189,22 +220,26 @@ describe('SubagentHeaderLineage', () => { }) it('removes the disclosure column from branchless catalog levels', () => { - const input = props(catalog({ - entries: [{ - kind: 'child', id: CHILD, mode: 'continuable', label: 'worker', - activity: 'running', hasChildren: false, - }], - })) - render() + render() hoverCatalog(screen.getByRole('button', { name: /1 个子代理/ })) expect(screen.getByRole('treeitem', { name: /worker/ }).children).toHaveLength(1) }) + it('aligns a known leaf with siblings whose child catalog is still unknown', () => { + render() + hoverCatalog(screen.getByRole('button', { name: /1 个子代理,正在运行/ })) + + expect(screen.getByRole('treeitem', { name: /worker/ }).children).toHaveLength(2) + expect(screen.getByRole('button', { name: /展开 reviewer/ })).toBeTruthy() + }) + it('supports trigger/menu keyboard traversal, Escape focus restore, and outside close', async () => { const input = props(catalog()) render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) fireEvent.keyDown(trigger, { key: 'ArrowDown' }) await Promise.resolve() expect(document.activeElement).toBe(screen.getByRole('treeitem', { name: /worker/ })) @@ -233,7 +268,7 @@ describe('SubagentHeaderLineage', () => { await act(async () => { await vi.advanceTimersByTimeAsync(duration) }) } const view = render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) const triggerRect = vi.spyOn(trigger, 'getBoundingClientRect') .mockReturnValue({ bottom: 40, left: 50 } as DOMRect) @@ -270,7 +305,7 @@ describe('SubagentHeaderLineage', () => { it('repositions an open catalog after viewport resize and document scroll', () => { const view = render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) const bounds = vi.spyOn(trigger, 'getBoundingClientRect') bounds.mockReturnValue({ bottom: 20, left: 30 } as DOMRect) hoverCatalog(trigger) @@ -293,7 +328,7 @@ describe('SubagentHeaderLineage', () => { it('cancels a pending hover when the trigger becomes hidden', async () => { vi.useFakeTimers() const view = render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) fireEvent.mouseEnter(trigger.parentElement!) await vi.advanceTimersByTimeAsync(149) @@ -305,40 +340,36 @@ describe('SubagentHeaderLineage', () => { expect(screen.queryByRole('tree')).toBeNull() }) - it('covers diagnostic variants, fallback labels, and keyboard row activation', () => { - const unsupported = 'unsupported' as SessionId - const unavailable = 'unavailable' as SessionId + it('covers fallback labels and keyboard row activation', () => { const unlabeled = 'unlabeled' as SessionId const input = props(catalog({ entries: [ - { kind: 'diagnostic', id: unsupported, reason: 'unsupported' }, - { kind: 'diagnostic', id: unavailable, reason: 'unavailable' }, { - kind: 'child', id: CHILD, mode: 'continuable', label: 'worker', - activity: 'running', hasChildren: false, + id: CHILD, mode: 'continuable', label: 'worker', + activity: 'running', }, { - kind: 'child', id: unlabeled, mode: 'one-shot', - activity: 'inactive', hasChildren: false, + id: unlabeled, mode: 'one-shot', + activity: 'inactive', }, ], })) render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) fireEvent.keyDown(trigger, { key: 'Tab' }) expect(screen.queryByRole('tree')).toBeNull() hoverCatalog(trigger) - expect(screen.getByRole('treeitem', { name: /子代理记录版本不受支持/ })).toBeTruthy() - expect(screen.getByRole('treeitem', { name: /会话记录暂不可用/ })).toBeTruthy() fireEvent.keyDown(screen.getByRole('treeitem', { name: /worker/ }), { key: 'Enter' }) expect(input.openChild).toHaveBeenLastCalledWith({ - parentSessionId: PARENT, childSessionId: CHILD, mode: 'continuable', + parentSessionId: PARENT, + childSessionId: CHILD, mode: 'continuable', }) hoverCatalog(trigger) fireEvent.keyDown(screen.getByRole('treeitem', { name: /unlabeled/ }), { key: ' ' }) expect(input.openChild).toHaveBeenLastCalledWith({ - parentSessionId: PARENT, childSessionId: unlabeled, mode: 'one-shot', + parentSessionId: PARENT, + childSessionId: unlabeled, mode: 'one-shot', }) }) @@ -381,12 +412,10 @@ describe('SubagentHeaderLineage', () => { }, } as const const entries = rows.map(([id, activity]) => ({ - kind: 'child' as const, id: id as SessionId, mode: 'continuable' as const, label: id, activity, - hasChildren: false, })) const summaries = Object.fromEntries(rows.map(([ id, activity, settledMs, activeSince, activeThrough, updatedAt, @@ -439,12 +468,47 @@ describe('SubagentHeaderLineage', () => { expect(screen.getByRole('treeitem', { name: /interrupted.*123M tok · 6秒/ })).toBeTruthy() }) + it('ticks expanded running grandchildren under an idle child and releases their clock on collapse', async () => { + const now = 2_000_000_000_000 + vi.useFakeTimers() + vi.setSystemTime(now) + const input = props(catalog({ entries: [{ + id: CHILD, mode: 'continuable', label: 'worker', activity: 'inactive', + }] }), { + [CHILD]: catalog({ entries: [{ + id: GRANDCHILD, mode: 'continuable', label: 'indexer', activity: 'running', + }] }), + }, { + [GRANDCHILD]: { + ...summary(GRANDCHILD, now), + parentId: CHILD, + origin: 'subagent', + running: true, + projectionValues: { + subagentTiming: { settledMs: 0, active: { since: now - 5_000, through: now } }, + }, + }, + }) + render() + hoverCatalog(screen.getByRole('button', { name: '1 个子代理' })) + const beforeExpand = vi.getTimerCount() + fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) + expect(screen.getByRole('treeitem', { name: /indexer.*5秒/ })).toBeTruthy() + await act(async () => { await vi.advanceTimersByTimeAsync(1_000) }) + expect(screen.getByRole('treeitem', { name: /indexer.*6秒/ })).toBeTruthy() + fireEvent.click(screen.getByRole('button', { name: '收起 worker 的下级子代理' })) + expect(vi.getTimerCount()).toBe(beforeExpand) + await act(async () => { await vi.advanceTimersByTimeAsync(1_000) }) + fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) + expect(screen.getByRole('treeitem', { name: /indexer.*7秒/ })).toBeTruthy() + }) + it('lazily expands and collapses descendant catalogs with direct-parent navigation', () => { const childCatalog = catalog({ entries: [ { - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'inactive', hasChildren: false, + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'inactive', }, ], }) @@ -454,24 +518,24 @@ describe('SubagentHeaderLineage', () => { [GRANDCHILD]: grandchildCatalog, }) render() - hoverCatalog(screen.getByRole('button', { name: /2 个子代理/ })) + hoverCatalog(screen.getByRole('button', { name: /1 个子代理,正在运行/ })) fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) - expect(input.setCatalogOpen).toHaveBeenCalledWith(CHILD, true) + expect(input.refresh).toHaveBeenCalledWith(CHILD) const nested = screen.getByRole('treeitem', { name: /indexer/ }) expect(nested.getAttribute('aria-level')).toBe('2') fireEvent.click(nested) expect(input.openChild).toHaveBeenCalledWith({ - parentSessionId: CHILD, childSessionId: GRANDCHILD, mode: 'continuable', + parentSessionId: CHILD, + childSessionId: GRANDCHILD, mode: 'continuable', }) - expect(input.setCatalogOpen).toHaveBeenCalledWith(PARENT, false) - expect(input.setCatalogOpen).toHaveBeenCalledWith(CHILD, false) }) - it('shows known descendant rows while their catalog loads', () => { + it('shows one generic state while a child catalog loads', () => { const secondGrandchild = 'grandchild-2' as SessionId const summaries = { + [CHILD]: { ...summary(CHILD, 1), running: true }, [GRANDCHILD]: { ...summary(GRANDCHILD, 1), parentId: CHILD, origin: 'subagent' as const, }, @@ -482,32 +546,30 @@ describe('SubagentHeaderLineage', () => { } const deferred = props(catalog(), {}, summaries) const view = render() - hoverCatalog(screen.getByRole('button', { name: /2 个子代理/ })) + hoverCatalog(screen.getByRole('button', { name: /1 个子代理,正在运行/ })) fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) - expect(deferred.setCatalogOpen).toHaveBeenCalledWith(CHILD, true) + expect(deferred.refresh).toHaveBeenCalledWith(CHILD) expect(screen.getByRole('group').getAttribute('aria-busy')).toBe('true') - const loadingRows = screen.getAllByRole('treeitem', { name: '正在加载子代理' }) - expect(loadingRows).toHaveLength(2) - expect(loadingRows.every(row => row.getAttribute('aria-level') === '2')).toBe(true) - expect(loadingRows[1]?.querySelector('[data-state="ongoing"]')).not.toBeNull() + expect(screen.getByText('正在加载子代理…')).toBeTruthy() + expect(screen.queryByRole('treeitem', { name: '正在加载子代理' })).toBeNull() const loading = props(catalog(), { [CHILD]: catalog({ entries: [], state: 'loading' }), }, summaries) view.rerender() - expect(screen.getAllByRole('treeitem', { name: '正在加载子代理' })).toHaveLength(2) + expect(screen.getByText('正在加载子代理…')).toBeTruthy() const ready = props(catalog(), { [CHILD]: catalog({ entries: [ { - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'inactive', hasChildren: false, + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'inactive', }, { - kind: 'child', id: secondGrandchild, mode: 'one-shot', - label: 'critic', activity: 'running', hasChildren: false, + id: secondGrandchild, mode: 'one-shot', + label: 'critic', activity: 'running', }, ], }), @@ -516,20 +578,20 @@ describe('SubagentHeaderLineage', () => { expect(screen.getByRole('group').getAttribute('aria-busy')).toBeNull() expect(screen.getByRole('treeitem', { name: /indexer/ })).toBeTruthy() expect(screen.getByRole('treeitem', { name: /critic/ })).toBeTruthy() - expect(screen.queryByRole('treeitem', { name: '正在加载子代理' })).toBeNull() + expect(screen.queryByText('正在加载子代理…')).toBeNull() }) it('uses ArrowRight and ArrowLeft for branch disclosure', async () => { const input = props(catalog(), { [CHILD]: catalog({ entries: [{ - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'running', hasChildren: false, + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'running', }], }), }) render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) fireEvent.keyDown(trigger, { key: 'ArrowDown' }) await Promise.resolve() const worker = screen.getByRole('treeitem', { name: /worker/ }) @@ -537,29 +599,23 @@ describe('SubagentHeaderLineage', () => { expect(screen.getByRole('treeitem', { name: /indexer/ })).toBeTruthy() fireEvent.keyDown(worker, { key: 'ArrowLeft' }) expect(screen.queryByRole('treeitem', { name: /indexer/ })).toBeNull() - expect(input.setCatalogOpen).toHaveBeenCalledWith(CHILD, false) }) it('closes expanded descendants even when their own catalogs have not arrived', () => { const input = props(catalog(), { [CHILD]: catalog({ - entries: [ - { - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'running', hasChildren: true, - }, - { kind: 'diagnostic', id: 'nested-bad' as SessionId, reason: 'corrupt' }, - ], + entries: [{ + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'running', + }], }), }) render() - hoverCatalog(screen.getByRole('button', { name: /2 个子代理/ })) + hoverCatalog(screen.getByRole('button', { name: /1 个子代理,正在运行/ })) fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) fireEvent.click(screen.getByRole('button', { name: '展开 indexer 的下级子代理' })) fireEvent.click(screen.getByRole('button', { name: '收起 worker 的下级子代理' })) - expect(input.setCatalogOpen).toHaveBeenCalledWith(GRANDCHILD, false) - expect(input.setCatalogOpen).toHaveBeenCalledWith(CHILD, false) expect(screen.queryByRole('treeitem', { name: /indexer/ })).toBeNull() }) @@ -585,7 +641,7 @@ describe('SubagentHeaderLineage', () => { expect(failed.refresh).toHaveBeenCalledWith(PARENT) }) - it('keeps known descendants reachable while their catalog is absent or stale-empty', () => { + it('does not expose summary-only descendants as catalog rows', () => { const second = 'child-2' as SessionId const summaries = { [CHILD]: { @@ -597,19 +653,11 @@ describe('SubagentHeaderLineage', () => { } const absent = props(undefined, {}, summaries) const view = render() - - const trigger = screen.getByRole('button', { name: '1 个子代理,正在运行' }) - expect(within(trigger).getByText('2 个子代理')).toBeTruthy() - hoverCatalog(trigger) - expect(absent.setCatalogOpen).toHaveBeenCalledWith(PARENT, true) - expect(screen.getAllByRole('treeitem', { name: '正在加载子代理' })).toHaveLength(2) - expect(absent.openChild).not.toHaveBeenCalled() + expect(screen.queryByRole('button')).toBeNull() const staleEmpty = props(catalog({ entries: [] }), {}, summaries) view.rerender() - expect(screen.getByRole('button', { name: '1 个子代理,正在运行' })).toBeTruthy() - expect(screen.getAllByRole('treeitem', { name: '正在加载子代理' })).toHaveLength(2) - expect(staleEmpty.openChild).not.toHaveBeenCalled() + expect(screen.queryByRole('button')).toBeNull() }) it('hides a bare loading catalog and keeps the error fallback without focusable rows', async () => { @@ -634,7 +682,7 @@ describe('SubagentHeaderLineage', () => { it('navigates from outside the tree and tolerates a deferred focus after unmount', async () => { const input = props(catalog()) const view = render() - const trigger = screen.getByRole('button', { name: /2 个子代理/ }) + const trigger = screen.getByRole('button', { name: /1 个子代理,正在运行/ }) hoverCatalog(trigger) fireEvent.keyDown(screen.getByRole('tree'), { key: 'ArrowUp' }) expect(document.activeElement).toBe(screen.getByRole('treeitem', { name: /reviewer/ })) @@ -647,27 +695,25 @@ describe('SubagentHeaderLineage', () => { const populated = props(catalog(), { [CHILD]: catalog({ entries: [{ - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'inactive', hasChildren: false, + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'inactive', }], }), }) const view = render() - hoverCatalog(screen.getByRole('button', { name: /2 个子代理/ })) + hoverCatalog(screen.getByRole('button', { name: /1 个子代理,正在运行/ })) fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) const empty = props(catalog({ entries: [] })) view.rerender() expect(screen.queryByRole('button')).toBeNull() - expect(empty.setCatalogOpen).toHaveBeenCalledWith(PARENT, false) - expect(empty.setCatalogOpen).toHaveBeenCalledWith(CHILD, false) }) - it('places a separator before a visible ordinary-session descendant count', () => { + it('places a separator before a visible ordinary-session direct-child count', () => { const view = render() expect(screen.getByText('/')).toBeTruthy() - expect(screen.getByRole('button', { name: /2 个子代理/ })).toBeTruthy() + expect(screen.getByRole('button', { name: /1 个子代理,正在运行/ })).toBeTruthy() view.rerender() expect(screen.queryByText('/')).toBeNull() @@ -700,21 +746,37 @@ describe('SubagentHeaderLineage', () => { expect(switcherIcon?.getAttribute('height')).toBe('16') hoverCatalog(switcher) - expect(input.setCatalogOpen).toHaveBeenCalledWith(PARENT, true) + expect(input.refresh).toHaveBeenCalledWith(PARENT) const current = screen.getByRole('treeitem', { name: /worker/ }) expect(current.getAttribute('aria-current')).toBe('true') expect(within(current).getByText('worker').className).toContain('currentLabel') fireEvent.click(screen.getByRole('treeitem', { name: /reviewer/ })) expect(input.openChild).toHaveBeenCalledWith({ - parentSessionId: PARENT, childSessionId: sibling, mode: 'one-shot', + parentSessionId: PARENT, + childSessionId: sibling, mode: 'one-shot', }) }) + it('does not derive a subagent address from Session summary lineage', () => { + const input = { + ...props(undefined, {}, { + [CHILD]: { + ...summary(CHILD, 1), parentId: PARENT, origin: 'subagent' as const, + }, + }), + lineageSessionId: CHILD, + displayTitle: 'worker', + } + render() + + expect(screen.queryByRole('button', { name: '切换子代理:worker' })).toBeNull() + }) + it('falls back to the catalog session id when the selected row has no label', () => { const input = { ...props(catalog({ entries: [{ - kind: 'child', id: CHILD, mode: 'one-shot', - activity: 'inactive', hasChildren: false, + id: CHILD, mode: 'one-shot', + activity: 'inactive', }] }), {}, { [CHILD]: { ...summary(CHILD, 1), parentId: PARENT, origin: 'subagent' as const, @@ -733,8 +795,8 @@ describe('SubagentHeaderLineage', () => { const input = { ...props(catalog(), { [CHILD]: catalog({ entries: [{ - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'inactive', hasChildren: false, + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'inactive', }] }), }, { [CHILD]: { @@ -777,7 +839,7 @@ describe('SubagentHeaderLineage', () => { ...summary(CHILD, 1), parentId: PARENT, origin: 'subagent' as const, displayTitle: '正在扫描项目文件', }, - }), + }, { parentSessionId: PARENT, childSessionId: CHILD, mode: 'continuable' }), lineageSessionId: CHILD, displayTitle: '正在扫描项目文件', ...(openTitle === undefined ? {} : { openTitle }), @@ -791,8 +853,8 @@ describe('SubagentHeaderLineage', () => { const input = { ...props(catalog(), { [CHILD]: catalog({ entries: [{ - kind: 'child', id: GRANDCHILD, mode: 'continuable', - label: 'indexer', activity: 'inactive', hasChildren: false, + id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'inactive', }] }), }, { [CHILD]: { @@ -810,7 +872,7 @@ describe('SubagentHeaderLineage', () => { hoverCatalog(screen.getByRole('button', { name: '切换子代理:indexer' })) - expect(input.setCatalogOpen).toHaveBeenCalledWith(CHILD, true) + expect(input.refresh).toHaveBeenCalledWith(CHILD) const current = screen.getByRole('treeitem', { name: /indexer/ }) expect(current.getAttribute('aria-current')).toBe('true') expect(within(current).getByText('indexer').className).toContain('currentLabel') diff --git a/packages/client/ui-subagent/tests/subagent-lineage.client.spec.ts b/packages/client/ui-subagent/tests/subagent-lineage.client.spec.ts deleted file mode 100644 index 17b3a8acdf..0000000000 --- a/packages/client/ui-subagent/tests/subagent-lineage.client.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { SessionId } from '@deepseek-ai/dsh-session/types' -import { indexSubagentDescendants } from '../src/client/subagent-lineage.ts' - -const sid = (id: string): SessionId => id as SessionId - -describe('UI Subagent descendant projection', () => { - it('counts nested running descendants and stops at ordinary forks', () => { - const owner = { id: sid('owner'), running: false } - const child = { id: sid('child'), parentId: owner.id, origin: 'subagent' as const, running: false } - const grandchild = { id: sid('grandchild'), parentId: child.id, origin: 'subagent' as const, running: true } - const fork = { id: sid('fork'), parentId: child.id, running: false } - const forkChild = { id: sid('fork-child'), parentId: fork.id, origin: 'subagent' as const, running: true } - const result = indexSubagentDescendants(Object.fromEntries( - [owner, child, grandchild, fork, forkChild].map(item => [item.id, item]), - )) - expect(result.get(owner.id)).toEqual({ count: 2, runningCount: 1 }) - expect(result.get(child.id)).toEqual({ count: 1, runningCount: 1 }) - expect(result.get(fork.id)).toEqual({ count: 1, runningCount: 1 }) - }) - - it('terminates cycles and retains missing-parent aggregates', () => { - const cycleA = { id: sid('a'), parentId: sid('b'), origin: 'subagent' as const, running: false } - const cycleB = { id: sid('b'), parentId: sid('a'), origin: 'subagent' as const, running: false } - const orphan = { id: sid('orphan'), parentId: sid('missing'), origin: 'subagent' as const, running: true } - const result = indexSubagentDescendants({ [cycleA.id]: cycleA, [cycleB.id]: cycleB, [orphan.id]: orphan }) - expect(result.get(cycleA.id)?.count).toBe(2) - expect(result.get(cycleB.id)?.count).toBe(2) - expect(result.get(sid('missing'))).toEqual({ count: 1, runningCount: 1 }) - }) -}) diff --git a/packages/client/ui-theme/tests/appearance-row.client.spec.tsx b/packages/client/ui-theme/tests/appearance-row.client.spec.tsx index 5ad602ff05..f06485dca2 100644 --- a/packages/client/ui-theme/tests/appearance-row.client.spec.tsx +++ b/packages/client/ui-theme/tests/appearance-row.client.spec.tsx @@ -26,7 +26,7 @@ const COPY: Record = { function emptySessions() { const store = createSnapshotStore( - { ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined }) + { ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined }) return bindSnapshotSelector(store) } function emptyWorkspaces() { diff --git a/packages/client/ui-theme/tests/font-size-row.client.spec.tsx b/packages/client/ui-theme/tests/font-size-row.client.spec.tsx index c917901cab..ed433c85e7 100644 --- a/packages/client/ui-theme/tests/font-size-row.client.spec.tsx +++ b/packages/client/ui-theme/tests/font-size-row.client.spec.tsx @@ -28,7 +28,7 @@ const COPY: Record = { /** Empty global standard-kit hooks (the row reads neither). */ function emptySessions() { const store = createSnapshotStore( - { ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined }) + { ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined }) return bindSnapshotSelector(store) } function emptyWorkspaces() { diff --git a/packages/client/ui-tool/tests/coverage-tails.client.spec.tsx b/packages/client/ui-tool/tests/coverage-tails.client.spec.tsx index 04e464d968..b4a55c1789 100644 --- a/packages/client/ui-tool/tests/coverage-tails.client.spec.tsx +++ b/packages/client/ui-tool/tests/coverage-tails.client.spec.tsx @@ -29,7 +29,7 @@ function listStore() { }, current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) } diff --git a/packages/client/ui-tool/tests/diff-card.client.spec.tsx b/packages/client/ui-tool/tests/diff-card.client.spec.tsx index 1e8b2fdef6..83766a110c 100644 --- a/packages/client/ui-tool/tests/diff-card.client.spec.tsx +++ b/packages/client/ui-tool/tests/diff-card.client.spec.tsx @@ -203,7 +203,7 @@ describe('FileMutationRow diff card', () => { byId: { [SID]: { id: SID, displayTitle: 'r', running: false, blank: false, updatedAt: 0, cwd: '/w/app' } }, current: SID, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) diff --git a/packages/client/ui-tool/tests/image-card.client.spec.tsx b/packages/client/ui-tool/tests/image-card.client.spec.tsx index 53578e25d9..74b2a9a127 100644 --- a/packages/client/ui-tool/tests/image-card.client.spec.tsx +++ b/packages/client/ui-tool/tests/image-card.client.spec.tsx @@ -269,7 +269,7 @@ describe('ReadImageRow keyed toolview', () => { byId: { [SID]: { id: SID, displayTitle: 'r', running: false, blank: false, updatedAt: 0, cwd: '/w/app' } }, current: SID, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } as unknown as SessionListState) diff --git a/packages/client/ui-tool/tests/read-card.client.spec.tsx b/packages/client/ui-tool/tests/read-card.client.spec.tsx index 21ace19335..0357632371 100644 --- a/packages/client/ui-tool/tests/read-card.client.spec.tsx +++ b/packages/client/ui-tool/tests/read-card.client.spec.tsx @@ -207,7 +207,7 @@ describe('ReadRow keyed toolview', () => { byId: { [SID]: { id: SID, displayTitle: 'r', running: false, blank: false, updatedAt: 0, cwd: '/w/app' } }, current: SID, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) diff --git a/packages/client/ui-tool/tests/terminal-card.client.spec.tsx b/packages/client/ui-tool/tests/terminal-card.client.spec.tsx index 11a9ebe63e..e537df57ef 100644 --- a/packages/client/ui-tool/tests/terminal-card.client.spec.tsx +++ b/packages/client/ui-tool/tests/terminal-card.client.spec.tsx @@ -408,7 +408,7 @@ describe('BashRow terminal card', () => { byId: { [SID]: { id: SID, displayTitle: 'r', running: false, blank: false, updatedAt: 0 } }, current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }) diff --git a/packages/client/ui-trajectory/tests/views.client.spec.tsx b/packages/client/ui-trajectory/tests/views.client.spec.tsx index 58d786293d..706832b481 100644 --- a/packages/client/ui-trajectory/tests/views.client.spec.tsx +++ b/packages/client/ui-trajectory/tests/views.client.spec.tsx @@ -172,7 +172,7 @@ function standaloneDuration(): Pick< /** Empty sessions-list hook; breadcrumbs therefore fall back to the raw id. */ function emptySessions() { const store = createSnapshotStore( - { ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined }) + { ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined }) return bindSnapshotSelector(store) } diff --git a/packages/client/ui-user-questions/tests/plan-review-panel.client.spec.tsx b/packages/client/ui-user-questions/tests/plan-review-panel.client.spec.tsx index 62146d7130..a884fd3690 100644 --- a/packages/client/ui-user-questions/tests/plan-review-panel.client.spec.tsx +++ b/packages/client/ui-user-questions/tests/plan-review-panel.client.spec.tsx @@ -52,7 +52,7 @@ const sessionList = { byId: { [SID]: { id: SID, displayTitle: 'Session', running: false, blank: false, updatedAt: 0 } }, current: SID, phase: 'ready' as const, - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } diff --git a/packages/client/ui-user-questions/tests/user-questions-composer.client.spec.tsx b/packages/client/ui-user-questions/tests/user-questions-composer.client.spec.tsx index 2570efe7cd..ded24a3014 100644 --- a/packages/client/ui-user-questions/tests/user-questions-composer.client.spec.tsx +++ b/packages/client/ui-user-questions/tests/user-questions-composer.client.spec.tsx @@ -51,7 +51,7 @@ const sessionList = { byId: { [SID]: { id: SID, displayTitle: 'Session', running: false, blank: false, updatedAt: 0 } }, current: SID, phase: 'ready' as const, - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } diff --git a/packages/client/ui-workflow-run/README.i18n.yaml b/packages/client/ui-workflow-run/README.i18n.yaml index b9860d366f..c70550363a 100644 --- a/packages/client/ui-workflow-run/README.i18n.yaml +++ b/packages/client/ui-workflow-run/README.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 packages/client/ui-workflow-run/README.md -README.md: 2f61cbee94414349030c67a45c03057f21fd9afe -README.zh.md: 94d90d057a119e1093ec014bad29f0f4fff82af6 +README.md: 661bd7d4ce4b04edb0188a4d04e01d3a89de216a +README.zh.md: c5929c2d04cb115700fe30aa866b16afb0d02474 diff --git a/packages/client/ui-workflow-run/README.md b/packages/client/ui-workflow-run/README.md index 2f61cbee94..661bd7d4ce 100644 --- a/packages/client/ui-workflow-run/README.md +++ b/packages/client/ui-workflow-run/README.md @@ -29,7 +29,7 @@ A top-level workflow run through `dsh-tool-workflow` appears in the conversation ### Navigating the node -The run uses a 32-pixel row with persistent chevrons, an inline state dot, and status text; phases use disclosure rows with title and member count in the main area and a fixed aggregate-status tail; members use a 16-pixel dot slot, a truncating name area, and a fixed status column. Opening a member's child Session requires the member to be running, the child id to be in the ordinary Session list, the row to have `origin: 'subagent'`, its `parentId` to be the current Session, and the list row to still be running — remote, addressed-only, wrong-parent, or terminal rows remain non-interactive. +The run uses a 32-pixel row with persistent chevrons, an inline state dot, and status text; phases use disclosure rows with title and member count in the main area and a fixed aggregate-status tail; members use a 16-pixel dot slot, a truncating name area, and a fixed status column. Opening a member's child Session requires the member to be running and the current Session's direct-child catalog to report that child as running. Session summaries do not establish membership; absent, wrong-parent, or terminal catalog entries remain non-interactive. ### State and completion diff --git a/packages/client/ui-workflow-run/README.zh.md b/packages/client/ui-workflow-run/README.zh.md index 94d90d057a..c5929c2d04 100644 --- a/packages/client/ui-workflow-run/README.zh.md +++ b/packages/client/ui-workflow-run/README.zh.md @@ -29,7 +29,7 @@ kind: "package-reference" ### 导航节点 -运行使用 32 像素行,带常驻 chevron、行内状态点与状态文字;阶段使用 disclosure 行,在主区显示标题与成员数、在固定尾部显示聚合状态;成员使用 16 像素状态点槽、会截断文本的名称区与固定状态列。打开成员的子会话需要成员仍在运行、子 id 位于普通会话列表、列表行为 `origin: 'subagent'`、`parentId` 等于当前会话,且列表行仍标记运行——远程、仅地址化、父级不符或终态的行都不可交互。 +运行使用 32 像素行,带常驻 chevron、行内状态点与状态文字;阶段使用 disclosure 行,在主区显示标题与成员数、在固定尾部显示聚合状态;成员使用 16 像素状态点槽、可省略名称区与固定状态列。打开成员的子 Session 需要成员仍在运行,且当前 Session 的直接子级目录将该子级标记为运行中。Session 摘要不建立成员关系;目录中缺失、父级不符或终态的条目不可交互。 ### 状态与完成 diff --git a/packages/client/ui-workflow-run/src/client/WorkflowRunPanel.tsx b/packages/client/ui-workflow-run/src/client/WorkflowRunPanel.tsx index 56237975ff..1fd06e661d 100644 --- a/packages/client/ui-workflow-run/src/client/WorkflowRunPanel.tsx +++ b/packages/client/ui-workflow-run/src/client/WorkflowRunPanel.tsx @@ -184,16 +184,13 @@ function navigableMembers( phases: readonly WorkflowRunPhaseData[], parentId: SessionId, ): readonly SessionId[] { - const ordinary = new Set(sessions.ids) + const catalog = sessions.projectionsBySession[parentId] const result: SessionId[] = [] for (const phase of phases) { for (const member of phase.members) { - const summary = sessions.byId[member.childId] + const child = catalog?.values.subagentCatalog?.find(entry => entry.id === member.childId) if (member.status === 'running' - && ordinary.has(member.childId) - && summary?.origin === 'subagent' - && summary.parentId === parentId - && summary.running) { + && child !== undefined && sessions.byId[child.id]?.running === true) { result.push(member.childId) } } diff --git a/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx b/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx index 4ef71e2a10..f09265dcf5 100644 --- a/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx +++ b/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx @@ -304,7 +304,9 @@ const listState = (overrides: Partial = {}): SessionListState }, current: PARENT_ID, phase: 'ready', - subagentsByParent: {}, + projectionsBySession: { [PARENT_ID]: { state: 'ready', error: null, values: { subagentCatalog: [ + { createdAt: 1, id: CHILD_ID, mode: 'one-shot' }, + ] } } }, jobsBySession: {}, currentAddress: undefined, ...overrides, @@ -664,6 +666,10 @@ describe('WorkflowRunPanel', () => { it('defers normal completion collapse until focused member content loses focus', () => { const sessions = listState({ ids: [PARENT_ID, CHILD_ID, SECOND_ID], + projectionsBySession: { [PARENT_ID]: { state: 'ready', error: null, values: { subagentCatalog: [ + { createdAt: 1, id: CHILD_ID, mode: 'one-shot' }, + { createdAt: 1, id: SECOND_ID, mode: 'one-shot' }, + ] } } }, byId: { ...listState().byId, [SECOND_ID]: { @@ -825,40 +831,32 @@ describe('WorkflowRunPanel', () => { expect(screen.getByRole('button', { name: /未分阶段/ }).getAttribute('aria-expanded')).toBe('true') }) - it('opens only a running ordinary-list subagent proven to have this parent', () => { + it('opens a running member confirmed by the direct parent catalog', () => { const data: WorkflowRunChatData = { name: 'audit', status: 'running', phases: [phase()], } const openSession = vi.fn() - render() + const sessions = listState() + render() fireEvent.click(screen.getByRole('button', { name: '打开 worker' })) expect(openSession).toHaveBeenCalledWith('child-1') }) - it('promotes a running member when its ordinary Session row arrives', () => { + it('promotes a running member when its parent catalog arrives', () => { const data: WorkflowRunChatData = { name: 'audit', status: 'running', phases: [phase()], } - const view = render() + const view = render() expect(screen.queryByRole('button', { name: '打开 worker' })).toBeNull() view.rerender() expect(screen.getByRole('button', { name: '打开 worker' })).toBeTruthy() }) it.each([ - ['not in ordinary list', listState({ ids: [PARENT_ID] }), 'running'], - ['remote row', listState({ byId: { - ...listState().byId, - [CHILD_ID]: { ...listState().byId[CHILD_ID]!, origin: undefined }, - } }), 'running'], - ['wrong parent', listState({ byId: { - ...listState().byId, - [CHILD_ID]: { ...listState().byId[CHILD_ID]!, parentId: 'other' as SessionId }, - } }), 'running'], - ['list terminal', listState({ byId: { - ...listState().byId, - [CHILD_ID]: { ...listState().byId[CHILD_ID]!, running: false }, - } }), 'running'], + ['catalog absent', listState({ projectionsBySession: {} }), 'running'], + ['catalog empty', listState({ projectionsBySession: { [PARENT_ID]: { state: 'ready', error: null, values: { subagentCatalog: [] } } } }), 'running'], + ['wrong parent', listState({ projectionsBySession: { ['other' as SessionId]: { state: 'ready', error: null, values: { subagentCatalog: [{ createdAt: 1, id: CHILD_ID, mode: 'one-shot' }] } } } }), 'running'], + ['child inactive', listState({ byId: { ...listState().byId, [CHILD_ID]: { ...listState().byId[CHILD_ID]!, running: false } } }), 'running'], ['member terminal', listState(), 'completed'], ] as const)('does not navigate when %s', (_name, sessions, memberStatus) => { const data: WorkflowRunChatData = { diff --git a/packages/client/ui-workspace/README.i18n.yaml b/packages/client/ui-workspace/README.i18n.yaml index ebd9d1db07..1e488c147b 100644 --- a/packages/client/ui-workspace/README.i18n.yaml +++ b/packages/client/ui-workspace/README.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 packages/client/ui-workspace/README.md -README.md: 1edf9223c72e7094ce305734119975c3954cce59 -README.zh.md: 122f1d97a5a4dd7c5b54b0d9a27e323cdc6fb8ca +README.md: 1b3825c6b01f742a07ff1cc465315af80f045fad +README.zh.md: 9dcc37856a62c0661f6c23d530792a9f2825efe4 diff --git a/packages/client/ui-workspace/README.md b/packages/client/ui-workspace/README.md index 1edf9223c7..1b3825c6b0 100644 --- a/packages/client/ui-workspace/README.md +++ b/packages/client/ui-workspace/README.md @@ -67,7 +67,7 @@ Each registration declares a **directory-flow child hole** (`single` kind: `conv ### View state -Once the Workspace list baseline is ready, browser-persisted expansion and manual Session-order records retain only current Workspace ids plus Ungrouped and the flat-list account. `WorkspaceView.sessionIds` supplies real-Workspace membership, not Session display order. View actions require the current account orders explicitly. Flat-list membership and ordering use Session ids; row rendering adds status indicators once. Entering Manual snapshots every active account from the current display; reconciliation retains saved members that still belong to the account, removes departed members, and appends newly known members by recency. A new membership entry without a Session summary is omitted until that summary arrives, while an already saved slot survives a temporarily missing summary. During Workspace reconnection, Manual records an observed blank Session at the front of its saved flat and known group orders without removing other saved members; full membership reconciliation waits for the Workspace baseline. This reconciliation remains mounted while the sidebar is a rail or search replaces its body. Last updated derives directly from each current list snapshot without reading or writing saved positions; equal timestamps use Session ids as a stable tie-break. The shared sidebar projection hides rows whose durable Session summary has `origin: 'subagent'`, and each visible ordinary row inherits the blue activity indicator while any descendant reached through uninterrupted subagent-origin lineage is running. The same pure derivation reads the Schedule key from list projection values for grouped, flat, and search nodes; the package uses only the type-only `@deepseek-ai/dsh-schedule/client` dependency and does not import the Schedule runtime or `ui-schedule`. +Once the Workspace list baseline is ready, browser-persisted expansion and manual Session-order records retain only current Workspace ids plus Ungrouped and the flat-list account. `WorkspaceView.sessionIds` supplies real-Workspace membership, not Session display order. View actions require the current account orders explicitly. Flat-list membership and ordering use Session ids; row rendering adds status indicators once. Entering Manual snapshots every active account from the current display; reconciliation retains saved members that still belong to the account, removes departed members, and appends newly known members by recency. A new membership entry without a Session summary is omitted until that summary arrives, while an already saved slot survives a temporarily missing summary. During Workspace reconnection, Manual records an observed blank Session at the front of its saved flat and known group orders without removing other saved members; full membership reconciliation waits for the Workspace baseline. This reconciliation remains mounted while the sidebar is a rail or search replaces its body. Last updated derives directly from each current list snapshot without reading or writing saved positions; equal timestamps use Session ids as a stable tie-break. The shared sidebar projection hides rows whose durable Session summary has `origin: 'subagent'`, a visible ordinary row shows the blue subagent activity indicator from running direct children in its loaded parent catalog, never from summary lineage. The same pure derivation reads the Schedule key from list projection values for grouped, flat, and search nodes; the package uses only the type-only `@deepseek-ai/dsh-schedule/client` dependency and does not import the Schedule runtime or `ui-schedule`. ### Hover cards diff --git a/packages/client/ui-workspace/README.zh.md b/packages/client/ui-workspace/README.zh.md index 122f1d97a5..9dcc37856a 100644 --- a/packages/client/ui-workspace/README.zh.md +++ b/packages/client/ui-workspace/README.zh.md @@ -67,7 +67,7 @@ Session 行渲染运行时的实时 `pendingInteraction` 分类:审批显示** ### 视图状态 -Workspace 列表基线就绪后,浏览器持久化的展开状态和手动 Session 顺序记录只保留当前 Workspace id、Ungrouped 和单列表记账。`WorkspaceView.sessionIds` 提供真实 Workspace 的成员关系,而不提供 Session 显示顺序。视图操作要求显式传入当前各记账的顺序。单列表的成员筛选和排序使用 Session id,行渲染只计算一次状态指示。进入手动排序会从当前显示结果一次性记录每个有效记账;对账会保留仍属于该记账的已保存成员、移除已经离开的成员,并按最近更新时间追加新发现的成员。尚无 Session 摘要的新成员会等摘要到达后再加入,而已经保存的位置在摘要暂时缺失时仍会保留。Workspace 重连期间,手动排序会将已观察到的空白 Session 记录到已保存的单列表及已知分组顺序首位,不移除其他已保存成员;完整成员对账等待 Workspace 基线到齐。即使侧边栏收成窄栏或搜索替代列表主体,这项对账也保持挂载。最近更新直接从每份当前列表快照派生,不读取或写入已保存位置;时间相同时按 Session id 稳定排序。共享侧边栏投影会隐藏持久化 Session 摘要中带有 `origin: 'subagent'` 的行;每个可见普通行都会在经不间断的 subagent 谱系可达的任一后代运行时继承蓝色活动指示器。同一项纯派生逻辑还会为分组、平铺与搜索节点读取列表 projection value 中的 Schedule key;本包只使用纯类型依赖 `@deepseek-ai/dsh-schedule/client`,不会导入 Schedule 运行时或 `ui-schedule`。 +Workspace 列表基线就绪后,浏览器持久化的展开状态和手动 Session 顺序记录只保留当前 Workspace id、Ungrouped 和单列表记账。`WorkspaceView.sessionIds` 提供真实 Workspace 的成员关系,而不提供 Session 显示顺序。视图操作要求显式传入当前各记账的顺序。单列表的成员筛选和排序使用 Session id,行渲染只计算一次状态指示。进入手动排序会从当前显示结果一次性记录每个有效记账;对账会保留仍属于该记账的已保存成员、移除已经离开的成员,并按最近更新时间追加新发现的成员。尚无 Session 摘要的新成员会等摘要到达后再加入,而已经保存的位置在摘要暂时缺失时仍会保留。Workspace 重连期间,手动排序会将已观察到的空白 Session 记录到已保存的单列表及已知分组顺序首位,不移除其他已保存成员;完整成员对账等待 Workspace 基线到齐。即使侧边栏收成窄栏或搜索替代列表主体,这项对账也保持挂载。最近更新直接从每份当前列表快照派生,不读取或写入已保存位置;时间相同时按 Session id 稳定排序。共享侧边栏投影会隐藏持久化 Session 摘要中带有 `origin: 'subagent'` 的行;可见普通行的蓝色 subagent 活动指示器来自其已加载 parent 目录中正在运行的直接 child,绝不来自摘要谱系。同一项纯派生逻辑还会为分组、平铺与搜索节点读取列表 projection value 中的 Schedule key;本包只使用纯类型依赖 `@deepseek-ai/dsh-schedule/client`,不会导入 Schedule 运行时或 `ui-schedule`。 ### 悬浮卡片 diff --git a/packages/client/ui-workspace/src/client/subagent-lineage.ts b/packages/client/ui-workspace/src/client/subagent-lineage.ts deleted file mode 100644 index bd145d723a..0000000000 --- a/packages/client/ui-workspace/src/client/subagent-lineage.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** UI Workspace-owned projection of descendant counts from Session summaries. */ - -import type { SessionId } from '@deepseek-ai/dsh-session/types' - -interface LineageEntry { - readonly id: SessionId - readonly parentId?: SessionId - readonly origin?: 'subagent' - readonly running: boolean -} - -/** Descendant counts for one possible parent Session. */ -export interface SubagentDescendantSummary { - readonly count: number - readonly runningCount: number -} - -/* jscpd:ignore-start -- UI Subagent and UI Workspace independently project their own views. */ -/** - * Index uninterrupted subagent descendants under each ancestor. - * @param summaries - Session summaries keyed by id. - * @returns descendant totals keyed by possible parent id. - */ -export function indexSubagentDescendants( - summaries: Readonly>, -): ReadonlyMap { - const indexed = new Map() - for (const descendant of Object.values(summaries)) { - if (descendant.origin !== 'subagent') continue - const seen = new Set() - let current: LineageEntry | undefined = descendant - while (current?.origin === 'subagent' && current.parentId !== undefined && !seen.has(current.id)) { - seen.add(current.id) - const aggregate = indexed.get(current.parentId) - if (aggregate === undefined) { - indexed.set(current.parentId, { count: 1, runningCount: descendant.running ? 1 : 0 }) - } else { - aggregate.count += 1 - if (descendant.running) aggregate.runningCount += 1 - } - current = summaries[current.parentId] - } - } - return indexed -} -/* jscpd:ignore-end */ diff --git a/packages/client/ui-workspace/src/client/tree.ts b/packages/client/ui-workspace/src/client/tree.ts index 8a82361f77..c8ab448623 100644 --- a/packages/client/ui-workspace/src/client/tree.ts +++ b/packages/client/ui-workspace/src/client/tree.ts @@ -13,9 +13,6 @@ import type { import type {} from '@deepseek-ai/dsh-schedule/client' import type { SessionId } from '@deepseek-ai/dsh-session/types' import { workspaceTitleOf } from '@deepseek-ai/dsh-util-workspace-path' -import { - indexSubagentDescendants, type SubagentDescendantSummary, -} from './subagent-lineage.ts' /** Group key for Sessions outside every Workspace. */ export const UNGROUPED_KEY = '' @@ -48,7 +45,7 @@ export interface SessionNode { /** A Session-scoped UI consumer is awaiting this user. */ pendingInteraction?: SessionPendingInteractionStatus running: boolean - /** Running descendants connected through uninterrupted subagent-origin lineage. */ + /** Running direct children in the loaded subagent catalog. */ runningSubagentCount: number /** Finished running while not selected and not yet opened (the green "done" reminder dot). */ completed: boolean @@ -87,7 +84,7 @@ export interface SearchResultNode { /** A Session-scoped UI consumer is awaiting this user. */ pendingInteraction?: SessionPendingInteractionStatus running: boolean - /** Running descendants connected through uninterrupted subagent-origin lineage. */ + /** Running direct children in the loaded subagent catalog. */ runningSubagentCount: number /** Finished running while not selected and not yet opened (the green "done" reminder dot). */ completed: boolean @@ -308,7 +305,7 @@ function visiblePendingKind(kind: string | undefined): SessionPendingInteraction function sessionNode( s: SessionSummary, - descendants: ReadonlyMap, + list: SessionListState, pendingInteractions: SessionPendingInteractions, ): SessionNode { const pendingInteraction = visiblePendingKind(pendingInteractions.get(s.id)?.kind) @@ -317,7 +314,10 @@ function sessionNode( title: sessionTitle(s), blank: s.blank, running: s.running, - runningSubagentCount: descendants.get(s.id)?.runningCount ?? 0, + runningSubagentCount: list.projectionsBySession[s.id]?.values.subagentCatalog?.reduce( + (count, child) => count + (list.byId[child.id]?.running === true ? 1 : 0), + 0, + ) ?? 0, completed: s.completed === true, hasActiveSchedule: hasActiveSchedule(s), updatedAt: s.updatedAt, @@ -349,7 +349,6 @@ export function deriveGroups( ): GroupNode[] { const archived = new Set(archivedSessionIds) const expandedGroups = new Set(view.expandedGroups) - const descendants = indexSubagentDescendants(list.byId) const currentGroup = list.current === undefined ? undefined : owningGroupKey(workspaces, list.current) @@ -366,7 +365,7 @@ export function deriveGroups( expanded, containsCurrent: g.key === currentGroup, sessions: expanded - ? g.sessions.map(session => sessionNode(session, descendants, pendingInteractions)) + ? g.sessions.map(session => sessionNode(session, list, pendingInteractions)) : [], }) } @@ -402,9 +401,7 @@ export function deriveFlat( sessionIds: readonly SessionId[], pendingInteractions: SessionPendingInteractions, ): SessionNode[] { - const descendants = indexSubagentDescendants(list.byId) - return sessionIds - .map(id => sessionNode(list.byId[id] as SessionSummary, descendants, pendingInteractions)) + return sessionIds.map(id => sessionNode(list.byId[id] as SessionSummary, list, pendingInteractions)) } /** @@ -432,7 +429,6 @@ export function deriveSearchResults( const q = query.trim().toLowerCase() if (q === '') return { items: [], hasMore: false } const archived = new Set(archivedSessionIds) - const descendants = indexSubagentDescendants(list.byId) const workspaceBySession = new Map() for (const workspace of workspaces) { @@ -486,7 +482,10 @@ export function deriveSearchResults( title: sessionTitle(summary), workspace: labelOf(summary), running: summary.running, - runningSubagentCount: descendants.get(summary.id)?.runningCount ?? 0, + runningSubagentCount: list.projectionsBySession[summary.id]?.values.subagentCatalog?.reduce( + (count, child) => count + (list.byId[child.id]?.running === true ? 1 : 0), + 0, + ) ?? 0, ...(pendingInteraction === undefined ? {} : { pendingInteraction }), diff --git a/packages/client/ui-workspace/tests/apply.client.spec.ts b/packages/client/ui-workspace/tests/apply.client.spec.ts index 101dd0d266..fdda2c6921 100644 --- a/packages/client/ui-workspace/tests/apply.client.spec.ts +++ b/packages/client/ui-workspace/tests/apply.client.spec.ts @@ -48,7 +48,7 @@ async function bench() { list: { getSnapshot: () => ({ ids: [], byId: {}, current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, }), subscribe, }, diff --git a/packages/client/ui-workspace/tests/subagent-lineage.client.spec.ts b/packages/client/ui-workspace/tests/subagent-lineage.client.spec.ts deleted file mode 100644 index cefcad61c2..0000000000 --- a/packages/client/ui-workspace/tests/subagent-lineage.client.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { SessionId } from '@deepseek-ai/dsh-session/types' -import { indexSubagentDescendants } from '../src/client/subagent-lineage.ts' - -const sid = (id: string): SessionId => id as SessionId - -describe('UI Workspace descendant projection', () => { - it('counts nested running descendants and stops at ordinary forks', () => { - const root = { id: sid('root'), running: false } - const child = { id: sid('child'), parentId: root.id, origin: 'subagent' as const, running: true } - const leaf = { id: sid('leaf'), parentId: child.id, origin: 'subagent' as const, running: false } - const fork = { id: sid('fork'), parentId: child.id, running: false } - const result = indexSubagentDescendants(Object.fromEntries( - [root, child, leaf, fork].map(item => [item.id, item]), - )) - expect(result.get(root.id)).toEqual({ count: 2, runningCount: 1 }) - expect(result.get(child.id)).toEqual({ count: 1, runningCount: 0 }) - expect(result.has(fork.id)).toBe(false) - }) - - it('terminates cycles and retains missing-parent aggregates', () => { - const a = { id: sid('a'), parentId: sid('b'), origin: 'subagent' as const, running: false } - const b = { id: sid('b'), parentId: sid('a'), origin: 'subagent' as const, running: false } - const orphan = { id: sid('orphan'), parentId: sid('missing'), origin: 'subagent' as const, running: true } - const result = indexSubagentDescendants({ [a.id]: a, [b.id]: b, [orphan.id]: orphan }) - expect(result.get(a.id)?.count).toBe(2) - expect(result.get(b.id)?.count).toBe(2) - expect(result.get(sid('missing'))).toEqual({ count: 1, runningCount: 1 }) - }) -}) diff --git a/packages/client/ui-workspace/tests/tree.client.spec.ts b/packages/client/ui-workspace/tests/tree.client.spec.ts index 0443c291ab..9dacde17ae 100644 --- a/packages/client/ui-workspace/tests/tree.client.spec.ts +++ b/packages/client/ui-workspace/tests/tree.client.spec.ts @@ -4,6 +4,7 @@ import type { WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace- import type { SessionPendingInteractionBase } from '@deepseek-ai/dsh-client-ui-session/client' import type { ScheduleId, ScheduleRecord } from '@deepseek-ai/dsh-schedule/client' import type { SessionId } from '@deepseek-ai/dsh-session/types' +import type { SessionProjectionSnapshot } from '@deepseek-ai/dsh-api-session-controller/client' import { deriveFlat, deriveGroups, deriveSearchResults, orderByRecency, owningGroupKey, pinCurrentBlank, reconcileManualOrder, visibleSessionIds, workspaceLabel, UNGROUPED_KEY, @@ -20,7 +21,17 @@ const list = (...items: SessionSummary[]): SessionListState => ({ ids: items.map(item => item.id), byId: Object.fromEntries(items.map(item => [item.id, item])), current: undefined, - phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, +}) +const catalog = ( + ...entries: Array<{ id: string; activity: 'running' | 'inactive' }> +): SessionProjectionSnapshot => ({ + values: { subagentCatalog: entries.map(entry => ({ + id: sid(entry.id), mode: 'continuable', label: entry.id, + createdAt: 1, + })) }, + state: 'ready', + error: null, }) const workspace = (id: string, sessionIds: string[], title = id): WorkspaceView => ({ workspaceId: wid(id), path: `/projects/${id}`, title, @@ -214,7 +225,7 @@ describe('deriveGroups', () => { ).items.map(node => [node.id, node.hasActiveSchedule])).toEqual(expected) }) - it('hides subagent-origin sessions without hiding ordinary forks', () => { + it('hides subagent-origin sessions and reads direct running counts from catalogs', () => { const parent = summary('parent', 1) const subagent = { ...summary('subagent', 3), parentId: parent.id, origin: 'subagent' as const, running: true, @@ -226,7 +237,18 @@ describe('deriveGroups', () => { const forkChild = { ...summary('fork-child', 5), parentId: fork.id, origin: 'subagent' as const, running: true, } - const sessions = { ...list(parent, fork, subagent, grandchild, forkChild), current: subagent.id } + const sessions = { + ...list(parent, fork, subagent, grandchild, forkChild), + current: subagent.id, + projectionsBySession: { + [parent.id]: catalog( + { id: 'subagent', activity: 'running' }, + { id: 'inactive-child', activity: 'inactive' }, + ), + [fork.id]: catalog({ id: 'fork-child', activity: 'running' }), + [subagent.id]: catalog({ id: 'grandchild', activity: 'running' }), + }, + } const groups = deriveGroups( sessions, [workspace('first', ['parent', 'fork', 'subagent', 'grandchild', 'fork-child'])], @@ -237,16 +259,16 @@ describe('deriveGroups', () => { expect(groups[0]!.sessions.map(node => node.id)).toEqual([parent.id, fork.id]) expect(groups[0]!.sessionCount).toBe(2) - expect(groups[0]!.sessions[0]).toMatchObject({ running: false, runningSubagentCount: 2 }) + expect(groups[0]!.sessions[0]).toMatchObject({ running: false, runningSubagentCount: 1 }) expect(groups[0]!.sessions[1]).toMatchObject({ running: false, runningSubagentCount: 1 }) expect(deriveFlat(sessions, visibleSessionIds(sessions, noArchive), noAttention) .map(node => [node.id, node.runningSubagentCount])).toEqual([ - [parent.id, 2], [fork.id, 1], + [parent.id, 1], [fork.id, 1], ]) expect(deriveSearchResults( sessions, [workspace('first', ['parent', 'fork'])], 'parent', noArchive, noAttention, { items: [], hasMore: false }, 10, - ).items[0]).toMatchObject({ id: parent.id, runningSubagentCount: 2 }) + ).items[0]).toMatchObject({ id: parent.id, runningSubagentCount: 1 }) }) it('ignores fork lineage and sorts every ungrouped session as a top-level row', () => { diff --git a/packages/client/ui-workspace/tests/workspace-browser.client.spec.tsx b/packages/client/ui-workspace/tests/workspace-browser.client.spec.tsx index ae62df5324..42fd702bd1 100644 --- a/packages/client/ui-workspace/tests/workspace-browser.client.spec.tsx +++ b/packages/client/ui-workspace/tests/workspace-browser.client.spec.tsx @@ -44,7 +44,7 @@ const sessionState = (items: readonly SessionSummary[], overrides: Partial [item.id, item])), current: undefined, phase: 'ready', - subagentsByParent: {}, jobsBySession: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, ...overrides, }) diff --git a/packages/client/ui-workspace/tests/workspace-picker.client.spec.tsx b/packages/client/ui-workspace/tests/workspace-picker.client.spec.tsx index 3783a1d16a..bcf0aac953 100644 --- a/packages/client/ui-workspace/tests/workspace-picker.client.spec.tsx +++ b/packages/client/ui-workspace/tests/workspace-picker.client.spec.tsx @@ -35,7 +35,7 @@ function hook(snapshot: T) { return function select(selector: (state: T) => S): S { return selector(snapshot) } } const sessions: SessionListState = { - ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined, + ids: [], byId: {}, current: undefined, phase: 'ready', projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } const noPendingInteraction: SessionPendingInteractionSnapshot = new Map() const workspaceState = (items: readonly WorkspaceView[]): WorkspaceSnapshot => ({ diff --git a/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts b/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts index 3cd4995413..fabbdf40f2 100644 --- a/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts +++ b/packages/client/ui-workspace/tests/workspaces-service.client.spec.ts @@ -57,7 +57,7 @@ function sessionState( byId: Object.fromEntries(summaries.map(item => [item.id, item])), current, phase, - subagentsByParent: {}, + projectionsBySession: {}, jobsBySession: {}, currentAddress: undefined, } diff --git a/packages/experimental/client-ui-agent-team/src/client/mount.ts b/packages/experimental/client-ui-agent-team/src/client/mount.ts index c23bb88063..aaec4a03ae 100644 --- a/packages/experimental/client-ui-agent-team/src/client/mount.ts +++ b/packages/experimental/client-ui-agent-team/src/client/mount.ts @@ -53,8 +53,11 @@ function registerUi(ctx: ClientContext): void { async openTeammate(sessionId: SessionId, member: TeamRosterMember): Promise { if (member.role !== 'teammate') return const parentSessionId = leadSessionId(sessionId) - await sessions.refreshSubagents(parentSessionId) + await sessions.refreshProjections(parentSessionId) if (sessions.list.getSnapshot().current !== sessionId) return + const catalog = sessions.list.getSnapshot().projectionsBySession[parentSessionId] + const child = catalog?.values.subagentCatalog?.find(entry => entry.id === member.id) + if (child === undefined) return sessions.openSubagent({ parentSessionId, childSessionId: member.id, diff --git a/packages/experimental/client-ui-agent-team/tests/browser-plugin.client.spec.ts b/packages/experimental/client-ui-agent-team/tests/browser-plugin.client.spec.ts index 64a798f998..ea0c5e03ab 100644 --- a/packages/experimental/client-ui-agent-team/tests/browser-plugin.client.spec.ts +++ b/packages/experimental/client-ui-agent-team/tests/browser-plugin.client.spec.ts @@ -25,6 +25,7 @@ async function bench(options: { registrationFailure?: boolean remoteFailure?: 'view' | 'update' refreshGate?: Promise + catalog?: 'missing' | 'empty' } = {}) { const ctx = new Context() const calls: { method: string; args: unknown[] }[] = [] @@ -86,8 +87,23 @@ async function bench(options: { }) const navigation: unknown[] = [] let current = options.addressed === true ? CHILD : SESSION + const projectionsBySession = options.catalog === 'missing' + ? {} + : { + [SESSION]: { state: 'ready' as const, error: null, values: { subagentCatalog: options.catalog === 'empty' ? [] : [{ createdAt: 1, id: CHILD, + mode: 'continuable' as const, + label: 'worker' as const, + }] } }, + } ctx.provide('sessions', { - list: { getSnapshot: () => ({ current }) }, + list: { getSnapshot: () => ({ current, projectionsBySession }) }, + subagentAddress: (id: SessionId) => options.addressed === true && id === CHILD + ? { + parentSessionId: SESSION, + childSessionId: CHILD, + mode: 'continuable' as const, + } + : undefined, binding: (id: SessionId) => options.addressed === true && id === CHILD ? { session: { getSnapshot: () => ({ subagent: { @@ -99,7 +115,7 @@ async function bench(options: { }, }) } } : undefined, - refreshSubagents: (id: SessionId) => { + refreshProjections: (id: SessionId) => { navigation.push(['refresh', id]) return options.refreshGate ?? Promise.resolve() }, @@ -281,6 +297,22 @@ describe('ui-team browser plugin', () => { expect(b.navigation).toEqual([['refresh', SESSION]]) }) + it('does not open a teammate missing from the parent catalog', async () => { + for (const catalog of ['missing', 'empty'] as const) { + const b = await bench({ catalog }) + const actions = (b.entry()!.inject as unknown as () => TeamActionInjected)() + await actions.openTeammate(SESSION, { + id: CHILD, + name: 'worker', + role: 'teammate', + status: 'inactive', + diagnostics: [], + }) + expect(b.navigation).toEqual([['refresh', SESSION]]) + await b.fiber.dispose() + } + }) + it('re-registers after the conversation header slot is collapsed and declared again', async () => { const b = await bench() expect(b.entry()).toBeDefined() diff --git a/packages/experimental/tool-agent-team/tests/tool-team.spec.ts b/packages/experimental/tool-agent-team/tests/tool-team.spec.ts index bd09be0221..f940958ae2 100644 --- a/packages/experimental/tool-agent-team/tests/tool-team.spec.ts +++ b/packages/experimental/tool-agent-team/tests/tool-team.spec.ts @@ -594,18 +594,27 @@ describe('dsh-tool-team', () => { }) it('reinstalls Team scope before a cold-resumed teammate request', async () => { - const { ctx, lead, adapter } = await setup([textResponse('first'), 'hang', 'hang']) + const { ctx, lead, adapter } = await setup([textResponse('first'), textResponse('lead received settlement'), 'hang']) const spawned = await execute(ctx, lead, 'spawn_teammate', { name: 'cold-worker', description: 'cold worker', prompt: 'finish once', }) const childId = spawnedChildId(spawned) await vi.waitFor(() => { expect(ctx.agents.get(childId)).toBeUndefined() }, { timeout: 5_000 }) + expect(await ctx.subagents.listChildren(lead.id)).toContainEqual(expect.objectContaining({ + id: childId, + mode: 'continuable', + })) + await vi.waitFor(() => { + expect(adapter.requests.filter(request => request.sessionId === lead.id)).toHaveLength(1) + }) + await lead.whenIdle() - await ctx.agentTeams.sendMessage(lead, { + const receipt = await ctx.agentTeams.sendMessage(lead, { target: 'cold-worker', content: [{ type: 'text', text: 'resume with Team scope' }], signal: SIGNAL, }) + expect(receipt.status).toBe('accepted') const resumed = await waitRunning(ctx, childId) expect((await assembly(ctx, resumed)).tools.map(schema => schema.name) .filter(name => TOOL_NAMES.includes(name)).sort()).toEqual(TOOL_NAMES) diff --git a/packages/extensions/cordis-client-runner/src/client/api-catalog.ts b/packages/extensions/cordis-client-runner/src/client/api-catalog.ts index 17151804db..db7d5233f4 100644 --- a/packages/extensions/cordis-client-runner/src/client/api-catalog.ts +++ b/packages/extensions/cordis-client-runner/src/client/api-catalog.ts @@ -193,14 +193,9 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ parameters: [{ name: 'address', description: 'catalog-derived parent and child ids.' }], }, { - signature: 'setSubagentCatalogOpen(parentSessionId: SessionId, open: boolean): void', - description: 'Mark whether a catalog menu is consuming live membership updates.', - parameters: [{ name: 'parentSessionId', description: 'catalog owner.' }, { name: 'open', description: 'current menu state.' }], - }, - { - signature: 'refreshSubagents(parentSessionId: SessionId): Promise', - description: 'Refresh one direct-child catalog.', - parameters: [{ name: 'parentSessionId', description: 'catalog owner.' }], + signature: 'refreshProjections(sessionId: SessionId): Promise', + description: 'Load all Session projections once per connection; retry an unsuccessful initial read.', + parameters: [{ name: 'sessionId', description: 'Session to inspect without opening its conversation.' }], returns: 'completion of the current or newly started refresh.', }, { diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts index 8611059309..25f01e187e 100644 --- a/packages/extensions/tool-cordis/src/api-catalog.ts +++ b/packages/extensions/tool-cordis/src/api-catalog.ts @@ -1696,6 +1696,12 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ parameters: [{ name: 'request', description: 'durable address and last committed sequence already held by the caller.' }, { name: 'signal', description: 'cancellation owned by the Remote stream carrier.' }], returns: 'a complete opening snapshot followed by gap-free durable event frames and optional cursorless assistant-stream frames.', }, + { + signature: '@Remote(\'projections\') async projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise', + description: 'Read all registered projections without activating an Agent.', + parameters: [{ name: 'request', description: 'Session whose current values are required.' }, { name: 'signal', description: 'cancellation for the Session observation.' }], + returns: 'complete baseline, or null when the Session does not exist.', + }, { signature: '@Remote({ mode: \'stream\' }) control(signal: AbortSignal): AsyncIterable', description: 'Stream a complete live-control baseline followed by replacement frames.', @@ -2495,25 +2501,18 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ throws: ['{SubagentError} `UNAUTHORIZED` when a resident target belongs to a different parent or the supplied parent identity is stale.'], }, { - signature: 'listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise', - description: 'Enumerate the parent\'s direct session-backed subagents without loading or resuming an Agent. The Session query service supplies one live-preferred corpus and shared point observations; the projection cache supplies immutable descriptor hits without opening cold logs. The registered `subagent` projection remains the sole mode/label classifier.\n\nEvery query receives `signal`, and the listing rechecks cancellation around each await. Read rejections that settle after an abort become a stable `SubagentError` with code `CANCELLED`.', - parameters: [{ name: 'parentSessionId', description: 'parent session whose direct children are listed.' }, { name: 'signal', description: 'caller-owned cancellation forwarded to Session queries and observed around every read await.' }], - returns: 'children and per-child diagnostics ordered by `createdAt`, then id.', - throws: ['{@link SubagentError} when the projection registry or the session store is not mounted, or the caller cancels the listing.'], + signature: 'listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise', + description: 'Read the parent\'s durable direct-child catalog without loading or resuming an Agent. The service owns and releases the live-preferred Session observation.', + parameters: [{ name: 'parentSessionId', description: 'parent whose direct children are requested.' }, { name: 'signal', description: 'cancellation forwarded to the Session query.' }], + returns: 'catalog children in parent event order.', + throws: ['{@link SubagentError} when query or catalog projection is unavailable.', 'SessionQueryError when the parent cannot be read or the query is cancelled.'], }, { signature: 'listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise', - description: 'Enumerate the root\'s complete session-backed subagent tree in stable pre-order from one live-preferred corpus, without loading or resuming an Agent. Ordinary sessions and one-shot children remain traversal nodes so continuable descendants below them are discovered; each returned entry adds its durable `parentId` and root-relative `depth`. Identity resolution, diagnostics, optional persistence, and cancellation follow the same projection-backed contract as listChildren.', + description: 'Enumerate the root\'s complete session-backed subagent tree in stable pre-order from one live-preferred corpus, without loading or resuming an Agent. Ordinary sessions and one-shot children remain traversal nodes so continuable descendants below them are discovered; each returned entry adds its durable `parentId` and root-relative `depth`. Identity resolution, diagnostics, optional persistence, and cancellation use the registered child identity projection and complete Session corpus.', parameters: [{ name: 'rootSessionId', description: 'session whose complete descendant tree is listed.' }, { name: 'signal', description: 'caller-owned cancellation forwarded to persistence reads and observed around every read await.' }], returns: 'children and per-candidate diagnostics with tree position, in stable pre-order.', - throws: ['{@link SubagentError} under the same conditions as {@link listChildren}.'], - }, - { - signature: '@Remote(\'list\') async remoteExportList(parentSessionId: SessionId, signal: AbortSignal): Promise', - description: 'Remote face of listChildren for one browser: the durable listing plus live Agent activity and the delivery-time parent availability hint. Parent availability is a hint; prompt performs the authoritative check. Named apart from the provider-name list, which owns the member.', - parameters: [{ name: 'parentSessionId', description: 'parent session whose direct children are listed.' }, { name: 'signal', description: 'carrier cancellation forwarded to Session queries.' }], - returns: 'the catalog view for that parent.', - throws: ['{RemoteError} `gateway/bad-request` for an empty parent id, `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when the deployment has no projection registry, otherwise `gateway/internal`.'], + throws: ['{@link SubagentError} when listing dependencies are unavailable or the caller cancels.'], }, { signature: '@Remote(\'prompt\') async prompt(request: SubagentPromptRequest, signal: AbortSignal): Promise', @@ -3405,9 +3404,9 @@ export const EVENT_API: readonly EventApiEntry[] = [ name: 'api-session/added', mode: 'emit', signature: '\'api-session/added\'(summary: SessionSummary): void', - summary: 'A Session became visible to Session list consumers.', - description: 'A Session became visible to Session list consumers.', - parameters: [{ name: 'summary', description: 'initial list row for the Session.' }], + summary: 'A Session became visible or its Agent was created or disposed.', + description: 'A Session became visible or its Agent was created or disposed. Consumers upsert the summary and replace its current running and availability state.', + parameters: [{ name: 'summary', description: 'current list row for the Session.' }], }, { name: 'api-session/error', @@ -5753,10 +5752,18 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionProjectionMap', declaration: 'export interface SessionProjectionMap {\n}', }, + { + name: 'SessionProjectionsRequest', + declaration: 'export interface SessionProjectionsRequest {\n readonly sessionId: SessionId;\n}', + }, { name: 'SessionProjectionStateMap', declaration: 'export interface SessionProjectionStateMap {\n}', }, + { + name: 'SessionProjectionsValue', + declaration: 'export type SessionProjectionsValue = SessionProjectionBaseline | null;', + }, { name: 'SessionProjectionUpdate', declaration: 'export interface SessionProjectionUpdate {\n readonly sessionId: SessionId;\n readonly key: string;\n readonly value: JsonValue;\n readonly seq: number;\n}', @@ -5867,7 +5874,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SessionSummary', - declaration: 'export interface SessionSummary {\n readonly sessionId: SessionId;\n readonly updatedAt: number;\n readonly running: boolean;\n readonly blank: boolean;\n readonly parentSessionId?: SessionId;\n readonly origin?: \'subagent\';\n readonly cwd?: string;\n readonly projections?: SessionProjectionHints;\n}', + declaration: 'export interface SessionSummary {\n readonly agentAvailable: boolean;\n readonly sessionId: SessionId;\n readonly updatedAt: number;\n readonly running: boolean;\n readonly blank: boolean;\n readonly parentSessionId?: SessionId;\n readonly origin?: \'subagent\';\n readonly cwd?: string;\n readonly projections?: SessionProjectionHints;\n}', }, { name: 'SessionSurface', @@ -6142,8 +6149,12 @@ export const TYPE_API: readonly TypeApiEntry[] = [ declaration: 'export interface SubagentCapabilities {\n readonly agentOptions: boolean;\n readonly outputSchema: boolean;\n readonly depthLimit: boolean;\n readonly toolFilter: boolean;\n readonly persona: boolean;\n}', }, { - name: 'SubagentCatalog', - declaration: 'export interface SubagentCatalog {\n readonly entries: readonly SubagentListEntry[];\n readonly parentAvailable: boolean;\n}', + name: 'SubagentCatalogEntry', + declaration: 'export type SubagentCatalogEntry = {\n readonly id: SessionId;\n readonly createdAt: number;\n} & ({\n readonly mode: \'one-shot\';\n readonly label?: string;\n} | {\n readonly mode: \'continuable\';\n readonly label: string;\n});', + }, + { + name: 'SubagentCatalogRow', + declaration: 'export type SubagentCatalogRow = {\n readonly id: SessionId;\n readonly activity: \'running\' | \'inactive\';\n} & ({\n readonly mode: \'one-shot\';\n readonly label?: string;\n} | {\n readonly mode: \'continuable\';\n readonly label: string;\n});', }, { name: 'SubagentDescendantListEntry', @@ -6163,7 +6174,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SubagentListEntry', - declaration: 'export type SubagentListEntry = {\n readonly kind: \'child\';\n readonly id: SessionId;\n readonly activity: \'running\' | \'inactive\';\n readonly hasChildren: boolean;\n} & ({\n readonly mode: \'one-shot\';\n readonly label?: string;\n} | {\n readonly mode: \'continuable\';\n readonly label: string;\n}) | {\n readonly kind: \'diagnostic\';\n readonly id: SessionId;\n readonly reason: \'corrupt\' | \'unsupported\' | \'unavailable\';\n};', + declaration: 'export type SubagentListEntry = SubagentCatalogRow & {\n readonly kind: \'child\';\n readonly hasChildren: boolean;\n} | {\n readonly kind: \'diagnostic\';\n readonly id: SessionId;\n readonly reason: \'corrupt\' | \'unsupported\' | \'unavailable\';\n};', }, { name: 'SubagentPromptReceipt', @@ -6203,7 +6214,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SubagentRuntime', - declaration: 'export class SubagentRuntime extends TypertRemoteService {\n constructor(ctx: Context);\n async startContinuable(spec: ContinuableStartSpec): Promise;\n async sendMessage(sender: Agent, targetId: SessionId, content: ContentBlock[], options: SubagentSendMessageOptions): Promise;\n interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void;\n async drainContinuableDescendants(parents: readonly Agent[]): Promise;\n async drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise;\n listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise;\n listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise;\n @Remote(\'list\')\n async remoteExportList(parentSessionId: SessionId, signal: AbortSignal): Promise;\n @Remote(\'prompt\')\n async prompt(request: SubagentPromptRequest, signal: AbortSignal): Promise;\n @Remote(\'interruptByParent\')\n interruptByParent(childSessionId: SessionId, parentSessionId: SessionId, mode: \'continuable\'): SubagentInterruptReceipt;\n registerProvider(provider: SubagentProvider): () => void;\n getProvider(name: string): SubagentProvider | undefined;\n list(): string[];\n async start(name: string, request: SubagentStartRequest): Promise;\n}', + declaration: 'export class SubagentRuntime extends TypertRemoteService {\n constructor(ctx: Context);\n async startContinuable(spec: ContinuableStartSpec): Promise;\n async sendMessage(sender: Agent, targetId: SessionId, content: ContentBlock[], options: SubagentSendMessageOptions): Promise;\n interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void;\n async drainContinuableDescendants(parents: readonly Agent[]): Promise;\n async drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise;\n listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise;\n listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise;\n @Remote(\'prompt\')\n async prompt(request: SubagentPromptRequest, signal: AbortSignal): Promise;\n @Remote(\'interruptByParent\')\n interruptByParent(childSessionId: SessionId, parentSessionId: SessionId, mode: \'continuable\'): SubagentInterruptReceipt;\n registerProvider(provider: SubagentProvider): () => void;\n getProvider(name: string): SubagentProvider | undefined;\n list(): string[];\n async start(name: string, request: SubagentStartRequest): Promise;\n}', }, { name: 'SubagentSendMessageOptions', diff --git a/packages/subagent/subagent/README.i18n.yaml b/packages/subagent/subagent/README.i18n.yaml index a642a59bcf..f4c075364c 100644 --- a/packages/subagent/subagent/README.i18n.yaml +++ b/packages/subagent/subagent/README.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 packages/subagent/subagent/README.md -README.md: 74cca45462f17e1de74e2fa0132c4e7dccad414b -README.zh.md: 39e598c3e88d2f82811c85357c3b82d98eec7327 +README.md: b61f19c2c5b4b8193fa0364e786d0f88a0fff30c +README.zh.md: 247c123e73e536f26e22d5162ec84955ea3b94a0 diff --git a/packages/subagent/subagent/README.md b/packages/subagent/subagent/README.md index 74cca45462..b61f19c2c5 100644 --- a/packages/subagent/subagent/README.md +++ b/packages/subagent/subagent/README.md @@ -48,7 +48,7 @@ One-shot children run once and settle with a single result, plus an optional str ### Messaging, interrupting, and discovering -Every exact live Agent can use `sendMessage()` with a direct continuable child; a resident continuable child can also use it with its direct parent. A working target receives the Agent message through Steer at its nearest step; an idle target starts a turn, and only a direct child can be cold-resumed. The parent can also interrupt a running descendant or list its children at any time. A browser continuation prompt independently selects Queue or Steer and may carry image parts: the Host admits and persists each image batch through the attachment store before the child inbox accepts the message, and refuses delivery when the child's declared model does not accept image input. Discovery covers both shapes: the service lists direct children and the full descendant tree — mode, activity, and lineage — reading live session state and optional persistence, without loading any child. +Every exact live Agent can use `sendMessage()` with a direct continuable child; a resident continuable child can also use it with its direct parent. A working target receives the Agent message through Steer at its nearest step; an idle target starts a turn, and only a direct child can be cold-resumed. The parent can also interrupt a running descendant or list its children at any time. A browser continuation prompt independently selects Queue or Steer and may carry image parts: the Host admits and persists each image batch through the attachment store before the child inbox accepts the message, and refuses delivery when the child's declared model does not accept image input. Direct-child discovery reads the parent-owned `subagentCatalog` projection. `listChildren(parentSessionId, signal?)` owns a live-preferred Session observation and returns the catalog asynchronously without reading child logs. It forwards cancellation and releases the observation after materialization. Materialization preserves parent event order in O(D) time for D facts. Complete descendant discovery retains the Session corpus and child identity projection; neither path loads or resumes a child Agent. ### Failure and recovery @@ -83,9 +83,10 @@ This section explains how the service is built and where the observable behavior | [`src/inbox.ts`](src/inbox.ts) | Activation-local Queue and Steer admission plus the synchronous closing cutoff | | [`src/types.ts`](src/types.ts) | Public request, result, and provider contracts | | [`src/descriptor.ts`](src/descriptor.ts) | Versioned `subagent/descriptor` session-event vocabulary | +| [`src/catalog.ts`](src/catalog.ts) | Parent-owned `subagent/catalog` event and chunked host projection | | [`src/child-agent.ts`](src/child-agent.ts) | Child composition, delegated policy, depth helpers | -| [`src/list-children.ts`](src/list-children.ts) | Discovery over the live session store and optional persistence | -| [`src/control.ts`](src/control.ts) | Browser control assembly: catalog activity sampling, browser-zone validation, failure codes | +| [`src/list-children.ts`](src/list-children.ts) | Direct parent-catalog reads and complete descendant-corpus reads | +| [`src/control.ts`](src/control.ts) | Browser control request validation and stable failure codes | | [`src/control-types.ts`](src/control-types.ts) | Client-safe catalog row, control requests, receipts, and failures | ### One-shot flow diff --git a/packages/subagent/subagent/README.zh.md b/packages/subagent/subagent/README.zh.md index 39e598c3e8..247c123e73 100644 --- a/packages/subagent/subagent/README.zh.md +++ b/packages/subagent/subagent/README.zh.md @@ -48,7 +48,7 @@ kind: "package-reference" ### 消息、中断与发现 -每个确切在线 Agent 都可以对直接可继续 child 使用 `sendMessage()`;驻留的可继续 child 还可以对自己的直接 parent 使用它。正在工作的目标通过 Steer 在最近 step 接收 Agent 消息;空闲目标启动轮次,且只有直接 child 可以冷恢复。parent 也可以随时中断正在运行的后代或列举自己的子级。浏览器发出的继续执行提示词会独立选择 Queue 或 Steer,并且可以携带图片部分:Host 先通过附件存储完成整批图片的准入与持久化,子级 inbox 才接受这条消息;当子级声明的模型不接受图片输入时拒绝投递。发现覆盖两种形态:服务列举直接子级与完整后代树——模式、活动状态与谱系——直接读取在线会话状态与可选持久化,不加载任何子 agent。 +每个确切在线 Agent 都可以对直接可继续 child 使用 `sendMessage()`;驻留的可继续 child 还可以对自己的直接 parent 使用它。正在工作的目标通过 Steer 在最近 step 接收 Agent 消息;空闲目标启动轮次,且只有直接 child 可以冷恢复。parent 也可以随时中断正在运行的后代或列举自己的子级。浏览器发出的继续执行 prompt 会独立选择 Queue 或 Steer,并且可以携带图片部分:Host 先通过附件存储完成整批图片的准入与持久化,子级 inbox 才接受这条消息;当子级声明的模型不接受图片输入时拒绝投递。 直接子级发现读取 parent 自有的 `subagentCatalog` projection。`listChildren(parentSessionId, signal?)` 持有一次优先实时来源的 Session 观察,异步返回目录,不读取子级日志。它转发取消信号,并在物化后释放观察。物化以 O(D) 时间保留 D 条事实的父日志事件顺序。完整后代发现保留 Session 语料库与子级身份 projection;两条路径都不加载或恢复子级 Agent。 ### 失败与恢复 @@ -83,9 +83,10 @@ kind: "package-reference" | [`src/inbox.ts`](src/inbox.ts) | Activation 局部的 Queue 和 Steer 准入,以及同步 closing cutoff | | [`src/types.ts`](src/types.ts) | 公开的请求、结果与提供方约定 | | [`src/descriptor.ts`](src/descriptor.ts) | 版本化的 `subagent/descriptor` 会话事件词汇 | +| [`src/catalog.ts`](src/catalog.ts) | parent 自有的 `subagent/catalog` 事件与分块 host projection | | [`src/child-agent.ts`](src/child-agent.ts) | 子级组装、委派策略、深度辅助函数 | -| [`src/list-children.ts`](src/list-children.ts) | 基于在线会话存储与可选持久化的发现 | -| [`src/control.ts`](src/control.ts) | 浏览器控制面组装:目录活性采样、浏览器时区校验、失败分码 | +| [`src/list-children.ts`](src/list-children.ts) | 直接 parent 目录读取与完整后代语料读取 | +| [`src/control.ts`](src/control.ts) | 浏览器控制请求校验与稳定失败分码 | | [`src/control-types.ts`](src/control-types.ts) | client-safe 的目录行、控制面请求、回执与失败 | ### 一次性流程 @@ -96,7 +97,7 @@ kind: "package-reference" 管理器预留 child 身份、解析持久化描述符、创建(或冷恢复)child、把它安装进 Activation 并提交提示词。模型编写的消息通过固定 Steer 调度跨一条 parent/child 边;浏览器人类 prompt 通过内部适配器选择 Queue 或 best-effort Steer,其他 host 协议仍可保留 Queue 以创建独立轮次。Session queue command 仅根据 child 自身的 continuable descriptor 准入在线 subagent-owned Agent。Settlement 会等待 Agent 活动结束、Inbox 为空且没有所拥有子级,再在准入开放时 flush 最终 Session 状态。管理器随后在 child lock 内重新验证 wake generation、Session 序号、Inbox 与所拥有子级;`Agent.runMaintenance()` 的同步 task 入口会占用 idle 阶段,并在同一个 JavaScript turn 内关闭私有 subagent Inbox,然后才释放句柄。直接 child 不存在 Activation 时会从持久化会话冷恢复。当驻留 Activation 结算时,管理器会在 parent 自身的轮次流中告知该 child 的直接 parent。 -本地子级创建成功时,父 Session 追加一条 `subagent/catalog` 事实。一次性创建在提供方返回后记录;可继续创建在初始 inbox 准入后、返回子级 id 前记录。失败会释放子级,不发布补偿性目录事件。一次性目录追加失败时会处理 run 的结果拒绝,并保留目录错误;资源释放失败会单独记录。`subagentCatalog` projection 排除 fork 继承的事实,通过 Session 观察和客户端快照中的 `projections.values.subagentCatalog` 暴露直接子级列表。无效的自身 catalog payload(包括不支持的版本)会使 projection 恢复失败。其不可变存储和检查点校验使用 [`dsh-chunked-list`](../../util/chunked-list/README.zh.md)。其视图对 D 条事实以 O(D) 时间保留父目录事件顺序。[父目录决策](../../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md) 说明排序、持久化成本和替代方案。 +本地子级创建成功时,父 Session 追加一条 `subagent/catalog` 事实。一次性创建在 提供方返回后记录;可继续创建在初始 inbox 准入后、返回子级 id 前记录。失败会释放子级,不发布补偿性目录事件。一次性目录追加失败时会处理 run 的结果拒绝,并保留目录错误;资源释放失败会单独记录。`subagentCatalog` projection 排除 fork 继承的事实,通过 Session 观察和客户端快照中的 `projections.values.subagentCatalog` 暴露直接子级列表。无效的自身 catalog payload(包括不支持的版本)会使 projection 恢复失败。其不可变存储和检查点校验使用 [`dsh-chunked-list`](../../util/chunked-list/README.zh.md)。其视图对 D 条事实以 O(D) 时间保留父目录事件顺序。[父目录决策](../../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md) 说明排序、持久化成本和替代方案。 ### 所有权与不变式 diff --git a/packages/subagent/subagent/src/control-types.ts b/packages/subagent/subagent/src/control-types.ts index 0325da892f..10a8cfc426 100644 --- a/packages/subagent/subagent/src/control-types.ts +++ b/packages/subagent/subagent/src/control-types.ts @@ -1,7 +1,6 @@ /** - * Client-safe subagent catalog and control vocabulary: the durable direct-child - * row both the listing and the browser catalog answer with, plus the - * browser-facing control surface's prompt, receipts, and failures. + * Client-safe complete-descendant rows and browser continuation requests, + * receipts, and failures. * * @module @deepseek-ai/dsh-subagent/control-types */ @@ -20,46 +19,41 @@ import type { SessionId } from '@deepseek-ai/dsh-session/types' */ export type SubagentPromptRequestId = Branded<'session-request-id'> -/** - * One durable direct-child row, ordered by header `createdAt` with ties broken - * on id. Only a candidate whose durable header has `origin: 'subagent'` is - * interpreted. A served `subagent` projection value produces a `child`; a - * settled candidate whose fold served no identity produces a `diagnostic`; a - * running candidate without one is omitted — its descriptor may not be - * appended yet (the creation window). Diagnostics relay the projection fold's - * outcome or a failed read, never a per-child event scan, and never expose - * model-hidden descriptor content. - */ -export type SubagentListEntry = - | { - readonly kind: 'child' +/** Shared child fields for complete-descendant listing. */ +export type SubagentCatalogRow = + & { /** The durable child session id, stable across Activations. */ readonly id: SessionId /** - * Whether the child is live at the moment its reader sampled it: the - * durable listing reads the Session store (`running` means the logical - * record is resident, `inactive` that it exists only in persistence), - * while the browser catalog re-samples the child's Agent driver. Neither - * encodes a durable outcome, and a continuable child may still reject - * delivery as an ownership conflict. + * Whether complete-descendant listing observed a resident Session. This + * does not encode a durable outcome or guarantee continuation delivery. */ readonly activity: 'running' | 'inactive' - /** Whether a direct descendant has durable `origin: 'subagent'`. */ - readonly hasChildren: boolean } & ( | { /** A terminal one-shot child. */ readonly mode: 'one-shot' - /** Optional durable creation label from the child's descriptor. */ + /** Optional durable creation label from the owning catalog or child descriptor. */ readonly label?: string } | { /** A resumable conversation. */ readonly mode: 'continuable' - /** Durable creation label from the child's descriptor. */ + /** Durable creation label from the owning catalog or child descriptor. */ readonly label: string } ) + +/** + * One complete-descendant row. Enumeration may also return diagnostics for + * child identity observations from the complete Session corpus. + */ +export type SubagentListEntry = + | SubagentCatalogRow & { + readonly kind: 'child' + /** Whether complete-corpus enumeration observed a direct child. */ + readonly hasChildren: boolean + } | { readonly kind: 'diagnostic' /** The candidate's session id. */ @@ -77,12 +71,6 @@ export type SubagentListEntry = readonly reason: 'corrupt' | 'unsupported' | 'unavailable' } -/** Complete direct-child catalog plus the delivery-time parent availability hint. */ -export interface SubagentCatalog { - readonly entries: readonly SubagentListEntry[] - readonly parentAvailable: boolean -} - /** Durable parent/child address that selects subagent transport in the client. */ export type SubagentAddress = & { @@ -125,8 +113,8 @@ export interface SubagentInterruptReceipt { } /** - * Failure details the control surface answers with. Catalog reads, prompts, - * and interrupts share this vocabulary with the Client Remote result. + * Failure details the control surface answers with. Prompts and interrupts + * share these failures with the Client Remote result. */ declare module '@deepseek-ai/dsh-typert-protocol' { interface RemoteErrorDetailsMap { @@ -142,7 +130,5 @@ declare module '@deepseek-ai/dsh-typert-protocol' { 'subagent/attachment-invalid': { readonly reason: string } /** The child exists but its inbox cannot admit the message now. */ 'subagent/delivery-unavailable': { readonly childSessionId: SessionId } - /** The deployment mounts no session-projection registry. */ - 'subagent/projections-unavailable': {} } } diff --git a/packages/subagent/subagent/src/control.ts b/packages/subagent/subagent/src/control.ts index 25fe4f475b..9886e9040a 100644 --- a/packages/subagent/subagent/src/control.ts +++ b/packages/subagent/subagent/src/control.ts @@ -1,22 +1,18 @@ /** - * Browser-facing subagent control assembly: the catalog view sampled against - * the live Agent registry, one browser zone's validation, and the stable - * failure codes the Remote surface answers with. + * Browser-facing subagent prompt and interrupt request validation plus the + * stable prompt failure codes returned by the Remote surface. * * @module @deepseek-ai/dsh-subagent */ -import type { Context } from '@deepseek-ai/cordis' import { AttachmentError } from '@deepseek-ai/dsh-attachment' import type { SessionId } from '@deepseek-ai/dsh-session' import { RemoteError } from '@deepseek-ai/dsh-typert-protocol' import { z } from 'zod' -import type { SubagentCatalog, SubagentListEntry } from './control-types.ts' import { SubagentError } from './error.ts' const SESSION_ID_SCHEMA = z.string().min(1) const CONTROL_ID_SCHEMAS = { - 'subagent.list': z.object({ parentSessionId: SESSION_ID_SCHEMA }), 'subagent.prompt': z.object({ parentSessionId: SESSION_ID_SCHEMA, childSessionId: SESSION_ID_SCHEMA, @@ -47,53 +43,6 @@ export function validateControlRequest( } } -/** - * Project one durable listing onto the catalog view, replacing each row's - * store-derived activity with the live Agent driver's status and reporting - * whether the exact parent Agent is live. Without an Agent registry no driver - * runs at all, so every row is inactive and the parent is unavailable. - * @param ctx - Host context that may carry the Agent registry. - * @param parentSessionId - the listed parent. - * @param entries - the durable direct-child listing. - * @returns the catalog view answered to one browser. - */ -export function catalogView( - ctx: Context, - parentSessionId: SessionId, - entries: readonly SubagentListEntry[], -): SubagentCatalog { - const agents = ctx.get('agents') - return { - entries: entries.map((entry): SubagentListEntry => entry.kind === 'child' - ? { ...entry, activity: agents?.get(entry.id)?.status === 'running' ? 'running' : 'inactive' } - : entry), - parentAvailable: agents?.get(parentSessionId) !== undefined, - } -} - -/** - * Refuse one catalog read while preserving cancellation and a missing - * projections registry as distinct failures. - * @param error - the thrown value. - * @param signal - the caller's cancellation. - * @returns Never — the refusal is thrown. - * @throws {RemoteError} always. - */ -export function rejectCatalogRead(error: unknown, signal: AbortSignal): never { - if (isCancellation(error, signal)) { - throw new RemoteError('gateway/cancelled', 'subagent catalog read was cancelled', {}, { cause: error }) - } - if (error instanceof SubagentError && error.code === 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE') { - throw new RemoteError( - 'subagent/projections-unavailable', - 'subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)', - {}, - { cause: error }, - ) - } - throw new RemoteError('gateway/internal', 'subagent catalog read failed', {}, { cause: error }) -} - /** * Refuse one continuation prompt without exposing provider detail: admission * failures the caller can act on keep their own code, everything else is diff --git a/packages/subagent/subagent/src/index.ts b/packages/subagent/subagent/src/index.ts index de908ad0c4..75adf93b75 100644 --- a/packages/subagent/subagent/src/index.ts +++ b/packages/subagent/subagent/src/index.ts @@ -17,9 +17,9 @@ * is resident. Continuable children never become a {@link SubagentRun}: the * continuation manager holds their `AgentHandle` directly and orders every turn * through the child's own inbox, so providers contribute only the detached - * creation spec and see no handle, turn, or teardown. Child and descendant - * discovery read the live session store and optional session persistence - * directly and do not require that continuation runtime. + * creation spec and see no handle, turn, or teardown. Direct-child + * discovery uses the parent catalog; descendant discovery uses the Session + * corpus. Neither read requires the continuation runtime. * * Same-process providers are trusted typed collaborators. Requests, provider * descriptors, results, and lifecycle payloads are borrowed immutable values; @@ -40,10 +40,9 @@ import type { SessionId } from '@deepseek-ai/dsh-session' import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time' import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol' import { - catalogView, rejectCatalogRead, rejectPrompt, validateControlRequest, + rejectPrompt, validateControlRequest, } from './control.ts' import type { - SubagentCatalog, SubagentInterruptReceipt, SubagentPromptReceipt, SubagentPromptRequest, @@ -71,10 +70,11 @@ import type { ActivationObserver, LifecycleEmitter } from './lifecycle.ts' import SubagentContinuationManager from './continuation.ts' import type { SubagentDelivery } from './inbox.ts' import { listChildren as listSubagentChildren, listDescendants as listSubagentDescendants } from './list-children.ts' -import type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts' +import type { SubagentDescendantListEntry } from './list-children.ts' import { snapshotSubagentDescriptor } from './descriptor.ts' import { subagentIdentityProjectionDefinition, subagentTimingProjectionDefinition } from './projection.ts' import { establishCatalogChild, subagentCatalogProjectionDefinition } from './catalog.ts' +import type { SubagentCatalogEntry } from './projection-types.ts' import { deliverSubagentPrompt } from './internal.ts' export type {} from './catalog.ts' @@ -110,6 +110,7 @@ export type { SubagentDescriptorData, SubagentDescriptorInput, } from './descriptor.ts' +export type { SubagentCatalogEntry } from './projection-types.ts' export { SubagentError } from './error.ts' export { settleRun } from './run-settlement.ts' export { assertSubagentMaxDepth, delegationDepthOf } from './depth.ts' @@ -210,9 +211,10 @@ export class SubagentRuntime extends TypertRemoteService { }, 'subagents.continuationBinding()') }) ctx.inject(['sessionProjections'], (projectionCtx) => { - projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition) - projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition) - projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition) + const projections = projectionCtx.sessionProjections + projections.register(subagentCatalogProjectionDefinition) + projections.register(subagentTimingProjectionDefinition) + projections.register(subagentIdentityProjectionDefinition) }) } @@ -330,23 +332,15 @@ export class SubagentRuntime extends TypertRemoteService { } /** - * Enumerate the parent's direct session-backed subagents without loading or - * resuming an Agent. The Session query service supplies one live-preferred - * corpus and shared point observations; the projection cache supplies - * immutable descriptor hits without opening cold logs. The registered - * `subagent` projection remains the sole mode/label classifier. - * - * Every query receives `signal`, and the listing rechecks cancellation - * around each await. Read rejections that settle - * after an abort become a stable `SubagentError` with code `CANCELLED`. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - caller-owned cancellation forwarded to Session queries - * and observed around every read await. - * @returns children and per-child diagnostics ordered by `createdAt`, then id. - * @throws {@link SubagentError} when the projection registry or the session - * store is not mounted, or the caller cancels the listing. + * Read the parent's durable direct-child catalog without loading or resuming an Agent. + * The service owns and releases the live-preferred Session observation. + * @param parentSessionId - parent whose direct children are requested. + * @param signal - cancellation forwarded to the Session query. + * @returns catalog children in parent event order. + * @throws {@link SubagentError} when query or catalog projection is unavailable. + * @throws SessionQueryError when the parent cannot be read or the query is cancelled. */ - listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise { + listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise { return listSubagentChildren(this.ctx, parentSessionId, signal) } @@ -356,42 +350,19 @@ export class SubagentRuntime extends TypertRemoteService { * Agent. Ordinary sessions and one-shot children remain traversal nodes so * continuable descendants below them are discovered; each returned entry * adds its durable `parentId` and root-relative `depth`. Identity resolution, - * diagnostics, optional persistence, and cancellation follow the same - * projection-backed contract as {@link listChildren}. + * diagnostics, optional persistence, and cancellation use the registered + * child identity projection and complete Session corpus. * @param rootSessionId - session whose complete descendant tree is listed. * @param signal - caller-owned cancellation forwarded to persistence reads * and observed around every read await. * @returns children and per-candidate diagnostics with tree position, in * stable pre-order. - * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + * @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels. */ listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise { return listSubagentDescendants(this.ctx, rootSessionId, signal) } - /** - * Remote face of {@link listChildren} for one browser: the durable listing - * plus live Agent activity and the delivery-time parent availability hint. - * Parent availability is a hint; {@link prompt} performs the authoritative - * check. Named apart from the provider-name {@link list}, which owns the - * member. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - carrier cancellation forwarded to Session queries. - * @returns the catalog view for that parent. - * @throws {RemoteError} `gateway/bad-request` for an empty parent id, - * `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when - * the deployment has no projection registry, otherwise `gateway/internal`. - */ - @Remote('list') - async remoteExportList(parentSessionId: SessionId, signal: AbortSignal): Promise { - validateControlRequest('subagent.list', { parentSessionId }) - try { - return catalogView(this.ctx, parentSessionId, await this.listChildren(parentSessionId, signal)) - } catch (error: unknown) { - return rejectCatalogRead(error, signal) - } - } - /** * Deliver one browser-authored message to a continuable child through the * exact live direct parent, retaining the caller-minted request identity and diff --git a/packages/subagent/subagent/src/list-children.ts b/packages/subagent/subagent/src/list-children.ts index 1d2c58ba6d..9de66e771c 100644 --- a/packages/subagent/subagent/src/list-children.ts +++ b/packages/subagent/subagent/src/list-children.ts @@ -1,31 +1,23 @@ /** - * Read-only enumeration of durable subagent children and descendant trees - * through the Session query service. Candidates come from one live-preferred - * corpus; each child's mode/label is the registered `subagent` projection - * unit's value, resolved - * down a three-rung ladder: the registry's watermark cache for a live child, - * an unseeded durable projection-cache row, and one shared Session observation - * otherwise. A seeded header deliberately lacks its exact inherited cut, so - * it takes the body-bearing observation path before classifying an identity. - * The projection fold is the single classification - * authority — this module parses no descriptor - * itself. Absent persistence, enumeration is live-only: a cold child is - * unreachable for resume anyway, so its absence is capability absence, not an - * error. The module owns no catalog state and does not consult Activation, - * Agent-registry, continuation-manager, or provider state. + * Direct-child discovery from a parent-owned `subagent/catalog` projection, + * plus complete descendant-tree enumeration from the Session corpus. A direct + * listing owns one parent observation and reads no child log. Descendant + * enumeration retains the complete corpus and the child identity projection + * because ordinary Sessions and one-shot children remain traversal nodes. * * @module @deepseek-ai/dsh-subagent */ import type { Context } from '@deepseek-ai/cordis' -import { SessionLogOffset } from '@deepseek-ai/dsh-session' -import type { Session, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' +import { type Session, SessionLogOffset } from '@deepseek-ai/dsh-session' +import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session' import type { SessionProjectionRegistry } from '@deepseek-ai/dsh-session-projection' import type { SessionProjectionCache } from '@deepseek-ai/dsh-session-projection-cache' import type { SessionObservation, SessionQueryEngine } from '@deepseek-ai/dsh-session-query' import type { SubagentListEntry } from './control-types.ts' import { SubagentError } from './error.ts' import type { SubagentIdentityProjection } from './projection-types.ts' +import type { SubagentCatalogEntry } from './projection-types.ts' export type { SubagentListEntry } from './control-types.ts' @@ -65,47 +57,49 @@ interface PositionedCandidate { } /** - * Enumerate one parent's origin-classified direct children from the - * live-preferred merge of `ctx.sessions` and optional session persistence, - * serving each identity from the `subagent` projection unit: the registry's - * watermark snapshot for a live child; for a cold one, a durable - * projection-cache read for an unseeded lifecycle, else one bounded-concurrency - * shared Session observation carrying the exact inherited cut. - * @see SubagentRuntime.listChildren for the public cancellation and failure contract. - * @param ctx - context carrying the session store, the projection registry, - * optional persistence, and the optional projection cache. - * @param parentSessionId - parent session whose direct children are listed. - * @param signal - caller-owned cancellation observed around every persistence read. - * @returns children and per-child diagnostics ordered by `createdAt`, then id. - * @throws {@link SubagentError} when the projection registry or the session - * store is not mounted, or the caller cancels the listing. + * Read one parent's durable catalog through a live-preferred Session observation. + * @param ctx - context carrying the Session query service. + * @param parentSessionId - parent whose direct children are requested. + * @param signal - cancellation forwarded to the Session observation. + * @returns direct-child rows in parent catalog event order. + * @throws {@link SubagentError} when query or catalog projection is unavailable. */ export async function listChildren( ctx: Context, parentSessionId: SessionId, signal?: AbortSignal, -): Promise { - const listing = await prepareListing(ctx, signal) - const candidates = [...listing.corpus.values()] - .filter(record => record.header.parentSession === parentSessionId - && record.header.origin === 'subagent') - .sort(compareCorpusRecords) - const rows = await resolveCandidateRows(candidates, listing, signal) - return rows.filter((row): row is SubagentListEntry => row !== undefined) +): Promise { + const query = ctx.get('sessionQuery') + if (query === undefined) { + throw new SubagentError( + 'listing subagents requires the sessionQuery service (load @deepseek-ai/dsh-session-query)', + 'SUBAGENT_CONTROL_QUERY_UNAVAILABLE', + ) + } + using parent = await query.observeSession(parentSessionId, { + ...signal === undefined ? {} : { signal }, + }) + const entries = parent.projections?.values.subagentCatalog + if (entries === undefined) { + throw new SubagentError( + 'listing subagents requires the registered subagentCatalog projection', + 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE', + ) + } + return entries } /** * Enumerate every session-backed subagent below one root in stable pre-order. * Ordinary sessions and one-shot children remain traversal nodes, so a * continuable child below either is still discovered. Classification uses the - * same projection-backed runtime as {@link listChildren}; no Agent is loaded or - * resumed. + * registered child identity projection; no Agent is loaded or resumed. * @see SubagentRuntime.listDescendants for the public cancellation and failure contract. * @param ctx - context carrying the session store, projection registry, and optional persistence/cache. * @param rootSessionId - session whose complete descendant tree is listed. * @param signal - caller-owned cancellation observed around every persistence read. * @returns interpreted subagents with durable direct-parent and root-relative depth. - * @throws {@link SubagentError} under the same conditions as {@link listChildren}. + * @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels. */ export async function listDescendants( ctx: Context, diff --git a/packages/subagent/subagent/tests/control.spec.ts b/packages/subagent/subagent/tests/control.spec.ts index 54f6a8a7f6..4a35847b4d 100644 --- a/packages/subagent/subagent/tests/control.spec.ts +++ b/packages/subagent/subagent/tests/control.spec.ts @@ -1,7 +1,5 @@ -// The browser-facing control surface: catalog assembly against the live Agent -// registry, prompt admission, and the stable failure codes each answers with. -// The durable listing, continuation, and interrupt primitives they wrap have -// their own specs, so each case scripts them. +// The browser-facing prompt and interrupt controls and their stable failure +// codes. Session Controller owns catalog observation and transport. import { describe, expect, it, vi } from 'vitest' import { Context } from '@deepseek-ai/cordis' @@ -10,15 +8,13 @@ import type { MessageId } from '@deepseek-ai/dsh-llm' import { SessionId } from '@deepseek-ai/dsh-session' import SubagentRuntime, { SubagentError, - type SubagentListEntry, type SubagentPromptRequestId, } from '@deepseek-ai/dsh-subagent' import { deliverSubagentPrompt, type HostPromptDeliverer } from '@deepseek-ai/dsh-subagent/internal' const PARENT = SessionId('parent') const CHILD = SessionId('child') -const OTHER = SessionId('other') -const BROKEN = SessionId('broken') +const PARENT_CREATED_AT = 1 const REQUEST_ID = 'req-1' as SubagentPromptRequestId const signal = new AbortController().signal /** Durable-reference base for the fake store; per-test ids and media types override. */ @@ -29,7 +25,14 @@ async function bench(live?: Record) { const ctx = new Context() await ctx.plugin(SubagentRuntime) if (live !== undefined) { - ctx.provide('agents', { get: (id: SessionId) => live[id] } as never) + ctx.provide('agents', { + get: (id: SessionId) => { + const agent = live[id] + return agent === undefined + ? undefined + : { ...agent, session: { header: { createdAt: PARENT_CREATED_AT } } } + }, + } as never) } return { ctx, subagents: ctx.subagents } } @@ -39,10 +42,6 @@ function promptDelivery(subagents: SubagentRuntime) { return vi.spyOn(subagents as unknown as HostPromptDeliverer, deliverSubagentPrompt) } -function childRow(id: SessionId, activity: 'running' | 'inactive'): SubagentListEntry { - return { kind: 'child', id, mode: 'continuable', label: 'worker', activity, hasChildren: false } -} - function promptRequest(clientTimeZone?: string, delivery: 'queue' | 'steer' = 'queue') { return { requestId: REQUEST_ID, @@ -72,81 +71,6 @@ function emptyIdFailure(method: string, field: string) { } } -describe('subagent catalog Remote', () => { - it('rejects an empty parent id before listing', async () => { - const { subagents } = await bench() - const listChildren = vi.spyOn(subagents, 'listChildren') - - await expect(subagents.remoteExportList(SessionId(''), signal)) - .rejects.toMatchObject(emptyIdFailure('subagent.list', 'parentSessionId')) - expect(listChildren).not.toHaveBeenCalled() - }) - - it('samples row activity from the live Agent driver and reports parent availability', async () => { - const { subagents } = await bench({ [PARENT]: { status: 'idle' }, [CHILD]: { status: 'running' } }) - vi.spyOn(subagents, 'listChildren').mockResolvedValue([ - // The durable listing reports store presence; the browser row reports the driver. - childRow(CHILD, 'inactive'), - childRow(OTHER, 'running'), - { kind: 'diagnostic', id: BROKEN, reason: 'corrupt' }, - ]) - - await expect(subagents.remoteExportList(PARENT, signal)).resolves.toEqual({ - entries: [ - childRow(CHILD, 'running'), - childRow(OTHER, 'inactive'), - { kind: 'diagnostic', id: BROKEN, reason: 'corrupt' }, - ], - parentAvailable: true, - }) - }) - - it('reports every row inactive and the parent unavailable without an Agent registry', async () => { - const { subagents } = await bench() - vi.spyOn(subagents, 'listChildren').mockResolvedValue([childRow(CHILD, 'running')]) - - await expect(subagents.remoteExportList(PARENT, signal)).resolves.toEqual({ - entries: [childRow(CHILD, 'inactive')], - parentAvailable: false, - }) - }) - - it('reports an unknown parent as unavailable while the registry serves other sessions', async () => { - const { subagents } = await bench({ [CHILD]: { status: 'running' } }) - vi.spyOn(subagents, 'listChildren').mockResolvedValue([]) - - await expect(subagents.remoteExportList(PARENT, signal)) - .resolves.toEqual({ entries: [], parentAvailable: false }) - }) - - it('separates cancellation, the missing projections capability, and an unexplained read failure', async () => { - const { subagents } = await bench() - const listChildren = vi.spyOn(subagents, 'listChildren') - - const aborted = new AbortController() - aborted.abort() - listChildren.mockRejectedValue(new Error('read stopped')) - await expect(subagents.remoteExportList(PARENT, aborted.signal)) - .rejects.toMatchObject({ code: 'gateway/cancelled' }) - - listChildren.mockRejectedValue(new SubagentError('cancelled', 'CANCELLED')) - await expect(subagents.remoteExportList(PARENT, signal)) - .rejects.toMatchObject({ code: 'gateway/cancelled' }) - - listChildren.mockRejectedValue( - new SubagentError('no registry', 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE'), - ) - await expect(subagents.remoteExportList(PARENT, signal)).rejects.toMatchObject({ - code: 'subagent/projections-unavailable', - message: expect.stringContaining('sessionProjections') as unknown as string, - }) - - listChildren.mockRejectedValue(new Error('disk gone')) - await expect(subagents.remoteExportList(PARENT, signal)) - .rejects.toMatchObject({ code: 'gateway/internal', message: 'subagent catalog read failed' }) - }) -}) - describe('subagent prompt Remote', () => { it('rejects empty parent and child ids before delivery', async () => { const { subagents } = await bench({ [PARENT]: { status: 'idle' } }) @@ -259,7 +183,7 @@ describe('subagent prompt Remote', () => { await expect(subagents.prompt(promptRequest('Asia/Shanghai'), signal)) .resolves.toEqual({ messageId: 'm-1' }) expect(delivery).toHaveBeenCalledWith( - { status: 'idle' }, + expect.objectContaining({ status: 'idle' }), CHILD, [{ type: 'text', text: 'continue' }], { kind: 'user', rpcId: REQUEST_ID, clientTimeZone: 'Asia/Shanghai' }, @@ -360,7 +284,11 @@ describe('subagent interrupt Remote', () => { [CHILD, SessionId('')], ] as const) { const field = childSessionId.length === 0 ? 'childSessionId' : 'parentSessionId' - expect(() => subagents.interruptByParent(childSessionId, parentSessionId, 'continuable')) + expect(() => subagents.interruptByParent( + childSessionId, + parentSessionId, + 'continuable', + )) .toThrow(expect.objectContaining(emptyIdFailure('subagent.interrupt', field))) } expect(interrupt).not.toHaveBeenCalled() @@ -370,8 +298,15 @@ describe('subagent interrupt Remote', () => { const { subagents } = await bench() const interrupt = vi.spyOn(subagents, 'interrupt').mockReturnValue() - expect(subagents.interruptByParent(CHILD, PARENT, 'continuable')).toEqual({ accepted: true }) - expect(interrupt).toHaveBeenCalledWith(CHILD, { kind: 'user', parentSessionId: PARENT }) + expect(subagents.interruptByParent( + CHILD, + PARENT, + 'continuable', + )).toEqual({ accepted: true }) + expect(interrupt).toHaveBeenCalledWith(CHILD, { + kind: 'user', + parentSessionId: PARENT, + }) }) it('answers a foreign address as unauthorized and everything else as internal', async () => { @@ -379,7 +314,11 @@ describe('subagent interrupt Remote', () => { const interrupt = vi.spyOn(subagents, 'interrupt') interrupt.mockImplementation(() => { throw new SubagentError('not yours', 'UNAUTHORIZED') }) - expect(() => subagents.interruptByParent(CHILD, PARENT, 'continuable')).toThrow( + expect(() => subagents.interruptByParent( + CHILD, + PARENT, + 'continuable', + )).toThrow( expect.objectContaining({ code: 'subagent/unauthorized', message: expect.any(String) as unknown as string, @@ -388,7 +327,11 @@ describe('subagent interrupt Remote', () => { ) interrupt.mockImplementation(() => { throw new Error('boom') }) - expect(() => subagents.interruptByParent(CHILD, PARENT, 'continuable')).toThrow( + expect(() => subagents.interruptByParent( + CHILD, + PARENT, + 'continuable', + )).toThrow( expect.objectContaining({ code: 'gateway/internal', message: 'subagent interrupt failed', details: {} }), ) }) diff --git a/packages/subagent/subagent/tests/list-children.spec.ts b/packages/subagent/subagent/tests/list-children.spec.ts index 2794f825bd..84bcd8d6be 100644 --- a/packages/subagent/subagent/tests/list-children.spec.ts +++ b/packages/subagent/subagent/tests/list-children.spec.ts @@ -1,8 +1,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest' -import { mkdtempSync, rmSync } from 'node:fs' +import { mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { z } from 'zod' +import { dirname, join } from 'node:path' import { Context } from '@deepseek-ai/cordis' import { createUserMessage } from '@deepseek-ai/dsh-llm' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -10,10 +9,9 @@ import type { Agent } from '@deepseek-ai/dsh-agent' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' import SessionStore, { SessionLogOffset, SessionSeq, SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session' -import type { SessionObservation } from '@deepseek-ai/dsh-session-query' import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' +import { generationLogPath } from '../../../session/session-persistence-jsonl/src/format.ts' import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection' -import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection' import SessionProjectionCache from '@deepseek-ai/dsh-session-projection-cache' import Storage from '@deepseek-ai/dsh-storage' import { @@ -24,7 +22,6 @@ import { } from '@deepseek-ai/dsh-storage-domain' import SubagentRuntime, { SUBAGENT_DESCRIPTOR_VERSION, - SubagentError, } from '@deepseek-ai/dsh-subagent' import * as SubagentSpawn from '@deepseek-ai/dsh-subagent-spawn-in-process' import * as SubagentFork from '@deepseek-ai/dsh-subagent-fork-in-process' @@ -49,13 +46,16 @@ afterEach(async () => { /** Boot the continuable stack with real JSONL session persistence. */ async function setup( script: Script, - options: { projectionCache?: boolean } = {}, + options: { projectionCache?: boolean; compression?: 'none' | 'zstd' } = {}, ) { const ctx = new Context() await mountAgentLoopTestDependencies(ctx) const root = mkdtempSync(join(tmpdir(), 'dsh-subagent-list-')) roots.push(root) - const persistence = await ctx.plugin(JsonlSessionPersistence, { root }) + const persistence = await ctx.plugin(JsonlSessionPersistence, { + root, + ...options.compression === undefined ? {} : { compression: options.compression }, + }) persistenceDisposers.push(() => persistence.dispose()) await ctx.plugin(AgentLoop, { agents: [] }) if (options.projectionCache === true) { @@ -81,14 +81,7 @@ async function setup( return { id: session.id, session } as Awaited> })() : await loop.create(SessionId('parent'), { provider: 'mock', model: 'mock' }) - return { ctx, parent } -} - -async function setupWithoutProjections(): Promise { - const ctx = new Context() - await ctx.plugin(SessionStore) - await ctx.plugin(SubagentRuntime) - return ctx + return { ctx, parent, root } } const testSignal = new AbortController().signal @@ -142,6 +135,26 @@ async function authorChild( return sessionId } +/** Minimal complete-turn child log with one descriptor payload. */ +function childEvents(descriptor: unknown): SessionEvent[] { + return [ + { type: 'turn/start', seq: SessionSeq(0), time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, + { + type: 'user/message', + seq: SessionSeq(1), + time: 2, + data: createUserMessage({ content: [{ type: 'text', text: 'work' }], source: { kind: 'user' } }), + surfaceOp: 'append', + }, + { type: 'subagent/descriptor', seq: SessionSeq(2), time: 3, data: descriptor }, + { type: 'turn/end', seq: SessionSeq(3), time: 4, data: { turn: 1, reason: { kind: 'completed' } } }, + ] as SessionEvent[] +} + +function descriptorPayload(label: string, version = SUBAGENT_DESCRIPTOR_VERSION) { + return { version, mode: 'continuable' as const, provider: 'spawn', label } +} + /** * Serve one cold session's point read (the open handle) with a transformed * header while the enumeration listing keeps reporting the stored original — @@ -170,962 +183,180 @@ function mutateStoredHeader( } } -/** Minimal complete-turn child log with one descriptor payload. */ -function childEvents(descriptor: unknown): SessionEvent[] { - return [ - { type: 'turn/start', seq: SessionSeq(0), time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, - { - type: 'user/message', - seq: SessionSeq(1), - time: 2, - data: createUserMessage({ content: [{ type: 'text', text: 'work' }], source: { kind: 'user' } }), - surfaceOp: 'append', - }, - { type: 'subagent/descriptor', seq: SessionSeq(2), time: 3, data: descriptor }, - { type: 'turn/end', seq: SessionSeq(3), time: 4, data: { turn: 1, reason: { kind: 'completed' } } }, - ] as SessionEvent[] -} - -function descriptorPayload(label: string, version = SUBAGENT_DESCRIPTOR_VERSION) { - return { version, mode: 'continuable' as const, provider: 'spawn', label } -} - -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - subagentListHostileProbe: { poisoned?: boolean | undefined } - } - interface SessionProjectionMap { - /** Test-only hostile probe proving per-child isolation of foreign unit failures. */ - subagentListHostileProbe: null - } -} - -/** - * A foreign registered unit that rejects one specific child's log at view - * time: `apply` never throws (the eager drive passes every committed event - * through it), while the poisoned state detonates only when a listing read - * folds or serves this child through the registry. - */ -const hostileProjectionDefinition = { - key: 'subagentListHostileProbe', - stateSchema: z.object({ poisoned: z.boolean().optional() }), - init: () => ({}), - apply: (state, event) => - event.type === 'subagent/descriptor' && (event.data as { label?: string }).label === 'poison me' - ? { poisoned: true } - : state, - wire: { - viewSchema: z.null(), - view: (state) => { - if (state.poisoned === true) throw new Error('hostile unit rejects the poisoned log') - return null - }, - }, - stateVersion: 1, -} satisfies ProjectionDefinition<'subagentListHostileProbe', { poisoned?: boolean | undefined }> - describe('SubagentRuntime.listChildren', () => { - it('lists live children without persistence or the continuation runtime', async () => { - const ctx = new Context() - await ctx.plugin(SessionStore) - await ctx.plugin(SessionProjectionRegistry) - await ctx.plugin(TestSessionQuery) - await ctx.plugin(SubagentRuntime) - expect(ctx.get('jobs')).toBeUndefined() - expect(ctx.get('agents')).toBeUndefined() - expect(ctx.get('sessionPersistence')).toBeUndefined() - - const parentId = SessionId('live-only-parent') - ctx.sessions.create(parentId) - const childId = SessionId('live-only-child') - const child = ctx.sessions.create(childId, { - meta: { parentSession: parentId, origin: 'subagent' }, + it('lists historical children through a migrated parent while preserving V3 files', async () => { + const { ctx, root } = await setup([], { compression: 'none' }) + const parent = SessionId('historical-parent') + const child = SessionId('historical-child') + const header = { type: 'session', version: 3, id: parent, createdAt: 1, isSeeded: false, delegationDepth: 0 } + const source = [ + [header, []], + [{ ...header, id: child, createdAt: 2, origin: 'subagent', parentSession: parent, delegationDepth: 1 }, [{ + type: 'subagent/descriptor', seq: 0, time: 2, + data: { version: 3, mode: 'continuable', provider: 'spawn', label: 'historical child' }, + }]], + ] as const + const originals = source.map(([meta, events]) => { + const path = generationLogPath(root, undefined, meta.id, 3, 'none') + const content = [meta, ...events].map(row => JSON.stringify(row)).join('\n') + '\n' + mkdirSync(dirname(path), { recursive: true }) + writeFileSync(path, content) + return { path, content } }) - child.append('turn/start', { - turn: 1, - }) - child.append('subagent/descriptor', descriptorPayload('live-only child')) - await expect(ctx.subagents.listChildren(parentId)).resolves.toEqual([ - { - kind: 'child', id: childId, label: 'live-only child', mode: 'continuable', - activity: 'running', hasChildren: false, - }, - ]) + expect(await ctx.subagents.listChildren(parent)).toEqual([{ + id: child, createdAt: 2, mode: 'continuable', label: 'historical child', + }]) + for (const { path, content } of originals) { + expect(readFileSync(path, 'utf8')).toBe(content) + expect(readdirSync(dirname(path))).toEqual(['session.v3.jsonl']) + } }) - it('fails loud when the projection registry is not mounted, even with no children', async () => { - const ctx = await setupWithoutProjections() - await expect(ctx.subagents.listChildren(SessionId('no-projections-parent'))).rejects.toThrow( - expect.objectContaining({ code: 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE' }) as Error, - ) - }) - - it('fails loud when the session store is not mounted', async () => { - const ctx = new Context() - await ctx.plugin(SessionProjectionRegistry) - await ctx.plugin(SubagentRuntime) - await expect(ctx.subagents.listChildren(SessionId('no-store-parent'))).rejects.toThrow( - expect.objectContaining({ code: 'SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE' }) as Error, - ) - }) - - it('fails loud when the Session query service is not mounted', async () => { - const ctx = new Context() - await ctx.plugin(SessionStore) - await ctx.plugin(SessionProjectionRegistry) - await ctx.plugin(SubagentRuntime) - - await expect(ctx.subagents.listChildren(SessionId('no-query-parent'))).rejects.toThrow( - expect.objectContaining({ code: 'SUBAGENT_CONTROL_QUERY_UNAVAILABLE' }) as Error, - ) - }) - - it('lists a persisted continuable child as inactive with its durable label', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const childId = await startChild(ctx, parent, 'summarize the doc') - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([ - { - kind: 'child', id: childId, label: 'summarize the doc', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }, - ]) - }) - - it('lists one-shot and continuable children under the same parent', async () => { + it('lists provider-established children from the parent catalog without a corpus or child read', async () => { const { ctx, parent } = await setup([textResponse('once'), textResponse('again')]) const oneShot = await ctx.subagents.start('spawn', { prompt: [{ type: 'text', text: 'finish once' }], + agentOptions: { model: 'child-model' }, parent, - signal: new AbortController().signal, + signal: testSignal, }) const oneShotId = oneShot.id await oneShot.result await oneShot.dispose() const continuableId = await startChild(ctx, parent, 'continuable child') + const listSessions = vi.spyOn(ctx.sessionQuery, 'listSessions') + const observeSession = vi.spyOn(ctx.sessionQuery, 'observeSession') - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toHaveLength(2) - expect(entries).toContainEqual({ - kind: 'child', - id: oneShotId, - mode: 'one-shot', - activity: 'inactive', - hasChildren: false, - }) - expect(entries).toContainEqual({ - kind: 'child', - id: continuableId, - label: 'continuable child', - mode: 'continuable', - activity: 'inactive', - hasChildren: false, - }) - }) - - it('accepts a persisted (non-live) parent target after restart', async () => { - const { ctx } = await setup([]) - // A parent that exists only in persistence — the restart shape. - const coldParent = SessionId('00000000-0000-4000-8000-00000000cccc') - await seedStoredSession(ctx.sessionPersistence, { - version: SESSION_FORMAT_VERSION, - id: coldParent, - createdAt: 1, - isSeeded: false, - }, [ - { type: 'turn/start', seq: SessionSeq(0), time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, - { type: 'turn/end', seq: SessionSeq(1), time: 2, data: { turn: 1, reason: { kind: 'completed' } } }, - ] as SessionEvent[]) - const childId = await authorChild(ctx, '00000000-0000-4000-8000-00000000cdcd', { - parentSession: coldParent, - origin: 'subagent', - }, childEvents(descriptorPayload('persisted parent case'))) - const entries = await ctx.subagents.listChildren(coldParent) - expect(entries).toEqual([ - { - kind: 'child', id: childId, label: 'persisted parent case', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }, + const children = await ctx.subagents.listChildren(parent.id) + expect(children.map(({ createdAt: _createdAt, ...child }) => child)).toEqual([ + { id: oneShotId, mode: 'one-shot' }, + { id: continuableId, label: 'continuable child', mode: 'continuable' }, ]) + expect(children.every(child => Number.isFinite(child.createdAt))).toBe(true) + expect(listSessions).not.toHaveBeenCalled() + expect(observeSession).toHaveBeenCalledOnce() }) - it('orders children by createdAt then id without listing ordinary forks', async () => { + it('releases its observation after reading the catalog view', async () => { const { ctx, parent } = await setup([]) - /** Publish one live child with a pinned header ordering key. */ - const liveChild = (parentId: SessionId, id: string, createdAt: number, label: string): SessionId => { - const session = ctx.sessions.create(SessionId(id), { - meta: { parentSession: parentId, origin: 'subagent', createdAt }, - }) - session.append('turn/start', { turn: 1 }) - session.append('subagent/descriptor', descriptorPayload(label)) - return session.header.id - } - // Live creation order is deliberately shuffled against the expected - // result: same-createdAt ties break on id, different createdAt orders - // ascending. - const late = liveChild(parent.id, '00000000-0000-4000-8000-000000000009', 9, 'late child') - const tieB = liveChild(parent.id, '00000000-0000-4000-8000-000000000002', 5, 'tie b') - const tieA = liveChild(parent.id, '00000000-0000-4000-8000-000000000001', 5, 'tie a') - // An ordinary session fork shares parentSession but has no subagent origin. - const fork = ctx.sessions.fork(parent.session, undefined, SessionId('plain-fork')) - await ctx.sessions.flush(fork) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries.map(entry => entry.id)).toEqual([tieA, tieB, late]) - expect(entries.every(entry => entry.kind === 'child')).toBe(true) - }) - - it('omits a live child that has not appended its descriptor yet', async () => { - const { ctx, parent } = await setup([]) - const pending = ctx.sessions.create(SessionId('creation-window-child'), { - meta: { parentSession: parent.id, origin: 'subagent' }, + const childId = SessionId('cold-state-child') + parent.session.append('subagent/catalog', { + version: 0, + childId, + childCreatedAt: 3, + mode: 'one-shot', + label: 'state child', }) - pending.append('turn/start', { turn: 1 }) - // The creation window: the establishing provider has not appended the - // descriptor yet, so the row is omitted rather than diagnosed. - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([]) - }) - - it('contains a live child projection failure as one corrupt diagnostic', async () => { - const { ctx, parent } = await setup([]) - const childId = SessionId('live-projection-failure') - const child = ctx.sessions.create(childId, { - meta: { parentSession: parent.id, origin: 'subagent' }, - }) - child.append('subagent/descriptor', descriptorPayload('broken live child')) - const snapshot = ctx.sessionProjections.snapshot.bind(ctx.sessionProjections) - vi.spyOn(ctx.sessionProjections, 'snapshot').mockImplementation((session, keys) => { - if (session.id === childId) throw new Error('projection failed') - return snapshot(session, keys) - }) - - await expect(ctx.subagents.listChildren(parent.id)).resolves.toContainEqual({ - kind: 'diagnostic', id: childId, reason: 'corrupt', - }) - }) - - it('maps a non-Error cold observation failure to unavailable', async () => { - const { ctx, parent } = await setup([]) - const childId = await authorChild(ctx, '00000000-0000-4000-8000-00000000aa01', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('unreadable child'))) - const observe = ctx.sessionQuery.observeSession.bind(ctx.sessionQuery) - vi.spyOn(ctx.sessionQuery, 'observeSession').mockImplementation((id, options) => { - if (id === childId) { - return Promise.reject('backend unavailable') // oxlint-disable-line typescript/prefer-promise-reject-errors - } - return observe(id, options) - }) - - await expect(ctx.subagents.listChildren(parent.id)).resolves.toContainEqual({ - kind: 'diagnostic', id: childId, reason: 'unavailable', - }) - }) - - it('releases a cold observation when cancellation lands after its read', async () => { - const { ctx, parent } = await setup([]) - const controller = new AbortController() - const childId = await authorChild(ctx, '00000000-0000-4000-8000-00000000aa02', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('cancelled child'))) + using observed = await ctx.sessionQuery.observeSession(parent.id) const dispose = vi.fn() - vi.spyOn(ctx.sessionQuery, 'observeSession').mockImplementation((id) => { - if (id !== childId) throw new Error(`unexpected observation: ${id}`) - controller.abort(new Error('cancelled after observation')) - return Promise.resolve({ - source: 'prepared', - header: { - version: SESSION_FORMAT_VERSION, - id: childId, - createdAt: 1, - parentSession: parent.id, - origin: 'subagent', - }, - events: [], - cursor: -1, - projections: { asOfSeq: -1, values: {} }, - retain: vi.fn(), - [Symbol.dispose]: dispose, - } as unknown as SessionObservation) + vi.spyOn(ctx.sessionQuery, 'observeSession').mockResolvedValue({ + ...observed, + [Symbol.dispose]: dispose, }) - - await expect(ctx.subagents.listChildren(parent.id, controller.signal)) - .rejects.toMatchObject({ code: 'CANCELLED' }) + expect(await ctx.subagents.listChildren(parent.id)).toEqual([{ + id: childId, createdAt: 3, label: 'state child', mode: 'one-shot', + }]) expect(dispose).toHaveBeenCalledOnce() }) - it('lists a one-shot child with its durable creation label', async () => { + it('releases the observation when its catalog projection is unavailable', async () => { const { ctx, parent } = await setup([]) - const labeled = await authorChild(ctx, '00000000-0000-4000-8000-00000000ab02', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents({ - version: SUBAGENT_DESCRIPTOR_VERSION, + using observed = await ctx.sessionQuery.observeSession(parent.id, { projectionMode: 'none' }) + const dispose = vi.fn() + vi.spyOn(ctx.sessionQuery, 'observeSession').mockResolvedValue({ ...observed, [Symbol.dispose]: dispose }) + await expect(ctx.subagents.listChildren(parent.id)).rejects.toMatchObject({ + code: 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE', + }) + expect(dispose).toHaveBeenCalledOnce() + }) + + it('forwards cancellation and preserves query failures', async () => { + const { ctx, parent } = await setup([]) + const controller = new AbortController() + controller.abort(new Error('cancel catalog')) + await expect(ctx.subagents.listChildren(parent.id, controller.signal)).rejects.toMatchObject({ + code: 'SESSION_QUERY_ABORTED', + }) + const failure = new Error('parent read failed') + vi.spyOn(ctx.sessionQuery, 'observeSession').mockRejectedValue(failure) + await expect(ctx.subagents.listChildren(parent.id)).rejects.toBe(failure) + }) + + it('ignores inherited fork facts and accepts facts in the fork own suffix', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(SessionProjectionRegistry) + await ctx.plugin(TestSessionQuery) + await ctx.plugin(SubagentRuntime) + const ancestor = ctx.sessions.create(SessionId('catalog-ancestor')) + ancestor.append('turn/start', { turn: 1 }) + ancestor.append('subagent/catalog', { + version: 0, + childId: SessionId('inherited-child'), + childCreatedAt: 1, mode: 'one-shot', - provider: 'spawn', - label: 'labeled one-shot', - })) - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([ - { - kind: 'child', id: labeled, mode: 'one-shot', label: 'labeled one-shot', - activity: 'inactive', hasChildren: false, - }, - ]) - }) - - it('reports a live child as running while keeping settled siblings complete', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const settled = await startChild(ctx, parent, 'settled child') - // A live child session outside persistence: publish a live session with a - // descriptor and the parent lineage, without starting an Activation. - const liveId = SessionId('live-child') - const live = ctx.sessions.create(liveId, { - meta: { parentSession: parent.id, origin: 'subagent' }, }) - live.append('turn/start', { turn: 1 }) - live.append('subagent/descriptor', descriptorPayload('live child')) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toContainEqual({ - kind: 'child', id: settled, label: 'settled child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - expect(entries).toContainEqual({ - kind: 'child', id: liveId, label: 'live child', mode: 'continuable', - activity: 'running', hasChildren: false, - }) - }) - - it('lists the last descriptor when a log carries more than one', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const healthy = await startChild(ctx, parent, 'healthy sibling') - const events = childEvents(descriptorPayload('twice')) - events.splice(3, 0, { - type: 'subagent/descriptor', - seq: SessionSeq(3), - time: 3, - data: descriptorPayload('twice again'), - } as SessionEvent) - events[4] = { ...events[4]!, seq: SessionSeq(4) } - const doubled = await authorChild(ctx, '00000000-0000-4000-8000-00000000dupe', { - parentSession: parent.id, - origin: 'subagent', - }, events) - // The last-wins projection fold serves the final descriptor's identity; a - // repeated descriptor is not a per-child corruption diagnostic. - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toContainEqual({ - kind: 'child', id: doubled, label: 'twice again', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - expect(entries).toContainEqual({ - kind: 'child', id: healthy, label: 'healthy sibling', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - }) - - it('serves the serializable null sentinel when a later descriptor invalidates the identity', async () => { - const { ctx, parent } = await setup([]) - const liveId = SessionId('invalidated-live-child') - const live = ctx.sessions.create(liveId, { - meta: { parentSession: parent.id, origin: 'subagent' }, - }) - live.append('turn/start', { turn: 1 }) - live.append('subagent/descriptor', descriptorPayload('was valid')) - expect(ctx.sessionProjections.snapshot(live).values.subagent) - .toEqual({ mode: 'continuable', label: 'was valid', seq: SessionSeq(1) }) - // Last-wins: the malformed follow-up resets the identity to the sentinel. - live.append( - 'subagent/descriptor', - { version: SUBAGENT_DESCRIPTOR_VERSION, mode: 'continuable', provider: 7 } as never, - ) - const values = ctx.sessionProjections.snapshot(live).values - expect(values.subagent).toBeNull() - // The sentinel survives a JSON push frame; an undefined field would be - // dropped there and a consumer would keep the stale identity forever. - const wired = JSON.parse(JSON.stringify(values)) as Record - expect('subagent' in wired).toBe(true) - expect(wired['subagent']).toBeNull() - // The listing reads the same null as no value: running → omitted. - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([]) - }) - - it('diagnoses a settled child whose later descriptor invalidated the identity as corrupt', async () => { - const { ctx, parent } = await setup([]) - const events = childEvents(descriptorPayload('was valid')) - events.splice(3, 0, { - type: 'subagent/descriptor', - seq: SessionSeq(3), - time: 3, - data: { version: SUBAGENT_DESCRIPTOR_VERSION, mode: 'continuable', provider: 7 }, - } as unknown as SessionEvent) - events[4] = { ...events[4]!, seq: SessionSeq(4) } - const invalidated = await authorChild(ctx, '00000000-0000-4000-8000-00000000ad01', { - parentSession: parent.id, - origin: 'subagent', - }, events) - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([ - { kind: 'diagnostic', id: invalidated, reason: 'corrupt' }, - ]) - }) - - it('serves a cached own-suffix identity directly without inspection', async () => { - const { ctx, parent } = await setup([], { projectionCache: true }) - const child = await authorChild(ctx, '00000000-0000-4000-8000-00000000ae01', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('disk label'))) - // seq 2 >= seedLength 0: the cached identity provably comes from the - // child's own suffix, so it is final and the log is never re-read — the - // divergent label proves the row, not the log, produced the entry. - ctx.sessionProjectionCache.cachedSnapshot = () => ({ - asOfSeq: SessionSeq(2), - values: { subagent: { mode: 'continuable', label: 'cached own', seq: SessionSeq(2) } }, - }) - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: child, label: 'cached own', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - expect(inspect).not.toHaveBeenCalled() - }) - - it('refuses a cached ancestor identity from the fork seed and lets preparation rule', async () => { - const { ctx, parent } = await setup([], { projectionCache: true }) - // A fork child: the seed replays the ancestor's descriptor (seq 2), and - // the child's own descriptor arrives in its first own turn (seq 5). - const seed = childEvents(descriptorPayload('ancestor label')) - const events = [ - ...seed, - { type: 'turn/start', seq: SessionSeq(4), time: 5, data: { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } } }, - { type: 'subagent/descriptor', seq: SessionSeq(5), time: 6, data: descriptorPayload('own label') }, - { type: 'turn/end', seq: SessionSeq(6), time: 7, data: { turn: 2, reason: { kind: 'completed' } } }, - ] as SessionEvent[] - const forkChild = await authorChild(ctx, '00000000-0000-4000-8000-00000000ae02', { - parentSession: parent.id, - origin: 'subagent', - }, events, seed.length) - // A creation-window checkpoint carried the ANCESTOR identity: its seq 2 - // fails the own-suffix gate (< seedLength 4), so preparation rules. - ctx.sessionProjectionCache.cachedSnapshot = () => ({ - asOfSeq: SessionSeq(2), - values: { subagent: { mode: 'continuable', label: 'ancestor label', seq: SessionSeq(2) } }, - }) - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: forkChild, label: 'own label', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - expect(inspect).toHaveBeenCalledTimes(1) - }) - - it.each([ - ['id', (meta: SessionHeader): SessionHeader => ({ ...meta, id: SessionId('another-lifecycle') })], - ['createdAt', (meta: SessionHeader): SessionHeader => ({ ...meta, createdAt: meta.createdAt + 1 })], - ['cwd', (meta: SessionHeader): SessionHeader => ({ ...meta, cwd: '/elsewhere' })], - ['parentSession', (meta: SessionHeader): SessionHeader => ({ ...meta, parentSession: SessionId('another-parent') })], - ['isSeeded', (meta: SessionHeader): SessionHeader => ({ ...meta, isSeeded: !meta.isSeeded })], - ['delegationDepth', (meta: SessionHeader): SessionHeader => ({ ...meta, delegationDepth: (meta.delegationDepth ?? 0) + 1 })], - ] as const)('diagnoses an inspection returning another lifecycle (%s) as corrupt', async (_field, mutate) => { - const { ctx, parent } = await setup([textResponse('done')]) - const healthy = await startChild(ctx, parent, 'healthy sibling') - const reborn = await authorChild(ctx, '00000000-0000-4000-8000-00000000ae03', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('reborn child'))) - // The id was re-published as a different lifecycle after enumeration. - mutateStoredHeader(ctx, reborn, mutate) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toContainEqual({ kind: 'diagnostic', id: reborn, reason: 'corrupt' }) - expect(entries).toContainEqual({ - kind: 'child', id: healthy, label: 'healthy sibling', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - }) - - it('lets preparation rule when the cache serves the null sentinel', async () => { - const { ctx, parent } = await setup([], { projectionCache: true }) - const healthy = await authorChild(ctx, '00000000-0000-4000-8000-00000000ad02', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('actually valid'))) - // A stale cached sentinel must not out-rank the authoritative re-fold. - ctx.sessionProjectionCache.cachedSnapshot = () => ({ asOfSeq: SessionSeq(0), values: { subagent: null } }) - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: healthy, label: 'actually valid', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - expect(inspect).toHaveBeenCalledTimes(1) - }) - - it('maps a child rejected by persistence validation to corrupt', async () => { - const { ctx, parent } = await setup([]) - // The canonical envelope contains a message without an id; persistence - // adoption rejects it before any projection fold can run. - const invalid = await authorChild(ctx, '00000000-0000-4000-8000-0000000000ee', { - parentSession: parent.id, - origin: 'subagent', - }, [ - { type: 'turn/start', seq: SessionSeq(0), time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, - { - type: 'user/message', - seq: SessionSeq(1), - time: 2, - data: { role: 'user', content: [{ type: 'text', text: 'work' }], source: { kind: 'user' } }, - surfaceOp: 'append', - }, - { type: 'subagent/descriptor', seq: SessionSeq(2), time: 3, data: descriptorPayload('broken message') }, - ] as SessionEvent[]) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([{ kind: 'diagnostic', id: invalid, reason: 'corrupt' }]) - }) - - it('diagnoses a malformed descriptor payload as corrupt', async () => { - const { ctx, parent } = await setup([]) - const malformed = await authorChild(ctx, '00000000-0000-4000-8000-0000000000ff', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents({ version: SUBAGENT_DESCRIPTOR_VERSION, mode: 'continuable', provider: 7 })) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([{ kind: 'diagnostic', id: malformed, reason: 'corrupt' }]) - }) - - it('diagnoses an unknown descriptor version as corrupt', async () => { - const { ctx, parent } = await setup([]) - const future = await authorChild(ctx, '00000000-0000-4000-8000-0000000000aa', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('from the future', SUBAGENT_DESCRIPTOR_VERSION + 1))) - // The projection fold does not distinguish an unrecognized version from - // other invalid descriptors: both serve no identity, and a settled - // no-value candidate is corrupt. - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([{ kind: 'diagnostic', id: future, reason: 'corrupt' }]) - }) - - it('rejects a fork whose only descriptor belongs to its inherited seed', async () => { - const { ctx, parent } = await setup([]) - // A seed-replayed descriptor predates this child's own suffix and cannot - // identify the fork as a resumable child. - const seed = childEvents(descriptorPayload('ancestor label')) - const forkChild = await authorChild(ctx, '00000000-0000-4000-8000-0000000000f0', { - parentSession: parent.id, - origin: 'subagent', - }, seed, seed.length) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([{ kind: 'diagnostic', id: forkChild, reason: 'corrupt' }]) - }) - - it('does not filter by provider availability: children of unmounted providers stay listed', async () => { - const { ctx, parent } = await setup([]) - const foreign = await authorChild(ctx, '00000000-0000-4000-8000-0000000000bb', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents({ - version: SUBAGENT_DESCRIPTOR_VERSION, + ancestor.append('turn/end', { turn: 1, reason: { kind: 'completed' } }) + const fork = ctx.sessions.fork(ancestor, undefined, SessionId('catalog-fork')) + fork.append('subagent/catalog', { + version: 0, + childId: SessionId('own-child'), + childCreatedAt: 2, mode: 'continuable', - provider: 'not-mounted', - label: 'orphan provider', - })) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([ - { - kind: 'child', id: foreign, label: 'orphan provider', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }, - ]) + label: 'own', + }) + + expect(await ctx.subagents.listChildren(fork.id)).toEqual([{ + id: SessionId('own-child'), createdAt: 2, mode: 'continuable', label: 'own', + }]) }) - it('contains a foreign unit failure during a cold fold to that child as corrupt', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - ctx.sessionProjections.register(hostileProjectionDefinition) - const healthy = await startChild(ctx, parent, 'healthy sibling') - const poisoned = await authorChild(ctx, '00000000-0000-4000-8000-00000000d00d', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('poison me'))) - // The subagent unit itself folds this child cleanly; the FOREIGN unit's - // view throws, and that damage stays contained to the one child. - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toContainEqual({ kind: 'diagnostic', id: poisoned, reason: 'corrupt' }) - expect(entries).toContainEqual({ - kind: 'child', id: healthy, label: 'healthy sibling', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - }) - - it('does not evaluate an unrelated wire view when exposing a live child identity', async () => { - const { ctx, parent } = await setup([]) - ctx.sessionProjections.register(hostileProjectionDefinition) - const poisonedId = SessionId('live-poisoned-child') - const poisoned = ctx.sessions.create(poisonedId, { - meta: { parentSession: parent.id, origin: 'subagent' }, - }) - poisoned.append('turn/start', { turn: 1 }) - poisoned.append('subagent/descriptor', descriptorPayload('poison me')) - const healthyId = SessionId('live-healthy-child') - const healthy = ctx.sessions.create(healthyId, { - meta: { parentSession: parent.id, origin: 'subagent' }, - }) - healthy.append('turn/start', { turn: 1 }) - healthy.append('subagent/descriptor', descriptorPayload('live healthy')) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toContainEqual({ - kind: 'child', id: poisonedId, label: 'poison me', mode: 'continuable', - activity: 'running', hasChildren: false, - }) - expect(entries).toContainEqual({ - kind: 'child', id: healthyId, label: 'live healthy', mode: 'continuable', - activity: 'running', hasChildren: false, - }) - }) - - it('fails the whole enumeration when the persisted listing itself fails', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - await startChild(ctx, parent, 'never listed') - ctx.sessionPersistence.list = () => Promise.reject(new Error('backend listing failed')) - // Without any abort in flight, the original backend failure propagates - // as the operation failure — no cancellation mapping, no diagnostic rows. - await expect(ctx.subagents.listChildren(parent.id)).rejects.toThrow('backend listing failed') - }) - - it('maps a failed cold inspection to one unavailable diagnostic and retries it next listing', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const healthy = await startChild(ctx, parent, 'healthy sibling') - const flaky = await authorChild(ctx, '00000000-0000-4000-8000-00000000f1a7', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('flaky storage'))) - const original = ctx.sessionPersistence.open.bind(ctx.sessionPersistence) - ctx.sessionPersistence.open = (sessionId, access, options) => { - if (sessionId === flaky) { - return Promise.reject(new Error('backend read failed')) - } - return original(sessionId, access, options) + it('bounds chunk growth and ignores more than 1,000 unrelated Sessions', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(SessionProjectionRegistry) + await ctx.plugin(TestSessionQuery) + await ctx.plugin(SubagentRuntime) + const parent = ctx.sessions.create(SessionId('chunk-parent')) + for (let index = 0; index < 1_001; index += 1) { + ctx.sessions.create(SessionId(`unrelated-${String(index).padStart(4, '0')}`)) } - // Per-child isolation: the failed child degrades to one diagnostic while - // the healthy sibling stays complete. - const degraded = await ctx.subagents.listChildren(parent.id) - expect(degraded).toContainEqual({ kind: 'diagnostic', id: flaky, reason: 'unavailable' }) - expect(degraded).toContainEqual({ - kind: 'child', id: healthy, label: 'healthy sibling', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - // Nothing is memoized: with the backend healthy again, the next listing - // folds the same child to its identity. - ctx.sessionPersistence.open = original - await expect(ctx.subagents.listChildren(parent.id)).resolves.toContainEqual({ - kind: 'child', id: flaky, label: 'flaky storage', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }) - }) - - it('lists compacted and uncompacted children identically', async () => { - const { ctx, parent } = await setup([]) - const plain = await authorChild(ctx, '00000000-0000-4000-8000-00000000c0de', { - parentSession: parent.id, - createdAt: 1, - origin: 'subagent', - }, childEvents(descriptorPayload('twin child'))) - // The compacted twin: a compaction checkpoint replaces the whole surface, - // while the append-only log retains the model-hidden descriptor event. - const compactedEvents = childEvents(descriptorPayload('twin child')) - compactedEvents.push({ - type: 'user/message', - seq: SessionSeq(4), - time: 5, - data: createUserMessage({ - content: [{ type: 'text', text: 'summary of everything' }], - source: { kind: 'plugin', plugin: 'compact' }, - }), - surfaceOp: { op: 'replace', startSeq: SessionSeq(1), endSeq: SessionSeq(1) }, - sourceEventSeqs: [SessionSeq(1)], - }) - const compacted = await authorChild(ctx, '00000000-0000-4000-8000-00000000c1de', { - parentSession: parent.id, - createdAt: 2, - origin: 'subagent', - }, compactedEvents) - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([ - { - kind: 'child', id: plain, label: 'twin child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }, - { - kind: 'child', id: compacted, label: 'twin child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }, - ]) - }) - - it('reports an origin-classified grandchild without inspecting it', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const childId = await startChild(ctx, parent, 'direct child') - const grandchildId = await authorChild(ctx, '00000000-0000-4000-8000-0000000000cc', { - parentSession: childId, - origin: 'subagent', - }, childEvents(descriptorPayload('grandchild'))) - const inspected: SessionId[] = [] - const original = ctx.sessionPersistence.open.bind(ctx.sessionPersistence) - ctx.sessionPersistence.open = (sessionId, access, options) => { - inspected.push(sessionId) - return original(sessionId, access, options) - } - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toEqual([ - { - kind: 'child', id: childId, label: 'direct child', mode: 'continuable', - activity: 'inactive', hasChildren: true, - }, - ]) - // The grandchild contributes only its header to the hasChildren hint. - expect(inspected).toContain(childId) - expect(inspected).not.toContain(grandchildId) - }) - - it('inspects each cold child exactly once and a live child never', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const coldStarted = await startChild(ctx, parent, 'cold started child') - const coldAuthored = await authorChild(ctx, '00000000-0000-4000-8000-00000000ab01', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('cold authored child'))) - const liveId = SessionId('live-mixed-child') - const live = ctx.sessions.create(liveId, { - meta: { parentSession: parent.id, origin: 'subagent' }, - }) - live.append('turn/start', { turn: 1 }) - live.append('subagent/descriptor', descriptorPayload('live mixed child')) - - const inspected: SessionId[] = [] - const original = ctx.sessionPersistence.open.bind(ctx.sessionPersistence) - ctx.sessionPersistence.open = (sessionId, access, options) => { - inspected.push(sessionId) - return original(sessionId, access, options) - } - const entries = await ctx.subagents.listChildren(parent.id) - expect(entries).toHaveLength(3) - // The cost model: one inspection per cold child, none for a live child, - // whose identity is served from the registry's watermark cache. - expect(inspected.filter(id => id === coldStarted)).toHaveLength(1) - expect(inspected.filter(id => id === coldAuthored)).toHaveLength(1) - expect(inspected).not.toContain(liveId) - }) - - it('serves a cold child from the projection cache without any inspection', async () => { - const { ctx, parent } = await setup([textResponse('done')], { projectionCache: true }) - const childId = await startChild(ctx, parent, 'cached child') - // The child's turn/end and disposal are the cache's mandatory checkpoint - // points; both writes are fail-soft asynchronous, so wait for the row. - const header = (await ctx.sessionPersistence.list()).find(snapshot => snapshot.header.id === childId)?.header - await vi.waitFor(() => { - expect(ctx.sessionProjectionCache.cachedSnapshot(header!, SessionLogOffset(0))?.values.subagent).toBeDefined() - }, { timeout: 5_000 }) - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: childId, label: 'cached child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - expect(inspect).not.toHaveBeenCalled() - }) - - it('falls back to inspection when the cache serves no identity for the child', async () => { - const { ctx, parent } = await setup([], { projectionCache: true }) - const foreign = await authorChild(ctx, '00000000-0000-4000-8000-00000000ac01', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('uncached child'))) - const expected = [{ - kind: 'child', id: foreign, label: 'uncached child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }] - // No stored row at all for a foreign child this process never ran. - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual(expected) - expect(inspect).toHaveBeenCalledTimes(1) - // A stored row whose cut predates the descriptor: the subagent key is - // absent from the served values, and preparation still rules. - ctx.sessionProjectionCache.cachedSnapshot = () => ({ asOfSeq: SessionSeq(0), values: {} }) - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual(expected) - expect(inspect).toHaveBeenCalledTimes(2) - }) - - it('takes the preparation rung directly when no projection cache is mounted', async () => { - const { ctx, parent } = await setup([]) - expect(ctx.get('sessionProjectionCache')).toBeUndefined() - const foreign = await authorChild(ctx, '00000000-0000-4000-8000-00000000ac02', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('uncacheable child'))) - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: foreign, label: 'uncacheable child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - expect(inspect).toHaveBeenCalledTimes(1) - }) - - it('silently falls through to preparation when the cache read throws', async () => { - const { ctx, parent } = await setup([], { projectionCache: true }) - const recovered = await authorChild(ctx, '00000000-0000-4000-8000-00000000ac03', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('recovered child'))) - ctx.sessionProjectionCache.cachedSnapshot = () => { - // A poisoned stored row (any unit's) detonates at view time; the cache - // is derived data, so its failure must not become a verdict. - throw new Error('poisoned cache row') - } - const inspect = vi.spyOn(ctx.sessionPersistence, 'open') - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: recovered, label: 'recovered child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - expect(inspect).toHaveBeenCalledTimes(1) - }) - - it('does not count an ordinary grandchild without subagent origin', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const childId = await startChild(ctx, parent, 'direct child') - await authorChild(ctx, '00000000-0000-4000-8000-0000000000f1', { - parentSession: childId, - }, [ - { type: 'turn/start', seq: SessionSeq(0), time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, - { type: 'turn/end', seq: SessionSeq(1), time: 2, data: { turn: 1, reason: { kind: 'completed' } } }, - ] as SessionEvent[]) - - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: childId, label: 'direct child', mode: 'continuable', - activity: 'inactive', hasChildren: false, - }]) - }) - - it('counts an origin-classified diagnostic grandchild', async () => { - const { ctx, parent } = await setup([textResponse('done')]) - const childId = await startChild(ctx, parent, 'direct child') - const diagnosticId = await authorChild(ctx, '00000000-0000-4000-8000-0000000000f2', { - parentSession: childId, - origin: 'subagent', - }, childEvents({ version: SUBAGENT_DESCRIPTOR_VERSION, mode: 'continuable', provider: 7 })) - - await expect(ctx.subagents.listChildren(childId)).resolves.toEqual([ - { kind: 'diagnostic', id: diagnosticId, reason: 'corrupt' }, - ]) - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([{ - kind: 'child', id: childId, label: 'direct child', mode: 'continuable', - activity: 'inactive', hasChildren: true, - }]) - }) - - it('a pre-aborted signal stops before any persistence read', async () => { - const { ctx, parent } = await setup([]) - const controller = new AbortController() - controller.abort() - ctx.sessionPersistence.list = () => Promise.reject(new Error('must not be called')) - await expect(ctx.subagents.listChildren(parent.id, controller.signal)).rejects.toThrow( - expect.objectContaining({ code: 'CANCELLED' }) as Error, - ) - }) - - it('forwards cancellation to the persisted listing and reports the stable subagent error', async () => { - const { ctx, parent } = await setup([]) - const controller = new AbortController() - const entered = Promise.withResolvers() - ctx.sessionPersistence.list = (options) => { - entered.resolve(undefined) - return new Promise((_resolve, reject) => { - options?.signal?.addEventListener('abort', () => { - reject(new Error('backend listing aborted')) - }, { once: true }) + for (let index = 0; index < 1_025; index += 1) { + parent.append('subagent/catalog', { + version: 0, + childId: SessionId(`child-${String(index).padStart(3, '0')}`), + childCreatedAt: index, + mode: 'one-shot', }) } - const listing = ctx.subagents.listChildren(parent.id, controller.signal) - await entered.promise - controller.abort() - await expect(listing).rejects.toThrow( - expect.objectContaining({ code: 'CANCELLED' }) as Error, - ) - }) - - it('forwards cancellation to a cold inspection and reports the stable subagent error', async () => { - const { ctx, parent } = await setup([]) - await authorChild(ctx, '00000000-0000-4000-8000-00000000ce11', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('cancelled cold read'))) - const controller = new AbortController() - const entered = Promise.withResolvers() - ctx.sessionPersistence.open = (_sessionId, _access, options) => { - entered.resolve(undefined) - return new Promise((_resolve, reject) => { - options?.signal?.addEventListener('abort', () => { - reject(new Error('backend read aborted')) - }, { once: true }) - }) + const listSessions = vi.spyOn(ctx.sessionQuery, 'listSessions') + const state = ctx.sessionProjections.stateOf(parent, 'subagentCatalog') + const chunkLengths: number[] = [] + for (let chunk = state?.head; chunk !== undefined; chunk = chunk.previous) { + chunkLengths.push(chunk.values.length) } - const listing = ctx.subagents.listChildren(parent.id, controller.signal) - await entered.promise - controller.abort() - await expect(listing).rejects.toThrow( - expect.objectContaining({ code: 'CANCELLED' }) as Error, - ) + expect(chunkLengths).toEqual([1, ...Array.from({ length: 16 }, () => 64)]) + const entries = await ctx.subagents.listChildren(parent.id) + expect(listSessions).not.toHaveBeenCalled() + expect(entries).toHaveLength(1_025) + expect(entries.find(entry => entry.id === 'child-064')).toEqual({ + id: SessionId('child-064'), createdAt: 64, mode: 'one-shot', + }) }) - it('an abort observed after a cold inspection resolves cannot become a successful result', async () => { - const { ctx, parent } = await setup([]) - await authorChild(ctx, '00000000-0000-4000-8000-00000000ce12', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('cancelled mid-listing'))) - const controller = new AbortController() - const original = ctx.sessionPersistence.open.bind(ctx.sessionPersistence) - ctx.sessionPersistence.open = async (sessionId, access, options) => { - const result = await original(sessionId, access, options) - controller.abort() - return result - } - // The post-read checkpoint throws the stable subagent error instead of - // interpreting the fully-read log as a successful listing. - await expect(ctx.subagents.listChildren(parent.id, controller.signal)) - .rejects.toThrow(expect.objectContaining({ code: 'CANCELLED' }) as Error) + it('fails loud when the query service is unavailable', async () => { + const withoutProjection = new Context() + await withoutProjection.plugin(SessionStore) + await withoutProjection.plugin(SubagentRuntime) + const parent = withoutProjection.sessions.create(SessionId('parent')) + await expect(withoutProjection.subagents.listChildren(parent.id)).rejects.toMatchObject({ + code: 'SUBAGENT_CONTROL_QUERY_UNAVAILABLE', + }) }) - it('a cold inspection failure during an abort cannot become an unavailable diagnostic', async () => { - const { ctx, parent } = await setup([]) - await authorChild(ctx, '00000000-0000-4000-8000-00000000ce13', { - parentSession: parent.id, - origin: 'subagent', - }, childEvents(descriptorPayload('aborted behind a failure'))) - const controller = new AbortController() - ctx.sessionPersistence.open = () => { - // The read fails while the caller aborts: cancellation normalization - // must fail the listing rather than return a one-diagnostic success. - controller.abort() - return Promise.reject(new Error('backend read failed')) - } - await expect(ctx.subagents.listChildren(parent.id, controller.signal)).rejects.toThrow( - expect.objectContaining({ code: 'CANCELLED' }) as Error, - ) - }) - it('returns an empty array for a parent with no children', async () => { - const { ctx, parent } = await setup([]) - await ctx.sessions.flush(parent.session) - await expect(ctx.subagents.listChildren(parent.id)).resolves.toEqual([]) - }) - - it('SubagentError from listChildren is typed with its stable code', async () => { - const ctx = await setupWithoutProjections() - const caught: unknown = await ctx.subagents.listChildren(SessionId('typed-no-projections-parent')) - .catch((error: unknown) => error) - expect(caught).toBeInstanceOf(SubagentError) - expect((caught as SubagentError).code).toBe('SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE') - }) }) - describe('SubagentRuntime.listDescendants', () => { it('flattens the complete tree in stable pre-order with verified parent and depth', async () => { const { ctx, parent } = await setup([]) @@ -1328,20 +559,200 @@ describe('SubagentRuntime.listDescendants', () => { ]) }) - it('verifies a cold candidate still belongs to its enumerated lifecycle', async () => { + it('fails loud when descendant enumeration lacks the Session store or query service', async () => { + const withoutStore = new Context() + await withoutStore.plugin(SessionProjectionRegistry) + await withoutStore.plugin(SubagentRuntime) + await expect(withoutStore.subagents.listDescendants(SessionId('no-store-parent'))).rejects.toMatchObject({ + code: 'SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE', + }) + + const withoutQuery = new Context() + await withoutQuery.plugin(SessionStore) + await withoutQuery.plugin(SessionProjectionRegistry) + await withoutQuery.plugin(SubagentRuntime) + await expect(withoutQuery.subagents.listDescendants(SessionId('no-query-parent'))).rejects.toMatchObject({ + code: 'SUBAGENT_CONTROL_QUERY_UNAVAILABLE', + }) + }) + + it('propagates a descendant corpus listing failure', async () => { const { ctx, parent } = await setup([]) - const childId = await authorChild(ctx, '00000000-0000-4000-8000-00000000ddd1', { - parentSession: parent.id, - createdAt: 1, - origin: 'subagent', - }, childEvents(descriptorPayload('lineage checked'))) - // The exact read reports a different durable parent than enumeration did. - mutateStoredHeader(ctx, childId, meta => ({ ...meta, parentSession: SessionId('someone-else') })) + const failure = new Error('backend listing failed') + vi.spyOn(ctx.sessionQuery, 'listSessions').mockRejectedValue(failure) + await expect(ctx.subagents.listDescendants(parent.id)).rejects.toBe(failure) + }) + + it('maps an aborted descendant corpus listing to the stable cancellation error', async () => { + const { ctx, parent } = await setup([]) + const controller = new AbortController() + vi.spyOn(ctx.sessionQuery, 'listSessions').mockImplementation(() => { + controller.abort() + return Promise.reject(new Error('backend listing aborted')) + }) + await expect(ctx.subagents.listDescendants(parent.id, controller.signal)).rejects.toMatchObject({ + code: 'CANCELLED', + }) + }) + + it('contains a live descendant projection failure and orders sibling ties by id', async () => { + const { ctx, parent } = await setup([]) + const laterId = SessionId('live-projection-z') + const earlierId = SessionId('live-projection-a') + for (const id of [laterId, earlierId]) { + const child = ctx.sessions.create(id, { + meta: { parentSession: parent.id, origin: 'subagent', createdAt: 5 }, + }) + child.append('subagent/descriptor', descriptorPayload(String(id))) + } + const snapshot = ctx.sessionProjections.snapshot.bind(ctx.sessionProjections) + vi.spyOn(ctx.sessionProjections, 'snapshot').mockImplementation((session, keys) => { + if (session.id === laterId) throw new Error('projection failed') + return snapshot(session, keys) + }) + await expect(ctx.subagents.listDescendants(parent.id)).resolves.toEqual([ - { kind: 'diagnostic', id: childId, reason: 'corrupt', parentId: parent.id, depth: 1 }, + { + kind: 'child', id: earlierId, label: String(earlierId), mode: 'continuable', + activity: 'running', hasChildren: false, parentId: parent.id, depth: 1, + }, + { kind: 'diagnostic', id: laterId, reason: 'corrupt', parentId: parent.id, depth: 1 }, ]) }) + it('serves a valid own-suffix descendant identity from the projection cache', async () => { + const { ctx, parent } = await setup([], { projectionCache: true }) + const childId = await authorChild(ctx, '00000000-0000-4000-8000-00000000ae01', { + parentSession: parent.id, + origin: 'subagent', + }, childEvents(descriptorPayload('disk label'))) + ctx.sessionProjectionCache.cachedSnapshot = () => ({ + asOfSeq: SessionSeq(2), + values: { subagent: { mode: 'one-shot', seq: SessionSeq(2) } }, + }) + const open = vi.spyOn(ctx.sessionPersistence, 'open') + + await expect(ctx.subagents.listDescendants(parent.id)).resolves.toEqual([{ + kind: 'child', id: childId, mode: 'one-shot', activity: 'inactive', hasChildren: false, + parentId: parent.id, depth: 1, + }]) + expect(open).not.toHaveBeenCalled() + }) + + it.each([ + ['absent', () => ({ asOfSeq: SessionSeq(0), values: {} })], + ['null', () => ({ asOfSeq: SessionSeq(0), values: { subagent: null } })], + ['inherited', () => ({ + asOfSeq: SessionSeq(1), + values: { subagent: { mode: 'continuable' as const, label: 'ancestor', seq: SessionSeq(1) } }, + })], + ])('falls back to the authoritative descendant fold for a %s cached identity', async (_name, cachedSnapshot) => { + const { ctx, parent } = await setup([], { projectionCache: true }) + const childId = await authorChild(ctx, `cached-fallback-${_name}`, { + parentSession: parent.id, + origin: 'subagent', + }, _name === 'inherited' + ? [ + { type: 'turn/start', seq: SessionSeq(0), time: 1, data: { turn: 1 } }, + { type: 'turn/end', seq: SessionSeq(1), time: 2, data: { turn: 1, reason: { kind: 'completed' } } }, + { type: 'subagent/descriptor', seq: SessionSeq(2), time: 3, data: descriptorPayload('own label') }, + ] as SessionEvent[] + : childEvents(descriptorPayload('own label')), + _name === 'inherited' ? 2 : undefined) + ctx.sessionProjectionCache.cachedSnapshot = cachedSnapshot + const open = vi.spyOn(ctx.sessionPersistence, 'open') + + await expect(ctx.subagents.listDescendants(parent.id, testSignal)).resolves.toEqual([{ + kind: 'child', id: childId, label: 'own label', mode: 'continuable', + activity: 'inactive', hasChildren: false, parentId: parent.id, depth: 1, + }]) + expect(open).toHaveBeenCalledTimes(1) + }) + + it('falls back to the authoritative descendant fold when a cache read throws', async () => { + const { ctx, parent } = await setup([], { projectionCache: true }) + const childId = await authorChild(ctx, 'cache-read-failure', { + parentSession: parent.id, + origin: 'subagent', + }, childEvents(descriptorPayload('recovered'))) + ctx.sessionProjectionCache.cachedSnapshot = () => { throw new Error('poisoned cache row') } + + await expect(ctx.subagents.listDescendants(parent.id)).resolves.toEqual([{ + kind: 'child', id: childId, label: 'recovered', mode: 'continuable', + activity: 'inactive', hasChildren: false, parentId: parent.id, depth: 1, + }]) + }) + + it.each([ + ['SESSION_QUERY_CORRUPT_SESSION', 'corrupt'], + ['SESSION_QUERY_SOURCE_CONFLICT', 'corrupt'], + ['OTHER', 'unavailable'], + ] as const)('maps a %s cold descendant read failure to %s', async (code, reason) => { + const { ctx, parent } = await setup([]) + const childId = await authorChild(ctx, `cold-failure-${code}`, { + parentSession: parent.id, + origin: 'subagent', + }, childEvents(descriptorPayload('unreadable'))) + const failure = Object.assign(new Error('cold read failed'), { code }) + vi.spyOn(ctx.sessionQuery, 'observeSession').mockRejectedValue(failure) + + await expect(ctx.subagents.listDescendants(parent.id)).resolves.toEqual([{ + kind: 'diagnostic', id: childId, reason, parentId: parent.id, depth: 1, + }]) + }) + + it('maps a non-Error cold descendant rejection to unavailable', async () => { + const { ctx, parent } = await setup([]) + const childId = await authorChild(ctx, 'cold-non-error-failure', { + parentSession: parent.id, + origin: 'subagent', + }, childEvents(descriptorPayload('unreadable'))) + vi.spyOn(ctx.sessionQuery, 'observeSession').mockImplementation(() => + // A backend can violate the Error rejection convention at this durable boundary. + // oxlint-disable-next-line typescript/prefer-promise-reject-errors -- exercises that non-Error boundary + Promise.reject('cold read failed')) + + await expect(ctx.subagents.listDescendants(parent.id)).resolves.toEqual([{ + kind: 'diagnostic', id: childId, reason: 'unavailable', parentId: parent.id, depth: 1, + }]) + }) + + it('maps a cold descendant failure racing cancellation to cancellation', async () => { + const { ctx, parent } = await setup([]) + await authorChild(ctx, 'cold-cancelled-failure', { + parentSession: parent.id, + origin: 'subagent', + }, childEvents(descriptorPayload('cancelled'))) + const controller = new AbortController() + vi.spyOn(ctx.sessionQuery, 'observeSession').mockImplementation(() => { + controller.abort() + return Promise.reject(new Error('cold read failed')) + }) + + await expect(ctx.subagents.listDescendants(parent.id, controller.signal)).rejects.toMatchObject({ + code: 'CANCELLED', + }) + }) + + it('maps cancellation after a successful cold descendant read to cancellation', async () => { + const { ctx, parent } = await setup([]) + await authorChild(ctx, 'cold-cancelled-success', { + parentSession: parent.id, + origin: 'subagent', + }, childEvents(descriptorPayload('cancelled'))) + const controller = new AbortController() + const observe = ctx.sessionQuery.observeSession.bind(ctx.sessionQuery) + vi.spyOn(ctx.sessionQuery, 'observeSession').mockImplementation(async (id, options) => { + const observation = await observe(id, options) + controller.abort() + return observation + }) + + await expect(ctx.subagents.listDescendants(parent.id, controller.signal)).rejects.toMatchObject({ + code: 'CANCELLED', + }) + }) + it('a pre-aborted signal stops the descendant scan before persistence reads', async () => { const { ctx, parent } = await setup([textResponse('done')]) await startChild(ctx, parent, 'never read') @@ -1355,9 +766,25 @@ describe('SubagentRuntime.listDescendants', () => { }) it('fails loud when the projection registry is not mounted', async () => { - const ctx = await setupWithoutProjections() + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(SubagentRuntime) await expect(ctx.subagents.listDescendants(SessionId('no-projections-root'))).rejects.toThrow( expect.objectContaining({ code: 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE' }) as Error, ) }) + it('verifies a cold candidate still belongs to its enumerated lifecycle', async () => { + const { ctx, parent } = await setup([]) + const childId = await authorChild(ctx, '00000000-0000-4000-8000-00000000ddd1', { + parentSession: parent.id, + createdAt: 1, + origin: 'subagent', + }, childEvents(descriptorPayload('lineage checked'))) + // The exact read reports a different durable parent than enumeration did. + mutateStoredHeader(ctx, childId, meta => ({ ...meta, parentSession: SessionId('someone-else') })) + await expect(ctx.subagents.listDescendants(parent.id)).resolves.toEqual([ + { kind: 'diagnostic', id: childId, reason: 'corrupt', parentId: parent.id, depth: 1 }, + ]) + }) + }) diff --git a/packages/subagent/subagent/tests/service.spec.ts b/packages/subagent/subagent/tests/service.spec.ts index f40fc11dff..01a17cb591 100644 --- a/packages/subagent/subagent/tests/service.spec.ts +++ b/packages/subagent/subagent/tests/service.spec.ts @@ -276,7 +276,7 @@ describe('SubagentRuntime', () => { const parentSession = Session.create(SessionId('catalog-parent')) const childSession = Session.create(SessionId('catalog-child')) const parent = { id: parentSession.id, session: parentSession } as Agent - const localAgent = { id: childSession.id, session: childSession } as Agent + const localAgent = { id: childSession.id, session: childSession, options: {} } as Agent const result = Promise.withResolvers() const cleanupFailure = new Error('dispose also failed') const warnings = vi.spyOn(ctx.logger, 'warn') diff --git a/packages/subagent/tool-subagent-control/README.i18n.yaml b/packages/subagent/tool-subagent-control/README.i18n.yaml index d4f18d593e..654111e850 100644 --- a/packages/subagent/tool-subagent-control/README.i18n.yaml +++ b/packages/subagent/tool-subagent-control/README.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 packages/subagent/tool-subagent-control/README.md -README.md: 99ca52dd4a7ea2629441c4d661632b8598c8171d -README.zh.md: 1ff49a3179dbe61db1a9353e2fab131082cb29ae +README.md: 4d20c6b933040dbf2f31978303b8ff7fe31f64ac +README.zh.md: 7066fc040b06967592c1f45a2e078513d5cdacd1 diff --git a/packages/subagent/tool-subagent-control/README.md b/packages/subagent/tool-subagent-control/README.md index 99ca52dd4a..4d20c6b933 100644 --- a/packages/subagent/tool-subagent-control/README.md +++ b/packages/subagent/tool-subagent-control/README.md @@ -54,7 +54,7 @@ Stops only the target's current turn: queued messages stay parked until a later ### list_agents -Lists the continuable children below the calling agent: `children` (default) shows direct children, `descendants` walks the whole tree in stable pre-order, annotating each entry with its durable direct-parent session id and depth. Status comes from the live Agent registry — `running`, `idle`, or `ready`. One-shot children are intentionally absent because they cannot accept `send_message`, and unreadable candidates appear as diagnostics. +Lists the continuable children below the calling agent: `children` (default) reads direct children from the parent catalog without opening child logs; `descendants` walks the whole tree in stable pre-order, annotating each entry with its durable direct-parent session id and depth. Status comes from the live Agent registry — `running`, `idle`, or `ready`. One-shot children are intentionally absent because they cannot accept `send_message`, and unreadable candidates appear as diagnostics only in `descendants` scope. ----- @@ -150,7 +150,7 @@ Append-only; newly visible content follows the reusable request prefix and does #### What the model sees -One line per continuable child in stable catalog order: ` [] —