('[data-submission-echo]')
+ if (echo === null) throw new Error('submission echo missing on the send keystroke')
+ expect(echo.textContent).toContain('回显这条消息')
+ expect(echo.querySelector('img')?.getAttribute('src')?.split(':')[0]).toBe('blob')
+ expect(composer.textContent).toBe('')
+ expect(composer.getAttribute('contenteditable')).toBe('true')
+ expect(document.querySelector('[role="group"][aria-label="Pending images"]')).toBeNull()
+
+ // The fixture's durable user/message (source.rpcId echoes the prompt
+ // requestId) replaces the echo: one bubble, no marker left, and the image
+ // now renders from the durable gallery.
+ await waitFor(() => {
+ if (document.querySelector('[data-submission-echo]') !== null) {
+ throw new Error('submission echo still present after the durable node arrived')
+ }
+ }, { timeout: 10_000 })
+ expect(screen.getAllByText('回显这条消息')).toHaveLength(1)
+ await waitFor(() => {
+ if (document.querySelector('[data-align="end"] img') === null) {
+ throw new Error('durable user gallery missing')
+ }
+ }, { timeout: 10_000 })
+})
diff --git a/apps/web/tests/support.ts b/apps/web/tests/support.ts
index 66bfd4111d..63cf8c3ff8 100644
--- a/apps/web/tests/support.ts
+++ b/apps/web/tests/support.ts
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync } from 'node:fs'
import { createServer } from 'node:net'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
-import type { Browser, Page } from 'playwright'
+import type { Browser, Locator, Page } from 'playwright'
/** The built page under test; `pnpm run test:web` rebuilds it before running. */
export const DIST_INDEX = fileURLToPath(new URL('../dist/index.html', import.meta.url))
@@ -31,6 +31,35 @@ export async function newEnglishPage(browser: Browser, height = 1000): Promise {
+ const controls = page.locator('[data-turn-process]')
+ await controls.first().waitFor({ state: 'visible', timeout: 10_000 })
+ const count = await controls.count()
+ for (let index = 0; index < count; index++) {
+ const control = controls.nth(index)
+ if (await control.getAttribute('aria-expanded') !== 'true') await control.click()
+ }
+}
+
+/**
+ * Expand the Turn-process group containing one possibly hidden descendant.
+ * @param page - page containing the Chat view.
+ * @param target - descendant whose owning Turn process should open.
+ */
+export async function expandOwningTurnProcess(page: Page, target: Locator): Promise {
+ const turn = await target.evaluate(element => element.closest('[data-chat-turn]')?.dataset.chatTurn)
+ if (turn === undefined || await target.isVisible()) return
+ const control = page.locator(`[data-turn-process="${turn}"]`)
+ await control.waitFor({ state: 'visible', timeout: 10_000 })
+ if (await control.getAttribute('aria-expanded') !== 'true') await control.click()
+}
+
/** Fail loud on a stale checkout instead of testing yesterday's bundle. */
export function requireDist(): void {
if (!existsSync(DIST_INDEX)) {
@@ -83,7 +112,7 @@ export async function connectFreshWorkspace(page: Page, root: string, name = 'wo
await dialog.getByRole('button', { name: 'Open', exact: true }).click()
// The pick connected the workspace: the blank session's live composer
// replaces the locked placeholder and enables.
- await page.locator('[data-composer-input][contenteditable="true"][data-placeholder="Describe what you want to build"]')
+ await page.locator('[data-composer-input][contenteditable="true"][data-placeholder="Describe what you want to build... / commands, @ files or sessions"]')
.waitFor({ timeout: 15_000 })
}
@@ -106,7 +135,7 @@ export async function connectFreshWorkspaceZh(page: Page, root: string, name = '
await pathInput.fill(join(root, name))
await pathInput.press('Enter')
await dialog.getByRole('button', { name: '打开', exact: true }).click()
- await page.locator('[data-composer-input][contenteditable="true"][data-placeholder="描述你想要构建的内容"]')
+ await page.locator('[data-composer-input][contenteditable="true"][data-placeholder="描述你想要构建的内容… / 调用指令 @ 文件或对话"]')
.waitFor({ timeout: 15_000 })
}
diff --git a/apps/web/tests/todo-row.expected.e2e.ts b/apps/web/tests/todo-row.expected.e2e.ts
index 5672dd09a0..21fa70d9bf 100644
--- a/apps/web/tests/todo-row.expected.e2e.ts
+++ b/apps/web/tests/todo-row.expected.e2e.ts
@@ -1,7 +1,7 @@
// @vitest-environment jsdom
// Assembled todo snapshot: boots the real built `packages/client/*/lib/
// client.js` bundles through AppWebEntry's ModuleLoader path against the
-// keyless FixtureApiClient transport, opens the fixture session, and pins the
+// keyless fixture Connection RPC, opens the fixture session, and pins the
// two surfaces the fixture's parallel plan (turn 74, two items `in_progress`)
// reaches — the `todo_write` tool row and the dock's plan strip.
//
diff --git a/apps/web/tests/trajectory-image-display.expected.e2e.ts b/apps/web/tests/trajectory-image-display.expected.e2e.ts
index 07ed9330b2..315d3baa1e 100644
--- a/apps/web/tests/trajectory-image-display.expected.e2e.ts
+++ b/apps/web/tests/trajectory-image-display.expected.e2e.ts
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
-// Trajectory image surfaces over the BUILT client graph (the code-mode-fixture
-// idiom: real bundles via AppWebEntry, keyless FixtureApiClient transport).
+// Trajectory image surfaces over the BUILT client graph (the ptc-fixture
+// idiom: real bundles via AppWebEntry, keyless fixture Connection RPC).
// Opens the fixture history session whose turn 73 carries an image in BOTH a
// user message and an assistant message, and pins the Trajectory surfaces:
// selecting the ledger record renders the shared ui-attachment gallery from
diff --git a/apps/web/tests/turn-tail-actions.e2e.ts b/apps/web/tests/turn-tail-actions.e2e.ts
index 9a78fb9f9c..c207d9278b 100644
--- a/apps/web/tests/turn-tail-actions.e2e.ts
+++ b/apps/web/tests/turn-tail-actions.e2e.ts
@@ -24,10 +24,12 @@ import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './suppor
const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/turn-tail-actions', import.meta.url))
const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl')
-// Two goldens for the same message: parked mid-turn, then settled.
+// Three goldens for the same message: parked mid-turn, aborted, and completed.
const RUNNING_EXPECTED = join(SNAPSHOT_DIR, 'running.expected.md')
const SETTLED_EXPECTED = join(SNAPSHOT_DIR, 'settled.expected.md')
const USAGE_EXPANDED_EXPECTED = join(SNAPSHOT_DIR, 'usage-expanded.expected.md')
+const COMPLETED_EXPECTED = join(SNAPSHOT_DIR, 'completed.expected.md')
+const FOCUSED_EXPECTED = join(SNAPSHOT_DIR, 'focused.expected.md')
const MODE = webSnapshotMode()
// The recording must carry text in the SAME assistant message as the tool
@@ -60,7 +62,10 @@ describe('web e2e: assistant IconActions wait for the turn to end', () => {
})
/** Boot scaffold + page, materializing the sidecar before the replay row installs. */
- async function launch(buildOverride?: (sidecarHome: string) => ReplayOverrideDoc): Promise {
+ async function launch(
+ buildOverride?: (sidecarHome: string) => ReplayOverrideDoc,
+ paceMs?: number,
+ ): Promise {
sessionEvents = []
let overridePath: string | undefined
if (buildOverride !== undefined) {
@@ -75,6 +80,7 @@ describe('web e2e: assistant IconActions wait for the turn to end', () => {
replayFixture: FIXTURE,
...(overridePath === undefined ? {} : { replayOverride: overridePath }),
compareReplaySession: overridePath === undefined,
+ ...(paceMs === undefined ? {} : { paceMs }),
},
)
scaffold.ctx.on('session/event', (_session, event: SessionEvent) => { sessionEvents.push(event) })
@@ -122,13 +128,13 @@ describe('web e2e: assistant IconActions wait for the turn to end', () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-turn-tail-actions'))
// The barrier is armed before the park and awaited only after the stop
// click, so its budget must cover the whole parked phase: marker poll,
- // three UI polls, and two captures with their stability windows. The
+ // live-state polls, and two captures with their stability windows. The
// replay default (30s) leaves no headroom on a slow runner.
const { settled } = await sendPrompt(120_000)
// The marker IS the synchronization: the second call is provably parked,
// so the first step's message and tool result are already durable.
await expect.poll(() => existsSync(marker), { timeout: 20_000 }).toBe(true)
- await expect.poll(() => page.getByText(NARRATION, { exact: true }).count(), { timeout: 10_000 }).toBe(1)
+ expect(await page.locator('[data-turn-process]').count()).toBe(0)
await expect.poll(
() => page.getByRole('status').filter({ hasText: 'Deep diving...' }).isVisible(),
{ timeout: 10_000 },
@@ -148,6 +154,7 @@ describe('web e2e: assistant IconActions wait for the turn to end', () => {
await page.getByRole('button', { name: 'Stop generating' }).click()
await settled
expect(sessionEvents.filter(e => e.type === 'turn/end').map(e => e.data.reason.kind)).toEqual(['aborted'])
+ await page.locator('[data-turn-process]').waitFor({ timeout: 10_000 })
await expect.poll(() => copyButtons.count(), { timeout: 10_000 }).toBe(2)
await expect.poll(() => page.locator('[data-streaming="true"]').count(), { timeout: 10_000 }).toBe(0)
await copyButtons.last().focus()
@@ -182,9 +189,89 @@ describe('web e2e: assistant IconActions wait for the turn to end', () => {
expect(tripwire.warnings).toEqual([])
}, 120_000)
+ it.skipIf(MODE === 'record')('folds the Turn process after the completed reply becomes the answer', async () => {
+ await launch()
+ onTestFailed(() => saveFailureShot(page, 'web-e2e-turn-tail-actions-completed'))
+ const { settled } = await sendPrompt()
+ await settled
+ await expect.poll(() => page.getByText('DONE', { exact: true }).count(), { timeout: 10_000 }).toBe(1)
+ const process = page.locator('[data-turn-process]')
+ await expect.poll(() => process.count(), { timeout: 10_000 }).toBe(1)
+ expect(await process.getAttribute('aria-expanded')).toBe('false')
+ expect(await process.evaluate(element => getComputedStyle(element).borderBottomWidth)).toBe('1px')
+ const processBottom = await process.evaluate(element =>
+ element.closest('[data-chat-flow-kind="turn-process"]')?.getBoundingClientRect().bottom)
+ const answerTop = await page.getByText('DONE', { exact: true }).evaluate(element =>
+ element.closest('[data-chat-flow-kind="assistant-step"]')?.getBoundingClientRect().top)
+ expect(answerTop).toBe((processBottom ?? 0) + 8)
+ await process.focus()
+ const completed = await captureStableAria(page, '[class*="centerCol"]', scaffold!.workspaceCwd)
+ await compareOrRefreshGolden(COMPLETED_EXPECTED, completed, MODE)
+ expect(tripwire.pageErrors).toEqual([])
+ expect(tripwire.warnings).toEqual([])
+ }, 60_000)
+
+ it.skipIf(MODE === 'record')('switches a completed Turn between Compact and Normal', async () => {
+ await launch()
+ onTestFailed(() => saveFailureShot(page, 'web-e2e-turn-process-setting'))
+ const { settled } = await sendPrompt()
+ await settled
+ const process = page.locator('[data-turn-process]')
+ const tool = page.getByRole('button', { name: 'Bash Print alpha to stdout' })
+ await process.waitFor({ timeout: 10_000 })
+ expect(await process.getAttribute('aria-expanded')).toBe('false')
+ expect(await tool.isVisible()).toBe(false)
+
+ await page.getByRole('button', { name: 'Settings', exact: true }).click()
+ const dialog = page.getByRole('dialog', { name: 'Settings' })
+ await dialog.getByRole('button', { name: 'Compact', exact: true }).click()
+ await page.getByRole('menuitem', { name: 'Normal', exact: true }).click()
+ await page.keyboard.press('Escape')
+
+ await expect.poll(() => process.count(), { timeout: 10_000 }).toBe(0)
+ await tool.waitFor({ state: 'visible', timeout: 10_000 })
+ await expect.poll(async () => readFile(join(scaffold!.harnessHome, 'settings.yaml'), 'utf8'), { timeout: 5_000 })
+ .toMatch(/ui-chat:\n\s+transcriptView: normal/)
+
+ await page.getByRole('button', { name: 'Settings', exact: true }).click()
+ const restored = page.getByRole('dialog', { name: 'Settings' })
+ await restored.getByRole('button', { name: 'Normal', exact: true }).click()
+ await page.getByRole('menuitem', { name: 'Compact', exact: true }).click()
+ await page.keyboard.press('Escape')
+ await process.waitFor({ timeout: 10_000 })
+ expect(await process.getAttribute('aria-expanded')).toBe('false')
+ expect(await tool.isVisible()).toBe(false)
+ expect(tripwire.pageErrors).toEqual([])
+ expect(tripwire.warnings).toEqual([])
+ }, 60_000)
+
+ it.skipIf(MODE === 'record')('keeps a focused process member open when the completed reply arrives', async () => {
+ await launch(undefined, 200)
+ onTestFailed(() => saveFailureShot(page, 'web-e2e-turn-tail-actions-focused'))
+ const { settled } = await sendPrompt()
+ const tool = page.getByRole('button', { name: 'Bash Print alpha to stdout' })
+ await tool.waitFor({ timeout: 30_000 })
+ await tool.focus()
+ expect(await tool.evaluate(element => element.ownerDocument.activeElement === element)).toBe(true)
+ await settled
+ await expect.poll(() => page.getByText('DONE', { exact: true }).count(), { timeout: 10_000 }).toBe(1)
+ const process = page.locator('[data-turn-process]')
+ await expect.poll(() => process.count(), { timeout: 10_000 }).toBe(1)
+ expect(await process.getAttribute('aria-expanded')).toBe('true')
+ expect(await tool.evaluate(element => element.ownerDocument.activeElement === element)).toBe(true)
+ const focused = await captureStableAria(page, '[class*="centerCol"]', scaffold!.workspaceCwd)
+ await compareOrRefreshGolden(FOCUSED_EXPECTED, focused, MODE)
+ expect(tripwire.pageErrors).toEqual([])
+ expect(tripwire.warnings).toEqual([])
+ }, 60_000)
+
it.skipIf(MODE === 'record')('keeps a closed fixture inventory', async () => {
- await assertFixtureInventory(SNAPSHOT_DIR, [
- 'running.expected.md', 'session.jsonl', 'settled.expected.md', 'usage-expanded.expected.md',
- ])
+ await assertFixtureInventory(
+ SNAPSHOT_DIR,
+ [
+ 'completed.expected.md', 'focused.expected.md', 'running.expected.md', 'session.jsonl',
+ 'settled.expected.md', 'usage-expanded.expected.md',
+ ],
+ )
})
})
diff --git a/apps/web/tests/web-search-round.e2e.ts b/apps/web/tests/web-search-round.e2e.ts
index bba79e3ad4..5f9e118767 100644
--- a/apps/web/tests/web-search-round.e2e.ts
+++ b/apps/web/tests/web-search-round.e2e.ts
@@ -16,7 +16,7 @@ import {
assertFixtureInventory, captureStableAria, compareOrRefreshGolden, fixtureUserPrompts,
launchWebScaffold, recordFixture, watchConsole, webSnapshotMode, type WebScaffold,
} from './scaffold.ts'
-import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts'
+import { connectFreshWorkspace, expandOwningTurnProcess, newEnglishPage, saveFailureShot } from './support.ts'
const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/web-search-round', import.meta.url))
const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/web-search-round/session.jsonl', import.meta.url))
@@ -263,7 +263,9 @@ describe('web e2e: shipped default web search', () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-search-aria'))
await expect.poll(() => page.getByText('SEARCH_DONE', { exact: true }).count(), { timeout: 15_000 })
.toBeGreaterThanOrEqual(1)
- await page.locator('[data-tool="web_search"]').waitFor({ timeout: 10_000 })
+ const searchTool = page.locator('[data-tool="web_search"]')
+ await expandOwningTurnProcess(page, searchTool)
+ await searchTool.waitFor({ timeout: 10_000 })
const snapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)
await compareOrRefreshGolden(UI_EXPECTED, snapshot, MODE)
})
@@ -271,6 +273,7 @@ describe('web e2e: shipped default web search', () => {
it.skipIf(MODE === 'record')('scrolls the capped source list inside the fixed-height container', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-search-sources-scroll'))
const row = page.locator('[data-tool="web_search"] [data-expandable]').first()
+ await expandOwningTurnProcess(page, row)
await row.click()
await expect.poll(() => row.getAttribute('aria-expanded'), { timeout: 5_000 }).toBe('true')
@@ -299,6 +302,7 @@ describe('web e2e: shipped default web search', () => {
it.skipIf(MODE === 'record')('reserves marker room a scroll container cannot clip back', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-search-marker-room'))
+ await expandOwningTurnProcess(page, page.locator('[data-tool="web_search"]'))
// `overflow-y: auto` clips inline-start overflow with no way to scroll it
// back, and markers are right-aligned to the content edge, so a marker wider
// than `padding-left` silently loses its leading digits. `searchMaxResults`
diff --git a/apps/web/tests/workflow-run.e2e.ts b/apps/web/tests/workflow-run.e2e.ts
index ede39f8e0f..da846b1c6b 100644
--- a/apps/web/tests/workflow-run.e2e.ts
+++ b/apps/web/tests/workflow-run.e2e.ts
@@ -15,7 +15,7 @@ import {
type WebScaffold,
} from './scaffold.ts'
import {
- connectFreshWorkspace, newEnglishPage, REPO_ROOT, saveFailureShot,
+ connectFreshWorkspace, expandTurnProcesses, newEnglishPage, REPO_ROOT, saveFailureShot,
} from './support.ts'
const MODE = webSnapshotMode()
@@ -161,6 +161,7 @@ describe.skipIf(MODE === 'record')('web e2e: durable workflow run in Chat', () =
const sessions = page.getByRole('tree', { name: 'Sessions' })
await sessions.getByRole('treeitem', { name: /Use the workflow tool exactly/ }).click()
await settled
+ await expandTurnProcesses(page)
await page.locator('[data-workflow-run][data-run-status="completed"]').waitFor()
expect(await page.locator('[data-chat-flow-kind="tool-call"]').count()).toBeGreaterThanOrEqual(1)
@@ -186,6 +187,7 @@ describe.skipIf(MODE === 'record')('web e2e: durable workflow run in Chat', () =
onTestFailed(() => saveFailureShot(page, 'web-e2e-workflow-run-history'))
await page.reload({ waitUntil: 'load' })
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
+ await expandTurnProcesses(page)
const workflow = page.getByRole('button', { name: /^snapshot-flow/ })
await workflow.waitFor({ timeout: 15_000 })
expect(await workflow.getAttribute('aria-expanded')).toBe('false')
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json
index 0388704e61..2357de9d14 100644
--- a/apps/web/tsconfig.json
+++ b/apps/web/tsconfig.json
@@ -59,7 +59,7 @@
"tests/sidebar-scrollbar.e2e.ts",
"tests/rail-search-expand.e2e.ts",
"tests/conversation-column-overflow.e2e.ts",
- "tests/code-mode-round.e2e.ts",
+ "tests/ptc-round.e2e.ts",
"tests/composer-draft-scroll.e2e.ts",
"tests/cordis-tool-round.e2e.ts",
"tests/web-search-round.e2e.ts",
@@ -82,6 +82,7 @@
"tests/shipped-composition.e2e.ts",
"tests/schedule-after.e2e.ts",
"tests/feedback-command.e2e.ts",
+ "tests/feedback-release.e2e.ts",
"tests/agent-team-panel.e2e.ts",
"tests/startup-auto-selection.e2e.ts",
"tests/produced-files.e2e.ts",
diff --git a/docs/api-gateway.i18n.yaml b/docs/api-gateway.i18n.yaml
index 07858f39c4..c5feee2c91 100644
--- a/docs/api-gateway.i18n.yaml
+++ b/docs/api-gateway.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/api-gateway.md
-api-gateway.md: 86c43ccc5719107ded1e4004d6fabbc32b760520
-api-gateway.zh.md: 6fa170b84129eb96a70d0831158a9f9c43db256c
+api-gateway.md: 43b00bcff3da0adb1d53ac25534b65366bc42611
+api-gateway.zh.md: bb2711220fd75ef0119e1188c22a0af5ad4169a8
diff --git a/docs/api-gateway.md b/docs/api-gateway.md
index 86c43ccc57..43b00bcff3 100644
--- a/docs/api-gateway.md
+++ b/docs/api-gateway.md
@@ -118,13 +118,13 @@ Strict analysis requires a Remote to be a public, non-static instance method wit
## Runtime invocation
-Remote and API Proxy share the Connection's `/api` route. The Client Remote calls `connection.rpc.call('/api', '/', { args }, signal)`; the HTTP carrier maps this to `POST /api//`, with a payload containing only a named `args` object.
+Remote calls use the Connection's `/api` route. The Client Remote calls `connection.rpc.call('/api', '/', { args }, signal)`; the HTTP carrier maps this to `POST /api//`, with a payload containing only a named `args` object.
-The Connection performs the unified trust check for `/api` before the HTTP bridge, then dispatches inside the shared FetchHandler in interceptor order. The Typert Gateway claims only two-segment endpoints that have a strict descriptor or active SRC marker; unclaimed requests fall back to the existing API Proxy. The Connection owns transport, RPC ids, response envelopes, and request cancellation, while the Gateway owns only the Remote data protocol and business dispatch. Replacing the Connection carrier does not require changes to Remote descriptors or the Client programming interface.
+The Connection performs the unified trust check for `/api` before the HTTP bridge, then dispatches inside the shared FetchHandler. The Typert Gateway claims only two-segment endpoints that have a strict descriptor or active SRC marker; feature-owned exact Fetch routes handle non-JSON responses, and other requests return 404. The Connection owns transport, RPC ids, response envelopes, and request cancellation, while the Gateway owns only the Remote data protocol and business dispatch. Replacing the Connection carrier does not require changes to Remote descriptors or the Client programming interface.
For every call, the Gateway resolves the descriptor and live service from the current registries instead of caching business objects. It requires the fields in `args` to match the descriptor exactly, validates wire values with codecs, resolves objects or receivers through registered lookup or Context providers, invokes the service method targeted by the binding, and validates the return value. A missing provider, unknown identity, binding mismatch, missing or extra argument, schema failure, or missing method fails before entering or after leaving business code.
-The lookup provider's `register()` supplies both the stable declaration and the default resolver; `configure()` supplies a resolver owned by Host composition that may execute asynchronously and is scoped to an effect lifetime. Configuration may precede provider mounting; without a provider, invocation still fails with `lookup-unavailable`, and unloading the configuration restores the provider's default policy. The Session Controller owns the standard `agentFor()` semantics for `agent` and `session`: it reuses a live Agent, automatically resumes ordinary cold sessions, deduplicates concurrent resumes, and rejects identities owned by subagent routing; the `session` lookup returns that Agent's Session. The Web API Proxy supplies its Agent defaults and scope setup, then consumes the same resolver for legacy methods. Resume failures and ownership fences pass through unchanged as existing RPC errors rather than being collapsed into the Gateway's `internal` error.
+The lookup provider's `register()` supplies both the stable declaration and the default resolver; `configure()` supplies a resolver owned by Host composition that may execute asynchronously and is scoped to an effect lifetime. Configuration may precede provider mounting; without a provider, invocation still fails with `lookup-unavailable`, and unloading the configuration restores the provider's default policy. The Session Controller owns the standard `agentFor()` semantics for `agent` and `session`: it reuses a live Agent, automatically resumes ordinary cold sessions, deduplicates concurrent resumes, and rejects identities owned by subagent routing; the `session` lookup returns that Agent's Session. Resume failures and ownership fences pass through unchanged as existing RPC errors rather than being collapsed into the Gateway's `internal` error.
Unloading a Client contribution removes its descriptors and concrete methods together, aborts its in-flight calls, and makes stale method handles retained by external code reject further calls. A strict endpoint withdrawn on the Host also does not degrade to SRC inference, preventing a hot unload from silently weakening validation.
@@ -159,6 +159,6 @@ The running Client watcher consumes these generated files when it rebundles. If
Remote handles only unary method calls with one request and one result. Session event streams, pagination, incremental reduce, projection, and entity substreams require a separate data protocol and registration model; even when they reuse the Connection, they must not masquerade as Remote methods or enter invocation descriptors.
-The API layers are organized as `remotes → gateway → connection → webserver`. The BFF and Typert RPC layers live under `packages/api`; Connection and WebServer live at `packages/client/connection` and `packages/host/webserver`. The API Proxy at `packages/host/apiproxy` handles endpoints without Remote descriptors.
+The API layers are organized as `remotes → gateway → connection → webserver`. The BFF and Typert RPC layers live under `packages/api`; Connection and WebServer live at `packages/client/connection` and `packages/host/webserver`. A feature that needs a streamed or browser-native response registers an exact Connection Fetch route instead of defining a Remote method.
Lookup policy is configured per key, so all `agent` or `session` parameters share the cold-resume behavior. Accepting live objects only would require an explicit per-parameter or per-endpoint policy, which does not exist; the business method must not guess whether the object came from restoration.
diff --git a/docs/api-gateway.zh.md b/docs/api-gateway.zh.md
index 6fa170b841..bb2711220f 100644
--- a/docs/api-gateway.zh.md
+++ b/docs/api-gateway.zh.md
@@ -118,13 +118,13 @@ Remote Client 声明中的参数名来自 wire 字段,参数和返回类型则
## 运行时调用
-Remote 与 API Proxy 共用 Connection 的 `/api` 路由。Client Remote 调用 `connection.rpc.call('/api', '/', { args }, signal)`;HTTP carrier 对应 `POST /api//`,payload 只包含一个具名 `args` 对象。
+Remote 调用使用 Connection 的 `/api` 路由。Client Remote 调用 `connection.rpc.call('/api', '/', { args }, signal)`;HTTP carrier 对应 `POST /api//`,payload 只包含一个具名 `args` 对象。
-Connection 在 HTTP bridge 之前执行 `/api` 的统一信任检查,再在共享 FetchHandler 内按 interceptor 顺序分发。Typert Gateway 只认领存在严格描述符或活跃 SRC marker 的两段式 endpoint;未认领的请求回退到既有 API Proxy。Connection 拥有传输、RPC id、响应 envelope 和请求取消,Gateway 只拥有 Remote 数据协议和业务分发。替换 Connection carrier 不要求改变 Remote 描述符或 Client 编程接口。
+Connection 在 HTTP bridge 之前执行 `/api` 的统一信任检查,再在共享 FetchHandler 内分发。Typert Gateway 只认领存在严格描述符或活跃 SRC marker 的两段式 endpoint;功能自有的精确 Fetch 路由处理非 JSON 响应,其他请求返回 404。Connection 拥有传输、RPC id、响应 envelope 和请求取消,Gateway 只拥有 Remote 数据协议和业务分发。替换 Connection carrier 不要求改变 Remote 描述符或 Client 编程接口。
Gateway 每次调用都从当前注册表解析描述符和实时服务,不缓存业务对象。它要求 `args` 的字段集合与描述符完全一致,先用 codec 校验 wire 值,再通过注册的 lookup 或 Context 提供方解析对象或接收者,最后调用 binding 指向的服务方法并校验返回值。缺少提供方、identity 未命中、binding 不一致、参数缺失或多余、schema 失败和方法不存在都会在进入业务代码前或离开业务代码后失败。
-lookup 提供方的 `register()` 同时提供稳定声明和默认 resolver;`configure()` 提供由 Host 组合拥有、可异步执行且受 effect 生命周期约束的 resolver。配置可以先于提供方挂载;没有提供方时调用仍以 `lookup-unavailable` 失败,配置卸载后则恢复提供方默认策略。Session Controller 负责 `agent` 与 `session` 的标准 `agentFor()` 语义:复用 live Agent,自动恢复普通冷会话,对并发恢复去重,并拒绝由 subagent routing 拥有的 identity;`session` lookup 返回该 Agent 的 Session。Web API Proxy 提供 Agent 默认值与 scope 设置,再让旧方法使用同一个 resolver。恢复失败和 ownership fence 通过既有 RPC error 原样返回,不折叠为 Gateway 的 `internal` 错误。
+lookup 提供方的 `register()` 同时提供稳定声明和默认 resolver;`configure()` 提供由 Host 组合拥有、可异步执行且受 effect 生命周期约束的 resolver。配置可以先于提供方挂载;没有提供方时调用仍以 `lookup-unavailable` 失败,配置卸载后则恢复提供方默认策略。Session Controller 负责 `agent` 与 `session` 的标准 `agentFor()` 语义:复用 live Agent,自动恢复普通冷会话,对并发恢复去重,并拒绝由 subagent routing 拥有的 identity;`session` lookup 返回该 Agent 的 Session。恢复失败和 ownership fence 通过既有 RPC error 原样返回,不折叠为 Gateway 的 `internal` 错误。
Client 卸载一个贡献时会一起移除描述符和具体方法,中止其进行中的调用,并使外部仍持有的陈旧方法句柄拒绝继续调用。Host 上已经注册过的严格 endpoint 被撤回后也不会降级到 SRC 推断,以免热卸载悄然降低校验强度。
@@ -159,6 +159,6 @@ pnpm run build:lib
Remote 只处理有单个请求与单个结果的一元方法调用。会话事件流、分页、增量 reduce、projection 和实体子流需要独立的数据协议与注册模型;即使它们复用 Connection,也不应伪装成 Remote 方法或放入调用描述符。
-API 各层按 `remotes → gateway → connection → webserver` 组织。BFF 与 Typert RPC 层位于 `packages/api`;Connection 与 WebServer 位于 `packages/client/connection` 和 `packages/host/webserver`。位于 `packages/host/apiproxy` 的 API Proxy 处理没有 Remote 描述符的 endpoint。
+API 各层按 `remotes → gateway → connection → webserver` 组织。BFF 与 Typert RPC 层位于 `packages/api`;Connection 与 WebServer 位于 `packages/client/connection` 和 `packages/host/webserver`。需要流式或浏览器原生响应的功能注册精确的 Connection Fetch 路由,而不定义 Remote 方法。
lookup 策略按 key 配置,因此所有 `agent` 或 `session` 参数共享冷恢复行为。只接受 live 对象需要显式的逐参数或逐 endpoint 策略,而这种策略并不存在;不能通过业务方法内部猜测对象是否来自恢复。
diff --git a/docs/capability-seams.i18n.yaml b/docs/capability-seams.i18n.yaml
index 5d1d98a404..e004cf0452 100644
--- a/docs/capability-seams.i18n.yaml
+++ b/docs/capability-seams.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/capability-seams.md
-capability-seams.md: 1e7e6e39d307a9e72b5d57420bde99f51063f64d
-capability-seams.zh.md: e33a1e6da7f71838c48b961f93389ba1a089f57f
+capability-seams.md: 5c3ba40df35f40e211de2bf90037f998eeb5a15d
+capability-seams.zh.md: 47402e1b6d9514a77e8fff6c4f0d0a8bbb34586d
diff --git a/docs/capability-seams.md b/docs/capability-seams.md
index 1e7e6e39d3..5c3ba40df3 100644
--- a/docs/capability-seams.md
+++ b/docs/capability-seams.md
@@ -11,7 +11,6 @@ flowchart LR
svc_attachments["ctx.attachments
Durable binary attachment storage"]
pkg_attachment_local["attachment-local"]
pkg_api_session_controller["api-session-controller"]
- pkg_host_apiproxy["host-apiproxy"]
pkg_tool_fs["tool-fs"]
pkg_llm_pi_ai["llm-pi-ai"]
pkg_llm_deepseek["llm-deepseek"]
@@ -38,6 +37,8 @@ flowchart LR
pkg_invariants["invariants"]
pkg_message_feedback["message-feedback"]
svc_sessionController["ctx.sessionController
Host Session Remote controller"]
+ svc_sessionFileReferences["ctx.sessionFileReferences
Session-addressed file-reference Remote adapter"]
+ svc_sessionSkillCatalog["ctx.sessionSkillCatalog
Session-addressed skill Remote adapter"]
pkg_api_settings_controller["api-settings-controller"]
svc_credentialsController["ctx.credentialsController
Host credential-surface Remote controller"]
svc_settingsController["ctx.settingsController
Host settings-surface Remote controller"]
@@ -112,6 +113,7 @@ flowchart LR
svc_sessionProjections["ctx.sessionProjections
Session projection units"]
pkg_session_projection_cache["session-projection-cache"]
svc_sessionProjectionCache["ctx.sessionProjectionCache
Persisted projection cache"]
+ pkg_subagent["subagent"]
pkg_skill["skill"]
svc_skills["ctx.skills
Skill provider registry"]
pkg_skill_badge["skill-badge"]
@@ -166,7 +168,6 @@ flowchart LR
pkg_fs_observation_policy["fs-observation-policy"]
pkg_compaction["compaction"]
svc_compaction["ctx.compaction
Compaction seam"]
- pkg_subagent["subagent"]
svc_subagents["ctx.subagents
Subagent provider and continuation service"]
pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
pkg_subagent_fork_in_process["subagent-fork-in-process"]
@@ -177,6 +178,8 @@ flowchart LR
svc_agentTeams["ctx.agentTeams
Agent Teams coordination domain"]
pkg_experimental_tool_agent_team["experimental-tool-agent-team"]
pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"]
+ pkg_inspector["inspector"]
+ svc_inspector["ctx.inspector
Cross-realm runtime inspection"]
pkg_jobs["jobs"]
svc_jobs["ctx.jobs
Background job registry"]
pkg_jobs_local["jobs-local"]
@@ -211,7 +214,6 @@ flowchart LR
pkg_lsp["lsp"]
svc_lsp["ctx.lsp
Language-server navigation seam"]
pkg_tool_lsp["tool-lsp"]
- svc_apiProxy["ctx.apiProxy
Host API dispatch"]
pkg_cordis_host_runner["cordis-host-runner"]
svc_dynamicCordisRunner["ctx.dynamicCordisRunner
Dynamic Cordis package host runner"]
svc_cordisInspect["ctx.cordisInspect
Dynamic Cordis inspect registry"]
@@ -221,6 +223,8 @@ flowchart LR
pkg_agent_presets --> svc_agentPresets
pkg_api_gateway --> svc_typertGateway
pkg_api_session_controller --> svc_sessionController
+ pkg_api_session_controller --> svc_sessionFileReferences
+ pkg_api_session_controller --> svc_sessionSkillCatalog
pkg_api_settings_controller --> svc_credentialsController
pkg_api_settings_controller --> svc_settingsController
pkg_api_workspace_controller --> svc_directoryPickerController
@@ -251,11 +255,11 @@ flowchart LR
pkg_fs_local --> svc_fs
pkg_fs_sandbox --> svc_fs
pkg_goal --> svc_goals
- pkg_host_apiproxy --> svc_apiProxy
pkg_host_directory_picker --> svc_directoryPicker
pkg_host_directory_picker_browse --> svc_directoryPicker
pkg_host_directory_picker_native --> svc_directoryPicker
pkg_host_webserver --> svc_webServer
+ pkg_inspector --> svc_inspector
pkg_invariants --> svc_invariants
pkg_jobs --> svc_jobs
pkg_jobs_local --> svc_jobs
@@ -329,20 +333,18 @@ flowchart LR
pkg_workflow --> svc_workflowEngine
pkg_workflow_worker_thread --> svc_workflowEngine
pkg_workspace --> svc_workspaceRegistry
+ svc_agentDefaultModel --> pkg_api_session_controller
svc_agentDefaultModel --> pkg_headless
- svc_agentDefaultModel --> pkg_host_apiproxy
svc_agentLoop --> pkg_agent_spine_demo
svc_agentTeams --> pkg_experimental_client_ui_agent_team
svc_agentTeams --> pkg_experimental_tool_agent_team
svc_agents --> pkg_acp
svc_agents --> pkg_agent_loop
svc_agents --> pkg_subagent_in_process_driver
- svc_apiProxy --> pkg_client_connection
svc_approval --> pkg_acp
svc_approval --> pkg_tool_bash
svc_approval --> pkg_tools
svc_attachments --> pkg_api_session_controller
- svc_attachments --> pkg_host_apiproxy
svc_attachments --> pkg_llm_deepseek
svc_attachments --> pkg_llm_pi_ai
svc_attachments --> pkg_tool_fs
@@ -351,7 +353,7 @@ flowchart LR
svc_codeRuntime --> pkg_tools
svc_compaction --> pkg_compaction_basic
svc_cordisInspect --> pkg_tool_cordis
- svc_credentials --> pkg_host_apiproxy
+ svc_credentials --> pkg_api_settings_controller
svc_credentials --> pkg_llm_deepseek
svc_credentials --> pkg_llm_pi_ai
svc_deepseekLlmApiExtensions --> pkg_llm_deepseek
@@ -359,6 +361,7 @@ flowchart LR
svc_dynamicCordisRunner --> pkg_tool_cordis
svc_e2b --> pkg_fs_e2b
svc_e2b --> pkg_subprocess_e2b
+ svc_fileReferences --> pkg_api_session_controller
svc_fs --> pkg_tool_fs
svc_invariants --> pkg_agent
svc_invariants --> pkg_agent_loop
@@ -376,7 +379,6 @@ flowchart LR
svc_sandboxPolicy --> pkg_bash_sandbox
svc_sandboxPolicy --> pkg_fs_sandbox
svc_sandboxPolicy --> pkg_terminal_bash
- svc_sessionController --> pkg_host_apiproxy
svc_sessionPersistence --> pkg_agent_loop
svc_sessionPersistence --> pkg_hooks_claude_code
svc_sessionPersistence --> pkg_hooks_codex
@@ -384,8 +386,11 @@ flowchart LR
svc_sessionPersistence --> pkg_session_query
svc_sessionPersistence --> pkg_session_query_sqlite
svc_sessionPersistence --> pkg_tool_bash
- svc_sessionProjectionCache --> pkg_host_apiproxy
- svc_sessionProjections --> pkg_host_apiproxy
+ svc_sessionProjectionCache --> pkg_api_session_controller
+ svc_sessionProjectionCache --> pkg_session_query
+ svc_sessionProjectionCache --> pkg_session_reference
+ svc_sessionProjectionCache --> pkg_subagent
+ svc_sessionProjections --> pkg_api_session_controller
svc_sessionProjections --> pkg_session_title
svc_sessionProjections --> pkg_tool_todo
svc_sessionQuery --> pkg_session_reference
@@ -398,7 +403,7 @@ flowchart LR
svc_sessions --> pkg_session_query
svc_sessions --> pkg_session_query_sqlite
svc_sessions --> pkg_subagent_in_process_driver
- svc_settings --> pkg_host_apiproxy
+ svc_settings --> pkg_api_settings_controller
svc_settings --> pkg_llm_deepseek
svc_settings --> pkg_llm_pi_ai
svc_shell --> pkg_hooks_claude_code
@@ -458,13 +463,15 @@ flowchart LR
| ctx key | Role | Owner | Implementations | Direct consumers | Companion plugins | Note |
| --- | --- | --- | --- | --- | --- | --- |
-| `ctx.attachments` | `seam` | [`attachment`](../packages/attachment/attachment) | [`attachment-local`](../packages/attachment/attachment-local) | [`api-session-controller`](../packages/api/session-controller), [`host-apiproxy`](../packages/host/apiproxy), [`tool-fs`](../packages/fs/tool-fs), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-deepseek`](../packages/llm/llm-deepseek) | - | The host commits accepted images before session events; provider adapters resolve authorized durable references into provider-native content. |
+| `ctx.attachments` | `seam` | [`attachment`](../packages/attachment/attachment) | [`attachment-local`](../packages/attachment/attachment-local) | [`api-session-controller`](../packages/api/session-controller), [`tool-fs`](../packages/fs/tool-fs), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-deepseek`](../packages/llm/llm-deepseek) | - | The host commits accepted images before session events; provider adapters resolve authorized durable references into provider-native content. |
| `ctx.llm` | `seam` | [`llm`](../packages/llm/llm) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-replay`](../packages/test-support/llm-replay) | [`agent-loop`](../packages/core/agent-loop), [`compaction-basic`](../packages/compaction/compaction-basic) | - | Adapters register provider implementations; the loop and compaction call the provider-neutral stream service. |
| `ctx.deepseekLlmApiExtensions` | `seam` | [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions) | [`session-log-deepseek`](../packages/session/session-log-deepseek), [`plugin-package-inventory-deepseek`](../packages/llm/plugin-package-inventory-deepseek) | [`llm-deepseek`](../packages/llm/llm-deepseek) | - | Plugins prepare independent top-level fields; the official adapter merges them and commits their delivery state after HTTP acceptance. |
| `ctx.tokenMeter` | `core` | [`token-meter`](../packages/llm/token-meter) | - | [`compaction-basic`](../packages/compaction/compaction-basic) | - | Owns isolated per-session replay folds; pressure consumers share immutable revisioned measurements. |
| `ctx.toolResultPruner` | `core` | [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | - | [`compaction-basic`](../packages/compaction/compaction-basic) | - | Rewrites oversized current tool results through replayable single-node surface replacements before summary compaction. |
| `ctx.sessions` | `core` | [`session`](../packages/core/session) | - | [`agent-loop`](../packages/core/agent-loop), [`agent`](../packages/core/agent), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback) | - | Owns append-only Session instances and emits the durable session event feed. |
-| `ctx.sessionController` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | [`host-apiproxy`](../packages/host/apiproxy) | - | Owns Session commands, cold reads, durable-event following, live control state, and Agent activation policy; apiProxy reuses its inspection and Agent-resolution operations for Session-aware domains. |
+| `ctx.sessionController` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | - | - | Owns Session commands, cold reads, durable-event following, live control state, model catalogs, workspace opening, and Agent activation policy. |
+| `ctx.sessionFileReferences` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | - | - | Delegates file-reference discovery through the Session Controller's established Agent lookup policy. |
+| `ctx.sessionSkillCatalog` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | - | - | Lists the Session composition's user-invocable skills without activating a cold Agent. |
| `ctx.credentialsController` | `core` | [`api-settings-controller`](../packages/api/settings-controller) | - | - | - | Projects the credential-reference seam onto the generated Remote namespace: batch fan-out, view projection, and refusal mapping live here, not on the seam Definition. |
| `ctx.settingsController` | `core` | [`api-settings-controller`](../packages/api/settings-controller) | - | - | - | Projects the user-settings seam onto the generated Remote namespace: the read is always redacted and every refusal is classified here, not on the seam Definition. |
| `ctx.workspaceController` | `core` | [`api-workspace-controller`](../packages/api/workspace-controller) | - | - | - | Owns Workspace commands and reconnect-safe Workspace state delivery through the generated Remote namespace. |
@@ -473,9 +480,9 @@ flowchart LR
| `ctx.typert` | `core` | [`typert-registry`](../packages/typert/registry) | - | [`typert-loader`](../packages/typert/loader), [`api-gateway`](../packages/api/gateway) | - | Plugins register live zod contributions directly or through dsh-typert-loader; the API gateway consumes invocation descriptors and providers, while other runtime consumers query schemas and reflection metadata at their own edges. |
| `ctx.typertGateway` | `core` | [`api-gateway`](../packages/api/gateway) | - | - | - | Associates generated Remote descriptors with live Cordis services, resolves registered identities, and exposes unary calls through the shared Connection RPC carrier. |
| `ctx.sessionPersistence` | `seam` | [`session-persistence`](../packages/session/session-persistence) | [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-persistence-sqlite`](../packages/session/session-persistence-sqlite) | [`agent-loop`](../packages/core/agent-loop), [`tool-bash`](../packages/shell/tool-bash), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`message-feedback`](../packages/feedback/message-feedback) | - | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. |
-| `ctx.settings` | `seam` | [`settings`](../packages/settings/settings) | [`settings-file`](../packages/settings/settings-file) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`host-apiproxy`](../packages/host/apiproxy) | - | Plugins register namespace schemas and resolve layered values; providers store the raw document. The LLM adapters register their entry config as the composition base under the user section; the web gateway serves redacted layered descriptors and writes the user layer. |
+| `ctx.settings` | `seam` | [`settings`](../packages/settings/settings) | [`settings-file`](../packages/settings/settings-file) | [`api-settings-controller`](../packages/api/settings-controller), [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai) | - | Plugins register namespace schemas and resolve layered values; providers store the raw document. The LLM adapters register their entry config as the composition base under the user section; the settings controller serves redacted layered descriptors and writes the user layer. |
| `ctx.subagentModelSelection` | `core` | [`tool-subagent`](../packages/subagent/tool-subagent) | - | [`tool-subagent`](../packages/subagent/tool-subagent) | - | Owns the default-off settings namespace that Agent-scoped delegation tools sample when composing a new top-level Session. |
-| `ctx.credentials` | `seam` | [`credentials`](../packages/credentials/credentials) | [`credentials-local`](../packages/credentials/credentials-local) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`host-apiproxy`](../packages/host/apiproxy) | - | Configuration carries references to secrets; providers own the values. Consumers resolve per operation, so a rotated credential reaches the very next request; the web gateway exposes value-free views and write-only storage. |
+| `ctx.credentials` | `seam` | [`credentials`](../packages/credentials/credentials) | [`credentials-local`](../packages/credentials/credentials-local) | [`api-settings-controller`](../packages/api/settings-controller), [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai) | - | Configuration carries references to secrets; providers own the values. Consumers resolve per operation, so a rotated credential reaches the very next request; the settings controller exposes value-free views and write-only storage. |
| `ctx.authorization` | `seam` | [`authorization`](../packages/credentials/authorization) | - | [`llm-pi-ai`](../packages/llm/llm-pi-ai) | - | Flows are registered by the plugin that knows how to obtain one credential and keyed by the record they write; the seam owns the conversation and the one-attempt-per-key lifecycle, never the protocol. |
| `ctx.sessionTelemetry` | `seam` | [`session-telemetry`](../packages/session/session-telemetry) | [`session-telemetry-otel`](../packages/session/session-telemetry-otel) | - | - | The seam captures, redacts, and hands session records to one backend; nothing else consumes the service — its output leaves the process. |
| `ctx.storage` | `seam` | [`storage`](../packages/storage/storage) | [`storage-json`](../packages/storage/storage-json), [`storage-sqlite`](../packages/storage/storage-sqlite) | [`storage-domain`](../packages/storage/storage-domain) | - | Backends register side by side under names; data forms (domain first) mount on the hub and translate typed operations into opaque KV-unit primitives. |
@@ -483,20 +490,20 @@ flowchart LR
| `ctx.messageFeedback` | `core` | [`message-feedback`](../packages/feedback/message-feedback) | - | - | - | Owns local per-assistant-message feedback, lifecycle and target validation, per-item compare-and-set, and the Host unary Remote contract without entering Session history or telemetry. |
| `ctx.workspaceRegistry` | `core` | [`workspace`](../packages/workspace/workspace) | - | [`api-workspace-controller`](../packages/api/workspace-controller), [`api-session-controller`](../packages/api/session-controller) | - | Owns WorkspaceId-branded records over the domain facility; stable sessionIds accounts drive Host RPC and GUI projections. |
| `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | [`session-reference`](../packages/context/session-reference), [`tool-session-query`](../packages/session-query/tool-session-query) | - | The interface supplies exact reads, filters, and traces; its concrete backend adds full-text reconciliation, ranking, snippets, and cursor generations, while the model consumer owns workspace authority and cursor-free rendering. |
-| `ctx.fileReferences` | `seam` | [`file-reference`](../packages/context/file-reference) | [`file-reference-local`](../packages/context/file-reference-local) | - | - | The interface returns path-only completion candidates within the addressed Agent cwd through its unary Remote contract; providers own namespace access and ranking without reading file contents. |
+| `ctx.fileReferences` | `seam` | [`file-reference`](../packages/context/file-reference) | [`file-reference-local`](../packages/context/file-reference-local) | [`api-session-controller`](../packages/api/session-controller) | - | The interface returns path-only completion candidates within an Agent cwd; providers own namespace access and ranking without reading file contents. |
| `ctx.sessionReferenceResolver` | `core` | [`session-reference`](../packages/context/session-reference) | - | - | - | Projects bounded current-surface conversation snapshots into durable untrusted message context; host adapters own mention syntax. |
| `ctx.sessionTitle` | `seam` | [`session-title`](../packages/session/session-title) | [`session-title-first-prompt-llm`](../packages/session/session-title-first-prompt-llm), [`session-title-all-prompts-llm`](../packages/session/session-title-all-prompts-llm) | - | - | Owns the deterministic fallback, latest-title fold, and sole optional asynchronous provider registration. |
| `ctx.systemPrompt` | `core` | [`system-prompt`](../packages/core/system-prompt) | - | [`agent-loop`](../packages/core/agent-loop), [`tools`](../packages/core/tools), [`tool-fs`](../packages/fs/tool-fs), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-web`](../packages/web/tool-web) | - | Collects prompt sections and model-facing tool schemas for each step. |
-| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/interaction/tool-ask-user), [`tool-bash`](../packages/shell/tool-bash), [`tool-cordis`](../packages/extensions/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web) | - | Registers capabilities, owns Code Mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation. |
+| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/interaction/tool-ask-user), [`tool-bash`](../packages/shell/tool-bash), [`tool-cordis`](../packages/extensions/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web) | - | Registers capabilities, owns PTC mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation. |
| `ctx.userQuestions` | `seam` | [`user-questions`](../packages/interaction/user-questions) | - | [`tool-ask-user`](../packages/interaction/tool-ask-user) | - | UI front ends provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise. |
| `ctx.planMode` | `core` | [`plan-mode`](../packages/plan/plan-mode) | - | - | - | Folds logged plan/mode state, flushes user selections at turn boundaries, renders deployment-owned guidance, registers /plan, and keeps the plan-exit schema stable across transitions. |
| `ctx.agentPresets` | `core` | [`agent-presets`](../packages/preset/agent-presets) | - | - | - | Discovers preset directories over trusted and user-authored roots and mounts one preset cordis.yml under an agent scope during creation, rejecting a row that never activates or that publishes into the root service realm. |
| `ctx.commands` | `core` | [`commands`](../packages/interaction/commands) | - | - | - | Plugins register direct human commands without sending invocations to the model. |
-| `ctx.sessionProjections` | `core` | [`session-projection`](../packages/session/session-projection) | - | [`tool-todo`](../packages/todo/tool-todo), [`session-title`](../packages/session/session-title), [`host-apiproxy`](../packages/host/apiproxy) | - | Domains register state-driven fold units; the eager drive keeps per-session watermark states and api-proxy serves baselines and pushes changed values. |
-| `ctx.sessionProjectionCache` | `core` | [`session-projection-cache`](../packages/session/session-projection-cache) | - | [`host-apiproxy`](../packages/host/apiproxy) | - | Durably checkpoints projection unit states per session (throttled + turn/end/detach mandatory points) and serves the cold-read ladder: cache row + persistence tail replay, so listings never load full logs. |
+| `ctx.sessionProjections` | `core` | [`session-projection`](../packages/session/session-projection) | - | [`api-session-controller`](../packages/api/session-controller), [`tool-todo`](../packages/todo/tool-todo), [`session-title`](../packages/session/session-title) | - | Domains register state-driven fold units; the eager drive keeps per-session watermark states and the Session controller serves baselines and pushes changed values. |
+| `ctx.sessionProjectionCache` | `core` | [`session-projection-cache`](../packages/session/session-projection-cache) | - | [`api-session-controller`](../packages/api/session-controller), [`session-query`](../packages/session-query/session-query), [`session-reference`](../packages/context/session-reference), [`subagent`](../packages/subagent/subagent) | - | Durably checkpoints projection unit states per session (throttled + turn/end/detach mandatory points) and serves the cold-read ladder: cache row + persistence tail replay, so listings never load full logs. |
| `ctx.skills` | `seam` | [`skill`](../packages/skill/skill) | [`skill-badge`](../packages/skill/skill-badge), [`skill-filesystem`](../packages/skill/skill-filesystem) | [`tool-skill`](../packages/skill/tool-skill) | - | Merges provider skill catalogs; tool-skill renders the session-prefix catalog and loads complete skill bodies. |
| `ctx.agents` | `core` | [`agent`](../packages/core/agent) | - | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/acp/acp), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) | - | Owns live Agent handles, the create/resume factory seam, and process-local initiator propagation. |
-| `ctx.agentDefaultModel` | `core` | [`agent-default-model`](../packages/core/agent-default-model) | - | [`headless`](../packages/bundle/headless), [`host-apiproxy`](../packages/host/apiproxy) | - | Layers the default ModelSelection through settings so direct and Host-backed Agent entry points share one state owner. |
+| `ctx.agentDefaultModel` | `core` | [`agent-default-model`](../packages/core/agent-default-model) | - | [`api-session-controller`](../packages/api/session-controller), [`headless`](../packages/bundle/headless) | - | Layers the default ModelSelection through settings so direct and Host-backed Agent entry points share one state owner. |
| `ctx.agentLoop` | `bundle` | [`agent-loop`](../packages/core/agent-loop) | - | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | - | The one concrete loop plugin; extension packages depend on dsh-agent events and services, not on this package. |
| `ctx.goals` | `core` | [`goal`](../packages/goal/goal) | - | - | - | Folds revisioned objective state from the session log and keeps live continuation activation process-local. |
| `ctx.e2b` | `core` | [`e2b`](../packages/e2b/e2b) | - | [`fs-e2b`](../packages/e2b/fs-e2b), [`subprocess-e2b`](../packages/e2b/subprocess-e2b) | - | Owns one shared E2B SDK handle, remote working directory, and final sandbox disposition so both fundamental E2B providers inhabit the same Linux runtime. |
@@ -508,11 +515,12 @@ flowchart LR
| `ctx.sandboxPolicy` | `core` | [`sandbox-policy`](../packages/sandbox/sandbox-policy) | - | [`bash-sandbox`](../packages/shell/bash-sandbox), [`fs-sandbox`](../packages/fs/fs-sandbox), [`terminal-bash`](../packages/terminal/terminal-bash) | - | The one home for the deployment default mode + workspace root; only the sandboxed executor and provider read the service (the tool layers use the pure `sandbox/mode` fold it also exports). Both enforcing families read it so bash and fs cannot confine to different roots. |
| `ctx.approval` | `seam` | [`user-approval`](../packages/interaction/user-approval) | - | [`tools`](../packages/core/tools), [`tool-bash`](../packages/shell/tool-bash), [`acp`](../packages/acp/acp) | - | One-shot permission decisions dispatched over the `approval/request` waterfall; answerers are listeners (the ACP bridge for its own agents), absence fails closed to `unavailable`. |
| `ctx.permissionPresets` | `core` | [`permission-presets`](../packages/interaction/permission-presets) | - | - | - | User-facing preset table (`workspace-write`/`danger-full-access`) bundling the sandbox-mode and approval-policy knobs; a switch writes one `permission/preset` event through to both knob events. |
-| `ctx.codeRuntime` | `seam` | [`code-runtime`](../packages/code-runtime/code-runtime) | [`code-runtime-worker-thread`](../packages/code-runtime/code-runtime-worker-thread) | [`tools`](../packages/core/tools) | - | Runs one model-written program against host-provided async bindings; backends differ by substrate and language (the tool registry consumes it for Code Mode). |
+| `ctx.codeRuntime` | `seam` | [`code-runtime`](../packages/code-runtime/code-runtime) | [`code-runtime-worker-thread`](../packages/code-runtime/code-runtime-worker-thread) | [`tools`](../packages/core/tools) | - | Runs one model-written program against host-provided async bindings; backends differ by substrate and language (the tool registry consumes it for PTC mode). |
| `ctx.fs` | `seam` | [`fs`](../packages/fs/fs) | [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox), [`fs-e2b`](../packages/e2b/fs-e2b) | [`tool-fs`](../packages/fs/tool-fs) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) | tool-fs executes read/write/edit through ctx.fs; fs-sandbox fences mutations by the shared sandbox mode; fs-observation-policy contributes observed-state checks through the fs/* event gate. |
| `ctx.compaction` | `seam` | [`compaction`](../packages/compaction/compaction) | [`compaction-basic`](../packages/compaction/compaction-basic) | [`compaction-basic`](../packages/compaction/compaction-basic) | - | The basic backend consumes post-step pressure and request-error recovery events; there is no model-facing compact tool. |
| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/workflow/tool-ralph) | - | Providers implement transports; the service also owns optional Activation-based continuation orchestration, tool-subagent selects one-shot or continuable delegation, tool-subagent-control delivers follow-ups, and tool-ralph requires one fresh structured-output route. |
| `ctx.agentTeams` | `core` | [`experimental-agent-team`](../packages/experimental/agent-team) | - | [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team), [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | - | Owns the implicit-root roster, durable peer mailbox, shared task DAG, continuable-child lifecycle, and generated Team Remote methods; tool-agent-team contributes model controls and client-ui-agent-team mounts the browser contribution. |
+| `ctx.inspector` | `core` | `inspector` | - | - | - | Owns the Worker-hosted CDP target and the transport-independent Host and Client observation and Cordis-tree query API. |
| `ctx.jobs` | `seam` | [`jobs`](../packages/jobs/jobs) | [`jobs-local`](../packages/jobs/jobs-local) | [`tool-bash`](../packages/shell/tool-bash), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-jobs`](../packages/jobs/tool-jobs) | - | Producers (background bash, PTY sends, and subagent delegations) register running work; tool-jobs is the model-facing controller that reads, lists, and kills it; jobs-local is the process-local registry. |
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names. |
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | The backend saves oversized tool text and returns a model-facing locator plus retrieval hint; spill-policy is the tools/post-execute consumer that decides when to spill. |
@@ -522,7 +530,6 @@ flowchart LR
| `ctx.workflowEngine` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | [`tool-workflow`](../packages/workflow/tool-workflow), [`tool-ralph`](../packages/workflow/tool-ralph) | - | One engine per context, as in bash, with no named-provider registry; the general workflow and fixed Ralph consumers start runs whose agent() calls fan out through ctx.subagents. |
| `ctx.webhookRuntime` | `core` | [`webhook`](../packages/webhook/webhook) | - | [`webhook-github`](../packages/webhook/webhook-github) | - | Provider adapters dispatch authenticated deliveries; trusted plugins register independent process-local rules, and the runtime turns non-null results into ordinary Workspace-backed Sessions without delivery or completion state. |
| `ctx.lsp` | `seam` | [`lsp`](../packages/lsp/lsp) | [`lsp-stdio`](../packages/lsp/lsp-stdio) | [`tool-lsp`](../packages/lsp/tool-lsp) | - | Provider registration and selection plus normalized query execution over exactly four operations; the seam offers no protocol escape hatch, so a backend translates into the normalized request and result. |
-| `ctx.apiProxy` | `core` | [`host-apiproxy`](../packages/host/apiproxy) | - | [`client-connection`](../packages/client/connection) | - | The transport-agnostic host gateway face: it dispatches browser API calls, and each open host stream subscribes to the events it forwards rather than being pushed to through a broadcast verb. |
| `ctx.dynamicCordisRunner` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | Owns the in-memory definition registry, the vm sandbox for host halves, and the request-run round trip; browser pages reach the same service over the wire through its remote namespace. |
| `ctx.cordisInspect` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | Registers host inspect providers, mirrors the client provider manifest, and routes client queries through the dynamic Cordis transport. |
diff --git a/docs/capability-seams.zh.md b/docs/capability-seams.zh.md
index e33a1e6da7..47402e1b6d 100644
--- a/docs/capability-seams.zh.md
+++ b/docs/capability-seams.zh.md
@@ -13,7 +13,6 @@ flowchart LR
svc_attachments["ctx.attachments
Durable binary attachment storage"]
pkg_attachment_local["attachment-local"]
pkg_api_session_controller["api-session-controller"]
- pkg_host_apiproxy["host-apiproxy"]
pkg_tool_fs["tool-fs"]
pkg_llm_pi_ai["llm-pi-ai"]
pkg_llm_deepseek["llm-deepseek"]
@@ -40,6 +39,8 @@ flowchart LR
pkg_invariants["invariants"]
pkg_message_feedback["message-feedback"]
svc_sessionController["ctx.sessionController
Host Session Remote controller"]
+ svc_sessionFileReferences["ctx.sessionFileReferences
Session-addressed file-reference Remote adapter"]
+ svc_sessionSkillCatalog["ctx.sessionSkillCatalog
Session-addressed skill Remote adapter"]
pkg_api_settings_controller["api-settings-controller"]
svc_credentialsController["ctx.credentialsController
Host credential-surface Remote controller"]
svc_settingsController["ctx.settingsController
Host settings-surface Remote controller"]
@@ -114,6 +115,7 @@ flowchart LR
svc_sessionProjections["ctx.sessionProjections
Session projection units"]
pkg_session_projection_cache["session-projection-cache"]
svc_sessionProjectionCache["ctx.sessionProjectionCache
Persisted projection cache"]
+ pkg_subagent["subagent"]
pkg_skill["skill"]
svc_skills["ctx.skills
Skill provider registry"]
pkg_skill_badge["skill-badge"]
@@ -168,7 +170,6 @@ flowchart LR
pkg_fs_observation_policy["fs-observation-policy"]
pkg_compaction["compaction"]
svc_compaction["ctx.compaction
Compaction seam"]
- pkg_subagent["subagent"]
svc_subagents["ctx.subagents
Subagent provider and continuation service"]
pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
pkg_subagent_fork_in_process["subagent-fork-in-process"]
@@ -179,6 +180,8 @@ flowchart LR
svc_agentTeams["ctx.agentTeams
Agent Teams coordination domain"]
pkg_experimental_tool_agent_team["experimental-tool-agent-team"]
pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"]
+ pkg_inspector["inspector"]
+ svc_inspector["ctx.inspector
Cross-realm runtime inspection"]
pkg_jobs["jobs"]
svc_jobs["ctx.jobs
Background job registry"]
pkg_jobs_local["jobs-local"]
@@ -213,7 +216,6 @@ flowchart LR
pkg_lsp["lsp"]
svc_lsp["ctx.lsp
Language-server navigation seam"]
pkg_tool_lsp["tool-lsp"]
- svc_apiProxy["ctx.apiProxy
Host API dispatch"]
pkg_cordis_host_runner["cordis-host-runner"]
svc_dynamicCordisRunner["ctx.dynamicCordisRunner
Dynamic Cordis package host runner"]
svc_cordisInspect["ctx.cordisInspect
Dynamic Cordis inspect registry"]
@@ -223,6 +225,8 @@ flowchart LR
pkg_agent_presets --> svc_agentPresets
pkg_api_gateway --> svc_typertGateway
pkg_api_session_controller --> svc_sessionController
+ pkg_api_session_controller --> svc_sessionFileReferences
+ pkg_api_session_controller --> svc_sessionSkillCatalog
pkg_api_settings_controller --> svc_credentialsController
pkg_api_settings_controller --> svc_settingsController
pkg_api_workspace_controller --> svc_directoryPickerController
@@ -253,11 +257,11 @@ flowchart LR
pkg_fs_local --> svc_fs
pkg_fs_sandbox --> svc_fs
pkg_goal --> svc_goals
- pkg_host_apiproxy --> svc_apiProxy
pkg_host_directory_picker --> svc_directoryPicker
pkg_host_directory_picker_browse --> svc_directoryPicker
pkg_host_directory_picker_native --> svc_directoryPicker
pkg_host_webserver --> svc_webServer
+ pkg_inspector --> svc_inspector
pkg_invariants --> svc_invariants
pkg_jobs --> svc_jobs
pkg_jobs_local --> svc_jobs
@@ -331,20 +335,18 @@ flowchart LR
pkg_workflow --> svc_workflowEngine
pkg_workflow_worker_thread --> svc_workflowEngine
pkg_workspace --> svc_workspaceRegistry
+ svc_agentDefaultModel --> pkg_api_session_controller
svc_agentDefaultModel --> pkg_headless
- svc_agentDefaultModel --> pkg_host_apiproxy
svc_agentLoop --> pkg_agent_spine_demo
svc_agentTeams --> pkg_experimental_client_ui_agent_team
svc_agentTeams --> pkg_experimental_tool_agent_team
svc_agents --> pkg_acp
svc_agents --> pkg_agent_loop
svc_agents --> pkg_subagent_in_process_driver
- svc_apiProxy --> pkg_client_connection
svc_approval --> pkg_acp
svc_approval --> pkg_tool_bash
svc_approval --> pkg_tools
svc_attachments --> pkg_api_session_controller
- svc_attachments --> pkg_host_apiproxy
svc_attachments --> pkg_llm_deepseek
svc_attachments --> pkg_llm_pi_ai
svc_attachments --> pkg_tool_fs
@@ -353,7 +355,7 @@ flowchart LR
svc_codeRuntime --> pkg_tools
svc_compaction --> pkg_compaction_basic
svc_cordisInspect --> pkg_tool_cordis
- svc_credentials --> pkg_host_apiproxy
+ svc_credentials --> pkg_api_settings_controller
svc_credentials --> pkg_llm_deepseek
svc_credentials --> pkg_llm_pi_ai
svc_deepseekLlmApiExtensions --> pkg_llm_deepseek
@@ -361,6 +363,7 @@ flowchart LR
svc_dynamicCordisRunner --> pkg_tool_cordis
svc_e2b --> pkg_fs_e2b
svc_e2b --> pkg_subprocess_e2b
+ svc_fileReferences --> pkg_api_session_controller
svc_fs --> pkg_tool_fs
svc_invariants --> pkg_agent
svc_invariants --> pkg_agent_loop
@@ -378,7 +381,6 @@ flowchart LR
svc_sandboxPolicy --> pkg_bash_sandbox
svc_sandboxPolicy --> pkg_fs_sandbox
svc_sandboxPolicy --> pkg_terminal_bash
- svc_sessionController --> pkg_host_apiproxy
svc_sessionPersistence --> pkg_agent_loop
svc_sessionPersistence --> pkg_hooks_claude_code
svc_sessionPersistence --> pkg_hooks_codex
@@ -386,8 +388,11 @@ flowchart LR
svc_sessionPersistence --> pkg_session_query
svc_sessionPersistence --> pkg_session_query_sqlite
svc_sessionPersistence --> pkg_tool_bash
- svc_sessionProjectionCache --> pkg_host_apiproxy
- svc_sessionProjections --> pkg_host_apiproxy
+ svc_sessionProjectionCache --> pkg_api_session_controller
+ svc_sessionProjectionCache --> pkg_session_query
+ svc_sessionProjectionCache --> pkg_session_reference
+ svc_sessionProjectionCache --> pkg_subagent
+ svc_sessionProjections --> pkg_api_session_controller
svc_sessionProjections --> pkg_session_title
svc_sessionProjections --> pkg_tool_todo
svc_sessionQuery --> pkg_session_reference
@@ -400,7 +405,7 @@ flowchart LR
svc_sessions --> pkg_session_query
svc_sessions --> pkg_session_query_sqlite
svc_sessions --> pkg_subagent_in_process_driver
- svc_settings --> pkg_host_apiproxy
+ svc_settings --> pkg_api_settings_controller
svc_settings --> pkg_llm_deepseek
svc_settings --> pkg_llm_pi_ai
svc_shell --> pkg_hooks_claude_code
@@ -460,13 +465,15 @@ flowchart LR
| ctx 键 | 角色 | 所属包 | 实现 | 直接消费方 | 配套插件 | 说明 |
| --- | --- | --- | --- | --- | --- | --- |
-| `ctx.attachments` | `seam` | [`attachment`](../packages/attachment/attachment) | [`attachment-local`](../packages/attachment/attachment-local) | [`api-session-controller`](../packages/api/session-controller), [`host-apiproxy`](../packages/host/apiproxy), [`tool-fs`](../packages/fs/tool-fs), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-deepseek`](../packages/llm/llm-deepseek) | - | 宿主会在会话事件之前提交已接受的图片;提供方适配器将已授权的持久引用解析为提供方原生内容。 |
+| `ctx.attachments` | `seam` | [`attachment`](../packages/attachment/attachment) | [`attachment-local`](../packages/attachment/attachment-local) | [`api-session-controller`](../packages/api/session-controller), [`tool-fs`](../packages/fs/tool-fs), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-deepseek`](../packages/llm/llm-deepseek) | - | 宿主会在会话事件之前提交已接受的图片;提供方适配器将已授权的持久引用解析为提供方原生内容。 |
| `ctx.llm` | `seam` | [`llm`](../packages/llm/llm) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-replay`](../packages/test-support/llm-replay) | [`agent-loop`](../packages/core/agent-loop), [`compaction-basic`](../packages/compaction/compaction-basic) | - | 适配器注册提供方实现;agent loop(智能体循环)与压缩功能调用提供方无关的流服务。 |
| `ctx.deepseekLlmApiExtensions` | `seam` | [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions) | [`session-log-deepseek`](../packages/session/session-log-deepseek), [`plugin-package-inventory-deepseek`](../packages/llm/plugin-package-inventory-deepseek) | [`llm-deepseek`](../packages/llm/llm-deepseek) | - | 插件准备彼此独立的顶层字段;官方适配器会合并这些字段,并在 HTTP 接受后提交其交付状态。 |
| `ctx.tokenMeter` | `core` | [`token-meter`](../packages/llm/token-meter) | - | [`compaction-basic`](../packages/compaction/compaction-basic) | - | 拥有按会话隔离的回放折叠区;压力消费方共享不可变且带修订版本的测量结果。 |
| `ctx.toolResultPruner` | `core` | [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | - | [`compaction-basic`](../packages/compaction/compaction-basic) | - | 在摘要压缩前,通过可回放的单节点表层替换来改写过大的当前工具结果。 |
| `ctx.sessions` | `core` | [`session`](../packages/core/session) | - | [`agent-loop`](../packages/core/agent-loop), [`agent`](../packages/core/agent), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback) | - | 拥有仅追加的 Session 实例,并发出持久的会话事件流。 |
-| `ctx.sessionController` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | [`host-apiproxy`](../packages/host/apiproxy) | - | 负责 Session 命令、冷读取、持久事件跟随、实时控制状态与 Agent 激活策略;apiProxy 在需要 Session 上下文的领域中复用其检查和 Agent 解析操作。 |
+| `ctx.sessionController` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | - | - | 负责 Session 命令、冷读取、持久事件跟随、实时控制状态、模型目录、workspace 打开与 Agent 激活策略。 |
+| `ctx.sessionFileReferences` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | - | - | 通过 Session Controller 的既有 Agent lookup 策略委托文件引用发现。 |
+| `ctx.sessionSkillCatalog` | `core` | [`api-session-controller`](../packages/api/session-controller) | - | - | - | 在不激活冷 Agent 的前提下列出 Session 组合中允许用户调用的 skill。 |
| `ctx.credentialsController` | `core` | [`api-settings-controller`](../packages/api/settings-controller) | - | - | - | 把凭据引用 seam 投影到生成的 Remote namespace:批量扇出、视图投影与拒绝映射都在这里,而不在 seam Definition 上。 |
| `ctx.settingsController` | `core` | [`api-settings-controller`](../packages/api/settings-controller) | - | - | - | 把用户设置 seam 投影到生成的 Remote namespace:读取一律脱敏,所有拒绝在这里分类,而不在 seam Definition 上。 |
| `ctx.workspaceController` | `core` | [`api-workspace-controller`](../packages/api/workspace-controller) | - | - | - | 通过生成的 Remote namespace 负责 Workspace 命令和可在重连后收敛的 Workspace 状态投递。 |
@@ -475,9 +482,9 @@ flowchart LR
| `ctx.typert` | `core` | [`typert-registry`](../packages/typert/registry) | - | [`typert-loader`](../packages/typert/loader), [`api-gateway`](../packages/api/gateway) | - | 插件直接或通过 dsh-typert-loader 注册实时 zod 贡献;API 网关消费调用描述符和提供方,其他运行时消费方则在各自边界查询 schema 与反射元数据。 |
| `ctx.typertGateway` | `core` | [`api-gateway`](../packages/api/gateway) | - | - | - | 将生成的 Remote 描述符与实时 Cordis 服务关联,解析已注册的身份,并通过共享的 Connection RPC 载体提供一元调用。 |
| `ctx.sessionPersistence` | `seam` | [`session-persistence`](../packages/session/session-persistence) | [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-persistence-sqlite`](../packages/session/session-persistence-sqlite) | [`agent-loop`](../packages/core/agent-loop), [`tool-bash`](../packages/shell/tool-bash), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`message-feedback`](../packages/feedback/message-feedback) | - | 各后端持久化同一套 SessionEvent 词汇;应用在组合时选择后端。 |
-| `ctx.settings` | `seam` | [`settings`](../packages/settings/settings) | [`settings-file`](../packages/settings/settings-file) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`host-apiproxy`](../packages/host/apiproxy) | - | 插件注册命名空间 schema 并解析分层值;提供方存储原始文档。LLM(大语言模型)适配器在用户分区下将其入口配置注册为组合基础;Web 网关提供经过脱敏的分层描述符,并写入用户层。 |
+| `ctx.settings` | `seam` | [`settings`](../packages/settings/settings) | [`settings-file`](../packages/settings/settings-file) | [`api-settings-controller`](../packages/api/settings-controller), [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai) | - | 插件注册命名空间 schema 并解析分层值;提供方存储原始文档。LLM(大语言模型)适配器在用户分区下将其入口配置注册为组合基础;settings controller 提供经过脱敏的分层描述符,并写入用户层。 |
| `ctx.subagentModelSelection` | `core` | [`tool-subagent`](../packages/subagent/tool-subagent) | - | [`tool-subagent`](../packages/subagent/tool-subagent) | - | 拥有默认关闭的设置命名空间;Agent 作用域的委派工具会在组合新顶层 Session 时读取它。 |
-| `ctx.credentials` | `seam` | [`credentials`](../packages/credentials/credentials) | [`credentials-local`](../packages/credentials/credentials-local) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`host-apiproxy`](../packages/host/apiproxy) | - | 配置携带对机密信息的引用;提供方拥有实际值。消费方按操作解析,因此轮换后的凭据会在紧接着的下一次请求中生效;Web 网关提供不含实际值的视图和只写存储。 |
+| `ctx.credentials` | `seam` | [`credentials`](../packages/credentials/credentials) | [`credentials-local`](../packages/credentials/credentials-local) | [`api-settings-controller`](../packages/api/settings-controller), [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai) | - | 配置携带对机密信息的引用;提供方拥有实际值。消费方按操作解析,因此轮换后的凭据会在紧接着的下一次请求中生效;settings controller 提供不含实际值的视图和只写存储。 |
| `ctx.authorization` | `seam` | [`authorization`](../packages/credentials/authorization) | - | [`llm-pi-ai`](../packages/llm/llm-pi-ai) | - | flow 由知道如何取得某份凭据的插件注册,并以其写入的记录为键;seam 拥有这段对话与"每个键同时只跑一次尝试"的生命周期,而非协议本身。 |
| `ctx.sessionTelemetry` | `seam` | [`session-telemetry`](../packages/session/session-telemetry) | [`session-telemetry-otel`](../packages/session/session-telemetry-otel) | - | - | 该 seam 捕获会话记录、进行脱敏并交给一个后端;没有其他组件消费该服务,其输出会离开当前进程。 |
| `ctx.storage` | `seam` | [`storage`](../packages/storage/storage) | [`storage-json`](../packages/storage/storage-json), [`storage-sqlite`](../packages/storage/storage-sqlite) | [`storage-domain`](../packages/storage/storage-domain) | - | 各后端以不同名称并列注册;数据形态(领域优先)挂载到枢纽上,并将类型化操作转换为不透明的 KV 单元原语。 |
@@ -485,20 +492,20 @@ flowchart LR
| `ctx.messageFeedback` | `core` | [`message-feedback`](../packages/feedback/message-feedback) | - | - | - | 拥有本地逐 assistant 消息反馈、生命周期与目标校验、逐条目 compare-and-set 及 Host 一元 Remote 契约,且不进入 Session 历史或遥测。 |
| `ctx.workspaceRegistry` | `core` | [`workspace`](../packages/workspace/workspace) | - | [`api-workspace-controller`](../packages/api/workspace-controller), [`api-session-controller`](../packages/api/session-controller) | - | 通过领域设施拥有带 WorkspaceId 品牌类型的记录;稳定的 sessionIds 账户驱动 Host RPC 与 GUI 投影。 |
| `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | [`session-reference`](../packages/context/session-reference), [`tool-session-query`](../packages/session-query/tool-session-query) | - | 该接口提供精确读取、过滤和追踪;具体后端还提供全文协调、排序、摘要片段和游标世代,而模型消费方负责工作区权限与不含游标的渲染。 |
-| `ctx.fileReferences` | `seam` | [`file-reference`](../packages/context/file-reference) | [`file-reference-local`](../packages/context/file-reference-local) | - | - | 该接口通过其一元 Remote 契约返回指定 Agent cwd 内仅含路径的补全候选;提供方负责命名空间访问和排序,但不会读取文件内容。 |
+| `ctx.fileReferences` | `seam` | [`file-reference`](../packages/context/file-reference) | [`file-reference-local`](../packages/context/file-reference-local) | [`api-session-controller`](../packages/api/session-controller) | - | 该接口返回 Agent cwd 内仅含路径的补全候选;提供方负责命名空间访问与排序,但不读取文件内容。 |
| `ctx.sessionReferenceResolver` | `core` | [`session-reference`](../packages/context/session-reference) | - | - | - | 将当前表层中有界的对话快照投影为持久但不可信的消息上下文;Host 适配器负责提及语法。 |
| `ctx.sessionTitle` | `seam` | [`session-title`](../packages/session/session-title) | [`session-title-first-prompt-llm`](../packages/session/session-title-first-prompt-llm), [`session-title-all-prompts-llm`](../packages/session/session-title-all-prompts-llm) | - | - | 负责确定性回退、最新标题折叠区,以及唯一的可选异步提供方注册。 |
| `ctx.systemPrompt` | `core` | [`system-prompt`](../packages/core/system-prompt) | - | [`agent-loop`](../packages/core/agent-loop), [`tools`](../packages/core/tools), [`tool-fs`](../packages/fs/tool-fs), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-web`](../packages/web/tool-web) | - | 为每个步骤收集提示词各部分和面向模型的工具 schema。 |
-| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/interaction/tool-ask-user), [`tool-bash`](../packages/shell/tool-bash), [`tool-cordis`](../packages/extensions/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web) | - | 注册能力,负责 Code Mode 传输,并让调用依次经过策略前处理、单调守卫、环绕分派、策略后处理和最终结果观测。 |
+| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/interaction/tool-ask-user), [`tool-bash`](../packages/shell/tool-bash), [`tool-cordis`](../packages/extensions/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web) | - | 注册能力,负责 PTC mode 传输,并让调用依次经过策略前处理、单调守卫、环绕分派、策略后处理和最终结果观测。 |
| `ctx.userQuestions` | `seam` | [`user-questions`](../packages/interaction/user-questions) | - | [`tool-ask-user`](../packages/interaction/tool-ask-user) | - | UI 前端提供当前生效的人工回答提供方;tool-ask-user 在提供方无关的 ask() promise 上暂停工具调用。 |
| `ctx.planMode` | `core` | [`plan-mode`](../packages/plan/plan-mode) | - | - | - | 折叠已记录的计划/模式状态,在轮次边界刷新用户选择,渲染由部署方拥有的指导信息,注册 /plan,并在状态转换期间保持计划退出 schema 稳定。 |
| `ctx.agentPresets` | `core` | [`agent-presets`](../packages/preset/agent-presets) | - | - | - | 在受信任根目录与用户创作根目录上发现 preset 目录,并在创建期把一份 preset cordis.yml 挂载到 agent 作用域之下,拒绝始终未激活或向根服务 realm 发布服务的行。 |
| `ctx.commands` | `core` | [`commands`](../packages/interaction/commands) | - | - | - | 插件注册直接面向人的命令,而不会把调用发送给模型。 |
-| `ctx.sessionProjections` | `core` | [`session-projection`](../packages/session/session-projection) | - | [`tool-todo`](../packages/todo/tool-todo), [`session-title`](../packages/session/session-title), [`host-apiproxy`](../packages/host/apiproxy) | - | 各领域注册由状态驱动的折叠单元;主动驱动过程维护每个会话的水位状态,api-proxy 提供基线并推送发生变化的值。 |
-| `ctx.sessionProjectionCache` | `core` | [`session-projection-cache`](../packages/session/session-projection-cache) | - | [`host-apiproxy`](../packages/host/apiproxy) | - | 按会话持久保存投影单元状态的检查点(节流检查点,以及轮次/结束/分离时的必选检查点),并提供冷读取阶梯:缓存行加持久化尾部回放,因此列表读取永远不需要加载完整日志。 |
+| `ctx.sessionProjections` | `core` | [`session-projection`](../packages/session/session-projection) | - | [`api-session-controller`](../packages/api/session-controller), [`tool-todo`](../packages/todo/tool-todo), [`session-title`](../packages/session/session-title) | - | 各领域注册由状态驱动的折叠单元;主动驱动过程维护每个会话的水位状态,Session controller 提供 baseline 并推送发生变化的值。 |
+| `ctx.sessionProjectionCache` | `core` | [`session-projection-cache`](../packages/session/session-projection-cache) | - | [`api-session-controller`](../packages/api/session-controller), [`session-query`](../packages/session-query/session-query), [`session-reference`](../packages/context/session-reference), [`subagent`](../packages/subagent/subagent) | - | 按会话持久保存投影单元状态的检查点(节流检查点,以及轮次/结束/分离时的必选检查点),并提供冷读取阶梯:缓存行加持久化尾部回放,因此列表读取永远不需要加载完整日志。 |
| `ctx.skills` | `seam` | [`skill`](../packages/skill/skill) | [`skill-badge`](../packages/skill/skill-badge), [`skill-filesystem`](../packages/skill/skill-filesystem) | [`tool-skill`](../packages/skill/tool-skill) | - | 合并提供方的 skill(技能)目录;tool-skill 渲染会话前缀目录,并加载完整的 skill 正文。 |
| `ctx.agents` | `core` | [`agent`](../packages/core/agent) | - | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/acp/acp), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) | - | 拥有实时 Agent 句柄、创建/恢复工厂 seam,以及进程本地的发起方传播。 |
-| `ctx.agentDefaultModel` | `core` | [`agent-default-model`](../packages/core/agent-default-model) | - | [`headless`](../packages/bundle/headless), [`host-apiproxy`](../packages/host/apiproxy) | - | 通过 settings 分层默认 `ModelSelection`,让直接入口与 Host 支撑的 Agent 入口共享同一个状态所有者。 |
+| `ctx.agentDefaultModel` | `core` | [`agent-default-model`](../packages/core/agent-default-model) | - | [`api-session-controller`](../packages/api/session-controller), [`headless`](../packages/bundle/headless) | - | 通过 settings 分层默认 `ModelSelection`,让直接入口与 Host 支撑的 Agent 入口共享同一个状态所有者。 |
| `ctx.agentLoop` | `bundle` | [`agent-loop`](../packages/core/agent-loop) | - | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | - | 唯一的具体循环插件;扩展包依赖 dsh-agent 的事件和服务,而不依赖此包。 |
| `ctx.goals` | `core` | [`goal`](../packages/goal/goal) | - | - | - | 从会话日志折叠带修订版本的目标状态,并将实时延续激活保留在进程本地。 |
| `ctx.e2b` | `core` | [`e2b`](../packages/e2b/e2b) | - | [`fs-e2b`](../packages/e2b/fs-e2b), [`subprocess-e2b`](../packages/e2b/subprocess-e2b) | - | 拥有一个共享的 E2B SDK 句柄、远程工作目录和最终沙箱处置,使两个基础 E2B 提供方处于同一个 Linux 运行时中。 |
@@ -510,11 +517,12 @@ flowchart LR
| `ctx.sandboxPolicy` | `core` | [`sandbox-policy`](../packages/sandbox/sandbox-policy) | - | [`bash-sandbox`](../packages/shell/bash-sandbox), [`fs-sandbox`](../packages/fs/fs-sandbox), [`terminal-bash`](../packages/terminal/terminal-bash) | - | 统一保存部署默认模式和工作区根目录;只有沙箱执行器和提供方读取该服务(工具层使用它同时导出的纯 `sandbox/mode` 折叠区)。两类强制执行组件都读取该服务,因此 bash 与 fs 不会限制到不同的根目录。 |
| `ctx.approval` | `seam` | [`user-approval`](../packages/interaction/user-approval) | - | [`tools`](../packages/core/tools), [`tool-bash`](../packages/shell/tool-bash), [`acp`](../packages/acp/acp) | - | 一次性权限决策通过 `approval/request` waterfall(瀑布式事件)分派;回答方是监听器(即 ACP 为自身 agent 提供的桥接),没有回答方时以 `unavailable` 关闭失败。 |
| `ctx.permissionPresets` | `core` | [`permission-presets`](../packages/interaction/permission-presets) | - | - | - | 面向用户的预设表(`workspace-write`/`danger-full-access`),将沙箱模式与审批策略选项组合在一起;一次切换会写入一个 `permission/preset` 事件,并贯通到两个选项事件。 |
-| `ctx.codeRuntime` | `seam` | [`code-runtime`](../packages/code-runtime/code-runtime) | [`code-runtime-worker-thread`](../packages/code-runtime/code-runtime-worker-thread) | [`tools`](../packages/core/tools) | - | 使用 Host 提供的异步绑定运行一段由模型编写的程序;各后端采用不同的基础环境和语言(工具注册表在 Code Mode 下消费该服务)。 |
+| `ctx.codeRuntime` | `seam` | [`code-runtime`](../packages/code-runtime/code-runtime) | [`code-runtime-worker-thread`](../packages/code-runtime/code-runtime-worker-thread) | [`tools`](../packages/core/tools) | - | 使用 Host 提供的异步绑定运行一段由模型编写的程序;各后端采用不同的基础环境和语言(工具注册表在 PTC mode 下消费该服务)。 |
| `ctx.fs` | `seam` | [`fs`](../packages/fs/fs) | [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox), [`fs-e2b`](../packages/e2b/fs-e2b) | [`tool-fs`](../packages/fs/tool-fs) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) | tool-fs 通过 ctx.fs 执行读取/写入/编辑;fs-sandbox 按共享沙箱模式限制变更;fs-observation-policy 通过 fs/* 事件门禁贡献基于观测状态的检查。 |
| `ctx.compaction` | `seam` | [`compaction`](../packages/compaction/compaction) | [`compaction-basic`](../packages/compaction/compaction-basic) | [`compaction-basic`](../packages/compaction/compaction-basic) | - | 基础后端消费步骤后的压力事件和请求错误恢复事件;不存在面向模型的压缩工具。 |
| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/workflow/tool-ralph) | - | 提供方实现传输;该服务还负责可选的、基于 Activation 的延续编排,tool-subagent 选择一次性或可延续委派,tool-subagent-control 传递后续消息,而 tool-ralph 要求一条全新的结构化输出路由。 |
| `ctx.agentTeams` | `core` | [`experimental-agent-team`](../packages/experimental/agent-team) | - | [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team), [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | - | 负责隐式 Root roster、持久 peer mailbox、共享任务 DAG、continuable child 生命周期与生成式 Team Remote method;tool-agent-team 提供模型控制工具,client-ui-agent-team 挂载浏览器 contribution。 |
+| `ctx.inspector` | `core` | `inspector` | - | - | - | 负责 Worker 托管的 CDP target,以及独立于传输的 Host 和 Client observation 与 Cordis tree query API。 |
| `ctx.jobs` | `seam` | [`jobs`](../packages/jobs/jobs) | [`jobs-local`](../packages/jobs/jobs-local) | [`tool-bash`](../packages/shell/tool-bash), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-jobs`](../packages/jobs/tool-jobs) | - | 生产方(后台 bash、PTY 发送和 subagent 委派)登记正在运行的工作;tool-jobs 是面向模型的控制器,用于读取、列出和终止这些工作;jobs-local 是进程本地注册表。 |
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | 搜索和抓取提供方注册到同一个 ctx.web seam;tool-web 负责稳定的面向模型名称。 |
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | 后端保存过大的工具文本,并返回面向模型的定位信息和取回提示;spill-policy 是 tools/post-execute 消费方,负责决定何时 spill。 |
@@ -524,7 +532,6 @@ flowchart LR
| `ctx.workflowEngine` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | [`tool-workflow`](../packages/workflow/tool-workflow), [`tool-ralph`](../packages/workflow/tool-ralph) | - | 每个上下文使用一个引擎,与 bash 相同,且没有具名提供方注册表;通用工作流与固定 Ralph 消费方启动运行,其中的 agent() 调用通过 ctx.subagents 扇出。 |
| `ctx.webhookRuntime` | `core` | [`webhook`](../packages/webhook/webhook) | - | [`webhook-github`](../packages/webhook/webhook-github) | - | 提供方适配器分派已认证交付;可信插件注册独立的进程本地规则,runtime 把非 null 结果转换为普通的 Workspace-backed Session,不保留交付或完成状态。 |
| `ctx.lsp` | `seam` | [`lsp`](../packages/lsp/lsp) | [`lsp-stdio`](../packages/lsp/lsp-stdio) | [`tool-lsp`](../packages/lsp/tool-lsp) | - | 提供方注册与选择,加上恰好四种操作的标准化查询执行;该 seam 不提供协议逃生口,后端必须转换为标准化请求和结果。 |
-| `ctx.apiProxy` | `core` | [`host-apiproxy`](../packages/host/apiproxy) | - | [`client-connection`](../packages/client/connection) | - | 与传输无关的 Host 网关接口:它分派浏览器 API 调用,每条打开的 Host 流自行订阅转发事件,而不是由广播方法向其推送。 |
| `ctx.dynamicCordisRunner` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | 拥有内存定义注册表、Host 半的 vm 沙箱和 request-run 往返流程;浏览器页面通过其 Remote 命名空间在线访问同一服务。 |
| `ctx.cordisInspect` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | 注册 Host inspect 提供方、镜像 Client 提供方 manifest,并通过动态 Cordis 传输路由 Client 查询。 |
diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml
index d7081d60fc..ba3f56d510 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: 16508819d0cc46ff93707337d97c6f88541152fb
-config-catalog.zh.md: 049f266ed8f9014bfd377ae515efdb920b952f83
+config-catalog.md: b2d8379dd799ab0e836a2ab0572d6af08ababc5d
+config-catalog.zh.md: d768b40c54d27aeeb1294d4fee7417f54c11afb0
diff --git a/docs/config-catalog.md b/docs/config-catalog.md
index 16508819d0..b2d8379dd7 100644
--- a/docs/config-catalog.md
+++ b/docs/config-catalog.md
@@ -261,7 +261,7 @@ Requires: `tools`
export interface Config {
/**
* The form this agent's model sees. `native` sends every visible schema,
- * `code` sends only `run_code` plus a generated SDK, `both` sends both.
+ * `ptc` sends only `run_code` plus a generated SDK, `both` sends both.
* Required rather than defaulted: the deployment default is what a preset
* without this row already gets, so an omitted value would mean the row was
* composed for nothing.
@@ -274,6 +274,22 @@ Depends on: [`ToolPresentationMode`](subsystems/tools.md)
Source: [`packages/core/agent-tool-presentation/src/index.ts:38`](../packages/core/agent-tool-presentation/src/index.ts)
+
+
+## `@deepseek-ai/dsh-api-gateway`
+
+Requires: `typert`
+
+```ts config-catalog
+/** Gateway transport configuration. */
+export interface Config {
+ /** WebSocket Ping interval from 1 through 2,147,483,647 milliseconds. @default 30000 */
+ readonly websocketHeartbeatIntervalMs?: number
+}
+```
+
+Source: [`packages/api/gateway/src/index.ts:117`](../packages/api/gateway/src/index.ts)
+
## `@deepseek-ai/dsh-api-session-controller`
@@ -285,10 +301,26 @@ Requires: `agentDefaultModel` · `agents` · `attachments` · `llm` · `sessions
export interface Config {
/** Maximum cold Session artifact size eligible for one full projection observation. */
readonly coldBlankProbeMaxBytes?: number
+ /** Override platform desktop-opener detection. */
+ readonly nativeOpen?: boolean
}
```
-Source: [`packages/api/session-controller/src/index.ts:58`](../packages/api/session-controller/src/index.ts)
+Source: [`packages/api/session-controller/src/index.ts:67`](../packages/api/session-controller/src/index.ts)
+
+
+
+## `@deepseek-ai/dsh-api-settings-controller`
+
+```ts config-catalog
+/** Native document-opening policy. */
+export interface Config {
+ /** Override platform desktop-opener detection. */
+ readonly nativeOpen?: boolean
+}
+```
+
+Source: [`packages/api/settings-controller/src/index.ts:41`](../packages/api/settings-controller/src/index.ts)
@@ -397,7 +429,7 @@ export interface ConnectionConfig {
}
```
-Source: [`packages/client/connection/src/index.ts:55`](../packages/client/connection/src/index.ts)
+Source: [`packages/client/connection/src/index.ts:70`](../packages/client/connection/src/index.ts)
@@ -596,6 +628,74 @@ export interface Config {
Source: [`packages/experimental/agent-team/src/types.ts:131`](../packages/experimental/agent-team/src/types.ts)
+
+
+## `@deepseek-ai/dsh-experimental-inspector`
+
+Requires: `webServer`
+
+```ts config-catalog
+/** Host plugin configuration. Fetch capture is enabled by default. */
+export interface Config extends Omit {
+ /** Browser origins allowed to open the Client ingest WebSocket. */
+ clientOrigins?: string[]
+}
+
+/** User-facing Host options; every memory and lifecycle bound is configurable. */
+export interface InspectorOptions {
+ /** Loopback address used by the Worker HTTP and WebSocket endpoint. */
+ readonly host?: '127.0.0.1'
+ /** First port to bind; occupied ports advance until one is available. */
+ readonly port?: number
+ /** Additional exact browser origins admitted to the Client ingest socket. */
+ readonly clientOrigins?: readonly string[]
+ /** Whether to observe calls made through the current global fetch function. */
+ readonly captureFetch?: boolean
+ /** Maximum request-body prefix retained for one fetch. */
+ readonly maxRequestBodyBytes?: number
+ /** Maximum response-body prefix retained for one fetch. */
+ readonly maxResponseBodyBytes?: number
+ /** Maximum raw bytes encoded into one body observation. */
+ readonly maxBodyChunkBytes?: number
+ /** Maximum total request and response body bytes retained by the Worker. */
+ readonly maxJournalBytes?: number
+ /** Maximum active and completed fetch requests retained by the Worker. */
+ readonly maxRetainedRequests?: number
+ /** Maximum encoded bytes accepted in one source transport frame. */
+ readonly maxSourceFrameBytes?: number
+ /** Maximum observation records accepted in one source batch. */
+ readonly maxSourceRecordsPerFrame?: number
+ /** Maximum records waiting in one producer queue. */
+ readonly maxQueuedRecords?: number
+ /** Maximum encoded bytes waiting in one producer queue. */
+ readonly maxQueuedBytes?: number
+ /** Maximum time allowed for the Worker to become ready. */
+ readonly startupTimeoutMs?: number
+ /** Grace period before a stopping Worker is terminated. */
+ readonly stopTimeoutMs?: number
+ /** Initial upper bound for randomized Client reconnect delay. */
+ readonly clientReconnectBaseMs?: number
+ /** Maximum upper bound for randomized Client reconnect delay. */
+ readonly clientReconnectMaxMs?: number
+ /** Deadline for one Worker-to-Client Runtime or Sources request. */
+ readonly clientRuntimeTimeoutMs?: number
+ /** Deadline for one non-CDP semantic query. */
+ readonly queryTimeoutMs?: number
+ /** Maximum live object handles retained per Client Runtime session. */
+ readonly maxClientRuntimeObjects?: number
+ /** Maximum descriptors returned by one Client property request. */
+ readonly maxClientRuntimeProperties?: number
+ /** Maximum encoded bytes read for one Client script or source map. */
+ readonly maxClientSourceBytes?: number
+ /** Maximum Context and Fiber nodes retained in one realm snapshot. */
+ readonly maxCordisNodes?: number
+ /** Disconnected Cordis snapshots retained after their live realm closes. */
+ readonly maxDisconnectedCordisTrees?: number
+}
+```
+
+Source: [`packages/experimental/inspector/src/index.ts:66`](../packages/experimental/inspector/src/index.ts)
+
## `@deepseek-ai/dsh-experimental-tool-agent-team`
@@ -770,34 +870,6 @@ export interface Config {
Source: [`packages/hooks/hooks-codex/src/index.ts:44`](../packages/hooks/hooks-codex/src/index.ts)
-
-
-## `@deepseek-ai/dsh-host-apiproxy`
-
-Requires: `agentDefaultModel` · `agents` · `attachments` · `directoryPicker` · `llm` · `sessions` · `sessionQuery` · `sessionController`
-
-```ts config-catalog
-/** Gateway plugin configuration. */
-export interface Config {
- /**
- * Whether this deployment can hand paths to a native desktop opener —
- * the `hasDocument` capability the agent-preset roster reports. Absent,
- * the platform is asked (macOS/Windows/WSL yes; Linux only with a display
- * server); set it explicitly where detection misleads, e.g. `false` in a
- * container whose DISPLAY points nowhere a user can see.
- */
- nativeOpen?: boolean
- /**
- * DEFLATE level for every session-log ZIP entry: `0` stores without
- * compression, `1` favors CPU/latency, and `9` favors archive size.
- * @default 6
- */
- sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
-}
-```
-
-Source: [`packages/host/apiproxy/src/index.ts:42`](../packages/host/apiproxy/src/index.ts)
-
## `@deepseek-ai/dsh-host-directory-picker-browse`
@@ -1752,6 +1824,25 @@ export interface Config {
Source: [`packages/session/session-log-deepseek/src/index.ts:22`](../packages/session/session-log-deepseek/src/index.ts)
+
+
+## `@deepseek-ai/dsh-session-log-export`
+
+Requires: `commands` · `connection`
+
+```ts config-catalog
+/** Session-log archive policy. */
+export interface Config {
+ /** DEFLATE level for each ZIP entry. @default 6 */
+ readonly compressionLevel?: SessionLogCompressionLevel
+}
+
+/** Valid fflate DEFLATE levels accepted by session-log export. */
+export type SessionLogCompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
+```
+
+Source: [`packages/session-query/session-log-export/src/index.ts:41`](../packages/session-query/session-log-export/src/index.ts)
+
## `@deepseek-ai/dsh-session-persistence-jsonl`
@@ -1840,7 +1931,7 @@ export interface Config {
}
```
-Source: [`packages/session/session-projection-cache/src/index.ts:45`](../packages/session/session-projection-cache/src/index.ts)
+Source: [`packages/session/session-projection-cache/src/index.ts:48`](../packages/session/session-projection-cache/src/index.ts)
@@ -2863,12 +2954,9 @@ export interface Config {
* a distinct name.
*/
toolName?: string
- /** Let the model discover and select the child LLM route (default false). */
- enableModelSelection?: boolean
/**
* Sample the Host `subagent-model-selection` user setting for each new
- * top-level session and inherit that decision in its child sessions. Mutually
- * exclusive with `enableModelSelection`.
+ * top-level session and inherit that decision in its child sessions.
*/
modelSelectionSettings?: boolean
/**
@@ -2918,7 +3006,7 @@ export interface Config {
Depends on: [`AgentOptions`](subsystems/core.md)
-Source: [`packages/subagent/tool-subagent/src/index.ts:48`](../packages/subagent/tool-subagent/src/index.ts)
+Source: [`packages/subagent/tool-subagent/src/index.ts:49`](../packages/subagent/tool-subagent/src/index.ts)
@@ -3038,13 +3126,13 @@ Requires: `systemPrompt`
/** Plugin config: how the registered tools are presented to the model. */
export interface Config {
/**
- * Model presentation. `native` (default) sends every visible schema; `code`
+ * Model presentation. `native` (default) sends every visible schema; `ptc`
* sends only `run_code` plus a generated SDK prompt and collapses the
* executor to the same surface (a model-direct call may only name
* `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both`
- * sends both forms. Code modes require a `ctx.codeRuntime` whose `language`
+ * sends both forms. PTC mode requires a `ctx.codeRuntime` whose `language`
* has a registered SDK renderer (TypeScript or Python) and fail prompt
- * assembly when it is absent or has no renderer. Under `code`, native names
+ * assembly when it is absent or has no renderer. Under `ptc`, native names
* in `toolOrder` are invalid.
*/
mode?: ToolPresentationMode
@@ -3059,7 +3147,7 @@ export interface Config {
}
/** How the registry presents its tools to the model (see {@link Config.mode}). */
-export type ToolPresentationMode = 'native' | 'code' | 'both'
+export type ToolPresentationMode = 'native' | 'ptc' | 'both'
```
Source: [`packages/core/tools/src/index.ts:655`](../packages/core/tools/src/index.ts)
@@ -3317,9 +3405,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
- `@deepseek-ai/dsh-acp-app` — requires `cmdlineArgs` ([`packages/bundle/acp-app/src/index.ts`](../packages/bundle/acp-app/src/index.ts))
- `@deepseek-ai/dsh-agent` ([`packages/core/agent/src/index.ts`](../packages/core/agent/src/index.ts))
-- `@deepseek-ai/dsh-api-gateway` — requires `typert` ([`packages/api/gateway/src/index.ts`](../packages/api/gateway/src/index.ts))
- `@deepseek-ai/dsh-api-remotes` — requires `typertGateway` ([`packages/api/remotes/src/index.ts`](../packages/api/remotes/src/index.ts))
-- `@deepseek-ai/dsh-api-settings-controller` ([`packages/api/settings-controller/src/index.ts`](../packages/api/settings-controller/src/index.ts))
- `@deepseek-ai/dsh-api-workspace-controller` — requires `typert` · `workspaceRegistry` ([`packages/api/workspace-controller/src/index.ts`](../packages/api/workspace-controller/src/index.ts))
- `@deepseek-ai/dsh-authorization` — requires `credentials` ([`packages/credentials/authorization/src/index.ts`](../packages/credentials/authorization/src/index.ts))
- `@deepseek-ai/dsh-client-locale` ([`packages/client/locale/src/index.ts`](../packages/client/locale/src/index.ts))
@@ -3379,7 +3465,6 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
- `@deepseek-ai/dsh-schedule` — requires `agents` · `sessions` · `tools` · `sessionPersistence` ([`packages/schedule/schedule/src/index.ts`](../packages/schedule/schedule/src/index.ts))
- `@deepseek-ai/dsh-session` ([`packages/core/session/src/index.ts`](../packages/core/session/src/index.ts))
- `@deepseek-ai/dsh-session-checkpoint-policy` — requires `llm` · `sessionPersistence` · `sessions` · `tools` ([`packages/session/session-checkpoint-policy/src/index.ts`](../packages/session/session-checkpoint-policy/src/index.ts))
-- `@deepseek-ai/dsh-session-log-export` — requires `commands` ([`packages/session-query/session-log-export/src/index.ts`](../packages/session-query/session-log-export/src/index.ts))
- `@deepseek-ai/dsh-session-projection` ([`packages/session/session-projection/src/index.ts`](../packages/session/session-projection/src/index.ts))
- `@deepseek-ai/dsh-session-stats` — requires `sessionProjections` ([`packages/session/session-stats/src/index.ts`](../packages/session/session-stats/src/index.ts))
- `@deepseek-ai/dsh-skill-badge` — requires `skills` ([`packages/skill/skill-badge/src/index.ts`](../packages/skill/skill-badge/src/index.ts))
diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md
index 049f266ed8..d768b40c54 100644
--- a/docs/config-catalog.zh.md
+++ b/docs/config-catalog.zh.md
@@ -263,7 +263,7 @@ export interface GoalConfig {
export interface Config {
/**
* The form this agent's model sees. `native` sends every visible schema,
- * `code` sends only `run_code` plus a generated SDK, `both` sends both.
+ * `ptc` sends only `run_code` plus a generated SDK, `both` sends both.
* Required rather than defaulted: the deployment default is what a preset
* without this row already gets, so an omitted value would mean the row was
* composed for nothing.
@@ -276,6 +276,22 @@ export interface Config {
来源:[`packages/core/agent-tool-presentation/src/index.ts:38`](../packages/core/agent-tool-presentation/src/index.ts)
+
+
+## `@deepseek-ai/dsh-api-gateway`
+
+需要:`typert`
+
+```ts config-catalog
+/** Gateway transport configuration. */
+export interface Config {
+ /** WebSocket Ping interval from 1 through 2,147,483,647 milliseconds. @default 30000 */
+ readonly websocketHeartbeatIntervalMs?: number
+}
+```
+
+来源:[`packages/api/gateway/src/index.ts:117`](../packages/api/gateway/src/index.ts)
+
## `@deepseek-ai/dsh-api-session-controller`
@@ -287,10 +303,26 @@ export interface Config {
export interface Config {
/** Maximum cold Session artifact size eligible for one full projection observation. */
readonly coldBlankProbeMaxBytes?: number
+ /** Override platform desktop-opener detection. */
+ readonly nativeOpen?: boolean
}
```
-来源:[`packages/api/session-controller/src/index.ts:58`](../packages/api/session-controller/src/index.ts)
+来源:[`packages/api/session-controller/src/index.ts:67`](../packages/api/session-controller/src/index.ts)
+
+
+
+## `@deepseek-ai/dsh-api-settings-controller`
+
+```ts config-catalog
+/** Native document-opening policy. */
+export interface Config {
+ /** Override platform desktop-opener detection. */
+ readonly nativeOpen?: boolean
+}
+```
+
+来源:[`packages/api/settings-controller/src/index.ts:41`](../packages/api/settings-controller/src/index.ts)
@@ -598,6 +630,74 @@ export interface Config {
来源:[`packages/experimental/agent-team/src/types.ts:125`](../packages/experimental/agent-team/src/types.ts)
+
+
+## `@deepseek-ai/dsh-experimental-inspector`
+
+需要:`webServer`
+
+```ts config-catalog
+/** Host plugin configuration. Fetch capture is enabled by default. */
+export interface Config extends Omit {
+ /** Browser origins allowed to open the Client ingest WebSocket. */
+ clientOrigins?: string[]
+}
+
+/** User-facing Host options; every memory and lifecycle bound is configurable. */
+export interface InspectorOptions {
+ /** Loopback address used by the Worker HTTP and WebSocket endpoint. */
+ readonly host?: '127.0.0.1'
+ /** First port to bind; occupied ports advance until one is available. */
+ readonly port?: number
+ /** Additional exact browser origins admitted to the Client ingest socket. */
+ readonly clientOrigins?: readonly string[]
+ /** Whether to observe calls made through the current global fetch function. */
+ readonly captureFetch?: boolean
+ /** Maximum request-body prefix retained for one fetch. */
+ readonly maxRequestBodyBytes?: number
+ /** Maximum response-body prefix retained for one fetch. */
+ readonly maxResponseBodyBytes?: number
+ /** Maximum raw bytes encoded into one body observation. */
+ readonly maxBodyChunkBytes?: number
+ /** Maximum total request and response body bytes retained by the Worker. */
+ readonly maxJournalBytes?: number
+ /** Maximum active and completed fetch requests retained by the Worker. */
+ readonly maxRetainedRequests?: number
+ /** Maximum encoded bytes accepted in one source transport frame. */
+ readonly maxSourceFrameBytes?: number
+ /** Maximum observation records accepted in one source batch. */
+ readonly maxSourceRecordsPerFrame?: number
+ /** Maximum records waiting in one producer queue. */
+ readonly maxQueuedRecords?: number
+ /** Maximum encoded bytes waiting in one producer queue. */
+ readonly maxQueuedBytes?: number
+ /** Maximum time allowed for the Worker to become ready. */
+ readonly startupTimeoutMs?: number
+ /** Grace period before a stopping Worker is terminated. */
+ readonly stopTimeoutMs?: number
+ /** Initial upper bound for randomized Client reconnect delay. */
+ readonly clientReconnectBaseMs?: number
+ /** Maximum upper bound for randomized Client reconnect delay. */
+ readonly clientReconnectMaxMs?: number
+ /** Deadline for one Worker-to-Client Runtime or Sources request. */
+ readonly clientRuntimeTimeoutMs?: number
+ /** Deadline for one non-CDP semantic query. */
+ readonly queryTimeoutMs?: number
+ /** Maximum live object handles retained per Client Runtime session. */
+ readonly maxClientRuntimeObjects?: number
+ /** Maximum descriptors returned by one Client property request. */
+ readonly maxClientRuntimeProperties?: number
+ /** Maximum encoded bytes read for one Client script or source map. */
+ readonly maxClientSourceBytes?: number
+ /** Maximum Context and Fiber nodes retained in one realm snapshot. */
+ readonly maxCordisNodes?: number
+ /** Disconnected Cordis snapshots retained after their live realm closes. */
+ readonly maxDisconnectedCordisTrees?: number
+}
+```
+
+来源:[`packages/experimental/inspector/src/index.ts:66`](../packages/experimental/inspector/src/index.ts)
+
## `@deepseek-ai/dsh-experimental-tool-agent-team`
@@ -772,34 +872,6 @@ export interface Config {
来源:[`packages/hooks/hooks-codex/src/index.ts:44`](../packages/hooks/hooks-codex/src/index.ts)
-
-
-## `@deepseek-ai/dsh-host-apiproxy`
-
-需要:`agentDefaultModel` · `agents` · `attachments` · `directoryPicker` · `llm` · `sessions` · `sessionQuery` · `sessionController`
-
-```ts config-catalog
-/** Gateway plugin configuration. */
-export interface Config {
- /**
- * Whether this deployment can hand paths to a native desktop opener —
- * the `hasDocument` capability the agent-preset roster reports. Absent,
- * the platform is asked (macOS/Windows/WSL yes; Linux only with a display
- * server); set it explicitly where detection misleads, e.g. `false` in a
- * container whose DISPLAY points nowhere a user can see.
- */
- nativeOpen?: boolean
- /**
- * DEFLATE level for every session-log ZIP entry: `0` stores without
- * compression, `1` favors CPU/latency, and `9` favors archive size.
- * @default 6
- */
- sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
-}
-```
-
-来源:[`packages/host/apiproxy/src/index.ts:42`](../packages/host/apiproxy/src/index.ts)
-
## `@deepseek-ai/dsh-host-directory-picker-browse`
@@ -1754,6 +1826,25 @@ export interface Config {
来源:[`packages/session/session-log-deepseek/src/index.ts:22`](../packages/session/session-log-deepseek/src/index.ts)
+
+
+## `@deepseek-ai/dsh-session-log-export`
+
+需要:`commands` · `connection`
+
+```ts config-catalog
+/** Session-log archive policy. */
+export interface Config {
+ /** DEFLATE level for each ZIP entry. @default 6 */
+ readonly compressionLevel?: SessionLogCompressionLevel
+}
+
+/** Valid fflate DEFLATE levels accepted by session-log export. */
+export type SessionLogCompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
+```
+
+来源:[`packages/session-query/session-log-export/src/index.ts:41`](../packages/session-query/session-log-export/src/index.ts)
+
## `@deepseek-ai/dsh-session-persistence-jsonl`
@@ -2865,12 +2956,9 @@ export interface Config {
* a distinct name.
*/
toolName?: string
- /** Let the model discover and select the child LLM route (default false). */
- enableModelSelection?: boolean
/**
* Sample the Host `subagent-model-selection` user setting for each new
- * top-level session and inherit that decision in its child sessions. Mutually
- * exclusive with `enableModelSelection`.
+ * top-level session and inherit that decision in its child sessions.
*/
modelSelectionSettings?: boolean
/**
@@ -3040,13 +3128,13 @@ export interface Config {
/** Plugin config: how the registered tools are presented to the model. */
export interface Config {
/**
- * Model presentation. `native` (default) sends every visible schema; `code`
+ * Model presentation. `native` (default) sends every visible schema; `ptc`
* sends only `run_code` plus a generated SDK prompt and collapses the
* executor to the same surface (a model-direct call may only name
* `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both`
- * sends both forms. Code modes require a `ctx.codeRuntime` whose `language`
+ * sends both forms. PTC mode requires a `ctx.codeRuntime` whose `language`
* has a registered SDK renderer (TypeScript or Python) and fail prompt
- * assembly when it is absent or has no renderer. Under `code`, native names
+ * assembly when it is absent or has no renderer. Under `ptc`, native names
* in `toolOrder` are invalid.
*/
mode?: ToolPresentationMode
@@ -3061,7 +3149,7 @@ export interface Config {
}
/** How the registry presents its tools to the model (see {@link Config.mode}). */
-export type ToolPresentationMode = 'native' | 'code' | 'both'
+export type ToolPresentationMode = 'native' | 'ptc' | 'both'
```
来源:[`packages/core/tools/src/index.ts:655`](../packages/core/tools/src/index.ts)
@@ -3319,9 +3407,7 @@ export interface Config {
- `@deepseek-ai/dsh-acp-app` — 需要 `cmdlineArgs`([`packages/bundle/acp-app/src/index.ts`](../packages/bundle/acp-app/src/index.ts))
- `@deepseek-ai/dsh-agent`([`packages/core/agent/src/index.ts`](../packages/core/agent/src/index.ts))
-- `@deepseek-ai/dsh-api-gateway` — 需要 `typert`([`packages/api/gateway/src/index.ts`](../packages/api/gateway/src/index.ts))
- `@deepseek-ai/dsh-api-remotes` — 需要 `typertGateway`([`packages/api/remotes/src/index.ts`](../packages/api/remotes/src/index.ts))
-- `@deepseek-ai/dsh-api-settings-controller`([`packages/api/settings-controller/src/index.ts`](../packages/api/settings-controller/src/index.ts))
- `@deepseek-ai/dsh-api-workspace-controller` — 需要 `typert` · `workspaceRegistry`([`packages/api/workspace-controller/src/index.ts`](../packages/api/workspace-controller/src/index.ts))
- `@deepseek-ai/dsh-authorization` — 需要 `credentials`([`packages/credentials/authorization/src/index.ts`](../packages/credentials/authorization/src/index.ts))
- `@deepseek-ai/dsh-client-locale`([`packages/client/locale/src/index.ts`](../packages/client/locale/src/index.ts))
@@ -3381,7 +3467,6 @@ export interface Config {
- `@deepseek-ai/dsh-schedule` — 需要 `agents` · `sessions` · `tools` · `sessionPersistence`([`packages/schedule/schedule/src/index.ts`](../packages/schedule/schedule/src/index.ts))
- `@deepseek-ai/dsh-session`([`packages/core/session/src/index.ts`](../packages/core/session/src/index.ts))
- `@deepseek-ai/dsh-session-checkpoint-policy` — 需要 `llm` · `sessionPersistence` · `sessions` · `tools`([`packages/session/session-checkpoint-policy/src/index.ts`](../packages/session/session-checkpoint-policy/src/index.ts))
-- `@deepseek-ai/dsh-session-log-export` — 需要 `commands`([`packages/session-query/session-log-export/src/index.ts`](../packages/session-query/session-log-export/src/index.ts))
- `@deepseek-ai/dsh-session-projection`([`packages/session/session-projection/src/index.ts`](../packages/session/session-projection/src/index.ts))
- `@deepseek-ai/dsh-session-stats` — 需要 `sessionProjections`([`packages/session/session-stats/src/index.ts`](../packages/session/session-stats/src/index.ts))
- `@deepseek-ai/dsh-skill-badge` — 需要 `skills`([`packages/skill/skill-badge/src/index.ts`](../packages/skill/skill-badge/src/index.ts))
diff --git a/docs/cookbook/adding-a-tool.i18n.yaml b/docs/cookbook/adding-a-tool.i18n.yaml
index 3aaabe5ef5..9d02664a90 100644
--- a/docs/cookbook/adding-a-tool.i18n.yaml
+++ b/docs/cookbook/adding-a-tool.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-tool.md
-adding-a-tool.md: 9ec025426a2304f4bda56ddb8e6f5c42e3e8f4a8
-adding-a-tool.zh.md: 2c73b40ff53b5b58507b716ff32dd1fea26148f4
+adding-a-tool.md: f6b2703f3db69a6abc04dbd0fd9893555eed0602
+adding-a-tool.zh.md: d4831e2be061c2565e88004062cbb1558491bb9d
diff --git a/docs/cookbook/adding-a-tool.md b/docs/cookbook/adding-a-tool.md
index 9ec025426a..f6b2703f3d 100644
--- a/docs/cookbook/adding-a-tool.md
+++ b/docs/cookbook/adding-a-tool.md
@@ -50,7 +50,7 @@ Registration is effect-based: disposing the plugin fiber unregisters the tool. S
## Long-running work
-Gate `run_in_background` with producer config, then register through `ctx.jobs.start({ kind, label, owner: exec.agent, run })`. The registry rejects a pre-aborted invocation before the producer body; the runtime validates ownership and task-controller availability before `run()` starts work, then supplies the id, session fence, generic control tools, notices, and owner cleanup. A successful background branch returns a typed canonical handle such as `{ kind: 'background', jobId }`; its Native renderer may keep human prose such as `started background job bash-1`, but Code Mode must never parse that prose to recover the id.
+Gate `run_in_background` with producer config, then register through `ctx.jobs.start({ kind, label, owner: exec.agent, run })`. The registry rejects a pre-aborted invocation before the producer body; the runtime validates ownership and task-controller availability before `run()` starts work, then supplies the id, session fence, generic control tools, notices, and owner cleanup. A successful background branch returns a typed canonical handle such as `{ kind: 'background', jobId }`; its Native renderer may keep human prose such as `started background job bash-1`, but PTC mode must never parse that prose to recover the id.
The producer supplies synchronous `cancel`, non-rejecting `done` that settles after resource cleanup, and optional consuming `readOutput` with bounded-output formatting. A pre-aborted call is a failure because no task exists whose id could satisfy the successful output schema. Once `ctx.jobs.start()` publishes the id, use a task-owned cancellation signal rather than `exec.signal`: later outer-call cancellation stops waiting for the call but does not kill published work; `job_kill`, owner disposal, and service teardown own that lifetime. Foreground work remains coupled to `exec.signal`. See the [background job runtime Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) and `dsh-tool-bash` for a stream producer.
@@ -58,9 +58,9 @@ The producer supplies synchronous `cancel`, non-rejecting `done` that settles af
Prefer not to build deployment policy into the tool. Use `tools/pre-execute` for extensible allow/deny/ask policy (the [permission-gate example](extension-cookbook.md#a-hook-plugin-permission-gate-example)), `ctx.tools.guard()` for a final monotonic deny that later listeners cannot undo, `tools/execute` to wrap dispatch with a deadline, retry, or metrics collection, `tools/post-execute` to replace presentation content or the returned value, block the result, or attach model-facing context, and `tools/result` to observe the immutable normalized outcome. A content replacement leaves programmatic access to `value` intact; confidentiality policy blocks or replaces the value. A sandboxing implementation can also run inside the tool's executor implementation; the [`dsh-tools` README](../../packages/core/tools/README.md#extension-points) defines each extension point's inputs, order, return values, and failure behavior.
-## Code Mode reaches your tool for free
+## PTC mode reaches your tool for free
-In [Code Mode](../../packages/core/tools/README.md), every visible registered tool is available as `await tools.(args)` without extra integration. The generated `ToolArgsMap` and `ToolOutputMap` derive exact argument and canonical-return types from the same schemas, and calls re-enter the normal execution pipeline. A successful call resolves to the final canonical JSON value after policy, not to rendered Native content. A failed call rejects with the real `ToolCallError`; programs can inspect only its `name`, `toolName`, and human-readable `message`, not internal error codes or a failure union.
+In [PTC mode](../../packages/core/tools/README.md), every visible registered tool is available as `await tools.(args)` without extra integration. The generated `ToolArgsMap` and `ToolOutputMap` derive exact argument and canonical-return types from the same schemas, and calls re-enter the normal execution pipeline. A successful call resolves to the final canonical JSON value after policy, not to rendered Native content. A failed call rejects with the real `ToolCallError`; programs can inspect only its `name`, `toolName`, and human-readable `message`, not internal error codes or a failure union.
Design `output.schema` as a useful programmatic API: return handles and fields directly, allow scalar/array/null roots when they are the honest value, and keep human explanation in `output.render`. Intermediate values are execution-local, are not persisted or prompt-truncated, and have no byte cap, so the producer's truthful acquisition bounds and process memory still matter. Only the outer `run_code` logs/result cross the configurable output cap and model-facing spill pipeline.
diff --git a/docs/cookbook/adding-a-tool.zh.md b/docs/cookbook/adding-a-tool.zh.md
index 2c73b40ff5..d4831e2be0 100644
--- a/docs/cookbook/adding-a-tool.zh.md
+++ b/docs/cookbook/adding-a-tool.zh.md
@@ -50,7 +50,7 @@ export function apply(ctx: Context) {
## 长时间运行的工作
-通过 producer 配置控制 `run_in_background`,然后使用 `ctx.jobs.start({ kind, label, owner: exec.agent, run })` 注册任务。注册表会在进入 producer 主体前将已预先中止的调用判为失败;运行时会在 `run()` 启动工作前校验 owner 和任务控制器是否可用,随后提供 id、会话围栏、通用控制工具、通知和 owner cleanup。成功的后台分支会返回类型化的规范句柄,如 `{ kind: 'background', jobId }`;其 Native 渲染器可以保留 `started background job bash-1` 这类供人阅读的自然语言,但 Code Mode 绝不能通过解析该文本取得 id。
+通过 producer 配置控制 `run_in_background`,然后使用 `ctx.jobs.start({ kind, label, owner: exec.agent, run })` 注册任务。注册表会在进入 producer 主体前将已预先中止的调用判为失败;运行时会在 `run()` 启动工作前校验 owner 和任务控制器是否可用,随后提供 id、会话围栏、通用控制工具、通知和 owner cleanup。成功的后台分支会返回类型化的规范句柄,如 `{ kind: 'background', jobId }`;其 Native 渲染器可以保留 `started background job bash-1` 这类供人阅读的自然语言,但 PTC mode 绝不能通过解析该文本取得 id。
producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 `done`,以及可选的消费式 `readOutput`(负责有界输出的格式化)。预先中止的调用属于失败,因为此时没有任务,其 id 无法满足成功输出 schema。`ctx.jobs.start()` 发布 id 后,应使用任务自有的取消信号,而不是 `exec.signal`:之后取消外层调用只会停止等待本次调用,不会终止已经发布的工作;该生命周期归 `job_kill`、owner dispose 和服务 teardown 所有。前台工作仍与 `exec.signal` 耦合。流式 producer 的示例和完整约定见[后台任务运行时 Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md)与 `dsh-tool-bash`。
@@ -60,9 +60,9 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的
尽量不要把部署策略内建到工具中。使用 `tools/pre-execute` 实现可扩展的允许/拒绝/询问策略(见[权限门禁示例](extension-cookbook.zh.md#a-hook-plugin-permission-gate-example));使用 `ctx.tools.guard()` 设置最终的单调拒绝,后续监听器无法撤销;使用 `tools/execute` 为分发添加截止时间、重试或指标收集;使用 `tools/post-execute` 替换展示内容或返回值、阻止结果,或附加模型可见上下文;使用 `tools/result` 观测不可变的归一化结果而不改变它。替换内容不会阻止程序化访问 `value`;保密策略会屏蔽或替换该值。沙箱实现也可以在工具的执行器实现中运行;[`dsh-tools` README](../../packages/core/tools/README.zh.md#extension-points) 定义每个扩展点的输入、顺序、返回值和失败行为。
-## Code Mode 自动触达你的工具
+## PTC mode 自动触达你的工具
-在 [Code Mode](../../packages/core/tools/README.zh.md) 中,每个可见的已注册工具都可通过 `await tools.(args)` 调用,无需额外集成。生成的 `ToolArgsMap` 和 `ToolOutputMap` 会根据同一组 schema 分别派生精确的参数类型与规范返回类型,调用则重新进入正常的执行流水线。成功调用会解析为策略处理后的最终规范 JSON 值,而不是渲染后的 Native 内容。失败调用会以真正的 `ToolCallError` reject;程序只能检查其 `name`、`toolName` 和可供人阅读的 `message`,无法取得内部错误代码或失败联合。
+在 [PTC mode](../../packages/core/tools/README.zh.md) 中,每个可见的已注册工具都可通过 `await tools.(args)` 调用,无需额外集成。生成的 `ToolArgsMap` 和 `ToolOutputMap` 会根据同一组 schema 分别派生精确的参数类型与规范返回类型,调用则重新进入正常的执行流水线。成功调用会解析为策略处理后的最终规范 JSON 值,而不是渲染后的 Native 内容。失败调用会以真正的 `ToolCallError` reject;程序只能检查其 `name`、`toolName` 和可供人阅读的 `message`,无法取得内部错误代码或失败联合。
请把 `output.schema` 设计为实用的程序化 API:直接返回句柄与字段;当标量、数组或 null 确实就是结果时,允许采用相应的根类型;将面向人类的解释放入 `output.render`。中间值只存在于执行期间,不会被持久化或按提示词上限截断,也不设字节上限,因此生产方如实声明的采集边界和进程内存仍然重要。只有外层 `run_code` 日志/结果会受到可配置输出上限和面向模型的 spill 流水线约束。
diff --git a/docs/cookbook/extension-cookbook.i18n.yaml b/docs/cookbook/extension-cookbook.i18n.yaml
index 24c280ae11..b24e6b88b2 100644
--- a/docs/cookbook/extension-cookbook.i18n.yaml
+++ b/docs/cookbook/extension-cookbook.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/extension-cookbook.md
-extension-cookbook.md: 7b8c55837038aa421850449ebf553eb1ef47218f
-extension-cookbook.zh.md: 899fcca4ad3c8977044da5a17e40283905abc752
+extension-cookbook.md: bb3f327691d1ff6199407c241f4fa77cd4b23b87
+extension-cookbook.zh.md: db8f0850bdada35cb6d33eed874c44f20d7be9d3
diff --git a/docs/cookbook/extension-cookbook.md b/docs/cookbook/extension-cookbook.md
index 7b8c558370..bb3f327691 100644
--- a/docs/cookbook/extension-cookbook.md
+++ b/docs/cookbook/extension-cookbook.md
@@ -96,7 +96,7 @@ Shipped applications contribute profile layers through `packages/bundle/*/cordis
Every product feature maps to a listener on a documented extension point — the microkernel claim made checkable ([microkernel Agent Note](../../.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md)). No row modifies the loop.
-`system-prompt/assemble` is an expert cooperative whole-assembly transform: its returned assembly is authoritative, so listener authors own preserving active Code Mode and structured-output protocol contributions. Prefer `ctx.tools.restrict()` for tool filtering that must stay aligned across presentation, lookup, and execution.
+`system-prompt/assemble` is an expert cooperative whole-assembly transform: its returned assembly is authoritative, so listener authors own preserving active PTC mode and structured-output protocol contributions. Prefer `ctx.tools.restrict()` for tool filtering that must stay aligned across presentation, lookup, and execution.
| Product feature | Plugin mechanism |
|---|---|
diff --git a/docs/cookbook/extension-cookbook.zh.md b/docs/cookbook/extension-cookbook.zh.md
index 899fcca4ad..db8f0850bd 100644
--- a/docs/cookbook/extension-cookbook.zh.md
+++ b/docs/cookbook/extension-cookbook.zh.md
@@ -100,7 +100,7 @@ export function apply(ctx: Context) {
每个产品功能都映射到一个文档化扩展点上的监听器——微内核声明由此可验证([微内核 Agent Note](../../.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md))。没有任何一行修改循环本身。
-`system-prompt/assemble` 是一个专家协作式的整体装配变换:其返回的装配结果具有权威性,因此监听器作者有责任保留活跃的 Code Mode 和结构化输出协议的贡献。对于需要在展示、查找和执行之间保持对齐的工具过滤,优先使用 `ctx.tools.restrict()`。
+`system-prompt/assemble` 是一个专家协作式的整体装配变换:其返回的装配结果具有权威性,因此监听器作者有责任保留活跃的 PTC mode 和结构化输出协议的贡献。对于需要在展示、查找和执行之间保持对齐的工具过滤,优先使用 `ctx.tools.restrict()`。
| 产品功能 | 插件机制 |
|---|---|
diff --git a/docs/development.i18n.yaml b/docs/development.i18n.yaml
index fad92b97e3..c45e00ced7 100644
--- a/docs/development.i18n.yaml
+++ b/docs/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 docs/development.md
-development.md: 12797904fab31d613db92af0da0656146eeea51a
-development.zh.md: c759f4236efa356c5cc82dcec758654362fcc284
+development.md: 7fc6ae14266253b9e50a1a5f3e9ee6f8e6fbcde7
+development.zh.md: 79e25b489d4c7c3f425460d5bffd0c0265f5b02b
diff --git a/docs/development.md b/docs/development.md
index 12797904fa..7fc6ae1426 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -59,7 +59,7 @@ Host and Client stay two aggregate programs because both sides declaration-merge
- A script that builds a repo-wide `ts.Program` seeds `tsconfig.host.json` or `tsconfig.client.json` explicitly — never the root solution, because flattening both aggregates into one program collides the `Context` merges.
- A new package is registered in exactly one aggregate; only the split packages above carry both leaf configs, and the shared leaves are registered in both aggregates because each side must type-check the same source. Having both a Node loader entry and a browser entry is not a reason to split a package; an ordinary Client plugin produces both runtime artifacts during the Client build phase.
-Five packages split Host and Client tsconfigs: `api/remotes`, `api/gateway`, `api/session-controller`, `api/workspace-controller`, and `client/connection`. `api/remotes`' Host entry must participate in the Host Typert graph, while its Client entry imports `/remote` declarations that Host tsdown must generate first. Each split package-root `tsconfig.json` is therefore only a solution, and the two aggregates and direct consumers reference `tsconfig.host.json` or `tsconfig.client.json` respectively. The workspace `constraints` gate walks the reachable Project Reference graph and checks each referencing project's own compiler face: a single-config target remains valid from either face, while a split target must name the matching leaf rather than its solution root or opposite leaf; it discovers split packages from the presence of both leaf configs, so a new split joins the gate automatically. The [`api-remotes` README](../packages/api/remotes/README.md) explains the Host/Client split and build order.
+Six packages split Host and Client tsconfigs: `api/remotes`, `api/gateway`, `api/session-controller`, `api/workspace-controller`, `client/connection`, and `session-query/session-log-export`. `api/remotes`' Host entry participates in the Host Typert graph while its Client entry imports generated `/remote` declarations; `session-log-export` keeps Node archive production out of its browser controller. Each split package-root `tsconfig.json` is therefore only a solution, and the two aggregates and direct consumers reference `tsconfig.host.json` or `tsconfig.client.json` respectively. The workspace `constraints` gate walks the reachable Project Reference graph and checks each referencing project's own compiler face: a single-config target remains valid from either face, while a split target must name the matching leaf rather than its solution root or opposite leaf; it discovers split packages from the presence of both leaf configs, so a new split joins the gate automatically. The [`api-remotes` README](../packages/api/remotes/README.md) and [`session-log-export` README](../packages/session-query/session-log-export/README.md) explain their splits.
The root build follows the generated dependency order:
@@ -140,10 +140,10 @@ The one-shot Headless coding agent needs `DEEPSEEK_API_KEY` in the environment o
pnpm dsh --profile headless "summarize this workspace"
```
-The Code Mode demo runs the same headless profile with code presentation enabled:
+The PTC mode demo runs the same headless profile with code presentation enabled:
```sh
-pnpm run demo:code-mode -- "summarize this workspace"
+pnpm run demo:ptc -- "summarize this workspace"
```
### TODO markers
diff --git a/docs/development.zh.md b/docs/development.zh.md
index c759f4236e..79e25b489d 100644
--- a/docs/development.zh.md
+++ b/docs/development.zh.md
@@ -63,7 +63,7 @@ Host 与 Client 保持两个 aggregate program,是因为两侧在相同键下
- 构造全仓 `ts.Program` 的脚本显式以 `tsconfig.host.json` 或 `tsconfig.client.json` 为种子——根 solution 永不作为种子,因为把两个 aggregate 展平进一个 program 会撞上 `Context` 合并冲突。
- 新包只登记进一个 aggregate;只有上述拆分包同时携带两个 leaf 配置,共享 leaf 因两侧需要对同一份源码做类型检查而登记进两个 aggregate。包同时具有 Node loader 入口和 browser 入口并不构成拆分理由;普通 Client 插件的两份运行时产物都在 Client 构建阶段生成。
-拆分 Host/Client tsconfig 的包有五个:`api/remotes`、`api/gateway`、`api/session-controller`、`api/workspace-controller` 与 `client/connection`。`api/remotes` 的 Host 入口必须进入 Host Typert 图,而 Client 入口导入 Host tsdown 才会生成的 `/remote` 声明,因此每个拆分包根 `tsconfig.json` 只作为 solution,两个 aggregate 和直接消费方分别引用 `tsconfig.host.json` 或 `tsconfig.client.json`。workspace `constraints` 门禁遍历可达的 Project Reference 图,并按各引用 project 自身的 compiler face 检查:只有单一配置的目标可由任一 face 引用,拆分配置的目标则必须引用匹配的 leaf,不得引用 solution 根或另一侧 leaf;该门禁按「两个 leaf 配置同时存在」自动发现拆分包,所以新拆分的包会自动纳入管辖。[`api-remotes` README](../packages/api/remotes/README.zh.md) 说明 Host/Client 拆分与构建顺序。
+拆分 Host/Client tsconfig 的包有六个:`api/remotes`、`api/gateway`、`api/session-controller`、`api/workspace-controller`、`client/connection` 与 `session-query/session-log-export`。`api/remotes` 的 Host 入口进入 Host Typert 图,而 Client 入口导入生成的 `/remote` 声明;`session-log-export` 则让 Node archive 生产代码不进入浏览器 controller。每个拆分包根 `tsconfig.json` 因此只作为 solution,两个 aggregate 和直接消费方分别引用 `tsconfig.host.json` 或 `tsconfig.client.json`。workspace `constraints` 门禁遍历可达的 Project Reference 图,并按各引用 project 自身的 compiler face 检查:只有单一配置的目标可由任一 face 引用,拆分配置的目标则必须引用匹配的 leaf,不得引用 solution 根或另一侧 leaf;该门禁按「两个 leaf 配置同时存在」自动发现拆分包,所以新拆分的包会自动纳入管辖。[`api-remotes` README](../packages/api/remotes/README.zh.md) 与 [`session-log-export` README](../packages/session-query/session-log-export/README.zh.md)分别说明其拆分。
根构建按生成依赖排序:
@@ -144,10 +144,10 @@ pnpm run build
pnpm dsh --profile headless "summarize this workspace"
```
-Code Mode 演示启用代码式工具展示,并运行同一个 headless profile:
+PTC mode 演示启用代码式工具展示,并运行同一个 headless profile:
```sh
-pnpm run demo:code-mode -- "summarize this workspace"
+pnpm run demo:ptc -- "summarize this workspace"
```
### TODO 标记
diff --git a/docs/event-producer-consumer.i18n.yaml b/docs/event-producer-consumer.i18n.yaml
index dc55a4ee59..7883982b1b 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: 91bfb814a4370fdafb6d62bc79259495b0069dda
-event-producer-consumer.zh.md: e7dcd089f28888bdb235ee0a6df97dc4189f0723
+event-producer-consumer.md: 8c3a8a3f0e19f50e5a3164e2f5f4ac0a4e1046eb
+event-producer-consumer.zh.md: 65b8fba3dd5b9654ffbd037dded15abe85c5885c
diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md
index 91bfb814a4..8c3a8a3f0e 100644
--- a/docs/event-producer-consumer.md
+++ b/docs/event-producer-consumer.md
@@ -21,11 +21,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `agent/session-start` | `emit` | [`packages/core/agent/src/runtime-types.ts:224`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | `agent-team`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:185`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`schedule`](../packages/schedule/schedule), `server`, `session-controller` |
| `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:285`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
-| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:502`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:482`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:509`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:488`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:495`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:537`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:517`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:544`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:523`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:530`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
| `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:85`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes` |
| `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | [`authorization`](../packages/credentials/authorization) |
| `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:80`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` |
@@ -43,7 +43,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:58`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) |
| `goal/changed` | `emit` | [`packages/goal/goal/src/domain.ts:114`](../packages/goal/goal/src/domain.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver) |
| `llm/adapters-updated` | `emit` | [`packages/llm/llm/src/types.ts:23`](../packages/llm/llm/src/types.ts) | [`llm`](../packages/llm/llm) (`events.dispatch`) | [`acp`](../packages/acp/acp), [`llm`](../packages/llm/llm), `remotes` |
-| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:66`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`waterfall`) | [`agent-loop`](../packages/core/agent-loop), [`llm`](../packages/llm/llm), [`llm-replay`](../packages/test-support/llm-replay), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-title`](../packages/session/session-title) |
+| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:67`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`waterfall`) | [`agent-loop`](../packages/core/agent-loop), [`llm`](../packages/llm/llm), [`llm-replay`](../packages/test-support/llm-replay), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-title`](../packages/session/session-title) |
| `session-telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:43`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:54`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`compaction`](../packages/compaction/compaction), [`goal`](../packages/goal/goal), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`schedule`](../packages/schedule/schedule), `server`, [`session`](../packages/core/session), `session-controller`, [`session-log-deepseek`](../packages/session/session-log-deepseek), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tool-workflow`](../packages/workflow/tool-workflow), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:64`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `agent-team`, `session-controller`, [`session-persistence`](../packages/session/session-persistence), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-title`](../packages/session/session-title) |
@@ -59,13 +59,13 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `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), [`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:207`](../packages/core/tools/src/index.ts) | [`agent-presets`](../packages/preset/agent-presets) (`emit`), [`tools`](../packages/core/tools) (`emit`) | [`tool-subagent`](../packages/subagent/tool-subagent) |
-| `tools/code-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:189`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) |
| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:163`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), `timeout-policy` |
| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:175`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search) |
| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:152`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-jobs`](../packages/jobs/tool-jobs) |
+| `tools/ptc-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:189`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) |
| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:197`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`agent-instructions`](../packages/context/agent-instructions), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
| `user-questions/request` | `waterfall` | [`packages/interaction/user-questions/src/types.ts:85`](../packages/interaction/user-questions/src/types.ts) | [`user-questions`](../packages/interaction/user-questions) (`waterfall`) | `remotes` |
-| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `modules` |
+| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `inspector`, `modules` |
| `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
| `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
| `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) |
@@ -78,8 +78,8 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| Event string | Dispatchers | Listeners |
| --- | --- | --- |
| `internal/dispatch` | - | `agent-team`, [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`schedule`](../packages/schedule/schedule), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-log-deepseek`](../packages/session/session-log-deepseek), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`terminal-bash`](../packages/terminal/terminal-bash), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tool-workflow`](../packages/workflow/tool-workflow), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval), [`webhook`](../packages/webhook/webhook), [`workflow`](../packages/workflow/workflow) |
-| `internal/plugin` | - | `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` |
+| `internal/plugin` | - | `inspector`, `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` |
| `internal/service` | - | [`agent-presets`](../packages/preset/agent-presets), `gateway` |
-| `internal/status` | - | [`agent`](../packages/core/agent) |
+| `internal/status` | - | [`agent`](../packages/core/agent), `inspector` |
Maintenance mode: generated: Cordis event declarations and producer/listener edges are resolved from the repository TypeScript Program.
diff --git a/docs/event-producer-consumer.zh.md b/docs/event-producer-consumer.zh.md
index e7dcd089f2..65b8fba3dd 100644
--- a/docs/event-producer-consumer.zh.md
+++ b/docs/event-producer-consumer.zh.md
@@ -23,11 +23,11 @@
| `agent/session-start` | `emit` | [`packages/core/agent/src/runtime-types.ts:224`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | `agent-team`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:185`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`schedule`](../packages/schedule/schedule), `server`, `session-controller` |
| `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:285`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
-| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:502`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:482`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:509`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:488`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
-| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:495`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:537`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:517`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:544`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:523`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
+| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:530`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` |
| `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:85`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes` |
| `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | [`authorization`](../packages/credentials/authorization) |
| `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:80`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` |
@@ -45,7 +45,7 @@
| `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:58`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) |
| `goal/changed` | `emit` | [`packages/goal/goal/src/domain.ts:114`](../packages/goal/goal/src/domain.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver) |
| `llm/adapters-updated` | `emit` | [`packages/llm/llm/src/types.ts:23`](../packages/llm/llm/src/types.ts) | [`llm`](../packages/llm/llm) (`events.dispatch`) | [`acp`](../packages/acp/acp), [`llm`](../packages/llm/llm), `remotes` |
-| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:66`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`waterfall`) | [`agent-loop`](../packages/core/agent-loop), [`llm`](../packages/llm/llm), [`llm-replay`](../packages/test-support/llm-replay), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-title`](../packages/session/session-title) |
+| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:67`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`waterfall`) | [`agent-loop`](../packages/core/agent-loop), [`llm`](../packages/llm/llm), [`llm-replay`](../packages/test-support/llm-replay), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-title`](../packages/session/session-title) |
| `session-telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:43`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:54`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`compaction`](../packages/compaction/compaction), [`goal`](../packages/goal/goal), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`schedule`](../packages/schedule/schedule), `server`, [`session`](../packages/core/session), `session-controller`, [`session-log-deepseek`](../packages/session/session-log-deepseek), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tool-workflow`](../packages/workflow/tool-workflow), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:64`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `agent-team`, `session-controller`, [`session-persistence`](../packages/session/session-persistence), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-title`](../packages/session/session-title) |
@@ -61,13 +61,13 @@
| `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), [`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:207`](../packages/core/tools/src/index.ts) | [`agent-presets`](../packages/preset/agent-presets) (`emit`), [`tools`](../packages/core/tools) (`emit`) | [`tool-subagent`](../packages/subagent/tool-subagent) |
-| `tools/code-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:189`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) |
| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:163`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), `timeout-policy` |
| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:175`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search) |
| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:152`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-jobs`](../packages/jobs/tool-jobs) |
+| `tools/ptc-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:189`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) |
| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:197`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`agent-instructions`](../packages/context/agent-instructions), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
| `user-questions/request` | `waterfall` | [`packages/interaction/user-questions/src/types.ts:85`](../packages/interaction/user-questions/src/types.ts) | [`user-questions`](../packages/interaction/user-questions) (`waterfall`) | `remotes` |
-| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `modules` |
+| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `inspector`, `modules` |
| `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
| `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
| `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) |
@@ -80,8 +80,8 @@
| 事件字符串 | 派发方 | 监听方 |
| --- | --- | --- |
| `internal/dispatch` | - | `agent-team`, [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`schedule`](../packages/schedule/schedule), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-log-deepseek`](../packages/session/session-log-deepseek), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`terminal-bash`](../packages/terminal/terminal-bash), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tool-workflow`](../packages/workflow/tool-workflow), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval), [`webhook`](../packages/webhook/webhook), [`workflow`](../packages/workflow/workflow) |
-| `internal/plugin` | - | `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` |
+| `internal/plugin` | - | `inspector`, `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` |
| `internal/service` | - | [`agent-presets`](../packages/preset/agent-presets), `gateway` |
-| `internal/status` | - | [`agent`](../packages/core/agent) |
+| `internal/status` | - | [`agent`](../packages/core/agent), `inspector` |
维护模式:生成内容。Cordis 事件声明及生产方/监听方的关系边由仓库的 TypeScript Program 解析。
diff --git a/docs/module-graph.i18n.yaml b/docs/module-graph.i18n.yaml
index 8842ee368d..e07ac51810 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: a8549be65dfd33b1fb18632215b7b1d5ab28e36a
-module-graph.zh.md: cfea33efc07579aebfc25b91675b8d32bedeeb0e
+module-graph.md: 1f1f35789f38e60cb88aee6a6de0c967db53c117
+module-graph.zh.md: 5835824321026e0fd4733a0967289550d704ad02
diff --git a/docs/module-graph.md b/docs/module-graph.md
index a8549be65d..1f1f35789f 100644
--- a/docs/module-graph.md
+++ b/docs/module-graph.md
@@ -210,6 +210,7 @@ flowchart TD
pkg_experimental_agent_team_profile["experimental-agent-team-profile"]
pkg_experimental_agent_team_web_profile["experimental-agent-team-web-profile"]
pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"]
+ pkg_experimental_inspector["experimental-inspector"]
pkg_experimental_tool_agent_team["experimental-tool-agent-team"]
pkg_experimental_webworker_packer["experimental-webworker-packer"]
pkg_experimental_webworker_runtime["experimental-webworker-runtime"]
@@ -229,7 +230,6 @@ flowchart TD
pkg_tool_call_timeout_policy["tool-call-timeout-policy"]
end
subgraph group_host["packages/host"]
- pkg_host_apiproxy["host-apiproxy"]
pkg_host_directory_picker["host-directory-picker"]
pkg_host_directory_picker_auto["host-directory-picker-auto"]
pkg_host_directory_picker_browse["host-directory-picker-browse"]
@@ -427,6 +427,7 @@ flowchart TD
pkg_llm --> pkg_brand
pkg_llm --> pkg_invariants
pkg_llm --> pkg_timeout
+ pkg_llm --> pkg_typert_protocol
pkg_attachment_local --> pkg_attachment
pkg_attachment_local --> pkg_home_paths
pkg_attachment_local --> pkg_invariants
@@ -438,6 +439,9 @@ flowchart TD
pkg_credentials_local --> pkg_home_paths
pkg_credentials_local --> pkg_invariants
pkg_credentials_local --> pkg_launch_environment
+ pkg_experimental_inspector --> pkg_client_modules
+ pkg_experimental_inspector --> pkg_host_webserver
+ pkg_experimental_inspector --> pkg_invariants
pkg_session --> pkg_brand
pkg_session --> pkg_invariants
pkg_session --> pkg_llm
@@ -536,16 +540,11 @@ flowchart TD
pkg_web_search_deepseek --> pkg_web
pkg_spill_local --> pkg_invariants
pkg_spill_local --> pkg_spill
- pkg_api_settings_controller --> pkg_credentials
- pkg_api_settings_controller --> pkg_invariants
- pkg_api_settings_controller --> pkg_session
- pkg_api_settings_controller --> pkg_settings
- pkg_api_settings_controller --> pkg_typert_protocol
pkg_file_reference --> pkg_agent
pkg_file_reference --> pkg_invariants
- pkg_file_reference --> pkg_typert_protocol
pkg_time_context --> pkg_agent
pkg_time_context --> pkg_invariants
+ pkg_time_context --> pkg_llm
pkg_time_context --> pkg_session
pkg_message_feedback --> pkg_brand
pkg_message_feedback --> pkg_invariants
@@ -1009,9 +1008,27 @@ flowchart TD
pkg_acp --> pkg_session_persistence
pkg_acp --> pkg_token_meter
pkg_acp --> pkg_user_approval
+ pkg_api_settings_controller --> pkg_agent_presets
+ pkg_api_settings_controller --> pkg_credentials
+ pkg_api_settings_controller --> pkg_invariants
+ pkg_api_settings_controller --> pkg_native_command
+ pkg_api_settings_controller --> pkg_session
+ pkg_api_settings_controller --> pkg_settings
+ pkg_api_settings_controller --> pkg_typert_protocol
pkg_web_app --> pkg_invariants
pkg_web_app --> pkg_shell_env
pkg_web_app --> pkg_system_prompt
+ pkg_client_connection --> pkg_attachment
+ pkg_client_connection --> pkg_brand
+ pkg_client_connection --> pkg_commands
+ pkg_client_connection --> pkg_credentials
+ pkg_client_connection --> pkg_host_directory_picker
+ pkg_client_connection --> pkg_host_webserver
+ pkg_client_connection --> pkg_invariants
+ pkg_client_connection --> pkg_llm
+ pkg_client_connection --> pkg_session
+ pkg_client_connection --> pkg_settings
+ pkg_client_connection --> pkg_tool_todo
pkg_compaction_tool_result_pruner --> pkg_compaction
pkg_compaction_tool_result_pruner --> pkg_invariants
pkg_compaction_tool_result_pruner --> pkg_llm
@@ -1025,8 +1042,6 @@ flowchart TD
pkg_tool_cordis --> pkg_session
pkg_tool_cordis --> pkg_system_prompt
pkg_tool_cordis --> pkg_tools
- pkg_host_apiproxy --> pkg_agent_presets
- pkg_host_apiproxy --> pkg_invariants
pkg_tool_bash --> pkg_agent
pkg_tool_bash --> pkg_invariants
pkg_tool_bash --> pkg_jobs
@@ -1088,17 +1103,11 @@ flowchart TD
pkg_tool_session_query --> pkg_system_prompt
pkg_tool_session_query --> pkg_timeout
pkg_tool_session_query --> pkg_tools
- pkg_client_connection --> pkg_attachment
- pkg_client_connection --> pkg_commands
- pkg_client_connection --> pkg_credentials
- pkg_client_connection --> pkg_host_apiproxy
- pkg_client_connection --> pkg_host_directory_picker
- pkg_client_connection --> pkg_host_webserver
- pkg_client_connection --> pkg_invariants
- pkg_client_connection --> pkg_llm
- pkg_client_connection --> pkg_session
- pkg_client_connection --> pkg_settings
- pkg_client_connection --> pkg_tool_todo
+ pkg_api_gateway --> pkg_brand
+ pkg_api_gateway --> pkg_client_connection
+ pkg_api_gateway --> pkg_host_webserver
+ pkg_api_gateway --> pkg_invariants
+ pkg_api_gateway --> pkg_typert_registry
pkg_compaction_basic --> pkg_agent
pkg_compaction_basic --> pkg_commands
pkg_compaction_basic --> pkg_compaction
@@ -1113,7 +1122,10 @@ flowchart TD
pkg_session_reference --> pkg_llm
pkg_session_reference --> pkg_output_retention
pkg_session_reference --> pkg_session
+ pkg_session_reference --> pkg_session_projection
+ pkg_session_reference --> pkg_session_projection_cache
pkg_session_reference --> pkg_session_query
+ pkg_session_reference --> pkg_session_title
pkg_session_reference --> pkg_typert_protocol
pkg_agent_spine_demo --> pkg_agent
pkg_agent_spine_demo --> pkg_agent_instructions
@@ -1137,10 +1149,13 @@ flowchart TD
pkg_agent_spine_demo --> pkg_tool_jobs
pkg_agent_spine_demo --> pkg_tool_skill
pkg_agent_spine_demo --> pkg_tools
+ pkg_experimental_webworker_runtime --> pkg_client_connection
pkg_experimental_webworker_runtime --> pkg_client_modules
- pkg_experimental_webworker_runtime --> pkg_host_apiproxy
pkg_experimental_webworker_runtime --> pkg_host_webserver
pkg_experimental_webworker_runtime --> pkg_invariants
+ pkg_host_frontend_static --> pkg_client_connection
+ pkg_host_frontend_static --> pkg_host_webserver
+ pkg_host_frontend_static --> pkg_invariants
pkg_webhook_github --> pkg_credentials
pkg_webhook_github --> pkg_host_webserver
pkg_webhook_github --> pkg_invariants
@@ -1200,11 +1215,39 @@ flowchart TD
pkg_hooks_claude_code --> pkg_session_persistence
pkg_hooks_claude_code --> pkg_subagent
pkg_hooks_claude_code --> pkg_tools
- pkg_api_gateway --> pkg_brand
- pkg_api_gateway --> pkg_client_connection
- pkg_api_gateway --> pkg_host_webserver
- pkg_api_gateway --> pkg_invariants
- pkg_api_gateway --> pkg_typert_registry
+ pkg_api_session_controller --> pkg_agent
+ pkg_api_session_controller --> pkg_agent_default_model
+ pkg_api_session_controller --> pkg_agent_presets
+ pkg_api_session_controller --> pkg_api_gateway
+ pkg_api_session_controller --> pkg_attachment
+ pkg_api_session_controller --> pkg_brand
+ pkg_api_session_controller --> pkg_client_connection
+ pkg_api_session_controller --> pkg_file_reference
+ pkg_api_session_controller --> pkg_invariants
+ pkg_api_session_controller --> pkg_jobs
+ pkg_api_session_controller --> pkg_llm
+ pkg_api_session_controller --> pkg_native_command
+ pkg_api_session_controller --> pkg_scope
+ pkg_api_session_controller --> pkg_session
+ pkg_api_session_controller --> pkg_session_persistence
+ pkg_api_session_controller --> pkg_session_projection
+ pkg_api_session_controller --> pkg_session_projection_cache
+ pkg_api_session_controller --> pkg_session_query
+ pkg_api_session_controller --> pkg_session_title
+ pkg_api_session_controller --> pkg_skill
+ pkg_api_session_controller --> pkg_subagent
+ pkg_api_session_controller --> pkg_typert_protocol
+ pkg_api_session_controller --> pkg_typert_registry
+ pkg_api_session_controller --> pkg_util_workspace_path
+ pkg_api_session_controller --> pkg_workspace
+ pkg_api_workspace_controller --> pkg_api_gateway
+ pkg_api_workspace_controller --> pkg_client_connection
+ pkg_api_workspace_controller --> pkg_host_directory_picker
+ pkg_api_workspace_controller --> pkg_invariants
+ pkg_api_workspace_controller --> pkg_session
+ pkg_api_workspace_controller --> pkg_storage_domain
+ pkg_api_workspace_controller --> pkg_typert_protocol
+ pkg_api_workspace_controller --> pkg_workspace
pkg_experimental_agent_team --> pkg_agent
pkg_experimental_agent_team --> pkg_brand
pkg_experimental_agent_team --> pkg_invariants
@@ -1213,9 +1256,6 @@ flowchart TD
pkg_experimental_agent_team --> pkg_session_persistence
pkg_experimental_agent_team --> pkg_subagent
pkg_experimental_agent_team --> pkg_typert_protocol
- pkg_host_frontend_static --> pkg_client_connection
- pkg_host_frontend_static --> pkg_host_webserver
- pkg_host_frontend_static --> pkg_invariants
pkg_sdk_protocol --> pkg_invariants
pkg_sdk_protocol --> pkg_llm
pkg_sdk_protocol --> pkg_session
@@ -1243,36 +1283,30 @@ flowchart TD
pkg_subagent_spawn_in_process --> pkg_invariants
pkg_subagent_spawn_in_process --> pkg_subagent
pkg_subagent_spawn_in_process --> pkg_subagent_in_process_driver
- pkg_api_session_controller --> pkg_agent
- pkg_api_session_controller --> pkg_agent_default_model
- pkg_api_session_controller --> pkg_agent_presets
- pkg_api_session_controller --> pkg_api_gateway
- pkg_api_session_controller --> pkg_attachment
- pkg_api_session_controller --> pkg_brand
- pkg_api_session_controller --> pkg_client_connection
- pkg_api_session_controller --> pkg_invariants
- pkg_api_session_controller --> pkg_jobs
- pkg_api_session_controller --> pkg_llm
- pkg_api_session_controller --> pkg_scope
- pkg_api_session_controller --> pkg_session
- pkg_api_session_controller --> pkg_session_persistence
- pkg_api_session_controller --> pkg_session_projection
- pkg_api_session_controller --> pkg_session_projection_cache
- pkg_api_session_controller --> pkg_session_query
- pkg_api_session_controller --> pkg_session_title
- pkg_api_session_controller --> pkg_subagent
- pkg_api_session_controller --> pkg_typert_protocol
- pkg_api_session_controller --> pkg_typert_registry
- pkg_api_session_controller --> pkg_util_workspace_path
- pkg_api_session_controller --> pkg_workspace
- pkg_api_workspace_controller --> pkg_api_gateway
- pkg_api_workspace_controller --> pkg_client_connection
- pkg_api_workspace_controller --> pkg_host_directory_picker
- pkg_api_workspace_controller --> pkg_invariants
- pkg_api_workspace_controller --> pkg_session
- pkg_api_workspace_controller --> pkg_storage_domain
- pkg_api_workspace_controller --> pkg_typert_protocol
- pkg_api_workspace_controller --> pkg_workspace
+ pkg_api_remotes --> pkg_agent_presets
+ pkg_api_remotes --> pkg_api_gateway
+ pkg_api_remotes --> pkg_api_session_controller
+ pkg_api_remotes --> pkg_api_settings_controller
+ pkg_api_remotes --> pkg_api_workspace_controller
+ pkg_api_remotes --> pkg_commands
+ pkg_api_remotes --> pkg_cordis_host_runner
+ pkg_api_remotes --> pkg_credentials
+ pkg_api_remotes --> pkg_file_reference
+ pkg_api_remotes --> pkg_goal
+ pkg_api_remotes --> pkg_host_plugin_inventory
+ pkg_api_remotes --> pkg_invariants
+ pkg_api_remotes --> pkg_llm
+ pkg_api_remotes --> pkg_message_feedback
+ pkg_api_remotes --> pkg_session
+ pkg_api_remotes --> pkg_session_reference
+ pkg_api_remotes --> pkg_settings
+ pkg_api_remotes --> pkg_subagent
+ pkg_api_remotes --> pkg_user_approval
+ pkg_api_remotes --> pkg_user_questions
+ pkg_client_ui_session --> pkg_api_session_controller
+ pkg_client_ui_session --> pkg_client_ui_renderer
+ pkg_client_ui_session --> pkg_invariants
+ pkg_client_ui_session --> pkg_session
pkg_experimental_tool_agent_team --> pkg_agent
pkg_experimental_tool_agent_team --> pkg_experimental_agent_team
pkg_experimental_tool_agent_team --> pkg_invariants
@@ -1299,30 +1333,6 @@ flowchart TD
pkg_subagent_dsh_sdk --> pkg_session
pkg_subagent_dsh_sdk --> pkg_subagent
pkg_subagent_dsh_sdk --> pkg_subprocess
- pkg_api_remotes --> pkg_agent_presets
- pkg_api_remotes --> pkg_api_gateway
- pkg_api_remotes --> pkg_api_session_controller
- pkg_api_remotes --> pkg_api_settings_controller
- pkg_api_remotes --> pkg_api_workspace_controller
- pkg_api_remotes --> pkg_commands
- pkg_api_remotes --> pkg_cordis_host_runner
- pkg_api_remotes --> pkg_credentials
- pkg_api_remotes --> pkg_file_reference
- pkg_api_remotes --> pkg_goal
- pkg_api_remotes --> pkg_host_plugin_inventory
- pkg_api_remotes --> pkg_invariants
- pkg_api_remotes --> pkg_llm
- pkg_api_remotes --> pkg_message_feedback
- pkg_api_remotes --> pkg_session
- pkg_api_remotes --> pkg_session_reference
- pkg_api_remotes --> pkg_settings
- pkg_api_remotes --> pkg_subagent
- pkg_api_remotes --> pkg_user_approval
- pkg_api_remotes --> pkg_user_questions
- pkg_client_ui_session --> pkg_api_session_controller
- pkg_client_ui_session --> pkg_client_ui_renderer
- pkg_client_ui_session --> pkg_invariants
- pkg_client_ui_session --> pkg_session
pkg_client_ui_settings --> pkg_api_remotes
pkg_client_ui_settings --> pkg_client_connection
pkg_client_ui_settings --> pkg_invariants
@@ -1334,7 +1344,6 @@ flowchart TD
pkg_client_locale --> pkg_invariants
pkg_client_locale --> pkg_settings
pkg_client_ui_settings_models --> pkg_api_remotes
- pkg_client_ui_settings_models --> pkg_client_connection
pkg_client_ui_settings_models --> pkg_client_locale
pkg_client_ui_settings_models --> pkg_client_ui_renderer
pkg_client_ui_settings_models --> pkg_client_ui_settings
@@ -1345,6 +1354,7 @@ flowchart TD
pkg_client_ui_settings_plugin_inventory --> pkg_client_ui_settings
pkg_client_ui_settings_plugin_inventory --> pkg_invariants
pkg_client_ui_settings_plugins --> pkg_api_remotes
+ pkg_client_ui_settings_plugins --> pkg_client_connection
pkg_client_ui_settings_plugins --> pkg_client_locale
pkg_client_ui_settings_plugins --> pkg_client_ui_renderer
pkg_client_ui_settings_plugins --> pkg_client_ui_settings
@@ -1531,6 +1541,7 @@ flowchart TD
pkg_client_ui_chat --> pkg_client_ui_layout
pkg_client_ui_chat --> pkg_client_ui_renderer
pkg_client_ui_chat --> pkg_client_ui_session
+ pkg_client_ui_chat --> pkg_client_ui_settings
pkg_client_ui_chat --> pkg_client_ui_workspace
pkg_client_ui_chat --> pkg_commands
pkg_client_ui_chat --> pkg_compaction
@@ -1539,6 +1550,7 @@ flowchart TD
pkg_client_ui_chat --> pkg_llm_retry
pkg_client_ui_chat --> pkg_session
pkg_client_ui_chat --> pkg_session_stats
+ pkg_client_ui_chat --> pkg_settings
pkg_client_ui_chat --> pkg_token_meter
pkg_client_ui_chat --> pkg_tools
pkg_client_ui_chat --> pkg_util_workspace_path
@@ -1553,12 +1565,15 @@ flowchart TD
pkg_client_ui_commands --> pkg_invariants
pkg_client_ui_commands --> pkg_session
pkg_client_ui_reference --> pkg_api_remotes
+ pkg_client_ui_reference --> pkg_api_session_controller
+ pkg_client_ui_reference --> pkg_client_connection
pkg_client_ui_reference --> pkg_client_locale
pkg_client_ui_reference --> pkg_client_ui_input_trigger
pkg_client_ui_reference --> pkg_file_reference
pkg_client_ui_reference --> pkg_invariants
pkg_client_ui_reference --> pkg_session_reference
pkg_client_ui_reference --> pkg_typert_protocol
+ pkg_client_ui_reference --> pkg_util_workspace_path
pkg_client_ui_subagent --> pkg_api_session_controller
pkg_client_ui_subagent --> pkg_client_connection
pkg_client_ui_subagent --> pkg_client_locale
@@ -1576,6 +1591,8 @@ flowchart TD
pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
pkg_host_directory_picker_auto --> pkg_host_webserver
pkg_host_directory_picker_auto --> pkg_invariants
+ pkg_session_log_export --> pkg_attachment
+ pkg_session_log_export --> pkg_client_connection
pkg_session_log_export --> pkg_client_locale
pkg_session_log_export --> pkg_client_ui_commands
pkg_session_log_export --> pkg_client_ui_conversation
@@ -1583,12 +1600,16 @@ flowchart TD
pkg_session_log_export --> pkg_client_ui_session
pkg_session_log_export --> pkg_commands
pkg_session_log_export --> pkg_invariants
+ pkg_session_log_export --> pkg_session
+ pkg_session_log_export --> pkg_session_persistence
+ pkg_session_log_export --> pkg_session_query
pkg_client_ui_attachment --> pkg_attachment
pkg_client_ui_attachment --> pkg_client_ui_chat
pkg_client_ui_attachment --> pkg_client_ui_conversation
pkg_client_ui_attachment --> pkg_client_ui_renderer
pkg_client_ui_attachment --> pkg_client_ui_trajectory
pkg_client_ui_attachment --> pkg_invariants
+ pkg_client_ui_deliverables --> pkg_api_remotes
pkg_client_ui_deliverables --> pkg_client_connection
pkg_client_ui_deliverables --> pkg_client_locale
pkg_client_ui_deliverables --> pkg_client_ui_chat
@@ -1622,7 +1643,6 @@ flowchart TD
pkg_client_ui_message_feedback --> pkg_typert_protocol
pkg_client_ui_model_selection --> pkg_api_remotes
pkg_client_ui_model_selection --> pkg_api_session_controller
- pkg_client_ui_model_selection --> pkg_client_connection
pkg_client_ui_model_selection --> pkg_client_locale
pkg_client_ui_model_selection --> pkg_client_ui_commands
pkg_client_ui_model_selection --> pkg_client_ui_conversation
@@ -1750,10 +1770,11 @@ flowchart TD
| [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
| [`subprocess-local`](../packages/subprocess/subprocess-local) | `subprocess` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`typert-loader`](../packages/typert/loader) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
-| [`llm`](../packages/llm/llm) | `llm` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout) |
+| [`llm`](../packages/llm/llm) | `llm` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`typert-protocol`](../packages/typert/protocol) |
| [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`client-hmr`](../packages/client/hmr) | `client` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) |
+| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`session`](../packages/core/session) | `core` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`typert-protocol`](../packages/typert/protocol) |
| [`system-prompt`](../packages/core/system-prompt) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
| [`skill`](../packages/skill/skill) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
@@ -1781,9 +1802,8 @@ flowchart TD
| [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) |
| [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`web`](../packages/web/web) |
| [`spill-local`](../packages/spill/spill-local) | `spill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`spill`](../packages/spill/spill) |
-| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
-| [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) |
-| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
+| [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
| [`message-feedback`](../packages/feedback/message-feedback) | `feedback` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol) |
| [`commands`](../packages/interaction/commands) | `interaction` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
| [`user-approval`](../packages/interaction/user-approval) | `interaction` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
@@ -1866,21 +1886,23 @@ flowchart TD
| [`plugin-package-inventory-deepseek`](../packages/llm/plugin-package-inventory-deepseek) | `llm` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
| [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-title`](../packages/session/session-title), [`tool-todo`](../packages/todo/tool-todo) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
+| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`native-command`](../packages/util/native-command), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
+| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) |
| [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | `compaction` | [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`agent`](../packages/core/agent), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
-| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`agent-presets`](../packages/preset/agent-presets), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`tool-bash`](../packages/shell/tool-bash) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`tool-pwsh`](../packages/shell/tool-pwsh) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`webhook`](../packages/webhook/webhook) | `webhook` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`workspace`](../packages/workspace/workspace) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) |
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
-| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-apiproxy`](../packages/host/apiproxy), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) |
+| [`api-gateway`](../packages/api/gateway) | `api` | [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
| [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
-| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`typert-protocol`](../packages/typert/protocol) |
+| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`typert-protocol`](../packages/typert/protocol) |
| [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
-| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-modules`](../packages/client/modules), [`host-apiproxy`](../packages/host/apiproxy), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`webhook-github`](../packages/webhook/webhook-github) | `webhook` | [`credentials`](../packages/credentials/credentials), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`webhook`](../packages/webhook/webhook) |
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-claude-code`](../packages/subagent/subagent-claude-code) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
@@ -1890,27 +1912,25 @@ flowchart TD
| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`hooks-claude-code`](../packages/hooks/hooks-claude-code) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
-| [`api-gateway`](../packages/api/gateway) | `api` | [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
+| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`native-command`](../packages/util/native-command), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`skill`](../packages/skill/skill), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
+| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
| [`experimental-agent-team`](../packages/experimental/agent-team) | `experimental` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
-| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
| [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
-| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
-| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
+| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) |
+| [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
| [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team) | `experimental` | [`agent`](../packages/core/agent), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
| [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
-| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) |
-| [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
-| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
@@ -1930,17 +1950,17 @@ flowchart TD
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`agent`](../packages/core/agent), [`api-session-controller`](../packages/api/session-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
| [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol), [`user-questions`](../packages/interaction/user-questions) |
| [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
-| [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) |
+| [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`settings`](../packages/settings/settings), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) |
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
-| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol) |
+| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) |
| [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter) |
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`client-ui-attachment`](../packages/client/ui-attachment) | `client` | [`attachment`](../packages/attachment/attachment), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-trajectory`](../packages/client/ui-trajectory), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
+| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
| [`client-ui-goal`](../packages/client/ui-goal) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
| [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
-| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
+| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) |
| [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`util-workspace-path`](../packages/util/workspace-path) |
| [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md
index cfea33efc0..5835824321 100644
--- a/docs/module-graph.zh.md
+++ b/docs/module-graph.zh.md
@@ -212,6 +212,7 @@ flowchart TD
pkg_experimental_agent_team_profile["experimental-agent-team-profile"]
pkg_experimental_agent_team_web_profile["experimental-agent-team-web-profile"]
pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"]
+ pkg_experimental_inspector["experimental-inspector"]
pkg_experimental_tool_agent_team["experimental-tool-agent-team"]
pkg_experimental_webworker_packer["experimental-webworker-packer"]
pkg_experimental_webworker_runtime["experimental-webworker-runtime"]
@@ -231,7 +232,6 @@ flowchart TD
pkg_tool_call_timeout_policy["tool-call-timeout-policy"]
end
subgraph group_host["packages/host"]
- pkg_host_apiproxy["host-apiproxy"]
pkg_host_directory_picker["host-directory-picker"]
pkg_host_directory_picker_auto["host-directory-picker-auto"]
pkg_host_directory_picker_browse["host-directory-picker-browse"]
@@ -429,6 +429,7 @@ flowchart TD
pkg_llm --> pkg_brand
pkg_llm --> pkg_invariants
pkg_llm --> pkg_timeout
+ pkg_llm --> pkg_typert_protocol
pkg_attachment_local --> pkg_attachment
pkg_attachment_local --> pkg_home_paths
pkg_attachment_local --> pkg_invariants
@@ -440,6 +441,9 @@ flowchart TD
pkg_credentials_local --> pkg_home_paths
pkg_credentials_local --> pkg_invariants
pkg_credentials_local --> pkg_launch_environment
+ pkg_experimental_inspector --> pkg_client_modules
+ pkg_experimental_inspector --> pkg_host_webserver
+ pkg_experimental_inspector --> pkg_invariants
pkg_session --> pkg_brand
pkg_session --> pkg_invariants
pkg_session --> pkg_llm
@@ -538,16 +542,11 @@ flowchart TD
pkg_web_search_deepseek --> pkg_web
pkg_spill_local --> pkg_invariants
pkg_spill_local --> pkg_spill
- pkg_api_settings_controller --> pkg_credentials
- pkg_api_settings_controller --> pkg_invariants
- pkg_api_settings_controller --> pkg_session
- pkg_api_settings_controller --> pkg_settings
- pkg_api_settings_controller --> pkg_typert_protocol
pkg_file_reference --> pkg_agent
pkg_file_reference --> pkg_invariants
- pkg_file_reference --> pkg_typert_protocol
pkg_time_context --> pkg_agent
pkg_time_context --> pkg_invariants
+ pkg_time_context --> pkg_llm
pkg_time_context --> pkg_session
pkg_message_feedback --> pkg_brand
pkg_message_feedback --> pkg_invariants
@@ -1011,9 +1010,27 @@ flowchart TD
pkg_acp --> pkg_session_persistence
pkg_acp --> pkg_token_meter
pkg_acp --> pkg_user_approval
+ pkg_api_settings_controller --> pkg_agent_presets
+ pkg_api_settings_controller --> pkg_credentials
+ pkg_api_settings_controller --> pkg_invariants
+ pkg_api_settings_controller --> pkg_native_command
+ pkg_api_settings_controller --> pkg_session
+ pkg_api_settings_controller --> pkg_settings
+ pkg_api_settings_controller --> pkg_typert_protocol
pkg_web_app --> pkg_invariants
pkg_web_app --> pkg_shell_env
pkg_web_app --> pkg_system_prompt
+ pkg_client_connection --> pkg_attachment
+ pkg_client_connection --> pkg_brand
+ pkg_client_connection --> pkg_commands
+ pkg_client_connection --> pkg_credentials
+ pkg_client_connection --> pkg_host_directory_picker
+ pkg_client_connection --> pkg_host_webserver
+ pkg_client_connection --> pkg_invariants
+ pkg_client_connection --> pkg_llm
+ pkg_client_connection --> pkg_session
+ pkg_client_connection --> pkg_settings
+ pkg_client_connection --> pkg_tool_todo
pkg_compaction_tool_result_pruner --> pkg_compaction
pkg_compaction_tool_result_pruner --> pkg_invariants
pkg_compaction_tool_result_pruner --> pkg_llm
@@ -1027,8 +1044,6 @@ flowchart TD
pkg_tool_cordis --> pkg_session
pkg_tool_cordis --> pkg_system_prompt
pkg_tool_cordis --> pkg_tools
- pkg_host_apiproxy --> pkg_agent_presets
- pkg_host_apiproxy --> pkg_invariants
pkg_tool_bash --> pkg_agent
pkg_tool_bash --> pkg_invariants
pkg_tool_bash --> pkg_jobs
@@ -1090,17 +1105,11 @@ flowchart TD
pkg_tool_session_query --> pkg_system_prompt
pkg_tool_session_query --> pkg_timeout
pkg_tool_session_query --> pkg_tools
- pkg_client_connection --> pkg_attachment
- pkg_client_connection --> pkg_commands
- pkg_client_connection --> pkg_credentials
- pkg_client_connection --> pkg_host_apiproxy
- pkg_client_connection --> pkg_host_directory_picker
- pkg_client_connection --> pkg_host_webserver
- pkg_client_connection --> pkg_invariants
- pkg_client_connection --> pkg_llm
- pkg_client_connection --> pkg_session
- pkg_client_connection --> pkg_settings
- pkg_client_connection --> pkg_tool_todo
+ pkg_api_gateway --> pkg_brand
+ pkg_api_gateway --> pkg_client_connection
+ pkg_api_gateway --> pkg_host_webserver
+ pkg_api_gateway --> pkg_invariants
+ pkg_api_gateway --> pkg_typert_registry
pkg_compaction_basic --> pkg_agent
pkg_compaction_basic --> pkg_commands
pkg_compaction_basic --> pkg_compaction
@@ -1115,7 +1124,10 @@ flowchart TD
pkg_session_reference --> pkg_llm
pkg_session_reference --> pkg_output_retention
pkg_session_reference --> pkg_session
+ pkg_session_reference --> pkg_session_projection
+ pkg_session_reference --> pkg_session_projection_cache
pkg_session_reference --> pkg_session_query
+ pkg_session_reference --> pkg_session_title
pkg_session_reference --> pkg_typert_protocol
pkg_agent_spine_demo --> pkg_agent
pkg_agent_spine_demo --> pkg_agent_instructions
@@ -1139,10 +1151,13 @@ flowchart TD
pkg_agent_spine_demo --> pkg_tool_jobs
pkg_agent_spine_demo --> pkg_tool_skill
pkg_agent_spine_demo --> pkg_tools
+ pkg_experimental_webworker_runtime --> pkg_client_connection
pkg_experimental_webworker_runtime --> pkg_client_modules
- pkg_experimental_webworker_runtime --> pkg_host_apiproxy
pkg_experimental_webworker_runtime --> pkg_host_webserver
pkg_experimental_webworker_runtime --> pkg_invariants
+ pkg_host_frontend_static --> pkg_client_connection
+ pkg_host_frontend_static --> pkg_host_webserver
+ pkg_host_frontend_static --> pkg_invariants
pkg_webhook_github --> pkg_credentials
pkg_webhook_github --> pkg_host_webserver
pkg_webhook_github --> pkg_invariants
@@ -1202,11 +1217,39 @@ flowchart TD
pkg_hooks_claude_code --> pkg_session_persistence
pkg_hooks_claude_code --> pkg_subagent
pkg_hooks_claude_code --> pkg_tools
- pkg_api_gateway --> pkg_brand
- pkg_api_gateway --> pkg_client_connection
- pkg_api_gateway --> pkg_host_webserver
- pkg_api_gateway --> pkg_invariants
- pkg_api_gateway --> pkg_typert_registry
+ pkg_api_session_controller --> pkg_agent
+ pkg_api_session_controller --> pkg_agent_default_model
+ pkg_api_session_controller --> pkg_agent_presets
+ pkg_api_session_controller --> pkg_api_gateway
+ pkg_api_session_controller --> pkg_attachment
+ pkg_api_session_controller --> pkg_brand
+ pkg_api_session_controller --> pkg_client_connection
+ pkg_api_session_controller --> pkg_file_reference
+ pkg_api_session_controller --> pkg_invariants
+ pkg_api_session_controller --> pkg_jobs
+ pkg_api_session_controller --> pkg_llm
+ pkg_api_session_controller --> pkg_native_command
+ pkg_api_session_controller --> pkg_scope
+ pkg_api_session_controller --> pkg_session
+ pkg_api_session_controller --> pkg_session_persistence
+ pkg_api_session_controller --> pkg_session_projection
+ pkg_api_session_controller --> pkg_session_projection_cache
+ pkg_api_session_controller --> pkg_session_query
+ pkg_api_session_controller --> pkg_session_title
+ pkg_api_session_controller --> pkg_skill
+ pkg_api_session_controller --> pkg_subagent
+ pkg_api_session_controller --> pkg_typert_protocol
+ pkg_api_session_controller --> pkg_typert_registry
+ pkg_api_session_controller --> pkg_util_workspace_path
+ pkg_api_session_controller --> pkg_workspace
+ pkg_api_workspace_controller --> pkg_api_gateway
+ pkg_api_workspace_controller --> pkg_client_connection
+ pkg_api_workspace_controller --> pkg_host_directory_picker
+ pkg_api_workspace_controller --> pkg_invariants
+ pkg_api_workspace_controller --> pkg_session
+ pkg_api_workspace_controller --> pkg_storage_domain
+ pkg_api_workspace_controller --> pkg_typert_protocol
+ pkg_api_workspace_controller --> pkg_workspace
pkg_experimental_agent_team --> pkg_agent
pkg_experimental_agent_team --> pkg_brand
pkg_experimental_agent_team --> pkg_invariants
@@ -1215,9 +1258,6 @@ flowchart TD
pkg_experimental_agent_team --> pkg_session_persistence
pkg_experimental_agent_team --> pkg_subagent
pkg_experimental_agent_team --> pkg_typert_protocol
- pkg_host_frontend_static --> pkg_client_connection
- pkg_host_frontend_static --> pkg_host_webserver
- pkg_host_frontend_static --> pkg_invariants
pkg_sdk_protocol --> pkg_invariants
pkg_sdk_protocol --> pkg_llm
pkg_sdk_protocol --> pkg_session
@@ -1245,36 +1285,30 @@ flowchart TD
pkg_subagent_spawn_in_process --> pkg_invariants
pkg_subagent_spawn_in_process --> pkg_subagent
pkg_subagent_spawn_in_process --> pkg_subagent_in_process_driver
- pkg_api_session_controller --> pkg_agent
- pkg_api_session_controller --> pkg_agent_default_model
- pkg_api_session_controller --> pkg_agent_presets
- pkg_api_session_controller --> pkg_api_gateway
- pkg_api_session_controller --> pkg_attachment
- pkg_api_session_controller --> pkg_brand
- pkg_api_session_controller --> pkg_client_connection
- pkg_api_session_controller --> pkg_invariants
- pkg_api_session_controller --> pkg_jobs
- pkg_api_session_controller --> pkg_llm
- pkg_api_session_controller --> pkg_scope
- pkg_api_session_controller --> pkg_session
- pkg_api_session_controller --> pkg_session_persistence
- pkg_api_session_controller --> pkg_session_projection
- pkg_api_session_controller --> pkg_session_projection_cache
- pkg_api_session_controller --> pkg_session_query
- pkg_api_session_controller --> pkg_session_title
- pkg_api_session_controller --> pkg_subagent
- pkg_api_session_controller --> pkg_typert_protocol
- pkg_api_session_controller --> pkg_typert_registry
- pkg_api_session_controller --> pkg_util_workspace_path
- pkg_api_session_controller --> pkg_workspace
- pkg_api_workspace_controller --> pkg_api_gateway
- pkg_api_workspace_controller --> pkg_client_connection
- pkg_api_workspace_controller --> pkg_host_directory_picker
- pkg_api_workspace_controller --> pkg_invariants
- pkg_api_workspace_controller --> pkg_session
- pkg_api_workspace_controller --> pkg_storage_domain
- pkg_api_workspace_controller --> pkg_typert_protocol
- pkg_api_workspace_controller --> pkg_workspace
+ pkg_api_remotes --> pkg_agent_presets
+ pkg_api_remotes --> pkg_api_gateway
+ pkg_api_remotes --> pkg_api_session_controller
+ pkg_api_remotes --> pkg_api_settings_controller
+ pkg_api_remotes --> pkg_api_workspace_controller
+ pkg_api_remotes --> pkg_commands
+ pkg_api_remotes --> pkg_cordis_host_runner
+ pkg_api_remotes --> pkg_credentials
+ pkg_api_remotes --> pkg_file_reference
+ pkg_api_remotes --> pkg_goal
+ pkg_api_remotes --> pkg_host_plugin_inventory
+ pkg_api_remotes --> pkg_invariants
+ pkg_api_remotes --> pkg_llm
+ pkg_api_remotes --> pkg_message_feedback
+ pkg_api_remotes --> pkg_session
+ pkg_api_remotes --> pkg_session_reference
+ pkg_api_remotes --> pkg_settings
+ pkg_api_remotes --> pkg_subagent
+ pkg_api_remotes --> pkg_user_approval
+ pkg_api_remotes --> pkg_user_questions
+ pkg_client_ui_session --> pkg_api_session_controller
+ pkg_client_ui_session --> pkg_client_ui_renderer
+ pkg_client_ui_session --> pkg_invariants
+ pkg_client_ui_session --> pkg_session
pkg_experimental_tool_agent_team --> pkg_agent
pkg_experimental_tool_agent_team --> pkg_experimental_agent_team
pkg_experimental_tool_agent_team --> pkg_invariants
@@ -1301,30 +1335,6 @@ flowchart TD
pkg_subagent_dsh_sdk --> pkg_session
pkg_subagent_dsh_sdk --> pkg_subagent
pkg_subagent_dsh_sdk --> pkg_subprocess
- pkg_api_remotes --> pkg_agent_presets
- pkg_api_remotes --> pkg_api_gateway
- pkg_api_remotes --> pkg_api_session_controller
- pkg_api_remotes --> pkg_api_settings_controller
- pkg_api_remotes --> pkg_api_workspace_controller
- pkg_api_remotes --> pkg_commands
- pkg_api_remotes --> pkg_cordis_host_runner
- pkg_api_remotes --> pkg_credentials
- pkg_api_remotes --> pkg_file_reference
- pkg_api_remotes --> pkg_goal
- pkg_api_remotes --> pkg_host_plugin_inventory
- pkg_api_remotes --> pkg_invariants
- pkg_api_remotes --> pkg_llm
- pkg_api_remotes --> pkg_message_feedback
- pkg_api_remotes --> pkg_session
- pkg_api_remotes --> pkg_session_reference
- pkg_api_remotes --> pkg_settings
- pkg_api_remotes --> pkg_subagent
- pkg_api_remotes --> pkg_user_approval
- pkg_api_remotes --> pkg_user_questions
- pkg_client_ui_session --> pkg_api_session_controller
- pkg_client_ui_session --> pkg_client_ui_renderer
- pkg_client_ui_session --> pkg_invariants
- pkg_client_ui_session --> pkg_session
pkg_client_ui_settings --> pkg_api_remotes
pkg_client_ui_settings --> pkg_client_connection
pkg_client_ui_settings --> pkg_invariants
@@ -1336,7 +1346,6 @@ flowchart TD
pkg_client_locale --> pkg_invariants
pkg_client_locale --> pkg_settings
pkg_client_ui_settings_models --> pkg_api_remotes
- pkg_client_ui_settings_models --> pkg_client_connection
pkg_client_ui_settings_models --> pkg_client_locale
pkg_client_ui_settings_models --> pkg_client_ui_renderer
pkg_client_ui_settings_models --> pkg_client_ui_settings
@@ -1347,6 +1356,7 @@ flowchart TD
pkg_client_ui_settings_plugin_inventory --> pkg_client_ui_settings
pkg_client_ui_settings_plugin_inventory --> pkg_invariants
pkg_client_ui_settings_plugins --> pkg_api_remotes
+ pkg_client_ui_settings_plugins --> pkg_client_connection
pkg_client_ui_settings_plugins --> pkg_client_locale
pkg_client_ui_settings_plugins --> pkg_client_ui_renderer
pkg_client_ui_settings_plugins --> pkg_client_ui_settings
@@ -1533,6 +1543,7 @@ flowchart TD
pkg_client_ui_chat --> pkg_client_ui_layout
pkg_client_ui_chat --> pkg_client_ui_renderer
pkg_client_ui_chat --> pkg_client_ui_session
+ pkg_client_ui_chat --> pkg_client_ui_settings
pkg_client_ui_chat --> pkg_client_ui_workspace
pkg_client_ui_chat --> pkg_commands
pkg_client_ui_chat --> pkg_compaction
@@ -1541,6 +1552,7 @@ flowchart TD
pkg_client_ui_chat --> pkg_llm_retry
pkg_client_ui_chat --> pkg_session
pkg_client_ui_chat --> pkg_session_stats
+ pkg_client_ui_chat --> pkg_settings
pkg_client_ui_chat --> pkg_token_meter
pkg_client_ui_chat --> pkg_tools
pkg_client_ui_chat --> pkg_util_workspace_path
@@ -1555,12 +1567,15 @@ flowchart TD
pkg_client_ui_commands --> pkg_invariants
pkg_client_ui_commands --> pkg_session
pkg_client_ui_reference --> pkg_api_remotes
+ pkg_client_ui_reference --> pkg_api_session_controller
+ pkg_client_ui_reference --> pkg_client_connection
pkg_client_ui_reference --> pkg_client_locale
pkg_client_ui_reference --> pkg_client_ui_input_trigger
pkg_client_ui_reference --> pkg_file_reference
pkg_client_ui_reference --> pkg_invariants
pkg_client_ui_reference --> pkg_session_reference
pkg_client_ui_reference --> pkg_typert_protocol
+ pkg_client_ui_reference --> pkg_util_workspace_path
pkg_client_ui_subagent --> pkg_api_session_controller
pkg_client_ui_subagent --> pkg_client_connection
pkg_client_ui_subagent --> pkg_client_locale
@@ -1578,6 +1593,8 @@ flowchart TD
pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
pkg_host_directory_picker_auto --> pkg_host_webserver
pkg_host_directory_picker_auto --> pkg_invariants
+ pkg_session_log_export --> pkg_attachment
+ pkg_session_log_export --> pkg_client_connection
pkg_session_log_export --> pkg_client_locale
pkg_session_log_export --> pkg_client_ui_commands
pkg_session_log_export --> pkg_client_ui_conversation
@@ -1585,12 +1602,16 @@ flowchart TD
pkg_session_log_export --> pkg_client_ui_session
pkg_session_log_export --> pkg_commands
pkg_session_log_export --> pkg_invariants
+ pkg_session_log_export --> pkg_session
+ pkg_session_log_export --> pkg_session_persistence
+ pkg_session_log_export --> pkg_session_query
pkg_client_ui_attachment --> pkg_attachment
pkg_client_ui_attachment --> pkg_client_ui_chat
pkg_client_ui_attachment --> pkg_client_ui_conversation
pkg_client_ui_attachment --> pkg_client_ui_renderer
pkg_client_ui_attachment --> pkg_client_ui_trajectory
pkg_client_ui_attachment --> pkg_invariants
+ pkg_client_ui_deliverables --> pkg_api_remotes
pkg_client_ui_deliverables --> pkg_client_connection
pkg_client_ui_deliverables --> pkg_client_locale
pkg_client_ui_deliverables --> pkg_client_ui_chat
@@ -1624,7 +1645,6 @@ flowchart TD
pkg_client_ui_message_feedback --> pkg_typert_protocol
pkg_client_ui_model_selection --> pkg_api_remotes
pkg_client_ui_model_selection --> pkg_api_session_controller
- pkg_client_ui_model_selection --> pkg_client_connection
pkg_client_ui_model_selection --> pkg_client_locale
pkg_client_ui_model_selection --> pkg_client_ui_commands
pkg_client_ui_model_selection --> pkg_client_ui_conversation
@@ -1752,10 +1772,11 @@ flowchart TD
| [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
| [`subprocess-local`](../packages/subprocess/subprocess-local) | `subprocess` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`typert-loader`](../packages/typert/loader) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
-| [`llm`](../packages/llm/llm) | `llm` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout) |
+| [`llm`](../packages/llm/llm) | `llm` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`typert-protocol`](../packages/typert/protocol) |
| [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`client-hmr`](../packages/client/hmr) | `client` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) |
+| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`session`](../packages/core/session) | `core` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`typert-protocol`](../packages/typert/protocol) |
| [`system-prompt`](../packages/core/system-prompt) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
| [`skill`](../packages/skill/skill) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
@@ -1783,9 +1804,8 @@ flowchart TD
| [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) |
| [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`web`](../packages/web/web) |
| [`spill-local`](../packages/spill/spill-local) | `spill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`spill`](../packages/spill/spill) |
-| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
-| [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) |
-| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
+| [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
| [`message-feedback`](../packages/feedback/message-feedback) | `feedback` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol) |
| [`commands`](../packages/interaction/commands) | `interaction` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
| [`user-approval`](../packages/interaction/user-approval) | `interaction` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
@@ -1868,21 +1888,23 @@ flowchart TD
| [`plugin-package-inventory-deepseek`](../packages/llm/plugin-package-inventory-deepseek) | `llm` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
| [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-title`](../packages/session/session-title), [`tool-todo`](../packages/todo/tool-todo) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
+| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`native-command`](../packages/util/native-command), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
+| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) |
| [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | `compaction` | [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`agent`](../packages/core/agent), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
-| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`agent-presets`](../packages/preset/agent-presets), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`tool-bash`](../packages/shell/tool-bash) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`tool-pwsh`](../packages/shell/tool-pwsh) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
| [`webhook`](../packages/webhook/webhook) | `webhook` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`workspace`](../packages/workspace/workspace) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) |
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
-| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-apiproxy`](../packages/host/apiproxy), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) |
+| [`api-gateway`](../packages/api/gateway) | `api` | [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
| [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
-| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`typert-protocol`](../packages/typert/protocol) |
+| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`typert-protocol`](../packages/typert/protocol) |
| [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
-| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-modules`](../packages/client/modules), [`host-apiproxy`](../packages/host/apiproxy), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`webhook-github`](../packages/webhook/webhook-github) | `webhook` | [`credentials`](../packages/credentials/credentials), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`webhook`](../packages/webhook/webhook) |
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-claude-code`](../packages/subagent/subagent-claude-code) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
@@ -1892,27 +1914,25 @@ flowchart TD
| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`hooks-claude-code`](../packages/hooks/hooks-claude-code) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
-| [`api-gateway`](../packages/api/gateway) | `api` | [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
+| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`native-command`](../packages/util/native-command), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`skill`](../packages/skill/skill), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
+| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
| [`experimental-agent-team`](../packages/experimental/agent-team) | `experimental` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
-| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
| [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
-| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
-| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
+| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) |
+| [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
| [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team) | `experimental` | [`agent`](../packages/core/agent), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
| [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
-| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) |
-| [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
-| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
@@ -1932,17 +1952,17 @@ flowchart TD
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`agent`](../packages/core/agent), [`api-session-controller`](../packages/api/session-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
| [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol), [`user-questions`](../packages/interaction/user-questions) |
| [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
-| [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) |
+| [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`settings`](../packages/settings/settings), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) |
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
-| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol) |
+| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) |
| [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter) |
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`client-ui-attachment`](../packages/client/ui-attachment) | `client` | [`attachment`](../packages/attachment/attachment), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-trajectory`](../packages/client/ui-trajectory), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
+| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
| [`client-ui-goal`](../packages/client/ui-goal) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
| [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
-| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
+| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) |
| [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`util-workspace-path`](../packages/util/workspace-path) |
| [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml
index 13c2a19a3c..39462f81db 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: b9839833308afbd0d561bc227a95b236a10238a1
-persistence-catalog.zh.md: 7b5fa938b23ea9112e370133bf7575c8d689806d
+persistence-catalog.md: 2143f7881edad36a986869fcbb458ae464014a44
+persistence-catalog.zh.md: abe6511a8ad9edbbc0e73ab77e02cf10d6346364
diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md
index b983983330..2143f7881e 100644
--- a/docs/persistence-catalog.md
+++ b/docs/persistence-catalog.md
@@ -738,9 +738,9 @@ Source: [`packages/core/session/src/types.ts:239`](../packages/core/session/src/
Source: [`packages/subagent/subagent/src/descriptor.ts:38`](../packages/subagent/subagent/src/descriptor.ts)
-
+
-#### `subagent/model-selection-enabled` — log-only
+#### `subagent/model-selection-policy` — log-only
```ts persistence-catalog
/**
@@ -749,10 +749,13 @@ Source: [`packages/subagent/subagent/src/descriptor.ts:38`](../packages/subagent
* request; absence means the fixed-route definition. Log-only: it carries
* no `surfaceOp` and never enters model history.
*/
-'subagent/model-selection-enabled': Record
+'subagent/model-selection-policy': {
+ /** Exact routes this Session may select explicitly for a child. */
+ allowedModels: AllowedModelRoute[]
+}
```
-Source: [`packages/subagent/tool-subagent/src/model-selection-state.ts:13`](../packages/subagent/tool-subagent/src/model-selection-state.ts)
+Source: [`packages/subagent/tool-subagent/src/model-selection-state.ts:14`](../packages/subagent/tool-subagent/src/model-selection-state.ts)
### `team/*`
@@ -867,7 +870,7 @@ Source: [`packages/core/session/src/types.ts:268`](../packages/core/session/src/
* before returning), so its execution-enclosure relation holds by
* construction.
*/
-'tool/code-dispatch': CodeDispatchEventData
+'tool/code-dispatch': PtcDispatchEventData
```
Source: [`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types.ts)
@@ -890,7 +893,7 @@ Source: [`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types
* with `tool/code-dispatch` by `subCallId` (timing = the two events'
* `time` fields).
*/
-'tool/code-dispatch-start': CodeDispatchStartEventData
+'tool/code-dispatch-start': PtcDispatchStartEventData
```
Source: [`packages/core/tools/src/types.ts:40`](../packages/core/tools/src/types.ts)
diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md
index 7b5fa938b2..abe6511a8a 100644
--- a/docs/persistence-catalog.zh.md
+++ b/docs/persistence-catalog.zh.md
@@ -740,9 +740,9 @@ export type SessionEvent = {
来源:[`packages/subagent/subagent/src/descriptor.ts:38`](../packages/subagent/subagent/src/descriptor.ts)
-
+
-#### `subagent/model-selection-enabled` — log-only
+#### `subagent/model-selection-policy` — 仅日志
```ts persistence-catalog
/**
@@ -751,10 +751,13 @@ export type SessionEvent = {
* request; absence means the fixed-route definition. Log-only: it carries
* no `surfaceOp` and never enters model history.
*/
-'subagent/model-selection-enabled': Record
+'subagent/model-selection-policy': {
+ /** Exact routes this Session may select explicitly for a child. */
+ allowedModels: AllowedModelRoute[]
+}
```
-来源:[`packages/subagent/tool-subagent/src/model-selection-state.ts:13`](../packages/subagent/tool-subagent/src/model-selection-state.ts)
+来源:[`packages/subagent/tool-subagent/src/model-selection-state.ts:14`](../packages/subagent/tool-subagent/src/model-selection-state.ts)
### `team/*`
@@ -869,7 +872,7 @@ export type SessionEvent = {
* before returning), so its execution-enclosure relation holds by
* construction.
*/
-'tool/code-dispatch': CodeDispatchEventData
+'tool/code-dispatch': PtcDispatchEventData
```
来源:[`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types.ts)
@@ -892,7 +895,7 @@ export type SessionEvent = {
* with `tool/code-dispatch` by `subCallId` (timing = the two events'
* `time` fields).
*/
-'tool/code-dispatch-start': CodeDispatchStartEventData
+'tool/code-dispatch-start': PtcDispatchStartEventData
```
来源:[`packages/core/tools/src/types.ts:40`](../packages/core/tools/src/types.ts)
diff --git a/docs/subsystems/client-modules.i18n.yaml b/docs/subsystems/client-modules.i18n.yaml
index 56d92e2097..db0e53ba0e 100644
--- a/docs/subsystems/client-modules.i18n.yaml
+++ b/docs/subsystems/client-modules.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/client-modules.md
-client-modules.md: 6188880fcd682c7c3c105764f212e92395444b61
-client-modules.zh.md: a732758492e1dbc9cbaef8d3effbd3310e4f10a1
+client-modules.md: f58cb6592a009292ffc4f87a207fe4e103fd2365
+client-modules.zh.md: 18c72dfba6f851776100a9b6200e7222d580db7c
diff --git a/docs/subsystems/client-modules.md b/docs/subsystems/client-modules.md
index 6188880fcd..f58cb6592a 100644
--- a/docs/subsystems/client-modules.md
+++ b/docs/subsystems/client-modules.md
@@ -74,11 +74,11 @@ Each initial row's `rev` is an opaque process nonce plus sequence, so graph comp
## The scan
-A package joins the table by declaring `dsh.client` (`platform: 'web'`, optional `inject` edges, optional `immediately`) in its package.json and exporting its built bundle at `exports["./client"]`. Package resolution anchors at the config tree's `ctx.baseUrl` — the cordis.yml directory, whose package declares every composed plugin as a dependency — and construction throws when that anchor is unset.
+A package joins the table by declaring `dsh.client` (`platform: 'web'`, optional `inject` edges, optional `immediately`) in its package.json and exporting its built bundle at `exports["./client"]`. Each live row resolves from its own Loader specifier and owning-tree `baseUrl`, through the same `loader.internal.resolveSync` implementation that imports its Host face when available. The nearest owning package manifest supplies the browser module id, so relative source and built overlays retain the package identity. Distinct active Loader sources resolving to one package name fail composition; after one source unloads, the surviving source supplies the row without a fiber restart.
Scanning is incremental per package; there is no full-rescan code path. Every cordis `internal/plugin` emission (fiber construction or disposal) marks the fiber's entry name dirty, and a microtask flush reconciles each dirty name against the live loader entries. The activation pass seeds the same dirty set with all current entries and flushes synchronously, so first scan and steady state share one implementation — with opposite failure postures. At activation, a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud `AggregateError` listing every broken package: the fiber FAILS and the boot's fail-loud sweep reports it. In steady state, a broken package logs a warning and must not poison the others.
-Package metadata — including the negative "not a client package" verdict — is cached per name and never expires: plugin-set changes take effect on restart. A fiber restart reuses its row and rev untouched; bundle content changes reach the graph only through `rebuilt()`.
+Package metadata — including the negative "not a client package" verdict — is cached per Loader specifier and owning-tree base URL until restart. A fiber restart from the same source reuses its row and rev untouched; bundle content changes reach the graph only through `rebuilt()`.
## The bundle route and index injection
diff --git a/docs/subsystems/client-modules.zh.md b/docs/subsystems/client-modules.zh.md
index a732758492..18c72dfba6 100644
--- a/docs/subsystems/client-modules.zh.md
+++ b/docs/subsystems/client-modules.zh.md
@@ -74,11 +74,11 @@ interface WebBootGraph {
## 扫描
-包加入这张表的方式,是在自己的 package.json 中声明 `dsh.client`(`platform: 'web'`、可选的 `inject` 边、可选的 `immediately`),并在 `exports["./client"]` 导出构建好的 bundle。包解析锚定在配置树的 `ctx.baseUrl`——即 cordis.yml 所在目录,该目录的包把每个被组合的插件声明为依赖——这一锚点未设置时,构造即抛错。
+包加入这张表的方式,是在自己的 package.json 中声明 `dsh.client`(`platform: 'web'`、可选的 `inject` 边、可选的 `immediately`),并在 `exports["./client"]` 导出构建好的 bundle。每个 live row 都从自己的 Loader specifier 与所属 tree `baseUrl` 解析;若 `loader.internal.resolveSync` 可用,则使用 Host face import 所用的同一个实现。最近归属的 package manifest 提供浏览器模块 id,因此相对 source 与 built overlay 仍保留包身份。若不同的 active Loader source 解析到同一包名,组合会失败;一个来源卸载后,仍存活的来源无需重启 fiber 即可提供该 row。
扫描是单包增量的;不存在全量重扫代码路径。fiber 构造或 dispose(资源释放)时的每次 cordis `internal/plugin` 发射都把该 fiber 的 entry 名标脏,一次微任务 flush 把每个脏名与实时 loader entry 对账。激活趟以全部当前 entry 灌入同一个脏集合并同步 flush,因此初扫与稳态共享一条实现——但失败姿态相反。激活时,已加载 entry 中的畸形声明或缺失 bundle 会聚合为一个大声的 `AggregateError`,列出每个损坏的包:该 fiber 进入 FAILED,由启动的大声失败 sweep 上报。稳态下,损坏的包只记录一条警告,且不得殃及其他包。
-包元数据——包括「非 client 包」这一否定结论——按名缓存且永不过期:插件集合的变更在重启后生效。fiber 重启原样复用其行与 rev;bundle 内容变更只经 `rebuilt()` 到达图。
+包元数据——包括「非 client 包」这一否定结论——按 Loader specifier 与所属 tree base URL 缓存至重启。同一来源的 fiber 重启会原样复用其 row 与 rev;bundle 内容变更只经 `rebuilt()` 到达图。
## bundle 路由与 index 注入
diff --git a/docs/subsystems/code-runtime.i18n.yaml b/docs/subsystems/code-runtime.i18n.yaml
index 97886685e5..228ed14b56 100644
--- a/docs/subsystems/code-runtime.i18n.yaml
+++ b/docs/subsystems/code-runtime.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/code-runtime.md
-code-runtime.md: ae760487eff19f6a0b91620b92007d0a86eb1589
-code-runtime.zh.md: b48e1a01b2817d9dafb25ac96673d00cf7d9ed08
+code-runtime.md: 0f633df9fc657d9d80fc04df3bc8ad6fafdddcb2
+code-runtime.zh.md: 43b78ce49575741f7ae6c4e2751b63b7562fc99a
diff --git a/docs/subsystems/code-runtime.md b/docs/subsystems/code-runtime.md
index ae760487ef..0f633df9fc 100644
--- a/docs/subsystems/code-runtime.md
+++ b/docs/subsystems/code-runtime.md
@@ -2,7 +2,7 @@
English | [中文](code-runtime.zh.md)
-The code-execution seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose Service Definition ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread Service Provider and tool-registry Consumer are specified by the [Code Mode foundation](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) and [typed-return contract](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md).
+The code-execution seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose Service Definition ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread Service Provider and tool-registry Consumer are specified by the [PTC mode foundation](../../.agents/notes/implemented/feature/2026-06-15-ptc.md) and [typed-return contract](../../.agents/notes/implemented/feature/2026-07-20-ptc-typed-tool-returns.md).
Source: [`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts)
@@ -61,7 +61,7 @@ interface CodeRunResult {
## Bindings: host functions as program globals
-Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the Code Mode consumer passes one: `tools`). Arguments and resolutions must be lossless JSON and cross without a seam-level byte cap; the runtime may bridge them through structured clone. A namespace may declare a program-visible error class without making the runtime know the consumer's names: the runtime injects the real constructor and turns rejected calls into its instances. A runtime also treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision):
+Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the PTC mode consumer passes one: `tools`). Arguments and resolutions must be lossless JSON and cross without a seam-level byte cap; the runtime may bridge them through structured clone. A namespace may declare a program-visible error class without making the runtime know the consumer's names: the runtime injects the real constructor and turns rejected calls into its instances. A runtime also treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision):
```ts type-equiv
/**
@@ -69,7 +69,7 @@ Each `CodeBindingNamespace` becomes one global object of async callables inside
* injects a real error constructor under `name`; rejected member calls become
* its instances and expose the exact member name through
* `memberNameProperty`. Both strings are runtime data rather than knowledge
- * of a particular consumer such as Code Mode.
+ * of a particular consumer such as PTC mode.
*/
interface CodeBindingErrorClass {
/** Constructor global and resulting `Error.name`; same portable identifier rule as {@link CodeBindingNamespace.global}. */
diff --git a/docs/subsystems/code-runtime.zh.md b/docs/subsystems/code-runtime.zh.md
index b48e1a01b2..43b78ce495 100644
--- a/docs/subsystems/code-runtime.zh.md
+++ b/docs/subsystems/code-runtime.zh.md
@@ -2,7 +2,7 @@
[English](code-runtime.md) | 中文
-代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md):其 Service Definition([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.zh.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread Service Provider 与工具注册表 Consumer 的约定见 [Code Mode 基础设计](../../.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md) 和[类型化返回约定](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md)。
+代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md):其 Service Definition([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.zh.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread Service Provider 与工具注册表 Consumer 的约定见 [PTC mode 基础设计](../../.agents/notes/implemented/feature/2026-06-15-ptc.zh.md) 和[类型化返回约定](../../.agents/notes/implemented/feature/2026-07-20-ptc-typed-tool-returns.zh.md)。
源码:[`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts)
@@ -61,7 +61,7 @@ interface CodeRunResult {
## 绑定:宿主函数作为程序全局变量
-每个 `CodeBindingNamespace` 在程序内成为一个由异步可调用函数组成的全局对象(Code Mode Consumer 传入一个:`tools`)。参数与返回值必须是无损 JSON,且跨越边界时不受 seam 层字节上限约束;运行时可以通过结构化克隆桥接它们。命名空间可以声明程序可见的错误类,而无需让运行时知道 Consumer 的名称:运行时会注入真实构造函数,并将被拒绝的调用转为该类的实例。运行时也将绑定名视为不可信输入(`__proto__` 是普通自有属性,绝不会发生原型碰撞):
+每个 `CodeBindingNamespace` 在程序内成为一个由异步可调用函数组成的全局对象(PTC mode Consumer 传入一个:`tools`)。参数与返回值必须是无损 JSON,且跨越边界时不受 seam 层字节上限约束;运行时可以通过结构化克隆桥接它们。命名空间可以声明程序可见的错误类,而无需让运行时知道 Consumer 的名称:运行时会注入真实构造函数,并将被拒绝的调用转为该类的实例。运行时也将绑定名视为不可信输入(`__proto__` 是普通自有属性,绝不会发生原型碰撞):
```ts type-equiv
/**
@@ -69,7 +69,7 @@ interface CodeRunResult {
* injects a real error constructor under `name`; rejected member calls become
* its instances and expose the exact member name through
* `memberNameProperty`. Both strings are runtime data rather than knowledge
- * of a particular consumer such as Code Mode.
+ * of a particular consumer such as PTC mode.
*/
interface CodeBindingErrorClass {
/** Constructor global and resulting `Error.name`; same portable identifier rule as {@link CodeBindingNamespace.global}. */
diff --git a/docs/subsystems/extensions.i18n.yaml b/docs/subsystems/extensions.i18n.yaml
index e3a18d04d7..91f9f20574 100644
--- a/docs/subsystems/extensions.i18n.yaml
+++ b/docs/subsystems/extensions.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/extensions.md
-extensions.md: 0418afc7f1b6b6cd892deb618a4f346f6cde720d
-extensions.zh.md: f2d86add9f1b62913fcc1b89abf1fc1a1d2a178f
+extensions.md: 540f3c477b4e128b0c1062192185e6276c9e9263
+extensions.zh.md: ebfe7827484cea2cf8c6d77ca26796f7751d203a
diff --git a/docs/subsystems/extensions.md b/docs/subsystems/extensions.md
index 0418afc7f1..540f3c477b 100644
--- a/docs/subsystems/extensions.md
+++ b/docs/subsystems/extensions.md
@@ -256,6 +256,24 @@ Types: [Agent](core.md)
Source: [`packages/extensions/cordis-host-runner/src/index.ts`](../../packages/extensions/cordis-host-runner/src/index.ts)
+
+
+### `ctx.inspector` — `InspectorService`
+
+Shared Host/Client service façade over the realm's source publisher.
+
+```ts cordis-catalog
+/**
+ * Publish one JSON observation without waiting for Worker delivery.
+ * @param topic - Domain-owned topic name.
+ * @param payload - JSON value validated before it reaches the carrier.
+ * @param monotonicMs - Source-clock timestamp; defaults to `performance.now()`.
+ */
+publish(topic: string, payload: InspectorJsonValue, monotonicMs?: number): void
+```
+
+Source: [`packages/experimental/inspector/src/index.ts`](../../packages/experimental/inspector/src/index.ts)
+
### `cordis/*` events
diff --git a/docs/subsystems/extensions.zh.md b/docs/subsystems/extensions.zh.md
index f2d86add9f..ebfe782748 100644
--- a/docs/subsystems/extensions.zh.md
+++ b/docs/subsystems/extensions.zh.md
@@ -256,6 +256,24 @@ Types: [Agent](core.zh.md)
Source: [`packages/extensions/cordis-host-runner/src/index.ts`](../../packages/extensions/cordis-host-runner/src/index.ts)
+
+
+### `ctx.inspector` — `InspectorService`
+
+Shared Host/Client service façade over the realm's source publisher.
+
+```ts cordis-catalog
+/**
+ * Publish one JSON observation without waiting for Worker delivery.
+ * @param topic - Domain-owned topic name.
+ * @param payload - JSON value validated before it reaches the carrier.
+ * @param monotonicMs - Source-clock timestamp; defaults to `performance.now()`.
+ */
+publish(topic: string, payload: InspectorJsonValue, monotonicMs?: number): void
+```
+
+Source: [`packages/experimental/inspector/src/index.ts`](../../packages/experimental/inspector/src/index.ts)
+
### `cordis/*` events
diff --git a/docs/subsystems/llm-streaming.i18n.yaml b/docs/subsystems/llm-streaming.i18n.yaml
index 7b91ec4729..19974d41f8 100644
--- a/docs/subsystems/llm-streaming.i18n.yaml
+++ b/docs/subsystems/llm-streaming.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/llm-streaming.md
-llm-streaming.md: 331c30e1039741462df7ae3e7a9e6497281a5df0
-llm-streaming.zh.md: f05c67bc7552a4bc5a9359416d98b62f238f1c65
+llm-streaming.md: e37356d91e75334987b6fc707744f2376df1b2fc
+llm-streaming.zh.md: 05f24bed6beff9508db88e60af7b259eda33f474
diff --git a/docs/subsystems/llm-streaming.md b/docs/subsystems/llm-streaming.md
index 331c30e103..e37356d91e 100644
--- a/docs/subsystems/llm-streaming.md
+++ b/docs/subsystems/llm-streaming.md
@@ -659,8 +659,6 @@ interface LlmModelDiscoveryRequest {
api?: string
/** Credential for this interrogation alone; the harness never stores it. */
apiKey?: string
- /** Caller cancellation; implementations must settle promptly after it aborts. */
- signal?: AbortSignal
}
```
@@ -883,7 +881,7 @@ registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHa
* Describe provider routes with a registered adapter.
* @returns detached provider metadata in registration order.
*/
-listProviders(): LlmProviderInfo[]
+@Remote listProviders(): LlmProviderInfo[]
/**
* Declare provider routes an adapter plugin can activate through
@@ -899,7 +897,7 @@ registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): Dire
* List every declared configurable provider, registered or dormant.
* @returns detached directory entries in declaration order.
*/
-listConfigurableProviders(): LlmConfigurableProvider[]
+@Remote listConfigurableProviders(): LlmConfigurableProvider[]
/**
* Offer to interrogate provider endpoints on behalf of the settings
@@ -908,10 +906,10 @@ listConfigurableProviders(): LlmConfigurableProvider[]
* directory, and because a provider being *added* has no route to name yet.
* Disposed with the fiber.
* @param settingsNs - the namespace whose profiles this discovery serves.
- * @param discover - interrogates one endpoint; must honor `request.signal`.
+ * @param discover - interrogates one endpoint and must honor the supplied signal.
* @returns the disposer that withdraws the offer.
*/
-registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise, ): () => void
+registerModelDiscovery( settingsNs: string, discover: ( request: LlmModelDiscoveryRequest, signal?: AbortSignal, ) => Promise, ): () => void
/**
* Interrogate one provider endpoint for the models it advertises. The
@@ -920,9 +918,20 @@ registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscover
* candidate metadata a surface may offer for adoption.
* @param settingsNs - namespace whose registered discovery serves this draft.
* @param request - the endpoint, protocol, and one-shot credential to use.
+ * @param signal - caller cancellation.
* @returns the advertised models, deduplicated in endpoint order.
*/
-async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, ): Promise
+async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, signal?: AbortSignal, ): Promise
+
+/**
+ * Remote adapter for one draft provider interrogation.
+ * @param settingsNs - namespace whose registered discovery serves this draft.
+ * @param request - endpoint, protocol, and one-shot credential to use.
+ * @param signal - caller cancellation supplied by the Remote carrier.
+ * @returns advertised models in endpoint order.
+ * @throws TypertRemoteFailure with `model-discovery-failed` when discovery refuses or fails.
+ */
+@Remote('discoverModels') async remoteDiscoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, signal: AbortSignal, ): Promise
/**
* Resolve the retry policy captured when one provider route was registered.
diff --git a/docs/subsystems/llm-streaming.zh.md b/docs/subsystems/llm-streaming.zh.md
index f05c67bc75..05f24bed6b 100644
--- a/docs/subsystems/llm-streaming.zh.md
+++ b/docs/subsystems/llm-streaming.zh.md
@@ -665,8 +665,6 @@ interface LlmModelDiscoveryRequest {
api?: string
/** Credential for this interrogation alone; the harness never stores it. */
apiKey?: string
- /** Caller cancellation; implementations must settle promptly after it aborts. */
- signal?: AbortSignal
}
```
@@ -889,7 +887,7 @@ registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHa
* Describe provider routes with a registered adapter.
* @returns detached provider metadata in registration order.
*/
-listProviders(): LlmProviderInfo[]
+@Remote listProviders(): LlmProviderInfo[]
/**
* Declare provider routes an adapter plugin can activate through
@@ -905,7 +903,7 @@ registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): Dire
* List every declared configurable provider, registered or dormant.
* @returns detached directory entries in declaration order.
*/
-listConfigurableProviders(): LlmConfigurableProvider[]
+@Remote listConfigurableProviders(): LlmConfigurableProvider[]
/**
* Offer to interrogate provider endpoints on behalf of the settings
@@ -914,10 +912,10 @@ listConfigurableProviders(): LlmConfigurableProvider[]
* directory, and because a provider being *added* has no route to name yet.
* Disposed with the fiber.
* @param settingsNs - the namespace whose profiles this discovery serves.
- * @param discover - interrogates one endpoint; must honor `request.signal`.
+ * @param discover - interrogates one endpoint and must honor the supplied signal.
* @returns the disposer that withdraws the offer.
*/
-registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise, ): () => void
+registerModelDiscovery( settingsNs: string, discover: ( request: LlmModelDiscoveryRequest, signal?: AbortSignal, ) => Promise, ): () => void
/**
* Interrogate one provider endpoint for the models it advertises. The
@@ -926,9 +924,20 @@ registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscover
* candidate metadata a surface may offer for adoption.
* @param settingsNs - namespace whose registered discovery serves this draft.
* @param request - the endpoint, protocol, and one-shot credential to use.
+ * @param signal - caller cancellation.
* @returns the advertised models, deduplicated in endpoint order.
*/
-async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, ): Promise
+async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, signal?: AbortSignal, ): Promise
+
+/**
+ * Remote adapter for one draft provider interrogation.
+ * @param settingsNs - namespace whose registered discovery serves this draft.
+ * @param request - endpoint, protocol, and one-shot credential to use.
+ * @param signal - caller cancellation supplied by the Remote carrier.
+ * @returns advertised models in endpoint order.
+ * @throws TypertRemoteFailure with `model-discovery-failed` when discovery refuses or fails.
+ */
+@Remote('discoverModels') async remoteDiscoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, signal: AbortSignal, ): Promise
/**
* Resolve the retry policy captured when one provider route was registered.
diff --git a/docs/subsystems/schedule.i18n.yaml b/docs/subsystems/schedule.i18n.yaml
index b1a9db8e25..37a91f5c75 100644
--- a/docs/subsystems/schedule.i18n.yaml
+++ b/docs/subsystems/schedule.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/schedule.md
-schedule.md: a0a35569dc1be87553b341323b98dfb122baee16
-schedule.zh.md: a10f9a5f5eac66bb211ac8f6a1cfa1570fc36e7c
+schedule.md: f98cf319d588f805e4630ca572f10c3c45e94b79
+schedule.zh.md: bee816be9cc49943f5815d4d13869b27e30380d5
diff --git a/docs/subsystems/schedule.md b/docs/subsystems/schedule.md
index a0a35569dc..f98cf319d5 100644
--- a/docs/subsystems/schedule.md
+++ b/docs/subsystems/schedule.md
@@ -2,7 +2,7 @@
English | [中文](schedule.zh.md)
-Schedule owns durable reminders that return to the original live Session as ordinary later conversation turns. The [durable Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns the persistence and lifecycle decisions, [conversational delivery](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) owns the no-receipt boundary, the [read-only Web catalog](../../.agents/notes/implemented/feature/2026-08-25-read-only-web-schedule-catalog.md) owns active-state presentation, the [explicit time-zone boundary](../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.md) owns browser-local interpretation, and [bounded fixed-rate Schedule](../../.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.md) owns recurrence. This page records the durable and model-facing shapes from [`packages/schedule/schedule/src/types.ts`](../../packages/schedule/schedule/src/types.ts); the [package README](../../packages/schedule/schedule/README.md) owns composition, tool behavior, and the exact reminder framing.
+Schedule owns durable reminders that return to the original live Session as ordinary later conversation turns. The [durable Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns persistence, lifecycle, and active-state presentation, [conversational delivery](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) owns the no-receipt boundary, the [explicit time-zone boundary](../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.md) owns browser-local interpretation, and [bounded fixed-rate Schedule](../../.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.md) owns recurrence. This page records the durable and model-facing shapes from [`packages/schedule/schedule/src/types.ts`](../../packages/schedule/schedule/src/types.ts); the [package README](../../packages/schedule/schedule/README.md) owns composition, tool behavior, and the exact reminder framing.
## Durable records
@@ -149,7 +149,7 @@ type ScheduleDispatchChange = OneShotScheduleDispatchChange | EveryScheduleDispa
type ScheduleChange = ScheduleCreateChange | ScheduleDeleteChange | ScheduleDispatchChange
```
-The strict decoder and fold reject unknown versions, extra fields, reused ids, mismatched one-shot or Every dispatch shapes, and delete or dispatch transitions against inactive records. A normal Session folds its complete event stream. A fork folds only events at or after `SessionHeader.seedLength`, so it retains history without adopting the parent Session's active reminders. The Schedule projection derives that boundary from the immutable header passed to `init(header)`, uses the shared transition, and persists both active records and used-id history so cached restore preserves strict replay; the registry validates the boundary against the observed log. The `schedule/change` declaration and source location are also indexed in the [persistence catalog](../persistence-catalog.md#schedulechange--log-only).
+The strict decoder and fold reject unknown versions, extra fields, reused ids, mismatched one-shot or Every dispatch shapes, and delete or dispatch transitions against inactive records. A normal Session folds its complete event stream. A fork folds only events at or after `SessionHeader.seedLength`, so it retains history without adopting the parent Session's active reminders. The Schedule projection derives that boundary from the immutable header passed to `init(header)`, uses the shared transition, and persists both active records and used-id history so cached restore preserves strict replay. The `schedule/change` declaration and source location are also indexed in the [persistence catalog](../persistence-catalog.md#schedulechange--log-only).
## Active views and management
@@ -181,7 +181,7 @@ The generated [tool catalog](../tool-catalog.md#deepseek-aidsh-schedule) owns th
When the optional Session projection registry is present, Schedule registers the client-visible `schedule` key whose value is the complete active `ScheduleRecord[]`. Live, cache, history, and detached reads use the same header-aware strict fold; malformed authoritative input fails the existing read path instead of publishing a partial value.
-The shipped Web bundle keeps `ui-schedule` disabled by default, while the explicit Schedule overlay enables it together with the Host capability. [`dsh-client-ui-schedule`](../../packages/client/ui-schedule/README.md), [`dsh-client-ui-workspace`](../../packages/client/ui-workspace/README.md), and the [catalog decision](../../.agents/notes/implemented/feature/2026-08-25-read-only-web-schedule-catalog.md) own the presentation contracts. The shared value represents current active state, never delivery history or a receipt; due reminders still appear through the ordinary Assistant output described below.
+The shipped Web bundle keeps `ui-schedule` disabled by default, while the explicit Schedule overlay enables it together with the Host capability. [`dsh-client-ui-schedule`](../../packages/client/ui-schedule/README.md) owns the header interaction, [`dsh-client-ui-workspace`](../../packages/client/ui-workspace/README.md) owns list-row presentation, and the durable Schedule Agent Note owns their shared active-state boundary. The shared value represents current active state, never delivery history or a receipt; due reminders still appear through the ordinary Assistant output described below.
## Live delivery
diff --git a/docs/subsystems/schedule.zh.md b/docs/subsystems/schedule.zh.md
index a10f9a5f5e..bee816be9c 100644
--- a/docs/subsystems/schedule.zh.md
+++ b/docs/subsystems/schedule.zh.md
@@ -2,7 +2,7 @@
[English](schedule.md) | 中文
-Schedule 拥有持久提醒;这些提醒会作为普通的后续对话轮次返回原 live Session。[持久 Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.zh.md) 负责持久化与生命周期决策,[对话式交付](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.zh.md) 负责无回执边界,[只读 Web 目录](../../.agents/notes/implemented/feature/2026-08-25-read-only-web-schedule-catalog.zh.md)负责活动状态呈现,[显式时区边界](../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.zh.md) 负责浏览器本地解释,[有界固定速率 Schedule](../../.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.zh.md) 负责重复调度。本页记录 [`packages/schedule/schedule/src/types.ts`](../../packages/schedule/schedule/src/types.ts) 中的持久数据形状和面向模型的数据形状;[包 README](../../packages/schedule/schedule/README.zh.md) 负责组合、工具行为与确切的提醒 framing。
+Schedule 拥有持久提醒;这些提醒会作为普通的后续对话轮次返回原 live Session。[持久 Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.zh.md) 负责持久化、生命周期与活动状态呈现,[对话式交付](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.zh.md) 负责无回执边界,[显式时区边界](../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.zh.md) 负责浏览器本地解释,[有界固定速率 Schedule](../../.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.zh.md) 负责重复调度。本页记录 [`packages/schedule/schedule/src/types.ts`](../../packages/schedule/schedule/src/types.ts) 中的持久数据形状和面向模型的数据形状;[包 README](../../packages/schedule/schedule/README.zh.md) 负责组合、工具行为与确切的提醒 framing。
## 持久记录
@@ -149,7 +149,7 @@ type ScheduleDispatchChange = OneShotScheduleDispatchChange | EveryScheduleDispa
type ScheduleChange = ScheduleCreateChange | ScheduleDeleteChange | ScheduleDispatchChange
```
-严格 decoder 与 fold 会拒绝未知版本、额外字段、复用 id、不匹配的一次性提醒或 Every dispatch 形状,以及针对非活动记录的 delete 或 dispatch 转换。普通 Session 折叠完整事件流。fork 只折叠 `SessionHeader.seedLength` 位置及其后的事件,因此保留历史,但不会接管父 Session 的活动提醒。Schedule projection 从传给 `init(header)` 的不可变 header 派生该边界,复用共享 transition,并持久化活动记录与已使用 id 历史,使缓存恢复继续保持严格回放;注册表会对照已观察日志校验边界。`schedule/change` 声明和源码位置也编入[持久化目录](../persistence-catalog.zh.md#schedulechange--log-only)。
+严格 decoder 与 fold 会拒绝未知版本、额外字段、复用 id、不匹配的一次性提醒或 Every dispatch 形状,以及针对非活动记录的 delete 或 dispatch 转换。普通 Session 折叠完整事件流。fork 只折叠 `SessionHeader.seedLength` 位置及其后的事件,因此保留历史,但不会接管父 Session 的活动提醒。Schedule projection 从传给 `init(header)` 的不可变 header 派生该边界,复用共享 transition,并持久化活动记录与已使用 id 历史,使缓存恢复继续保持严格回放。`schedule/change` 声明和源码位置也编入[持久化目录](../persistence-catalog.zh.md#schedulechange--log-only)。
## 活动视图与管理
@@ -181,7 +181,7 @@ type ScheduleView = ScheduleRecord & {
可选 Session projection 注册表存在时,Schedule 会注册客户端可见的 `schedule` key,其值是完整的活动 `ScheduleRecord[]`。live、cache、history 与 detached 读取共用同一套 header-aware 严格 fold;畸形权威输入会使既有读取路径失败,而不会发布部分值。
-shipped Web bundle 默认禁用 `ui-schedule`,显式 Schedule overlay 则把它与 Host 能力一同启用。[`dsh-client-ui-schedule`](../../packages/client/ui-schedule/README.zh.md)、[`dsh-client-ui-workspace`](../../packages/client/ui-workspace/README.zh.md)与[目录决策](../../.agents/notes/implemented/feature/2026-08-25-read-only-web-schedule-catalog.zh.md)分别拥有呈现合同。共享值只表示当前活动状态,绝不表示交付历史或回执;到期提醒仍通过下文所述的普通 Assistant 输出出现。
+shipped Web bundle 默认禁用 `ui-schedule`,显式 Schedule overlay 则把它与 Host 能力一同启用。[`dsh-client-ui-schedule`](../../packages/client/ui-schedule/README.zh.md)拥有 header 交互,[`dsh-client-ui-workspace`](../../packages/client/ui-workspace/README.zh.md)拥有列表行呈现,持久 Schedule Agent Note 拥有二者共享的活动状态边界。共享值只表示当前活动状态,绝不表示交付历史或回执;到期提醒仍通过下文所述的普通 Assistant 输出出现。
## Live 交付
diff --git a/docs/subsystems/session-projection.i18n.yaml b/docs/subsystems/session-projection.i18n.yaml
index 176f6fab80..4bdbc164e8 100644
--- a/docs/subsystems/session-projection.i18n.yaml
+++ b/docs/subsystems/session-projection.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-projection.md
-session-projection.md: 87a11475bd12ed922030f08ae5d164641b95ec09
-session-projection.zh.md: 7af0cfc7e9eba696d3bf826de6b0e4067a245aaf
+session-projection.md: fd40408c380a3694c6b91b9ad79417cd0feb738b
+session-projection.zh.md: 392a537416bc7968e04997724e97512db4c6232d
diff --git a/docs/subsystems/session-projection.md b/docs/subsystems/session-projection.md
index 87a11475bd..fd40408c38 100644
--- a/docs/subsystems/session-projection.md
+++ b/docs/subsystems/session-projection.md
@@ -63,7 +63,7 @@ interface ProjectionDefinition<
}
```
-The load-bearing rule is a deterministic synchronous fold with a complete wire value. A domain may own whole-value events or incremental transitions, but it validates and folds them on the Host; clients never replay those events or receive a delta. `init(header)` receives the immutable `SessionHeader` that accompanies the observed events, and the registry rejects a normalized `header.seedLength ?? 0` beyond that log. Definitions may interpret relevant immutable fields but never consult ambient mutable state.
+The whole-value event rule is load-bearing: a state-carrying log event carries the complete post-change state, never a bare delta — it keeps every transition trivially cheap and every served value self-describing (last-wins for consumers).
## The snapshot and the change feed
@@ -99,7 +99,7 @@ type ProjectionChangeListener = (
## The registry: `ctx.sessionProjections`
-`SessionProjectionRegistry` ([signatures](#ctxsessionprojections--sessionprojectionregistry)) owns the drive: one `session/event` subscription, eager `apply` over every registered unit, and per-session per-unit watermark cells. Cells build lazily — for a unit registered after events flowed, or a session older than the registry, the registry validates the normalized seed boundary and then passes the immutable `SessionHeader` to the unit's sole `init(header)` call before the in-memory log folds on first touch (event or read). Detached cache, history, and Subagent restore paths pass the immutable header returned with the same persisted event read to that same initializer. Registration is an effect whose disposer rides the calling fiber: a duplicate key with a different `stateVersion` throws, while same-version registrants share one unit and are counted; the key and its cells disappear after the last registrant unloads. Domain plugins register under `ctx.inject(['sessionProjections'], …)` so headless assemblies without the registry stay unaffected.
+`SessionProjectionRegistry` ([signatures](#ctxsessionprojections--sessionprojectionregistry)) owns the drive: one `session/event` subscription, eager `apply` over every registered unit, and per-session per-unit watermark cells. Cells build lazily — a unit registered after events flowed, or a session older than the registry, folds `init` over the in-memory log on first touch (event or read). Registration is an effect whose disposer rides the calling fiber: an unloaded domain plugin's key (with its cached cells) disappears from subsequent drives and snapshots, and clients read that as capability absence; a duplicate key with a different `stateVersion` throws, while same-version registrants share one unit and are counted. Domain plugins register under `ctx.inject(['sessionProjections'], …)` so headless assemblies without the registry stay unaffected.
@@ -118,11 +118,12 @@ The persisted projection cache service. Opens the `session_projcache` domain at
```ts cordis-catalog
/**
* The zero-I/O listing read: whole values viewed straight from the stored
- * rows (version-matching keys only), with the lowest served watermark carried
- * for later authoritative reconciliation. The caller's header keeps unrelated
- * lifecycles out; repeated list blocks are arrival-ordered tentative hints
- * because crash repair may lower the durable sequence; authoritative frames
- * replace matching rows, and complete baselines replace the full set.
+ * rows (version-matching keys only), each cut carried with its watermark so
+ * a client value store can seed under its higher-seq-wins rule — as stale
+ * as the last durable checkpoint but never wrong, and never from an
+ * unrelated log (the caller's header is the identity witness). Fresher
+ * paths (the history tail baseline) supersede these values whenever a
+ * session is actually opened.
* @param meta - the listed session's header (identity witness; no log read).
* @param keys - optional projection keys required by the caller's audience.
* @returns the cut (`asOfSeq` = lowest served-row watermark), or
@@ -273,11 +274,10 @@ restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined
/**
* View a checkpoint's rows without any log read: for every registered
* client-visible unit whose row's `ver` matches, serve the schema-validated
- * `view` of the schema-validated stored state; mismatched, malformed, or
- * absent rows leave their key absent. The current log extent is unknown, so
- * returned values are tentative hints: a row may trail the log or overreach
- * a crash-repaired truncation. Exact restore validates the cut before using
- * a row as authoritative state.
+ * `view` of the schema-validated stored state; mismatched, malformed, or absent rows leave their key
+ * absent (a cold or listing consumer treats it as not-yet-available and a
+ * fuller read path refolds it). The zero-I/O rung of the read ladder —
+ * values are as stale as their rows, never wrong.
* @param checkpoint - persisted rows for one session (possibly stale or empty).
* @param keys - optional wire keys to view.
* @returns whole values per key with a usable row; empty when none.
diff --git a/docs/subsystems/session-projection.zh.md b/docs/subsystems/session-projection.zh.md
index 7af0cfc7e9..392a537416 100644
--- a/docs/subsystems/session-projection.zh.md
+++ b/docs/subsystems/session-projection.zh.md
@@ -63,7 +63,7 @@ interface ProjectionDefinition<
}
```
-承重规则是确定性同步 fold 与完整 wire 值。领域可以拥有全量值事件,也可以拥有增量 transition,但它会在 Host 上校验并折叠这些事件;客户端既不回放这些事件,也不会收到 delta。`init(header)` 接收与已观察事件配套的不可变 `SessionHeader`,注册表会拒绝超过该日志长度的规范化 `header.seedLength ?? 0`。definition 可以解释相关的不可变字段,但不能读取环境中的可变状态。
+全量值事件规则是承重结构:携带状态的日志事件携带的是变更后的完整状态,绝不是裸增量——这让每次状态转移始终足够廉价,也让每个被供给的值自描述(对消费方即 last-wins)。
## 快照与变更流
@@ -99,7 +99,7 @@ type ProjectionChangeListener = (
## 注册表:`ctx.sessionProjections`
-`SessionProjectionRegistry`([签名](#ctxsessionprojections--sessionprojectionregistry))拥有驱动权:一份 `session/event` 订阅、对每个已注册单元即时调用 `apply`,以及每会话每单元的水位线(watermark)cell。cell 惰性构建:对于在事件流过之后才注册的单元,或比注册表更早的会话,注册表会先校验规范化的 seed 边界,再通过唯一一次 `init(header)` 调用把不可变的 `SessionHeader` 传给单元,随后在首次触达(事件或读取)时折叠内存日志。detached cache、history 与 Subagent restore 路径把与持久事件同一次读取返回的不可变 header 传给同一个初始化器。注册是一个 effect,其 disposer 随调用方 fiber 走:同一 key 以不同 `stateVersion` 重复注册时抛错,同版本注册方则共享一个单元并计数;最后一个注册方卸载后,该 key 与其 cell 才会消失。领域插件在 `ctx.inject(['sessionProjections'], …)` 下注册,因此不带注册表的 headless 组装完全不受影响。
+`SessionProjectionRegistry`([签名](#ctxsessionprojections--sessionprojectionregistry))拥有驱动权:一份 `session/event` 订阅、对每个已注册单元即时调用 `apply`,以及每会话每单元的水位线(watermark)cell。cell 惰性构建:在事件流过之后才注册的单元,或比注册表更早的会话,都在首次触达(事件或读取)时从 `init` 出发在内存日志上折叠。注册是一个 effect,其 disposer 随调用方 fiber 走:领域插件卸载后,其 key(连同缓存的 cell)从后续驱动与快照中消失,客户端将其读作能力缺失;key 以不同 `stateVersion` 重复时直接 throw,同版本注册方则共享一个单元并被计数。领域插件在 `ctx.inject(['sessionProjections'], …)` 下注册,因此不带注册表的 headless 组装完全不受影响。
@@ -118,11 +118,12 @@ The persisted projection cache service. Opens the `session_projcache` domain at
```ts cordis-catalog
/**
* The zero-I/O listing read: whole values viewed straight from the stored
- * rows (version-matching keys only), with the lowest served watermark carried
- * for later authoritative reconciliation. The caller's header keeps unrelated
- * lifecycles out; repeated list blocks are arrival-ordered tentative hints
- * because crash repair may lower the durable sequence; authoritative frames
- * replace matching rows, and complete baselines replace the full set.
+ * rows (version-matching keys only), each cut carried with its watermark so
+ * a client value store can seed under its higher-seq-wins rule — as stale
+ * as the last durable checkpoint but never wrong, and never from an
+ * unrelated log (the caller's header is the identity witness). Fresher
+ * paths (the history tail baseline) supersede these values whenever a
+ * session is actually opened.
* @param meta - the listed session's header (identity witness; no log read).
* @param keys - optional projection keys required by the caller's audience.
* @returns the cut (`asOfSeq` = lowest served-row watermark), or
@@ -273,11 +274,10 @@ restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined
/**
* View a checkpoint's rows without any log read: for every registered
* client-visible unit whose row's `ver` matches, serve the schema-validated
- * `view` of the schema-validated stored state; mismatched, malformed, or
- * absent rows leave their key absent. The current log extent is unknown, so
- * returned values are tentative hints: a row may trail the log or overreach
- * a crash-repaired truncation. Exact restore validates the cut before using
- * a row as authoritative state.
+ * `view` of the schema-validated stored state; mismatched, malformed, or absent rows leave their key
+ * absent (a cold or listing consumer treats it as not-yet-available and a
+ * fuller read path refolds it). The zero-I/O rung of the read ladder —
+ * values are as stale as their rows, never wrong.
* @param checkpoint - persisted rows for one session (possibly stale or empty).
* @param keys - optional wire keys to view.
* @returns whole values per key with a usable row; empty when none.
diff --git a/docs/subsystems/session-reference.i18n.yaml b/docs/subsystems/session-reference.i18n.yaml
index 886a442517..29ba36ab67 100644
--- a/docs/subsystems/session-reference.i18n.yaml
+++ b/docs/subsystems/session-reference.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-reference.md
-session-reference.md: 17c0d14485bd5a0eea97781c8f5fe1c4b3bda886
-session-reference.zh.md: 31a94bf94442a3778763457869bf916e18964a5c
+session-reference.md: 1dd5cc1ee8c594b34015f9bf2d765f68621b86a1
+session-reference.zh.md: 75b5018a6afbd1bbe21f303013e0e7fa0d1f89ab
diff --git a/docs/subsystems/session-reference.md b/docs/subsystems/session-reference.md
index 17c0d14485..1dd5cc1ee8 100644
--- a/docs/subsystems/session-reference.md
+++ b/docs/subsystems/session-reference.md
@@ -34,7 +34,7 @@ interface SessionReferenceInput {
}
```
-`SessionReferenceCandidate` is host-facing discovery output. Its label uses the latest session title when present, while filtering still searches only session id and cwd and never transcript text.
+`SessionReferenceCandidate` is host-facing discovery output. Its label uses the latest session title when present, and filtering searches that label alongside session id and cwd, never transcript text.
```ts type-equiv
/** One host-facing candidate from exact session metadata. */
@@ -45,6 +45,12 @@ interface SessionReferenceCandidate {
label: string
/** Source session working directory, when recorded. */
cwd?: string
+ /**
+ * True when {@link SessionReferenceCandidate.cwd} is recorded and equals the
+ * requesting agent's. Hosts that only surface a distinguishing location
+ * read this instead of comparing paths they never received.
+ */
+ sameWorkspace: boolean
/** Source session creation time in Unix epoch milliseconds. */
createdAt: number
}
@@ -113,22 +119,33 @@ Host capability for cancellable file-reference discovery.
* @returns deterministic path-only candidates.
*/
abstract list( agent: Agent, query: string, signal: AbortSignal, ): Promise
-
-/**
- * Remote face of {@link list}; the decorator cannot mark the abstract
- * member, so this concrete adapter carries the identical contract.
- * @param agent - target agent whose session cwd bounds discovery.
- * @param query - path text following `@` or `@"`.
- * @param signal - caller cancellation.
- * @returns deterministic path-only candidates.
- */
-@Remote('list') remoteExportList( agent: Agent, query: string, signal: AbortSignal, ): Promise
```
Types: [Agent](core.md)
Source: [`packages/context/file-reference/src/index.ts`](../../packages/context/file-reference/src/index.ts)
+
+
+### `ctx.sessionFileReferences` — `SessionFileReferences`
+
+Host Remote adapter over the composed file-reference provider.
+
+```ts cordis-catalog
+/**
+ * List file and directory candidates for one Agent's working directory.
+ * @param agent - target Agent resolved from the Session identity on the wire.
+ * @param query - path text following `@` or `@"`.
+ * @param signal - caller cancellation.
+ * @returns deterministic path-only candidates from the composed provider.
+ */
+@Remote list( agent: Agent, query: string, signal: AbortSignal, ): Promise
+```
+
+Types: [Agent](core.md)
+
+Source: [`packages/api/session-controller/src/file-references.ts`](../../packages/api/session-controller/src/file-references.ts)
+
### `ctx.sessionReferenceResolver` — `SessionReferenceResolver`
@@ -138,6 +155,10 @@ Exact-read consumer that prepares immutable cross-session message context.
```ts cordis-catalog
/**
* List reference candidates, ranked by working-directory affinity.
+ *
+ * Discovery runs at keystroke rate, so a title only ever comes from a
+ * projection read: see {@link SessionReferenceResolver.projectedTitle} for
+ * which sessions can answer one and which fall back to their id.
* @param agent - target agent; self is excluded and its cwd drives ranking.
* @param query - optional case-insensitive session-id/cwd/title substring.
* @param limit - optional positive result cap.
diff --git a/docs/subsystems/session-reference.zh.md b/docs/subsystems/session-reference.zh.md
index 31a94bf944..75b5018a6a 100644
--- a/docs/subsystems/session-reference.zh.md
+++ b/docs/subsystems/session-reference.zh.md
@@ -34,7 +34,7 @@ interface SessionReferenceInput {
}
```
-`SessionReferenceCandidate` 是面向宿主的发现输出。存在最新会话标题时,它的 label 使用该标题;筛选仍只搜索 session id 和 cwd,绝不搜索 transcript(文本记录)。
+`SessionReferenceCandidate` 是面向宿主的发现输出。存在最新会话标题时,它的 label 使用该标题;筛选搜索该 label 以及 session id 和 cwd,绝不搜索 transcript(文本记录)。
```ts type-equiv
/** One host-facing candidate from exact session metadata. */
@@ -45,6 +45,12 @@ interface SessionReferenceCandidate {
label: string
/** Source session working directory, when recorded. */
cwd?: string
+ /**
+ * True when {@link SessionReferenceCandidate.cwd} is recorded and equals the
+ * requesting agent's. Hosts that only surface a distinguishing location
+ * read this instead of comparing paths they never received.
+ */
+ sameWorkspace: boolean
/** Source session creation time in Unix epoch milliseconds. */
createdAt: number
}
@@ -113,22 +119,33 @@ Host capability for cancellable file-reference discovery.
* @returns deterministic path-only candidates.
*/
abstract list( agent: Agent, query: string, signal: AbortSignal, ): Promise
-
-/**
- * Remote face of {@link list}; the decorator cannot mark the abstract
- * member, so this concrete adapter carries the identical contract.
- * @param agent - target agent whose session cwd bounds discovery.
- * @param query - path text following `@` or `@"`.
- * @param signal - caller cancellation.
- * @returns deterministic path-only candidates.
- */
-@Remote('list') remoteExportList( agent: Agent, query: string, signal: AbortSignal, ): Promise
```
Types: [Agent](core.zh.md)
Source: [`packages/context/file-reference/src/index.ts`](../../packages/context/file-reference/src/index.ts)
+
+
+### `ctx.sessionFileReferences` — `SessionFileReferences`
+
+Host Remote adapter over the composed file-reference provider.
+
+```ts cordis-catalog
+/**
+ * List file and directory candidates for one Agent's working directory.
+ * @param agent - target Agent resolved from the Session identity on the wire.
+ * @param query - path text following `@` or `@"`.
+ * @param signal - caller cancellation.
+ * @returns deterministic path-only candidates from the composed provider.
+ */
+@Remote list( agent: Agent, query: string, signal: AbortSignal, ): Promise
+```
+
+Types: [Agent](core.zh.md)
+
+Source: [`packages/api/session-controller/src/file-references.ts`](../../packages/api/session-controller/src/file-references.ts)
+
### `ctx.sessionReferenceResolver` — `SessionReferenceResolver`
@@ -138,6 +155,10 @@ Exact-read consumer that prepares immutable cross-session message context.
```ts cordis-catalog
/**
* List reference candidates, ranked by working-directory affinity.
+ *
+ * Discovery runs at keystroke rate, so a title only ever comes from a
+ * projection read: see {@link SessionReferenceResolver.projectedTitle} for
+ * which sessions can answer one and which fall back to their id.
* @param agent - target agent; self is excluded and its cwd drives ranking.
* @param query - optional case-insensitive session-id/cwd/title substring.
* @param limit - optional positive result cap.
diff --git a/docs/subsystems/session.i18n.yaml b/docs/subsystems/session.i18n.yaml
index 80666a3c88..f459ae1fd9 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: 87e8b33dec8eda6f7a716d71f5c4afa69a420d35
-session.zh.md: d30b7d24412a04521300c657c1b07daa1620ca5f
+session.md: f3c246f7a77386a088f0559d233031bdb8d997f8
+session.zh.md: bc706a11e9b504f6806cbf7c1beb67b972fb4f75
diff --git a/docs/subsystems/session.md b/docs/subsystems/session.md
index 87e8b33dec..f3c246f7a7 100644
--- a/docs/subsystems/session.md
+++ b/docs/subsystems/session.md
@@ -577,6 +577,12 @@ What a persistence backend relies on: the durable log persists every event lossl
The backends that consume this contract are on [persistence.md](persistence.md).
+## Remote catalog and workspace opening
+
+`ModelCatalog` is the Host-generation model directory returned by `session/modelCatalog`: it carries the deployment default, routable provider ids, successful provider groups, and isolated provider failures. It is not derived from one Session and remains separate from Session projections.
+
+`SessionOpenWorkspacePathRequest` carries an absolute or workspace-resolved `path`. `SessionOpenWorkspacePathValue` confirms that the Host accepted the native handoff. A Session-aware Client resolves relative paths against its current Session cwd when known; the controller hands the path to the opener unchanged and reports invalid requests, cancellation, and opener failures through the Session Remote error vocabulary.
+
@@ -637,6 +643,27 @@ inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<{ meta: SessionH
*/
@Remote('selectModel') selectModel(request: SessionSelectModelRequest): Promise
+/**
+ * Describe every currently routable model for Host-generation selectors.
+ * @returns provider-grouped models, the deployment default, and isolated provider failures.
+ */
+@Remote('modelCatalog') modelCatalog(): Promise
+
+/**
+ * Report whether this deployment can hand a Session workspace path to a native desktop.
+ * @returns true when the matching open operation is available.
+ */
+@Remote canOpenWorkspacePath(): boolean
+
+/**
+ * Open one path prepared by a Session-aware caller on the Host desktop.
+ * @param request - path after best-effort Session workspace resolution.
+ * @param signal - caller lifetime; abort terminates the native command.
+ * @returns confirmation after the native opener accepts the path.
+ * @throws TypertRemoteFailure when the request is invalid, cancelled, or the opener fails.
+ */
+@Remote('openWorkspacePath') async openWorkspacePath( request: SessionOpenWorkspacePathRequest, signal: AbortSignal, ): Promise
+
/**
* Rename one Session after explicitly resuming it.
* @param request - Session identity and proposed title.
diff --git a/docs/subsystems/session.zh.md b/docs/subsystems/session.zh.md
index d30b7d2441..bc706a11e9 100644
--- a/docs/subsystems/session.zh.md
+++ b/docs/subsystems/session.zh.md
@@ -581,6 +581,12 @@ interface TurnEndReasonMap {
消费此约定的后端见 [persistence.md](persistence.zh.md)。
+## Remote 目录与 workspace 打开
+
+`ModelCatalog` 是 `session/modelCatalog` 返回的 Host generation 模型目录:它携带部署默认值、可路由 provider id、成功的 provider 分组与相互隔离的 provider 失败。它不由某个 Session 派生,因此与 Session projection 分开保存。
+
+`SessionOpenWorkspacePathRequest` 携带绝对路径或已按 workspace 解析的 `path`。`SessionOpenWorkspacePathValue` 确认 Host 已接受原生交接。Session-aware Client 会在已知当前 Session cwd 时据此解析相对路径;controller 将路径原样交给打开器,并通过 Session Remote 错误词汇表报告无效请求、取消与打开器失败。
+
@@ -641,6 +647,27 @@ inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<{ meta: SessionH
*/
@Remote('selectModel') selectModel(request: SessionSelectModelRequest): Promise
+/**
+ * Describe every currently routable model for Host-generation selectors.
+ * @returns provider-grouped models, the deployment default, and isolated provider failures.
+ */
+@Remote('modelCatalog') modelCatalog(): Promise
+
+/**
+ * Report whether this deployment can hand a Session workspace path to a native desktop.
+ * @returns true when the matching open operation is available.
+ */
+@Remote canOpenWorkspacePath(): boolean
+
+/**
+ * Open one path prepared by a Session-aware caller on the Host desktop.
+ * @param request - path after best-effort Session workspace resolution.
+ * @param signal - caller lifetime; abort terminates the native command.
+ * @returns confirmation after the native opener accepts the path.
+ * @throws TypertRemoteFailure when the request is invalid, cancelled, or the opener fails.
+ */
+@Remote('openWorkspacePath') async openWorkspacePath( request: SessionOpenWorkspacePathRequest, signal: AbortSignal, ): Promise
+
/**
* Rename one Session after explicitly resuming it.
* @param request - Session identity and proposed title.
diff --git a/docs/subsystems/settings.i18n.yaml b/docs/subsystems/settings.i18n.yaml
index 0c345cf749..2efb877591 100644
--- a/docs/subsystems/settings.i18n.yaml
+++ b/docs/subsystems/settings.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/settings.md
-settings.md: 59bd06a6e7a8659097c726b85db13caa46dd461f
-settings.zh.md: a6bbdbce633a8b51167615f7838e55b698d48829
+settings.md: 3215de191b4ef8fecb373d280c8bc8e4a89bbc7e
+settings.zh.md: 0c28ef381ee6ea8e59da64717575fbf80c8a2e5f
diff --git a/docs/subsystems/settings.md b/docs/subsystems/settings.md
index 59bd06a6e7..3215de191b 100644
--- a/docs/subsystems/settings.md
+++ b/docs/subsystems/settings.md
@@ -161,6 +161,10 @@ Every committed change — an in-process write or an externally observed provide
type SettingsUpdateSource = 'update' | 'provider'
```
+## Native document operations
+
+`SettingsDocumentOpenValue` confirms that `settings/openSettingsDocument` prepared the provider-owned document and handed it to the native text editor. `AgentPresetDirectoryOpenValue` reports either a completed native handoff or the resolved user-preset directory when desktop opening is unavailable. Neither operation accepts a browser-selected Host path.
+
@@ -269,6 +273,12 @@ Host service backing the generated `ctx.remote.settings` namespace. Every remote
*/
@Remote describe(): SettingsDescribeValue
+/**
+ * Report whether this deployment can open an authored Agent preset directory natively.
+ * @returns true when the matching open operation is available.
+ */
+@Remote canOpenAgentPresetDirectory(): boolean
+
/**
* Merge a patch into one namespace's stored user section.
* @param ns - namespace key to write.
@@ -300,6 +310,23 @@ Host service backing the generated `ctx.remote.settings` namespace. Every remote
* @throws TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.
*/
@Remote async mutate( ns: string, ops: SettingsPathOpView[], expectedRevision: number | undefined, ): Promise
+
+/**
+ * Materialize the provider-owned settings document and open it in a native text editor.
+ * @param signal - caller lifetime; abort terminates preparation or the native command.
+ * @returns confirmation after the native opener accepts the document.
+ * @throws TypertRemoteFailure when no document exists, preparation fails, or opening fails.
+ */
+@Remote async openSettingsDocument(signal: AbortSignal): Promise
+
+/**
+ * Open one user-authored Agent preset directory or return its path when no native opener exists.
+ * @param agentPreset - preset id resolved against Host-owned roots.
+ * @param signal - caller lifetime; abort terminates the native command.
+ * @returns an opened confirmation or the resolved directory for text display.
+ * @throws TypertRemoteFailure when the preset is missing, read-only, invalid, or cannot be opened.
+ */
+@Remote async openAgentPresetDirectory( agentPreset: string, signal: AbortSignal, ): Promise
```
Source: [`packages/api/settings-controller/src/index.ts`](../../packages/api/settings-controller/src/index.ts)
diff --git a/docs/subsystems/settings.zh.md b/docs/subsystems/settings.zh.md
index a6bbdbce63..0c28ef381e 100644
--- a/docs/subsystems/settings.zh.md
+++ b/docs/subsystems/settings.zh.md
@@ -161,6 +161,10 @@ interface SettingsDescribeOptions {
type SettingsUpdateSource = 'update' | 'provider'
```
+## 原生文档操作
+
+`SettingsDocumentOpenValue` 确认 `settings/openSettingsDocument` 已准备好 provider 持有的文档,并将其交给原生文本编辑器。`AgentPresetDirectoryOpenValue` 报告已完成的原生交接,或在桌面打开不可用时返回解析后的用户 preset 目录。两项操作都不接受由浏览器选择的 Host 路径。
+
@@ -269,6 +273,12 @@ Host service backing the generated `ctx.remote.settings` namespace. Every remote
*/
@Remote describe(): SettingsDescribeValue
+/**
+ * Report whether this deployment can open an authored Agent preset directory natively.
+ * @returns true when the matching open operation is available.
+ */
+@Remote canOpenAgentPresetDirectory(): boolean
+
/**
* Merge a patch into one namespace's stored user section.
* @param ns - namespace key to write.
@@ -300,6 +310,23 @@ Host service backing the generated `ctx.remote.settings` namespace. Every remote
* @throws TypertRemoteFailure when the request is invalid, no provider is mounted, or the provider refuses the write.
*/
@Remote async mutate( ns: string, ops: SettingsPathOpView[], expectedRevision: number | undefined, ): Promise
+
+/**
+ * Materialize the provider-owned settings document and open it in a native text editor.
+ * @param signal - caller lifetime; abort terminates preparation or the native command.
+ * @returns confirmation after the native opener accepts the document.
+ * @throws TypertRemoteFailure when no document exists, preparation fails, or opening fails.
+ */
+@Remote async openSettingsDocument(signal: AbortSignal): Promise
+
+/**
+ * Open one user-authored Agent preset directory or return its path when no native opener exists.
+ * @param agentPreset - preset id resolved against Host-owned roots.
+ * @param signal - caller lifetime; abort terminates the native command.
+ * @returns an opened confirmation or the resolved directory for text display.
+ * @throws TypertRemoteFailure when the preset is missing, read-only, invalid, or cannot be opened.
+ */
+@Remote async openAgentPresetDirectory( agentPreset: string, signal: AbortSignal, ): Promise
```
Source: [`packages/api/settings-controller/src/index.ts`](../../packages/api/settings-controller/src/index.ts)
diff --git a/docs/subsystems/skills.i18n.yaml b/docs/subsystems/skills.i18n.yaml
index 93efc1068d..7bf2ead73e 100644
--- a/docs/subsystems/skills.i18n.yaml
+++ b/docs/subsystems/skills.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/skills.md
-skills.md: 5abfa84356dc947f8b3359ad5f0fc5c42a99553a
-skills.zh.md: 87759b5ab5bdfc5e9ab10cf9a86147c16893efd3
+skills.md: 18eb4d3289cec5c7807feab4229096b5799d4168
+skills.zh.md: aa167373cb9736cf24d7bf20dc965e68568826be
diff --git a/docs/subsystems/skills.md b/docs/subsystems/skills.md
index 5abfa84356..18eb4d3289 100644
--- a/docs/subsystems/skills.md
+++ b/docs/subsystems/skills.md
@@ -234,6 +234,10 @@ Before each later model step, the consumer applies exact tool visibility and dig
The model-facing `skill({ name })` tool validates the kebab-case name, finds the summary in the invocation-neutral catalog, rejects it before loading unless `isModelInvocable` permits access, then rereads the complete definition for the calling agent cwd and rechecks the policy before returning content. It reports an unresolved skill as unknown or no longer available and returns a tool result containing ``, ``, and ``. `resourceBase` resolves explicitly referenced scripts, references, and assets only as needed; the loaded result does not enumerate a skill directory. Body-only edits therefore change later tool calls without producing catalog messages or rewriting earlier tool results.
+## Browser Session catalog
+
+`SkillListRequest` addresses one Session by `sessionId`; `SkillListValue` returns the user-invocable entries with name, description, optional usage guidance, and model-invocation availability. `SessionSkillCatalog` reads the Session cwd and recorded preset without activating an Agent. A live Agent may supply its scoped registry, while a cold Session uses the preset's standing scope.
+
@@ -242,6 +246,25 @@ The model-facing `skill({ name })` tool validates the kebab-case name, finds the
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
+
+
+### `ctx.sessionSkillCatalog` — `SessionSkillCatalog`
+
+Host service backing `ctx.remote.skills` without activating a cold Agent.
+
+```ts cordis-catalog
+/**
+ * List the user-invocable skills visible to one Session composition.
+ * @param request - Session identity whose cwd and preset select the catalog view.
+ * @param signal - caller lifetime carried by the Remote transport; admitted catalog reads retain their existing completion semantics.
+ * @returns user-invocable skill metadata without loading skill bodies.
+ * @throws TypertRemoteFailure when the Session cannot be inspected or no registry can serve it.
+ */
+@Remote async list(request: SkillListRequest, signal: AbortSignal): Promise
+```
+
+Source: [`packages/api/session-controller/src/skill-catalog.ts`](../../packages/api/session-controller/src/skill-catalog.ts)
+
### `ctx.skills` — `SkillRegistry`
diff --git a/docs/subsystems/skills.zh.md b/docs/subsystems/skills.zh.md
index 87759b5ab5..aa167373cb 100644
--- a/docs/subsystems/skills.zh.md
+++ b/docs/subsystems/skills.zh.md
@@ -234,6 +234,10 @@ interface Config {
面向模型的 `skill({ name })` 工具校验 kebab-case 名称,在与调用策略无关的目录中查找摘要,并在加载前通过 `isModelInvocable` 拒绝无权访问的 skill;随后它根据调用方 agent 的 cwd 重新读取完整定义,并在返回内容前再次检查策略。该工具将无法解析的 skill 报告为未知或已不可用,并返回包含 ``、`` 和 `` 的工具结果。`resourceBase` 仅按需解析显式引用的脚本、参考资料和资产;加载结果不枚举 skill 目录。因此,仅修改正文会改变后续工具调用,而不会生成目录消息或改写先前工具结果。
+## 浏览器 Session 目录
+
+`SkillListRequest` 通过 `sessionId` 指定一个 Session;`SkillListValue` 返回允许用户调用的条目,其中包含名称、描述、可选使用提示与模型调用可用性。`SessionSkillCatalog` 在不激活 Agent 的前提下读取 Session cwd 与记录的 preset。live Agent 可以提供其作用域 registry,冷 Session 则使用 preset 的 standing scope。
+
@@ -242,6 +246,25 @@ interface Config {
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.zh.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
+
+
+### `ctx.sessionSkillCatalog` — `SessionSkillCatalog`
+
+Host service backing `ctx.remote.skills` without activating a cold Agent.
+
+```ts cordis-catalog
+/**
+ * List the user-invocable skills visible to one Session composition.
+ * @param request - Session identity whose cwd and preset select the catalog view.
+ * @param signal - caller lifetime carried by the Remote transport; admitted catalog reads retain their existing completion semantics.
+ * @returns user-invocable skill metadata without loading skill bodies.
+ * @throws TypertRemoteFailure when the Session cannot be inspected or no registry can serve it.
+ */
+@Remote async list(request: SkillListRequest, signal: AbortSignal): Promise
+```
+
+Source: [`packages/api/session-controller/src/skill-catalog.ts`](../../packages/api/session-controller/src/skill-catalog.ts)
+
### `ctx.skills` — `SkillRegistry`
diff --git a/docs/subsystems/subagent.i18n.yaml b/docs/subsystems/subagent.i18n.yaml
index f4414983b1..9e82c64ceb 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: f854711f1161ba1c533fdbc43d7d6c35681f2f7f
-subagent.zh.md: 960d9b099d915fcf5b1e321ab74374664bb8e468
+subagent.md: 9206672b89ac31e30bee176f536b3057eb37f3ee
+subagent.zh.md: 30e4e09a145a4b3d51044d85c602ce81fd44c3b3
diff --git a/docs/subsystems/subagent.md b/docs/subsystems/subagent.md
index f854711f11..9206672b89 100644
--- a/docs/subsystems/subagent.md
+++ b/docs/subsystems/subagent.md
@@ -505,10 +505,10 @@ Singleton settings owner read by delegation tools when an Agent is published.
```ts cordis-catalog
/**
- * Read the preference for the next eligible Agent publication.
- * @returns whether that Agent should receive model-selectable delegation.
+ * Read a detached selection preference for the next eligible Agent publication.
+ * @returns the enabled state and exact allowed routes.
*/
-currentEnabled(): boolean
+current(): SubagentModelSelectionSettings
```
Source: [`packages/subagent/tool-subagent/src/model-selection-settings.ts`](../../packages/subagent/tool-subagent/src/model-selection-settings.ts)
diff --git a/docs/subsystems/subagent.zh.md b/docs/subsystems/subagent.zh.md
index 960d9b099d..30e4e09a14 100644
--- a/docs/subsystems/subagent.zh.md
+++ b/docs/subsystems/subagent.zh.md
@@ -509,10 +509,10 @@ Singleton settings owner read by delegation tools when an Agent is published.
```ts cordis-catalog
/**
- * Read the preference for the next eligible Agent publication.
- * @returns whether that Agent should receive model-selectable delegation.
+ * Read a detached selection preference for the next eligible Agent publication.
+ * @returns the enabled state and exact allowed routes.
*/
-currentEnabled(): boolean
+current(): SubagentModelSelectionSettings
```
Source: [`packages/subagent/tool-subagent/src/model-selection-settings.ts`](../../packages/subagent/tool-subagent/src/model-selection-settings.ts)
diff --git a/docs/subsystems/tools.i18n.yaml b/docs/subsystems/tools.i18n.yaml
index 3de50c917a..d448297059 100644
--- a/docs/subsystems/tools.i18n.yaml
+++ b/docs/subsystems/tools.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/tools.md
-tools.md: 5ac2401d662bca52cac529c0620a39930565a7c7
-tools.zh.md: a081c58a2ba4df50b035a4dae8fa7f9ab7d9de1a
+tools.md: 9939e8ab9fff9fa5bd23fd370e07f6296a608824
+tools.zh.md: 52e812a35d6932a5ed00a86a3d3fe71460b26cd4
diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md
index 5ac2401d66..9939e8ab9f 100644
--- a/docs/subsystems/tools.md
+++ b/docs/subsystems/tools.md
@@ -157,7 +157,7 @@ Registration is a trusted same-process contract. The registry borrows the typed
```ts type-equiv
/**
* Per-scope filter over global tools. Restrictions intersect and do not affect
- * scoped registrations or the reserved Code Mode transport.
+ * scoped registrations or the reserved PTC mode transport.
*/
interface ToolRestriction {
/** Global tool names that stay visible; everything else is removed. */
@@ -195,11 +195,11 @@ interface ToolExecutionInput {
/** The agent on whose behalf the call runs (set by the agent loop). */
readonly agent?: Agent
/**
- * Opaque token of the enclosing transport execution, when one exists. Code
- * Mode sets this on SDK sub-dispatches so commit-style observers can wait for
+ * Opaque token of the enclosing transport execution, when one exists. PTC
+ * mode sets this on SDK sub-dispatches so commit-style observers can wait for
* the outer `run_code` outcome without receiving its live mutable execution.
* The token also marks the call as a transport sub-dispatch rather than a
- * model-direct call: under `mode: 'code'`, only calls WITH a parent may
+ * model-direct call: under `mode: 'ptc'`, only calls WITH a parent may
* execute a native tool name — a model-direct call (no parent) is denied as
* `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRuntime.execute}.
*/
@@ -252,19 +252,19 @@ type ToolExecutionMode =
| { kind: 'exclusive' }
```
-Code Mode's bridge additionally exposes each settled sub-dispatch to the `tools/code-dispatch-log` waterfall, which may change the durable event's copy of the content (the program's value and model-visible result remain untouched):
+PTC mode's bridge additionally exposes each settled sub-dispatch to the `tools/ptc-dispatch-log` waterfall, which may change the durable event's copy of the content (the program's value and model-visible result remain untouched):
```ts type-equiv
/**
* One settled `run_code` sub-dispatch about to be logged, as seen by the
- * `tools/code-dispatch-log` waterfall: the parent execution (session owner,
+ * `tools/ptc-dispatch-log` waterfall: the parent execution (session owner,
* outer call identity), the sub-call identity, and the outcome whose durable
* copy a listener may reshape. `content` is the RENDERED result projection
* (what a native `tool/result` would carry) — the program itself received
* the structured `value` (or just the error message on failure); only the
* `tool/code-dispatch` event's copy changes.
*/
-interface CodeDispatchLog {
+interface PtcDispatchLog {
/** The outer `run_code` execution. */
readonly exec: ToolExecution
/** The calling agent (the scope routing key and the spill owner), when the outer call has one. */
@@ -488,7 +488,7 @@ Tool registry and execution pipeline. Scoped registrations shadow globals; one v
* declaration covers every agent joined under it.
*
* Scoped only, and one declaration per scope: this is how an agent preset
- * composes Code Mode agents beside native ones in the same process, and a
+ * composes PTC mode agents beside native ones in the same process, and a
* process-global override would be the `mode` config field instead.
* @param mode - the presentation the covered agents' models see.
* @returns the exact disposer that restores the deployment default.
@@ -598,33 +598,6 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai
Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
-
-
-#### `tools/code-dispatch-log` — waterfall
-
-Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
-
-```ts cordis-catalog
-/**
- * Allow a listener to replace content in the DURABLE LOG COPY of one
- * `run_code` sub-dispatch outcome before the bridge appends its
- * `tool/code-dispatch` event. `next()` keeps the
- * content unchanged; a listener may return replacement blocks (e.g. the
- * spill policy's preview + locator for an oversized text result). Only the
- * logged copy is affected — the program already received the complete
- * value, and the model sees neither. A throwing listener is contained:
- * the bridge falls back to logging the original settled content.
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
- * @param dispatch - the parent execution, sub-call identity, and the settled content to log.
- * @mode waterfall
- */
-'tools/code-dispatch-log'(this: Scoped, dispatch: CodeDispatchLog, next: () => Promise): Promise
-```
-
-Types: [ContentBlock](llm-streaming.md) · [Scoped](scope.md)
-
-Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
-
#### `tools/execute` — waterfall
@@ -697,6 +670,33 @@ Types: [Scoped](scope.md)
Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
+
+
+#### `tools/ptc-dispatch-log` — waterfall
+
+Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
+
+```ts cordis-catalog
+/**
+ * Allow a listener to replace content in the DURABLE LOG COPY of one
+ * `run_code` sub-dispatch outcome before the bridge appends its
+ * `tool/code-dispatch` event. `next()` keeps the
+ * content unchanged; a listener may return replacement blocks (e.g. the
+ * spill policy's preview + locator for an oversized text result). Only the
+ * logged copy is affected — the program already received the complete
+ * value, and the model sees neither. A throwing listener is contained:
+ * the bridge falls back to logging the original settled content.
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
+ * @param dispatch - the parent execution, sub-call identity, and the settled content to log.
+ * @mode waterfall
+ */
+'tools/ptc-dispatch-log'(this: Scoped, dispatch: PtcDispatchLog, next: () => Promise): Promise
+```
+
+Types: [ContentBlock](llm-streaming.md) · [Scoped](scope.md)
+
+Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
+
#### `tools/result` — emit
diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md
index a081c58a2b..52e812a35d 100644
--- a/docs/subsystems/tools.zh.md
+++ b/docs/subsystems/tools.zh.md
@@ -157,7 +157,7 @@ type InferArgs = InferProperties
```ts type-equiv
/**
* Per-scope filter over global tools. Restrictions intersect and do not affect
- * scoped registrations or the reserved Code Mode transport.
+ * scoped registrations or the reserved PTC mode transport.
*/
interface ToolRestriction {
/** Global tool names that stay visible; everything else is removed. */
@@ -195,11 +195,11 @@ interface ToolExecutionInput {
/** The agent on whose behalf the call runs (set by the agent loop). */
readonly agent?: Agent
/**
- * Opaque token of the enclosing transport execution, when one exists. Code
- * Mode sets this on SDK sub-dispatches so commit-style observers can wait for
+ * Opaque token of the enclosing transport execution, when one exists. PTC
+ * mode sets this on SDK sub-dispatches so commit-style observers can wait for
* the outer `run_code` outcome without receiving its live mutable execution.
* The token also marks the call as a transport sub-dispatch rather than a
- * model-direct call: under `mode: 'code'`, only calls WITH a parent may
+ * model-direct call: under `mode: 'ptc'`, only calls WITH a parent may
* execute a native tool name — a model-direct call (no parent) is denied as
* `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRuntime.execute}.
*/
@@ -252,19 +252,19 @@ type ToolExecutionMode =
| { kind: 'exclusive' }
```
-Code Mode 的桥接层还会把每个已结算的子分派暴露给 `tools/code-dispatch-log` waterfall,该 waterfall 可以更改持久事件所存的内容副本(程序取得的值和模型可见结果均不受影响):
+PTC mode 的桥接层还会把每个已结算的子分派暴露给 `tools/ptc-dispatch-log` waterfall,该 waterfall 可以更改持久事件所存的内容副本(程序取得的值和模型可见结果均不受影响):
```ts type-equiv
/**
* One settled `run_code` sub-dispatch about to be logged, as seen by the
- * `tools/code-dispatch-log` waterfall: the parent execution (session owner,
+ * `tools/ptc-dispatch-log` waterfall: the parent execution (session owner,
* outer call identity), the sub-call identity, and the outcome whose durable
* copy a listener may reshape. `content` is the RENDERED result projection
* (what a native `tool/result` would carry) — the program itself received
* the structured `value` (or just the error message on failure); only the
* `tool/code-dispatch` event's copy changes.
*/
-interface CodeDispatchLog {
+interface PtcDispatchLog {
/** The outer `run_code` execution. */
readonly exec: ToolExecution
/** The calling agent (the scope routing key and the spill owner), when the outer call has one. */
@@ -488,7 +488,7 @@ Tool registry and execution pipeline. Scoped registrations shadow globals; one v
* declaration covers every agent joined under it.
*
* Scoped only, and one declaration per scope: this is how an agent preset
- * composes Code Mode agents beside native ones in the same process, and a
+ * composes PTC mode agents beside native ones in the same process, and a
* process-global override would be the `mode` config field instead.
* @param mode - the presentation the covered agents' models see.
* @returns the exact disposer that restores the deployment default.
@@ -598,33 +598,6 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai
Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
-
-
-#### `tools/code-dispatch-log` — waterfall
-
-Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
-
-```ts cordis-catalog
-/**
- * Allow a listener to replace content in the DURABLE LOG COPY of one
- * `run_code` sub-dispatch outcome before the bridge appends its
- * `tool/code-dispatch` event. `next()` keeps the
- * content unchanged; a listener may return replacement blocks (e.g. the
- * spill policy's preview + locator for an oversized text result). Only the
- * logged copy is affected — the program already received the complete
- * value, and the model sees neither. A throwing listener is contained:
- * the bridge falls back to logging the original settled content.
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
- * @param dispatch - the parent execution, sub-call identity, and the settled content to log.
- * @mode waterfall
- */
-'tools/code-dispatch-log'(this: Scoped, dispatch: CodeDispatchLog, next: () => Promise): Promise
-```
-
-Types: [ContentBlock](llm-streaming.zh.md) · [Scoped](scope.zh.md)
-
-Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
-
#### `tools/execute` — waterfall
@@ -697,6 +670,33 @@ Types: [Scoped](scope.zh.md)
Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
+
+
+#### `tools/ptc-dispatch-log` — waterfall
+
+Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
+
+```ts cordis-catalog
+/**
+ * Allow a listener to replace content in the DURABLE LOG COPY of one
+ * `run_code` sub-dispatch outcome before the bridge appends its
+ * `tool/code-dispatch` event. `next()` keeps the
+ * content unchanged; a listener may return replacement blocks (e.g. the
+ * spill policy's preview + locator for an oversized text result). Only the
+ * logged copy is affected — the program already received the complete
+ * value, and the model sees neither. A throwing listener is contained:
+ * the bridge falls back to logging the original settled content.
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
+ * @param dispatch - the parent execution, sub-call identity, and the settled content to log.
+ * @mode waterfall
+ */
+'tools/ptc-dispatch-log'(this: Scoped, dispatch: PtcDispatchLog, next: () => Promise): Promise
+```
+
+Types: [ContentBlock](llm-streaming.zh.md) · [Scoped](scope.zh.md)
+
+Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts)
+
#### `tools/result` — emit
diff --git a/docs/subsystems/typert.i18n.yaml b/docs/subsystems/typert.i18n.yaml
index 598956872e..498532ed69 100644
--- a/docs/subsystems/typert.i18n.yaml
+++ b/docs/subsystems/typert.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/typert.md
-typert.md: bf43280f7fa01e6300caeaadeadb2c6c8f78cdd2
-typert.zh.md: c50663ad2546d864efc5648059dde735ae4de5bd
+typert.md: 20734175cc6b853ae7eeb18e6d5fc91a97cdbe0d
+typert.zh.md: e900011f24a5a232ab8764501594b563f320e090
diff --git a/docs/subsystems/typert.md b/docs/subsystems/typert.md
index bf43280f7f..20734175cc 100644
--- a/docs/subsystems/typert.md
+++ b/docs/subsystems/typert.md
@@ -185,9 +185,13 @@ interface TypertGateway {
/**
* Register the application-selected forwarded-event source.
* @param source - stream factory installed by the Remote assembly.
+ * @param host - stable Host facts included in each Client generation's opening frame.
* @returns disposer removing this exact source and cancelling its active streams.
*/
- registerRemoteEvents(source: TypertRemoteEventSource): () => Promise
+ registerRemoteEvents(
+ source: TypertRemoteEventSource,
+ host: RemoteEventHostInfo,
+ ): () => Promise
/**
* Invoke one live Remote method without assuming a carrier or response envelope.
* @param request - decoded endpoint and named wire arguments.
@@ -238,14 +242,6 @@ interface TypertClientRemote extends TypertRemoteNamespaceMap {
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
-
-
-### `ctx.apiProxy` — `ApiProxy`
-
-Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row.
-
-Source: [`packages/host/apiproxy/src/api/index.ts`](../../packages/host/apiproxy/src/api/index.ts)
-
### `ctx.typert` — `TypertRegistry`
@@ -322,9 +318,10 @@ Resolve strict generated definitions or conservative SRC markers against current
/**
* Register the sole application-selected forwarded-event source.
* @param source - stream factory installed by the Remote assembly.
+ * @param host - stable Host facts included in each Client generation's opening frame.
* @returns disposer removing this source and cancelling its active streams.
*/
-registerRemoteEvents(source: TypertRemoteEventSource): () => Promise
+registerRemoteEvents( source: TypertRemoteEventSource, host: RemoteEventHostInfo, ): () => Promise
/**
* Invoke one live Remote method through strict generated reflection or SRC markers.
diff --git a/docs/subsystems/typert.zh.md b/docs/subsystems/typert.zh.md
index c50663ad25..e900011f24 100644
--- a/docs/subsystems/typert.zh.md
+++ b/docs/subsystems/typert.zh.md
@@ -185,9 +185,13 @@ interface TypertGateway {
/**
* Register the application-selected forwarded-event source.
* @param source - stream factory installed by the Remote assembly.
+ * @param host - stable Host facts included in each Client generation's opening frame.
* @returns disposer removing this exact source and cancelling its active streams.
*/
- registerRemoteEvents(source: TypertRemoteEventSource): () => Promise
+ registerRemoteEvents(
+ source: TypertRemoteEventSource,
+ host: RemoteEventHostInfo,
+ ): () => Promise
/**
* Invoke one live Remote method without assuming a carrier or response envelope.
* @param request - decoded endpoint and named wire arguments.
@@ -238,14 +242,6 @@ interface TypertClientRemote extends TypertRemoteNamespaceMap {
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.zh.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
-
-
-### `ctx.apiProxy` — `ApiProxy`
-
-Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row.
-
-Source: [`packages/host/apiproxy/src/api/index.ts`](../../packages/host/apiproxy/src/api/index.ts)
-
### `ctx.typert` — `TypertRegistry`
@@ -322,9 +318,10 @@ Resolve strict generated definitions or conservative SRC markers against current
/**
* Register the sole application-selected forwarded-event source.
* @param source - stream factory installed by the Remote assembly.
+ * @param host - stable Host facts included in each Client generation's opening frame.
* @returns disposer removing this source and cancelling its active streams.
*/
-registerRemoteEvents(source: TypertRemoteEventSource): () => Promise
+registerRemoteEvents( source: TypertRemoteEventSource, host: RemoteEventHostInfo, ): () => Promise
/**
* Invoke one live Remote method through strict generated reflection or SRC markers.
diff --git a/docs/subsystems/web-client.i18n.yaml b/docs/subsystems/web-client.i18n.yaml
index 98e549a149..5a83be6c89 100644
--- a/docs/subsystems/web-client.i18n.yaml
+++ b/docs/subsystems/web-client.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/web-client.md
-web-client.md: e67da4980af881e426f2bc031c6ec49cc1df2857
-web-client.zh.md: c5e9904226de66381a54bcb8a4783a062d70750f
+web-client.md: 166ad50df661e37318c5ed2f271569c292cce39a
+web-client.zh.md: cdf91958e23c0ea5c99562e6ca347947fbeff292
diff --git a/docs/subsystems/web-client.md b/docs/subsystems/web-client.md
index e67da4980a..166ad50df6 100644
--- a/docs/subsystems/web-client.md
+++ b/docs/subsystems/web-client.md
@@ -27,9 +27,9 @@ The Web boot kernel creates the module system, prefetches `immediately` entries,
Host business services annotate callable methods with Typert Remote decorators. Host generation emits strict descriptors, runtime codecs, declaration merges, and source maps. The Client-side `api-remotes` assembly selects those generated contributions and mounts concrete methods under `ctx.remote.` and Session-scoped `agentCtx.remote.`. Feature packages depend on the generated service face, not the Gateway implementation or a Host package's runtime entry.
-The Connection owns request correlation, the `/api` carrier, trust checks, Host description, and connection generations. API Gateway owns Remote dispatch, cancellation, logical streams, and selected Host event forwarding. API Proxy handles only `/api` endpoints that no strict Remote descriptor claims; new controller operations belong on generated Remote methods or explicit Remote streams. The [API Gateway reference](../api-gateway.md) defines generation and invocation, while the [Connection README](../../packages/client/connection/README.md) defines the physical carrier and trust policy.
+The Connection owns request correlation, the `/api` carrier, trust checks, exact Fetch routes, and connection generations. API Gateway owns Remote dispatch, cancellation, logical streams, and selected Host event forwarding. Controller operations belong on generated Remote methods or explicit Remote streams; feature-owned downloads register exact Fetch routes. The [API Gateway reference](../api-gateway.md) defines generation and invocation, while the [Connection README](../../packages/client/connection/README.md) defines the physical carrier and trust policy.
-The internal `$events` logical stream is the Connection generation source. A generation becomes connected only after the event source emits `ready` and `host.describe` succeeds. Host listeners are therefore attached before any controller begins a baseline read. `ctx.remote.$on()` delivers allowlisted ordinary events to the root Client Context and scoped waterfall events to the resolved Session Context; a waterfall listener returns a result, calls `next()`, or rejects.
+The internal `$events` logical stream is the Connection generation source. Its opening `ready` frame carries the Host home used for path display and establishes the generation after Host listeners are attached, before any controller begins a baseline read. `ctx.remote.$on()` delivers allowlisted ordinary events to the root Client Context and scoped waterfall events to the resolved Session Context; a waterfall listener returns a result, calls `next()`, or rejects.
## Client models
diff --git a/docs/subsystems/web-client.zh.md b/docs/subsystems/web-client.zh.md
index c5e9904226..cdf91958e2 100644
--- a/docs/subsystems/web-client.zh.md
+++ b/docs/subsystems/web-client.zh.md
@@ -27,9 +27,9 @@ Web boot kernel 创建模块系统、预取 `immediately` entry、挂载 vendore
Host 业务 service 使用 Typert Remote decorator 标记可调用 method。Host generation 产出严格 descriptor、runtime codec、declaration merge 与 source map。Client 侧 `api-remotes` assembly 选择这些生成贡献,并把具体 method 挂到 `ctx.remote.` 与 Session scope 的 `agentCtx.remote.`。功能包依赖生成的 service face,而不依赖 Gateway 实现或 Host 包的运行时 entry。
-Connection 拥有 request correlation、`/api` carrier、trust check、Host description 与 connection generation。API Gateway 拥有 Remote dispatch、取消、logical stream 与选定 Host event 的转发。API Proxy 只处理没有被严格 Remote descriptor 认领的 `/api` endpoint;新的 controller 操作应进入生成的 Remote method 或显式 Remote stream。[API Gateway 参考](../api-gateway.zh.md)定义生成与调用,[Connection README](../../packages/client/connection/README.zh.md)定义物理 carrier 与信任策略。
+Connection 拥有 request correlation、`/api` carrier、trust check、精确 Fetch 路由与 connection generation。API Gateway 拥有 Remote dispatch、取消、logical stream 与选定 Host event 的转发。Controller 操作应进入生成的 Remote method 或显式 Remote stream;功能自有的下载则注册精确 Fetch 路由。[API Gateway 参考](../api-gateway.zh.md)定义 generation 与调用,[Connection README](../../packages/client/connection/README.zh.md)定义物理 carrier 与信任策略。
-内部 `$events` logical stream 是 Connection generation source。只有 event source 发出 `ready` 且 `host.describe` 成功后,一代 connection 才会进入 connected。Host listener 因而先于任何 controller baseline read 挂载。`ctx.remote.$on()` 把 allowlist 内的普通 event 交付给 root Client Context,并把 scoped waterfall event 交付给已解析的 Session Context;waterfall listener 可以返回结果、调用 `next()` 或拒绝。
+内部 `$events` logical stream 是 Connection generation source。它的 opening `ready` frame 携带用于路径显示的 Host home,并在 Host listener 已挂载、任何 controller 开始 baseline read 之前建立 generation。`ctx.remote.$on()` 把 allowlist 内的普通 event 交付给 root Client Context,并把 scoped waterfall event 交付给已解析的 Session Context;waterfall listener 可以返回结果、调用 `next()` 或拒绝。
## Client models
diff --git a/docs/subsystems/web-server.i18n.yaml b/docs/subsystems/web-server.i18n.yaml
index 87cca8b0b2..bec49cab10 100644
--- a/docs/subsystems/web-server.i18n.yaml
+++ b/docs/subsystems/web-server.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/web-server.md
-web-server.md: b806f5b40a2f5ddada40752367e3da23e86ea13d
-web-server.zh.md: e5f4a8794d46a2b55d4a69e2cdd13c7dc4c2a6dd
+web-server.md: d9b1ec007bc73274bb0c8b5d58745da1c76e6cb6
+web-server.zh.md: 66375534a89e2c4674e748d4178cb7a31761e57e
diff --git a/docs/subsystems/web-server.md b/docs/subsystems/web-server.md
index b806f5b40a..d9b1ec007b 100644
--- a/docs/subsystems/web-server.md
+++ b/docs/subsystems/web-server.md
@@ -2,7 +2,7 @@
English | [中文](web-server.zh.md)
-[dsh-host-webserver](../../packages/host/webserver) is the browser HTTP carrier for the GUI host: a single `node:http` plugin providing `ctx.webServer`, a named-route registry, optional gzip response compression, index.html transform callbacks, and one fallback handler that a plugin may claim. It is not part of the agent loop and not a capability seam; it knows no harness concepts, and another plugin registers every feature route, including the `/api` bridge, plugin bundles, and the HMR event stream ([layering note](../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md)). It serves browsers only: Electron loads the built files over `file://` and sends fetch requests through an IPC bridge instead of this server.
+[dsh-host-webserver](../../packages/host/webserver) is the browser HTTP carrier for the GUI host: a single `node:http` plugin providing `ctx.webServer`, a named-route registry, optional gzip response compression, index.html transform callbacks, and one fallback handler that a plugin may claim. It is not part of the agent loop and not a capability seam; it knows no harness concepts, and another plugin registers every feature route, including the `/api` bridge, plugin bundles, and the HMR event stream ([layering note](../../.agents/notes/implemented/architecture/2026-07-24-web-config-tree-boot-and-transport-layering.md)). It serves browsers only: Electron loads the built files over `file://` and sends fetch requests through an IPC bridge instead of this server.
Source: [`packages/host/webserver/src/index.ts`](../../packages/host/webserver/src/index.ts)
diff --git a/docs/subsystems/web-server.zh.md b/docs/subsystems/web-server.zh.md
index e5f4a8794d..66375534a8 100644
--- a/docs/subsystems/web-server.zh.md
+++ b/docs/subsystems/web-server.zh.md
@@ -2,7 +2,7 @@
[English](web-server.md) | 中文
-[dsh-host-webserver](../../packages/host/webserver) 是 GUI 宿主的浏览器 HTTP 载体:它是一个提供 `ctx.webServer` 的 `node:http` 插件,包含具名路由注册表、可选的 gzip 响应压缩、index.html 转换回调,以及一个可由插件认领的回退处理器。它不属于 agent loop(智能体循环),也不是能力 seam;它不了解任何 harness 概念。其他插件负责注册所有功能路由,包括 `/api` 桥接、插件 bundle 和 HMR(热模块替换)事件流([分层说明](../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.zh.md))。该服务器只服务浏览器:Electron 通过 `file://` 加载已构建文件,并经 IPC 桥接发送 fetch 请求,不使用本服务器。
+[dsh-host-webserver](../../packages/host/webserver) 是 GUI Host 的浏览器 HTTP 载体:它是一个提供 `ctx.webServer` 的 `node:http` 插件,包含具名路由注册表、可选的 gzip 响应压缩、index.html 转换回调,以及一个可由插件认领的回退处理器。它不属于 agent loop(智能体循环),也不是能力 seam;它不了解任何 harness 概念。其他插件负责注册所有功能路由,包括 `/api` 桥接、插件 bundle 和 HMR(热模块替换)事件流([分层说明](../../.agents/notes/implemented/architecture/2026-07-24-web-config-tree-boot-and-transport-layering.zh.md))。该服务器只服务浏览器:Electron 通过 `file://` 加载已构建文件,并经 IPC 桥接发送 fetch 请求,不使用本服务器。
源码:[`packages/host/webserver/src/index.ts`](../../packages/host/webserver/src/index.ts)
diff --git a/docs/tool-catalog.i18n.yaml b/docs/tool-catalog.i18n.yaml
index 5b23decb3c..392f448802 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: 7b166243fc3f5ef2c1bacdddaf5ee44c5b155622
-tool-catalog.zh.md: b44a0de4968dbcd760db546037f35e844608c819
+tool-catalog.md: 91ff093e79cc05a2c08b5aa1130378440cd963f3
+tool-catalog.zh.md: 35daf5a7c6b1c27975721c0b9d8ddfe71eaeb803
diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md
index 7b166243fc..91ff093e79 100644
--- a/docs/tool-catalog.md
+++ b/docs/tool-catalog.md
@@ -16,7 +16,7 @@ This table connects model-visible tool names to the plugin package and service s
| Tool package | Model-visible names | Requires | Writes / affects | Shipped aliases | Deployment note |
| --- | --- | --- | --- | --- | --- |
| `@deepseek-ai/dsh-tool-ask-user` | `ask_user_question` | `ctx.tools`, `ctx.userQuestions` | `tool/call`, `tool/result after a UI/provider answers the question` | - | ask_user_question pauses the tool call until the active UI provider returns a human answer. |
-| `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`, `ctx.codeRuntime (execution time)`, `ctx.systemPrompt` | `tool/call`, `one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call`, `tool/result` | - | Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
+| `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`, `ctx.codeRuntime (execution time)`, `ctx.systemPrompt` | `tool/call`, `one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call`, `tool/result` | - | Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: ptc` / `mode: both` (see the PTC mode Agent Note). Under `ptc` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
| `@deepseek-ai/dsh-plan-mode` | `exit_plan_mode` | `ctx.tools`, `ctx.systemPrompt`, `ctx.userQuestions (execution time, opportunistic)` | `tool/call`, `plan/mode inactive on an approved review`, `tool/result` | - | exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary. |
| `@deepseek-ai/dsh-tool-bash` | `bash` | `ctx.tools`, `ctx.shell`, `ctx.systemPrompt`, `ctx.shellEnv`, `ctx.jobs at call time for run_in_background` | `tool/call`, `tool/result` | - | The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.jobs` runtime and is collected/stopped through the `job_*` tools from `@deepseek-ai/dsh-tool-jobs`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled. |
| `@deepseek-ai/dsh-tool-pwsh` | `pwsh` | `ctx.tools`, `ctx.shell`, `ctx.systemPrompt`, `ctx.shellEnv`, `ctx.jobs at call time for run_in_background` | `tool/call`, `tool/result` | - | The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as `@deepseek-ai/dsh-pwsh-local` backs `ctx.shell`); it mirrors the bash tool call-for-call minus sandbox controls — `run_in_background` runs register with the generic `ctx.jobs` runtime and are collected/stopped through the `job_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-shell-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\...` paths and `$env:NAME` variables. |
@@ -33,7 +33,7 @@ This table connects model-visible tool names to the plugin package and service s
| `@deepseek-ai/dsh-tool-ralph` | `ralph` | `ctx.tools`, `ctx.workflowEngine`, `ctx.subagents`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents every fresh round)` | `tool/call`, `tool/result`, `workflow and child session events during execution` | - | A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap. |
| `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.tools`, `ctx.agents`, `ctx.skills` | `tool/call`, `tool/result`, `user/message replacement catalogs via agent.inject()` | - | - |
| `@deepseek-ai/dsh-tool-session-query` | `session_event_read`, `session_event_search`, `session_event_trace`, `session_search`, `session_trace` | `ctx.tools`, `ctx.systemPrompt`, `ctx.sessionQuery`, `a calling Agent for workspace authority` | `tool/call`, `tool/result` | - | The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. |
-| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered delegation name is the load-time `toolName` config (default `subagent`); the schema above shows static model selection enabled for reference. Model selection defaults off. Web presets sample the default-off Models preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Explicit compositions may instead use static `enableModelSelection`. Each instance independently controls model selection, discovery ownership, and background behavior through `enableModelSelection`, `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`. |
+| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered delegation name is the load-time `toolName` config (default `subagent`); the default schema above has model selection off, while the discovery schema is shown as the fixed companion available in an enabled Session. Web presets sample the Plugins preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Each instance independently controls whether it reads model-selection settings and its background behavior through `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`. |
| `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`, `list_agents`, `send_message` | `ctx.tools`, `ctx.subagents`, `ctx.agents and ctx.sessionProjections (list_agents only)` | `tool/call`, `tool/result`, `child session events through ctx.subagents` | - | The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` and `interrupt_agent` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows use the sessionProjections and live Agent registries). |
| `@deepseek-ai/dsh-tool-subagent-report` | `report` | `ctx.subagents`, `ctx.systemPrompt`, `a live continuable in-process child Agent` | `tool/call`, `tool/result`, `a user-role message in the direct parent session` | - | Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global `toolFilter`. The same contribution installs the child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing `send_message` tool is installed independently. |
| `@deepseek-ai/dsh-tool-jobs` | `job_kill`, `job_list`, `job_output` | `ctx.tools`, `ctx.jobs`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `user/message via agent.inject() for background completion notices` | - | The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' `ctx.jobs.start()`. |
@@ -144,9 +144,9 @@ Execute a TypeScript program against the available tools. Takes two required arg
}
```
-Source: [`packages/core/tools/src/code-mode.ts`](../packages/core/tools/src/code-mode.ts)
+Source: [`packages/core/tools/src/ptc.ts`](../packages/core/tools/src/ptc.ts)
-Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
+Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: ptc` / `mode: both` (see the PTC mode Agent Note). Under `ptc` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
@@ -1561,7 +1561,7 @@ Source: [`packages/subagent/tool-subagent/src/list-models.ts`](../packages/subag
### `subagent`
-Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This call waits for the result by default. Set `run_in_background: true` to return a job id; collect with `job_output` and stop with `job_kill`. Child LLM selection is optional. Omit `provider`, `model`, and `reasoning_effort` to use configured child defaults and inherit compatible missing values from the parent Agent. Supply `provider` and `model` together after using `list_subagent_models` to inspect advertised routes and efforts. Changing the effective route without naming an effort uses the selected model's default effort.
+Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This call waits for the result by default. Set `run_in_background: true` to return a job id; collect with `job_output` and stop with `job_kill`.
```json
{
@@ -1575,18 +1575,6 @@ Delegate a self-contained task to a subagent (a separate agent that works in its
"type": "string",
"description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
},
- "provider": {
- "type": "string",
- "description": "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or inherit the parent route."
- },
- "model": {
- "type": "string",
- "description": "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or inherit the parent route."
- },
- "reasoning_effort": {
- "type": "string",
- "description": "Adapter-owned reasoning effort for the effective child route. Omit to inherit a compatible configured/parent effort or use a newly selected model's default."
- },
"run_in_background": {
"type": "boolean",
"description": "Whether to run as a background job and return its id. Defaults to false; collect with job_output or stop with job_kill."
@@ -1601,7 +1589,7 @@ Delegate a self-contained task to a subagent (a separate agent that works in its
Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts)
-The registered delegation name is the load-time `toolName` config (default `subagent`); the schema above shows static model selection enabled for reference. Model selection defaults off. Web presets sample the default-off Models preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Explicit compositions may instead use static `enableModelSelection`. Each instance independently controls model selection, discovery ownership, and background behavior through `enableModelSelection`, `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`.
+The registered delegation name is the load-time `toolName` config (default `subagent`); the default schema above has model selection off, while the discovery schema is shown as the fixed companion available in an enabled Session. Web presets sample the Plugins preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Each instance independently controls whether it reads model-selection settings and its background behavior through `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`.
diff --git a/docs/tool-catalog.zh.md b/docs/tool-catalog.zh.md
index b44a0de496..35daf5a7c6 100644
--- a/docs/tool-catalog.zh.md
+++ b/docs/tool-catalog.zh.md
@@ -20,7 +20,7 @@
| 工具包 | 模型可见名称 | 依赖 | 写入/影响 | 随产品发布的别名 | 部署说明 |
| --- | --- | --- | --- | --- | --- |
| `@deepseek-ai/dsh-tool-ask-user` | `ask_user_question` | `ctx.tools`、`ctx.userQuestions` | `tool/call`、`tool/result after a UI/provider answers the question` | - | ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类答案。 |
-| `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`、`ctx.codeRuntime (execution time)`、`ctx.systemPrompt` | `tool/call`、`one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call`、`tool/result` | - | 在 `mode: code`/`mode: both` 下,它由工具注册表所有,作为可过滤能力层之外的保留传输机制(参见 Code Mode Agent Note)。在 `code` 下,它是注册表对协议格式(wire format)的唯一贡献;其他可见能力在使用已加载运行时语言生成的 SDK 章节中声明。程序通过 binding 调用这些能力,调用按照原生并发约定调度:启动顺序和策略遵循提交顺序,并发安全的函数体最多重叠执行 `maxParallelSubCalls` 个。调用会重新进入完整且受守卫保护的工具流水线,并将每个嵌套执行关联到此外层结果。 |
+| `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`、`ctx.codeRuntime (execution time)`、`ctx.systemPrompt` | `tool/call`、`one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call`、`tool/result` | - | 在 `mode: ptc`/`mode: both` 下,它由工具注册表所有,作为可过滤能力层之外的保留传输机制(参见 PTC mode Agent Note)。在 `ptc` 下,它是注册表对协议格式(wire format)的唯一贡献;其他可见能力在使用已加载运行时语言生成的 SDK 章节中声明。程序通过 binding 调用这些能力,调用按照原生并发约定调度:启动顺序和策略遵循提交顺序,并发安全的函数体最多重叠执行 `maxParallelSubCalls` 个。调用会重新进入完整且受守卫保护的工具流水线,并将每个嵌套执行关联到此外层结果。 |
| `@deepseek-ai/dsh-plan-mode` | `exit_plan_mode` | `ctx.tools`、`ctx.systemPrompt`、`ctx.userQuestions (execution time, opportunistic)` | `tool/call`、`plan/mode inactive on an approved review`、`tool/result` | - | 规划未激活时,exit_plan_mode 仍保留在面向模型的 schema 中,这样状态转换不会在规划策略变更之外额外造成工具目录变动。其执行路径会拒绝规划模式之外的调用;在规划模式下,它通过用户交互 seam 提交计划(批准/根据反馈继续规划),批准后会在步骤边界记录规划模式已停用。 |
| `@deepseek-ai/dsh-tool-bash` | `bash` | `ctx.tools`、`ctx.shell`、`ctx.systemPrompt`、`ctx.shellEnv`、`ctx.jobs at call time for run_in_background` | `tool/call`、`tool/result` | - | bash 工具是 bash 执行器 seam 面向模型的消费方。使用 `run_in_background` 的运行会注册到通用 `ctx.jobs` 运行时,并通过 `job_*` 工具(来自 `@deepseek-ai/dsh-tool-jobs`)收集/停止;禁用 `enableRunInBackground` 配置(默认为 true)后,该参数会被完全移除。 |
| `@deepseek-ai/dsh-tool-pwsh` | `pwsh` | `ctx.tools`、`ctx.shell`、`ctx.systemPrompt`、`ctx.shellEnv`、`ctx.jobs at call time for run_in_background` | `tool/call`、`tool/result` | - | pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费方(由 `@deepseek-ai/dsh-pwsh-local` 等 PowerShell 执行器为 `ctx.shell` 提供后端);除沙箱接口外,它逐项对应 bash 工具调用。使用 `run_in_background` 的运行会注册到通用 `ctx.jobs` 运行时,并通过 `job_*` 工具收集/停止;托管的 `DSH_*` 环境来自 `@deepseek-ai/dsh-shell-env`。每次调用都在新进程中运行,不使用持久 PTY 会话。路径采用原生 `C:\...` 形式,变量采用 `$env:NAME`。 |
@@ -37,7 +37,7 @@
| `@deepseek-ai/dsh-tool-ralph` | `ralph` | `ctx.tools`、`ctx.workflowEngine`、`ctx.subagents`、`ctx.systemPrompt`、`a calling Agent (exec.agent parents every fresh round)` | `tool/call`、`tool/result`、`workflow and child session events during execution` | - | 固定的前台工作流会在每个 Round 启动一个全新的结构化子级;模型只能选择不可变目标和可选的 Round 上限。 |
| `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.tools`、`ctx.agents`、`ctx.skills` | `tool/call`、`tool/result`、`user/message replacement catalogs via agent.inject()` | - | - |
| `@deepseek-ai/dsh-tool-session-query` | `session_event_read`、`session_event_search`、`session_event_trace`、`session_search`、`session_trace` | `ctx.tools`、`ctx.systemPrompt`、`ctx.sessionQuery`、`a calling Agent for workspace authority` | `tool/call`、`tool/result` | - | 这 5 个只读工具会隐藏提供方游标,并根据不可变的调用 agent 会话为每个结果授权。该包需要选择启用;需要强制截止时间或限制行内输出的组合还会挂载通用超时或 spill 策略。 |
-| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`、`subagent` | `ctx.tools`、`ctx.subagents`、`ctx.systemPrompt`、`用于模型发现和所选路由校验的 ctx.llm` | `tool/call`、`tool/result`、`child session events through the chosen provider` | `subagent`、`subagent_fork` | 注册的委派工具名称取决于加载时 `toolName` 配置(默认为 `subagent`);上述 schema 以静态启用模型选择作为参考。模型选择默认为关闭。Web preset 会在每个新顶层 Session 创建时读取 Models 页中默认关闭的偏好,并为其子 Session 保留该决定;`subagent_fork` 始终使用固定路由。显式组合也可以改用静态 `enableModelSelection`。每个实例通过 `enableModelSelection`、`modelSelectionSettings`、`backgroundMode` 与 `enableRunInBackground` 独立控制模型选择、发现工具持有权和后台行为。 |
+| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`、`subagent` | `ctx.tools`、`ctx.subagents`、`ctx.systemPrompt`、`用于模型发现和所选路由校验的 ctx.llm` | `tool/call`、`tool/result`、`child session events through the chosen provider` | `subagent`、`subagent_fork` | 注册的委派工具名称取决于加载时 `toolName` 配置(默认为 `subagent`);上述默认 schema 关闭模型选择,而发现 schema 则展示为已启用 Session 中可用的固定配套工具。Web preset 会在每个新顶层 Session 创建时读取插件页偏好,并为其子 Session 保留该决定;`subagent_fork` 始终使用固定路由。每个实例通过 `modelSelectionSettings`、`backgroundMode` 与 `enableRunInBackground` 独立控制是否读取模型选择设置及其后台行为。 |
| `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`、`list_agents`、`send_message` | `ctx.tools`、`ctx.subagents`、`ctx.agents and ctx.sessionProjections (list_agents only)` | `tool/call`、`tool/result`、`child session events through ctx.subagents` | - | 这些是控制可继续后台 subagent 的全局命名工具:绑定提供方的 `tool-subagent` 实例注册不同的委派工具;本包注册一次 `send_message` 和 `interrupt_agent`,另由 `list_agents` 通过单独加载的 `/list-agents` 插件提供,其目录行使用 sessionProjections 和实时 Agent 注册表。 |
| `@deepseek-ai/dsh-tool-subagent-report` | `report` | `ctx.subagents`、`ctx.systemPrompt`、`a live continuable in-process child Agent` | `tool/call`、`tool/result`、`a user-role message in the direct parent session` | - | 按可继续的进程内子级注册,而非全局注册,因此该 schema 仅在这种子级内部可见,并且不受其全局 `toolFilter` 影响。同一份贡献还会安装子级作用域的 `tool:report` 系统提示词 section,本目录不渲染该 section。面向父级的 `send_message` 工具单独安装。 |
| `@deepseek-ai/dsh-tool-jobs` | `job_kill`、`job_list`、`job_output` | `ctx.tools`、`ctx.jobs`、`ctx.systemPrompt` | `tool/call`、`tool/result`、`user/message via agent.inject() for background completion notices` | - | 与任务种类无关的后台任务控制器:后台 bash 命令、PTY 发送和 subagent 都通过相同的 3 个工具读取、列出和终止。加载该插件会挂接控制器,从而启用生产方的 `ctx.jobs.start()`。 |
@@ -148,9 +148,9 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类
}
```
-来源:[`packages/core/tools/src/code-mode.ts`](../packages/core/tools/src/code-mode.ts)
+来源:[`packages/core/tools/src/ptc.ts`](../packages/core/tools/src/ptc.ts)
-在 `mode: code`/`mode: both` 下,它由工具注册表所有,作为可过滤能力层之外的保留传输机制(参见 Code Mode Agent Note)。在 `code` 下,它是注册表对协议格式的唯一贡献;其他可见能力在使用已加载运行时语言生成的 SDK 章节中声明。程序通过 binding 调用这些能力,调用按照原生并发约定调度:启动顺序和策略遵循提交顺序,并发安全的函数体最多重叠执行 `maxParallelSubCalls` 个。调用会重新进入完整且受守卫保护的工具流水线,并将每个嵌套执行关联到此外层结果。
+在 `mode: ptc`/`mode: both` 下,它由工具注册表所有,作为可过滤能力层之外的保留传输机制(参见 PTC mode Agent Note)。在 `ptc` 下,它是注册表对协议格式的唯一贡献;其他可见能力在使用已加载运行时语言生成的 SDK 章节中声明。程序通过 binding 调用这些能力,调用按照原生并发约定调度:启动顺序和策略遵循提交顺序,并发安全的函数体最多重叠执行 `maxParallelSubCalls` 个。调用会重新进入完整且受守卫保护的工具流水线,并将每个嵌套执行关联到此外层结果。
@@ -1567,7 +1567,7 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
### `subagent`
-将一项自包含任务委派给 subagent(在自身上下文中工作的独立 agent),用它卸载聚焦且独立的工作,例如研究、限定范围的实现或分析,以免消耗当前对话的上下文。subagent 会返回结果,但不会返回中间步骤。请提供完整、独立的提示词,因为它看不到当前对话。此调用默认等待结果。设置 `run_in_background: true` 可返回 job id;使用 `job_output` 收集结果,使用 `job_kill` 停止任务。子级 LLM 选择是可选的。省略 `provider`、`model` 与 `reasoning_effort` 会使用配置的子级默认值,并从父 Agent 继承兼容的缺失值。先用 `list_subagent_models` 检查公布的路由和强度,再一起提供 `provider` 与 `model`。改变生效路由但不指定强度时,会使用所选模型的默认强度。
+将一项自包含任务委派给 subagent(在自身上下文中工作的独立 agent),用它卸载聚焦且独立的工作,例如研究、限定范围的实现或分析,以免消耗当前对话的上下文。subagent 会返回结果,但不会返回中间步骤。请提供完整、独立的提示词,因为它看不到当前对话。此调用默认等待结果。设置 `run_in_background: true` 可返回 job id;使用 `job_output` 收集结果,使用 `job_kill` 停止任务。
```json
{
@@ -1581,18 +1581,6 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
"type": "string",
"description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
},
- "provider": {
- "type": "string",
- "description": "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or inherit the parent route."
- },
- "model": {
- "type": "string",
- "description": "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or inherit the parent route."
- },
- "reasoning_effort": {
- "type": "string",
- "description": "Adapter-owned reasoning effort for the effective child route. Omit to inherit a compatible configured/parent effort or use a newly selected model's default."
- },
"run_in_background": {
"type": "boolean",
"description": "Whether to run as a background job and return its id. Defaults to false; collect with job_output or stop with job_kill."
@@ -1607,7 +1595,7 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
来源:[`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts)
-注册的委派工具名称取决于加载时 `toolName` 配置(默认为 `subagent`);上述 schema 以静态启用模型选择作为参考。模型选择默认为关闭。Web preset 会在每个新顶层 Session 创建时读取 Models 页中默认关闭的偏好,并为其子 Session 保留该决定;`subagent_fork` 始终使用固定路由。显式组合也可以改用静态 `enableModelSelection`。每个实例通过 `enableModelSelection`、`modelSelectionSettings`、`backgroundMode` 与 `enableRunInBackground` 独立控制模型选择、发现工具持有权和后台行为。
+注册的委派工具名称取决于加载时 `toolName` 配置(默认为 `subagent`);上述默认 schema 关闭模型选择,而发现 schema 则展示为已启用 Session 中可用的固定配套工具。Web preset 会在每个新顶层 Session 创建时读取插件页偏好,并为其子 Session 保留该决定;`subagent_fork` 始终使用固定路由。每个实例通过 `modelSelectionSettings`、`backgroundMode` 与 `enableRunInBackground` 独立控制是否读取模型选择设置及其后台行为。
diff --git a/docs/tool-execution-pipeline.i18n.yaml b/docs/tool-execution-pipeline.i18n.yaml
index bd8de3ba60..6ff5ef0a15 100644
--- a/docs/tool-execution-pipeline.i18n.yaml
+++ b/docs/tool-execution-pipeline.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-execution-pipeline.md
-tool-execution-pipeline.md: d04d2e4e5093fee92f8921f0eb0112c960a81bb8
-tool-execution-pipeline.zh.md: 15627023d3be6ac2b3aae70c2ef01ef9f1077d3e
+tool-execution-pipeline.md: a799c68a60f6782ef3bb79c52f89cbc78d762ab3
+tool-execution-pipeline.zh.md: 7ffdd34298f630c975b23f23daf875a3c4cdc84d
diff --git a/docs/tool-execution-pipeline.md b/docs/tool-execution-pipeline.md
index d04d2e4e50..a799c68a60 100644
--- a/docs/tool-execution-pipeline.md
+++ b/docs/tool-execution-pipeline.md
@@ -57,6 +57,6 @@ flowchart TD
allResults --> context
```
-Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition's snapshotted `finalizeContent` callback enforces its synchronous content-only invariant. `tools/result` then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, return denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.
+Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition's snapshotted `finalizeContent` callback enforces its synchronous content-only invariant. `tools/result` then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. PTC mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, return denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.
Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.
diff --git a/docs/tool-execution-pipeline.zh.md b/docs/tool-execution-pipeline.zh.md
index 15627023d3..7ffdd34298 100644
--- a/docs/tool-execution-pipeline.zh.md
+++ b/docs/tool-execution-pipeline.zh.md
@@ -59,6 +59,6 @@ flowchart TD
allResults --> context
```
-文件系统的先读后编辑检查位于 `tool-fs` 之下,通过 `fs/*` 事件实现。通用的前置/后置 waterfall 承载钩子与审批策略;`ctx.approval` 在单调守卫之前处理询问,而不得重新排序的所有者策略仍作为已注册的守卫。超时等环绕分发关注点对 `tools/execute` 进行包装。注册表会对候选结果进行无损快照;如果快照失败,则会先将失败规范化,之后再由可见定义中已随快照固定的 `finalizeContent` 回调强制执行其同步且仅限内容的不变式。随后,`tools/result` 会观察不可变、可由 JSON 无损表示的结果。这样一来,钩子便可跨越不同工具系列,而无需让工具与某个策略服务耦合。Code Mode 会将保留的 `run_code` 传输及其序列化子调用都送入流水线;子调用携带父级 token、记录 `tool/code-dispatch`、将拒绝呈现为具有约束力的驳回,并省略 `additionalContexts`,以保持调用与结果相邻。
+文件系统的先读后编辑检查位于 `tool-fs` 之下,通过 `fs/*` 事件实现。通用的前置/后置 waterfall 承载钩子与审批策略;`ctx.approval` 在单调守卫之前处理询问,而不得重新排序的所有者策略仍作为已注册的守卫。超时等环绕分发关注点对 `tools/execute` 进行包装。注册表会对候选结果进行无损快照;如果快照失败,则会先将失败规范化,之后再由可见定义中已随快照固定的 `finalizeContent` 回调强制执行其同步且仅限内容的不变式。随后,`tools/result` 会观察不可变、可由 JSON 无损表示的结果。这样一来,钩子便可跨越不同工具系列,而无需让工具与某个策略服务耦合。PTC mode 会将保留的 `run_code` 传输及其序列化子调用都送入流水线;子调用携带父级 token、记录 `tool/code-dispatch`、将拒绝呈现为具有约束力的驳回,并省略 `additionalContexts`,以保持调用与结果相邻。
维护模式:英文源文件包含人工维护的 Mermaid 流程图,并由生成器写出;本中文文件作为经评审对侧通过双语配对维护。确切的工具 schema 与事件签名位于生成的目录中。
diff --git a/docs/user/develop/basic/tool.i18n.yaml b/docs/user/develop/basic/tool.i18n.yaml
index 99fdfe2139..0c7c5bbc82 100644
--- a/docs/user/develop/basic/tool.i18n.yaml
+++ b/docs/user/develop/basic/tool.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/user/develop/basic/tool.md
-tool.md: 24a82d277e626ba78760a0afb1c41e2a157eb8ee
-tool.zh.md: a07bef588f5a18093cf2eb1971b855bf40d1d0b6
+tool.md: aeed5cf0e742cdde33bdcb86bfac4de471ae2597
+tool.zh.md: 25538e42b7777fe3b05b361379a8bce70d6ec5f5
diff --git a/docs/user/develop/basic/tool.md b/docs/user/develop/basic/tool.md
index 24a82d277e..aeed5cf0e7 100644
--- a/docs/user/develop/basic/tool.md
+++ b/docs/user/develop/basic/tool.md
@@ -48,5 +48,5 @@ Open `http://127.0.0.1:3080` and ask: `Use the greet tool to greet Ada.` The mod
## Next steps
- [Plugin configuration](./config.md) — make the greeting configurable.
-- [Tool authoring reference](../../../cookbook/adding-a-tool.md) — look up nested schemas, canonical values, background work, policy hooks, Code Mode, and UI cards.
+- [Tool authoring reference](../../../cookbook/adding-a-tool.md) — look up nested schemas, canonical values, background work, policy hooks, PTC mode, and UI cards.
- [Capability layering](../practice/index.md) — split a replaceable capability into Service Definition, Service Provider, and Consumer packages.
diff --git a/docs/user/develop/basic/tool.zh.md b/docs/user/develop/basic/tool.zh.md
index a07bef588f..25538e42b7 100644
--- a/docs/user/develop/basic/tool.zh.md
+++ b/docs/user/develop/basic/tool.zh.md
@@ -48,5 +48,5 @@ pnpm dsh web --patch ./scratch-plugin/cordis.yml
## 下一步
- [插件配置](./config.zh.md) — 让问候语可配置。
-- [工具编写参考](../../../cookbook/adding-a-tool.zh.md) — 查阅嵌套 schema、规范值、后台工作、策略钩子、Code Mode 和 UI 卡片。
+- [工具编写参考](../../../cookbook/adding-a-tool.zh.md) — 查阅嵌套 schema、规范值、后台工作、策略钩子、PTC mode 和 UI 卡片。
- [能力分层](../practice/index.zh.md) — 将可替换能力拆分为 Service Definition、Service Provider 和 Consumer 三类包。
diff --git a/docs/user/guide/schedule.i18n.yaml b/docs/user/guide/schedule.i18n.yaml
index 1726916a52..9ca6e303d4 100644
--- a/docs/user/guide/schedule.i18n.yaml
+++ b/docs/user/guide/schedule.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/user/guide/schedule.md
-schedule.md: 58cfda2e79f05129b367fad98c595a2c67a6e32e
-schedule.zh.md: 75f85b1847c8e02cbd06d21f953ea6814a71ef40
+schedule.md: fdb4899925f34d6c58fa34cc6ee1e589b461c001
+schedule.zh.md: d5d134ed7ec53c61e7efdf5267f915fc26a427ff
diff --git a/docs/user/guide/schedule.md b/docs/user/guide/schedule.md
index 58cfda2e79..fdb4899925 100644
--- a/docs/user/guide/schedule.md
+++ b/docs/user/guide/schedule.md
@@ -10,6 +10,8 @@ dsh web --patch apps/cli/config/examples/schedule/cordis.yml
The current overlay supports reminders created with a positive whole-number `after_seconds`, an absolute `at` target, or a fixed-rate `every_seconds` interval of at least 300 seconds. The model manages them through `schedule_create`, `schedule_list`, and `schedule_delete`; every result identifies delivery as `session-local`.
+With this overlay enabled, a successfully opened Session with active reminders shows a read-only catalog in the conversation header. It lists the complete prompt, scheduled or overdue status, one-time or exact repeating cadence, browser-local target time, and relative time. The sidebar also places a non-interactive alarm after the title of grouped, flat, and search rows when their currently available projection value is non-empty. These surfaces never create, edit, delete, or acknowledge reminders, and a cold Session's cached alarm can be briefly missing or stale.
+
The browser attaches its IANA zone to each prompt. Time-context tells the model to interpret otherwise-unqualified dates and times in that request's browser zone. This assumption belongs to natural-language interpretation only: `schedule_create.at` must be either a strict RFC 3339 date-time with `Z` or a numeric offset, or `{ date, time, time_zone }` with an explicit `UTC` or IANA Area/Location zone. Schedule does not retain or infer a Session default zone. Daylight-saving gaps are rejected, overlaps choose the first instant, and successful records keep only the resulting UTC target.
The original Session log owns each reminder. A live root Agent waits until it is fully idle, then queues a normal follow-up turn in that conversation. It never steers current work and adds no separate receipt or reminder card. Closing the process or leaving the Session cold stops its in-memory timer without deleting the record; reopening that same Session restores the wait and delivers an overdue reminder. Reading cold history never activates it, and a fork does not inherit its parent's reminders.
diff --git a/docs/user/guide/schedule.zh.md b/docs/user/guide/schedule.zh.md
index 75f85b1847..d5d134ed7e 100644
--- a/docs/user/guide/schedule.zh.md
+++ b/docs/user/guide/schedule.zh.md
@@ -10,6 +10,8 @@ dsh web --patch apps/cli/config/examples/schedule/cordis.yml
当前 overlay 支持使用正整数 `after_seconds`、绝对时间 `at` 目标,或至少 300 秒的固定速率 `every_seconds` 间隔创建提醒。模型通过 `schedule_create`、`schedule_list` 和 `schedule_delete` 管理它们;每个结果都会把交付标为 `session-local`。
+启用此 overlay 后,成功打开且存在活动提醒的 Session 会在对话 header 中显示只读目录。目录列出完整 prompt、等待中或已逾期状态、单次或精确重复周期、浏览器本地目标时间与相对时间。侧边栏还会在 grouped、flat 与 search 行当前可用的 projection 值非空时,于标题后显示不可交互的闹钟。这些界面不会创建、编辑、删除或确认提醒;cold Session 的缓存闹钟允许短暂漏显或残留。
+
浏览器会为每条提示词附加其 IANA 时区。Time-context 会告诉模型,把未明确限定时区的日期和时间解释为该请求的浏览器时区。此假设仅用于自然语言解释:`schedule_create.at` 必须是带 `Z` 或数值偏移量且严格符合 RFC 3339 的日期时间,或是带显式 `UTC` 或 IANA Area/Location 时区的 `{ date, time, time_zone }`。Schedule 不保留或推断 Session 默认时区。夏令时缺口会被拒绝,重叠时段选择第一个时刻;成功创建的记录只保留所得的 UTC 目标。
每条提醒由原 Session 日志拥有。live 根 Agent 会等待到完全 idle,再在该对话中排入一个普通 follow-up 轮次。它绝不会中途引导当前工作,也不会添加独立回执或提醒卡片。关闭进程或让 Session 保持 cold 会停止内存 timer,但不会删除记录;重新打开同一个 Session 会恢复等待并交付逾期提醒。查看 cold 历史不会激活提醒,fork 也不会继承父 Session 的提醒。
diff --git a/knip.json b/knip.json
index b08fe22a25..a1c247f0d5 100644
--- a/knip.json
+++ b/knip.json
@@ -45,6 +45,15 @@
"@deepseek-ai/dsh-client-ui-directory-picker-native"
]
},
+ "packages/experimental/inspector": {
+ "entry": [
+ "tests/**/*.e2e.ts"
+ ],
+ "project": [
+ "src/**/*.ts",
+ "tests/**/*.ts"
+ ]
+ },
"packages/extensions/cordis-host-runner": {
"entry": [
"tests/**/*.spec.ts"
@@ -406,6 +415,11 @@
"tests/**/*.ts"
]
},
+ "packages/llm/llm": {
+ "ignoreDependencies": [
+ "zod"
+ ]
+ },
"packages/llm/llm-deepseek": {
"entry": [
"tests/**/*.spec.ts",
@@ -446,11 +460,6 @@
"tests/**/*.ts"
]
},
- "packages/context/file-reference": {
- "ignoreDependencies": [
- "zod"
- ]
- },
"packages/context/session-reference": {
"ignoreDependencies": [
"zod"
@@ -696,8 +705,7 @@
"@deepseek-ai/dsh-llm-deepseek",
"@deepseek-ai/dsh-session-checkpoint-policy",
"@deepseek-ai/dsh-session-persistence-jsonl",
- "@deepseek-ai/dsh-skill-filesystem",
- "@deepseek-ai/dsh-tool-subagent"
+ "@deepseek-ai/dsh-skill-filesystem"
]
},
"packages/shell/tool-pwsh": {
diff --git a/package.json b/package.json
index bec66ae4c9..f5718565aa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@deepseek-ai/dsh-root",
- "version": "0.1.1-rc.2",
+ "version": "0.1.2-alpha.1",
"license": "MIT",
"private": true,
"type": "module",
@@ -112,6 +112,8 @@
"rescope-vendor": "tsx scripts/rescope-vendor.ts",
"rescope-vendor:check": "tsx scripts/rescope-vendor.ts --check",
"verify-client-domain-graph": "tsx scripts/verify-client-domain-graph.ts",
+ "gen-tsconfig-paths": "tsx scripts/gen-tsconfig-paths.ts",
+ "verify-tsconfig-paths": "tsx scripts/gen-tsconfig-paths.ts --check",
"gen-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts",
"verify-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts --check",
"gen-cordis-api": "tsx scripts/gen-cordis-api.ts",
@@ -146,7 +148,8 @@
"release:verify-packed-install": "tsx scripts/release/verify-packed-install.ts",
"release:publish": "tsx scripts/release/publish.ts",
"dsh": "node --import tsx/esm apps/cli/src/bin.ts",
- "demo:code-mode": "node scripts/demo-code-mode.mjs",
+ "demo:ptc": "node scripts/demo-ptc.mjs",
+ "demo:inspector": "node --import tsx/esm apps/cli/src/bin.ts web --patch ./packages/experimental/inspector/cordis.source.patch.yml",
"mock:llm": "node --import tsx packages/test-support/llm-mock-server/src/bin.ts",
"dev:web": "tsx scripts/dev-web.ts --poll",
"postinstall": "node scripts/install-lefthook.mjs"
diff --git a/packages/AGENTS.md b/packages/AGENTS.md
index e753147a72..af47b16740 100644
--- a/packages/AGENTS.md
+++ b/packages/AGENTS.md
@@ -19,7 +19,7 @@ These package-specific rules supplement the repo-wide [conventions](../AGENTS.md
[Naming rules](../docs/cookbook/adding-a-package.md#name-the-role-that-exists):
-- **Package tsconfig:** extends `tsconfig.base.json` (Client: `tsconfig.base.client.json`), uses `rootDir: src`, `outDir: lib/types`, and references each workspace dependency plus `runtime-diagnostics/invariants`; registers in exactly one aggregate. Only `api/remotes` splits for generated contracts; ordinary two-entry Client plugins do not ([layout](../docs/development.md#typescript-project-layout)).
+- **Package tsconfig:** extends `tsconfig.base.json` (Client: `tsconfig.base.client.json`), sets `rootDir: src` and `outDir: lib/types`, references workspace dependencies plus `runtime-diagnostics/invariants`, and registers in one aggregate. Packages with distinct Host and Client compiler faces use `tsconfig.host.json` and `tsconfig.client.json` leaves plus a solution-only root; ordinary two-entry Client plugins do not split ([layout](../docs/development.md#typescript-project-layout)).
- `src/types.ts` contains only types — no runtime code.
- Tests live at package level under `tests/`, not `src/__tests__/`.
- Update package README and JSDoc contracts in the same commit as behavior, and verify them against code with [dsh-prose-standard](../.agents/skills/dsh-prose-standard/SKILL.md). Group READMEs declare subsystem ownership through a canonical English page link or justified [exemption](../scripts/verify-subsystem-pages.ts).
diff --git a/packages/README.i18n.yaml b/packages/README.i18n.yaml
index 7816391ff8..158a9ead5c 100644
--- a/packages/README.i18n.yaml
+++ b/packages/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/README.md
-README.md: c3dcbd3032e3eadad21b640f3a614ef5a1a6c6e7
-README.zh.md: 80518ef0de7c2022db45aefa411f507870cf09aa
+README.md: e1a729a6c80d8f8125e0d4c4b038dc631edd7a26
+README.zh.md: 754ad0fc44677afb243c3a32a0281f58ec3b3af2
diff --git a/packages/README.md b/packages/README.md
index c3dcbd3032..e1a729a6c8 100644
--- a/packages/README.md
+++ b/packages/README.md
@@ -40,7 +40,7 @@ Every package lives in exactly one group; new packages join existing groups, and
| [`subprocess/`](subprocess/README.md) | Subprocess capability family: Service Definition + local process-tree provider |
| [`shell/`](shell/README.md) | Bash capability family: executor seam, local impl, model-facing tools |
| [`terminal/`](terminal/README.md) | Persistent PTY capability family: owner-scoped sessions, local implementation, model-facing tools |
-| [`code-runtime/`](code-runtime/README.md) | Code-execution capability family: Service Definition + worker-thread provider + Code Mode Consumer |
+| [`code-runtime/`](code-runtime/README.md) | Code-execution capability family: Service Definition + worker-thread provider + PTC mode Consumer |
| [`sandbox/`](sandbox/README.md) | Process-confinement seam; bwrap/Landlock/Seatbelt backends |
| [`fs/`](fs/README.md) | Filesystem capability family: seam, local impl, model-facing file tools, discovery tools |
| [`lsp/`](lsp/README.md) | LSP capability family: seam, generic stdio provider, and the `lsp` tool |
diff --git a/packages/README.zh.md b/packages/README.zh.md
index 80518ef0de..754ad0fc44 100644
--- a/packages/README.zh.md
+++ b/packages/README.zh.md
@@ -40,7 +40,7 @@ harness 由 `packages/` 下的 npm 包组装而成,按能力系列分组:会
| [`subprocess/`](subprocess/README.zh.md) | 子进程能力系列:Service Definition + 本地进程树提供方 |
| [`shell/`](shell/README.zh.md) | Bash 能力系列:执行器 seam、本地实现、面向模型的工具 |
| [`terminal/`](terminal/README.zh.md) | 持久 PTY 能力系列:限定所有者范围的会话、本地实现、面向模型的工具 |
-| [`code-runtime/`](code-runtime/README.zh.md) | 代码执行能力系列:Service Definition + worker 线程提供方 + Code Mode Consumer |
+| [`code-runtime/`](code-runtime/README.zh.md) | 代码执行能力系列:Service Definition + worker 线程提供方 + PTC mode Consumer |
| [`sandbox/`](sandbox/README.zh.md) | 进程限制 seam;bwrap/Landlock/Seatbelt 后端 |
| [`fs/`](fs/README.zh.md) | 文件系统能力系列:seam、本地实现、面向模型的文件工具、发现工具 |
| [`lsp/`](lsp/README.zh.md) | LSP 能力系列:seam、通用 stdio 提供方和 `lsp` 工具 |
diff --git a/packages/acp/acp/package.json b/packages/acp/acp/package.json
index 1bd6af44c1..038be6f7a9 100644
--- a/packages/acp/acp/package.json
+++ b/packages/acp/acp/package.json
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-acp",
"description": "Automation-only Agent Client Protocol server for driving DeepSeek Harness agents over JSON-RPC stdio",
- "version": "0.1.1-rc.2",
+ "version": "0.1.2-alpha.1",
"publishConfig": {
"access": "public"
},
diff --git a/packages/api/README.i18n.yaml b/packages/api/README.i18n.yaml
index b93fd190e7..c47c67f406 100644
--- a/packages/api/README.i18n.yaml
+++ b/packages/api/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/README.md
-README.md: aaea6ef47aabdc8baa63ef7a875de065bcae94b9
-README.zh.md: 8e87f97c413620ede4ee160384d00f18382cfdf7
+README.md: b4d8ddd84baa411a2675c95dda1701937e06fe6d
+README.zh.md: 5dff7a59219a539c75d7ab85d293cd5b389018ec
diff --git a/packages/api/README.md b/packages/api/README.md
index aaea6ef47a..b4d8ddd84b 100644
--- a/packages/api/README.md
+++ b/packages/api/README.md
@@ -32,19 +32,18 @@ The packages below provide the Remote layer; the package READMEs own the exhaust
| [`settings-controller/`](settings-controller/README.md) | Owns the configuration-surface reads and writes over the settings-domain seams. | `ctx.settingsController`, `ctx.credentialsController` / `ctx.remote.settings`, `ctx.remote.credentials` |
| [`workspace-controller/`](workspace-controller/README.md) | Owns Workspace mutations and the complete Client Workspace projection. | `ctx.workspaceController` / `ctx.remote.workspace` |
-Remote calls run Client → Host over the application's shared Connection. API Gateway owns Remote transport, while the controller packages own Session, configuration-surface, and Workspace behavior. Endpoints without a Remote definition fall through to the application's API Proxy.
+Remote calls run Client → Host over the application's shared Connection. API Gateway owns Remote transport, while the controller packages own Session, configuration-surface, and Workspace behavior. Feature packages register exact Connection Fetch routes for responses that do not fit Remote invocation, such as streamed downloads.
-----
## Related documentation
-Start with the API Gateway reference to see the Remote model end to end, then the Typert subsystem page for the shared definitions, and the carrier and fallback packages for how calls travel and how endpoints without Remote definitions are served.
+Start with the API Gateway reference to see the Remote model end to end, then the Typert subsystem page for the shared definitions and Connection for the physical carrier.
- [API Gateway reference](../../docs/api-gateway.md) — the current-state reference for the Typert API Gateway: programming model, generation pipeline, and runtime invocation.
- [Typert subsystem reference](../../docs/subsystems/typert.md) — the public contracts shared by protocol, Gateway, and consumer assemblies.
- [Connection](../client/connection/README.md) — the RPC carrier, `/api` trust fence, and response envelopes behind every Remote call.
-- [API Proxy](../host/apiproxy/README.md) — the fallback for endpoints without Remote descriptors.
## Dev Note
diff --git a/packages/api/README.zh.md b/packages/api/README.zh.md
index 8e87f97c41..5dff7a5921 100644
--- a/packages/api/README.zh.md
+++ b/packages/api/README.zh.md
@@ -32,19 +32,18 @@ kind: "package-group"
| [`settings-controller/`](settings-controller/README.zh.md) | 拥有 settings 域各 seam 之上的配置界面读写。 | `ctx.settingsController`、`ctx.credentialsController` / `ctx.remote.settings`、`ctx.remote.credentials` |
| [`workspace-controller/`](workspace-controller/README.zh.md) | 拥有 Workspace 变更与完整 Client Workspace 投影。 | `ctx.workspaceController` / `ctx.remote.workspace` |
-Remote 调用沿 Client → Host 方向运行在应用共享的 Connection 之上。API Gateway 拥有 Remote 传输,各 controller 包分别拥有 Session、配置界面与 Workspace 行为。没有 Remote 定义的 endpoint 会回退到应用的 API Proxy。
+Remote 调用沿 Client → Host 方向运行在应用共享的 Connection 之上。API Gateway 拥有 Remote 传输,各 controller 包分别拥有 Session、配置界面与 Workspace 行为。流式下载等不适合 Remote 调用的响应由功能包注册精确的 Connection Fetch 路由。
-----
## 相关文档
-先读 API Gateway 参考以端到端了解 Remote 模型,再读 Typert 子系统页了解共享定义,以及载体与回退包了解调用如何传输、没有 Remote 定义的 endpoint 如何被服务。
+先读 API Gateway 参考以端到端了解 Remote 模型,再读 Typert 子系统页了解共享定义,并通过 Connection 了解物理载体。
- [API Gateway 参考](../../docs/api-gateway.zh.md)——Typert API Gateway 的现状参考:编程模型、生成流水线与运行时调用。
- [Typert 子系统参考](../../docs/subsystems/typert.zh.md)——protocol、Gateway 与消费方装配共享的公共约定。
- [Connection](../client/connection/README.zh.md)——每次 Remote 调用背后的 RPC 载体、`/api` 信任围栏与响应封装。
-- [API Proxy](../host/apiproxy/README.zh.md)——没有 Remote 描述符的 endpoint 的回退路径。
## 开发备注
diff --git a/packages/api/gateway/README.i18n.yaml b/packages/api/gateway/README.i18n.yaml
index 9bc399b963..f1d957d143 100644
--- a/packages/api/gateway/README.i18n.yaml
+++ b/packages/api/gateway/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/gateway/README.md
-README.md: 2e0cb32e4db6c1bee8576a5addd5492fb7ef53ac
-README.zh.md: f67e13f6b1f789da02796397a121e59a55427cca
+README.md: d10eed46d5534a2459995bd687942d799f009c7b
+README.zh.md: 310b44cfe633758089771cda4040679c09373ec2
diff --git a/packages/api/gateway/README.md b/packages/api/gateway/README.md
index 2e0cb32e4d..d10eed46d5 100644
--- a/packages/api/gateway/README.md
+++ b/packages/api/gateway/README.md
@@ -28,13 +28,13 @@ Two-sided Typert RPC endpoint for Host and Client Cordis environments. The Host
Strict mode reads generated invocation descriptors from `ctx.typert.local`. Lookup parameters use the currently active resolver in `ctx.typert.lookups`: the business package registers the stable declaration and default policy, while Host composition can override resolution behavior with effect-scoped `configure()`; `@RemoteScope` resolves its receiver through a registered Host Context adapter. SRC mode is a development fallback for endpoints that have never had a strict definition; it parses simple parameter names and accepts only JSON-safe values for non-lookup parameters. Withdrawing an observed strict definition fails instead of weakening validation.
-The Host entry registers a trusted-host interceptor on Connection's shared `/api` FetchHandler. Connection passes this composite handler through its HTTP bridge; the handler dispatches claimed endpoints to Gateway and unclaimed endpoints to API Proxy. Direct `invoke()` calls preserve business errors; `TypertGatewayError` distinguishes failures owned by dispatch, binding, providers, lookup, Context, arguments, and codecs. A resolver may use `TypertLookupFailure` to carry an existing RPC error, preserving its original error code for policy rejections such as cold-resume failures or ownership fences.
+The Host entry registers a trusted-host interceptor on Connection's shared `/api` FetchHandler. Connection passes this composite handler through its HTTP bridge; the handler dispatches claimed endpoints to Gateway and returns 404 for unclaimed requests unless an exact Fetch route owns them. Direct `invoke()` calls preserve business errors; `TypertGatewayError` distinguishes failures owned by dispatch, binding, providers, lookup, Context, arguments, and codecs. A resolver may use `TypertLookupFailure` to carry an existing RPC error, preserving its original error code for policy rejections such as cold-resume failures or ownership fences.
A cancellation-aware Remote method declares `signal: AbortSignal` as its final Host parameter. The signal is descriptor metadata rather than a wire argument: Connection supplies it to the Gateway, and the Gateway injects it after decoded business parameters. SRC recognizes the reserved final name, while strict generation additionally requires the global `AbortSignal` type.
-A stream Remote uses `@Remote({ mode: 'stream' })` and returns an `Iterable` or `AsyncIterable`. `ctx.typertGateway.stream()` applies the same endpoint, argument, lookup, and cancellation checks as unary invocation, then validates each yielded item with the generated result codec. The Client opens the Gateway-owned `/api/remote.mux` WebSocket when its plugin activates, keeps it connected while idle, and retries physical connection failures with capped backoff. Independently cancellable logical streams share that socket; an in-process Connection carrier provides equivalent streams directly without opening it.
+A stream Remote uses `@Remote({ mode: 'stream' })` and returns an `Iterable` or `AsyncIterable`. `ctx.typertGateway.stream()` applies the same endpoint, argument, lookup, and cancellation checks as unary invocation, then validates each yielded item with the generated result codec. The Client opens the Gateway-owned `/api/remote.mux` WebSocket when its plugin activates, keeps it connected while idle, and retries physical connection failures with capped backoff. The Host sends Ping control frames at the configured `websocketHeartbeatIntervalMs` interval (30 seconds by default), and the browser answers Pong at the WebSocket protocol layer, so idle network intermediaries see traffic without any Remote stream frame. Independently cancellable logical streams share that socket; an in-process Connection carrier provides equivalent streams directly without opening it.
-Host composition can register one application event source through `registerRemoteEvents()`. Gateway reserves the internal `$events` logical endpoint for that source, accepts only empty `args`, and aborts streams opened by the registration when the source is withdrawn. API Remotes owns the event selection, argument validation, and per-Client queues. Its source factory attaches incremental listeners synchronously; Gateway then yields `{ type: 'ready' }` before iterating the source, so the Client starts baseline reads only after incremental delivery is ready.
+Host composition can register one application event source through `registerRemoteEvents()`. Gateway reserves the internal `$events` logical endpoint for that source, accepts only empty `args`, and aborts streams opened by the registration when the source is withdrawn. API Remotes owns the event selection, argument validation, per-Client queues, and the Host home sent in the opening `{ type: 'ready', clientId, host: { home } }` frame. Its source factory attaches incremental listeners synchronously, so the Client publishes the generation and starts baseline reads only after incremental delivery is ready.
## Client service: `ClientRemote` (ctx key: `remote`)
@@ -45,7 +45,7 @@ Each unary call validates positional inputs, constructs the descriptor's exact n
`ctx.remote.$stream()` returns a single-consumer `RemoteStream` spanning physical carrier generations. It permits one immediate retry while the Host remains available, otherwise waits for the next connected Host generation, and annotates each item with its physical generation. The domain consumer validates and accepts each generation's opening value; business and protocol failures remain terminal. `RemoteSnapshotStream` adds one opening snapshot followed by deltas. `RemoteJournalStream` adds follow-before-page opening, pagination, reconnect catch-up, and gap repair over domain-defined inclusive entry ranges; it removes complete duplicates and rejects gaps, inverted ranges, and partial overlaps. Disposing any stream cancels its requests and resolves after the active iterator is fully stopped.
-`ctx.remote.$on()` subscribes to one forwarded Host event. Its legal keys are exactly the Host assembly's forwarding selection, and the listener type is the owning package's own Cordis `Events` declaration, so no second signature can drift from it. Each subscription belongs to the calling fiber and disappears with it. The Client Remote service registers the `$events` pump as a Connection generation source when it activates, whether any `$on` listener exists. Browsers use Remote mux, while in-process compositions use `connection.rpc.open`; the `ready` item and `host.describe` jointly establish a Connection generation. Carrier failure, Remote stream failure, unexpected normal completion, a non-ready opening item, or a malformed event item ends that generation and lets Connection reopen it after backoff. Ordinary notifications run in registration order and isolate listener failures. Agent-scoped waterfalls let a listener return a result, call `next()`, or reject; Gateway returns that outcome through the existing HTTP unary carrier.
+`ctx.remote.$on()` subscribes to one forwarded Host event. Its legal keys are exactly the Host assembly's forwarding selection, and the listener type is the owning package's own Cordis `Events` declaration, so no second signature can drift from it. Each subscription belongs to the calling fiber and disappears with it. The Client Remote service registers the `$events` pump as a Connection generation source when it activates, whether any `$on` listener exists. Browsers use Remote mux, while in-process compositions use `connection.rpc.open`; the opening `ready` item establishes a Connection generation and supplies its Host facts. Carrier failure, Remote stream failure, unexpected normal completion, a non-ready opening item, or a malformed event item ends that generation and lets Connection reopen it after backoff. Ordinary notifications run in registration order and isolate listener failures. Agent-scoped waterfalls let a listener return a result, call `next()`, or reject; Gateway returns that outcome through the existing HTTP unary carrier.
Generated declaration merges provide the TypeScript API through the shared `TypertClientRemote` contract. The Client entry contains no Host Service or Host Cordis interface merge, and method lookup and invocation use ordinary objects and functions rather than a JavaScript Proxy.
@@ -68,6 +68,7 @@ No direct effect; invoked business Services own any model-visible result.
- `$stream()` supervises carrier replacement but does not infer replay semantics; each domain owns its resume cursor or replacement-baseline validation and normal-end classification. Connection generations reopen the internal `$events` stream; one-way notifications are not replayed, while pending scoped waterfalls retain their event id across replay.
- Lookup resolvers are configured per key; an individual Remote parameter or endpoint cannot currently select a live-only policy under the same `agent`/`session` key.
- Forwarded events reach `$on` without business-payload projection or redaction. Ordinary notifications are not replayed after reconnect; Agent-scoped waterfalls project only the top-level Agent identity needed to select the Client Context and carry their own pending lifetime.
+- WebSocket heartbeats keep idle intermediaries active but do not require a timely Pong or terminate an unresponsive peer. Half-open carriers remain subject to TCP or intermediary failure detection before the Client reconnects.
diff --git a/packages/api/gateway/README.zh.md b/packages/api/gateway/README.zh.md
index f67e13f6b1..310b44cfe6 100644
--- a/packages/api/gateway/README.zh.md
+++ b/packages/api/gateway/README.zh.md
@@ -28,13 +28,13 @@ kind: "package-reference"
严格模式从 `ctx.typert.local` 读取生成的调用描述符。查找参数使用 `ctx.typert.lookups` 中当前有效的 resolver:业务包注册稳定声明与默认策略,Host 组合可用 effect-scoped `configure()` 覆盖解析行为;`@RemoteScope` 则通过已注册的 Host Context adapter 解析其接收者。SRC 模式是开发阶段的回退路径,适用于从未具备严格定义的端点;它解析简单参数名,并且只允许非查找参数使用可安全表示为 JSON 的值。已观测到的严格定义一旦撤回,系统会直接报错,而不会降低校验强度。
-Connection 可用时,Host 入口会在 Connection 共享的 `/api` FetchHandler 上注册 trusted-host interceptor。Connection 把这个复合 handler 交给 HTTP bridge;handler 将已认领 endpoint 分发给 Gateway,未认领 endpoint 则交给 API Proxy。直接调用 `invoke()` 会保留业务错误;`TypertGatewayError` 可区分分发、绑定、提供方、查找、Context、参数和编解码器各自负责的故障。resolver 可以用 `TypertLookupFailure` 携带既有 RPC error,使冷恢复失败或 ownership fence 等策略拒绝保持原错误码。
+Connection 可用时,Host 入口会在 Connection 共享的 `/api` FetchHandler 上注册 trusted-host interceptor。Connection 把这个复合 handler 交给 HTTP bridge;handler 将已认领 endpoint 分发给 Gateway,未认领且没有精确 Fetch 路由负责的请求返回 404。直接调用 `invoke()` 会保留业务错误;`TypertGatewayError` 可区分分发、绑定、提供方、查找、Context、参数和编解码器各自负责的故障。resolver 可以用 `TypertLookupFailure` 携带既有 RPC error,使冷恢复失败或 ownership fence 等策略拒绝保持原错误码。
支持取消的 Remote 方法会把 `signal: AbortSignal` 声明为最后一个 Host 参数。signal 是 descriptor 元数据,而不是 wire 参数:Connection 将它提供给 Gateway,Gateway 则在已解码的业务参数之后注入它。SRC 识别这个保留的末位参数名,严格生成还要求它具有全局 `AbortSignal` 类型。
-流式 Remote 使用 `@Remote({ mode: 'stream' })` 并返回 `Iterable` 或 `AsyncIterable`。`ctx.typertGateway.stream()` 执行与一元调用相同的 endpoint、参数、lookup 和取消校验,再用生成的 result codec 校验每个产出项。Client 插件激活时打开 Gateway 自有的 `/api/remote.mux` WebSocket,使其在空闲时保持连接,并以有上限的退避重试物理连接失败。可独立取消的逻辑流共享这条连接;进程内 Connection 载体直接提供等价的流,不打开该 WebSocket。
+流式 Remote 使用 `@Remote({ mode: 'stream' })` 并返回 `Iterable` 或 `AsyncIterable`。`ctx.typertGateway.stream()` 执行与一元调用相同的 endpoint、参数、lookup 和取消校验,再用生成的 result codec 校验每个产出项。Client 插件激活时打开 Gateway 自有的 `/api/remote.mux` WebSocket,使其在空闲时保持连接,并以有上限的退避重试物理连接失败。Host 按配置的 `websocketHeartbeatIntervalMs` 间隔(默认 30 秒)发送 Ping 控制帧,浏览器在 WebSocket 协议层自动回复 Pong,使空闲网络中间层持续看到流量,而不新增 Remote stream frame。可独立取消的逻辑流共享这条连接;进程内 Connection 载体直接提供等价的流,不打开该 WebSocket。
-Host 组合可通过 `registerRemoteEvents()` 注册唯一的应用事件 source。Gateway 为它保留内部 `$events` logical endpoint,只接受空 `args`,并在 source 撤回时中止该注册打开的 stream。事件名单、参数校验和每 Client 队列由 API Remotes 拥有。source factory 在返回 iterable 前同步挂好增量 listener;Gateway 随后先产出 `{ type: 'ready' }`,再迭代 source,让 Client 只在增量投递就绪后开始 baseline 读取。
+Host 组合可通过 `registerRemoteEvents()` 注册唯一的应用事件 source。Gateway 为它保留内部 `$events` logical endpoint,只接受空 `args`,并在 source 撤回时中止该注册打开的 stream。事件名单、参数校验、每 Client 队列及 opening `{ type: 'ready', clientId, host: { home } }` frame 中的 Host home 由 API Remotes 拥有。source factory 在返回 iterable 前同步挂好增量 listener,因此 Client 只在增量投递就绪后发布 generation 并开始 baseline 读取。
## Client 服务:`ClientRemote`(ctx key:`remote`)
@@ -45,7 +45,7 @@ Host 组合可通过 `registerRemoteEvents()` 注册唯一的应用事件 source
`ctx.remote.$stream()` 返回跨越多个物理载体代次的单消费方 `RemoteStream`。Host 仍在线时,它允许一次立即重试;Host 离线时,它等待下一代连接,并为每个流项标注物理代次。领域消费方校验并接受各代次的 opening value;业务与协议错误仍然终止流。`RemoteSnapshotStream` 在此之上规定每代由一个 opening snapshot 和后续 delta 组成。`RemoteJournalStream` 基于领域提供的 entry 闭区间提供 follow-before-page、分页、重连追赶与缺口修复;它丢弃完整重复项,并拒绝缺口、倒置区间和部分重叠。dispose 任一种 stream 都会取消其请求,并在活动 iterator 完全停止后完成。
-`ctx.remote.$on()` 订阅一条被转发的 Host 事件。它的合法键恰好等于 Host 装配声明的转发选择,listener 类型就是事件所属包自己的 Cordis `Events` 声明,因此不存在会与之漂移的第二份签名。每个订阅归属发起调用的 fiber,并随该 fiber 一起消失。Client Remote 服务激活时就把 `$events` pump 注册为 Connection generation source,因此即使当前无 `$on` 订阅,它也会在 Connection 循环启动时打开。浏览器使用 Remote mux,进程内组合使用 `connection.rpc.open`;`ready` 项与 `host.describe` 共同建立一个 Connection generation。物理 carrier 失败、Remote stream error、意外正常结束、非 ready 首项或畸形事件项都会终止该 generation,由 Connection 退避后重开。普通通知按注册顺序运行并隔离 listener 失败;Agent-scoped waterfall 允许 listener 返回结果、调用 `next()` 或拒绝,Gateway 再通过现有 HTTP 一元载体回送该结果。
+`ctx.remote.$on()` 订阅一条被转发的 Host 事件。它的合法键恰好等于 Host 装配声明的转发选择,listener 类型就是事件所属包自己的 Cordis `Events` 声明,因此不存在会与之漂移的第二份签名。每个订阅归属发起调用的 fiber,并随该 fiber 一起消失。Client Remote 服务激活时就把 `$events` pump 注册为 Connection generation source,因此即使当前无 `$on` 订阅,它也会在 Connection 循环启动时打开。浏览器使用 Remote mux,进程内组合使用 `connection.rpc.open`;opening `ready` 项建立 Connection generation 并提供 Host 信息。物理 carrier 失败、Remote stream error、意外正常结束、非 ready 首项或畸形事件项都会终止该 generation,由 Connection 退避后重开。普通通知按注册顺序运行并隔离 listener 失败;Agent-scoped waterfall 允许 listener 返回结果、调用 `next()` 或拒绝,Gateway 再通过现有 HTTP 一元载体回送该结果。
生成的声明合并通过共享的 `TypertClientRemote` 约定提供 TypeScript API。Client 入口不包含 Host 服务或 Host Cordis 接口合并;方法查找和调用使用普通对象与函数,而不使用 JavaScript Proxy。
@@ -68,6 +68,7 @@ Host 组合可通过 `registerRemoteEvents()` 注册唯一的应用事件 source
- `$stream()` 监督载体替换,但不推断回放语义;各领域自行拥有恢复 cursor 或替换 baseline 的校验,以及正常结束的分类。Connection generation 会重开内部 `$events`;单向通知不会重放,仍处于 pending 的 scoped waterfall 则沿用同一个 event id 重放。
- lookup resolver 按 key 配置;当前无法让单个 Remote 参数或 endpoint 在同一 `agent`/`session` key 下选择 live-only 策略。
- 被转发的事件到达 `$on` 时不做业务载荷投影或脱敏。普通通知在重连后不重放;Agent-scoped waterfall 只投影选择 Client Context 所需的顶层 Agent 身份,并自行携带 pending 生命周期。
+- WebSocket 心跳用于保持空闲中间层活跃,但不会要求及时收到 Pong,也不会主动终止无响应对端。半开 carrier 仍需等待 TCP 或中间层检测失败后,Client 才会重连。
diff --git a/packages/api/gateway/package.json b/packages/api/gateway/package.json
index e74d19946f..d5601ab188 100644
--- a/packages/api/gateway/package.json
+++ b/packages/api/gateway/package.json
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-gateway",
"description": "Typert Remote Host dispatcher and Client API endpoint",
- "version": "0.1.1-rc.2",
+ "version": "0.1.2-alpha.1",
"publishConfig": {
"access": "public"
},
@@ -56,7 +56,9 @@
],
"license": "MIT",
"dependencies": {
+ "@deepseek-ai/dsh-timeout": "workspace:^",
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
+ "@deepseek-ai/schemastery": "workspace:^",
"ws": "^8.21.0"
},
"peerDependencies": {
diff --git a/packages/api/gateway/src/client/remote-events.ts b/packages/api/gateway/src/client/remote-events.ts
index 341c1f3f4d..9552478162 100644
--- a/packages/api/gateway/src/client/remote-events.ts
+++ b/packages/api/gateway/src/client/remote-events.ts
@@ -3,6 +3,7 @@
import type { Context } from '@deepseek-ai/cordis'
import type {
ConnectionGenerationSource,
+ ConnectionHostInfo,
ConnectionHandle,
} from '@deepseek-ai/dsh-client-connection/client'
import type {
@@ -118,7 +119,10 @@ export class ClientRemoteEvents {
}
/** Run one Connection generation over the forwarded-event logical stream. */
- private async pumpEvents(signal: AbortSignal, ready: () => void): Promise {
+ private async pumpEvents(
+ signal: AbortSignal,
+ ready: (host: ConnectionHostInfo) => void,
+ ): Promise {
let clientId: RemoteEventClientId | undefined
const failed = new AbortController()
const generationSignal = AbortSignal.any([signal, failed.signal])
@@ -134,8 +138,9 @@ export class ClientRemoteEvents {
try {
for await (const value of source) {
if (clientId === undefined) {
- clientId = parseRemoteEventReady(value)
- ready()
+ const opening = parseRemoteEventReady(value)
+ clientId = opening.clientId
+ ready(opening.host)
continue
}
const frame = parseRemoteEventFrame(value)
@@ -251,15 +256,21 @@ export class ClientRemoteEvents {
}
}
-/** Validate and return the Client identity from one generation's opening item. */
-function parseRemoteEventReady(value: unknown): RemoteEventClientId {
+/** Validate and return one generation's Client identity and Host facts. */
+function parseRemoteEventReady(value: unknown): {
+ readonly clientId: RemoteEventClientId
+ readonly host: ConnectionHostInfo
+} {
if (!isRemoteEventRecord(value)
- || !hasExactRemoteEventKeys(value, ['type', 'clientId'])
+ || !hasExactRemoteEventKeys(value, ['type', 'clientId', 'host'])
|| value.type !== 'ready'
- || !isRemoteEventClientId(value.clientId)) {
+ || !isRemoteEventClientId(value.clientId)
+ || !isRemoteEventRecord(value.host)
+ || !hasExactRemoteEventKeys(value.host, ['home'])
+ || typeof value.host.home !== 'string') {
throw new TypeError('client api: forwarded Remote event stream did not begin with ready')
}
- return value.clientId
+ return { clientId: value.clientId, host: { home: value.host.home } }
}
/** Validate one untrusted value from the Gateway-internal forwarded-event stream. */
diff --git a/packages/api/gateway/src/client/remote-stream.ts b/packages/api/gateway/src/client/remote-stream.ts
index 799a371ef5..71f1f546ae 100644
--- a/packages/api/gateway/src/client/remote-stream.ts
+++ b/packages/api/gateway/src/client/remote-stream.ts
@@ -48,7 +48,7 @@ export class RemoteStream- implements AsyncIterable>
* @param options - domain stream opener, end classification, and diagnostics.
*/
constructor(
- private readonly connection: Pick,
+ private readonly connection: Pick,
private readonly options: RemoteStreamOptions
- ,
) {}
@@ -157,13 +157,13 @@ export class RemoteStream
- implements AsyncIterable>
}
async function waitForRemoteStreamRetry(
- connection: Pick,
+ connection: Pick,
error: RemoteStreamCarrierError,
attempt: number,
signal: AbortSignal,
): Promise {
signal.throwIfAborted()
- if (connection.hostDescription.getSnapshot() !== undefined) {
+ if (connection.generation.getSnapshot() !== undefined) {
if (attempt === 1) return
throw error
}
@@ -181,12 +181,12 @@ async function waitForRemoteStreamRetry(
else reject(failure)
}
const inspect = (): void => {
- if (connection.hostDescription.getSnapshot() !== undefined) finish()
+ if (connection.generation.getSnapshot() !== undefined) finish()
}
const aborted = (): void => {
finish(new Error('Remote stream retry aborted', { cause: signal.reason }))
}
- const dispose = connection.hostDescription.subscribe(inspect)
+ const dispose = connection.generation.subscribe(inspect)
subscription.dispose = dispose
if (subscription.finished) dispose()
signal.addEventListener('abort', aborted, { once: true })
diff --git a/packages/api/gateway/src/index.ts b/packages/api/gateway/src/index.ts
index 86a71d834a..1d754b05a7 100644
--- a/packages/api/gateway/src/index.ts
+++ b/packages/api/gateway/src/index.ts
@@ -9,6 +9,8 @@ import { randomUUID } from 'node:crypto'
import { Context, Service, symbols } from '@deepseek-ai/cordis'
import type { ConnectionRpcHandler } from '@deepseek-ai/dsh-client-connection'
import type { WebUpgradeRoute } from '@deepseek-ai/dsh-host-webserver'
+import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
+import z from '@deepseek-ai/schemastery'
import {
remoteMethods,
TypertLookupFailure,
@@ -46,6 +48,7 @@ import {
type RemoteEventCancellationFrame,
type RemoteEventClientId,
type RemoteEventEmitFrame,
+ type RemoteEventHostInfo,
type RemoteEventId,
type RemoteEventInvocationFrame,
type RemoteEventReadyFrame,
@@ -64,6 +67,7 @@ export type {
TypertRemoteEventOutcome,
TypertRemoteEventSource,
} from './types.ts'
+export type { RemoteEventHostInfo } from './stream-protocol.ts'
interface GatewayErrorOptions {
readonly cause?: unknown
@@ -86,6 +90,7 @@ interface PreparedInvocation {
interface RegisteredRemoteEventSource {
readonly lifetime: AbortController
readonly done: Promise
+ readonly host: RemoteEventHostInfo
}
interface RemoteEventClient {
@@ -106,6 +111,17 @@ interface PendingRemoteEvent {
type ConnectionRpcResult = Awaited>
type ConnectionRpcError = Extract['error']
const NEVER_ABORTED_SIGNAL = new AbortController().signal
+const DEFAULT_WEBSOCKET_HEARTBEAT_INTERVAL_MS = 30_000
+
+/** Gateway transport configuration. */
+export interface Config {
+ /** WebSocket Ping interval from 1 through 2,147,483,647 milliseconds. @default 30000 */
+ readonly websocketHeartbeatIntervalMs?: number
+}
+
+interface ResolvedConfig extends Config {
+ readonly websocketHeartbeatIntervalMs: number
+}
/** Dispatch failure produced outside the invoked business method. */
export class TypertGatewayError extends Error {
@@ -156,6 +172,10 @@ class RemoteInvocationCancelled extends Error {
*/
export class TypertGatewayService extends Service implements TypertGateway {
static inject = ['typert']
+ static Config: z = z.object({
+ websocketHeartbeatIntervalMs: z.number().step(1).min(1).max(MAX_TIMER_DELAY_MS)
+ .default(DEFAULT_WEBSOCKET_HEARTBEAT_INTERVAL_MS),
+ })
/** Carrier adapter shared by the WebSocket mux and local Host transports. */
readonly wireStream: TypertGatewayWireStream = {
@@ -171,9 +191,11 @@ export class TypertGatewayService extends Service implements TypertGateway {
/**
* Register the Gateway against the active Typert registry.
* @param ctx - owning Host Context with Typert registry access.
+ * @param config - validated Gateway transport configuration.
*/
- constructor(ctx: Context) {
+ constructor(ctx: Context, config: Config) {
super(ctx, 'typertGateway')
+ const resolved = config as ResolvedConfig
ctx.on('internal/service', () => {
this.srcClaims = undefined
})
@@ -188,6 +210,7 @@ export class TypertGatewayService extends Service implements TypertGateway {
const mux = new RemoteStreamMuxServer(
(endpoint, payload, signal) => this.openWireStream(endpoint, payload, signal),
this.wireStream.failure,
+ resolved.websocketHeartbeatIntervalMs,
)
webCtx.effect(() => {
const route: WebUpgradeRoute = {
@@ -213,9 +236,13 @@ export class TypertGatewayService extends Service implements TypertGateway {
/**
* Register the sole application-selected forwarded-event source.
* @param source - stream factory installed by the Remote assembly.
+ * @param host - stable Host facts included in each Client generation's opening frame.
* @returns disposer removing this source and cancelling its active streams.
*/
- registerRemoteEvents(source: TypertRemoteEventSource): () => Promise {
+ registerRemoteEvents(
+ source: TypertRemoteEventSource,
+ host: RemoteEventHostInfo,
+ ): () => Promise {
if (this.remoteEvents !== undefined) {
throw new Error('typert gateway: forwarded Remote event source is already registered')
}
@@ -227,7 +254,7 @@ export class TypertGatewayService extends Service implements TypertGateway {
this.remoteEvents = undefined
lifetime.abort(error)
})
- const registration: RegisteredRemoteEventSource = { lifetime, done }
+ const registration: RegisteredRemoteEventSource = { lifetime, done, host: { home: host.home } }
this.remoteEvents = registration
return async () => {
if (this.remoteEvents === registration) {
@@ -397,7 +424,7 @@ export class TypertGatewayService extends Service implements TypertGateway {
this.remoteEventClients.set(clientId, client)
for (const pending of this.pendingRemoteEvents.values()) this.deliverRemoteEvent(pending, client)
try {
- yield { ...REMOTE_EVENT_STREAM_READY, clientId }
+ yield { ...REMOTE_EVENT_STREAM_READY, clientId, host: registration.host }
yield* client.queue.iterate(lifetime)
} finally {
this.removeRemoteEventClient(client)
diff --git a/packages/api/gateway/src/stream-protocol.ts b/packages/api/gateway/src/stream-protocol.ts
index 2c6e8ebf70..142598863e 100644
--- a/packages/api/gateway/src/stream-protocol.ts
+++ b/packages/api/gateway/src/stream-protocol.ts
@@ -23,10 +23,18 @@ export type RemoteEventClientId = Branded<'RemoteEventClientId'>
/** Opaque correlation id for one pending Host-to-Client Remote Event. */
export type RemoteEventId = Branded<'RemoteEventId'>
+/** Stable Host facts published with every established Client event generation. */
+export interface RemoteEventHostInfo {
+ /** Host account home used only to abbreviate displayed filesystem paths. */
+ readonly home: string
+}
+
/** Opening item that binds later HTTP results to this active event stream. */
export interface RemoteEventReadyFrame {
readonly type: 'ready'
readonly clientId: RemoteEventClientId
+ /** Stable Host facts attached to this connection generation. */
+ readonly host: RemoteEventHostInfo
}
/** Opaque Agent identity carried by one scoped Remote Event. */
diff --git a/packages/api/gateway/src/stream-server.ts b/packages/api/gateway/src/stream-server.ts
index 04b0df0427..28a3589542 100644
--- a/packages/api/gateway/src/stream-server.ts
+++ b/packages/api/gateway/src/stream-server.ts
@@ -23,14 +23,17 @@ export type RemoteStreamFailureMapper = (error: unknown) => RemoteStreamFailure
export class RemoteStreamMuxServer {
private readonly server = new WebSocketServer({ noServer: true })
private readonly connections = new Set>()
+ private heartbeatTimer: NodeJS.Timeout | undefined
/**
* @param open - Gateway stream dispatcher.
* @param failure - Gateway error-to-wire mapper.
+ * @param heartbeatIntervalMs - interval between WebSocket Ping control frames.
*/
constructor(
private readonly open: RemoteStreamOpener,
private readonly failure: RemoteStreamFailureMapper,
+ private readonly heartbeatIntervalMs: number,
) {}
/**
@@ -41,6 +44,7 @@ export class RemoteStreamMuxServer {
*/
handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer): void {
this.server.handleUpgrade(req, socket, head, (websocket) => {
+ this.startHeartbeat()
const connection = new RemoteStreamMuxConnection(websocket, this.open, this.failure)
const done = connection.run()
this.connections.add(done)
@@ -50,6 +54,8 @@ export class RemoteStreamMuxServer {
/** Terminate all sockets and wait until every iterator has returned. */
async close(): Promise