@botbotgo/agent-harness 0.0.340 → 0.0.342
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/cli/chat-stream.js +48 -0
- package/dist/contracts/workspace.d.ts +10 -0
- package/dist/package-version.d.ts +2 -2
- package/dist/package-version.js +2 -2
- package/dist/runtime/adapter/flow/execution-context.js +3 -2
- package/dist/runtime/adapter/flow/stream-runtime.d.ts +6 -0
- package/dist/runtime/adapter/flow/stream-runtime.js +54 -15
- package/dist/runtime/adapter/invocation-result.js +111 -9
- package/dist/runtime/adapter/local-tool-invocation.js +21 -1
- package/dist/runtime/adapter/middleware/context-hygiene.d.ts +5 -0
- package/dist/runtime/adapter/middleware/context-hygiene.js +83 -0
- package/dist/runtime/adapter/middleware-assembly.d.ts +11 -0
- package/dist/runtime/adapter/middleware-assembly.js +154 -178
- package/dist/runtime/adapter/model/invocation-request.js +39 -1
- package/dist/runtime/adapter/runtime-adapter-support.js +33 -3
- package/dist/runtime/adapter/stream-event-projection.js +6 -5
- package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +7 -0
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +31 -24
- package/dist/runtime/agent-runtime-adapter.d.ts +3 -2
- package/dist/runtime/agent-runtime-adapter.js +128 -9
- package/dist/runtime/agent-runtime-assembly.d.ts +1 -0
- package/dist/runtime/agent-runtime-assembly.js +10 -2
- package/dist/runtime/harness/run/inspection.js +4 -5
- package/dist/runtime/harness/run/stream-run.js +232 -48
- package/dist/runtime/parsing/output-parsing.d.ts +1 -1
- package/dist/runtime/parsing/output-parsing.js +1 -1
- package/dist/runtime/parsing/output-recovery.d.ts +9 -0
- package/dist/runtime/parsing/output-recovery.js +46 -1
- package/dist/runtime/support/compiled-binding.d.ts +5 -0
- package/dist/runtime/support/compiled-binding.js +12 -0
- package/dist/workspace/agent-binding-compiler.js +8 -0
- package/dist/workspace/object-loader.js +6 -0
- package/package.json +1 -1
|
@@ -43,7 +43,7 @@ function readTerminalStructuredStatus(value) {
|
|
|
43
43
|
return readTerminalStructuredStatus(JSON.parse(value));
|
|
44
44
|
}
|
|
45
45
|
catch {
|
|
46
|
-
return null;
|
|
46
|
+
return /^\s*Status:\s*completed\b/im.test(value) ? "completed" : null;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
if (typeof value !== "object" || value === null) {
|
|
@@ -54,9 +54,20 @@ function readTerminalStructuredStatus(value) {
|
|
|
54
54
|
return typed.status;
|
|
55
55
|
}
|
|
56
56
|
return (readTerminalStructuredStatus(typed.structuredResponse)
|
|
57
|
+
?? readTerminalStructuredStatus(typed.content)
|
|
57
58
|
?? readTerminalStructuredStatus(typed.output)
|
|
58
59
|
?? readTerminalStructuredStatus(typed.data));
|
|
59
60
|
}
|
|
61
|
+
function isSubstantiveTerminalAssistantOutput(value) {
|
|
62
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
63
|
+
if (normalized.length < 80) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (/\b(?:delegated|waiting|wait for|initiated)\b/i.test(normalized) && !/\b(?:finding|summary|root cause|evidence|completed|result|issue)\b/i.test(normalized)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
60
71
|
function reconcilePlanStateToTerminalStatus(planState, status, updatedAt) {
|
|
61
72
|
const items = planState.items.map((item) => ({
|
|
62
73
|
...item,
|
|
@@ -134,6 +145,57 @@ function buildPlanStateSignature(planState) {
|
|
|
134
145
|
summary: planState.summary,
|
|
135
146
|
});
|
|
136
147
|
}
|
|
148
|
+
function recomputePlanSummary(items) {
|
|
149
|
+
return {
|
|
150
|
+
total: items.length,
|
|
151
|
+
pending: items.filter((item) => item.status === "pending").length,
|
|
152
|
+
inProgress: items.filter((item) => item.status === "in_progress").length,
|
|
153
|
+
completed: items.filter((item) => item.status === "completed").length,
|
|
154
|
+
failed: items.filter((item) => item.status === "failed").length,
|
|
155
|
+
cancelled: items.filter((item) => item.status === "cancelled").length,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function normalizePlanItemKey(item) {
|
|
159
|
+
return typeof item.id === "string" && item.id.trim().length > 0
|
|
160
|
+
? `id:${item.id.trim()}`
|
|
161
|
+
: `content:${item.content.trim().toLowerCase()}`;
|
|
162
|
+
}
|
|
163
|
+
function mergePartialPlanState(currentPlanState, incomingPlanState) {
|
|
164
|
+
if (!currentPlanState || incomingPlanState.items.length >= currentPlanState.items.length) {
|
|
165
|
+
return incomingPlanState;
|
|
166
|
+
}
|
|
167
|
+
const currentByKey = new Map(currentPlanState.items.map((item, index) => [normalizePlanItemKey(item), { item, index }]));
|
|
168
|
+
const incomingByKey = new Map();
|
|
169
|
+
for (const incomingItem of incomingPlanState.items) {
|
|
170
|
+
const key = normalizePlanItemKey(incomingItem);
|
|
171
|
+
if (!currentByKey.has(key)) {
|
|
172
|
+
const currentStructuredIds = countStructuredTodoIds(currentPlanState.items);
|
|
173
|
+
const incomingStructuredIds = countStructuredTodoIds(incomingPlanState.items);
|
|
174
|
+
if (currentStructuredIds > 0 && incomingStructuredIds === 0) {
|
|
175
|
+
return currentPlanState;
|
|
176
|
+
}
|
|
177
|
+
const mergedItems = currentPlanState.items.map((item, index) => {
|
|
178
|
+
const incomingByIndex = incomingPlanState.items[index];
|
|
179
|
+
return incomingByIndex ? { ...item, status: incomingByIndex.status } : item;
|
|
180
|
+
});
|
|
181
|
+
return {
|
|
182
|
+
...incomingPlanState,
|
|
183
|
+
items: mergedItems,
|
|
184
|
+
summary: recomputePlanSummary(mergedItems),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
incomingByKey.set(key, incomingItem);
|
|
188
|
+
}
|
|
189
|
+
const mergedItems = currentPlanState.items.map((item) => {
|
|
190
|
+
const incomingItem = incomingByKey.get(normalizePlanItemKey(item));
|
|
191
|
+
return incomingItem ? { ...item, ...incomingItem } : item;
|
|
192
|
+
});
|
|
193
|
+
return {
|
|
194
|
+
...incomingPlanState,
|
|
195
|
+
items: mergedItems,
|
|
196
|
+
summary: recomputePlanSummary(mergedItems),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
137
199
|
function countStructuredTodoIds(items) {
|
|
138
200
|
return items.filter((item) => typeof item.id === "string" && item.id.length > 0).length;
|
|
139
201
|
}
|
|
@@ -283,16 +345,49 @@ function summarizePlanState(planState) {
|
|
|
283
345
|
if (planState.summary.total <= 0) {
|
|
284
346
|
return null;
|
|
285
347
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
348
|
+
const statusMarker = (status) => {
|
|
349
|
+
switch (status) {
|
|
350
|
+
case "completed":
|
|
351
|
+
return "[x]";
|
|
352
|
+
case "in_progress":
|
|
353
|
+
return "[~]";
|
|
354
|
+
case "failed":
|
|
355
|
+
return "[!]";
|
|
356
|
+
case "cancelled":
|
|
357
|
+
return "[-]";
|
|
358
|
+
default:
|
|
359
|
+
return "[ ]";
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
const items = planState.items.slice(0, 6).map((item) => `${statusMarker(item.status)} ${item.content}`);
|
|
363
|
+
const suffix = planState.items.length > items.length ? ` | +${planState.items.length - items.length} more` : "";
|
|
364
|
+
return `TODO: ${items.join(" | ")}${suffix}`;
|
|
365
|
+
}
|
|
366
|
+
function summarizePlanStateTerminalTransitions(previousPlanState, nextPlanState) {
|
|
367
|
+
const previousByKey = new Map((previousPlanState?.items ?? []).map((item) => [normalizePlanItemKey(item), item]));
|
|
368
|
+
const terminalLabel = (status) => {
|
|
369
|
+
switch (status) {
|
|
370
|
+
case "completed":
|
|
371
|
+
return "completed";
|
|
372
|
+
case "failed":
|
|
373
|
+
return "failed";
|
|
374
|
+
case "cancelled":
|
|
375
|
+
return "cancelled";
|
|
376
|
+
default:
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
return nextPlanState.items.flatMap((item) => {
|
|
381
|
+
const label = terminalLabel(item.status);
|
|
382
|
+
if (!label) {
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
const previousStatus = previousByKey.get(normalizePlanItemKey(item))?.status;
|
|
386
|
+
if (previousStatus === item.status) {
|
|
387
|
+
return [];
|
|
388
|
+
}
|
|
389
|
+
return [`TODO ${label}: ${item.content}.`];
|
|
390
|
+
});
|
|
296
391
|
}
|
|
297
392
|
function createSurfaceCommentary(surfaceItem) {
|
|
298
393
|
const name = normalizeCommentaryText(surfaceItem.name);
|
|
@@ -446,6 +541,10 @@ export async function* streamHarnessRun(options) {
|
|
|
446
541
|
let delegationChain = [options.selectedAgentId];
|
|
447
542
|
let upstreamEventOrdinal = 0;
|
|
448
543
|
let syntheticFallback;
|
|
544
|
+
const toolErrors = [];
|
|
545
|
+
let sawSuccessfulToolResult = false;
|
|
546
|
+
let lastToolResultKey = null;
|
|
547
|
+
const executedToolResults = [];
|
|
449
548
|
const emittedCommentary = new Set();
|
|
450
549
|
const emitCommentary = function* (content) {
|
|
451
550
|
const normalized = normalizeCommentaryText(content);
|
|
@@ -467,10 +566,6 @@ export async function* streamHarnessRun(options) {
|
|
|
467
566
|
options.releaseRequestSlotPromise,
|
|
468
567
|
]).then(([loadedPriorHistory, resolvedReleaseRunSlot]) => [loadedPriorHistory, resolvedReleaseRunSlot]);
|
|
469
568
|
releaseRunSlot = acquiredReleaseRunSlot;
|
|
470
|
-
const toolErrors = [];
|
|
471
|
-
let sawSuccessfulToolResult = false;
|
|
472
|
-
let lastToolResultKey = null;
|
|
473
|
-
const executedToolResults = [];
|
|
474
569
|
const recalledMemories = options.invocation.memoryRecall?.items ?? [];
|
|
475
570
|
for (const item of createRuntimeMemoryRecallSteps(options.sessionId, options.requestId, recalledMemories)) {
|
|
476
571
|
yield item;
|
|
@@ -502,32 +597,20 @@ export async function* streamHarnessRun(options) {
|
|
|
502
597
|
updatedAt: new Date().toISOString(),
|
|
503
598
|
});
|
|
504
599
|
if (upstreamPlanState) {
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
600
|
+
const mergedPlanState = mergePartialPlanState(currentPlanState, upstreamPlanState);
|
|
601
|
+
const signature = buildPlanStateSignature(mergedPlanState);
|
|
602
|
+
if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
|
|
603
|
+
const previousPlanState = currentPlanState;
|
|
604
|
+
planStateVersion = mergedPlanState.version;
|
|
508
605
|
lastPlanStateSignature = signature;
|
|
509
|
-
currentPlanState =
|
|
510
|
-
for (const item of await emitPlanStateUpdate(options, currentAgentId,
|
|
606
|
+
currentPlanState = mergedPlanState;
|
|
607
|
+
for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
|
|
511
608
|
yield item;
|
|
512
609
|
}
|
|
513
|
-
const commentary
|
|
514
|
-
if (commentary) {
|
|
610
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, mergedPlanState)) {
|
|
515
611
|
yield* emitCommentary(commentary);
|
|
516
612
|
}
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
const terminalStructuredStatus = readTerminalStructuredStatus(normalizedChunk.event);
|
|
520
|
-
if (terminalStructuredStatus && currentPlanState && planStateHasActiveItems(currentPlanState)) {
|
|
521
|
-
const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
|
|
522
|
-
const signature = buildPlanStateSignature(reconciledPlanState);
|
|
523
|
-
if (signature !== lastPlanStateSignature) {
|
|
524
|
-
planStateVersion = reconciledPlanState.version;
|
|
525
|
-
lastPlanStateSignature = signature;
|
|
526
|
-
currentPlanState = reconciledPlanState;
|
|
527
|
-
for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
|
|
528
|
-
yield item;
|
|
529
|
-
}
|
|
530
|
-
const commentary = summarizePlanState(reconciledPlanState);
|
|
613
|
+
const commentary = summarizePlanState(mergedPlanState);
|
|
531
614
|
if (commentary) {
|
|
532
615
|
yield* emitCommentary(commentary);
|
|
533
616
|
}
|
|
@@ -677,30 +760,41 @@ export async function* streamHarnessRun(options) {
|
|
|
677
760
|
updatedAt: new Date().toISOString(),
|
|
678
761
|
});
|
|
679
762
|
if (planState) {
|
|
680
|
-
const
|
|
681
|
-
|
|
763
|
+
const mergedPlanState = mergePartialPlanState(currentPlanState, planState);
|
|
764
|
+
const signature = buildPlanStateSignature(mergedPlanState);
|
|
765
|
+
if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
|
|
766
|
+
const previousPlanState = currentPlanState;
|
|
682
767
|
lastPlanStateSignature = signature;
|
|
683
|
-
currentPlanState =
|
|
684
|
-
for (const item of await emitPlanStateUpdate(options, currentAgentId,
|
|
768
|
+
currentPlanState = mergedPlanState;
|
|
769
|
+
for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
|
|
685
770
|
yield item;
|
|
686
771
|
}
|
|
687
|
-
const commentary
|
|
772
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, mergedPlanState)) {
|
|
773
|
+
yield* emitCommentary(commentary);
|
|
774
|
+
}
|
|
775
|
+
const commentary = summarizePlanState(mergedPlanState);
|
|
688
776
|
if (commentary) {
|
|
689
777
|
yield* emitCommentary(commentary);
|
|
690
778
|
}
|
|
691
779
|
}
|
|
692
780
|
}
|
|
693
|
-
const terminalStructuredStatus =
|
|
781
|
+
const terminalStructuredStatus = normalizedChunk.toolName === "task"
|
|
782
|
+
? readTerminalStructuredStatus(normalizedChunk.output)
|
|
783
|
+
: null;
|
|
694
784
|
if (terminalStructuredStatus && currentPlanState && planStateHasActiveItems(currentPlanState)) {
|
|
695
785
|
const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
|
|
696
786
|
const signature = buildPlanStateSignature(reconciledPlanState);
|
|
697
787
|
if (signature !== lastPlanStateSignature) {
|
|
788
|
+
const previousPlanState = currentPlanState;
|
|
698
789
|
planStateVersion = reconciledPlanState.version;
|
|
699
790
|
lastPlanStateSignature = signature;
|
|
700
791
|
currentPlanState = reconciledPlanState;
|
|
701
792
|
for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
|
|
702
793
|
yield item;
|
|
703
794
|
}
|
|
795
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
|
|
796
|
+
yield* emitCommentary(commentary);
|
|
797
|
+
}
|
|
704
798
|
const commentary = summarizePlanState(reconciledPlanState);
|
|
705
799
|
if (commentary) {
|
|
706
800
|
yield* emitCommentary(commentary);
|
|
@@ -757,15 +851,20 @@ export async function* streamHarnessRun(options) {
|
|
|
757
851
|
updatedAt: new Date().toISOString(),
|
|
758
852
|
});
|
|
759
853
|
if (finalPlanState) {
|
|
760
|
-
const
|
|
761
|
-
|
|
762
|
-
|
|
854
|
+
const mergedPlanState = mergePartialPlanState(currentPlanState, finalPlanState);
|
|
855
|
+
const signature = buildPlanStateSignature(mergedPlanState);
|
|
856
|
+
if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
|
|
857
|
+
const previousPlanState = currentPlanState;
|
|
858
|
+
planStateVersion = mergedPlanState.version;
|
|
763
859
|
lastPlanStateSignature = signature;
|
|
764
|
-
currentPlanState =
|
|
765
|
-
for (const item of await emitPlanStateUpdate(options, currentAgentId,
|
|
860
|
+
currentPlanState = mergedPlanState;
|
|
861
|
+
for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
|
|
766
862
|
yield item;
|
|
767
863
|
}
|
|
768
|
-
const commentary
|
|
864
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, mergedPlanState)) {
|
|
865
|
+
yield* emitCommentary(commentary);
|
|
866
|
+
}
|
|
867
|
+
const commentary = summarizePlanState(mergedPlanState);
|
|
769
868
|
if (commentary) {
|
|
770
869
|
yield* emitCommentary(commentary);
|
|
771
870
|
}
|
|
@@ -777,12 +876,16 @@ export async function* streamHarnessRun(options) {
|
|
|
777
876
|
const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
|
|
778
877
|
const signature = buildPlanStateSignature(reconciledPlanState);
|
|
779
878
|
if (signature !== lastPlanStateSignature) {
|
|
879
|
+
const previousPlanState = currentPlanState;
|
|
780
880
|
planStateVersion = reconciledPlanState.version;
|
|
781
881
|
lastPlanStateSignature = signature;
|
|
782
882
|
currentPlanState = reconciledPlanState;
|
|
783
883
|
for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
|
|
784
884
|
yield item;
|
|
785
885
|
}
|
|
886
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
|
|
887
|
+
yield* emitCommentary(commentary);
|
|
888
|
+
}
|
|
786
889
|
const commentary = summarizePlanState(reconciledPlanState);
|
|
787
890
|
if (commentary) {
|
|
788
891
|
yield* emitCommentary(commentary);
|
|
@@ -791,6 +894,26 @@ export async function* streamHarnessRun(options) {
|
|
|
791
894
|
}
|
|
792
895
|
}
|
|
793
896
|
currentPlanState = await refreshPlanStateFromPersistence(options, currentPlanState);
|
|
897
|
+
if (isSubstantiveTerminalAssistantOutput(assistantOutput) && planStateHasActiveItems(currentPlanState)) {
|
|
898
|
+
const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, "completed", new Date().toISOString());
|
|
899
|
+
const signature = buildPlanStateSignature(reconciledPlanState);
|
|
900
|
+
if (signature !== lastPlanStateSignature) {
|
|
901
|
+
const previousPlanState = currentPlanState;
|
|
902
|
+
planStateVersion = reconciledPlanState.version;
|
|
903
|
+
lastPlanStateSignature = signature;
|
|
904
|
+
currentPlanState = reconciledPlanState;
|
|
905
|
+
for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
|
|
906
|
+
yield item;
|
|
907
|
+
}
|
|
908
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
|
|
909
|
+
yield* emitCommentary(commentary);
|
|
910
|
+
}
|
|
911
|
+
const commentary = summarizePlanState(reconciledPlanState);
|
|
912
|
+
if (commentary) {
|
|
913
|
+
yield* emitCommentary(commentary);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
794
917
|
if (assistantOutputCameFromInvokeFallback
|
|
795
918
|
&& nonUpstreamStreamActivityObserved
|
|
796
919
|
&& planStateHasActiveItems(currentPlanState)) {
|
|
@@ -833,6 +956,67 @@ export async function* streamHarnessRun(options) {
|
|
|
833
956
|
};
|
|
834
957
|
}
|
|
835
958
|
catch (error) {
|
|
959
|
+
const deterministicToolEvidenceOutput = resolveDeterministicFinalOutput({
|
|
960
|
+
visibleOutput: assistantOutput,
|
|
961
|
+
executedToolResults,
|
|
962
|
+
});
|
|
963
|
+
if (!assistantOutput && sawSuccessfulToolResult && deterministicToolEvidenceOutput) {
|
|
964
|
+
const terminalStructuredStatus = readTerminalStructuredStatus(deterministicToolEvidenceOutput);
|
|
965
|
+
if (terminalStructuredStatus && currentPlanState && planStateHasActiveItems(currentPlanState)) {
|
|
966
|
+
const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
|
|
967
|
+
const signature = buildPlanStateSignature(reconciledPlanState);
|
|
968
|
+
if (signature !== lastPlanStateSignature) {
|
|
969
|
+
const previousPlanState = currentPlanState;
|
|
970
|
+
planStateVersion = reconciledPlanState.version;
|
|
971
|
+
lastPlanStateSignature = signature;
|
|
972
|
+
currentPlanState = reconciledPlanState;
|
|
973
|
+
for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
|
|
974
|
+
yield item;
|
|
975
|
+
}
|
|
976
|
+
for (const commentary of summarizePlanStateTerminalTransitions(previousPlanState, reconciledPlanState)) {
|
|
977
|
+
yield* emitCommentary(commentary);
|
|
978
|
+
}
|
|
979
|
+
const commentary = summarizePlanState(reconciledPlanState);
|
|
980
|
+
if (commentary) {
|
|
981
|
+
yield* emitCommentary(commentary);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
await options.appendAssistantMessage(options.sessionId, options.requestId, deterministicToolEvidenceOutput);
|
|
986
|
+
yield {
|
|
987
|
+
type: "event",
|
|
988
|
+
event: await options.emit(options.sessionId, options.requestId, 3, "output.delta", { content: deterministicToolEvidenceOutput }),
|
|
989
|
+
};
|
|
990
|
+
yield {
|
|
991
|
+
type: "content",
|
|
992
|
+
sessionId: options.sessionId,
|
|
993
|
+
requestId: options.requestId,
|
|
994
|
+
agentId: currentAgentId,
|
|
995
|
+
content: deterministicToolEvidenceOutput,
|
|
996
|
+
};
|
|
997
|
+
const completedEvent = await options.setRequestStateAndEmit(options.sessionId, options.requestId, 6, "completed", {
|
|
998
|
+
previousState: "running",
|
|
999
|
+
});
|
|
1000
|
+
yield {
|
|
1001
|
+
type: "event",
|
|
1002
|
+
event: completedEvent,
|
|
1003
|
+
};
|
|
1004
|
+
yield {
|
|
1005
|
+
type: "result",
|
|
1006
|
+
result: {
|
|
1007
|
+
sessionId: options.sessionId,
|
|
1008
|
+
requestId: options.requestId,
|
|
1009
|
+
agentId: currentAgentId,
|
|
1010
|
+
state: "completed",
|
|
1011
|
+
output: deterministicToolEvidenceOutput,
|
|
1012
|
+
finalMessageText: deterministicToolEvidenceOutput,
|
|
1013
|
+
metadata: {
|
|
1014
|
+
executedToolResults,
|
|
1015
|
+
},
|
|
1016
|
+
},
|
|
1017
|
+
};
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
836
1020
|
const shouldRetryAfterStreamingCompatibilityError = !assistantOutput &&
|
|
837
1021
|
isOpenAICompatibleStreamingCompatibilityError(options.binding, error);
|
|
838
1022
|
if ((emitted || streamActivityObserved)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
|
|
1
|
+
export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, resolveMissingPlanRecoveryInstruction, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
|
|
2
2
|
export { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
|
|
3
3
|
export { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, hasToolCalls, readTextContent, sanitizeVisibleText, } from "./output-content.js";
|
|
4
4
|
export { isLikelyToolArgsObject, salvageToolArgs, tryParseJson, } from "./output-tool-args.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
|
|
1
|
+
export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, resolveMissingPlanRecoveryInstruction, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
|
|
2
2
|
export { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
|
|
3
3
|
export { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, hasToolCalls, readTextContent, sanitizeVisibleText, } from "./output-content.js";
|
|
4
4
|
export { isLikelyToolArgsObject, salvageToolArgs, tryParseJson, } from "./output-tool-args.js";
|
|
@@ -7,11 +7,20 @@ export declare function isRepairableWriteTodosEmptyFailure(error: unknown): bool
|
|
|
7
7
|
export declare function isToolCallRecoveryFailure(error: unknown): boolean;
|
|
8
8
|
export declare function isRetrySafeInvalidToolSelectionError(value: unknown): boolean;
|
|
9
9
|
export declare function shouldValidateExecutionWithoutToolEvidence(request: unknown): boolean;
|
|
10
|
+
export declare function shouldRequireVisibleTodoPlan(request: unknown): boolean;
|
|
11
|
+
export declare function resolveMissingPlanRecoveryInstruction(params: {
|
|
12
|
+
request: unknown;
|
|
13
|
+
assistantText?: string;
|
|
14
|
+
hasPlanStateEvidence?: boolean;
|
|
15
|
+
hasWriteTodosEvidence?: boolean;
|
|
16
|
+
hasToolResultEvidence?: boolean;
|
|
17
|
+
}): string | null;
|
|
10
18
|
export declare function resolveExecutionWithoutToolEvidenceInstruction(request: unknown, result: unknown): string | null;
|
|
11
19
|
export declare function resolveExecutionWithoutToolEvidenceTextInstruction(request: unknown, assistantText: string, toolCallEvidence?: boolean, resultEvidence?: {
|
|
12
20
|
hasWriteTodosEvidence?: boolean;
|
|
13
21
|
hasToolResultEvidence?: boolean;
|
|
14
22
|
hasIncompletePlanState?: boolean;
|
|
23
|
+
hasPlanStateEvidence?: boolean;
|
|
15
24
|
hasOpenTaskDelegation?: boolean;
|
|
16
25
|
hasMissingDelegatedExecutionEvidence?: boolean;
|
|
17
26
|
}): string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INTERNAL_RUNTIME_SPILL_PATH_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
|
|
1
|
+
import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INTERNAL_RUNTIME_SPILL_PATH_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, WRITE_TODOS_REQUIRED_PLAN_INSTRUCTION, } from "../prompts/runtime-prompts.js";
|
|
2
2
|
import { wrapNormalizedMessage, readTextContent } from "./output-content.js";
|
|
3
3
|
function collectRequestMessages(request) {
|
|
4
4
|
if (typeof request !== "object" || !request || Array.isArray(request)) {
|
|
@@ -111,6 +111,41 @@ export function shouldValidateExecutionWithoutToolEvidence(request) {
|
|
|
111
111
|
}
|
|
112
112
|
return readSystemInstructionText(request).length > 0;
|
|
113
113
|
}
|
|
114
|
+
export function shouldRequireVisibleTodoPlan(request) {
|
|
115
|
+
const userText = readLatestUserRequestText(request).toLowerCase();
|
|
116
|
+
if (!userText) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return [
|
|
120
|
+
"investigate",
|
|
121
|
+
"investigation",
|
|
122
|
+
"issue",
|
|
123
|
+
"issues",
|
|
124
|
+
"rca",
|
|
125
|
+
"root cause",
|
|
126
|
+
"go deeper",
|
|
127
|
+
"deep research",
|
|
128
|
+
"debug",
|
|
129
|
+
"排查",
|
|
130
|
+
"调查",
|
|
131
|
+
"问题",
|
|
132
|
+
"根因",
|
|
133
|
+
"故障",
|
|
134
|
+
"集群",
|
|
135
|
+
"cluster",
|
|
136
|
+
].some((keyword) => userText.includes(keyword));
|
|
137
|
+
}
|
|
138
|
+
export function resolveMissingPlanRecoveryInstruction(params) {
|
|
139
|
+
const hasPlanEvidence = params.hasWriteTodosEvidence === true
|
|
140
|
+
|| params.hasPlanStateEvidence === true;
|
|
141
|
+
if (!shouldRequireVisibleTodoPlan(params.request) || hasPlanEvidence) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
if (params.hasToolResultEvidence === true) {
|
|
145
|
+
return WRITE_TODOS_REQUIRED_PLAN_INSTRUCTION;
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
114
149
|
export function resolveExecutionWithoutToolEvidenceInstruction(request, result) {
|
|
115
150
|
const assistantText = readTextContent(result).trim();
|
|
116
151
|
return resolveExecutionWithoutToolEvidenceTextInstruction(request, assistantText, false, {});
|
|
@@ -120,6 +155,16 @@ export function resolveExecutionWithoutToolEvidenceTextInstruction(request, assi
|
|
|
120
155
|
return null;
|
|
121
156
|
}
|
|
122
157
|
const normalizedText = assistantText.trim();
|
|
158
|
+
const missingPlanRecoveryInstruction = resolveMissingPlanRecoveryInstruction({
|
|
159
|
+
request,
|
|
160
|
+
assistantText: normalizedText,
|
|
161
|
+
hasWriteTodosEvidence: resultEvidence.hasWriteTodosEvidence,
|
|
162
|
+
hasPlanStateEvidence: resultEvidence.hasIncompletePlanState === true || resultEvidence.hasPlanStateEvidence === true,
|
|
163
|
+
hasToolResultEvidence: resultEvidence.hasToolResultEvidence,
|
|
164
|
+
});
|
|
165
|
+
if (missingPlanRecoveryInstruction) {
|
|
166
|
+
return missingPlanRecoveryInstruction;
|
|
167
|
+
}
|
|
123
168
|
const hasUnfinishedExecution = resultEvidence.hasIncompletePlanState === true
|
|
124
169
|
|| resultEvidence.hasOpenTaskDelegation === true
|
|
125
170
|
|| resultEvidence.hasMissingDelegatedExecutionEvidence === true;
|
|
@@ -31,6 +31,11 @@ export declare function getBindingDeepAgentSubagents(binding: CompiledAgentBindi
|
|
|
31
31
|
export declare function getBindingGeneralPurposeAgent(binding: CompiledAgentBinding): boolean | undefined;
|
|
32
32
|
export declare function getBindingTaskDescription(binding: CompiledAgentBinding): string | undefined;
|
|
33
33
|
export declare function getBindingBackendConfig(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
34
|
+
export declare function getBindingInteractionMode(binding: CompiledAgentBinding): "stream" | "invoke" | undefined;
|
|
35
|
+
export declare function getBindingBuiltinToolsConfig(binding: CompiledAgentBinding): {
|
|
36
|
+
filesystem?: boolean;
|
|
37
|
+
todos?: boolean;
|
|
38
|
+
} | undefined;
|
|
34
39
|
export declare function getBindingFilesystemConfig(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
35
40
|
export declare function isLangChainBinding(binding: CompiledAgentBinding): boolean;
|
|
36
41
|
export declare function isDeepAgentBinding(binding: CompiledAgentBinding): boolean;
|
|
@@ -229,6 +229,18 @@ export function getBindingBackendConfig(binding) {
|
|
|
229
229
|
const backend = execution?.backend;
|
|
230
230
|
return typeof backend === "object" && backend ? backend : undefined;
|
|
231
231
|
}
|
|
232
|
+
export function getBindingInteractionMode(binding) {
|
|
233
|
+
const execution = getBindingExecutionParams(binding);
|
|
234
|
+
const mode = execution?.interactionMode;
|
|
235
|
+
return mode === "invoke" || mode === "stream" ? mode : undefined;
|
|
236
|
+
}
|
|
237
|
+
export function getBindingBuiltinToolsConfig(binding) {
|
|
238
|
+
const execution = getBindingExecutionParams(binding);
|
|
239
|
+
const builtinTools = execution?.builtinTools;
|
|
240
|
+
return typeof builtinTools === "object" && builtinTools
|
|
241
|
+
? builtinTools
|
|
242
|
+
: undefined;
|
|
243
|
+
}
|
|
232
244
|
export function getBindingFilesystemConfig(binding) {
|
|
233
245
|
const langchainFilesystem = binding.harnessRuntime?.langchain?.filesystem;
|
|
234
246
|
if (typeof langchainFilesystem === "object" && langchainFilesystem) {
|
|
@@ -169,6 +169,7 @@ export function requireTools(tools, bindings, ownerId) {
|
|
|
169
169
|
function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parentModel) {
|
|
170
170
|
const execution = compileExecutionCore(agent, workspaceRoot, models, tools);
|
|
171
171
|
return {
|
|
172
|
+
agentId: agent.id,
|
|
172
173
|
name: resolveAgentRuntimeName(agent),
|
|
173
174
|
description: agent.description,
|
|
174
175
|
systemPrompt: execution.systemPrompt ?? WORKSPACE_BOUNDARY_GUIDANCE,
|
|
@@ -178,6 +179,7 @@ function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parent
|
|
|
178
179
|
skills: compileAgentSkills(workspaceRoot, agent, parentSkills),
|
|
179
180
|
responseFormat: execution.responseFormat,
|
|
180
181
|
middleware: execution.middleware,
|
|
182
|
+
builtinTools: getAgentExecutionObject(agent, "builtinTools"),
|
|
181
183
|
};
|
|
182
184
|
}
|
|
183
185
|
function resolveSystemPrompt(agent, workspaceRoot) {
|
|
@@ -484,6 +486,12 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
484
486
|
name: resolveAgentRuntimeName(agent),
|
|
485
487
|
memory: compiledAgentMemory,
|
|
486
488
|
skills: compiledAgentSkills,
|
|
489
|
+
interactionMode: getAgentExecutionConfigValue(agent, "interactionMode", { executionMode: "deepagent" }) === "invoke"
|
|
490
|
+
? "invoke"
|
|
491
|
+
: getAgentExecutionConfigValue(agent, "interactionMode", { executionMode: "deepagent" }) === "stream"
|
|
492
|
+
? "stream"
|
|
493
|
+
: undefined,
|
|
494
|
+
builtinTools: getAgentExecutionObject(agent, "builtinTools"),
|
|
487
495
|
},
|
|
488
496
|
};
|
|
489
497
|
return attachLegacyExecutionAliases({
|
|
@@ -27,6 +27,8 @@ const CONSUMED_AGENT_CONFIG_KEYS = [
|
|
|
27
27
|
"taskDescription",
|
|
28
28
|
"generalPurposeAgent",
|
|
29
29
|
"filesystem",
|
|
30
|
+
"builtinTools",
|
|
31
|
+
"interactionMode",
|
|
30
32
|
];
|
|
31
33
|
const NON_AGENT_CONFIG_ITEM_KEYS = [
|
|
32
34
|
"id",
|
|
@@ -61,6 +63,8 @@ const MIGRATED_AGENT_CONFIG_KEYS = [
|
|
|
61
63
|
"taskDescription",
|
|
62
64
|
"generalPurposeAgent",
|
|
63
65
|
"filesystem",
|
|
66
|
+
"builtinTools",
|
|
67
|
+
"interactionMode",
|
|
64
68
|
];
|
|
65
69
|
function normalizeAgentItemForMerge(item) {
|
|
66
70
|
const normalized = { ...item };
|
|
@@ -223,6 +227,7 @@ function resolveExecutionBackend(item, current) {
|
|
|
223
227
|
function readSharedAgentConfigFields(config, options = {}) {
|
|
224
228
|
return {
|
|
225
229
|
...(typeof config.store === "object" && config.store ? { store: config.store } : {}),
|
|
230
|
+
...(typeof config.builtinTools === "object" && config.builtinTools ? { builtinTools: cloneConfigValue(config.builtinTools) } : {}),
|
|
226
231
|
...(options.includeDelegationControls && typeof config.taskDescription === "string" && config.taskDescription.trim()
|
|
227
232
|
? { taskDescription: config.taskDescription }
|
|
228
233
|
: {}),
|
|
@@ -258,6 +263,7 @@ function readSharedAgentConfig(config) {
|
|
|
258
263
|
...(config.stateSchema !== undefined ? { stateSchema: config.stateSchema } : {}),
|
|
259
264
|
...(config.responseFormat !== undefined ? { responseFormat: config.responseFormat } : {}),
|
|
260
265
|
...(config.contextSchema !== undefined ? { contextSchema: config.contextSchema } : {}),
|
|
266
|
+
...(config.interactionMode === "stream" || config.interactionMode === "invoke" ? { interactionMode: config.interactionMode } : {}),
|
|
261
267
|
...(config.includeAgentName === "inline" ? { includeAgentName: "inline" } : {}),
|
|
262
268
|
...(config.version === "v1" || config.version === "v2" ? { version: config.version } : {}),
|
|
263
269
|
...(typeof config.filesystem === "object" && config.filesystem ? { filesystem: config.filesystem } : {}),
|