@primo-ai/core 0.1.2 → 0.1.4

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 (197) hide show
  1. package/dist/agent.d.ts +13 -1
  2. package/dist/agent.js +128 -4
  3. package/dist/checkpoint-store.d.ts +0 -1
  4. package/dist/checkpoint-store.js +0 -1
  5. package/dist/concurrency-controller.d.ts +0 -1
  6. package/dist/concurrency-controller.js +0 -1
  7. package/dist/config-merge.d.ts +0 -1
  8. package/dist/config-merge.js +0 -1
  9. package/dist/config.d.ts +0 -1
  10. package/dist/config.js +0 -1
  11. package/dist/context-builder.d.ts +0 -1
  12. package/dist/context-builder.js +0 -1
  13. package/dist/dynamic-resolver.d.ts +0 -1
  14. package/dist/dynamic-resolver.js +0 -1
  15. package/dist/errors.d.ts +0 -1
  16. package/dist/errors.js +0 -1
  17. package/dist/event-bus.d.ts +1 -1
  18. package/dist/event-bus.js +8 -1
  19. package/dist/event-system.d.ts +0 -1
  20. package/dist/event-system.js +0 -1
  21. package/dist/fallback-runner.d.ts +0 -1
  22. package/dist/fallback-runner.js +0 -1
  23. package/dist/gateways/builtin-gateway.d.ts +0 -1
  24. package/dist/gateways/builtin-gateway.js +0 -1
  25. package/dist/gateways/gateway-chain.d.ts +4 -1
  26. package/dist/gateways/gateway-chain.js +6 -1
  27. package/dist/gateways/openai-compatible-gateway.d.ts +0 -1
  28. package/dist/gateways/openai-compatible-gateway.js +0 -1
  29. package/dist/harness.d.ts +0 -1
  30. package/dist/harness.js +0 -1
  31. package/dist/hook-manager.d.ts +0 -1
  32. package/dist/hook-manager.js +0 -1
  33. package/dist/index.d.ts +3 -1
  34. package/dist/index.js +2 -1
  35. package/dist/llm-invoker.d.ts +3 -4
  36. package/dist/llm-invoker.js +10 -10
  37. package/dist/loop-orchestrator.d.ts +0 -1
  38. package/dist/loop-orchestrator.js +10 -1
  39. package/dist/model-factory.d.ts +4 -1
  40. package/dist/model-factory.js +3 -1
  41. package/dist/model-profile.d.ts +0 -1
  42. package/dist/model-profile.js +0 -1
  43. package/dist/model-resolver.d.ts +0 -1
  44. package/dist/model-resolver.js +0 -1
  45. package/dist/parse-model.d.ts +0 -1
  46. package/dist/parse-model.js +0 -1
  47. package/dist/pending-permission.d.ts +16 -0
  48. package/dist/pending-permission.js +24 -0
  49. package/dist/pipeline.d.ts +3 -3
  50. package/dist/pipeline.js +29 -4
  51. package/dist/plugin-manager.d.ts +0 -1
  52. package/dist/plugin-manager.js +12 -13
  53. package/dist/processors/build-context.d.ts +0 -1
  54. package/dist/processors/build-context.js +0 -1
  55. package/dist/processors/evaluate-iteration.d.ts +0 -1
  56. package/dist/processors/evaluate-iteration.js +7 -4
  57. package/dist/processors/execute-tools.d.ts +0 -1
  58. package/dist/processors/execute-tools.js +0 -1
  59. package/dist/processors/gate-tool.d.ts +0 -1
  60. package/dist/processors/gate-tool.js +0 -1
  61. package/dist/processors/index.d.ts +0 -1
  62. package/dist/processors/index.js +0 -1
  63. package/dist/processors/invoke-llm.d.ts +0 -1
  64. package/dist/processors/invoke-llm.js +0 -1
  65. package/dist/processors/prepare-step.d.ts +0 -1
  66. package/dist/processors/prepare-step.js +0 -1
  67. package/dist/processors/process-input.d.ts +0 -1
  68. package/dist/processors/process-input.js +0 -1
  69. package/dist/processors/process-output.d.ts +0 -1
  70. package/dist/processors/process-output.js +0 -1
  71. package/dist/processors/process-step-output.d.ts +0 -1
  72. package/dist/processors/process-step-output.js +0 -1
  73. package/dist/processors/provider-history-compat.d.ts +0 -1
  74. package/dist/processors/provider-history-compat.js +0 -1
  75. package/dist/provider-capabilities.d.ts +0 -1
  76. package/dist/provider-capabilities.js +0 -1
  77. package/dist/retry.d.ts +0 -1
  78. package/dist/retry.js +0 -1
  79. package/dist/serialize.d.ts +0 -1
  80. package/dist/serialize.js +0 -1
  81. package/dist/session-manager.d.ts +0 -1
  82. package/dist/session-manager.js +0 -1
  83. package/dist/session-persistence.d.ts +0 -1
  84. package/dist/session-persistence.js +0 -1
  85. package/dist/session-storage-sqlite.d.ts +41 -0
  86. package/dist/session-storage-sqlite.js +239 -0
  87. package/dist/session-storage.d.ts +6 -1
  88. package/dist/session-storage.js +65 -1
  89. package/dist/state-machine.d.ts +0 -1
  90. package/dist/state-machine.js +0 -1
  91. package/dist/storage-replay-backend.d.ts +0 -1
  92. package/dist/storage-replay-backend.js +0 -1
  93. package/dist/sub-agent.d.ts +0 -1
  94. package/dist/sub-agent.js +0 -1
  95. package/dist/task-manager.d.ts +0 -1
  96. package/dist/task-manager.js +6 -3
  97. package/dist/token-counter.d.ts +0 -1
  98. package/dist/token-counter.js +0 -1
  99. package/dist/tool-registry.d.ts +0 -1
  100. package/dist/tool-registry.js +0 -1
  101. package/package.json +8 -4
  102. package/dist/agent.d.ts.map +0 -1
  103. package/dist/agent.js.map +0 -1
  104. package/dist/checkpoint-store.d.ts.map +0 -1
  105. package/dist/checkpoint-store.js.map +0 -1
  106. package/dist/concurrency-controller.d.ts.map +0 -1
  107. package/dist/concurrency-controller.js.map +0 -1
  108. package/dist/config-merge.d.ts.map +0 -1
  109. package/dist/config-merge.js.map +0 -1
  110. package/dist/config.d.ts.map +0 -1
  111. package/dist/config.js.map +0 -1
  112. package/dist/context-builder.d.ts.map +0 -1
  113. package/dist/context-builder.js.map +0 -1
  114. package/dist/dynamic-resolver.d.ts.map +0 -1
  115. package/dist/dynamic-resolver.js.map +0 -1
  116. package/dist/errors.d.ts.map +0 -1
  117. package/dist/errors.js.map +0 -1
  118. package/dist/event-bus.d.ts.map +0 -1
  119. package/dist/event-bus.js.map +0 -1
  120. package/dist/event-system.d.ts.map +0 -1
  121. package/dist/event-system.js.map +0 -1
  122. package/dist/fallback-runner.d.ts.map +0 -1
  123. package/dist/fallback-runner.js.map +0 -1
  124. package/dist/gateways/builtin-gateway.d.ts.map +0 -1
  125. package/dist/gateways/builtin-gateway.js.map +0 -1
  126. package/dist/gateways/gateway-chain.d.ts.map +0 -1
  127. package/dist/gateways/gateway-chain.js.map +0 -1
  128. package/dist/gateways/openai-compatible-gateway.d.ts.map +0 -1
  129. package/dist/gateways/openai-compatible-gateway.js.map +0 -1
  130. package/dist/harness.d.ts.map +0 -1
  131. package/dist/harness.js.map +0 -1
  132. package/dist/hook-manager.d.ts.map +0 -1
  133. package/dist/hook-manager.js.map +0 -1
  134. package/dist/index.d.ts.map +0 -1
  135. package/dist/index.js.map +0 -1
  136. package/dist/llm-invoker.d.ts.map +0 -1
  137. package/dist/llm-invoker.js.map +0 -1
  138. package/dist/loop-orchestrator.d.ts.map +0 -1
  139. package/dist/loop-orchestrator.js.map +0 -1
  140. package/dist/model-factory.d.ts.map +0 -1
  141. package/dist/model-factory.js.map +0 -1
  142. package/dist/model-profile.d.ts.map +0 -1
  143. package/dist/model-profile.js.map +0 -1
  144. package/dist/model-resolver.d.ts.map +0 -1
  145. package/dist/model-resolver.js.map +0 -1
  146. package/dist/parse-model.d.ts.map +0 -1
  147. package/dist/parse-model.js.map +0 -1
  148. package/dist/pipeline.d.ts.map +0 -1
  149. package/dist/pipeline.js.map +0 -1
  150. package/dist/plugin-manager.d.ts.map +0 -1
  151. package/dist/plugin-manager.js.map +0 -1
  152. package/dist/processors/build-context.d.ts.map +0 -1
  153. package/dist/processors/build-context.js.map +0 -1
  154. package/dist/processors/evaluate-iteration.d.ts.map +0 -1
  155. package/dist/processors/evaluate-iteration.js.map +0 -1
  156. package/dist/processors/execute-tools.d.ts.map +0 -1
  157. package/dist/processors/execute-tools.js.map +0 -1
  158. package/dist/processors/gate-tool.d.ts.map +0 -1
  159. package/dist/processors/gate-tool.js.map +0 -1
  160. package/dist/processors/index.d.ts.map +0 -1
  161. package/dist/processors/index.js.map +0 -1
  162. package/dist/processors/invoke-llm.d.ts.map +0 -1
  163. package/dist/processors/invoke-llm.js.map +0 -1
  164. package/dist/processors/prepare-step.d.ts.map +0 -1
  165. package/dist/processors/prepare-step.js.map +0 -1
  166. package/dist/processors/process-input.d.ts.map +0 -1
  167. package/dist/processors/process-input.js.map +0 -1
  168. package/dist/processors/process-output.d.ts.map +0 -1
  169. package/dist/processors/process-output.js.map +0 -1
  170. package/dist/processors/process-step-output.d.ts.map +0 -1
  171. package/dist/processors/process-step-output.js.map +0 -1
  172. package/dist/processors/provider-history-compat.d.ts.map +0 -1
  173. package/dist/processors/provider-history-compat.js.map +0 -1
  174. package/dist/provider-capabilities.d.ts.map +0 -1
  175. package/dist/provider-capabilities.js.map +0 -1
  176. package/dist/retry.d.ts.map +0 -1
  177. package/dist/retry.js.map +0 -1
  178. package/dist/serialize.d.ts.map +0 -1
  179. package/dist/serialize.js.map +0 -1
  180. package/dist/session-manager.d.ts.map +0 -1
  181. package/dist/session-manager.js.map +0 -1
  182. package/dist/session-persistence.d.ts.map +0 -1
  183. package/dist/session-persistence.js.map +0 -1
  184. package/dist/session-storage.d.ts.map +0 -1
  185. package/dist/session-storage.js.map +0 -1
  186. package/dist/state-machine.d.ts.map +0 -1
  187. package/dist/state-machine.js.map +0 -1
  188. package/dist/storage-replay-backend.d.ts.map +0 -1
  189. package/dist/storage-replay-backend.js.map +0 -1
  190. package/dist/sub-agent.d.ts.map +0 -1
  191. package/dist/sub-agent.js.map +0 -1
  192. package/dist/task-manager.d.ts.map +0 -1
  193. package/dist/task-manager.js.map +0 -1
  194. package/dist/token-counter.d.ts.map +0 -1
  195. package/dist/token-counter.js.map +0 -1
  196. package/dist/tool-registry.d.ts.map +0 -1
  197. package/dist/tool-registry.js.map +0 -1
package/dist/agent.d.ts CHANGED
@@ -40,6 +40,7 @@ export declare class Agent {
40
40
  private orchestrator;
41
41
  private sessionManager?;
42
42
  private contextBuilder;
43
+ private activeAbortController;
43
44
  constructor(config: AgentConfig, deps?: AgentDependencies);
44
45
  use(factory: Processor | PluginFactory): void;
45
46
  teardown(): Promise<void>;
@@ -54,6 +55,18 @@ export declare class Agent {
54
55
  resume(sessionId: string, signal?: globalThis.AbortSignal): Promise<AgentRunResult>;
55
56
  stream(input: string, signal?: globalThis.AbortSignal): AsyncGenerator<string>;
56
57
  streamEvents(input: string, signal?: globalThis.AbortSignal): AsyncGenerator<import('@primo-ai/sdk').StreamEvent>;
58
+ /** Abort a running agent. Idempotent — no-op if agent is not running. */
59
+ abort(): void;
60
+ /**
61
+ * Continue an existing session by restoring its context and running the pipeline
62
+ * with a new user message.
63
+ */
64
+ continue(sessionId: string, message: string, signal?: globalThis.AbortSignal): Promise<AgentRunResult>;
65
+ /**
66
+ * Continue an existing session with streaming. Yields StreamEvents for the
67
+ * continued conversation.
68
+ */
69
+ continueStream(sessionId: string, message: string, signal?: globalThis.AbortSignal): AsyncGenerator<import('@primo-ai/sdk').StreamEvent>;
57
70
  /** Clear the cached model so the next run re-resolves from the factory. */
58
71
  invalidateModel(): void;
59
72
  /** Auto-invalidate cached model when the error indicates auth failure or model-not-found. */
@@ -63,4 +76,3 @@ export declare class Agent {
63
76
  private registerTools;
64
77
  private registerBuiltinProcessors;
65
78
  }
66
- //# sourceMappingURL=agent.d.ts.map
package/dist/agent.js CHANGED
@@ -22,6 +22,7 @@ export class Agent {
22
22
  orchestrator;
23
23
  sessionManager;
24
24
  contextBuilder;
25
+ activeAbortController = null;
25
26
  constructor(config, deps) {
26
27
  this.config = config;
27
28
  this.modelFactory = deps?.modelFactory ?? new ModelFactory();
@@ -83,10 +84,15 @@ export class Agent {
83
84
  // agent.start hook
84
85
  await hm.invoke('agent.start', { sessionId: context.request.sessionId, request: context.request, agentConfig: this.config }, {});
85
86
  const maxIter = typeof this.config.maxIterations === 'number' ? this.config.maxIterations : 10;
87
+ const controller = new AbortController();
88
+ this.activeAbortController = controller;
89
+ if (signal) {
90
+ signal.addEventListener('abort', () => controller.abort(), { once: true });
91
+ }
86
92
  try {
87
93
  const { context: finalCtx, compatRetries } = await this.orchestrator.runLoop(context, {
88
94
  maxIterations: maxIter,
89
- signal,
95
+ signal: controller.signal,
90
96
  modelString: this.config.model,
91
97
  sessionId: context.request.sessionId,
92
98
  autoCheckpoint: this._autoCheckpoint,
@@ -103,6 +109,7 @@ export class Agent {
103
109
  throw error;
104
110
  }
105
111
  finally {
112
+ this.activeAbortController = null;
106
113
  // agent.end hook — always fires, even on error; suppress hook errors to preserve original
107
114
  try {
108
115
  await hm.invoke('agent.end', { sessionId: context.request.sessionId }, {});
@@ -149,16 +156,22 @@ export class Agent {
149
156
  // agent.start hook
150
157
  await hm.invoke('agent.start', { sessionId: context.request.sessionId, request: context.request, agentConfig: this.config }, {});
151
158
  const maxIter = typeof this.config.maxIterations === 'number' ? this.config.maxIterations : 10;
159
+ const controller = new AbortController();
160
+ this.activeAbortController = controller;
161
+ if (signal) {
162
+ signal.addEventListener('abort', () => controller.abort(), { once: true });
163
+ }
152
164
  try {
153
165
  yield* this.orchestrator.streamLoop(context, {
154
166
  maxIterations: maxIter,
155
- signal,
167
+ signal: controller.signal,
156
168
  modelString: this.config.model,
157
169
  sessionId: context.request.sessionId,
158
170
  autoCheckpoint: this._autoCheckpoint,
159
171
  });
160
172
  }
161
173
  finally {
174
+ this.activeAbortController = null;
162
175
  try {
163
176
  await hm.invoke('agent.end', { sessionId: context.request.sessionId }, {});
164
177
  }
@@ -172,16 +185,128 @@ export class Agent {
172
185
  const hm = this._pluginManager.hookManager;
173
186
  await hm.invoke('agent.start', { sessionId: context.request.sessionId, request: context.request, agentConfig: this.config }, {});
174
187
  const maxIter = typeof this.config.maxIterations === 'number' ? this.config.maxIterations : 10;
188
+ const controller = new AbortController();
189
+ this.activeAbortController = controller;
190
+ if (signal) {
191
+ signal.addEventListener('abort', () => controller.abort(), { once: true });
192
+ }
175
193
  try {
176
194
  yield* this.orchestrator.streamEvents(context, {
177
195
  maxIterations: maxIter,
178
- signal,
196
+ signal: controller.signal,
197
+ modelString: this.config.model,
198
+ sessionId: context.request.sessionId,
199
+ autoCheckpoint: this._autoCheckpoint,
200
+ });
201
+ }
202
+ finally {
203
+ this.activeAbortController = null;
204
+ try {
205
+ await hm.invoke('agent.end', { sessionId: context.request.sessionId }, {});
206
+ }
207
+ catch { /* hook error must not mask original */ }
208
+ }
209
+ }
210
+ /** Abort a running agent. Idempotent — no-op if agent is not running. */
211
+ abort() {
212
+ if (!this.orchestrator.stateMachine.canTransition('cancelled'))
213
+ return;
214
+ this.orchestrator.stateMachine.transition('cancelled');
215
+ this.activeAbortController?.abort();
216
+ this.activeAbortController = null;
217
+ }
218
+ /**
219
+ * Continue an existing session by restoring its context and running the pipeline
220
+ * with a new user message.
221
+ */
222
+ async continue(sessionId, message, signal) {
223
+ if (signal?.aborted)
224
+ throw new DOMException('Agent continue aborted', 'AbortError');
225
+ if (!this.sessionManager)
226
+ throw new Error('Session manager is required for continue()');
227
+ const context = await this.sessionManager.restore(sessionId);
228
+ context.request.input = message;
229
+ if (context.session.messageHistory) {
230
+ context.session.messageHistory.push({ role: 'user', content: message });
231
+ }
232
+ else {
233
+ context.session.messageHistory = [{ role: 'user', content: message }];
234
+ }
235
+ context.iteration = { step: 0 };
236
+ this._pluginManager.freezeHarnessInstances();
237
+ const hm = this._pluginManager.hookManager;
238
+ await hm.invoke('agent.start', { sessionId: context.request.sessionId, request: context.request, agentConfig: this.config }, {});
239
+ const maxIter = typeof this.config.maxIterations === 'number' ? this.config.maxIterations : 10;
240
+ const controller = new AbortController();
241
+ this.activeAbortController = controller;
242
+ if (signal) {
243
+ signal.addEventListener('abort', () => controller.abort(), { once: true });
244
+ }
245
+ try {
246
+ const { context: finalCtx, compatRetries } = await this.orchestrator.runLoop(context, {
247
+ maxIterations: maxIter,
248
+ signal: controller.signal,
249
+ modelString: this.config.model,
250
+ sessionId: context.request.sessionId,
251
+ autoCheckpoint: this._autoCheckpoint,
252
+ });
253
+ return {
254
+ response: finalCtx.iteration.response ?? '',
255
+ tokenUsage: finalCtx.session.totalTokenUsage ?? { input: 0, output: 0 },
256
+ sessionId: context.request.sessionId,
257
+ compatRetries,
258
+ };
259
+ }
260
+ catch (error) {
261
+ this.autoInvalidateModel(error);
262
+ throw error;
263
+ }
264
+ finally {
265
+ this.activeAbortController = null;
266
+ try {
267
+ await hm.invoke('agent.end', { sessionId: context.request.sessionId }, {});
268
+ }
269
+ catch { /* hook error must not mask original */ }
270
+ }
271
+ }
272
+ /**
273
+ * Continue an existing session with streaming. Yields StreamEvents for the
274
+ * continued conversation.
275
+ */
276
+ async *continueStream(sessionId, message, signal) {
277
+ if (signal?.aborted)
278
+ throw new DOMException('Agent continue stream aborted', 'AbortError');
279
+ if (!this.sessionManager)
280
+ throw new Error('Session manager is required for continueStream()');
281
+ const context = await this.sessionManager.restore(sessionId);
282
+ context.request.input = message;
283
+ if (context.session.messageHistory) {
284
+ context.session.messageHistory.push({ role: 'user', content: message });
285
+ }
286
+ else {
287
+ context.session.messageHistory = [{ role: 'user', content: message }];
288
+ }
289
+ context.iteration = { step: 0 };
290
+ this._pluginManager.freezeHarnessInstances();
291
+ const hm = this._pluginManager.hookManager;
292
+ await hm.invoke('agent.start', { sessionId: context.request.sessionId, request: context.request, agentConfig: this.config }, {});
293
+ const maxIter = typeof this.config.maxIterations === 'number' ? this.config.maxIterations : 10;
294
+ const controller = new AbortController();
295
+ this.activeAbortController = controller;
296
+ if (signal) {
297
+ signal.addEventListener('abort', () => controller.abort(), { once: true });
298
+ }
299
+ try {
300
+ yield* this.orchestrator.streamEvents(context, {
301
+ maxIterations: maxIter,
302
+ signal: controller.signal,
179
303
  modelString: this.config.model,
180
304
  sessionId: context.request.sessionId,
181
305
  autoCheckpoint: this._autoCheckpoint,
182
306
  });
183
307
  }
184
308
  finally {
309
+ this.activeAbortController = null;
185
310
  try {
186
311
  await hm.invoke('agent.end', { sessionId: context.request.sessionId }, {});
187
312
  }
@@ -257,4 +382,3 @@ function isAuthOrNotFoundError(error) {
257
382
  const code = err.statusCode ?? err.status;
258
383
  return code === 401 || code === 403 || code === 404;
259
384
  }
260
- //# sourceMappingURL=agent.js.map
@@ -16,4 +16,3 @@ export declare class JsonlCheckpointStore<T = unknown> implements CheckpointStor
16
16
  delete(sessionId: string): Promise<void>;
17
17
  list(): Promise<string[]>;
18
18
  }
19
- //# sourceMappingURL=checkpoint-store.d.ts.map
@@ -76,4 +76,3 @@ export class JsonlCheckpointStore {
76
76
  }
77
77
  }
78
78
  }
79
- //# sourceMappingURL=checkpoint-store.js.map
@@ -6,4 +6,3 @@ export declare class ConcurrencyController {
6
6
  getActiveCount(slotKey: string): number;
7
7
  private releaseSlot;
8
8
  }
9
- //# sourceMappingURL=concurrency-controller.d.ts.map
@@ -68,4 +68,3 @@ export class ConcurrencyController {
68
68
  }
69
69
  }
70
70
  }
71
- //# sourceMappingURL=concurrency-controller.js.map
@@ -9,4 +9,3 @@
9
9
  * - The target is NOT mutated; a new object is returned.
10
10
  */
11
11
  export declare function deepMerge(target: Record<string, unknown>, ...sources: Record<string, unknown>[]): Record<string, unknown>;
12
- //# sourceMappingURL=config-merge.d.ts.map
@@ -44,4 +44,3 @@ export function deepMerge(target, ...sources) {
44
44
  function isObject(value) {
45
45
  return typeof value === 'object' && value !== null && !Array.isArray(value);
46
46
  }
47
- //# sourceMappingURL=config-merge.js.map
package/dist/config.d.ts CHANGED
@@ -13,4 +13,3 @@ export declare class ConfigLoader {
13
13
  parseJsonc(content: string): Record<string, unknown>;
14
14
  load(sources: ConfigSource): Promise<HarnessConfig>;
15
15
  }
16
- //# sourceMappingURL=config.d.ts.map
package/dist/config.js CHANGED
@@ -141,4 +141,3 @@ const HarnessConfigSchema = z.object({
141
141
  apiKey: z.string().optional(),
142
142
  })).optional(),
143
143
  }).passthrough();
144
- //# sourceMappingURL=config.js.map
@@ -26,4 +26,3 @@ export declare class ContextBuilder {
26
26
  private countToolDeclarations;
27
27
  private matchProfile;
28
28
  }
29
- //# sourceMappingURL=context-builder.d.ts.map
@@ -175,4 +175,3 @@ export class ContextBuilder {
175
175
  return undefined;
176
176
  }
177
177
  }
178
- //# sourceMappingURL=context-builder.js.map
@@ -4,4 +4,3 @@ import type { Dynamic, ResolveContext } from '@primo-ai/sdk';
4
4
  * otherwise return the static value as-is.
5
5
  */
6
6
  export declare function resolveDynamic<T>(value: Dynamic<T>, ctx: ResolveContext): Promise<T>;
7
- //# sourceMappingURL=dynamic-resolver.d.ts.map
@@ -8,4 +8,3 @@ export async function resolveDynamic(value, ctx) {
8
8
  }
9
9
  return value;
10
10
  }
11
- //# sourceMappingURL=dynamic-resolver.js.map
package/dist/errors.d.ts CHANGED
@@ -27,4 +27,3 @@ export declare class ModelNotFoundError extends FatalError {
27
27
  export declare class ToolExecutionError extends RecoverableError {
28
28
  constructor(message: string, cause?: Error);
29
29
  }
30
- //# sourceMappingURL=errors.d.ts.map
package/dist/errors.js CHANGED
@@ -37,4 +37,3 @@ export class ToolExecutionError extends RecoverableError {
37
37
  super(message, { code: 'TOOL_ERROR', cause });
38
38
  }
39
39
  }
40
- //# sourceMappingURL=errors.js.map
@@ -4,5 +4,5 @@ export declare class EventBus {
4
4
  constructor(onError?: ((error: unknown, eventType: string) => void) | undefined);
5
5
  emit(eventType: string, data?: unknown): void;
6
6
  subscribe(eventType: string, handler: (data?: unknown) => void): () => void;
7
+ once(eventType: string): Promise<unknown>;
7
8
  }
8
- //# sourceMappingURL=event-bus.d.ts.map
package/dist/event-bus.js CHANGED
@@ -32,5 +32,12 @@ export class EventBus {
32
32
  set.add(handler);
33
33
  return () => set.delete(handler);
34
34
  }
35
+ once(eventType) {
36
+ return new Promise((resolve) => {
37
+ const unsub = this.subscribe(eventType, (data) => {
38
+ unsub();
39
+ resolve(data);
40
+ });
41
+ });
42
+ }
35
43
  }
36
- //# sourceMappingURL=event-bus.js.map
@@ -16,4 +16,3 @@ export declare class EventSystem {
16
16
  replay(sessionId: string, options?: ReplayOptions): Promise<void>;
17
17
  private filterEvents;
18
18
  }
19
- //# sourceMappingURL=event-system.d.ts.map
@@ -55,4 +55,3 @@ export class EventSystem {
55
55
  return result;
56
56
  }
57
57
  }
58
- //# sourceMappingURL=event-system.js.map
@@ -27,4 +27,3 @@ export declare class FallbackRunner {
27
27
  tokenUsage: TokenUsage;
28
28
  }>;
29
29
  }
30
- //# sourceMappingURL=fallback-runner.d.ts.map
@@ -37,4 +37,3 @@ export class FallbackRunner {
37
37
  throw lastError;
38
38
  }
39
39
  }
40
- //# sourceMappingURL=fallback-runner.js.map
@@ -14,4 +14,3 @@ export declare function registerProvider(name: string, factory: ProviderFactory)
14
14
  /** @internal Access the default singleton instance. */
15
15
  export declare function getDefaultBuiltInGateway(): BuiltInGateway;
16
16
  export {};
17
- //# sourceMappingURL=builtin-gateway.d.ts.map
@@ -55,4 +55,3 @@ export function registerProvider(name, factory) {
55
55
  export function getDefaultBuiltInGateway() {
56
56
  return defaultInstance;
57
57
  }
58
- //# sourceMappingURL=builtin-gateway.js.map
@@ -5,5 +5,8 @@ export declare class GatewayChain {
5
5
  register(gateway: ModelGateway): void;
6
6
  resolve(modelString: string): Promise<LanguageModel>;
7
7
  get size(): number;
8
+ listGateways(): Array<{
9
+ name: string;
10
+ canResolve: (model: string) => boolean;
11
+ }>;
8
12
  }
9
- //# sourceMappingURL=gateway-chain.d.ts.map
@@ -14,5 +14,10 @@ export class GatewayChain {
14
14
  get size() {
15
15
  return this.gateways.length;
16
16
  }
17
+ listGateways() {
18
+ return this.gateways.map(gw => ({
19
+ name: gw.name,
20
+ canResolve: (model) => gw.canResolve(model),
21
+ }));
22
+ }
17
23
  }
18
- //# sourceMappingURL=gateway-chain.js.map
@@ -7,4 +7,3 @@ export declare class OpenAICompatibleGateway implements ModelGateway {
7
7
  canResolve(modelString: string): boolean;
8
8
  resolve(modelString: string): Promise<unknown>;
9
9
  }
10
- //# sourceMappingURL=openai-compatible-gateway.d.ts.map
@@ -23,4 +23,3 @@ export class OpenAICompatibleGateway {
23
23
  return sdk.chatModel(modelId);
24
24
  }
25
25
  }
26
- //# sourceMappingURL=openai-compatible-gateway.js.map
package/dist/harness.d.ts CHANGED
@@ -41,4 +41,3 @@ export declare class HarnessAPIImpl implements HarnessAPI {
41
41
  getResources(): ResourceDeclaration[];
42
42
  getUnsubFns(): Array<() => void>;
43
43
  }
44
- //# sourceMappingURL=harness.d.ts.map
package/dist/harness.js CHANGED
@@ -67,4 +67,3 @@ export class HarnessAPIImpl {
67
67
  return this.unsubFns;
68
68
  }
69
69
  }
70
- //# sourceMappingURL=harness.js.map
@@ -19,4 +19,3 @@ export declare class HookManager {
19
19
  private getSortedHooks;
20
20
  private bridge;
21
21
  }
22
- //# sourceMappingURL=hook-manager.d.ts.map
@@ -89,4 +89,3 @@ export class HookManager {
89
89
  }
90
90
  }
91
91
  }
92
- //# sourceMappingURL=hook-manager.js.map
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export { StorageReplayBackend } from './storage-replay-backend.js';
10
10
  export { HookManager, type HookManagerOptions } from './hook-manager.js';
11
11
  export { ToolRegistry, type AiSdkToolSchema, type ToolRegistryOptions } from './tool-registry.js';
12
12
  export { FilesystemSessionStorage } from './session-storage.js';
13
+ export { SqliteSessionStorage } from './session-storage-sqlite.js';
13
14
  export { SessionPersistence } from './session-persistence.js';
14
15
  export { SessionManagerImpl } from './session-manager.js';
15
16
  export { createSubAgentTool } from './sub-agent.js';
@@ -31,4 +32,5 @@ export { TiktokenCounter } from './token-counter.js';
31
32
  export type { StreamEvent } from '@primo-ai/sdk';
32
33
  export { OpenAICompatibleGateway } from './gateways/openai-compatible-gateway.js';
33
34
  export { AgentForgeError, RecoverableError, FatalError, AuthError, ModelNotFoundError, ToolExecutionError, type AgentErrorOptions, } from './errors.js';
34
- //# sourceMappingURL=index.d.ts.map
35
+ export { PermissionManager } from './pending-permission.js';
36
+ export type { PendingPermission } from './pending-permission.js';
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ export { StorageReplayBackend } from './storage-replay-backend.js';
11
11
  export { HookManager } from './hook-manager.js';
12
12
  export { ToolRegistry } from './tool-registry.js';
13
13
  export { FilesystemSessionStorage } from './session-storage.js';
14
+ export { SqliteSessionStorage } from './session-storage-sqlite.js';
14
15
  export { SessionPersistence } from './session-persistence.js';
15
16
  export { SessionManagerImpl } from './session-manager.js';
16
17
  export { createSubAgentTool } from './sub-agent.js';
@@ -31,4 +32,4 @@ export { HarnessAPIImpl } from './harness.js';
31
32
  export { TiktokenCounter } from './token-counter.js';
32
33
  export { OpenAICompatibleGateway } from './gateways/openai-compatible-gateway.js';
33
34
  export { AgentForgeError, RecoverableError, FatalError, AuthError, ModelNotFoundError, ToolExecutionError, } from './errors.js';
34
- //# sourceMappingURL=index.js.map
35
+ export { PermissionManager } from './pending-permission.js';
@@ -17,18 +17,17 @@ export interface LLMInvokeInput {
17
17
  }
18
18
  export interface LLMInvokeResult {
19
19
  response: string;
20
- tokenUsage: TokenUsage;
20
+ tokenUsage: TokenUsage | null;
21
21
  }
22
22
  export interface LLMStreamHandle {
23
23
  fullStream: AsyncIterable<unknown>;
24
- usage: Promise<TokenUsage>;
24
+ usage: Promise<TokenUsage | null>;
25
25
  reasoning: Promise<string | undefined>;
26
26
  }
27
- export declare function extractTokenUsage(usage: unknown): TokenUsage;
27
+ export declare function extractTokenUsage(usage: unknown): TokenUsage | null;
28
28
  export declare class LLMInvoker {
29
29
  private options;
30
30
  constructor(options: LLMInvokerOptions);
31
31
  invoke(input: LLMInvokeInput): Promise<LLMInvokeResult>;
32
32
  stream(input: LLMInvokeInput): LLMStreamHandle;
33
33
  }
34
- //# sourceMappingURL=llm-invoker.d.ts.map
@@ -3,14 +3,15 @@ import { SpanType } from '@primo-ai/sdk';
3
3
  import { streamWithRetry } from './retry.js';
4
4
  export function extractTokenUsage(usage) {
5
5
  const u = usage;
6
- return {
7
- input: typeof u?.inputTokens === 'number'
8
- ? u.inputTokens
9
- : u?.inputTokens?.total ?? 0,
10
- output: typeof u?.outputTokens === 'number'
11
- ? u.outputTokens
12
- : u?.outputTokens?.total ?? 0,
13
- };
6
+ if (!u)
7
+ return null;
8
+ const input = typeof u?.inputTokens === 'number'
9
+ ? u.inputTokens
10
+ : u?.inputTokens?.total ?? 0;
11
+ const output = typeof u?.outputTokens === 'number'
12
+ ? u.outputTokens
13
+ : u?.outputTokens?.total ?? 0;
14
+ return { input, output };
14
15
  }
15
16
  export class LLMInvoker {
16
17
  options;
@@ -112,7 +113,7 @@ export class LLMInvoker {
112
113
  .catch((err) => {
113
114
  endSpan();
114
115
  this.options.eventBus?.emit('llm:usage_unavailable', { error: err instanceof Error ? err.message : String(err) });
115
- return { input: 0, output: 0 };
116
+ return null;
116
117
  }),
117
118
  reasoning: Promise.resolve(result.reasoningText).catch((err) => {
118
119
  this.options.eventBus?.emit('llm:reasoning_error', { error: err instanceof Error ? err.message : String(err) });
@@ -121,4 +122,3 @@ export class LLMInvoker {
121
122
  };
122
123
  }
123
124
  }
124
- //# sourceMappingURL=llm-invoker.js.map
@@ -45,4 +45,3 @@ export declare class LoopOrchestrator {
45
45
  private afterIteration;
46
46
  private finalizeState;
47
47
  }
48
- //# sourceMappingURL=loop-orchestrator.d.ts.map
@@ -124,6 +124,8 @@ export class LoopOrchestrator {
124
124
  yield event;
125
125
  return;
126
126
  }
127
+ if (event.type === 'error')
128
+ throw event.error;
127
129
  if (event.type === 'complete')
128
130
  loopCtx = event.context;
129
131
  yield event;
@@ -161,6 +163,14 @@ export class LoopOrchestrator {
161
163
  yield event;
162
164
  return;
163
165
  }
166
+ if (event.type === 'error') {
167
+ if (event.recoverable) {
168
+ this.eventBus?.emit('pipeline:stage_error', { stage: event.stage, error: event.error });
169
+ loopBreak = true;
170
+ break;
171
+ }
172
+ throw event.error;
173
+ }
164
174
  if (event.type === 'complete')
165
175
  loopCtx = event.context;
166
176
  yield event;
@@ -244,4 +254,3 @@ export class LoopOrchestrator {
244
254
  }
245
255
  }
246
256
  }
247
- //# sourceMappingURL=loop-orchestrator.js.map
@@ -8,6 +8,9 @@ export declare class ModelFactory {
8
8
  resolve(modelString: string): Promise<LanguageModel>;
9
9
  registerGateway(gateway: ModelGateway): void;
10
10
  registerProvider(name: string, factory: ProviderFactory): void;
11
+ listGateways(): Array<{
12
+ name: string;
13
+ canResolve: (model: string) => boolean;
14
+ }>;
11
15
  }
12
16
  export {};
13
- //# sourceMappingURL=model-factory.d.ts.map
@@ -36,5 +36,7 @@ export class ModelFactory {
36
36
  registerProvider(name, factory) {
37
37
  this.providerGateway.addProvider(name, factory);
38
38
  }
39
+ listGateways() {
40
+ return this.chain.listGateways();
41
+ }
39
42
  }
40
- //# sourceMappingURL=model-factory.js.map
@@ -14,4 +14,3 @@ export declare function matchProfile(model: string, profiles: ModelProfile[]): M
14
14
  * - toolOverrides.exclude removes matching tools; description overrides update them.
15
15
  */
16
16
  export declare function applyProfile(ctx: PipelineContext, profile: ModelProfile): PipelineContext;
17
- //# sourceMappingURL=model-profile.d.ts.map
@@ -54,4 +54,3 @@ export function applyProfile(ctx, profile) {
54
54
  },
55
55
  };
56
56
  }
57
- //# sourceMappingURL=model-profile.js.map
@@ -13,4 +13,3 @@ export { parseModel, type ParsedModel } from './parse-model.js';
13
13
  export declare function resolveModel(modelString: string): Promise<LanguageModel>;
14
14
  /** Create a gateway chain with custom gateways prepended before BuiltInGateway. */
15
15
  export declare function createChain(configs?: GatewayConfig[]): GatewayChain;
16
- //# sourceMappingURL=model-resolver.d.ts.map
@@ -25,4 +25,3 @@ export function createChain(configs) {
25
25
  chain.register(getDefaultBuiltInGateway());
26
26
  return chain;
27
27
  }
28
- //# sourceMappingURL=model-resolver.js.map
@@ -3,4 +3,3 @@ export interface ParsedModel {
3
3
  modelId: string;
4
4
  }
5
5
  export declare function parseModel(modelString: string): ParsedModel;
6
- //# sourceMappingURL=parse-model.d.ts.map
@@ -8,4 +8,3 @@ export function parseModel(modelString) {
8
8
  modelId: modelString.slice(idx + 1),
9
9
  };
10
10
  }
11
- //# sourceMappingURL=parse-model.js.map
@@ -0,0 +1,16 @@
1
+ export interface PendingPermission {
2
+ permissionId: string;
3
+ sessionId: string;
4
+ toolName: string;
5
+ args: Record<string, unknown>;
6
+ reason: string;
7
+ createdAt: string;
8
+ }
9
+ export declare class PermissionManager {
10
+ private pending;
11
+ awaitDecision(permission: PendingPermission): Promise<boolean>;
12
+ resolve(permissionId: string, approved: boolean): void;
13
+ list(): PendingPermission[];
14
+ getBySession(sessionId: string): PendingPermission[];
15
+ get(permissionId: string): PendingPermission | undefined;
16
+ }