@botbotgo/agent-harness 0.0.423 → 0.0.424
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.
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.424";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-03";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.424";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-05-03";
|
|
@@ -407,17 +407,11 @@ function parseFirstJsonObject(value) {
|
|
|
407
407
|
}
|
|
408
408
|
function parseCompactRouterSelection(value, subagentNames) {
|
|
409
409
|
const trimmed = value.trim();
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
+
const resolveExactName = (candidate) => Array.from(subagentNames).find((name) => name.toLowerCase() === candidate.trim().toLowerCase());
|
|
411
|
+
const exactTrimmedName = resolveExactName(trimmed);
|
|
412
|
+
if (exactTrimmedName) {
|
|
413
|
+
return { subagentType: exactTrimmedName };
|
|
414
|
+
}
|
|
421
415
|
const parsed = parseFirstJsonObject(trimmed);
|
|
422
416
|
const toolCall = salvageJsonToolCalls(trimmed).at(0);
|
|
423
417
|
const payload = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
@@ -426,8 +420,7 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
426
420
|
? { name: toolCall.name, arguments: toolCall.args }
|
|
427
421
|
: null;
|
|
428
422
|
if (!payload) {
|
|
429
|
-
|
|
430
|
-
return relaxedMatch ? { subagentType: relaxedMatch } : null;
|
|
423
|
+
return null;
|
|
431
424
|
}
|
|
432
425
|
const args = typeof payload.arguments === "object" && payload.arguments !== null && !Array.isArray(payload.arguments)
|
|
433
426
|
? payload.arguments
|
|
@@ -439,8 +432,9 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
439
432
|
: typeof args.subagent_type === "string"
|
|
440
433
|
? args.subagent_type.trim()
|
|
441
434
|
: "";
|
|
442
|
-
|
|
443
|
-
|
|
435
|
+
const resolvedSubagentType = resolveExactName(subagentType);
|
|
436
|
+
if (resolvedSubagentType) {
|
|
437
|
+
return { subagentType: resolvedSubagentType };
|
|
444
438
|
}
|
|
445
439
|
const rawDelegations = Array.isArray(payload.delegations)
|
|
446
440
|
? payload.delegations
|
|
@@ -491,139 +485,8 @@ function parseCompactRouterSelection(value, subagentNames) {
|
|
|
491
485
|
: "No configured subagent can handle the request.";
|
|
492
486
|
return { refusedReason: reason };
|
|
493
487
|
}
|
|
494
|
-
const relaxedMatch = resolveRelaxedMatch();
|
|
495
|
-
if (relaxedMatch) {
|
|
496
|
-
return { subagentType: relaxedMatch };
|
|
497
|
-
}
|
|
498
488
|
return null;
|
|
499
489
|
}
|
|
500
|
-
function inferCompactRouterSelectionFromRequest(requestText, subagents) {
|
|
501
|
-
const normalized = requestText.toLowerCase();
|
|
502
|
-
const requestTokens = extractRouterMatchTokens(normalized);
|
|
503
|
-
const score = (subagent) => {
|
|
504
|
-
const name = subagent.name.toLowerCase();
|
|
505
|
-
const description = (subagent.description ?? "").toLowerCase();
|
|
506
|
-
const descriptionTokens = extractRouterMatchTokens(`${name} ${description}`);
|
|
507
|
-
let value = 0;
|
|
508
|
-
if (normalized.includes(name))
|
|
509
|
-
value += 4;
|
|
510
|
-
for (const token of requestTokens) {
|
|
511
|
-
if (token === name) {
|
|
512
|
-
value += 4;
|
|
513
|
-
}
|
|
514
|
-
else if (descriptionTokens.has(token)) {
|
|
515
|
-
value += token.length > 2 ? 2 : 1;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
return value;
|
|
519
|
-
};
|
|
520
|
-
const ranked = subagents
|
|
521
|
-
.map((subagent) => ({ name: subagent.name, score: score(subagent) }))
|
|
522
|
-
.filter((item) => item.score > 0)
|
|
523
|
-
.sort((left, right) => right.score - left.score);
|
|
524
|
-
if (ranked.length === 0 || (ranked[1] && ranked[1].score === ranked[0].score)) {
|
|
525
|
-
return null;
|
|
526
|
-
}
|
|
527
|
-
return ranked[0].name;
|
|
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
490
|
function resolveSingleExplicitOwnerMention(requestText, subagentNames) {
|
|
628
491
|
const numberedClauses = requestText
|
|
629
492
|
.split(/\r?\n/u)
|
|
@@ -673,6 +536,55 @@ function extractExplicitSubagentTasks(requestText, subagentNames) {
|
|
|
673
536
|
}
|
|
674
537
|
return deduped;
|
|
675
538
|
}
|
|
539
|
+
function buildCompactRouterPolicy(routingPolicy, subagentNames) {
|
|
540
|
+
if (!routingPolicy) {
|
|
541
|
+
return "";
|
|
542
|
+
}
|
|
543
|
+
const lines = routingPolicy
|
|
544
|
+
.split(/\r?\n/u)
|
|
545
|
+
.map((line) => line.trim())
|
|
546
|
+
.filter((line) => line.length > 0);
|
|
547
|
+
const selected = [];
|
|
548
|
+
let inRoutingBlock = false;
|
|
549
|
+
let inDelegationBlock = false;
|
|
550
|
+
const subagentPatterns = Array.from(subagentNames).map((name) => {
|
|
551
|
+
const escaped = escapeRegExp(name);
|
|
552
|
+
return new RegExp(`(?:^|[^\\p{L}\\p{N}_-])\`?${escaped}\`?(?:$|[^\\p{L}\\p{N}_-])`, "iu");
|
|
553
|
+
});
|
|
554
|
+
for (const line of lines) {
|
|
555
|
+
const normalized = line.toLowerCase();
|
|
556
|
+
if (/^route by meaning\b/iu.test(line)) {
|
|
557
|
+
inRoutingBlock = true;
|
|
558
|
+
inDelegationBlock = false;
|
|
559
|
+
selected.push(line);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (/^delegation rules\b/iu.test(line)) {
|
|
563
|
+
inRoutingBlock = false;
|
|
564
|
+
inDelegationBlock = true;
|
|
565
|
+
selected.push(line);
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
if (/^(output|role|rules|working style|tool rules)\b/iu.test(line)) {
|
|
569
|
+
inRoutingBlock = false;
|
|
570
|
+
inDelegationBlock = false;
|
|
571
|
+
}
|
|
572
|
+
const mentionsSubagent = subagentPatterns.some((pattern) => pattern.test(line));
|
|
573
|
+
const mentionsDelegationPrimitive = normalized.includes("task")
|
|
574
|
+
|| normalized.includes("delegate")
|
|
575
|
+
|| normalized.includes("delegating")
|
|
576
|
+
|| normalized.includes("委托")
|
|
577
|
+
|| normalized.includes("路由");
|
|
578
|
+
if (inRoutingBlock && mentionsSubagent) {
|
|
579
|
+
selected.push(line);
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
if (inDelegationBlock && (mentionsSubagent || mentionsDelegationPrimitive)) {
|
|
583
|
+
selected.push(line);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return selected.slice(0, 80).join("\n");
|
|
587
|
+
}
|
|
676
588
|
function buildDelegatedOwnedTaskInstruction(input) {
|
|
677
589
|
const relevantPolicyLines = (input.routingPolicy ?? "")
|
|
678
590
|
.split(/\r?\n/u)
|
|
@@ -696,77 +608,6 @@ function buildDelegatedOwnedTaskInstruction(input) {
|
|
|
696
608
|
function escapeRegExp(value) {
|
|
697
609
|
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
698
610
|
}
|
|
699
|
-
function extractRouterMatchTokens(value) {
|
|
700
|
-
const tokens = new Set();
|
|
701
|
-
for (const match of value.matchAll(/[\p{L}\p{N}_-]+/gu)) {
|
|
702
|
-
const token = match[0].toLowerCase();
|
|
703
|
-
if (token.length >= 2) {
|
|
704
|
-
tokens.add(token);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
return tokens;
|
|
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
|
-
}
|
|
770
611
|
function isDelegationOnlyDeepAgentBinding(binding) {
|
|
771
612
|
return isDeepAgentBinding(binding)
|
|
772
613
|
&& getBindingSubagents(binding).length > 0
|
|
@@ -1584,18 +1425,21 @@ export class AgentRuntimeAdapter {
|
|
|
1584
1425
|
}
|
|
1585
1426
|
const subagents = getBindingSubagents(binding);
|
|
1586
1427
|
const subagentNames = new Set(subagents.map((subagent) => subagent.name));
|
|
1587
|
-
|
|
1588
|
-
let selection = inferredSubagent ? { subagentType: inferredSubagent } : null;
|
|
1428
|
+
let selection = null;
|
|
1589
1429
|
const subagentCatalog = subagents
|
|
1590
1430
|
.map((subagent) => `- ${subagent.name}: ${subagent.description}`)
|
|
1591
1431
|
.join("\n");
|
|
1592
1432
|
const routingPolicy = getBindingSystemPrompt(binding);
|
|
1433
|
+
const compactRoutingPolicy = buildCompactRouterPolicy(routingPolicy, subagentNames);
|
|
1593
1434
|
const prompt = [
|
|
1594
1435
|
primaryModel.init?.think === false ? "/no_think" : "",
|
|
1595
1436
|
"You are selecting a subagent for a delegation-only agent.",
|
|
1596
1437
|
"Choose exactly one listed subagent when it can responsibly handle the request.",
|
|
1597
|
-
|
|
1598
|
-
|
|
1438
|
+
"Use the agent routing policy as authoritative routing configuration when it maps the request meaning to a listed subagent.",
|
|
1439
|
+
"Do not refuse while any listed subagent can own the request after applying the routing policy.",
|
|
1440
|
+
"Refuse only when the request is outside every listed subagent's configured responsibility.",
|
|
1441
|
+
compactRoutingPolicy ? "Agent routing policy:" : "",
|
|
1442
|
+
compactRoutingPolicy,
|
|
1599
1443
|
"Return only JSON with this shape:",
|
|
1600
1444
|
"{\"subagent_type\":\"<listed subagent name>\"}",
|
|
1601
1445
|
"If no listed subagent can handle the request, return only:",
|
|
@@ -1605,12 +1449,12 @@ export class AgentRuntimeAdapter {
|
|
|
1605
1449
|
"User request:",
|
|
1606
1450
|
requestText,
|
|
1607
1451
|
].filter(Boolean).join("\n\n");
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
if (typeof model.invoke !== "function") {
|
|
1452
|
+
let model = null;
|
|
1453
|
+
const invokeRouter = async (activePrompt, operationName) => {
|
|
1454
|
+
if (!model || typeof model.invoke !== "function") {
|
|
1611
1455
|
return null;
|
|
1612
1456
|
}
|
|
1613
|
-
|
|
1457
|
+
return this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
|
|
1614
1458
|
sessionId,
|
|
1615
1459
|
requestId,
|
|
1616
1460
|
context: options.context,
|
|
@@ -1620,6 +1464,12 @@ export class AgentRuntimeAdapter {
|
|
|
1620
1464
|
requestId,
|
|
1621
1465
|
}),
|
|
1622
1466
|
})), resolveBindingTimeout(binding), operationName, "invoke"));
|
|
1467
|
+
};
|
|
1468
|
+
if (!selection) {
|
|
1469
|
+
model = await this.resolveModel(primaryModel);
|
|
1470
|
+
if (typeof model.invoke !== "function") {
|
|
1471
|
+
return null;
|
|
1472
|
+
}
|
|
1623
1473
|
const routerPrompts = [
|
|
1624
1474
|
prompt,
|
|
1625
1475
|
[
|
|
@@ -1654,10 +1504,20 @@ export class AgentRuntimeAdapter {
|
|
|
1654
1504
|
? routerPrompts[index]
|
|
1655
1505
|
: [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
|
|
1656
1506
|
const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
|
|
1507
|
+
if (raw === null) {
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1657
1510
|
previousRawText = readModelText(raw);
|
|
1658
|
-
|
|
1511
|
+
const parsedSelection = parseCompactRouterSelection(previousRawText, subagentNames);
|
|
1512
|
+
selection = parsedSelection?.refusedReason && index < routerPrompts.length - 1
|
|
1513
|
+
? null
|
|
1514
|
+
: parsedSelection;
|
|
1659
1515
|
}
|
|
1660
1516
|
}
|
|
1517
|
+
const explicitOwner = resolveSingleExplicitOwnerMention(requestText, subagentNames);
|
|
1518
|
+
if ((selection?.refusedReason || !selection) && explicitOwner) {
|
|
1519
|
+
selection = { subagentType: explicitOwner };
|
|
1520
|
+
}
|
|
1661
1521
|
if (selection?.delegations && selection.delegations.length > 0) {
|
|
1662
1522
|
selection = { subagentType: selection.delegations[0].subagentType };
|
|
1663
1523
|
}
|
|
@@ -1676,15 +1536,6 @@ export class AgentRuntimeAdapter {
|
|
|
1676
1536
|
};
|
|
1677
1537
|
}
|
|
1678
1538
|
let subagentType = selection?.subagentType ?? "";
|
|
1679
|
-
if (!subagentNames.has(subagentType)) {
|
|
1680
|
-
const fallbackSubagent = subagentNames.values().next().value;
|
|
1681
|
-
if (typeof fallbackSubagent === "string" && fallbackSubagent) {
|
|
1682
|
-
subagentType = fallbackSubagent;
|
|
1683
|
-
}
|
|
1684
|
-
else {
|
|
1685
|
-
return null;
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
1539
|
if (!subagentNames.has(subagentType)) {
|
|
1689
1540
|
return null;
|
|
1690
1541
|
}
|
|
@@ -1884,7 +1735,7 @@ export class AgentRuntimeAdapter {
|
|
|
1884
1735
|
return {
|
|
1885
1736
|
status: state,
|
|
1886
1737
|
routing: [
|
|
1887
|
-
`1) 路由判断: 已选择 sub-agent = ${delegatedSubagentType}
|
|
1738
|
+
`1) 路由判断: 已选择 sub-agent = ${delegatedSubagentType}。`,
|
|
1888
1739
|
],
|
|
1889
1740
|
plan: [
|
|
1890
1741
|
"1) 选择具备匹配能力的子代理并创建委托任务。",
|
|
@@ -1934,32 +1785,23 @@ export class AgentRuntimeAdapter {
|
|
|
1934
1785
|
}
|
|
1935
1786
|
const subagents = getBindingSubagents(binding);
|
|
1936
1787
|
const subagentNames = new Set(subagents.map((subagent) => subagent.name));
|
|
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
1788
|
let selection = null;
|
|
1952
1789
|
const subagentCatalog = subagents
|
|
1953
1790
|
.map((subagent) => `- ${subagent.name}: ${subagent.description}`)
|
|
1954
1791
|
.join("\n");
|
|
1955
1792
|
const routingPolicy = getBindingSystemPrompt(binding);
|
|
1793
|
+
const compactRoutingPolicy = buildCompactRouterPolicy(routingPolicy, subagentNames);
|
|
1956
1794
|
const prompt = [
|
|
1957
1795
|
primaryModel.init?.think === false ? "/no_think" : "",
|
|
1958
1796
|
"You are planning delegation for a delegation-only agent.",
|
|
1959
1797
|
"Choose exactly one listed subagent when one specialist can responsibly handle the request.",
|
|
1960
1798
|
"If the request naturally requires multiple specialist-owned steps, return an ordered delegation plan instead of one subagent.",
|
|
1961
|
-
|
|
1962
|
-
|
|
1799
|
+
"Use the agent routing policy as authoritative routing configuration when it maps request meaning to listed subagents.",
|
|
1800
|
+
"A broad request can still be handleable when multiple listed subagents each own part of it; return a delegation plan in that case.",
|
|
1801
|
+
"Do not refuse while any listed subagent can own the request or a subtask after applying the routing policy.",
|
|
1802
|
+
"Refuse only when the request is outside every listed subagent's configured responsibility.",
|
|
1803
|
+
compactRoutingPolicy ? "Agent routing policy:" : "",
|
|
1804
|
+
compactRoutingPolicy,
|
|
1963
1805
|
"For one specialist, return only JSON with this shape:",
|
|
1964
1806
|
"{\"subagent_type\":\"<listed subagent name>\"}",
|
|
1965
1807
|
"For multiple specialist steps, return only JSON with this shape:",
|
|
@@ -1971,12 +1813,12 @@ export class AgentRuntimeAdapter {
|
|
|
1971
1813
|
"User request:",
|
|
1972
1814
|
requestText,
|
|
1973
1815
|
].filter(Boolean).join("\n\n");
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
if (typeof model.invoke !== "function") {
|
|
1816
|
+
let model = null;
|
|
1817
|
+
const invokeRouter = async (activePrompt, operationName) => {
|
|
1818
|
+
if (!model || typeof model.invoke !== "function") {
|
|
1977
1819
|
return null;
|
|
1978
1820
|
}
|
|
1979
|
-
|
|
1821
|
+
return this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
|
|
1980
1822
|
sessionId,
|
|
1981
1823
|
requestId,
|
|
1982
1824
|
context: options.context,
|
|
@@ -1986,6 +1828,12 @@ export class AgentRuntimeAdapter {
|
|
|
1986
1828
|
requestId,
|
|
1987
1829
|
}),
|
|
1988
1830
|
})), resolveBindingTimeout(binding), operationName, "invoke"));
|
|
1831
|
+
};
|
|
1832
|
+
if (!selection) {
|
|
1833
|
+
model = await this.resolveModel(primaryModel);
|
|
1834
|
+
if (typeof model.invoke !== "function") {
|
|
1835
|
+
return null;
|
|
1836
|
+
}
|
|
1989
1837
|
const routerPrompts = [
|
|
1990
1838
|
prompt,
|
|
1991
1839
|
[
|
|
@@ -2023,8 +1871,14 @@ export class AgentRuntimeAdapter {
|
|
|
2023
1871
|
? routerPrompts[index]
|
|
2024
1872
|
: [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
|
|
2025
1873
|
const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
|
|
1874
|
+
if (raw === null) {
|
|
1875
|
+
break;
|
|
1876
|
+
}
|
|
2026
1877
|
previousRawText = readModelText(raw);
|
|
2027
|
-
|
|
1878
|
+
const parsedSelection = parseCompactRouterSelection(previousRawText, subagentNames);
|
|
1879
|
+
selection = parsedSelection?.refusedReason && index < routerPrompts.length - 1
|
|
1880
|
+
? null
|
|
1881
|
+
: parsedSelection;
|
|
2028
1882
|
}
|
|
2029
1883
|
}
|
|
2030
1884
|
const explicitTasks = extractExplicitSubagentTasks(requestText, subagentNames);
|
|
@@ -2032,10 +1886,47 @@ export class AgentRuntimeAdapter {
|
|
|
2032
1886
|
if (selection?.refusedReason && explicitOwner) {
|
|
2033
1887
|
selection = { subagentType: explicitOwner };
|
|
2034
1888
|
}
|
|
2035
|
-
const
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
1889
|
+
const numberedRequestSteps = requestText
|
|
1890
|
+
.split(/\r?\n/u)
|
|
1891
|
+
.map((item) => item.trim())
|
|
1892
|
+
.filter((item) => /^\d+\s*[.)、.]\s*/u.test(item));
|
|
1893
|
+
if ((!selection || selection.refusedReason) && !explicitOwner && explicitTasks.length === 0 && model) {
|
|
1894
|
+
const routeClauses = numberedRequestSteps.length > 1 ? numberedRequestSteps : [requestText];
|
|
1895
|
+
const routedDelegations = [];
|
|
1896
|
+
for (const [index, clause] of routeClauses.entries()) {
|
|
1897
|
+
const clausePrompt = [
|
|
1898
|
+
primaryModel.init?.think === false ? "/no_think" : "",
|
|
1899
|
+
"You are a strict JSON router for one bounded task.",
|
|
1900
|
+
"Choose exactly one owner from this list:",
|
|
1901
|
+
Array.from(subagentNames).join(", "),
|
|
1902
|
+
"Return only JSON with this shape:",
|
|
1903
|
+
"{\"subagent_type\":\"<one listed subagent name>\"}",
|
|
1904
|
+
compactRoutingPolicy ? "Agent routing policy:" : "",
|
|
1905
|
+
compactRoutingPolicy,
|
|
1906
|
+
"Available subagents:",
|
|
1907
|
+
subagentCatalog,
|
|
1908
|
+
"Task:",
|
|
1909
|
+
clause,
|
|
1910
|
+
].filter(Boolean).join("\n\n");
|
|
1911
|
+
const raw = await invokeRouter(clausePrompt, routeClauses.length > 1
|
|
1912
|
+
? `delegation router clause invoke ${index + 1}`
|
|
1913
|
+
: "delegation router single-clause invoke");
|
|
1914
|
+
const routed = raw === null ? null : parseCompactRouterSelection(readModelText(raw), subagentNames);
|
|
1915
|
+
if (!routed?.subagentType || routed.refusedReason) {
|
|
1916
|
+
routedDelegations.length = 0;
|
|
1917
|
+
break;
|
|
1918
|
+
}
|
|
1919
|
+
if (routedDelegations.some((item) => item.subagentType === routed.subagentType)) {
|
|
1920
|
+
continue;
|
|
1921
|
+
}
|
|
1922
|
+
routedDelegations.push({ subagentType: routed.subagentType, description: clause });
|
|
1923
|
+
}
|
|
1924
|
+
if (routedDelegations.length > 1) {
|
|
1925
|
+
selection = { delegations: routedDelegations };
|
|
1926
|
+
}
|
|
1927
|
+
else if (routedDelegations.length === 1) {
|
|
1928
|
+
selection = { subagentType: routedDelegations[0].subagentType };
|
|
1929
|
+
}
|
|
2039
1930
|
}
|
|
2040
1931
|
if (!selection) {
|
|
2041
1932
|
if (explicitTasks.length > 1) {
|
|
@@ -2049,25 +1940,10 @@ export class AgentRuntimeAdapter {
|
|
|
2049
1940
|
else if (explicitTasks.length === 1) {
|
|
2050
1941
|
selection = { subagentType: explicitTasks[0].subagentType };
|
|
2051
1942
|
}
|
|
2052
|
-
else {
|
|
2053
|
-
|
|
2054
|
-
if (inferred) {
|
|
2055
|
-
selection = { subagentType: inferred };
|
|
2056
|
-
}
|
|
1943
|
+
else if (explicitOwner) {
|
|
1944
|
+
selection = { subagentType: explicitOwner };
|
|
2057
1945
|
}
|
|
2058
1946
|
}
|
|
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
1947
|
if (selection?.delegations?.length === 1) {
|
|
2072
1948
|
const onlyDelegation = selection.delegations[0];
|
|
2073
1949
|
selection = { subagentType: onlyDelegation.subagentType };
|
|
@@ -2077,16 +1953,6 @@ export class AgentRuntimeAdapter {
|
|
|
2077
1953
|
selection = { subagentType: explicitOwner };
|
|
2078
1954
|
}
|
|
2079
1955
|
}
|
|
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
1956
|
if (selection?.delegations && selection.delegations.length > 1) {
|
|
2091
1957
|
const plannedDelegations = selection.delegations;
|
|
2092
1958
|
const plannedNames = new Set(plannedDelegations.map((item) => item.subagentType));
|
|
@@ -2323,13 +2189,7 @@ export class AgentRuntimeAdapter {
|
|
|
2323
2189
|
}
|
|
2324
2190
|
let subagentType = selection?.subagentType ?? "";
|
|
2325
2191
|
if (!subagentNames.has(subagentType)) {
|
|
2326
|
-
|
|
2327
|
-
if (typeof fallbackSubagent === "string" && fallbackSubagent) {
|
|
2328
|
-
subagentType = fallbackSubagent;
|
|
2329
|
-
}
|
|
2330
|
-
else {
|
|
2331
|
-
return null;
|
|
2332
|
-
}
|
|
2192
|
+
return null;
|
|
2333
2193
|
}
|
|
2334
2194
|
const selectedBinding = this.options.bindingResolver(subagentType);
|
|
2335
2195
|
if (!selectedBinding) {
|