Merge remote-tracking branch 'origin/worktree/context-source-cards' into worktree/context-forms-remaining
# Conflicts: # apps/web/tests/snapshots/queue-actions/layout.expected.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.i18n.yaml # docs/core-data-structures/goal.i18n.yaml # docs/core-data-structures/goal.md # docs/core-data-structures/goal.zh.md # docs/event-producer-consumer.md # examples/acp-agent/tests/goal-snapshots/goal-session/session.expected.jsonl # examples/acp-agent/tests/goal-snapshots/goal-wrapup/session.expected.jsonl # examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl # examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl # examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl # examples/acp-agent/tests/snapshots/bash-spill/session.jsonl # examples/acp-agent/tests/snapshots/bash-tool-turn/session.jsonl # examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl # examples/acp-agent/tests/snapshots/cancel/session.jsonl # examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # examples/acp-agent/tests/snapshots/empty-response-retry/session.jsonl # examples/acp-agent/tests/snapshots/error-finish/session.jsonl # examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl # examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl # examples/acp-agent/tests/snapshots/fs-edit/session.jsonl # examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl # examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl # examples/acp-agent/tests/snapshots/fs-read-window/session.jsonl # examples/acp-agent/tests/snapshots/fs-read/session.jsonl # examples/acp-agent/tests/snapshots/fs-write-overwrite/session.jsonl # examples/acp-agent/tests/snapshots/fs-write/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-invalid-matcher/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-posttool-context/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-promptsubmit-context/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-stop-continue/session.jsonl # examples/acp-agent/tests/snapshots/hook-codex-invalid-matcher/session.jsonl # examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl # examples/acp-agent/tests/snapshots/hook-codex-posttool-context/session.jsonl # examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl # examples/acp-agent/tests/snapshots/hook-codex-promptsubmit-context/session.jsonl # examples/acp-agent/tests/snapshots/hook-codex-stop-continue/session.jsonl # examples/acp-agent/tests/snapshots/lsp-definition/session.jsonl # examples/acp-agent/tests/snapshots/missing-sandbox-runner/session.jsonl # examples/acp-agent/tests/snapshots/multi-turn/session.jsonl # examples/acp-agent/tests/snapshots/packed-chunks/session.jsonl # examples/acp-agent/tests/snapshots/parallel-tool-calls/session.jsonl # examples/acp-agent/tests/snapshots/partial-landlock-child-failure/session.jsonl # examples/acp-agent/tests/snapshots/pty-tools/session.jsonl # examples/acp-agent/tests/snapshots/repeat-tool-guard/session.jsonl # examples/acp-agent/tests/snapshots/session-query-spill/session.jsonl # examples/acp-agent/tests/snapshots/session-sandbox-root/session.jsonl # examples/acp-agent/tests/snapshots/session-title-after-turn/session.jsonl # examples/acp-agent/tests/snapshots/skill-load/session.jsonl # examples/acp-agent/tests/snapshots/subagent-continuable/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-continuable/session.jsonl # examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl # examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.jsonl # examples/acp-agent/tests/snapshots/subagent-fork/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-fork/session.jsonl # examples/acp-agent/tests/snapshots/subagent-list-agents/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-list-agents/session.jsonl # examples/acp-agent/tests/snapshots/subagent-mixed/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-mixed/session.2.jsonl # examples/acp-agent/tests/snapshots/subagent-mixed/session.jsonl # examples/acp-agent/tests/snapshots/subagent-multi/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-multi/session.2.jsonl # examples/acp-agent/tests/snapshots/subagent-multi/session.jsonl # examples/acp-agent/tests/snapshots/subagent-published-run-failure/session.jsonl # examples/acp-agent/tests/snapshots/subagent-report/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-report/session.jsonl # examples/acp-agent/tests/snapshots/subagent-spawn/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-spawn/session.jsonl # examples/acp-agent/tests/snapshots/text-turn/session.jsonl # examples/acp-agent/tests/snapshots/todo-write/session.jsonl # examples/acp-agent/tests/snapshots/tool-call-turn/session.jsonl # examples/acp-agent/tests/snapshots/web-fetch/session.jsonl # examples/acp-agent/tests/snapshots/workflow-run/session.1.jsonl # examples/acp-agent/tests/snapshots/workflow-run/session.jsonl # examples/acp-agent/tests/snapshots/workspace-context/session.jsonl # examples/acp-agent/tests/snapshots/workspace-edit/session.jsonl # examples/headless-agent/tests/snapshots/goal-tools/stream-json.expected.jsonl # examples/headless-agent/tests/snapshots/pty-tools/session.jsonl # examples/headless-agent/tests/snapshots/pty-tools/stream-json.expected.jsonl # examples/headless-agent/tests/subagent-inheritance-snapshots/parent-override/child.expected.jsonl # examples/headless-agent/tests/subagent-inheritance-snapshots/parent-override/parent.expected.jsonl # examples/jsonrpc-agent/tests/snapshots/persistent-tools/notifications.expected.jsonl # examples/jsonrpc-agent/tests/snapshots/persistent-tools/session.jsonl # packages/bash/tool-bash/tests/integration.spec.ts # packages/context/time-context/src/index.ts # packages/context/tmux-context/src/index.ts # packages/core/agent-loop/src/agent.ts # packages/core/system-prompt/src/index.ts # packages/goal/goal/src/domain.ts # packages/goal/goal/src/index.ts # packages/goal/goal/src/render.ts # packages/plan/plan-mode/src/index.ts
This commit is contained in:
@@ -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/tasks/README.md
|
||||
README.md: 9bafe5633bb7e57a5404ffb41fad04b621832b6d
|
||||
README.zh.md: 37b0aeeddcaafd872f906eb2c35e75345d904b99
|
||||
README.md: 05ed9c439684337c45abe11f03c861a1b795b2ac
|
||||
README.zh.md: 16fe6c0a2b183b719cb6aa8ac068e34d51832a2b
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# tasks/ — background task capability family
|
||||
# tasks/ — background-task capability family
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
The shared home for background-task ids, owner isolation, reads, cancellation, waiting, and completion notices. Bash, subagents, and future long-running tools use one model-facing protocol. See the [background-task runtime Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) and the [task-registry seam Agent Note](../../.agents/notes/implemented/architecture/2026-07-26-task-registry-seam.md).
|
||||
This family gives long-running tools one owner-isolated background-task protocol for observation, cancellation, waiting, and completion notices.
|
||||
|
||||
| Package | ctx key | Role |
|
||||
| Package | Role | ctx key |
|
||||
|---|---|---|
|
||||
| [`tasks`](tasks/README.md) (`@deepseek-ai/dsh-tasks`) | `ctx.tasks` | The registry seam: branded `<kind>-N` ids, the owner-fenced read/kill/wait/list contract, snapshot vocabulary, the `attachSurface` misconfiguration fence, and the snapshot invariant companion |
|
||||
| [`tasks-local`](tasks-local/README.md) (`@deepseek-ai/dsh-tasks-local`) | — | The process-local registry implementation: in-memory records, first-wins settlement bookkeeping, and the awaited owner-cleanup and teardown paths |
|
||||
| [`tool-tasks`](tool-tasks/README.md) (`@deepseek-ai/dsh-tool-tasks`) | — | The model-facing control surface: `task_output`, `task_list`, `task_kill`, the completion-notice injection, and the background-habit prompt section |
|
||||
| [`tasks/`](tasks/README.md) | Defines the task registry and lifecycle contract | `ctx.tasks` |
|
||||
| [`tasks-local/`](tasks-local/README.md) | Implements the process-local task registry | registers on `ctx.tasks` |
|
||||
| [`tool-tasks/`](tool-tasks/README.md) | Exposes task control and completion notices to the model | registers on `ctx.tools` |
|
||||
|
||||
The registry owns state across producer or surface reloads; the tool package owns presentation. Producers register execution hooks through `ctx.tasks.start` and own whether their config exposes `run_in_background`.
|
||||
See the [background-task runtime](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) and [task-registry](../../.agents/notes/implemented/architecture/2026-07-26-task-registry-seam.md) decisions.
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
这是后台任务 id、所有者隔离、读取、取消、等待和完成通知的共用归属位置。Bash、subagent(子 agent)及未来的长时间运行工具共用一套面向模型的协议。参见[后台任务运行时 Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)和[任务注册表 seam Agent Note](../../.agents/notes/implemented/architecture/2026-07-26-task-registry-seam.md)。
|
||||
本家族为长时间运行的工具提供一套按所有者隔离的后台任务协议,用于观察、取消、等待和完成通知。
|
||||
|
||||
| 包 | ctx 键 | 角色 |
|
||||
| 包 | 职责 | ctx 键 |
|
||||
|---|---|---|
|
||||
| [`tasks`](tasks/README.md)(`@deepseek-ai/dsh-tasks`) | `ctx.tasks` | 注册表 seam:带品牌类型的 `<kind>-N` id、按所有者隔离的读取/终止/等待/列出契约、快照词汇、`attachSurface` 配置错误防线,以及快照不变式配套项 |
|
||||
| [`tasks-local`](tasks-local/README.md)(`@deepseek-ai/dsh-tasks-local`) | 无 | 进程内注册表实现:内存记录、以首次结算为准的簿记,以及会等待执行完毕的所有者清理路径和销毁路径 |
|
||||
| [`tool-tasks`](tool-tasks/README.md)(`@deepseek-ai/dsh-tool-tasks`) | 无 | 面向模型的控制接口:`task_output`、`task_list`、`task_kill`、完成通知注入和后台工作习惯提示词段落 |
|
||||
| [`tasks/`](tasks/README.md) | 定义任务注册表和生命周期契约 | `ctx.tasks` |
|
||||
| [`tasks-local/`](tasks-local/README.md) | 实现进程本地任务注册表 | 注册到 `ctx.tasks` |
|
||||
| [`tool-tasks/`](tool-tasks/README.md) | 向模型公开任务控制和完成通知 | 注册到 `ctx.tools` |
|
||||
|
||||
生产方或接口重载时,状态仍由注册表持有;工具包负责呈现。生产方通过 `ctx.tasks.start` 注册执行钩子,并自行决定其配置是否公开 `run_in_background`。
|
||||
参见[后台任务运行时](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)和[任务注册表](../../.agents/notes/implemented/architecture/2026-07-26-task-registry-seam.md)决策。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, expectTypeOf, it, vi } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import AgentRegistry, {} from '@deepseek-ai/dsh-agent'
|
||||
import AgentRegistry, { Inbox } from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import { TaskId } from '@deepseek-ai/dsh-tasks'
|
||||
import type { TaskHooks, TaskKind, TaskOutcome, TaskSnapshot, TaskStart } from '@deepseek-ai/dsh-tasks'
|
||||
@@ -18,20 +18,20 @@ const agentScopeDisposers = new WeakMap<Agent, () => Promise<void>>()
|
||||
function stubAgent(ctx: Context, rawId: string): Agent {
|
||||
const id = SessionId(rawId)
|
||||
const scopeFiber = ctx.plugin(() => {})
|
||||
const session = Session.create(id)
|
||||
const agent = {
|
||||
id,
|
||||
options: {},
|
||||
session: Session.create(id),
|
||||
session,
|
||||
inbox: new Inbox(session, { inserted: () => {}, discarded: () => {}, claimed: () => {} }),
|
||||
status: 'idle' as const,
|
||||
acceptsNextStep: false,
|
||||
ctx: scopeFiber.ctx,
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => ({ outcome: Promise.resolve({ status: 'rejected' as const }) }),
|
||||
inject: () => {},
|
||||
send: () => {},
|
||||
updateInbox: (): 'not-found' => 'not-found',
|
||||
reserveTurnAdmission: () => undefined,
|
||||
cancel() {},
|
||||
runMaintenance: <T>(task: (signal: AbortSignal) => Promise<T>) => task(new AbortController().signal),
|
||||
whenIdle() { return Promise.resolve() },
|
||||
}
|
||||
agentScopeDisposers.set(agent, async () => { await scopeFiber.dispose() })
|
||||
|
||||
@@ -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/tasks/tool-tasks/README.md
|
||||
README.md: 276ca3f8284b366bee54e585297c3a033a65c8d1
|
||||
README.zh.md: 823c25c3e0c7c208ffef9c5be5b2e4ef7e96bad8
|
||||
README.md: 6e8e889c2330d6991cb384674b011e4d2e988268
|
||||
README.zh.md: 9e54e2de69f36d5d5b70094cab12e5503eaeb5fd
|
||||
|
||||
@@ -18,7 +18,7 @@ When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`
|
||||
|
||||
## Completion notices
|
||||
|
||||
An unreported completion injects `background task <id> (<kind>: <label>) finished [status: ...]. Read its output with task_output.` into the exact owner's session. When bounded, the stable id prefix and collection command outrank variable label/detail so the notice remains actionable at PTY's supported 64-byte minimum. Injection is durable context for the next request, not a wake-up. A kill or terminal read/wait marks delivery reported and suppresses the redundant notice. An owner-disposal race needs no special handling: the loop has no terminal state, so a notice injected during teardown appends as idle context — persisted for resume while the session is still attached, dropped with the detached log afterwards.
|
||||
An unreported completion injects `background task <id> (<kind>: <label>) finished [status: ...]. Read its output with task_output.` into the exact owner's next-step inbox. When bounded, the stable id prefix and collection command outrank variable label/detail so the notice remains actionable at PTY's supported 64-byte minimum. Injection is durable pending context for a later pre-step claim, not a wake-up; cancellation or owner disposal may discard it before claim. A kill or terminal read/wait marks delivery reported and suppresses the redundant notice.
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
## 完成通知
|
||||
|
||||
一项尚未报告的完成会向精确 owner 的会话注入 `background task <id> (<kind>: <label>) finished [status: ...]. Read its output with task_output.`。应用上限时,即使采用 PTY 支持的 64 字节下限,稳定 id 前缀和收集命令的优先级也高于可变 label/detail,因此通知仍可操作。注入是下一次请求使用的持久上下文,并非唤醒。kill 或针对已终止任务的 read/wait 会把交付标为已报告,并抑制重复通知。owner 释放竞态无需特殊处理:循环没有终结状态,teardown 期间注入的通知作为空闲上下文追加——会话仍挂接时随之持久化以供恢复,之后随脱离挂接的日志一并丢弃。
|
||||
一项尚未报告的完成会把 `background task <id> (<kind>: <label>) finished [status: ...]. Read its output with task_output.` 注入到精确 owner 的 next-step inbox。应用上限时,即使采用 PTY 支持的 64 字节下限,稳定 id 前缀和收集命令的优先级也高于可变 label/detail,因此通知仍可操作。注入是等待后续 pre-step 领取的持久上下文,并非唤醒;取消或 owner 释放可能在领取前丢弃它。kill 或针对已终止任务的 read/wait 会把交付标为已报告,并抑制重复通知。
|
||||
|
||||
## 配置
|
||||
|
||||
|
||||
@@ -227,11 +227,9 @@ export function apply(ctx: Context, config: Config): void {
|
||||
})
|
||||
|
||||
// Use the exact lifecycle owner; reusable ids could resolve to a replacement.
|
||||
// Delivery into a tearing-down owner is well-defined: the loop treats
|
||||
// disposal like any cancel, so the notice appends as durable idle context
|
||||
// (still attached and persisted during owner cleanup, presented on resume);
|
||||
// after detach it lands in an unreferenced in-memory log and is dropped
|
||||
// with it.
|
||||
// Delivery targets the exact lifecycle owner. The notice waits in its
|
||||
// next-step inbox until another step claims it; disposal before that
|
||||
// boundary discards it with the owner.
|
||||
ctx.tasks.onTaskDone((snapshot, owner) => {
|
||||
if (snapshot.reported || owner === undefined) return
|
||||
owner.inject(createUserMessage({
|
||||
|
||||
Reference in New Issue
Block a user