@botbotgo/agent-harness 0.0.467 → 0.0.468

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.467";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.468";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-04";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.467";
1
+ export const AGENT_HARNESS_VERSION = "0.0.468";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-05-04";
@@ -205,6 +205,44 @@ function parseCompactRouterSelection(value, subagentNames) {
205
205
  return { delegations: deduped };
206
206
  }
207
207
  }
208
+ const routingMap = typeof payload.routing === "object" && payload.routing !== null && !Array.isArray(payload.routing)
209
+ ? payload.routing
210
+ : typeof args.routing === "object" && args.routing !== null && !Array.isArray(args.routing)
211
+ ? args.routing
212
+ : undefined;
213
+ if (routingMap) {
214
+ const nestedSubagents = Array.isArray(routingMap.subagents)
215
+ ? routingMap.subagents
216
+ .map((item) => {
217
+ if (typeof item !== "string") {
218
+ return null;
219
+ }
220
+ const resolvedName = resolveExactName(item);
221
+ return resolvedName ? { subagentType: resolvedName, description: "" } : null;
222
+ })
223
+ .filter((item) => item !== null)
224
+ : [];
225
+ const delegations = Object.entries(routingMap)
226
+ .map(([rawName, rawDescription]) => {
227
+ const resolvedName = resolveExactName(rawName);
228
+ if (!resolvedName) {
229
+ return null;
230
+ }
231
+ const description = typeof rawDescription === "string" && rawDescription.trim()
232
+ ? rawDescription.trim()
233
+ : "";
234
+ return { subagentType: resolvedName, description };
235
+ })
236
+ .filter((item) => item !== null);
237
+ for (const delegation of nestedSubagents) {
238
+ if (!delegations.some((item) => item.subagentType === delegation.subagentType)) {
239
+ delegations.push(delegation);
240
+ }
241
+ }
242
+ if (delegations.length > 0) {
243
+ return { delegations };
244
+ }
245
+ }
208
246
  const status = typeof payload.status === "string" ? payload.status.trim().toLowerCase() : "";
209
247
  if (status === "refused") {
210
248
  const reason = typeof payload.reason === "string" && payload.reason.trim()
@@ -1278,7 +1316,7 @@ export class AgentRuntimeAdapter {
1278
1316
  ].filter(Boolean).join("\n\n"),
1279
1317
  ];
1280
1318
  let previousRawText = "";
1281
- for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
1319
+ for (let index = 0; index < routerPrompts.length; index += 1) {
1282
1320
  const activePrompt = index <= 1 || !previousRawText
1283
1321
  ? routerPrompts[index]
1284
1322
  : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
@@ -1288,9 +1326,18 @@ export class AgentRuntimeAdapter {
1288
1326
  }
1289
1327
  previousRawText = readModelText(raw);
1290
1328
  const parsedSelection = parseCompactRouterSelection(previousRawText, subagentNames);
1291
- selection = parsedSelection?.refusedReason && index < routerPrompts.length - 1
1292
- ? null
1293
- : parsedSelection;
1329
+ if (!parsedSelection) {
1330
+ continue;
1331
+ }
1332
+ if (parsedSelection.delegations && parsedSelection.delegations.length > 1) {
1333
+ selection = parsedSelection;
1334
+ break;
1335
+ }
1336
+ if (!selection || selection.refusedReason || parsedSelection.subagentType) {
1337
+ selection = parsedSelection.refusedReason && index < routerPrompts.length - 1
1338
+ ? selection
1339
+ : parsedSelection;
1340
+ }
1294
1341
  }
1295
1342
  }
1296
1343
  if (selection?.delegations && selection.delegations.length > 0) {
@@ -1564,7 +1611,11 @@ export class AgentRuntimeAdapter {
1564
1611
  "You are planning delegation for a delegation-only agent.",
1565
1612
  "Choose exactly one listed subagent when one specialist can responsibly handle the request.",
1566
1613
  "If the request naturally requires multiple specialist-owned steps, return an ordered delegation plan instead of one subagent.",
1614
+ "For multi-line or numbered requests, evaluate every requested item semantically before choosing the final owner list.",
1567
1615
  "Use the agent routing policy as authoritative routing configuration when it maps request meaning to listed subagents.",
1616
+ "Apply the routing policy and subagent catalog literally; do not assign work to a subagent when the policy says that subagent is not the owner.",
1617
+ "Evaluate each listed subagent independently against the request and include every listed owner whose configured responsibility is required.",
1618
+ "Do not merge one listed subagent's configured responsibility into another listed subagent's task.",
1568
1619
  "A broad request can still be handleable when multiple listed subagents each own part of it; return a delegation plan in that case.",
1569
1620
  "Do not refuse while any listed subagent can own the request or a subtask after applying the routing policy.",
1570
1621
  "Refuse only when the request is outside every listed subagent's configured responsibility.",
@@ -1632,9 +1683,26 @@ export class AgentRuntimeAdapter {
1632
1683
  "Request:",
1633
1684
  requestText,
1634
1685
  ].filter(Boolean).join("\n\n"),
1686
+ [
1687
+ primaryModel.init?.think === false ? "/no_think" : "",
1688
+ "Multi-specialist delegation is supported.",
1689
+ "If a request needs multiple listed specialists, that is not a refusal condition.",
1690
+ "Return a delegations array that assigns each specialist-owned work item to listed subagents.",
1691
+ "Evaluate each listed subagent independently against the request and include every listed owner whose configured responsibility is required.",
1692
+ "Do not merge one listed subagent's configured responsibility into another listed subagent's task.",
1693
+ "Never return final response fields such as routing, todoTrace, stepResults, summary, findings, blockers, nextActions, or report.",
1694
+ "Return JSON only with this exact shape:",
1695
+ "{\"delegations\":[{\"subagent_type\":\"<one exact listed name>\",\"description\":\"<owned subtask>\"}]}",
1696
+ compactRoutingPolicy ? "Agent routing policy:" : "",
1697
+ compactRoutingPolicy,
1698
+ "Available subagents:",
1699
+ subagentCatalog,
1700
+ "User request:",
1701
+ requestText,
1702
+ ].filter(Boolean).join("\n\n"),
1635
1703
  ];
1636
1704
  let previousRawText = "";
1637
- for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
1705
+ for (let index = 0; index < routerPrompts.length; index += 1) {
1638
1706
  const activePrompt = index <= 1 || !previousRawText
1639
1707
  ? routerPrompts[index]
1640
1708
  : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
@@ -1644,59 +1712,64 @@ export class AgentRuntimeAdapter {
1644
1712
  }
1645
1713
  previousRawText = readModelText(raw);
1646
1714
  const parsedSelection = parseCompactRouterSelection(previousRawText, subagentNames);
1647
- selection = parsedSelection?.refusedReason && index < routerPrompts.length - 1
1648
- ? null
1649
- : parsedSelection;
1650
- }
1651
- }
1652
- const numberedRequestSteps = requestText
1653
- .split(/\r?\n/u)
1654
- .map((item) => item.trim())
1655
- .filter((item) => /^\d+\s*[.)、.]\s*/u.test(item));
1656
- const shouldRouteNumberedClauses = model
1657
- && numberedRequestSteps.length > 1
1658
- && (!selection
1659
- || Boolean(selection.refusedReason)
1660
- || (Array.isArray(selection.delegations)
1661
- && selection.delegations.length > 1
1662
- && selection.delegations.length < numberedRequestSteps.length));
1663
- if (shouldRouteNumberedClauses || ((!selection || selection.refusedReason) && model)) {
1664
- const routeClauses = numberedRequestSteps.length > 1 ? numberedRequestSteps : [requestText];
1665
- const routedDelegations = [];
1666
- for (const [index, clause] of routeClauses.entries()) {
1667
- const clausePrompt = [
1668
- primaryModel.init?.think === false ? "/no_think" : "",
1669
- "You are a strict JSON router for one bounded task.",
1670
- "Choose exactly one owner from this list:",
1671
- Array.from(subagentNames).join(", "),
1672
- "Return only JSON with this shape:",
1673
- "{\"subagent_type\":\"<one listed subagent name>\"}",
1674
- compactRoutingPolicy ? "Agent routing policy:" : "",
1675
- compactRoutingPolicy,
1676
- "Available subagents:",
1677
- subagentCatalog,
1678
- "Task:",
1679
- clause,
1680
- ].filter(Boolean).join("\n\n");
1681
- const raw = await invokeRouter(clausePrompt, routeClauses.length > 1
1682
- ? `delegation router clause invoke ${index + 1}`
1683
- : "delegation router single-clause invoke");
1684
- const routed = raw === null ? null : parseCompactRouterSelection(readModelText(raw), subagentNames);
1685
- if (!routed?.subagentType || routed.refusedReason) {
1686
- routedDelegations.length = 0;
1715
+ if (!parsedSelection) {
1716
+ continue;
1717
+ }
1718
+ if (parsedSelection.delegations && parsedSelection.delegations.length > 1) {
1719
+ selection = parsedSelection;
1687
1720
  break;
1688
1721
  }
1689
- if (routedDelegations.some((item) => item.subagentType === routed.subagentType)) {
1690
- continue;
1722
+ if (!selection || selection.refusedReason || parsedSelection.subagentType) {
1723
+ selection = parsedSelection.refusedReason && index < routerPrompts.length - 1
1724
+ ? selection
1725
+ : parsedSelection;
1691
1726
  }
1692
- routedDelegations.push({ subagentType: routed.subagentType, description: clause });
1693
- }
1694
- const existingDelegationCount = selection?.delegations?.length ?? 0;
1695
- if (routedDelegations.length > 1 && routedDelegations.length > existingDelegationCount) {
1696
- selection = { delegations: routedDelegations };
1697
1727
  }
1698
- else if (routedDelegations.length === 1 && existingDelegationCount === 0) {
1699
- selection = { subagentType: routedDelegations[0].subagentType };
1728
+ }
1729
+ if (selection?.delegations || selection?.subagentType) {
1730
+ const candidateDelegations = selection.delegations ?? [{
1731
+ subagentType: selection.subagentType,
1732
+ description: requestText,
1733
+ }];
1734
+ const candidatePlan = candidateDelegations
1735
+ .map((item, index) => `${index + 1}. ${item.subagentType}: ${item.description}`)
1736
+ .join("\n");
1737
+ const coveragePrompt = [
1738
+ primaryModel.init?.think === false ? "/no_think" : "",
1739
+ "Verify this delegation plan against the user request and routing policy.",
1740
+ "Internally review every sentence or list item in the user request before returning JSON.",
1741
+ "Return one corrected JSON object only.",
1742
+ "Keep the candidate plan unchanged when it already covers every specialist-owned work item.",
1743
+ "If the candidate omits a specialist-owned work item, add that listed subagent in the correct user-requested order.",
1744
+ "If the candidate includes a subagent whose described work is not owned by that subagent, remove or replace it.",
1745
+ "Evaluate each listed subagent independently against the request and include every listed owner whose configured responsibility is required.",
1746
+ "Do not merge one listed subagent's configured responsibility into another listed subagent's task.",
1747
+ "Do not add a subagent unless the routing policy or subagent catalog makes ownership clear.",
1748
+ "When the routing policy states that a subagent is not the owner for a domain, do not assign that domain to that subagent.",
1749
+ "Use only listed subagent names.",
1750
+ compactRoutingPolicy ? "Agent routing policy:" : "",
1751
+ compactRoutingPolicy,
1752
+ "Available subagents:",
1753
+ subagentCatalog,
1754
+ "Candidate delegation plan:",
1755
+ candidatePlan,
1756
+ "Required JSON shape:",
1757
+ "{\"delegations\":[{\"subagent_type\":\"<listed subagent name>\",\"description\":\"<only that specialist's owned portion>\"}]}",
1758
+ "User request:",
1759
+ requestText,
1760
+ ].filter(Boolean).join("\n\n");
1761
+ const rawCoverage = await invokeRouter(coveragePrompt, "delegation router coverage invoke");
1762
+ if (rawCoverage !== null) {
1763
+ const coverageText = readModelText(rawCoverage);
1764
+ const coverageSelection = parseCompactRouterSelection(coverageText, subagentNames);
1765
+ if (coverageSelection?.delegations && coverageSelection.delegations.length > 1) {
1766
+ const candidateNames = new Set(candidateDelegations.map((item) => item.subagentType));
1767
+ const coverageNames = new Set(coverageSelection.delegations.map((item) => item.subagentType));
1768
+ const preservesCandidateOwners = Array.from(candidateNames).every((name) => coverageNames.has(name));
1769
+ if (coverageSelection.delegations.length > candidateDelegations.length || preservesCandidateOwners) {
1770
+ selection = coverageSelection;
1771
+ }
1772
+ }
1700
1773
  }
1701
1774
  }
1702
1775
  if (selection?.delegations?.length === 1) {
@@ -1705,12 +1778,7 @@ export class AgentRuntimeAdapter {
1705
1778
  }
1706
1779
  if (selection?.delegations && selection.delegations.length > 1) {
1707
1780
  const plannedDelegations = selection.delegations;
1708
- const plannedNames = new Set(plannedDelegations.map((item) => item.subagentType));
1709
- const planCoversEverySubagent = plannedDelegations.length === subagents.length
1710
- && plannedNames.size === subagentNames.size
1711
- && Array.from(subagentNames).every((name) => plannedNames.has(name));
1712
- const shouldCollapseOverbroadPlan = planCoversEverySubagent && numberedRequestSteps.length < 3;
1713
- const executableDelegations = shouldCollapseOverbroadPlan ? plannedDelegations.slice(0, 1) : plannedDelegations;
1781
+ const executableDelegations = plannedDelegations;
1714
1782
  const aggregateToolResults = [];
1715
1783
  const childReports = [];
1716
1784
  yield {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.467",
3
+ "version": "0.0.468",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",