agentenkit 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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -0
  3. package/dist/adapters/inline.d.ts +27 -0
  4. package/dist/adapters/inline.d.ts.map +1 -0
  5. package/dist/adapters/inline.js +41 -0
  6. package/dist/adapters/inline.js.map +1 -0
  7. package/dist/adapters/memory.d.ts +74 -0
  8. package/dist/adapters/memory.d.ts.map +1 -0
  9. package/dist/adapters/memory.js +194 -0
  10. package/dist/adapters/memory.js.map +1 -0
  11. package/dist/adapters/prisma.d.ts +176 -0
  12. package/dist/adapters/prisma.d.ts.map +1 -0
  13. package/dist/adapters/prisma.js +107 -0
  14. package/dist/adapters/prisma.js.map +1 -0
  15. package/dist/adapters/qstash.d.ts +36 -0
  16. package/dist/adapters/qstash.d.ts.map +1 -0
  17. package/dist/adapters/qstash.js +26 -0
  18. package/dist/adapters/qstash.js.map +1 -0
  19. package/dist/adapters/redis.d.ts +49 -0
  20. package/dist/adapters/redis.d.ts.map +1 -0
  21. package/dist/adapters/redis.js +60 -0
  22. package/dist/adapters/redis.js.map +1 -0
  23. package/dist/adapters/sqlite.d.ts +67 -0
  24. package/dist/adapters/sqlite.d.ts.map +1 -0
  25. package/dist/adapters/sqlite.js +199 -0
  26. package/dist/adapters/sqlite.js.map +1 -0
  27. package/dist/adapters/upstash.d.ts +48 -0
  28. package/dist/adapters/upstash.d.ts.map +1 -0
  29. package/dist/adapters/upstash.js +46 -0
  30. package/dist/adapters/upstash.js.map +1 -0
  31. package/dist/admin/default.d.ts +15 -0
  32. package/dist/admin/default.d.ts.map +1 -0
  33. package/dist/admin/default.js +22 -0
  34. package/dist/admin/default.js.map +1 -0
  35. package/dist/admin/memory.d.ts +29 -0
  36. package/dist/admin/memory.d.ts.map +1 -0
  37. package/dist/admin/memory.js +83 -0
  38. package/dist/admin/memory.js.map +1 -0
  39. package/dist/admin/postgres.d.ts +43 -0
  40. package/dist/admin/postgres.d.ts.map +1 -0
  41. package/dist/admin/postgres.js +201 -0
  42. package/dist/admin/postgres.js.map +1 -0
  43. package/dist/admin/sqlite.d.ts +35 -0
  44. package/dist/admin/sqlite.d.ts.map +1 -0
  45. package/dist/admin/sqlite.js +187 -0
  46. package/dist/admin/sqlite.js.map +1 -0
  47. package/dist/core/admin.d.ts +88 -0
  48. package/dist/core/admin.d.ts.map +1 -0
  49. package/dist/core/admin.js +147 -0
  50. package/dist/core/admin.js.map +1 -0
  51. package/dist/core/agent.d.ts +29 -0
  52. package/dist/core/agent.d.ts.map +1 -0
  53. package/dist/core/agent.js +41 -0
  54. package/dist/core/agent.js.map +1 -0
  55. package/dist/core/cache.d.ts +37 -0
  56. package/dist/core/cache.d.ts.map +1 -0
  57. package/dist/core/cache.js +68 -0
  58. package/dist/core/cache.js.map +1 -0
  59. package/dist/core/context.d.ts +13 -0
  60. package/dist/core/context.d.ts.map +1 -0
  61. package/dist/core/context.js +87 -0
  62. package/dist/core/context.js.map +1 -0
  63. package/dist/core/deleteThread.d.ts +14 -0
  64. package/dist/core/deleteThread.d.ts.map +1 -0
  65. package/dist/core/deleteThread.js +34 -0
  66. package/dist/core/deleteThread.js.map +1 -0
  67. package/dist/core/engine.d.ts +79 -0
  68. package/dist/core/engine.d.ts.map +1 -0
  69. package/dist/core/engine.js +489 -0
  70. package/dist/core/engine.js.map +1 -0
  71. package/dist/core/follow.d.ts +50 -0
  72. package/dist/core/follow.d.ts.map +1 -0
  73. package/dist/core/follow.js +153 -0
  74. package/dist/core/follow.js.map +1 -0
  75. package/dist/core/hitl.d.ts +98 -0
  76. package/dist/core/hitl.d.ts.map +1 -0
  77. package/dist/core/hitl.js +199 -0
  78. package/dist/core/hitl.js.map +1 -0
  79. package/dist/core/keys.d.ts +26 -0
  80. package/dist/core/keys.d.ts.map +1 -0
  81. package/dist/core/keys.js +32 -0
  82. package/dist/core/keys.js.map +1 -0
  83. package/dist/core/loop.d.ts +105 -0
  84. package/dist/core/loop.d.ts.map +1 -0
  85. package/dist/core/loop.js +234 -0
  86. package/dist/core/loop.js.map +1 -0
  87. package/dist/core/publish.d.ts +18 -0
  88. package/dist/core/publish.d.ts.map +1 -0
  89. package/dist/core/publish.js +34 -0
  90. package/dist/core/publish.js.map +1 -0
  91. package/dist/core/reclaim.d.ts +20 -0
  92. package/dist/core/reclaim.d.ts.map +1 -0
  93. package/dist/core/reclaim.js +56 -0
  94. package/dist/core/reclaim.js.map +1 -0
  95. package/dist/core/run.d.ts +8 -0
  96. package/dist/core/run.d.ts.map +1 -0
  97. package/dist/core/run.js +102 -0
  98. package/dist/core/run.js.map +1 -0
  99. package/dist/core/state.d.ts +50 -0
  100. package/dist/core/state.d.ts.map +1 -0
  101. package/dist/core/state.js +39 -0
  102. package/dist/core/state.js.map +1 -0
  103. package/dist/core/stop.d.ts +7 -0
  104. package/dist/core/stop.d.ts.map +1 -0
  105. package/dist/core/stop.js +15 -0
  106. package/dist/core/stop.js.map +1 -0
  107. package/dist/core/stream.d.ts +12 -0
  108. package/dist/core/stream.d.ts.map +1 -0
  109. package/dist/core/stream.js +21 -0
  110. package/dist/core/stream.js.map +1 -0
  111. package/dist/core/subagent.d.ts +77 -0
  112. package/dist/core/subagent.d.ts.map +1 -0
  113. package/dist/core/subagent.js +261 -0
  114. package/dist/core/subagent.js.map +1 -0
  115. package/dist/core/tools.d.ts +36 -0
  116. package/dist/core/tools.d.ts.map +1 -0
  117. package/dist/core/tools.js +22 -0
  118. package/dist/core/tools.js.map +1 -0
  119. package/dist/core/types.d.ts +286 -0
  120. package/dist/core/types.d.ts.map +1 -0
  121. package/dist/core/types.js +49 -0
  122. package/dist/core/types.js.map +1 -0
  123. package/dist/core/usage.d.ts +40 -0
  124. package/dist/core/usage.d.ts.map +1 -0
  125. package/dist/core/usage.js +43 -0
  126. package/dist/core/usage.js.map +1 -0
  127. package/dist/index.d.ts +25 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +23 -0
  130. package/dist/index.js.map +1 -0
  131. package/dist/ports/admin.d.ts +102 -0
  132. package/dist/ports/admin.d.ts.map +1 -0
  133. package/dist/ports/admin.js +2 -0
  134. package/dist/ports/admin.js.map +1 -0
  135. package/dist/ports/bus.d.ts +13 -0
  136. package/dist/ports/bus.d.ts.map +1 -0
  137. package/dist/ports/bus.js +2 -0
  138. package/dist/ports/bus.js.map +1 -0
  139. package/dist/ports/kv.d.ts +16 -0
  140. package/dist/ports/kv.d.ts.map +1 -0
  141. package/dist/ports/kv.js +2 -0
  142. package/dist/ports/kv.js.map +1 -0
  143. package/dist/ports/queue.d.ts +18 -0
  144. package/dist/ports/queue.d.ts.map +1 -0
  145. package/dist/ports/queue.js +2 -0
  146. package/dist/ports/queue.js.map +1 -0
  147. package/dist/ports/runtime.d.ts +260 -0
  148. package/dist/ports/runtime.d.ts.map +1 -0
  149. package/dist/ports/runtime.js +2 -0
  150. package/dist/ports/runtime.js.map +1 -0
  151. package/dist/ports/storage.d.ts +72 -0
  152. package/dist/ports/storage.d.ts.map +1 -0
  153. package/dist/ports/storage.js +2 -0
  154. package/dist/ports/storage.js.map +1 -0
  155. package/dist/runtime.d.ts +5 -0
  156. package/dist/runtime.d.ts.map +1 -0
  157. package/dist/runtime.js +177 -0
  158. package/dist/runtime.js.map +1 -0
  159. package/package.json +126 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/core/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,234 @@
1
+ import { generateText, streamText } from 'ai';
2
+ import { systemCacheMessage } from './cache.js';
3
+ import { attributeTokens } from './usage.js';
4
+ import { drainOrThrow } from './stream.js';
5
+ import { publish, publishNotice } from './publish.js';
6
+ import { HITL_PARKED } from './hitl.js';
7
+ /** True for the sentinel a parked `requiresConfirmation` tool returns (§2.5).
8
+ * It is never a real tool result and is never persisted. */
9
+ export const isParked = (result) => typeof result === 'object' &&
10
+ result !== null &&
11
+ result[HITL_PARKED] !== undefined;
12
+ export async function executeStep(agent, call) {
13
+ // Ownership rule (§3.1): user args spread FIRST, platform keys LAST. The
14
+ // user's stream callbacks are stripped here and re-chained by the platform
15
+ // (onChunk below, onFinish at finalize) so the SDK can never own them.
16
+ const { onChunk: _userOnChunk, onFinish: _userOnFinish, onStepFinish: userOnStepFinish, system: specSystem, ...userArgs } = agent.args;
17
+ // A nested run brings its own persona and must not inherit the parent's.
18
+ const system = call.system ?? specSystem;
19
+ const hoistSystem = call.cacheSystemPrompt === true && typeof system === 'string' && system.length > 0;
20
+ const shared = {
21
+ ...userArgs,
22
+ model: call.model,
23
+ // Hoisted, the system prompt leads the messages and carries the
24
+ // breakpoint; a fresh array each step leaves the loop's own array alone.
25
+ messages: hoistSystem ? [systemCacheMessage(system), ...call.messages] : call.messages,
26
+ tools: call.tools,
27
+ abortSignal: call.abortSignal,
28
+ maxSteps: 1, // the loop owns continuation
29
+ ...(hoistSystem || system === undefined ? {} : { system }),
30
+ // Provider-specific options (§3.1): forwarded under both the v5-native
31
+ // key and the v4 alias.
32
+ ...(call.providerOptions
33
+ ? {
34
+ providerOptions: call.providerOptions,
35
+ experimental_providerMetadata: call.providerOptions,
36
+ }
37
+ : {}),
38
+ ...(call.onChunk
39
+ ? { onChunk: async ({ chunk }) => { await call.onChunk(chunk); } }
40
+ : {}),
41
+ ...(userOnStepFinish
42
+ ? { onStepFinish: (step) => userOnStepFinish?.(step) } // user callback still fires
43
+ : {}),
44
+ };
45
+ if (call.kind === 'stream-text') {
46
+ const result = streamText(shared);
47
+ // streamText is lazy: drain the full stream so onChunk fires per part, and
48
+ // let a provider failure throw here rather than hanging on promises that
49
+ // never settle (see drainOrThrow).
50
+ await drainOrThrow(result.fullStream);
51
+ const [text, usage, finishReason, response, steps, meta] = await Promise.all([
52
+ result.text,
53
+ result.usage,
54
+ result.finishReason,
55
+ result.response,
56
+ result.steps,
57
+ // v4 exposes it under the experimental name; v5 drops the prefix.
58
+ result.providerMetadata ?? result.experimental_providerMetadata,
59
+ ]);
60
+ return {
61
+ text,
62
+ finishReason,
63
+ usage: usage,
64
+ responseMessages: (response?.messages ?? []),
65
+ toolResults: (steps?.at(-1)?.toolResults ?? []),
66
+ providerMetadata: meta,
67
+ };
68
+ }
69
+ const result = await generateText(shared);
70
+ return {
71
+ text: result.text,
72
+ finishReason: result.finishReason,
73
+ usage: result.usage,
74
+ responseMessages: (result.response?.messages ?? []),
75
+ toolResults: (result.steps?.at(-1)?.toolResults ?? []),
76
+ providerMetadata: (result.providerMetadata ??
77
+ result.experimental_providerMetadata),
78
+ };
79
+ }
80
+ /** Keep a recorded value small: one oversized tool result should not be able
81
+ * to bloat the operational store (§2.9). Structured values are truncated by
82
+ * their serialised form so the shape stays readable. */
83
+ const cap = (text, limit) => !text ? null : text.length > limit ? `${text.slice(0, limit)}…` : text;
84
+ function capValue(value, limit) {
85
+ if (value === undefined)
86
+ return null;
87
+ if (typeof value === 'string')
88
+ return cap(value, limit);
89
+ const json = JSON.stringify(value) ?? 'null';
90
+ return json.length <= limit ? value : `${json.slice(0, limit)}…`;
91
+ }
92
+ /** The platform-owned loop (§2.1, §5.6), run by the main agent and by every
93
+ * nested run alike (§2.7).
94
+ *
95
+ * One single-round-trip step per iteration. After EVERY step the produced
96
+ * messages are persisted under this loop's `agentId`, so a worker that dies
97
+ * mid-run resumes from the last step — and so a parked nested run can be
98
+ * re-entered later instead of restarted. Every continuation decision — tool
99
+ * results ready, budget spent, step ceiling, HITL park, user stop — is made
100
+ * here between steps, never inside the SDK. */
101
+ export async function runLoop(deps, agent, threadId, input, ledger) {
102
+ const attribution = {
103
+ inputTokens: 0,
104
+ cachedInputTokens: 0,
105
+ outputTokens: 0,
106
+ totalTokens: 0,
107
+ };
108
+ let tokensUsed = 0;
109
+ let lastText = '';
110
+ let lastFinishReason = '';
111
+ let parked = false;
112
+ let parkedToolCallId;
113
+ let stepsLeft = input.maxSteps;
114
+ let stepsRun = 0;
115
+ while (stepsLeft > 0 && !input.abortSignal.aborted) {
116
+ stepsLeft--;
117
+ const stepStartedAt = Date.now();
118
+ let step;
119
+ try {
120
+ step = await executeStep(agent, {
121
+ kind: input.kind,
122
+ model: input.model,
123
+ messages: input.messages,
124
+ tools: input.tools,
125
+ providerOptions: input.providerOptions,
126
+ abortSignal: input.abortSignal,
127
+ onChunk: input.kind === 'stream-text' ? input.onChunk : undefined,
128
+ system: input.system,
129
+ cacheSystemPrompt: input.cacheSystemPrompt,
130
+ });
131
+ }
132
+ catch (err) {
133
+ if (input.abortSignal.aborted)
134
+ break; // user stop mid-step
135
+ throw err; // real failure → §2.8 redrive policy
136
+ }
137
+ // Per-step durability (§5.6): append this step's turns BEFORE the next
138
+ // step. A parked HITL tool result (the sentinel) is NOT a real result —
139
+ // it is skipped here; the resumed segment appends the user's verdict.
140
+ const persisted = step.responseMessages.filter((m) => {
141
+ if (m.role !== 'tool')
142
+ return true;
143
+ const parts = Array.isArray(m.content) ? m.content : [];
144
+ return !parts.some((p) => isParked(p?.result));
145
+ });
146
+ for (const m of persisted) {
147
+ await deps.storage.messages.append(threadId, {
148
+ role: m.role,
149
+ content: m.content,
150
+ agentId: input.agentId,
151
+ });
152
+ }
153
+ input.messages.push(...step.responseMessages);
154
+ // A replay boundary (§2.2). Everything this step produced is now durable
155
+ // history, so a reconnecting client must NOT also replay its chunks — it
156
+ // would render the same text twice, once from the message and once from
157
+ // the stream that produced it. Persisted (not a bus notice) because the
158
+ // snapshot needs its seq to know where durable ends and live begins.
159
+ await publish(deps, threadId, 'STEP_COMMITTED', {
160
+ index: stepsRun,
161
+ agentId: input.agentId,
162
+ });
163
+ // Token attribution (§4), accumulated across the segment's steps — and
164
+ // into the run-wide ledger the safety cap is checked against (§2.7).
165
+ const a = attributeTokens(step.usage, step.providerMetadata);
166
+ attribution.inputTokens += a.inputTokens;
167
+ attribution.cachedInputTokens += a.cachedInputTokens;
168
+ attribution.outputTokens += a.outputTokens;
169
+ attribution.totalTokens += a.totalTokens;
170
+ tokensUsed += a.totalTokens;
171
+ ledger.tokensUsed += a.totalTokens;
172
+ lastText = step.text ?? '';
173
+ lastFinishReason = step.finishReason;
174
+ stepsRun += 1;
175
+ // §2.9: one row per step in the platform's OWN store, plus a bus-only
176
+ // notice so live dashboards see it. The notice is not persisted to the
177
+ // caller's event log — operational history is not their data to carry.
178
+ const marker = {
179
+ runId: input.runId ?? '',
180
+ threadId,
181
+ agentId: input.agentId,
182
+ index: stepsRun,
183
+ durationMs: Date.now() - stepStartedAt,
184
+ finishReason: step.finishReason,
185
+ inputTokens: a.inputTokens,
186
+ cachedInputTokens: a.cachedInputTokens,
187
+ outputTokens: a.outputTokens,
188
+ totalTokens: a.totalTokens,
189
+ tools: (step.toolResults ?? [])
190
+ .map((r) => r?.toolName)
191
+ .filter(Boolean),
192
+ ...(deps.config.recordPayloads
193
+ ? {
194
+ text: cap(step.text, deps.config.payloadCapChars),
195
+ toolCalls: (step.toolResults ?? []).map((r) => ({
196
+ toolName: r?.toolName,
197
+ args: capValue(r?.args, deps.config.payloadCapChars),
198
+ result: capValue(r?.result, deps.config.payloadCapChars),
199
+ })),
200
+ }
201
+ : {}),
202
+ };
203
+ if (input.runId)
204
+ await deps.admin.steps.record(marker);
205
+ await publishNotice(deps, threadId, 'STEP_FINISHED', marker);
206
+ // §2.5 park: a requiresConfirmation tool returned the sentinel — the
207
+ // segment ends here on WAITING_FOR_INPUT (set by parkForApproval).
208
+ const parkedResult = (step.toolResults ?? []).find((r) => isParked(r?.result));
209
+ if (parkedResult) {
210
+ parked = true;
211
+ parkedToolCallId = parkedResult.result[HITL_PARKED];
212
+ break;
213
+ }
214
+ // Budget check BETWEEN steps (§2.1) — the step that crossed the line is
215
+ // kept in full; the next one never starts.
216
+ if (input.tokenBudget && ledger.tokensUsed >= input.tokenBudget)
217
+ break;
218
+ // 'tool-calls' → the SDK executed the step's tools; the loop feeds the
219
+ // results back. Anything else ('stop', 'length', …) ends the run.
220
+ if (step.finishReason !== 'tool-calls')
221
+ break;
222
+ }
223
+ return {
224
+ text: lastText,
225
+ finishReason: lastFinishReason,
226
+ attribution,
227
+ tokensUsed,
228
+ parked,
229
+ parkedToolCallId,
230
+ aborted: input.abortSignal.aborted,
231
+ steps: stepsRun,
232
+ };
233
+ }
234
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/core/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAK9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,eAAe,EAAyB,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC;6DAC6D;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAe,EAAW,EAAE,CACnD,OAAO,MAAM,KAAK,QAAQ;IAC1B,MAAM,KAAK,IAAI;IACd,MAAkC,CAAC,WAAW,CAAC,KAAK,SAAS,CAAC;AAqBjE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAsB,EACtB,IAeC;IAED,yEAAyE;IACzE,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,EACJ,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,aAAa,EACvB,YAAY,EAAE,gBAAgB,EAC9B,MAAM,EAAE,UAAU,EAClB,GAAG,QAAQ,EACZ,GAAG,KAAK,CAAC,IAA2B,CAAC;IAEtC,yEAAyE;IACzE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC;IACzC,MAAM,WAAW,GACf,IAAI,CAAC,iBAAiB,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAErF,MAAM,MAAM,GAAG;QACb,GAAG,QAAQ;QACX,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,gEAAgE;QAChE,yEAAyE;QACzE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ;QACtF,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,CAAC,EAAE,6BAA6B;QAC1C,GAAG,CAAC,WAAW,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1D,uEAAuE;QACvE,wBAAwB;QACxB,GAAG,CAAC,IAAI,CAAC,eAAe;YACtB,CAAC,CAAC;gBACE,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,6BAA6B,EAAE,IAAI,CAAC,eAAsB;aAC3D;YACH,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,IAAI,CAAC,OAAO;YACd,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAO,EAAE,EAAE,GAAG,MAAM,IAAI,CAAC,OAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YACxE,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,gBAAgB;YAClB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,4BAA4B;YACxF,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IAEF,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAa,CAAC,CAAC;QACzC,2EAA2E;QAC3E,yEAAyE;QACzE,mCAAmC;QACnC,MAAM,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEtC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC3E,MAAM,CAAC,IAAI;YACX,MAAM,CAAC,KAAK;YACZ,MAAM,CAAC,YAAY;YACnB,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,KAAK;YACZ,kEAAkE;YACjE,MAAc,CAAC,gBAAgB,IAAK,MAAc,CAAC,6BAA6B;SAClF,CAAC,CAAC;QACH,OAAO;YACL,IAAI;YACJ,YAAY;YACZ,KAAK,EAAE,KAAY;YACnB,gBAAgB,EAAE,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAQ;YACnD,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,EAAE,CAAQ;YACtD,gBAAgB,EAAE,IAAW;SAC9B,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAa,CAAC,CAAC;IACjD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,KAAK,EAAE,MAAM,CAAC,KAAY;QAC1B,gBAAgB,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAQ;QAC1D,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,EAAE,CAAQ;QAC7D,gBAAgB,EACd,CAAE,MAAc,CAAC,gBAAgB;YAC9B,MAAc,CAAC,6BAA6B,CAAQ;KAC1D,CAAC;AACJ,CAAC;AAED;;yDAEyD;AACzD,MAAM,GAAG,GAAG,CAAC,IAAwB,EAAE,KAAa,EAAiB,EAAE,CACrE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAEzE,SAAS,QAAQ,CAAC,KAAc,EAAE,KAAa;IAC7C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC;IAC7C,OAAO,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC;AACnE,CAAC;AAkDD;;;;;;;;gDAQgD;AAChD,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAkB,EAClB,KAAsB,EACtB,QAAgB,EAChB,KAAgB,EAChB,MAAiB;IAEjB,MAAM,WAAW,GAAqB;QACpC,WAAW,EAAE,CAAC;QACd,iBAAiB,EAAE,CAAC;QACpB,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;KACf,CAAC;IACF,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,gBAAgB,GAAG,EAAE,CAAC;IAC1B,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,gBAAoC,CAAC;IACzC,IAAI,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC/B,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,OAAO,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACnD,SAAS,EAAE,CAAC;QACZ,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACjC,IAAI,IAAgB,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE;gBAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,OAAO,EAAE,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;gBACjE,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;aAC3C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO;gBAAE,MAAM,CAAC,qBAAqB;YAC3D,MAAM,GAAG,CAAC,CAAC,qCAAqC;QAClD,CAAC;QAED,uEAAuE;QACvE,wEAAwE;QACxE,sEAAsE;QACtE,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACnD,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAC;YACnC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE;gBAC3C,IAAI,EAAE,CAAC,CAAC,IAAW;gBACnB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAE9C,yEAAyE;QACzE,yEAAyE;QACzE,wEAAwE;QACxE,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE;YAC9C,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;QAEH,uEAAuE;QACvE,qEAAqE;QACrE,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,KAAY,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACpE,WAAW,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC;QACzC,WAAW,CAAC,iBAAiB,IAAI,CAAC,CAAC,iBAAiB,CAAC;QACrD,WAAW,CAAC,YAAY,IAAI,CAAC,CAAC,YAAY,CAAC;QAC3C,WAAW,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC;QACzC,UAAU,IAAI,CAAC,CAAC,WAAW,CAAC;QAC5B,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC,WAAW,CAAC;QACnC,QAAQ,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAC3B,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC;QACrC,QAAQ,IAAI,CAAC,CAAC;QAEd,sEAAsE;QACtE,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,MAAM,GAAG;YACb,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;YACxB,QAAQ;YACR,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa;YACtC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,iBAAiB,EAAE,CAAC,CAAC,iBAAiB;YACtC,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,KAAK,EAAE,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;iBAC5B,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC;iBAC5B,MAAM,CAAC,OAAO,CAAa;YAC9B,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc;gBAC5B,CAAC,CAAC;oBACE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;oBACjD,SAAS,EAAE,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;wBACnD,QAAQ,EAAE,CAAC,EAAE,QAAQ;wBACrB,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;wBACpD,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;qBACzD,CAAC,CAAC;iBACJ;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACF,IAAI,KAAK,CAAC,KAAK;YAAE,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;QAE7D,qEAAqE;QACrE,mEAAmE;QACnE,MAAM,YAAY,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACpF,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,GAAG,IAAI,CAAC;YACd,gBAAgB,GAAI,YAAY,CAAC,MAAc,CAAC,WAAW,CAAC,CAAC;YAC7D,MAAM;QACR,CAAC;QAED,wEAAwE;QACxE,2CAA2C;QAC3C,IAAI,KAAK,CAAC,WAAW,IAAI,MAAM,CAAC,UAAU,IAAI,KAAK,CAAC,WAAW;YAAE,MAAM;QAEvE,uEAAuE;QACvE,kEAAkE;QAClE,IAAI,IAAI,CAAC,YAAY,KAAK,YAAY;YAAE,MAAM;IAChD,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,gBAAgB;QAC9B,WAAW;QACX,UAAU;QACV,MAAM;QACN,gBAAgB;QAChB,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO;QAClC,KAAK,EAAE,QAAQ;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { RuntimePorts } from '../ports/runtime.js';
2
+ import type { ExecutionState } from './types.js';
3
+ import type { AgentEvent } from './types.js';
4
+ /** Persist to the replayable event log, then fan out live to all subscribers
5
+ * (§2.2). Seq comes from Kv.incr — monotonic per thread (§3.4). */
6
+ export declare function publish(deps: RuntimePorts, threadId: string, type: string, payload: unknown): Promise<AgentEvent>;
7
+ /** Publish a bus-only notice (never persisted) — e.g. HITL death notices (§2.5). */
8
+ export declare function publishNotice(deps: RuntimePorts, threadId: string, type: string, payload: unknown): Promise<void>;
9
+ /** Move a thread to a new state on BOTH the caller's storage and the
10
+ * platform's own operational view (§2.9).
11
+ *
12
+ * One choke point on purpose: the admin thread table is what lets a dashboard
13
+ * answer "what is running right now" without reading the caller's database,
14
+ * and it is only true if every transition passes through here. `model` is
15
+ * looked up when not supplied, so callers that already hold the thread can
16
+ * skip a read. */
17
+ export declare function setThreadState(deps: RuntimePorts, threadId: string, state: ExecutionState, model?: string): Promise<void>;
18
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/core/publish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;oEACoE;AACpE,wBAAsB,OAAO,CAC3B,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,UAAU,CAAC,CAMrB;AAED,oFAAoF;AACpF,wBAAsB,aAAa,CACjC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;;;;mBAOmB;AACnB,wBAAsB,cAAc,CAClC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,cAAc,EACrB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -0,0 +1,34 @@
1
+ /** Persist to the replayable event log, then fan out live to all subscribers
2
+ * (§2.2). Seq comes from Kv.incr — monotonic per thread (§3.4). */
3
+ export async function publish(deps, threadId, type, payload) {
4
+ const seq = await deps.kv.incr(`agent:seq:${threadId}`);
5
+ const event = { threadId, seq, type, payload, createdAt: new Date() };
6
+ await deps.storage.events.append(threadId, event);
7
+ await deps.bus.publish(threadId, event);
8
+ return event;
9
+ }
10
+ /** Publish a bus-only notice (never persisted) — e.g. HITL death notices (§2.5). */
11
+ export async function publishNotice(deps, threadId, type, payload) {
12
+ await deps.bus.publish(threadId, {
13
+ threadId, seq: 0, type, payload, createdAt: new Date(),
14
+ });
15
+ }
16
+ /** Move a thread to a new state on BOTH the caller's storage and the
17
+ * platform's own operational view (§2.9).
18
+ *
19
+ * One choke point on purpose: the admin thread table is what lets a dashboard
20
+ * answer "what is running right now" without reading the caller's database,
21
+ * and it is only true if every transition passes through here. `model` is
22
+ * looked up when not supplied, so callers that already hold the thread can
23
+ * skip a read. */
24
+ export async function setThreadState(deps, threadId, state, model) {
25
+ await deps.storage.threads.setState(threadId, state);
26
+ try {
27
+ const resolved = model ?? (await deps.storage.threads.get(threadId))?.model ?? 'unknown';
28
+ await deps.admin.threads.upsert({ id: threadId, state, model: resolved });
29
+ }
30
+ catch {
31
+ // Observability must never be able to fail a transition that succeeded.
32
+ }
33
+ }
34
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/core/publish.ts"],"names":[],"mappings":"AAIA;oEACoE;AACpE,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAkB,EAClB,QAAgB,EAChB,IAAY,EACZ,OAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;IACxD,MAAM,KAAK,GAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IAClF,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClD,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAkB,EAClB,QAAgB,EAChB,IAAY,EACZ,OAAgB;IAEhB,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE;QAC/B,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE;KACzC,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;;mBAOmB;AACnB,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAkB,EAClB,QAAgB,EAChB,KAAqB,EACrB,KAAc;IAEd,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,IAAI,SAAS,CAAC;QACzF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;IAC1E,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { RuntimePorts } from '../ports/runtime.js';
2
+ export declare function reclaimGraceAfterMs(deps: RuntimePorts): number;
3
+ /** §2.5 orphan reclamation, the FALLBACK path.
4
+ *
5
+ * A park schedules its own expiry on the queue (see parkForApproval), so the
6
+ * deadline holds whether or not anyone is watching. This covers what a timer
7
+ * cannot: threads parked before that existed, and queue adapters that drop a
8
+ * delay. Callers are first-touch checks in run() and respond(), plus any
9
+ * listener that wants the denial to land live in front of a user.
10
+ *
11
+ * It no longer heals inline. It re-dispatches the run and lets the engine
12
+ * resolve the park, so there is exactly ONE definition of what an expired
13
+ * approval becomes — and so a thread holding several open approvals (§2.7)
14
+ * is resolved as a set rather than one request at a time. Re-dispatching the
15
+ * same run twice is safe: the run lock and the engine's readiness check make
16
+ * the duplicate a no-op (§2.8).
17
+ *
18
+ * Returns true iff a re-dispatch was enqueued. */
19
+ export declare function reclaimIfOrphaned(deps: RuntimePorts, threadId: string): Promise<boolean>;
20
+ //# sourceMappingURL=reclaim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reclaim.d.ts","sourceRoot":"","sources":["../../src/core/reclaim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOxD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED;;;;;;;;;;;;;;;mDAemD;AACnD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgC9F"}
@@ -0,0 +1,56 @@
1
+ import { currentRunId } from './keys.js';
2
+ import { loadOpenHitls } from './hitl.js';
3
+ // Small grace so an in-flight /respond delivery always lands first —
4
+ // reclamation only ever sees true orphans.
5
+ export function reclaimGraceAfterMs(deps) {
6
+ return deps.config.hitlTtlMs + deps.config.reclaimGraceMs;
7
+ }
8
+ /** §2.5 orphan reclamation, the FALLBACK path.
9
+ *
10
+ * A park schedules its own expiry on the queue (see parkForApproval), so the
11
+ * deadline holds whether or not anyone is watching. This covers what a timer
12
+ * cannot: threads parked before that existed, and queue adapters that drop a
13
+ * delay. Callers are first-touch checks in run() and respond(), plus any
14
+ * listener that wants the denial to land live in front of a user.
15
+ *
16
+ * It no longer heals inline. It re-dispatches the run and lets the engine
17
+ * resolve the park, so there is exactly ONE definition of what an expired
18
+ * approval becomes — and so a thread holding several open approvals (§2.7)
19
+ * is resolved as a set rather than one request at a time. Re-dispatching the
20
+ * same run twice is safe: the run lock and the engine's readiness check make
21
+ * the duplicate a no-op (§2.8).
22
+ *
23
+ * Returns true iff a re-dispatch was enqueued. */
24
+ export async function reclaimIfOrphaned(deps, threadId) {
25
+ const thread = await deps.storage.threads.get(threadId);
26
+ if (thread?.state !== 'WAITING_FOR_INPUT')
27
+ return false;
28
+ const open = await loadOpenHitls(deps, threadId);
29
+ if (open.length === 0)
30
+ return false;
31
+ // Every open request must be past its window. One that is still answerable
32
+ // would make the resumed segment a no-op anyway (§2.7).
33
+ const deadline = reclaimGraceAfterMs(deps);
34
+ if (!open.every((p) => Date.now() - p.requestedAt >= deadline))
35
+ return false;
36
+ // Rebuild the original dispatch from the ticket persisted in the event
37
+ // payload; a legacy park without one falls back to the default handle.
38
+ const requested = await deps.storage.events.listByType(threadId, 'INPUT_REQUIRED');
39
+ const resume = requested.at(-1)?.payload?.resume;
40
+ await deps.queue.enqueue({
41
+ threadId,
42
+ // Resuming a parked run REUSES its id — it is the same run continuing,
43
+ // and the park's own expiry job must stay a duplicate of this one (§2.1).
44
+ runId: await currentRunId(deps, threadId),
45
+ model: resume?.model ?? thread.model,
46
+ ...(resume
47
+ ? {
48
+ agent: resume.agent,
49
+ ...(resume.tokenBudget !== undefined ? { tokenBudget: resume.tokenBudget } : {}),
50
+ ...(resume.providerOptions ? { providerOptions: resume.providerOptions } : {}),
51
+ }
52
+ : {}),
53
+ });
54
+ return true;
55
+ }
56
+ //# sourceMappingURL=reclaim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reclaim.js","sourceRoot":"","sources":["../../src/core/reclaim.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,qEAAqE;AACrE,2CAA2C;AAC3C,MAAM,UAAU,mBAAmB,CAAC,IAAkB;IACpD,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;;;;;mDAemD;AACnD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAkB,EAAE,QAAgB;IAC1E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxD,IAAI,MAAM,EAAE,KAAK,KAAK,mBAAmB;QAAE,OAAO,KAAK,CAAC;IAExD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEpC,2EAA2E;IAC3E,wDAAwD;IACxD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,WAAW,IAAI,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAE7E,uEAAuE;IACvE,uEAAuE;IACvE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IACnF,MAAM,MAAM,GAAI,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,OAA0C,EAAE,MAAM,CAAC;IAErF,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QACvB,QAAQ;QACR,uEAAuE;QACvE,0EAA0E;QAC1E,KAAK,EAAE,MAAM,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;QACzC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK;QACpC,GAAG,CAAC,MAAM;YACR,CAAC,CAAC;gBACE,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChF,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/E;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { RuntimePorts, RunInput, RunResult } from '../ports/runtime.js';
2
+ import type { RegisteredAgent } from './agent.js';
3
+ /** The §5.1 behavior: heal orphans → billing pre-check (§4) → persist the user
4
+ * message → state RUNNING (hot + durable) → enqueue on the dispatch queue
5
+ * (§2.8). Accepts no execution responsibility whatsoever — the queue does
6
+ * the rest, and the job dispatches back to THIS handle. */
7
+ export declare function run(deps: RuntimePorts, agent: RegisteredAgent, input: RunInput): Promise<RunResult>;
8
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/core/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD;;;4DAG4D;AAC5D,wBAAsB,GAAG,CACvB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,QAAQ,GACd,OAAO,CAAC,SAAS,CAAC,CAyGpB"}
@@ -0,0 +1,102 @@
1
+ import { reclaimIfOrphaned } from './reclaim.js';
2
+ import { claimRun } from './keys.js';
3
+ import { publish, setThreadState } from './publish.js';
4
+ /** The §5.1 behavior: heal orphans → billing pre-check (§4) → persist the user
5
+ * message → state RUNNING (hot + durable) → enqueue on the dispatch queue
6
+ * (§2.8). Accepts no execution responsibility whatsoever — the queue does
7
+ * the rest, and the job dispatches back to THIS handle. */
8
+ export async function run(deps, agent, input) {
9
+ // Model resolution order (§3.1): run input → spec default → 'gpt-4o'
10
+ const model = input.model ?? agent.spec.model ?? 'gpt-4o';
11
+ let threadId = input.threadId;
12
+ if (!threadId) {
13
+ const created = await deps.storage.threads.create({ model });
14
+ threadId = created.id;
15
+ }
16
+ // Heal an orphaned HITL wait first (§2.5)
17
+ await reclaimIfOrphaned(deps, threadId);
18
+ const state = await deps.kv.get(`agent:state:${threadId}`);
19
+ if (state === 'RUNNING' || state === 'WAITING_FOR_INPUT') {
20
+ return { accepted: false, threadId, error: 'Thread has an active run' };
21
+ }
22
+ // Billing pre-execution check (§4) — user-injected hook
23
+ if (deps.config.billingPreCheck) {
24
+ const check = await deps.config.billingPreCheck(threadId);
25
+ if (!check.ok) {
26
+ return { accepted: false, threadId, error: check.error ?? 'Billing check failed' };
27
+ }
28
+ }
29
+ // Edit + resend (§5.1): the edited turn and everything it led to are
30
+ // dropped, then the new text is appended in its place — one thread, no
31
+ // forking. Only a user turn may be edited: cutting from anywhere else can
32
+ // strip a tool result off the assistant tool-call that produced it, and a
33
+ // dangling call is a conversation no provider accepts.
34
+ if (input.editMessageId) {
35
+ // Only the main agent's turns are editable — a nested run's stream is
36
+ // never addressed from the outside (§2.7)
37
+ const history = await deps.storage.messages.list(threadId, { agentId: null });
38
+ const target = history.find((m) => m.id === input.editMessageId);
39
+ if (!target)
40
+ return { accepted: false, threadId, error: 'Message not found' };
41
+ if (target.role !== 'user') {
42
+ return { accepted: false, threadId, error: 'Only a user message can be edited' };
43
+ }
44
+ await deps.storage.messages.deleteFrom(threadId, input.editMessageId);
45
+ // Other clients are showing turns that no longer exist (§2.2). The tab
46
+ // that made the edit truncated its own view; every other one needs telling.
47
+ await publish(deps, threadId, 'MESSAGES_DROPPED', { fromMessageId: input.editMessageId });
48
+ }
49
+ const userMessage = await deps.storage.messages.append(threadId, {
50
+ role: 'user',
51
+ content: input.prompt,
52
+ });
53
+ // The user's turn goes on the bus like everything else (§2.2). Without it a
54
+ // second client watching the same thread sees the reply stream in with no
55
+ // question in front of it — the sending tab had only ever added the message
56
+ // to its own local state.
57
+ await publish(deps, threadId, 'MESSAGE_APPENDED', {
58
+ id: userMessage.id,
59
+ role: userMessage.role,
60
+ content: userMessage.content,
61
+ agentId: userMessage.agentId,
62
+ createdAt: userMessage.createdAt,
63
+ });
64
+ // Claim the thread for THIS run before the state key is touched (§2.1). The
65
+ // next line overwrites whatever stop() may have just written, so the run id
66
+ // — not the state key — is what retires a worker still running the previous
67
+ // message.
68
+ const runId = await claimRun(deps, threadId);
69
+ await deps.kv.set(`agent:state:${threadId}`, 'RUNNING');
70
+ await setThreadState(deps, threadId, 'RUNNING', model);
71
+ // A durable run boundary lets reconnecting clients distinguish this turn's
72
+ // in-flight chunks from earlier completed turns.
73
+ await publish(deps, threadId, 'STATE_CHANGE', { state: 'RUNNING' });
74
+ // The run's durable record opens here (§2.9): a thread accumulates many runs
75
+ // and Thread.state only ever describes the latest, so this is the only place
76
+ // "what happened, how long, what did it cost" can be answered from.
77
+ await deps.admin.runs.start({
78
+ id: runId, threadId, agent: agent.name, model,
79
+ // What this run was asked to do (§2.9) — without it a dashboard can show
80
+ // that a run was slow but not what it was slow at.
81
+ ...(deps.config.recordPayloads
82
+ ? {
83
+ prompt: input.prompt.length > deps.config.payloadCapChars
84
+ ? `${input.prompt.slice(0, deps.config.payloadCapChars)}…`
85
+ : input.prompt,
86
+ tokenBudget: input.tokenBudget ?? null,
87
+ runState: input.state ?? null,
88
+ }
89
+ : {}),
90
+ });
91
+ await deps.queue.enqueue({
92
+ threadId, runId, model, agent: agent.name,
93
+ enqueuedAt: Date.now(),
94
+ // Persisted on the ticket so a worker — or a resume after an approval,
95
+ // hours later, in another process — rehydrates the same state (§2.10).
96
+ ...(input.state ? { state: input.state } : {}),
97
+ tokenBudget: input.tokenBudget,
98
+ providerOptions: input.providerOptions,
99
+ });
100
+ return { accepted: true, threadId, runId, state: 'RUNNING' };
101
+ }
102
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/core/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { Storage } from '../ports/storage.js';
2
+ /** Whatever a caller needs carried through a run: tenant, user, request id,
3
+ * feature flags (§2.10). The platform never reads it — it only guarantees
4
+ * that everything acting on behalf of a run can see it.
5
+ *
6
+ * Augment it to type your own fields:
7
+ *
8
+ * ```ts
9
+ * declare module 'agentenkit' {
10
+ * interface AgentRunState { orgId: string; userId: string }
11
+ * }
12
+ * ```
13
+ *
14
+ * Declaration merging rather than a `<TState>` type parameter, which would
15
+ * otherwise have to appear on Storage, AgentCore, AgentHandle, every tool and
16
+ * every subagent before it reached the one place it is read. */
17
+ export interface AgentRunState {
18
+ [key: string]: unknown;
19
+ }
20
+ /** Passed to every domain storage call so an implementation can scope a query,
21
+ * stamp a row, or route to a tenant's database (§2.10). */
22
+ export interface StorageContext {
23
+ state: AgentRunState;
24
+ /** The run this call serves. Absent for reads outside a run — a thread
25
+ * listing, for instance. */
26
+ runId?: string;
27
+ }
28
+ /** Strips the trailing StorageContext from every method of T. */
29
+ type Bound<T> = {
30
+ [K in keyof T]: T[K] extends (...args: [...infer A, StorageContext]) => infer R ? (...args: A) => R : T[K] extends object ? Bound<T[K]> : T[K];
31
+ };
32
+ /** The Storage shape core works against: the caller's implementation with this
33
+ * run's context already attached. */
34
+ export type BoundStorage = Bound<Storage>;
35
+ /** Attach a run's context to every storage method once, so core keeps calling
36
+ * `storage.messages.append(threadId, msg)` and the implementation still
37
+ * receives the state (§2.10). Threading a parameter through every call site
38
+ * in the engine instead would put the plumbing in ~60 places and make it
39
+ * possible to forget it in one. */
40
+ export declare function bindStorage(storage: Storage, ctx: StorageContext): BoundStorage;
41
+ /** Give every tool the run's state alongside the SDK's own options (§2.10).
42
+ *
43
+ * The AI SDK calls `execute(args, { toolCallId, abortSignal, … })`; this adds
44
+ * `state` to that second argument, so a tool reads it exactly where it already
45
+ * reads its tool-call id. Applied to the whole toolset, not just the marked
46
+ * ones — a tool that does not need approval still needs to know which tenant
47
+ * it is acting for. */
48
+ export declare function withRunState(tools: Record<string, any>, state: AgentRunState): Record<string, any>;
49
+ export {};
50
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD;;;;;;;;;;;;;;iEAciE;AACjE,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;4DAC4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB;iCAC6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,iEAAiE;AACjE,KAAK,KAAK,CAAC,CAAC,IAAI;KACb,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,cAAc,CAAC,KAAK,MAAM,CAAC,GAC3E,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,GACjB,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GACjB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACX,CAAC,CAAC,CAAC,CAAC;CACX,CAAC;AAEF;sCACsC;AACtC,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;AAE1C;;;;oCAIoC;AACpC,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,YAAY,CAc/E;AAED;;;;;;wBAMwB;AACxB,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
@@ -0,0 +1,39 @@
1
+ /** Attach a run's context to every storage method once, so core keeps calling
2
+ * `storage.messages.append(threadId, msg)` and the implementation still
3
+ * receives the state (§2.10). Threading a parameter through every call site
4
+ * in the engine instead would put the plumbing in ~60 places and make it
5
+ * possible to forget it in one. */
6
+ export function bindStorage(storage, ctx) {
7
+ const out = {};
8
+ for (const [group, methods] of Object.entries(storage)) {
9
+ if (!methods || typeof methods !== 'object')
10
+ continue;
11
+ const bound = {};
12
+ for (const [name, fn] of Object.entries(methods)) {
13
+ bound[name] =
14
+ typeof fn === 'function'
15
+ ? (...args) => fn.call(methods, ...args, ctx)
16
+ : fn;
17
+ }
18
+ out[group] = bound;
19
+ }
20
+ return out;
21
+ }
22
+ /** Give every tool the run's state alongside the SDK's own options (§2.10).
23
+ *
24
+ * The AI SDK calls `execute(args, { toolCallId, abortSignal, … })`; this adds
25
+ * `state` to that second argument, so a tool reads it exactly where it already
26
+ * reads its tool-call id. Applied to the whole toolset, not just the marked
27
+ * ones — a tool that does not need approval still needs to know which tenant
28
+ * it is acting for. */
29
+ export function withRunState(tools, state) {
30
+ const out = {};
31
+ for (const [name, t] of Object.entries(tools)) {
32
+ out[name] =
33
+ typeof t?.execute === 'function'
34
+ ? { ...t, execute: (args, opts) => t.execute(args, { ...opts, state }) }
35
+ : t;
36
+ }
37
+ return out;
38
+ }
39
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AA2CA;;;;oCAIoC;AACpC,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,GAAmB;IAC/D,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,SAAS;QACtD,MAAM,KAAK,GAA4B,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAkC,CAAC,EAAE,CAAC;YAC5E,KAAK,CAAC,IAAI,CAAC;gBACT,OAAO,EAAE,KAAK,UAAU;oBACtB,CAAC,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAAE,EAAe,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC;oBACtE,CAAC,CAAC,EAAE,CAAC;QACX,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IACrB,CAAC;IACD,OAAO,GAAmB,CAAC;AAC7B,CAAC;AAED;;;;;;wBAMwB;AACxB,MAAM,UAAU,YAAY,CAC1B,KAA0B,EAC1B,KAAoB;IAEpB,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU;gBAC9B,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,IAAa,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;gBACzF,CAAC,CAAC,CAAC,CAAC;IACV,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}