Files
deepseek-harness/docs/cordis-catalog/services.md
Tianyi Cui b61e68ae8c Merge branch 'codex/simp-unify-agent-session-id' into codex/simp-ui-identity-residue
# Conflicts:
#	docs/event-producer-consumer.md
2026-07-19 01:55:29 +08:00

21 KiB

Cordis Services Catalog

Every ctx.<key> service a plugin can call: the exact public interface plus the class JSDoc. This is one axis of the wiring reference a plugin author works against — the events a plugin listens to are the sibling events catalog, and core-data-structures/ catalogs the data structures these signatures move around. An abstract seam (e.g. ctx.bash) is implemented by a separate package; the interface is what consumers code against.

This file is GENERATED from source (scripts/gen-cordis-catalog.ts) and verified fresh by pnpm run verify-cordis-catalog (part of doc-sync) — do not edit it by hand. Signature blocks use a ts cordis-catalog fence (skipped by doc-typecheck, since a bare signature is not standalone-compilable). Type names in a signature link to the page that documents them.

The harness tier below (the @deepseek-ai/dsh-* packages) is the vocabulary this repo owns. The inherited tier at the end is the cordis-core + loader/hmr/timer ctx surface a plugin also sees — pinned vendor source, summarized tersely.

ctx.agentLoopAgentLoop

Concrete ReactLoopAgent factory and driver service.

create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd'> = {}): ReactLoopAgent
async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>
async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>

Source: packages/core/agent-loop/src/index.ts:408

ctx.agentsAgentRegistry

Agent registry (ctx.agents): tracks live agents so UI, hook, and orchestrator plugins can find them without depending on the concrete loop package. Agent creation is provided by whichever plugin implements the AgentFactory (@deepseek-ai/dsh-agent-loop), registered via setFactory.

setFactory(factory: AgentFactory): () => void
async create(options: CreateAgentOptions): Promise<AgentHandle>
async resume(options: ResumeAgentOptions): Promise<AgentHandle>
register(agent: Agent): () => void
enter(agent: Agent, owner: Agent | undefined): () => void
announce(agent: Agent): void
get(id: SessionId): Agent | undefined
isOwnedBy(id: SessionId, owner: Agent): boolean
list(): Agent[]
roots(): Agent[]

Types: Agent

Source: packages/core/agent/src/index.ts:201

ctx.approvalApprovalService

Approval service that applies session policy before answerers and logs every ask/outcome pair to the requesting session. It exposes deterministic policy changes to the model through prompt and pre-step notices.

async request(req: ApprovalRequest): Promise<ApprovalOutcome>

Types: ApprovalOutcome · ApprovalRequest

Source: packages/ui/user-approval/src/index.ts:229

ctx.bashBashExecutor (abstract seam)

Abstract bash execution service. Subclass, implement the abstract methods, and load the subclass as a plugin — it registers as ctx.bash (one implementation per context; loading a second throws, which is cordis' standard duplicate-service behavior).

Implementations must honor these semantics:

  • run rejects only for infrastructure failures. Nonzero exits, timeout kills, and abort kills resolve with a BashRunResult.
  • start returns immediately; no timeout applies to background processes. done settles at process close and never rejects; spawn failures settle as killed with the error on stderr.
  • BashProcess.readOutput is incremental: consecutive reads never repeat output. Lossy reads report truncation and available spill files.
  • Disposal kills all running background processes and awaits their exit.
abstract resolve(request: BashExecRequest): BashExecSpec
abstract run(spec: BashExecSpec): Promise<BashRunResult>
abstract start(spec: BashExecSpec): BashProcess

Types: BashExecRequest · BashExecSpec · BashRunResult

Source: packages/bash/bash/src/index.ts:49

ctx.bashEnvBashEnvRegistry

Registry (ctx.bashEnv) for trusted, per-execution DSH_* variables. The namespace is rebuilt for every model bash call: ambient DSH_* values are discarded by the executor, then the registry's current snapshot is injected. Built-in shell facts remain owned by the registry itself while plugins can register additional, enumerable facts with effect-scoped disposal.

register(contributor: BashEnvContributor): () => void
collect(execution: ToolExecution): DshEnvironment
list(): BashEnvVariableInfo[]

Types: ToolExecution

Source: packages/bash/tool-bash/src/index.ts:102

ctx.codeRuntimeCodeRuntime (abstract seam)

Registers one ctx.codeRuntime implementation. Program, budget, abort, and substrate failures resolve in CodeRunResult; only seam misuse rejects. Implementations bridge structured-cloneable bindings while treating programs as hostile peers, isolate runs from one another, and terminate and await in-flight runs during disposal.

abstract run(request: CodeRunRequest): Promise<CodeRunResult>

Types: CodeRunRequest · CodeRunResult

Source: packages/code-runtime/code-runtime/src/index.ts:30

ctx.compactCompactService (abstract seam)

Abstract compaction service. Implementations own trigger policy, retention, and summarization, and may consume a separate measurement service. A successful run replaces the selected surface span with one summary node and prevents concurrent compaction of the same session. Load one implementation per context as ctx.compact.

abstract compactIfNeeded( agent: CompactAgentContext, fullSystemPrompt: string, sessionPrefix: readonly Message[], signal: AbortSignal, ): Promise<CompactionResult | null>
abstract compactRegion( start: number, end: number, agent: CompactAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>

Types: Message

Source: packages/compact/compact/src/index.ts:38

ctx.fsFileSystem (abstract seam)

Abstract filesystem provider. Targets must preserve identity across aliases; reads expose regular UTF-8 text or typed errors, listings are stable and content-free, and mutations are atomic. Optional guards add stale protection without changing the unguarded provider contract.

abstract resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise<FsTarget>
abstract stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined>
abstract lstat(path: string, opts?: { cwd?: string }, signal?: AbortSignal): Promise<FsPathInfo | undefined>
abstract readText(target: FsTarget, signal?: AbortSignal): Promise<string>
abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>>
abstract listDir(target: FsTarget, signal?: AbortSignal): Promise<FsDirEntry[]>
abstract writeText(target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome>
abstract editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome>

Types: FsEditOutcome · FsEditRequest · FsInfo · FsTarget · FsVersion · FsWriteIntent · FsWriteOutcome

Source: packages/fs/fs/src/index.ts:80

ctx.llmLlmService

The abstract llm service: an adapter registry plus a streaming model-call surface, interceptable via the llm/stream waterfall.

registerAdapter(providers: string[], adapter: LlmAdapter): () => void
listProviders(): LlmProviderInfo[]
async listModels(provider: string): Promise<LlmModelInfo[]>
stream(options: GenerateOptions): AsyncIterable<StreamChunk>

Types: GenerateOptions · StreamChunk

Source: packages/llm/llm/src/index.ts:96

ctx.permissionPermissionService

Owns the deployment's permission presets and their write path. Requires a confining ctx.bash executor and ctx.approval; unmatched knob values are reported as CUSTOM_PRESET, not an error.

current(events: readonly SessionEvent[]): string
resolve(name: string): PresetSpec
optionOf(name: string): PresetOption
set(session: Session, name: string): void

Types: SessionEvent

Source: packages/ui/permission/src/index.ts:94

ctx.sandboxSandboxProvider (abstract seam)

Abstract process-sandbox service. confine must return enforcing argv or fail closed at wrap or runner-execution time; silent unconfined passthrough is forbidden. Functional probes arbitrate multi-runner chains and may be skipped for a sole candidate, whose own refusal remains the fail-closed end.

abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv

Types: ConfinedArgv · SandboxPolicy

Source: packages/sandbox/sandbox/src/index.ts:111

ctx.sessionPersistenceSessionPersistence (abstract seam)

Durable append-only session storage. Implementations preserve contiguous, losslessly JSON-serializable events; append resolves only after durability, and load balances a complete interrupted tail without rewriting committed events.

abstract locate(meta: SessionHeader): SessionLocation | undefined
abstract create(meta: SessionHeader): Promise<void>
abstract append(id: SessionId, events: readonly SessionEvent[]): Promise<void>
abstract load(id: SessionId): Promise<{ meta: SessionHeader; events: SessionEvent[] }>
abstract list(): Promise<SessionHeader[]>

Types: SessionEvent

Source: packages/session-persistence/session-persistence/src/index.ts:42

ctx.sessionQuerySessionQueryService

Live-preferred logical-corpus exact-read and relationship-tracing service.

listSessions(): Promise<SessionRecord[]>
async listEvents(sessionId: SessionId): Promise<SessionEventRecord[]>
async traceSession(sessionId: SessionId): Promise<SessionLineageTrace>
async traceEvent(request: SessionEventTraceRequest): Promise<SessionEventTrace>
async readEvent(request: SessionEventReadRequest): Promise<SessionEventWindow>

Source: packages/session-query/session-query/src/index.ts:38

ctx.sessionsSessionStore

In-memory session store (ctx.sessions).

Persistence is intentionally not implemented here — persistence plugins subscribe to session/event and flush on session/flush / dispose.

create(id?: SessionId, options?: CreateSessionOptions): Session
prepare(id?: SessionId, options?: CreateSessionOptions): Session
enter(session: Session): () => void
announce(session: Session): void
async flush(session: Session): Promise<void>
get(id: SessionId): Session | undefined
list(): Session[]
fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session

Source: packages/core/session/src/index.ts:585

ctx.skillsSkillService

Registry of skill providers. It merges provider catalogs with stable first-wins duplicate handling, exposes sorted model-visible summaries, and loads full skill bodies on demand.

registerProvider(provider: SkillProvider): () => void
register(skill: SkillRegistration): () => void
async list(options: SkillLookupOptions = {}): Promise<SkillSummary[]>
async get(name: string, options: SkillLookupOptions = {}): Promise<SkillDefinition | undefined>

Source: packages/skill/skill/src/index.ts:141

ctx.spillStoreSpillStore (abstract seam)

Abstract spill storage service. Subclass, implement saveText, and load the subclass as a plugin — it registers as ctx.spillStore (one implementation per context; loading a second throws, cordis' standard duplicate-service behavior).

Semantics every implementation must honor:

  • saveText persists the FULL content verbatim and returns an opaque locator, exact byte length, and model-facing retrieval guidance.
  • Storage is scoped by the request's SaveTextSpill.owner session; the backend chooses a private (not world-readable) location and a collision-free name derived from — never equal to — the caller's suggestedName.
  • saveText REJECTS on a real storage failure (permissions, ENOSPC, backend unavailable); the caller decides how to degrade (the spill policy treats a rejection as best-effort and keeps the inline result).
abstract saveText(input: SaveTextSpill): Promise<SpillRef>

Source: packages/spill/spill/src/index.ts:45

ctx.subagentsSubagentService

Named provider registry and capability-checked start surface.

registerProvider(provider: SubagentProvider): () => void
getProvider(name: string): SubagentProvider | undefined
list(): string[]
async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>

Source: packages/subagent/subagent/src/index.ts:153

ctx.systemPromptSystemPrompt

Registry service for the prompt inputs assembled before each model step.

section(section: PromptSection): () => void
tools(provider: (context: AssembleContext) => ToolProviderResult): () => void
variable(name: string, provider: (context: AssembleContext) => string | undefined): () => void
async assemble(context: AssembleContext = {}): Promise<PromptAssembly>

Source: packages/core/system-prompt/src/index.ts:209

ctx.tasksTaskService

The tasks service: the runtime-global background task registry. See the module doc for the ownership, isolation, and lifecycle contracts.

start(spec: TaskStart): TaskId
list(caller?: Agent): TaskSnapshot[]
get(id: TaskId, caller?: Agent): TaskSnapshot
read(id: TaskId, caller?: Agent): TaskRead
kill(id: TaskId, caller?: Agent, reason?: string): 'requested' | 'already-finished'
async wait(id: TaskId, timeoutMs: number, caller?: Agent, signal?: AbortSignal): Promise<TaskSnapshot>
onTaskDone(listener: TaskDoneListener): () => void
attachSurface(name: string): () => void

Types: Agent

Source: packages/tasks/tasks/src/index.ts:76

ctx.tokenMeterTokenMeterService

Replay owner for one service-wide estimator and isolated per-session folds.

measure(session: Session, requestHeader?: EpochHeader): TokenMeasurement
estimateMessage(message: Message): number

Types: Message

Source: packages/llm/token-meter/src/index.ts:106

ctx.toolsToolRegistry

Tool registry and execution pipeline. Scoped registrations shadow globals; one visibility resolver feeds presentation, lookup, and dispatch.

register(definition: ToolDefinition): () => void
restrict(filter: ToolRestriction): () => void
guard(guard: ToolGuard): () => void
get(name: string, scope?: ScopeKey): ToolDefinition | undefined
schemas(scope?: ScopeKey): ToolSchema[]
executionMode(exec: ToolExecutionInput): ToolExecutionMode
async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>

Types: ToolDefinition · ToolExecutionInput · ToolExecutionMode · ToolExecutionResult

Source: packages/core/tools/src/index.ts:438

ctx.userInteractionUserInteractionService

ctx.userInteraction: one active UI provider plus an ask() surface.

registerProvider(provider: UserInteractionProvider): () => void
async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>

Source: packages/ui/user-interaction/src/index.ts:82

ctx.webWebService

The web access service. Registered as ctx.web (one instance per context).

Selection semantics (resolved at execution time, never order-dependent):

  • A configured id that is registered and available() → that provider.
  • A configured id not registered → WEB_PROVIDER_CONFIGURED_MISSING.
  • A configured id registered but unavailable → WEB_PROVIDER_CONFIGURED_UNAVAILABLE.
  • No id configured, exactly one registered usable provider → that provider.
  • No id configured, multiple usable providers → WEB_PROVIDER_AMBIGUOUS.
  • No id configured, no usable provider → WEB_PROVIDER_UNAVAILABLE.
registerSearchProvider(provider: WebSearchProvider): () => void
registerFetchProvider(provider: WebFetchProvider): () => void
async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>
async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>

Source: packages/web/web/src/index.ts:74

ctx.workflowsWorkflowService (abstract seam)

Workflow execution seam. Invalid requests throw before publication; a live run is holder-owned, its result never rejects, cancellation and disposal are bounded, and disposal waits for child cleanup within that bound. Lifecycle listener failures are contained, and workflow/end fires exactly once as the result settles.

abstract start(request: WorkflowStartRequest): WorkflowRun

Source: packages/workflow/workflow/src/index.ts:159

Inherited ctx members (cordis core + loader/hmr/timer)

The framework ctx surface every plugin also sees, beyond the harness services above. This is pinned vendor source (vendoring policy); it is summarized here so the page is a complete picture of what ctx offers, without elevating framework internals to the harness tier's prominence.