@orcareplay/core 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/dist/blobs.d.ts +21 -0
- package/dist/blobs.d.ts.map +1 -0
- package/dist/blobs.js +97 -0
- package/dist/blobs.js.map +1 -0
- package/dist/graph.d.ts +106 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +393 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +45 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +115 -0
- package/dist/paths.js.map +1 -0
- package/dist/reader.d.ts +45 -0
- package/dist/reader.d.ts.map +1 -0
- package/dist/reader.js +152 -0
- package/dist/reader.js.map +1 -0
- package/dist/redaction.d.ts +48 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +245 -0
- package/dist/redaction.js.map +1 -0
- package/dist/writer.d.ts +66 -0
- package/dist/writer.d.ts.map +1 -0
- package/dist/writer.js +182 -0
- package/dist/writer.js.map +1 -0
- package/package.json +18 -0
package/dist/blobs.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlobRef } from '@orcareplay/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Content-addressed blob store, laid out as `<dir>/<first two hex>/<full hex>` (spec §2.2).
|
|
4
|
+
*
|
|
5
|
+
* Every model turn resends the whole conversation, so identical content arrives over and over.
|
|
6
|
+
* Addressing by digest is what keeps a trace O(n) in new content instead of O(n²) in turns —
|
|
7
|
+
* hence `put` of existing content must not touch the file at all.
|
|
8
|
+
*/
|
|
9
|
+
export declare class BlobStore {
|
|
10
|
+
#private;
|
|
11
|
+
/** @param dir The blob root, conventionally `<runDir>/blobs`. */
|
|
12
|
+
constructor(dir: string);
|
|
13
|
+
get dir(): string;
|
|
14
|
+
put(data: Uint8Array | string, mediaType?: string): Promise<BlobRef>;
|
|
15
|
+
get(ref: BlobRef | string): Promise<Uint8Array>;
|
|
16
|
+
has(digest: BlobRef | string): Promise<boolean>;
|
|
17
|
+
count(): Promise<number>;
|
|
18
|
+
}
|
|
19
|
+
/** SHA-256 of a whole file, streamed — this is the integrity root of a run (spec §6). */
|
|
20
|
+
export declare function sha256File(path: string): Promise<string>;
|
|
21
|
+
//# sourceMappingURL=blobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAqBlD;;;;;;GAMG;AACH,qBAAa,SAAS;;IAGpB,iEAAiE;gBACrD,GAAG,EAAE,MAAM;IAIvB,IAAI,GAAG,IAAI,MAAM,CAEhB;IAEK,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBpE,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAY/C,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK/C,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;CAS/B;AAED,yFAAyF;AACzF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D"}
|
package/dist/blobs.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
3
|
+
import { mkdir, readFile, readdir, rename, stat, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
/** Traces are sensitive material (design §7), so nothing is group- or world-readable. */
|
|
6
|
+
const FILE_MODE = 0o600;
|
|
7
|
+
const DIR_MODE = 0o700;
|
|
8
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
9
|
+
const PREFIX = 'sha256:';
|
|
10
|
+
/** Accepts `sha256:<hex>` or a bare hex digest and returns the bare hex. */
|
|
11
|
+
function bareDigest(ref) {
|
|
12
|
+
const raw = typeof ref === 'string' ? ref : ref.$blob;
|
|
13
|
+
const hex = raw.startsWith(PREFIX) ? raw.slice(PREFIX.length) : raw;
|
|
14
|
+
if (!HEX64.test(hex))
|
|
15
|
+
throw new Error(`invalid blob digest: ${JSON.stringify(raw)}`);
|
|
16
|
+
return hex;
|
|
17
|
+
}
|
|
18
|
+
function toBytes(data) {
|
|
19
|
+
return typeof data === 'string' ? new Uint8Array(Buffer.from(data, 'utf8')) : data;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Content-addressed blob store, laid out as `<dir>/<first two hex>/<full hex>` (spec §2.2).
|
|
23
|
+
*
|
|
24
|
+
* Every model turn resends the whole conversation, so identical content arrives over and over.
|
|
25
|
+
* Addressing by digest is what keeps a trace O(n) in new content instead of O(n²) in turns —
|
|
26
|
+
* hence `put` of existing content must not touch the file at all.
|
|
27
|
+
*/
|
|
28
|
+
export class BlobStore {
|
|
29
|
+
#dir;
|
|
30
|
+
/** @param dir The blob root, conventionally `<runDir>/blobs`. */
|
|
31
|
+
constructor(dir) {
|
|
32
|
+
this.#dir = dir;
|
|
33
|
+
}
|
|
34
|
+
get dir() {
|
|
35
|
+
return this.#dir;
|
|
36
|
+
}
|
|
37
|
+
async put(data, mediaType) {
|
|
38
|
+
const bytes = toBytes(data);
|
|
39
|
+
const hex = createHash('sha256').update(bytes).digest('hex');
|
|
40
|
+
const ref = { $blob: `${PREFIX}${hex}`, bytes: bytes.byteLength };
|
|
41
|
+
if (mediaType !== undefined)
|
|
42
|
+
ref.media_type = mediaType;
|
|
43
|
+
const shard = join(this.#dir, hex.slice(0, 2));
|
|
44
|
+
const path = join(shard, hex);
|
|
45
|
+
if (await exists(path))
|
|
46
|
+
return ref;
|
|
47
|
+
await mkdir(shard, { recursive: true, mode: DIR_MODE });
|
|
48
|
+
// Write then rename so a reader never sees a half-written blob under its final digest.
|
|
49
|
+
const tmp = `${path}.${randomBytes(6).toString('hex')}.tmp`;
|
|
50
|
+
await writeFile(tmp, bytes, { mode: FILE_MODE });
|
|
51
|
+
await rename(tmp, path);
|
|
52
|
+
return ref;
|
|
53
|
+
}
|
|
54
|
+
async get(ref) {
|
|
55
|
+
const hex = bareDigest(ref);
|
|
56
|
+
const path = join(this.#dir, hex.slice(0, 2), hex);
|
|
57
|
+
let buf;
|
|
58
|
+
try {
|
|
59
|
+
buf = await readFile(path);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw new Error(`blob not found: ${PREFIX}${hex} (looked in ${path})`);
|
|
63
|
+
}
|
|
64
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
65
|
+
}
|
|
66
|
+
async has(digest) {
|
|
67
|
+
const hex = bareDigest(digest);
|
|
68
|
+
return exists(join(this.#dir, hex.slice(0, 2), hex));
|
|
69
|
+
}
|
|
70
|
+
async count() {
|
|
71
|
+
let n = 0;
|
|
72
|
+
for (const shard of await readdir(this.#dir, { withFileTypes: true }).catch(() => [])) {
|
|
73
|
+
if (!shard.isDirectory())
|
|
74
|
+
continue;
|
|
75
|
+
const files = await readdir(join(this.#dir, shard.name)).catch(() => []);
|
|
76
|
+
n += files.filter((f) => HEX64.test(f)).length;
|
|
77
|
+
}
|
|
78
|
+
return n;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** SHA-256 of a whole file, streamed — this is the integrity root of a run (spec §6). */
|
|
82
|
+
export async function sha256File(path) {
|
|
83
|
+
const hash = createHash('sha256');
|
|
84
|
+
for await (const chunk of createReadStream(path))
|
|
85
|
+
hash.update(chunk);
|
|
86
|
+
return hash.digest('hex');
|
|
87
|
+
}
|
|
88
|
+
async function exists(path) {
|
|
89
|
+
try {
|
|
90
|
+
await stat(path);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=blobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"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"}
|
package/dist/graph.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { TraceEvent } from '@orcareplay/schema';
|
|
2
|
+
/** A forkable point in a run. Derived from the log, never recorded (spec §3). */
|
|
3
|
+
export interface Checkpoint {
|
|
4
|
+
seq: number;
|
|
5
|
+
turn: number;
|
|
6
|
+
/** Tree id from the governing `fs.snapshot`, when it recorded one. */
|
|
7
|
+
fsTree?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Turn {
|
|
10
|
+
turn: number;
|
|
11
|
+
startSeq: number;
|
|
12
|
+
endSeq: number;
|
|
13
|
+
events: TraceEvent[];
|
|
14
|
+
}
|
|
15
|
+
export interface SnapResult {
|
|
16
|
+
checkpoint: Checkpoint;
|
|
17
|
+
/** True when the target was not itself a checkpoint and had to move back. */
|
|
18
|
+
snapped: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Every seq that satisfies both checkpoint conditions of spec §3: an `fs.snapshot` at or before it
|
|
22
|
+
* in the same turn, and a complete conversation prefix.
|
|
23
|
+
*/
|
|
24
|
+
export declare function deriveCheckpoints(events: TraceEvent[]): Checkpoint[];
|
|
25
|
+
/**
|
|
26
|
+
* The checkpoint a fork of `target` must actually start from — the nearest preceding one.
|
|
27
|
+
*
|
|
28
|
+
* Never rounds forward. Forking from state the run had not reached yet would produce a child run
|
|
29
|
+
* that silently disagrees with its parent, which is worse than refusing outright.
|
|
30
|
+
*/
|
|
31
|
+
export declare function snapToCheckpoint(cps: Checkpoint[], target: number): SnapResult;
|
|
32
|
+
/** The events of a run grouped into model turns, in turn order. */
|
|
33
|
+
export declare function turnsOf(events: TraceEvent[]): Turn[];
|
|
34
|
+
/** The event at `seq` and everything transitively named by `causes`, oldest first. */
|
|
35
|
+
export declare function causalChain(events: TraceEvent[], seq: number): TraceEvent[];
|
|
36
|
+
/** Where an edge came from. The distinction is the whole honesty mechanism — see `runGraph`. */
|
|
37
|
+
export type EdgeKind = 'recorded' | 'inferred';
|
|
38
|
+
export interface GraphNode {
|
|
39
|
+
seq: number;
|
|
40
|
+
turn: number;
|
|
41
|
+
type: TraceEvent['type'];
|
|
42
|
+
attrs?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
export interface GraphEdge {
|
|
45
|
+
/** The cause. Always less than `to`, as spec §2.1 requires of `causes`. */
|
|
46
|
+
from: number;
|
|
47
|
+
to: number;
|
|
48
|
+
kind: EdgeKind;
|
|
49
|
+
/** Why this edge exists. For an inferred edge, the rule that produced it. */
|
|
50
|
+
rule: string;
|
|
51
|
+
}
|
|
52
|
+
export interface RunGraph {
|
|
53
|
+
nodes: GraphNode[];
|
|
54
|
+
edges: GraphEdge[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A run as nodes and edges, with every edge saying whether the trace vouches for it.
|
|
58
|
+
*
|
|
59
|
+
* Two kinds, and they are not interchangeable. A `recorded` edge came out of `causes`, which the
|
|
60
|
+
* recorder wrote because it watched the relationship happen. An `inferred` edge was derived here,
|
|
61
|
+
* just now, by the named rule — a filesystem snapshot is taken once per turn rather than once per
|
|
62
|
+
* tool call, and shell frames are bucketed into turns by wall clock, so attributing an effect to a
|
|
63
|
+
* *particular* call is a guess however good the heuristic is.
|
|
64
|
+
*
|
|
65
|
+
* Inferred edges are therefore never written back to the trace. That is the same discipline spec
|
|
66
|
+
* §3 applies to checkpoints, which are derived and never recorded, and it exists so that a field
|
|
67
|
+
* a third-party reader trusts never contains something orca made up.
|
|
68
|
+
*/
|
|
69
|
+
export declare function runGraph(events: TraceEvent[]): RunGraph;
|
|
70
|
+
/**
|
|
71
|
+
* The sub-graph that produced `seq`: that event and everything transitively behind it.
|
|
72
|
+
*
|
|
73
|
+
* `causalChain` walks `causes` alone and so stops at the first inferred hop, which in a real run
|
|
74
|
+
* is the hop from a tool call to the shell command it ran — exactly the one a person following a
|
|
75
|
+
* failure backwards needs. This walks the derived graph instead, so it crosses both kinds.
|
|
76
|
+
*/
|
|
77
|
+
export declare function chainTo(graph: RunGraph, seq: number): RunGraph;
|
|
78
|
+
/**
|
|
79
|
+
* The event a card about this run should be about, or undefined when nothing stands out.
|
|
80
|
+
*
|
|
81
|
+
* Which chain to draw *is* the feature. A card gets screenshotted whether or not it happens to be
|
|
82
|
+
* the interesting one, so an arbitrary pick travels further than no card at all — hence a run with
|
|
83
|
+
* nothing notable returns undefined and the caller refuses rather than drawing something.
|
|
84
|
+
*
|
|
85
|
+
* The order is failure first, then the largest visible effect: a command that exited non-zero, a
|
|
86
|
+
* tool that reported an error, an error orca itself recorded, a replay divergence, and only then
|
|
87
|
+
* the last file the run changed. Within a kind the last one wins, since that is where the run
|
|
88
|
+
* ended up.
|
|
89
|
+
*/
|
|
90
|
+
export declare function pickChainTarget(events: TraceEvent[]): number | undefined;
|
|
91
|
+
/** Tool calls that hand work to another agent, by the argument every harness gives them. */
|
|
92
|
+
export declare function isDelegation(event: TraceEvent): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* The delegation whose span encloses `seq`, if any.
|
|
95
|
+
*
|
|
96
|
+
* A replay that halts inside one is the hardest kind of miss to read: the distance is small, the
|
|
97
|
+
* trace is intact, and nothing on the line says why the same run asked a different question. The
|
|
98
|
+
* answer is that the harness wrote the delegate's prompt itself and writes a fresh one every time,
|
|
99
|
+
* so that request genuinely was not the recorded one. Naming the delegation turns a number into
|
|
100
|
+
* that sentence.
|
|
101
|
+
*/
|
|
102
|
+
export declare function enclosingDelegation(events: TraceEvent[], seq: number): {
|
|
103
|
+
seq: number;
|
|
104
|
+
subagent: string;
|
|
105
|
+
} | undefined;
|
|
106
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,iFAAiF;AACjF,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,6EAA6E;IAC7E,OAAO,EAAE,OAAO,CAAC;CAClB;AAyBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAmBpE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAkB9E;AAED,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,CAepD;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAsB3E;AAED,gGAAgG;AAChG,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,SAAS;IACxB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AA6GD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,QAAQ,CAgDvD;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CA8B9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,GAAG,SAAS,CAiBxE;AAOD,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAMvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAAE,EACpB,GAAG,EAAE,MAAM,GACV;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAkB/C"}
|
package/dist/graph.js
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
function bySeq(events) {
|
|
2
|
+
return [...events].sort((a, b) => a.seq - b.seq);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* The seq of the first `model.request` with no reply, or Infinity when the conversation is whole.
|
|
6
|
+
*
|
|
7
|
+
* Requests and responses are paired in order, so a second request that is still in flight is not
|
|
8
|
+
* excused by the first one's reply. Everything after an unanswered request is un-forkable: the
|
|
9
|
+
* model's effect on the run is unknown there.
|
|
10
|
+
*/
|
|
11
|
+
function firstUnansweredRequest(events) {
|
|
12
|
+
const requests = events.filter((e) => e.type === 'model.request');
|
|
13
|
+
const responses = events.filter((e) => e.type === 'model.response');
|
|
14
|
+
for (let i = 0; i < requests.length; i++) {
|
|
15
|
+
const request = requests[i];
|
|
16
|
+
const response = responses[i];
|
|
17
|
+
if (!request)
|
|
18
|
+
continue;
|
|
19
|
+
if (!response || response.seq <= request.seq)
|
|
20
|
+
return request.seq;
|
|
21
|
+
}
|
|
22
|
+
return Number.POSITIVE_INFINITY;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Every seq that satisfies both checkpoint conditions of spec §3: an `fs.snapshot` at or before it
|
|
26
|
+
* in the same turn, and a complete conversation prefix.
|
|
27
|
+
*/
|
|
28
|
+
export function deriveCheckpoints(events) {
|
|
29
|
+
const ordered = bySeq(events);
|
|
30
|
+
const cutoff = firstUnansweredRequest(ordered);
|
|
31
|
+
const checkpoints = [];
|
|
32
|
+
let snapshot;
|
|
33
|
+
for (const e of ordered) {
|
|
34
|
+
if (e.seq > cutoff)
|
|
35
|
+
break;
|
|
36
|
+
if (e.type === 'fs.snapshot') {
|
|
37
|
+
const tree = e.attrs?.['tree'];
|
|
38
|
+
snapshot = { turn: e.turn, tree: typeof tree === 'string' ? tree : undefined };
|
|
39
|
+
}
|
|
40
|
+
// A snapshot only vouches for the state of its own turn; work in a later turn has moved on.
|
|
41
|
+
if (!snapshot || snapshot.turn !== e.turn)
|
|
42
|
+
continue;
|
|
43
|
+
const checkpoint = { seq: e.seq, turn: e.turn };
|
|
44
|
+
if (snapshot.tree !== undefined)
|
|
45
|
+
checkpoint.fsTree = snapshot.tree;
|
|
46
|
+
checkpoints.push(checkpoint);
|
|
47
|
+
}
|
|
48
|
+
return checkpoints;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The checkpoint a fork of `target` must actually start from — the nearest preceding one.
|
|
52
|
+
*
|
|
53
|
+
* Never rounds forward. Forking from state the run had not reached yet would produce a child run
|
|
54
|
+
* that silently disagrees with its parent, which is worse than refusing outright.
|
|
55
|
+
*/
|
|
56
|
+
export function snapToCheckpoint(cps, target) {
|
|
57
|
+
const ordered = [...cps].sort((a, b) => a.seq - b.seq);
|
|
58
|
+
if (ordered.length === 0) {
|
|
59
|
+
throw new Error(`cannot fork at seq ${target}: this run has no checkpoints — it recorded no fs.snapshot`);
|
|
60
|
+
}
|
|
61
|
+
let found;
|
|
62
|
+
for (const cp of ordered) {
|
|
63
|
+
if (cp.seq > target)
|
|
64
|
+
break;
|
|
65
|
+
found = cp;
|
|
66
|
+
}
|
|
67
|
+
if (!found) {
|
|
68
|
+
throw new Error(`no checkpoint at or before ${target}: the earliest forkable seq is ${ordered[0]?.seq}`);
|
|
69
|
+
}
|
|
70
|
+
return { checkpoint: found, snapped: found.seq !== target };
|
|
71
|
+
}
|
|
72
|
+
/** The events of a run grouped into model turns, in turn order. */
|
|
73
|
+
export function turnsOf(events) {
|
|
74
|
+
const byTurn = new Map();
|
|
75
|
+
for (const e of bySeq(events)) {
|
|
76
|
+
const bucket = byTurn.get(e.turn);
|
|
77
|
+
if (bucket)
|
|
78
|
+
bucket.push(e);
|
|
79
|
+
else
|
|
80
|
+
byTurn.set(e.turn, [e]);
|
|
81
|
+
}
|
|
82
|
+
return [...byTurn.entries()]
|
|
83
|
+
.sort((a, b) => a[0] - b[0])
|
|
84
|
+
.map(([turn, group]) => ({
|
|
85
|
+
turn,
|
|
86
|
+
startSeq: group[0]?.seq ?? 0,
|
|
87
|
+
endSeq: group[group.length - 1]?.seq ?? 0,
|
|
88
|
+
events: group,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
/** The event at `seq` and everything transitively named by `causes`, oldest first. */
|
|
92
|
+
export function causalChain(events, seq) {
|
|
93
|
+
const index = new Map(events.map((e) => [e.seq, e]));
|
|
94
|
+
const start = index.get(seq);
|
|
95
|
+
if (!start)
|
|
96
|
+
throw new Error(`no event with seq ${seq} in this trace`);
|
|
97
|
+
const seen = new Set([seq]);
|
|
98
|
+
const queue = [start];
|
|
99
|
+
const chain = [];
|
|
100
|
+
while (queue.length > 0) {
|
|
101
|
+
const event = queue.shift();
|
|
102
|
+
if (!event)
|
|
103
|
+
break;
|
|
104
|
+
chain.push(event);
|
|
105
|
+
for (const cause of event.causes ?? []) {
|
|
106
|
+
// A cycle is malformed, and an ancestor may be missing because the reader skipped an
|
|
107
|
+
// unknown event type. Neither may stop the walk.
|
|
108
|
+
if (seen.has(cause))
|
|
109
|
+
continue;
|
|
110
|
+
seen.add(cause);
|
|
111
|
+
const parent = index.get(cause);
|
|
112
|
+
if (parent)
|
|
113
|
+
queue.push(parent);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return chain.sort((a, b) => a.seq - b.seq);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* What a recorded pair means, when the pair is one orca itself writes.
|
|
120
|
+
*
|
|
121
|
+
* `causes` says *that* one event caused another and never *why*, so this is a post-hoc reading of
|
|
122
|
+
* the type pair rather than anything the trace claims. An unrecognised pair says `causes` and
|
|
123
|
+
* stops there, which is the honest answer for an edge written by a reader we do not know.
|
|
124
|
+
*/
|
|
125
|
+
const RECORDED_RULES = {
|
|
126
|
+
'tool.call→tool.result': 'tool result answers its call',
|
|
127
|
+
'shell.exec→shell.result': 'shell result answers its exec',
|
|
128
|
+
'net.request→net.response': 'network response answers its request',
|
|
129
|
+
'model.response→tool.call': 'tool_use block in the response',
|
|
130
|
+
'tool.result→model.request': 'tool_result block in the request',
|
|
131
|
+
};
|
|
132
|
+
const ARGV_RULE = 'argv matches tool input, same or previous turn';
|
|
133
|
+
const PATH_RULE = 'changed path appears in tool input, same or previous turn';
|
|
134
|
+
/**
|
|
135
|
+
* How many turns back an effect may reach for the call that caused it.
|
|
136
|
+
*
|
|
137
|
+
* One, not zero. A snapshot is taken when the turn's exchange is persisted, which races the agent
|
|
138
|
+
* actually running the tool — an end-to-end recording produced the edit in the turn's own snapshot
|
|
139
|
+
* on one run and in the next turn's on another. A same-turn rule therefore made the graph differ
|
|
140
|
+
* between two identical runs. Not more than one either: an effect two turns later would have been
|
|
141
|
+
* reported by the snapshot in between.
|
|
142
|
+
*/
|
|
143
|
+
const TURN_REACH = 1;
|
|
144
|
+
/** The longest string in an argv array — in practice the command, not the shell that ran it. */
|
|
145
|
+
function commandOf(argv) {
|
|
146
|
+
if (!Array.isArray(argv))
|
|
147
|
+
return '';
|
|
148
|
+
let longest = '';
|
|
149
|
+
for (const part of argv) {
|
|
150
|
+
if (typeof part === 'string' && part.length > longest.length)
|
|
151
|
+
longest = part;
|
|
152
|
+
}
|
|
153
|
+
return longest;
|
|
154
|
+
}
|
|
155
|
+
function inputText(call) {
|
|
156
|
+
const input = (call.attrs ?? {})['input'];
|
|
157
|
+
if (input === undefined)
|
|
158
|
+
return '';
|
|
159
|
+
try {
|
|
160
|
+
return typeof input === 'string' ? input : (JSON.stringify(input) ?? '');
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return '';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The one tool call that can be said to have caused `effect`, or undefined when that is not
|
|
168
|
+
* exactly one call.
|
|
169
|
+
*
|
|
170
|
+
* Candidates are calls whose input names `needle`, that happened first, and that are within
|
|
171
|
+
* `TURN_REACH` turns. Of those, only the nearest turn is considered: a later call supersedes an
|
|
172
|
+
* earlier one, since a file edited twice was last edited by the most recent call to name it.
|
|
173
|
+
*
|
|
174
|
+
* Two calls in that nearest turn is the case worth dwelling on. Picking either would produce an
|
|
175
|
+
* edge indistinguishable from a true one and wrong half the time, and a wrong edge is worse than
|
|
176
|
+
* a missing one because the missing one is visible. So ambiguity yields nothing.
|
|
177
|
+
*/
|
|
178
|
+
function soleMatchingCall(calls, effect, needle) {
|
|
179
|
+
if (needle === '')
|
|
180
|
+
return undefined;
|
|
181
|
+
const candidates = calls.filter((call) => call.seq < effect.seq &&
|
|
182
|
+
effect.turn - call.turn >= 0 &&
|
|
183
|
+
effect.turn - call.turn <= TURN_REACH &&
|
|
184
|
+
inputText(call).includes(needle));
|
|
185
|
+
if (candidates.length === 0)
|
|
186
|
+
return undefined;
|
|
187
|
+
const nearest = Math.max(...candidates.map((c) => c.turn));
|
|
188
|
+
const inNearest = candidates.filter((c) => c.turn === nearest);
|
|
189
|
+
return inNearest.length === 1 ? inNearest[0] : undefined;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The longest string a graph node carries. A graph is about structure, not payloads.
|
|
193
|
+
*
|
|
194
|
+
* `orca_graph` answers an agent, and the answer lands in its context — so a `tool.call` whose
|
|
195
|
+
* `input` holds a whole file body would spend that context on something the graph never uses. The
|
|
196
|
+
* shape survives so a label can still read `input.path`; the bulk does not. `orca events` is one
|
|
197
|
+
* command away when the full value is what you want.
|
|
198
|
+
*/
|
|
199
|
+
const ATTR_MAX = 200;
|
|
200
|
+
function clampValue(value, depth = 0) {
|
|
201
|
+
if (typeof value === 'string') {
|
|
202
|
+
return value.length <= ATTR_MAX ? value : `${value.slice(0, ATTR_MAX)}…`;
|
|
203
|
+
}
|
|
204
|
+
if (depth >= 4 || value === null || typeof value !== 'object')
|
|
205
|
+
return value;
|
|
206
|
+
if (Array.isArray(value))
|
|
207
|
+
return value.slice(0, 20).map((v) => clampValue(v, depth + 1));
|
|
208
|
+
const out = {};
|
|
209
|
+
for (const [key, v] of Object.entries(value)) {
|
|
210
|
+
out[key] = clampValue(v, depth + 1);
|
|
211
|
+
}
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
function clampAttrs(attrs) {
|
|
215
|
+
return clampValue(attrs);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* A run as nodes and edges, with every edge saying whether the trace vouches for it.
|
|
219
|
+
*
|
|
220
|
+
* Two kinds, and they are not interchangeable. A `recorded` edge came out of `causes`, which the
|
|
221
|
+
* recorder wrote because it watched the relationship happen. An `inferred` edge was derived here,
|
|
222
|
+
* just now, by the named rule — a filesystem snapshot is taken once per turn rather than once per
|
|
223
|
+
* tool call, and shell frames are bucketed into turns by wall clock, so attributing an effect to a
|
|
224
|
+
* *particular* call is a guess however good the heuristic is.
|
|
225
|
+
*
|
|
226
|
+
* Inferred edges are therefore never written back to the trace. That is the same discipline spec
|
|
227
|
+
* §3 applies to checkpoints, which are derived and never recorded, and it exists so that a field
|
|
228
|
+
* a third-party reader trusts never contains something orca made up.
|
|
229
|
+
*/
|
|
230
|
+
export function runGraph(events) {
|
|
231
|
+
const ordered = bySeq(events);
|
|
232
|
+
const present = new Set(ordered.map((e) => e.seq));
|
|
233
|
+
const nodes = ordered.map((e) => ({
|
|
234
|
+
seq: e.seq,
|
|
235
|
+
turn: e.turn,
|
|
236
|
+
type: e.type,
|
|
237
|
+
...(e.attrs === undefined ? {} : { attrs: clampAttrs(e.attrs) }),
|
|
238
|
+
}));
|
|
239
|
+
const byType = new Map(ordered.map((e) => [e.seq, e.type]));
|
|
240
|
+
const edges = [];
|
|
241
|
+
for (const event of ordered) {
|
|
242
|
+
for (const cause of event.causes ?? []) {
|
|
243
|
+
// A reader may have dropped an event type it did not know (spec §2.3), so an edge can name
|
|
244
|
+
// an ancestor that is not here. Naming a node that does not exist is worse than no edge.
|
|
245
|
+
if (!present.has(cause))
|
|
246
|
+
continue;
|
|
247
|
+
const pair = `${byType.get(cause)}→${event.type}`;
|
|
248
|
+
edges.push({
|
|
249
|
+
from: cause,
|
|
250
|
+
to: event.seq,
|
|
251
|
+
kind: 'recorded',
|
|
252
|
+
rule: RECORDED_RULES[pair] ?? 'causes',
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const calls = ordered.filter((e) => e.type === 'tool.call');
|
|
257
|
+
if (calls.length > 0) {
|
|
258
|
+
for (const event of ordered) {
|
|
259
|
+
const attrs = event.attrs ?? {};
|
|
260
|
+
let match;
|
|
261
|
+
let rule = '';
|
|
262
|
+
if (event.type === 'shell.exec') {
|
|
263
|
+
match = soleMatchingCall(calls, event, commandOf(attrs['argv']));
|
|
264
|
+
rule = ARGV_RULE;
|
|
265
|
+
}
|
|
266
|
+
else if (event.type === 'fs.change') {
|
|
267
|
+
const path = attrs['path'];
|
|
268
|
+
match = soleMatchingCall(calls, event, typeof path === 'string' ? path : '');
|
|
269
|
+
rule = PATH_RULE;
|
|
270
|
+
}
|
|
271
|
+
if (match)
|
|
272
|
+
edges.push({ from: match.seq, to: event.seq, kind: 'inferred', rule });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
edges.sort((a, b) => a.to - b.to || a.from - b.from);
|
|
276
|
+
return { nodes, edges };
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* The sub-graph that produced `seq`: that event and everything transitively behind it.
|
|
280
|
+
*
|
|
281
|
+
* `causalChain` walks `causes` alone and so stops at the first inferred hop, which in a real run
|
|
282
|
+
* is the hop from a tool call to the shell command it ran — exactly the one a person following a
|
|
283
|
+
* failure backwards needs. This walks the derived graph instead, so it crosses both kinds.
|
|
284
|
+
*/
|
|
285
|
+
export function chainTo(graph, seq) {
|
|
286
|
+
if (!graph.nodes.some((n) => n.seq === seq)) {
|
|
287
|
+
throw new Error(`no event with seq ${seq} in this graph`);
|
|
288
|
+
}
|
|
289
|
+
const incoming = new Map();
|
|
290
|
+
for (const edge of graph.edges) {
|
|
291
|
+
const bucket = incoming.get(edge.to);
|
|
292
|
+
if (bucket)
|
|
293
|
+
bucket.push(edge);
|
|
294
|
+
else
|
|
295
|
+
incoming.set(edge.to, [edge]);
|
|
296
|
+
}
|
|
297
|
+
const kept = new Set([seq]);
|
|
298
|
+
const edges = [];
|
|
299
|
+
const queue = [seq];
|
|
300
|
+
while (queue.length > 0) {
|
|
301
|
+
const at = queue.shift();
|
|
302
|
+
if (at === undefined)
|
|
303
|
+
break;
|
|
304
|
+
for (const edge of incoming.get(at) ?? []) {
|
|
305
|
+
edges.push(edge);
|
|
306
|
+
// A cycle is malformed rather than impossible, and it must not hang the walk.
|
|
307
|
+
if (kept.has(edge.from))
|
|
308
|
+
continue;
|
|
309
|
+
kept.add(edge.from);
|
|
310
|
+
queue.push(edge.from);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
nodes: graph.nodes.filter((n) => kept.has(n.seq)),
|
|
315
|
+
edges: edges.sort((a, b) => a.to - b.to || a.from - b.from),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The event a card about this run should be about, or undefined when nothing stands out.
|
|
320
|
+
*
|
|
321
|
+
* Which chain to draw *is* the feature. A card gets screenshotted whether or not it happens to be
|
|
322
|
+
* the interesting one, so an arbitrary pick travels further than no card at all — hence a run with
|
|
323
|
+
* nothing notable returns undefined and the caller refuses rather than drawing something.
|
|
324
|
+
*
|
|
325
|
+
* The order is failure first, then the largest visible effect: a command that exited non-zero, a
|
|
326
|
+
* tool that reported an error, an error orca itself recorded, a replay divergence, and only then
|
|
327
|
+
* the last file the run changed. Within a kind the last one wins, since that is where the run
|
|
328
|
+
* ended up.
|
|
329
|
+
*/
|
|
330
|
+
export function pickChainTarget(events) {
|
|
331
|
+
const ordered = bySeq(events);
|
|
332
|
+
const last = (match) => {
|
|
333
|
+
for (let i = ordered.length - 1; i >= 0; i--) {
|
|
334
|
+
const event = ordered[i];
|
|
335
|
+
if (event && match(event))
|
|
336
|
+
return event.seq;
|
|
337
|
+
}
|
|
338
|
+
return undefined;
|
|
339
|
+
};
|
|
340
|
+
return (last((e) => e.type === 'shell.result' && (e.attrs?.['exit_code'] ?? 0) !== 0) ??
|
|
341
|
+
last((e) => e.type === 'tool.result' && e.attrs?.['is_error'] === true) ??
|
|
342
|
+
last((e) => e.type === 'error') ??
|
|
343
|
+
last((e) => e.type === 'divergence') ??
|
|
344
|
+
last((e) => e.type === 'fs.change'));
|
|
345
|
+
}
|
|
346
|
+
/** Attributes as a plain record, since the envelope leaves them optional. */
|
|
347
|
+
function toAttrs(event) {
|
|
348
|
+
return event.attrs ?? {};
|
|
349
|
+
}
|
|
350
|
+
/** Tool calls that hand work to another agent, by the argument every harness gives them. */
|
|
351
|
+
export function isDelegation(event) {
|
|
352
|
+
if (event.type !== 'tool.call')
|
|
353
|
+
return false;
|
|
354
|
+
const input = toAttrs(event)['input'];
|
|
355
|
+
if (input === null || typeof input !== 'object')
|
|
356
|
+
return false;
|
|
357
|
+
const shape = input;
|
|
358
|
+
return typeof shape['subagent_type'] === 'string' || typeof shape['agent'] === 'string';
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* The delegation whose span encloses `seq`, if any.
|
|
362
|
+
*
|
|
363
|
+
* A replay that halts inside one is the hardest kind of miss to read: the distance is small, the
|
|
364
|
+
* trace is intact, and nothing on the line says why the same run asked a different question. The
|
|
365
|
+
* answer is that the harness wrote the delegate's prompt itself and writes a fresh one every time,
|
|
366
|
+
* so that request genuinely was not the recorded one. Naming the delegation turns a number into
|
|
367
|
+
* that sentence.
|
|
368
|
+
*/
|
|
369
|
+
export function enclosingDelegation(events, seq) {
|
|
370
|
+
const closesAt = new Map();
|
|
371
|
+
for (const event of events) {
|
|
372
|
+
if (event.type !== 'tool.result')
|
|
373
|
+
continue;
|
|
374
|
+
for (const cause of event.causes ?? [])
|
|
375
|
+
closesAt.set(cause, event.seq);
|
|
376
|
+
}
|
|
377
|
+
let found;
|
|
378
|
+
for (const event of events) {
|
|
379
|
+
if (event.seq > seq)
|
|
380
|
+
break;
|
|
381
|
+
if (!isDelegation(event))
|
|
382
|
+
continue;
|
|
383
|
+
const closes = closesAt.get(event.seq);
|
|
384
|
+
// Still open at `seq`: an unclosed delegation ran to the end of the trace.
|
|
385
|
+
if (closes !== undefined && closes < seq)
|
|
386
|
+
continue;
|
|
387
|
+
const input = toAttrs(event)['input'];
|
|
388
|
+
const subagent = String(input?.['subagent_type'] ?? input?.['agent'] ?? 'sub-agent');
|
|
389
|
+
found = { seq: event.seq, subagent };
|
|
390
|
+
}
|
|
391
|
+
return found;
|
|
392
|
+
}
|
|
393
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|