mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Four values complete the vocabulary, so the opaque body is reached only by producers that genuinely promise no shape. `snapshot` — current state a later snapshot supersedes. system-prompt now exposes `renderContextSections()`, the named contributions `renderContextSnapshot()` already joins for the model, so the body attributes each part to the subsystem that produced it instead of re-splitting joined prose. The runtime snapshot, time-context, and tmux-context declare it. `notice` — a one-off account of what just happened, declared by tool-tasks, goal state changes, tool-goal wrap-up, plan-mode switches, and repeat-tool-guard. Its `summary` rides the COLLAPSED row: these five are the majority of shipped producers and none of them needs expanding to be read. The task summary bounds itself because its inputs are unbounded caller text. `relay` — a message another agent addressed to this one; both subagent sources declare it and the body names the sender above what it said. `recall` — material lifted from another session's log. session-reference needed no new field: its references already record retained and omitted counts and the truncation flag, which the body shows first, because recalled context is bounded on the way in. `ContextFormed` is now discriminated by `form`, so a producer cannot declare a shape without the facts that shape is presented from — a notice without its summary, or a snapshot without its sections, fails to compile. Only the two hook bridges stay opaque, by design: their content is whatever an external program printed, so no shape can be promised for it. Unknown kinds and unreadable records land there too.
77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
/**
|
|
* The globally named `send_message` tool: a thin model-facing adapter over
|
|
* `ctx.subagents.followup()`. It performs no lifecycle routing of its own —
|
|
* residency and cold resume belong to the subagent service — and it lives apart
|
|
* from the provider-bound `@deepseek-ai/dsh-tool-subagent` instances so multiple
|
|
* delegation tools share one control tool.
|
|
* @module @deepseek-ai/dsh-tool-subagent-control
|
|
*/
|
|
|
|
import type { Context } from 'cordis'
|
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
|
import { SessionId } from '@deepseek-ai/dsh-session'
|
|
import type {} from '@deepseek-ai/dsh-subagent'
|
|
|
|
export const name = 'tool-subagent-control'
|
|
export const inject = ['tools', 'subagents']
|
|
|
|
/**
|
|
* Register the `send_message` tool.
|
|
* @param ctx - context carrying the tool registry and subagent service.
|
|
*/
|
|
export function apply(ctx: Context): void {
|
|
ctx.tools.register(defineTool({
|
|
name: 'send_message',
|
|
description:
|
|
'Send a message to a background subagent by its subagent id, continuing the same conversation. It '
|
|
+ 'becomes the subagent\'s next turn: if it is still working, the message waits until its current turn '
|
|
+ 'finishes, so it cannot redirect work already underway. This call returns no answer from the '
|
|
+ 'subagent — only confirmation that the message was delivered — so use it to give it more work. A '
|
|
+ 'failure means the message was NOT delivered.',
|
|
parameters: {
|
|
subagent_id: {
|
|
type: 'string',
|
|
required: true,
|
|
description: 'The subagent id returned when the background subagent was started.',
|
|
},
|
|
message: {
|
|
type: 'string',
|
|
required: true,
|
|
description: 'The message to deliver to the subagent.',
|
|
},
|
|
},
|
|
output: {
|
|
schema: {
|
|
type: 'object',
|
|
additionalProperties: false,
|
|
properties: {
|
|
messageId: { type: 'string', required: true },
|
|
},
|
|
},
|
|
render: (args, _value) => [{
|
|
type: 'text',
|
|
text: `message queued as the next turn for subagent ${args.subagent_id}`,
|
|
}],
|
|
},
|
|
async execute(args, exec) {
|
|
const parent = exec.agent
|
|
if (!parent) {
|
|
// Parent authority requires an exact live calling agent.
|
|
throw new Error('send_message requires a calling agent (exec.agent was undefined)')
|
|
}
|
|
const message: ContentBlock[] = [{ type: 'text', text: args.message }]
|
|
const messageId = await ctx.subagents.followup(
|
|
parent,
|
|
SessionId(args.subagent_id),
|
|
message,
|
|
{
|
|
source: { kind: 'coordinator', form: 'relay', senderSessionId: parent.id },
|
|
signal: exec.signal,
|
|
},
|
|
)
|
|
return { messageId }
|
|
},
|
|
}))
|
|
}
|