@sapiom/harness 0.1.5 → 0.1.6

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 (86) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/cli/bin.js +24 -7
  3. package/dist/cli/bin.js.map +1 -1
  4. package/dist/cli/consent.js +1 -1
  5. package/dist/core/adapters/adapter.d.ts +2 -2
  6. package/dist/core/api-key-provider.d.ts +79 -0
  7. package/dist/core/api-key-provider.d.ts.map +1 -0
  8. package/dist/core/api-key-provider.js +91 -0
  9. package/dist/core/api-key-provider.js.map +1 -0
  10. package/dist/core/canvas-run-state.d.ts +9 -5
  11. package/dist/core/canvas-run-state.d.ts.map +1 -1
  12. package/dist/core/canvas-run-state.js +42 -13
  13. package/dist/core/canvas-run-state.js.map +1 -1
  14. package/dist/core/definition-slug-resolver.d.ts +13 -0
  15. package/dist/core/definition-slug-resolver.d.ts.map +1 -1
  16. package/dist/core/definition-slug-resolver.js +29 -0
  17. package/dist/core/definition-slug-resolver.js.map +1 -1
  18. package/dist/core/render-local-run.d.ts +82 -0
  19. package/dist/core/render-local-run.d.ts.map +1 -0
  20. package/dist/core/render-local-run.js +105 -0
  21. package/dist/core/render-local-run.js.map +1 -0
  22. package/dist/core/render-log-slice.d.ts +30 -0
  23. package/dist/core/render-log-slice.d.ts.map +1 -0
  24. package/dist/core/render-log-slice.js +49 -0
  25. package/dist/core/render-log-slice.js.map +1 -0
  26. package/dist/core/render-run-state.d.ts.map +1 -1
  27. package/dist/core/render-run-state.js +30 -49
  28. package/dist/core/render-run-state.js.map +1 -1
  29. package/dist/core/run-local-bootstrap.d.ts +93 -0
  30. package/dist/core/run-local-bootstrap.d.ts.map +1 -0
  31. package/dist/core/run-local-bootstrap.js +155 -0
  32. package/dist/core/run-local-bootstrap.js.map +1 -0
  33. package/dist/core/run-state.d.ts +16 -1
  34. package/dist/core/run-state.d.ts.map +1 -1
  35. package/dist/core/run-state.js +75 -25
  36. package/dist/core/run-state.js.map +1 -1
  37. package/dist/core/stub-feedback.d.ts +52 -0
  38. package/dist/core/stub-feedback.d.ts.map +1 -0
  39. package/dist/core/stub-feedback.js +33 -0
  40. package/dist/core/stub-feedback.js.map +1 -0
  41. package/dist/server/actions.d.ts +139 -0
  42. package/dist/server/actions.d.ts.map +1 -0
  43. package/dist/server/actions.js +430 -0
  44. package/dist/server/actions.js.map +1 -0
  45. package/dist/server/auth-routes.d.ts +92 -0
  46. package/dist/server/auth-routes.d.ts.map +1 -0
  47. package/dist/server/auth-routes.js +151 -0
  48. package/dist/server/auth-routes.js.map +1 -0
  49. package/dist/server/index.d.ts.map +1 -1
  50. package/dist/server/index.js +0 -0
  51. package/dist/server/index.js.map +1 -1
  52. package/dist/server/rest.d.ts.map +1 -1
  53. package/dist/server/rest.js +0 -2
  54. package/dist/server/rest.js.map +1 -1
  55. package/dist/server/runs.d.ts +16 -15
  56. package/dist/server/runs.d.ts.map +1 -1
  57. package/dist/server/runs.js +15 -80
  58. package/dist/server/runs.js.map +1 -1
  59. package/dist/server/static.d.ts +15 -1
  60. package/dist/server/static.d.ts.map +1 -1
  61. package/dist/server/static.js +54 -4
  62. package/dist/server/static.js.map +1 -1
  63. package/dist/shared/types.d.ts +79 -35
  64. package/dist/shared/types.d.ts.map +1 -1
  65. package/dist/shared/types.js.map +1 -1
  66. package/dist/web/assets/index-DCtyI4VW.css +32 -0
  67. package/dist/web/assets/index-WSw5RvYR.js +445 -0
  68. package/dist/web/canvas/sess-boot/index.html +305 -0
  69. package/dist/web/index.html +4 -9
  70. package/dist/web/welcome-hero-dark.png +0 -0
  71. package/dist/web/welcome-hero-light.png +0 -0
  72. package/package.json +6 -3
  73. package/dist/core/run-spend.d.ts +0 -55
  74. package/dist/core/run-spend.d.ts.map +0 -1
  75. package/dist/core/run-spend.js +0 -109
  76. package/dist/core/run-spend.js.map +0 -1
  77. package/dist/core/run-transactions.d.ts +0 -60
  78. package/dist/core/run-transactions.d.ts.map +0 -1
  79. package/dist/core/run-transactions.js +0 -129
  80. package/dist/core/run-transactions.js.map +0 -1
  81. package/dist/server/skills.d.ts +0 -51
  82. package/dist/server/skills.d.ts.map +0 -1
  83. package/dist/server/skills.js +0 -312
  84. package/dist/server/skills.js.map +0 -1
  85. package/dist/web/assets/index-DM84J83Y.js +0 -234
  86. package/dist/web/assets/index-DemtWW4L.css +0 -32
@@ -0,0 +1,82 @@
1
+ /**
2
+ * renderLocalRun — the pure mapper from an offline stub run's per-step traces
3
+ * ({@link LocalStepTrace}[], streamed as NDJSON by `POST /api/runs/local`) to
4
+ * the same {@link RunView} the canvas renders for prod runs. Its twin is
5
+ * {@link renderRunState} (prod / local-backend); both emit the identical
6
+ * cost-free {@link StepView} shape, so ONE inspector renders every run source.
7
+ *
8
+ * Pure and deterministic: no LLM, no I/O, no clock. Every field is derived from
9
+ * the traces (plus the caller-supplied execution id and terminal outcome), so
10
+ * the same function can map a partial trace mid-stream and the final trace at
11
+ * the end — only the input grows, never this mapping. It is a Stryker target;
12
+ * the tests are mutation-first.
13
+ *
14
+ * Honest absence, matching renderRunState and the SDK's "null is honest absence,
15
+ * never a fabricated value" contract:
16
+ * - **No cost** — local runs are stubbed and free by construction; a StepView
17
+ * from here never carries `costUsd` (so the inspector reads "local run ·
18
+ * free", never "$0.00").
19
+ * - **No latency** — a {@link LocalStepTrace} carries no timing (agent-core's
20
+ * in-process dispatcher records none, and agent-core is consumed as-is), so
21
+ * `latencyMs` is ABSENT rather than a fabricated `0`.
22
+ * - **Output** is present only when the trace captured one (a step that threw,
23
+ * or a `continue` with no value, carries none) — but ABSENCE is `undefined`
24
+ * on the trace, and a genuine `null`/`false`/`0`/`""` output is a real value
25
+ * that passes through.
26
+ * - **Input** is always carried by a trace (every attempt ran on some input,
27
+ * even `undefined`); it is surfaced whenever it isn't `undefined`.
28
+ * - **Logs and errors** collapse to the same `logSlice`/`error` fields prod
29
+ * uses, via the shared formatter.
30
+ * - **Stub signal (WB15-2)** is RUN-LEVEL. A local run is stub-served by
31
+ * construction, so the run carries `stubbed: true` (prod's renderRunState
32
+ * never does) and the inspector marks each executed step with a "stubbed"
33
+ * chip — agent-core records no per-CALL stub attribution, so that is the
34
+ * honest granularity. The terminal summary's `unusedStubs` (a supplied key
35
+ * that matched nothing) and `stubWarnings` (a wrong-shape value) pass through
36
+ * only when NON-empty, so a clean run surfaces no notice at all.
37
+ */
38
+ import type { LocalStepTrace, LocalRunOutcome } from "@sapiom/agent-core";
39
+ import type { RunView, UnusedStubView } from "../shared/types.js";
40
+ /**
41
+ * Options carrying the run-level facts a `LocalStepTrace[]` alone can't provide.
42
+ * Both are optional so the mapper can render a live, still-streaming trace (no
43
+ * terminal summary yet) exactly as it renders the final one.
44
+ */
45
+ export interface RenderLocalRunOptions {
46
+ /**
47
+ * The execution id to stamp on the {@link RunView}. A local run has no
48
+ * server-issued id, so the caller (the SPA's run store) synthesizes and owns
49
+ * one; the mapper stays pure by taking it rather than minting time/randomness.
50
+ * Defaults to an empty string when the caller has none yet.
51
+ */
52
+ executionId?: string;
53
+ /**
54
+ * The run's terminal outcome from the NDJSON summary line, when it has
55
+ * arrived. Absent while the stream is still open — the mapper then reports the
56
+ * run as `running` (steps may still be coming). Passing it flips the run to
57
+ * its settled status.
58
+ */
59
+ outcome?: LocalRunOutcome;
60
+ /**
61
+ * Supplied stub keys that matched no capability call this run — from the
62
+ * terminal summary line. A no-op mock (typo'd path, wrong plural/singular)
63
+ * otherwise fails silently; surfacing it is the whole point of WB15-2. Only a
64
+ * NON-empty list reaches the {@link RunView} (honest absence), so pass it as-is
65
+ * from the summary and the mapper decides. Absent while the stream is open.
66
+ */
67
+ unusedStubs?: UnusedStubView[];
68
+ /**
69
+ * Warnings about stub values that matched a key but carried the wrong shape —
70
+ * from the terminal summary line. Same honest-absence handling as
71
+ * {@link RenderLocalRunOptions.unusedStubs}: an empty list is dropped.
72
+ */
73
+ stubWarnings?: string[];
74
+ }
75
+ /**
76
+ * Map an offline stub run's traces (plus the caller-owned execution id and, once
77
+ * known, terminal outcome) to the {@link RunView} the canvas renders. Order-
78
+ * preserving over `traces` (execution order); total — never throws, mirroring
79
+ * renderRunState — because the traces are already the decoded wire shape.
80
+ */
81
+ export declare function renderLocalRun(traces: LocalStepTrace[], options?: RenderLocalRunOptions): RunView;
82
+ //# sourceMappingURL=render-local-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-local-run.d.ts","sourceRoot":"","sources":["../../src/core/render-local-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1E,OAAO,KAAK,EACV,OAAO,EAIP,cAAc,EACf,MAAM,oBAAoB,CAAC;AAQ5B;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAoED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,cAAc,EAAE,EACxB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAsBT"}
@@ -0,0 +1,105 @@
1
+ // Reuse prod's exact log-buffer formatter so a step's `logSlice` is byte-
2
+ // identical whether it came from a prod projection or a local trace — the
3
+ // inspector can never disagree with itself about how a log renders. Imported
4
+ // from the dependency-free module (NOT render-run-state) so this mapper carries
5
+ // no `@sapiom/agent-core`/`node:fs` runtime dep into the browser bundle.
6
+ import { toLogSlice } from "./render-log-slice.js";
7
+ /**
8
+ * Fold a single step-attempt's status into a {@link StepStatus}. A local trace's
9
+ * status vocabulary is exactly `succeeded | threw` (see agent-core's
10
+ * LocalStubDispatcher). `succeeded` → `passed`; `threw` → `failed` (it did not
11
+ * pass — mirrors renderRunState's fold of `threw`). Anything unrecognized is
12
+ * `pending` (defensive; the union shouldn't produce it), NEVER silently
13
+ * `passed`.
14
+ */
15
+ function toStepStatus(raw) {
16
+ if (raw === "succeeded")
17
+ return "passed";
18
+ if (raw === "threw")
19
+ return "failed";
20
+ return "pending";
21
+ }
22
+ /**
23
+ * Fold the run's terminal outcome into the four states the UI draws. A local run
24
+ * that `paused` is not yet done (the auto-resume loop or a human must advance
25
+ * it), so it reads as `running`, not a terminal state. An absent outcome (stream
26
+ * still open) is also `running`. `completed`/`failed` map straight through;
27
+ * there is no local "cancelled" outcome.
28
+ */
29
+ function toRunStatus(outcome) {
30
+ if (outcome === "completed")
31
+ return "completed";
32
+ if (outcome === "failed")
33
+ return "failed";
34
+ // "paused", "running", or absent (still streaming) — not terminal.
35
+ return "running";
36
+ }
37
+ /**
38
+ * Map one trace line to its {@link StepView}. Optional fields are assigned only
39
+ * when they carry a real value, so honest absence survives into the JSON the
40
+ * inspector reads (a missing field renders nothing rather than a fabricated
41
+ * zero/empty payload).
42
+ */
43
+ function toStepView(trace) {
44
+ const view = {
45
+ // Local traces have no OTel span id; the (step, attempt) pair is the stable,
46
+ // collision-free key across a run's attempts of the same step.
47
+ id: `${trace.step}-${trace.attempt}`,
48
+ name: trace.step,
49
+ status: toStepStatus(trace.status),
50
+ };
51
+ // No costUsd, no latencyMs — a local run is free and untimed (see the file
52
+ // header). Their honest absence is the whole point of the local target.
53
+ if (trace.input !== undefined)
54
+ view.input = trace.input;
55
+ if (trace.output !== undefined)
56
+ view.output = trace.output;
57
+ if (trace.error?.message)
58
+ view.error = trace.error.message;
59
+ const logSlice = toLogSlice(trace.logs);
60
+ if (logSlice !== undefined)
61
+ view.logSlice = logSlice;
62
+ // Per-step capability calls from the stub client. Honest absence: only a
63
+ // non-empty list reaches the view (an empty list means no calls were made —
64
+ // but absence on the trace means the sink was never wired, so we leave it
65
+ // absent too). The StubCallRecord shape maps directly onto StepCall.
66
+ if (trace.calls && trace.calls.length > 0) {
67
+ view.calls = trace.calls.map((c) => ({
68
+ capability: c.capability,
69
+ stubUsed: c.stubUsed,
70
+ args: c.args,
71
+ result: c.result,
72
+ }));
73
+ }
74
+ return view;
75
+ }
76
+ /**
77
+ * Map an offline stub run's traces (plus the caller-owned execution id and, once
78
+ * known, terminal outcome) to the {@link RunView} the canvas renders. Order-
79
+ * preserving over `traces` (execution order); total — never throws, mirroring
80
+ * renderRunState — because the traces are already the decoded wire shape.
81
+ */
82
+ export function renderLocalRun(traces, options = {}) {
83
+ const view = {
84
+ executionId: options.executionId ?? "",
85
+ status: toRunStatus(options.outcome),
86
+ steps: traces.map(toStepView),
87
+ // A local run is stub-served by construction (every ctx.sapiom.* call
88
+ // resolves from a stub, never the network) — so the run itself is `stubbed`,
89
+ // and the inspector marks each executed step with the chip. This is the
90
+ // honest per-run truth: agent-core records no per-CALL stub attribution, so
91
+ // there is nothing finer to claim. renderRunState (prod) never sets this.
92
+ stubbed: true,
93
+ };
94
+ // Honest absence: only a NON-empty signal reaches the view, so the read-only
95
+ // notice renders nothing when the run had no stub-hygiene problems. A supplied
96
+ // empty array is indistinguishable from "no problems" and must not surface.
97
+ if (options.unusedStubs && options.unusedStubs.length > 0) {
98
+ view.unusedStubs = options.unusedStubs;
99
+ }
100
+ if (options.stubWarnings && options.stubWarnings.length > 0) {
101
+ view.stubWarnings = options.stubWarnings;
102
+ }
103
+ return view;
104
+ }
105
+ //# sourceMappingURL=render-local-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-local-run.js","sourceRoot":"","sources":["../../src/core/render-local-run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * render-log-slice — the shared, dependency-free formatter for a step's executor
3
+ * log buffer. Both run mappers use it so a step's `logSlice` is byte-identical
4
+ * whether it came from a prod {@link import("./render-run-state.js").renderRunState}
5
+ * projection or a local {@link import("./render-local-run.js").renderLocalRun}
6
+ * trace — the inspector can never disagree with itself about how a log renders.
7
+ *
8
+ * Kept in its OWN module (rather than in render-run-state.ts) precisely because
9
+ * it has NO `@sapiom/agent-core` dependency: render-run-state pulls in agent-core
10
+ * runtime helpers (e.g. `isExecutionTerminal`) that reach for `node:fs`, which
11
+ * must never enter the browser bundle. The local-run mapper is imported by the
12
+ * SPA, so it depends on THIS pure module instead — no Node built-ins ride along.
13
+ *
14
+ * Pure and deterministic: no I/O, no clock. Safe in both Node and the browser.
15
+ */
16
+ /**
17
+ * Cap on the characters of a step's executor log buffer surfaced in `logSlice`.
18
+ * The TAIL is kept (most recent lines) because failures surface at the end of a
19
+ * log. This is a payload guard on the poll/stream response; the debug-macro
20
+ * context extractor does the final, smaller trim for prompt injection.
21
+ */
22
+ export declare const LOG_SLICE_MAX = 4000;
23
+ /** One executor log entry → a compact line. Accepts the `{ ts, level, msg }`
24
+ * wire shape (or `message`), a bare string, or anything else (stringified).
25
+ * A local trace's `{ level, msg }` entry is a subset of this same shape. */
26
+ export declare function formatLogEntry(entry: unknown): string;
27
+ /** Format the executor log buffer into a trimmed, tail-preserving slice, or
28
+ * `undefined` when there are no usable logs. */
29
+ export declare function toLogSlice(logs: unknown): string | undefined;
30
+ //# sourceMappingURL=render-log-slice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-log-slice.d.ts","sourceRoot":"","sources":["../../src/core/render-log-slice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,aAAa,OAAO,CAAC;AAElC;;6EAE6E;AAC7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAgBrD;AAED;iDACiD;AACjD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAO5D"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * render-log-slice — the shared, dependency-free formatter for a step's executor
3
+ * log buffer. Both run mappers use it so a step's `logSlice` is byte-identical
4
+ * whether it came from a prod {@link import("./render-run-state.js").renderRunState}
5
+ * projection or a local {@link import("./render-local-run.js").renderLocalRun}
6
+ * trace — the inspector can never disagree with itself about how a log renders.
7
+ *
8
+ * Kept in its OWN module (rather than in render-run-state.ts) precisely because
9
+ * it has NO `@sapiom/agent-core` dependency: render-run-state pulls in agent-core
10
+ * runtime helpers (e.g. `isExecutionTerminal`) that reach for `node:fs`, which
11
+ * must never enter the browser bundle. The local-run mapper is imported by the
12
+ * SPA, so it depends on THIS pure module instead — no Node built-ins ride along.
13
+ *
14
+ * Pure and deterministic: no I/O, no clock. Safe in both Node and the browser.
15
+ */
16
+ /**
17
+ * Cap on the characters of a step's executor log buffer surfaced in `logSlice`.
18
+ * The TAIL is kept (most recent lines) because failures surface at the end of a
19
+ * log. This is a payload guard on the poll/stream response; the debug-macro
20
+ * context extractor does the final, smaller trim for prompt injection.
21
+ */
22
+ export const LOG_SLICE_MAX = 4000;
23
+ /** One executor log entry → a compact line. Accepts the `{ ts, level, msg }`
24
+ * wire shape (or `message`), a bare string, or anything else (stringified).
25
+ * A local trace's `{ level, msg }` entry is a subset of this same shape. */
26
+ export function formatLogEntry(entry) {
27
+ if (typeof entry === "string")
28
+ return entry;
29
+ if (entry !== null && typeof entry === "object") {
30
+ const e = entry;
31
+ const parts = [e.ts, e.level, e.msg ?? e.message].filter((p) => typeof p === "string" || typeof p === "number");
32
+ if (parts.length > 0)
33
+ return parts.map(String).join(" ");
34
+ }
35
+ return String(entry);
36
+ }
37
+ /** Format the executor log buffer into a trimmed, tail-preserving slice, or
38
+ * `undefined` when there are no usable logs. */
39
+ export function toLogSlice(logs) {
40
+ if (!Array.isArray(logs) || logs.length === 0)
41
+ return undefined;
42
+ const text = logs.map(formatLogEntry).join("\n").trim();
43
+ if (text === "")
44
+ return undefined;
45
+ return text.length > LOG_SLICE_MAX
46
+ ? text.slice(text.length - LOG_SLICE_MAX)
47
+ : text;
48
+ }
49
+ //# sourceMappingURL=render-log-slice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-log-slice.js","sourceRoot":"","sources":["../../src/core/render-log-slice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAElC;;6EAE6E;AAC7E,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,CAAC,GAAG,KAKT,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CACtD,CAAC,CAAC,EAAwB,EAAE,CAC1B,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,CACjD,CAAC;QACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED;iDACiD;AACjD,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAClC,OAAO,IAAI,CAAC,MAAM,GAAG,aAAa;QAChC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC;QACzC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"render-run-state.d.ts","sourceRoot":"","sources":["../../src/core/render-run-state.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,mBAAmB,EAEpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAwB,MAAM,oBAAoB,CAAC;AAoHxE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAMpE"}
1
+ {"version":3,"file":"render-run-state.d.ts","sourceRoot":"","sources":["../../src/core/render-run-state.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAwB,MAAM,oBAAoB,CAAC;AA0FxE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAMpE"}
@@ -4,24 +4,21 @@
4
4
  *
5
5
  * Pure and deterministic: no LLM, no I/O, no clock. Every field is derived from
6
6
  * the decoded projection, so the same function drives the polling path today and
7
- * a future WebSocket push (only the data source swaps, never this mapping). Cost
8
- * and latency are read straight from the projection and rendered statically — the
7
+ * a future WebSocket push (only the data source swaps, never this mapping).
8
+ * Latency is read straight from the projection and rendered statically — the
9
9
  * LLM is only ever invoked later by an explicit debug-macro press, never to
10
10
  * compute what's shown here.
11
11
  *
12
- * Honest absence is preserved end to end: a step with no cost on this read gets
13
- * no `costUsd` (not `0`), a still-running step gets no `latencyMs`, and a step
14
- * with no logs gets no `logSlice`matching the SDK's "null cost is honest
15
- * absence, never a fabricated $0" contract.
12
+ * Honest absence is preserved end to end: a still-running step gets no
13
+ * `latencyMs`, and a step with no logs gets no `logSlice`. The inspector
14
+ * surfaces logs, latency, and pass/fail only no cost.
16
15
  */
17
16
  import { isExecutionTerminal } from "@sapiom/agent-core";
18
- /**
19
- * Cap on the characters of a step's executor log buffer surfaced in `logSlice`.
20
- * The TAIL is kept (most recent lines) because failures surface at the end of a
21
- * log. This is a payload guard on the poll response; the debug-macro context
22
- * extractor does the final, smaller trim for prompt injection.
23
- */
24
- const LOG_SLICE_MAX = 4000;
17
+ // The log-buffer formatter lives in its own dependency-free module so the
18
+ // local-run mapper (imported by the browser SPA) can share the SAME formatter
19
+ // WITHOUT dragging this file's `@sapiom/agent-core` runtime import and its
20
+ // `node:fs` reach into the web bundle.
21
+ import { toLogSlice } from "./render-log-slice.js";
25
22
  /**
26
23
  * Fold the run's lifecycle status into the four states the UI distinguishes.
27
24
  * Reuses `isExecutionTerminal` (agent-core's single source of truth for "won't
@@ -57,14 +54,6 @@ function toStepStatus(raw) {
57
54
  return "running";
58
55
  return "pending";
59
56
  }
60
- /** Captured USD as a number; `undefined` on honest absence (null cost) or an
61
- * unparseable amount — never a fabricated `0`. */
62
- function toCostUsd(cost) {
63
- if (!cost)
64
- return undefined;
65
- const n = Number(cost.capturedUsd);
66
- return Number.isFinite(n) ? n : undefined;
67
- }
68
57
  /** `finishedAt − startedAt` in ms; `undefined` while still running (no finish)
69
58
  * or when either timestamp is unparseable. A negative delta (clock skew) is
70
59
  * dropped rather than shown as a misleading negative latency. */
@@ -78,31 +67,6 @@ function toLatencyMs(startedAt, finishedAt) {
78
67
  const delta = end - start;
79
68
  return delta >= 0 ? delta : undefined;
80
69
  }
81
- /** One executor log entry → a compact line. Accepts the `{ ts, level, msg }`
82
- * wire shape (or `message`), a bare string, or anything else (stringified). */
83
- function formatLogEntry(entry) {
84
- if (typeof entry === "string")
85
- return entry;
86
- if (entry !== null && typeof entry === "object") {
87
- const e = entry;
88
- const parts = [e.ts, e.level, e.msg ?? e.message].filter((p) => typeof p === "string" || typeof p === "number");
89
- if (parts.length > 0)
90
- return parts.map(String).join(" ");
91
- }
92
- return String(entry);
93
- }
94
- /** Format the executor log buffer into a trimmed, tail-preserving slice, or
95
- * `undefined` when there are no usable logs. */
96
- function toLogSlice(logs) {
97
- if (!Array.isArray(logs) || logs.length === 0)
98
- return undefined;
99
- const text = logs.map(formatLogEntry).join("\n").trim();
100
- if (text === "")
101
- return undefined;
102
- return text.length > LOG_SLICE_MAX
103
- ? text.slice(text.length - LOG_SLICE_MAX)
104
- : text;
105
- }
106
70
  /** Map one projection step to its render view. Optional fields are assigned only
107
71
  * when present so absence stays absent (not `undefined`) in the JSON payload. */
108
72
  function toStepView(step) {
@@ -111,9 +75,6 @@ function toStepView(step) {
111
75
  name: step.stepName,
112
76
  status: toStepStatus(step.status),
113
77
  };
114
- const costUsd = toCostUsd(step.cost);
115
- if (costUsd !== undefined)
116
- view.costUsd = costUsd;
117
78
  const latencyMs = toLatencyMs(step.startedAt, step.finishedAt);
118
79
  if (latencyMs !== undefined)
119
80
  view.latencyMs = latencyMs;
@@ -122,6 +83,26 @@ function toStepView(step) {
122
83
  const logSlice = toLogSlice(step.logs);
123
84
  if (logSlice !== undefined)
124
85
  view.logSlice = logSlice;
86
+ // Real per-step IO for the inspector's "Last run" block. The decoder
87
+ // collapses an absent input/output to `null` (its absence sentinel), so a
88
+ // `null` here means "the read carried nothing" — surfaced as ABSENT, never a
89
+ // fabricated payload. Any non-null value (including `0`, `false`, `""`) is a
90
+ // real payload and passes through. Capability, not model: these are the
91
+ // step's own values, with no provider/model surfaced.
92
+ if (step.input !== null)
93
+ view.input = step.input;
94
+ if (step.output !== null)
95
+ view.output = step.output;
96
+ // `step.events` are capability execution events forwarded by dispatched
97
+ // capabilities (e.g. tool_use / thinking / result events from a coding run).
98
+ // They do NOT represent dotted workflow capability calls (search.webSearch,
99
+ // memory.append, etc.) with args/results in the StepCall format, so we
100
+ // cannot map them to StepView.calls without fabricating structure that isn't
101
+ // there. `calls` is left absent for prod steps. The inspector's
102
+ // input/output/logs already carry the step-level evidence for prod runs;
103
+ // per-call detail is a fast-follow that requires a server-side addition to
104
+ // the projection shape (emitting dotted-capability call records alongside
105
+ // their args/results at the step level).
125
106
  return view;
126
107
  }
127
108
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"render-run-state.js","sourceRoot":"","sources":["../../src/core/render-run-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render-run-state.js","sourceRoot":"","sources":["../../src/core/render-run-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * run-local bootstrap — the child-process entrypoint behind
3
+ * `POST /api/runs/local`.
4
+ *
5
+ * It runs an agent entirely in-process against stub capabilities
6
+ * (`runLocalFromDir` from @sapiom/agent-core) and writes the result as an
7
+ * NDJSON stream to stdout: one line per {@link LocalStepTrace}, then a single
8
+ * terminal summary line `{ outcome, output, error, unusedStubs, stubWarnings }`.
9
+ * Fully offline and zero-cost — run-local resolves every `ctx.sapiom.*` call
10
+ * from stubs and never touches the network.
11
+ *
12
+ * Why a separate child process (not an in-process import):
13
+ * 1. `runLocalFromDir` esbuild-bundles and dynamically `import()`s a workflow
14
+ * project the harness doesn't control, so a stray top-level side effect,
15
+ * infinite loop, or crash in someone else's step body is bounded to this
16
+ * one child instead of taking the long-lived harness server down.
17
+ * 2. It sidesteps a Vite/Vitest limitation: the dynamic `import(\`file://…\`)`
18
+ * inside the loader gets intercepted by the SSR dynamic-import-vars
19
+ * transform when pulled into a Vitest module graph, and mishandles the
20
+ * tmpdir `file://` URL on darwin. A plain child `node` process never goes
21
+ * through that transform. (Mirrors the reasoning in canvas-manifest-check.)
22
+ *
23
+ * Contract with the route ({@link createActionsRouter}):
24
+ * - Request arrives as one JSON object on **stdin**: `{ sourceDir, input?,
25
+ * stubs?, maxAttemptsPerStep? }`.
26
+ * - Output is line-oriented JSON on **stdout** — the route forwards each line
27
+ * through unchanged, so the shapes here ARE the wire shapes the SPA parses.
28
+ * - Diagnostics go to **stderr**; the route keeps a bounded tail for failures.
29
+ * - Exit 0 once the terminal line is written (even for a failed run — a failed
30
+ * *run* is a successful *invocation*); exit 1 only when no run happened
31
+ * (bad request, load error) after writing a terminal `error` line.
32
+ */
33
+ import { type LocalRunOutcome, type StubFile } from "@sapiom/agent-core";
34
+ /** The request shape the route writes to this child's stdin. */
35
+ export interface RunLocalRequest {
36
+ /** Absolute path to the agent project directory (contains `index.ts`). */
37
+ sourceDir: string;
38
+ /** The workflow's entry-step input (optional; agent-core defaults it). */
39
+ input?: unknown;
40
+ /** Explicit stub overrides. When omitted the project's committed
41
+ * `.sapiom-dev/stubs.json` is used (agent-core's own precedence). */
42
+ stubs?: StubFile;
43
+ /** Per-step attempt cap (optional; agent-core defaults it). */
44
+ maxAttemptsPerStep?: number;
45
+ }
46
+ /**
47
+ * The terminal NDJSON line, written after every per-step trace line. Carries
48
+ * the run-level outcome and the two stub-hygiene signals the inspector surfaces
49
+ * (WB15-2): `unusedStubs` (supplied keys that matched no capability call) and
50
+ * `stubWarnings` (keys that matched but carried the wrong shape).
51
+ *
52
+ * `kind: "summary"` discriminates it from a step-trace line so a consumer never
53
+ * has to guess which line is terminal.
54
+ */
55
+ export interface RunLocalSummaryLine {
56
+ kind: "summary";
57
+ outcome: LocalRunOutcome;
58
+ output?: unknown;
59
+ error?: unknown;
60
+ unusedStubs: Array<{
61
+ step: string;
62
+ key: string;
63
+ }>;
64
+ stubWarnings: string[];
65
+ }
66
+ /**
67
+ * The terminal line written when the run could not be *invoked* at all — a
68
+ * malformed request, an unreadable stub file, a project that fails to load.
69
+ * `outcome` is always `"failed"`; the child then exits non-zero. Distinct from
70
+ * a `summary` line, which represents a run that actually executed (even if that
71
+ * run's own outcome was `failed`).
72
+ */
73
+ export interface RunLocalErrorLine {
74
+ kind: "error";
75
+ outcome: "failed";
76
+ error: string;
77
+ }
78
+ /**
79
+ * Parse the stdin payload into a {@link RunLocalRequest}. Throws a plain Error
80
+ * with a caller-safe message (no key material, no provider names) on anything
81
+ * that isn't a JSON object carrying a non-empty string `sourceDir`.
82
+ */
83
+ export declare function parseRunLocalRequest(raw: string): RunLocalRequest;
84
+ /**
85
+ * Run the request and emit its NDJSON stream to `out`. Returns the process exit
86
+ * code: 0 when a run executed (any outcome), 1 when the run could not be
87
+ * invoked (a terminal `error` line is emitted first). Never throws — every
88
+ * failure becomes an in-band terminal line, because a half-written stream with
89
+ * a thrown stack on stderr is far harder for the route to reason about than a
90
+ * clean terminal line plus an exit code.
91
+ */
92
+ export declare function runBootstrap(request: RunLocalRequest, out: NodeJS.WritableStream): Promise<number>;
93
+ //# sourceMappingURL=run-local-bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-local-bootstrap.d.ts","sourceRoot":"","sources":["../../src/core/run-local-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,oBAAoB,CAAC;AAE5B,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;0EACsE;IACtE,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,QAAQ,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAWD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAwBjE;AAYD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,eAAe,EACxB,GAAG,EAAE,MAAM,CAAC,cAAc,GACzB,OAAO,CAAC,MAAM,CAAC,CAkCjB"}