docs: align one-shot demo prose
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# @deepseek-ai/dsh-cli-demo
|
||||
|
||||
Headless one-shot app and bin for running one agent task without a readline or editor client. The app composes [`@deepseek-ai/dsh-agent-spine-demo`](../agent-spine-demo/README.md), JSONL persistence, and one fresh `main` agent; the bin submits one task, waits through all model and tool steps, emits the selected result, disposes to quiescence, and exits.
|
||||
Headless one-shot app and bin for running one agent task without a readline or editor client. It composes [`@deepseek-ai/dsh-agent-spine-demo`](../agent-spine-demo/README.md), JSONL persistence, and exactly one fresh top-level agent. The bin submits the task, waits for its durable turn ending, renders the selected output, disposes to quiescence, and exits.
|
||||
|
||||
The package mounts no console logger, readline UI, user-interaction service, or `ask_user_question` tool. Stdout is reserved for the selected output format; diagnostics use stderr.
|
||||
|
||||
@@ -8,8 +8,8 @@ The package mounts no console logger, readline UI, user-interaction service, or
|
||||
|
||||
| Key | Default | Routed to |
|
||||
|---|---|---|
|
||||
| `provider` | required | the pre-created `main` agent's provider route |
|
||||
| `model` | required | the pre-created `main` agent's model |
|
||||
| `provider` | required | the configured agent's provider route |
|
||||
| `model` | required | the configured agent's model |
|
||||
| `persona` | — | the deployment persona in `dsh-system-prompt` |
|
||||
| `toolOrder` | lexicographic | explicit model-facing tool order in `dsh-system-prompt` |
|
||||
| `tools` | `{ mode: 'native' }` | tool-registry presentation config through `dsh-agent-spine-demo` |
|
||||
@@ -17,8 +17,6 @@ The package mounts no console logger, readline UI, user-interaction service, or
|
||||
| `persistenceRoot` | `./.sessions` | JSONL session root |
|
||||
| `workspaceContext` | required | workspace-instruction byte budget, or `false` to disable loading |
|
||||
|
||||
Each process creates a new session whose workspace cwd is the launch directory. The app has no resume setting.
|
||||
|
||||
## CLI contract
|
||||
|
||||
```sh
|
||||
@@ -39,7 +37,7 @@ Loader configs with bare package specifiers require `node --expose-internals` or
|
||||
|
||||
- `text` writes the last assistant message containing text, followed by one newline.
|
||||
- `json` writes one DSH-native result record: `{ type: "result", success, sessionId, turn, result, reason, usage? }`. `usage` sums every model step in the task turn.
|
||||
- `stream-json` writes each canonical event from the `main` session's task turn as `{ type: "session_event", sessionId, event }`, then the same result record. Child-agent activity appears only through the parent tool events and results.
|
||||
- `stream-json` writes each canonical event from the top-level session's task turn as `{ type: "session_event", sessionId, event }`, then the same result record. Child-agent activity appears only through the parent tool events and results.
|
||||
|
||||
Only `reason.kind === "completed"` exits successfully. Other durable turn endings still emit partial text or a result record, add a stderr diagnostic, and exit nonzero. Argument and boot failures leave stdout empty. SIGINT and SIGTERM cancel active work, await disposal, and exit 130 and 143 respectively.
|
||||
|
||||
@@ -53,12 +51,12 @@ The headless-agent leaf supplies local bash, filesystem, skill, subagent, workfl
|
||||
|
||||
### One-shot task turn
|
||||
|
||||
**What the model sees**: The positional task becomes one user message. Through `dsh-agent-spine-demo`, the `main` agent also receives configured workspace instructions and persona, the skill catalog, visible tool schemas, and retained tool results needed for later steps in the same turn.
|
||||
**What the model sees**: The positional task becomes one user message. Through `dsh-agent-spine-demo`, the top-level agent also receives configured workspace instructions and persona, the skill catalog, visible tool schemas, and retained tool results needed for later steps in the same turn.
|
||||
|
||||
**Token effect**: The task, prompt sections, tool schemas, assistant output, and tool results consume tokens on each model step. JSON event streaming and final rendering add no model tokens; delegated child work has its own model usage and is not included in the parent result's `usage` total.
|
||||
|
||||
## Known Limitations and Deferred Work
|
||||
|
||||
- **One fresh main session per process** — there is no resume, second prompt, stdin context, or concurrent top-level session in this app.
|
||||
- **One fresh top-level session per process** — its workspace cwd is the launch directory; there is no resume, second prompt, stdin context, or concurrent top-level session in this app.
|
||||
- **No interactive question or approval provider** — tools that require a human answer cannot complete unless a different leaf composes a non-interactive provider with explicit policy.
|
||||
- **Streaming is main-session-only** — child sessions are not flattened into the stream, and aggregate usage covers only model steps recorded on the parent task turn.
|
||||
- **Streaming is top-level-session-only** — child sessions are not flattened into the stream, and aggregate usage covers only model steps recorded on the parent task turn.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Covered command parser and one-turn driver for `dsh-cli-demo`. The executable
|
||||
* entry only installs process signal handlers and delegates here.
|
||||
* Command parser and one-turn driver for `dsh-cli-demo`. The executable wrapper
|
||||
* owns process signals; this module owns output, durability, and cleanup.
|
||||
* @module @deepseek-ai/dsh-cli-demo/cli
|
||||
*/
|
||||
|
||||
@@ -44,9 +44,9 @@ export interface CliResult {
|
||||
export interface OneShotOptions {
|
||||
/** Exactly one nonblank user task. */
|
||||
readonly task: string
|
||||
/** Optional cancellation signal owned by the process wrapper. */
|
||||
/** Optional signal that cancels the selected agent. */
|
||||
readonly signal?: AbortSignal
|
||||
/** Synchronous observer for each canonical event in the selected task turn. */
|
||||
/** Synchronous task-turn observer; a throw cancels the agent and fails the run after flush. */
|
||||
readonly onEvent?: (sessionId: string, event: SessionEvent) => void
|
||||
}
|
||||
|
||||
@@ -91,12 +91,10 @@ class CliInterruptedError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert an unknown thrown value to an Error without losing its text. */
|
||||
function toError(error: unknown): Error {
|
||||
return error instanceof Error ? error : new Error(String(error))
|
||||
}
|
||||
|
||||
/** Render the reason carried by an AbortSignal. */
|
||||
function interruptionReason(signal: AbortSignal): string {
|
||||
return signal.reason === undefined ? 'interrupted' : String(signal.reason)
|
||||
}
|
||||
@@ -145,7 +143,6 @@ export function parseCliArgs(args: readonly string[]): CliCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/** Add one model step's usage into a detached turn total. */
|
||||
function addUsage(total: TokenUsage | undefined, step: TokenUsage): TokenUsage {
|
||||
const next: TokenUsage = {
|
||||
inputTokens: (total?.inputTokens ?? 0) + step.inputTokens,
|
||||
@@ -157,7 +154,6 @@ function addUsage(total: TokenUsage | undefined, step: TokenUsage): TokenUsage {
|
||||
return next
|
||||
}
|
||||
|
||||
/** Select the text blocks from an assistant message, or undefined when it has none. */
|
||||
function assistantText(event: Extract<SessionEvent, { type: 'assistant/message' }>): string | undefined {
|
||||
const blocks = event.data.content.filter(block => block.type === 'text')
|
||||
return blocks.length === 0 ? undefined : blocks.map(block => block.text).join('')
|
||||
@@ -189,8 +185,11 @@ async function waitForStartupIdle(agent: Agent, signal?: AbortSignal): Promise<v
|
||||
* Run one message-triggered turn on the configured top-level agent, aggregate its
|
||||
* final text and model usage, wait for idle plus an explicit persistence flush,
|
||||
* and return its durable ending. Only the selected agent's task turn reaches
|
||||
* `onEvent`; startup injections and unrelated sessions are ignored.
|
||||
* @param ctx - settled Loader root containing `ctx.agents` and `ctx.sessions`.
|
||||
* `onEvent`; startup injections and unrelated sessions are ignored. The context
|
||||
* must contain exactly one top-level agent. Signal abort cancels that agent; an
|
||||
* abort before the correlated task turn rejects. An observer throw cancels the
|
||||
* turn and is rethrown after the agent reaches idle and the session flushes.
|
||||
* @param ctx - settled Loader root containing one agent plus `ctx.sessions`.
|
||||
* @param options - task, optional cancellation, and optional stream observer.
|
||||
* @returns the DSH-native result envelope after durable quiescence.
|
||||
*/
|
||||
@@ -291,7 +290,6 @@ export async function runOneShot(ctx: Context, options: OneShotOptions): Promise
|
||||
}
|
||||
}
|
||||
|
||||
/** Render one final result in the selected output encoding. */
|
||||
function renderResult(outputFormat: OutputFormat, result: CliResult): string {
|
||||
return outputFormat === 'text' ? `${result.result}\n` : `${JSON.stringify(result)}\n`
|
||||
}
|
||||
@@ -315,9 +313,8 @@ export function formatTurnFailure(reason: TurnEndReason): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse, boot, run, render, diagnose, and dispose one CLI invocation. Argument
|
||||
* and boot failures never write stdout; all booted contexts are disposed before
|
||||
* this promise resolves.
|
||||
* Execute one CLI invocation. Argument and boot failures never write stdout;
|
||||
* every booted context is disposed before this promise resolves.
|
||||
* @param args - arguments after the executable name.
|
||||
* @param runtime - optional injected process boundaries for tests and embedding.
|
||||
* @returns the ordinary process exit code; the thin bin overrides it for Unix signals.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Headless one-shot app composition: the default agent spine, JSONL session
|
||||
* persistence, and one pre-created `main` agent. The CLI driver owns task
|
||||
* persistence, and one fresh top-level agent. The CLI driver owns task
|
||||
* submission and output; the app deliberately mounts no interactive or logging
|
||||
* front door so stdout remains protocol-pure.
|
||||
* @module @deepseek-ai/dsh-cli-demo
|
||||
@@ -18,11 +18,11 @@ const DEFAULT_PERSISTENCE_ROOT = './.sessions'
|
||||
|
||||
export const name = 'cli-demo'
|
||||
|
||||
/** App config forwarded to the spine, pre-created agent, and JSONL backend. */
|
||||
/** App config forwarded to the spine, configured agent, and JSONL backend. */
|
||||
export interface Config {
|
||||
/** Provider route for the `main` agent. */
|
||||
/** Provider route for the configured agent. */
|
||||
provider: string
|
||||
/** Model name for the `main` agent; a matching adapter must be registered. */
|
||||
/** Model name for the configured agent; a matching adapter must be registered. */
|
||||
model: string
|
||||
/** Deployment persona forwarded to the system-prompt plugin. */
|
||||
persona?: string
|
||||
@@ -51,7 +51,7 @@ export const Config: z<Config> = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Compose the UI-less spine, a fresh `main` agent rooted at the process cwd,
|
||||
* Compose the UI-less spine, a fresh top-level agent rooted at the process cwd,
|
||||
* and JSONL persistence. Swappable adapters, executors, and product tools stay
|
||||
* in the leaf `cordis.yml`.
|
||||
* @param ctx - app context that owns the composed child plugins.
|
||||
|
||||
Reference in New Issue
Block a user