Merge remote-tracking branch 'origin/master' into worktree/web-background-tasks-display-258f7e

# Conflicts:
#	docs/subsystems/tasks.i18n.yaml
#	docs/subsystems/tasks.md
#	docs/subsystems/tasks.zh.md
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.md
#	packages/host/apiproxy/README.zh.md
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/tasks/tasks-local/src/index.ts
#	packages/tasks/tasks/README.i18n.yaml
#	packages/tasks/tasks/README.md
#	packages/tasks/tasks/README.zh.md
#	packages/tasks/tasks/src/index.ts
This commit is contained in:
Yichen Jiang
2026-08-11 11:57:33 +08:00
2697 changed files with 39978 additions and 18500 deletions

View File

@@ -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/self-modification/tool-cordis/README.md
README.md: f2a65043a1d2f74553e98caf59ed3d38b5a70b7c
README.zh.md: 66742094992d219ccfbd60b935dcd10e48cb12b8
README.md: 4f856523cca4800cdbb98951183fbea1e3c96c87
README.zh.md: 7bb21396452ddbe49cf3008cd89cd6044b3c4a51

View File

@@ -14,7 +14,7 @@ Exact model-facing schemas: [the generated tool catalog](../../../docs/tool-cata
Canonical successes are the inspection string, mount `{ id, pluginName, state, provides, waitingFor }`, and unmount `{ id, pluginName }`. Native rendering says whether the temporary Plugin is running or pending and that it remains available until unmounted or DSH restarts; unmount confirms that it was removed.
Temporary Plugins live only in the shared DSH process memory. They remain active across later turns and may affect other sessions in that process, but disappear after `cordis_unmount`, toolset unload, or DSH restart. They create no Plugin file, install no package, change no `cordis.yml` or personal/project configuration, do not survive restart, and cannot be promoted automatically. To keep an experiment, ask the Agent to implement a normal local, project, or repository Plugin through the regular development workflow.
Temporary Plugins live only in the shared DSH process memory. They remain active across later turns and may affect other sessions in that process, but disappear after `cordis_unmount`, toolset unload, or DSH restart. They create no Plugin file, install no package, change no `cordis.yml` or personal/project configuration, do not survive restart, and cannot be promoted automatically. To keep an experiment, ask the Agent to implement an SDK Plugin or installable profile bundle through the regular development workflow.
## Trust stance

View File

@@ -14,7 +14,7 @@
规范成功结果分别为检查字符串、挂载 `{ id, pluginName, state, provides, waitingFor }`,以及卸载 `{ id, pluginName }`。原生渲染会说明临时插件正在运行还是等待中,并说明它可用至被卸载或 DSH 重启;卸载结果确认它已移除。
临时插件只存在于共享 DSH 进程内存中。它可跨后续轮次保持活跃,也可能影响同一进程中的其他会话,但会在 `cordis_unmount`、工具集卸载或 DSH 重启后消失。它不会创建插件文件、安装任何包、修改 `cordis.yml` 或个人/项目配置、跨重启存续,也不能自动转为正式插件。若要保留实验结果,应让 agent(智能体)通过常规开发流程实现普通的本地、项目或仓库插件。
临时插件只存在于共享 DSH 进程内存中。它可跨后续轮次保持活跃,也可能影响同一进程中的其他会话,但会在 `cordis_unmount`、工具集卸载或 DSH 重启后消失。它不会创建插件文件、安装任何包、修改 `cordis.yml` 或个人/项目配置、跨重启存续,也不能自动转为正式插件。若要保留实验结果,应让 agent(智能体)通过常规开发流程实现 SDK 插件或可安装的 profile 组合包。
## 信任立场

View File

@@ -1,8 +1,15 @@
{
"name": "@deepseek-ai/dsh-tool-cordis",
"description": "Self-referential cordis toolset: inspect the live runtime, mount and dispose model-written plugins",
"version": "0.0.1",
"private": true,
"version": "0.0.1-rc.1",
"publishConfig": {
"access": "restricted"
},
"repository": {
"type": "git",
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
"directory": "packages/self-modification/tool-cordis"
},
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
@@ -25,17 +32,17 @@
],
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"@deepseek-ai/dsh-scope": "^0.0.1",
"@deepseek-ai/dsh-tools": "^0.0.1",
"cordis": "^4.0.0-rc.7"
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-scope": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
},
"dependencies": {
"schemastery": "^3.18.0"
"@deepseek-ai/schemastery": "workspace:^"
},
"devDependencies": {
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
"@cordisjs/plugin-timer": "workspace:^",
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
"@deepseek-ai/cordis-plugin-timer": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-agent-loop-testkit": "workspace:^",
@@ -45,6 +52,6 @@
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"cordis": "^4.0.0-rc.7"
"@deepseek-ai/cordis": "workspace:^"
}
}

View File

@@ -72,7 +72,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
signature: 'async saveSelection(next: ModelSelection): Promise<void>',
jsDoc: '/**\n * Save the complete default model selection. A deployment without a settings\n * provider keeps its composition entry.\n * @param next - resolved selection accepted by a front door.\n * @returns fulfillment after the optional settings write settles.\n */',
jsDoc: '/**\n * Save the complete default model selection. A deployment without a settings\n * provider keeps its composition entry.\n * @param next - resolved selection accepted by an entry point.\n * @returns fulfillment after the optional settings write settles.\n */',
},
],
},
@@ -110,6 +110,14 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
signature: 'async mount(agentCtx: Context, id?: string): Promise<AgentPreset>',
jsDoc: '/**\n * Compose one agent from a preset: ensure the preset\'s standing mount, then\n * parent the agent\'s scope key to it so the mount\'s registrations and\n * listeners cover this agent.\n *\n * Call from the agent factory\'s `setup(agentCtx)`; a rejection there rolls\n * the agent creation back, so a broken preset never yields a half-composed\n * session.\n * @param agentCtx - the agent\'s scope context.\n * @param id - the preset id, or `undefined` for {@link defaultId}.\n * @returns the preset that was composed, for the caller to record.\n * @throws when the preset is unknown or its composition is unusable.\n */',
},
{
signature: 'composeFrom(agentCtx: Context, parentCtx: Context): string | undefined',
jsDoc: '/**\n * Join one agent to the SAME standing composition another already runs on.\n *\n * This is how a child agent inherits its parent\'s capabilities. It is a bind,\n * not a mount: the parent\'s generation is already composed, so the child gets\n * that exact instance — the same plugin objects, the same tool registrations,\n * the same prompt sections. Re-resolving the parent\'s preset by id instead\n * would re-read the roster, and a composition file edited since the parent\n * started would hand the child a DIFFERENT generation than the one its\n * parent\'s history was produced under (and a preset deleted since would fail\n * the child outright while its parent keeps running).\n *\n * Synchronous, and with no composition failure mode of its own — it reads no\n * roster, mounts nothing, and touches no file — which is what lets a child\n * creation window use it: the two in-process subagent drivers compose their\n * children inside a synchronous `setup`. It still rejects a caller error, as\n * the `@throws` below record.\n *\n * A parent that joined no preset — a rosterless deployment — yields no join\n * and no error: there, the model-facing rows sit in the host composition and\n * the child already sees them through the global layer.\n * @param agentCtx - the joining agent\'s scope context.\n * @param parentCtx - the scope context of the agent whose composition to join.\n * @returns the preset id joined, or undefined when the parent joined none.\n * @throws when `agentCtx` carries no scope, or has already joined a preset.\n */',
},
{
signature: 'composedPreset(agentCtx: Context): string | undefined',
jsDoc: '/**\n * The preset one live agent runs on.\n *\n * Read from the live scope chain rather than from the session, so it answers\n * for an agent whose session has not recorded a preset yet — a child agent\n * whose durable header is being built from its parent\'s composition.\n * @param agentCtx - the agent\'s scope context.\n * @returns the preset id, or undefined when the agent joined none.\n */',
},
{
signature: 'async read(id: string): Promise<string>',
jsDoc: '/**\n * Read one preset\'s composition text.\n * @param id - the preset id.\n * @returns the composition exactly as stored.\n * @throws when no configured root supplies that id.\n */',
@@ -216,6 +224,24 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
],
},
{
key: 'attachments',
summary: 'Immutable binary attachment service.',
methods: [
{
signature: 'abstract validateImage(input: SaveImageAttachment): Promise<void>',
jsDoc: '/**\n * Validate one image without persisting it.\n * Batch callers validate every member before saving any member.\n * @param input - encoded bytes, declared media type, and optional display name.\n * @returns completion after the encoded raster has been fully decoded.\n */',
},
{
signature: 'abstract saveImage(input: SaveImageAttachment): Promise<ImageAttachmentRef>',
jsDoc: '/**\n * Validate and durably commit one image before its owning session event is appended.\n * @param input - encoded bytes, declared media type, and optional display name.\n * @returns a durable content-addressed reference.\n */',
},
{
signature: 'abstract readImage(ref: ImageAttachmentRef): Promise<StoredImageAttachment>',
jsDoc: '/**\n * Read one image and verify that bytes still match the recorded reference.\n * @param ref - durable reference from the session log.\n * @returns the verified bytes and canonical reference.\n */',
},
],
},
{
key: 'bash',
summary: 'Abstract bash execution service.',
@@ -254,7 +280,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
key: 'clientModuleHost',
summary: 'The web plugin table service: incremental dshClient scan + wire composition + bundle route + index tap.',
summary: 'The web plugin table service: incremental `dsh.client` scan + wire composition + bundle route + index tap.',
methods: [
{
signature: 'graph(): WebBootGraph',
@@ -468,7 +494,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
key: 'httpServer',
summary: 'The web-shape HTTP carrier service.',
summary: 'The browser HTTP carrier service.',
methods: [
{
signature: 'register(route: WebRoute): () => void',
@@ -584,15 +610,15 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
key: 'planMode',
summary: '`ctx.planMode`: owns logged plan state, boundary application and narration, the `plan:policy` section, the `/plan` command, and the stable exit tool.',
summary: '`ctx.planMode`: owns logged plan state, applies and narrates selected state at step start, the `plan:policy` section, the `/plan` command, and the stable exit tool.',
methods: [
{
signature: 'get(agent: Agent): { active: boolean; pending?: boolean }',
jsDoc: '/**\n * Read the logged plan state and any selected state awaiting a boundary.\n *\n * @param agent The agent to read.\n * @returns Current logged state plus a pending selection, when present.\n */',
jsDoc: '/**\n * Read the logged plan state and any selected state awaiting the next\n * accepted in-turn pre-step.\n *\n * @param agent The agent to read.\n * @returns Current logged state plus a pending selection, when present.\n */',
},
{
signature: 'set(agent: Agent, active: boolean): \'committed\' | \'queued\' | \'cancelled\' | \'noop\'',
jsDoc: '/**\n * Select whether plan mode should be active. Between turns the change\n * commits immediately — no request boundary would arrive until the next\n * prompt, so a queued intent would hang (the open-turn fold is the idle\n * signal: agent status stays `running` through post-turn checkpointing,\n * where a boundary equally never comes). During an open turn the\n * selection is held as pending intent for the next in-turn request\n * boundary. Repeated selection of the current or already-pending state is\n * a no-op.\n *\n * @param agent The agent to switch.\n * @param active Whether plan mode should be active.\n * @returns what happened: `committed` (logged now), `queued` (awaiting the\n * next boundary), `cancelled` (an opposite pending selection was cleared;\n * the logged state already matches), or `noop` (already in that state).\n */',
jsDoc: '/**\n * Select whether plan mode should be active. Between turns the method\n * appends the change immediately because no in-turn pre-step will run until\n * another prompt starts a turn. The open-turn fold is the idle signal:\n * agent status stays `running` through post-turn checkpointing, when no\n * further in-turn pre-step runs. During an open turn the selection remains\n * pending until the next accepted in-turn pre-step. Repeated selection of\n * the current or already-pending state is a no-op.\n *\n * @param agent The agent to switch.\n * @param active Whether plan mode should be active.\n * @returns what happened: `committed` (logged now), `queued` (awaiting the\n * next accepted in-turn pre-step), `cancelled` (an opposite pending selection\n * was cleared; the logged state already matches), or `noop` (already in that\n * state).\n */',
},
],
},
@@ -728,7 +754,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
methods: [
{
signature: 'register<K extends keyof SessionProjectionMap, S>(definition: ProjectionDefinition<K, S>): () => void',
jsDoc: '/**\n * Register one domain\'s unit. The registration is an effect on the calling\n * context\'s fiber: disposing the fiber (or calling the returned disposer)\n * removes the key — and the unit\'s cached cells — from subsequent drives\n * and snapshots.\n * @param definition - key, boundary schema, pure unit functions, and stateVersion.\n * @returns the exact disposer that unregisters this unit.\n */',
jsDoc: '/**\n * Register one domain\'s unit. The registration is an effect on the calling\n * context\'s fiber: disposing the fiber (or calling the returned disposer)\n * removes the key — and the unit\'s cached cells — from subsequent drives\n * and snapshots.\n * @param definition - key, state schema, pure unit functions, and stateVersion.\n * @returns the exact disposer that unregisters this unit.\n */',
},
{
signature: 'onChanged(listener: ProjectionChangeListener): () => void',
@@ -802,11 +828,11 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
signature: 'async readSurface(sessionId: SessionId): Promise<SessionSurfaceSnapshot>',
jsDoc: '/**\n * Read one session\'s complete current model surface from one corpus observation.\n * @param sessionId - live-preferred session id to read.\n * @returns cloned header, current surface, and raw-log capture boundary.\n * @throws when source resolution fails or the session surface is invalid.\n */',
jsDoc: '/**\n * Read one session\'s complete current model surface from one corpus observation.\n * @param sessionId - live-preferred session id to read.\n * @returns cloned header, current surface, and the last sequence number included in the raw-log capture.\n * @throws when source resolution fails or the session surface is invalid.\n */',
},
{
signature: 'async traceSession(sessionId: SessionId, signal?: AbortSignal): Promise<SessionLineageTrace>',
jsDoc: '/**\n * Trace known ancestry and descendants from one corpus observation.\n * @param sessionId - logical session id to trace.\n * @param signal - optional cancellation for persistence listing.\n * @returns a complete lineage or an explicit unresolved parent boundary.\n * @throws when corpus resolution fails, the target is absent, or its known ancestry cycles.\n */',
jsDoc: '/**\n * Trace known ancestry and descendants from one corpus observation.\n * @param sessionId - logical session id to trace.\n * @param signal - optional cancellation for persistence listing.\n * @returns a complete lineage or the first parent that could not be resolved.\n * @throws when corpus resolution fails, the target is absent, or its known ancestry cycles.\n */',
},
{
signature: 'async traceEvent(request: SessionEventTraceRequest, signal?: AbortSignal): Promise<SessionEventTraceObservation>',
@@ -1088,7 +1114,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
signature: 'async assemble(context: AssembleContext = {}): Promise<PromptAssembly>',
jsDoc: '/**\n * Assemble global and scoped providers, detach tool parameters, apply\n * canonical ordering, then run the assembly waterfall. Scoped sections and\n * variables shadow globals; the returned waterfall value is authoritative.\n * @param context - the optional scope and plugin-defined assembly fields.\n * @returns the authoritative post-waterfall assembly.\n */',
jsDoc: '/**\n * Assemble global and scoped providers, detach tool parameters, apply\n * canonical ordering, then run the assembly waterfall. Scoped sections and\n * variables shadow globals. The returned waterfall value is authoritative\n * except that an effective complete section is restored afterwards as the\n * sole prompt section.\n * @param context - the optional scope and plugin-defined assembly fields.\n * @returns the post-waterfall assembly with any complete prompt enforced.\n */',
},
],
},
@@ -1122,21 +1148,21 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
signature: 'abstract onTaskDone(listener: TaskDoneListener): () => void',
jsDoc: '/**\n * Register an effect-scoped completion listener. Each listener is contained;\n * returned promises are observed but not awaited. No listener runs after\n * service disposal.\n * @param listener - receives each terminal snapshot and its exact owner.\n * @returns disposer that unregisters the listener.\n */',
jsDoc: '/**\n * Register an effect-scoped completion listener. It receives the settlements\n * of the owners its registering context\'s scope covers; each listener is\n * contained; returned promises are observed but not awaited. No listener runs\n * after service disposal.\n * @param listener - receives each terminal snapshot and its exact owner.\n * @returns disposer that unregisters the listener.\n */',
},
{
signature: 'abstract onTasksChanged(listener: TasksChangedListener): () => void',
jsDoc: '/**\n * Register an effect-scoped observer of visible-set changes. It fires after\n * every commit that changes what {@link list} returns for that owner —\n * registration, every stopping transition (including the one teardown\n * performs before it awaits a slow producer), settlement, owner-disposal\n * removal, and the emptying that service disposal commits — so an observer\n * re-reads rather than accumulating deltas.\n *\n * The registration binds to the CALLING fiber, so an observer mounted outside\n * this service still receives the disposal emptying; that is what stops a\n * consumer from retaining rows after the registry unloads.\n *\n * This is not a superset of {@link onTaskDone}: that one delivers the terminal\n * record under first-wins semantics a control surface couples to notice\n * delivery, while this one carries no delivery meaning and marks nothing\n * reported. Listeners are contained and never awaited.\n * @param listener - receives the owner whose visible set changed, or\n * `undefined` when an unowned task changed and every caller\'s set did.\n * @returns disposer that unregisters the listener.\n */',
jsDoc: '/**\n/**\n * Register an effect-scoped observer of visible-set changes. It fires after\n * every commit that changes what {@link list} returns for that owner —\n * registration, every stopping transition (including the one teardown\n * performs before it awaits a slow producer), settlement, owner-disposal\n * removal, and the emptying that service disposal commits — so an observer\n * re-reads rather than accumulating deltas.\n *\n * Delivery is owner-relative on the same terms as {@link onTaskDone}: an\n * observer registered from an unscoped context — a host composition\'s own\n * carrier — sees every owner, while one registered under an agent\n * composition\'s scope sees exactly the agents composed under it.\n *\n * This is not a superset of {@link onTaskDone}: that one delivers the terminal\n * record under first-wins semantics a control surface couples to notice\n * delivery, while this one carries no delivery meaning and marks nothing\n * reported. Listeners are contained and never awaited.\n * @param listener - receives the owner whose visible set changed, or\n * `undefined` when an unowned task changed and every caller\'s set did.\n * @returns disposer that unregisters the listener.\n */',
},
{
signature: 'abstract attachSurface(name: string): () => void',
jsDoc: '/**\n * Attach an effect-scoped surface that can read and stop tasks. {@link start}\n * refuses work while none is attached.\n * @param name - diagnostic label; duplicate names remain independent.\n * @returns disposer that detaches this surface.\n */',
jsDoc: '/**\n * Attach an effect-scoped surface that can read and stop tasks. It serves the\n * owners its registering context\'s scope covers, and {@link start} refuses an\n * owner no attached surface serves.\n * @param name - diagnostic label; duplicate names remain independent.\n * @returns disposer that detaches this surface.\n */',
},
],
},
{
key: 'telemetry',
summary: 'The backend contract in its loadable form: one implementation per context — the cordis `Service` registration under the `telemetry` key throws on a duplicate, cordis\' standard behavior.',
summary: 'Loadable form of the backend contract: one implementation per context — the cordis `Service` registration under the `telemetry` key throws on a duplicate, cordis\' standard behavior.',
methods: [
{
signature: 'abstract emit(record: TelemetryRecord): void',
@@ -1294,7 +1320,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
signature: 'async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>',
jsDoc: '/**\n * Run one search through the selected provider. Resolves the provider at call\n * time with the selection rules above; throws {@link WebError} when the\n * capability cannot run. The seam enforces `request.maxResults` on the result:\n * if the provider over-returns, `sources[]` is truncated and `truncated` set.\n * @param request - the query plus result-shaping options.\n * @param signal - optional cancellation signal forwarded to the provider.\n * @returns the provider\'s results, capped to `request.maxResults`.\n */',
jsDoc: '/**\n * Run one search through the selected provider. Resolves the provider at call\n * time with the selection rules above; throws {@link WebError} when the\n * capability cannot run. The seam enforces `request.maxResults` on the result:\n * if the provider over-returns, `sources[]` is truncated and `truncated` set.\n * @param request - the query and optional result limit.\n * @param signal - optional cancellation signal forwarded to the provider.\n * @returns the provider\'s results, capped to `request.maxResults`.\n */',
},
{
signature: 'async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>',
@@ -1588,7 +1614,7 @@ export const EVENT_API: readonly EventApiEntry[] = [
name: 'system-prompt/assemble',
mode: 'waterfall',
signature: '\'system-prompt/assemble\'(this: Scoped<SystemPrompt>, assembly: PromptAssembly, context: AssembleContext, next: () => Promise<PromptAssembly>): Promise<PromptAssembly>',
jsDoc: '/**\n * Expert waterfall over the assembled sections, contexts, tools, and variables.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners\n * receive only that scope\'s assemblies. The returned value is authoritative.\n * A supplied signal controls only this explicit assembly request and must not\n * be retained to control later turns.\n * @param assembly - the mutable assembly built from registered providers.\n * @param context - the caller\'s per-assembly context.\n * @mode waterfall\n */',
jsDoc: '/**\n * Expert waterfall over the assembled sections, contexts, tools, and variables.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners\n * receive only that scope\'s assemblies. The returned value is authoritative.\n * A supplied signal controls only this explicit assembly request and must not\n * be retained to control later turns. A registered complete section is\n * restored after this waterfall, so listeners cannot add to or replace\n * that scope\'s system prompt.\n * @param assembly - the mutable assembly built from registered providers.\n * @param context - the caller\'s per-assembly context.\n * @mode waterfall\n */',
summary: 'Expert waterfall over the assembled sections, contexts, tools, and variables.',
},
{
@@ -1616,8 +1642,8 @@ export const EVENT_API: readonly EventApiEntry[] = [
name: 'tools/code-dispatch-log',
mode: 'waterfall',
signature: '\'tools/code-dispatch-log\'(this: Scoped<ToolRegistry>, dispatch: CodeDispatchLog, next: () => Promise<ContentBlock[]>): Promise<ContentBlock[]>',
jsDoc: '/**\n * Shape the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before\n * the bridge appends its `tool/code-dispatch` event. `next()` keeps the\n * content unchanged; a listener may return replacement blocks (e.g. the\n * spill policy\'s preview + locator for an oversized text result). Only the\n * logged copy is affected — the program already received the complete\n * value, and the model sees neither. A throwing listener is contained:\n * the bridge falls back to logging the unshaped content.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent\'s dispatches.\n * @param dispatch - the parent execution, sub-call identity, and the settled content to log.\n * @mode waterfall\n */',
summary: 'Shape the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event.',
jsDoc: '/**\n * Allow a listener to replace content in the DURABLE LOG COPY of one\n * `run_code` sub-dispatch outcome before the bridge appends its\n * `tool/code-dispatch` event. `next()` keeps the\n * content unchanged; a listener may return replacement blocks (e.g. the\n * spill policy\'s preview + locator for an oversized text result). Only the\n * logged copy is affected — the program already received the complete\n * value, and the model sees neither. A throwing listener is contained:\n * the bridge falls back to logging the original settled content.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent\'s dispatches.\n * @param dispatch - the parent execution, sub-call identity, and the settled content to log.\n * @mode waterfall\n */',
summary: '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.',
},
{
name: 'tools/execute',
@@ -1789,6 +1815,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'AssistantProvenance',
declaration: 'export interface AssistantProvenance {\n provider: string;\n model: string;\n replayState?: unknown;\n}',
},
{
name: 'AttachmentId',
declaration: 'export type AttachmentId = Branded<\'AttachmentId\'>;',
},
{
name: 'BashEnvContributor',
declaration: 'export interface BashEnvContributor {\n name: string;\n variables: Readonly<Record<DshEnvironmentKey, BashEnvVariable>>;\n resolve(execution: ToolExecution): Readonly<Partial<Record<DshEnvironmentKey, string>>>;\n}',
@@ -1927,7 +1957,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
},
{
name: 'ContentBlockMap',
declaration: 'export interface ContentBlockMap {\n \'text\': TextBlock;\n \'reasoning\': ReasoningBlock;\n \'tool-call\': ToolCallBlock;\n \'tool-result\': ToolResultBlock;\n}',
declaration: 'export interface ContentBlockMap {\n \'text\': TextBlock;\n \'reasoning\': ReasoningBlock;\n \'image\': ImageBlock;\n \'tool-call\': ToolCallBlock;\n \'tool-result\': ToolResultBlock;\n}',
},
{
name: 'ContentBlockType',
@@ -2165,6 +2195,18 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'GoalView',
declaration: 'export interface GoalView extends GoalSnapshot {\n readonly roundsStarted: number;\n readonly createdAt: number;\n readonly updatedAt: number;\n readonly activation: GoalActivation;\n}',
},
{
name: 'ImageAttachmentRef',
declaration: 'export interface ImageAttachmentRef {\n attachmentId: AttachmentId;\n mediaType: ImageMediaType;\n bytes: number;\n width: number;\n height: number;\n name?: string;\n}',
},
{
name: 'ImageBlock',
declaration: 'export interface ImageBlock {\n type: \'image\';\n attachment: ImageAttachmentRef;\n}',
},
{
name: 'ImageMediaType',
declaration: 'export type ImageMediaType = \'image/png\' | \'image/jpeg\' | \'image/webp\' | \'image/gif\';',
},
{
name: 'Inbox',
declaration: 'export class Inbox {\n constructor(private readonly session: Session, private readonly notifications: InboxNotifications);\n get nextTurn(): readonly UserMessage[];\n get nextStep(): readonly UserMessage[];\n get hasPending(): boolean;\n clear(): void;\n claim(target: InboxTarget, turn: number): UserMessage[];\n append(target: InboxTarget, message: UserMessage): void;\n prepend(target: InboxTarget, message: UserMessage): void;\n replace(messageId: MessageId, newMessage: UserMessage): boolean;\n remove(messageId: MessageId): boolean;\n splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];\n}',
@@ -2263,7 +2305,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
},
{
name: 'LlmModelInfo',
declaration: 'export interface LlmModelInfo {\n provider: string;\n id: string;\n name: string;\n description?: string;\n}',
declaration: 'export interface LlmModelInfo {\n provider: string;\n id: string;\n name: string;\n description?: string;\n inputModalities?: readonly ModelModality[];\n}',
},
{
name: 'LlmModelReasoningInfo',
@@ -2305,6 +2347,14 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'ModelMessageSource',
declaration: 'export interface ModelMessageSource extends AssistantProvenance {\n kind: \'model\';\n}',
},
{
name: 'ModelModality',
declaration: 'export type ModelModality = ModelModalityMap[keyof ModelModalityMap];',
},
{
name: 'ModelModalityMap',
declaration: 'export interface ModelModalityMap {\n text: \'text\';\n image: \'image\';\n}',
},
{
name: 'ModelSelection',
declaration: 'export interface ModelSelection {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n}',
@@ -2375,7 +2425,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
},
{
name: 'PromptSection',
declaration: 'export interface PromptSection {\n readonly name: string;\n readonly order: number;\n readonly text: string | ((context: AssembleContext) => string);\n}',
declaration: 'export interface PromptSection {\n readonly name: string;\n readonly order: number;\n readonly text: string | ((context: AssembleContext) => string);\n readonly complete?: boolean;\n}',
},
{
name: 'ProviderRequestId',
@@ -2545,6 +2595,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'SandboxPolicyRequest',
declaration: 'export interface SandboxPolicyRequest {\n session?: Session;\n mode?: SandboxMode;\n}',
},
{
name: 'SaveImageAttachment',
declaration: 'export interface SaveImageAttachment {\n data: Uint8Array;\n mediaType: ImageMediaType;\n name?: string;\n}',
},
{
name: 'SaveTextSpill',
declaration: 'export interface SaveTextSpill {\n owner: SpillOwner;\n source: SpillSource;\n suggestedName: string;\n content: string;\n}',
@@ -2583,7 +2637,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
},
{
name: 'SessionEvent',
declaration: 'export type SessionEvent<T extends SessionEventType = SessionEventType> = {\n [K in SessionEventType]: {\n type: K;\n seq: number;\n time: number;\n data: SessionEventMap[K];\n } & (K extends SurfaceEventType ? {\n sourceEventSeqs?: number[];\n surfaceOp?: SurfaceOp;\n } : object);\n}[T];',
declaration: 'export type SessionEvent<T extends SessionEventType = SessionEventType> = {\n [K in SessionEventType]: {\n type: K;\n seq: number;\n time: number;\n data: SessionEventMap[K];\n ignorable?: true;\n } & (K extends SurfaceEventType ? {\n sourceEventSeqs?: number[];\n surfaceOp?: SurfaceOp;\n } : object);\n}[T];',
},
{
name: 'SessionEventMap',
@@ -2893,6 +2947,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'StorageForms',
declaration: 'export interface StorageForms {\n}',
},
{
name: 'StoredImageAttachment',
declaration: 'export interface StoredImageAttachment {\n ref: ImageAttachmentRef;\n data: Uint8Array;\n}',
},
{
name: 'StreamChunk',
declaration: 'export type StreamChunk = {\n type: \'block-start\';\n index: number;\n blockType: ContentBlockType;\n} | {\n type: \'text-delta\';\n index: number;\n text: string;\n} | {\n type: \'reasoning-delta\';\n index: number;\n text: string;\n} | {\n type: \'tool-call-delta\';\n index: number;\n id: CallId;\n name?: string;\n argumentsDelta: string;\n} | {\n type: \'block-end\';\n index: number;\n block: ContentBlock;\n} | {\n type: \'usage\';\n usage: TokenUsage;\n} | {\n type: \'finish\';\n reason: FinishReason;\n replayState?: unknown;\n};',

View File

@@ -5,7 +5,7 @@
* @module @deepseek-ai/dsh-tool-cordis/fiber-state
*/
import type { FiberState as FiberStateEnum } from 'cordis'
import type { FiberState as FiberStateEnum } from '@deepseek-ai/cordis'
/** Value mirror of the cordis `FiberState` const enum (see the module doc for why a mirror exists). */
export const FiberState = {

View File

@@ -12,8 +12,8 @@
* @module @deepseek-ai/dsh-tool-cordis/guard
*/
import { Context } from 'cordis'
import type { Plugin } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import type { Plugin } from '@deepseek-ai/cordis'
import { scopeOf } from '@deepseek-ai/dsh-scope'
import { assertSupportedJsonSchema, defineTool } from '@deepseek-ai/dsh-tools'
import type { ToolDefinition } from '@deepseek-ai/dsh-tools'

View File

@@ -7,8 +7,8 @@
* @module @deepseek-ai/dsh-tool-cordis
*/
import type { Context } from 'cordis'
import z from 'schemastery'
import type { Context } from '@deepseek-ai/cordis'
import z from '@deepseek-ai/schemastery'
import { defineTool } from '@deepseek-ai/dsh-tools'
import { STATE_LABELS } from './fiber-state.ts'
import { isPlugin, pluginName } from './guard.ts'
@@ -112,7 +112,7 @@ export function apply(ctx: Context, config: Config): void {
+ 'This creates an in-memory runtime Plugin, not an installed or configured Plugin. '
+ 'It remains active across later turns until cordis_unmount, toolset unload, or DSH restart. '
+ 'It does not create files, install a package, change cordis.yml or personal/project config, survive restart, or automatically become permanent. '
+ 'To keep it, ask the Agent to implement a normal local, project, or repository Plugin through the regular development workflow. '
+ 'To keep it, ask the Agent to implement an SDK Plugin or installable profile bundle through the regular development workflow. '
+ 'It may affect other sessions in the same process; the sandbox is not a security boundary, and injected services reach the real runtime. '
+ '`code` runs now as the body of an async JavaScript function '
+ 'in an isolated sandbox and MUST `return` a plugin. Two forms: '

View File

@@ -6,7 +6,7 @@
* @module @deepseek-ai/dsh-tool-cordis/inspect
*/
import type { Context, Fiber } from 'cordis'
import type { Context, Fiber } from '@deepseek-ai/cordis'
import type { ScopeKey } from '@deepseek-ai/dsh-scope'
import { EVENT_API, INHERITED_CTX_API, SERVICE_API, TYPE_API } from './api-catalog.ts'
import type { EventApiEntry, InheritedApiEntry, ServiceApiEntry, TypeApiEntry } from './api-catalog.ts'

View File

@@ -4,7 +4,7 @@
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-tool-cordis'

View File

@@ -9,7 +9,7 @@
* @module @deepseek-ai/dsh-tool-cordis/mount
*/
import type { Context, Fiber, Plugin } from 'cordis'
import type { Context, Fiber, Plugin } from '@deepseek-ai/cordis'
import { guardedPlugin } from './guard.ts'
/** One tracked dynamic mount: the fiber plus the display name captured at mount time. */

View File

@@ -15,7 +15,7 @@ import { sandboxDefineTool, sandboxRegisterTool } from './guard.ts'
* A write-through console for one sandbox, tagging every line with the mount
* id. Write-through (host stdout/stderr), NOT buffered into the tool result:
* a mounted listener fires long after the mount call returned, and its output
* must land somewhere the user can see — for a terminal front door, the host terminal.
* must land somewhere the user can see — for a terminal entry point, the host terminal.
*/
function taggedConsole(id: string): Record<'log' | 'info' | 'warn' | 'error' | 'debug', (...args: unknown[]) => void> {
const tag = `[cordis:${id}]`
@@ -56,8 +56,8 @@ const TIMER_REDIRECT
/**
* The callable Node APIs the sandbox deliberately disables, each mapped to the
* cordis alternative its trap error names. Only FUNCTION-shaped globals are
* trapped — a data-shaped global like `process` stays `undefined`, because a
* cordis alternative its trap error names. Only function-valued globals are
* trapped; a data-valued global such as `process` stays `undefined`, because a
* throwing accessor would detonate the common `typeof process` feature probe
* at resolution time.
*/

View File

@@ -1,4 +1,4 @@
import { Context, CordisError, FiberState, type Fiber } from 'cordis'
import { Context, CordisError, FiberState, type Fiber } from '@deepseek-ai/cordis'
import { describe, expect, it } from 'vitest'
/**

View File

@@ -1,5 +1,5 @@
import { Context } from 'cordis'
import Timer from '@cordisjs/plugin-timer'
import { Context } from '@deepseek-ai/cordis'
import Timer from '@deepseek-ai/cordis-plugin-timer'
import { CallId } from '@deepseek-ai/dsh-llm'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import type { Context, Fiber } from 'cordis'
import type { Context, Fiber } from '@deepseek-ai/cordis'
import { FiberState } from '../src/fiber-state.ts'
import { describeApi, describeEvents, describePlugins, describeServices } from '../src/inspect.ts'
import { call, LISTENER_CODE, setup, text } from './helpers.ts'

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import { createUserMessage, CallId } from '@deepseek-ai/dsh-llm'
import { SessionId } from '@deepseek-ai/dsh-session'
import type { Agent } from '@deepseek-ai/dsh-agent'

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import Loader from '@cordisjs/plugin-loader'
import Loader from '@deepseek-ai/cordis-plugin-loader'
import * as tool from '../src/index.ts'
import { setup } from './helpers.ts'

View File

@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
import * as tool from '../src/index.ts'