@cat-factory/executor-harness 1.78.0 → 1.82.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/README.md +1 -0
- package/dist/agent-capabilities.d.ts +130 -0
- package/dist/agent-runner.d.ts +114 -0
- package/dist/agent-runner.js +15 -1
- package/dist/agent-shared.d.ts +18 -0
- package/dist/agent.d.ts +66 -0
- package/dist/bootstrap-mode.d.ts +20 -0
- package/dist/captured-command.d.ts +58 -0
- package/dist/claude-call-aggregator.d.ts +164 -0
- package/dist/claude-call-aggregator.js +123 -17
- package/dist/claude-stream.d.ts +56 -0
- package/dist/claude-stream.js +23 -0
- package/dist/coding-agent.d.ts +263 -0
- package/dist/dependency-install.d.ts +111 -0
- package/dist/effort.d.ts +19 -0
- package/dist/embed.d.ts +4 -0
- package/dist/failure.d.ts +42 -0
- package/dist/follow-ups.d.ts +28 -0
- package/dist/frontend-infra.d.ts +25 -0
- package/dist/fs-utils.d.ts +2 -0
- package/dist/git.d.ts +394 -0
- package/dist/host-markdown.d.ts +28 -0
- package/dist/inline.d.ts +10 -0
- package/dist/job.d.ts +666 -0
- package/dist/logger.d.ts +16 -0
- package/dist/onboarding-preseed.d.ts +24 -0
- package/dist/package-registries.d.ts +32 -0
- package/dist/pi-workspace.d.ts +194 -0
- package/dist/pi-workspace.js +4 -0
- package/dist/pi.d.ts +475 -0
- package/dist/pr-description.d.ts +85 -0
- package/dist/pr-template.d.ts +101 -0
- package/dist/process-exit.d.ts +7 -0
- package/dist/process.d.ts +19 -0
- package/dist/progress-guard.d.ts +88 -0
- package/dist/progress.d.ts +87 -0
- package/dist/redact.d.ts +31 -0
- package/dist/reproduction-proof.d.ts +224 -0
- package/dist/runner.d.ts +282 -0
- package/dist/runner.js +3 -0
- package/dist/server.d.ts +3 -0
- package/dist/structured-output.d.ts +75 -0
- package/dist/subagents.d.ts +88 -0
- package/dist/subagents.js +74 -4
- package/dist/transcript-retention.d.ts +21 -0
- package/dist/validation-checks.d.ts +159 -0
- package/dist/vcs-api.d.ts +73 -0
- package/dist/version.d.ts +2 -0
- package/package.json +9 -5
- package/src/agent-runner.ts +21 -2
- package/src/claude-call-aggregator.ts +181 -32
- package/src/claude-stream.ts +21 -0
- package/src/pi-workspace.ts +4 -0
- package/src/runner.ts +24 -0
- package/src/subagents.ts +57 -3
package/dist/job.d.ts
ADDED
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
import type { HarnessCallMetric, PiRunStats } from './pi.js';
|
|
2
|
+
import type { HarnessKind } from './pi-workspace.js';
|
|
3
|
+
import type { FailureCause } from './failure.js';
|
|
4
|
+
import type { EffortReport } from './effort.js';
|
|
5
|
+
import { type ValidationChecksSpec, type ValidationReport } from './validation-checks.js';
|
|
6
|
+
import { type ReproductionReport, type ReproductionSpec } from './reproduction-proof.js';
|
|
7
|
+
import { type DependencyInstallSpec } from './dependency-install.js';
|
|
8
|
+
import { type McpServerSpec, type SkillResourceSpec, type SkillSpec } from './agent-capabilities.js';
|
|
9
|
+
export type { McpServerSpec, SkillResourceSpec, SkillSpec };
|
|
10
|
+
/**
|
|
11
|
+
* Per-job auth fields, shared across every job shape. The Pi harness carries the
|
|
12
|
+
* proxy base URL + a model-locked session token; the subscription harnesses
|
|
13
|
+
* (Claude Code / Codex) carry a leased subscription token instead and talk direct
|
|
14
|
+
* to the vendor. `harness` selects which; absent ⇒ Pi.
|
|
15
|
+
*/
|
|
16
|
+
export interface HarnessAuthFields {
|
|
17
|
+
harness?: HarnessKind;
|
|
18
|
+
/** Worker LLM proxy base URL, including /v1 (Pi harness only). */
|
|
19
|
+
proxyBaseUrl?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The backend declaring that it serves the phase-tagged completions route
|
|
22
|
+
* (`${proxyBaseUrl}/phase/<phase>/chat/completions`), so this run may attribute each model
|
|
23
|
+
* call to the phase that spent it (`docs/initiatives/token-burn-instrumentation.md`). The
|
|
24
|
+
* same shape as {@link AgentJob.webSearch}: the backend states what IT serves, and the
|
|
25
|
+
* harness points Pi accordingly.
|
|
26
|
+
*
|
|
27
|
+
* Not a capability handshake — the harness never asks and never adapts to an answer. It
|
|
28
|
+
* exists because the harness image and the backend are only a matched set on the Cloudflare
|
|
29
|
+
* deployment: a runner pool pins its own image and `LOCAL_HARNESS_IMAGE` overrides the
|
|
30
|
+
* recommended pin, so an image ahead of its backend would otherwise 404 every model call.
|
|
31
|
+
* Absent ⇒ the plain path, and the run's calls are recorded as unattributed.
|
|
32
|
+
*/
|
|
33
|
+
proxyPhasePath?: boolean;
|
|
34
|
+
/** Signed, model-locked proxy session token (Pi harness only). */
|
|
35
|
+
sessionToken?: string;
|
|
36
|
+
/** Leased subscription credential (Claude Code OAuth token / Codex auth.json). */
|
|
37
|
+
subscriptionToken?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Anthropic-compatible base URL for a non-Anthropic Claude-Code vendor (GLM via
|
|
40
|
+
* Z.ai, Kimi via Moonshot). Present ⇒ the claude-code runner points
|
|
41
|
+
* ANTHROPIC_BASE_URL there with ANTHROPIC_AUTH_TOKEN; absent ⇒ Anthropic itself
|
|
42
|
+
* (CLAUDE_CODE_OAUTH_TOKEN against api.anthropic.com).
|
|
43
|
+
*/
|
|
44
|
+
subscriptionBaseUrl?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Native local execution: the `claude-code` / `codex` CLI runs with the developer's
|
|
47
|
+
* OWN ambient login (`~/.claude` / `~/.codex`) instead of a leased subscription token.
|
|
48
|
+
* Set only by the local native transport; when true `subscriptionToken` is not required.
|
|
49
|
+
*/
|
|
50
|
+
ambientAuth?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface RepoSpec {
|
|
53
|
+
owner: string;
|
|
54
|
+
name: string;
|
|
55
|
+
baseBranch: string;
|
|
56
|
+
cloneUrl: string;
|
|
57
|
+
/**
|
|
58
|
+
* The VCS provider the repo lives on, when the dispatcher set it. Selects GitHub-PR vs
|
|
59
|
+
* GitLab-MR for the "open the PR" call AUTHORITATIVELY (rather than guessing from the
|
|
60
|
+
* clone URL host, which can't recognise an arbitrarily-named self-managed GitLab). Absent
|
|
61
|
+
* ⇒ inferred from the clone URL.
|
|
62
|
+
*/
|
|
63
|
+
provider?: 'github' | 'gitlab';
|
|
64
|
+
/**
|
|
65
|
+
* For a monorepo service, the subdirectory (relative to the repo root, e.g.
|
|
66
|
+
* `packages/api`) the agent should run within. Sanitised on parse to a safe
|
|
67
|
+
* relative path so it can never escape the checkout. Absent ⇒ run at the repo root.
|
|
68
|
+
*/
|
|
69
|
+
serviceDirectory?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface PrSpec {
|
|
72
|
+
title: string;
|
|
73
|
+
body: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A connected service's repo to check out as a SIBLING alongside the primary during a
|
|
77
|
+
* multi-repo coding run (service-connections phase 3). The agent clones every peer repo
|
|
78
|
+
* into a sibling directory under the workspace root, makes the coherent cross-service
|
|
79
|
+
* change, and the harness opens ONE PR per peer repo it actually changed. The clone URL is
|
|
80
|
+
* host-allowlisted exactly like the primary `repo.cloneUrl`.
|
|
81
|
+
*/
|
|
82
|
+
export interface PeerRepoSpec {
|
|
83
|
+
repo: RepoSpec;
|
|
84
|
+
/** The involved service frame this repo resolved from, echoed back on the peer PR. */
|
|
85
|
+
frameId?: string;
|
|
86
|
+
/**
|
|
87
|
+
* The work branch to create off the peer's base and push (the shared `cat-factory/<block>`).
|
|
88
|
+
* Present for a COING fan-out (coder / ci-fixer). Absent for a READ-ONLY explore fan-out
|
|
89
|
+
* (the bug-investigator), which only clones the peer to read it and never pushes.
|
|
90
|
+
*/
|
|
91
|
+
newBranch?: string;
|
|
92
|
+
/**
|
|
93
|
+
* The EXISTING branch to check the peer out at for a READ-ONLY explore fan-out (the `merger`
|
|
94
|
+
* scoring the combined diff clones each peer at its PR branch so the diff sees the PR change).
|
|
95
|
+
* Absent ⇒ the peer is cloned at its repo default branch (the bug-investigator). Ignored on the
|
|
96
|
+
* coding fan-out, which creates `newBranch` instead.
|
|
97
|
+
*/
|
|
98
|
+
cloneBranch?: string;
|
|
99
|
+
/** Open a PR/MR in this peer when set AND the run changed the peer (skipped for a clean repo). */
|
|
100
|
+
pr?: PrSpec;
|
|
101
|
+
/** Per-repo GitHub token; defaults to the job's `ghToken` (one installation per workspace today). */
|
|
102
|
+
ghToken?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A repository checked out READ-ONLY as a sibling alongside the primary during a
|
|
106
|
+
* document-authoring coding run — the doc-writer reads it (to reuse existing solutions as a
|
|
107
|
+
* reference) but the harness never creates a branch, commits, or opens a PR for it. Deliberately
|
|
108
|
+
* carries NO branch/PR fields (unlike {@link PeerRepoSpec}), so it is structurally impossible to
|
|
109
|
+
* push: the read-only guarantee is enforced by the shape itself, by cloning at the repo's own
|
|
110
|
+
* base branch with no work branch, and by skipping the leg in the push phase. The clone URL is
|
|
111
|
+
* host-allowlisted exactly like the primary `repo.cloneUrl`.
|
|
112
|
+
*/
|
|
113
|
+
export interface ReferenceRepoSpec {
|
|
114
|
+
repo: RepoSpec;
|
|
115
|
+
/** Per-repo GitHub token; defaults to the job's `ghToken` (one installation per workspace today). */
|
|
116
|
+
ghToken?: string;
|
|
117
|
+
}
|
|
118
|
+
/** Hosts the harness is willing to send the installation token to. */
|
|
119
|
+
export declare function allowedGithubHosts(env?: NodeJS.ProcessEnv): Set<string>;
|
|
120
|
+
/** One private-registry entry: rendered into `~/.npmrc` before the agent runs. */
|
|
121
|
+
export interface PackageRegistrySpec {
|
|
122
|
+
ecosystem: 'npm';
|
|
123
|
+
/** Registry host, e.g. `registry.npmjs.org` — allowlisted, never a full URL. */
|
|
124
|
+
host: string;
|
|
125
|
+
/** npm scopes (`@org`) routed to this registry; EMPTY ⇒ authenticate the host only. */
|
|
126
|
+
scopes: string[];
|
|
127
|
+
token: string;
|
|
128
|
+
}
|
|
129
|
+
/** npm registry hosts the harness is willing to send a registry token to. */
|
|
130
|
+
export declare function allowedNpmRegistryHosts(env?: NodeJS.ProcessEnv): Set<string>;
|
|
131
|
+
/** Validate the optional `packageRegistries` list (see {@link PackageRegistrySpec}). */
|
|
132
|
+
export declare function parsePackageRegistries(value: unknown, env?: NodeJS.ProcessEnv): PackageRegistrySpec[];
|
|
133
|
+
/**
|
|
134
|
+
* One sensitive test credential the tester receives: an env-var name + its (secret) value.
|
|
135
|
+
* The backend seals these at rest and decrypts them at dispatch; the harness injects each as an
|
|
136
|
+
* environment variable the tester's shell can read (out of band — the value is NEVER in the
|
|
137
|
+
* prompt/telemetry). See {@link parseTestSecrets}.
|
|
138
|
+
*/
|
|
139
|
+
export interface TestSecretSpec {
|
|
140
|
+
key: string;
|
|
141
|
+
value: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Validate the optional tester `testSecrets` list — `{ key, value }` env pairs the harness
|
|
145
|
+
* injects into the run environment. Keys must be valid env-var names; toolchain-critical /
|
|
146
|
+
* reserved names ({@link isReservedEnvName}) and duplicates are dropped so a drifted body can't
|
|
147
|
+
* clobber PATH/NODE_OPTIONS/etc. Absent ⇒ no secrets injected.
|
|
148
|
+
*/
|
|
149
|
+
export declare function parseTestSecrets(value: unknown): TestSecretSpec[];
|
|
150
|
+
/** The new repository a repo-bootstrap run force-pushes its fresh history to. */
|
|
151
|
+
export interface BootstrapTargetSpec {
|
|
152
|
+
owner: string;
|
|
153
|
+
name: string;
|
|
154
|
+
cloneUrl: string;
|
|
155
|
+
defaultBranch: string;
|
|
156
|
+
}
|
|
157
|
+
/** How the generic agent runs: read-only exploration, or edit-and-push coding. */
|
|
158
|
+
export type AgentMode = 'explore' | 'coding' | 'preview';
|
|
159
|
+
/**
|
|
160
|
+
* Explore mode: how a container agent stands its dependencies up before the run (the
|
|
161
|
+
* tester). Two shapes, discriminated by `kind` (absent ⇒ `service`, the backend tester):
|
|
162
|
+
* - `service` — a backend service under test: `local` brings the service's
|
|
163
|
+
* docker-compose infra up on localhost for the run; `ephemeral` is a no-op stand-up
|
|
164
|
+
* (the env is already deployed and its URL reaches the agent through its prompt).
|
|
165
|
+
* - `frontend` — a frontend app under test (the self-contained UI-test flow): build the
|
|
166
|
+
* frontend, stand WireMock up for its mocked upstreams, serve the built app, and point
|
|
167
|
+
* the (`tester-ui`) agent at it. Everything runs as localhost PROCESSES in the one
|
|
168
|
+
* container (no Docker-in-Docker), so it works on Cloudflare + Apple `container` too.
|
|
169
|
+
* Absent ⇒ the harness manages no infra.
|
|
170
|
+
*/
|
|
171
|
+
export type AgentInfraSpec = ServiceInfraSpec | FrontendInfraSpec;
|
|
172
|
+
/** Backend-service tester infra (docker-compose local, or a deployed ephemeral env). */
|
|
173
|
+
export interface ServiceInfraSpec {
|
|
174
|
+
/** Discriminant. Absent ⇒ `service` (the backend tester). */
|
|
175
|
+
kind?: 'service';
|
|
176
|
+
/** `local` stands infra up via docker-compose; `ephemeral` tests a deployed env. */
|
|
177
|
+
environment: 'local' | 'ephemeral';
|
|
178
|
+
/** Local mode: the service declared no infra dependencies (spin nothing up). */
|
|
179
|
+
noInfraDependencies?: boolean;
|
|
180
|
+
/** Local mode: repo-relative docker-compose path to stand the dependencies up. */
|
|
181
|
+
composePath?: string;
|
|
182
|
+
/** Ephemeral mode: the provisioned environment URL (echoed for context only). */
|
|
183
|
+
environmentUrl?: string;
|
|
184
|
+
/**
|
|
185
|
+
* The connected services "directly involved" in this task that have a LIVE ephemeral env this
|
|
186
|
+
* run (service title → URL), so a cross-service integration test can reach a peer's real
|
|
187
|
+
* environment. Echoed for context only (surfaced in the agent's prompt); the harness stands
|
|
188
|
+
* nothing up for it. Absent when no involved peer is live.
|
|
189
|
+
*/
|
|
190
|
+
peerEnvironments?: Record<string, string>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Frontend UI-test infra (the self-contained `tester-ui` flow). The backend has already
|
|
194
|
+
* resolved every backend upstream to a concrete URL — the bound service's live ephemeral
|
|
195
|
+
* env URL for the service under test, `http://localhost:<wiremockPort>` for every mocked
|
|
196
|
+
* upstream — and handed them here as {@link env}. The harness installs, builds (injecting
|
|
197
|
+
* `env` at build time, or writing a `window.env` shim for runtime injection), stands
|
|
198
|
+
* WireMock up on {@link wiremockPort} seeded from {@link wiremockMappingsPath}, serves the
|
|
199
|
+
* built app on {@link servePort}, health-checks it, and tells the agent the serve URL.
|
|
200
|
+
*/
|
|
201
|
+
export interface FrontendInfraSpec {
|
|
202
|
+
kind: 'frontend';
|
|
203
|
+
/**
|
|
204
|
+
* The frontend app's subdirectory within the checkout (a monorepo frontend). Absent ⇒ the
|
|
205
|
+
* checkout root. When set, install/build/serve run there and `outputDir`/`wiremockMappingsPath`
|
|
206
|
+
* are resolved relative to it.
|
|
207
|
+
*/
|
|
208
|
+
directory?: string;
|
|
209
|
+
/** Package manager for install/build. Default `pnpm`. */
|
|
210
|
+
packageManager?: 'pnpm' | 'npm' | 'yarn';
|
|
211
|
+
/** Explicit install command, overriding the one derived from `packageManager`. */
|
|
212
|
+
install?: string;
|
|
213
|
+
/** package.json script that produces the built app. Default `build`. */
|
|
214
|
+
buildScript?: string;
|
|
215
|
+
/** The build's output directory, served in `static` mode. Default `dist`. */
|
|
216
|
+
outputDir?: string;
|
|
217
|
+
/** How the built app is served: static server of `outputDir`, or run `serveScript`. */
|
|
218
|
+
serveMode?: 'static' | 'command';
|
|
219
|
+
/** package.json script to run when `serveMode: 'command'` (e.g. `preview`). */
|
|
220
|
+
serveScript?: string;
|
|
221
|
+
/** The port the served app listens on inside the container. Default 4173. */
|
|
222
|
+
servePort?: number;
|
|
223
|
+
/** Build-time env vars vs a runtime `window.env` shim. Default `build`. */
|
|
224
|
+
envInjection?: 'build' | 'runtime';
|
|
225
|
+
/** Resolved backend upstream env vars (name → URL) to inject. Empty names filtered out. */
|
|
226
|
+
env?: Record<string, string>;
|
|
227
|
+
/** The WireMock mappings directory in the FE repo. Default `mocks/`. */
|
|
228
|
+
wiremockMappingsPath?: string;
|
|
229
|
+
/** The port WireMock listens on inside the container. Default 8089. */
|
|
230
|
+
wiremockPort?: number;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Coding mode (repo bootstrap): the divergent push of a bootstrap run. Instead of pushing
|
|
234
|
+
* a work branch on the cloned repo, the agent's result is force-pushed as a fresh
|
|
235
|
+
* single-commit history to a SEPARATE, pre-created target repository's default branch.
|
|
236
|
+
* Clone-and-adapt: `job.repo` is the reference architecture to clone + adapt, `target` is
|
|
237
|
+
* the new repo. From-scratch (`fromScratch`): start from an empty directory (the agent
|
|
238
|
+
* scaffolds), `job.repo` is unused as a clone source. Absent ⇒ the ordinary coding flow.
|
|
239
|
+
*/
|
|
240
|
+
export interface AgentBootstrapSpec {
|
|
241
|
+
/** The new repository the bootstrapped contents are pushed to (the push target). */
|
|
242
|
+
target: BootstrapTargetSpec;
|
|
243
|
+
/** Scaffold from an empty directory instead of cloning `job.repo` (no reference). */
|
|
244
|
+
fromScratch?: boolean;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* A linked-context file the backend prepared (requirements / RFC / PRD / tracker issue)
|
|
248
|
+
* for the harness to materialise under CONTEXT_DIR in the checkout, so the agent can read
|
|
249
|
+
* it on demand. The harness can't reach Jira/GitHub itself, so all such context is fetched
|
|
250
|
+
* and shipped here up front. `path` is sanitised to a safe basename on parse.
|
|
251
|
+
*/
|
|
252
|
+
export interface ContextFileSpec {
|
|
253
|
+
path: string;
|
|
254
|
+
title: string;
|
|
255
|
+
url: string;
|
|
256
|
+
content: string;
|
|
257
|
+
}
|
|
258
|
+
/** How an explore agent's reply is consumed. */
|
|
259
|
+
export interface AgentOutputSpec {
|
|
260
|
+
/** `prose` keeps the reply text; `structured` parses (and optionally repairs) it to JSON. */
|
|
261
|
+
kind: 'prose' | 'structured';
|
|
262
|
+
/** Compact shape description fed to the one-shot structured-output repair call. */
|
|
263
|
+
shapeHint?: string;
|
|
264
|
+
/** Whether to attempt the one-shot repair on a malformed reply (structured only). */
|
|
265
|
+
repair?: boolean;
|
|
266
|
+
/**
|
|
267
|
+
* Fail the run LOUDLY when the FINAL answer is unusable (cut off at the output ceiling,
|
|
268
|
+
* or empty) instead of repairing it — opt-in for kinds whose JSON deliverable is handed
|
|
269
|
+
* onward to be parsed/committed (e.g. the spec-writer). Absent ⇒ off.
|
|
270
|
+
*/
|
|
271
|
+
failOnUnusableFinal?: boolean;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* The generic agent job. `mode` selects the flow; the remaining fields are the union
|
|
275
|
+
* the flows need. Explore: clone `branch`, run read-only, return prose (or a parsed
|
|
276
|
+
* `custom` JSON object when `output.kind==='structured'`). Coding: clone `branch` (or
|
|
277
|
+
* resume `newBranch`), run, commit + push to `pushBranch`, and open `pr` when one is set
|
|
278
|
+
* and the run produced changes. Preview (local/node only): clone `branch`, build + serve
|
|
279
|
+
* the frontend (`infra.kind==='frontend'`) with its other upstreams mocked and KEEP IT
|
|
280
|
+
* RUNNING — no agent runs and the serve is deliberately not torn down when the job returns
|
|
281
|
+
* (see {@link AgentResult.preview}).
|
|
282
|
+
*/
|
|
283
|
+
/**
|
|
284
|
+
* Coding mode (Ralph loop): the programmatic completion criterion. After the coding agent
|
|
285
|
+
* commits + pushes, the harness runs {@link command} in the checkout and reports its exit
|
|
286
|
+
* code back on {@link AgentResult.ralphVerdict} — exit 0 means the loop is done. This is the
|
|
287
|
+
* whole point of a Ralph loop's exit condition being a REAL check: the harness runs it, not
|
|
288
|
+
* the model. The command runs only inside the sandboxed run container (same trust boundary
|
|
289
|
+
* as the coding agent). Absent for every non-`ralph` coding run.
|
|
290
|
+
*/
|
|
291
|
+
export interface ValidationSpec {
|
|
292
|
+
/** The shell command the harness runs against the checkout (exit 0 = the criterion is met). */
|
|
293
|
+
command: string;
|
|
294
|
+
/** Repo-relative progress-log path the agent maintains (informational; the harness doesn't write it). */
|
|
295
|
+
progressPath?: string;
|
|
296
|
+
/** 1-based iteration number, echoed back on the verdict for the engine's attempt log. */
|
|
297
|
+
iteration?: number;
|
|
298
|
+
}
|
|
299
|
+
export interface AgentJob extends HarnessAuthFields {
|
|
300
|
+
jobId: string;
|
|
301
|
+
/**
|
|
302
|
+
* The backend run this job belongs to, bound onto the per-job logger beside `jobId` and used
|
|
303
|
+
* for NOTHING else. The container is the far side of the platform's longest seam: the backend
|
|
304
|
+
* knows a run as `executionId` and the harness knew it only as `jobId`, so a container log line
|
|
305
|
+
* could not be joined to the run that dispatched it except through the
|
|
306
|
+
* `${executionId}-${agentKind}` job-id naming convention. Optional because a body predating the
|
|
307
|
+
* field (or a hand-rolled acceptance fixture) must still run — an absent id costs correlation,
|
|
308
|
+
* never the job.
|
|
309
|
+
*/
|
|
310
|
+
workspaceId?: string;
|
|
311
|
+
executionId?: string;
|
|
312
|
+
mode: AgentMode;
|
|
313
|
+
systemPrompt: string;
|
|
314
|
+
userPrompt: string;
|
|
315
|
+
model: string;
|
|
316
|
+
ghToken: string;
|
|
317
|
+
repo: RepoSpec;
|
|
318
|
+
/** The branch to clone (the backend resolves base/pr/work to a concrete name). */
|
|
319
|
+
branch: string;
|
|
320
|
+
githubApiBase?: string;
|
|
321
|
+
webToolsGuidance?: string;
|
|
322
|
+
webSearch?: boolean;
|
|
323
|
+
/** Full-history clone (needed to diff against / merge the base). Default shallow. */
|
|
324
|
+
full?: boolean;
|
|
325
|
+
/**
|
|
326
|
+
* Coding mode (conflict-resolver): merge `origin/<mergeBase>` into the cloned PR branch
|
|
327
|
+
* to surface the Git conflicts, run the agent to resolve them, then complete the merge
|
|
328
|
+
* commit and push back onto the SAME branch (no new branch / PR). Requires `full` so the
|
|
329
|
+
* merge base + `origin/<mergeBase>` are present. Absent ⇒ the ordinary coding flow.
|
|
330
|
+
*/
|
|
331
|
+
mergeBase?: string;
|
|
332
|
+
/**
|
|
333
|
+
* Coding mode (repo bootstrap): force-push the agent's output as a fresh single-commit
|
|
334
|
+
* history to a separate, pre-created target repo (clone + adapt `repo`, or scaffold from
|
|
335
|
+
* scratch). Absent ⇒ the ordinary clone-edit-push-on-the-same-repo coding flow.
|
|
336
|
+
*/
|
|
337
|
+
bootstrap?: AgentBootstrapSpec;
|
|
338
|
+
/** Explore mode: how to consume the reply. Absent ⇒ prose. */
|
|
339
|
+
output?: AgentOutputSpec;
|
|
340
|
+
/**
|
|
341
|
+
* Linked-context files to materialise under CONTEXT_DIR before the run (both modes).
|
|
342
|
+
* The agent reads them on demand; they are kept out of any commit. Absent ⇒ none.
|
|
343
|
+
*/
|
|
344
|
+
contextFiles?: ContextFileSpec[];
|
|
345
|
+
/**
|
|
346
|
+
* Private package-registry auth (npm private orgs, GitHub Packages), rendered into
|
|
347
|
+
* `~/.npmrc` before the run so the checkout's installs — the agent's own and the
|
|
348
|
+
* frontend-infra stand-up's — resolve private dependencies. Hosts are hard-allowlisted
|
|
349
|
+
* (see {@link allowedNpmRegistryHosts}). Absent ⇒ any stale `~/.npmrc` from a prior
|
|
350
|
+
* job on a reused container is removed.
|
|
351
|
+
*/
|
|
352
|
+
packageRegistries?: PackageRegistrySpec[];
|
|
353
|
+
/**
|
|
354
|
+
* The skills to make available for this run (see {@link SkillSpec}) — a `skill` step's picked
|
|
355
|
+
* skill and/or the playbooks the running agent kind declares. Materialised harness-aware before
|
|
356
|
+
* the run: natively into `CLAUDE_CONFIG_DIR/skills/<name>/` for claude-code, or
|
|
357
|
+
* `.cat-context/skill/<name>/<relPath>` for Pi/codex. Absent ⇒ no skills installed.
|
|
358
|
+
*/
|
|
359
|
+
skills?: SkillSpec[];
|
|
360
|
+
/**
|
|
361
|
+
* Tool servers (MCP) to wire into the agent CLI for this run (see {@link McpServerSpec}). The
|
|
362
|
+
* backend has already dropped anything this harness cannot serve, so every entry here is
|
|
363
|
+
* expected to work. SECRET-BEARING (`env`/`headers` carry resolved credentials), so the config
|
|
364
|
+
* files written from it live outside the checkout and are never logged. Absent ⇒ the CLI's
|
|
365
|
+
* built-in tools only.
|
|
366
|
+
*/
|
|
367
|
+
mcpServers?: McpServerSpec[];
|
|
368
|
+
/**
|
|
369
|
+
* Tester kinds only: sensitive test credentials injected into the run's ENVIRONMENT (out of
|
|
370
|
+
* band) as `{ key, value }` env pairs, so the tester's shell can read `$KEY` without the value
|
|
371
|
+
* ever appearing in the prompt or telemetry. Reserved/toolchain env names are dropped at parse.
|
|
372
|
+
* Absent ⇒ no secrets injected.
|
|
373
|
+
*/
|
|
374
|
+
testSecrets?: TestSecretSpec[];
|
|
375
|
+
/**
|
|
376
|
+
* Explore mode: stand the service's dependencies up before the agent runs (the
|
|
377
|
+
* tester). Brings the docker-compose infra up on localhost for the duration of the
|
|
378
|
+
* run and tears it down afterward; a stand-up failure is non-fatal (surfaced to the
|
|
379
|
+
* agent as a note). The agent makes no commits regardless. Absent ⇒ no infra managed.
|
|
380
|
+
*
|
|
381
|
+
* Preview mode: REQUIRED and must be the `frontend` variant — it is the whole job (build
|
|
382
|
+
* + serve + WireMock, kept alive). No agent runs and, unlike the tester, the stand-up is
|
|
383
|
+
* NOT torn down when the job returns.
|
|
384
|
+
*/
|
|
385
|
+
infra?: AgentInfraSpec;
|
|
386
|
+
/** Coding mode: a fresh branch to create off the clone before running (else work on `branch`). */
|
|
387
|
+
newBranch?: string;
|
|
388
|
+
/** Coding mode: branch the produced change is pushed to (defaults to `newBranch ?? branch`). */
|
|
389
|
+
pushBranch?: string;
|
|
390
|
+
/** Coding mode: commit message for any work the agent left uncommitted. */
|
|
391
|
+
commitMessage?: string;
|
|
392
|
+
/** Coding mode: open this PR when the run pushed changes. Absent ⇒ push only, no PR. */
|
|
393
|
+
pr?: PrSpec;
|
|
394
|
+
/**
|
|
395
|
+
* Coding mode (implementer): connected services' repos to clone as SIBLINGS for a MULTI-REPO
|
|
396
|
+
* change (service-connections phase 3). When present, the agent works with its cwd at the
|
|
397
|
+
* workspace ROOT (all repos are sibling checkouts under it), and the harness opens one PR per
|
|
398
|
+
* peer repo it actually changed — in addition to the primary. Absent ⇒ single-repo run.
|
|
399
|
+
*/
|
|
400
|
+
peerRepos?: PeerRepoSpec[];
|
|
401
|
+
/**
|
|
402
|
+
* Coding mode (doc-writer): repositories to clone READ-ONLY as SIBLINGS for the agent to
|
|
403
|
+
* reference while it drafts the document. When present the agent works at the workspace ROOT
|
|
404
|
+
* (all checkouts are siblings under it); the harness clones each reference at its own base
|
|
405
|
+
* branch and NEVER creates a branch, commits, or opens a PR for it. Only the primary is
|
|
406
|
+
* pushed. Absent ⇒ single-repo run. Independent of {@link peerRepos} (those are writable).
|
|
407
|
+
*/
|
|
408
|
+
referenceRepos?: ReferenceRepoSpec[];
|
|
409
|
+
/**
|
|
410
|
+
* Pre-existing branch names of the PRIMARY repo attached to the task as READ-ONLY reference
|
|
411
|
+
* points (the apriori-branches reference mode). After the primary checkout the harness fetches
|
|
412
|
+
* each into its `origin/<b>` tracking ref (best-effort per branch) so the agent can inspect it —
|
|
413
|
+
* `git log origin/<b>`, two-dot `git diff origin/<b>`, `git show origin/<b>:<path>` — but never
|
|
414
|
+
* commits to or pushes it (that guarantee lives in the prompt guidance, not a git constraint).
|
|
415
|
+
* Distinct from {@link referenceRepos}: those are separate sibling repos; these are branches of
|
|
416
|
+
* the same primary repo. Absent ⇒ none. Consumed by the coding + explore flows.
|
|
417
|
+
*/
|
|
418
|
+
referenceBranches?: string[];
|
|
419
|
+
/**
|
|
420
|
+
* Explore mode (the `pr-reviewer`): the reviewed PR/MR number. Present ⇒ after the base
|
|
421
|
+
* checkout the harness fetches that PR's HEAD into `origin/pr-head` (best-effort) so the
|
|
422
|
+
* read-only reviewer can diff/read the PROPOSED code — files the PR adds are otherwise absent
|
|
423
|
+
* from the base checkout, and the agent has no git credential to fetch the head itself. The
|
|
424
|
+
* GitHub-vs-GitLab pull ref is chosen from `repo.provider` (host-inferred when absent). Absent
|
|
425
|
+
* ⇒ no head fetch (every non-review run). See {@link file://./git.ts} `fetchPullRequestHead`.
|
|
426
|
+
*/
|
|
427
|
+
reviewPrNumber?: number;
|
|
428
|
+
/**
|
|
429
|
+
* Coding mode: whether a no-op run (nothing changed) is a failure. The implementer
|
|
430
|
+
* fails on a no-op; the in-place fixers (ci-fix / fix-tests) treat it as a non-fatal
|
|
431
|
+
* no-op. Default true.
|
|
432
|
+
*/
|
|
433
|
+
noChangesIsError?: boolean;
|
|
434
|
+
/**
|
|
435
|
+
* Reuse a STABLE per-repo checkout (clean-sweep + fetch + switch branch) instead of a
|
|
436
|
+
* fresh clone into a throwaway temp dir. Set ONLY by the local warm-pool transport,
|
|
437
|
+
* whose containers are reused across runs; absent everywhere else, so every other
|
|
438
|
+
* runtime keeps the ephemeral fresh-clone behaviour. The explore + ordinary coding
|
|
439
|
+
* flows honour it; bootstrap (resets `.git`) and conflict-resolution (needs full
|
|
440
|
+
* multi-branch state) always run ephemeral regardless.
|
|
441
|
+
*/
|
|
442
|
+
persistentCheckout?: boolean;
|
|
443
|
+
/**
|
|
444
|
+
* Coding mode (implementer): tail the Coder's follow-up sentinel file and stream the
|
|
445
|
+
* forward-looking items it surfaces (loose ends / side-tasks / questions) out on the job
|
|
446
|
+
* view, so the backend lifts them onto the run's step (the Follow-up companion). Set only
|
|
447
|
+
* for the `coder` dispatch when the companion is enabled. Absent ⇒ no follow-up streaming.
|
|
448
|
+
*/
|
|
449
|
+
streamFollowUps?: boolean;
|
|
450
|
+
/**
|
|
451
|
+
* Per-job overrides for the anti-rabbithole progress guard, set by the backend per
|
|
452
|
+
* AGENT KIND (a read-heavy kind tolerates more web/exploration before it counts as a
|
|
453
|
+
* stall). Each knob is optional and falls back to the env / built-in default
|
|
454
|
+
* ({@link progressGuardLimitsFromEnv}); only the knobs present here override. These are
|
|
455
|
+
* loosen-only: `mergeGuardLimits` clamps each override up to the base, so a value
|
|
456
|
+
* tighter than the default is ignored and a legitimately-progressing run is never
|
|
457
|
+
* killed for a kind's normal working pattern. Absent ⇒ env/default for all knobs.
|
|
458
|
+
*/
|
|
459
|
+
guardLimits?: GuardLimitsSpec;
|
|
460
|
+
/**
|
|
461
|
+
* Coding mode (Ralph loop): the programmatic completion command the harness runs after the
|
|
462
|
+
* agent commits + pushes. Present only for a `ralph` iteration. See {@link ValidationSpec}.
|
|
463
|
+
*/
|
|
464
|
+
validation?: ValidationSpec;
|
|
465
|
+
/**
|
|
466
|
+
* Coding mode: the service's PRE-PR VALIDATION CHECKS — commands the harness runs against the
|
|
467
|
+
* checkout after the agent settles and BEFORE opening a PR, feeding a failure back to the agent
|
|
468
|
+
* until they pass or the budget is spent. Present only on a dispatch that opens a PR and whose
|
|
469
|
+
* service configured checks; absent ⇒ the run behaves exactly as before. Deliberately keyed off
|
|
470
|
+
* job DATA, not the agent kind. See {@link ValidationChecksSpec}.
|
|
471
|
+
*/
|
|
472
|
+
validationChecks?: ValidationChecksSpec;
|
|
473
|
+
/**
|
|
474
|
+
* Coding mode: the run's BUGFIX REPRODUCTION PROOF — the declared reproduction command, the
|
|
475
|
+
* test file(s) that constitute it, and an optional setup command. When set, the harness runs
|
|
476
|
+
* that command against the pre-fix tree AND the tree the PR will open from, and reports both
|
|
477
|
+
* exit codes: only red-then-green is proof. Present only on a dispatch that opens a PR and
|
|
478
|
+
* whose run carries a reproduction declaration; absent ⇒ the run behaves exactly as before.
|
|
479
|
+
* Deliberately keyed off job DATA, not the agent kind. See
|
|
480
|
+
* `docs/initiatives/bugfix-reproduction-proof.md`.
|
|
481
|
+
*/
|
|
482
|
+
reproduction?: ReproductionSpec;
|
|
483
|
+
/**
|
|
484
|
+
* DEPENDENCY PREPOPULATION: the service's install command, run against the checkout BEFORE the
|
|
485
|
+
* agent's first turn so it reads a tree whose dependencies are present rather than inferring
|
|
486
|
+
* them from a manifest. Applies to EVERY mode that gets a checkout (explore as well as coding)
|
|
487
|
+
* — unlike {@link validationChecks}, which is a pre-PR gate — because an agent reading or
|
|
488
|
+
* reviewing a tree needs its dependencies as much as one changing it.
|
|
489
|
+
*
|
|
490
|
+
* Best-effort: a failure becomes a note in the agent's prompt, never a failed job. Absent ⇒ the
|
|
491
|
+
* run behaves exactly as before. Deliberately keyed off job DATA, not the agent kind. See
|
|
492
|
+
* `docs/initiatives/agent-dependency-prepopulation.md`.
|
|
493
|
+
*/
|
|
494
|
+
dependencyInstall?: DependencyInstallSpec;
|
|
495
|
+
}
|
|
496
|
+
/** Per-job, per-knob progress-guard overrides (see {@link AgentJob.guardLimits}). */
|
|
497
|
+
export interface GuardLimitsSpec {
|
|
498
|
+
maxToolCallsWithoutEdit?: number;
|
|
499
|
+
maxConsecutiveErrors?: number;
|
|
500
|
+
maxConsecutiveWebCalls?: number;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* The record of standing the service's docker-compose dependencies up before a tester
|
|
504
|
+
* run (explore mode, `infra.environment === 'local'`). The compose stand-up happens
|
|
505
|
+
* INSIDE the container, so its output never reaches the orchestrator's provisioning-log
|
|
506
|
+
* store (which records only the backend-side container/env spin-up); this carries the
|
|
507
|
+
* captured (redacted + bounded) command output back structurally so the test window can
|
|
508
|
+
* show WHY the dependencies failed to come up — previously this was trapped in the
|
|
509
|
+
* harness's own logs. Absent for ephemeral / no-infra / no-compose-path runs.
|
|
510
|
+
*/
|
|
511
|
+
export interface InfraSetupRecord {
|
|
512
|
+
/** Whether `docker compose up --wait` succeeded (the dependencies are up). */
|
|
513
|
+
started: boolean;
|
|
514
|
+
/** The repo-relative compose file that was stood up. */
|
|
515
|
+
composePath?: string;
|
|
516
|
+
/** Epoch ms the stand-up attempt finished. */
|
|
517
|
+
at: number;
|
|
518
|
+
/** Wall-clock of the stand-up attempt, ms. */
|
|
519
|
+
durationMs?: number;
|
|
520
|
+
/** Captured (redacted, tail-bounded) stdout+stderr of the stand-up command. */
|
|
521
|
+
logs?: string;
|
|
522
|
+
/** The verbatim (redacted) failure message when stand-up failed, else absent. */
|
|
523
|
+
error?: string;
|
|
524
|
+
}
|
|
525
|
+
/** The generic agent response. `custom` carries a structured explore result. */
|
|
526
|
+
export interface AgentResult {
|
|
527
|
+
summary?: string;
|
|
528
|
+
stats?: PiRunStats;
|
|
529
|
+
/** Structured explore output (the parsed JSON object) when `output.kind==='structured'`. */
|
|
530
|
+
custom?: unknown;
|
|
531
|
+
/**
|
|
532
|
+
* The tester's docker-compose stand-up record (explore mode, local infra). Carried back
|
|
533
|
+
* so the backend can surface the in-container dependency stand-up logs on the Tester step
|
|
534
|
+
* — the failure-class artifact the orchestrator-side provisioning logs can't capture.
|
|
535
|
+
*/
|
|
536
|
+
infraSetup?: InfraSetupRecord;
|
|
537
|
+
/**
|
|
538
|
+
* The PRE-PR VALIDATION report: the outcome of running the service's configured check commands
|
|
539
|
+
* against the checkout after the agent settled and before opening a PR, plus how many repair
|
|
540
|
+
* rounds the harness spent. Present on BOTH outcomes — a passing report accompanies the opened
|
|
541
|
+
* PR (the captured proof), and a failing one accompanies the run's `error` (no PR was opened).
|
|
542
|
+
* Absent when the job carried no {@link AgentJob.validationChecks}.
|
|
543
|
+
*/
|
|
544
|
+
validationReport?: ValidationReport;
|
|
545
|
+
/**
|
|
546
|
+
* The BUGFIX REPRODUCTION PROOF: the declared reproduction command's verdict across the pre-fix
|
|
547
|
+
* tree and the final tree, computed by the harness from exit codes. Present on every outcome of
|
|
548
|
+
* a job that carried {@link AgentJob.reproduction} — a verdict is evidence, not a gate, so an
|
|
549
|
+
* `inconclusive` one accompanies the opened PR exactly like a `reproduced` one does. Absent
|
|
550
|
+
* when the job carried no reproduction declaration.
|
|
551
|
+
*/
|
|
552
|
+
reproductionReport?: ReproductionReport;
|
|
553
|
+
/**
|
|
554
|
+
* Preview mode: the in-container URL the built app is served at (e.g. `http://localhost:4173`).
|
|
555
|
+
* This is NOT host-reachable on its own — the container runtime publishes the serve port to an
|
|
556
|
+
* ephemeral host port and the backend forms the browsable URL from that; this is echoed for
|
|
557
|
+
* logging/context. Present only on a successful preview stand-up.
|
|
558
|
+
*/
|
|
559
|
+
preview?: {
|
|
560
|
+
url: string;
|
|
561
|
+
};
|
|
562
|
+
/** Coding mode: whether a change was pushed. */
|
|
563
|
+
pushed?: boolean;
|
|
564
|
+
prUrl?: string;
|
|
565
|
+
branch?: string;
|
|
566
|
+
/**
|
|
567
|
+
* Coding mode (Ralph loop): the harness-computed verdict of the post-commit validation
|
|
568
|
+
* command — whether it exited 0, its exit code, and a bounded, redacted output tail. The
|
|
569
|
+
* engine reads this (never a model self-report) to decide whether the loop is done or must
|
|
570
|
+
* iterate again. Present only for a `ralph` iteration ({@link AgentJob.validation} set).
|
|
571
|
+
*/
|
|
572
|
+
ralphVerdict?: {
|
|
573
|
+
validationPassed: boolean;
|
|
574
|
+
exitCode: number;
|
|
575
|
+
validationOutputTail?: string;
|
|
576
|
+
iteration?: number;
|
|
577
|
+
/**
|
|
578
|
+
* The work-branch HEAD the command was judged against. The engine compares it across
|
|
579
|
+
* consecutive failing iterations to end a loop that has stopped committing anything,
|
|
580
|
+
* instead of spending the rest of its budget re-learning that. Absent when unreadable.
|
|
581
|
+
*/
|
|
582
|
+
headSha?: string;
|
|
583
|
+
};
|
|
584
|
+
/**
|
|
585
|
+
* Coding mode (multi-repo): the PRs opened in the connected services' PEER repos, one per
|
|
586
|
+
* repo the run actually changed (service-connections phase 3). Beside the own-service
|
|
587
|
+
* `prUrl`/`branch`; the backend lifts these onto the block's `peerPullRequests`. Absent for
|
|
588
|
+
* a single-repo run.
|
|
589
|
+
*/
|
|
590
|
+
peerPullRequests?: {
|
|
591
|
+
repo: string;
|
|
592
|
+
frameId?: string;
|
|
593
|
+
prUrl: string;
|
|
594
|
+
branch: string;
|
|
595
|
+
}[];
|
|
596
|
+
/** Coding mode (bootstrap): the default branch the bootstrapped contents were pushed to. */
|
|
597
|
+
defaultBranch?: string;
|
|
598
|
+
error?: string;
|
|
599
|
+
/**
|
|
600
|
+
* The structured failure cause set alongside `error` on a clean-exit failure (no usable
|
|
601
|
+
* output, no changes to push, unresolved conflicts, …). The job registry copies it onto
|
|
602
|
+
* the job view so the backend classifies the failure without regex. See {@link FailureCause}.
|
|
603
|
+
*/
|
|
604
|
+
failureCause?: FailureCause;
|
|
605
|
+
usage?: {
|
|
606
|
+
inputTokens: number;
|
|
607
|
+
outputTokens: number;
|
|
608
|
+
};
|
|
609
|
+
/**
|
|
610
|
+
* Per-model-call telemetry from a subscription harness's CLI stream (absent for the
|
|
611
|
+
* proxy-metered Pi harness). The backend records these into `llm_call_metrics`. See
|
|
612
|
+
* {@link HarnessCallMetric}.
|
|
613
|
+
*/
|
|
614
|
+
callMetrics?: HarnessCallMetric[];
|
|
615
|
+
/**
|
|
616
|
+
* The agent's effort self-assessment (how hard the work was, what reduced its effectiveness,
|
|
617
|
+
* the key obstacles), lifted from its sentinel file after the run. The backend forwards it onto
|
|
618
|
+
* the job result and records it on the step for run details. Absent when the agent wrote none.
|
|
619
|
+
*/
|
|
620
|
+
effortReport?: EffortReport;
|
|
621
|
+
}
|
|
622
|
+
/** The one-shot inline completion job. `harness` must be a subscription harness. */
|
|
623
|
+
export interface InlineJob extends HarnessAuthFields {
|
|
624
|
+
jobId: string;
|
|
625
|
+
/** Real vendor model id, e.g. `claude-opus-4-8` / `gpt-5.5-codex`. */
|
|
626
|
+
model: string;
|
|
627
|
+
/** Composed role + best-practice fragments (Claude: `--append-system-prompt`; Codex: prepended). */
|
|
628
|
+
systemPrompt: string;
|
|
629
|
+
/** The concrete task/user prompt fed to the CLI over stdin. */
|
|
630
|
+
userPrompt: string;
|
|
631
|
+
/** Advisory output cap, forwarded for parity; the one-shot CLIs don't all honour it. */
|
|
632
|
+
maxOutputTokens?: number;
|
|
633
|
+
}
|
|
634
|
+
/** The inline completion result: the reply text plus lifted token usage / per-call telemetry. */
|
|
635
|
+
export interface InlineResult {
|
|
636
|
+
text: string;
|
|
637
|
+
/** `length` when the model hit its output cap (the reviewer rejects a truncated doc). */
|
|
638
|
+
finishReason?: 'stop' | 'length';
|
|
639
|
+
/**
|
|
640
|
+
* The job's token usage with the input side split into its three ORTHOGONAL classes:
|
|
641
|
+
* `inputTokens` is FRESH input only, so the total input is
|
|
642
|
+
* `inputTokens + cacheReadTokens + cacheWriteTokens`. Folded from the per-call metrics below,
|
|
643
|
+
* which is the only channel that knows the split; a CLI that streamed none falls back to the
|
|
644
|
+
* coarse total with both cache classes 0 — honest, since on that shape nothing is known to
|
|
645
|
+
* have been cached.
|
|
646
|
+
*/
|
|
647
|
+
usage?: {
|
|
648
|
+
inputTokens: number;
|
|
649
|
+
cacheReadTokens: number;
|
|
650
|
+
cacheWriteTokens: number;
|
|
651
|
+
outputTokens: number;
|
|
652
|
+
};
|
|
653
|
+
/** Per-model-call telemetry lifted from the CLI stream (recorded into `llm_call_metrics`). */
|
|
654
|
+
callMetrics?: HarnessCallMetric[];
|
|
655
|
+
/** A structured failure marks a job-level failure even on a clean HTTP exit (see JobResultBase). */
|
|
656
|
+
error?: string;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Validate + narrow an untrusted body into an {@link InlineJob}. The harness MUST be a
|
|
660
|
+
* subscription harness (`claude-code` / `codex`) — the inline path never runs Pi (that goes
|
|
661
|
+
* through the LLM proxy inline, not a container CLI). Reuses {@link parseHarnessAuth}, so a
|
|
662
|
+
* non-ambient job requires `subscriptionToken`.
|
|
663
|
+
*/
|
|
664
|
+
export declare function parseInlineJob(input: unknown): InlineJob;
|
|
665
|
+
/** Validate + narrow an untrusted body into an {@link AgentJob}, throwing on bad input. */
|
|
666
|
+
export declare function parseAgentJob(input: unknown): AgentJob;
|