feat(subagent): add explicit child reports

This commit is contained in:
Dudu-0223
2026-07-31 22:45:21 +08:00
committed by Tianyi Cui
parent a1b3bebb61
commit 431fb4b035
76 changed files with 3831 additions and 143 deletions

View File

@@ -162,12 +162,16 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
SpillRef: 'spill.md',
ContinuableCreateRequest: 'subagent.md',
ContinuableCreateSpec: 'subagent.md',
ContinuableSetupContribution: 'subagent.md',
ContinuableStart: 'subagent.md',
ContinuableStartSpec: 'subagent.md',
CoordinatorMessageSource: 'subagent.md',
SubagentFollowupOptions: 'subagent.md',
SubagentListEntry: 'subagent.md',
SubagentProvider: 'subagent.md',
SubagentReportDelivery: 'subagent.md',
SubagentReportMessageSource: 'subagent.md',
SubagentReportOptions: 'subagent.md',
SubagentRun: 'subagent.md',
SubagentService: 'subagent.md',
SubagentStartRequest: 'subagent.md',

View File

@@ -11,7 +11,9 @@ import { basename, resolve } from 'node:path'
import { Context } from 'cordis'
import type { ToolSchema } from '@deepseek-ai/dsh-llm'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import SessionStore from '@deepseek-ai/dsh-session'
import type { Agent } from '@deepseek-ai/dsh-agent'
import { createScope } from '@deepseek-ai/dsh-scope'
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
import SessionQuerySqlite from '@deepseek-ai/dsh-session-query-sqlite'
import GoalService from '@deepseek-ai/dsh-goal'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
@@ -30,6 +32,7 @@ import SubagentService from '@deepseek-ai/dsh-subagent'
import type { SubagentProvider } from '@deepseek-ai/dsh-subagent'
import * as ToolSubagentControl from '@deepseek-ai/dsh-tool-subagent-control'
import * as ToolSubagentListAgents from '@deepseek-ai/dsh-tool-subagent-control/list-agents'
import * as ToolSubagentReport from '@deepseek-ai/dsh-tool-subagent-report'
import SkillService from '@deepseek-ai/dsh-skill'
import * as SkillLocal from '@deepseek-ai/dsh-skill-local'
import LocalTaskService from '@deepseek-ai/dsh-tasks-local'
@@ -114,6 +117,26 @@ function registerCatalogSubagentProvider(ctx: Context, name: string): void {
ctx.subagents.registerProvider(provider)
}
/** Minted child-scope keys for packages whose tools are never global. */
const catalogChildScopes = new WeakMap<Context, Agent>()
/**
* Install one scope-local tool package into an agent-like child scope for
* schema harvest, without starting a model, Agent loop, or persistence backend.
* @param ctx - catalog context owning the scope.
* @param mountScoped - package installer for the scoped context.
*/
async function mountCatalogChildScope(
ctx: Context,
mountScoped: (childCtx: Context) => void,
): Promise<void> {
const key = { id: SessionId('tool-catalog-child') } as Agent
await ctx.plugin(Object.assign((inner: Context) => {
mountScoped(createScope(inner, key).ctx)
}, { inject: ['tools', 'systemPrompt', 'subagents'] }))
catalogChildScopes.set(ctx, key)
}
/**
* Tool package plus its hand-maintained boot recipe. The caller mounts the
* prompt and registry; each recipe supplies only package-specific seams and
@@ -139,6 +162,8 @@ interface ToolPackage {
/** Plug the injected seams + the tool plugin onto a context that already
* carries `systemPrompt` + `tools`. */
mount: (ctx: Context) => Promise<void>
/** Agent-like scope key whose tool view is catalogued instead of the global view. */
scope?: (ctx: Context) => Agent
/**
* Config for the caller's `ToolRegistry` mount. The registry itself ships a
* model-facing tool (`run_code`, registered under a non-native `mode`), so
@@ -408,6 +433,25 @@ const TOOL_PACKAGES: ToolPackage[] = [
note:
'The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` once, plus `list_agents` from its separately loaded `/list-agents` plugin (which additionally requires session query).',
},
{
pkg: '@deepseek-ai/dsh-tool-subagent-report',
dir: 'tool-subagent-report',
source: 'packages/subagent/tool-subagent-report/src/index.ts',
requires: ['ctx.subagents', 'a live continuable in-process child Agent'],
writes: ['tool/call', 'tool/result', 'a user-role message in the direct parent session'],
async mount(ctx) {
await ctx.plugin(AgentRegistry)
await ctx.plugin(SubagentService)
await mountCatalogChildScope(ctx, (childCtx) => {
ToolSubagentReport.installReportTool(childCtx, ctx, 'quiet')
})
},
scope: ctx => catalogChildScopes.get(ctx) as Agent,
note:
'Registered per continuable in-process child rather than globally, so this schema is visible only '
+ 'inside such a child and survives its global `toolFilter`. The parent-facing `send_message` tool '
+ 'is installed independently.',
},
{
pkg: '@deepseek-ai/dsh-tool-tasks',
dir: 'tool-tasks',
@@ -523,7 +567,7 @@ export async function collectToolCatalog(packages: ToolPackage[] = TOOL_PACKAGES
await ctx.plugin(SystemPrompt)
await ctx.plugin(ToolRegistry, entry.toolsConfig ?? {})
await entry.mount(ctx)
const schemas = ctx.tools.schemas().sort((a, b) => a.name.localeCompare(b.name))
const schemas = ctx.tools.schemas(entry.scope?.(ctx)).sort((a, b) => a.name.localeCompare(b.name))
catalog.push({
pkg: entry.pkg,
sources: Object.fromEntries(schemas.map(schema => [
@@ -599,8 +643,8 @@ export function render(catalog: ToolCatalog): string {
lines.push(`## \`${entry.pkg}\``, '')
for (const schema of entry.schemas) {
// Collection validated that every harvested schema has a source.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
lines.push(...renderTool(schema, entry.sources[schema.name]!))
const source = entry.sources[schema.name] as string
lines.push(...renderTool(schema, source))
}
if (entry.note) lines.push(entry.note, '')
}

View File

@@ -1104,6 +1104,21 @@
"symbol": "CoordinatorMessageSource",
"source": "packages/subagent/subagent/src/continuation.ts"
},
{
"doc": "docs/core-data-structures/subagent.md",
"symbol": "SubagentReportMessageSource",
"source": "packages/subagent/subagent/src/continuation.ts"
},
{
"doc": "docs/core-data-structures/subagent.md",
"symbol": "SubagentReportDelivery",
"source": "packages/subagent/subagent/src/continuation.ts"
},
{
"doc": "docs/core-data-structures/subagent.md",
"symbol": "SubagentReportOptions",
"source": "packages/subagent/subagent/src/continuation.ts"
},
{
"doc": "docs/core-data-structures/subagent.md",
"symbol": "SubagentFollowupOptions",