@loops-adk/core 0.1.1 → 0.2.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 +105 -13
- package/assets/logo.png +0 -0
- package/dist/{agent-sdk-RF5VJZAT.js → agent-sdk-4QJDWM7N.js} +3 -3
- package/dist/{agent-sdk-RF5VJZAT.js.map → agent-sdk-4QJDWM7N.js.map} +1 -1
- package/dist/api.d.ts +108 -3
- package/dist/api.js +26 -10
- package/dist/api.js.map +1 -1
- package/dist/{chunk-XC46B4FD.js → chunk-MA6NDQMO.js} +2 -2
- package/dist/chunk-MA6NDQMO.js.map +1 -0
- package/dist/{chunk-6BDWTFOS.js → chunk-WM5QVHM2.js} +592 -35
- package/dist/chunk-WM5QVHM2.js.map +1 -0
- package/dist/{claude-cli-U7WEVAOL.js → claude-cli-75AOQUKG.js} +3 -3
- package/dist/{claude-cli-U7WEVAOL.js.map → claude-cli-75AOQUKG.js.map} +1 -1
- package/dist/{codex-6I5UZ2HM.js → codex-LYZF52WL.js} +25 -13
- package/dist/codex-LYZF52WL.js.map +1 -0
- package/dist/env/command.d.ts +1 -1
- package/dist/env/docker.d.ts +1 -1
- package/dist/env/sst.d.ts +1 -1
- package/dist/index.js +140 -11
- package/dist/index.js.map +1 -1
- package/dist/{types-B4wGVpqo.d.ts → types-Cv_3ymr9.d.ts} +118 -37
- package/package.json +10 -1
- package/skills/author-loop/SKILL.md +14 -5
- package/skills/design-agent-team/SKILL.md +108 -0
- package/skills/supervise-loop-run/SKILL.md +64 -0
- package/dist/chunk-6BDWTFOS.js.map +0 -1
- package/dist/chunk-XC46B4FD.js.map +0 -1
- package/dist/codex-6I5UZ2HM.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo.png" alt="loops" width="320">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Stop prompting agents. Write the loop that prompts them. Make "done" mean <em>converged</em>, not <em>claimed</em>.</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@loops-adk/core"><img src="https://img.shields.io/npm/v/@loops-adk/core" alt="npm"></a>
|
|
11
|
+
<img src="https://img.shields.io/badge/status-alpha-orange" alt="status: alpha">
|
|
12
|
+
<img src="https://img.shields.io/badge/TypeScript-strict-3178c6" alt="TypeScript">
|
|
13
|
+
<img src="https://img.shields.io/badge/node-%3E%3D20-3c873a" alt="node >=20">
|
|
14
|
+
<img src="https://img.shields.io/badge/license-MIT-blue" alt="license: MIT">
|
|
15
|
+
</p>
|
|
4
16
|
|
|
5
17
|
`loops` is a small, nestable library for running an agent in a convergence loop. The loop finds the work, hands it to an agent, checks the result, records what it learned, and goes again until a gate _you_ define says the work is finished. You write the loop once and it drives the agent, rather than prompting the agent by hand. Compose loops and DAGs both ways, run them against any model behind a one-method `Engine`, and watch a run in a live terminal UI.
|
|
6
18
|
|
|
@@ -8,10 +20,31 @@ Every iteration runs with a **fresh context**, so a long run never rots. Progres
|
|
|
8
20
|
|
|
9
21
|
Where most "agent memory" recalls a _conversation_, this keeps your _decisions_ consistent across long work. No vector database, no embeddings, no index to sync or let go stale. **Git is the memory.**
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
23
|
+
## The fastest proof
|
|
24
|
+
|
|
25
|
+
A downstream agent had to preserve one upstream decision: snapshots must start
|
|
26
|
+
with the exact wire tag `SSv1|`. That decision lived only in a git commit body,
|
|
27
|
+
not in the source files or the downstream task prompt. The commit was not just a
|
|
28
|
+
fact store; it was the thread back through the journey, what was decided, why it
|
|
29
|
+
was decided, and what downstream work had to honour.
|
|
30
|
+
|
|
31
|
+
| Runner | What it could read | Result |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| Memoryless graph | files plus task prompt | 0/10 preserved the contract |
|
|
34
|
+
| Loops Ledger | gated commit bodies plus grounding | 9/10 preserved the contract |
|
|
35
|
+
| Raw git dump | full git log pasted into every prompt | 10/10 on a toy log, not a real-repo operating mode |
|
|
36
|
+
|
|
37
|
+
That is the honest shape of the claim. Loops is not just `git log`: it is the
|
|
38
|
+
deterministic enforcement layer that makes agents write useful commit bodies when
|
|
39
|
+
work converges, then the grounding layer that reads those verified reasons back
|
|
40
|
+
into later fresh contexts. The value is not bare recall. A fresh agent can pull
|
|
41
|
+
on one thread and reconstruct how and why the repository got here. Full-log dump
|
|
42
|
+
is a useful sanity check on tiny histories, but on a repo with significant
|
|
43
|
+
history it is context rot and cost.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run bench:compare
|
|
47
|
+
```
|
|
15
48
|
|
|
16
49
|
```ts
|
|
17
50
|
import { loop, agentJob, commandSucceeds, agentCheck } from '@loops-adk/core';
|
|
@@ -151,6 +184,7 @@ loops run \
|
|
|
151
184
|
```bash
|
|
152
185
|
loops validate examples/confidence-gate.loop.ts # offline pre-flight: load + print the shape, no model calls
|
|
153
186
|
loops describe examples/confidence-gate.loop.ts # print the loop's shape (gate, body, nodes) without running
|
|
187
|
+
loops describe examples/confidence-gate.loop.ts --json # machine-readable shape for agents
|
|
154
188
|
loops run examples/confidence-gate.loop.ts # live Ink TUI
|
|
155
189
|
loops run examples/confidence-gate.loop.ts --no-tui # plain streamed logs
|
|
156
190
|
loops run examples/confidence-gate.loop.ts --json # NDJSON event stream
|
|
@@ -160,6 +194,19 @@ loops run examples/confidence-gate.loop.ts --json # NDJSON event stream
|
|
|
160
194
|
|
|
161
195
|
**Authoring is agent-native.** Both commands work from any repo, including one that consumes `loops` as a submodule or dependency (the recipe's folder just needs an ES module scope, which such repos already have). `loops validate <file>` is the cheap, no-model pre-flight an agent runs before `loops run`: it loads the loop, reports a fix-oriented error if anything is wrong, and prints the loop's shape (its gate, body, and dag nodes), all without spending a single agent turn. `loops describe <file>` prints that same shape on its own, so an agent can see exactly what it just authored. The authoring guide an agent reads to compose a loop is [`skills/author-loop/SKILL.md`](skills/author-loop/SKILL.md).
|
|
162
196
|
|
|
197
|
+
The end-to-end agent workflow, from authoring through reading a supervised run's decisions back as structured records rather than a raw event stream:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
loops validate feature.loop.ts --json # pre-flight: loads, no spend
|
|
201
|
+
loops describe feature.loop.ts --json # the shape, incl. each agent node's contract
|
|
202
|
+
loops run feature.loop.ts --no-tui --supervise # run it, registered for observation
|
|
203
|
+
loops list # find the runId
|
|
204
|
+
loops tail <runId> # follow live events
|
|
205
|
+
loops records <runId> --kind revision --path ship/implementation --json # the semantic decision stream, filtered
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Two supervision skills go deeper: [`skills/supervise-loop-run/SKILL.md`](skills/supervise-loop-run/SKILL.md) (monitor a run) and [`skills/design-agent-team/SKILL.md`](skills/design-agent-team/SKILL.md) (compose a specialist team).
|
|
209
|
+
|
|
163
210
|
**Offline demo** (no network, no key; uses the mock engine):
|
|
164
211
|
|
|
165
212
|
```bash
|
|
@@ -276,10 +323,10 @@ The agent launch only ever touches the `Engine` interface, so the loop knows not
|
|
|
276
323
|
|
|
277
324
|
| name | backend | notes |
|
|
278
325
|
| --------------- | -------------------------------- | ----------------------------------------------------------- |
|
|
279
|
-
| `
|
|
280
|
-
| `
|
|
281
|
-
| `
|
|
282
|
-
| `
|
|
326
|
+
| `codex` | `codex exec` subprocess (`execa`) | fresh process per call; read-only unless `bypassPermissions` |
|
|
327
|
+
| `claude-cli` | `claude` subprocess (`execa`) | fresh process per call; uses host Claude auth, no key |
|
|
328
|
+
| `agent-sdk` | `@anthropic-ai/claude-agent-sdk` | fresh `query()` per call; host Claude auth |
|
|
329
|
+
| `anthropic-api` | `@anthropic-ai/sdk` | token-level streaming; cheapest for judges; needs a key |
|
|
283
330
|
| `mock` | scripted, offline | for tests and examples |
|
|
284
331
|
|
|
285
332
|
Select per-run (`--engine`, `RunOptions.engine`) or per-job/condition (`engine:` takes a name **or** a ready-made `Engine`). Bring your own in ~10 lines:
|
|
@@ -314,15 +361,23 @@ const storeEngineer = defineAgent({
|
|
|
314
361
|
system: fromFile(new URL('./agents/store-engineer.md', import.meta.url)), // the persona, as markdown
|
|
315
362
|
model: 'sonnet',
|
|
316
363
|
tools: ['edit', 'bash'],
|
|
364
|
+
tier: 'worker',
|
|
317
365
|
capabilities: ['storage engine', 'id stability'],
|
|
366
|
+
outputs: [{ name: 'patch' }, { name: 'test-report' }],
|
|
367
|
+
requiresSkills: ['contract-first'],
|
|
318
368
|
skills: [tdd], // methodologies fold into the system
|
|
369
|
+
usesSkills: ['small-diff'],
|
|
370
|
+
humanGates: [{ name: 'prod-approval', when: 'deploying production changes' }],
|
|
319
371
|
failureModes: [{ mode: 'tests-flaky', recovery: 'isolate the flake, retry once' }],
|
|
320
372
|
});
|
|
321
373
|
|
|
322
374
|
agentJob({ agent: storeEngineer, prompt: 'Build the store to its tests.', ground: true });
|
|
323
375
|
```
|
|
324
376
|
|
|
325
|
-
|
|
377
|
+
For a small runnable contract plus feedback example, see
|
|
378
|
+
[`examples/contracted-agent.loop.ts`](examples/contracted-agent.loop.ts).
|
|
379
|
+
|
|
380
|
+
`agentJob` resolves the def into the engine request (`system` = persona + skills, plus `model`/`tools`); inline `system`/`model`/`tools` still override it. A **skill** is a methodology (how to work: TDD, writing-plans), not a worker. The extra contract fields are optional metadata for validation, `loops describe`, docs, and future discovery. They do not give an agent dispatch authority. This is what turns a `dag` into a named **team** (`storeEngineer`, `apiEngineer`, `securityReviewer` as small files) orchestrated by the DAG and gated by `quorum(...)`.
|
|
326
381
|
|
|
327
382
|
## Environments: test the running thing
|
|
328
383
|
|
|
@@ -381,6 +436,43 @@ dag({
|
|
|
381
436
|
|
|
382
437
|
`needs` = dependencies; a non-`pass` required dependency blocks its dependents; `optional` nodes never block or fail the DAG; an unmet `when` skips a node (counts green); cycles are detected before any work runs. `sequence(name, ...jobs)` and `parallel(name, jobs, concurrency?)` are sugar over `dag`.
|
|
383
438
|
|
|
439
|
+
### Feedback between nodes
|
|
440
|
+
|
|
441
|
+
Review feedback is a structured revision request. In a loop, a failing `review`
|
|
442
|
+
outcome is threaded into the next body turn as `ctx.lastReview`; with
|
|
443
|
+
`consumeFeedback: true`, `agentJob` appends it to the implementation prompt in a
|
|
444
|
+
standard block.
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
const implement = agentJob({
|
|
448
|
+
label: 'implementation',
|
|
449
|
+
prompt: brief,
|
|
450
|
+
consumeFeedback: true,
|
|
451
|
+
});
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
For several reviewers, use `reviewPanel` to aggregate their verdicts into one
|
|
455
|
+
outcome. Every reviewer is a gate: the panel passes when all of them clear (or
|
|
456
|
+
`pass: N` of them, k-of-n), and each failing reviewer's concern is surfaced as a
|
|
457
|
+
blocking finding threaded into the next pass. An empty panel is a construction
|
|
458
|
+
error, not a vacuous pass.
|
|
459
|
+
|
|
460
|
+
```ts
|
|
461
|
+
const review = reviewPanel({
|
|
462
|
+
// pass: 2, // optional: k-of-n instead of all
|
|
463
|
+
reviewers: [
|
|
464
|
+
{ name: 'security', review: agentCheck({ question: 'Is it safe?', context: reviewContext({ diff: true, ledger: true }) }) },
|
|
465
|
+
{ name: 'correctness', review: agentCheck({ question: 'Is it correct?' }) },
|
|
466
|
+
{ name: 'simplicity', review: agentCheck({ question: 'Is it simple?', context: reviewContext({ files: ['src/**'] }) }) },
|
|
467
|
+
],
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
In a DAG, a targeted `revisionRequest({ target, findings })` reruns the target
|
|
472
|
+
node and its dependents when `maxKickbacks` allows it. `kickback(to, reason)` is
|
|
473
|
+
the terse compatibility helper for the same routed feedback. Agents can opt into
|
|
474
|
+
a small graph-position prompt block with `graphContext: true`.
|
|
475
|
+
|
|
384
476
|
**Worktree isolation: branches as teams.** A concurrent node can run in its own git worktree on a fork branch (`isolation: 'worktree'` on the DAG, or `isolate: true` per node), so parallel writers never collide on files or the index. On pass, its committed work lands back into the line with a `--no-ff` merge; a conflict fails the node honestly (loops does not auto-resolve; that's a separate layer). Each team gets its own branch, its own scratch files, and (with `DagConfig.environment`) its own stage, all born and torn down together.
|
|
385
477
|
|
|
386
478
|
For **dynamic** dispatch (a loop that discovers each unit at runtime and routes it to its own isolated sub-loop), `isolated(job)` is the same boundary as a composable wrapper rather than a predeclared node (fork, run, land back on pass):
|
|
@@ -458,7 +550,7 @@ loops status <runId> # its shape plus where it is now: iterati
|
|
|
458
550
|
loops tail <runId> # stream its events live
|
|
459
551
|
```
|
|
460
552
|
|
|
461
|
-
`list` marks a run dead if its process is gone. The read side is also on the public surface (`listRuns`, `readRunStatus`, `runEventsPath`), so an agent supervising a fleet of loops, killing the ones that drift and kicking work back into the ones that hit a problem, reads the same files. Out-of-process control (pause, abort, and kickback from outside) is the next step.
|
|
553
|
+
Each run keeps the raw event stream in `events.jsonl` and a smaller semantic stream in `semantic.jsonl` with dispatch, completion, surfacing, `revision-emitted`, and `revision-routed` records. Use `loops records <runId>` to inspect those records without knowing the registry path; add `--kind revision-routed`, `--kind revision` (both revision kinds), `--path ship/implementation`, `--since <time>`, `--last <n>`, or `--json` when an agent needs a filtered machine-readable stream. `list` marks a run dead if its process is gone. The read side is also on the public surface (`listRuns`, `readRunStatus`, `runEventsPath`, `runSemanticRecordsPath`), so an agent supervising a fleet of loops, killing the ones that drift and kicking work back into the ones that hit a problem, reads the same files. Out-of-process control (pause, abort, and kickback from outside) is the next step.
|
|
462
554
|
|
|
463
555
|
## What `loops` is (and isn't)
|
|
464
556
|
|
package/assets/logo.png
ADDED
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { newAccumulator, mapMessage } from './chunk-CXEPZHSR.js';
|
|
2
|
-
import { SUBAGENT_TOOLS } from './chunk-
|
|
2
|
+
import { SUBAGENT_TOOLS } from './chunk-MA6NDQMO.js';
|
|
3
3
|
import { LoopError } from './chunk-I3STY7U6.js';
|
|
4
4
|
import pTimeout from 'p-timeout';
|
|
5
5
|
|
|
@@ -91,5 +91,5 @@ var AgentSdkEngine = class {
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
export { AgentSdkEngine };
|
|
94
|
-
//# sourceMappingURL=agent-sdk-
|
|
95
|
-
//# sourceMappingURL=agent-sdk-
|
|
94
|
+
//# sourceMappingURL=agent-sdk-4QJDWM7N.js.map
|
|
95
|
+
//# sourceMappingURL=agent-sdk-4QJDWM7N.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engines/agent-sdk.ts"],"names":[],"mappings":";;;;;AA8BA,SAAS,iBAAiB,KAAA,EAAuC;AAC/D,EAAA,MAAM,GAAA,GAAO,SAAS,EAAC;AACvB,EAAA,MAAM,MAAM,OAAO,GAAA,CAAI,KAAA,KAAU,QAAA,GAAW,IAAI,KAAA,GAAQ,EAAA;AACxD,EAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,EAAA,MAAM,WAAW,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,OAAO,GAAG,WAAA,EAAY;AAEjD,EAAA,MAAM,IAAA,GAAQ,GAAA,CAAI,eAAA,IAAmB,EAAC;AACtC,EAAA,MAAM,OAAA,GACJ,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,GACrB,IAAA,CAAK,QAAA,GACL,OAAO,IAAA,CAAK,eAAA,KAAoB,QAAA,GAC9B,IAAA,CAAK,eAAA,GACL,MAAA;AAER,EAAA,MAAM,OAAA,GACJ,QAAQ,eAAA,IACR,IAAA,CAAK,cAAc,kBAAA,IACnB,kCAAA,CAAmC,KAAK,QAAQ,CAAA;AAClD,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,OAAO,IAAI,SAAA,CAAU;AAAA,MACnB,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,QAAA;AAAA,MACP,OAAA,EAAS,kCAAkC,OAAO,CAAA,CAAA;AAAA,MAClD,KAAA,EAAO,KAAA;AAAA,MACP;AAAA,KACD,CAAA;AAAA,EACH;AACA,EAAA,MAAM,SACJ,GAAA,KAAQ,YAAA,IACR,QAAQ,YAAA,IACR,oDAAA,CAAqD,KAAK,QAAQ,CAAA;AACpE,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,OAAO,IAAI,SAAA,CAAU;AAAA,MACnB,IAAA,EAAM,YAAA;AAAA,MACN,KAAA,EAAO,QAAA;AAAA,MACP,OAAA,EAAS,2BAA2B,OAAO,CAAA,CAAA;AAAA,MAC3C,KAAA,EAAO,KAAA;AAAA,MACP;AAAA,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,MAAA;AACT;AAEO,IAAM,iBAAN,MAAuC;AAAA,EAE5C,WAAA,CAA6B,IAAA,GAAsB,EAAC,EAAG;AAA1B,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EAA2B;AAAA,EAA3B,IAAA;AAAA,EADpB,IAAA,GAAO,WAAA;AAAA,EAGhB,MAAM,GAAA,CACJ,GAAA,EACA,OAAA,EACA,MAAA,EACsB;AAEtB,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,OAAO,gCAAgC,CAAA;AAE/D,IAAA,MAAM,GAAA,GAAM,cAAA;AAAA,MACV,GAAA,CAAI,KAAA,IAAS,IAAA,CAAK,IAAA,CAAK,YAAA,IAAgB;AAAA,KACzC;AACA,IAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,EAAgB;AAClC,IAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,KAAA,EAAM;AAClC,IAAA,IAAI,MAAA,CAAO,OAAA,EAAS,KAAA,CAAM,KAAA,EAAM;AAAA,gBACpB,gBAAA,CAAiB,OAAA,EAAS,SAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAG7D,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,KAAA,EAAO,GAAA,CAAI,KAAA,IAAS,IAAA,CAAK,IAAA,CAAK,YAAA;AAAA,MAC9B,cAAc,GAAA,CAAI,MAAA;AAAA,MAClB,KAAK,GAAA,CAAI,GAAA;AAAA,MACT,cAAc,GAAA,CAAI,YAAA;AAAA;AAAA,MAElB,eAAA,EAAiB,GAAA,CAAI,IAAA,GAAO,cAAA,GAAiB,MAAA;AAAA,MAC7C,cAAA,EAAgB,KAAK,IAAA,CAAK,cAAA;AAAA,MAC1B,sBAAA,EAAwB,IAAA;AAAA,MACxB,eAAA,EAAiB;AAAA,KACnB;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,WAAW,KAAA,CAAM;AAAA,QACrB,QAAQ,GAAA,CAAI,MAAA;AAAA,QACZ;AAAA,OACQ,CAAA;AACV,MAAA,MAAM,WAAW,YAAY;AAC3B,QAAA,WAAA,MAAiB,OAAA,IAAW,QAAA,EAAU,UAAA,CAAW,OAAA,EAAS,KAAK,OAAO,CAAA;AAAA,MACxE,CAAA,GAAG;AACH,MAAA,OAAO,GAAA,CAAI,YACP,QAAA,CAAS,OAAA,EAAS,EAAE,YAAA,EAAc,GAAA,CAAI,SAAA,EAAW,CAAA,GACjD,OAAA,CAAA;AAAA,IACN,SAAS,CAAA,EAAG;AACV,MAAA,IAAI,MAAA,CAAO,OAAA;AACT,QAAA,MAAM,IAAI,SAAA,CAAU;AAAA,UAClB,IAAA,EAAM,SAAA;AAAA,UACN,KAAA,EAAO,QAAA;AAAA,UACP,OAAA,EAAS;AAAA,SACV,CAAA;AACH,MAAA,MAAM,KAAA,GAAQ,iBAAiB,CAAC,CAAA;AAChC,MAAA,IAAI,OAAO,MAAM,KAAA;AACjB,MAAA,MAAM,SAAA,CAAU,KAAK,CAAA,EAAG,EAAE,MAAM,QAAA,EAAU,KAAA,EAAO,UAAU,CAAA;AAAA,IAC7D,CAAA,SAAE;AACA,MAAA,MAAA,CAAO,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAAA,IAC7C;AAEA,IAAA,OAAA,CAAQ,EAAE,MAAM,OAAA,EAAS,KAAA,EAAO,IAAI,KAAA,EAAO,KAAA,EAAO,GAAA,CAAI,KAAA,EAAO,CAAA;AAC7D,IAAA,OAAO;AAAA,MACL,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,YAAY,GAAA,CAAI;AAAA,KAClB;AAAA,EACF;AACF","file":"agent-sdk-
|
|
1
|
+
{"version":3,"sources":["../src/engines/agent-sdk.ts"],"names":[],"mappings":"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","file":"agent-sdk-4QJDWM7N.js","sourcesContent":["/**\n * Engine adapter: the Claude Agent SDK (`@anthropic-ai/claude-agent-sdk`).\n * Each `run` is a fresh `query()` — a clean context per loop iteration, which\n * is the whole point. Uses the host's Claude Code auth, so it needs no API key.\n */\n\nimport pTimeout from 'p-timeout';\n\nimport {\n SUBAGENT_TOOLS,\n type AgentRequest,\n type AgentResult,\n type Engine,\n type EngineEventSink,\n type EngineOptions,\n} from './engine.ts';\nimport { mapMessage, newAccumulator } from './message-map.ts';\nimport { LoopError } from '../core/errors.ts';\n\n/**\n * Best-effort classification of an Agent SDK error into a provider-limit\n * `LoopError`, or `undefined` to fall through to the generic ENGINE mapping.\n * The SDK exposes limit state in a few shapes (a thrown error message, an\n * `error` field carrying an `SDKAssistantMessageError` string, and a\n * `rate_limit_info.resetsAt` epoch). We read defensively rather than depend on\n * an exact internal shape:\n * - a rate-limit / overloaded signal → RATE_LIMIT (resets on its own).\n * - a billing / usage / credits signal → QUOTA. A `resetsAt` (when present)\n * makes it auto-waitable; otherwise QUOTA has no reset.\n */\nfunction classifySdkLimit(error: unknown): LoopError | undefined {\n const err = (error ?? {}) as Record<string, unknown>;\n const tag = typeof err.error === 'string' ? err.error : '';\n const message = error instanceof Error ? error.message : String(error);\n const haystack = `${tag} ${message}`.toLowerCase();\n\n const info = (err.rate_limit_info ?? {}) as Record<string, unknown>;\n const resetAt =\n typeof info.resetsAt === 'number'\n ? info.resetsAt\n : typeof info.overageResetsAt === 'number'\n ? info.overageResetsAt\n : undefined;\n\n const isUsage =\n tag === 'billing_error' ||\n info.errorCode === 'credits_required' ||\n /billing|credit|usage limit|quota/.test(haystack);\n if (isUsage) {\n return new LoopError({\n code: 'QUOTA',\n phase: 'engine',\n message: `agent-sdk usage/billing limit: ${message}`,\n cause: error,\n resetAt,\n });\n }\n const isRate =\n tag === 'rate_limit' ||\n tag === 'overloaded' ||\n /rate limit|rate-limit|too many requests|overloaded/.test(haystack);\n if (isRate) {\n return new LoopError({\n code: 'RATE_LIMIT',\n phase: 'engine',\n message: `agent-sdk rate limited: ${message}`,\n cause: error,\n resetAt,\n });\n }\n return undefined;\n}\n\nexport class AgentSdkEngine implements Engine {\n readonly name = 'agent-sdk';\n constructor(private readonly opts: EngineOptions = {}) {}\n\n async run(\n req: AgentRequest,\n onEvent: EngineEventSink,\n signal: AbortSignal,\n ): Promise<AgentResult> {\n // Lazy import so installs/runs that never touch this engine don't pay for it.\n const { query } = await import('@anthropic-ai/claude-agent-sdk');\n\n const acc = newAccumulator(\n req.model ?? this.opts.defaultModel ?? 'unknown',\n );\n const abort = new AbortController();\n const onAbort = () => abort.abort();\n if (signal.aborted) abort.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n\n // The SDK option surface drifts across versions; cast at this boundary.\n const options = {\n model: req.model ?? this.opts.defaultModel,\n systemPrompt: req.system,\n cwd: req.cwd,\n allowedTools: req.allowedTools,\n // A leaf agent may not spawn sub-agents — disallow the spawn tool.\n disallowedTools: req.leaf ? SUBAGENT_TOOLS : undefined,\n permissionMode: this.opts.permissionMode,\n includePartialMessages: true,\n abortController: abort,\n } as Record<string, unknown>;\n\n try {\n const response = query({\n prompt: req.prompt,\n options,\n } as never) as AsyncIterable<unknown>;\n const consume = (async () => {\n for await (const message of response) mapMessage(message, acc, onEvent);\n })();\n await (req.timeoutMs\n ? pTimeout(consume, { milliseconds: req.timeoutMs })\n : consume);\n } catch (e) {\n if (signal.aborted)\n throw new LoopError({\n code: 'ABORTED',\n phase: 'engine',\n message: 'agent-sdk run aborted',\n });\n const limit = classifySdkLimit(e);\n if (limit) throw limit;\n throw LoopError.from(e, { code: 'ENGINE', phase: 'engine' });\n } finally {\n signal.removeEventListener('abort', onAbort);\n }\n\n onEvent({ type: 'usage', usage: acc.usage, model: acc.model });\n return {\n text: acc.text,\n usage: acc.usage,\n model: acc.model,\n stopReason: acc.stopReason,\n };\n }\n}\n"]}
|
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { C as ConditionInput, J as Job, R as RevisionRerun, F as FeedbackFinding, a as FeedbackDecision, O as Outcome, G as GraphPosition, b as FeedbackSeverity, c as FeedbackActionSeverity, d as JobContext, e as RevisionRequest, L as LoopConfig, D as DagConfig, f as JobMeta, g as EngineRef, W as Workspace, A as AgentDef, h as Condition, i as EngineOptions, j as Engine, k as EngineName, l as AgentRequest, U as Usage, m as EngineEventSink, n as AgentResult, E as Environment, o as EnvHandle, p as LoopEvent, q as Forge, B as BudgetConfig, r as LimitPolicy } from './types-Cv_3ymr9.js';
|
|
2
|
+
export { s as AgentContractSummary, t as AgentFailureMode, u as AgentHumanGate, v as AgentJobConfig, w as AgentOutputContract, x as AgentSkillRef, y as AgentTier, z as Budget, H as CommitJobConfig, I as ConditionResult, K as DagNode, M as EngineStreamEvent, N as ForgeOpts, P as GhForge, Q as GroundConfig, S as LogLevel, T as LoopError, V as LoopErrorCode, X as MergeOptions, Y as MockForge, Z as MockForgeOptions, _ as OutcomeStatus, $ as PrInput, a0 as PrPatch, a1 as PrRef, a2 as RawPredicate, a3 as RetryPolicy, a4 as SUBAGENT_TOOLS, a5 as Skill, a6 as agentContract, a7 as agentJob, a8 as buildChecksArgs, a9 as buildCreateArgs, aa as buildEditArgs, ab as buildMergeArgs, ac as buildViewArgs, ad as commitJob, ae as defineAgent, af as defineSkill, ag as fnJob, ah as fromFile, ai as isEngine, aj as isEnvironment, ak as isForge, al as resolveSystem } from './types-Cv_3ymr9.js';
|
|
3
|
+
|
|
4
|
+
interface RevisionRequestInput {
|
|
5
|
+
target?: string;
|
|
6
|
+
reason?: string;
|
|
7
|
+
findings?: FeedbackFinding[];
|
|
8
|
+
rerun?: RevisionRerun;
|
|
9
|
+
source?: string;
|
|
10
|
+
decision?: FeedbackDecision;
|
|
11
|
+
}
|
|
12
|
+
declare function normalizeFeedbackSeverity(severity: FeedbackSeverity | undefined): FeedbackActionSeverity;
|
|
13
|
+
declare function isRequiredFeedbackSeverity(severity: FeedbackSeverity | undefined): boolean;
|
|
14
|
+
declare function revisionRequest(input: RevisionRequestInput, over?: Partial<Outcome>): Outcome;
|
|
15
|
+
declare function kickback(to: string, reason: string, over?: Partial<Outcome>): Outcome;
|
|
16
|
+
/**
|
|
17
|
+
* The single accessor for an outcome's revision request. `Outcome.revision` is
|
|
18
|
+
* the one channel a producer sets (`revisionRequest`, `kickback`, `reviewPanel`,
|
|
19
|
+
* dag routing), so there is exactly one place to read it — no parallel `kickback`
|
|
20
|
+
* field or `data` copy to keep in sync.
|
|
21
|
+
*/
|
|
22
|
+
declare function revisionFromOutcome(outcome: Outcome): RevisionRequest | undefined;
|
|
23
|
+
declare function feedbackBlock(outcome: Outcome): string;
|
|
24
|
+
declare function graphPositionBlock(graph: GraphPosition): string;
|
|
25
|
+
type ReviewTarget = {
|
|
26
|
+
name?: string;
|
|
27
|
+
review: ConditionInput;
|
|
28
|
+
} | {
|
|
29
|
+
name?: string;
|
|
30
|
+
job: Job;
|
|
31
|
+
};
|
|
32
|
+
interface ReviewPanelConfig {
|
|
33
|
+
label?: string;
|
|
34
|
+
reviewers: ReviewTarget[];
|
|
35
|
+
/** Default `all`: every reviewer must pass. A number means k-of-n over all reviewers. */
|
|
36
|
+
pass?: 'all' | number;
|
|
37
|
+
/** When set, a failing panel emits a targeted revision request for dag routing. */
|
|
38
|
+
target?: string;
|
|
39
|
+
rerun?: RevisionRerun;
|
|
40
|
+
}
|
|
41
|
+
declare function reviewPanel(config: ReviewPanelConfig): Job;
|
|
42
|
+
interface ReviewContextConfig {
|
|
43
|
+
diff?: boolean;
|
|
44
|
+
files?: string[];
|
|
45
|
+
ledger?: boolean;
|
|
46
|
+
tests?: boolean | {
|
|
47
|
+
command: string;
|
|
48
|
+
args?: string[];
|
|
49
|
+
cwd?: string;
|
|
50
|
+
};
|
|
51
|
+
maxChars?: number;
|
|
52
|
+
}
|
|
53
|
+
declare function reviewContext(config: ReviewContextConfig): (ctx: JobContext, last: Outcome | undefined) => Promise<string>;
|
|
3
54
|
|
|
4
55
|
/**
|
|
5
56
|
* The loop primitive. `loop(config)` returns a `Job`, so loops nest by simply
|
|
@@ -1001,9 +1052,63 @@ declare function readRunStatus(runId: string): RunStatus | undefined;
|
|
|
1001
1052
|
declare function listRuns(): RunStatus[];
|
|
1002
1053
|
/** Path to a run's appended event stream (for tailing). */
|
|
1003
1054
|
declare function runEventsPath(runId: string): string;
|
|
1055
|
+
/** Path to a run's semantic record stream. */
|
|
1056
|
+
declare function runSemanticRecordsPath(runId: string): string;
|
|
1004
1057
|
/** A compact one-line rendering of an event, for `loops tail`. */
|
|
1005
1058
|
declare function formatEvent(event: LoopEvent): string;
|
|
1006
1059
|
|
|
1060
|
+
type SemanticDecision = FeedbackDecision;
|
|
1061
|
+
type SemanticRunRecord = {
|
|
1062
|
+
kind: 'dispatch';
|
|
1063
|
+
ts: number;
|
|
1064
|
+
path: string[];
|
|
1065
|
+
unit: 'job' | 'dag-node';
|
|
1066
|
+
label?: string;
|
|
1067
|
+
node?: string;
|
|
1068
|
+
/** Present for a dag-node: which run this is (1-based; +1 per kickback re-run). */
|
|
1069
|
+
attempt?: number;
|
|
1070
|
+
} | {
|
|
1071
|
+
kind: 'completion';
|
|
1072
|
+
ts: number;
|
|
1073
|
+
path: string[];
|
|
1074
|
+
unit: 'job' | 'loop' | 'dag' | 'dag-node';
|
|
1075
|
+
label?: string;
|
|
1076
|
+
outcome: SemanticOutcome;
|
|
1077
|
+
iterations?: number;
|
|
1078
|
+
/** Present for a dag-node: which run this completion is for. */
|
|
1079
|
+
attempt?: number;
|
|
1080
|
+
} | {
|
|
1081
|
+
kind: 'surfacing';
|
|
1082
|
+
ts: number;
|
|
1083
|
+
path: string[];
|
|
1084
|
+
source: 'loop-review' | 'dag-kickback';
|
|
1085
|
+
decision: SemanticDecision;
|
|
1086
|
+
severity?: FeedbackActionSeverity;
|
|
1087
|
+
from?: string;
|
|
1088
|
+
to?: string;
|
|
1089
|
+
reason: string;
|
|
1090
|
+
note?: string;
|
|
1091
|
+
} | {
|
|
1092
|
+
kind: 'revision-emitted';
|
|
1093
|
+
ts: number;
|
|
1094
|
+
path: string[];
|
|
1095
|
+
sourceEvent: 'job:end';
|
|
1096
|
+
revision: RevisionRequest;
|
|
1097
|
+
} | {
|
|
1098
|
+
kind: 'revision-routed';
|
|
1099
|
+
ts: number;
|
|
1100
|
+
path: string[];
|
|
1101
|
+
sourceEvent: 'loop:review' | 'dag:kickback';
|
|
1102
|
+
decision: SemanticDecision;
|
|
1103
|
+
revision: RevisionRequest;
|
|
1104
|
+
};
|
|
1105
|
+
interface SemanticOutcome {
|
|
1106
|
+
status: Outcome['status'];
|
|
1107
|
+
summary?: string;
|
|
1108
|
+
confidence?: number;
|
|
1109
|
+
}
|
|
1110
|
+
declare function semanticRecordsFromEvent(event: LoopEvent): SemanticRunRecord[];
|
|
1111
|
+
|
|
1007
1112
|
/**
|
|
1008
1113
|
* Public API. A loop-definition file imports from here and `export default`s a
|
|
1009
1114
|
* `Job` (usually a `loop(...)` or `dag(...)`). The CLI runs that default export.
|
|
@@ -1015,4 +1120,4 @@ declare function formatEvent(event: LoopEvent): string;
|
|
|
1015
1120
|
/** Identity helper that pins the type of a default export to `Job`. */
|
|
1016
1121
|
declare function defineJob(job: Job): Job;
|
|
1017
1122
|
|
|
1018
|
-
export { type AgentCheckConfig, AgentDef, AgentRequest, AgentResult, BudgetConfig, type CommitInput, type CommitRecord, type CompactOptions, Condition, ConditionInput, type ConsolidateJobConfig, type ConsolidateOptions, DagConfig, EXIT_PAUSED, Engine, type EngineFactory, EngineName, EngineOptions, EngineRef, EngineRegistry, EnvHandle, Environment, Forge, type GroundOptions, type IsolatedOptions, Job, JobContext, JobMeta, type LedgerEntry, LimitPolicy, type LogQuery, LoopConfig, LoopEvent, type MergeJobConfig, type MergeResult, type MergeSynthesisConfig, type MergeSynthesisResult, MockEngine, type MockEnvOptions, MockEnvironment, type MockResponder, Outcome, type PromptNote, type PullRequestJobConfig, type PushJobConfig, type PushOptions, type PushResult, type RetrieveOptions, type RunLive, type RunOptions, type RunResult, type RunStatus, Stats, type StatsSnapshot, type TournamentConfig, Usage, Workspace, type WorktreeHandle, addWorktree, agentCheck, all, always, any, appendLedger, appendPrompt, bodyPassed, commandSucceeds, commit, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, dag, defineJob, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, forgeChecks, formatEvent, gateJob, groundingText, hasStagedChanges, headSha, isDirty, isRepo, isolated, jobMeta, ledgerPath, listRuns, log, loop, mergeAbort, mergeBranch, mergeJob, mergeNoCommit, mergeSynthesis, minConfidence, mockVerdict, never, not, parallel, predicate, promptPath, pullRequestJob, push, pushJob, quorum, readLedger, readPrompt, readRunStatus, removeWorktree, renderPlan, resetLedger, resetPrompt, retrieveLedger, run, runEventsPath, runsHome, sequence, stageAll, toCondition, tournament };
|
|
1123
|
+
export { type AgentCheckConfig, AgentDef, AgentRequest, AgentResult, BudgetConfig, type CommitInput, type CommitRecord, type CompactOptions, Condition, ConditionInput, type ConsolidateJobConfig, type ConsolidateOptions, DagConfig, EXIT_PAUSED, Engine, type EngineFactory, EngineName, EngineOptions, EngineRef, EngineRegistry, EnvHandle, Environment, FeedbackActionSeverity, FeedbackDecision, FeedbackFinding, FeedbackSeverity, Forge, GraphPosition, type GroundOptions, type IsolatedOptions, Job, JobContext, JobMeta, type LedgerEntry, LimitPolicy, type LogQuery, LoopConfig, LoopEvent, type MergeJobConfig, type MergeResult, type MergeSynthesisConfig, type MergeSynthesisResult, MockEngine, type MockEnvOptions, MockEnvironment, type MockResponder, Outcome, type PromptNote, type PullRequestJobConfig, type PushJobConfig, type PushOptions, type PushResult, type RetrieveOptions, type ReviewContextConfig, type ReviewPanelConfig, RevisionRequest, type RevisionRequestInput, RevisionRerun, type RunLive, type RunOptions, type RunResult, type RunStatus, type SemanticDecision, type SemanticOutcome, type SemanticRunRecord, Stats, type StatsSnapshot, type TournamentConfig, Usage, Workspace, type WorktreeHandle, addWorktree, agentCheck, all, always, any, appendLedger, appendPrompt, bodyPassed, commandSucceeds, commit, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, dag, defineJob, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, feedbackBlock, forgeChecks, formatEvent, gateJob, graphPositionBlock, groundingText, hasStagedChanges, headSha, isDirty, isRepo, isRequiredFeedbackSeverity, isolated, jobMeta, kickback, ledgerPath, listRuns, log, loop, mergeAbort, mergeBranch, mergeJob, mergeNoCommit, mergeSynthesis, minConfidence, mockVerdict, never, normalizeFeedbackSeverity, not, parallel, predicate, promptPath, pullRequestJob, push, pushJob, quorum, readLedger, readPrompt, readRunStatus, removeWorktree, renderPlan, resetLedger, resetPrompt, retrieveLedger, reviewContext, reviewPanel, revisionFromOutcome, revisionRequest, run, runEventsPath, runSemanticRecordsPath, runsHome, semanticRecordsFromEvent, sequence, stageAll, toCondition, tournament };
|
package/dist/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { mergeNoCommit, stageAll, commit, mergeAbort, log, setMeta, jobMeta, isRepo, addWorktree, childContext, composeCommitBody, mergeBranch, removeWorktree, deleteBranch, push, consolidate, toCondition, GhForge } from './chunk-
|
|
2
|
-
export { Budget, EXIT_PAUSED, EngineRegistry, GhForge, MockForge, Stats, addWorktree, agentCheck, agentJob, all, always, any, appendLedger, appendPrompt, bodyPassed, buildChecksArgs, buildCreateArgs, buildEditArgs, buildMergeArgs, buildViewArgs, commandSucceeds, commit, commitJob, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, defineAgent, defineSkill, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, fnJob, forgeChecks, formatEvent, fromFile, gateJob, groundingText, hasStagedChanges, headSha, isDirty, isForge, isRepo, jobMeta, kickback, ledgerPath, listRuns, log, loop, mergeAbort, mergeBranch, mergeNoCommit, minConfidence, never, not, predicate, promptPath, push, quorum, readLedger, readPrompt, readRunStatus, removeWorktree, renderPlan, resetLedger, resetPrompt, resolveSystem, retrieveLedger, run, runEventsPath, runsHome, stageAll, toCondition } from './chunk-
|
|
1
|
+
import { mergeNoCommit, stageAll, commit, mergeAbort, log, setMeta, jobMeta, isRepo, addWorktree, childContext, composeCommitBody, mergeBranch, removeWorktree, deleteBranch, push, consolidate, toCondition, revisionFromOutcome, GhForge } from './chunk-WM5QVHM2.js';
|
|
2
|
+
export { Budget, EXIT_PAUSED, EngineRegistry, GhForge, MockForge, Stats, addWorktree, agentCheck, agentContract, agentJob, all, always, any, appendLedger, appendPrompt, bodyPassed, buildChecksArgs, buildCreateArgs, buildEditArgs, buildMergeArgs, buildViewArgs, commandSucceeds, commit, commitJob, compactLedger, composeCommitBody, conflictedFiles, consolidate, consolidateJob, currentBranch, defineAgent, defineSkill, deleteBranch, describeConditions, ensureIgnored, exitCodeFor, feedbackBlock, fnJob, forgeChecks, formatEvent, fromFile, gateJob, graphPositionBlock, groundingText, hasStagedChanges, headSha, isDirty, isForge, isRepo, isRequiredFeedbackSeverity, jobMeta, kickback, ledgerPath, listRuns, log, loop, mergeAbort, mergeBranch, mergeNoCommit, minConfidence, never, normalizeFeedbackSeverity, not, predicate, promptPath, push, quorum, readLedger, readPrompt, readRunStatus, removeWorktree, renderPlan, resetLedger, resetPrompt, resolveSystem, retrieveLedger, reviewContext, reviewPanel, revisionFromOutcome, revisionRequest, run, runEventsPath, runSemanticRecordsPath, runsHome, semanticRecordsFromEvent, stageAll, toCondition } from './chunk-WM5QVHM2.js';
|
|
3
3
|
import './chunk-JFTXJ7I2.js';
|
|
4
|
-
export { SUBAGENT_TOOLS, isEngine } from './chunk-
|
|
4
|
+
export { SUBAGENT_TOOLS, isEngine } from './chunk-MA6NDQMO.js';
|
|
5
5
|
import './chunk-Y2SD7GBL.js';
|
|
6
6
|
import { LoopError } from './chunk-I3STY7U6.js';
|
|
7
7
|
export { LoopError } from './chunk-I3STY7U6.js';
|
|
@@ -160,6 +160,7 @@ function dag(config) {
|
|
|
160
160
|
const limit = pLimit(limitN);
|
|
161
161
|
const results = /* @__PURE__ */ new Map();
|
|
162
162
|
const memo = /* @__PURE__ */ new Map();
|
|
163
|
+
const attempts = /* @__PURE__ */ new Map();
|
|
163
164
|
let stopped = false;
|
|
164
165
|
const pendingKickback = /* @__PURE__ */ new Map();
|
|
165
166
|
const nodeCtx = (name, workspace, environment) => childContext(parent, {
|
|
@@ -167,7 +168,14 @@ function dag(config) {
|
|
|
167
168
|
path: [...path, name],
|
|
168
169
|
workspace,
|
|
169
170
|
environment,
|
|
170
|
-
lastReview: pendingKickback.get(name)
|
|
171
|
+
lastReview: pendingKickback.get(name),
|
|
172
|
+
graph: {
|
|
173
|
+
dag: config.name,
|
|
174
|
+
node: name,
|
|
175
|
+
path: [...path, name],
|
|
176
|
+
needs: nodes.get(name).needs ?? [],
|
|
177
|
+
dependents: dependents.get(name) ?? []
|
|
178
|
+
}
|
|
171
179
|
});
|
|
172
180
|
const mergeLimit = pLimit(1);
|
|
173
181
|
let forkSeq2 = 0;
|
|
@@ -264,11 +272,12 @@ function dag(config) {
|
|
|
264
272
|
path,
|
|
265
273
|
node: name,
|
|
266
274
|
phase,
|
|
267
|
-
outcome: outcome2
|
|
275
|
+
outcome: outcome2,
|
|
276
|
+
attempt: attempts.get(name)
|
|
268
277
|
});
|
|
269
278
|
if (phase === "done" && outcome2.status !== "pass" && nodes.get(name).optional !== true && stopOnError && // A node requesting a kickback is going to be re-run — don't let its
|
|
270
279
|
// (provisional) non-pass abort siblings before the feedback is resolved.
|
|
271
|
-
!(maxKickbacks > 0 && outcome2
|
|
280
|
+
!(maxKickbacks > 0 && revisionFromOutcome(outcome2)?.target)) {
|
|
272
281
|
stopped = true;
|
|
273
282
|
}
|
|
274
283
|
return outcome2;
|
|
@@ -278,6 +287,7 @@ function dag(config) {
|
|
|
278
287
|
if (existing) return existing;
|
|
279
288
|
const node = nodes.get(name);
|
|
280
289
|
const promise = (async () => {
|
|
290
|
+
attempts.set(name, (attempts.get(name) ?? 0) + 1);
|
|
281
291
|
try {
|
|
282
292
|
const needs = node.needs ?? [];
|
|
283
293
|
const deps = await Promise.all(needs.map(run2));
|
|
@@ -324,7 +334,8 @@ function dag(config) {
|
|
|
324
334
|
ts: ts(),
|
|
325
335
|
path,
|
|
326
336
|
node: name,
|
|
327
|
-
phase: "start"
|
|
337
|
+
phase: "start",
|
|
338
|
+
attempt: attempts.get(name)
|
|
328
339
|
});
|
|
329
340
|
return { outcome: await runNodeJob(name, node), phase: "done" };
|
|
330
341
|
}
|
|
@@ -369,10 +380,15 @@ function dag(config) {
|
|
|
369
380
|
});
|
|
370
381
|
for (; ; ) {
|
|
371
382
|
const from = order.find(
|
|
372
|
-
(n) =>
|
|
383
|
+
(n) => {
|
|
384
|
+
const result = results.get(n);
|
|
385
|
+
return result !== void 0 && revisionFromOutcome(result)?.target !== void 0 && !rejected.has(n);
|
|
386
|
+
}
|
|
373
387
|
);
|
|
374
388
|
if (!from) break;
|
|
375
|
-
const
|
|
389
|
+
const request = revisionFromOutcome(results.get(from));
|
|
390
|
+
const to = request.target;
|
|
391
|
+
const { reason } = request;
|
|
376
392
|
const allow = nodes.get(from).acceptsKickbackTo;
|
|
377
393
|
const note = !nodes.has(to) ? `unknown node "${to}"` : !ancestorsOf(from).has(to) ? `"${to}" is not an ancestor of "${from}"` : allow && !allow.includes(to) ? `"${from}" does not accept kickback to "${to}"` : void 0;
|
|
378
394
|
if (note) {
|
|
@@ -401,7 +417,7 @@ function dag(config) {
|
|
|
401
417
|
pendingKickback.set(to, {
|
|
402
418
|
status: "fail",
|
|
403
419
|
summary: `Kicked back from "${from}": ${reason}`,
|
|
404
|
-
|
|
420
|
+
revision: { ...request, source: request.source ?? from }
|
|
405
421
|
});
|
|
406
422
|
stopped = false;
|
|
407
423
|
await Promise.all(names.map(run2));
|