@hunterzhu/pulse-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/context/builder.d.ts +68 -0
  2. package/dist/context/builder.js +127 -0
  3. package/dist/context/index.d.ts +2 -0
  4. package/dist/context/index.js +2 -0
  5. package/dist/context/merger.d.ts +25 -0
  6. package/dist/context/merger.js +125 -0
  7. package/dist/core/actions.d.ts +1 -0
  8. package/dist/core/actions.js +1 -0
  9. package/dist/core/errors.d.ts +8 -0
  10. package/dist/core/errors.js +36 -0
  11. package/dist/core/events.d.ts +10 -0
  12. package/dist/core/events.js +24 -0
  13. package/dist/core/factory.d.ts +35 -0
  14. package/dist/core/factory.js +27 -0
  15. package/dist/core/inbox.d.ts +119 -0
  16. package/dist/core/inbox.js +217 -0
  17. package/dist/core/mutations.d.ts +80 -0
  18. package/dist/core/mutations.js +127 -0
  19. package/dist/core/records.d.ts +1 -0
  20. package/dist/core/records.js +1 -0
  21. package/dist/core/types.d.ts +615 -0
  22. package/dist/core/types.js +109 -0
  23. package/dist/dependencies/graph.d.ts +25 -0
  24. package/dist/dependencies/graph.js +92 -0
  25. package/dist/dependencies/index.d.ts +1 -0
  26. package/dist/dependencies/index.js +1 -0
  27. package/dist/dsl/context-proxy.d.ts +20 -0
  28. package/dist/dsl/context-proxy.js +64 -0
  29. package/dist/dsl/index.d.ts +4 -0
  30. package/dist/dsl/index.js +4 -0
  31. package/dist/dsl/program.d.ts +314 -0
  32. package/dist/dsl/program.js +756 -0
  33. package/dist/dsl/session.d.ts +45 -0
  34. package/dist/dsl/session.js +93 -0
  35. package/dist/dsl/templates-index.d.ts +1 -0
  36. package/dist/dsl/templates-index.js +1 -0
  37. package/dist/dsl/templates.d.ts +85 -0
  38. package/dist/dsl/templates.js +110 -0
  39. package/dist/index.d.ts +15 -0
  40. package/dist/index.js +15 -0
  41. package/dist/lifecycle/index.d.ts +2 -0
  42. package/dist/lifecycle/index.js +2 -0
  43. package/dist/lifecycle/scopes.d.ts +38 -0
  44. package/dist/lifecycle/scopes.js +50 -0
  45. package/dist/lifecycle/watchdog.d.ts +16 -0
  46. package/dist/lifecycle/watchdog.js +66 -0
  47. package/dist/models/actions.d.ts +10 -0
  48. package/dist/models/actions.js +68 -0
  49. package/dist/models/index.d.ts +2 -0
  50. package/dist/models/index.js +2 -0
  51. package/dist/models/router.d.ts +187 -0
  52. package/dist/models/router.js +353 -0
  53. package/dist/scheduler/clock.d.ts +45 -0
  54. package/dist/scheduler/clock.js +92 -0
  55. package/dist/scheduler/decision.d.ts +72 -0
  56. package/dist/scheduler/decision.js +63 -0
  57. package/dist/scheduler/index.d.ts +6 -0
  58. package/dist/scheduler/index.js +6 -0
  59. package/dist/scheduler/locks.d.ts +18 -0
  60. package/dist/scheduler/locks.js +106 -0
  61. package/dist/scheduler/ready-queue.d.ts +32 -0
  62. package/dist/scheduler/ready-queue.js +40 -0
  63. package/dist/scheduler/runtime.d.ts +486 -0
  64. package/dist/scheduler/runtime.js +3445 -0
  65. package/dist/scheduler/telemetry.d.ts +111 -0
  66. package/dist/scheduler/telemetry.js +177 -0
  67. package/dist/scheduler/worker.d.ts +158 -0
  68. package/dist/scheduler/worker.js +744 -0
  69. package/dist/storage/artifacts.d.ts +17 -0
  70. package/dist/storage/artifacts.js +90 -0
  71. package/dist/storage/findings.d.ts +12 -0
  72. package/dist/storage/findings.js +70 -0
  73. package/dist/storage/index.d.ts +8 -0
  74. package/dist/storage/index.js +8 -0
  75. package/dist/storage/memory.d.ts +11 -0
  76. package/dist/storage/memory.js +21 -0
  77. package/dist/storage/mutation-log.d.ts +41 -0
  78. package/dist/storage/mutation-log.js +140 -0
  79. package/dist/storage/outbox.d.ts +30 -0
  80. package/dist/storage/outbox.js +59 -0
  81. package/dist/storage/persistence.d.ts +183 -0
  82. package/dist/storage/persistence.js +999 -0
  83. package/dist/storage/policy.d.ts +80 -0
  84. package/dist/storage/policy.js +268 -0
  85. package/dist/storage/session.d.ts +140 -0
  86. package/dist/storage/session.js +447 -0
  87. package/dist/tools/registry.d.ts +125 -0
  88. package/dist/tools/registry.js +308 -0
  89. package/dist/transitions/index.d.ts +2 -0
  90. package/dist/transitions/index.js +1 -0
  91. package/dist/transitions/validate.d.ts +4 -0
  92. package/dist/transitions/validate.js +1118 -0
  93. package/package.json +21 -0
@@ -0,0 +1,80 @@
1
+ import type { JsonValue } from '../core/types.js';
2
+ export type StorageKind = 'event' | 'result' | 'artifact' | 'snapshot';
3
+ export type StorageState = 'memory' | 'persisted' | 'compacted';
4
+ export interface StoragePolicyConfig {
5
+ maxEventLogBytes?: number;
6
+ maxResultBytes?: number;
7
+ maxArtifactBytes?: number;
8
+ maxSnapshotBytes?: number;
9
+ maxTotalMemoryBytes?: number;
10
+ }
11
+ export interface StoredRecord {
12
+ key: string;
13
+ kind: StorageKind;
14
+ storageState: StorageState;
15
+ pinCount: number;
16
+ bytes: number;
17
+ hash: string;
18
+ value?: JsonValue;
19
+ }
20
+ /** Record metadata without the body; safe to hand out without cloning the value. */
21
+ export type StoredRecordInfo = Omit<StoredRecord, 'value'>;
22
+ export interface StoragePolicySnapshot {
23
+ schemaVersion: 1;
24
+ limits: Required<StoragePolicyConfig>;
25
+ records: StoredRecord[];
26
+ pinSources: Array<[string, string[]]>;
27
+ }
28
+ /**
29
+ * Session-wide memory accounting for events, results, artifacts and snapshots.
30
+ *
31
+ * Records are treated as immutable values: every state change replaces the
32
+ * record object instead of mutating it. That makes `clone()` a shallow copy of
33
+ * the maps (copy-on-write), keeps per-kind byte totals as O(1) counters, and
34
+ * lets `put()` roll back by restoring the handful of records it touched instead
35
+ * of snapshotting the whole policy. Values are still cloned on the way in and
36
+ * out, so callers can never alias internal state.
37
+ */
38
+ export declare class SessionStoragePolicy {
39
+ private records;
40
+ private pinSources;
41
+ /** Reverse index: record key -> number of pin sources holding it. */
42
+ private managedPins;
43
+ private readonly limits;
44
+ private memoryByKind;
45
+ private memoryTotal;
46
+ constructor(config?: StoragePolicyConfig);
47
+ put(kind: StorageKind, key: string, value: JsonValue, pin?: boolean): StoredRecord;
48
+ get(key: string): JsonValue | undefined;
49
+ has(key: string): boolean;
50
+ /** Metadata for one record without cloning its body. */
51
+ record(key: string): StoredRecordInfo | undefined;
52
+ pin(key: string): void;
53
+ unpin(key: string): void;
54
+ remove(key: string): boolean;
55
+ /** Replace one logical owner’s pins without double-counting repeated reconciliation. */
56
+ replacePinSource(source: string, keys: Iterable<string>): void;
57
+ /** Make a private copy suitable for validate-stage storage admission. Shallow: records are immutable and shared. */
58
+ clone(): SessionStoragePolicy;
59
+ /** Adopt the state of a clone produced by `clone()` after it has been mutated as a candidate. */
60
+ adopt(candidate: SessionStoragePolicy): void;
61
+ snapshot(): StoragePolicySnapshot;
62
+ /** Atomically replace this policy with a previously validated candidate snapshot. */
63
+ replaceSnapshot(snapshot: StoragePolicySnapshot): void;
64
+ static fromSnapshot(snapshot: StoragePolicySnapshot | JsonValue): SessionStoragePolicy;
65
+ compact(key: string): boolean;
66
+ /** Mark records durable only after the persistence backend has acknowledged the snapshot. */
67
+ markPersisted(keys?: Iterable<string>): void;
68
+ inspect(): StoredRecord[];
69
+ /** Keys of all records, without copying bodies. */
70
+ keys(): IterableIterator<string>;
71
+ get memoryBytesTotal(): number;
72
+ private compactToFit;
73
+ /** Install a record and keep the byte counters in sync with its residency. */
74
+ private set;
75
+ private unset;
76
+ private kindLimit;
77
+ private require;
78
+ private copyRecord;
79
+ private restore;
80
+ }
@@ -0,0 +1,268 @@
1
+ import { contentHash, stableSerialize } from '../context/builder.js';
2
+ const storageLimitKeys = ['maxEventLogBytes', 'maxResultBytes', 'maxArtifactBytes', 'maxSnapshotBytes', 'maxTotalMemoryBytes'];
3
+ function validStorageLimits(value) {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value))
5
+ return false;
6
+ const limits = value;
7
+ return storageLimitKeys.every((key) => Number.isInteger(limits[key]) && limits[key] >= 0);
8
+ }
9
+ function validStoragePolicySnapshot(value) {
10
+ if (!value || typeof value !== 'object' || Array.isArray(value))
11
+ return false;
12
+ const snapshot = value;
13
+ if (snapshot.schemaVersion !== 1 || !validStorageLimits(snapshot.limits) || !Array.isArray(snapshot.records) || !Array.isArray(snapshot.pinSources))
14
+ return false;
15
+ const keys = new Set();
16
+ for (const record of snapshot.records) {
17
+ if (!record || typeof record.key !== 'string' || record.key.length === 0 || keys.has(record.key) || !['event', 'result', 'artifact', 'snapshot'].includes(record.kind) || !['memory', 'persisted', 'compacted'].includes(record.storageState) || !Number.isInteger(record.pinCount) || record.pinCount < 0 || !Number.isInteger(record.bytes) || record.bytes < 0 || !/^[a-f0-9]{64}$/.test(record.hash) || (record.kind === 'event' && record.storageState === 'compacted') || (record.storageState === 'memory' && record.value === undefined) || (record.storageState !== 'memory' && record.value !== undefined))
18
+ return false;
19
+ if (record.value !== undefined) {
20
+ try {
21
+ if (Buffer.byteLength(stableSerialize(record.value), 'utf8') !== record.bytes || contentHash(record.value) !== record.hash)
22
+ return false;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ keys.add(record.key);
29
+ }
30
+ const sources = new Set();
31
+ const managedPins = new Map();
32
+ for (const entry of snapshot.pinSources) {
33
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== 'string' || entry[0].length === 0 || sources.has(entry[0]) || !Array.isArray(entry[1]) || new Set(entry[1]).size !== entry[1].length || entry[1].some((key) => typeof key !== 'string' || key.length === 0))
34
+ return false;
35
+ sources.add(entry[0]);
36
+ for (const key of entry[1])
37
+ managedPins.set(key, (managedPins.get(key) ?? 0) + 1);
38
+ }
39
+ for (const record of snapshot.records)
40
+ if (record.pinCount < (managedPins.get(record.key) ?? 0))
41
+ return false;
42
+ return true;
43
+ }
44
+ /**
45
+ * Session-wide memory accounting for events, results, artifacts and snapshots.
46
+ *
47
+ * Records are treated as immutable values: every state change replaces the
48
+ * record object instead of mutating it. That makes `clone()` a shallow copy of
49
+ * the maps (copy-on-write), keeps per-kind byte totals as O(1) counters, and
50
+ * lets `put()` roll back by restoring the handful of records it touched instead
51
+ * of snapshotting the whole policy. Values are still cloned on the way in and
52
+ * out, so callers can never alias internal state.
53
+ */
54
+ export class SessionStoragePolicy {
55
+ records = new Map();
56
+ pinSources = new Map();
57
+ /** Reverse index: record key -> number of pin sources holding it. */
58
+ managedPins = new Map();
59
+ limits;
60
+ memoryByKind = { event: 0, result: 0, artifact: 0, snapshot: 0 };
61
+ memoryTotal = 0;
62
+ constructor(config = {}) {
63
+ const limits = { maxEventLogBytes: config.maxEventLogBytes ?? 1_000_000, maxResultBytes: config.maxResultBytes ?? 1_000_000, maxArtifactBytes: config.maxArtifactBytes ?? 4_000_000, maxSnapshotBytes: config.maxSnapshotBytes ?? 1_000_000, maxTotalMemoryBytes: config.maxTotalMemoryBytes ?? 4_000_000 };
64
+ if (!validStorageLimits(limits))
65
+ throw new Error('INVALID_STORAGE_POLICY_LIMITS');
66
+ this.limits = limits;
67
+ }
68
+ put(kind, key, value, pin = false) {
69
+ const bytes = Buffer.byteLength(stableSerialize(value));
70
+ const hash = contentHash(value);
71
+ const previous = this.records.get(key);
72
+ if (previous && previous.kind !== kind)
73
+ throw new Error('STORAGE_KEY_KIND_CONFLICT');
74
+ const managedPin = previous === undefined ? this.managedPins.get(key) ?? 0 : 0;
75
+ const unchanged = previous !== undefined && previous.bytes === bytes && previous.hash === hash;
76
+ const storageState = unchanged ? previous.storageState : 'memory';
77
+ const record = { key, kind, storageState, pinCount: (previous?.pinCount ?? 0) + (pin ? 1 : 0) + managedPin, bytes, hash, ...(storageState === 'memory' ? { value: unchanged && previous.value !== undefined ? previous.value : structuredClone(value) } : {}) };
78
+ const touched = new Map([[key, previous]]);
79
+ this.set(record);
80
+ this.compactToFit(kind, key, touched);
81
+ if (this.memoryByKind[kind] > this.kindLimit(kind) || this.memoryTotal > this.limits.maxTotalMemoryBytes) {
82
+ for (const [touchedKey, original] of touched)
83
+ if (original === undefined)
84
+ this.unset(touchedKey);
85
+ else
86
+ this.set(original);
87
+ throw new Error('SESSION_STORAGE_LIMIT_EXCEEDED');
88
+ }
89
+ return this.copyRecord(record);
90
+ }
91
+ get(key) {
92
+ const record = this.records.get(key);
93
+ return record?.storageState === 'memory' && record.value !== undefined ? structuredClone(record.value) : undefined;
94
+ }
95
+ has(key) { return this.records.has(key); }
96
+ /** Metadata for one record without cloning its body. */
97
+ record(key) {
98
+ const record = this.records.get(key);
99
+ if (!record)
100
+ return undefined;
101
+ const { value: _value, ...info } = record;
102
+ return info;
103
+ }
104
+ pin(key) { const record = this.require(key); this.set({ ...record, pinCount: record.pinCount + 1 }); }
105
+ unpin(key) { const record = this.require(key); this.set({ ...record, pinCount: Math.max(0, record.pinCount - 1) }); }
106
+ remove(key) {
107
+ const record = this.records.get(key);
108
+ if (!record || record.pinCount > 0 || record.kind === 'event')
109
+ return false;
110
+ this.unset(key);
111
+ if (this.managedPins.has(key)) {
112
+ for (const [source, keys] of this.pinSources) {
113
+ if (!keys.has(key))
114
+ continue;
115
+ const next = new Set(keys);
116
+ next.delete(key);
117
+ if (next.size === 0)
118
+ this.pinSources.delete(source);
119
+ else
120
+ this.pinSources.set(source, next);
121
+ }
122
+ this.managedPins.delete(key);
123
+ }
124
+ return true;
125
+ }
126
+ /** Replace one logical owner’s pins without double-counting repeated reconciliation. */
127
+ replacePinSource(source, keys) {
128
+ const next = new Set(keys);
129
+ const previous = this.pinSources.get(source) ?? new Set();
130
+ for (const key of previous)
131
+ if (!next.has(key)) {
132
+ const count = (this.managedPins.get(key) ?? 1) - 1;
133
+ if (count <= 0)
134
+ this.managedPins.delete(key);
135
+ else
136
+ this.managedPins.set(key, count);
137
+ if (this.records.has(key))
138
+ this.unpin(key);
139
+ }
140
+ for (const key of next)
141
+ if (!previous.has(key)) {
142
+ this.managedPins.set(key, (this.managedPins.get(key) ?? 0) + 1);
143
+ if (this.records.has(key))
144
+ this.pin(key);
145
+ }
146
+ if (next.size)
147
+ this.pinSources.set(source, next);
148
+ else
149
+ this.pinSources.delete(source);
150
+ }
151
+ /** Make a private copy suitable for validate-stage storage admission. Shallow: records are immutable and shared. */
152
+ clone() {
153
+ const copy = new SessionStoragePolicy(this.limits);
154
+ copy.records = new Map(this.records);
155
+ copy.pinSources = new Map(this.pinSources);
156
+ copy.managedPins = new Map(this.managedPins);
157
+ copy.memoryByKind = { ...this.memoryByKind };
158
+ copy.memoryTotal = this.memoryTotal;
159
+ return copy;
160
+ }
161
+ /** Adopt the state of a clone produced by `clone()` after it has been mutated as a candidate. */
162
+ adopt(candidate) {
163
+ if (storageLimitKeys.some((key) => candidate.limits[key] !== this.limits[key]))
164
+ throw new Error('STORAGE_POLICY_LIMITS_MISMATCH');
165
+ this.records = new Map(candidate.records);
166
+ this.pinSources = new Map(candidate.pinSources);
167
+ this.managedPins = new Map(candidate.managedPins);
168
+ this.memoryByKind = { ...candidate.memoryByKind };
169
+ this.memoryTotal = candidate.memoryTotal;
170
+ }
171
+ snapshot() { return { schemaVersion: 1, limits: { ...this.limits }, records: [...this.records.values()].map((record) => this.copyRecord(record)), pinSources: [...this.pinSources.entries()].map(([source, keys]) => [source, [...keys]]) }; }
172
+ /** Atomically replace this policy with a previously validated candidate snapshot. */
173
+ replaceSnapshot(snapshot) {
174
+ if (!validStoragePolicySnapshot(snapshot))
175
+ throw new Error('INVALID_STORAGE_POLICY_SNAPSHOT');
176
+ this.restore(snapshot);
177
+ }
178
+ static fromSnapshot(snapshot) {
179
+ const value = snapshot;
180
+ if (!validStoragePolicySnapshot(value))
181
+ throw new Error('INVALID_STORAGE_POLICY_SNAPSHOT');
182
+ const policy = new SessionStoragePolicy(value.limits);
183
+ policy.restore(value);
184
+ return policy;
185
+ }
186
+ compact(key) {
187
+ const record = this.require(key);
188
+ if (record.kind === 'event')
189
+ throw new Error('FACT_EVENT_REQUIRES_PERSISTENCE');
190
+ if (record.pinCount > 0 || record.storageState === 'compacted')
191
+ return false;
192
+ const { value: _value, ...rest } = record;
193
+ this.set({ ...rest, storageState: 'compacted' });
194
+ return true;
195
+ }
196
+ /** Mark records durable only after the persistence backend has acknowledged the snapshot. */
197
+ markPersisted(keys) {
198
+ const selected = keys === undefined ? [...this.records.keys()] : [...keys];
199
+ for (const key of selected) {
200
+ const record = this.require(key);
201
+ if (record.storageState === 'compacted')
202
+ continue;
203
+ const { value: _value, ...rest } = record;
204
+ this.set({ ...rest, storageState: 'persisted' });
205
+ }
206
+ }
207
+ inspect() { return [...this.records.values()].map((record) => this.copyRecord(record)); }
208
+ /** Keys of all records, without copying bodies. */
209
+ keys() { return this.records.keys(); }
210
+ get memoryBytesTotal() { return this.memoryTotal; }
211
+ compactToFit(kind, protectedKey, touched) {
212
+ while (this.memoryByKind[kind] > this.kindLimit(kind) || this.memoryTotal > this.limits.maxTotalMemoryBytes) {
213
+ let candidate;
214
+ for (const record of this.records.values())
215
+ if (record.key !== protectedKey && record.storageState === 'memory' && record.pinCount === 0 && record.kind !== 'event') {
216
+ candidate = record;
217
+ break;
218
+ }
219
+ if (!candidate)
220
+ break;
221
+ if (!touched.has(candidate.key))
222
+ touched.set(candidate.key, candidate);
223
+ if (!this.compact(candidate.key))
224
+ break;
225
+ }
226
+ }
227
+ /** Install a record and keep the byte counters in sync with its residency. */
228
+ set(record) {
229
+ const previous = this.records.get(record.key);
230
+ if (previous?.storageState === 'memory') {
231
+ this.memoryByKind[previous.kind] -= previous.bytes;
232
+ this.memoryTotal -= previous.bytes;
233
+ }
234
+ if (record.storageState === 'memory') {
235
+ this.memoryByKind[record.kind] += record.bytes;
236
+ this.memoryTotal += record.bytes;
237
+ }
238
+ this.records.set(record.key, record);
239
+ }
240
+ unset(key) {
241
+ const previous = this.records.get(key);
242
+ if (!previous)
243
+ return;
244
+ if (previous.storageState === 'memory') {
245
+ this.memoryByKind[previous.kind] -= previous.bytes;
246
+ this.memoryTotal -= previous.bytes;
247
+ }
248
+ this.records.delete(key);
249
+ }
250
+ kindLimit(kind) { return kind === 'event' ? this.limits.maxEventLogBytes : kind === 'result' ? this.limits.maxResultBytes : kind === 'artifact' ? this.limits.maxArtifactBytes : this.limits.maxSnapshotBytes; }
251
+ require(key) { const record = this.records.get(key); if (!record)
252
+ throw new Error(`UNKNOWN_STORAGE_KEY:${key}`); return record; }
253
+ copyRecord(record) { return { ...record, ...(record.value === undefined ? {} : { value: structuredClone(record.value) }) }; }
254
+ restore(snapshot) {
255
+ this.records = new Map();
256
+ this.memoryByKind = { event: 0, result: 0, artifact: 0, snapshot: 0 };
257
+ this.memoryTotal = 0;
258
+ for (const record of snapshot.records)
259
+ this.set(this.copyRecord(record));
260
+ this.pinSources = new Map();
261
+ this.managedPins = new Map();
262
+ for (const [source, keys] of snapshot.pinSources) {
263
+ this.pinSources.set(source, new Set(keys));
264
+ for (const key of keys)
265
+ this.managedPins.set(key, (this.managedPins.get(key) ?? 0) + 1);
266
+ }
267
+ }
268
+ }
@@ -0,0 +1,140 @@
1
+ import type { AgentRecord, ArtifactRecord, EffectRecord, JsonValue, LaneRecord, MergeProposal, PrivacyLabel, PrivacyMetadata, ResultRecord, RuntimeEvent, RuntimeState, WaitRecord, ToolCallCorrelation } from '../core/types.js';
2
+ export interface SessionSnapshot {
3
+ schemaVersion: 1;
4
+ state: {
5
+ now: number;
6
+ agents: Array<[string, Omit<AgentRecord, 'globalVersions' | 'globalPrivacy'> & {
7
+ globalVersions: Array<[number, JsonValue]>;
8
+ globalPrivacy?: Array<[number, PrivacyMetadata]>;
9
+ }]>;
10
+ lanes: Array<[string, Omit<LaneRecord, 'children' | 'ownedEffectIds' | 'visibleResultRefs'> & {
11
+ children: string[];
12
+ ownedEffectIds: string[];
13
+ visibleResultRefs?: string[];
14
+ }]>;
15
+ effects: Array<[string, EffectRecord]>;
16
+ waits: Array<[string, WaitRecord]>;
17
+ results: Array<[string, ResultRecord]>;
18
+ artifacts?: Array<[string, ArtifactRecord]>;
19
+ toolCallCorrelations?: Array<[string, ToolCallCorrelation]>;
20
+ mergeProposals: Array<[string, MergeProposal]>;
21
+ events: RuntimeEvent[];
22
+ eventsCompactedThrough?: number;
23
+ nextIds: RuntimeState['nextIds'];
24
+ maxTotalLanes: number;
25
+ maxQueuedEffects: number;
26
+ maxRunning: Record<'llm' | 'tool' | 'agent' | 'none', number | 'Infinity'>;
27
+ forkAffinity?: 'off' | 'advise' | 'coalesce';
28
+ historySoftTokens?: number;
29
+ historyHardTokens?: number;
30
+ maxResultSummaryBytes?: number;
31
+ trustedSanitizerIds?: string[];
32
+ };
33
+ }
34
+ export interface RuntimeWarmStartSnapshot {
35
+ schemaVersion: 1;
36
+ sessionId: string;
37
+ agent: {
38
+ rootLaneId: string;
39
+ latestGlobalVersion: number;
40
+ globalVersions: Array<[number, JsonValue]>;
41
+ globalPrivacy?: Array<[number, PrivacyMetadata]>;
42
+ };
43
+ visibleResultRefs: string[];
44
+ results: Array<[string, ResultRecord]>;
45
+ }
46
+ export interface RuntimeSessionStore {
47
+ get(sessionId: string): RuntimeWarmStartSnapshot | undefined;
48
+ put(snapshot: RuntimeWarmStartSnapshot): void;
49
+ }
50
+ export interface RuntimeSessionRevision {
51
+ snapshot: RuntimeWarmStartSnapshot;
52
+ revision: number;
53
+ }
54
+ export interface VersionedRuntimeSessionStore extends RuntimeSessionStore {
55
+ getWithRevision(sessionId: string): RuntimeSessionRevision | undefined;
56
+ putIfRevision(snapshot: RuntimeWarmStartSnapshot, expectedRevision?: number): number;
57
+ }
58
+ export declare class InMemoryRuntimeSessionStore implements RuntimeSessionStore {
59
+ private readonly snapshots;
60
+ get(sessionId: string): RuntimeWarmStartSnapshot | undefined;
61
+ put(snapshot: RuntimeWarmStartSnapshot): void;
62
+ getWithRevision(sessionId: string): RuntimeSessionRevision | undefined;
63
+ putIfRevision(snapshot: RuntimeWarmStartSnapshot, expectedRevision?: number): number;
64
+ }
65
+ /** Durable synchronous Session Store for hosts that need createAgent() to remain synchronous. */
66
+ export declare class FileRuntimeSessionStore implements VersionedRuntimeSessionStore {
67
+ readonly filePath: string;
68
+ constructor(filePath: string);
69
+ get(sessionId: string): RuntimeWarmStartSnapshot | undefined;
70
+ getWithRevision(sessionId: string): RuntimeSessionRevision | undefined;
71
+ put(snapshot: RuntimeWarmStartSnapshot): void;
72
+ putIfRevision(snapshot: RuntimeWarmStartSnapshot, expectedRevision?: number): number;
73
+ private readEnvelope;
74
+ private writeEnvelope;
75
+ private withLock;
76
+ }
77
+ /** Durable SQLite Session Store with transaction-scoped revision CAS. */
78
+ export declare class SqliteRuntimeSessionStore implements VersionedRuntimeSessionStore {
79
+ readonly filePath: string;
80
+ private database;
81
+ constructor(filePath: string);
82
+ get(sessionId: string): RuntimeWarmStartSnapshot | undefined;
83
+ getWithRevision(sessionId: string): RuntimeSessionRevision | undefined;
84
+ put(snapshot: RuntimeWarmStartSnapshot): void;
85
+ putIfRevision(snapshot: RuntimeWarmStartSnapshot, expectedRevision?: number): number;
86
+ close(): void;
87
+ private open;
88
+ }
89
+ export interface SessionLogExportOptions {
90
+ maxPrivacy?: PrivacyLabel;
91
+ }
92
+ export type SessionLogResult = Omit<ResultRecord, 'value' | 'summary'> & {
93
+ value?: JsonValue;
94
+ summary?: JsonValue;
95
+ redacted?: boolean;
96
+ };
97
+ export type SessionLogArtifact = Omit<ArtifactRecord, 'contentBase64'> & {
98
+ contentBase64?: string;
99
+ redacted?: boolean;
100
+ };
101
+ export interface SessionLogExport {
102
+ schemaVersion: 1;
103
+ maxPrivacy: PrivacyLabel;
104
+ events: RuntimeEvent[];
105
+ results: SessionLogResult[];
106
+ artifacts: SessionLogArtifact[];
107
+ }
108
+ export interface RuntimeLogSink {
109
+ append(log: SessionLogExport): Promise<void> | void;
110
+ }
111
+ /** A durable JSONL audit sink. Each successfully returned append is fsync'd. */
112
+ export declare class FileRuntimeLogSink implements RuntimeLogSink {
113
+ readonly filePath: string;
114
+ private pending;
115
+ constructor(filePath: string);
116
+ append(log: SessionLogExport): Promise<void>;
117
+ }
118
+ export interface HttpRuntimeLogSinkOptions {
119
+ endpoint: string;
120
+ headers?: Record<string, string>;
121
+ timeoutMs?: number;
122
+ fetch?: typeof globalThis.fetch;
123
+ }
124
+ /** Sends privacy-filtered audit exports to a host-owned collector. */
125
+ export declare class HttpRuntimeLogSink implements RuntimeLogSink {
126
+ private readonly endpoint;
127
+ private readonly headers;
128
+ private readonly timeoutMs;
129
+ private readonly fetcher;
130
+ constructor(options: HttpRuntimeLogSinkOptions);
131
+ append(log: SessionLogExport): Promise<void>;
132
+ }
133
+ export declare function exportRuntimeState(state: RuntimeState): SessionSnapshot;
134
+ export declare function exportWarmStartSession(state: RuntimeState, sessionId: string): RuntimeWarmStartSnapshot;
135
+ /** Export audit/log data with an explicit privacy ceiling; this is not a recovery snapshot. */
136
+ export declare function exportRuntimeLog(state: RuntimeState, options?: SessionLogExportOptions): SessionLogExport;
137
+ /** Applies the privacy ceiling before handing an audit export to its sink. */
138
+ export declare function exportRuntimeLogTo(state: RuntimeState, sink: RuntimeLogSink, options?: SessionLogExportOptions): Promise<SessionLogExport>;
139
+ export declare function serializeRuntimeState(state: RuntimeState): JsonValue;
140
+ export declare function importRuntimeState(snapshot: SessionSnapshot | JsonValue): RuntimeState;