@boardwalk-labs/runner 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +68 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +214 -0
- package/dist/contract.d.ts +154 -0
- package/dist/contract.js +196 -0
- package/dist/daemon/daemon.d.ts +45 -0
- package/dist/daemon/daemon.js +129 -0
- package/dist/daemon/identity.d.ts +15 -0
- package/dist/daemon/identity.js +44 -0
- package/dist/daemon/index.d.ts +3 -0
- package/dist/daemon/index.js +4 -0
- package/dist/daemon/pool_client.d.ts +31 -0
- package/dist/daemon/pool_client.js +101 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/runtime/agent/budget.d.ts +123 -0
- package/dist/runtime/agent/budget.js +174 -0
- package/dist/runtime/agent/events.d.ts +46 -0
- package/dist/runtime/agent/events.js +8 -0
- package/dist/runtime/agent/model_rates.d.ts +7 -0
- package/dist/runtime/agent/model_rates.js +21 -0
- package/dist/runtime/agent/secret_redactor.d.ts +42 -0
- package/dist/runtime/agent/secret_redactor.js +98 -0
- package/dist/runtime/broker_artifact_store.d.ts +17 -0
- package/dist/runtime/broker_artifact_store.js +46 -0
- package/dist/runtime/broker_child_dispatcher.d.ts +31 -0
- package/dist/runtime/broker_child_dispatcher.js +88 -0
- package/dist/runtime/broker_event_publisher.d.ts +25 -0
- package/dist/runtime/broker_event_publisher.js +69 -0
- package/dist/runtime/broker_tool_host.d.ts +49 -0
- package/dist/runtime/broker_tool_host.js +240 -0
- package/dist/runtime/cancel_watcher.d.ts +31 -0
- package/dist/runtime/cancel_watcher.js +77 -0
- package/dist/runtime/credit_watcher.d.ts +30 -0
- package/dist/runtime/credit_watcher.js +78 -0
- package/dist/runtime/direct_inference.d.ts +29 -0
- package/dist/runtime/direct_inference.js +78 -0
- package/dist/runtime/index.d.ts +85 -0
- package/dist/runtime/index.js +525 -0
- package/dist/runtime/inference_transport.d.ts +5 -0
- package/dist/runtime/inference_transport.js +9 -0
- package/dist/runtime/leaf_executor.d.ts +104 -0
- package/dist/runtime/leaf_executor.js +333 -0
- package/dist/runtime/lease_renewer.d.ts +31 -0
- package/dist/runtime/lease_renewer.js +80 -0
- package/dist/runtime/main.d.ts +1 -0
- package/dist/runtime/main.js +7 -0
- package/dist/runtime/phase_tracker.d.ts +26 -0
- package/dist/runtime/phase_tracker.js +45 -0
- package/dist/runtime/program_log_capture.d.ts +20 -0
- package/dist/runtime/program_log_capture.js +79 -0
- package/dist/runtime/program_runner.d.ts +82 -0
- package/dist/runtime/program_runner.js +116 -0
- package/dist/runtime/program_worker.d.ts +177 -0
- package/dist/runtime/program_worker.js +272 -0
- package/dist/runtime/recording_secret_resolver.d.ts +9 -0
- package/dist/runtime/recording_secret_resolver.js +22 -0
- package/dist/runtime/run_abort.d.ts +16 -0
- package/dist/runtime/run_abort.js +38 -0
- package/dist/runtime/run_event_emitter.d.ts +24 -0
- package/dist/runtime/run_event_emitter.js +63 -0
- package/dist/runtime/runner_control_client.d.ts +184 -0
- package/dist/runtime/runner_control_client.js +501 -0
- package/dist/runtime/runtime_flusher.d.ts +41 -0
- package/dist/runtime/runtime_flusher.js +90 -0
- package/dist/runtime/sandbox_config.d.ts +21 -0
- package/dist/runtime/sandbox_config.js +34 -0
- package/dist/runtime/support/index.d.ts +53 -0
- package/dist/runtime/support/index.js +114 -0
- package/dist/runtime/suspension.d.ts +141 -0
- package/dist/runtime/suspension.js +120 -0
- package/dist/runtime/testing_artifact_build.d.ts +27 -0
- package/dist/runtime/testing_artifact_build.js +96 -0
- package/dist/runtime/tools/artifacts.d.ts +146 -0
- package/dist/runtime/tools/artifacts.js +125 -0
- package/dist/runtime/tools/types.d.ts +114 -0
- package/dist/runtime/tools/types.js +61 -0
- package/dist/runtime/tools/web_search.d.ts +66 -0
- package/dist/runtime/tools/web_search.js +165 -0
- package/dist/runtime/wire/artifact_storage.d.ts +37 -0
- package/dist/runtime/wire/artifact_storage.js +93 -0
- package/dist/runtime/wire/artifact_verify.d.ts +1 -0
- package/dist/runtime/wire/artifact_verify.js +8 -0
- package/dist/runtime/wire/human_input.d.ts +62 -0
- package/dist/runtime/wire/human_input.js +156 -0
- package/dist/runtime/wire/inference_proxy.d.ts +70 -0
- package/dist/runtime/wire/inference_proxy.js +157 -0
- package/dist/runtime/wire/manifest.d.ts +16 -0
- package/dist/runtime/wire/manifest.js +18 -0
- package/dist/runtime/wire/run.d.ts +54 -0
- package/dist/runtime/wire/run.js +2 -0
- package/dist/runtime/workflow_host.d.ts +194 -0
- package/dist/runtime/workflow_host.js +382 -0
- package/dist/runtime/workspace_store.d.ts +73 -0
- package/dist/runtime/workspace_store.js +118 -0
- package/package.json +70 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// RecordingSecretResolver — the redaction feeder (MASTER_SPEC §12, plan #9).
|
|
2
|
+
//
|
|
3
|
+
// Decorates any SecretResolver so EVERY value a run resolves — whether the workflow program asked
|
|
4
|
+
// via `secrets.get(name)` or a tool asked via `ctx.secrets.resolve(ref)` — is recorded into the
|
|
5
|
+
// run's SecretRedactor. The leaf executor then scrubs those known values out of all LLM-bound
|
|
6
|
+
// content. Wrapping at the resolver level means there is exactly one chokepoint: a value cannot be
|
|
7
|
+
// resolved without becoming redactable.
|
|
8
|
+
//
|
|
9
|
+
// A failed resolve (FORBIDDEN/NOT_FOUND) records nothing — the error propagates unchanged.
|
|
10
|
+
export class RecordingSecretResolver {
|
|
11
|
+
inner;
|
|
12
|
+
redactor;
|
|
13
|
+
constructor(inner, redactor) {
|
|
14
|
+
this.inner = inner;
|
|
15
|
+
this.redactor = redactor;
|
|
16
|
+
}
|
|
17
|
+
async resolve(ref) {
|
|
18
|
+
const value = await this.inner.resolve(ref);
|
|
19
|
+
this.redactor.record(value);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Why a run was aborted mid-flight. Extensible — user-initiated cancel will add to this.
|
|
2
|
+
* `lease_lost`: another worker reclaimed this run (our lease expired + a sweep re-dispatched it),
|
|
3
|
+
* so we must stop WITHOUT finalizing — the new owner owns the terminal write. */
|
|
4
|
+
export type AbortReason = "credit_exhausted" | "cancelled" | "lease_lost";
|
|
5
|
+
/** Thrown by WorkflowHost hooks once the run's AbortSignal has fired, so the program unwinds. A plain
|
|
6
|
+
* Error subclass (no AppError/model coupling) carrying the machine-readable reason. */
|
|
7
|
+
export declare class RunAbortedError extends Error {
|
|
8
|
+
readonly reason: AbortReason;
|
|
9
|
+
constructor(reason: AbortReason);
|
|
10
|
+
}
|
|
11
|
+
/** The reason an aborted signal carries (set via `controller.abort(new RunAbortedError(reason))`), or
|
|
12
|
+
* null when the signal isn't aborted / wasn't aborted with a RunAbortedError. */
|
|
13
|
+
export declare function abortReason(signal: AbortSignal): AbortReason | null;
|
|
14
|
+
/** Throw if the signal has already aborted — the guard every WorkflowHost hook calls at entry. Re-uses
|
|
15
|
+
* the signal's own RunAbortedError when present, so the reason propagates verbatim. */
|
|
16
|
+
export declare function throwIfAborted(signal: AbortSignal | undefined): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// run_abort — the provider-agnostic cooperative-cancellation substrate for a run (docs/RUNNER_BROKER.md
|
|
2
|
+
// §15 credit watching; the foundation user-initiated cancel will reuse).
|
|
3
|
+
//
|
|
4
|
+
// The cancellation primitive is a Web-standard `AbortSignal` — NOT a Strands/model concept. The worker
|
|
5
|
+
// owns one `AbortController` per run session; a watcher (credit, later user-cancel) calls
|
|
6
|
+
// `controller.abort(new RunAbortedError(reason))`. The WorkflowHost honors that signal at every hook
|
|
7
|
+
// boundary (`agent`/`sleep`/`workflows.call`/…), unwinding the program. The ONLY place that translates
|
|
8
|
+
// the signal into a model-specific stop is the Strands leaf (signal → `agent.cancel()`); a future
|
|
9
|
+
// non-Strands leaf honors the SAME `AbortSignal` its own way. So nothing here, in the host, or in the
|
|
10
|
+
// program-facing SDK depends on the model backend.
|
|
11
|
+
//
|
|
12
|
+
// `signal.aborted` is AUTHORITATIVE at the orchestrator: a program that catches RunAbortedError and
|
|
13
|
+
// keeps going still stops, because every subsequent host hook re-throws and the orchestrator finalizes
|
|
14
|
+
// the run terminal based on the signal regardless of how the program returned.
|
|
15
|
+
/** Thrown by WorkflowHost hooks once the run's AbortSignal has fired, so the program unwinds. A plain
|
|
16
|
+
* Error subclass (no AppError/model coupling) carrying the machine-readable reason. */
|
|
17
|
+
export class RunAbortedError extends Error {
|
|
18
|
+
reason;
|
|
19
|
+
constructor(reason) {
|
|
20
|
+
super(`Run aborted: ${reason}`);
|
|
21
|
+
this.reason = reason;
|
|
22
|
+
this.name = "RunAbortedError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** The reason an aborted signal carries (set via `controller.abort(new RunAbortedError(reason))`), or
|
|
26
|
+
* null when the signal isn't aborted / wasn't aborted with a RunAbortedError. */
|
|
27
|
+
export function abortReason(signal) {
|
|
28
|
+
const r = signal.reason;
|
|
29
|
+
return r instanceof RunAbortedError ? r.reason : null;
|
|
30
|
+
}
|
|
31
|
+
/** Throw if the signal has already aborted — the guard every WorkflowHost hook calls at entry. Re-uses
|
|
32
|
+
* the signal's own RunAbortedError when present, so the reason propagates verbatim. */
|
|
33
|
+
export function throwIfAborted(signal) {
|
|
34
|
+
if (signal?.aborted === true) {
|
|
35
|
+
const r = signal.reason;
|
|
36
|
+
throw r instanceof RunAbortedError ? r : new RunAbortedError("cancelled");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RunEvent, RunEventBody, RedisPublisher } from "./agent/events.js";
|
|
2
|
+
export interface RunEventEmitterOptions {
|
|
3
|
+
runId: string;
|
|
4
|
+
publisher: RedisPublisher;
|
|
5
|
+
/** The durable store's max cursor at claim (0 ⇒ fresh run). Restart resumes in the next block. */
|
|
6
|
+
resumeAfterCursor?: number;
|
|
7
|
+
/** Injected clock for deterministic tests. Defaults to Date.now. */
|
|
8
|
+
now?: () => number;
|
|
9
|
+
}
|
|
10
|
+
export declare class WorkerRunEventEmitter {
|
|
11
|
+
private readonly runId;
|
|
12
|
+
private readonly publisher;
|
|
13
|
+
private readonly now;
|
|
14
|
+
private turn;
|
|
15
|
+
private seq;
|
|
16
|
+
constructor(opts: RunEventEmitterOptions);
|
|
17
|
+
/** Stamp + publish a run-level or agent frame. Agent frames pass their turnId. */
|
|
18
|
+
emit(body: RunEventBody, turnId?: string): RunEvent;
|
|
19
|
+
/** Restart resume: jump past the previous session's frames (claim carries the store max). */
|
|
20
|
+
resumeAfter(maxCursor: number): void;
|
|
21
|
+
/** Open a new agent stride block and emit its opening `turn_started` frame (built by the caller,
|
|
22
|
+
* which names the leaf). */
|
|
23
|
+
beginTurn(turnId: string, started: RunEventBody): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// WorkerRunEventEmitter — the run's SINGLE event envelope counter, engine-parity
|
|
2
|
+
// (boardwalk-labs/boardwalk supervisor semantics):
|
|
3
|
+
//
|
|
4
|
+
// * One shared `{turn, seq}` per run session. Every emit bumps `seq` (1-based);
|
|
5
|
+
// `cursor = makeCursor(turn, seq)` is run-globally monotonic.
|
|
6
|
+
// * `beginTurn(turnId)` opens a new agent stride block: `turn += 1`, `seq = 0`, then emits
|
|
7
|
+
// the block's opening `turn_started` frame.
|
|
8
|
+
// * Run-level frames (run_status / phase / output / program_output) carry `turnId = runId`
|
|
9
|
+
// and ride the CURRENT block — there is no separate "program band", which is what keeps
|
|
10
|
+
// cursors monotonic when program logs interleave with agent turns.
|
|
11
|
+
// * Resume (crash-restart re-runs the program from the top): the claim response carries the
|
|
12
|
+
// store's max cursor; the emitter starts in the NEXT stride block so new frames always
|
|
13
|
+
// order after the previous session's.
|
|
14
|
+
//
|
|
15
|
+
// Frames publish as the stored row shape `{cursor, event}` (JSON) on `run:<id>` — the broker's
|
|
16
|
+
// telemetry endpoint fans out + appends verbatim. Publishing is best-effort (telemetry must
|
|
17
|
+
// never fail a run); the publisher (BrokerEventPublisher) batches.
|
|
18
|
+
import { makeCursor, TURN_CURSOR_STRIDE } from "./agent/events.js";
|
|
19
|
+
export class WorkerRunEventEmitter {
|
|
20
|
+
runId;
|
|
21
|
+
publisher;
|
|
22
|
+
now;
|
|
23
|
+
turn;
|
|
24
|
+
seq;
|
|
25
|
+
constructor(opts) {
|
|
26
|
+
this.runId = opts.runId;
|
|
27
|
+
this.publisher = opts.publisher;
|
|
28
|
+
this.now = opts.now ?? Date.now;
|
|
29
|
+
const max = opts.resumeAfterCursor ?? 0;
|
|
30
|
+
this.turn = max > 0 ? Math.floor(max / TURN_CURSOR_STRIDE) + 1 : 0;
|
|
31
|
+
this.seq = 0;
|
|
32
|
+
}
|
|
33
|
+
/** Stamp + publish a run-level or agent frame. Agent frames pass their turnId. */
|
|
34
|
+
emit(body, turnId) {
|
|
35
|
+
this.seq += 1;
|
|
36
|
+
const event = {
|
|
37
|
+
...body,
|
|
38
|
+
runId: this.runId,
|
|
39
|
+
turnId: turnId ?? this.runId,
|
|
40
|
+
seq: this.seq,
|
|
41
|
+
t: this.now(),
|
|
42
|
+
};
|
|
43
|
+
const cursor = makeCursor(this.turn, this.seq);
|
|
44
|
+
this.publisher
|
|
45
|
+
.publish(`run:${this.runId}`, JSON.stringify({ cursor, event }))
|
|
46
|
+
.catch(() => undefined); // best-effort; the publisher logs its own failures
|
|
47
|
+
return event;
|
|
48
|
+
}
|
|
49
|
+
/** Restart resume: jump past the previous session's frames (claim carries the store max). */
|
|
50
|
+
resumeAfter(maxCursor) {
|
|
51
|
+
if (maxCursor > 0) {
|
|
52
|
+
this.turn = Math.floor(maxCursor / TURN_CURSOR_STRIDE) + 1;
|
|
53
|
+
this.seq = 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Open a new agent stride block and emit its opening `turn_started` frame (built by the caller,
|
|
57
|
+
* which names the leaf). */
|
|
58
|
+
beginTurn(turnId, started) {
|
|
59
|
+
this.turn += 1;
|
|
60
|
+
this.seq = 0;
|
|
61
|
+
this.emit(started, turnId);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { McpTokenResult } from "@boardwalk-labs/engine/core";
|
|
2
|
+
import type { Run } from "./wire/run.js";
|
|
3
|
+
import { type JournalKind, type JournalLookup, type JournalSeam, type SuspendSignal } from "./suspension.js";
|
|
4
|
+
import type { WebSearchOutput } from "./tools/web_search.js";
|
|
5
|
+
import type { ArtifactCommitInput, ArtifactPresignInput, ArtifactPresignResult, ArtifactSignResult, ArtifactSummary, ArtifactWriteInput, ArtifactWriteResult } from "./tools/artifacts.js";
|
|
6
|
+
import { type InferenceFrame, type InferenceProxyRequest } from "./wire/inference_proxy.js";
|
|
7
|
+
export interface RunnerControlClientConfig {
|
|
8
|
+
/** Base URL of the Runner Control API (BOARDWALK_CONTROL_PLANE_URL). */
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
/** The per-run bearer token (BOARDWALK_RUN_TOKEN). */
|
|
11
|
+
runToken: string;
|
|
12
|
+
/** The run this client (and token) is bound to. */
|
|
13
|
+
runId: string;
|
|
14
|
+
/** Injected fetch (defaults to global fetch). */
|
|
15
|
+
fetchImpl?: typeof fetch;
|
|
16
|
+
}
|
|
17
|
+
/** The pinned program's download reference (the worker fetches + verifies + extracts it). */
|
|
18
|
+
export interface BrokerProgram {
|
|
19
|
+
entry: string;
|
|
20
|
+
digest: string;
|
|
21
|
+
sdkVersion: string;
|
|
22
|
+
downloadUrl: string;
|
|
23
|
+
}
|
|
24
|
+
export interface BrokerVersion {
|
|
25
|
+
manifest: unknown;
|
|
26
|
+
program: BrokerProgram;
|
|
27
|
+
}
|
|
28
|
+
/** The schedule spec the worker sends for `workflows.schedule` (exactly one of cron/rate/at). `at`
|
|
29
|
+
* is a ms epoch or ISO string — a Date is serialized to ISO by the host before it reaches here. */
|
|
30
|
+
export interface BrokerScheduleSpec {
|
|
31
|
+
cron?: string;
|
|
32
|
+
rate?: string;
|
|
33
|
+
at?: string | number;
|
|
34
|
+
timezone?: string;
|
|
35
|
+
idempotencyKey?: string;
|
|
36
|
+
}
|
|
37
|
+
/** A child run's terminal-relevant state, as returned by the `children` create/poll endpoints. */
|
|
38
|
+
export interface BrokerChild {
|
|
39
|
+
childRunId: string;
|
|
40
|
+
status: string;
|
|
41
|
+
output: unknown;
|
|
42
|
+
}
|
|
43
|
+
export declare class RunnerControlClient {
|
|
44
|
+
private readonly cfg;
|
|
45
|
+
private readonly base;
|
|
46
|
+
private readonly fetchImpl;
|
|
47
|
+
constructor(cfg: RunnerControlClientConfig);
|
|
48
|
+
/** Claim the run's lease. Returns the run on success, or null when it isn't claimable (409 —
|
|
49
|
+
* another worker has it, or it isn't pending), which the worker treats as "claim lost". */
|
|
50
|
+
claim(workerId: string, leaseSeconds: number): Promise<{
|
|
51
|
+
run: Run;
|
|
52
|
+
lastEventCursor: number;
|
|
53
|
+
lastJournalSeq: number;
|
|
54
|
+
} | null>;
|
|
55
|
+
/** Heartbeat: extend our lease so a long run isn't reclaimed mid-flight. Returns the new
|
|
56
|
+
* `leaseUntil`, or null when the lease was lost (409 — another worker reclaimed the run), which
|
|
57
|
+
* the worker treats as "stop". */
|
|
58
|
+
renewLease(workerId: string, leaseSeconds: number): Promise<number | null>;
|
|
59
|
+
/** Mark the run terminal. `workerId` lets the broker reject a finalize from a DISPLACED worker (one
|
|
60
|
+
* whose lease expired and whose run was reclaimed + re-dispatched to a new owner), so a
|
|
61
|
+
* hung/partitioned worker that later recovers can't clobber the live run or revive a terminal one. */
|
|
62
|
+
finalize(status: "completed" | "failed", output: unknown, workerId: string): Promise<void>;
|
|
63
|
+
/** Look up a durable-seam journal entry by its seq (docs/SUSPENSION.md), or null on a replay miss
|
|
64
|
+
* (404). The broker joins a parked agent leaf's answers into the result server-side. */
|
|
65
|
+
journalGet(seq: number): Promise<JournalLookup | null>;
|
|
66
|
+
/** Record a RESOLVED seam result (idempotent on the run + seq server-side; a resolved entry is
|
|
67
|
+
* immutable). The broker writes the memoized value the next replay returns. */
|
|
68
|
+
journalPut(entry: {
|
|
69
|
+
seq: number;
|
|
70
|
+
kind: JournalKind;
|
|
71
|
+
fingerprint: string;
|
|
72
|
+
label: string;
|
|
73
|
+
result: unknown;
|
|
74
|
+
}): Promise<void>;
|
|
75
|
+
/** Persist a durable SUSPENSION: the broker records the wake condition (a pending/suspended journal
|
|
76
|
+
* entry + a human-input request row for HITL, or the wake time for a long sleep), flips the run to
|
|
77
|
+
* its suspended status, and releases the lease — transactionally. No finalize; a wake re-dispatches. */
|
|
78
|
+
suspend(signal: SuspendSignal, workerId: string): Promise<void>;
|
|
79
|
+
/** The {@link JournalSeam} the worker host reads/writes — a thin adapter over the broker methods. */
|
|
80
|
+
journalSeam(): JournalSeam;
|
|
81
|
+
/** Fetch the run's pinned manifest + program source, or null when the version is missing (404). */
|
|
82
|
+
getVersion(): Promise<BrokerVersion | null>;
|
|
83
|
+
/** Book a runtime-seconds DELTA (the worker's RuntimeFlusher → broker). `identifier` makes a
|
|
84
|
+
* retried/duplicate flush idempotent; distinct per-flush ids sum into the run's runtime total. */
|
|
85
|
+
reportUsage(runtimeSeconds: number, identifier: string): Promise<void>;
|
|
86
|
+
/** Report a token-usage delta for incremental in-run metering (the usage flusher → broker). The
|
|
87
|
+
* broker gates on the run's per-connection `billed_by_boardwalk` server-side + meters to Stripe;
|
|
88
|
+
* `identifier` makes a retried/duplicate flush idempotent. Satisfies {@link TokenUsageReporter}. */
|
|
89
|
+
meterTokens(input: {
|
|
90
|
+
inputTokens: number;
|
|
91
|
+
outputTokens: number;
|
|
92
|
+
model?: string;
|
|
93
|
+
identifier: string;
|
|
94
|
+
/** Cache-served input tokens — display-only annotation (omitted when zero/unknown). */
|
|
95
|
+
cachedReadTokens?: number;
|
|
96
|
+
cachedWriteTokens?: number;
|
|
97
|
+
}): Promise<void>;
|
|
98
|
+
/** Check whether the run's org is still funded (the CreditWatcher → broker). The broker reads the
|
|
99
|
+
* live Stripe balance server-side; `false` means out of credit (the watcher then aborts the run). */
|
|
100
|
+
checkCredit(): Promise<boolean>;
|
|
101
|
+
/** Check whether the run has been asked to cancel (the CancelWatcher → broker). `true` once the user
|
|
102
|
+
* cancelled the run (the broker flipped it to `cancelling`/`cancelled`); the watcher then aborts the
|
|
103
|
+
* run. Brokered because the runner holds no DB/Redis — this replaces the unreachable Redis channel. */
|
|
104
|
+
checkCancelled(): Promise<boolean>;
|
|
105
|
+
/** Mint a presigned GET URL to restore this workflow's last `/workspace` snapshot (workspace
|
|
106
|
+
* persistence, §5). `null` when the run isn't eligible (not opted-in, or self-hosted). */
|
|
107
|
+
workspaceHydrateUrl(): Promise<string | null>;
|
|
108
|
+
/** Mint a presigned PUT URL to snapshot this workflow's `/workspace` (the worker uploads the tarball
|
|
109
|
+
* straight to S3). `null` when the run isn't eligible. `sizeBytes` is the archive's on-disk size
|
|
110
|
+
* (the worker tars BEFORE requesting the URL) — the broker records it for the org storage counter +
|
|
111
|
+
* daily meter; the snapshot overwrites one per-workflow key, so it's the workflow's full footprint. */
|
|
112
|
+
workspacePersistUrl(sizeBytes: number): Promise<{
|
|
113
|
+
url: string;
|
|
114
|
+
contentType: string;
|
|
115
|
+
} | null>;
|
|
116
|
+
/** Download bytes from a presigned S3 URL (workspace hydrate). `null` on 404 (no snapshot yet —
|
|
117
|
+
* e.g. the workflow's first run); throws on any other non-2xx. Goes straight to S3, not the broker. */
|
|
118
|
+
downloadBytes(url: string): Promise<Uint8Array | null>;
|
|
119
|
+
/** Request an OIDC run id-token for `audience` (§OIDC). The broker mints an asymmetric,
|
|
120
|
+
* third-party-verifiable token (gated server-side on `permissions.id_token: "write"`) — used to
|
|
121
|
+
* federate into the org's OWN cloud (AWS/GCP). DIFFERENT from this client's run token. */
|
|
122
|
+
requestOidcToken(audience: string): Promise<{
|
|
123
|
+
token: string;
|
|
124
|
+
expiresIn: number;
|
|
125
|
+
}>;
|
|
126
|
+
/** Publish a batch of live agent-event frames (the SSE live-tail source) — the broker publishes
|
|
127
|
+
* them to the run's Redis channel server-side, so the runner holds no Redis credential. */
|
|
128
|
+
publishTelemetry(frames: string[]): Promise<void>;
|
|
129
|
+
/** Store a run artifact through the broker (which holds the S3 credential + neutralizes the served
|
|
130
|
+
* content type server-side). Returns the catalog id + a signed download URL. */
|
|
131
|
+
writeArtifact(input: ArtifactWriteInput): Promise<ArtifactWriteResult>;
|
|
132
|
+
/** Phase 1 of the LARGE-artifact path (docs/RUNNER_BROKER.md §7 step 4): presign an S3 PUT. The
|
|
133
|
+
* broker derives the S3 key + neutralizes/pins the served content type; it returns the upload URL +
|
|
134
|
+
* required headers + the `s3Key` to echo back at commit. No catalog row exists yet. */
|
|
135
|
+
presignArtifact(input: ArtifactPresignInput): Promise<ArtifactPresignResult>;
|
|
136
|
+
/** Upload bytes to a presigned S3 URL (the large-artifact path). The `headers` come from the
|
|
137
|
+
* presign response and MUST be sent verbatim — the content type is pinned into the signature, so
|
|
138
|
+
* S3 rejects a mismatch. This call goes straight to S3, not the broker. */
|
|
139
|
+
uploadBytes(url: string, headers: Record<string, string>, body: Uint8Array): Promise<void>;
|
|
140
|
+
/** Phase 2 of the LARGE-artifact path: register the catalog row AFTER the bytes have landed in S3
|
|
141
|
+
* (called only on a successful {@link uploadBytes}, so a failed upload leaves no dangling row). The
|
|
142
|
+
* broker re-validates the run prefix + re-neutralizes the content type, then returns the catalog id
|
|
143
|
+
* + a signed download URL. */
|
|
144
|
+
commitArtifact(input: ArtifactCommitInput): Promise<ArtifactWriteResult>;
|
|
145
|
+
/** List the artifacts this run has produced. */
|
|
146
|
+
listArtifacts(): Promise<ArtifactSummary[]>;
|
|
147
|
+
/** Mint a fresh signed download URL for one of this run's artifacts. */
|
|
148
|
+
signArtifactUrl(artifactId: string, ttlSeconds: number): Promise<ArtifactSignResult>;
|
|
149
|
+
/** Resolve an org secret the run's manifest allows (the program's `secrets.get`). The broker
|
|
150
|
+
* enforces the allowlist + returns the value; a forbidden/missing secret surfaces as a throw. */
|
|
151
|
+
resolveSecret(name: string): Promise<string>;
|
|
152
|
+
/** Broker a short-lived OAuth bearer for a hosted MCP server (the engine's `mcpToken` hook, called
|
|
153
|
+
* reactively after a 401). The broker vends from the org's connection vault and re-checks egress.
|
|
154
|
+
* A 403 (no active connection / non-allowlisted host) degrades to `{ accessToken: null, hint }` so
|
|
155
|
+
* the engine surfaces a clean failure instead of a thrown 500 mid-run; the token is never logged. */
|
|
156
|
+
mcpToken(serverUrl: string, invalidateToken?: string): Promise<McpTokenResult>;
|
|
157
|
+
/** Proxy a web_search through the broker (which holds the Tavily key) — the runner sends the
|
|
158
|
+
* query, the broker calls Tavily and returns the results. */
|
|
159
|
+
webSearch(input: unknown): Promise<WebSearchOutput>;
|
|
160
|
+
/** Create (or idempotently re-attach to) a child run for `workflows.call`. */
|
|
161
|
+
startChild(slug: string, input: unknown): Promise<BrokerChild>;
|
|
162
|
+
/** Provision a durable schedule for `workflows.schedule`; returns the new schedule's id. */
|
|
163
|
+
scheduleWorkflow(slug: string, input: unknown, spec: BrokerScheduleSpec): Promise<string>;
|
|
164
|
+
/** Poll a child run's status/output, or null when it isn't this run's child (404). */
|
|
165
|
+
getChild(childRunId: string): Promise<{
|
|
166
|
+
id: string;
|
|
167
|
+
status: string;
|
|
168
|
+
output: unknown;
|
|
169
|
+
} | null>;
|
|
170
|
+
/**
|
|
171
|
+
* Proxy one model turn through the broker (docs/RUNNER_BROKER.md §4 — Inference). POSTs the
|
|
172
|
+
* neutral conversation; the broker resolves the REAL model server-side (the runner holds no model
|
|
173
|
+
* creds), invokes the matching engine adapter, and relays the model's stream back as NDJSON
|
|
174
|
+
* `InferenceFrame`s (delta / result / error). Yields each frame; the engine-backed leaf surfaces
|
|
175
|
+
* deltas via `providerIo.onDelta`, takes the terminal `result` as the turn, and throws on `error`.
|
|
176
|
+
*
|
|
177
|
+
* Backs {@link InferenceProxyTransport} (inference_transport.ts) — the model swap is invisible to
|
|
178
|
+
* the engine loop, which keeps the runner provider-agnostic (the broker owns model invocation). A
|
|
179
|
+
* non-200 (a failure BEFORE the stream began) throws the broker's already-classified message.
|
|
180
|
+
*/
|
|
181
|
+
streamInference(req: InferenceProxyRequest): AsyncGenerator<InferenceFrame, void, undefined>;
|
|
182
|
+
private url;
|
|
183
|
+
private headers;
|
|
184
|
+
}
|