@botbotgo/agent-harness 0.0.374 → 0.0.377

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.374";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.377";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.374";
1
+ export const AGENT_HARNESS_VERSION = "0.0.377";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-04-30";
@@ -153,6 +153,39 @@ function parseCompactRouterSelection(value, subagentNames) {
153
153
  }
154
154
  return null;
155
155
  }
156
+ function inferCompactRouterSelectionFromRequest(requestText, subagents) {
157
+ const normalized = requestText.toLowerCase();
158
+ const score = (subagent) => {
159
+ const name = subagent.name.toLowerCase();
160
+ const description = (subagent.description ?? "").toLowerCase();
161
+ let value = 0;
162
+ if (normalized.includes(name))
163
+ value += 4;
164
+ const keywordGroups = {
165
+ k8s: ["k8s", "kubernetes", "kubectl", "cluster", "pod", "node", "节点", "集群", "调度"],
166
+ software: ["code", "repo", "implementation", "debug", "代码", "仓库", "实现", "配置"],
167
+ ops: ["ci", "cd", "github actions", "disk", "storage", "deploy", "磁盘", "存储", "运维"],
168
+ qa: ["test", "coverage", "regression", "验证", "测试", "回归"],
169
+ release: ["release", "publish", "version", "tag", "发版", "发布", "版本"],
170
+ research: ["research", "web", "latest", "调查资料", "外部", "搜索"],
171
+ secretary: ["summary", "transcript", "youtube", "brief", "摘要", "讲稿", "转写"],
172
+ };
173
+ const keywords = keywordGroups[name] ?? [];
174
+ for (const keyword of keywords) {
175
+ if (normalized.includes(keyword))
176
+ value += description.includes(keyword) || name.includes(keyword) ? 3 : 1;
177
+ }
178
+ return value;
179
+ };
180
+ const ranked = subagents
181
+ .map((subagent) => ({ name: subagent.name, score: score(subagent) }))
182
+ .filter((item) => item.score > 0)
183
+ .sort((left, right) => right.score - left.score);
184
+ if (ranked.length === 0 || (ranked[1] && ranked[1].score === ranked[0].score)) {
185
+ return null;
186
+ }
187
+ return ranked[0].name;
188
+ }
156
189
  function isDelegationOnlyDeepAgentBinding(binding) {
157
190
  return isDeepAgentBinding(binding)
158
191
  && getBindingSubagents(binding).length > 0
@@ -846,6 +879,8 @@ export class AgentRuntimeAdapter {
846
879
  }
847
880
  const subagents = getBindingSubagents(binding);
848
881
  const subagentNames = new Set(subagents.map((subagent) => subagent.name));
882
+ const inferredSubagent = inferCompactRouterSelectionFromRequest(requestText, subagents);
883
+ let selection = inferredSubagent ? { subagentType: inferredSubagent } : null;
849
884
  const subagentCatalog = subagents
850
885
  .map((subagent) => `- ${subagent.name}: ${subagent.description}`)
851
886
  .join("\n");
@@ -865,57 +900,58 @@ export class AgentRuntimeAdapter {
865
900
  "User request:",
866
901
  requestText,
867
902
  ].filter(Boolean).join("\n\n");
868
- const model = await this.resolveModel(primaryModel);
869
- if (typeof model.invoke !== "function") {
870
- return null;
871
- }
872
- const invokeRouter = async (activePrompt, operationName) => this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
873
- sessionId,
874
- requestId,
875
- context: options.context,
876
- toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
877
- ...options,
903
+ if (!selection) {
904
+ const model = await this.resolveModel(primaryModel);
905
+ if (typeof model.invoke !== "function") {
906
+ return null;
907
+ }
908
+ const invokeRouter = async (activePrompt, operationName) => this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
878
909
  sessionId,
879
910
  requestId,
880
- }),
881
- })), resolveBindingTimeout(binding), operationName, "invoke"));
882
- const routerPrompts = [
883
- prompt,
884
- [
911
+ context: options.context,
912
+ toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
913
+ ...options,
914
+ sessionId,
915
+ requestId,
916
+ }),
917
+ })), resolveBindingTimeout(binding), operationName, "invoke"));
918
+ const routerPrompts = [
885
919
  prompt,
886
- "Your previous router output was invalid.",
887
- "Return only one JSON object now. Do not include prose, markdown, labels, or tool-call wrappers.",
888
- ].join("\n\n"),
889
- [
890
- primaryModel.init?.think === false ? "/no_think" : "",
891
- "Select one subagent from this exact list:",
892
- Array.from(subagentNames).join(", "),
893
- "Return JSON only:",
894
- "{\"subagent_type\":\"<one exact listed name>\"}",
895
- "User request:",
896
- requestText,
897
- ].filter(Boolean).join("\n\n"),
898
- [
899
- primaryModel.init?.think === false ? "/no_think" : "",
900
- "JSON only. Pick a listed subagent or refuse.",
901
- "Listed subagents:",
902
- Array.from(subagentNames).join(", "),
903
- "Allowed outputs:",
904
- "{\"subagent_type\":\"<listed name>\"}",
905
- "{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
906
- "Request:",
907
- requestText,
908
- ].filter(Boolean).join("\n\n"),
909
- ];
910
- let selection = null;
911
- let previousRawText = "";
912
- for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
913
- const activePrompt = index <= 1 || !previousRawText
914
- ? routerPrompts[index]
915
- : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
916
- const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
917
- previousRawText = readModelText(raw);
918
- selection = parseCompactRouterSelection(previousRawText, subagentNames);
920
+ [
921
+ prompt,
922
+ "Your previous router output was invalid.",
923
+ "Return only one JSON object now. Do not include prose, markdown, labels, or tool-call wrappers.",
924
+ ].join("\n\n"),
925
+ [
926
+ primaryModel.init?.think === false ? "/no_think" : "",
927
+ "Select one subagent from this exact list:",
928
+ Array.from(subagentNames).join(", "),
929
+ "Return JSON only:",
930
+ "{\"subagent_type\":\"<one exact listed name>\"}",
931
+ "User request:",
932
+ requestText,
933
+ ].filter(Boolean).join("\n\n"),
934
+ [
935
+ primaryModel.init?.think === false ? "/no_think" : "",
936
+ "JSON only. Pick a listed subagent or refuse.",
937
+ "Listed subagents:",
938
+ Array.from(subagentNames).join(", "),
939
+ "Allowed outputs:",
940
+ "{\"subagent_type\":\"<listed name>\"}",
941
+ "{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
942
+ "Request:",
943
+ requestText,
944
+ ].filter(Boolean).join("\n\n"),
945
+ ];
946
+ let previousRawText = "";
947
+ for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
948
+ const activePrompt = index <= 1 || !previousRawText
949
+ ? routerPrompts[index]
950
+ : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
951
+ const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
952
+ previousRawText = readModelText(raw);
953
+ selection = parseCompactRouterSelection(previousRawText, subagentNames);
954
+ }
919
955
  }
920
956
  if (selection?.refusedReason) {
921
957
  return {
@@ -1211,6 +1247,8 @@ export class AgentRuntimeAdapter {
1211
1247
  }
1212
1248
  const subagents = getBindingSubagents(binding);
1213
1249
  const subagentNames = new Set(subagents.map((subagent) => subagent.name));
1250
+ const inferredSubagent = inferCompactRouterSelectionFromRequest(requestText, subagents);
1251
+ let selection = inferredSubagent ? { subagentType: inferredSubagent } : null;
1214
1252
  const subagentCatalog = subagents
1215
1253
  .map((subagent) => `- ${subagent.name}: ${subagent.description}`)
1216
1254
  .join("\n");
@@ -1230,57 +1268,58 @@ export class AgentRuntimeAdapter {
1230
1268
  "User request:",
1231
1269
  requestText,
1232
1270
  ].filter(Boolean).join("\n\n");
1233
- const model = await this.resolveModel(primaryModel);
1234
- if (typeof model.invoke !== "function") {
1235
- return null;
1236
- }
1237
- const invokeRouter = async (activePrompt, operationName) => this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
1238
- sessionId,
1239
- requestId,
1240
- context: options.context,
1241
- toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
1242
- ...options,
1271
+ if (!selection) {
1272
+ const model = await this.resolveModel(primaryModel);
1273
+ if (typeof model.invoke !== "function") {
1274
+ return null;
1275
+ }
1276
+ const invokeRouter = async (activePrompt, operationName) => this.invokeWithProviderRetry(binding, () => this.withTimeout(() => model.invoke(activePrompt, resolveLangChainInvocationConfig(binding, {
1243
1277
  sessionId,
1244
1278
  requestId,
1245
- }),
1246
- })), resolveBindingTimeout(binding), operationName, "invoke"));
1247
- const routerPrompts = [
1248
- prompt,
1249
- [
1279
+ context: options.context,
1280
+ toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
1281
+ ...options,
1282
+ sessionId,
1283
+ requestId,
1284
+ }),
1285
+ })), resolveBindingTimeout(binding), operationName, "invoke"));
1286
+ const routerPrompts = [
1250
1287
  prompt,
1251
- "Your previous router output was invalid.",
1252
- "Return only one JSON object now. Do not include prose, markdown, labels, or tool-call wrappers.",
1253
- ].join("\n\n"),
1254
- [
1255
- primaryModel.init?.think === false ? "/no_think" : "",
1256
- "Select one subagent from this exact list:",
1257
- Array.from(subagentNames).join(", "),
1258
- "Return JSON only:",
1259
- "{\"subagent_type\":\"<one exact listed name>\"}",
1260
- "User request:",
1261
- requestText,
1262
- ].filter(Boolean).join("\n\n"),
1263
- [
1264
- primaryModel.init?.think === false ? "/no_think" : "",
1265
- "JSON only. Pick a listed subagent or refuse.",
1266
- "Listed subagents:",
1267
- Array.from(subagentNames).join(", "),
1268
- "Allowed outputs:",
1269
- "{\"subagent_type\":\"<listed name>\"}",
1270
- "{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
1271
- "Request:",
1272
- requestText,
1273
- ].filter(Boolean).join("\n\n"),
1274
- ];
1275
- let selection = null;
1276
- let previousRawText = "";
1277
- for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
1278
- const activePrompt = index <= 1 || !previousRawText
1279
- ? routerPrompts[index]
1280
- : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
1281
- const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
1282
- previousRawText = readModelText(raw);
1283
- selection = parseCompactRouterSelection(previousRawText, subagentNames);
1288
+ [
1289
+ prompt,
1290
+ "Your previous router output was invalid.",
1291
+ "Return only one JSON object now. Do not include prose, markdown, labels, or tool-call wrappers.",
1292
+ ].join("\n\n"),
1293
+ [
1294
+ primaryModel.init?.think === false ? "/no_think" : "",
1295
+ "Select one subagent from this exact list:",
1296
+ Array.from(subagentNames).join(", "),
1297
+ "Return JSON only:",
1298
+ "{\"subagent_type\":\"<one exact listed name>\"}",
1299
+ "User request:",
1300
+ requestText,
1301
+ ].filter(Boolean).join("\n\n"),
1302
+ [
1303
+ primaryModel.init?.think === false ? "/no_think" : "",
1304
+ "JSON only. Pick a listed subagent or refuse.",
1305
+ "Listed subagents:",
1306
+ Array.from(subagentNames).join(", "),
1307
+ "Allowed outputs:",
1308
+ "{\"subagent_type\":\"<listed name>\"}",
1309
+ "{\"status\":\"refused\",\"reason\":\"No configured subagent can handle the request.\"}",
1310
+ "Request:",
1311
+ requestText,
1312
+ ].filter(Boolean).join("\n\n"),
1313
+ ];
1314
+ let previousRawText = "";
1315
+ for (let index = 0; index < routerPrompts.length && !selection; index += 1) {
1316
+ const activePrompt = index <= 1 || !previousRawText
1317
+ ? routerPrompts[index]
1318
+ : [routerPrompts[index], "Previous output:", previousRawText].join("\n\n");
1319
+ const raw = await invokeRouter(activePrompt, index === 0 ? "delegation router invoke" : `delegation router retry invoke ${index}`);
1320
+ previousRawText = readModelText(raw);
1321
+ selection = parseCompactRouterSelection(previousRawText, subagentNames);
1322
+ }
1284
1323
  }
1285
1324
  if (selection?.refusedReason) {
1286
1325
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.374",
3
+ "version": "0.0.377",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",