@botbotgo/agent-harness 0.0.359 → 0.0.362

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +2 -0
  3. package/dist/config/catalogs/response-formats.yaml +43 -0
  4. package/dist/config/runtime/workspace.yaml +8 -0
  5. package/dist/contracts/runtime-requests.d.ts +19 -0
  6. package/dist/contracts/workspace.d.ts +6 -0
  7. package/dist/package-version.d.ts +2 -2
  8. package/dist/package-version.js +2 -2
  9. package/dist/projections/request-events.d.ts +1 -0
  10. package/dist/projections/request-events.js +97 -45
  11. package/dist/protocol/acp/harness-client.js +2 -3
  12. package/dist/runtime/adapter/flow/invocation-flow.js +26 -1
  13. package/dist/runtime/adapter/flow/stream-runtime.js +117 -94
  14. package/dist/runtime/adapter/invocation-result.js +15 -0
  15. package/dist/runtime/adapter/middleware-assembly.js +25 -3
  16. package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +5 -0
  17. package/dist/runtime/adapter/tool/builtin-middleware-tools.js +30 -6
  18. package/dist/runtime/agent-runtime-adapter.d.ts +1 -0
  19. package/dist/runtime/agent-runtime-adapter.js +174 -28
  20. package/dist/runtime/harness/events/streaming.js +2 -3
  21. package/dist/workspace/agent-binding-compiler.js +90 -12
  22. package/dist/workspace/compile.js +1 -0
  23. package/dist/workspace/framework-contract-validation.d.ts +2 -1
  24. package/dist/workspace/framework-contract-validation.js +77 -5
  25. package/dist/workspace/object-loader.js +9 -0
  26. package/dist/workspace/support/workspace-ref-utils.d.ts +1 -0
  27. package/dist/workspace/support/workspace-ref-utils.js +40 -0
  28. package/dist/workspace/yaml-object-reader.js +13 -9
  29. package/package.json +1 -1
@@ -362,17 +362,32 @@ export async function invokeBuiltinTaskTool(input) {
362
362
  const typedInput = isRecord(input.toolInput) ? input.toolInput : {};
363
363
  const description = typeof typedInput.description === "string"
364
364
  ? typedInput.description
365
- : "";
365
+ : typeof typedInput.instruction === "string"
366
+ ? typedInput.instruction
367
+ : typeof typedInput.task === "string"
368
+ ? typedInput.task
369
+ : typeof typedInput.prompt === "string"
370
+ ? typedInput.prompt
371
+ : "";
366
372
  const subagentType = typeof typedInput.subagent_type === "string"
367
373
  ? typedInput.subagent_type
368
- : "";
374
+ : typeof typedInput.agentId === "string"
375
+ ? typedInput.agentId
376
+ : typeof typedInput.agent_id === "string"
377
+ ? typedInput.agent_id
378
+ : typeof typedInput.subagent === "string"
379
+ ? typedInput.subagent
380
+ : "";
369
381
  const builtinBackend = input.resolveBuiltinMiddlewareBackend(input.binding, input.options);
370
382
  const resolvedSubagents = await input.resolveSubagents(compiledSubagents, input.binding);
371
383
  const selectedSubagent = resolvedSubagents.find((subagent) => subagent.name === subagentType);
372
384
  const selectedCompiledSubagent = compiledSubagents.find((subagent) => subagent.name === subagentType);
373
385
  if (!selectedSubagent) {
374
386
  const allowed = resolvedSubagents.map((subagent) => subagent.name);
375
- throw new Error(`Error: invoked agent of type ${subagentType}, the only allowed types are ${allowed.map((name) => `\`${name}\``).join(", ")}`);
387
+ const available = resolvedSubagents
388
+ .map((subagent) => `- ${subagent.name}: ${subagent.description}`)
389
+ .join("\n");
390
+ throw new Error(`Error: invoked agent of type ${subagentType}, the only allowed types are ${allowed.map((name) => `\`${name}\``).join(", ")}.${available ? `\nAvailable subagents:\n${available}` : ""}`);
376
391
  }
377
392
  const resolvedHostModel = selectedSubagent.model ? undefined : await input.resolveModel(primaryModel);
378
393
  const summarizationModel = selectedSubagent.model ?? resolvedHostModel;
@@ -446,8 +461,15 @@ export async function resolveBuiltinMiddlewareTools(input) {
446
461
  ...(input.binding.agent.asyncSubagents ?? []),
447
462
  ];
448
463
  const includeTaskTool = configuredSubagents.length > 0;
464
+ const taskSubagents = getBindingDeepAgentSubagents(input.binding)
465
+ .filter((subagent) => !("graphId" in subagent))
466
+ .map((subagent) => ({
467
+ name: subagent.name,
468
+ description: subagent.description,
469
+ }));
449
470
  const tools = (await createBuiltinMiddlewareTools(backend, {
450
471
  includeTaskTool,
472
+ taskSubagents,
451
473
  workspaceRoot: input.binding.harnessRuntime.workspaceRoot,
452
474
  toolRuntimeContext: input.options?.toolRuntimeContext,
453
475
  invokeTaskTool: includeTaskTool
@@ -188,6 +188,10 @@ export type BuiltinExecutableTool = {
188
188
  schema: unknown;
189
189
  invoke: (input: unknown, config?: Record<string, unknown>) => Promise<unknown>;
190
190
  };
191
+ export type BuiltinTaskSubagentDescriptor = {
192
+ name: string;
193
+ description: string;
194
+ };
191
195
  export declare const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS: readonly [{
192
196
  readonly name: "write_todos";
193
197
  readonly description: "Create and update the runtime todo board for multi-step work.";
@@ -254,6 +258,7 @@ export declare function filterBuiltinMiddlewareToolDescriptors(options?: {
254
258
  export declare function createBuiltinMiddlewareTools(backend: BuiltinMiddlewareBackend, options: {
255
259
  includeTaskTool: boolean;
256
260
  invokeTaskTool?: (input: unknown) => Promise<unknown>;
261
+ taskSubagents?: BuiltinTaskSubagentDescriptor[];
257
262
  workspaceRoot?: string;
258
263
  toolRuntimeContext?: Record<string, unknown>;
259
264
  }): Promise<Map<string, BuiltinExecutableTool>>;
@@ -4,10 +4,33 @@ import { isSandboxBackend } from "deepagents";
4
4
  import { isRecord } from "../../../utils/object.js";
5
5
  import { formatBuiltinTodoSnapshot, isLowSignalTodoContent, summarizeBuiltinWriteTodosArgs, truncateLines } from "../runtime-adapter-support.js";
6
6
  import { maybePersistLargeToolOutput, resolveToolRuntimeContext } from "./tool-output-artifacts.js";
7
- const taskToolSchema = z.object({
8
- description: z.string(),
9
- subagent_type: z.string(),
10
- }).passthrough();
7
+ function buildTaskToolDescription(subagents) {
8
+ const lines = [
9
+ "Delegate a bounded task to the subagent whose declared description best matches the task.",
10
+ "Use this only when a subagent is a better fit than the current agent. Set subagent_type to exactly one listed subagent name.",
11
+ ];
12
+ const available = (subagents ?? [])
13
+ .filter((subagent) => subagent.name.trim().length > 0)
14
+ .map((subagent) => {
15
+ const description = subagent.description.trim() || "No description provided.";
16
+ return `- ${subagent.name}: ${description}`;
17
+ });
18
+ return available.length > 0
19
+ ? [...lines, "", "Available subagents:", ...available].join("\n")
20
+ : lines.join(" ");
21
+ }
22
+ function buildTaskToolSchema(subagents) {
23
+ const names = (subagents ?? [])
24
+ .map((subagent) => subagent.name.trim())
25
+ .filter((name) => name.length > 0);
26
+ const subagentTypeSchema = names.length > 0
27
+ ? z.enum(names)
28
+ : z.string();
29
+ return z.object({
30
+ description: z.string().describe("Concrete bounded task for the selected subagent to perform."),
31
+ subagent_type: subagentTypeSchema.describe("Exact name of the selected subagent."),
32
+ }).passthrough();
33
+ }
11
34
  export const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS = [
12
35
  { name: "write_todos", description: "Create and update the runtime todo board for multi-step work." },
13
36
  { name: "read_todos", description: "Read the current runtime todo board." },
@@ -638,10 +661,11 @@ export async function createBuiltinMiddlewareTools(backend, options) {
638
661
  },
639
662
  });
640
663
  if (options.includeTaskTool && options.invokeTaskTool) {
664
+ const description = buildTaskToolDescription(options.taskSubagents);
641
665
  tools.set("task", {
642
666
  name: "task",
643
- description: "Delegate a bounded task to a subagent.",
644
- schema: taskToolSchema,
667
+ description,
668
+ schema: buildTaskToolSchema(options.taskSubagents),
645
669
  invoke: async (input) => options.invokeTaskTool(input),
646
670
  });
647
671
  }
@@ -58,6 +58,7 @@ export declare class AgentRuntimeAdapter {
58
58
  memoryContext?: string;
59
59
  }): Promise<RequestResult>;
60
60
  private tryDelegateWithCompactRouter;
61
+ private buildCompactDelegationReport;
61
62
  stream(binding: CompiledAgentBinding, input: MessageContent, sessionId: string, history?: TranscriptMessage[], options?: {
62
63
  context?: Record<string, unknown>;
63
64
  state?: Record<string, unknown>;
@@ -10,6 +10,7 @@ import { EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION } from "./prompts/runtim
10
10
  import { buildToolNameMapping, } from "./adapter/tool/tool-name-mapping.js";
11
11
  import { executeRequestInvocation } from "./adapter/flow/invocation-flow.js";
12
12
  import { streamRuntimeExecution } from "./adapter/flow/stream-runtime.js";
13
+ import { resolveDeterministicFinalOutput } from "./adapter/invocation-result.js";
13
14
  import { applyToolRecoveryInstruction as applyToolRecoveryInstructionHelper, applyStrictToolJsonInstruction as applyStrictToolJsonInstructionHelper, callRuntimeWithToolParseRecovery as callRuntimeWithToolParseRecoveryHelper, createModelFallbackRunnable as createModelFallbackRunnableHelper, invokeWithProviderRetry as invokeWithProviderRetryHelper, iterateWithTimeout as iterateWithTimeoutHelper, materializeModelStream as materializeModelStreamHelper, RuntimeOperationTimeoutError, withRuntimeTimeout, } from "./adapter/runtime-shell.js";
14
15
  import { extractSubagentRequestText, invokeBuiltinTaskTool as invokeBuiltinTaskToolHelper, materializeAutomaticSummarizationMiddleware as materializeAutomaticSummarizationMiddlewareHelper, resolveBuiltinMiddlewareBackend as resolveBuiltinMiddlewareBackendHelper, resolveBuiltinMiddlewareTools as resolveBuiltinMiddlewareToolsHelper, resolveLangChainRuntimeExtensionMiddleware as resolveLangChainRuntimeExtensionMiddlewareHelper, resolveMiddleware as resolveMiddlewareHelper, resolveSubagents as resolveSubagentsHelper, wrapRequestResultAsSubagentResponse, } from "./adapter/middleware-assembly.js";
15
16
  import { isEmptyFinalAiMessageError, resolveBindingTimeout, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
@@ -111,6 +112,15 @@ function parseCompactRouterSelection(value, subagentNames) {
111
112
  if (subagentNames.has(trimmed)) {
112
113
  return { subagentType: trimmed };
113
114
  }
115
+ const lowered = trimmed.toLowerCase();
116
+ const relaxedMatch = Array.from(subagentNames).find((name) => {
117
+ const lowerName = name.toLowerCase();
118
+ return lowerName.length > 0
119
+ && (trimmed === name || lowered.includes(lowerName));
120
+ });
121
+ if (relaxedMatch) {
122
+ return { subagentType: relaxedMatch };
123
+ }
114
124
  const parsed = parseFirstJsonObject(trimmed);
115
125
  const toolCall = salvageJsonToolCalls(trimmed).at(0);
116
126
  const payload = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
@@ -154,6 +164,29 @@ function hasDelegatedPlanEvidence(result) {
154
164
  return Array.isArray(toolResults)
155
165
  && toolResults.some((item) => item.toolName === "write_todos" || item.toolName === "read_todos");
156
166
  }
167
+ function resolveDelegatedResultOutput(result) {
168
+ const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
169
+ ? result.metadata.executedToolResults
170
+ : [];
171
+ const deterministicOutput = resolveDeterministicFinalOutput({
172
+ visibleOutput: typeof result.output === "string" ? result.output : "",
173
+ executedToolResults,
174
+ });
175
+ return deterministicOutput || result.output;
176
+ }
177
+ function selectDelegatedToolResultsForVisibleProgress(result) {
178
+ const executedToolResults = Array.isArray(result?.metadata?.executedToolResults)
179
+ ? result.metadata.executedToolResults
180
+ : [];
181
+ const hasSuccessfulExecutionEvidence = executedToolResults.some((toolResult) => (toolResult.isError !== true
182
+ && toolResult.toolName !== "write_todos"
183
+ && toolResult.toolName !== "read_todos"));
184
+ return hasSuccessfulExecutionEvidence
185
+ ? executedToolResults.filter((toolResult) => (toolResult.isError !== true
186
+ && toolResult.toolName !== "write_todos"
187
+ && toolResult.toolName !== "read_todos"))
188
+ : executedToolResults;
189
+ }
157
190
  export class AgentRuntimeAdapter {
158
191
  options;
159
192
  modelCache = new Map();
@@ -690,9 +723,10 @@ export class AgentRuntimeAdapter {
690
723
  requestId,
691
724
  });
692
725
  if (compactDelegation) {
693
- const output = typeof compactDelegation.toolOutput === "string"
726
+ const compactReport = this.buildCompactDelegationReport(compactDelegation);
727
+ const output = JSON.stringify(compactDelegation.delegatedSubagentType === null
694
728
  ? compactDelegation.toolOutput
695
- : JSON.stringify(compactDelegation.toolOutput);
729
+ : compactReport);
696
730
  const delegatedToolResults = Array.isArray(compactDelegation.delegatedResult?.metadata?.executedToolResults)
697
731
  ? compactDelegation.delegatedResult.metadata.executedToolResults
698
732
  : [];
@@ -789,10 +823,13 @@ export class AgentRuntimeAdapter {
789
823
  const subagentCatalog = subagents
790
824
  .map((subagent) => `- ${subagent.name}: ${subagent.description}`)
791
825
  .join("\n");
826
+ const routingPolicy = getBindingSystemPrompt(binding);
792
827
  const prompt = [
793
828
  primaryModel.init?.think === false ? "/no_think" : "",
794
829
  "You are selecting a subagent for a delegation-only agent.",
795
830
  "Choose exactly one listed subagent when it can responsibly handle the request.",
831
+ routingPolicy ? "Agent routing policy:" : "",
832
+ routingPolicy ?? "",
796
833
  "Return only JSON with this shape:",
797
834
  "{\"subagent_type\":\"<listed subagent name>\"}",
798
835
  "If no listed subagent can handle the request, return only:",
@@ -806,7 +843,7 @@ export class AgentRuntimeAdapter {
806
843
  if (typeof model.invoke !== "function") {
807
844
  return null;
808
845
  }
809
- const raw = await this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(prompt, resolveLangChainInvocationConfig(binding, {
846
+ const invokeRouter = async (activePrompt, operationName) => this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
810
847
  sessionId,
811
848
  requestId,
812
849
  context: options.context,
@@ -815,32 +852,49 @@ export class AgentRuntimeAdapter {
815
852
  sessionId,
816
853
  requestId,
817
854
  }),
818
- })), resolveBindingTimeout(binding), "delegation router invoke", "invoke"));
819
- const rawText = readModelText(raw);
820
- let selection = parseCompactRouterSelection(rawText, subagentNames);
821
- if (!selection) {
822
- const retryPrompt = [
855
+ })), resolveBindingTimeout(binding), operationName, "invoke"));
856
+ const routerPrompts = [
857
+ prompt,
858
+ [
823
859
  prompt,
824
860
  "Your previous router output was invalid.",
825
- "Previous output:",
826
- rawText,
827
861
  "Return only one JSON object now. Do not include prose, markdown, labels, or tool-call wrappers.",
828
- ].join("\n\n");
829
- const retryRaw = await this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(retryPrompt, resolveLangChainInvocationConfig(binding, {
830
- sessionId,
831
- requestId,
832
- context: options.context,
833
- toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
834
- ...options,
835
- sessionId,
836
- requestId,
837
- }),
838
- })), resolveBindingTimeout(binding), "delegation router retry invoke", "invoke"));
839
- selection = parseCompactRouterSelection(readModelText(retryRaw), subagentNames);
862
+ ].join("\n\n"),
863
+ [
864
+ primaryModel.init?.think === false ? "/no_think" : "",
865
+ "Select one subagent from this exact list:",
866
+ Array.from(subagentNames).join(", "),
867
+ "Return JSON only:",
868
+ "{\"subagent_type\":\"<one exact listed name>\"}",
869
+ "User request:",
870
+ requestText,
871
+ ].filter(Boolean).join("\n\n"),
872
+ [
873
+ primaryModel.init?.think === false ? "/no_think" : "",
874
+ "JSON only. Pick a listed subagent or refuse.",
875
+ "Listed subagents:",
876
+ Array.from(subagentNames).join(", "),
877
+ "Allowed outputs:",
878
+ "{\"subagent_type\":\"<listed name>\"}",
879
+ "{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
880
+ "Request:",
881
+ requestText,
882
+ ].filter(Boolean).join("\n\n"),
883
+ ];
884
+ let selection = null;
885
+ let previousRawText = "";
886
+ for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
887
+ const activePrompt = index <= 1 || !previousRawText
888
+ ? routerPrompts[index]
889
+ : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
890
+ const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
891
+ previousRawText = readModelText(raw);
892
+ selection = parseCompactRouterSelection(previousRawText, subagentNames);
840
893
  }
841
894
  if (selection?.refusedReason) {
842
895
  return {
843
896
  toolOutput: selection.refusedReason,
897
+ delegatedSubagentType: null,
844
898
  delegatedResult: {
845
899
  sessionId,
846
900
  requestId,
@@ -851,7 +905,16 @@ export class AgentRuntimeAdapter {
851
905
  },
852
906
  };
853
907
  }
854
- const subagentType = selection?.subagentType ?? "";
908
+ let subagentType = selection?.subagentType ?? "";
909
+ if (!subagentNames.has(subagentType)) {
910
+ const fallbackSubagent = subagentNames.values().next().value;
911
+ if (typeof fallbackSubagent === "string" && fallbackSubagent) {
912
+ subagentType = fallbackSubagent;
913
+ }
914
+ else {
915
+ return null;
916
+ }
917
+ }
855
918
  if (!subagentNames.has(subagentType)) {
856
919
  return null;
857
920
  }
@@ -865,15 +928,49 @@ export class AgentRuntimeAdapter {
865
928
  files: options.files,
866
929
  memoryContext: options.memoryContext,
867
930
  });
868
- let delegatedResult = await runDelegatedRequest(requestText);
931
+ let delegatedResult;
932
+ try {
933
+ delegatedResult = await runDelegatedRequest(requestText);
934
+ }
935
+ catch (error) {
936
+ const output = error instanceof Error ? error.message : String(error);
937
+ return {
938
+ toolOutput: output,
939
+ delegatedSubagentType: subagentType,
940
+ delegatedResult: {
941
+ sessionId,
942
+ requestId,
943
+ agentId: selectedBinding.agent.id,
944
+ state: "failed",
945
+ output,
946
+ finalMessageText: output,
947
+ },
948
+ };
949
+ }
869
950
  const targetRequiresExecutionToolEvidence = getBindingPrimaryTools(selectedBinding).length > 0;
870
951
  if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
871
- delegatedResult = await runDelegatedRequest([requestText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":tool-evidence-retry");
952
+ try {
953
+ delegatedResult = await runDelegatedRequest([requestText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":tool-evidence-retry");
954
+ }
955
+ catch (error) {
956
+ const output = error instanceof Error ? error.message : String(error);
957
+ return {
958
+ toolOutput: output,
959
+ delegatedSubagentType: subagentType,
960
+ delegatedResult: {
961
+ ...delegatedResult,
962
+ state: "failed",
963
+ output,
964
+ finalMessageText: output,
965
+ },
966
+ };
967
+ }
872
968
  }
873
969
  if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
874
970
  const output = `runtime_error=Delegated agent ${selectedBinding.agent.id} completed without tool execution evidence.`;
875
971
  return {
876
972
  toolOutput: output,
973
+ delegatedSubagentType: subagentType,
877
974
  delegatedResult: {
878
975
  ...delegatedResult,
879
976
  state: "failed",
@@ -888,6 +985,7 @@ export class AgentRuntimeAdapter {
888
985
  const output = "runtime_error=Delegated agent ended before producing required plan evidence.";
889
986
  return {
890
987
  toolOutput: output,
988
+ delegatedSubagentType: subagentType,
891
989
  delegatedResult: {
892
990
  ...delegatedResult,
893
991
  state: "failed",
@@ -896,7 +994,48 @@ export class AgentRuntimeAdapter {
896
994
  },
897
995
  };
898
996
  }
899
- return { toolOutput: delegatedResult.output, delegatedResult };
997
+ return {
998
+ toolOutput: resolveDelegatedResultOutput(delegatedResult),
999
+ delegatedSubagentType: subagentType,
1000
+ delegatedResult,
1001
+ };
1002
+ }
1003
+ buildCompactDelegationReport(compactDelegation) {
1004
+ const delegatedSubagentType = compactDelegation.delegatedSubagentType ?? "unknown";
1005
+ const delegatedOutput = typeof compactDelegation.toolOutput === "string"
1006
+ ? [compactDelegation.toolOutput]
1007
+ : [];
1008
+ const delegatedToolNames = Array.isArray(compactDelegation.delegatedResult?.metadata?.executedToolResults)
1009
+ ? compactDelegation.delegatedResult.metadata.executedToolResults
1010
+ .filter((toolResult) => toolResult?.toolName)
1011
+ .map((toolResult) => toolResult.toolName)
1012
+ : [];
1013
+ const state = compactDelegation.delegatedResult?.state === "failed" ? "failed" : "completed";
1014
+ return {
1015
+ status: state,
1016
+ routing: [
1017
+ `1) 路由判断: 已选择 sub-agent = ${delegatedSubagentType}(基于请求语义)。`,
1018
+ ],
1019
+ plan: [
1020
+ "1) 选择具备匹配能力的子代理并创建委托任务。",
1021
+ "2) 执行子代理的原生工作流并收集委托工具输出。",
1022
+ "3) 合成汇总报告并返回给用户。",
1023
+ ],
1024
+ execution: [
1025
+ `1) 调用 task 工具,目标子代理:${delegatedSubagentType}`,
1026
+ delegatedToolNames.length > 0
1027
+ ? `2) 子代理返回工具证据:${[...new Set(delegatedToolNames)].join(", ")}`
1028
+ : "2) 子代理返回文本结果。",
1029
+ "3) 产出主编排汇总并返回结构化结果。",
1030
+ ],
1031
+ summary: [
1032
+ `已完成子代理 ${delegatedSubagentType} 委托执行。`,
1033
+ ],
1034
+ findings: delegatedOutput.length > 0 ? delegatedOutput.slice(0, 3) : ["none"],
1035
+ blockers: state === "failed" ? ["子代理执行未能完成。"] : ["none"],
1036
+ nextActions: ["如需更深入,可继续追问该次委托的细节。"],
1037
+ report: delegatedOutput.join("\n") || "委托已完成,未返回附加报告。",
1038
+ };
900
1039
  }
901
1040
  async *stream(binding, input, sessionId, history = [], options = {}) {
902
1041
  const directListing = await this.tryHandleDirectWorkspaceListing(binding, input, {
@@ -916,12 +1055,19 @@ export class AgentRuntimeAdapter {
916
1055
  };
917
1056
  return;
918
1057
  }
1058
+ if (isDelegationOnlyDeepAgentBinding(binding)) {
1059
+ yield {
1060
+ kind: "commentary",
1061
+ content: "Selecting a specialist for delegated execution.",
1062
+ };
1063
+ }
919
1064
  const compactDelegation = await this.tryDelegateWithCompactRouter(binding, input, sessionId, options.requestId ?? sessionId, {
920
1065
  ...options,
921
1066
  sessionId,
922
1067
  requestId: options.requestId,
923
1068
  });
924
1069
  if (compactDelegation) {
1070
+ const compactReport = this.buildCompactDelegationReport(compactDelegation);
925
1071
  yield {
926
1072
  kind: "tool-result",
927
1073
  toolName: "task",
@@ -929,9 +1075,9 @@ export class AgentRuntimeAdapter {
929
1075
  };
930
1076
  yield {
931
1077
  kind: "content",
932
- content: typeof compactDelegation.toolOutput === "string"
1078
+ content: JSON.stringify(compactDelegation.delegatedSubagentType === null
933
1079
  ? compactDelegation.toolOutput
934
- : JSON.stringify(compactDelegation.toolOutput),
1080
+ : compactReport),
935
1081
  };
936
1082
  return;
937
1083
  }
@@ -1,5 +1,5 @@
1
1
  import { createFallbackRequestResultFromLatestEvent, mergeRequestResultOutput } from "../run/helpers.js";
2
- import { applyRequestStreamItemToSnapshot, createInitialRequestEventSnapshot, toRequestDataEvent, } from "../../../projections/request-events.js";
2
+ import { applyRequestStreamItemToSnapshot, createInitialRequestEventSnapshot, toRequestDataEvents, } from "../../../projections/request-events.js";
3
3
  export async function emitOutputDeltaAndCreateItem(emit, sessionId, requestId, agentId, content) {
4
4
  await emit(sessionId, requestId, 3, "output.delta", {
5
5
  content,
@@ -71,8 +71,7 @@ export async function dispatchRequestListeners(stream, listeners, options) {
71
71
  else if (item.type === "content") {
72
72
  output += item.content;
73
73
  }
74
- const dataEvent = toRequestDataEvent(item);
75
- if (dataEvent) {
74
+ for (const dataEvent of toRequestDataEvents(item)) {
76
75
  await notifyIfPresent(listeners.dataListener, dataEvent);
77
76
  }
78
77
  await notifyIfPresent(listeners.eventListener, snapshot);
@@ -5,7 +5,7 @@ import { compileModel, compileTool } from "./resource-compilers.js";
5
5
  import { inferAgentCapabilities } from "./support/agent-capabilities.js";
6
6
  import { getAgentExecutionConfigValue, getAgentExecutionObject, getAgentExecutionString } from "./support/agent-execution-config.js";
7
7
  import { discoverSkillPaths } from "./support/discovery.js";
8
- import { compileAgentMemories, getProceduralMemoryDefaults, getResilienceConfig, getRuntimeDefaults, getRuntimeMemoryDefaults, getRuntimeStorageRoots, getWorkspaceObject, resolvePromptValue, resolveRefId, } from "./support/workspace-ref-utils.js";
8
+ import { compileAgentMemories, getProceduralMemoryDefaults, getResilienceConfig, getRuntimeAgentDefaults, getRuntimeDefaults, getRuntimeMemoryDefaults, getRuntimeStorageRoots, getWorkspaceObject, resolvePromptValue, resolveRefId, } from "./support/workspace-ref-utils.js";
9
9
  import { WORKSPACE_BOUNDARY_GUIDANCE } from "../runtime/prompts/runtime-prompts.js";
10
10
  function requireSkills(pathEntries, workspaceRoot) {
11
11
  return Array.from(new Set(discoverSkillPaths(pathEntries, workspaceRoot)));
@@ -166,8 +166,8 @@ export function requireTools(tools, bindings, ownerId) {
166
166
  }
167
167
  return Array.from(deduped.values());
168
168
  }
169
- function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parentModel) {
170
- const execution = compileExecutionCore(agent, workspaceRoot, models, tools);
169
+ function buildSubagent(agent, workspaceRoot, refs, models, tools, parentSkills, parentModel) {
170
+ const execution = compileExecutionCore(agent, workspaceRoot, refs, models, tools);
171
171
  return {
172
172
  agentId: agent.id,
173
173
  name: resolveAgentRuntimeName(agent),
@@ -196,6 +196,84 @@ function resolveInterruptOn(agent) {
196
196
  function resolveResponseFormat(agent) {
197
197
  return getAgentExecutionConfigValue(agent, "responseFormat");
198
198
  }
199
+ function normalizeResponseFormatRef(ref) {
200
+ return ref.startsWith("response-format/") ? ref : `response-format/${ref}`;
201
+ }
202
+ function resolveResponseFormatObject(refs, ref, ownerLabel) {
203
+ if (!ref) {
204
+ return undefined;
205
+ }
206
+ const object = getWorkspaceObject(refs, normalizeResponseFormatRef(ref));
207
+ if (!object) {
208
+ throw new Error(`${ownerLabel} responseFormatRef references missing object ${ref}`);
209
+ }
210
+ if (object.kind !== "response-format") {
211
+ throw new Error(`${ownerLabel} responseFormatRef references ${ref}, but expected response-format`);
212
+ }
213
+ if (!("format" in object.value)) {
214
+ throw new Error(`${ownerLabel} responseFormatRef ${ref} must define format`);
215
+ }
216
+ return object.value.format;
217
+ }
218
+ function mergeResponseFormats(base, override) {
219
+ if (override === undefined) {
220
+ return base;
221
+ }
222
+ if (typeof base === "object" &&
223
+ base &&
224
+ typeof override === "object" &&
225
+ override &&
226
+ !Array.isArray(base) &&
227
+ !Array.isArray(override)) {
228
+ const merged = { ...base };
229
+ for (const [key, value] of Object.entries(override)) {
230
+ if (key === "required" && Array.isArray(merged.required) && Array.isArray(value)) {
231
+ merged.required = Array.from(new Set([...merged.required, ...value]));
232
+ continue;
233
+ }
234
+ if (key === "properties" &&
235
+ typeof merged.properties === "object" &&
236
+ merged.properties &&
237
+ !Array.isArray(merged.properties) &&
238
+ typeof value === "object" &&
239
+ value &&
240
+ !Array.isArray(value)) {
241
+ merged.properties = {
242
+ ...merged.properties,
243
+ ...value,
244
+ };
245
+ continue;
246
+ }
247
+ merged[key] = key in merged ? mergeResponseFormats(merged[key], value) : value;
248
+ }
249
+ return merged;
250
+ }
251
+ return override;
252
+ }
253
+ function resolveInheritedResponseFormat(agent, refs) {
254
+ const defaults = getRuntimeAgentDefaults(refs);
255
+ if (defaults && "responseFormat" in defaults) {
256
+ return defaults.responseFormat === null ? undefined : defaults.responseFormat;
257
+ }
258
+ const defaultRef = typeof defaults?.responseFormatRef === "string" ? defaults.responseFormatRef.trim() : "";
259
+ if (defaultRef) {
260
+ return resolveResponseFormatObject(refs, defaultRef, "Runtime defaults.agent.config");
261
+ }
262
+ return undefined;
263
+ }
264
+ function resolveEffectiveResponseFormat(agent, refs) {
265
+ const explicitResponseFormat = resolveResponseFormat(agent);
266
+ if (explicitResponseFormat !== undefined) {
267
+ return explicitResponseFormat === null
268
+ ? undefined
269
+ : mergeResponseFormats(resolveInheritedResponseFormat(agent, refs), explicitResponseFormat);
270
+ }
271
+ const explicitRef = getAgentExecutionConfigValue(agent, "responseFormatRef");
272
+ if (typeof explicitRef === "string" && explicitRef.trim().length > 0) {
273
+ return resolveResponseFormatObject(refs, explicitRef.trim(), `Agent ${agent.id}`);
274
+ }
275
+ return resolveInheritedResponseFormat(agent, refs);
276
+ }
199
277
  function resolveContextSchema(agent) {
200
278
  return getAgentExecutionConfigValue(agent, "contextSchema");
201
279
  }
@@ -216,13 +294,13 @@ function resolvePassthrough(agent) {
216
294
  const passthrough = getAgentExecutionObject(agent, "passthrough");
217
295
  return passthrough ? { ...passthrough } : undefined;
218
296
  }
219
- function compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel) {
297
+ function compileSubagents(agent, agents, workspaceRoot, refs, models, tools, compiledAgentSkills, compiledAgentModel) {
220
298
  return agent.subagentRefs.map((ref) => {
221
299
  const subagent = agents.get(resolveRefId(ref));
222
300
  if (!subagent) {
223
301
  throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
224
302
  }
225
- return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel);
303
+ return buildSubagent(subagent, workspaceRoot, refs, models, tools, compiledAgentSkills, compiledAgentModel);
226
304
  });
227
305
  }
228
306
  function compileAsyncSubagents(agent) {
@@ -234,18 +312,18 @@ function compileAsyncSubagents(agent) {
234
312
  ...(subagent.headers ? { headers: { ...subagent.headers } } : {}),
235
313
  }));
236
314
  }
237
- function compileDeepAgentSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel) {
315
+ function compileDeepAgentSubagents(agent, agents, workspaceRoot, refs, models, tools, compiledAgentSkills, compiledAgentModel) {
238
316
  return [
239
- ...compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel),
317
+ ...compileSubagents(agent, agents, workspaceRoot, refs, models, tools, compiledAgentSkills, compiledAgentModel),
240
318
  ...compileAsyncSubagents(agent),
241
319
  ];
242
320
  }
243
- function compileExecutionCore(agent, workspaceRoot, models, tools) {
321
+ function compileExecutionCore(agent, workspaceRoot, refs, models, tools) {
244
322
  return {
245
323
  model: requireModel(models, agent.modelRef, agent.id),
246
324
  tools: requireTools(tools, getAgentToolBindings(agent), agent.id),
247
325
  systemPrompt: resolveSystemPrompt(agent, workspaceRoot),
248
- responseFormat: resolveResponseFormat(agent),
326
+ responseFormat: resolveEffectiveResponseFormat(agent, refs),
249
327
  contextSchema: resolveContextSchema(agent),
250
328
  middleware: resolveCompiledMiddleware(agent, models),
251
329
  };
@@ -395,7 +473,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
395
473
  const executionCore = compileExecutionCore({
396
474
  ...agent,
397
475
  modelRef: agent.modelRef || (internalSubagent ? "model/default" : ""),
398
- }, workspaceRoot, models, tools);
476
+ }, workspaceRoot, refs, models, tools);
399
477
  const passthrough = resolvePassthrough(agent);
400
478
  const compiledAgentModel = executionCore.model;
401
479
  const backend = resolveBackendConfig(agent, refs);
@@ -442,7 +520,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
442
520
  passthrough,
443
521
  interruptOn: resolveInterruptOn(agent),
444
522
  filesystem: compiledFilesystemConfig,
445
- subagents: compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel),
523
+ subagents: compileSubagents(agent, agents, workspaceRoot, refs, models, tools, compiledAgentSkills, compiledAgentModel),
446
524
  memory: compiledAgentMemory,
447
525
  skills: compiledAgentSkills,
448
526
  generalPurposeAgent: getAgentExecutionConfigValue(agent, "generalPurposeAgent", { executionMode: "langchain-v1" }),
@@ -491,7 +569,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
491
569
  responseFormat: executionCore.responseFormat,
492
570
  contextSchema: executionCore.contextSchema,
493
571
  middleware: executionCore.middleware,
494
- subagents: compileDeepAgentSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel),
572
+ subagents: compileDeepAgentSubagents(agent, agents, workspaceRoot, refs, models, tools, compiledAgentSkills, compiledAgentModel),
495
573
  interruptOn: resolveInterruptOn(agent),
496
574
  ...(backend ? { backend: backend.config } : {}),
497
575
  ...(store ? { store: store.config } : {}),
@@ -425,6 +425,7 @@ export async function loadWorkspace(workspaceRoot, options = {}) {
425
425
  tools,
426
426
  skillRegistry,
427
427
  ownedRoots: contractOwnedRoots,
428
+ refs: loaded.refs,
428
429
  mode: frameworkContractValidation,
429
430
  });
430
431
  }, {
@@ -1,4 +1,4 @@
1
- import type { ParsedAgentObject, ParsedToolObject } from "../contracts/types.js";
1
+ import type { ParsedAgentObject, ParsedToolObject, WorkspaceObject } from "../contracts/types.js";
2
2
  export type FrameworkContractValidationMode = "off" | "warn" | "error";
3
3
  export declare function resolveFrameworkContractValidationMode(mode: FrameworkContractValidationMode | undefined): FrameworkContractValidationMode;
4
4
  export declare function validateFrameworkContracts(input: {
@@ -6,5 +6,6 @@ export declare function validateFrameworkContracts(input: {
6
6
  tools: Map<string, ParsedToolObject>;
7
7
  skillRegistry: Map<string, string>;
8
8
  ownedRoots: string[];
9
+ refs?: Map<string, WorkspaceObject | ParsedAgentObject>;
9
10
  mode?: FrameworkContractValidationMode;
10
11
  }): void;