@sweny-ai/core 0.1.177 → 0.1.178
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/dist/cli/config-file.d.ts +22 -1
- package/dist/cli/config-file.js +42 -0
- package/dist/cli/main.d.ts +2 -1
- package/dist/cli/main.js +4 -6
- package/dist/cli/resume.js +1 -0
- package/dist/cli/run-history.d.ts +3 -7
- package/dist/cli/run-history.js +1 -10
- package/dist/cli/run-output.d.ts +16 -10
- package/dist/cli/run-output.js +19 -13
- package/dist/cli/ticket.js +3 -2
- package/dist/decider.d.ts +176 -64
- package/dist/decider.js +475 -155
- package/dist/executor.d.ts +49 -6
- package/dist/executor.js +456 -89
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/journal.d.ts +33 -4
- package/dist/journal.js +36 -6
- package/dist/schema.d.ts +189 -241
- package/dist/schema.js +56 -36
- package/dist/types.d.ts +49 -3
- package/dist/types.js +22 -0
- package/dist/when.d.ts +8 -1
- package/dist/when.js +8 -1
- package/dist/workflow-builder.js +3 -1
- package/dist/workflows/browser.js +2 -2
- package/dist/workflows/implement.yml +37 -5
- package/dist/workflows/triage.yml +40 -6
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -27,8 +27,8 @@ export { EVALUATOR_KINDS, EVAL_POLICIES, REQUIRES_ON_FAIL, NODE_ON_FAIL, MCP_TRA
|
|
|
27
27
|
export { consoleLogger } from "./types.js";
|
|
28
28
|
export { execute, RouteEvaluationError } from "./executor.js";
|
|
29
29
|
export type { ExecuteOptions } from "./executor.js";
|
|
30
|
-
export { systemOneProvider
|
|
31
|
-
export type {
|
|
30
|
+
export { systemOneProvider } from "./decider.js";
|
|
31
|
+
export type { DeciderConfig, DeciderOperatorConfig } from "./decider.js";
|
|
32
32
|
export { BudgetGuard, describeOverrun, minLimits, toLimits } from "./budget.js";
|
|
33
33
|
export type { Budget, BudgetOverrun, BudgetUnit, SpendLimits } from "./budget.js";
|
|
34
34
|
export { resolveNodePermissions, buildNodePolicy } from "./node-policy.js";
|
package/dist/index.js
CHANGED
|
@@ -27,8 +27,8 @@ export { EVALUATOR_KINDS, EVAL_POLICIES, REQUIRES_ON_FAIL, NODE_ON_FAIL, MCP_TRA
|
|
|
27
27
|
export { consoleLogger } from "./types.js";
|
|
28
28
|
// Executor
|
|
29
29
|
export { execute, RouteEvaluationError } from "./executor.js";
|
|
30
|
-
// Decision models
|
|
31
|
-
export { systemOneProvider
|
|
30
|
+
// Decision models (#357): config types and the provider adapter only
|
|
31
|
+
export { systemOneProvider } from "./decider.js";
|
|
32
32
|
// Least-privilege nodes and safe outputs (#365)
|
|
33
33
|
export { BudgetGuard, describeOverrun, minLimits, toLimits } from "./budget.js";
|
|
34
34
|
export { resolveNodePermissions, buildNodePolicy } from "./node-policy.js";
|
package/dist/journal.d.ts
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* output:intent a write is about to be applied (idempotency key + tool)
|
|
30
30
|
* output:applied the write returned (key + the ids it produced)
|
|
31
31
|
* node:end final result of the visit and the write-stage counters
|
|
32
|
-
* route the edge taken after the visit (null = the run ended)
|
|
32
|
+
* route the edge taken after the visit (null = the run ended), and the rung that chose it
|
|
33
33
|
* usage spend of one agent attempt (cumulative; live while it runs, final when it returns)
|
|
34
34
|
* run:end success | failed | crashed
|
|
35
35
|
*
|
|
@@ -52,9 +52,10 @@
|
|
|
52
52
|
* (the process died between the API call and the receipt) is looked up on the
|
|
53
53
|
* provider by a marker embedded in the body before anything is re-sent.
|
|
54
54
|
*/
|
|
55
|
-
import type { Logger, NodeResult, NodeUsage, Skill, Workflow } from "./types.js";
|
|
55
|
+
import type { Logger, NodeResult, NodeUsage, RouteRung, Skill, Workflow } from "./types.js";
|
|
56
56
|
import type { SafeOutputIntent, WriteStageState } from "./safe-outputs.js";
|
|
57
57
|
import { type Spend } from "./budget.js";
|
|
58
|
+
import type { DeciderCounters } from "./decider.js";
|
|
58
59
|
/** v2: records are authenticated with a per-run HMAC key (v1 used a public checksum and is refused). */
|
|
59
60
|
export declare const JOURNAL_SCHEMA_VERSION = 2;
|
|
60
61
|
export declare const JOURNAL_DIR: string;
|
|
@@ -139,6 +140,10 @@ export interface RunStartRecord extends JournalRecord {
|
|
|
139
140
|
sweny_version?: string;
|
|
140
141
|
input: unknown;
|
|
141
142
|
input_redacted: boolean;
|
|
143
|
+
decider?: {
|
|
144
|
+
mode: "on" | "off";
|
|
145
|
+
reason?: string;
|
|
146
|
+
};
|
|
142
147
|
}
|
|
143
148
|
export interface WriteStateSnapshot {
|
|
144
149
|
counts: Array<[string, number]>;
|
|
@@ -218,6 +223,8 @@ export interface PlannedVisit {
|
|
|
218
223
|
status?: NodeResult["status"];
|
|
219
224
|
/** Route taken after the visit: a node id, null for run end, undefined when not journaled. */
|
|
220
225
|
next?: string | null;
|
|
226
|
+
/** Who chose that route, when it was a decision (#357). */
|
|
227
|
+
rung?: RouteRung;
|
|
221
228
|
/** Writes the checkpointed write stage already applied (receipts in the journal). */
|
|
222
229
|
applied: number;
|
|
223
230
|
/** Writes with an intent but no receipt: checked on the provider before anything is re-sent. */
|
|
@@ -243,6 +250,8 @@ export interface ResumePlan {
|
|
|
243
250
|
receipts: Map<string, OutputRecord>;
|
|
244
251
|
/** Spend every earlier attempt journaled: the run budget starts here on resume. */
|
|
245
252
|
priorSpend: Spend;
|
|
253
|
+
/** The decider's mode at run start and its counters after the last journaled route (#357). */
|
|
254
|
+
decider?: JournalDeciderState;
|
|
246
255
|
}
|
|
247
256
|
/**
|
|
248
257
|
* Check that the records are a sequence the executor can write: one run:start
|
|
@@ -281,6 +290,21 @@ export interface JournalBeginInfo {
|
|
|
281
290
|
config: Record<string, string>;
|
|
282
291
|
writeState: WriteStageState;
|
|
283
292
|
harnessId?: string;
|
|
293
|
+
/** Whether the run's decider ran (#357), journaled so a resume keeps the same mode. */
|
|
294
|
+
decider?: {
|
|
295
|
+
mode: "on" | "off";
|
|
296
|
+
reason?: string;
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* The decider as an earlier attempt left it (#357): its mode at run start and
|
|
301
|
+
* the breaker / cap counters after the last journaled route. Cap and breaker
|
|
302
|
+
* are per logical run, so a resume continues them.
|
|
303
|
+
*/
|
|
304
|
+
export interface JournalDeciderState {
|
|
305
|
+
mode: "on" | "off";
|
|
306
|
+
reason?: string;
|
|
307
|
+
counters?: DeciderCounters;
|
|
284
308
|
}
|
|
285
309
|
export interface JournalCheckpoint {
|
|
286
310
|
result: NodeResult;
|
|
@@ -292,6 +316,7 @@ export type JournalReplay = {
|
|
|
292
316
|
kind: "complete";
|
|
293
317
|
result: NodeResult;
|
|
294
318
|
next?: string | null;
|
|
319
|
+
rung?: RouteRung;
|
|
295
320
|
} | ({
|
|
296
321
|
kind: "checkpoint";
|
|
297
322
|
} & JournalCheckpoint);
|
|
@@ -308,7 +333,8 @@ export interface ExecutionJournal {
|
|
|
308
333
|
/** The skill map the write stage applies through: write tools journaled and made idempotent. */
|
|
309
334
|
wrapWrites(node: string, iteration: number, skills: Map<string, Skill>): Map<string, Skill>;
|
|
310
335
|
nodeEnd(node: string, iteration: number, result: NodeResult, writeState: WriteStageState): void;
|
|
311
|
-
|
|
336
|
+
/** The edge taken after a visit, and for a decision the rung that chose it (#357), so resume replays it. */
|
|
337
|
+
route(from: string, to: string | null, rung?: RouteRung, decider?: DeciderCounters): void;
|
|
312
338
|
/**
|
|
313
339
|
* Spend of one agent attempt, cumulative for the attempt: `final` when the
|
|
314
340
|
* attempt returned, otherwise a live report (the journal may throttle those).
|
|
@@ -316,6 +342,8 @@ export interface ExecutionJournal {
|
|
|
316
342
|
usage?(node: string, iteration: number, attempt: number, usage: NodeUsage, final: boolean): void;
|
|
317
343
|
/** Spend earlier attempts of this run already journaled (resume); the run budget starts from it. */
|
|
318
344
|
priorSpend?(): Spend | undefined;
|
|
345
|
+
/** The decider state earlier attempts of this run journaled (resume); undefined otherwise. */
|
|
346
|
+
deciderResume?(): JournalDeciderState | undefined;
|
|
319
347
|
}
|
|
320
348
|
/** Minimum gap between two live usage records of one attempt. Final reports are always written. */
|
|
321
349
|
export declare const USAGE_JOURNAL_INTERVAL_MS = 2000;
|
|
@@ -389,11 +417,12 @@ export declare class RunJournal implements ExecutionJournal {
|
|
|
389
417
|
private closeFd;
|
|
390
418
|
private clean;
|
|
391
419
|
begin(info: JournalBeginInfo): void;
|
|
420
|
+
deciderResume(): JournalDeciderState | undefined;
|
|
392
421
|
replay(node: string, iteration: number): JournalReplay | undefined;
|
|
393
422
|
nodeStart(node: string, iteration: number): void;
|
|
394
423
|
checkpoint(node: string, iteration: number, cp: JournalCheckpoint): void;
|
|
395
424
|
nodeEnd(node: string, iteration: number, result: NodeResult, writeState: WriteStageState): void;
|
|
396
|
-
route(from: string, to: string | null): void;
|
|
425
|
+
route(from: string, to: string | null, rung?: RouteRung, decider?: DeciderCounters): void;
|
|
397
426
|
usage(node: string, iteration: number, attempt: number, usage: NodeUsage, final: boolean): void;
|
|
398
427
|
priorSpend(): Spend | undefined;
|
|
399
428
|
/** Close the run: `run:end`, then release the lock. Safe to call twice (one run:end). */
|
package/dist/journal.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* output:intent a write is about to be applied (idempotency key + tool)
|
|
30
30
|
* output:applied the write returned (key + the ids it produced)
|
|
31
31
|
* node:end final result of the visit and the write-stage counters
|
|
32
|
-
* route the edge taken after the visit (null = the run ended)
|
|
32
|
+
* route the edge taken after the visit (null = the run ended), and the rung that chose it
|
|
33
33
|
* usage spend of one agent attempt (cumulative; live while it runs, final when it returns)
|
|
34
34
|
* run:end success | failed | crashed
|
|
35
35
|
*
|
|
@@ -293,13 +293,15 @@ export function redact(value, secrets = []) {
|
|
|
293
293
|
return v.map((x) => walk(x, depth + 1));
|
|
294
294
|
if (v && typeof v === "object") {
|
|
295
295
|
const out = {};
|
|
296
|
+
// defineProperty, not assignment: a key named `__proto__` stays a plain key.
|
|
297
|
+
const put = (k, x) => Object.defineProperty(out, k, { value: x, enumerable: true, writable: true, configurable: true });
|
|
296
298
|
for (const [k, x] of Object.entries(v)) {
|
|
297
299
|
if (typeof x === "string" && isSecretKey(k) && x.length > 0) {
|
|
298
|
-
|
|
300
|
+
put(k, REDACTED);
|
|
299
301
|
redacted = true;
|
|
300
302
|
}
|
|
301
303
|
else if (x !== undefined && typeof x !== "function") {
|
|
302
|
-
|
|
304
|
+
put(k, walk(x, depth + 1));
|
|
303
305
|
}
|
|
304
306
|
}
|
|
305
307
|
return out;
|
|
@@ -467,6 +469,13 @@ const RECORD_TYPES = new Set([
|
|
|
467
469
|
const isPosInt = (v) => typeof v === "number" && Number.isInteger(v) && v > 0;
|
|
468
470
|
const isName = (v) => typeof v === "string" && v.length > 0;
|
|
469
471
|
const isAmount = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
472
|
+
const isRung = (v) => v === "expr" || v === "decider" || v === "agent";
|
|
473
|
+
const isCount = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
|
|
474
|
+
const isCounters = (v) => typeof v === "object" &&
|
|
475
|
+
v !== null &&
|
|
476
|
+
isCount(v.calls) &&
|
|
477
|
+
isCount(v.failures) &&
|
|
478
|
+
typeof v.open === "boolean";
|
|
470
479
|
/**
|
|
471
480
|
* Check that the records are a sequence the executor can write: one run:start
|
|
472
481
|
* first; nothing but run:resume after run:end; a visit starts only where the
|
|
@@ -583,6 +592,10 @@ export function checkRecordSequence(records) {
|
|
|
583
592
|
bad(r, `routes from ${String(r.from)}, but the visit that ended is ${cur.node}`);
|
|
584
593
|
if (r.to !== null && !isName(r.to))
|
|
585
594
|
bad(r, "has no valid target");
|
|
595
|
+
if (r.rung !== undefined && !isRung(r.rung))
|
|
596
|
+
bad(r, "has an unknown rung");
|
|
597
|
+
if (r.decider !== undefined && !isCounters(r.decider))
|
|
598
|
+
bad(r, "has invalid decider counters");
|
|
586
599
|
cur.routed = true;
|
|
587
600
|
next = r.to;
|
|
588
601
|
break;
|
|
@@ -663,6 +676,7 @@ export function buildResumePlan(records) {
|
|
|
663
676
|
const receipts = new Map();
|
|
664
677
|
let attempts = 1;
|
|
665
678
|
let lastStatus;
|
|
679
|
+
let deciderCounters;
|
|
666
680
|
for (const r of records) {
|
|
667
681
|
switch (r.type) {
|
|
668
682
|
case "run:resume":
|
|
@@ -681,6 +695,7 @@ export function buildResumePlan(records) {
|
|
|
681
695
|
// Re-run of a visit an earlier attempt did not finish (or finished failed).
|
|
682
696
|
delete v.end;
|
|
683
697
|
delete v.next;
|
|
698
|
+
delete v.rung;
|
|
684
699
|
}
|
|
685
700
|
break;
|
|
686
701
|
}
|
|
@@ -699,8 +714,14 @@ export function buildResumePlan(records) {
|
|
|
699
714
|
case "route": {
|
|
700
715
|
const from = r.from;
|
|
701
716
|
const v = [...order].reverse().find((x) => x.node === from);
|
|
702
|
-
if (v)
|
|
717
|
+
if (v) {
|
|
703
718
|
v.next = r.to ?? null;
|
|
719
|
+
if (isRung(r.rung))
|
|
720
|
+
v.rung = r.rung;
|
|
721
|
+
}
|
|
722
|
+
// Calls already made count even if the visit later re-runs.
|
|
723
|
+
if (isCounters(r.decider))
|
|
724
|
+
deciderCounters = r.decider;
|
|
704
725
|
break;
|
|
705
726
|
}
|
|
706
727
|
case "output:intent":
|
|
@@ -733,6 +754,7 @@ export function buildResumePlan(records) {
|
|
|
733
754
|
action: "replay",
|
|
734
755
|
status: v.end.result.status,
|
|
735
756
|
next: v.next,
|
|
757
|
+
...(v.rung ? { rung: v.rung } : {}),
|
|
736
758
|
applied,
|
|
737
759
|
unconfirmed,
|
|
738
760
|
});
|
|
@@ -776,6 +798,9 @@ export function buildResumePlan(records) {
|
|
|
776
798
|
intents,
|
|
777
799
|
receipts,
|
|
778
800
|
priorSpend: journaledSpend(records),
|
|
801
|
+
...(start.decider
|
|
802
|
+
? { decider: { ...start.decider, ...(deciderCounters ? { counters: { ...deciderCounters } } : {}) } }
|
|
803
|
+
: {}),
|
|
779
804
|
};
|
|
780
805
|
}
|
|
781
806
|
/**
|
|
@@ -1153,8 +1178,12 @@ export class RunJournal {
|
|
|
1153
1178
|
...(this.opts.swenyVersion ? { sweny_version: this.opts.swenyVersion } : {}),
|
|
1154
1179
|
input: input.value,
|
|
1155
1180
|
input_redacted: input.redacted,
|
|
1181
|
+
...(info.decider ? { decider: info.decider } : {}),
|
|
1156
1182
|
});
|
|
1157
1183
|
}
|
|
1184
|
+
deciderResume() {
|
|
1185
|
+
return this.resume?.plan.decider;
|
|
1186
|
+
}
|
|
1158
1187
|
replay(node, iteration) {
|
|
1159
1188
|
const plan = this.resume?.plan;
|
|
1160
1189
|
if (!plan)
|
|
@@ -1172,6 +1201,7 @@ export class RunJournal {
|
|
|
1172
1201
|
kind: "complete",
|
|
1173
1202
|
result: structuredClone(end.result),
|
|
1174
1203
|
...(visit.next !== undefined ? { next: visit.next } : {}),
|
|
1204
|
+
...(visit.rung ? { rung: visit.rung } : {}),
|
|
1175
1205
|
};
|
|
1176
1206
|
}
|
|
1177
1207
|
if (visit.action === "write-stage") {
|
|
@@ -1209,8 +1239,8 @@ export class RunJournal {
|
|
|
1209
1239
|
write_state: { counts: [...writeState.counts], total: writeState.total, seen: [...writeState.seen] },
|
|
1210
1240
|
});
|
|
1211
1241
|
}
|
|
1212
|
-
route(from, to) {
|
|
1213
|
-
this.append("route", { from, to });
|
|
1242
|
+
route(from, to, rung, decider) {
|
|
1243
|
+
this.append("route", { from, to, ...(rung ? { rung } : {}), ...(decider ? { decider } : {}) });
|
|
1214
1244
|
}
|
|
1215
1245
|
usage(node, iteration, attempt, usage, final) {
|
|
1216
1246
|
const s = spendOf(usage);
|