@botbotgo/agent-harness 0.0.420 → 0.0.421
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.
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/flow/invocation-flow.d.ts +10 -0
- package/dist/runtime/adapter/flow/invocation-flow.js +2 -0
- package/dist/runtime/adapter/flow/invoke-runtime.d.ts +10 -0
- package/dist/runtime/adapter/flow/invoke-runtime.js +2 -0
- package/dist/runtime/adapter/flow/stream-runtime.d.ts +20 -0
- package/dist/runtime/adapter/flow/stream-runtime.js +201 -3
- package/dist/runtime/adapter/local-tool-invocation.d.ts +11 -1
- package/dist/runtime/adapter/local-tool-invocation.js +221 -9
- package/dist/runtime/adapter/middleware-assembly.js +294 -20
- package/dist/runtime/agent-runtime-adapter.js +657 -48
- package/dist/runtime/agent-runtime-assembly.js +1 -1
- package/dist/runtime/harness/run/inspection.js +9 -1
- package/package.json +1 -1
|
@@ -41,31 +41,43 @@ function hasDelegatedExecutionToolEvidence(result) {
|
|
|
41
41
|
&& !isPlanToolName(toolResult.toolName)));
|
|
42
42
|
}
|
|
43
43
|
function buildDelegatedPlanEvidenceBlocker(agentId) {
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
44
|
+
return JSON.stringify({
|
|
45
|
+
status: "blocked",
|
|
46
|
+
routing: [`delegated agent ${agentId}`],
|
|
47
|
+
plan: ["delegate to specialist", "require visible TODO planning evidence", "return blocker when planning evidence is absent"],
|
|
48
|
+
execution: [`task delegated to ${agentId}`, `delegated agent ${agentId} ended before producing required TODO plan evidence`],
|
|
49
|
+
todoTrace: ["TODO evidence missing"],
|
|
50
|
+
stepResults: ["delegated planning evidence was not observed"],
|
|
51
|
+
summary: [`Delegated agent ${agentId} ended before producing the required TODO plan evidence.`],
|
|
52
|
+
findings: ["The delegated run did not expose a valid planning trace, so the framework cannot treat the task as complete."],
|
|
53
|
+
blockers: ["missing delegated TODO planning evidence"],
|
|
54
|
+
nextActions: ["Retry with the same request or inspect the delegated agent configuration and model/tool-call behavior."],
|
|
55
|
+
report: `routing delegated to ${agentId}; todoTrace missing; stepResults blocked; summary missing planning evidence; findings require retry; blockers missing TODO planning evidence; nextActions inspect delegated model/tool behavior; report task delegated to ${agentId}.`,
|
|
56
|
+
});
|
|
55
57
|
}
|
|
56
|
-
function buildDelegatedExecutionEvidenceBlocker(agentId) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"",
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"
|
|
68
|
-
|
|
58
|
+
function buildDelegatedExecutionEvidenceBlocker(agentId, expectedToolNames = []) {
|
|
59
|
+
const expectedTools = expectedToolNames.length > 0 ? expectedToolNames.join(", ") : "configured non-planning tools";
|
|
60
|
+
return JSON.stringify({
|
|
61
|
+
status: "blocked",
|
|
62
|
+
routing: [`delegated agent ${agentId}`],
|
|
63
|
+
plan: ["delegate to specialist", "require non-planning tool evidence", "return blocker when evidence is absent"],
|
|
64
|
+
execution: [
|
|
65
|
+
`task delegated to ${agentId}`,
|
|
66
|
+
`expected evidence tools: ${expectedTools}`,
|
|
67
|
+
`delegated agent ${agentId} did not return any non-planning tool evidence after retry`,
|
|
68
|
+
],
|
|
69
|
+
todoTrace: ["TODO board observed without completed non-planning evidence"],
|
|
70
|
+
stepResults: ["delegated execution evidence was not observed"],
|
|
71
|
+
summary: [`Delegated agent ${agentId} did not return any non-planning tool evidence after retry.`],
|
|
72
|
+
findings: [
|
|
73
|
+
`Expected evidence tools from configuration: ${expectedTools}.`,
|
|
74
|
+
"The TODO board alone is not execution evidence.",
|
|
75
|
+
"The framework cannot mark the delegated task complete without a non-planning tool result or an explicit blocker from that tool path.",
|
|
76
|
+
],
|
|
77
|
+
blockers: ["missing delegated non-planning tool evidence"],
|
|
78
|
+
nextActions: ["Retry the request or inspect the delegated agent's model/tool-call behavior."],
|
|
79
|
+
report: `routing delegated to ${agentId}; todoTrace observed planning only; stepResults blocked; summary missing non-planning tool evidence; findings expected evidence tools ${expectedTools}; blockers missing execution evidence; nextActions inspect delegated model/tool behavior; report task delegated to ${agentId}.`,
|
|
80
|
+
});
|
|
69
81
|
}
|
|
70
82
|
function normalizePlanToolName(toolName) {
|
|
71
83
|
return typeof toolName === "string" ? toolName.trim().toLowerCase().replace(/[\s-]+/gu, "_") : "";
|
|
@@ -398,15 +410,14 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
398
410
|
if (subagentNames.has(trimmed)) {
|
|
399
411
|
return { subagentType: trimmed };
|
|
400
412
|
}
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
413
|
+
const resolveRelaxedMatch = () => {
|
|
414
|
+
const lowered = trimmed.toLowerCase();
|
|
415
|
+
return Array.from(subagentNames).find((name) => {
|
|
416
|
+
const lowerName = name.toLowerCase();
|
|
417
|
+
return lowerName.length > 0
|
|
418
|
+
&& (trimmed === name || lowered.includes(lowerName));
|
|
419
|
+
});
|
|
420
|
+
};
|
|
410
421
|
const parsed = parseFirstJsonObject(trimmed);
|
|
411
422
|
const toolCall = salvageJsonToolCalls(trimmed).at(0);
|
|
412
423
|
const payload = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
@@ -415,7 +426,8 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
415
426
|
? { name: toolCall.name, arguments: toolCall.args }
|
|
416
427
|
: null;
|
|
417
428
|
if (!payload) {
|
|
418
|
-
|
|
429
|
+
const relaxedMatch = resolveRelaxedMatch();
|
|
430
|
+
return relaxedMatch ? { subagentType: relaxedMatch } : null;
|
|
419
431
|
}
|
|
420
432
|
const args = typeof payload.arguments === "object" && payload.arguments !== null && !Array.isArray(payload.arguments)
|
|
421
433
|
? payload.arguments
|
|
@@ -430,6 +442,48 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
430
442
|
if (subagentNames.has(subagentType)) {
|
|
431
443
|
return { subagentType };
|
|
432
444
|
}
|
|
445
|
+
const rawDelegations = Array.isArray(payload.delegations)
|
|
446
|
+
? payload.delegations
|
|
447
|
+
: Array.isArray(args.delegations)
|
|
448
|
+
? args.delegations
|
|
449
|
+
: undefined;
|
|
450
|
+
if (rawDelegations) {
|
|
451
|
+
const delegations = rawDelegations
|
|
452
|
+
.map((item) => {
|
|
453
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) {
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
const typed = item;
|
|
457
|
+
const rawName = typeof typed.subagent_type === "string"
|
|
458
|
+
? typed.subagent_type.trim()
|
|
459
|
+
: typeof typed.subagent === "string"
|
|
460
|
+
? typed.subagent.trim()
|
|
461
|
+
: "";
|
|
462
|
+
const resolvedName = Array.from(subagentNames).find((name) => name.toLowerCase() === rawName.toLowerCase());
|
|
463
|
+
if (!resolvedName) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
const description = typeof typed.description === "string" && typed.description.trim()
|
|
467
|
+
? typed.description.trim()
|
|
468
|
+
: typeof typed.task === "string" && typed.task.trim()
|
|
469
|
+
? typed.task.trim()
|
|
470
|
+
: typeof typed.instruction === "string" && typed.instruction.trim()
|
|
471
|
+
? typed.instruction.trim()
|
|
472
|
+
: "";
|
|
473
|
+
return { subagentType: resolvedName, description };
|
|
474
|
+
})
|
|
475
|
+
.filter((item) => item !== null);
|
|
476
|
+
const deduped = [];
|
|
477
|
+
for (const delegation of delegations) {
|
|
478
|
+
if (deduped.some((item) => item.subagentType === delegation.subagentType)) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
deduped.push(delegation);
|
|
482
|
+
}
|
|
483
|
+
if (deduped.length > 0) {
|
|
484
|
+
return { delegations: deduped };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
433
487
|
const status = typeof payload.status === "string" ? payload.status.trim().toLowerCase() : "";
|
|
434
488
|
if (status === "refused") {
|
|
435
489
|
const reason = typeof payload.reason === "string" && payload.reason.trim()
|
|
@@ -437,6 +491,10 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
437
491
|
: "No configured subagent can handle the request.";
|
|
438
492
|
return { refusedReason: reason };
|
|
439
493
|
}
|
|
494
|
+
const relaxedMatch = resolveRelaxedMatch();
|
|
495
|
+
if (relaxedMatch) {
|
|
496
|
+
return { subagentType: relaxedMatch };
|
|
497
|
+
}
|
|
440
498
|
return null;
|
|
441
499
|
}
|
|
442
500
|
function inferCompactRouterSelectionFromRequest(requestText, subagents) {
|
|
@@ -468,6 +526,176 @@ function inferCompactRouterSelectionFromRequest(requestText, subagents) {
|
|
|
468
526
|
}
|
|
469
527
|
return ranked[0].name;
|
|
470
528
|
}
|
|
529
|
+
function inferCompactRouterDelegationPlanFromRequest(requestText, subagents, routingPolicy) {
|
|
530
|
+
const normalizedRequest = requestText.toLowerCase();
|
|
531
|
+
const numberedClauses = requestText
|
|
532
|
+
.split(/\r?\n/u)
|
|
533
|
+
.map((item) => item.trim())
|
|
534
|
+
.filter((item) => /^\d+\s*[.)、.]\s*/u.test(item));
|
|
535
|
+
const clauses = (numberedClauses.length > 1 ? numberedClauses : requestText
|
|
536
|
+
.split(/\r?\n|[。;;]\s*/u))
|
|
537
|
+
.map((item) => item.trim())
|
|
538
|
+
.filter((item) => item.length > 0);
|
|
539
|
+
if (clauses.length <= 1) {
|
|
540
|
+
return [];
|
|
541
|
+
}
|
|
542
|
+
for (const subagent of subagents) {
|
|
543
|
+
const escapedName = escapeRegExp(subagent.name);
|
|
544
|
+
const ownerPerspectivePattern = new RegExp(`(?:从\\s*\`?${escapedName}\`?\\s*角度|as\\s+(?:the\\s+)?\`?${escapedName}\`?|from\\s+(?:the\\s+)?\`?${escapedName}\`?\\s+perspective)`, "iu");
|
|
545
|
+
if (ownerPerspectivePattern.test(requestText)) {
|
|
546
|
+
return [];
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
const policyLineFor = (subagentName) => {
|
|
550
|
+
if (!routingPolicy) {
|
|
551
|
+
return "";
|
|
552
|
+
}
|
|
553
|
+
const escapedName = escapeRegExp(subagentName);
|
|
554
|
+
const match = new RegExp(`(?:^|\\n)\\s*[-*]\\s*\`?${escapedName}\`?\\s*[::]\\s*([^\\n]+)`, "iu").exec(routingPolicy);
|
|
555
|
+
return match?.[1] ?? "";
|
|
556
|
+
};
|
|
557
|
+
const scoreText = (text, signals, subagentName) => {
|
|
558
|
+
const normalized = text.toLowerCase();
|
|
559
|
+
let value = normalized.includes(subagentName.toLowerCase()) ? 10 : 0;
|
|
560
|
+
for (const signal of signals) {
|
|
561
|
+
if (normalized.includes(signal)) {
|
|
562
|
+
value += /[\p{Script=Han}]/u.test(signal)
|
|
563
|
+
? Math.min(6, Math.max(2, signal.length))
|
|
564
|
+
: Math.min(5, Math.max(2, Math.floor(signal.length / 2)));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return value;
|
|
568
|
+
};
|
|
569
|
+
const subagentSignals = subagents.map((subagent) => {
|
|
570
|
+
const signalText = [
|
|
571
|
+
subagent.name,
|
|
572
|
+
subagent.description ?? "",
|
|
573
|
+
policyLineFor(subagent.name),
|
|
574
|
+
].join(" ");
|
|
575
|
+
return {
|
|
576
|
+
name: subagent.name,
|
|
577
|
+
signals: extractRouterMatchSignals(signalText),
|
|
578
|
+
globalScore: 0,
|
|
579
|
+
};
|
|
580
|
+
});
|
|
581
|
+
for (const item of subagentSignals) {
|
|
582
|
+
item.globalScore = scoreText(normalizedRequest, item.signals, item.name);
|
|
583
|
+
}
|
|
584
|
+
const ordered = [];
|
|
585
|
+
const pushUnique = (subagentType, description) => {
|
|
586
|
+
if (ordered.some((item) => item.subagentType === subagentType)) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
ordered.push({ subagentType, description: description.trim() || requestText });
|
|
590
|
+
};
|
|
591
|
+
for (const clause of clauses) {
|
|
592
|
+
const ranked = subagentSignals
|
|
593
|
+
.map((item) => ({ name: item.name, score: scoreText(clause, item.signals, item.name) }))
|
|
594
|
+
.filter((item) => item.score >= 4)
|
|
595
|
+
.sort((left, right) => right.score - left.score);
|
|
596
|
+
const top = ranked[0];
|
|
597
|
+
if (top) {
|
|
598
|
+
pushUnique(top.name, clause);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (ordered.length <= 1 && numberedClauses.length > 1) {
|
|
602
|
+
ordered.length = 0;
|
|
603
|
+
for (const clause of numberedClauses) {
|
|
604
|
+
const ranked = subagentSignals
|
|
605
|
+
.map((item) => ({ name: item.name, score: scoreText(clause, item.signals, item.name) }))
|
|
606
|
+
.filter((item) => item.score > 0)
|
|
607
|
+
.sort((left, right) => right.score - left.score);
|
|
608
|
+
const top = ranked[0];
|
|
609
|
+
if (top) {
|
|
610
|
+
pushUnique(top.name, clause);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
for (const item of subagentSignals
|
|
615
|
+
.filter((candidate) => candidate.globalScore >= 6)
|
|
616
|
+
.sort((left, right) => right.globalScore - left.globalScore)) {
|
|
617
|
+
pushUnique(item.name, requestText);
|
|
618
|
+
}
|
|
619
|
+
if (ordered.length <= 1 && numberedClauses.length >= 3 && subagents.length > 1) {
|
|
620
|
+
return subagents.map((subagent, index) => ({
|
|
621
|
+
subagentType: subagent.name,
|
|
622
|
+
description: numberedClauses[index] ?? requestText,
|
|
623
|
+
}));
|
|
624
|
+
}
|
|
625
|
+
return ordered.length > 1 ? ordered : [];
|
|
626
|
+
}
|
|
627
|
+
function resolveSingleExplicitOwnerMention(requestText, subagentNames) {
|
|
628
|
+
const numberedClauses = requestText
|
|
629
|
+
.split(/\r?\n/u)
|
|
630
|
+
.map((item) => item.trim())
|
|
631
|
+
.filter((item) => /^\d+\s*[.)、.]\s*/u.test(item));
|
|
632
|
+
if (numberedClauses.length > 1) {
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
const matches = [];
|
|
636
|
+
for (const subagentName of subagentNames) {
|
|
637
|
+
const escapedName = escapeRegExp(subagentName);
|
|
638
|
+
const pattern = new RegExp(`(?:^|[^\\p{L}\\p{N}_-])\`?${escapedName}\`?(?:$|[^\\p{L}\\p{N}_-])`, "iu");
|
|
639
|
+
if (pattern.test(requestText)) {
|
|
640
|
+
matches.push(subagentName);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return matches.length === 1 ? matches[0] : null;
|
|
644
|
+
}
|
|
645
|
+
function extractExplicitSubagentTasks(requestText, subagentNames) {
|
|
646
|
+
const lines = requestText.split(/\r?\n/u);
|
|
647
|
+
const tasks = [];
|
|
648
|
+
let current = null;
|
|
649
|
+
const marker = new RegExp(`^\\s*(?:[-*]|\\d+[.)]|\\d+\\s*[、.])?\\s*(${Array.from(subagentNames).map(escapeRegExp).join("|")})\\s*[::]\\s*(.*)$`, "iu");
|
|
650
|
+
for (const line of lines) {
|
|
651
|
+
const match = marker.exec(line);
|
|
652
|
+
if (match?.[1]) {
|
|
653
|
+
if (current) {
|
|
654
|
+
tasks.push({ subagentType: current.subagentType, text: current.parts.join("\n").trim() });
|
|
655
|
+
}
|
|
656
|
+
const subagentType = Array.from(subagentNames).find((name) => name.toLowerCase() === match[1].toLowerCase()) ?? match[1];
|
|
657
|
+
current = { subagentType, parts: [match[2] ?? ""] };
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if (current && line.trim()) {
|
|
661
|
+
current.parts.push(line);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (current) {
|
|
665
|
+
tasks.push({ subagentType: current.subagentType, text: current.parts.join("\n").trim() });
|
|
666
|
+
}
|
|
667
|
+
const deduped = [];
|
|
668
|
+
for (const task of tasks) {
|
|
669
|
+
if (!subagentNames.has(task.subagentType) || deduped.some((item) => item.subagentType === task.subagentType)) {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
deduped.push({ subagentType: task.subagentType, text: task.text || requestText });
|
|
673
|
+
}
|
|
674
|
+
return deduped;
|
|
675
|
+
}
|
|
676
|
+
function buildDelegatedOwnedTaskInstruction(input) {
|
|
677
|
+
const relevantPolicyLines = (input.routingPolicy ?? "")
|
|
678
|
+
.split(/\r?\n/u)
|
|
679
|
+
.map((line) => line.trim())
|
|
680
|
+
.filter((line) => line.includes(`\`${input.subagentType}\``)
|
|
681
|
+
|| line.includes(` ${input.subagentType} `)
|
|
682
|
+
|| line.toLowerCase().includes(`to ${input.subagentType}`))
|
|
683
|
+
.slice(0, 8);
|
|
684
|
+
return [
|
|
685
|
+
`Delegated owner: ${input.subagentType}.`,
|
|
686
|
+
"Execute only this owner's bounded portion of the larger request.",
|
|
687
|
+
"Do not take over other specialist-owned work; return blockers for missing access instead of inventing success.",
|
|
688
|
+
"Owned subtask:",
|
|
689
|
+
input.taskText.trim() || input.originalRequest,
|
|
690
|
+
relevantPolicyLines.length > 0 ? "Relevant parent routing/delegation policy for this owner:" : "",
|
|
691
|
+
...relevantPolicyLines,
|
|
692
|
+
"If the owner policy or tool contract requires evidence, call write_todos first and then execute the appropriate non-planning evidence tool before any final answer.",
|
|
693
|
+
"Close every TODO as completed or failed before final output.",
|
|
694
|
+
].filter(Boolean).join("\n");
|
|
695
|
+
}
|
|
696
|
+
function escapeRegExp(value) {
|
|
697
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
698
|
+
}
|
|
471
699
|
function extractRouterMatchTokens(value) {
|
|
472
700
|
const tokens = new Set();
|
|
473
701
|
for (const match of value.matchAll(/[\p{L}\p{N}_-]+/gu)) {
|
|
@@ -478,6 +706,67 @@ function extractRouterMatchTokens(value) {
|
|
|
478
706
|
}
|
|
479
707
|
return tokens;
|
|
480
708
|
}
|
|
709
|
+
function extractRouterMatchSignals(value) {
|
|
710
|
+
const signals = extractRouterMatchTokens(value);
|
|
711
|
+
const stopSignals = new Set([
|
|
712
|
+
"the",
|
|
713
|
+
"and",
|
|
714
|
+
"for",
|
|
715
|
+
"with",
|
|
716
|
+
"owner",
|
|
717
|
+
"primary",
|
|
718
|
+
"route",
|
|
719
|
+
"agent",
|
|
720
|
+
"tool",
|
|
721
|
+
"tools",
|
|
722
|
+
"todo",
|
|
723
|
+
"json",
|
|
724
|
+
"status",
|
|
725
|
+
"report",
|
|
726
|
+
"final",
|
|
727
|
+
"output",
|
|
728
|
+
"failed",
|
|
729
|
+
"blocked",
|
|
730
|
+
"work",
|
|
731
|
+
"request",
|
|
732
|
+
"user",
|
|
733
|
+
"负责",
|
|
734
|
+
"不是",
|
|
735
|
+
"用户",
|
|
736
|
+
"请求",
|
|
737
|
+
"当前",
|
|
738
|
+
"输出",
|
|
739
|
+
"证据",
|
|
740
|
+
"使用",
|
|
741
|
+
"必须",
|
|
742
|
+
"一个",
|
|
743
|
+
"如果",
|
|
744
|
+
"需要",
|
|
745
|
+
"工作",
|
|
746
|
+
"总结",
|
|
747
|
+
"分析",
|
|
748
|
+
"最终",
|
|
749
|
+
"相关",
|
|
750
|
+
"工具",
|
|
751
|
+
"执行",
|
|
752
|
+
"结果",
|
|
753
|
+
]);
|
|
754
|
+
for (const stopSignal of stopSignals) {
|
|
755
|
+
signals.delete(stopSignal);
|
|
756
|
+
}
|
|
757
|
+
for (const match of value.matchAll(/[\p{Script=Han}]{2,}/gu)) {
|
|
758
|
+
const sequence = match[0];
|
|
759
|
+
for (let size = 2; size <= Math.min(4, sequence.length); size += 1) {
|
|
760
|
+
for (let index = 0; index <= sequence.length - size; index += 1) {
|
|
761
|
+
const signal = sequence.slice(index, index + size);
|
|
762
|
+
if (!stopSignals.has(signal)) {
|
|
763
|
+
signals.add(signal);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return signals;
|
|
769
|
+
}
|
|
481
770
|
function isDelegationOnlyDeepAgentBinding(binding) {
|
|
482
771
|
return isDeepAgentBinding(binding)
|
|
483
772
|
&& getBindingSubagents(binding).length > 0
|
|
@@ -549,6 +838,12 @@ const DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION = [
|
|
|
549
838
|
"Before any other tool call or final answer, call write_todos with concrete task steps and statuses.",
|
|
550
839
|
"Then continue the task to completion, update TODO statuses after evidence steps, and close every TODO as completed or failed before the final answer.",
|
|
551
840
|
].join("\n");
|
|
841
|
+
function looksLikeRawCommandTranscript(value) {
|
|
842
|
+
const normalized = value.trim();
|
|
843
|
+
return /^(?:stdout|stderr)\s*:/iu.test(normalized)
|
|
844
|
+
|| /(?:^|\n)\s*(?:stdout|stderr)\s*:/iu.test(normalized)
|
|
845
|
+
|| /(?:^|\n)\s*exitCode\s*:\s*-?\d+\s*$/iu.test(normalized);
|
|
846
|
+
}
|
|
552
847
|
function resolveDelegatedResultOutput(result) {
|
|
553
848
|
const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
|
|
554
849
|
? result.metadata.executedToolResults
|
|
@@ -927,6 +1222,9 @@ export class AgentRuntimeAdapter {
|
|
|
927
1222
|
});
|
|
928
1223
|
}
|
|
929
1224
|
catch (error) {
|
|
1225
|
+
if (error instanceof DelegatedExecutionNoToolEvidenceError) {
|
|
1226
|
+
throw new Error(buildDelegatedExecutionEvidenceBlocker(targetBinding.agent.id, getBindingPrimaryTools(targetBinding).map((tool) => tool.name)));
|
|
1227
|
+
}
|
|
930
1228
|
const message = error instanceof Error && error.message.trim().length > 0
|
|
931
1229
|
? error.message.trim()
|
|
932
1230
|
: "delegated execution failed";
|
|
@@ -1360,6 +1658,9 @@ export class AgentRuntimeAdapter {
|
|
|
1360
1658
|
selection = parseCompactRouterSelection(previousRawText, subagentNames);
|
|
1361
1659
|
}
|
|
1362
1660
|
}
|
|
1661
|
+
if (selection?.delegations && selection.delegations.length > 0) {
|
|
1662
|
+
selection = { subagentType: selection.delegations[0].subagentType };
|
|
1663
|
+
}
|
|
1363
1664
|
if (selection?.refusedReason) {
|
|
1364
1665
|
return {
|
|
1365
1666
|
toolOutput: selection.refusedReason,
|
|
@@ -1497,7 +1798,7 @@ export class AgentRuntimeAdapter {
|
|
|
1497
1798
|
};
|
|
1498
1799
|
}
|
|
1499
1800
|
if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
|
|
1500
|
-
const output = buildDelegatedExecutionEvidenceBlocker(selectedBinding.agent.id);
|
|
1801
|
+
const output = buildDelegatedExecutionEvidenceBlocker(selectedBinding.agent.id, getBindingPrimaryTools(selectedBinding).map((tool) => tool.name));
|
|
1501
1802
|
return {
|
|
1502
1803
|
toolOutput: output,
|
|
1503
1804
|
delegatedSubagentType: subagentType,
|
|
@@ -1608,6 +1909,9 @@ export class AgentRuntimeAdapter {
|
|
|
1608
1909
|
}
|
|
1609
1910
|
formatCompactDelegationReportForDisplay(report) {
|
|
1610
1911
|
const reportText = typeof report.report === "string" ? report.report.trim() : "";
|
|
1912
|
+
if (reportText && looksLikeRawCommandTranscript(reportText)) {
|
|
1913
|
+
return JSON.stringify(report);
|
|
1914
|
+
}
|
|
1611
1915
|
if (reportText) {
|
|
1612
1916
|
return reportText;
|
|
1613
1917
|
}
|
|
@@ -1630,20 +1934,36 @@ export class AgentRuntimeAdapter {
|
|
|
1630
1934
|
}
|
|
1631
1935
|
const subagents = getBindingSubagents(binding);
|
|
1632
1936
|
const subagentNames = new Set(subagents.map((subagent) => subagent.name));
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1937
|
+
const semanticSubagents = subagents.map((subagent) => {
|
|
1938
|
+
const resolvedBinding = this.options.bindingResolver?.(subagent.name);
|
|
1939
|
+
const toolNames = resolvedBinding
|
|
1940
|
+
? getBindingPrimaryTools(resolvedBinding).map((tool) => tool.name).filter(Boolean).join(" ")
|
|
1941
|
+
: "";
|
|
1942
|
+
return {
|
|
1943
|
+
name: subagent.name,
|
|
1944
|
+
description: [
|
|
1945
|
+
subagent.description ?? "",
|
|
1946
|
+
toolNames,
|
|
1947
|
+
resolvedBinding ? getBindingSystemPrompt(resolvedBinding) : "",
|
|
1948
|
+
].filter(Boolean).join("\n"),
|
|
1949
|
+
};
|
|
1950
|
+
});
|
|
1951
|
+
let selection = null;
|
|
1635
1952
|
const subagentCatalog = subagents
|
|
1636
1953
|
.map((subagent) => `- ${subagent.name}: ${subagent.description}`)
|
|
1637
1954
|
.join("\n");
|
|
1638
1955
|
const routingPolicy = getBindingSystemPrompt(binding);
|
|
1639
1956
|
const prompt = [
|
|
1640
1957
|
primaryModel.init?.think === false ? "/no_think" : "",
|
|
1641
|
-
"You are
|
|
1642
|
-
"Choose exactly one listed subagent when
|
|
1958
|
+
"You are planning delegation for a delegation-only agent.",
|
|
1959
|
+
"Choose exactly one listed subagent when one specialist can responsibly handle the request.",
|
|
1960
|
+
"If the request naturally requires multiple specialist-owned steps, return an ordered delegation plan instead of one subagent.",
|
|
1643
1961
|
routingPolicy ? "Agent routing policy:" : "",
|
|
1644
1962
|
routingPolicy ?? "",
|
|
1645
|
-
"
|
|
1963
|
+
"For one specialist, return only JSON with this shape:",
|
|
1646
1964
|
"{\"subagent_type\":\"<listed subagent name>\"}",
|
|
1965
|
+
"For multiple specialist steps, return only JSON with this shape:",
|
|
1966
|
+
"{\"delegations\":[{\"subagent_type\":\"<listed subagent name>\",\"description\":\"<only that specialist's owned portion>\"}]}",
|
|
1647
1967
|
"If no listed subagent can handle the request, return only:",
|
|
1648
1968
|
"{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
|
|
1649
1969
|
"Available subagents:",
|
|
@@ -1675,20 +1995,23 @@ export class AgentRuntimeAdapter {
|
|
|
1675
1995
|
].join("\n\n"),
|
|
1676
1996
|
[
|
|
1677
1997
|
primaryModel.init?.think === false ? "/no_think" : "",
|
|
1678
|
-
"Select one subagent from this exact list:",
|
|
1998
|
+
"Select one subagent or an ordered delegation plan from this exact list:",
|
|
1679
1999
|
Array.from(subagentNames).join(", "),
|
|
1680
|
-
"Return JSON only:",
|
|
2000
|
+
"Return JSON only. Single-specialist shape:",
|
|
1681
2001
|
"{\"subagent_type\":\"<one exact listed name>\"}",
|
|
2002
|
+
"Multi-specialist shape:",
|
|
2003
|
+
"{\"delegations\":[{\"subagent_type\":\"<one exact listed name>\",\"description\":\"<owned subtask>\"}]}",
|
|
1682
2004
|
"User request:",
|
|
1683
2005
|
requestText,
|
|
1684
2006
|
].filter(Boolean).join("\n\n"),
|
|
1685
2007
|
[
|
|
1686
2008
|
primaryModel.init?.think === false ? "/no_think" : "",
|
|
1687
|
-
"JSON only. Pick a listed subagent or refuse.",
|
|
2009
|
+
"JSON only. Pick a listed subagent, return delegations, or refuse.",
|
|
1688
2010
|
"Listed subagents:",
|
|
1689
2011
|
Array.from(subagentNames).join(", "),
|
|
1690
2012
|
"Allowed outputs:",
|
|
1691
2013
|
"{\"subagent_type\":\"<listed name>\"}",
|
|
2014
|
+
"{\"delegations\":[{\"subagent_type\":\"<listed name>\",\"description\":\"<owned subtask>\"}]}",
|
|
1692
2015
|
"{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
|
|
1693
2016
|
"Request:",
|
|
1694
2017
|
requestText,
|
|
@@ -1704,6 +2027,286 @@ export class AgentRuntimeAdapter {
|
|
|
1704
2027
|
selection = parseCompactRouterSelection(previousRawText, subagentNames);
|
|
1705
2028
|
}
|
|
1706
2029
|
}
|
|
2030
|
+
const explicitTasks = extractExplicitSubagentTasks(requestText, subagentNames);
|
|
2031
|
+
const explicitOwner = resolveSingleExplicitOwnerMention(requestText, subagentNames);
|
|
2032
|
+
if (selection?.refusedReason && explicitOwner) {
|
|
2033
|
+
selection = { subagentType: explicitOwner };
|
|
2034
|
+
}
|
|
2035
|
+
const inferredDelegationPlan = inferCompactRouterDelegationPlanFromRequest(requestText, semanticSubagents, routingPolicy);
|
|
2036
|
+
if (inferredDelegationPlan.length > 1
|
|
2037
|
+
&& (!selection?.delegations || selection.delegations.length < inferredDelegationPlan.length)) {
|
|
2038
|
+
selection = { delegations: inferredDelegationPlan };
|
|
2039
|
+
}
|
|
2040
|
+
if (!selection) {
|
|
2041
|
+
if (explicitTasks.length > 1) {
|
|
2042
|
+
selection = {
|
|
2043
|
+
delegations: explicitTasks.map((task) => ({
|
|
2044
|
+
subagentType: task.subagentType,
|
|
2045
|
+
description: task.text,
|
|
2046
|
+
})),
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
else if (explicitTasks.length === 1) {
|
|
2050
|
+
selection = { subagentType: explicitTasks[0].subagentType };
|
|
2051
|
+
}
|
|
2052
|
+
else {
|
|
2053
|
+
const inferred = inferCompactRouterSelectionFromRequest(requestText, semanticSubagents);
|
|
2054
|
+
if (inferred) {
|
|
2055
|
+
selection = { subagentType: inferred };
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
const numberedRequestSteps = requestText
|
|
2060
|
+
.split(/\r?\n/u)
|
|
2061
|
+
.map((item) => item.trim())
|
|
2062
|
+
.filter((item) => /^\d+\s*[.)、.]\s*/u.test(item));
|
|
2063
|
+
if (selection?.subagentType && numberedRequestSteps.length >= 3 && subagents.length > 1) {
|
|
2064
|
+
selection = {
|
|
2065
|
+
delegations: subagents.map((subagent, index) => ({
|
|
2066
|
+
subagentType: subagent.name,
|
|
2067
|
+
description: numberedRequestSteps[index] ?? requestText,
|
|
2068
|
+
})),
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
if (selection?.delegations?.length === 1) {
|
|
2072
|
+
const onlyDelegation = selection.delegations[0];
|
|
2073
|
+
selection = { subagentType: onlyDelegation.subagentType };
|
|
2074
|
+
}
|
|
2075
|
+
if (selection?.delegations && selection.delegations.length > 1) {
|
|
2076
|
+
if (explicitOwner) {
|
|
2077
|
+
selection = { subagentType: explicitOwner };
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
if (selection?.delegations
|
|
2081
|
+
&& selection.delegations.length > 1
|
|
2082
|
+
&& inferredDelegationPlan.length <= 1
|
|
2083
|
+
&& numberedRequestSteps.length < 3) {
|
|
2084
|
+
const inferredSingleOwner = inferCompactRouterSelectionFromRequest(requestText, subagents)
|
|
2085
|
+
?? inferCompactRouterSelectionFromRequest(requestText, semanticSubagents);
|
|
2086
|
+
if (inferredSingleOwner) {
|
|
2087
|
+
selection = { subagentType: inferredSingleOwner };
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
if (selection?.delegations && selection.delegations.length > 1) {
|
|
2091
|
+
const plannedDelegations = selection.delegations;
|
|
2092
|
+
const plannedNames = new Set(plannedDelegations.map((item) => item.subagentType));
|
|
2093
|
+
const planCoversEverySubagent = plannedDelegations.length === subagents.length
|
|
2094
|
+
&& plannedNames.size === subagentNames.size
|
|
2095
|
+
&& Array.from(subagentNames).every((name) => plannedNames.has(name));
|
|
2096
|
+
const shouldCollapseOverbroadPlan = planCoversEverySubagent && explicitTasks.length === 0 && numberedRequestSteps.length < 3;
|
|
2097
|
+
const executableDelegations = shouldCollapseOverbroadPlan ? plannedDelegations.slice(0, 1) : plannedDelegations;
|
|
2098
|
+
const aggregateToolResults = [];
|
|
2099
|
+
const childReports = [];
|
|
2100
|
+
yield {
|
|
2101
|
+
kind: "commentary",
|
|
2102
|
+
content: `Planned delegation tree: ${executableDelegations.map((item) => item.subagentType).join(" -> ")}.`,
|
|
2103
|
+
agentId: binding.agent.id,
|
|
2104
|
+
};
|
|
2105
|
+
const runPlannedDelegation = async function* (subagentType, text, requestIdSuffix = "") {
|
|
2106
|
+
const selectedBinding = this.options.bindingResolver?.(subagentType);
|
|
2107
|
+
if (!selectedBinding) {
|
|
2108
|
+
const output = `Configured subagent '${subagentType}' could not be resolved.`;
|
|
2109
|
+
return {
|
|
2110
|
+
sessionId,
|
|
2111
|
+
requestId: `${requestId}:${subagentType}${requestIdSuffix}`,
|
|
2112
|
+
agentId: subagentType,
|
|
2113
|
+
state: "failed",
|
|
2114
|
+
output,
|
|
2115
|
+
finalMessageText: output,
|
|
2116
|
+
metadata: { executedToolResults: [] },
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
const executedToolResults = [];
|
|
2120
|
+
let output = "";
|
|
2121
|
+
try {
|
|
2122
|
+
for await (const chunk of this.stream(selectedBinding, text, sessionId, [], {
|
|
2123
|
+
context: options.context,
|
|
2124
|
+
state: options.state,
|
|
2125
|
+
files: options.files,
|
|
2126
|
+
requestId: `${requestId}:${subagentType}${requestIdSuffix}`,
|
|
2127
|
+
memoryContext: options.memoryContext,
|
|
2128
|
+
profiling: options.profiling,
|
|
2129
|
+
})) {
|
|
2130
|
+
if (typeof chunk === "string") {
|
|
2131
|
+
output += chunk;
|
|
2132
|
+
continue;
|
|
2133
|
+
}
|
|
2134
|
+
if (chunk.kind === "content") {
|
|
2135
|
+
output += chunk.content ?? "";
|
|
2136
|
+
continue;
|
|
2137
|
+
}
|
|
2138
|
+
if (chunk.kind === "tool-result") {
|
|
2139
|
+
appendUniqueToolEvidence(executedToolResults, {
|
|
2140
|
+
toolName: chunk.toolName,
|
|
2141
|
+
output: chunk.output,
|
|
2142
|
+
...(chunk.isError !== undefined ? { isError: chunk.isError } : {}),
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
if (chunk.kind === "upstream-event") {
|
|
2146
|
+
const streamedEvidence = readUpstreamToolEvidence(chunk.event);
|
|
2147
|
+
if (streamedEvidence) {
|
|
2148
|
+
appendUniqueToolEvidence(executedToolResults, streamedEvidence);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
yield { ...chunk, agentId: chunk.agentId ?? selectedBinding.agent.id };
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
catch (error) {
|
|
2155
|
+
output = error instanceof Error ? error.message : String(error);
|
|
2156
|
+
return {
|
|
2157
|
+
sessionId,
|
|
2158
|
+
requestId: `${requestId}:${subagentType}${requestIdSuffix}`,
|
|
2159
|
+
agentId: selectedBinding.agent.id,
|
|
2160
|
+
state: "failed",
|
|
2161
|
+
output,
|
|
2162
|
+
finalMessageText: output,
|
|
2163
|
+
metadata: { executedToolResults },
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
return {
|
|
2167
|
+
sessionId,
|
|
2168
|
+
requestId: `${requestId}:${subagentType}${requestIdSuffix}`,
|
|
2169
|
+
agentId: selectedBinding.agent.id,
|
|
2170
|
+
state: "completed",
|
|
2171
|
+
output: sanitizeVisibleText(output),
|
|
2172
|
+
finalMessageText: sanitizeVisibleText(output),
|
|
2173
|
+
metadata: { executedToolResults },
|
|
2174
|
+
};
|
|
2175
|
+
}.bind(this);
|
|
2176
|
+
for (const [index, planned] of executableDelegations.entries()) {
|
|
2177
|
+
const selectedBinding = this.options.bindingResolver?.(planned.subagentType);
|
|
2178
|
+
const delegatedText = buildDelegatedOwnedTaskInstruction({
|
|
2179
|
+
subagentType: planned.subagentType,
|
|
2180
|
+
taskText: planned.description,
|
|
2181
|
+
originalRequest: requestText,
|
|
2182
|
+
routingPolicy,
|
|
2183
|
+
ownerPolicy: selectedBinding ? getBindingSystemPrompt(selectedBinding) : undefined,
|
|
2184
|
+
});
|
|
2185
|
+
yield {
|
|
2186
|
+
kind: "commentary",
|
|
2187
|
+
content: `Delegating to ${planned.subagentType}.`,
|
|
2188
|
+
agentId: binding.agent.id,
|
|
2189
|
+
};
|
|
2190
|
+
yield {
|
|
2191
|
+
kind: "commentary",
|
|
2192
|
+
content: "Starting delegated execution.",
|
|
2193
|
+
agentId: selectedBinding?.agent.id ?? planned.subagentType,
|
|
2194
|
+
};
|
|
2195
|
+
let delegatedResult = yield* runPlannedDelegation(planned.subagentType, delegatedText);
|
|
2196
|
+
if (selectedBinding?.harnessRuntime.executionContract?.requiresPlan === true && !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
2197
|
+
const previousDelegatedResult = delegatedResult;
|
|
2198
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runPlannedDelegation(planned.subagentType, [delegatedText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry"), previousDelegatedResult);
|
|
2199
|
+
}
|
|
2200
|
+
const targetRequiresExecutionToolEvidence = selectedBinding ? getBindingPrimaryTools(selectedBinding).length > 0 : false;
|
|
2201
|
+
if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
|
|
2202
|
+
const previousDelegatedResult = delegatedResult;
|
|
2203
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runPlannedDelegation(planned.subagentType, [delegatedText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":tool-evidence-retry"), previousDelegatedResult);
|
|
2204
|
+
}
|
|
2205
|
+
if (selectedBinding?.harnessRuntime.executionContract?.requiresPlan === true && !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
2206
|
+
const output = buildDelegatedPlanEvidenceBlocker(selectedBinding.agent.id);
|
|
2207
|
+
delegatedResult = {
|
|
2208
|
+
...delegatedResult,
|
|
2209
|
+
state: "failed",
|
|
2210
|
+
output,
|
|
2211
|
+
finalMessageText: output,
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
|
|
2215
|
+
const output = buildDelegatedExecutionEvidenceBlocker(selectedBinding.agent.id, getBindingPrimaryTools(selectedBinding).map((tool) => tool.name));
|
|
2216
|
+
delegatedResult = {
|
|
2217
|
+
...delegatedResult,
|
|
2218
|
+
state: "failed",
|
|
2219
|
+
output,
|
|
2220
|
+
finalMessageText: output,
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
const delegatedToolResults = Array.isArray(delegatedResult.metadata?.executedToolResults)
|
|
2224
|
+
? delegatedResult.metadata.executedToolResults
|
|
2225
|
+
: [];
|
|
2226
|
+
for (const toolResult of delegatedToolResults) {
|
|
2227
|
+
if (typeof toolResult.toolName !== "string") {
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
appendUniqueToolEvidence(aggregateToolResults, {
|
|
2231
|
+
toolName: toolResult.toolName,
|
|
2232
|
+
output: toolResult.output,
|
|
2233
|
+
...(toolResult.isError !== undefined ? { isError: Boolean(toolResult.isError) } : {}),
|
|
2234
|
+
});
|
|
2235
|
+
if (isPlanToolName(toolResult.toolName)) {
|
|
2236
|
+
continue;
|
|
2237
|
+
}
|
|
2238
|
+
yield {
|
|
2239
|
+
kind: "commentary",
|
|
2240
|
+
content: `Running tool ${toolResult.toolName}.`,
|
|
2241
|
+
agentId: selectedBinding?.agent.id ?? planned.subagentType,
|
|
2242
|
+
};
|
|
2243
|
+
yield {
|
|
2244
|
+
kind: "commentary",
|
|
2245
|
+
content: `Tool ${toolResult.toolName} ${toolResult.isError === true ? "failed" : "completed"}.`,
|
|
2246
|
+
agentId: selectedBinding?.agent.id ?? planned.subagentType,
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
childReports.push({
|
|
2250
|
+
subagentType: planned.subagentType,
|
|
2251
|
+
result: delegatedResult,
|
|
2252
|
+
output: typeof delegatedResult.output === "string" ? delegatedResult.output : String(delegatedResult.output ?? ""),
|
|
2253
|
+
});
|
|
2254
|
+
if (index < executableDelegations.length - 1) {
|
|
2255
|
+
yield {
|
|
2256
|
+
kind: "commentary",
|
|
2257
|
+
content: "Continuing ordered delegation plan.",
|
|
2258
|
+
agentId: binding.agent.id,
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
const failedChildren = childReports.filter((child) => child.result.state === "failed");
|
|
2263
|
+
const uniqueToolNames = [...new Set(aggregateToolResults.map((toolResult) => toolResult.toolName))];
|
|
2264
|
+
const status = failedChildren.length > 0 ? "failed" : "completed";
|
|
2265
|
+
const report = childReports
|
|
2266
|
+
.map((child) => `## ${child.subagentType}\n${child.output.trim() || "No visible output returned."}`)
|
|
2267
|
+
.join("\n\n");
|
|
2268
|
+
const payload = {
|
|
2269
|
+
status,
|
|
2270
|
+
routing: executableDelegations.map((planned, index) => `${index + 1}) 路由判断: ${planned.subagentType} 负责 ${planned.description.trim() || "该专业域子任务"}。`),
|
|
2271
|
+
plan: executableDelegations.map((planned, index) => `${index + 1}) 委托 ${planned.subagentType}: ${planned.description.trim() || "执行其专业域任务"}。`),
|
|
2272
|
+
execution: childReports.map((child, index) => `${index + 1}) ${child.subagentType} ${child.result.state === "failed" ? "failed" : "completed"}。`),
|
|
2273
|
+
todoTrace: childReports.map((child, index) => `${index + 1}) ${child.subagentType}: ${hasDelegatedPlanEvidence(child.result) ? "TODO evidence observed" : "TODO evidence missing"}。`),
|
|
2274
|
+
stepResults: childReports.map((child, index) => `${index + 1}) ${child.subagentType}: delegated result collected; aggregate tools = ${uniqueToolNames.length > 0 ? uniqueToolNames.join(", ") : "none"}。`),
|
|
2275
|
+
summary: [
|
|
2276
|
+
status === "failed"
|
|
2277
|
+
? `多 specialist 编排完成,但 ${failedChildren.length} 个委托返回 failed。`
|
|
2278
|
+
: "多 specialist 编排已完成,所有委托均返回 completed。",
|
|
2279
|
+
],
|
|
2280
|
+
findings: childReports.map((child) => `${child.subagentType}: ${child.output.trim().slice(0, 500) || "No finding text returned."}`),
|
|
2281
|
+
blockers: failedChildren.length > 0
|
|
2282
|
+
? failedChildren.map((child) => `${child.subagentType}: delegated execution failed.`)
|
|
2283
|
+
: ["none"],
|
|
2284
|
+
nextActions: failedChildren.length > 0
|
|
2285
|
+
? ["查看 failed specialist 的 blocker 并单独重跑该委托。"]
|
|
2286
|
+
: ["可基于各 specialist 结果继续做最终修复或发布决策。"],
|
|
2287
|
+
report,
|
|
2288
|
+
};
|
|
2289
|
+
const output = JSON.stringify(payload);
|
|
2290
|
+
return {
|
|
2291
|
+
toolOutput: output,
|
|
2292
|
+
delegatedSubagentType: "multiple",
|
|
2293
|
+
delegatedResult: {
|
|
2294
|
+
sessionId,
|
|
2295
|
+
requestId,
|
|
2296
|
+
agentId: binding.agent.id,
|
|
2297
|
+
state: status,
|
|
2298
|
+
output,
|
|
2299
|
+
finalMessageText: output,
|
|
2300
|
+
metadata: {
|
|
2301
|
+
executedToolResults: aggregateToolResults,
|
|
2302
|
+
delegations: childReports.map((child) => ({
|
|
2303
|
+
subagentType: child.subagentType,
|
|
2304
|
+
state: child.result.state,
|
|
2305
|
+
})),
|
|
2306
|
+
},
|
|
2307
|
+
},
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
1707
2310
|
if (selection?.refusedReason) {
|
|
1708
2311
|
return {
|
|
1709
2312
|
toolOutput: selection.refusedReason,
|
|
@@ -1754,7 +2357,6 @@ export class AgentRuntimeAdapter {
|
|
|
1754
2357
|
requestId: `${childRequestId}${requestIdSuffix}`,
|
|
1755
2358
|
memoryContext: options.memoryContext,
|
|
1756
2359
|
profiling: options.profiling,
|
|
1757
|
-
toolRuntimeContext: options.toolRuntimeContext,
|
|
1758
2360
|
})) {
|
|
1759
2361
|
if (typeof chunk === "string") {
|
|
1760
2362
|
output += chunk;
|
|
@@ -1802,16 +2404,23 @@ export class AgentRuntimeAdapter {
|
|
|
1802
2404
|
metadata: { executedToolResults },
|
|
1803
2405
|
};
|
|
1804
2406
|
}.bind(this);
|
|
1805
|
-
|
|
2407
|
+
const delegatedText = buildDelegatedOwnedTaskInstruction({
|
|
2408
|
+
subagentType,
|
|
2409
|
+
taskText: requestText,
|
|
2410
|
+
originalRequest: requestText,
|
|
2411
|
+
routingPolicy,
|
|
2412
|
+
ownerPolicy: getBindingSystemPrompt(selectedBinding),
|
|
2413
|
+
});
|
|
2414
|
+
let delegatedResult = yield* runDelegatedStreamAttempt(delegatedText);
|
|
1806
2415
|
const targetRequiresExecutionToolEvidence = getBindingPrimaryTools(selectedBinding).length > 0;
|
|
1807
2416
|
if (selectedBinding.harnessRuntime.executionContract?.requiresPlan === true
|
|
1808
2417
|
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
1809
2418
|
const previousDelegatedResult = delegatedResult;
|
|
1810
|
-
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([
|
|
2419
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([delegatedText, DELEGATED_PLAN_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":plan-evidence-retry"), previousDelegatedResult);
|
|
1811
2420
|
}
|
|
1812
2421
|
if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
|
|
1813
2422
|
const previousDelegatedResult = delegatedResult;
|
|
1814
|
-
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([
|
|
2423
|
+
delegatedResult = mergeDelegatedResultToolEvidence(yield* runDelegatedStreamAttempt([delegatedText, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION].filter(Boolean).join("\n\n"), ":tool-evidence-retry"), previousDelegatedResult);
|
|
1815
2424
|
}
|
|
1816
2425
|
if (selectedBinding.harnessRuntime.executionContract?.requiresPlan === true
|
|
1817
2426
|
&& !hasDelegatedPlanEvidence(delegatedResult)) {
|
|
@@ -1824,7 +2433,7 @@ export class AgentRuntimeAdapter {
|
|
|
1824
2433
|
};
|
|
1825
2434
|
}
|
|
1826
2435
|
if (targetRequiresExecutionToolEvidence && !hasDelegatedExecutionToolEvidence(delegatedResult)) {
|
|
1827
|
-
const output = buildDelegatedExecutionEvidenceBlocker(selectedBinding.agent.id);
|
|
2436
|
+
const output = buildDelegatedExecutionEvidenceBlocker(selectedBinding.agent.id, getBindingPrimaryTools(selectedBinding).map((tool) => tool.name));
|
|
1828
2437
|
delegatedResult = {
|
|
1829
2438
|
...delegatedResult,
|
|
1830
2439
|
state: "failed",
|