@shapeshift-labs/frontier-swarm 0.2.0 → 0.4.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 +35 -4
- package/benchmarks/package-bench.mjs +103 -1
- package/dist/index.d.ts +801 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1302 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ The published Frontier package family is generated from one shared package catal
|
|
|
36
36
|
- [`@shapeshift-labs/frontier-workflow`](https://www.npmjs.com/package/@shapeshift-labs/frontier-workflow): Serializable durable workflow/process manifests for Frontier apps, including steps, waits, approvals, timers, retries, expected patches, compensation, records, timelines, and registry graph output.
|
|
37
37
|
- [`@shapeshift-labs/frontier-worker`](https://www.npmjs.com/package/@shapeshift-labs/frontier-worker): Serializable worker and edge task descriptors for Frontier apps, including queues, idempotency keys, retry and timeout policy, declared reads/writes/effects, snapshots, patch outputs, produced assets, execution records, logs, trace links, proof hashes, dedupe indexes, and registry graph output.
|
|
38
38
|
- [`@shapeshift-labs/frontier-queue`](https://www.npmjs.com/package/@shapeshift-labs/frontier-queue): Serializable durable queue state, leases, retries, dedupe keys, patch-carrying jobs, dead-letter records, replay evidence, and queue inspection for Frontier apps.
|
|
39
|
-
- [`@shapeshift-labs/frontier-swarm-codex`](https://www.npmjs.com/package/@shapeshift-labs/frontier-swarm-codex): Node Codex CLI adapter for Frontier swarm plans, including prompt rendering, worktree and snapshot workspaces, Codex argument
|
|
39
|
+
- [`@shapeshift-labs/frontier-swarm-codex`](https://www.npmjs.com/package/@shapeshift-labs/frontier-swarm-codex): Node Codex CLI adapter for Frontier swarm plans, including prompt rendering, worktree and snapshot workspaces, Codex argument compatibility, JSONL capture, verification commands, pid-backed stop, collect/apply workflows, merge indexes, queue overlays, merge bundles, and result artifacts.
|
|
40
40
|
- [`@shapeshift-labs/frontier-kv`](https://www.npmjs.com/package/@shapeshift-labs/frontier-kv): Serializable in-memory key/value state for Frontier apps, including TTL, versioned compare-and-set, batched patch mutations, scans, watchers, snapshots, JSONL event evidence, and replay verification.
|
|
41
41
|
- [`@shapeshift-labs/frontier-kv-locks`](https://www.npmjs.com/package/@shapeshift-labs/frontier-kv-locks): Lease-style lock records on top of Frontier KV, including acquire, renew, release, fencing tokens, expiration, owner evidence, and replayable lock events.
|
|
42
42
|
- [`@shapeshift-labs/frontier-kv-rate-limit`](https://www.npmjs.com/package/@shapeshift-labs/frontier-kv-rate-limit): Patch-native rate limit buckets for Frontier KV, including fixed windows, sliding windows, token buckets, deterministic refill, consume evidence, and reset records.
|
|
@@ -211,10 +211,13 @@ Large swarms need a control plane, not just a flat worker loop. `frontier-swarm`
|
|
|
211
211
|
import {
|
|
212
212
|
checkSwarmBudget,
|
|
213
213
|
createSwarmArtifactIndex,
|
|
214
|
+
createSwarmEventStream,
|
|
214
215
|
createSwarmLeases,
|
|
215
216
|
createSwarmMergePlan,
|
|
217
|
+
createSwarmQueueSnapshot,
|
|
216
218
|
createSwarmReviewPlan,
|
|
217
|
-
createSwarmSchedule
|
|
219
|
+
createSwarmSchedule,
|
|
220
|
+
routeSwarmEventToMailboxes
|
|
218
221
|
} from '@shapeshift-labs/frontier-swarm';
|
|
219
222
|
|
|
220
223
|
const schedule = createSwarmSchedule({
|
|
@@ -237,10 +240,27 @@ The scale APIs are runtime-neutral and serializable:
|
|
|
237
240
|
- dependency DAGs are compiled into `plan.graph`,
|
|
238
241
|
- `createSwarmSchedule` returns ready, blocked, running, completed, and failed jobs under lane/compute/contention limits,
|
|
239
242
|
- `createSwarmLeases` gives workers expiring leases with fencing tokens,
|
|
243
|
+
- lane/task `capabilities` and `resourceRequirements` can reserve browser work with lower concurrency, port pools, profile directories, and explicit capability checks,
|
|
244
|
+
- `createSwarmQueueSnapshot` and run checkpoints give durable queue/run-store adapters a stable serialization shape,
|
|
245
|
+
- `createSwarmEventStream` and `routeSwarmEventToMailboxes` route global, lane, task, and worker events into coordinator-facing JSONL streams,
|
|
240
246
|
- `checkSwarmBudget` records token/cost/time/retry budget decisions,
|
|
241
247
|
- `createSwarmArtifactIndex` groups evidence, timelines, logs, and produced files,
|
|
242
248
|
- `createSwarmReviewPlan` samples or requires reviewer assignments,
|
|
243
249
|
- `createSwarmMergePlan` blocks jobs with failed checks, required reviews, ownership violations, or conflicting changed paths,
|
|
250
|
+
- job results include merge-readiness classification: `discovery-only`, `patch-candidate`, `verified-patch`, `rejected`, or `blocked`,
|
|
251
|
+
- `ownershipRegions` allow hot files to be split into semantic regions such as `content.docs.*` or `adminSettings.quota.*`; merge conflict detection compares explicit changed regions when both sides report them and falls back to path conflicts when either side omits regions,
|
|
252
|
+
- `createSwarmMergeBundle` builds a compact worker `merge.json` shape with touched owned files, patch path, evidence, verification, queue items satisfied, risk, and disposition,
|
|
253
|
+
- `createSwarmQueueOverlay` and `deriveSwarmQueueStatus` keep central queue files immutable while deriving status from worker result overlays,
|
|
254
|
+
- `createSwarmMergeIndex` records stale/patch status and region-aware conflicts so coordinators can review ready bundles before reading every worker directory,
|
|
255
|
+
- `checkSwarmRegionOwnership` makes semantic region ownership enforceable instead of only advisory,
|
|
256
|
+
- `createSwarmHotspotReport` highlights repeatedly touched files and suggests module/region splits for merge throughput,
|
|
257
|
+
- `createSwarmReviewerLanePlan` turns risky/conflicting merge bundles into reviewer-lane tasks,
|
|
258
|
+
- `createSwarmRunStoreShards` describes sharded event/result/checkpoint paths for large run stores,
|
|
259
|
+
- `createSwarmMergeAdmission` limits ready merges by count, touched paths/regions, and risk budget,
|
|
260
|
+
- `createSwarmPatchStackPlan` clusters compatible bundles into candidate patch stacks by lane, path, region, disposition, and risk so reviewers can evaluate batches instead of individual worker directories,
|
|
261
|
+
- `createSwarmContextPack` gives workers compact task context: relevant files, API maps, known failures, focused/oracle commands, expected evidence, exclusions, evidence schema, playbooks, and explicit dead ends to avoid,
|
|
262
|
+
- `createSwarmOracleCorpus` indexes deterministic reference artifacts such as traces, snapshots, classifications, expected outputs, or fixtures without assuming a project domain,
|
|
263
|
+
- `createSwarmLanePlaybook` turns successful prior bundles into persistent lane-specific guidance with commands, hot paths, evidence patterns, and avoid-investigating notes,
|
|
244
264
|
- `decomposeSwarmFeature` creates an initial task queue for feature work across lanes.
|
|
245
265
|
|
|
246
266
|
## Hierarchical Compute
|
|
@@ -260,11 +280,22 @@ That lets a parent swarm route implementation jobs to a deep model while evidenc
|
|
|
260
280
|
- `defineSwarmManifest`, `createSwarmManifest`
|
|
261
281
|
- `defineSwarmTasks`
|
|
262
282
|
- `compileSwarm`, `validateSwarmManifest`
|
|
283
|
+
- `createSwarmTaskSelection`
|
|
263
284
|
- `createSwarmPlan`, `createSwarmRun`
|
|
264
285
|
- `createSwarmSchedule`, `createSwarmLeases`
|
|
286
|
+
- `createSwarmQueueSnapshot`, `createSwarmRunCheckpoint`
|
|
287
|
+
- `createSwarmQueueOverlay`, `deriveSwarmQueueStatus`
|
|
288
|
+
- `createSwarmEventStream`, `createSwarmMailbox`, `routeSwarmEventToMailboxes`
|
|
265
289
|
- `checkSwarmBudget`
|
|
266
290
|
- `createSwarmArtifactIndex`
|
|
267
|
-
- `createSwarmReviewPlan`, `createSwarmMergePlan`
|
|
291
|
+
- `createSwarmReviewPlan`, `createSwarmReviewerLanePlan`, `createSwarmMergePlan`
|
|
292
|
+
- `createSwarmMergeBundle`
|
|
293
|
+
- `createSwarmMergeIndex`, `createSwarmMergeAdmission`
|
|
294
|
+
- `createSwarmHotspotReport`, `createSwarmRunStoreShards`
|
|
295
|
+
- `createSwarmPatchStackPlan`
|
|
296
|
+
- `createSwarmContextPack`, `createSwarmOracleCorpus`, `createSwarmLanePlaybook`
|
|
297
|
+
- `classifySwarmMergeReadiness`, `classifySwarmMergeDisposition`
|
|
298
|
+
- `resolveSwarmChangedRegions`, `checkSwarmRegionOwnership`
|
|
268
299
|
- `decomposeSwarmFeature`
|
|
269
300
|
- `recordSwarmEvent`, `completeSwarmJob`
|
|
270
301
|
- `resolveSwarmCompute`
|
|
@@ -280,7 +311,7 @@ Run the package-local benchmark:
|
|
|
280
311
|
npm run bench
|
|
281
312
|
```
|
|
282
313
|
|
|
283
|
-
The benchmark writes `benchmarks/results/frontier-swarm-package-bench-latest.json` when run from the monorepo. These are Frontier-only package measurements for plan creation, manifest validation, hierarchical compute resolution, ownership checks, run
|
|
314
|
+
The benchmark writes `benchmarks/results/frontier-swarm-package-bench-latest.json` when run from the monorepo. These are Frontier-only package measurements for plan creation, manifest validation, hierarchical compute resolution, ownership checks, scheduling/leases, queue snapshots, queue overlays, merge bundles, merge indexes, merge admission, hotspot reports, context packs, oracle corpora, lane playbooks, patch stack plans, event routing, run checkpoints, JSONL, and proof hashing.
|
|
284
315
|
|
|
285
316
|
## Source Repository
|
|
286
317
|
|
|
@@ -4,13 +4,28 @@ import { performance } from 'node:perf_hooks';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import {
|
|
6
6
|
checkSwarmOwnership,
|
|
7
|
+
createSwarmContextPack,
|
|
8
|
+
createSwarmHotspotReport,
|
|
9
|
+
createSwarmLanePlaybook,
|
|
10
|
+
createSwarmMergeAdmission,
|
|
7
11
|
createSwarmManifest,
|
|
12
|
+
createSwarmEventStream,
|
|
13
|
+
createSwarmLeases,
|
|
14
|
+
createSwarmMergeBundle,
|
|
15
|
+
createSwarmMergeIndex,
|
|
16
|
+
createSwarmOracleCorpus,
|
|
17
|
+
createSwarmPatchStackPlan,
|
|
8
18
|
createSwarmPlan,
|
|
9
19
|
createSwarmProof,
|
|
20
|
+
createSwarmQueueOverlay,
|
|
21
|
+
createSwarmQueueSnapshot,
|
|
10
22
|
createSwarmRun,
|
|
23
|
+
createSwarmRunCheckpoint,
|
|
24
|
+
createSwarmSchedule,
|
|
11
25
|
decodeSwarmJsonl,
|
|
12
26
|
defineSwarmTasks,
|
|
13
27
|
encodeSwarmJsonl,
|
|
28
|
+
routeSwarmEventToMailboxes,
|
|
14
29
|
resolveSwarmCompute,
|
|
15
30
|
validateSwarmManifest
|
|
16
31
|
} from '../dist/index.js';
|
|
@@ -31,6 +46,11 @@ let plan = createSwarmPlan(manifest, tasks, { limit: 64 });
|
|
|
31
46
|
let run = createSwarmRun({ plan });
|
|
32
47
|
let jsonl = encodeSwarmJsonl([plan, run]);
|
|
33
48
|
let cursor = 0;
|
|
49
|
+
let schedule = createSwarmSchedule({ plan, maxReadyJobs: 128 });
|
|
50
|
+
let leases = createSwarmLeases({ schedule, workerId: 'bench-worker', now: 1000, leaseMs: 60000, count: 16 });
|
|
51
|
+
let eventStream = createSwarmEventStream({ runId: 'bench', root: 'agent-runs/bench/streams', lanes: manifest.lanes });
|
|
52
|
+
let bundles = makeBundles(plan, 32);
|
|
53
|
+
let mergeIndex = createSwarmMergeIndex({ bundles });
|
|
34
54
|
|
|
35
55
|
const rows = [
|
|
36
56
|
measure('create-plan-' + taskCount, 8, () => {
|
|
@@ -49,7 +69,70 @@ const rows = [
|
|
|
49
69
|
return jsonl.length;
|
|
50
70
|
}),
|
|
51
71
|
measure('jsonl-decode', 16, () => decodeSwarmJsonl(jsonl).length),
|
|
52
|
-
measure('proof', 16, () => createSwarmProof(plan).hash.length)
|
|
72
|
+
measure('proof', 16, () => createSwarmProof(plan).hash.length),
|
|
73
|
+
measure('schedule-lease-' + taskCount, 8, () => {
|
|
74
|
+
schedule = createSwarmSchedule({ plan, maxReadyJobs: 128, maxComputeConcurrency: { fast: 64, deep: 32 } });
|
|
75
|
+
leases = createSwarmLeases({ schedule, workerId: 'bench-worker', now: 1000 + cursor++, leaseMs: 60000, count: 16 });
|
|
76
|
+
return schedule.ready.length + leases.length;
|
|
77
|
+
}),
|
|
78
|
+
measure('queue-snapshot-' + taskCount, 8, () => {
|
|
79
|
+
const snapshot = createSwarmQueueSnapshot({ plan, run, leases, generatedAt: 2000 + cursor++ });
|
|
80
|
+
return snapshot.summary.jobCount + snapshot.summary.leaseCount;
|
|
81
|
+
}),
|
|
82
|
+
measure('run-checkpoint-' + taskCount, 16, () => createSwarmRunCheckpoint({ run, sequence: cursor++ }).hash.length),
|
|
83
|
+
measure('merge-bundle-' + taskCount, 32, () => createSwarmMergeBundle({
|
|
84
|
+
job: plan.jobs[cursor % plan.jobs.length],
|
|
85
|
+
result: {
|
|
86
|
+
jobId: plan.jobs[cursor++ % plan.jobs.length].id,
|
|
87
|
+
status: 'completed',
|
|
88
|
+
changedPaths: ['src/runtime/file.ts'],
|
|
89
|
+
verification: [{ status: 0 }]
|
|
90
|
+
},
|
|
91
|
+
patchPath: 'agent-runs/bench/changes.patch'
|
|
92
|
+
}).id.length),
|
|
93
|
+
measure('queue-overlay-' + taskCount, 16, () => createSwarmQueueOverlay({ bundles, generatedAt: 3000 + cursor++ }).summary.entryCount),
|
|
94
|
+
measure('merge-index-' + taskCount, 8, () => {
|
|
95
|
+
bundles = makeBundles(plan, 32);
|
|
96
|
+
mergeIndex = createSwarmMergeIndex({ bundles, generatedAt: 4000 + cursor++ });
|
|
97
|
+
return mergeIndex.summary.entryCount + mergeIndex.summary.conflictCount;
|
|
98
|
+
}),
|
|
99
|
+
measure('merge-admission-' + taskCount, 16, () => createSwarmMergeAdmission({ index: mergeIndex, maxReady: 8, maxChangedPaths: 16 }).summary.admittedCount),
|
|
100
|
+
measure('hotspot-report-' + taskCount, 16, () => createSwarmHotspotReport({ bundles, threshold: 3 }).summary.recommendationCount),
|
|
101
|
+
measure('context-pack-' + taskCount, 32, () => createSwarmContextPack({
|
|
102
|
+
job: plan.jobs[cursor % plan.jobs.length],
|
|
103
|
+
files: ['src/runtime/file.ts', 'test/runtime-smoke.mjs'],
|
|
104
|
+
apiMap: {
|
|
105
|
+
runtime: ['createRuntime', 'stepRuntime'],
|
|
106
|
+
tests: ['runtime smoke gate']
|
|
107
|
+
},
|
|
108
|
+
knownFailures: ['shared renderer gate is noisy on old snapshots'],
|
|
109
|
+
oracleCommands: [{ name: 'focused-gate', command: 'npm', args: ['test'], required: true }],
|
|
110
|
+
evidenceSchema: { type: 'object', required: ['ok', 'commands'] },
|
|
111
|
+
avoidInvestigating: ['unrelated route snapshots'],
|
|
112
|
+
playbookIds: ['runtime-playbook']
|
|
113
|
+
}).files.length),
|
|
114
|
+
measure('oracle-corpus-' + taskCount, 32, () => createSwarmOracleCorpus({
|
|
115
|
+
artifacts: [
|
|
116
|
+
{ id: 'trace-runtime', path: 'oracles/runtime-trace.jsonl', kind: 'trace', tags: ['runtime', 'reference'], hash: 'fnv1a32:trace' },
|
|
117
|
+
{ id: 'snapshot-routing', path: 'oracles/routing-snapshot.json', kind: 'snapshot', tags: ['routing', 'reference'] }
|
|
118
|
+
]
|
|
119
|
+
}).summary.artifactCount),
|
|
120
|
+
measure('lane-playbook-' + taskCount, 16, () => createSwarmLanePlaybook({
|
|
121
|
+
lane: 'runtime',
|
|
122
|
+
successfulBundles: bundles,
|
|
123
|
+
notes: ['prefer narrow patches with focused evidence'],
|
|
124
|
+
commands: [{ name: 'runtime-smoke', command: 'npm', args: ['test'], required: true }],
|
|
125
|
+
avoidInvestigating: ['generated fixtures unless task owns them'],
|
|
126
|
+
evidencePatterns: ['evidence.json', 'commands.md']
|
|
127
|
+
}).successfulJobIds.length),
|
|
128
|
+
measure('patch-stack-plan-' + taskCount, 16, () => createSwarmPatchStackPlan({
|
|
129
|
+
index: mergeIndex,
|
|
130
|
+
maxStackSize: 8
|
|
131
|
+
}).summary.stackCount),
|
|
132
|
+
measure('event-route-' + taskCount, 64, () => {
|
|
133
|
+
eventStream = createSwarmEventStream({ runId: 'bench', root: 'agent-runs/bench/streams', lanes: manifest.lanes });
|
|
134
|
+
return routeSwarmEventToMailboxes(eventStream, { type: 'agent.evidence', jobId: plan.jobs[cursor++ % plan.jobs.length].id, lane: 'runtime' }).length;
|
|
135
|
+
})
|
|
53
136
|
];
|
|
54
137
|
|
|
55
138
|
const report = {
|
|
@@ -112,6 +195,25 @@ function makeTasks(count) {
|
|
|
112
195
|
return tasks;
|
|
113
196
|
}
|
|
114
197
|
|
|
198
|
+
function makeBundles(plan, count) {
|
|
199
|
+
const bundles = [];
|
|
200
|
+
for (let i = 0; i < Math.min(count, plan.jobs.length); i += 1) {
|
|
201
|
+
const job = plan.jobs[i];
|
|
202
|
+
bundles.push(createSwarmMergeBundle({
|
|
203
|
+
job,
|
|
204
|
+
result: {
|
|
205
|
+
jobId: job.id,
|
|
206
|
+
status: 'verified',
|
|
207
|
+
changedPaths: [job.task.targetRefs[0] ?? `src/runtime/file-${i}.ts`],
|
|
208
|
+
changedRegions: i % 2 === 0 ? [`region.${i}`] : [],
|
|
209
|
+
verification: [{ status: 0 }]
|
|
210
|
+
},
|
|
211
|
+
patchPath: `agent-runs/bench/${job.id}/changes.patch`
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
return bundles;
|
|
215
|
+
}
|
|
216
|
+
|
|
115
217
|
function measure(fixture, operationsPerRound, fn) {
|
|
116
218
|
const samples = [];
|
|
117
219
|
let checksum = 0;
|