@obversa/runtime 0.1.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 +21 -0
- package/README.md +192 -0
- package/dist/api.d.ts +72 -0
- package/dist/api.js +9775 -0
- package/dist/api.js.map +1 -0
- package/dist/artifacts/conformance.d.ts +1 -0
- package/dist/artifacts/file-store.d.ts +8 -0
- package/dist/artifacts/store.d.ts +1 -0
- package/dist/callback/approval.d.ts +8 -0
- package/dist/callback/client.d.ts +38 -0
- package/dist/callback/gate.d.ts +1 -0
- package/dist/callback/stored-client.d.ts +5 -0
- package/dist/chunk-3L6YNPN6.js +3 -0
- package/dist/chunk-3L6YNPN6.js.map +1 -0
- package/dist/chunk-5GLEABOU.js +3 -0
- package/dist/chunk-5GLEABOU.js.map +1 -0
- package/dist/chunk-DEW5R23M.js +338 -0
- package/dist/chunk-DEW5R23M.js.map +1 -0
- package/dist/chunk-DV5P4QLI.js +3056 -0
- package/dist/chunk-DV5P4QLI.js.map +1 -0
- package/dist/chunk-NIBHM5I5.js +34 -0
- package/dist/chunk-NIBHM5I5.js.map +1 -0
- package/dist/chunk-RZLMX3IA.js +368 -0
- package/dist/chunk-RZLMX3IA.js.map +1 -0
- package/dist/core/agent-md.d.ts +36 -0
- package/dist/core/agent.d.ts +86 -0
- package/dist/core/approval-job.d.ts +43 -0
- package/dist/core/assert-graph.d.ts +34 -0
- package/dist/core/budget.d.ts +49 -0
- package/dist/core/concurrency.d.ts +2 -0
- package/dist/core/condition.d.ts +209 -0
- package/dist/core/context.d.ts +36 -0
- package/dist/core/cost.d.ts +59 -0
- package/dist/core/dag.d.ts +20 -0
- package/dist/core/decision.d.ts +29 -0
- package/dist/core/describe.d.ts +56 -0
- package/dist/core/engine-meta.d.ts +5 -0
- package/dist/core/env-overlay.d.ts +35 -0
- package/dist/core/errors.d.ts +46 -0
- package/dist/core/feedback.d.ts +68 -0
- package/dist/core/git.d.ts +152 -0
- package/dist/core/guards.d.ts +70 -0
- package/dist/core/isolated.d.ts +40 -0
- package/dist/core/job.d.ts +134 -0
- package/dist/core/limits.d.ts +22 -0
- package/dist/core/loop.d.ts +24 -0
- package/dist/core/merge.d.ts +30 -0
- package/dist/core/pipeline.d.ts +35 -0
- package/dist/core/process.d.ts +11 -0
- package/dist/core/progress.d.ts +82 -0
- package/dist/core/redact.d.ts +1 -0
- package/dist/core/stats.d.ts +63 -0
- package/dist/core/team.d.ts +34 -0
- package/dist/core/text.d.ts +8 -0
- package/dist/core/tournament.d.ts +25 -0
- package/dist/core/types.d.ts +650 -0
- package/dist/engines/command-runner.d.ts +1 -0
- package/dist/engines/conformance.d.ts +1 -0
- package/dist/engines/engine.d.ts +4 -0
- package/dist/engines/failure.d.ts +1 -0
- package/dist/engines/fallback.d.ts +35 -0
- package/dist/engines/message-map.d.ts +1 -0
- package/dist/engines/mock.d.ts +1 -0
- package/dist/engines/preflight.d.ts +36 -0
- package/dist/env/command.d.ts +50 -0
- package/dist/env/command.js +65 -0
- package/dist/env/command.js.map +1 -0
- package/dist/env/environment.d.ts +4 -0
- package/dist/env/mock.d.ts +24 -0
- package/dist/events/conformance.d.ts +1 -0
- package/dist/events/envelope.d.ts +1 -0
- package/dist/events/jsonl-store.d.ts +8 -0
- package/dist/events/store.d.ts +1 -0
- package/dist/graph/commands.d.ts +5 -0
- package/dist/graph/conformance.d.ts +32 -0
- package/dist/graph/kernel.d.ts +5 -0
- package/dist/graph/plan.d.ts +1 -0
- package/dist/graph/type.d.ts +7 -0
- package/dist/graph/value.d.ts +1 -0
- package/dist/graph-types/dag.d.ts +137 -0
- package/dist/graph-types/loop.d.ts +194 -0
- package/dist/graph-types/team.d.ts +68 -0
- package/dist/memory.d.ts +82 -0
- package/dist/memory.js +397 -0
- package/dist/memory.js.map +1 -0
- package/dist/proof/acceptance.d.ts +5 -0
- package/dist/proof/artifact.d.ts +6 -0
- package/dist/proof/cache.d.ts +4 -0
- package/dist/runtime/attempt.d.ts +19 -0
- package/dist/runtime/budget.d.ts +4 -0
- package/dist/runtime/engine-availability.d.ts +18 -0
- package/dist/runtime/graph-executor.d.ts +7 -0
- package/dist/runtime/monitor.d.ts +80 -0
- package/dist/runtime/node-lifecycle.d.ts +84 -0
- package/dist/runtime/paths.d.ts +2 -0
- package/dist/runtime/persist.d.ts +31 -0
- package/dist/runtime/preflight-record.d.ts +149 -0
- package/dist/runtime/process-tree.d.ts +1 -0
- package/dist/runtime/result-contract.d.ts +4 -0
- package/dist/runtime/result-parts.d.ts +1 -0
- package/dist/runtime/run-definition.d.ts +24 -0
- package/dist/runtime/run-event.d.ts +9 -0
- package/dist/runtime/runner.d.ts +139 -0
- package/dist/runtime/supervisor.d.ts +111 -0
- package/dist/runtime/team-rooms.d.ts +13 -0
- package/dist/runtime/workspace-policy.d.ts +25 -0
- package/dist/storage/error.d.ts +1 -0
- package/dist/storage/id.d.ts +1 -0
- package/dist/storage/local.d.ts +12 -0
- package/dist/storage/local.js +1492 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/testing.d.ts +15 -0
- package/dist/testing.js +274 -0
- package/dist/testing.js.map +1 -0
- package/dist/workflow-agent-response.d.ts +3 -0
- package/dist/workflow-support.d.ts +36 -0
- package/dist/workflow-support.js +5 -0
- package/dist/workflow-support.js.map +1 -0
- package/dist/workflow.d.ts +73 -0
- package/dist/workspace/conformance.d.ts +1 -0
- package/dist/workspace/git-provider.d.ts +26 -0
- package/dist/workspace/provider.d.ts +2 -0
- package/package.json +91 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assertGraph(job, shape)` — turn `jobMeta` introspection into test
|
|
3
|
+
* assertions. The shape is a PARTIAL expectation: only asserted fields are
|
|
4
|
+
* compared, and extra actual nodes are allowed unless `exactNodes: true`.
|
|
5
|
+
* On mismatch it throws a plain `Error` whose message carries the JSON path
|
|
6
|
+
* to the mismatch (e.g. `nodes[build].needs`) plus expected vs actual — the
|
|
7
|
+
* message IS the API (vitest surfaces it verbatim).
|
|
8
|
+
*/
|
|
9
|
+
import type { Job, JobMeta } from './types.js';
|
|
10
|
+
export interface GraphNodeShape {
|
|
11
|
+
name: string;
|
|
12
|
+
needs?: string | string[];
|
|
13
|
+
desc?: string;
|
|
14
|
+
gate?: string;
|
|
15
|
+
optional?: boolean;
|
|
16
|
+
/** A boolean meaning "a `when` gate exists" — the meta stores condition
|
|
17
|
+
* labels, so this is a presence check, not label equality. */
|
|
18
|
+
when?: boolean;
|
|
19
|
+
isolate?: boolean;
|
|
20
|
+
/** Asserted against the node's nested job meta (`node.job.kind`). */
|
|
21
|
+
kind?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface GraphShape {
|
|
24
|
+
kind?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
nodes?: GraphNodeShape[];
|
|
27
|
+
/** Fail when the actual node set has names beyond `nodes`. */
|
|
28
|
+
exactNodes?: boolean;
|
|
29
|
+
body?: GraphShape;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** Assert a job's introspected shape matches a partial expectation. Accepts the
|
|
33
|
+
* `Job` itself (resolved via `jobMeta`) or a `JobMeta` directly. */
|
|
34
|
+
export declare function assertGraph(job: Job | JobMeta, shape: GraphShape): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A token-denominated budget for a whole run, threaded through the JobContext so
|
|
3
|
+
* every engine call site can refuse to spend past the cap. Where `max` and depth
|
|
4
|
+
* bound the count of calls, this bounds their cost.
|
|
5
|
+
*
|
|
6
|
+
* The runner feeds `add()` from each `engine:usage` event, so `spent()` is live.
|
|
7
|
+
* `assertBudget(ctx)` runs before an engine call; once the cap is reached it
|
|
8
|
+
* throws a non-retryable BUDGET error (hard mode, terminates the run) or logs
|
|
9
|
+
* and continues (soft mode, for exploratory runs).
|
|
10
|
+
*/
|
|
11
|
+
import type { UsageReceipt } from '../engines/engine.js';
|
|
12
|
+
interface BudgetContext {
|
|
13
|
+
readonly budget?: Budget;
|
|
14
|
+
log(message: string, level?: 'debug' | 'info' | 'warn' | 'error'): void;
|
|
15
|
+
}
|
|
16
|
+
export interface BudgetConfig {
|
|
17
|
+
/** Cap on total tokens (input + output) for the whole run. */
|
|
18
|
+
limit: number;
|
|
19
|
+
/**
|
|
20
|
+
* Refuse a new engine call once `spent + headroom >= limit`, i.e. stop with
|
|
21
|
+
* room to spare rather than only after the cap is already blown. Default 0.
|
|
22
|
+
*/
|
|
23
|
+
headroom?: number;
|
|
24
|
+
/** Warn and continue instead of refusing when the cap is hit. Default false. */
|
|
25
|
+
soft?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare class Budget {
|
|
28
|
+
readonly limit: number;
|
|
29
|
+
readonly headroom: number;
|
|
30
|
+
readonly soft: boolean;
|
|
31
|
+
private tokens;
|
|
32
|
+
private unknownCalls;
|
|
33
|
+
constructor(config: BudgetConfig);
|
|
34
|
+
/** Record consumed tokens. Non-finite or non-positive values are ignored. */
|
|
35
|
+
add(tokens: number): void;
|
|
36
|
+
addUsage(usage: UsageReceipt): void;
|
|
37
|
+
unknownUsageCalls(): number;
|
|
38
|
+
spent(): number;
|
|
39
|
+
remaining(): number;
|
|
40
|
+
/** True once the next call would breach the cap (accounting for headroom). */
|
|
41
|
+
exceeded(): boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Guard an engine call against the run budget. No-op when no budget is set or
|
|
45
|
+
* the cap is not yet reached. In `soft` mode a breach warns and continues; in
|
|
46
|
+
* hard mode it throws a non-retryable BUDGET error that terminates the run.
|
|
47
|
+
*/
|
|
48
|
+
export declare function assertBudget(ctx: BudgetContext): void;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditions answer a yes/no question against the run context and the latest
|
|
3
|
+
* body outcome. They power a loop's `start`, `until`, and `stopOn` gates.
|
|
4
|
+
*
|
|
5
|
+
* Two flavours, same type:
|
|
6
|
+
* - deterministic (`predicate`, `bodyPassed`, `maxConfidence`)
|
|
7
|
+
* - agent-validated (`agentCheck`): a model returns a verdict + confidence,
|
|
8
|
+
* and the gate opens only above a threshold.
|
|
9
|
+
*
|
|
10
|
+
* `gateJob` lifts any Condition into a `Job`, so a reviewer can be expressed
|
|
11
|
+
* as a condition and still slot into `loop({ review })`.
|
|
12
|
+
*/
|
|
13
|
+
import type { Condition, ConditionInput, Outcome, Job, JobContext } from './types.js';
|
|
14
|
+
import type { EngineRef } from '../engines/engine.js';
|
|
15
|
+
import { type AgentDef } from './agent.js';
|
|
16
|
+
/**
|
|
17
|
+
* Coerce any `ConditionInput` — a `Condition`, a bare predicate, or an array
|
|
18
|
+
* mixing both — into the single `Condition` primitive. This is what lets
|
|
19
|
+
* `until`/`start`/`stopOn` accept one or many items of either flavour.
|
|
20
|
+
*
|
|
21
|
+
* Arrays default to `all` (every item must hold); pass `'any'` for or-semantics.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toCondition(input: ConditionInput, combine?: 'all' | 'any'): Condition;
|
|
24
|
+
type ConditionPreparation = (ctx: JobContext) => Condition | Promise<Condition>;
|
|
25
|
+
/** Internal lifecycle hook for conditions that need state from loop entry. */
|
|
26
|
+
export declare function withConditionPreparation(condition: Condition, prepare: ConditionPreparation): Condition;
|
|
27
|
+
/** Prepare a condition tree once for one loop invocation. */
|
|
28
|
+
export declare function prepareCondition(input: ConditionInput, ctx: JobContext, combine?: 'all' | 'any'): Promise<Condition>;
|
|
29
|
+
/** Deterministic predicate over context + last outcome. */
|
|
30
|
+
export declare function predicate(fn: (ctx: JobContext, last: Outcome | undefined) => boolean | Promise<boolean>, reason?: string): Condition;
|
|
31
|
+
/** Met when the most recent body outcome passed. */
|
|
32
|
+
export declare function bodyPassed(): Condition;
|
|
33
|
+
/** Met when the last outcome carries confidence at or above `threshold`. */
|
|
34
|
+
export declare function minConfidence(threshold: number): Condition;
|
|
35
|
+
/**
|
|
36
|
+
* Deterministic gate that runs a shell command and is met on exit code 0. This
|
|
37
|
+
* is the deterministic convergence signal for coding loop jobs: pair it with an
|
|
38
|
+
* `agentCheck` in an `until` array so the loop stops only when the tests ACTUALLY
|
|
39
|
+
* pass AND a judge agrees the work matches intent, never on a model's self-report
|
|
40
|
+
* alone.
|
|
41
|
+
* Runs in `cwd` (default: the process working dir), inherits the run's abort
|
|
42
|
+
* signal, and never throws (a spawn failure counts as "not met"). A command's
|
|
43
|
+
* `timeoutMs` is explicit: node/agent turn timeouts do not become hard shell
|
|
44
|
+
* kills for deterministic gates.
|
|
45
|
+
* `opts.env` pins vars for this one gate command; it is the most specific
|
|
46
|
+
* layer, over any `withEnv` overlay and the running environment's vars.
|
|
47
|
+
* `opts.captureOutput` appends a scrubbed, bounded combined-output tail to a
|
|
48
|
+
* failed command's reason. The separate evidence output remains unchanged.
|
|
49
|
+
*/
|
|
50
|
+
export declare function commandSucceeds(command: string, args?: string[], opts?: {
|
|
51
|
+
cwd?: string;
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
env?: Record<string, string>;
|
|
54
|
+
captureOutput?: boolean;
|
|
55
|
+
}): Condition;
|
|
56
|
+
export declare const always: Condition;
|
|
57
|
+
export declare const never: Condition;
|
|
58
|
+
/** Inverts a condition. The inner result's `output` is carried through unchanged. */
|
|
59
|
+
export declare function not(c: ConditionInput): Condition;
|
|
60
|
+
/**
|
|
61
|
+
* Met only when every input holds (short-circuits on the first failure).
|
|
62
|
+
* On failure the FAILING item's `output` is carried; a success carries none.
|
|
63
|
+
*/
|
|
64
|
+
export declare function all(...inputs: ConditionInput[]): Condition;
|
|
65
|
+
/**
|
|
66
|
+
* Met when any input holds (short-circuits on the first success).
|
|
67
|
+
* On success THAT item's `output` is carried; on failure, the first defined
|
|
68
|
+
* `output` among the collected failures.
|
|
69
|
+
*/
|
|
70
|
+
export declare function any(...inputs: ConditionInput[]): Condition;
|
|
71
|
+
/**
|
|
72
|
+
* Met when at least `k` of the inputs hold. A hedge against a single agent
|
|
73
|
+
* judge's self-reported confidence: ask N independent judges and require a
|
|
74
|
+
* quorum (e.g. `quorum(2, j, j, j)`). All inputs run in parallel; a judge that
|
|
75
|
+
* throws counts as a "no" vote rather than sinking the whole gate. Each input
|
|
76
|
+
* may hit a model, so size N with cost in mind. Reported confidence is the mean
|
|
77
|
+
* of the holding inputs' confidences. On failure the first defined `output`
|
|
78
|
+
* among the non-holding voters is carried; a success carries none.
|
|
79
|
+
*/
|
|
80
|
+
export declare function quorum(k: number, ...inputs: ConditionInput[]): Condition;
|
|
81
|
+
export interface AgentCheckConfig {
|
|
82
|
+
/** The yes/no question the validator must answer. */
|
|
83
|
+
question: string;
|
|
84
|
+
/** Open the gate only at/above this confidence (0..1). Default 0.8. */
|
|
85
|
+
threshold?: number;
|
|
86
|
+
/** Cheap model recommended. A bare string, provider-agnostic. */
|
|
87
|
+
model?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Give the judge a persona — an `AgentDef` whose resolved system (persona +
|
|
90
|
+
* skills) is prepended to the validator's scoring instructions, so a reviewer
|
|
91
|
+
* can be a named specialist (e.g. an adversarial reviewer) instead of an
|
|
92
|
+
* anonymous yes/no. The validator's output contract stays authoritative (it
|
|
93
|
+
* comes last); `model` falls back to the agent's `model`. Mirrors `agentJob`.
|
|
94
|
+
*/
|
|
95
|
+
agent?: AgentDef;
|
|
96
|
+
/** Engine for validation: a registered name, your own `Engine`, or default. */
|
|
97
|
+
engine?: EngineRef;
|
|
98
|
+
/**
|
|
99
|
+
* Working directory for the judge's engine turn — a tool-using judge may
|
|
100
|
+
* need the workspace to read the artifact it is ruling on. Absent means the
|
|
101
|
+
* engine's default; deliberately NOT defaulted to the loop workspace.
|
|
102
|
+
*/
|
|
103
|
+
cwd?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Time cap on the judge turn, passed through to the engine. The
|
|
106
|
+
* anthropic-api engine ignores it.
|
|
107
|
+
*/
|
|
108
|
+
timeoutMs?: number;
|
|
109
|
+
/**
|
|
110
|
+
* What the validator sees. By default: the last outcome's summary/data plus
|
|
111
|
+
* the shared state. Override to feed something bespoke; may be async, since a
|
|
112
|
+
* judge often gathers evidence (read the artifact, ground on the history, run a
|
|
113
|
+
* probe) before ruling. Give it the thing it is meant to be reviewing.
|
|
114
|
+
*/
|
|
115
|
+
context?: (ctx: JobContext, last: Outcome | undefined) => string | Promise<string>;
|
|
116
|
+
maxTokens?: number;
|
|
117
|
+
/**
|
|
118
|
+
* Score these named dimensions (0..1 each) instead of a single yes/no
|
|
119
|
+
* confidence. The gate opens when the GEOMETRIC MEAN of the scores is
|
|
120
|
+
* >= `threshold`, so one weak dimension drags the whole verdict down. Stricter
|
|
121
|
+
* than a lone self-reported number, e.g.
|
|
122
|
+
* `['intent match', 'evidence quality', 'outcome coherence']`.
|
|
123
|
+
*/
|
|
124
|
+
dimensions?: string[];
|
|
125
|
+
/**
|
|
126
|
+
* Parse a free-form review that closes with `<confidence>N%</confidence>`
|
|
127
|
+
* (N is 0-100) instead of forcing a JSON shape. The gate opens at/above
|
|
128
|
+
* `threshold`; the reviewer's prose before the tag becomes the gate's `reason`,
|
|
129
|
+
* so a failing review carries its findings to the next iteration (`lastReview`).
|
|
130
|
+
* More robust than scraping JSON, and the natural fit for a report-then-rate
|
|
131
|
+
* reviewer persona. Takes precedence over `dimensions`.
|
|
132
|
+
*/
|
|
133
|
+
confidenceTag?: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Cap on the findings excerpt embedded in the `confidenceTag` gate `reason`.
|
|
136
|
+
* Default 280. The FULL findings always travel via `ConditionResult.output`.
|
|
137
|
+
*/
|
|
138
|
+
maxReasonChars?: number;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A Condition decided by a (preferably cheap) model. With a single yes/no
|
|
142
|
+
* question the gate opens when the verdict is "yes" AND confidence >= threshold.
|
|
143
|
+
* With `dimensions`, the model scores each dimension 0..1 and the gate opens
|
|
144
|
+
* when their geometric mean >= threshold, stricter than a single number.
|
|
145
|
+
*/
|
|
146
|
+
export declare function agentCheck(config: AgentCheckConfig): Condition;
|
|
147
|
+
/**
|
|
148
|
+
* Lift a Condition (or one-or-many `ConditionInput`) into a Job: `pass` when
|
|
149
|
+
* met, `fail` otherwise. This is how a reviewer becomes a drop-in `review` job
|
|
150
|
+
* (`gateJob('review', agentCheck(...))`). The condition's diagnostic `output`
|
|
151
|
+
* rides `Outcome.data`, so it survives the Job boundary.
|
|
152
|
+
*/
|
|
153
|
+
export declare function gateJob(label: string, condition: ConditionInput, opts?: {
|
|
154
|
+
/**
|
|
155
|
+
* The upstream node that owns the fix. When the condition is not met, the
|
|
156
|
+
* outcome carries a revision request to that node with the condition's
|
|
157
|
+
* evidence as the finding, so a red test suite goes straight back to the
|
|
158
|
+
* step that must fix it, with the output in hand and no agent in between.
|
|
159
|
+
* The enclosing `dag` routes it exactly as it routes a review panel's.
|
|
160
|
+
*/
|
|
161
|
+
target?: string;
|
|
162
|
+
}): Job;
|
|
163
|
+
/**
|
|
164
|
+
* A command as a job: `pass` on exit 0, `fail` otherwise, with the command's
|
|
165
|
+
* output as the evidence. Give the command as one string when no argument
|
|
166
|
+
* needs quoting (`'pnpm test'`), or as an array, one argument per entry
|
|
167
|
+
* (`['node', '--test', 'test/']`). `target` names the node that owns the fix,
|
|
168
|
+
* exactly as `gateJob` does: a red run goes back there with the output as the
|
|
169
|
+
* finding and no agent in between. `capture` (default true) appends the
|
|
170
|
+
* output tail to the failure summary.
|
|
171
|
+
*/
|
|
172
|
+
export declare function commandJob(label: string, command: string | readonly string[], opts?: {
|
|
173
|
+
cwd?: string;
|
|
174
|
+
timeoutMs?: number;
|
|
175
|
+
env?: Record<string, string>;
|
|
176
|
+
target?: string;
|
|
177
|
+
capture?: boolean;
|
|
178
|
+
}): Job;
|
|
179
|
+
/**
|
|
180
|
+
* Met when the named dependency passed. For a node's `when`: the node runs
|
|
181
|
+
* only on that path (`when: passed('size')`). A skipped dependency counts as
|
|
182
|
+
* passed, as it does everywhere in a dag. A name the node does not `need` is
|
|
183
|
+
* a configuration error, not a quiet false.
|
|
184
|
+
*/
|
|
185
|
+
export declare function passed(name: string): Condition;
|
|
186
|
+
/**
|
|
187
|
+
* Met when the named dependency ran and failed: the other branch of `passed`.
|
|
188
|
+
* A dependency that never got to decide (blocked by a failure upstream, or
|
|
189
|
+
* aborted) meets neither, so a branch runs only on a decision. The deciding
|
|
190
|
+
* node must be `optional: true`: a required node's failure blocks its
|
|
191
|
+
* dependents before any `when` runs, so a branch on `failed` would never be
|
|
192
|
+
* reached. `dag` refuses the graph at build time when it is not.
|
|
193
|
+
*/
|
|
194
|
+
export declare function failed(name: string): Condition;
|
|
195
|
+
/** One `passed(name)` or `failed(name)` found inside a condition input. */
|
|
196
|
+
export interface NeedDecision {
|
|
197
|
+
readonly on: 'passed' | 'failed';
|
|
198
|
+
readonly need: string;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Every `passed(name)` and `failed(name)` a condition input requires: the
|
|
202
|
+
* input itself, each item of an array, and each input of `all`, which carry
|
|
203
|
+
* their inputs in their meta. `not`, `any` and `quorum` are not walked: a
|
|
204
|
+
* branch composed with them can be met another way, so a `failed(x)` inside
|
|
205
|
+
* one does not make the branch dead. The graph builder reads this to refuse
|
|
206
|
+
* a branch that could never run.
|
|
207
|
+
*/
|
|
208
|
+
export declare function needDecisionsOf(input: ConditionInput): NeedDecision[];
|
|
209
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a child `JobContext` from a parent, overriding only the per-scope
|
|
3
|
+
* fields. One helper shared by `loop()` and `dag()` so the next field added to
|
|
4
|
+
* `JobContext` is threaded in exactly one place.
|
|
5
|
+
*/
|
|
6
|
+
import type { ConditionResult, GraphPosition, JobContext, Outcome, Workspace } from './types.js';
|
|
7
|
+
import type { EnvHandle } from '../env/environment.js';
|
|
8
|
+
export interface ContextOverride {
|
|
9
|
+
depth: number;
|
|
10
|
+
path: readonly string[];
|
|
11
|
+
iteration?: number;
|
|
12
|
+
lastOutcome?: Outcome;
|
|
13
|
+
lastReview?: Outcome;
|
|
14
|
+
lastGate?: ConditionResult;
|
|
15
|
+
/** The outcomes of a dag node's `needs`, set by the dag for that node only. */
|
|
16
|
+
needs?: Readonly<Record<string, Outcome>>;
|
|
17
|
+
/** Override the workspace (a worktree fork at a concurrency boundary). */
|
|
18
|
+
workspace?: Workspace;
|
|
19
|
+
/** Override the environment (a per-team env at a concurrency boundary). */
|
|
20
|
+
environment?: EnvHandle;
|
|
21
|
+
/** Override the pinned env vars (a `withEnv` wrapper layering its overlay). */
|
|
22
|
+
envOverlay?: Record<string, string>;
|
|
23
|
+
/** Override the DAG graph position for a node. */
|
|
24
|
+
graph?: GraphPosition;
|
|
25
|
+
/** Set or clear the acceptance criterion visible to a stage reviewer. */
|
|
26
|
+
reviewerGate?: string | null;
|
|
27
|
+
/** Carry the nearest DAG node's acceptance criterion through nested jobs. */
|
|
28
|
+
stageGate?: string | null;
|
|
29
|
+
/** Override the inherited timeout for jobs in this scope. */
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
/** Override the inherited timeout grace for jobs in this scope. */
|
|
32
|
+
timeoutGraceMs?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Resolve the criterion for the reviewer context currently being evaluated. */
|
|
35
|
+
export declare function criterionFor(ctx: Pick<JobContext, 'reviewerGate' | 'stageGate' | 'graph'>): string | undefined;
|
|
36
|
+
export declare function childContext(parent: JobContext, over: ContextOverride): JobContext;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost accounting over the run's measured token usage — the honest-receipt
|
|
3
|
+
* fold. Two rules keep cost reports honest:
|
|
4
|
+
*
|
|
5
|
+
* 1. **Never silently $0.** A model without complete price coverage lands in
|
|
6
|
+
* `unpricedModels`, and the totals stay `undefined` rather than pretending
|
|
7
|
+
* the run was free or pricing cached input at the base input rate.
|
|
8
|
+
* 2. **The baseline is labeled a reconstruction.** `baselineUsd` prices the
|
|
9
|
+
* SAME measured token stream at the baseline model's rates — "what these
|
|
10
|
+
* exact tokens would have cost on the ceiling model". It is a like-for-like
|
|
11
|
+
* counterfactual, not a measured alternative run, and consumers should say
|
|
12
|
+
* so when they print it.
|
|
13
|
+
*
|
|
14
|
+
* Prices are supplied by the caller (a JSON file via `--prices`, or a table
|
|
15
|
+
* in code). The library ships none: hardcoded prices go stale, and a wrong
|
|
16
|
+
* price is worse than no price.
|
|
17
|
+
*/
|
|
18
|
+
import type { StatsSnapshot } from './stats.js';
|
|
19
|
+
export interface ModelPrice {
|
|
20
|
+
/** Dollars per million input tokens. */
|
|
21
|
+
inputPerMTokUsd: number;
|
|
22
|
+
/** Dollars per million output tokens. */
|
|
23
|
+
outputPerMTokUsd: number;
|
|
24
|
+
}
|
|
25
|
+
/** Model id → price. Keys match exactly first, then by longest prefix, so
|
|
26
|
+
* `"claude-sonnet-5"` covers dated ids like `claude-sonnet-5-20250929`. */
|
|
27
|
+
export type PriceTable = Record<string, ModelPrice>;
|
|
28
|
+
export interface ModelCost {
|
|
29
|
+
model: string;
|
|
30
|
+
calls: number;
|
|
31
|
+
reportedCalls: number;
|
|
32
|
+
unknownUsageCalls: number;
|
|
33
|
+
inputTokens: number;
|
|
34
|
+
outputTokens: number;
|
|
35
|
+
/** Undefined when the table cannot price this model's complete usage. */
|
|
36
|
+
usd?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface CostReport {
|
|
39
|
+
/** Measured usage priced at each model's own rate; undefined if ANY used
|
|
40
|
+
* model is unpriced (a partial total masquerading as a total is a lie). */
|
|
41
|
+
spentUsd?: number;
|
|
42
|
+
/** The same token stream repriced at the baseline model — a reconstruction. */
|
|
43
|
+
baselineModel?: string;
|
|
44
|
+
baselineUsd?: number;
|
|
45
|
+
/** `baselineUsd - spentUsd` when both exist. Negative means the run cost
|
|
46
|
+
* MORE than the baseline would have. */
|
|
47
|
+
savedUsd?: number;
|
|
48
|
+
/** Models whose complete usage cannot be priced by the supplied table. */
|
|
49
|
+
unpricedModels: string[];
|
|
50
|
+
/** Models with calls whose provider reported no usage receipt. */
|
|
51
|
+
unknownUsageModels: string[];
|
|
52
|
+
models: ModelCost[];
|
|
53
|
+
}
|
|
54
|
+
/** Exact key first, then the longest prefix whose next char is a boundary. */
|
|
55
|
+
export declare function priceFor(table: PriceTable, model: string): ModelPrice | undefined;
|
|
56
|
+
export declare function costReport(snapshot: Pick<StatsSnapshot, 'models'>, prices: PriceTable, baselineModel?: string): CostReport;
|
|
57
|
+
/** A compact receipt for the exit summary. States what is measured and what
|
|
58
|
+
* is reconstructed; names unpriced models instead of zeroing them. */
|
|
59
|
+
export declare function formatCostReport(report: CostReport): string[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DAG / stages layer. `dag(config)` returns a `Job`, so it nests with
|
|
3
|
+
* `loop()` both ways. Nodes declare `needs` (dependencies); each node waits on
|
|
4
|
+
* its dependencies' promises, then runs under a shared `p-limit` concurrency
|
|
5
|
+
* gate. Cycle/missing-dep detection is delegated to `toposort` and happens
|
|
6
|
+
* before any work runs.
|
|
7
|
+
*
|
|
8
|
+
* Failure policy (ours, not the libs'):
|
|
9
|
+
* - a required node failing blocks its dependents (they don't run);
|
|
10
|
+
* - with `stopOnError` (default) the first required failure stops scheduling
|
|
11
|
+
* anything not already in flight;
|
|
12
|
+
* - `optional` nodes never fail the DAG nor block dependents;
|
|
13
|
+
* - an unmet `when` gate *skips* the node, which counts as green.
|
|
14
|
+
*/
|
|
15
|
+
import type { DagConfig, Job } from './types.js';
|
|
16
|
+
export declare function dag(config: DagConfig): Job;
|
|
17
|
+
/** Run jobs strictly in order; stop at the first non-pass. Sugar over `dag`. */
|
|
18
|
+
export declare function sequence(name: string, ...jobs: Job[]): Job;
|
|
19
|
+
/** Run jobs concurrently; default fan-out is capped at 4. */
|
|
20
|
+
export declare function parallel(name: string, jobs: Record<string, Job> | Job[], concurrency?: number): Job;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Condition, Job, JobContext } from './types.js';
|
|
2
|
+
export interface LastGateBriefOptions {
|
|
3
|
+
maxOutputChars?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface ConfidenceConditionOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Units used by `threshold`. `fraction` uses 0..1 (default 0.8), while
|
|
8
|
+
* `percent` uses 0..100 (default 80). Reported confidence stays normalized
|
|
9
|
+
* to 0..1 in both modes.
|
|
10
|
+
*/
|
|
11
|
+
scale?: 'fraction' | 'percent';
|
|
12
|
+
threshold?: number;
|
|
13
|
+
token?: string;
|
|
14
|
+
/** Accept an exact, case-insensitive `n/a` token when the wrapped job passes. */
|
|
15
|
+
allowNa?: boolean;
|
|
16
|
+
/** Use the full work output as the condition reason when it is nonempty. */
|
|
17
|
+
reason?: 'concise' | 'output';
|
|
18
|
+
}
|
|
19
|
+
export interface LastDecisionLineOptions {
|
|
20
|
+
/**
|
|
21
|
+
* `closing` requires the token to be the final nonblank line. `last-match`
|
|
22
|
+
* permits trailing prose and selects the last line-anchored token.
|
|
23
|
+
*/
|
|
24
|
+
mode?: 'closing' | 'last-match';
|
|
25
|
+
}
|
|
26
|
+
export declare function lastDecisionLine(text: string, token: string, values?: readonly string[], opts?: LastDecisionLineOptions): string | undefined;
|
|
27
|
+
export declare function confidenceFromText(text: string, token?: string): number | undefined;
|
|
28
|
+
export declare function confidenceCondition(job: Job, opts?: ConfidenceConditionOptions): Condition;
|
|
29
|
+
export declare function lastGateBrief(ctx: Pick<JobContext, 'lastGate'>, opts?: LastGateBriefOptions): string;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job introspection. The builders register a `JobMeta` for the `Job` they return
|
|
3
|
+
* (and a short label for the conditions they build) in a side table, so a loop's
|
|
4
|
+
* shape can be read back without running it. A host can validate or describe a
|
|
5
|
+
* graph without executing it.
|
|
6
|
+
*
|
|
7
|
+
* Kept in `WeakMap`s rather than on the function objects, so the `Job`/`Condition`
|
|
8
|
+
* types stay plain functions and nothing downstream has to know meta exists.
|
|
9
|
+
*/
|
|
10
|
+
import type { Job, JobMeta, ConditionInput } from './types.js';
|
|
11
|
+
/** Register a Job's shape and return the same Job (used inline at a builder's return). */
|
|
12
|
+
export declare function setMeta<T extends object>(target: T, meta: JobMeta): T;
|
|
13
|
+
/** Read a Job's registered shape, if it has one (a hand-written Job has none). */
|
|
14
|
+
export declare function jobMeta(job: Job): JobMeta | undefined;
|
|
15
|
+
/** Carry a Job's shape onto a wrapper that preserves its public behavior. */
|
|
16
|
+
export declare function copyJobMeta<T extends object>(target: T, source: Job): T;
|
|
17
|
+
/** Register a one-line label for a condition (used by the gate-describing path). */
|
|
18
|
+
export declare function setLabel<T extends object>(cond: T, label: string): T;
|
|
19
|
+
/** Flatten a gate input (`until`/`start`/`stopOn`) into one label per condition. */
|
|
20
|
+
export declare function describeConditions(input?: ConditionInput): string[];
|
|
21
|
+
/** Per-node shape `dag()` writes into its meta's `nodes` array. */
|
|
22
|
+
export interface NodeMeta {
|
|
23
|
+
name: string;
|
|
24
|
+
needs?: string[];
|
|
25
|
+
desc?: string;
|
|
26
|
+
gate?: string;
|
|
27
|
+
isolate?: boolean;
|
|
28
|
+
optional?: boolean;
|
|
29
|
+
/** Condition labels for the node's `when` gate, when one is configured. */
|
|
30
|
+
when?: string[];
|
|
31
|
+
job?: JobMeta;
|
|
32
|
+
}
|
|
33
|
+
export type InspectionCommand = 'validate' | 'describe';
|
|
34
|
+
export interface InspectionEnvelopeV1 {
|
|
35
|
+
schemaVersion: 1;
|
|
36
|
+
command: InspectionCommand;
|
|
37
|
+
file: string;
|
|
38
|
+
ok: true;
|
|
39
|
+
executed: false;
|
|
40
|
+
shape: JobShapeV1;
|
|
41
|
+
}
|
|
42
|
+
export type JobShapeV1 = {
|
|
43
|
+
kind: 'opaque';
|
|
44
|
+
} | {
|
|
45
|
+
kind: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
[producerField: string]: unknown;
|
|
48
|
+
};
|
|
49
|
+
export declare function jobShapeV1(meta: JobMeta | undefined): JobShapeV1;
|
|
50
|
+
export declare function inspectionEnvelopeV1(command: InspectionCommand, file: string, meta: JobMeta | undefined): InspectionEnvelopeV1;
|
|
51
|
+
/**
|
|
52
|
+
* Render a `JobMeta` tree to indented lines: the loop's name and cap, its gate
|
|
53
|
+
* and convergence actions, and its body / dag nodes recursively. A Job with no
|
|
54
|
+
* meta (hand-written) renders as a single opaque line.
|
|
55
|
+
*/
|
|
56
|
+
export declare function renderPlan(meta: JobMeta | undefined, indent?: string): string[];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentRequest, AgentResult } from '../engines/engine.js';
|
|
2
|
+
import type { JobContext } from './types.js';
|
|
3
|
+
export declare function attemptRequestMeta(ctx: JobContext, label: string): AgentRequest['attempt'];
|
|
4
|
+
/** Surface a completed result's later transport failure through run logs. */
|
|
5
|
+
export declare function logEngineTransportFailure(ctx: JobContext, result: Pick<AgentResult, 'transportFailure'>, env?: Record<string, string>): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env-var pinning for a job subtree. `withEnv` wraps any `Job` so everything beneath
|
|
3
|
+
* it (gate commands, judge calls, and the subprocesses agent leaves spawn) sees the
|
|
4
|
+
* given variables, without mutating the global `process.env`.
|
|
5
|
+
*
|
|
6
|
+
* Precedence (most specific wins):
|
|
7
|
+
* process.env
|
|
8
|
+
* < ctx.environment.env (the Environment interface's live-stack vars)
|
|
9
|
+
* < ctx.envOverlay (withEnv; nested wrappers merge inner-over-outer)
|
|
10
|
+
* < explicit per-call env (commandSucceeds `opts.env` / agentJob `config.env`)
|
|
11
|
+
*
|
|
12
|
+
* Non-goals: this is pinning, not a lifecycle. Unlike the Environment interface, an
|
|
13
|
+
* overlay has no `down()` and never touches the Environment handle. It cannot unset
|
|
14
|
+
* an inherited var: the process helper merges env over `process.env`, so an overlay only adds or
|
|
15
|
+
* shadows values.
|
|
16
|
+
*/
|
|
17
|
+
import type { Job, JobContext } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Layer env sources least- to most-specific into one record for a subprocess.
|
|
20
|
+
* Returns `undefined` when every layer is absent or empty, so call sites keep
|
|
21
|
+
* their exact no-env behavior (`env: undefined`, never `{}`). Internal: the public
|
|
22
|
+
* surface is `withEnv`; per-call layers ride `opts.env` / `config.env`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function mergeEnv(...layers: (Record<string, string> | undefined)[]): Record<string, string> | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* The layered env for one engine/subprocess call, least → most specific: the
|
|
27
|
+
* running environment's vars, then the `withEnv` overlay, then the per-call
|
|
28
|
+
* layer (`commandSucceeds` `opts.env` / `agentJob` `config.env`). The process helper (and
|
|
29
|
+
* the SDK adapter) merge the result over `process.env`, completing the
|
|
30
|
+
* precedence chain in the header. One helper so a new call site cannot forget
|
|
31
|
+
* a layer and silently break `withEnv`'s "everything beneath it" contract.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveEnv(ctx: JobContext, perCall?: Record<string, string>): Record<string, string> | undefined;
|
|
34
|
+
/** Pin env vars for `job` and everything beneath it (see the header above). */
|
|
35
|
+
export declare function withEnv(overlay: Record<string, string>, job: Job): Job;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured, classified errors so the exit report can say what failed, where in
|
|
3
|
+
* the loop tree, and why, instead of dumping a stack.
|
|
4
|
+
*/
|
|
5
|
+
export type LoopErrorCode = 'ENGINE' | 'TIMEOUT' | 'ABORTED' | 'VALIDATION' | 'WRITE_BOUNDARY' | 'CONFIG' | 'BUDGET' | 'RATE_LIMIT' | 'QUOTA' | 'BODY' | 'UNKNOWN';
|
|
6
|
+
export type LoopPhase = 'start' | 'body' | 'until' | 'stopOn' | 'review' | 'engine';
|
|
7
|
+
export interface LoopErrorInit {
|
|
8
|
+
code: LoopErrorCode;
|
|
9
|
+
message: string;
|
|
10
|
+
phase?: LoopPhase;
|
|
11
|
+
path?: readonly string[];
|
|
12
|
+
iteration?: number;
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
retryable?: boolean;
|
|
15
|
+
/** Suggested wait before retry, in ms (e.g. a `retry-after` header). */
|
|
16
|
+
retryAfterMs?: number;
|
|
17
|
+
/** When the limit resets, as epoch ms. The wait policy prefers this. */
|
|
18
|
+
resetAt?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class LoopError extends Error {
|
|
21
|
+
readonly code: LoopErrorCode;
|
|
22
|
+
readonly phase?: LoopPhase;
|
|
23
|
+
readonly path?: readonly string[];
|
|
24
|
+
readonly iteration?: number;
|
|
25
|
+
readonly retryable: boolean;
|
|
26
|
+
/** Suggested wait before retry, in ms (e.g. a `retry-after` header). */
|
|
27
|
+
readonly retryAfterMs?: number;
|
|
28
|
+
/** When the limit resets, as epoch ms. The wait policy prefers this. */
|
|
29
|
+
readonly resetAt?: number;
|
|
30
|
+
constructor(init: LoopErrorInit);
|
|
31
|
+
/** Wrap an arbitrary thrown value, preserving a `LoopError` as-is. */
|
|
32
|
+
static from(value: unknown, fallback: Omit<LoopErrorInit, 'message' | 'cause'>): LoopError;
|
|
33
|
+
toJSON(): {
|
|
34
|
+
name: string;
|
|
35
|
+
code: LoopErrorCode;
|
|
36
|
+
message: string;
|
|
37
|
+
phase: LoopPhase | undefined;
|
|
38
|
+
path: readonly string[] | undefined;
|
|
39
|
+
iteration: number | undefined;
|
|
40
|
+
retryable: boolean;
|
|
41
|
+
retryAfterMs: number | undefined;
|
|
42
|
+
resetAt: number | undefined;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export declare function isInfrastructureError(error: unknown): error is LoopError;
|
|
46
|
+
export declare function isEngineExecutionError(error: unknown): error is LoopError;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ConditionInput, FeedbackActionSeverity, FeedbackDecision, FeedbackFinding, FeedbackSeverity, GraphPosition, Job, JobContext, Outcome, RevisionRequest, RevisionRerun } from './types.js';
|
|
2
|
+
export type { FeedbackActionSeverity, FeedbackDecision, FeedbackFinding, FeedbackSeverity, RevisionRequest, RevisionRerun, } from './types.js';
|
|
3
|
+
export interface RevisionRequestInput {
|
|
4
|
+
target?: string;
|
|
5
|
+
reason?: string;
|
|
6
|
+
findings?: FeedbackFinding[];
|
|
7
|
+
rerun?: RevisionRerun;
|
|
8
|
+
source?: string;
|
|
9
|
+
decision?: FeedbackDecision;
|
|
10
|
+
}
|
|
11
|
+
export declare function normalizeFeedbackSeverity(severity: FeedbackSeverity | undefined): FeedbackActionSeverity;
|
|
12
|
+
export declare function isRequiredFeedbackSeverity(severity: FeedbackSeverity | undefined): boolean;
|
|
13
|
+
export declare function revisionRequest(input: RevisionRequestInput, over?: Partial<Outcome>): Outcome;
|
|
14
|
+
export declare function kickback(to: string, reason: string, over?: Partial<Outcome>): Outcome;
|
|
15
|
+
/**
|
|
16
|
+
* The single accessor for an outcome's revision request. `Outcome.revision` is
|
|
17
|
+
* the one channel a producer sets (`revisionRequest`, `kickback`, `reviewPanel`,
|
|
18
|
+
* dag routing), so there is exactly one place to read it — no parallel `kickback`
|
|
19
|
+
* field or `data` copy to keep in sync.
|
|
20
|
+
*/
|
|
21
|
+
export declare function revisionFromOutcome(outcome: Outcome): RevisionRequest | undefined;
|
|
22
|
+
export declare function feedbackBlock(outcome: Outcome): string;
|
|
23
|
+
export declare function graphPositionBlock(graph: GraphPosition, reviewerGate?: string | null): string;
|
|
24
|
+
type ReviewTarget = {
|
|
25
|
+
name?: string;
|
|
26
|
+
scope?: string;
|
|
27
|
+
/** Stable reviewer criteria version. Required when passes are persisted. */
|
|
28
|
+
cacheVersion?: string;
|
|
29
|
+
/** Workspace paths whose content can invalidate this reviewer's persisted pass. */
|
|
30
|
+
invalidateOn?: string[];
|
|
31
|
+
} & ({
|
|
32
|
+
review: ConditionInput;
|
|
33
|
+
} | {
|
|
34
|
+
job: Job;
|
|
35
|
+
});
|
|
36
|
+
export interface ReviewPanelConfig {
|
|
37
|
+
label?: string;
|
|
38
|
+
reviewers: ReviewTarget[];
|
|
39
|
+
/** Max reviewers running at once. Default 4. */
|
|
40
|
+
concurrency?: number;
|
|
41
|
+
/** Default `all`: every reviewer must pass. A number means k-of-n over all reviewers. */
|
|
42
|
+
pass?: 'all' | number;
|
|
43
|
+
/** Reuse only passing verdicts at or above this confidence while their evidence is unchanged. */
|
|
44
|
+
persistPasses?: {
|
|
45
|
+
minConfidence: number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* When set, findings scoped outside these surfaces are escalated and do not
|
|
49
|
+
* count against this panel's pass/fail decision. Unscoped findings stay
|
|
50
|
+
* actionable so a missing scope cannot bypass review.
|
|
51
|
+
*/
|
|
52
|
+
actionableScopes?: string[];
|
|
53
|
+
/** When set, a failing panel emits a targeted revision request for dag routing. */
|
|
54
|
+
target?: string;
|
|
55
|
+
rerun?: RevisionRerun;
|
|
56
|
+
}
|
|
57
|
+
export declare function reviewPanel(config: ReviewPanelConfig): Job;
|
|
58
|
+
export interface ReviewContextConfig {
|
|
59
|
+
diff?: boolean;
|
|
60
|
+
files?: string[];
|
|
61
|
+
tests?: boolean | {
|
|
62
|
+
command: string;
|
|
63
|
+
args?: string[];
|
|
64
|
+
cwd?: string;
|
|
65
|
+
};
|
|
66
|
+
maxChars?: number;
|
|
67
|
+
}
|
|
68
|
+
export declare function reviewContext(config: ReviewContextConfig): (ctx: JobContext, last: Outcome | undefined) => Promise<string>;
|