Merge remote-tracking branch 'origin/master' into codex/system-prompt-snapshots
# Conflicts: # examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/text-turn/session.jsonl # packages/support/acp-snapshot/src/suite.ts
This commit is contained in:
@@ -37,4 +37,4 @@ This example is the home of the harness's **snapshot tests** — they boot this
|
||||
|
||||
## MVP limitations
|
||||
|
||||
The bridge supports N concurrent sessions per connection, each in its own workspace `cwd` (RFC 011). Remaining limits: prompts support ACP's baseline `text` and `resource_link` blocks only, `additionalDirectories` and `mcpServers` are rejected, and the tool-permission gate is deferred (`TODO(rfc010-permission-gate)` — tools run with the executor's full authority). See `packages/ui/acp/README.md` for the full contract.
|
||||
The bridge supports N concurrent sessions per connection, each in its own workspace `cwd` (RFC 011). Remaining limits: prompts support ACP's baseline `text` and `resource_link` blocks only, and `additionalDirectories` and `mcpServers` are rejected. Permission prompts (`session/request_permission`) are wired through the approval seam, but this example composes no ask-producing policy, so tools run with the executor's full authority. See `packages/ui/acp/README.md` for the full contract.
|
||||
|
||||
@@ -63,7 +63,16 @@ function spawnAcpAgent(cwd: string, env: NodeJS.ProcessEnv = process.env): Spawn
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
['--import', tsxLoader, binScript, configPath],
|
||||
{ cwd, env: { ...env, TSX_TSCONFIG_PATH: repoTsconfig }, stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
{
|
||||
cwd,
|
||||
env: {
|
||||
...env,
|
||||
TSX_TSCONFIG_PATH: repoTsconfig,
|
||||
DSH_HOME: join(cwd, '.dsh'),
|
||||
DSH_AGENTS_HOME: join(cwd, '.agents'),
|
||||
},
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
},
|
||||
)
|
||||
const stderr: string[] = []
|
||||
child.stderr.setEncoding('utf8')
|
||||
@@ -80,8 +89,9 @@ function spawnAcpAgent(cwd: string, env: NodeJS.ProcessEnv = process.env): Spawn
|
||||
return Promise.resolve()
|
||||
},
|
||||
requestPermission(_params: RequestPermissionRequest): Promise<RequestPermissionResponse> {
|
||||
// Permission gate is deferred (TODO(rfc010-permission-gate)); the bridge
|
||||
// never requests permission yet, so just allow if it ever does.
|
||||
// This example composes no ask-producing policy (no hooks), so the
|
||||
// bridge never prompts here; answer cancelled (fail closed) if it ever
|
||||
// does — an unexpected prompt must not grant anything.
|
||||
return Promise.resolve({ outcome: { outcome: 'cancelled' } })
|
||||
},
|
||||
})
|
||||
@@ -150,7 +160,13 @@ describe('acp-agent over real stdio (no key required)', () => {
|
||||
// which this purity test never triggers). So this runs WITHOUT real creds.
|
||||
const child = spawn(process.execPath, ['--import', tsxLoader, binScript, configPath], {
|
||||
cwd: workdir,
|
||||
env: { ...process.env, DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY ?? 'sk-dummy-for-boot', TSX_TSCONFIG_PATH: repoTsconfig },
|
||||
env: {
|
||||
...process.env,
|
||||
DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY ?? 'sk-dummy-for-boot',
|
||||
TSX_TSCONFIG_PATH: repoTsconfig,
|
||||
DSH_HOME: join(workdir, '.dsh'),
|
||||
DSH_AGENTS_HOME: join(workdir, '.agents'),
|
||||
},
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
})
|
||||
const out: string[] = []
|
||||
|
||||
@@ -51,6 +51,7 @@ const SCENARIOS: Scenario[] = [
|
||||
{ name: 'tool-call-turn', hasModelTurn: true, recorded: true },
|
||||
{ name: 'fs-terminal-card', hasModelTurn: true, recorded: true },
|
||||
{ name: 'todo-plan', hasModelTurn: true, recorded: true },
|
||||
{ name: 'skill-load', hasModelTurn: true, recorded: false, pinsHeader: true, headerClass: 'skill' },
|
||||
{ name: 'workspace-edit', hasModelTurn: true, recorded: true },
|
||||
{ name: 'fs-read', hasModelTurn: true, recorded: true },
|
||||
{ name: 'fs-write', hasModelTurn: true, recorded: true },
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,7 +28,7 @@ The available tools:
|
||||
|
||||
```ts
|
||||
declare const tools: {
|
||||
/** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; poll it with `bash_output` and stop it with `bash_kill`. */
|
||||
/** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way (a background task reports the same marker via bash_output once it has finished). Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; poll it with `bash_output` and stop it with `bash_kill`. */
|
||||
bash(args: {
|
||||
/** The bash command to execute. */
|
||||
command: string;
|
||||
@@ -71,6 +71,11 @@ declare const tools: {
|
||||
/** Maximum number of lines to return. Defaults to 2000. */
|
||||
limit?: number;
|
||||
}): Promise<string>;
|
||||
/** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */
|
||||
skill(args: {
|
||||
/** The exact skill name from the available skills list. */
|
||||
name: string;
|
||||
}): Promise<string>;
|
||||
/** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. */
|
||||
subagent(args: {
|
||||
/** A short (3-5 word) description of the delegated task, for display. */
|
||||
|
||||
@@ -28,7 +28,7 @@ The available tools:
|
||||
|
||||
```ts
|
||||
declare const tools: {
|
||||
/** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; poll it with `bash_output` and stop it with `bash_kill`. */
|
||||
/** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way (a background task reports the same marker via bash_output once it has finished). Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; poll it with `bash_output` and stop it with `bash_kill`. */
|
||||
bash(args: {
|
||||
/** The bash command to execute. */
|
||||
command: string;
|
||||
@@ -71,6 +71,11 @@ declare const tools: {
|
||||
/** Maximum number of lines to return. Defaults to 2000. */
|
||||
limit?: number;
|
||||
}): Promise<string>;
|
||||
/** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */
|
||||
skill(args: {
|
||||
/** The exact skill name from the available skills list. */
|
||||
name: string;
|
||||
}): Promise<string>;
|
||||
/** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. */
|
||||
subagent(args: {
|
||||
/** A short (3-5 word) description of the delegated task, for display. */
|
||||
|
||||
7
examples/acp-agent/tests/snapshots/skill-load/input.json
Normal file
7
examples/acp-agent/tests/snapshots/skill-load/input.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"steps": [
|
||||
{ "op": "initialize" },
|
||||
{ "op": "newSession" },
|
||||
{ "op": "prompt", "text": "Load the snapshot-skill skill with the skill tool, then reply DONE." }
|
||||
]
|
||||
}
|
||||
29
examples/acp-agent/tests/snapshots/skill-load/session.jsonl
Normal file
29
examples/acp-agent/tests/snapshots/skill-load/session.jsonl
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":1,"agentInfo":{"name":"deepseek-harness-acp","version":"0.0.1"},"agentCapabilities":{"loadSession":true,"promptCapabilities":{"image":false,"audio":false,"embeddedContext":false}},"authMethods":[]}}
|
||||
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"{{sessionId}}"}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Load the requested skill."}}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_skill_load","title":"Load skill snapshot-skill","kind":"read","status":"in_progress","rawInput":"snapshot-skill"}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_skill_load","status":"completed","content":[{"type":"content","content":{"type":"text","text":"<skill_content name=\"snapshot-skill\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/.dsh/skills/snapshot-skill\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\nFollow these snapshot-only instructions.\nResolve referenced resources relative to this skill directory.\n</skill_instructions>\n</skill_content>"}}]}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The skill is loaded."}}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"DONE"}}}}
|
||||
{"jsonrpc":"2.0","id":3,"result":{"stopReason":"end_turn"}}
|
||||
@@ -0,0 +1,16 @@
|
||||
You are an AI agent powered by the DeepSeek Harness SDK.
|
||||
|
||||
You are a coding assistant powered by the deepseek-v4-flash model. Your working directory is {{cwd}}.
|
||||
|
||||
Verify your work by running the code or tests. Keep answers brief and factual.
|
||||
|
||||
|
||||
Use the read tool — not shell commands like cat — to inspect text files. Results include line numbers. Use offset and limit to continue reading large files.
|
||||
|
||||
Use the write tool to create files or completely replace file contents. Existing files are overwritten, so read an existing file first (the default fs-policy requires it) and prefer edit for targeted changes.
|
||||
|
||||
Use the edit tool for targeted changes to existing UTF-8 text files. It replaces literal old_string with new_string; by default old_string must appear exactly once. If old_string appears multiple times, provide a more specific old_string or set replace_all to true. Read the file first (the default fs-policy requires it), unless you just created or edited it in this session.
|
||||
|
||||
Check the [exit code: N] marker on every bash result; investigate failures before moving on.
|
||||
|
||||
Use the workflow tool ONLY when the user explicitly asks for a workflow or for large multi-agent orchestration: you write a JavaScript script (the tool description documents the exact format) that fans work out across many subagents with phases and structured results. For one or two delegations, prefer plain subagent calls.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: snapshot-skill
|
||||
description: Exercise project skill discovery and loading in snapshot tests.
|
||||
---
|
||||
|
||||
Follow these snapshot-only instructions.
|
||||
Resolve referenced resources relative to this skill directory.
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user