@tangle-network/agent-app 0.60.198 → 0.60.200

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 (41) hide show
  1. package/dist/chat-routes/index.js +6 -4
  2. package/dist/chat-routes/index.js.map +1 -1
  3. package/dist/chat-routes/turn-routes.d.ts +28 -0
  4. package/dist/{chunk-XJEIGVMQ.js → chunk-2OWT3TNV.js} +2 -2
  5. package/dist/{chunk-XP77DJEF.js → chunk-6XXKFYIM.js} +72 -30
  6. package/dist/chunk-6XXKFYIM.js.map +1 -0
  7. package/dist/chunk-7XQIY2LU.js +151 -0
  8. package/dist/chunk-7XQIY2LU.js.map +1 -0
  9. package/dist/chunk-BKPJFES3.js +229 -0
  10. package/dist/chunk-BKPJFES3.js.map +1 -0
  11. package/dist/{chunk-FPOOBGRG.js → chunk-T4BLISYH.js} +40 -5
  12. package/dist/chunk-T4BLISYH.js.map +1 -0
  13. package/dist/{chunk-SUIH5B55.js → chunk-ZHJ2TDWA.js} +199 -17
  14. package/dist/chunk-ZHJ2TDWA.js.map +1 -0
  15. package/dist/public-consultation/index.d.ts +1 -1
  16. package/dist/public-consultation/index.js +2 -1
  17. package/dist/public-consultation/index.js.map +1 -1
  18. package/dist/runtime/index.js +4 -2
  19. package/dist/runtime/index.js.map +1 -1
  20. package/dist/runtime/router-turn.d.ts +14 -1
  21. package/dist/runtime/router-turn.js +3 -1
  22. package/dist/sandbox/index.d.ts +20 -0
  23. package/dist/sandbox/index.js +4 -1
  24. package/dist/sandbox/prompt-trace.d.ts +26 -0
  25. package/dist/sandbox/sandbox-run-tool.d.ts +8 -0
  26. package/dist/trace/index.d.ts +0 -1
  27. package/dist/trace/index.js +0 -240
  28. package/dist/trace/index.js.map +1 -1
  29. package/dist/turn-trace/index.d.ts +11 -0
  30. package/dist/turn-trace/index.js +121 -0
  31. package/dist/turn-trace/index.js.map +1 -0
  32. package/dist/turn-trace/otel.d.ts +36 -0
  33. package/dist/turn-trace/recorder.d.ts +122 -0
  34. package/dist/turn-trace/server-timing.d.ts +15 -0
  35. package/dist/turn-trace/traced-fetch.d.ts +31 -0
  36. package/package.json +6 -1
  37. package/dist/chunk-FPOOBGRG.js.map +0 -1
  38. package/dist/chunk-SUIH5B55.js.map +0 -1
  39. package/dist/chunk-XP77DJEF.js.map +0 -1
  40. package/dist/trace/stage-timing.d.ts +0 -61
  41. /package/dist/{chunk-XJEIGVMQ.js.map → chunk-2OWT3TNV.js.map} +0 -0
@@ -21,6 +21,9 @@ import {
21
21
  import {
22
22
  buildAppToolMcpServer
23
23
  } from "./chunk-6A7MYOUI.js";
24
+ import {
25
+ nextCallIndex
26
+ } from "./chunk-7XQIY2LU.js";
24
27
  import {
25
28
  resolveTangleExecutionEnvironment,
26
29
  trimOrNull
@@ -40,6 +43,128 @@ var fail = (error) => ({
40
43
  error: error instanceof Error ? error : new Error(String(error))
41
44
  });
42
45
 
46
+ // src/sandbox/prompt-trace.ts
47
+ var asRec = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
48
+ var asNum = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
49
+ var PHASES = ["agent_run_start", "harness_spawn", "harness_ready", "first_model_request", "first_upstream_byte", "first_text"];
50
+ function createPromptTrace(trace, parent, meta) {
51
+ const startedAt = Date.now();
52
+ const prompt = trace.start("sandbox.prompt", "sandbox", meta, parent);
53
+ let firstEventAt;
54
+ let firstTextAt;
55
+ let generation;
56
+ let phases;
57
+ let events = 0;
58
+ const tools = /* @__PURE__ */ new Map();
59
+ const startTool = (id, name) => {
60
+ if (tools.has(id)) return;
61
+ tools.set(id, trace.start("tool.call", "tool", {
62
+ "gen_ai.tool.name": name,
63
+ "tool.call_id": id,
64
+ "call.index": nextCallIndex(trace, "tool.call"),
65
+ where: "sandbox",
66
+ approx: true
67
+ }, generation ?? prompt));
68
+ };
69
+ const observe = (raw) => {
70
+ try {
71
+ const event = asRec(raw);
72
+ if (!event) return;
73
+ const now = Date.now();
74
+ events++;
75
+ firstEventAt ??= now;
76
+ const type = typeof event.type === "string" ? event.type : "";
77
+ const data = asRec(event.data);
78
+ if (type === "result") {
79
+ const report = asRec(data?.firstTextPhases);
80
+ const offsets = asRec(report?.phasesMs);
81
+ if (offsets) {
82
+ phases = {
83
+ offsets,
84
+ warm: typeof report?.harnessWarm === "boolean" ? report.harnessWarm : null,
85
+ ...typeof report?.model === "string" ? { model: report.model } : {}
86
+ };
87
+ }
88
+ return;
89
+ }
90
+ if (type === "tool_call" || type === "tool.call") {
91
+ const id = String(data?.id ?? data?.callId ?? data?.callID ?? data?.name ?? "");
92
+ if (id) startTool(id, String(data?.name ?? data?.tool ?? "tool"));
93
+ return;
94
+ }
95
+ if (type === "tool_result" || type === "tool.result") {
96
+ const id = String(data?.id ?? data?.callId ?? data?.callID ?? data?.name ?? "");
97
+ tools.get(id)?.end(void 0, data?.error ?? (data?.status === "error" ? "tool_error" : void 0));
98
+ return;
99
+ }
100
+ if (type !== "message.part.updated") return;
101
+ const part = asRec(data?.part);
102
+ const partType = String(part?.type ?? "");
103
+ if (partType === "text" && firstTextAt === void 0 && (typeof data?.delta === "string" && data.delta || typeof part?.text === "string" && part.text)) {
104
+ firstTextAt = now;
105
+ generation = prompt.child("sandbox.generation", "model");
106
+ } else if (partType === "tool") {
107
+ const id = String(part?.id ?? part?.callID ?? "");
108
+ if (!id) return;
109
+ const state = asRec(part?.state);
110
+ const status = String(state?.status ?? part?.status ?? "");
111
+ startTool(id, String(part?.tool ?? "tool"));
112
+ if (status === "completed" || status === "error") tools.get(id)?.end(void 0, status === "error" ? "tool_error" : void 0);
113
+ }
114
+ } catch {
115
+ }
116
+ };
117
+ const end = (error) => {
118
+ try {
119
+ for (const span of tools.values()) span.end({ "tool.unclosed": true });
120
+ generation?.end();
121
+ if (phases && firstTextAt !== void 0) {
122
+ const firstText = asNum(phases.offsets.first_text);
123
+ if (firstText !== void 0 && firstTextAt - firstText >= startedAt) {
124
+ const origin = firstTextAt - firstText;
125
+ prompt.record("sandbox.transit", "sandbox", startedAt, origin, { note: "sdk, api, orchestrator and host hops, both ways" });
126
+ let previous = 0;
127
+ for (const phase of PHASES) {
128
+ const offset = asNum(phases.offsets[phase]);
129
+ if (offset === void 0 || offset < previous) continue;
130
+ prompt.record(`sidecar.${phase}`, phase === "first_upstream_byte" || phase === "first_text" ? "model" : "sandbox", origin + previous, origin + offset);
131
+ previous = offset;
132
+ }
133
+ }
134
+ }
135
+ prompt.set({
136
+ events,
137
+ ...firstEventAt !== void 0 ? { first_event_ms: firstEventAt - startedAt } : {},
138
+ ...firstTextAt !== void 0 ? { first_text_ms: firstTextAt - startedAt } : {},
139
+ ...phases?.warm !== null && phases?.warm !== void 0 ? { "sidecar.harness_warm": phases.warm } : {},
140
+ ...phases?.model ? { "sidecar.model": phases.model } : {},
141
+ ...Object.fromEntries(PHASES.flatMap((phase) => {
142
+ const offset = asNum(phases?.offsets[phase]);
143
+ return offset === void 0 ? [] : [[`sidecar.${phase}_ms`, Math.round(offset)]];
144
+ }))
145
+ });
146
+ prompt.end(void 0, error);
147
+ } catch {
148
+ }
149
+ };
150
+ return { observe, end };
151
+ }
152
+ async function* traceSandboxPromptEvents(events, options) {
153
+ const prompt = createPromptTrace(options.trace, options.parent, options.meta ?? {});
154
+ let failure;
155
+ try {
156
+ for await (const event of events) {
157
+ prompt.observe(event);
158
+ yield event;
159
+ }
160
+ } catch (error) {
161
+ failure = error;
162
+ throw error;
163
+ } finally {
164
+ prompt.end(failure);
165
+ }
166
+ }
167
+
43
168
  // src/sandbox/model.ts
44
169
  function backendModelFields(model) {
45
170
  return {
@@ -427,7 +552,14 @@ var DEFAULT_TIMEOUT_MS = 5 * 6e4;
427
552
  var TASK_LIMIT = 2e4;
428
553
  var SANDBOX_RUN_DESCRIPTION = "Run work that needs a computer in this workspace's sandbox: executing code or scripts, reading or converting PDFs, spreadsheets and archives, filling forms with the installed toolkits, or editing many files. Describe the whole task and the result you need; the sandbox agent does it and returns its answer. Takes seconds to minutes, so use it only when the answer needs the computer.";
429
554
  function sandboxPromptRunner(shell, prompt = {}) {
430
- return (box, task, { signal, timeoutMs }) => runSandboxPrompt(shell, box, task, { ...prompt, signal, timeoutMs, disallowQuestions: true });
555
+ return (box, task, { signal, timeoutMs, trace, span }) => runSandboxPrompt(shell, box, task, {
556
+ ...prompt,
557
+ signal,
558
+ timeoutMs,
559
+ disallowQuestions: true,
560
+ ...trace ? { trace } : {},
561
+ ...span ? { traceParent: span } : {}
562
+ });
431
563
  }
432
564
  function createSandboxRunTool(options) {
433
565
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -466,16 +598,25 @@ function createSandboxRunTool(options) {
466
598
  signal.addEventListener("abort", () => reject(signal.reason), { once: true });
467
599
  })]);
468
600
  let box;
601
+ const claim = context?.span?.child("sandbox.claim", "sandbox");
469
602
  try {
470
603
  box = await capped(options.box(signal));
604
+ claim?.end();
471
605
  } catch (error) {
606
+ claim?.end(void 0, error instanceof SandboxRunError ? error.code : "sandbox_unavailable");
472
607
  if (error instanceof SandboxRunError) return fail2(error.code, error.message, error.cause);
473
608
  return fail2("sandbox_unavailable", "The sandbox for this workspace could not start, so this work was not done.", error);
474
609
  }
475
610
  emit("box_ready", { ms: Date.now() - started });
476
611
  let answer;
477
612
  try {
478
- answer = await capped(runTask(box, task, { signal, timeoutMs: Math.max(1, timeoutMs - (Date.now() - started)), emit }));
613
+ answer = await capped(runTask(box, task, {
614
+ signal,
615
+ timeoutMs: Math.max(1, timeoutMs - (Date.now() - started)),
616
+ emit,
617
+ ...context?.trace ? { trace: context.trace } : {},
618
+ ...context?.span ? { span: context.span } : {}
619
+ }));
479
620
  } catch (error) {
480
621
  const timedOut = signal.aborted && !options.signal?.aborted;
481
622
  return fail2("sandbox_failed", timedOut ? `The sandbox did not finish within ${Math.round(timeoutMs / 1e3)} s, so this work was not done.` : "The sandbox run failed, so this work was not done.", error);
@@ -559,10 +700,13 @@ function createSandboxExecTool(options) {
559
700
  if (options.warm) await options.warm.leases.turn(options.warm.key).catch(() => {
560
701
  });
561
702
  let box;
703
+ const reused = ready !== null;
704
+ const claim = context?.span?.child("sandbox.claim", "sandbox");
562
705
  const starting = place(signal);
563
706
  try {
564
707
  box = await raceAbort(starting, signal);
565
708
  } catch (error) {
709
+ claim?.end(void 0, error instanceof SandboxRunError ? error.code : "sandbox_unavailable");
566
710
  if (ready === starting) ready = null;
567
711
  if (error instanceof SandboxRunError) {
568
712
  options.onFailure?.(error);
@@ -570,15 +714,22 @@ function createSandboxExecTool(options) {
570
714
  }
571
715
  return fail2("sandbox_unavailable", "The sandbox did not start in time, so the command did not run.", error);
572
716
  }
717
+ claim?.end({ "claim.reused": reused });
573
718
  emit("box_ready", { ms: Date.now() - started });
574
719
  let result;
720
+ const execSpan = context?.span?.child("sandbox.exec", "sandbox");
575
721
  try {
576
722
  result = await raceAbort(box.exec(command, {
577
723
  ...cwd ? { cwd } : {},
578
724
  ...options.env ? { env: options.env } : {},
579
- timeoutMs: Math.max(1, timeoutMs - (Date.now() - started))
725
+ timeoutMs: Math.max(1, timeoutMs - (Date.now() - started)),
726
+ // The same id the Router turn sends, so this command's Sandbox API and host records join the turn.
727
+ // SDK 0.62.2 added `traceId` to ExecOptions; an older SDK ignores the field.
728
+ ...context?.trace ? { traceId: context.trace.traceId } : {}
580
729
  }), signal);
730
+ execSpan?.end({ "exec.exit_code": result.exitCode });
581
731
  } catch (error) {
732
+ execSpan?.end(void 0, "exec_failed");
582
733
  const timedOut = signal.aborted && !options.signal?.aborted;
583
734
  return fail2("sandbox_failed", timedOut ? `The command did not finish within ${Math.round(timeoutMs / 1e3)} s.` : "The command could not run in the sandbox.", error);
584
735
  }
@@ -2384,9 +2535,24 @@ async function ensureWorkspaceSandbox(shell, options) {
2384
2535
  workspaceId: options.workspaceId,
2385
2536
  ...options.userId ? { userId: options.userId } : {}
2386
2537
  });
2387
- const box = await bringUpWorkspaceSandbox(shell, options);
2388
- await observeProvisionedBox(shell, options, box);
2389
- return box;
2538
+ const { trace } = options;
2539
+ const claim = trace?.start("sandbox.claim", "sandbox", { "workspace.harness": options.harness }, options.traceParent);
2540
+ const traced = trace && claim ? {
2541
+ ...options,
2542
+ measure: (stage, operation) => {
2543
+ const run = () => trace.measure(stage, "sandbox", () => operation(), void 0, claim);
2544
+ return options.measure ? options.measure(stage, run) : run();
2545
+ }
2546
+ } : options;
2547
+ try {
2548
+ const box = await bringUpWorkspaceSandbox(shell, traced);
2549
+ claim?.end({ "sandbox.id": box.id });
2550
+ await observeProvisionedBox(shell, options, box);
2551
+ return box;
2552
+ } catch (error) {
2553
+ claim?.end(void 0, error);
2554
+ throw error;
2555
+ }
2390
2556
  }
2391
2557
  async function observeProvisionedBox(shell, options, box) {
2392
2558
  if (!options.spend?.onProvisioned) return;
@@ -2521,11 +2687,12 @@ async function provisionWorkspaceSandbox(shell, options) {
2521
2687
  }
2522
2688
  }
2523
2689
  if (!replacementRequested && !forceNew && shell.resumeStopped !== false) {
2524
- const stopped = await listStopped(client, name);
2690
+ const stopped = await measure("list_stopped", () => listStopped(client, name));
2525
2691
  if (!stopped.succeeded) throw stopped.error;
2526
2692
  if (stopped.value) {
2527
- const runtimeEnv2 = await resolveWorkspaceRuntimeEnv(shell, scope);
2528
- const resumed = await resumeStoppedBox(stopped.value, resumeTimeout, runtimeEnv2, onProgress);
2693
+ const stoppedBox = stopped.value;
2694
+ const runtimeEnv2 = await measure("runtime_env", () => resolveWorkspaceRuntimeEnv(shell, scope));
2695
+ const resumed = await measure("resume", () => resumeStoppedBox(stoppedBox, resumeTimeout, runtimeEnv2, onProgress));
2529
2696
  if (!resumed.succeeded) {
2530
2697
  const recovery = await requestSandboxReplacement(
2531
2698
  shell.recoverStoppedSandbox,
@@ -2635,12 +2802,12 @@ async function provisionWorkspaceSandbox(shell, options) {
2635
2802
  SHELL_PROMPT_BUDGET_HINT
2636
2803
  );
2637
2804
  assertProvisionPayloadWithinCap(payload ?? {});
2638
- let box = await client.create(payload);
2639
- await box.waitFor("running", {
2805
+ let box = await measure("create", () => client.create(payload));
2806
+ await measure("wait_running", () => box.waitFor("running", {
2640
2807
  timeoutMs: shell.provisionTimeoutMs ?? DEFAULT_PROVISION_TIMEOUT_MS,
2641
2808
  ...onProgress ? { onProgress } : {}
2642
- });
2643
- box = await refreshRuntimeConnection(client, box);
2809
+ }));
2810
+ box = await measure("refresh_connection", () => refreshRuntimeConnection(client, box));
2644
2811
  if (deferredFiles.length > 0) {
2645
2812
  const written = await writeProfileFilesToBox(box, deferredFiles);
2646
2813
  if (!written.succeeded) {
@@ -2648,7 +2815,8 @@ async function provisionWorkspaceSandbox(shell, options) {
2648
2815
  }
2649
2816
  }
2650
2817
  if (shell.bootstrap) {
2651
- const boot = await shell.bootstrap(box, scope);
2818
+ const bootstrap = shell.bootstrap.bind(shell);
2819
+ const boot = await measure("bootstrap", () => bootstrap(box, scope));
2652
2820
  if (!boot.succeeded) {
2653
2821
  throw new Error(`bootstrap failed on new box ${name}`, { cause: boot.error });
2654
2822
  }
@@ -2793,7 +2961,8 @@ async function* detachedSandboxPromptEvents(box, prompt, options, backend) {
2793
2961
  ...options.expectedSecretProfileReceipt ? { expectedSecretProfileReceipt: options.expectedSecretProfileReceipt } : {},
2794
2962
  ...options.requireVisibleAssistantOutput !== void 0 ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput } : {},
2795
2963
  ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
2796
- ...options.ttlMs !== void 0 ? { ttlMs: options.ttlMs } : {}
2964
+ ...options.ttlMs !== void 0 ? { ttlMs: options.ttlMs } : {},
2965
+ ...options.trace ? { traceId: options.trace.traceId } : {}
2797
2966
  });
2798
2967
  const admittedExecutionId = admission?.executionId ?? executionId;
2799
2968
  if (!admittedExecutionId) {
@@ -2810,6 +2979,7 @@ async function* detachedSandboxPromptEvents(box, prompt, options, backend) {
2810
2979
  sessionId: admission?.sessionId ?? sessionId,
2811
2980
  executionId: admittedExecutionId,
2812
2981
  lastEventId: lastEventId || "0",
2982
+ ...options.trace ? { traceId: options.trace.traceId } : {},
2813
2983
  ...options.signal ? { signal: options.signal } : {}
2814
2984
  });
2815
2985
  }
@@ -3031,13 +3201,24 @@ async function* streamSandboxPrompt(shell, box, message, options) {
3031
3201
  ...options?.requireVisibleAssistantOutput !== void 0 ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput } : {},
3032
3202
  ...options?.expectedPublicProfileRequestDigest ? { expectedPublicProfileRequestDigest: options.expectedPublicProfileRequestDigest } : {},
3033
3203
  ...options?.expectedSecretProfileReceipt ? { expectedSecretProfileReceipt: options.expectedSecretProfileReceipt } : {},
3204
+ ...options?.trace ? { traceId: options.trace.traceId } : {},
3034
3205
  backend
3035
3206
  });
3036
3207
  const stream = options?.lastEventId ? dispatch() : resendRefusedDispatch(dispatch, options?.signal);
3037
3208
  emitSandboxActivity(options?.spend, box);
3038
3209
  let severedFinishReason = null;
3210
+ const observed = options?.trace ? traceSandboxPromptEvents(stream, {
3211
+ trace: options.trace,
3212
+ ...options.traceParent ? { parent: options.traceParent } : {},
3213
+ meta: {
3214
+ "sandbox.id": box.id,
3215
+ ...options.model ? { "gen_ai.request.model": options.model } : {},
3216
+ ...options.harness ? { "sandbox.harness": options.harness } : {},
3217
+ ...options.detach ? { "sandbox.detached": true } : {}
3218
+ }
3219
+ }) : stream;
3039
3220
  try {
3040
- for await (const event of stream) {
3221
+ for await (const event of observed) {
3041
3222
  const step = classifySeveredStream(event);
3042
3223
  if (step) severedFinishReason = step.kind === "step-finish" && step.severed ? step.reason : null;
3043
3224
  if (severedFinishReason && isTerminalPromptEvent(event)) {
@@ -3246,6 +3427,7 @@ function firstQuestionText(value) {
3246
3427
  }
3247
3428
 
3248
3429
  export {
3430
+ traceSandboxPromptEvents,
3249
3431
  backendModelFields,
3250
3432
  resolveModelSelection,
3251
3433
  resolveModel,
@@ -3345,4 +3527,4 @@ export {
3345
3527
  isTerminalPromptEvent,
3346
3528
  detectInteractiveQuestion
3347
3529
  };
3348
- //# sourceMappingURL=chunk-SUIH5B55.js.map
3530
+ //# sourceMappingURL=chunk-ZHJ2TDWA.js.map