@coreplane/switchboard 0.0.0 → 1.18.0
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 +201 -0
- package/README.md +18 -1
- package/dist/assets/.dockerignore +27 -0
- package/dist/assets/.env.example +33 -0
- package/dist/assets/Dockerfile +111 -0
- package/dist/assets/config/config.example.yaml +359 -0
- package/dist/assets/deploy/bin/build-stamp.d.mts +15 -0
- package/dist/assets/deploy/bin/build-stamp.mjs +98 -0
- package/dist/assets/deploy/bin/cf-logs +32 -0
- package/dist/assets/deploy/cloudflare/package.json +29 -0
- package/dist/assets/deploy/cloudflare/preflight.mjs +243 -0
- package/dist/assets/deploy/cloudflare/tsconfig.json +18 -0
- package/dist/assets/deploy/cloudflare/worker.ts +382 -0
- package/dist/assets/deploy/cloudflare/wrangler.template.jsonc +67 -0
- package/dist/assets/deploy/cloudflare/write-build.d.mts +7 -0
- package/dist/assets/deploy/cloudflare/write-build.mjs +53 -0
- package/dist/assets/deploy/cloudflare-docs/package.json +18 -0
- package/dist/assets/deploy/cloudflare-docs/wrangler.template.jsonc +30 -0
- package/dist/assets/deploy/cloudflare-memory/package.json +25 -0
- package/dist/assets/deploy/cloudflare-memory/tsconfig.json +17 -0
- package/dist/assets/deploy/cloudflare-memory/worker.ts +2635 -0
- package/dist/assets/deploy/cloudflare-memory/wrangler.template.jsonc +50 -0
- package/dist/assets/deploy/cloudflare-resident/Dockerfile +91 -0
- package/dist/assets/deploy/cloudflare-resident/gc.ts +287 -0
- package/dist/assets/deploy/cloudflare-resident/node-async-hooks.d.ts +11 -0
- package/dist/assets/deploy/cloudflare-resident/package.json +29 -0
- package/dist/assets/deploy/cloudflare-resident/preflight.mjs +224 -0
- package/dist/assets/deploy/cloudflare-resident/tsconfig.json +19 -0
- package/dist/assets/deploy/cloudflare-resident/worker.ts +6637 -0
- package/dist/assets/deploy/cloudflare-resident/wrangler.template.jsonc +120 -0
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +67 -0
- package/dist/assets/deploy/cloudflare-sandbox/docker-wrapper.sh +37 -0
- package/dist/assets/deploy/cloudflare-sandbox/package.json +26 -0
- package/dist/assets/deploy/cloudflare-sandbox/tsconfig.json +20 -0
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +410 -0
- package/dist/assets/deploy/cloudflare-sandbox/wrangler.template.jsonc +67 -0
- package/dist/assets/deploy/profile.example.json +13 -0
- package/dist/assets/deploy/secrets.manifest.json +108 -0
- package/dist/assets/docker-entrypoint.sh +15 -0
- package/dist/assets/package-lock.json +18407 -0
- package/dist/assets/package.json +104 -0
- package/dist/assets/project.json +219 -0
- package/dist/assets/source.json +5 -0
- package/dist/assets/src/core/authz/actor.ts +100 -0
- package/dist/assets/src/core/authz/authorize.ts +169 -0
- package/dist/assets/src/core/authz/grants.ts +347 -0
- package/dist/assets/src/core/authz/policy.ts +281 -0
- package/dist/assets/src/core/authz/resource.ts +147 -0
- package/dist/assets/src/core/authz/types.ts +164 -0
- package/dist/assets/src/core/drain.ts +54 -0
- package/dist/assets/src/core/ingressTokens.ts +64 -0
- package/dist/assets/src/core/memory/engine.ts +115 -0
- package/dist/assets/src/core/memory/scorer.ts +147 -0
- package/dist/assets/src/core/memory/types.ts +120 -0
- package/dist/assets/src/core/normalizeSpans.ts +299 -0
- package/dist/assets/src/core/prDescriptionTypes.ts +54 -0
- package/dist/assets/src/core/redact.ts +113 -0
- package/dist/assets/src/core/runEvents.ts +537 -0
- package/dist/assets/src/core/runFriction.ts +665 -0
- package/dist/assets/src/core/runLedger/decisions.ts +126 -0
- package/dist/assets/src/core/runLedger/types.ts +177 -0
- package/dist/assets/src/core/runRecord.ts +627 -0
- package/dist/assets/src/core/runShape.ts +61 -0
- package/dist/assets/src/core/schedules.ts +452 -0
- package/dist/assets/src/core/time/formatDuration.ts +61 -0
- package/dist/assets/src/core/trace/attrs.ts +203 -0
- package/dist/assets/src/core/trace/classify.ts +49 -0
- package/dist/assets/src/core/trace/clock.ts +6 -0
- package/dist/assets/src/core/trace/context.ts +9 -0
- package/dist/assets/src/core/trace/ids.ts +23 -0
- package/dist/assets/src/core/trace/partition.ts +235 -0
- package/dist/assets/src/core/trace/sinks.ts +68 -0
- package/dist/assets/src/core/trace/streamSpans.ts +163 -0
- package/dist/assets/src/core/trace/traceparent.ts +29 -0
- package/dist/assets/src/core/trace/tracer.ts +247 -0
- package/dist/assets/src/core/trace/types.ts +125 -0
- package/dist/assets/src/core/trace/workerTrace.ts +97 -0
- package/dist/assets/src/deploy/buildStamp.ts +93 -0
- package/dist/assets/src/deploy/liveGate.ts +203 -0
- package/dist/assets/src/deploy/profile.ts +162 -0
- package/dist/assets/src/deploy/restart.ts +393 -0
- package/dist/assets/src/effort.ts +17 -0
- package/dist/assets/src/execution/bashTimeout.ts +78 -0
- package/dist/assets/src/execution/bindingPurge.ts +43 -0
- package/dist/assets/src/execution/residentBackupTransfer.ts +50 -0
- package/dist/assets/src/execution/residentCleanliness.ts +95 -0
- package/dist/assets/src/execution/residentCredentials.ts +81 -0
- package/dist/assets/src/execution/residentDepCache.ts +321 -0
- package/dist/assets/src/execution/residentDepsStore.ts +326 -0
- package/dist/assets/src/execution/residentDetach.ts +48 -0
- package/dist/assets/src/execution/residentDisk.ts +107 -0
- package/dist/assets/src/execution/residentDiskBudget.ts +448 -0
- package/dist/assets/src/execution/residentExecWrap.ts +100 -0
- package/dist/assets/src/execution/residentHead.ts +85 -0
- package/dist/assets/src/execution/residentReadonly.ts +72 -0
- package/dist/assets/src/execution/residentRefresh.ts +429 -0
- package/dist/assets/src/execution/residentRestoreExtract.ts +130 -0
- package/dist/assets/src/execution/residentState.ts +47 -0
- package/dist/assets/src/execution/residentStepReport.ts +98 -0
- package/dist/assets/src/execution/residentStepTrace.ts +97 -0
- package/dist/assets/src/execution/residentSteps.ts +99 -0
- package/dist/assets/src/execution/residentText.ts +83 -0
- package/dist/assets/src/execution/residentTrace.ts +119 -0
- package/dist/assets/src/execution/sandboxEnv.ts +42 -0
- package/dist/assets/src/execution/sandboxErrors.ts +159 -0
- package/dist/assets/src/execution/sandboxKeepalive.ts +118 -0
- package/dist/assets/src/execution/shellQuote.ts +8 -0
- package/dist/assets/src/mcp/registry.ts +242 -0
- package/dist/assets/src/providers/types.ts +152 -0
- package/dist/assets/web/dist/.vite/manifest.json +176 -0
- package/dist/assets/web/dist/assets/AppShell-Bk2gbvet.js +1 -0
- package/dist/assets/web/dist/assets/CostsPage-CTZcMYYx.js +1 -0
- package/dist/assets/web/dist/assets/NotFoundPage-C-BuaSm8.js +1 -0
- package/dist/assets/web/dist/assets/ResidentDetailPage-D3shEnzl.js +1 -0
- package/dist/assets/web/dist/assets/ResidentsIndexPage-DWIubQ05.js +1 -0
- package/dist/assets/web/dist/assets/RunRoutePage-BMjuE-oX.js +126 -0
- package/dist/assets/web/dist/assets/RunRoutePage-XVFj0XDc.css +1 -0
- package/dist/assets/web/dist/assets/RunsIndexPage-C3_jYIo0.js +1 -0
- package/dist/assets/web/dist/assets/RunsTabs-C4krAL9o.js +1 -0
- package/dist/assets/web/dist/assets/ScheduledPage-g1W58mtN.js +1 -0
- package/dist/assets/web/dist/assets/StatusDot-DcPRw3zu.js +1 -0
- package/dist/assets/web/dist/assets/Tooltip-DJUkMYjo.js +1 -0
- package/dist/assets/web/dist/assets/favicon-DL1rdWJt.js +1 -0
- package/dist/assets/web/dist/assets/localIso-L06jV29p.js +1 -0
- package/dist/assets/web/dist/assets/main-BsBGUyMH.css +2 -0
- package/dist/assets/web/dist/assets/main-CyM5f4JC.js +28 -0
- package/dist/assets/web/dist/assets/residentDiskBudget-BMBKlYRH.js +1 -0
- package/dist/assets/web/dist/assets/seed-BglCRKLA.js +6 -0
- package/dist/assets/web/dist/assets/wallClock-Ckv3sKoR.js +1 -0
- package/dist/cli.js +34494 -0
- package/package.json +43 -10
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// The ledger's decisions (docs/reference/specs/run-history.md items 28–31), pure. The
|
|
2
|
+
// Durable Object applies them inside one transaction; the in-memory ledger
|
|
3
|
+
// applies them in tests; both agree because this is the only copy.
|
|
4
|
+
|
|
5
|
+
import type { ClaimResult, FenceResult, LivePhase } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/** One live run per thread. The existing row, if any, is what `live_runs` holds
|
|
8
|
+
* for the thread; the same run re-claimed by its owner is idempotent (a retry
|
|
9
|
+
* after a lost response), anything else is refused with what the steer
|
|
10
|
+
* message needs. */
|
|
11
|
+
export function decideClaim(
|
|
12
|
+
existing: { runId: string; agent?: string; startedAt: number; ownerGen: string } | undefined,
|
|
13
|
+
req: { runId: string; gen: string },
|
|
14
|
+
): ClaimResult {
|
|
15
|
+
if (!existing) return { ok: true };
|
|
16
|
+
if (existing.runId === req.runId && existing.ownerGen === req.gen) return { ok: true };
|
|
17
|
+
return {
|
|
18
|
+
ok: false,
|
|
19
|
+
reason: "thread-live",
|
|
20
|
+
live: {
|
|
21
|
+
runId: existing.runId,
|
|
22
|
+
...(existing.agent !== undefined ? { agent: existing.agent } : {}),
|
|
23
|
+
startedAt: existing.startedAt,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** What an accepted claim does to the thread's row (item 42). `insert`: no row.
|
|
29
|
+
* `promote`: the owner's claim WITH a prompt on its own `attaching` row — the
|
|
30
|
+
* prompt, tools, card and state land and the phase goes `live`, identity and
|
|
31
|
+
* start untouched. `refresh`: the owner re-reserves (a retry after a lost
|
|
32
|
+
* response) — the lease only. `keep`: any owner re-claim on a row past
|
|
33
|
+
* attaching — idempotent, nothing written (as it always was). Decided only
|
|
34
|
+
* after `decideClaim` accepted. */
|
|
35
|
+
export type ClaimWrite = "insert" | "promote" | "refresh" | "keep";
|
|
36
|
+
export function decideClaimWrite(
|
|
37
|
+
existing: { runId: string; ownerGen: string; phase: LivePhase } | undefined,
|
|
38
|
+
req: { runId: string; gen: string; phase?: "attaching" | "live" },
|
|
39
|
+
): ClaimWrite {
|
|
40
|
+
if (!existing) return "insert";
|
|
41
|
+
if (existing.phase !== "attaching") return "keep";
|
|
42
|
+
return (req.phase ?? "live") === "attaching" ? "refresh" : "promote";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The phase a reclaimed row lands in: an `attaching` row stays so — the
|
|
46
|
+
* launcher restarts it from its request rather than resuming a transcript it
|
|
47
|
+
* does not have; every other row becomes `live` under the new owner. */
|
|
48
|
+
export function reclaimPhase(from: LivePhase): LivePhase {
|
|
49
|
+
return from === "attaching" ? "attaching" : "live";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The fencing token: only the generation that holds the lease may write. */
|
|
53
|
+
export function checkFence(row: { ownerGen: string } | undefined, gen: string): FenceResult {
|
|
54
|
+
if (!row) return { ok: false, reason: "unknown-run" };
|
|
55
|
+
return row.ownerGen === gen ? { ok: true } : { ok: false, reason: "fenced" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** What a reclaiming generation takes over: every run whose lease has expired
|
|
59
|
+
* (a heartbeat lands strictly before `leaseUntil`, so equal is expired) and
|
|
60
|
+
* every run the previous generation handed off — **never a row it owns
|
|
61
|
+
* itself**. The reclaim runs on a sweep inside the live process too, and a
|
|
62
|
+
* lapsed lease on our own row means a heartbeat that could not land (a state
|
|
63
|
+
* Worker blip), not a dead owner: taking it would launch the run a second
|
|
64
|
+
* time in the same process, and the fence, which compares generations, would
|
|
65
|
+
* never stop the first. */
|
|
66
|
+
export function selectReclaim<T extends { leaseUntil: number; phase: LivePhase; ownerGen: string }>(
|
|
67
|
+
rows: readonly T[],
|
|
68
|
+
now: number,
|
|
69
|
+
gen: string,
|
|
70
|
+
): T[] {
|
|
71
|
+
return rows.filter((r) => r.ownerGen !== gen && (r.phase === "handoff" || r.leaseUntil <= now));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The compare-and-swap table for a run's phase. `attaching → live` (the
|
|
75
|
+
* prompt landed) or `→ finishing` (the dispatch failed before it — never
|
|
76
|
+
* handoff: an attaching run has nothing to resume from, so the drain waits
|
|
77
|
+
* for it and a dead owner's row is restarted instead), `live → handoff`
|
|
78
|
+
* (SIGTERM), `live → finishing` (before the reply), `handoff → finishing`
|
|
79
|
+
* (the owner finished inside its own handoff window, before any reclaim —
|
|
80
|
+
* the fence on the generation still keeps a reclaimed row from it), and back
|
|
81
|
+
* to `live` from `handoff` or `finishing` by a reclaim. Nothing else. */
|
|
82
|
+
export function phaseTransition(from: LivePhase, to: LivePhase): boolean {
|
|
83
|
+
switch (from) {
|
|
84
|
+
case "attaching":
|
|
85
|
+
return to === "live" || to === "finishing";
|
|
86
|
+
case "live":
|
|
87
|
+
return to === "handoff" || to === "finishing";
|
|
88
|
+
case "handoff":
|
|
89
|
+
return to === "live" || to === "finishing";
|
|
90
|
+
case "finishing":
|
|
91
|
+
return to === "live";
|
|
92
|
+
default:
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type Completeness = { kind: "resume" } | { kind: "run-step-fresh" } | { kind: "interrupted"; why: string };
|
|
98
|
+
|
|
99
|
+
/** What a resume does with the rows it finds. A step write lands the step's
|
|
100
|
+
* turns first (the previous results turn and this assistant turn: two turns),
|
|
101
|
+
* then the step record with `turnIndex` = the transcript's turn count. So:
|
|
102
|
+
* the count matches the last record → resume there; two more → the next
|
|
103
|
+
* step's turns landed but its record did not, nothing was dispatched, run
|
|
104
|
+
* that step's tools fresh; anything else is a partial write. With no record
|
|
105
|
+
* yet, the seed plays the role of the last record. */
|
|
106
|
+
export function transcriptCompleteness(input: {
|
|
107
|
+
lastStep: { turnIndex: number } | null;
|
|
108
|
+
seedTurns: number;
|
|
109
|
+
transcriptTurns: number;
|
|
110
|
+
}): Completeness {
|
|
111
|
+
const { lastStep, seedTurns, transcriptTurns } = input;
|
|
112
|
+
if (transcriptTurns === 0) return { kind: "interrupted", why: "no transcript stored" };
|
|
113
|
+
const base = lastStep ? lastStep.turnIndex : seedTurns;
|
|
114
|
+
if (transcriptTurns === base) return { kind: "resume" };
|
|
115
|
+
if (transcriptTurns === base + 2) return { kind: "run-step-fresh" };
|
|
116
|
+
if (transcriptTurns < base) {
|
|
117
|
+
return {
|
|
118
|
+
kind: "interrupted",
|
|
119
|
+
why: `transcript has ${transcriptTurns} turns but the last step recorded ${base}`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
kind: "interrupted",
|
|
124
|
+
why: `transcript has ${transcriptTurns} turns, one past the last step's ${base}: a partial step write`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// The run ledger's contract (docs/decisions/0019-durable-run-ledger-resume-after-kill.md;
|
|
2
|
+
// docs/reference/specs/run-history.md items 28–34): what a live run leaves on the state
|
|
3
|
+
// Worker so the next bot generation can resume it. Node-free — imported by the
|
|
4
|
+
// bot and by `deploy/cloudflare-memory/worker.ts` alike, the way runRecord.ts is.
|
|
5
|
+
|
|
6
|
+
import type { ChatMessage, ToolDef } from "../../providers/types.js";
|
|
7
|
+
import type { ChannelVisibility } from "../authz/types.js";
|
|
8
|
+
import type { RunEvent } from "../runEvents.js";
|
|
9
|
+
|
|
10
|
+
/** How long a generation's claim on a run lasts without a heartbeat. */
|
|
11
|
+
export const LEASE_MS = 30_000;
|
|
12
|
+
/** How often the owning generation renews the lease. */
|
|
13
|
+
export const HEARTBEAT_MS = 10_000;
|
|
14
|
+
/** The append flusher's batch window and size. */
|
|
15
|
+
export const APPEND_FLUSH_MS = 500;
|
|
16
|
+
export const APPEND_FLUSH_EVENTS = 32;
|
|
17
|
+
/** Request-body ceiling for a transcript write (the Worker's `/runs/put` fence). */
|
|
18
|
+
export const TRANSCRIPT_REQUEST_BYTES = 2 * 1024 * 1024;
|
|
19
|
+
/** One content part per row; a row must stay under the Durable Object's 2 MB
|
|
20
|
+
* row limit with headroom for the JSON envelope. */
|
|
21
|
+
export const TRANSCRIPT_PART_BYTES = 1_500_000;
|
|
22
|
+
/** Base64 attachment data over this size is stored once and referenced. */
|
|
23
|
+
export const ATTACHMENT_REF_BYTES = 1_000_000;
|
|
24
|
+
/** A generation id: the bot's process start plus a random suffix. */
|
|
25
|
+
export const GEN_PATTERN = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
26
|
+
|
|
27
|
+
/** `attaching`: reserved at admission (item 42) — the row holds the request
|
|
28
|
+
* and no prompt yet; a reclaim restarts the run from the request. `live`:
|
|
29
|
+
* the prompt and seed landed. `handoff`: the owner drained. `finishing`: the
|
|
30
|
+
* owner replied. */
|
|
31
|
+
export type LivePhase = "attaching" | "live" | "handoff" | "finishing";
|
|
32
|
+
export type StopMode = "soft" | "hard";
|
|
33
|
+
|
|
34
|
+
/** Where the run's status card is, so a resumed run edits the same message. */
|
|
35
|
+
export interface CardHandle {
|
|
36
|
+
channel: string;
|
|
37
|
+
ts: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The registry's `RunMeta` fields (spelled out rather than imported: the
|
|
41
|
+
* registry is a Node module and this file is shared with the state Worker)
|
|
42
|
+
* plus what a resume needs that the dispatcher otherwise keeps in closures. */
|
|
43
|
+
export interface LiveRunMeta {
|
|
44
|
+
agent?: string;
|
|
45
|
+
model?: string;
|
|
46
|
+
channelId: string;
|
|
47
|
+
userId: string;
|
|
48
|
+
threadKey: string;
|
|
49
|
+
channelVisibility?: ChannelVisibility;
|
|
50
|
+
repo?: string;
|
|
51
|
+
sourceUrl?: string;
|
|
52
|
+
userName?: string;
|
|
53
|
+
effort?: string;
|
|
54
|
+
ref?: string;
|
|
55
|
+
headSha?: string;
|
|
56
|
+
pr?: number;
|
|
57
|
+
readonly?: boolean;
|
|
58
|
+
/** Which executor the run attached: what `makeExecutor` chose. */
|
|
59
|
+
selection?: "resident" | "sandbox" | "local" | "none";
|
|
60
|
+
/** The worktree path the system prompt names. */
|
|
61
|
+
workspace?: string;
|
|
62
|
+
/** The request the run was admitted for (item 42), in the durable inbox
|
|
63
|
+
* row's shape — text with its directives, sender, link, arrival time, the
|
|
64
|
+
* attachments when they fit — so a reclaim of an `attaching` row can
|
|
65
|
+
* dispatch it again under the same run id and card. */
|
|
66
|
+
request?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Dispatcher-local run state a resume must restore (the `submit_*` callbacks,
|
|
70
|
+
* the checklist, the pushed branch, the review head, the infra counters). */
|
|
71
|
+
export type RunState = Record<string, unknown>;
|
|
72
|
+
|
|
73
|
+
export interface LiveRunRow {
|
|
74
|
+
runId: string;
|
|
75
|
+
threadKey: string;
|
|
76
|
+
ownerGen: string;
|
|
77
|
+
/** Epoch ms. */
|
|
78
|
+
leaseUntil: number;
|
|
79
|
+
startedAt: number;
|
|
80
|
+
phase: LivePhase;
|
|
81
|
+
stop: StopMode | null;
|
|
82
|
+
meta: LiveRunMeta;
|
|
83
|
+
card: CardHandle | null;
|
|
84
|
+
/** The composed system prompt, verbatim. */
|
|
85
|
+
system: string;
|
|
86
|
+
/** The tool definitions the run was started with, verbatim. */
|
|
87
|
+
tools: ToolDef[];
|
|
88
|
+
state: RunState;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** One tool call the step dispatched; `tool` decides how a resume settles it. */
|
|
92
|
+
export interface InFlightCall {
|
|
93
|
+
callId: string;
|
|
94
|
+
tool: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Written BEFORE a step's tools run (after its transcript turns landed). */
|
|
98
|
+
export interface StepRecord {
|
|
99
|
+
step: number;
|
|
100
|
+
/** The registry `seq` at the time, for ordering against events. */
|
|
101
|
+
seq: number;
|
|
102
|
+
/** Transcript turns present when this record was written. */
|
|
103
|
+
turnIndex: number;
|
|
104
|
+
inFlight: InFlightCall[];
|
|
105
|
+
/** The inbox `seq` the run has consumed up to (0 = none). */
|
|
106
|
+
inboxConsumedSeq: number;
|
|
107
|
+
remainingMs: number;
|
|
108
|
+
turn: number;
|
|
109
|
+
iteration: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface InboxItem {
|
|
113
|
+
seq: number;
|
|
114
|
+
/** The `IncomingMessage` minus attachment bytes, plus channel/ts/threadTs. */
|
|
115
|
+
message: Record<string, unknown>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface RunJob {
|
|
119
|
+
kind: string;
|
|
120
|
+
payload: unknown;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface ClaimRequest {
|
|
124
|
+
runId: string;
|
|
125
|
+
threadKey: string;
|
|
126
|
+
gen: string;
|
|
127
|
+
leaseMs: number;
|
|
128
|
+
startedAt: number;
|
|
129
|
+
meta: LiveRunMeta;
|
|
130
|
+
card?: CardHandle | null;
|
|
131
|
+
system: string;
|
|
132
|
+
tools: ToolDef[];
|
|
133
|
+
state?: RunState;
|
|
134
|
+
/** `attaching` reserves the thread at admission with an empty prompt (item
|
|
135
|
+
* 42); absent (or `live`) is the claim with the prompt — which, on the
|
|
136
|
+
* owner's own attaching row, promotes it in place. */
|
|
137
|
+
phase?: "attaching" | "live";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export type ClaimResult =
|
|
141
|
+
{ ok: true } | { ok: false; reason: "thread-live"; live: { runId: string; agent?: string; startedAt: number } };
|
|
142
|
+
|
|
143
|
+
export type FenceResult = { ok: true } | { ok: false; reason: "fenced" | "unknown-run" };
|
|
144
|
+
|
|
145
|
+
export interface ReclaimedRun {
|
|
146
|
+
/** The row as the new generation now holds it (`phase: live`, its lease). */
|
|
147
|
+
row: LiveRunRow;
|
|
148
|
+
/** The phase the row was in when taken: `live` (an expired lease — the
|
|
149
|
+
* owner died), `handoff` (the owner drained), or `finishing` (the owner
|
|
150
|
+
* had replied and died before `finish` — the run is closed, never resumed). */
|
|
151
|
+
reclaimedFrom: LivePhase;
|
|
152
|
+
lastStep: StepRecord | null;
|
|
153
|
+
inbox: InboxItem[];
|
|
154
|
+
jobs: RunJob[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** One transcript row: a content part of turn `idx`. */
|
|
158
|
+
export interface TranscriptRow {
|
|
159
|
+
idx: number;
|
|
160
|
+
part: number;
|
|
161
|
+
json: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** An externalized attachment: base64 data stored once, referenced from a row. */
|
|
165
|
+
export interface TranscriptAttachment {
|
|
166
|
+
ref: string;
|
|
167
|
+
mediaType: string;
|
|
168
|
+
data: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** The turns a step write carries: the previous step's results and this step's assistant turn. */
|
|
172
|
+
export interface TranscriptTurn {
|
|
173
|
+
idx: number;
|
|
174
|
+
message: ChatMessage;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export type AppendableEvent = RunEvent & { seq: number };
|