@botbotgo/agent-harness 0.0.298 → 0.0.299

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.
Files changed (166) hide show
  1. package/README.md +77 -37
  2. package/README.zh.md +79 -30
  3. package/dist/acp.d.ts +3 -0
  4. package/dist/acp.js +10 -2
  5. package/dist/api.d.ts +14 -2
  6. package/dist/api.js +19 -3
  7. package/dist/cli.d.ts +18 -1
  8. package/dist/cli.js +1408 -319
  9. package/dist/client/acp.d.ts +9 -3
  10. package/dist/client/acp.js +55 -1
  11. package/dist/client/in-process.d.ts +5 -2
  12. package/dist/client/in-process.js +4 -6
  13. package/dist/client/index.d.ts +1 -1
  14. package/dist/client/types.d.ts +6 -5
  15. package/dist/config/agents/direct.yaml +7 -17
  16. package/dist/config/agents/orchestra.yaml +9 -65
  17. package/dist/config/catalogs/embedding-models.yaml +1 -1
  18. package/dist/config/catalogs/stores.yaml +1 -1
  19. package/dist/config/knowledge/knowledge-runtime.yaml +36 -2
  20. package/dist/config/knowledge/procedural-memory-runtime.yaml +78 -0
  21. package/dist/config/{catalogs/models.yaml → models.yaml} +2 -2
  22. package/dist/config/prompts/direct-system.md +16 -0
  23. package/dist/config/prompts/orchestra-system.md +62 -0
  24. package/dist/config/prompts/routing-system.md +14 -0
  25. package/dist/config/runtime/runtime-memory.yaml +39 -5
  26. package/dist/config/runtime/workspace.yaml +7 -16
  27. package/dist/contracts/runtime.d.ts +242 -1
  28. package/dist/contracts/workspace.d.ts +2 -0
  29. package/dist/index.d.ts +5 -3
  30. package/dist/index.js +2 -1
  31. package/dist/init-project.js +178 -33
  32. package/dist/knowledge/contracts.d.ts +5 -0
  33. package/dist/knowledge/module.d.ts +5 -0
  34. package/dist/knowledge/module.js +340 -18
  35. package/dist/package-version.d.ts +1 -1
  36. package/dist/package-version.js +1 -1
  37. package/dist/persistence/file-store.d.ts +5 -1
  38. package/dist/persistence/file-store.js +16 -0
  39. package/dist/persistence/sqlite-store.d.ts +4 -1
  40. package/dist/persistence/sqlite-store.js +88 -14
  41. package/dist/persistence/types.d.ts +4 -1
  42. package/dist/procedural/config.d.ts +63 -0
  43. package/dist/procedural/config.js +125 -0
  44. package/dist/procedural/index.d.ts +2 -0
  45. package/dist/procedural/index.js +1 -0
  46. package/dist/protocol/ag-ui/http.d.ts +3 -0
  47. package/dist/protocol/ag-ui/http.js +10 -0
  48. package/dist/request-events.d.ts +63 -0
  49. package/dist/request-events.js +400 -0
  50. package/dist/resource/isolation.js +11 -0
  51. package/dist/resource/resource-impl.d.ts +1 -0
  52. package/dist/resource/resource-impl.js +103 -12
  53. package/dist/resources/init-templates/agent-context/deep-research.md +5 -0
  54. package/dist/resources/init-templates/prompts/research-analyst-basic.md +1 -0
  55. package/dist/resources/init-templates/prompts/research-analyst-web-search.md +1 -0
  56. package/dist/resources/init-templates/prompts/research-host-deep-research-basic.md +1 -0
  57. package/dist/resources/init-templates/prompts/research-host-deep-research-web-search.md +1 -0
  58. package/dist/resources/init-templates/prompts/research-host-single-agent-basic.md +1 -0
  59. package/dist/resources/init-templates/prompts/research-host-single-agent-web-search.md +1 -0
  60. package/dist/resources/prompts/runtime/browser-capability-disclaimer-recovery.md +1 -0
  61. package/dist/resources/prompts/runtime/default-subagent.md +2 -0
  62. package/dist/resources/prompts/runtime/durable-memory-context.md +7 -0
  63. package/dist/resources/prompts/runtime/execution-with-tool-evidence-retry.md +1 -0
  64. package/dist/resources/prompts/runtime/execution-with-tool-evidence.md +1 -0
  65. package/dist/resources/prompts/runtime/invalid-tool-selection-recovery.md +1 -0
  66. package/dist/resources/prompts/runtime/memory-manager.md +31 -0
  67. package/dist/resources/prompts/runtime/memory-mutation-reconciliation.md +22 -0
  68. package/dist/resources/prompts/runtime/slash-command-skill.md +6 -0
  69. package/dist/resources/prompts/runtime/strict-tool-json.md +1 -0
  70. package/dist/resources/prompts/runtime/workspace-boundary-guidance.md +3 -0
  71. package/dist/resources/prompts/runtime/workspace-relative-path.md +1 -0
  72. package/dist/resources/prompts/runtime/write-todos-descriptive-content.md +1 -0
  73. package/dist/resources/prompts/runtime/write-todos-full-entry.md +1 -0
  74. package/dist/resources/prompts/runtime/write-todos-non-empty-initial-list.md +1 -0
  75. package/dist/resources/tools/_runtime_tool_helpers.mjs +152 -0
  76. package/dist/resources/tools/cancel_request.mjs +21 -0
  77. package/dist/resources/tools/fetch_url.mjs +23 -0
  78. package/dist/resources/tools/http_request.mjs +30 -0
  79. package/dist/resources/tools/inspect_approvals.mjs +27 -0
  80. package/dist/resources/tools/inspect_artifacts.mjs +21 -0
  81. package/dist/resources/tools/inspect_events.mjs +21 -0
  82. package/dist/resources/tools/inspect_requests.mjs +27 -0
  83. package/dist/resources/tools/inspect_sessions.mjs +21 -0
  84. package/dist/resources/tools/list_files.mjs +27 -0
  85. package/dist/resources/tools/read_artifact.mjs +22 -0
  86. package/dist/resources/tools/request_approval.mjs +27 -0
  87. package/dist/resources/tools/run_command.mjs +21 -0
  88. package/dist/resources/tools/schedule_task.mjs +76 -0
  89. package/dist/resources/tools/search_files.mjs +47 -0
  90. package/dist/resources/tools/send_message.mjs +23 -0
  91. package/dist/runtime/adapter/direct-builtin-utility.d.ts +1 -0
  92. package/dist/runtime/adapter/direct-builtin-utility.js +90 -0
  93. package/dist/runtime/adapter/flow/execution-context.d.ts +1 -1
  94. package/dist/runtime/adapter/flow/execution-context.js +1 -1
  95. package/dist/runtime/adapter/flow/invocation-flow.d.ts +1 -0
  96. package/dist/runtime/adapter/flow/invocation-flow.js +9 -1
  97. package/dist/runtime/adapter/flow/invoke-runtime.d.ts +1 -1
  98. package/dist/runtime/adapter/flow/stream-runtime.d.ts +5 -1
  99. package/dist/runtime/adapter/flow/stream-runtime.js +556 -35
  100. package/dist/runtime/adapter/invocation-result.js +3 -2
  101. package/dist/runtime/adapter/local-tool-invocation.d.ts +1 -1
  102. package/dist/runtime/adapter/local-tool-invocation.js +28 -4
  103. package/dist/runtime/adapter/middleware-assembly.js +3 -1
  104. package/dist/runtime/adapter/model/invocation-request.d.ts +4 -1
  105. package/dist/runtime/adapter/model/invocation-request.js +138 -16
  106. package/dist/runtime/adapter/model/message-assembly.js +2 -6
  107. package/dist/runtime/adapter/model/model-providers.js +103 -5
  108. package/dist/runtime/adapter/resilience.js +17 -2
  109. package/dist/runtime/adapter/runtime-adapter-support.d.ts +11 -7
  110. package/dist/runtime/adapter/runtime-adapter-support.js +39 -5
  111. package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +63 -1
  112. package/dist/runtime/adapter/tool/builtin-middleware-tools.js +193 -21
  113. package/dist/runtime/adapter/tool/tool-arguments.d.ts +3 -1
  114. package/dist/runtime/adapter/tool/tool-arguments.js +52 -17
  115. package/dist/runtime/adapter/tool-resolution.d.ts +1 -0
  116. package/dist/runtime/adapter/tool-resolution.js +4 -2
  117. package/dist/runtime/agent-runtime-adapter.d.ts +27 -0
  118. package/dist/runtime/agent-runtime-adapter.js +163 -11
  119. package/dist/runtime/harness/events/event-bus.d.ts +1 -0
  120. package/dist/runtime/harness/events/event-bus.js +3 -0
  121. package/dist/runtime/harness/events/event-sink.d.ts +3 -0
  122. package/dist/runtime/harness/events/event-sink.js +16 -7
  123. package/dist/runtime/harness/events/streaming.d.ts +18 -1
  124. package/dist/runtime/harness/events/streaming.js +23 -10
  125. package/dist/runtime/harness/run/inspection.js +26 -5
  126. package/dist/runtime/harness/run/stream-run.d.ts +13 -4
  127. package/dist/runtime/harness/run/stream-run.js +448 -4
  128. package/dist/runtime/harness/run/surface-semantics.js +7 -34
  129. package/dist/runtime/harness/system/runtime-memory-manager.d.ts +3 -0
  130. package/dist/runtime/harness/system/runtime-memory-manager.js +384 -69
  131. package/dist/runtime/harness/system/runtime-memory-policy.d.ts +20 -1
  132. package/dist/runtime/harness/system/runtime-memory-policy.js +65 -17
  133. package/dist/runtime/harness/system/runtime-memory-records.js +100 -0
  134. package/dist/runtime/harness/system/runtime-memory-sync.js +2 -2
  135. package/dist/runtime/harness/system/store.d.ts +4 -0
  136. package/dist/runtime/harness/system/store.js +153 -0
  137. package/dist/runtime/harness.d.ts +9 -1
  138. package/dist/runtime/harness.js +141 -7
  139. package/dist/runtime/maintenance/sqlite-checkpoint-saver.d.ts +8 -3
  140. package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +152 -53
  141. package/dist/runtime/parsing/output-parsing.d.ts +10 -2
  142. package/dist/runtime/parsing/output-parsing.js +223 -16
  143. package/dist/runtime/parsing/stream-event-parsing.d.ts +7 -0
  144. package/dist/runtime/parsing/stream-event-parsing.js +51 -1
  145. package/dist/runtime/scheduling/system-schedule-manager.d.ts +41 -0
  146. package/dist/runtime/scheduling/system-schedule-manager.js +532 -0
  147. package/dist/runtime/support/embedding-models.d.ts +1 -1
  148. package/dist/runtime/support/embedding-models.js +5 -2
  149. package/dist/runtime/support/runtime-factories.js +1 -1
  150. package/dist/runtime/support/runtime-layout.d.ts +3 -0
  151. package/dist/runtime/support/runtime-layout.js +10 -1
  152. package/dist/runtime/support/runtime-prompts.d.ts +30 -0
  153. package/dist/runtime/support/runtime-prompts.js +55 -0
  154. package/dist/runtime/support/vector-stores.d.ts +1 -1
  155. package/dist/runtime/support/vector-stores.js +5 -2
  156. package/dist/upstream-events.js +8 -7
  157. package/dist/utils/bundled-text.d.ts +3 -0
  158. package/dist/utils/bundled-text.js +25 -0
  159. package/dist/utils/id.js +3 -2
  160. package/dist/workspace/agent-binding-compiler.js +53 -13
  161. package/dist/workspace/object-loader.js +64 -2
  162. package/dist/workspace/support/workspace-ref-utils.d.ts +2 -1
  163. package/dist/workspace/support/workspace-ref-utils.js +24 -5
  164. package/dist/workspace/yaml-object-reader.d.ts +1 -0
  165. package/dist/workspace/yaml-object-reader.js +95 -17
  166. package/package.json +11 -5
@@ -1,67 +1,477 @@
1
- import { isToolCallRecoveryFailure, resolveToolCallRecoveryInstruction, sanitizeVisibleText, } from "../../parsing/output-parsing.js";
1
+ import { extractVisibleOutput, isToolCallRecoveryFailure, isRetrySafeInvalidToolSelectionError, shouldValidateExecutionWithoutToolEvidence, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, sanitizeVisibleText, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, } from "../../parsing/output-parsing.js";
2
2
  import { buildInvocationRequest } from "../model/invocation-request.js";
3
3
  import { buildRawModelMessages } from "../model/message-assembly.js";
4
4
  import { projectRuntimeStreamEvent, createStreamEventProjectionState } from "../stream-event-projection.js";
5
5
  import { projectTextStreamChunks } from "../stream-text-consumption.js";
6
6
  import { computeRemainingTimeoutMs } from "../resilience.js";
7
7
  import { UPSTREAM_REQUEST_CONFIG_KEY, UPSTREAM_SESSION_CONFIG_KEY } from "../upstream-configurable-keys.js";
8
+ function toVisibleContent(value) {
9
+ const extracted = extractVisibleOutput(value);
10
+ return extracted ? sanitizeVisibleText(extracted) : "";
11
+ }
12
+ function createProfileStep(id, kind, name, action, status, detail) {
13
+ return {
14
+ kind: "profile",
15
+ step: {
16
+ id,
17
+ kind,
18
+ name,
19
+ action,
20
+ status,
21
+ ...(detail ? { detail } : {}),
22
+ },
23
+ };
24
+ }
25
+ function startProfileStep(input) {
26
+ const startedAt = new Date().toISOString();
27
+ return {
28
+ startedAt,
29
+ chunk: createProfileStep(input.id, input.kind, input.name, input.action, "started", {
30
+ ...(input.detail ?? {}),
31
+ startedAt,
32
+ }),
33
+ };
34
+ }
35
+ function finishProfileStep(input) {
36
+ const endedAt = new Date().toISOString();
37
+ return createProfileStep(input.id, input.kind, input.name, input.action, input.status, {
38
+ ...(input.detail ?? {}),
39
+ startedAt: input.startedAt,
40
+ endedAt,
41
+ durationMs: Math.max(0, new Date(endedAt).getTime() - new Date(input.startedAt).getTime()),
42
+ ...(input.error !== undefined ? { error: input.error instanceof Error ? input.error.message : String(input.error) } : {}),
43
+ });
44
+ }
8
45
  export async function* streamRuntimeExecution(options) {
9
46
  const request = buildInvocationRequest(options.binding, options.history, options.input, options.runtimeOptions);
47
+ let emittedUnsafeStreamSideEffects = false;
48
+ const shouldProfile = options.runtimeOptions.profiling === true;
49
+ const shouldValidateStreamOutput = shouldValidateExecutionWithoutToolEvidence(request);
50
+ const deferredStreamContent = [];
51
+ let sawRetrySafeInvalidToolSelectionError = false;
52
+ let sawNonRetrySafeToolSideEffects = false;
53
+ const shouldDeferStreamContent = () => shouldValidateStreamOutput && !emittedUnsafeStreamSideEffects;
54
+ const flushDeferredStreamContent = async function* () {
55
+ while (deferredStreamContent.length > 0) {
56
+ yield deferredStreamContent.shift();
57
+ }
58
+ };
10
59
  try {
11
60
  if (options.isLangChainBinding(options.binding) && options.canUseDirectModelStream && options.langChainStreamModel?.stream) {
12
- const stream = await options.withTimeout(() => options.langChainStreamModel.stream(buildRawModelMessages(options.binding, options.getSystemPrompt(options.binding), options.history, options.input, options.runtimeOptions.memoryContext)), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "model stream start", "stream");
61
+ const modelStreamStart = startProfileStep({
62
+ id: "profile:agent:model-stream-start",
63
+ kind: "agent",
64
+ name: "model stream",
65
+ action: "start",
66
+ });
67
+ if (shouldProfile)
68
+ yield modelStreamStart.chunk;
69
+ let stream;
70
+ try {
71
+ stream = await options.withTimeout(() => options.langChainStreamModel.stream(buildRawModelMessages(options.binding, options.getSystemPrompt(options.binding), options.history, options.input, options.runtimeOptions.memoryContext)), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "model stream start", "stream");
72
+ if (shouldProfile)
73
+ yield finishProfileStep({
74
+ id: "profile:agent:model-stream-start",
75
+ kind: "agent",
76
+ name: "model stream",
77
+ action: "start",
78
+ startedAt: modelStreamStart.startedAt,
79
+ status: "completed",
80
+ });
81
+ }
82
+ catch (error) {
83
+ if (shouldProfile)
84
+ yield finishProfileStep({
85
+ id: "profile:agent:model-stream-start",
86
+ kind: "agent",
87
+ name: "model stream",
88
+ action: "start",
89
+ startedAt: modelStreamStart.startedAt,
90
+ status: "failed",
91
+ error,
92
+ });
93
+ throw error;
94
+ }
13
95
  let emitted = false;
14
96
  const projected = projectTextStreamChunks(options.iterateWithTimeout(stream, options.streamIdleTimeoutMs, "model stream", options.streamDeadlineAt, options.invokeTimeoutMs));
15
- let nextChunk = await projected.next();
16
- while (!nextChunk.done) {
17
- if (nextChunk.value.kind === "content") {
18
- emitted = true;
97
+ const modelStreamConsume = startProfileStep({
98
+ id: "profile:agent:model-stream-consume",
99
+ kind: "agent",
100
+ name: "model stream",
101
+ action: "consume",
102
+ });
103
+ if (shouldProfile)
104
+ yield modelStreamConsume.chunk;
105
+ try {
106
+ let currentChunk = await projected.next();
107
+ while (!currentChunk.done) {
108
+ if (currentChunk.value.kind === "content") {
109
+ emitted = true;
110
+ emittedUnsafeStreamSideEffects = true;
111
+ }
112
+ yield currentChunk.value;
113
+ currentChunk = await projected.next();
114
+ }
115
+ if (shouldProfile)
116
+ yield finishProfileStep({
117
+ id: "profile:agent:model-stream-consume",
118
+ kind: "agent",
119
+ name: "model stream",
120
+ action: "consume",
121
+ startedAt: modelStreamConsume.startedAt,
122
+ status: "completed",
123
+ });
124
+ if (currentChunk.value.emittedContent || emitted) {
125
+ return;
19
126
  }
20
- yield nextChunk.value;
21
- nextChunk = await projected.next();
22
127
  }
23
- if (nextChunk.value.emittedContent || emitted) {
24
- return;
128
+ catch (error) {
129
+ if (shouldProfile)
130
+ yield finishProfileStep({
131
+ id: "profile:agent:model-stream-consume",
132
+ kind: "agent",
133
+ name: "model stream",
134
+ action: "consume",
135
+ startedAt: modelStreamConsume.startedAt,
136
+ status: "failed",
137
+ error,
138
+ });
139
+ throw error;
25
140
  }
26
141
  }
27
- const runnable = await options.createRunnable();
142
+ const createRunnableStep = startProfileStep({
143
+ id: "profile:agent:create-runnable",
144
+ kind: "agent",
145
+ name: "create runnable",
146
+ action: "startup",
147
+ });
148
+ if (shouldProfile)
149
+ yield createRunnableStep.chunk;
150
+ let runnable;
151
+ try {
152
+ runnable = await options.createRunnable();
153
+ if (shouldProfile)
154
+ yield finishProfileStep({
155
+ id: "profile:agent:create-runnable",
156
+ kind: "agent",
157
+ name: "create runnable",
158
+ action: "startup",
159
+ startedAt: createRunnableStep.startedAt,
160
+ status: "completed",
161
+ });
162
+ }
163
+ catch (error) {
164
+ if (shouldProfile)
165
+ yield finishProfileStep({
166
+ id: "profile:agent:create-runnable",
167
+ kind: "agent",
168
+ name: "create runnable",
169
+ action: "startup",
170
+ startedAt: createRunnableStep.startedAt,
171
+ status: "failed",
172
+ error,
173
+ });
174
+ throw error;
175
+ }
28
176
  if (!options.forceInvokeFallback && typeof runnable.streamEvents === "function") {
29
- const events = await options.withTimeout(() => runnable.streamEvents(request, { configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: options.runtimeOptions.requestId }, version: "v2", ...(options.runtimeOptions.context ? { context: options.runtimeOptions.context } : {}) }), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent streamEvents start", "stream");
177
+ const streamEventsStart = startProfileStep({
178
+ id: "profile:agent:stream-events-start",
179
+ kind: "agent",
180
+ name: "streamEvents",
181
+ action: "start",
182
+ });
183
+ if (shouldProfile)
184
+ yield streamEventsStart.chunk;
185
+ let events;
186
+ try {
187
+ events = await options.withTimeout(() => runnable.streamEvents(request, {
188
+ configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: options.runtimeOptions.requestId },
189
+ version: "v2",
190
+ ...(options.runtimeOptions.context ? { context: options.runtimeOptions.context } : {}),
191
+ ...(options.runtimeOptions.toolRuntimeContext ? { toolRuntimeContext: options.runtimeOptions.toolRuntimeContext } : {}),
192
+ }), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent streamEvents start", "stream");
193
+ if (shouldProfile)
194
+ yield finishProfileStep({
195
+ id: "profile:agent:stream-events-start",
196
+ kind: "agent",
197
+ name: "streamEvents",
198
+ action: "start",
199
+ startedAt: streamEventsStart.startedAt,
200
+ status: "completed",
201
+ });
202
+ }
203
+ catch (error) {
204
+ if (shouldProfile)
205
+ yield finishProfileStep({
206
+ id: "profile:agent:stream-events-start",
207
+ kind: "agent",
208
+ name: "streamEvents",
209
+ action: "start",
210
+ startedAt: streamEventsStart.startedAt,
211
+ status: "failed",
212
+ error,
213
+ });
214
+ throw error;
215
+ }
30
216
  const projectionState = createStreamEventProjectionState();
31
- for await (const event of options.iterateWithTimeout(events, options.streamIdleTimeoutMs, "agent streamEvents", options.streamDeadlineAt, options.invokeTimeoutMs)) {
32
- const projectedChunks = projectRuntimeStreamEvent({
33
- event,
34
- allowVisibleStreamDeltas: options.isLangChainBinding(options.binding),
35
- includeStateStreamOutput: options.isDeepAgentBinding(options.binding),
36
- toolNameMapping: options.toolNameMapping,
37
- primaryTools: options.primaryTools,
38
- state: projectionState,
217
+ const streamEventsConsume = startProfileStep({
218
+ id: "profile:agent:stream-events-consume",
219
+ kind: "agent",
220
+ name: "streamEvents",
221
+ action: "consume",
222
+ });
223
+ if (shouldProfile)
224
+ yield streamEventsConsume.chunk;
225
+ try {
226
+ for await (const event of options.iterateWithTimeout(events, options.streamIdleTimeoutMs, "agent streamEvents", options.streamDeadlineAt, options.invokeTimeoutMs)) {
227
+ const projectedChunks = projectRuntimeStreamEvent({
228
+ event,
229
+ allowVisibleStreamDeltas: options.isLangChainBinding(options.binding),
230
+ includeStateStreamOutput: options.isDeepAgentBinding(options.binding),
231
+ toolNameMapping: options.toolNameMapping,
232
+ primaryTools: options.primaryTools,
233
+ state: projectionState,
234
+ });
235
+ const eventContainsNonTodoToolResult = projectedChunks.some((chunk) => chunk.kind === "tool-result"
236
+ && chunk.toolName !== "write_todos"
237
+ && !(chunk.isError === true && isRetrySafeInvalidToolSelectionError(chunk.output)));
238
+ const eventContainsNonRetrySafeChunk = projectedChunks.some((chunk) => chunk.kind !== "upstream-event"
239
+ && chunk.kind !== "content"
240
+ && !(chunk.kind === "tool-result" && chunk.toolName === "write_todos")
241
+ && !(chunk.kind === "tool-result" && chunk.isError === true && isRetrySafeInvalidToolSelectionError(chunk.output)));
242
+ for (const chunk of projectedChunks) {
243
+ if (chunk.kind === "tool-result" && chunk.isError === true && isRetrySafeInvalidToolSelectionError(chunk.output)) {
244
+ sawRetrySafeInvalidToolSelectionError = true;
245
+ }
246
+ if ((eventContainsNonTodoToolResult || eventContainsNonRetrySafeChunk) && deferredStreamContent.length > 0) {
247
+ yield* flushDeferredStreamContent();
248
+ }
249
+ if (eventContainsNonTodoToolResult || eventContainsNonRetrySafeChunk) {
250
+ emittedUnsafeStreamSideEffects = true;
251
+ sawNonRetrySafeToolSideEffects = true;
252
+ }
253
+ if (chunk.kind === "content" && shouldDeferStreamContent()) {
254
+ deferredStreamContent.push(chunk);
255
+ continue;
256
+ }
257
+ yield chunk;
258
+ }
259
+ }
260
+ if (shouldProfile)
261
+ yield finishProfileStep({
262
+ id: "profile:agent:stream-events-consume",
263
+ kind: "agent",
264
+ name: "streamEvents",
265
+ action: "consume",
266
+ startedAt: streamEventsConsume.startedAt,
267
+ status: "completed",
268
+ });
269
+ }
270
+ catch (error) {
271
+ if (shouldProfile)
272
+ yield finishProfileStep({
273
+ id: "profile:agent:stream-events-consume",
274
+ kind: "agent",
275
+ name: "streamEvents",
276
+ action: "consume",
277
+ startedAt: streamEventsConsume.startedAt,
278
+ status: "failed",
279
+ error,
280
+ });
281
+ throw error;
282
+ }
283
+ const streamRecoveryInstruction = resolveExecutionWithoutToolEvidenceTextInstruction(request, projectionState.emittedOutput, projectionState.emittedToolResult || (projectionState.emittedToolError && (sawNonRetrySafeToolSideEffects || !sawRetrySafeInvalidToolSelectionError)));
284
+ const terminalRecoveryInstruction = streamRecoveryInstruction
285
+ ?? (!emittedUnsafeStreamSideEffects && sawRetrySafeInvalidToolSelectionError ? INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION : null);
286
+ if (!emittedUnsafeStreamSideEffects && terminalRecoveryInstruction) {
287
+ const toolRecovery = startProfileStep({
288
+ id: "profile:agent:stream-output-recovery-fallback",
289
+ kind: "agent",
290
+ name: "stream output recovery fallback",
291
+ action: "invoke",
292
+ detail: {
293
+ recoveryInstruction: terminalRecoveryInstruction,
294
+ },
39
295
  });
40
- for (const chunk of projectedChunks) {
41
- yield chunk;
296
+ if (shouldProfile)
297
+ yield toolRecovery.chunk;
298
+ let retried;
299
+ try {
300
+ retried = await options.invoke(options.applyToolRecoveryInstruction(options.binding, terminalRecoveryInstruction), options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
301
+ if (shouldProfile)
302
+ yield finishProfileStep({
303
+ id: "profile:agent:stream-output-recovery-fallback",
304
+ kind: "agent",
305
+ name: "stream output recovery fallback",
306
+ action: "invoke",
307
+ startedAt: toolRecovery.startedAt,
308
+ status: "completed",
309
+ detail: {
310
+ recoveryInstruction: terminalRecoveryInstruction,
311
+ },
312
+ });
313
+ }
314
+ catch (retryError) {
315
+ if (shouldProfile)
316
+ yield finishProfileStep({
317
+ id: "profile:agent:stream-output-recovery-fallback",
318
+ kind: "agent",
319
+ name: "stream output recovery fallback",
320
+ action: "invoke",
321
+ startedAt: toolRecovery.startedAt,
322
+ status: "failed",
323
+ detail: {
324
+ recoveryInstruction: terminalRecoveryInstruction,
325
+ },
326
+ error: retryError,
327
+ });
328
+ throw retryError;
329
+ }
330
+ const executedToolResults = Array.isArray(retried.metadata?.executedToolResults)
331
+ ? retried.metadata.executedToolResults
332
+ : [];
333
+ for (const toolResult of executedToolResults) {
334
+ yield {
335
+ kind: "tool-result",
336
+ toolName: toolResult.toolName,
337
+ output: toolResult.output,
338
+ isError: toolResult.isError,
339
+ };
42
340
  }
341
+ if (retried.output) {
342
+ const visible = toVisibleContent(retried.output);
343
+ if (visible) {
344
+ yield { kind: "content", content: visible };
345
+ }
346
+ }
347
+ return;
348
+ }
349
+ if (deferredStreamContent.length > 0) {
350
+ yield* flushDeferredStreamContent();
43
351
  }
44
352
  if (projectionState.emittedOutput || projectionState.emittedToolResult || projectionState.emittedToolError) {
45
353
  return;
46
354
  }
47
355
  }
48
356
  if (!options.forceInvokeFallback && options.isLangChainBinding(options.binding) && typeof runnable.stream === "function") {
49
- const stream = await options.withTimeout(() => runnable.stream(request, { configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: options.runtimeOptions.requestId } }), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent stream start", "stream");
357
+ const streamStart = startProfileStep({
358
+ id: "profile:agent:stream-start",
359
+ kind: "agent",
360
+ name: "stream",
361
+ action: "start",
362
+ });
363
+ if (shouldProfile)
364
+ yield streamStart.chunk;
365
+ let stream;
366
+ try {
367
+ stream = await options.withTimeout(() => runnable.stream(request, {
368
+ configurable: { [UPSTREAM_SESSION_CONFIG_KEY]: options.sessionId, [UPSTREAM_REQUEST_CONFIG_KEY]: options.runtimeOptions.requestId },
369
+ ...(options.runtimeOptions.toolRuntimeContext ? { toolRuntimeContext: options.runtimeOptions.toolRuntimeContext } : {}),
370
+ }), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent stream start", "stream");
371
+ if (shouldProfile)
372
+ yield finishProfileStep({
373
+ id: "profile:agent:stream-start",
374
+ kind: "agent",
375
+ name: "stream",
376
+ action: "start",
377
+ startedAt: streamStart.startedAt,
378
+ status: "completed",
379
+ });
380
+ }
381
+ catch (error) {
382
+ if (shouldProfile)
383
+ yield finishProfileStep({
384
+ id: "profile:agent:stream-start",
385
+ kind: "agent",
386
+ name: "stream",
387
+ action: "start",
388
+ startedAt: streamStart.startedAt,
389
+ status: "failed",
390
+ error,
391
+ });
392
+ throw error;
393
+ }
50
394
  let emitted = false;
51
395
  const projected = projectTextStreamChunks(options.iterateWithTimeout(stream, options.streamIdleTimeoutMs, "agent stream", options.streamDeadlineAt, options.invokeTimeoutMs));
52
- let nextChunk = await projected.next();
53
- while (!nextChunk.done) {
54
- if (nextChunk.value.kind === "content") {
55
- emitted = true;
396
+ const streamConsume = startProfileStep({
397
+ id: "profile:agent:stream-consume",
398
+ kind: "agent",
399
+ name: "stream",
400
+ action: "consume",
401
+ });
402
+ if (shouldProfile)
403
+ yield streamConsume.chunk;
404
+ try {
405
+ let nextChunk = await projected.next();
406
+ while (!nextChunk.done) {
407
+ if (nextChunk.value.kind === "content") {
408
+ emitted = true;
409
+ emittedUnsafeStreamSideEffects = true;
410
+ }
411
+ yield nextChunk.value;
412
+ nextChunk = await projected.next();
413
+ }
414
+ if (shouldProfile)
415
+ yield finishProfileStep({
416
+ id: "profile:agent:stream-consume",
417
+ kind: "agent",
418
+ name: "stream",
419
+ action: "consume",
420
+ startedAt: streamConsume.startedAt,
421
+ status: "completed",
422
+ });
423
+ if (nextChunk.value.emittedContent || emitted) {
424
+ return;
56
425
  }
57
- yield nextChunk.value;
58
- nextChunk = await projected.next();
59
426
  }
60
- if (nextChunk.value.emittedContent || emitted) {
61
- return;
427
+ catch (error) {
428
+ if (shouldProfile)
429
+ yield finishProfileStep({
430
+ id: "profile:agent:stream-consume",
431
+ kind: "agent",
432
+ name: "stream",
433
+ action: "consume",
434
+ startedAt: streamConsume.startedAt,
435
+ status: "failed",
436
+ error,
437
+ });
438
+ throw error;
62
439
  }
63
440
  }
64
- const result = await options.invoke(options.binding, options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
441
+ const invokeFallback = startProfileStep({
442
+ id: "profile:agent:invoke-fallback",
443
+ kind: "agent",
444
+ name: "invoke fallback",
445
+ action: "invoke",
446
+ });
447
+ if (shouldProfile)
448
+ yield invokeFallback.chunk;
449
+ let result;
450
+ try {
451
+ result = await options.invoke(options.binding, options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
452
+ if (shouldProfile)
453
+ yield finishProfileStep({
454
+ id: "profile:agent:invoke-fallback",
455
+ kind: "agent",
456
+ name: "invoke fallback",
457
+ action: "invoke",
458
+ startedAt: invokeFallback.startedAt,
459
+ status: "completed",
460
+ });
461
+ }
462
+ catch (error) {
463
+ if (shouldProfile)
464
+ yield finishProfileStep({
465
+ id: "profile:agent:invoke-fallback",
466
+ kind: "agent",
467
+ name: "invoke fallback",
468
+ action: "invoke",
469
+ startedAt: invokeFallback.startedAt,
470
+ status: "failed",
471
+ error,
472
+ });
473
+ throw error;
474
+ }
65
475
  const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
66
476
  ? result.metadata.executedToolResults
67
477
  : [];
@@ -74,10 +484,76 @@ export async function* streamRuntimeExecution(options) {
74
484
  };
75
485
  }
76
486
  if (result.output) {
77
- yield { kind: "content", content: sanitizeVisibleText(result.output) };
487
+ const visible = toVisibleContent(result.output);
488
+ if (visible) {
489
+ yield { kind: "content", content: visible };
490
+ }
78
491
  }
79
492
  }
80
493
  catch (error) {
494
+ if (!emittedUnsafeStreamSideEffects && options.isRetryableProviderError?.(options.binding, error)) {
495
+ const providerRetry = startProfileStep({
496
+ id: "profile:agent:provider-retry-fallback",
497
+ kind: "agent",
498
+ name: "provider retry fallback",
499
+ action: "invoke",
500
+ detail: {
501
+ error: error instanceof Error ? error.message : String(error),
502
+ },
503
+ });
504
+ if (shouldProfile)
505
+ yield providerRetry.chunk;
506
+ let recovered;
507
+ try {
508
+ recovered = await options.invoke(options.binding, options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
509
+ if (shouldProfile)
510
+ yield finishProfileStep({
511
+ id: "profile:agent:provider-retry-fallback",
512
+ kind: "agent",
513
+ name: "provider retry fallback",
514
+ action: "invoke",
515
+ startedAt: providerRetry.startedAt,
516
+ status: "completed",
517
+ detail: {
518
+ error: error instanceof Error ? error.message : String(error),
519
+ },
520
+ });
521
+ }
522
+ catch (retryError) {
523
+ if (shouldProfile)
524
+ yield finishProfileStep({
525
+ id: "profile:agent:provider-retry-fallback",
526
+ kind: "agent",
527
+ name: "provider retry fallback",
528
+ action: "invoke",
529
+ startedAt: providerRetry.startedAt,
530
+ status: "failed",
531
+ detail: {
532
+ error: error instanceof Error ? error.message : String(error),
533
+ },
534
+ error: retryError,
535
+ });
536
+ throw retryError;
537
+ }
538
+ const executedToolResults = Array.isArray(recovered.metadata?.executedToolResults)
539
+ ? recovered.metadata.executedToolResults
540
+ : [];
541
+ for (const toolResult of executedToolResults) {
542
+ yield {
543
+ kind: "tool-result",
544
+ toolName: toolResult.toolName,
545
+ output: toolResult.output,
546
+ isError: toolResult.isError,
547
+ };
548
+ }
549
+ if (recovered.output) {
550
+ const visible = toVisibleContent(recovered.output);
551
+ if (visible) {
552
+ yield { kind: "content", content: visible };
553
+ }
554
+ }
555
+ return;
556
+ }
81
557
  if (options.countConfiguredTools(options.binding) > 0 &&
82
558
  error instanceof Error &&
83
559
  error.message.includes("does not support tool binding")) {
@@ -90,9 +566,54 @@ export async function* streamRuntimeExecution(options) {
90
566
  if (!recoveryInstruction) {
91
567
  throw error;
92
568
  }
93
- const retried = await options.invoke(options.applyToolRecoveryInstruction(options.binding, recoveryInstruction), options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
569
+ const toolRecovery = startProfileStep({
570
+ id: "profile:agent:tool-recovery-fallback",
571
+ kind: "agent",
572
+ name: "tool recovery fallback",
573
+ action: "invoke",
574
+ detail: {
575
+ recoveryInstruction,
576
+ },
577
+ });
578
+ if (shouldProfile)
579
+ yield toolRecovery.chunk;
580
+ let retried;
581
+ try {
582
+ retried = await options.invoke(options.applyToolRecoveryInstruction(options.binding, recoveryInstruction), options.input, options.sessionId, options.runtimeOptions.requestId ?? options.sessionId, undefined, options.history, options.runtimeOptions);
583
+ if (shouldProfile)
584
+ yield finishProfileStep({
585
+ id: "profile:agent:tool-recovery-fallback",
586
+ kind: "agent",
587
+ name: "tool recovery fallback",
588
+ action: "invoke",
589
+ startedAt: toolRecovery.startedAt,
590
+ status: "completed",
591
+ detail: {
592
+ recoveryInstruction,
593
+ },
594
+ });
595
+ }
596
+ catch (retryError) {
597
+ if (shouldProfile)
598
+ yield finishProfileStep({
599
+ id: "profile:agent:tool-recovery-fallback",
600
+ kind: "agent",
601
+ name: "tool recovery fallback",
602
+ action: "invoke",
603
+ startedAt: toolRecovery.startedAt,
604
+ status: "failed",
605
+ detail: {
606
+ recoveryInstruction,
607
+ },
608
+ error: retryError,
609
+ });
610
+ throw retryError;
611
+ }
94
612
  if (retried.output) {
95
- yield { kind: "content", content: sanitizeVisibleText(retried.output) };
613
+ const visible = toVisibleContent(retried.output);
614
+ if (visible) {
615
+ yield { kind: "content", content: visible };
616
+ }
96
617
  }
97
618
  }
98
619
  }
@@ -1,4 +1,4 @@
1
- import { extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, sanitizeVisibleText, tryParseJson, } from "../parsing/output-parsing.js";
1
+ import { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, sanitizeVisibleText, tryParseJson, } from "../parsing/output-parsing.js";
2
2
  import { buildStateSnapshot } from "./model/message-assembly.js";
3
3
  import { asRecord } from "./tool/resolved-tool.js";
4
4
  export function finalizeRequestResult(params) {
@@ -11,7 +11,8 @@ export function finalizeRequestResult(params) {
11
11
  if (!visibleOutput && !toolFallback && emptyAssistantMessageFailure) {
12
12
  throw new Error(emptyAssistantMessageFailure);
13
13
  }
14
- const output = visibleOutput || toolFallback || JSON.stringify(result, null, 2);
14
+ const serializedResult = JSON.stringify(result, null, 2);
15
+ const output = visibleOutput || toolFallback || (containsLikelySkillDocument(result) ? "" : serializedResult);
15
16
  const finalMessageText = sanitizeVisibleText(output);
16
17
  const outputContent = extractOutputContent(result);
17
18
  const contentBlocks = extractContentBlocks(result);
@@ -4,7 +4,7 @@ import type { ExecutedToolResult } from "./invocation-result.js";
4
4
  type ExecutableTool = {
5
5
  name: string;
6
6
  schema: unknown;
7
- invoke: (input: unknown) => Promise<unknown>;
7
+ invoke: (input: unknown, config?: Record<string, unknown>) => Promise<unknown>;
8
8
  };
9
9
  type LocalToolInvocationParams = {
10
10
  binding: CompiledAgentBinding;