@standardagents/builder 0.40.9 → 0.40.11

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 (40) hide show
  1. package/dist/built-in-routes.js +452 -318
  2. package/dist/built-in-routes.js.map +1 -1
  3. package/dist/client/{ApiKeysView-DW_rcgbf.js → ApiKeysView-CLJcSURO.js} +1 -1
  4. package/dist/client/{CenteredContentView-BwxhThjf.js → CenteredContentView-Doo-25XV.js} +1 -1
  5. package/dist/client/{CompositionView-DQQloYHA.js → CompositionView-DkL-88Do.js} +1 -1
  6. package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-DCZCVtJJ.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-DX3R4n1_.js} +1 -1
  7. package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-DPaK8ZgZ.js → CopyButton.vue_vue_type_script_setup_true_lang-DdUwJPW0.js} +1 -1
  8. package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-oU3rezOQ.js → DataTable.vue_vue_type_script_setup_true_lang-DKoKf8B6.js} +1 -1
  9. package/dist/client/{JsonViewer-Dd0PDdAu.js → JsonViewer-jsOg5DGq.js} +1 -1
  10. package/dist/client/{LoginView-BoUWDaYZ.js → LoginView-BNjka0iU.js} +1 -1
  11. package/dist/client/{MarketplaceView-Dq3arYjz.js → MarketplaceView-3UAub3nO.js} +1 -1
  12. package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-CwLmWuhx.js → Modal.vue_vue_type_script_setup_true_lang-qePAuq2r.js} +1 -1
  13. package/dist/client/{ModelModal.vue_vue_type_script_setup_true_lang-ByVG_rEF.js → ModelModal.vue_vue_type_script_setup_true_lang-C5XxfCnh.js} +1 -1
  14. package/dist/client/{ModelsView-CNxZxuMY.js → ModelsView-Bud7F6og.js} +1 -1
  15. package/dist/client/{PromptEditView-CdALsRZ0.js → PromptEditView-Bjk45d3C.js} +1 -1
  16. package/dist/client/{PromptModal-Bg9-3prv.js → PromptModal-B9vO98yn.js} +1 -1
  17. package/dist/client/{PromptsView-BgumN2bU.js → PromptsView-BxllDChd.js} +1 -1
  18. package/dist/client/{ProvidersView-C9UvETp8.js → ProvidersView-DdwP0tM3.js} +1 -1
  19. package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-CpDJMTFJ.js +22 -0
  20. package/dist/client/{ThreadsView-G7WPUvXx.js → ThreadsView-R3VsT9cU.js} +1 -1
  21. package/dist/client/{ToolsView-VXM-IHXM.js → ToolsView-DfLtZHdm.js} +1 -1
  22. package/dist/client/{UsersView-C_LlI9x0.js → UsersView-9oV0DT6V.js} +1 -1
  23. package/dist/client/{VariablesView-BlsswVjj.js → VariablesView-Dg1ysfpJ.js} +1 -1
  24. package/dist/client/assets/{ThreadInspectorPane-CKH1L6Sn.css → ThreadInspectorPane-D5-ZEb8g.css} +1 -1
  25. package/dist/client/assets/index-kdYdNUXS.css +1 -0
  26. package/dist/client/{index-CRZrWTvf.js → index-CtrlevjG.js} +2 -2
  27. package/dist/client/index.html +2 -2
  28. package/dist/{index-DYhbT5Eq.d.ts → index-sEfQVa91.d.ts} +6 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.js +529 -359
  31. package/dist/index.js.map +1 -1
  32. package/dist/plugin.js +4 -0
  33. package/dist/plugin.js.map +1 -1
  34. package/dist/runtime.d.ts +10 -2
  35. package/dist/runtime.js +525 -359
  36. package/dist/runtime.js.map +1 -1
  37. package/dist/test.d.ts +1 -1
  38. package/package.json +5 -5
  39. package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-BNKZouHJ.js +0 -22
  40. package/dist/client/assets/index-DAABRRAA.css +0 -1
@@ -445,6 +445,7 @@ var init_logBroadcast = __esm({
445
445
  "message_id",
446
446
  "provider",
447
447
  "actual_provider",
448
+ "standard_agents_router_used",
448
449
  "model",
449
450
  "model_name",
450
451
  "prompt_name",
@@ -455,6 +456,7 @@ var init_logBroadcast = __esm({
455
456
  "retry_of_log_id",
456
457
  "error",
457
458
  "error_type",
459
+ "error_origin",
458
460
  "finish_reason",
459
461
  "cost_total",
460
462
  "cost_input",
@@ -477,6 +479,71 @@ var init_logBroadcast = __esm({
477
479
  ];
478
480
  }
479
481
  });
482
+
483
+ // src/agents/errorOrigin.ts
484
+ function normalizedOrigin(value) {
485
+ if (typeof value !== "string") return void 0;
486
+ const origin = value.trim();
487
+ return ERROR_ORIGIN_PATTERN.test(origin) ? origin : void 0;
488
+ }
489
+ function normalizedUpstream(value) {
490
+ if (typeof value !== "string") return void 0;
491
+ const upstream = value.trim();
492
+ return upstream.length > 0 ? upstream : void 0;
493
+ }
494
+ function errorObject(error) {
495
+ return error !== null && (typeof error === "object" || typeof error === "function") ? error : null;
496
+ }
497
+ function resolveErrorAttribution(error, context = {}) {
498
+ const object161 = errorObject(error);
499
+ const stored = object161?.[ATTRIBUTION];
500
+ if (stored) return stored;
501
+ const taggedOrigin = normalizedOrigin(object161?.origin);
502
+ const provider = normalizedUpstream(object161?.upstream) ?? normalizedUpstream(context.provider);
503
+ const standardAgentsRouterUsed = context.viaPlatform === true;
504
+ if (taggedOrigin) {
505
+ return {
506
+ origin: taggedOrigin,
507
+ ...provider ? { upstream: provider } : {},
508
+ standardAgentsRouterUsed
509
+ };
510
+ }
511
+ if (provider) {
512
+ return {
513
+ origin: standardAgentsRouterUsed ? "platform-router" : `provider:${provider}`,
514
+ upstream: provider,
515
+ standardAgentsRouterUsed
516
+ };
517
+ }
518
+ return {
519
+ origin: context.fallback ?? "runtime",
520
+ standardAgentsRouterUsed
521
+ };
522
+ }
523
+ function attributeThrownError(error, context) {
524
+ const attributed = errorObject(error) ?? new Error(String(error));
525
+ const attribution = resolveErrorAttribution(attributed, context);
526
+ try {
527
+ Object.defineProperty(attributed, ATTRIBUTION, {
528
+ configurable: true,
529
+ value: attribution
530
+ });
531
+ return attributed;
532
+ } catch {
533
+ const wrapped = new Error(error instanceof Error ? error.message : String(error), {
534
+ cause: error
535
+ });
536
+ Object.defineProperty(wrapped, ATTRIBUTION, { value: attribution });
537
+ return wrapped;
538
+ }
539
+ }
540
+ var ATTRIBUTION, ERROR_ORIGIN_PATTERN;
541
+ var init_errorOrigin = __esm({
542
+ "src/agents/errorOrigin.ts"() {
543
+ ATTRIBUTION = Symbol("standard-agents-error-attribution");
544
+ ERROR_ORIGIN_PATTERN = /^(?:platform-router|runtime|(?:provider|tool|hook):[A-Za-z0-9._/@-]+)$/;
545
+ }
546
+ });
480
547
  var init_types2 = __esm({
481
548
  "src/agents/providers/types.ts"() {
482
549
  }
@@ -1786,6 +1853,7 @@ var init_LLMRequest = __esm({
1786
1853
  init_FlowEngine();
1787
1854
  init_toolProgress();
1788
1855
  init_logBroadcast();
1856
+ init_errorOrigin();
1789
1857
  NON_VISION_PLACEHOLDER_TEXT = "[Image omitted: model does not support vision]";
1790
1858
  STREAM_FIRST_CHUNK_TIMEOUT_MS = 12e4;
1791
1859
  STREAM_STALL_TIMEOUT_MS = 45e3;
@@ -2083,6 +2151,7 @@ var init_LLMRequest = __esm({
2083
2151
  state.thread.instance,
2084
2152
  getThreadState
2085
2153
  );
2154
+ await this.logProviderRoute(state, logId, provider.name, viaPlatform);
2086
2155
  const streamAbort = new AbortController();
2087
2156
  const parentSignal = state.abortController?.signal;
2088
2157
  let onParentAbort;
@@ -2096,332 +2165,370 @@ var init_LLMRequest = __esm({
2096
2165
  }
2097
2166
  const request = buildProviderRequest(context, modelDef, streamAbort.signal, state.threadId);
2098
2167
  let response;
2099
- await state.stream.waitFor(
2100
- async () => {
2101
- const requestSentAt = Date.now();
2102
- const firstChunkTimeoutMs = resolveStreamTimeoutMs(
2103
- state.env,
2104
- "STANDARD_AGENTS_STREAM_FIRST_CHUNK_TIMEOUT_MS",
2105
- STREAM_FIRST_CHUNK_TIMEOUT_MS
2106
- );
2107
- const stallTimeoutMs = resolveStreamTimeoutMs(
2108
- state.env,
2109
- "STANDARD_AGENTS_STREAM_STALL_TIMEOUT_MS",
2110
- STREAM_STALL_TIMEOUT_MS
2111
- );
2112
- let stalled = false;
2113
- const stallError = (budgetMs) => new ProviderError(
2114
- `Provider sent no chunk for ${Math.round(budgetMs / 1e3)}s`,
2115
- "timeout"
2116
- );
2117
- const awaitWithStallGuard = (work, budgetMs) => {
2118
- let timer;
2119
- work.catch(() => {
2120
- });
2121
- const timeout = new Promise((_resolve, reject) => {
2122
- timer = setTimeout(() => {
2123
- stalled = true;
2124
- reject(stallError(budgetMs));
2125
- streamAbort.abort();
2126
- }, budgetMs);
2127
- });
2128
- return Promise.race([work, timeout]).finally(() => {
2129
- if (timer) clearTimeout(timer);
2130
- });
2131
- };
2132
- const stream = await awaitWithStallGuard(provider.stream(request), firstChunkTimeoutMs);
2133
- let content = "";
2134
- let reasoning = "";
2135
- let outputChars = 0;
2136
- let lastEmittedChars = 0;
2137
- const GEN_EMIT_STEP = 80;
2138
- const maybeEmitGeneration = () => {
2139
- if (outputChars - lastEmittedChars >= GEN_EMIT_STEP) {
2140
- lastEmittedChars = outputChars;
2168
+ try {
2169
+ await state.stream.waitFor(
2170
+ async () => {
2171
+ const requestSentAt = Date.now();
2172
+ const firstChunkTimeoutMs = resolveStreamTimeoutMs(
2173
+ state.env,
2174
+ "STANDARD_AGENTS_STREAM_FIRST_CHUNK_TIMEOUT_MS",
2175
+ STREAM_FIRST_CHUNK_TIMEOUT_MS
2176
+ );
2177
+ const stallTimeoutMs = resolveStreamTimeoutMs(
2178
+ state.env,
2179
+ "STANDARD_AGENTS_STREAM_STALL_TIMEOUT_MS",
2180
+ STREAM_STALL_TIMEOUT_MS
2181
+ );
2182
+ let stalled = false;
2183
+ const stallError = (budgetMs) => new ProviderError(
2184
+ `Provider sent no chunk for ${Math.round(budgetMs / 1e3)}s`,
2185
+ "timeout"
2186
+ );
2187
+ const awaitWithStallGuard = (work, budgetMs) => {
2188
+ let timer;
2189
+ work.catch(() => {
2190
+ });
2191
+ const timeout = new Promise((_resolve, reject) => {
2192
+ timer = setTimeout(() => {
2193
+ stalled = true;
2194
+ reject(stallError(budgetMs));
2195
+ streamAbort.abort();
2196
+ }, budgetMs);
2197
+ });
2198
+ return Promise.race([work, timeout]).finally(() => {
2199
+ if (timer) clearTimeout(timer);
2200
+ });
2201
+ };
2202
+ const stream = await awaitWithStallGuard(provider.stream(request), firstChunkTimeoutMs);
2203
+ let content = "";
2204
+ let reasoning = "";
2205
+ let outputChars = 0;
2206
+ let lastEmittedChars = 0;
2207
+ const GEN_EMIT_STEP = 80;
2208
+ const maybeEmitGeneration = () => {
2209
+ if (outputChars - lastEmittedChars >= GEN_EMIT_STEP) {
2210
+ lastEmittedChars = outputChars;
2211
+ try {
2212
+ state.emitEvent?.("generation", { outputTokens: Math.ceil(outputChars / 4) });
2213
+ } catch {
2214
+ }
2215
+ }
2216
+ };
2217
+ const toolCallsMap = /* @__PURE__ */ new Map();
2218
+ const images = [];
2219
+ const webSearches = [];
2220
+ const providerToolCalls = [];
2221
+ let finishReason = "stop";
2222
+ let usage;
2223
+ let reasoningDetails;
2224
+ let actualProvider;
2225
+ let providerResponseId;
2226
+ let firstChunkAt = 0;
2227
+ let firstTokenAt = 0;
2228
+ let lastTokenAt = 0;
2229
+ const noteToken = () => {
2230
+ const now = Date.now();
2231
+ if (firstTokenAt === 0) firstTokenAt = now;
2232
+ lastTokenAt = now;
2233
+ };
2234
+ const emitLogPatch = (data) => {
2141
2235
  try {
2142
- state.emitEvent?.("generation", { outputTokens: Math.ceil(outputChars / 4) });
2236
+ state.emitLog?.({ type: "log_data", log_id: logId, data: { id: logId, ...data } });
2143
2237
  } catch {
2144
2238
  }
2145
- }
2146
- };
2147
- const toolCallsMap = /* @__PURE__ */ new Map();
2148
- const images = [];
2149
- const webSearches = [];
2150
- const providerToolCalls = [];
2151
- let finishReason = "stop";
2152
- let usage;
2153
- let reasoningDetails;
2154
- let providerResponseId;
2155
- let firstChunkAt = 0;
2156
- let firstTokenAt = 0;
2157
- let lastTokenAt = 0;
2158
- const noteToken = () => {
2159
- const now = Date.now();
2160
- if (firstTokenAt === 0) firstTokenAt = now;
2161
- lastTokenAt = now;
2162
- };
2163
- const emitLogPatch = (data) => {
2239
+ };
2240
+ const streamedToolNames = [];
2241
+ let lastPreviewChars = 0;
2242
+ const PREVIEW_EMIT_STEP = 80;
2243
+ const maybeEmitPreview = () => {
2244
+ if (outputChars - lastPreviewChars >= PREVIEW_EMIT_STEP) {
2245
+ lastPreviewChars = outputChars;
2246
+ emitLogPatch({
2247
+ content: content || null,
2248
+ reasoning_content: reasoning || null
2249
+ });
2250
+ }
2251
+ };
2252
+ const iterator = stream[Symbol.asyncIterator]();
2164
2253
  try {
2165
- state.emitLog?.({ type: "log_data", log_id: logId, data: { id: logId, ...data } });
2166
- } catch {
2167
- }
2168
- };
2169
- const streamedToolNames = [];
2170
- let lastPreviewChars = 0;
2171
- const PREVIEW_EMIT_STEP = 80;
2172
- const maybeEmitPreview = () => {
2173
- if (outputChars - lastPreviewChars >= PREVIEW_EMIT_STEP) {
2174
- lastPreviewChars = outputChars;
2175
- emitLogPatch({
2176
- content: content || null,
2177
- reasoning_content: reasoning || null
2178
- });
2179
- }
2180
- };
2181
- const iterator = stream[Symbol.asyncIterator]();
2182
- try {
2183
- while (true) {
2184
- if (state.abortController?.signal?.aborted) break;
2185
- if (await state.thread.instance.shouldStop()) break;
2186
- let next;
2187
- try {
2188
- next = await awaitWithStallGuard(
2189
- iterator.next(),
2190
- firstChunkAt === 0 ? firstChunkTimeoutMs : stallTimeoutMs
2191
- );
2192
- } catch (streamErr) {
2193
- if (stalled) throw streamErr;
2194
- if (state.abortController?.signal?.aborted || await state.thread.instance.shouldStop()) {
2195
- break;
2254
+ while (true) {
2255
+ if (state.abortController?.signal?.aborted) break;
2256
+ if (await state.thread.instance.shouldStop()) break;
2257
+ let next;
2258
+ try {
2259
+ next = await awaitWithStallGuard(
2260
+ iterator.next(),
2261
+ firstChunkAt === 0 ? firstChunkTimeoutMs : stallTimeoutMs
2262
+ );
2263
+ } catch (streamErr) {
2264
+ if (stalled) throw streamErr;
2265
+ if (state.abortController?.signal?.aborted || await state.thread.instance.shouldStop()) {
2266
+ break;
2267
+ }
2268
+ throw streamErr;
2196
2269
  }
2197
- throw streamErr;
2198
- }
2199
- if (next.done) break;
2200
- const chunk = next.value;
2201
- state.thread.instance.noteExecutionProgress?.();
2202
- if (firstChunkAt === 0 && chunkCarriesPayload(chunk)) {
2203
- firstChunkAt = Date.now();
2204
- emitLogPatch({ time_to_first_token_ms: firstChunkAt - requestSentAt });
2205
- }
2206
- switch (chunk.type) {
2207
- case "content-delta":
2208
- content += chunk.delta;
2209
- state.stream.sendContent(chunk.delta);
2210
- this.emitContentChunk(chunk.delta, state);
2211
- outputChars += chunk.delta.length;
2212
- noteToken();
2213
- maybeEmitGeneration();
2214
- maybeEmitPreview();
2215
- break;
2216
- case "reasoning-delta":
2217
- reasoning += chunk.delta;
2218
- this.emitReasoningChunk(chunk.delta, state);
2219
- outputChars += chunk.delta.length;
2220
- noteToken();
2221
- maybeEmitGeneration();
2222
- maybeEmitPreview();
2223
- break;
2224
- case "tool-call-start":
2225
- {
2270
+ if (next.done) break;
2271
+ const chunk = next.value;
2272
+ state.thread.instance.noteExecutionProgress?.();
2273
+ if (firstChunkAt === 0 && chunkCarriesPayload(chunk)) {
2274
+ firstChunkAt = Date.now();
2275
+ emitLogPatch({ time_to_first_token_ms: firstChunkAt - requestSentAt });
2276
+ }
2277
+ switch (chunk.type) {
2278
+ case "content-delta":
2279
+ content += chunk.delta;
2280
+ state.stream.sendContent(chunk.delta);
2281
+ this.emitContentChunk(chunk.delta, state);
2282
+ outputChars += chunk.delta.length;
2226
2283
  noteToken();
2227
- const entry = {
2228
- id: chunk.id,
2229
- name: chunk.name,
2230
- argumentsDelta: "",
2231
- extraContent: chunk.extraContent,
2232
- startedFired: false,
2233
- progressArg: void 0
2234
- };
2235
- toolCallsMap.set(chunk.id, entry);
2236
- if (chunk.name) {
2237
- streamedToolNames.push(chunk.name);
2238
- emitLogPatch({ tools_called: JSON.stringify(streamedToolNames) });
2239
- }
2240
- const progressArg = await this.resolveProgressArgument(state, chunk.name);
2241
- if (progressArg) {
2242
- entry.progressArg = progressArg;
2243
- } else {
2244
- await this.fireToolCallStarted(state, entry, void 0);
2245
- }
2246
- }
2247
- break;
2248
- case "tool-call-delta":
2249
- {
2250
- const tc = toolCallsMap.get(chunk.id);
2251
- if (tc) {
2252
- tc.argumentsDelta += chunk.argumentsDelta;
2253
- outputChars += chunk.argumentsDelta.length;
2284
+ maybeEmitGeneration();
2285
+ maybeEmitPreview();
2286
+ break;
2287
+ case "reasoning-delta":
2288
+ reasoning += chunk.delta;
2289
+ this.emitReasoningChunk(chunk.delta, state);
2290
+ outputChars += chunk.delta.length;
2291
+ noteToken();
2292
+ maybeEmitGeneration();
2293
+ maybeEmitPreview();
2294
+ break;
2295
+ case "tool-call-start":
2296
+ {
2254
2297
  noteToken();
2255
- maybeEmitGeneration();
2256
- if (tc.progressArg && !tc.startedFired && tc.argumentsDelta.length <= PROGRESS_ARG_SCAN_CAP) {
2257
- const value = await readCompletedArg(tc.argumentsDelta, tc.progressArg);
2258
- if (value !== void 0) {
2259
- await this.fireToolCallStarted(state, tc, value);
2298
+ const entry = {
2299
+ id: chunk.id,
2300
+ name: chunk.name,
2301
+ argumentsDelta: "",
2302
+ extraContent: chunk.extraContent,
2303
+ startedFired: false,
2304
+ progressArg: void 0
2305
+ };
2306
+ toolCallsMap.set(chunk.id, entry);
2307
+ if (chunk.name) {
2308
+ streamedToolNames.push(chunk.name);
2309
+ emitLogPatch({ tools_called: JSON.stringify(streamedToolNames) });
2310
+ }
2311
+ const progressArg = await this.resolveProgressArgument(state, chunk.name);
2312
+ if (progressArg) {
2313
+ entry.progressArg = progressArg;
2314
+ } else {
2315
+ await this.fireToolCallStarted(state, entry, void 0);
2316
+ }
2317
+ }
2318
+ break;
2319
+ case "tool-call-delta":
2320
+ {
2321
+ const tc = toolCallsMap.get(chunk.id);
2322
+ if (tc) {
2323
+ tc.argumentsDelta += chunk.argumentsDelta;
2324
+ outputChars += chunk.argumentsDelta.length;
2325
+ noteToken();
2326
+ maybeEmitGeneration();
2327
+ if (tc.progressArg && !tc.startedFired && tc.argumentsDelta.length <= PROGRESS_ARG_SCAN_CAP) {
2328
+ const value = await readCompletedArg(tc.argumentsDelta, tc.progressArg);
2329
+ if (value !== void 0) {
2330
+ await this.fireToolCallStarted(state, tc, value);
2331
+ }
2260
2332
  }
2261
2333
  }
2262
2334
  }
2263
- }
2264
- break;
2265
- case "tool-call-done":
2266
- {
2267
- const existing = toolCallsMap.get(chunk.id);
2268
- toolCallsMap.set(chunk.id, {
2269
- ...existing,
2270
- id: chunk.id,
2271
- name: existing?.name ?? "",
2272
- argumentsDelta: JSON.stringify(chunk.arguments),
2273
- extraContent: chunk.extraContent ?? existing?.extraContent
2335
+ break;
2336
+ case "tool-call-done":
2337
+ {
2338
+ const existing = toolCallsMap.get(chunk.id);
2339
+ toolCallsMap.set(chunk.id, {
2340
+ ...existing,
2341
+ id: chunk.id,
2342
+ name: existing?.name ?? "",
2343
+ argumentsDelta: JSON.stringify(chunk.arguments),
2344
+ extraContent: chunk.extraContent ?? existing?.extraContent
2345
+ });
2346
+ }
2347
+ break;
2348
+ case "finish":
2349
+ finishReason = chunk.finishReason;
2350
+ usage = chunk.usage;
2351
+ reasoningDetails = chunk.reasoningDetails;
2352
+ providerResponseId = chunk.responseId;
2353
+ break;
2354
+ case "image-done":
2355
+ images.push({
2356
+ id: chunk.image.id,
2357
+ toolName: chunk.image.toolName,
2358
+ data: chunk.image.data,
2359
+ mediaType: chunk.image.mediaType,
2360
+ revisedPrompt: chunk.image.revisedPrompt
2274
2361
  });
2275
- }
2276
- break;
2277
- case "finish":
2278
- finishReason = chunk.finishReason;
2279
- usage = chunk.usage;
2280
- reasoningDetails = chunk.reasoningDetails;
2281
- providerResponseId = chunk.responseId;
2282
- break;
2283
- case "image-done":
2284
- images.push({
2285
- id: chunk.image.id,
2286
- toolName: chunk.image.toolName,
2287
- data: chunk.image.data,
2288
- mediaType: chunk.image.mediaType,
2289
- revisedPrompt: chunk.image.revisedPrompt
2290
- });
2291
- break;
2292
- case "web-search-done":
2293
- webSearches.push(chunk.result);
2294
- break;
2295
- case "provider-tool-done":
2296
- providerToolCalls.push(chunk.tool);
2297
- break;
2298
- case "error":
2299
- throw new ProviderError(
2300
- chunk.error,
2301
- chunk.code || "unknown"
2362
+ break;
2363
+ case "web-search-done":
2364
+ webSearches.push(chunk.result);
2365
+ break;
2366
+ case "provider-tool-done":
2367
+ providerToolCalls.push(chunk.tool);
2368
+ break;
2369
+ case "error":
2370
+ throw new ProviderError(
2371
+ chunk.error,
2372
+ chunk.code || "unknown"
2373
+ );
2374
+ }
2375
+ }
2376
+ } finally {
2377
+ if (onParentAbort && parentSignal) {
2378
+ parentSignal.removeEventListener("abort", onParentAbort);
2379
+ }
2380
+ try {
2381
+ const cleanup = iterator.return?.();
2382
+ if (cleanup) {
2383
+ await awaitBounded(
2384
+ Promise.resolve(cleanup),
2385
+ STREAM_CLEANUP_BUDGET_MS,
2386
+ "stream iterator cleanup"
2302
2387
  );
2388
+ }
2389
+ } catch {
2303
2390
  }
2304
2391
  }
2305
- } finally {
2306
- if (onParentAbort && parentSignal) {
2307
- parentSignal.removeEventListener("abort", onParentAbort);
2308
- }
2309
- try {
2310
- const cleanup = iterator.return?.();
2311
- if (cleanup) {
2312
- await awaitBounded(
2313
- Promise.resolve(cleanup),
2314
- STREAM_CLEANUP_BUDGET_MS,
2315
- "stream iterator cleanup"
2316
- );
2392
+ for (const tc of toolCallsMap.values()) {
2393
+ if (!tc.startedFired) {
2394
+ const progress = tc.progressArg ? await readCompletedArg(tc.argumentsDelta, tc.progressArg) : void 0;
2395
+ await this.fireToolCallStarted(state, tc, progress);
2317
2396
  }
2318
- } catch {
2319
- }
2320
- }
2321
- for (const tc of toolCallsMap.values()) {
2322
- if (!tc.startedFired) {
2323
- const progress = tc.progressArg ? await readCompletedArg(tc.argumentsDelta, tc.progressArg) : void 0;
2324
- await this.fireToolCallStarted(state, tc, progress);
2325
- }
2326
- }
2327
- const toolCalls = [];
2328
- for (const tc of toolCallsMap.values()) {
2329
- try {
2330
- toolCalls.push({
2331
- id: tc.id,
2332
- name: tc.name,
2333
- arguments: JSON.parse(tc.argumentsDelta || "{}"),
2334
- extraContent: tc.extraContent
2335
- });
2336
- } catch {
2337
- toolCalls.push({
2338
- id: tc.id,
2339
- name: tc.name,
2340
- arguments: {},
2341
- extraContent: tc.extraContent
2342
- });
2343
- }
2344
- }
2345
- const responseId = `res_${crypto.randomUUID().substring(0, 12)}`;
2346
- const responseImages = images.length > 0 ? images.map((img) => ({
2347
- type: "image_url",
2348
- id: img.id,
2349
- toolName: img.toolName,
2350
- image_url: {
2351
- url: img.data.startsWith("data:") ? img.data : `data:${img.mediaType};base64,${img.data}`
2352
2397
  }
2353
- })) : void 0;
2354
- response = {
2355
- id: responseId,
2356
- model: modelName,
2357
- content: content || null,
2358
- reasoning_content: reasoning || null,
2359
- reasoning_details: reasoningDetails,
2360
- // Include reasoning details for multi-turn context
2361
- tool_calls: toolCalls.length > 0 ? convertToolCalls(toolCalls) : void 0,
2362
- images: responseImages,
2363
- finish_reason: finishReason,
2364
- usage: usage ? convertUsage(usage) : {
2365
- prompt_tokens: 0,
2366
- completion_tokens: 0,
2367
- total_tokens: 0
2398
+ const toolCalls = [];
2399
+ for (const tc of toolCallsMap.values()) {
2400
+ try {
2401
+ toolCalls.push({
2402
+ id: tc.id,
2403
+ name: tc.name,
2404
+ arguments: JSON.parse(tc.argumentsDelta || "{}"),
2405
+ extraContent: tc.extraContent
2406
+ });
2407
+ } catch {
2408
+ toolCalls.push({
2409
+ id: tc.id,
2410
+ name: tc.name,
2411
+ arguments: {},
2412
+ extraContent: tc.extraContent
2413
+ });
2414
+ }
2368
2415
  }
2369
- };
2370
- response._provider = provider;
2371
- response._viaPlatform = viaPlatform;
2372
- if (platformProxyOrigin) {
2373
- const feePercent = getObservedRouterFeePercent(platformProxyOrigin);
2374
- if (feePercent !== null) {
2375
- response._routerFeePercent = feePercent;
2416
+ const responseId = `res_${crypto.randomUUID().substring(0, 12)}`;
2417
+ const responseImages = images.length > 0 ? images.map((img) => ({
2418
+ type: "image_url",
2419
+ id: img.id,
2420
+ toolName: img.toolName,
2421
+ image_url: {
2422
+ url: img.data.startsWith("data:") ? img.data : `data:${img.mediaType};base64,${img.data}`
2423
+ }
2424
+ })) : void 0;
2425
+ response = {
2426
+ id: responseId,
2427
+ model: modelName,
2428
+ content: content || null,
2429
+ reasoning_content: reasoning || null,
2430
+ reasoning_details: reasoningDetails,
2431
+ // Include reasoning details for multi-turn context
2432
+ tool_calls: toolCalls.length > 0 ? convertToolCalls(toolCalls) : void 0,
2433
+ images: responseImages,
2434
+ finish_reason: finishReason,
2435
+ usage: usage ? convertUsage(usage) : {
2436
+ prompt_tokens: 0,
2437
+ completion_tokens: 0,
2438
+ total_tokens: 0
2439
+ }
2440
+ };
2441
+ response._provider = provider;
2442
+ response._viaPlatform = viaPlatform;
2443
+ if (platformProxyOrigin) {
2444
+ const feePercent = getObservedRouterFeePercent(platformProxyOrigin);
2445
+ if (feePercent !== null) {
2446
+ response._routerFeePercent = feePercent;
2447
+ }
2376
2448
  }
2449
+ response._providerResponseId = providerResponseId;
2450
+ response._timing = {
2451
+ latencyMs: firstChunkAt > 0 ? firstChunkAt - requestSentAt : null,
2452
+ generationMs: firstTokenAt > 0 ? Math.max(0, lastTokenAt - firstTokenAt) : null
2453
+ };
2454
+ response._aggregate_response = {
2455
+ id: responseId,
2456
+ model: modelName,
2457
+ choices: [
2458
+ {
2459
+ index: 0,
2460
+ message: {
2461
+ role: "assistant",
2462
+ content: content || null,
2463
+ reasoning_content: reasoning || null,
2464
+ reasoning_details: reasoningDetails,
2465
+ tool_calls: toolCalls.length > 0 ? convertToolCalls(toolCalls) : void 0,
2466
+ // Include generated images in the aggregate response
2467
+ // Store ID for mapping to file paths later (don't store base64 data)
2468
+ images: images.length > 0 ? images.map((img) => ({
2469
+ type: "image_url",
2470
+ _id: img.id,
2471
+ // For path lookup
2472
+ image_url: {
2473
+ url: `[image:${img.id}]`
2474
+ // Placeholder, will be replaced with path
2475
+ }
2476
+ })) : void 0
2477
+ },
2478
+ finish_reason: finishReason
2479
+ }
2480
+ ],
2481
+ usage: response.usage,
2482
+ // Also store image count for quick reference
2483
+ image_count: images.length,
2484
+ // Store web search results for logging
2485
+ web_searches: webSearches.length > 0 ? webSearches : void 0,
2486
+ // Store generic provider-executed tools for logging
2487
+ provider_tools: providerToolCalls.length > 0 ? providerToolCalls : void 0
2488
+ };
2377
2489
  }
2378
- response._providerResponseId = providerResponseId;
2379
- response._timing = {
2380
- latencyMs: firstChunkAt > 0 ? firstChunkAt - requestSentAt : null,
2381
- generationMs: firstTokenAt > 0 ? Math.max(0, lastTokenAt - firstTokenAt) : null
2382
- };
2383
- response._aggregate_response = {
2384
- id: responseId,
2385
- model: modelName,
2386
- choices: [
2387
- {
2388
- index: 0,
2389
- message: {
2390
- role: "assistant",
2391
- content: content || null,
2392
- reasoning_content: reasoning || null,
2393
- reasoning_details: reasoningDetails,
2394
- tool_calls: toolCalls.length > 0 ? convertToolCalls(toolCalls) : void 0,
2395
- // Include generated images in the aggregate response
2396
- // Store ID for mapping to file paths later (don't store base64 data)
2397
- images: images.length > 0 ? images.map((img) => ({
2398
- type: "image_url",
2399
- _id: img.id,
2400
- // For path lookup
2401
- image_url: {
2402
- url: `[image:${img.id}]`
2403
- // Placeholder, will be replaced with path
2404
- }
2405
- })) : void 0
2406
- },
2407
- finish_reason: finishReason
2408
- }
2409
- ],
2410
- usage: response.usage,
2411
- // Also store image count for quick reference
2412
- image_count: images.length,
2413
- // Store web search results for logging
2414
- web_searches: webSearches.length > 0 ? webSearches : void 0,
2415
- // Store generic provider-executed tools for logging
2416
- provider_tools: providerToolCalls.length > 0 ? providerToolCalls : void 0
2417
- };
2490
+ );
2491
+ } catch (error) {
2492
+ if (onParentAbort && parentSignal) {
2493
+ parentSignal.removeEventListener("abort", onParentAbort);
2418
2494
  }
2419
- );
2495
+ throw attributeThrownError(error, {
2496
+ provider: provider.name,
2497
+ viaPlatform
2498
+ });
2499
+ }
2420
2500
  if (!response) {
2421
2501
  throw new Error("Provider stream returned no response");
2422
2502
  }
2423
2503
  return response;
2424
2504
  }
2505
+ /** Persist and broadcast provider-route attribution before any response. */
2506
+ static async logProviderRoute(state, logId, providerName, viaPlatform) {
2507
+ try {
2508
+ if (!state.storage?.sql) return;
2509
+ const upstream = viaPlatform ? providerName : null;
2510
+ await state.storage.sql.exec(
2511
+ `UPDATE logs
2512
+ SET standard_agents_router_used = ?1,
2513
+ actual_provider = COALESCE(actual_provider, ?2)
2514
+ WHERE id = ?3`,
2515
+ viaPlatform ? 1 : 0,
2516
+ upstream,
2517
+ logId
2518
+ );
2519
+ state.emitLog?.({
2520
+ type: "log_data",
2521
+ log_id: logId,
2522
+ data: {
2523
+ id: logId,
2524
+ standard_agents_router_used: viaPlatform,
2525
+ ...upstream ? { actual_provider: upstream } : {}
2526
+ }
2527
+ });
2528
+ } catch (error) {
2529
+ console.error("Failed to update provider route attribution (non-fatal):", error);
2530
+ }
2531
+ }
2425
2532
  /**
2426
2533
  * Emit content chunk to WebSocket for real-time UI updates
2427
2534
  */
@@ -2742,6 +2849,7 @@ var init_LLMRequest = __esm({
2742
2849
  */
2743
2850
  static async logError(state, error, errorType, modelId, startTime, existingLogId) {
2744
2851
  try {
2852
+ const attribution = resolveErrorAttribution(error);
2745
2853
  let rawErrorMessage = error instanceof Error ? error.message : String(error);
2746
2854
  const errorStack = error instanceof Error ? error.stack : void 0;
2747
2855
  if (error instanceof Error && error.name === "AbortError" && /operation was aborted/i.test(rawErrorMessage)) {
@@ -2783,8 +2891,12 @@ var init_LLMRequest = __esm({
2783
2891
  // Parameter that caused error
2784
2892
  "user_id",
2785
2893
  // User context
2786
- "response"
2894
+ "response",
2787
2895
  // Raw response
2896
+ "origin",
2897
+ // Structured error origin from ProviderError/custom providers
2898
+ "upstream"
2899
+ // Actual upstream behind an adapter/router
2788
2900
  ];
2789
2901
  const metadata = {};
2790
2902
  for (const field of relevantFields) {
@@ -2835,6 +2947,7 @@ ${errorStack}` : ""}${errorDetails}`;
2835
2947
  errorsArray.push({
2836
2948
  message: truncatedError,
2837
2949
  type: errorType,
2950
+ origin: attribution.origin,
2838
2951
  timestamp: Date.now()
2839
2952
  });
2840
2953
  await state.storage.sql.exec(
@@ -2842,20 +2955,29 @@ ${errorStack}` : ""}${errorDetails}`;
2842
2955
  UPDATE logs SET
2843
2956
  error = ?1,
2844
2957
  error_type = ?2,
2845
- errors = ?3,
2846
- latency_ms = ?4,
2847
- is_complete = ?5
2848
- WHERE id = ?6
2958
+ error_origin = ?3,
2959
+ errors = ?4,
2960
+ latency_ms = ?5,
2961
+ is_complete = ?6,
2962
+ actual_provider = COALESCE(actual_provider, ?7),
2963
+ standard_agents_router_used = CASE
2964
+ WHEN ?8 = 1 THEN 1
2965
+ ELSE standard_agents_router_used
2966
+ END
2967
+ WHERE id = ?9
2849
2968
  `,
2850
2969
  truncatedError,
2851
2970
  // Keep last error in error field for backwards compatibility
2852
2971
  errorType,
2853
2972
  // Keep last error type
2973
+ attribution.origin,
2854
2974
  JSON.stringify(errorsArray),
2855
2975
  // All errors in array
2856
2976
  Date.now() - startTime,
2857
2977
  1,
2858
2978
  // is_complete = true
2979
+ attribution.upstream ?? null,
2980
+ attribution.standardAgentsRouterUsed ? 1 : 0,
2859
2981
  trackedLogId
2860
2982
  );
2861
2983
  }
@@ -2868,6 +2990,9 @@ ${errorStack}` : ""}${errorDetails}`;
2868
2990
  id: trackedLogId,
2869
2991
  error: truncatedError,
2870
2992
  error_type: errorType,
2993
+ error_origin: attribution.origin,
2994
+ ...attribution.upstream ? { actual_provider: attribution.upstream } : {},
2995
+ ...attribution.standardAgentsRouterUsed ? { standard_agents_router_used: true } : {},
2871
2996
  latency_ms: Date.now() - startTime,
2872
2997
  is_complete: true
2873
2998
  }
@@ -2884,9 +3009,12 @@ ${errorStack}` : ""}${errorDetails}`;
2884
3009
  id,
2885
3010
  message_id: messageId || "00000000-0000-0000-0000-000000000000",
2886
3011
  provider: this.getProviderFromModel(modelId),
3012
+ actual_provider: attribution.upstream ?? null,
3013
+ standard_agents_router_used: attribution.standardAgentsRouterUsed,
2887
3014
  model: modelId,
2888
3015
  error: truncatedError,
2889
3016
  error_type: errorType,
3017
+ error_origin: attribution.origin,
2890
3018
  latency_ms: Date.now() - startTime,
2891
3019
  is_complete: true,
2892
3020
  created_at: Date.now() * TIMESTAMP_MULTIPLIER
@@ -2897,16 +3025,19 @@ ${errorStack}` : ""}${errorDetails}`;
2897
3025
  await state.storage.sql.exec(
2898
3026
  `
2899
3027
  INSERT INTO logs (
2900
- id, message_id, provider, model,
2901
- error, error_type, latency_ms, is_complete, created_at
2902
- ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)
3028
+ id, message_id, provider, actual_provider, standard_agents_router_used, model,
3029
+ error, error_type, error_origin, latency_ms, is_complete, created_at
3030
+ ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
2903
3031
  `,
2904
3032
  logData.id,
2905
3033
  messageId,
2906
3034
  logData.provider,
3035
+ logData.actual_provider,
3036
+ logData.standard_agents_router_used ? 1 : 0,
2907
3037
  logData.model,
2908
3038
  logData.error,
2909
3039
  logData.error_type,
3040
+ logData.error_origin,
2910
3041
  logData.latency_ms,
2911
3042
  1,
2912
3043
  logData.created_at
@@ -6489,11 +6620,13 @@ ${errorStack}` : ""}`;
6489
6620
  UPDATE logs
6490
6621
  SET
6491
6622
  error = ?1,
6492
- error_type = ?2
6493
- WHERE id = ?3
6623
+ error_type = ?2,
6624
+ error_origin = ?3
6625
+ WHERE id = ?4
6494
6626
  `,
6495
6627
  fullError,
6496
6628
  "tool_execution_error",
6629
+ `tool:${toolName}`,
6497
6630
  parentLogId
6498
6631
  );
6499
6632
  if (state.emitLog) {
@@ -6503,7 +6636,8 @@ ${errorStack}` : ""}`;
6503
6636
  data: {
6504
6637
  id: parentLogId,
6505
6638
  error: fullError,
6506
- error_type: "tool_execution_error"
6639
+ error_type: "tool_execution_error",
6640
+ error_origin: `tool:${toolName}`
6507
6641
  }
6508
6642
  });
6509
6643
  }
@@ -7000,7 +7134,7 @@ var init_FlowEngine = __esm({
7000
7134
  const error = "Request did not complete \u2014 the response was interrupted (the worker was evicted or the provider stalled) before it finished.";
7001
7135
  const errorType = "interrupted_incomplete";
7002
7136
  await state.storage.sql.exec(
7003
- `UPDATE logs SET is_complete = 1, error = ?1, error_type = ?2 WHERE is_complete = 0`,
7137
+ `UPDATE logs SET is_complete = 1, error = ?1, error_type = ?2, error_origin = 'runtime' WHERE is_complete = 0`,
7004
7138
  error,
7005
7139
  errorType
7006
7140
  );
@@ -7008,7 +7142,7 @@ var init_FlowEngine = __esm({
7008
7142
  state.emitLog?.({
7009
7143
  type: "log_data",
7010
7144
  log_id: row.id,
7011
- data: { id: row.id, is_complete: true, error, error_type: errorType }
7145
+ data: { id: row.id, is_complete: true, error, error_type: errorType, error_origin: "runtime" }
7012
7146
  });
7013
7147
  }
7014
7148
  console.warn(
@@ -7544,7 +7678,7 @@ This usually points to something I can't fix from here \u2014 for example the wo
7544
7678
  pendingMessageId
7545
7679
  );
7546
7680
  await state.storage.sql.exec(
7547
- `UPDATE logs SET error = ?, error_type = ? WHERE id = ?`,
7681
+ `UPDATE logs SET error = ?, error_type = ?, error_origin = 'runtime' WHERE id = ?`,
7548
7682
  "Interrupted by user",
7549
7683
  "user_interrupted",
7550
7684
  logId
@@ -11087,8 +11221,8 @@ ${errorStack}` : ""}`;
11087
11221
  `
11088
11222
  INSERT INTO logs (
11089
11223
  id, message_id, provider, model,
11090
- error, error_type, created_at
11091
- ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
11224
+ error, error_type, error_origin, created_at
11225
+ ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, 'runtime', ?7)
11092
11226
  `,
11093
11227
  crypto.randomUUID(),
11094
11228
  messageId,
@@ -68862,7 +68996,7 @@ var config_get_default = defineController2(async ({ config, env: env2, req }) =>
68862
68996
  });
68863
68997
 
68864
68998
  // src/version.ts
68865
- var BUILDER_VERSION = "0.40.9".length > 0 ? "0.40.9" : "dev";
68999
+ var BUILDER_VERSION = "0.40.11".length > 0 ? "0.40.11" : "dev";
68866
69000
 
68867
69001
  // src/api/diagnostics.get.ts
68868
69002
  init_LLMRequest();