Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification
# Conflicts: # .agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml # .agents/notes/implemented/architecture/2026-07-31-goal-owned-durable-events.i18n.yaml # .agents/notes/implemented/feature/2026-07-19-model-facing-goal-tools.i18n.yaml # .agents/notes/implemented/feature/2026-07-22-docked-web-goal-bar.i18n.yaml # docs/architecture.i18n.yaml # docs/architecture.md # docs/architecture.zh.md # docs/config-catalog.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.i18n.yaml # docs/core-data-structures/core.md # docs/core-data-structures/core.zh.md # docs/event-producer-consumer.md # docs/module-graph.md # docs/persistence-catalog.md # examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl # examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl # examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # examples/acp-agent/tests/snapshots/skill-load/session.jsonl # examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl # examples/acp-agent/tests/snapshots/subagent-fork/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-mixed/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-mixed/session.2.jsonl # examples/acp-agent/tests/snapshots/subagent-multi/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-multi/session.2.jsonl # examples/acp-agent/tests/snapshots/subagent-spawn/session.1.jsonl # examples/acp-agent/tests/snapshots/workflow-run/session.1.jsonl # examples/acp-agent/tests/snapshots/workspace-context/session.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl # examples/headless-agent/tests/snapshots/pty-tools/session.jsonl # examples/headless-agent/tests/subagent-inheritance-snapshots/parent-override/child.expected.jsonl # examples/jsonrpc-agent/tests/snapshots/subagent-spawn/notifications.expected.jsonl # examples/jsonrpc-agent/tests/snapshots/subagent-spawn/session.1.jsonl # packages/acp/acp/README.i18n.yaml # packages/acp/acp/src/index.ts # packages/client/connection/src/client/index.ts # packages/client/runtime/README.i18n.yaml # packages/client/runtime/README.md # packages/client/runtime/README.zh.md # packages/client/runtime/src/client/sessions/conversation.ts # packages/client/runtime/src/client/sessions/session.ts # packages/client/runtime/tests/queue-store.spec.ts # packages/client/ui-conversation/src/client/input/contract.ts # packages/client/ui-goal/README.i18n.yaml # packages/compact/compact-basic/src/index.ts # packages/context/time-context/tests/time-context.spec.ts # packages/context/tmux-context/tests/tmux-context.spec.ts # packages/context/workspace-context/tests/workspace-context.spec.ts # packages/cordis/tool-cordis/src/api-catalog.ts # packages/core/agent-loop/README.i18n.yaml # packages/core/agent-loop/README.md # packages/core/agent-loop/README.zh.md # packages/core/agent-loop/src/agent.ts # packages/core/agent-loop/tests/agent.spec.ts # packages/core/agent-loop/tests/loop.spec.ts # packages/core/agent/README.i18n.yaml # packages/core/agent/README.md # packages/core/agent/README.zh.md # packages/core/agent/src/types.ts # packages/core/session/README.i18n.yaml # packages/core/session/README.md # packages/core/session/README.zh.md # packages/goal/command-goal/tests/command-goal.spec.ts # packages/goal/goal/tests/goal.spec.ts # packages/goal/tool-goal/README.i18n.yaml # packages/goal/tool-goal/README.md # packages/goal/tool-goal/README.zh.md # packages/host/apiproxy/README.i18n.yaml # packages/host/apiproxy/README.md # packages/host/apiproxy/README.zh.md # packages/host/apiproxy/src/api-proxy.ts # packages/host/apiproxy/src/api/events.schema.ts # packages/host/apiproxy/src/api/events.ts # packages/host/apiproxy/src/api/rpc.ts # packages/host/apiproxy/tests/api-proxy-commands.spec.ts # packages/host/apiproxy/tests/api-proxy-projections.spec.ts # packages/host/apiproxy/tests/rpc-schemas.spec.ts # packages/pty/pty-local/tests/index.spec.ts # packages/pty/pty-local/tests/local.spec.ts # packages/pty/tool-pty/tests/loader-composition.spec.ts # packages/pty/tool-pty/tests/tools.spec.ts # packages/session-persistence/session-checkpoint-policy/src/index.ts # packages/session-persistence/session-persistence/tests/coordinator-contract.ts # packages/skill/tool-skill/tests/tool-skill.spec.ts # packages/subagent/subagent-inprocess/README.i18n.yaml # packages/subagent/subagent-inprocess/README.md # packages/subagent/subagent-inprocess/README.zh.md # packages/subagent/subagent-inprocess/src/index.ts # packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts # packages/support/acp-snapshot/src/harness.ts # packages/ui/tui/tests/tui.spec.ts
This commit is contained in:
@@ -37,6 +37,10 @@ flowchart LR
|
||||
cfg --> plugin_headless_subagent_spawn
|
||||
plugin_headless_subagent_fork["subagent-fork<br/>@deepseek-ai/dsh-subagent-fork"]
|
||||
cfg --> plugin_headless_subagent_fork
|
||||
plugin_headless_tool_subagent_control["tool-subagent-control<br/>@deepseek-ai/dsh-tool-subagent-control"]
|
||||
cfg --> plugin_headless_tool_subagent_control
|
||||
plugin_headless_tool_subagent_report["tool-subagent-report<br/>@deepseek-ai/dsh-tool-subagent-report"]
|
||||
cfg --> plugin_headless_tool_subagent_report
|
||||
plugin_headless_tool_subagent["tool-subagent<br/>@deepseek-ai/dsh-tool-subagent"]
|
||||
cfg --> plugin_headless_tool_subagent
|
||||
plugin_headless_tool_subagent_fork["tool-subagent-fork<br/>@deepseek-ai/dsh-tool-subagent"]
|
||||
@@ -70,6 +74,8 @@ flowchart LR
|
||||
| `subagent` | `@deepseek-ai/dsh-subagent` |
|
||||
| `subagent-spawn` | `@deepseek-ai/dsh-subagent-spawn` |
|
||||
| `subagent-fork` | `@deepseek-ai/dsh-subagent-fork` |
|
||||
| `tool-subagent-control` | `@deepseek-ai/dsh-tool-subagent-control` |
|
||||
| `tool-subagent-report` | `@deepseek-ai/dsh-tool-subagent-report` |
|
||||
| `tool-subagent` | `@deepseek-ai/dsh-tool-subagent` |
|
||||
| `tool-subagent-fork` | `@deepseek-ai/dsh-tool-subagent` |
|
||||
| `workflow-workerthread` | `@deepseek-ai/dsh-workflow-workerthread` |
|
||||
|
||||
@@ -86,11 +86,21 @@
|
||||
config:
|
||||
providerName: fork
|
||||
|
||||
# Continuable background children are selected per delegation tool. The
|
||||
# separately loaded control registers global `send_message`; `report` is
|
||||
# installed only in continuable child scopes.
|
||||
- id: tool-subagent-control
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control'
|
||||
|
||||
- id: tool-subagent-report
|
||||
name: '@deepseek-ai/dsh-tool-subagent-report'
|
||||
|
||||
- id: tool-subagent
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent
|
||||
backgroundMode: continuable
|
||||
maxDepth: 1
|
||||
|
||||
- id: tool-subagent-fork
|
||||
@@ -98,6 +108,7 @@
|
||||
config:
|
||||
provider: fork
|
||||
toolName: subagent_fork
|
||||
backgroundMode: continuable
|
||||
maxDepth: 1
|
||||
|
||||
# The worker-thread workflow engine fans a model-written JavaScript script's
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- id: cli-mock-llm
|
||||
name: './cli-mock-llm.ts'
|
||||
|
||||
- id: repository-plugin-fixture
|
||||
name: './repository-plugin/load.mjs'
|
||||
|
||||
- id: base
|
||||
name: '@cordisjs/plugin-include'
|
||||
config:
|
||||
@@ -16,4 +19,8 @@
|
||||
model: cli-mock
|
||||
persistenceRoot: './.sessions'
|
||||
workspaceContext: false
|
||||
dshHome: './.dsh-home'
|
||||
skills:
|
||||
local:
|
||||
agentsHome: './.agents-home'
|
||||
persona: 'Keyless headless-agent smoke.'
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
name: repository-fixture
|
||||
description: Repository fixture skill.
|
||||
---
|
||||
|
||||
Static instructions from a prepared repository plugin.
|
||||
9
examples/headless-agent/tests/fixtures/repository-plugin/dsh-plugin.mjs
vendored
Normal file
9
examples/headless-agent/tests/fixtures/repository-plugin/dsh-plugin.mjs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Generated by dsh-plugin-prepare. Do not edit.
|
||||
const manifest = {"name":"headless-repository-fixture","skills":["dsh-plugin-assets/skills/0"]}
|
||||
export const name = "headless-repository-fixture"
|
||||
export const inject = ["loader","skills"]
|
||||
export async function apply(ctx) {
|
||||
const runtime = ctx.loader.builtins["dsh-repository-plugin"]
|
||||
if (runtime === undefined) throw new Error("missing Cordis builtin dsh-repository-plugin")
|
||||
await ctx.plugin(runtime, { baseUrl: import.meta.url, manifest })
|
||||
}
|
||||
13
examples/headless-agent/tests/fixtures/repository-plugin/load.mjs
vendored
Normal file
13
examples/headless-agent/tests/fixtures/repository-plugin/load.mjs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Keyless fixture owner that mounts the runtime before its prepared wrapper.
|
||||
* Cordis starts sibling Loader entries concurrently, so row order is not a dependency edge.
|
||||
*/
|
||||
import * as RepositoryPlugin from '@deepseek-ai/dsh-repository-plugin'
|
||||
import * as PreparedPlugin from './dsh-plugin.mjs'
|
||||
|
||||
export const name = 'headless-repository-fixture-loader'
|
||||
|
||||
export async function apply(ctx) {
|
||||
await ctx.plugin(RepositoryPlugin)
|
||||
await ctx.plugin(PreparedPlugin)
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import { readFile, readdir } from 'node:fs/promises'
|
||||
import { cp, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { zstdDecompress } from 'node:zlib'
|
||||
import { promisify } from 'node:util'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-loader-smoke'
|
||||
import { PREPARED_ENTRY_FILENAME, prepareDshPlugin } from '@deepseek-ai/dsh-repository-plugin'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
|
||||
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
|
||||
@@ -36,6 +38,17 @@ describe('headless-agent keyless smoke', () => {
|
||||
const result = lines.at(-1)
|
||||
expect(stderr).toBe('')
|
||||
expect(events.some(event => event.type === 'tool/call' && event.data.name === 'bash')).toBe(true)
|
||||
const catalogMessage = events.find(event => event.type === 'user/message'
|
||||
&& event.data.source.kind === 'plugin'
|
||||
&& event.data.source.plugin === 'dsh-tool-skill')
|
||||
const catalog = catalogMessage?.type === 'user/message'
|
||||
? catalogMessage.data.content.filter(block => block.type === 'text').map(block => block.text).join('\n')
|
||||
: ''
|
||||
expect(catalog.split('\n').find(line => line.includes('repository-fixture'))).toMatchInlineSnapshot(
|
||||
`
|
||||
"- \`repository-fixture\`: Repository fixture skill."
|
||||
`,
|
||||
)
|
||||
const toolResult = events.find(event => event.type === 'tool/result')
|
||||
expect(JSON.stringify(toolResult)).toContain('CLI_TOOL_ROUND_TRIP')
|
||||
expect(result).toMatchObject({
|
||||
@@ -45,4 +58,28 @@ describe('headless-agent keyless smoke', () => {
|
||||
expect(String(result?.['output'])).toContain('CLI_TOOL_ROUND_TRIP')
|
||||
expect(persistedHeader).toMatchObject({ type: 'session' })
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('keeps the checked-in prepared wrapper identical to the generator output for its manifest', async () => {
|
||||
// The fixture claims "Generated by dsh-plugin-prepare"; this pin makes the
|
||||
// claim true — a wrapper-template change fails here until the fixture is
|
||||
// regenerated, so the assembled smoke can never exercise a stale shape.
|
||||
const fixture = fileURLToPath(new URL('./fixtures/repository-plugin/', import.meta.url))
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-fixture-drift-'))
|
||||
try {
|
||||
const plugin = join(root, '.dsh-plugin')
|
||||
await mkdir(plugin, { recursive: true })
|
||||
await cp(join(fixture, 'dsh-plugin-assets/skills/0'), join(root, 'skills'), { recursive: true })
|
||||
await writeFile(join(plugin, 'package.json'), `${JSON.stringify({
|
||||
name: 'headless-repository-fixture',
|
||||
version: '0.0.0',
|
||||
dsh: { skills: ['../skills'] },
|
||||
}, undefined, 2)}\n`)
|
||||
await prepareDshPlugin(plugin)
|
||||
const generated = await readFile(join(plugin, PREPARED_ENTRY_FILENAME), 'utf8')
|
||||
const checkedIn = await readFile(join(fixture, PREPARED_ENTRY_FILENAME), 'utf8')
|
||||
expect(checkedIn).toBe(generated)
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
dsh-cli-demo: dsh-cli-demo: 1 entry did not activate
|
||||
./activation-error.mjs: Error: startup activation snapshot failure
|
||||
dsh-cli-demo: dsh-cli-demo: plugin tree failed to load: failed to apply loader entry include (cordis:include): failed to apply loader entry activation-error (./activation-error.mjs): startup activation snapshot failure
|
||||
Error: startup activation snapshot failure
|
||||
at activation-error-fixture
|
||||
|
||||
Reference in New Issue
Block a user