Merge remote-tracking branch 'origin/master' into codex/project-instruction-files
# Conflicts: # docs/event-producer-consumer.md # docs/rfc/README.md # packages/core/agent-core/src/index.ts # packages/ui/acp-agent/src/index.ts
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
The model-facing bash tools — `bash`, `bash_output`, `bash_kill` — registered over the `ctx.bash` executor seam (`@deepseek-ai/dsh-bash`). Pure schema + text shaping; every process concern lives behind the seam, so sandboxed or remote executor implementations swap in without changing what the model sees.
|
||||
|
||||
Requires a loaded executor implementation (e.g. `@deepseek-ai/dsh-bash-local`); the plugin stays pending until `ctx.bash` exists (`inject: ['tools', 'bash']`).
|
||||
Requires a loaded executor implementation (e.g. `@deepseek-ai/dsh-bash-local`); the plugin stays pending until `ctx.bash` exists (`inject: ['tools', 'bash', 'systemPrompt']`).
|
||||
|
||||
The plugin also contributes the `tool:bash` prompt section (order 105) — the cross-call habit the per-tool descriptions cannot carry: check the `[exit code: N]` marker on every result and investigate failures before moving on.
|
||||
|
||||
## Tools
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@deepseek-ai/dsh-agent": "^0.0.1",
|
||||
"@deepseek-ai/dsh-bash": "^0.0.1",
|
||||
"@deepseek-ai/dsh-llm": "^0.0.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "^0.0.1",
|
||||
"@deepseek-ai/dsh-tools": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.6"
|
||||
},
|
||||
|
||||
@@ -43,11 +43,12 @@ import { isAbsolute, resolve as resolvePath } from 'node:path'
|
||||
import { defineTool } from '@deepseek-ai/dsh-tools'
|
||||
import type { GenericCallView, TerminalCallView, ToolResult, ToolResultView } from '@deepseek-ai/dsh-tools'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import type {} from '@deepseek-ai/dsh-system-prompt'
|
||||
import { BashTaskId, OwnerToken } from '@deepseek-ai/dsh-bash'
|
||||
import type { BashRunResult, BashTask, CollectedOutput } from '@deepseek-ai/dsh-bash'
|
||||
|
||||
export const name = 'tool-bash'
|
||||
export const inject = ['tools', 'bash']
|
||||
export const inject = ['tools', 'bash', 'systemPrompt']
|
||||
|
||||
/**
|
||||
* Validate the constraints the SchemaSpec can't express. `defineTool` now
|
||||
@@ -285,6 +286,15 @@ function statusLine(task: BashTask): string {
|
||||
}
|
||||
|
||||
export function apply(ctx: Context): void {
|
||||
// The bash tools' cross-call HABIT, which the per-tool descriptions cannot
|
||||
// carry (they describe one call each): the exit-code marker is only useful
|
||||
// if the model actually checks it every time.
|
||||
ctx.systemPrompt.section({
|
||||
name: 'tool:bash',
|
||||
order: 105,
|
||||
text: 'Check the [exit code: N] marker on every bash result; investigate failures before moving on.',
|
||||
})
|
||||
|
||||
/**
|
||||
* The caller's owner TOKEN — the owning agent's `session.header.id`, or
|
||||
* `undefined` for a non-agent caller. Read `session.header.id` (NOT
|
||||
|
||||
@@ -261,6 +261,14 @@ describe('bash tool', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('contributes the exit-code habit as its prompt section (guidance the descriptions cannot carry)', async () => {
|
||||
const ctx = await setup()
|
||||
const assembly = await ctx.systemPrompt.assemble()
|
||||
const section = assembly.sections.find(s => s.name === 'tool:bash')
|
||||
expect(section?.order).toBe(105)
|
||||
expect(section?.text).toContain('[exit code: N]')
|
||||
})
|
||||
|
||||
it('unregisters everything when the plugin fiber is disposed (HMR safety)', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
@@ -268,8 +276,11 @@ describe('bash tool', () => {
|
||||
await ctx.plugin(LocalBashExecutor, {})
|
||||
const fiber = await ctx.plugin(ToolBash)
|
||||
expect(ctx.tools.schemas()).toHaveLength(3)
|
||||
expect((await ctx.systemPrompt.assemble()).sections.map(s => s.name)).toEqual(['harness:identity', 'deployment:persona', 'tool:bash'])
|
||||
await fiber.dispose()
|
||||
expect(ctx.tools.schemas()).toHaveLength(0)
|
||||
// Only the system-prompt plugin's own built-in sections remain.
|
||||
expect((await ctx.systemPrompt.assemble()).sections.map(s => s.name)).toEqual(['harness:identity', 'deployment:persona'])
|
||||
})
|
||||
|
||||
it('tools depend on the executor: no registration without ctx.bash', async () => {
|
||||
|
||||
Reference in New Issue
Block a user