@vib-rato/agent-core 0.16.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 (69) hide show
  1. package/CHANGELOG.md +852 -0
  2. package/README.md +493 -0
  3. package/dist/types/agent-loop.d.ts +229 -0
  4. package/dist/types/agent.d.ts +533 -0
  5. package/dist/types/append-only-context.d.ts +141 -0
  6. package/dist/types/attempt-scope.d.ts +84 -0
  7. package/dist/types/compaction/adaptive.d.ts +31 -0
  8. package/dist/types/compaction/branch-summarization.d.ts +103 -0
  9. package/dist/types/compaction/compaction.d.ts +330 -0
  10. package/dist/types/compaction/entries.d.ts +124 -0
  11. package/dist/types/compaction/errors.d.ts +26 -0
  12. package/dist/types/compaction/index.d.ts +12 -0
  13. package/dist/types/compaction/messages.d.ts +61 -0
  14. package/dist/types/compaction/openai.d.ts +65 -0
  15. package/dist/types/compaction/pruning.d.ts +130 -0
  16. package/dist/types/compaction/utils.d.ts +32 -0
  17. package/dist/types/compaction.d.ts +1 -0
  18. package/dist/types/harmony-leak.d.ts +100 -0
  19. package/dist/types/heap-eviction-retainers.test.d.ts +1 -0
  20. package/dist/types/image-placeholder-guard.d.ts +4 -0
  21. package/dist/types/index.d.ts +13 -0
  22. package/dist/types/proxy.d.ts +95 -0
  23. package/dist/types/run-collector.d.ts +223 -0
  24. package/dist/types/run-resource-ledger.d.ts +2 -0
  25. package/dist/types/telemetry.d.ts +605 -0
  26. package/dist/types/thinking.d.ts +18 -0
  27. package/dist/types/tool-dispatch-identity.d.ts +27 -0
  28. package/dist/types/types.d.ts +790 -0
  29. package/package.json +72 -0
  30. package/src/agent-loop.ts +5632 -0
  31. package/src/agent.ts +2437 -0
  32. package/src/append-only-context.ts +496 -0
  33. package/src/attempt-scope.ts +195 -0
  34. package/src/compaction/adaptive.ts +92 -0
  35. package/src/compaction/branch-summarization.ts +358 -0
  36. package/src/compaction/compaction.ts +1569 -0
  37. package/src/compaction/entries.ts +158 -0
  38. package/src/compaction/errors.ts +31 -0
  39. package/src/compaction/index.ts +13 -0
  40. package/src/compaction/messages.ts +212 -0
  41. package/src/compaction/openai.ts +580 -0
  42. package/src/compaction/prompts/auto-handoff-threshold-focus.md +1 -0
  43. package/src/compaction/prompts/branch-summary-context.md +5 -0
  44. package/src/compaction/prompts/branch-summary-preamble.md +2 -0
  45. package/src/compaction/prompts/branch-summary.md +30 -0
  46. package/src/compaction/prompts/compaction-short-summary.md +9 -0
  47. package/src/compaction/prompts/compaction-summary-context.md +5 -0
  48. package/src/compaction/prompts/compaction-summary.md +38 -0
  49. package/src/compaction/prompts/compaction-turn-prefix.md +17 -0
  50. package/src/compaction/prompts/compaction-update-summary.md +45 -0
  51. package/src/compaction/prompts/file-operations.md +10 -0
  52. package/src/compaction/prompts/handoff-document.md +56 -0
  53. package/src/compaction/prompts/summarization-system.md +3 -0
  54. package/src/compaction/pruning.ts +1026 -0
  55. package/src/compaction/utils.ts +189 -0
  56. package/src/compaction.ts +1 -0
  57. package/src/harmony-leak.ts +457 -0
  58. package/src/heap-eviction-retainers.test.ts +293 -0
  59. package/src/image-placeholder-guard.ts +20 -0
  60. package/src/index.ts +23 -0
  61. package/src/prompts/escaped-nonascii-recovery.md +3 -0
  62. package/src/prompts/repeated-tool-failure-recovery.md +1 -0
  63. package/src/proxy.ts +408 -0
  64. package/src/run-collector.ts +728 -0
  65. package/src/run-resource-ledger.ts +345 -0
  66. package/src/telemetry.ts +2161 -0
  67. package/src/thinking.ts +20 -0
  68. package/src/tool-dispatch-identity.ts +87 -0
  69. package/src/types.ts +882 -0
@@ -0,0 +1,345 @@
1
+ import type {
2
+ ClaimProducerResult,
3
+ ForkProducerResult,
4
+ ReserveProducerResult,
5
+ RunCancellationDomain,
6
+ RunCancellationDomainBridge,
7
+ RunResourceEntry,
8
+ RunResourceKind,
9
+ RunResourceLedger,
10
+ RunResourceProducerLease,
11
+ RunSettlementProof,
12
+ } from "./types";
13
+
14
+ const MAX_TOMBSTONE_ENTRIES = 256;
15
+ type RunLifecycle = "open" | "sealed" | "quarantined";
16
+
17
+ interface TrackedResource {
18
+ entry: RunResourceEntry;
19
+ }
20
+
21
+ interface RunState {
22
+ lifecycle: RunLifecycle;
23
+ resourceRunId: string;
24
+ domain: RunCancellationDomain | undefined;
25
+ domainBridge: RunCancellationDomainBridge;
26
+ resources: Map<string, TrackedResource>;
27
+ tombstone: RunResourceEntry[];
28
+ waiters: Set<SettlementWaiter>;
29
+ claimedOwners: Set<object>;
30
+ released: boolean;
31
+ }
32
+
33
+ interface SettlementWaiter {
34
+ resolve: (proof: RunSettlementProof) => void;
35
+ timer: NodeJS.Timeout;
36
+ }
37
+
38
+ function copyEntries(entries: readonly RunResourceEntry[]): RunResourceEntry[] {
39
+ return entries.map(entry => ({ ...entry }));
40
+ }
41
+
42
+ export function createRunResourceLedger(): RunResourceLedger {
43
+ const runs = new Map<string, RunState>();
44
+ const standaloneDomains = new Map<string, { domain: RunCancellationDomain; controller: AbortController }>();
45
+ const standaloneReleased = new Set<string>();
46
+ const standaloneQuarantined = new Set<string>();
47
+ let bridge: RunCancellationDomainBridge | undefined;
48
+ let agentSessionClaimKey: object | undefined;
49
+ let sequence = 0;
50
+
51
+ const standaloneBridge: RunCancellationDomainBridge = {
52
+ open(resourceRunId) {
53
+ if (standaloneQuarantined.has(resourceRunId)) return { ok: false, reason: "quarantined" };
54
+ const existing = standaloneDomains.get(resourceRunId);
55
+ if (existing) return { ok: true, domain: existing.domain, created: false };
56
+ if (standaloneReleased.has(resourceRunId)) return { ok: false, reason: "duplicate_identity" };
57
+ const controller = new AbortController();
58
+ const domain: RunCancellationDomain = { resourceRunId, signal: controller.signal };
59
+ standaloneDomains.set(resourceRunId, { domain, controller });
60
+ return { ok: true, domain, created: true };
61
+ },
62
+ lookup(resourceRunId) {
63
+ return standaloneDomains.get(resourceRunId)?.domain;
64
+ },
65
+ abort(resourceRunId, reason) {
66
+ const record = standaloneDomains.get(resourceRunId);
67
+ if (!record)
68
+ return { ok: false, reason: standaloneQuarantined.has(resourceRunId) ? "quarantined" : "unknown_run" };
69
+ const newlyAborted = !record.controller.signal.aborted;
70
+ if (newlyAborted) record.controller.abort(reason);
71
+ return { ok: true, newlyAborted };
72
+ },
73
+ release(resourceRunId, disposition) {
74
+ const record = standaloneDomains.get(resourceRunId);
75
+ if (!record) return;
76
+ if (disposition === "quarantined") {
77
+ standaloneQuarantined.add(resourceRunId);
78
+ if (!record.controller.signal.aborted) record.controller.abort();
79
+ }
80
+ standaloneDomains.delete(resourceRunId);
81
+ standaloneReleased.add(resourceRunId);
82
+ },
83
+ };
84
+
85
+ const snapshot = (state: RunState): RunResourceEntry[] =>
86
+ state.lifecycle === "quarantined"
87
+ ? copyEntries(state.tombstone)
88
+ : [...state.resources.values()].map(resource => ({ ...resource.entry }));
89
+
90
+ const settlementProof = (state: RunState): RunSettlementProof | undefined => {
91
+ if (state.lifecycle === "quarantined")
92
+ return { status: "unfenced", reason: "quarantined", pending: copyEntries(state.tombstone) };
93
+ if (state.lifecycle === "sealed" && state.resources.size === 0) return { status: "settled" };
94
+ return undefined;
95
+ };
96
+
97
+ const releaseIfSettled = (state: RunState): void => {
98
+ if (state.released || state.lifecycle !== "sealed" || state.resources.size !== 0 || !state.domain) return;
99
+ state.released = true;
100
+ state.domainBridge.release(state.resourceRunId, "settled");
101
+ state.domain = undefined;
102
+ };
103
+
104
+ const notify = (state: RunState): void => {
105
+ const proof = settlementProof(state);
106
+ if (proof) {
107
+ for (const waiter of [...state.waiters]) {
108
+ clearTimeout(waiter.timer);
109
+ state.waiters.delete(waiter);
110
+ waiter.resolve(
111
+ proof.status === "settled"
112
+ ? proof
113
+ : { status: "unfenced", reason: proof.reason, pending: copyEntries(proof.pending) },
114
+ );
115
+ }
116
+ }
117
+ releaseIfSettled(state);
118
+ };
119
+
120
+ const appendTombstone = (state: RunState, entry: RunResourceEntry): void => {
121
+ state.tombstone.push({ ...entry });
122
+ if (state.tombstone.length > MAX_TOMBSTONE_ENTRIES)
123
+ state.tombstone.splice(0, state.tombstone.length - MAX_TOMBSTONE_ENTRIES);
124
+ };
125
+
126
+ const observeSettlement = (settled: PromiseLike<unknown>, onSettled: () => void): void => {
127
+ try {
128
+ void Promise.resolve(settled).then(onSettled, onSettled);
129
+ } catch {
130
+ onSettled();
131
+ }
132
+ };
133
+
134
+ const quarantineState = (state: RunState): RunResourceEntry[] => {
135
+ if (state.lifecycle !== "quarantined") {
136
+ state.lifecycle = "quarantined";
137
+ state.tombstone = [];
138
+ for (const resource of state.resources.values()) appendTombstone(state, resource.entry);
139
+ state.resources.clear();
140
+ if (state.domain) {
141
+ state.domainBridge.abort(state.resourceRunId);
142
+ if (!state.released) {
143
+ state.released = true;
144
+ state.domainBridge.release(state.resourceRunId, "quarantined");
145
+ }
146
+ state.domain = undefined;
147
+ }
148
+ }
149
+ notify(state);
150
+ return copyEntries(state.tombstone);
151
+ };
152
+
153
+ const register = (
154
+ state: RunState,
155
+ kind: RunResourceKind,
156
+ label: string,
157
+ settled: PromiseLike<unknown>,
158
+ ): string | undefined => {
159
+ if (state.lifecycle === "quarantined") {
160
+ const entry: RunResourceEntry = { id: `${++sequence}`, kind, label, registeredAt: Date.now() };
161
+ appendTombstone(state, entry);
162
+ observeSettlement(settled, () => {});
163
+ return undefined;
164
+ }
165
+ // Sealing only freezes admission of genuinely *new* work through
166
+ // reserveProducer()/claimProducer(); it does not mean the run's resources have
167
+ // all been registered yet. `agent_end` is published before seal(), and its
168
+ // handlers register their own post-prompt work while the event is still
169
+ // draining, so this late registration is the normal lifecycle rather than an
170
+ // escaped resource. Admit it into ordinary settlement accounting so the run
171
+ // stays unsettled until it completes; quarantining here would make every
172
+ // cancel unfenced forever.
173
+ const entry: RunResourceEntry = { id: `${++sequence}`, kind, label, registeredAt: Date.now() };
174
+ state.resources.set(entry.id, { entry });
175
+ observeSettlement(settled, () => {
176
+ state.resources.delete(entry.id);
177
+ notify(state);
178
+ });
179
+ return entry.id;
180
+ };
181
+
182
+ const leaseFor = (state: RunState, kind: RunResourceKind, label: string): RunResourceProducerLease | undefined => {
183
+ const domain = state.domain;
184
+ if (!domain) return undefined;
185
+ const completion = Promise.withResolvers<void>();
186
+ if (!register(state, kind, label, completion.promise)) return undefined;
187
+ let closed = false;
188
+ const close = (): void => {
189
+ if (closed) return;
190
+ closed = true;
191
+ completion.resolve();
192
+ };
193
+ const lease: RunResourceProducerLease = {
194
+ resourceRunId: state.resourceRunId,
195
+ domain,
196
+ signal: domain.signal,
197
+ track(childKind, childLabel, settled) {
198
+ if (closed || state.lifecycle === "quarantined") {
199
+ quarantineState(state);
200
+ observeSettlement(settled, () => {});
201
+ return false;
202
+ }
203
+ return register(state, childKind, childLabel, settled) !== undefined;
204
+ },
205
+ fork(expectedDomain, childKind, childLabel): ForkProducerResult {
206
+ if (expectedDomain !== domain) {
207
+ quarantineState(state);
208
+ return { ok: false, reason: "domain_mismatch" };
209
+ }
210
+ const wasQuarantined = state.lifecycle === "quarantined";
211
+ if (closed || wasQuarantined) {
212
+ quarantineState(state);
213
+ return { ok: false, reason: wasQuarantined ? "quarantined" : "parent_closed" };
214
+ }
215
+ const child = leaseFor(state, childKind, childLabel);
216
+ return child ? { ok: true, lease: child } : { ok: false, reason: "quarantined" };
217
+ },
218
+ closeDiscovery: close,
219
+ };
220
+ return lease;
221
+ };
222
+
223
+ return {
224
+ bindCancellationDomainBridge(nextBridge) {
225
+ if (bridge && bridge !== nextBridge) throw new Error("Run cancellation domain bridge is already bound");
226
+ bridge = nextBridge;
227
+ },
228
+ bindAgentSessionClaimKey(key) {
229
+ if (agentSessionClaimKey && agentSessionClaimKey !== key) {
230
+ throw new Error("AgentSession claim key is already bound");
231
+ }
232
+ agentSessionClaimKey = key;
233
+ },
234
+ open(resourceRunId) {
235
+ const existing = runs.get(resourceRunId);
236
+ if (existing) return existing.lifecycle === "open" ? existing.domain : undefined;
237
+ const domainBridge = bridge ?? standaloneBridge;
238
+ const opened = domainBridge.open(resourceRunId);
239
+ if (!opened.ok) return undefined;
240
+ const state: RunState = {
241
+ lifecycle: "open",
242
+ resourceRunId,
243
+ domain: opened.domain,
244
+ domainBridge,
245
+ resources: new Map(),
246
+ tombstone: [],
247
+ waiters: new Set(),
248
+ claimedOwners: new Set(),
249
+ released: false,
250
+ };
251
+ runs.set(resourceRunId, state);
252
+ return opened.domain;
253
+ },
254
+ lookupDomain(resourceRunId) {
255
+ return runs.get(resourceRunId)?.domain;
256
+ },
257
+ reserveProducer(resourceRunId, expectedDomain, kind, label): ReserveProducerResult {
258
+ const state = runs.get(resourceRunId);
259
+ if (!state) return { ok: false, reason: "unknown_run" };
260
+ if (state.lifecycle === "quarantined") return { ok: false, reason: "quarantined" };
261
+ if (state.lifecycle !== "open") {
262
+ quarantineState(state);
263
+ return { ok: false, reason: "sealed" };
264
+ }
265
+ if (expectedDomain && expectedDomain !== state.domain) {
266
+ quarantineState(state);
267
+ return { ok: false, reason: "domain_mismatch" };
268
+ }
269
+ const lease = leaseFor(state, kind, label);
270
+ return lease ? { ok: true, lease } : { ok: false, reason: "quarantined" };
271
+ },
272
+ claimProducer(resourceRunId, expectedDomain, ownerKey): ClaimProducerResult {
273
+ if (!agentSessionClaimKey || ownerKey !== agentSessionClaimKey) {
274
+ return { ok: false, reason: "closed" };
275
+ }
276
+ const state = runs.get(resourceRunId);
277
+ if (!state) return { ok: false, reason: "handle_mismatch" };
278
+ if (state.lifecycle === "quarantined") return { ok: false, reason: "quarantined" };
279
+ if (state.lifecycle !== "open") {
280
+ quarantineState(state);
281
+ return { ok: false, reason: "closed" };
282
+ }
283
+ if (expectedDomain && expectedDomain !== state.domain) {
284
+ quarantineState(state);
285
+ return { ok: false, reason: "domain_mismatch" };
286
+ }
287
+ if (state.claimedOwners.has(ownerKey)) {
288
+ quarantineState(state);
289
+ return { ok: false, reason: "already_claimed" };
290
+ }
291
+ state.claimedOwners.add(ownerKey);
292
+ const lease = leaseFor(state, "post_prompt", "agent-session");
293
+ return lease ? { ok: true, lease } : { ok: false, reason: "quarantined" };
294
+ },
295
+ track(resourceRunId, kind, label, settled) {
296
+ const state = runs.get(resourceRunId);
297
+ if (!state) {
298
+ observeSettlement(settled, () => {});
299
+ return;
300
+ }
301
+ register(state, kind, label, settled);
302
+ },
303
+ pending(resourceRunId) {
304
+ const state = runs.get(resourceRunId);
305
+ return state ? snapshot(state) : [];
306
+ },
307
+ seal(resourceRunId) {
308
+ const state = runs.get(resourceRunId);
309
+ if (state?.lifecycle !== "open") return;
310
+ state.lifecycle = "sealed";
311
+ notify(state);
312
+ },
313
+ waitForSettlement(resourceRunId, { graceMs }) {
314
+ const state = runs.get(resourceRunId);
315
+ if (!state) return Promise.resolve({ status: "unfenced", reason: "unknown_run", pending: [] });
316
+ const immediate = settlementProof(state);
317
+ if (immediate) return Promise.resolve(immediate);
318
+ const { promise, resolve } = Promise.withResolvers<RunSettlementProof>();
319
+ let waiter!: SettlementWaiter;
320
+ waiter = {
321
+ resolve,
322
+ timer: setTimeout(
323
+ () => {
324
+ state.waiters.delete(waiter);
325
+ const settled = settlementProof(state);
326
+ resolve(
327
+ settled ?? {
328
+ status: "unfenced",
329
+ reason: state.lifecycle === "open" ? "run_not_sealed" : "resources_pending",
330
+ pending: snapshot(state),
331
+ },
332
+ );
333
+ },
334
+ Math.max(0, graceMs),
335
+ ),
336
+ };
337
+ state.waiters.add(waiter);
338
+ return promise;
339
+ },
340
+ quarantine(resourceRunId) {
341
+ const state = runs.get(resourceRunId);
342
+ return state ? quarantineState(state) : [];
343
+ },
344
+ };
345
+ }