docs(session-title): record contracts and generated catalogs
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
# DeepSeek Harness Architecture
|
||||
|
||||
English | [中文](architecture.zh.md)
|
||||
|
||||
The **DeepSeek Harness SDK** builds agent harnesses on Cordis. The principle is simple: **everything is a plugin**. The shipped loop is one plugin, not a privileged kernel.
|
||||
|
||||
## Overview
|
||||
|
||||
A harness is one [Cordis](cordis-primer.md) context. Packages add services (`ctx.llm`, `ctx.tools`, `ctx.sessions`), typed events (`agent/request`, `tools/pre-execute`, `session/event`), and disposable prompt, tool, provider, adapter, and listener registrations.
|
||||
A harness is one [Cordis](cordis-primer.md) context. Packages add services (`ctx.llm`, `ctx.tools`, `ctx.sessions`, `ctx.sessionTitle`), typed events (`agent/request`, `tools/pre-execute`, `session/event`), and disposable registrations.
|
||||
|
||||
`packages/core/` groups the default agent flow; surrounding capabilities are equally first-class Cordis plugins.
|
||||
|
||||
@@ -38,6 +40,7 @@ A harness is one [Cordis](cordis-primer.md) context. Packages add services (`ctx
|
||||
| `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | script-driven multi-agent orchestration |
|
||||
| `ctx.sessionPersistence` | [`session-persistence/`](../packages/session-persistence/README.md) | durable storage for session logs |
|
||||
| `ctx.sessionQuery` | [`session-query/`](../packages/session-query/README.md) | live-preferred logical-corpus exact reads and relationship traces |
|
||||
| `ctx.sessionTitle` | [`session-title/`](../packages/session-title/README.md) | log-backed fallback titles and one optional asynchronous provider |
|
||||
|
||||
## Event
|
||||
|
||||
@@ -45,9 +48,9 @@ Events form the service extension API; see the exhaustive [events catalog](cordi
|
||||
|
||||
### Event Domains
|
||||
|
||||
- **Session events** are durable, replayable facts: boundaries, messages, tool activity, steering, compaction, and tool-owned records append to the log and flow through `session/event`.
|
||||
- **Agent events** carry the live `Agent` handle for status, diagnostics, prompt admission, request shaping, result validation, and continuation policy.
|
||||
- **Capability events** belong to their owning seam; `tools/*`, `llm/*`, `system-prompt/*`, `fs/*`, and `subagent/*` attach policy and adapters without importing the loop.
|
||||
- **Session events** are durable facts appended to the log and emitted through `session/event`.
|
||||
- **Agent events** carry the live `Agent` for status, prompt admission, request shaping, validation, and continuation.
|
||||
- **Capability events** let owning seams attach policy and adapters without importing the loop.
|
||||
|
||||
### Interception Semantics
|
||||
|
||||
@@ -57,9 +60,9 @@ Waterfall events behave like around-middleware: a listener delegates by calling
|
||||
|
||||
The shipped loop drains prompt-to-checkpoint work through plugin-visible services and events.
|
||||
|
||||
A **session** is an append-only log. Each ordinary **turn** claims one queued `send()` item; injection claims none. A claimed `send()` successor awaits the preceding claimed ordinary turn's checkpoint but may share its `running` interval ([decision](../.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.md)). A turn ends when model and plugins stop it. A **step** is one model request plus tools. Below ([sequence companion](agent-lifecycle.md)), quotes mark durable events; other names are extension points.
|
||||
A **session** is an append-only log. Each ordinary **turn** claims one queued `send()` item; injection claims none. Successors await the preceding claimed turn's checkpoint but may share its `running` interval ([decision](../.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.md)). A turn ends when model and plugins stop it. A **step** is one model request plus tools. Below ([sequence companion](agent-lifecycle.md)), quotes mark durable events.
|
||||
|
||||
No id mints `<config-id>-session-<uuid>`; `sessionId` resumes/creates; `resumeSessionId` needs history. Resume restores lineage, seeds, and delegation depth pre-publication. Failures emit `agent-loop/config-start-failed(sessionId, error)`; front doors reject; teardown stays silent.
|
||||
No id mints `<config-id>-session-<uuid>`; `sessionId` resumes/creates and `resumeSessionId` needs history. Resume restores lineage and delegation depth before publication. Setup failures emit `agent-loop/config-start-failed`; teardown stays silent.
|
||||
|
||||
### Turn Flow
|
||||
|
||||
@@ -107,15 +110,15 @@ forever:
|
||||
checkpoint persistence and notify idle/running status
|
||||
```
|
||||
|
||||
Each step assembles ordered prompt sections, tool schemas, and `{{name}}` variables; unknown or valueless references fail the turn. `dsh-system-prompt` owns the harness identity and default persona, which an agent scope may shadow. The loop supplies `model` and `cwd` ([prompt ownership](../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)).
|
||||
Each step assembles ordered prompt sections, tool schemas, and variables; unknown references fail the turn. `dsh-system-prompt` owns identity and persona, while the loop supplies `model` and `cwd` ([prompt ownership](../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)).
|
||||
|
||||
Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles, then follows recorded results. Steering drains before `agent/post-step`, which observes durable output, results, context, and steering before signal closure. Leftovers become queued input. Terminal `agent/turn-stop` runs after continuation and steering folding, stays authoritative through turn close and flush, and discards later steering but preserves queued prompts.
|
||||
Tool-time context settles after recorded results. Steering drains before `agent/post-step`; leftovers become queued input. Terminal `agent/turn-stop` runs after continuation and steering folding, stays authoritative through flush, and discards later steering while preserving queued prompts.
|
||||
|
||||
Pruning precedes summaries; overflow retries require durable progress. Bounded transient retries compose on `agent/request-error`; cancellation wins ([compaction](../.agents/notes/implemented/architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md), [retry](../.agents/notes/implemented/architecture/2026-06-21-bounded-llm-request-recovery.md)).
|
||||
|
||||
### Failure Boundaries
|
||||
|
||||
The turn is the containment boundary. Adapter failures close the step, entering `agent/request-error` with the exact `Error`, `LlmFailure`, and retry history. Retry opens a numbered step; success clears history; exhaustion stores the failure on `turn/end`. Failed chunks commit no message or tool.
|
||||
The turn is the containment boundary. Adapter failures close the step and enter `agent/request-error` with exact failure facts. Retry opens a numbered step; exhaustion stores the failure on `turn/end`. Failed chunks commit no message or tool.
|
||||
|
||||
Other failures use `agent/error`. Cancellation and disposal beat recovery; undispatched model tool calls receive synthetic `tool/call` and `ABORTED` result pairs before `turn/end`. `cancel()` clears queues and aborts active work; disposal awaits quiescence before unregistering.
|
||||
|
||||
@@ -123,11 +126,11 @@ Every session event is turn-enclosed. Reloading preserves an interrupted tail an
|
||||
|
||||
### Agent Handles
|
||||
|
||||
`ctx.agents` owns live agents and returns `AgentHandle { agent, dispose() }`. Plugins drive `Agent` through `send()`, `steer()`, `inject()`, `cancel()`, and `whenIdle()`. The caller fiber and factory provider structurally co-own programmatic lifecycles; the consumer handle is the only other teardown capability. All owners await one disposer.
|
||||
`ctx.agents` owns live agents and returns `AgentHandle { agent, dispose() }`. Plugins use `send()`, `steer()`, `inject()`, `cancel()`, and `whenIdle()`. The caller fiber, factory provider, and consumer handle co-own teardown through one awaited disposer.
|
||||
|
||||
### Agent Scope
|
||||
|
||||
Every live agent owns a scoped `agent.ctx`. Its registrations shadow globals, receive only that agent's dispatches, and unwind with it; async effects such as background-task cleanup are awaited. `CreateAgentOptions.setup(agentCtx)` composes the scope before publication. Typed resolvers derive carrier checks from merged `Events` signatures and `scopeTarget` ([semantic gates](../.agents/notes/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md)). See [agent scope](../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md) and [subagent composition controls](../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md). `AgentLoop` runs drivers inside `ctx.agents.withInitiator()`; private orchestration derives `agent.session`; other identities stay explicit ([decision](../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)).
|
||||
Every live agent owns a scoped `agent.ctx`. Registrations shadow globals, receive only that agent's dispatches, and unwind with it; async cleanup is awaited. `CreateAgentOptions.setup(agentCtx)` composes before publication. Typed resolvers derive carrier checks from merged `Events` signatures and `scopeTarget` ([semantic gates](../.agents/notes/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md)). See [agent scope](../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md) and [subagent composition](../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md). `AgentLoop` propagates its initiator; private orchestration derives `agent.session`, while other identities stay explicit ([decision](../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)).
|
||||
|
||||
## State
|
||||
|
||||
@@ -139,11 +142,13 @@ The session log is the source of truth. `deriveMessages()` projects session even
|
||||
|
||||
Durability is a plugin concern. Backends buffer synchronous `session/event` notifications; the loop awaits a turn-end checkpoint. `SessionPersistence` stores `SessionEvent` directly and metadata in `SessionHeader`; JSONL defaults to checksummed Zstandard, with SQLite under one contract.
|
||||
|
||||
Plugin-owned log-only events may opt into `ctx.sessions.appendOutOfBand()`: they join an open turn or receive a balanced, flushed zero-step turn. `session/title` uses that path as a latest-wins fold with source-message seqs and provenance. Its first-message fallback is immediate; at most one optional provider may replace it asynchronously without delaying the agent response. Forks inherit logged titles unchanged ([decision](../.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md)).
|
||||
|
||||
### Model Content
|
||||
|
||||
Messages contain typed blocks (`text`, `reasoning`, `tool-call`, `tool-result`) derived from merge-extensible `ContentBlockMap`; the same pattern types `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`. New block types coordinate adapters, UI bridges, compaction pricing, token metering, and persistence as one repo-wide contract; replay measurement types live in [token-meter.md](core-data-structures/token-meter.md).
|
||||
|
||||
Streaming uses raw chunks and `BlockAssembler`. One `LlmAdapter.stream()` is one provider attempt; adapters report facts, while recovery policy lives on `agent/request-error`. The loop logs chunks and successful provenance/replay state. Remote adapters stop stalled transport with per-read idle watchdogs. Replay state reaches targets only when routes share an adapter instance ([contract](core-data-structures/llm-streaming.md)).
|
||||
Streaming uses raw chunks and `BlockAssembler`. One `LlmAdapter.stream()` is one provider attempt; adapters report facts, while recovery lives on `agent/request-error`. The loop logs chunks and successful provenance/replay state. Remote adapters use per-read idle watchdogs. Replay state reaches targets only when routes share an adapter instance ([contract](core-data-structures/llm-streaming.md)).
|
||||
|
||||
## Extension And Composition
|
||||
|
||||
@@ -151,13 +156,13 @@ Streaming uses raw chunks and `BlockAssembler`. One `LlmAdapter.stream()` is one
|
||||
|
||||
A swappable capability usually splits into **interface / implementation / consumer**: the interface owns its `ctx` key and events, an implementation registers a backend, and a consumer exposes model behavior through tools or prompts. Bash is the reference; the [capability graph](capability-seams.md) shows every family.
|
||||
|
||||
Some seams bend the template deliberately: LLM combines interface and consumer because adapters implement it; filesystem wraps provider primitives with policy; web keeps search/fetch provider registries behind one service; skills and subagents use named providers. Subagents spawn fresh, fork a completed-turn prefix, or use ACP children ([subagent.md](core-data-structures/subagent.md)).
|
||||
Some seams bend the template: LLM combines interface and consumer; filesystem wraps providers with policy; web, skills, and subagents own registries. Session titles pair a built-in fallback with a single-provider registry and shared LLM helper. Subagents spawn fresh, fork a completed-turn prefix, or use ACP children ([subagent.md](core-data-structures/subagent.md)).
|
||||
|
||||
`dsh-workspace-context` composes baselines on `agent/session-prefix` and appends `ctx.fs`-discovered nested changes on `tools/post-execute`; its [decision](../.agents/notes/implemented/feature/2026-06-24-workspace-context.md) records isolation. `dsh-paths` owns shared paths.
|
||||
|
||||
### Bundles And Apps
|
||||
|
||||
`dsh-agent-spine-demo` bundles the default spine ([README](../packages/examples/agent-spine-demo/README.md)). `dsh-tui-demo` owns the interactive full-screen terminal; `dsh-cli-demo` runs one persisted headless turn with format-pure stdout; `dsh-acp-demo` adds stdout-pure ACP over JSON-RPC ([ui/](../packages/ui/README.md)). `dsh-jsonrpc-agent` boots external `cordis.yml`; the Python SDK supplies its default only without an explicit config channel and drives `dsh-jsonrpc` over line-delimited JSON-RPC ([Python SDK](../python/README.md)). Deployments remain thin leaves with swappable backends and optional product tools ([examples/](../examples/AGENTS.md), [runnable wirings](cookbook/extension-cookbook.md#runnable-wirings), [graph atlas](graph-atlas.md)).
|
||||
`dsh-agent-spine-demo` bundles the default spine, including fallback-only session titles; model title providers remain opt-in ([README](../packages/examples/agent-spine-demo/README.md)). `dsh-tui-demo` owns the terminal; `dsh-cli-demo` runs one persisted headless turn; `dsh-acp-demo` adds stdout-pure ACP ([ui/](../packages/ui/README.md)). `dsh-jsonrpc-agent` boots external `cordis.yml`; the Python SDK supplies a default only without an explicit config and drives line-delimited JSON-RPC ([Python SDK](../python/README.md)). Deployments remain thin leaves with swappable backends and optional tools ([examples/](../examples/AGENTS.md), [runnable wirings](cookbook/extension-cookbook.md#runnable-wirings), [graph atlas](graph-atlas.md)).
|
||||
|
||||
### Where New Behavior Goes
|
||||
|
||||
@@ -175,6 +180,7 @@ New behavior should attach to a documented extension point; changing the shipped
|
||||
| Add a session-stable request prefix outside history | compose it on `agent/session-prefix`, once per loop instance; logged on the request header |
|
||||
| Add UI or editor integration | drive `ctx.agents` and render from `session/event` |
|
||||
| Add durable session state | add a `SessionEventMap` member and render/replay from the log |
|
||||
| Add asynchronous session-title generation | register the sole provider on `ctx.sessionTitle` |
|
||||
| Fork a live session | use `ctx.sessions.fork(source, boundary?, childSessionId?)` |
|
||||
| Scope a tool, prompt section, or listener to ONE agent | register it through that agent's `agent.ctx` (see Agent Scope) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user