feat: add economy/maximum presets, tool-lab and subagent-cursor extensions
Some checks failed
CI / windows node 24 / wine blocking (push) Has been skipped
CI / node 22.19 (push) Has been skipped
CI / node 26 (push) Has been skipped
CI / python 3.10 / keyless SDK (push) Has been skipped
CI / python runtime / release-shaped Linux x64 (push) Has been skipped
CI / wine apt cache (push) Successful in 7s
CI / serial / linux (push) Has been skipped
Deploy documentation / build (push) Failing after 1m25s
Deploy documentation / deploy (push) Has been skipped
Landlock Run / Matrix (push) Successful in 5s
Release (vendor) / Pack npm tarballs (push) Failing after 2m47s
Release (dsh) / Pack npm tarballs (push) Failing after 1m56s
Sandbox / sandbox e2e (landlock, ubuntu-24.04) (push) Failing after 1m57s
Sandbox / sandbox e2e (bwrap, ubuntu-latest) (push) Failing after 1m19s
Release (vendor) / Publish to npm (push) Has been skipped
Release (dsh) / Publish to npm (push) Has been skipped
CI / serial / windows (self-hosted standby) (push) Has been cancelled
CI / larger-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, typecheck) (push) Has been cancelled
Landlock Run / darwin (no platform package — degradation proof) (push) Has been cancelled
Landlock Run / ${{ matrix.platform }} (push) Has been cancelled
CI / node 24 / static (push) Has been cancelled
CI / node 24 / coverage (push) Has been cancelled
CI / node 24 / snapshots and artifacts (push) Has been cancelled
CI / windows node 24 / native complete (push) Has been cancelled
CI / serial / linux (self-hosted standby) (push) Has been cancelled
CI / serial / macos (push) Has been cancelled
CI / larger-runner-benchmark (16, windows, dsh-windows-2025-16core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (32, windows, dsh-windows-2025-32core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (4, windows, dsh-windows-2025-4core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (64, windows, dsh-windows-2025-64core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (8, windows, dsh-windows-2025-8core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (96, windows, dsh-windows-2025-96core, production-site) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, 16) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, windows, dsh-windows-2025-16core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, windows, dsh-windows-2025-32core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, 4) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, windows, dsh-windows-2025-4core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, windows, dsh-windows-2025-64core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, 8) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, windows, dsh-windows-2025-8core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, windows, dsh-windows-2025-96core, 2) (push) Has been cancelled
CI / all checks passed (push) Has been cancelled
Sandbox / sandbox e2e (seatbelt, macos-latest) (push) Has been cancelled
CI / larger-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, typecheck) (push) Has been cancelled
Sandbox / sandbox e2e (landlock, ubuntu-24.04-arm) (push) Has been cancelled
E2E (real DeepSeek API) / e2e (push) Failing after 1m24s
Some checks failed
CI / windows node 24 / wine blocking (push) Has been skipped
CI / node 22.19 (push) Has been skipped
CI / node 26 (push) Has been skipped
CI / python 3.10 / keyless SDK (push) Has been skipped
CI / python runtime / release-shaped Linux x64 (push) Has been skipped
CI / wine apt cache (push) Successful in 7s
CI / serial / linux (push) Has been skipped
Deploy documentation / build (push) Failing after 1m25s
Deploy documentation / deploy (push) Has been skipped
Landlock Run / Matrix (push) Successful in 5s
Release (vendor) / Pack npm tarballs (push) Failing after 2m47s
Release (dsh) / Pack npm tarballs (push) Failing after 1m56s
Sandbox / sandbox e2e (landlock, ubuntu-24.04) (push) Failing after 1m57s
Sandbox / sandbox e2e (bwrap, ubuntu-latest) (push) Failing after 1m19s
Release (vendor) / Publish to npm (push) Has been skipped
Release (dsh) / Publish to npm (push) Has been skipped
CI / serial / windows (self-hosted standby) (push) Has been cancelled
CI / larger-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, typecheck) (push) Has been cancelled
Landlock Run / darwin (no platform package — degradation proof) (push) Has been cancelled
Landlock Run / ${{ matrix.platform }} (push) Has been cancelled
CI / node 24 / static (push) Has been cancelled
CI / node 24 / coverage (push) Has been cancelled
CI / node 24 / snapshots and artifacts (push) Has been cancelled
CI / windows node 24 / native complete (push) Has been cancelled
CI / serial / linux (self-hosted standby) (push) Has been cancelled
CI / serial / macos (push) Has been cancelled
CI / larger-runner-benchmark (16, windows, dsh-windows-2025-16core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (32, windows, dsh-windows-2025-32core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (4, windows, dsh-windows-2025-4core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (64, windows, dsh-windows-2025-64core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (8, windows, dsh-windows-2025-8core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (96, windows, dsh-windows-2025-96core, production-site) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, 16) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, windows, dsh-windows-2025-16core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, windows, dsh-windows-2025-32core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, 4) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, windows, dsh-windows-2025-4core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, windows, dsh-windows-2025-64core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, 8) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, windows, dsh-windows-2025-8core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, windows, dsh-windows-2025-96core, 2) (push) Has been cancelled
CI / all checks passed (push) Has been cancelled
Sandbox / sandbox e2e (seatbelt, macos-latest) (push) Has been cancelled
CI / larger-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, typecheck) (push) Has been cancelled
Sandbox / sandbox e2e (landlock, ubuntu-24.04-arm) (push) Has been cancelled
E2E (real DeepSeek API) / e2e (push) Failing after 1m24s
- new economy and maximum agent presets with three-role pipeline skill - new packages/extensions/tool-lab (home-lab ComfyUI/Docling/Whishper tools) - new packages/subagent/subagent-cursor provider - openrouter balance UI with on-demand refresh - session projection context-seed boundary fold - regenerate docs catalogs; keep local searxng benchmark scripts
This commit is contained in:
@@ -198,12 +198,14 @@
|
||||
toolName: subagent_fork
|
||||
backgroundMode: continuable
|
||||
|
||||
# Production dsh does not install these optional providers. An opting-in
|
||||
# Profile mounts each provider once on the host plane; copy this preset,
|
||||
# then remove `disabled` from the matching tool row.
|
||||
# External product agents. The base host plane mounts each provider, and
|
||||
# each run needs that product's own CLI on PATH plus its own account:
|
||||
# `codex`, `claude`, and `cursor-agent`. A missing CLI fails the call it is
|
||||
# asked for rather than the composition, so a deployment without one keeps
|
||||
# an inert tool row; copy this preset and add `disabled: true` to drop it
|
||||
# from the model's roster entirely.
|
||||
- id: tool-subagent-codex
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: codex
|
||||
toolName: subagent_codex
|
||||
@@ -212,13 +214,20 @@
|
||||
|
||||
- id: tool-subagent-claude-code
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: claude-code
|
||||
toolName: subagent_claude_code
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-cursor
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: cursor
|
||||
toolName: subagent_cursor
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
|
||||
@@ -185,12 +185,14 @@
|
||||
toolName: subagent_fork
|
||||
backgroundMode: continuable
|
||||
|
||||
# Production dsh does not install these optional providers. An opting-in
|
||||
# Profile mounts each provider once on the host plane; copy this preset,
|
||||
# then remove `disabled` from the matching tool row.
|
||||
# External product agents. The base host plane mounts each provider, and
|
||||
# each run needs that product's own CLI on PATH plus its own account:
|
||||
# `codex`, `claude`, and `cursor-agent`. A missing CLI fails the call it is
|
||||
# asked for rather than the composition, so a deployment without one keeps
|
||||
# an inert tool row; copy this preset and add `disabled: true` to drop it
|
||||
# from the model's roster entirely.
|
||||
- id: tool-subagent-codex
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: codex
|
||||
toolName: subagent_codex
|
||||
@@ -199,13 +201,20 @@
|
||||
|
||||
- id: tool-subagent-claude-code
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: claude-code
|
||||
toolName: subagent_claude_code
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-cursor
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: cursor
|
||||
toolName: subagent_cursor
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
|
||||
@@ -9,7 +9,7 @@ Every capability in this harness is a plugin row in a `cordis.yml`. There is no
|
||||
|
||||
## Off-limits
|
||||
|
||||
**Never edit, delete, or overwrite a preset that ships with the deployment** — the `agent-presets` directory beside the deployment's own config, which supplies `standard`, `code`, `minimal`, and `cordis`. Never escalate the sandbox to reach it, even when a change there looks quicker. An upgrade overwrites that install, and corrupting `cordis` disables preset authoring itself. Reading a shipped composition is the intended way to start; writing to one is not, and neither is editing the host composition to work around a preset limitation.
|
||||
**Never edit, delete, or overwrite a preset that ships with the deployment** — the `agent-presets` directory beside the deployment's own config, whose ids the roster reports. Never escalate the sandbox to reach it, even when a change there looks quicker. An upgrade overwrites that install, and corrupting `cordis` disables preset authoring itself. Reading a shipped composition is the intended way to start; writing to one is not, and neither is editing the host composition to work around a preset limitation.
|
||||
|
||||
To change what a shipped preset does, copy it and edit the copy. Locally authored presets under the user root are yours to create, edit, and delete.
|
||||
|
||||
|
||||
211
apps/cli/config/agent-presets/economy/agent.cordis.yml
Normal file
211
apps/cli/config/agent-presets/economy/agent.cordis.yml
Normal file
@@ -0,0 +1,211 @@
|
||||
# The `economy` agent preset: token-efficient agent with cost-aware delegation.
|
||||
|
||||
# ── identity ────────────────────────────────────────────────────────────────
|
||||
|
||||
- id: persona
|
||||
name: '@deepseek-ai/dsh-persona'
|
||||
config:
|
||||
text: >-
|
||||
You are an economy-focused coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
||||
|
||||
TOKEN & COST EFFICIENCY PRINCIPLES (MANDATORY OPERATING RULES):
|
||||
1. Do cheap work directly in the main thread:
|
||||
- A direct read/grep/glob call is almost always cheaper and faster than a subagent, which pays its own system prompt and tool catalog. Use read/grep/glob/pwsh directly for lookups, small edits, and tasks with a small working set.
|
||||
2. Delegate only when delegation clearly saves tokens:
|
||||
- Delegate large, self-contained subtasks that would otherwise add many tool-call rounds to the main context: whole-codebase exploration, running and analyzing a test suite, drafting an isolated implementation, independent research.
|
||||
- Use `subagent` for self-contained work; use `subagent_fork` only when the child must build on this conversation.
|
||||
- Group related questions into one delegation rather than one subagent per small question.
|
||||
3. Bound the delegation cost:
|
||||
- Prefer one subagent per work item; never spawn a subagent for a lookup a main-thread tool can answer.
|
||||
- Children are leaves: a delegated child works directly with its own tools and reports back; it must not delegate further.
|
||||
- Ignore or cancel a subagent whose result no longer matters; collect only the results you need.
|
||||
4. Context protection:
|
||||
- Keep the main conversation lean: paste conclusions, not raw file dumps.
|
||||
5. Communication:
|
||||
- Keep assistant responses concise, structured, and actionable.
|
||||
|
||||
- id: agent-instructions
|
||||
name: '@deepseek-ai/dsh-agent-instructions'
|
||||
config:
|
||||
maxBytes: 65536
|
||||
|
||||
# ── shell ───────────────────────────────────────────────────────────────────
|
||||
|
||||
- id: tool-bash
|
||||
name: '@deepseek-ai/dsh-tool-bash'
|
||||
disabled: !!js process.platform === 'win32'
|
||||
|
||||
- id: tool-pwsh
|
||||
name: '@deepseek-ai/dsh-tool-pwsh'
|
||||
disabled: !!js process.platform !== 'win32'
|
||||
|
||||
# ── filesystem ──────────────────────────────────────────────────────────────
|
||||
|
||||
- id: tool-fs
|
||||
name: '@deepseek-ai/dsh-tool-fs'
|
||||
|
||||
- id: tool-fs-search
|
||||
name: '@deepseek-ai/dsh-tool-fs-search'
|
||||
config:
|
||||
sampleOverCapGlobResults: false
|
||||
|
||||
# ── background jobs ────────────────────────────────────────────────────────
|
||||
|
||||
- id: tool-jobs
|
||||
name: '@deepseek-ai/dsh-tool-jobs'
|
||||
|
||||
# ── skills ──────────────────────────────────────────────────────────────────
|
||||
|
||||
- id: skill-filesystem
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
|
||||
# ── goals ───────────────────────────────────────────────────────────────────
|
||||
|
||||
- id: tool-goal
|
||||
name: '@deepseek-ai/dsh-tool-goal'
|
||||
|
||||
# ── plan mode ───────────────────────────────────────────────────────────────
|
||||
|
||||
- id: planning
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
planMode: true
|
||||
config:
|
||||
- id: plan-mode
|
||||
name: '@deepseek-ai/dsh-plan-mode'
|
||||
config:
|
||||
section: |
|
||||
You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
||||
|
||||
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
||||
|
||||
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
||||
|
||||
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
||||
|
||||
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
||||
|
||||
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
||||
|
||||
# ── compaction ──────────────────────────────────────────────────────────────
|
||||
|
||||
- id: compaction
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
compaction: true
|
||||
toolResultPruner: true
|
||||
config:
|
||||
- id: compaction-basic
|
||||
name: '@deepseek-ai/dsh-compaction-basic'
|
||||
|
||||
- id: command-compact
|
||||
name: '@deepseek-ai/dsh-command-compact'
|
||||
|
||||
- id: tool-result-pruner
|
||||
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
||||
config:
|
||||
thresholdChars: 4096
|
||||
headChars: 2048
|
||||
tailChars: 512
|
||||
|
||||
# ── delegation and workflows ────────────────────────────────────────────────
|
||||
|
||||
- id: delegation
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
workflowEngine: true
|
||||
config:
|
||||
- id: tool-subagent-control
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control'
|
||||
|
||||
- id: tool-subagent-list-agents
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
||||
|
||||
- id: tool-subagent
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent
|
||||
backgroundMode: one-shot
|
||||
# Children are leaves: the top-level agent may delegate, a child may
|
||||
# not, so the number of spawned agents is bounded by the top-level
|
||||
# delegations instead of cascading.
|
||||
maxDepth: 1
|
||||
|
||||
- id: tool-subagent-fork
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: fork
|
||||
toolName: subagent_fork
|
||||
backgroundMode: one-shot
|
||||
maxDepth: 1
|
||||
|
||||
# An economy mode should not reach for external paid agents by default, so
|
||||
# these rows stay off even though the base host plane mounts each provider.
|
||||
# A deployment that wants them copies this preset and removes `disabled`
|
||||
# from the matching row; each run then needs that product's own CLI on PATH
|
||||
# (`codex`, `claude`, `cursor-agent`) plus its own account.
|
||||
- id: tool-subagent-codex
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: codex
|
||||
toolName: subagent_codex
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-claude-code
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: claude-code
|
||||
toolName: subagent_claude_code
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-cursor
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: cursor
|
||||
toolName: subagent_cursor
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
provider: spawn
|
||||
|
||||
- id: tool-workflow
|
||||
name: '@deepseek-ai/dsh-tool-workflow'
|
||||
|
||||
- id: tool-ralph
|
||||
name: '@deepseek-ai/dsh-tool-ralph'
|
||||
config:
|
||||
# Fresh-agent rounds are the most expensive delegation pattern: every
|
||||
# round is a new child with no conversation seed. Keep the budget tight.
|
||||
subagentProvider: spawn
|
||||
maxRounds: 8
|
||||
|
||||
# ── remaining model-facing rows ─────────────────────────────────────────────
|
||||
|
||||
- id: tool-ask-user
|
||||
name: '@deepseek-ai/dsh-tool-ask-user'
|
||||
|
||||
- id: tool-todo
|
||||
name: '@deepseek-ai/dsh-tool-todo'
|
||||
config:
|
||||
allowParallelInProgress: true
|
||||
|
||||
- id: tool-web
|
||||
name: '@deepseek-ai/dsh-tool-web'
|
||||
config:
|
||||
fetch: false
|
||||
searchTimeoutMs: 60000
|
||||
3
apps/cli/config/agent-presets/economy/preset.yml
Normal file
3
apps/cli/config/agent-presets/economy/preset.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
name: Экономный режим
|
||||
description: Оптимизированный режим для экономии токенов и затрат на API: дешёвые операции выполняются в основном контексте, делегирование субагентам — только когда оно окупается, результаты инструментов активно сжимаются.
|
||||
order: 5
|
||||
539
apps/cli/config/agent-presets/maximum/agent.cordis.yml
Normal file
539
apps/cli/config/agent-presets/maximum/agent.cordis.yml
Normal file
@@ -0,0 +1,539 @@
|
||||
# The `maximum` agent preset: every model-facing capability this deployment
|
||||
# can compose, driven by a three-role delivery pipeline.
|
||||
#
|
||||
# Two things distinguish it from `standard`. It adds the capabilities the other
|
||||
# shipped presets leave out — persistent terminals, language-server queries,
|
||||
# session history, durable time and tmux context, reminders, self-modification,
|
||||
# the extra editor, and Code Mode beside the native schemas. And it adds three
|
||||
# ROLE delegation tools over the same `spawn` backend, each carrying its own
|
||||
# child persona: `subagent_architect` writes the specification,
|
||||
# `subagent_implementer` builds it, `subagent_reviewer` verifies it. The
|
||||
# orchestrating persona below owns the order they run in; the child personas
|
||||
# own what each role must produce.
|
||||
#
|
||||
# COST: this preset is deliberately the expensive one. Every row here adds tool
|
||||
# schemas and prompt sections to every request, `mode: both` sends the native
|
||||
# catalog AND a generated Code Mode SDK, and one pipeline pass is three child
|
||||
# agents with their own contexts. Copy it and delete rows to trade capability
|
||||
# for tokens; `standard` and `economy` are the smaller shipped points.
|
||||
#
|
||||
# TRUST: `cordis_mount` evaluates model-written JavaScript against the live
|
||||
# runtime, and the external product agents below run whatever their own CLI and
|
||||
# account allow. Treat a session on this preset as shell access.
|
||||
#
|
||||
# This file is an AGENT-PLANE composition. The roster mounts it ONCE under a
|
||||
# standing scope; every session naming it joins by scope parentage, so the tools
|
||||
# and prompt sections registered here cover each joined agent while a session's
|
||||
# own state stays keyed per Session/Agent inside the plugins. The host
|
||||
# composition (`base.cordis.yml` + `web.cordis.yml`) keeps everything a preset
|
||||
# must not own: the registries themselves, the sandbox and approval stack,
|
||||
# persistence, and the model route.
|
||||
#
|
||||
# A service row here MUST sit inside a group carrying an `isolate` realm.
|
||||
# Without one it publishes into the root realm, where it is process-global —
|
||||
# another preset publishing the same name collides, and a host reader would
|
||||
# resolve one preset's instance for every session; `dsh-agent-presets` rejects
|
||||
# that at mount. `true` means an entry-local realm: this standing mount's own
|
||||
# private instance, apart from every other preset's.
|
||||
|
||||
# ── identity ────────────────────────────────────────────────────────────────
|
||||
|
||||
# The preset's own persona, shadowing the deployment default for this agent.
|
||||
# `{{model}}` and `{{cwd}}` resolve from the agent's own route and workspace.
|
||||
# It states the pipeline the three role tools below exist for; each role's own
|
||||
# instructions live on that role's tool row, not here, because a child never
|
||||
# reads this section — the delegation replaces it with the role persona.
|
||||
- id: persona
|
||||
name: '@deepseek-ai/dsh-persona'
|
||||
config:
|
||||
text: |-
|
||||
You are the lead agent of a three-role delivery pipeline, powered by the {{model}} model. Your working directory is {{cwd}}.
|
||||
|
||||
Every change to the repository passes through three delegated roles, in this order:
|
||||
|
||||
1. `subagent_architect` turns the request into a specification: the goal, the files and subsystems involved, the ordered change plan, the acceptance checks, and the risks. It reads and never writes.
|
||||
2. `subagent_implementer` receives that specification and makes the repository satisfy it, running the checks the specification names.
|
||||
3. `subagent_reviewer` receives the specification and the implementer's report, inspects the working tree itself, and returns PASS with its evidence or FAIL with a numbered defect list.
|
||||
|
||||
On FAIL, hand the defect list plus the original specification back to `subagent_implementer` and review again. Stop after the third failed review and bring the disagreement to the user rather than starting a fourth round.
|
||||
|
||||
Each role runs as a fresh agent that cannot see this conversation or the other roles' sessions. Everything a role needs goes into its prompt as complete text — paste the specification and the verdict, never "as discussed above" or a session id.
|
||||
|
||||
Skip the pipeline for work that is not a change: questions, read-only investigation, running a command the user asked for, or a fix the user dictated line by line. Use it for anything that changes behavior, and say which stage you are in as you go.
|
||||
|
||||
Do your own reading, searching, and answering. Delegate the three roles, not your judgment.
|
||||
|
||||
- id: agent-instructions
|
||||
name: '@deepseek-ai/dsh-agent-instructions'
|
||||
config:
|
||||
maxBytes: 65536
|
||||
|
||||
# ── shell ───────────────────────────────────────────────────────────────────
|
||||
|
||||
# `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
|
||||
# the criterion for host-plane ownership — injection resolves before any session
|
||||
# exists, so there is no agent to key by. Both shell tools consume the host
|
||||
# registry from here; their executors (`bash-sandbox`/`pwsh-sandbox`) are
|
||||
# host-plane too.
|
||||
- id: tool-bash
|
||||
name: '@deepseek-ai/dsh-tool-bash'
|
||||
disabled: !!js process.platform === 'win32'
|
||||
|
||||
- id: tool-pwsh
|
||||
name: '@deepseek-ai/dsh-tool-pwsh'
|
||||
disabled: !!js process.platform !== 'win32'
|
||||
|
||||
# ── persistent terminals ────────────────────────────────────────────────────
|
||||
|
||||
# The PTY registry is an agent-owned service, so it lives in an entry-local
|
||||
# realm; the backend still consumes the host sandbox policy and subprocess
|
||||
# implementation. `tool-terminal` rather than `tool-bash-persistent` is what
|
||||
# joins the one-shot shell above: the persistent-bash tool registers under the
|
||||
# name `bash`, which this preset's `tool-bash` already owns, while the six
|
||||
# `terminal_*` tools add long-lived sessions under their own names.
|
||||
#
|
||||
# The backend starts an interactive `bash`. A machine without one fails
|
||||
# `terminal_open`, not the composition, exactly like the external agents below.
|
||||
- id: persistent-terminals
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
terminals: true
|
||||
config:
|
||||
- id: pty
|
||||
name: '@deepseek-ai/dsh-terminal'
|
||||
|
||||
- id: terminal-bash
|
||||
name: '@deepseek-ai/dsh-terminal-bash'
|
||||
config:
|
||||
timeoutMs: 300000
|
||||
|
||||
- id: tool-terminal
|
||||
name: '@deepseek-ai/dsh-tool-terminal'
|
||||
config:
|
||||
enableRunInBackground: true
|
||||
maxResultBytes: 262144
|
||||
|
||||
# ── filesystem ──────────────────────────────────────────────────────────────
|
||||
|
||||
# All three register into the host `tools` registry and provide nothing, so
|
||||
# they need no realm. The `fs` service and its policy stay in the host.
|
||||
# `str_replace_editor` is the standalone view/create/replace/insert editor; it
|
||||
# overlaps `edit` deliberately, since this preset's contract is that every
|
||||
# shipped model-facing tool is present.
|
||||
- id: tool-fs
|
||||
name: '@deepseek-ai/dsh-tool-fs'
|
||||
|
||||
- id: tool-fs-search
|
||||
name: '@deepseek-ai/dsh-tool-fs-search'
|
||||
config:
|
||||
sampleOverCapGlobResults: false
|
||||
|
||||
- id: tool-str-replace-editor
|
||||
name: '@deepseek-ai/dsh-tool-str-replace-editor'
|
||||
config:
|
||||
maxOutputChars: 16000
|
||||
|
||||
# ── language servers ────────────────────────────────────────────────────────
|
||||
|
||||
# The `lsp` registry has no consumer outside an agent, so it lives in an
|
||||
# entry-local realm with the tool that reads it. Without a provider the tool
|
||||
# stays in the catalog and every query answers the structured `LSP_UNAVAILABLE`
|
||||
# error, which is why the tool row is unconditional and the provider row is not.
|
||||
#
|
||||
# `lsp-stdio` resolves every configured executable AT LOAD and fails the mount
|
||||
# when one is missing, so a shipped preset cannot enable it: the language server
|
||||
# is a machine-local install, not a deployment fact. The row below is the
|
||||
# worked example — copy this preset, drop `disabled`, and name the servers this
|
||||
# machine actually has.
|
||||
- id: language-servers
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
lsp: true
|
||||
config:
|
||||
- id: lsp
|
||||
name: '@deepseek-ai/dsh-lsp'
|
||||
|
||||
- id: lsp-stdio
|
||||
name: '@deepseek-ai/dsh-lsp-stdio'
|
||||
disabled: true
|
||||
config:
|
||||
servers:
|
||||
typescript:
|
||||
command: typescript-language-server
|
||||
args: ['--stdio']
|
||||
extensionToLanguage:
|
||||
.ts: typescript
|
||||
.tsx: typescriptreact
|
||||
.mts: typescript
|
||||
.cts: typescript
|
||||
.js: javascript
|
||||
.jsx: javascriptreact
|
||||
|
||||
- id: tool-lsp
|
||||
name: '@deepseek-ai/dsh-tool-lsp'
|
||||
|
||||
# ── background jobs ────────────────────────────────────────────────────────
|
||||
|
||||
# Only the model-facing controls. The task REGISTRY stays on the host plane:
|
||||
# its producers sit outside any realm this file could put it in — `tool-bash`
|
||||
# and `tool-terminal` above resolve it with `ctx.get`, and an entry-local realm
|
||||
# here is invisible to every sibling row, so `run_in_background` would answer
|
||||
# "background jobs unavailable" while these controls sat in the catalog. The
|
||||
# registry is keyed by owning agent anyway, so one host instance serves every
|
||||
# session.
|
||||
- id: tool-jobs
|
||||
name: '@deepseek-ai/dsh-tool-jobs'
|
||||
|
||||
# ── skills ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# The skill REGISTRY lives in the host composition and is layered per scope:
|
||||
# these rows register into THIS preset's layer of it, so they need no realm.
|
||||
# The merged catalog carries the project and user roots this provider always
|
||||
# scans, whatever the deployment registered globally, and the two custom roots
|
||||
# below.
|
||||
#
|
||||
# The first custom root is this preset's own `skills/`, which travels with it.
|
||||
# The second is the `cordis` preset's, so composition authoring is documented
|
||||
# for the `cordis_*` tools this preset also carries; a copy of this preset that
|
||||
# lands beside no `cordis` directory simply scans a missing path, which is
|
||||
# valid empty state for this provider.
|
||||
- id: skill-filesystem
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
config:
|
||||
customSkillDirs:
|
||||
- !!js "process.getBuiltinModule('node:url').fileURLToPath(new URL('skills/', baseUrl))"
|
||||
- !!js "process.getBuiltinModule('node:url').fileURLToPath(new URL('../cordis/skills/', baseUrl))"
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
|
||||
# ── goals ───────────────────────────────────────────────────────────────────
|
||||
|
||||
# Only the model-facing tool. The goal SERVICE, its session driver, and the
|
||||
# `/goal` command stay on the host plane: the Gateway serves the goal domain as
|
||||
# Remote endpoints whose receiver comes from a generated descriptor, so it
|
||||
# resolves `goals` on the host and an entry-local realm here would hide it.
|
||||
- id: tool-goal
|
||||
name: '@deepseek-ai/dsh-tool-goal'
|
||||
|
||||
# ── session history ─────────────────────────────────────────────────────────
|
||||
|
||||
# Five read-only tools over the host `sessionQuery` service, each result
|
||||
# authorized from the calling agent's own session. The shipped host mounts that
|
||||
# service with `openAt: never`, so `session_search` and `session_event_search`
|
||||
# answer `SESSION_QUERY_SEARCH_DISABLED` while the three read and trace tools
|
||||
# work; full-text search is a host decision (`openAt: first-search` in a
|
||||
# profile patch), not one a preset can make.
|
||||
- id: tool-session-query
|
||||
name: '@deepseek-ai/dsh-tool-session-query'
|
||||
|
||||
# ── durable per-step context ────────────────────────────────────────────────
|
||||
|
||||
# Both inject their snapshot at `agent/pre-step`, which is scope-filtered, so
|
||||
# they reach only agents joined to this preset. Time context lets the model
|
||||
# read relative dates in the request's own zone; tmux context names the pane
|
||||
# this process runs in, and reads as "not in tmux" everywhere else.
|
||||
- id: time-context
|
||||
name: '@deepseek-ai/dsh-time-context'
|
||||
config:
|
||||
refreshIntervalMs: 60000
|
||||
|
||||
- id: tmux-context
|
||||
name: '@deepseek-ai/dsh-tmux-context'
|
||||
config:
|
||||
refreshIntervalMs: 60000
|
||||
|
||||
# ── scheduled reminders ─────────────────────────────────────────────────────
|
||||
|
||||
# Session-scoped durable reminders (`schedule_create`/`_list`/`_delete`). The
|
||||
# plugin installs on root agents created after it loads and takes its state
|
||||
# from the session log through the host persistence barrier, so one instance
|
||||
# per preset mount serves every session that joins — `agent/created` is
|
||||
# scope-filtered, and an agent on another preset never reaches this one.
|
||||
- id: schedule
|
||||
name: '@deepseek-ai/dsh-schedule'
|
||||
|
||||
# ── plan mode ───────────────────────────────────────────────────────────────
|
||||
|
||||
# Plan state is per-agent by nature, so an entry-local realm is not a
|
||||
# workaround here — it is the correct lifetime.
|
||||
- id: planning
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
planMode: true
|
||||
config:
|
||||
- id: plan-mode
|
||||
name: '@deepseek-ai/dsh-plan-mode'
|
||||
config:
|
||||
section: |
|
||||
You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
||||
|
||||
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery. Delegation does not lift this: a delegated role may read and report, and none of them may write while plan mode is active.
|
||||
|
||||
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
||||
|
||||
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
||||
|
||||
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
||||
|
||||
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
||||
|
||||
# ── compaction ──────────────────────────────────────────────────────────────
|
||||
|
||||
# `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner
|
||||
# must share this realm rather than sit outside it.
|
||||
#
|
||||
# `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
|
||||
# plane, and the rows here resolve that one instance. It keys every fold by
|
||||
# Session and owns the context-meter projection units the browser reads for
|
||||
# every session — behind a realm those units would come and go with whichever
|
||||
# presets happen to be mounted.
|
||||
- id: compaction
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
compaction: true
|
||||
toolResultPruner: true
|
||||
config:
|
||||
- id: compaction-basic
|
||||
name: '@deepseek-ai/dsh-compaction-basic'
|
||||
|
||||
- id: command-compact
|
||||
name: '@deepseek-ai/dsh-command-compact'
|
||||
|
||||
- id: tool-result-pruner
|
||||
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
||||
config:
|
||||
thresholdChars: 8192
|
||||
headChars: 4096
|
||||
tailChars: 1024
|
||||
|
||||
# ── delegation, roles, and workflows ────────────────────────────────────────
|
||||
|
||||
# The `subagents` registry and its spawn/fork backends live in the HOST
|
||||
# composition: the registry is a process singleton whose cross-session queries
|
||||
# the api-proxy serves to the browser, and a provider name may only be
|
||||
# registered once. This preset contributes the delegation TOOLS, which resolve
|
||||
# that host registry.
|
||||
#
|
||||
# `workflows` is different — nothing outside an agent reads it — so every row
|
||||
# that reaches it shares one entry-local realm here, and a consumer left
|
||||
# outside would resolve a host registry this preset does not populate.
|
||||
- id: delegation
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
workflowEngine: true
|
||||
config:
|
||||
- id: tool-subagent-control
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control'
|
||||
|
||||
- id: tool-subagent-list-agents
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
||||
|
||||
# The unshaped delegations, kept beside the roles: `subagent` for work that
|
||||
# is not a pipeline stage, `subagent_fork` for work that needs this
|
||||
# conversation's history.
|
||||
- id: tool-subagent
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent
|
||||
backgroundMode: continuable
|
||||
|
||||
- id: tool-subagent-fork
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: fork
|
||||
toolName: subagent_fork
|
||||
backgroundMode: continuable
|
||||
|
||||
# ── the three pipeline roles ────────────────────────────────────────────
|
||||
#
|
||||
# One `spawn` instance per role, distinguished only by its `toolName` and
|
||||
# its child `persona` — the provider applies that persona as a scoped
|
||||
# section shadowing `deployment:persona`, so a role child never reads the
|
||||
# orchestrating persona at the top of this file.
|
||||
#
|
||||
# All three are `one-shot`: a stage's result is the next stage's input, so
|
||||
# the default must be the foreground call that returns it. `maxDepth: 1`
|
||||
# keeps the pipeline flat — the roles are leaves and the lead agent owns
|
||||
# sequencing, so the agent count of one pass is exactly the stages run.
|
||||
#
|
||||
# A role's restrictions are stated in its persona rather than as a
|
||||
# `toolFilter`: the filter names GLOBAL tool names and fails the start when
|
||||
# one is unknown, and the shell tool's name differs by platform, so a
|
||||
# read-only filter here would be a Windows-versus-POSIX startup failure. A
|
||||
# persona cannot enforce a restriction; deployments that need enforcement
|
||||
# copy this preset and add the filter their platform actually registers.
|
||||
- id: tool-subagent-architect
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent_architect
|
||||
backgroundMode: one-shot
|
||||
maxDepth: 1
|
||||
persona: |-
|
||||
You are the ARCHITECT of a three-role delivery pipeline. You produce one specification and nothing else. An implementer who cannot see this session receives your reply verbatim and builds from it.
|
||||
|
||||
Ground the specification in the repository as it actually is. Read the files the change touches, the tests around them, and the existing patterns it must follow; prefer an existing function, module, or convention over new machinery. Resolve by inspection anything you could otherwise guess at.
|
||||
|
||||
Change nothing. No edits, no writes, no commits, no formatters, no code generation, no dependency installs. Running read-only commands and tests to learn how the code behaves today is expected.
|
||||
|
||||
Reply with exactly these sections:
|
||||
|
||||
GOAL — one paragraph: what will be true when this is done, and what is explicitly out of scope.
|
||||
CONTEXT — the files, symbols, and patterns the change must fit, each with a path, and what each one contributes.
|
||||
PLAN — ordered steps, each naming the file it changes and the change it makes, in enough detail that the implementer makes no design decisions.
|
||||
ACCEPTANCE — the checks that decide done: exact commands to run, and the observable behavior to confirm.
|
||||
RISKS — what could break elsewhere, the edge cases to cover, and every assumption you could not verify.
|
||||
|
||||
When the request is ambiguous in a way that changes the design, state the interpretation you chose and why in GOAL rather than asking; you cannot see the user.
|
||||
|
||||
- id: tool-subagent-implementer
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent_implementer
|
||||
backgroundMode: one-shot
|
||||
maxDepth: 1
|
||||
persona: |-
|
||||
You are the IMPLEMENTER of a three-role delivery pipeline. You receive a specification and make the repository satisfy it. A reviewer who cannot see this session checks your work against that same specification.
|
||||
|
||||
Follow the plan you were given. Match the surrounding code: its naming, its idioms, its comment density, its error handling. Change what the specification calls for and leave the rest alone.
|
||||
|
||||
Run the checks the specification names, plus whatever narrower test covers the code you touched. A check you did not run is not a check you may report.
|
||||
|
||||
When a step is wrong or impossible, do every step that is not blocked, then say exactly what you skipped and why. Never substitute a different design in silence, and never widen the scope past the specification.
|
||||
|
||||
Reply with exactly these sections:
|
||||
|
||||
CHANGES — one line per file: the path and what changed in it.
|
||||
VERIFICATION — each command you ran and its outcome, quoting the failing output where it failed.
|
||||
DEVIATIONS — everything you did differently from the plan, or did not do, each with its reason. Write "none" when there is nothing.
|
||||
|
||||
- id: tool-subagent-reviewer
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent_reviewer
|
||||
backgroundMode: one-shot
|
||||
maxDepth: 1
|
||||
persona: |-
|
||||
You are the REVIEWER of a three-role delivery pipeline. You receive a specification and an implementer's report, and you return a verdict on the work as it exists in the repository.
|
||||
|
||||
Verify, do not trust. Read the changed files yourself, re-run the acceptance checks the specification names, and confirm each claim in the report against what you observe. An unrunnable or skipped check is a defect, not a pass.
|
||||
|
||||
Judge the implementation against the specification: unmet acceptance criteria, missed edge cases and failure modes, behavior changed outside the plan, tests that assert nothing the change could break, and anything that contradicts the conventions of the surrounding code.
|
||||
|
||||
Fix nothing. Do not edit files, do not commit, do not run formatters or code generation. Reporting the defect is your whole job.
|
||||
|
||||
Reply with exactly these sections:
|
||||
|
||||
VERDICT — the first line, either PASS or FAIL and nothing else.
|
||||
EVIDENCE — the commands you ran and the files you read, each with its outcome.
|
||||
DEFECTS — numbered, each naming the file, what the specification requires, what the code does instead, and a severity of blocking or minor. PASS requires this list to be empty; a blocking defect requires FAIL.
|
||||
|
||||
# External product agents. The base host plane mounts each provider, and
|
||||
# each run needs that product's own CLI on PATH plus its own account:
|
||||
# `codex`, `claude`, and `cursor-agent`. A missing CLI fails the call it is
|
||||
# asked for rather than the composition, so a deployment without one keeps
|
||||
# an inert tool row; copy this preset and add `disabled: true` to drop it
|
||||
# from the model's roster entirely.
|
||||
- id: tool-subagent-codex
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: codex
|
||||
toolName: subagent_codex
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-claude-code
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: claude-code
|
||||
toolName: subagent_claude_code
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-cursor
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: cursor
|
||||
toolName: subagent_cursor
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
provider: spawn
|
||||
|
||||
- id: tool-workflow
|
||||
name: '@deepseek-ai/dsh-tool-workflow'
|
||||
|
||||
- id: tool-ralph
|
||||
name: '@deepseek-ai/dsh-tool-ralph'
|
||||
config:
|
||||
subagentProvider: spawn
|
||||
maxRounds: 64
|
||||
|
||||
# ── MCP servers ─────────────────────────────────────────────────────────────
|
||||
|
||||
# One row per external MCP server, each registering its tools on the host
|
||||
# registry as `mcp__<serverName>__<rawName>`. Which servers exist is a machine
|
||||
# fact — every one names a command to spawn or a URL to reach — so this preset
|
||||
# ships the worked example disabled. Copy the preset, drop `disabled`, and add
|
||||
# one row per server.
|
||||
- id: mcp-example
|
||||
name: '@deepseek-ai/dsh-mcp-client'
|
||||
disabled: true
|
||||
config:
|
||||
serverName: example
|
||||
transport: stdio
|
||||
command: npx
|
||||
args: ['-y', '@modelcontextprotocol/server-everything']
|
||||
|
||||
# ── remaining model-facing rows ─────────────────────────────────────────────
|
||||
|
||||
- id: tool-ask-user
|
||||
name: '@deepseek-ai/dsh-tool-ask-user'
|
||||
|
||||
- id: tool-todo
|
||||
name: '@deepseek-ai/dsh-tool-todo'
|
||||
config:
|
||||
allowParallelInProgress: true
|
||||
|
||||
# The `web` service and its search provider stay in the host composition; only
|
||||
# the model-facing tool is per-session. `fetch` stays off because the shipped
|
||||
# host mounts no fetch provider: that provider defers SSRF protection and the
|
||||
# model would choose the request target.
|
||||
- id: tool-web
|
||||
name: '@deepseek-ai/dsh-tool-web'
|
||||
config:
|
||||
fetch: false
|
||||
searchTimeoutMs: 60000
|
||||
|
||||
# ── self-modification ───────────────────────────────────────────────────────
|
||||
|
||||
# Read the live runtime, mount a temporary plugin, unmount it. The toolset is a
|
||||
# trust boundary, not a sandbox — see this file's header. The composition-
|
||||
# authoring skill reaches this agent through the second custom skill root above.
|
||||
- id: tool-cordis
|
||||
name: '@deepseek-ai/dsh-tool-cordis'
|
||||
|
||||
# ── presentation ────────────────────────────────────────────────────────────
|
||||
|
||||
# `both` sends the native tool schemas AND the generated Code Mode SDK, so the
|
||||
# model may call a tool directly or write one TypeScript program that combines
|
||||
# several. It waits for the host's `codeRuntime` rather than assuming it: a
|
||||
# deployment composing no TypeScript runtime fails this preset at mount, naming
|
||||
# this id, instead of at the first request.
|
||||
- id: tool-presentation
|
||||
name: '@deepseek-ai/dsh-agent-tool-presentation'
|
||||
config:
|
||||
mode: both
|
||||
3
apps/cli/config/agent-presets/maximum/preset.yml
Normal file
3
apps/cli/config/agent-presets/maximum/preset.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
name: 全能模式
|
||||
description: 组合全部可用插件、技能与外部 Agent,并以「架构师 → 实现者 → 审查者」三角色流水线规划、实现并验证每一次改动。
|
||||
order: 6
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: three-role-delivery-pipeline
|
||||
description: Use when running a change through this preset's architect → implementer → reviewer roles — writing the prompt for subagent_architect, subagent_implementer, or subagent_reviewer, deciding whether a task needs the pipeline at all, handing a FAIL verdict back for a second round, or splitting work that is too large for one pass.
|
||||
---
|
||||
|
||||
# The three-role delivery pipeline
|
||||
|
||||
This preset carries three delegation tools that are one tool each, distinguished by the persona their children run under:
|
||||
|
||||
| Tool | Role | Produces |
|
||||
|---|---|---|
|
||||
| `subagent_architect` | specify | GOAL / CONTEXT / PLAN / ACCEPTANCE / RISKS |
|
||||
| `subagent_implementer` | build | CHANGES / VERIFICATION / DEVIATIONS |
|
||||
| `subagent_reviewer` | verify | VERDICT / EVIDENCE / DEFECTS |
|
||||
|
||||
All three are foreground calls that return their reply as the tool result, and none of them can delegate further. You are the only agent that sees the whole pipeline.
|
||||
|
||||
## When it applies
|
||||
|
||||
Run the pipeline for anything that changes behavior: a feature, a bug fix, a refactor, a migration, a configuration change that alters what the system does.
|
||||
|
||||
Skip it for a question, a read-only investigation, a command the user asked you to run, or an edit the user dictated exactly. Answer those yourself. A pipeline pass costs three child agents; using it to rename one variable is waste, and the user notices.
|
||||
|
||||
Split before you delegate when the request holds several independent changes. One pipeline pass carries one specification; two unrelated changes in one specification produce a review that cannot say PASS or FAIL about either.
|
||||
|
||||
## The handoff is the whole design
|
||||
|
||||
Each child is a fresh agent. It cannot see this conversation, the user's message, the earlier stages, or the other children's sessions. Whatever you leave out of the prompt does not exist for that role.
|
||||
|
||||
**To the architect**, pass the user's request in full, the constraints the user stated, and anything you already learned that narrows the work — a file you found, a decision the user made mid-conversation, a check that already fails.
|
||||
|
||||
**To the implementer**, pass the architect's reply verbatim. Add nothing and remove nothing; if you disagree with the plan, say so to the user or re-run the architect, but do not edit a specification into the implementer's prompt.
|
||||
|
||||
**To the reviewer**, pass the same specification verbatim plus the implementer's complete report. The reviewer compares two texts against the repository; withholding either leaves it guessing.
|
||||
|
||||
Never write "as described above", "the plan from the previous step", or a session id in a role prompt. There is no above.
|
||||
|
||||
## The FAIL loop
|
||||
|
||||
A FAIL verdict comes back as a numbered defect list. Send the implementer the original specification, its own previous report, and that defect list, and say that this round fixes the listed defects and nothing else. Then review again, with the same specification and the new report.
|
||||
|
||||
Stop after the third failed review. Three rounds against one specification means the specification and the implementation disagree about something the reviewer cannot resolve — take it to the user with the specification, the last report, and the surviving defects, rather than starting a fourth round.
|
||||
|
||||
A `minor` defect does not have to block. When the reviewer returns PASS with minor defects, or FAIL where every defect is minor and unrelated to the acceptance criteria, say so to the user and let them decide whether to spend another round.
|
||||
|
||||
## Reporting
|
||||
|
||||
Say which stage you are in as you go: the user is waiting through three model calls and a silent gap reads as a hang. When the pipeline finishes, report what changed, what the reviewer verified, and any deviation or surviving defect. Never report the pipeline as complete when the reviewer never ran or returned FAIL.
|
||||
@@ -197,12 +197,14 @@
|
||||
toolName: subagent_fork
|
||||
backgroundMode: continuable
|
||||
|
||||
# Production dsh does not install these optional providers. An opting-in
|
||||
# Profile mounts each provider once on the host plane; copy this preset,
|
||||
# then remove `disabled` from the matching tool row.
|
||||
# External product agents. The base host plane mounts each provider, and
|
||||
# each run needs that product's own CLI on PATH plus its own account:
|
||||
# `codex`, `claude`, and `cursor-agent`. A missing CLI fails the call it is
|
||||
# asked for rather than the composition, so a deployment without one keeps
|
||||
# an inert tool row; copy this preset and add `disabled: true` to drop it
|
||||
# from the model's roster entirely.
|
||||
- id: tool-subagent-codex
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: codex
|
||||
toolName: subagent_codex
|
||||
@@ -211,13 +213,20 @@
|
||||
|
||||
- id: tool-subagent-claude-code
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
disabled: true
|
||||
config:
|
||||
provider: claude-code
|
||||
toolName: subagent_claude_code
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: tool-subagent-cursor
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: cursor
|
||||
toolName: subagent_cursor
|
||||
backgroundMode: one-shot
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
"@deepseek-ai/dsh-goal-round-driver": "workspace:^",
|
||||
"@deepseek-ai/dsh-cmdline": "workspace:^",
|
||||
"@deepseek-ai/dsh-launch-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-lsp": "workspace:^",
|
||||
"@deepseek-ai/dsh-lsp-stdio": "workspace:^",
|
||||
"@deepseek-ai/dsh-fs-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-headless": "workspace:^",
|
||||
"@deepseek-ai/dsh-mcp-client": "workspace:^",
|
||||
@@ -56,6 +58,9 @@
|
||||
"@deepseek-ai/dsh-jobs-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-tmux-context": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-subagent-claude-code": "workspace:^",
|
||||
"@deepseek-ai/dsh-subagent-codex": "workspace:^",
|
||||
"@deepseek-ai/dsh-subagent-cursor": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-ask-user": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-bash": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-bash-persistent": "workspace:^",
|
||||
@@ -70,7 +75,10 @@
|
||||
"@deepseek-ai/dsh-tool-str-replace-editor": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-subagent": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-subagent-control": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-session-query": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-terminal": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-jobs": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-lsp": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-todo": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-web": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-workflow": "workspace:^",
|
||||
|
||||
@@ -150,6 +150,21 @@ function enablePresetTool(composition: string, id: string): string {
|
||||
return composition.slice(0, disabled) + composition.slice(disabled + ' disabled: true\n'.length)
|
||||
}
|
||||
|
||||
function disablePresetTool(composition: string, id: string): string {
|
||||
const row = ` - id: ${id}\n`
|
||||
const start = composition.indexOf(row)
|
||||
if (start < 0) throw new Error(`missing preset row ${id}`)
|
||||
const end = composition.indexOf('\n - id:', start + row.length)
|
||||
const disabled = composition.indexOf(' disabled: true\n', start)
|
||||
if (disabled >= 0 && (end < 0 || disabled < end)) {
|
||||
throw new Error(`preset row ${id} is already disabled`)
|
||||
}
|
||||
// `disabled` is entry metadata, so it goes beside `name` rather than inside
|
||||
// the row's `config`.
|
||||
const nameLine = composition.indexOf('\n', start + row.length) + 1
|
||||
return `${composition.slice(0, nameLine)} disabled: true\n${composition.slice(nameLine)}`
|
||||
}
|
||||
|
||||
let ctx: Context
|
||||
beforeAll(async () => {
|
||||
const settingsFile = join(await mkdtemp(join(tmpdir(), 'dsh-web-presets-')), 'settings.yaml')
|
||||
@@ -197,7 +212,7 @@ describe('the shipped Web composition', () => {
|
||||
it('supplies both shipped presets, and only those, from the system root', async () => {
|
||||
const listed = await ctx.agentPresets.list()
|
||||
|
||||
expect(listed.map(preset => preset.id).sort()).toEqual(['code', 'cordis', 'minimal', 'standard'])
|
||||
expect(listed.map(preset => preset.id).sort()).toEqual(['code', 'cordis', 'economy', 'maximum', 'minimal', 'standard'])
|
||||
expect(listed.every(preset => preset.trust === 'system')).toBe(true)
|
||||
expect(ctx.agentPresets.defaultId).toBe('standard')
|
||||
})
|
||||
@@ -216,7 +231,8 @@ describe('the shipped Web composition', () => {
|
||||
expect(toolNames(ctx, handle.agent).filter(name => name !== 'glob' && name !== 'grep')).toEqual([
|
||||
'ask_user_question', 'bash', 'create_goal', 'edit', 'exit_plan_mode',
|
||||
'get_goal', 'interrupt_agent', 'job_kill', 'job_list', 'job_output', 'list_agents', 'ralph', 'read', 'read_image', 'send_message', 'skill',
|
||||
'subagent', 'subagent_fork', 'todo_write', 'update_goal', 'web_search',
|
||||
'subagent', 'subagent_claude_code', 'subagent_codex', 'subagent_cursor',
|
||||
'subagent_fork', 'todo_write', 'update_goal', 'web_search',
|
||||
'workflow', 'write',
|
||||
])
|
||||
} finally {
|
||||
@@ -224,6 +240,75 @@ describe('the shipped Web composition', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('composes the economy agent without external subagent providers', async () => {
|
||||
const handle = await ctx.agents.create({
|
||||
sessionId: SessionId('preset-economy'),
|
||||
setup: agentCtx => ctx.agentPresets.mount(agentCtx, 'economy').then(() => undefined),
|
||||
})
|
||||
try {
|
||||
const toolList = toolNames(ctx, handle.agent).filter(name => name !== 'glob' && name !== 'grep')
|
||||
// The shell row is platform-gated like `standard`'s: bash off Windows,
|
||||
// pwsh on it. Everything else is the standard catalog.
|
||||
const shell = process.platform === 'win32' ? 'pwsh' : 'bash'
|
||||
// `economy` keeps every standard tool except the external product
|
||||
// agents, which it disables to avoid paid delegations by default.
|
||||
expect(toolList).toEqual(expect.arrayContaining([
|
||||
'ask_user_question', shell, 'create_goal', 'edit', 'exit_plan_mode',
|
||||
'get_goal', 'interrupt_agent', 'job_kill', 'job_list', 'job_output', 'list_agents', 'ralph', 'read', 'read_image', 'send_message', 'skill',
|
||||
'subagent', 'subagent_fork', 'todo_write', 'update_goal', 'web_search',
|
||||
'workflow', 'write',
|
||||
]))
|
||||
expect(toolList).not.toEqual(expect.arrayContaining([
|
||||
'subagent_codex', 'subagent_claude_code', 'subagent_cursor',
|
||||
]))
|
||||
// The delegation tools default to foreground: one-shot, not the
|
||||
// continuable background scheduling `standard` uses.
|
||||
const subagent = ctx.tools.schemas(handle.agent).find(schema => schema.name === 'subagent')
|
||||
expect(subagent?.description).toContain('This call waits for the result by default.')
|
||||
} finally {
|
||||
await handle.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('composes every shipped capability and the three pipeline roles from `maximum`', async () => {
|
||||
const handle = await ctx.agents.create({
|
||||
sessionId: SessionId('preset-maximum'),
|
||||
setup: agentCtx => ctx.agentPresets.mount(agentCtx, 'maximum').then(() => undefined),
|
||||
})
|
||||
try {
|
||||
// The shell row is platform-gated like `standard`'s: bash off Windows,
|
||||
// pwsh on it. The registry answers in name order, so the gated name is
|
||||
// sorted in rather than written at a fixed position.
|
||||
const shell = process.platform === 'win32' ? 'pwsh' : 'bash'
|
||||
// The EXACT catalog, for the reason `standard`'s assertion states: a row
|
||||
// that registers into the wrong layer mounts cleanly and contributes
|
||||
// nothing, and this preset exists to carry every row at once.
|
||||
expect(toolNames(ctx, handle.agent).filter(name => name !== 'glob' && name !== 'grep')).toEqual([
|
||||
'ask_user_question', shell, 'cordis_define', 'cordis_inspect_list', 'cordis_inspect_query',
|
||||
'cordis_inspect_self', 'cordis_run', 'cordis_stop', 'cordis_undefine', 'create_goal', 'edit',
|
||||
'exit_plan_mode', 'get_goal', 'interrupt_agent', 'job_kill', 'job_list', 'job_output',
|
||||
'list_agents', 'lsp', 'ralph', 'read', 'read_image', 'run_code', 'schedule_create',
|
||||
'schedule_delete', 'schedule_list', 'send_message', 'session_event_read',
|
||||
'session_event_search', 'session_event_trace', 'session_search', 'session_trace', 'skill',
|
||||
'str_replace_editor', 'subagent', 'subagent_architect', 'subagent_claude_code',
|
||||
'subagent_codex', 'subagent_cursor', 'subagent_fork', 'subagent_implementer',
|
||||
'subagent_reviewer', 'terminal_close', 'terminal_list', 'terminal_open', 'terminal_read',
|
||||
'terminal_send', 'terminal_signal', 'todo_write', 'update_goal', 'web_search', 'workflow',
|
||||
'write',
|
||||
].sort())
|
||||
// Each role is one `spawn` instance carrying its own child persona, so
|
||||
// the roles are distinguishable only by what their descriptions and
|
||||
// personas say — the wire schemas are otherwise identical.
|
||||
const schemas = ctx.tools.schemas(handle.agent)
|
||||
for (const role of ['subagent_architect', 'subagent_implementer', 'subagent_reviewer']) {
|
||||
expect(schemas.find(schema => schema.name === role)?.description)
|
||||
.toContain('This call waits for the result by default.')
|
||||
}
|
||||
} finally {
|
||||
await handle.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('composes the exact RL prompt and two tools from `minimal`', async () => {
|
||||
const handle = await ctx.agents.create({
|
||||
sessionId: SessionId('preset-minimal'),
|
||||
@@ -436,7 +521,7 @@ describe('the shipped Web composition', () => {
|
||||
|
||||
describe('product subagent rows in user presets', () => {
|
||||
let productCtx: Context
|
||||
const ids = ['products-none', 'products-codex', 'products-claude', 'products-both'] as const
|
||||
const ids = ['products-none', 'products-codex', 'products-claude', 'products-all'] as const
|
||||
|
||||
beforeAll(async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-product-presets-'))
|
||||
@@ -444,23 +529,26 @@ describe('product subagent rows in user presets', () => {
|
||||
const settingsFile = join(root, 'settings.yaml')
|
||||
const standard = await readFile(join(CONFIG_DIR, 'agent-presets', 'standard', 'agent.cordis.yml'), 'utf8')
|
||||
await writeFile(settingsFile, '{}\n')
|
||||
// `standard` ships every product row enabled, so each variant is built by
|
||||
// REMOVING the rows it must not carry.
|
||||
for (const id of ids) {
|
||||
let composition = standard
|
||||
if (id === 'products-codex' || id === 'products-both') {
|
||||
composition = enablePresetTool(composition, 'tool-subagent-codex')
|
||||
if (id !== 'products-all' && id !== 'products-codex') {
|
||||
composition = disablePresetTool(composition, 'tool-subagent-codex')
|
||||
}
|
||||
if (id === 'products-claude' || id === 'products-both') {
|
||||
composition = enablePresetTool(composition, 'tool-subagent-claude-code')
|
||||
if (id !== 'products-all' && id !== 'products-claude') {
|
||||
composition = disablePresetTool(composition, 'tool-subagent-claude-code')
|
||||
}
|
||||
if (id !== 'products-all') {
|
||||
composition = disablePresetTool(composition, 'tool-subagent-cursor')
|
||||
}
|
||||
const directory = join(userRoot, id)
|
||||
await mkdir(directory, { recursive: true })
|
||||
await writeFile(join(directory, 'agent.cordis.yml'), composition)
|
||||
}
|
||||
// The base patch already mounts every product provider on the host plane,
|
||||
// so this boot adds only the preset roster.
|
||||
productCtx = await bootWeb(settingsFile, [
|
||||
{ insert: [
|
||||
{ id: 'subagent-codex', name: '@deepseek-ai/dsh-subagent-codex' },
|
||||
{ id: 'subagent-claude-code', name: '@deepseek-ai/dsh-subagent-claude-code' },
|
||||
] },
|
||||
{
|
||||
id: 'agent-presets',
|
||||
config: {
|
||||
@@ -479,15 +567,15 @@ describe('product subagent rows in user presets', () => {
|
||||
await productCtx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('composes none, either product, or both without changing the shared host registry', async () => {
|
||||
it('composes none, one product, or every product without changing the shared host registry', async () => {
|
||||
const expected = new Map<string, string[]>([
|
||||
['products-none', []],
|
||||
['products-codex', ['subagent_codex']],
|
||||
['products-claude', ['subagent_claude_code']],
|
||||
['products-both', ['subagent_claude_code', 'subagent_codex']],
|
||||
['products-all', ['subagent_claude_code', 'subagent_codex', 'subagent_cursor']],
|
||||
])
|
||||
expect(productCtx.subagents.list()).toEqual(expect.arrayContaining([
|
||||
'spawn', 'fork', 'codex', 'claude-code',
|
||||
'spawn', 'fork', 'codex', 'claude-code', 'cursor',
|
||||
]))
|
||||
|
||||
for (const [id, productTools] of expected) {
|
||||
@@ -497,7 +585,7 @@ describe('product subagent rows in user presets', () => {
|
||||
})
|
||||
try {
|
||||
const tools = toolNames(productCtx, handle.agent)
|
||||
expect(tools.filter(name => name === 'subagent_codex' || name === 'subagent_claude_code'))
|
||||
expect(tools.filter(name => name.startsWith('subagent_') && name !== 'subagent_fork'))
|
||||
.toEqual(productTools)
|
||||
expect(tools).toEqual(expect.arrayContaining(['job_kill', 'job_list', 'job_output']))
|
||||
for (const productTool of productTools) {
|
||||
|
||||
Reference in New Issue
Block a user