@dereekb/openrouter 13.37.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/firebase/index.cjs.default.js +1 -0
  4. package/firebase/index.cjs.js +666 -0
  5. package/firebase/index.cjs.mjs +2 -0
  6. package/firebase/index.d.ts +1 -0
  7. package/firebase/index.esm.js +626 -0
  8. package/firebase/package.json +25 -0
  9. package/firebase/src/index.d.ts +1 -0
  10. package/firebase/src/lib/index.d.ts +4 -0
  11. package/firebase/src/lib/openrouter.api.d.ts +226 -0
  12. package/firebase/src/lib/openrouter.id.d.ts +56 -0
  13. package/firebase/src/lib/openrouter.model.d.ts +609 -0
  14. package/firebase/src/lib/openrouter.query.d.ts +121 -0
  15. package/firebase-server/index.cjs.default.js +1 -0
  16. package/firebase-server/index.cjs.js +4520 -0
  17. package/firebase-server/index.cjs.mjs +2 -0
  18. package/firebase-server/index.d.ts +1 -0
  19. package/firebase-server/index.esm.js +4466 -0
  20. package/firebase-server/package.json +38 -0
  21. package/firebase-server/src/index.d.ts +1 -0
  22. package/firebase-server/src/lib/index.d.ts +10 -0
  23. package/firebase-server/src/lib/openrouter.action.server.d.ts +196 -0
  24. package/firebase-server/src/lib/openrouter.broadcast.d.ts +93 -0
  25. package/firebase-server/src/lib/openrouter.call.inline.d.ts +57 -0
  26. package/firebase-server/src/lib/openrouter.file.attachment.d.ts +97 -0
  27. package/firebase-server/src/lib/openrouter.module.d.ts +65 -0
  28. package/firebase-server/src/lib/openrouter.prompt.service.d.ts +109 -0
  29. package/firebase-server/src/lib/openrouter.runtask.handle.d.ts +56 -0
  30. package/firebase-server/src/lib/openrouter.runtask.service.d.ts +380 -0
  31. package/firebase-server/src/lib/openrouter.runtask.sweep.d.ts +170 -0
  32. package/firebase-server/src/lib/openrouter.state.accessor.d.ts +106 -0
  33. package/firebase-server/src/test/openrouter.fake.d.ts +134 -0
  34. package/index.cjs.default.js +1 -0
  35. package/index.cjs.js +1867 -0
  36. package/index.cjs.mjs +2 -0
  37. package/index.d.ts +1 -0
  38. package/index.esm.js +1771 -0
  39. package/package.json +32 -0
  40. package/src/index.d.ts +1 -0
  41. package/src/lib/index.d.ts +10 -0
  42. package/src/lib/openrouter.call.d.ts +268 -0
  43. package/src/lib/openrouter.config.d.ts +314 -0
  44. package/src/lib/openrouter.embedding.d.ts +87 -0
  45. package/src/lib/openrouter.generation.d.ts +46 -0
  46. package/src/lib/openrouter.input.d.ts +238 -0
  47. package/src/lib/openrouter.prompt.d.ts +79 -0
  48. package/src/lib/openrouter.request.d.ts +91 -0
  49. package/src/lib/openrouter.sdk.d.ts +37 -0
  50. package/src/lib/openrouter.tool.d.ts +99 -0
  51. package/src/lib/openrouter.type.d.ts +125 -0
@@ -0,0 +1,56 @@
1
+ import { type Maybe } from '@dereekb/util';
2
+ import { type OpenRouterRunTask } from '@dereekb/openrouter/firebase';
3
+ /**
4
+ * How a caller should proceed given a run task's current state.
5
+ *
6
+ * These three outcomes are what an async-work checkpoint needs, and they map 1:1 onto the
7
+ * complete / poll-again / failed branches an OpenAI `responses.retrieve(id)` call produces today — so an
8
+ * existing retry ladder survives the migration unchanged.
9
+ */
10
+ export type OpenRouterRunTaskOutcome = 'complete' | 'queued' | 'failure' | 'missing';
11
+ /**
12
+ * Classifies a run task into an outcome.
13
+ *
14
+ * `AWAITING_ASYNC_TOOLS` reports as `queued`: from the caller's side it is indistinguishable from
15
+ * waiting, because it is waiting — just on a tool result rather than on a sweep.
16
+ *
17
+ * @param task - The run task, or null when it does not exist.
18
+ * @returns The outcome.
19
+ *
20
+ * @__NO_SIDE_EFFECTS__
21
+ */
22
+ export declare function openRouterRunTaskOutcome(task: Maybe<OpenRouterRunTask>): OpenRouterRunTaskOutcome;
23
+ /**
24
+ * Handlers for each outcome.
25
+ */
26
+ export interface OpenRouterRunTaskResultHandlers<T> {
27
+ /**
28
+ * Called with a COMPLETE task.
29
+ */
30
+ readonly onComplete: (task: OpenRouterRunTask) => Promise<T> | T;
31
+ /**
32
+ * Called while the run is still in flight.
33
+ */
34
+ readonly onQueued: (task: OpenRouterRunTask) => Promise<T> | T;
35
+ /**
36
+ * Called when the run failed with its retry budget spent.
37
+ */
38
+ readonly onFailure: (task: OpenRouterRunTask) => Promise<T> | T;
39
+ /**
40
+ * Called when no run task exists for the key.
41
+ *
42
+ * Defaults to {@link OpenRouterRunTaskResultHandlers.onFailure} semantics via `onMissing` being
43
+ * required only when the caller wants to distinguish the two. A missing document is genuinely
44
+ * different from a failed one — it usually means the enqueue never landed — so it is worth handling.
45
+ */
46
+ readonly onMissing: () => Promise<T> | T;
47
+ }
48
+ /**
49
+ * Creates a reusable dispatcher for a fixed set of handlers.
50
+ *
51
+ * @param handlers - The per-outcome handlers.
52
+ * @returns A function that dispatches a run task.
53
+ *
54
+ * @__NO_SIDE_EFFECTS__
55
+ */
56
+ export declare function handleOpenRouterRunTaskResultFactory<T>(handlers: OpenRouterRunTaskResultHandlers<T>): (task: Maybe<OpenRouterRunTask>) => Promise<T>;
@@ -0,0 +1,380 @@
1
+ import { type FirebaseStorageContext } from '@dereekb/firebase';
2
+ import { type FirebaseServerEnvService } from '@dereekb/firebase-server';
3
+ import { type Maybe, type Milliseconds } from '@dereekb/util';
4
+ import { type OpenRouterAttachedFileReference, type OpenRouterCallResult, type OpenRouterCore, type OpenRouterDeferredToolResolution, type OpenRouterFileReference, type OpenRouterInput, type OpenRouterModelConfig, type OpenRouterPromptKey, type OpenRouterPromptVersionNumber, type OpenRouterRunTaskKey, type Tool } from '@dereekb/openrouter';
5
+ import { type OpenRouterRunTask, type OpenRouterRunTaskDocument, type OpenRouterRunTaskFirestoreCollections, type OpenRouterRunTaskPendingToolCall, OpenRouterRunTaskState, type OpenRouterRunTaskUnsentToolResult } from '@dereekb/openrouter/firebase';
6
+ import { type OpenRouterFileAttachmentMode } from './openrouter.file.attachment';
7
+ import { type OpenRouterPromptService } from './openrouter.prompt.service';
8
+ /**
9
+ * Default lease duration. A `RUNNING` task whose lease is older than this is reclaimable.
10
+ *
11
+ * Comfortably longer than any single inference plus its retries, so a healthy run is never stolen from
12
+ * itself, and short enough that a crashed sweep's work resumes on the next tick or two.
13
+ */
14
+ export declare const DEFAULT_OPENROUTER_LEASE_DURATION: Milliseconds;
15
+ /**
16
+ * Default number of attempts before a task is marked FAILED.
17
+ *
18
+ * Spent only on a failure {@link isRetryableOpenRouterError} classifies as transient; a deterministic
19
+ * failure reaches `FAILED` on its first attempt.
20
+ */
21
+ export declare const DEFAULT_OPENROUTER_MAX_ATTEMPTS = 3;
22
+ /**
23
+ * Maximum tasks one retention page may delete.
24
+ *
25
+ * A page's deletes go out as a single Firestore write batch, and a batch takes at most 500 writes.
26
+ */
27
+ export declare const OPENROUTER_MAX_EXPIRED_RUN_TASK_DELETE_PAGE_SIZE = 500;
28
+ /**
29
+ * Params for enqueueing a run task.
30
+ */
31
+ export interface OpenRouterEnqueueRunTaskParams {
32
+ /**
33
+ * The run key, which becomes the document id.
34
+ *
35
+ * Derive it deterministically (e.g. from the owning NotificationTask's model key) so re-entering the
36
+ * checkpoint that enqueued the run reuses this document instead of queueing a duplicate.
37
+ */
38
+ readonly key: OpenRouterRunTaskKey;
39
+ /**
40
+ * The prompt to run.
41
+ */
42
+ readonly promptKey: OpenRouterPromptKey;
43
+ /**
44
+ * Version to pin. Omit to resolve the prompt's active version.
45
+ */
46
+ readonly version?: Maybe<OpenRouterPromptVersionNumber>;
47
+ /**
48
+ * The call input.
49
+ */
50
+ readonly input?: Maybe<OpenRouterInput>;
51
+ /**
52
+ * Files to attach, as GCS object paths. Never signed urls.
53
+ */
54
+ readonly files?: Maybe<OpenRouterFileReference[]>;
55
+ /**
56
+ * Per-run config overrides.
57
+ */
58
+ readonly configOverrides?: Maybe<OpenRouterModelConfig>;
59
+ /**
60
+ * A prior run task to continue from — its history seeds this run's `msg`.
61
+ *
62
+ * This is what replaces `previous_response_id`, which OpenRouter rejects with a 400.
63
+ */
64
+ readonly continueFrom?: Maybe<OpenRouterRunTaskKey>;
65
+ /**
66
+ * Whether an existing document for this key is reset back to QUEUED.
67
+ *
68
+ * Defaults to false — the enqueue is IDEMPOTENT, so a re-entered checkpoint does not restart a run
69
+ * that is already in flight or already finished.
70
+ */
71
+ readonly restart?: Maybe<boolean>;
72
+ }
73
+ /**
74
+ * Result of enqueueing a run task.
75
+ */
76
+ export interface OpenRouterEnqueueRunTaskResult {
77
+ readonly key: OpenRouterRunTaskKey;
78
+ readonly document: OpenRouterRunTaskDocument;
79
+ /**
80
+ * Whether a new document was written. False when an existing run was reused.
81
+ */
82
+ readonly created: boolean;
83
+ readonly task: OpenRouterRunTask;
84
+ }
85
+ /**
86
+ * Params for claiming run tasks.
87
+ */
88
+ export interface OpenRouterClaimRunTasksParams {
89
+ /**
90
+ * Maximum number of tasks to claim.
91
+ */
92
+ readonly limit: number;
93
+ /**
94
+ * Identifier recorded as the lease owner.
95
+ */
96
+ readonly leaseOwner: string;
97
+ /**
98
+ * Lease duration. Defaults to {@link DEFAULT_OPENROUTER_LEASE_DURATION}.
99
+ */
100
+ readonly leaseDuration?: Maybe<Milliseconds>;
101
+ }
102
+ /**
103
+ * Params for deleting the run tasks past their retention age.
104
+ */
105
+ export interface OpenRouterDeleteExpiredRunTasksParams {
106
+ /**
107
+ * Maximum number of tasks to delete. Clamped to {@link OPENROUTER_MAX_EXPIRED_RUN_TASK_DELETE_PAGE_SIZE}.
108
+ */
109
+ readonly limit: number;
110
+ /**
111
+ * Tasks queued at or before this date are deleted. Defaults to `now - OPENROUTER_RUN_TASK_MAX_AGE`.
112
+ *
113
+ * A parameter rather than always-derived so a sweep can pin one cutoff across every page of a run, and
114
+ * so a test can assert against a fixed clock.
115
+ */
116
+ readonly before?: Maybe<Date>;
117
+ }
118
+ /**
119
+ * Result of one retention page.
120
+ */
121
+ export interface OpenRouterDeleteExpiredRunTasksResult {
122
+ readonly deleted: number;
123
+ /**
124
+ * The keys deleted — once the document is gone this is the only record the run existed.
125
+ */
126
+ readonly keys: OpenRouterRunTaskKey[];
127
+ }
128
+ /**
129
+ * Params for resolving a deferred tool call.
130
+ */
131
+ export interface OpenRouterResolveDeferredToolParams {
132
+ /**
133
+ * The run task holding the pending call.
134
+ */
135
+ readonly key: OpenRouterRunTaskKey;
136
+ /**
137
+ * The task id the pending call was registered under.
138
+ */
139
+ readonly taskId: string;
140
+ /**
141
+ * The successful output, when the task succeeded.
142
+ */
143
+ readonly output?: unknown;
144
+ /**
145
+ * The error, when it did not.
146
+ */
147
+ readonly error?: Maybe<string>;
148
+ }
149
+ /**
150
+ * Result of resolving a deferred tool call.
151
+ */
152
+ export interface OpenRouterResolveDeferredToolResult {
153
+ /**
154
+ * Whether a pending call matched and was resolved.
155
+ *
156
+ * False for a replayed or already-settled resolution. That is a no-op, not an error — resolutions
157
+ * arrive from outside this process and can be delivered more than once.
158
+ */
159
+ readonly resolved: boolean;
160
+ /**
161
+ * Whether every pending call is now resolved, so the run is ready to continue.
162
+ */
163
+ readonly ready: boolean;
164
+ }
165
+ /**
166
+ * Result of running one task.
167
+ */
168
+ export interface OpenRouterRunTaskExecutionResult {
169
+ readonly key: OpenRouterRunTaskKey;
170
+ readonly state: OpenRouterRunTaskState;
171
+ readonly result?: Maybe<OpenRouterCallResult>;
172
+ readonly error?: Maybe<unknown>;
173
+ }
174
+ /**
175
+ * Manages the app-owned run-task queue: the replacement for OpenAI's `background: true` plus its
176
+ * server-side job store, neither of which OpenRouter has.
177
+ */
178
+ export declare abstract class OpenRouterRunTaskService {
179
+ /**
180
+ * Writes one QUEUED document and returns. Nothing blocks on inference.
181
+ */
182
+ abstract enqueueRunTask(params: OpenRouterEnqueueRunTaskParams): Promise<OpenRouterEnqueueRunTaskResult>;
183
+ /**
184
+ * Reads a run task by key.
185
+ */
186
+ abstract readRunTask(key: OpenRouterRunTaskKey): Promise<Maybe<OpenRouterRunTask>>;
187
+ /**
188
+ * Loads a run task document by key.
189
+ */
190
+ abstract runTaskDocument(key: OpenRouterRunTaskKey): OpenRouterRunTaskDocument;
191
+ /**
192
+ * Claims up to `limit` runnable tasks by lease, transactionally.
193
+ *
194
+ * Claiming in a transaction is what makes two overlapping sweeps safe: only one can move a document
195
+ * out of QUEUED, so a task is never executed twice.
196
+ */
197
+ abstract claimNextRunTasks(params: OpenRouterClaimRunTasksParams): Promise<OpenRouterRunTaskDocument[]>;
198
+ /**
199
+ * Executes one already-claimed task and writes its result.
200
+ */
201
+ abstract executeRunTask(document: OpenRouterRunTaskDocument): Promise<OpenRouterRunTaskExecutionResult>;
202
+ /**
203
+ * Delivers a deferred tool result from another process.
204
+ */
205
+ abstract resolveDeferredTool(params: OpenRouterResolveDeferredToolParams): Promise<OpenRouterResolveDeferredToolResult>;
206
+ /**
207
+ * Deletes one page of run tasks older than {@link OPENROUTER_RUN_TASK_MAX_AGE}, in every state.
208
+ */
209
+ abstract deleteExpiredRunTasks(params: OpenRouterDeleteExpiredRunTasksParams): Promise<OpenRouterDeleteExpiredRunTasksResult>;
210
+ /**
211
+ * Resolves the files of a task into the attachments for one attempt. Exposed for tests, which is
212
+ * where the "does a retry get a NEW url" question actually gets answered.
213
+ */
214
+ abstract attachFilesForAttempt(files: Maybe<OpenRouterFileReference[]>): Promise<OpenRouterAttachedFileReference[]>;
215
+ }
216
+ /**
217
+ * Notified when a run task reaches a terminal state.
218
+ *
219
+ * This is the in-process replacement for OpenAI's completion webhook: because we hold the HTTP
220
+ * connection during inference, the runner already knows the moment a run finishes, so it can advance
221
+ * the owning work directly. No inbound round-trip, nothing to authenticate, and impossible to miss.
222
+ *
223
+ * A handler MUST NOT write to the run task document. It is still invoked with `FAILED` for a task the
224
+ * retention sweep deleted mid-flight — correctly, since the owning NotificationTask has to learn the run
225
+ * is not coming — and by then there is no document left to update.
226
+ */
227
+ export type OpenRouterRunTaskTerminalStateHandler = (document: OpenRouterRunTaskDocument, result: OpenRouterRunTaskExecutionResult) => Promise<void>;
228
+ /**
229
+ * Config for {@link openRouterRunTaskService}.
230
+ */
231
+ export interface OpenRouterRunTaskServiceConfig {
232
+ /**
233
+ * The run task collections.
234
+ */
235
+ readonly collections: OpenRouterRunTaskFirestoreCollections;
236
+ /**
237
+ * The prompt service used to resolve a run's prompt version.
238
+ */
239
+ readonly promptService: OpenRouterPromptService;
240
+ /**
241
+ * The OpenRouter client.
242
+ */
243
+ readonly client: OpenRouterCore;
244
+ /**
245
+ * Storage context used to read/sign the files of a task. Required only when tasks carry files.
246
+ */
247
+ readonly storageContext?: Maybe<FirebaseStorageContext>;
248
+ /**
249
+ * Environment service that selects how files are attached: a non-production environment attaches them inline.
250
+ *
251
+ * This is the whole gate. A signed url is unreachable from OpenRouter when the object lives in the
252
+ * Firebase storage emulator, so an emulator run has to carry the bytes — and an app should not have
253
+ * to remember to say so twice.
254
+ */
255
+ readonly envService?: Maybe<FirebaseServerEnvService>;
256
+ /**
257
+ * Explicit file attachment mode, overriding whatever `envService` would select.
258
+ */
259
+ readonly fileAttachmentMode?: Maybe<OpenRouterFileAttachmentMode>;
260
+ /**
261
+ * Inline size cap. Defaults to {@link DEFAULT_OPENROUTER_MAX_INLINE_FILE_SIZE_BYTES}.
262
+ */
263
+ readonly maxInlineFileSizeBytes?: Maybe<number>;
264
+ /**
265
+ * Client-side tools available to every run. Manual (`execute: false`) tools here are what produce a
266
+ * deferred pause.
267
+ */
268
+ readonly tools?: Maybe<readonly Tool[]>;
269
+ /**
270
+ * Called when a run reaches a terminal state.
271
+ */
272
+ readonly onTerminalState?: Maybe<OpenRouterRunTaskTerminalStateHandler>;
273
+ /**
274
+ * Signed-url lifetime. Defaults to {@link DEFAULT_OPENROUTER_SIGNED_URL_TTL}.
275
+ */
276
+ readonly signedUrlTtl?: Maybe<Milliseconds>;
277
+ /**
278
+ * Attempts a RETRYABLE failure may spend before a task is FAILED. Defaults to
279
+ * {@link DEFAULT_OPENROUTER_MAX_ATTEMPTS}.
280
+ */
281
+ readonly maxAttempts?: Maybe<number>;
282
+ /**
283
+ * Default lease duration. Defaults to {@link DEFAULT_OPENROUTER_LEASE_DURATION}.
284
+ */
285
+ readonly leaseDuration?: Maybe<Milliseconds>;
286
+ }
287
+ /**
288
+ * Creates an {@link OpenRouterRunTaskService}.
289
+ *
290
+ * @param config - The collections, prompt service, client, and execution settings.
291
+ * @returns The service.
292
+ */
293
+ export declare function openRouterRunTaskService(config: OpenRouterRunTaskServiceConfig): OpenRouterRunTaskService;
294
+ /**
295
+ * Whether a task may be claimed by a sweep running at the given lease cutoff.
296
+ *
297
+ * A `RUNNING` task is claimable exactly when its lease has gone stale — that is crash recovery, and it
298
+ * generalises the ad-hoc "unstick anything processing for over an hour" logic it replaces.
299
+ *
300
+ * @param task - The task to check.
301
+ * @param leaseCutoff - Leases taken at or before this date are stale.
302
+ * @returns True when the task may be claimed.
303
+ *
304
+ * @__NO_SIDE_EFFECTS__
305
+ */
306
+ export declare function isOpenRouterRunTaskClaimable(task: OpenRouterRunTask, leaseCutoff: Date): boolean;
307
+ /**
308
+ * Whether any pending deferred tool call is still missing its recorded result.
309
+ *
310
+ * The one predicate behind "is this run ready to resume": the claim check, the resolution's `ready` flag,
311
+ * and the conversation append all ask it, and three hand-written copies had already drifted apart.
312
+ *
313
+ * @param pending - The pending deferred tool calls.
314
+ * @param unsent - The recorded-but-unsent tool results.
315
+ * @returns True when at least one pending call has no recorded result.
316
+ *
317
+ * @__NO_SIDE_EFFECTS__
318
+ */
319
+ export declare function hasUnresolvedOpenRouterPendingToolCalls(pending: Maybe<readonly OpenRouterRunTaskPendingToolCall[]>, unsent: Maybe<readonly OpenRouterRunTaskUnsentToolResult[]>): boolean;
320
+ /**
321
+ * Extracts an error code from a thrown value.
322
+ *
323
+ * @param e - The thrown value.
324
+ * @returns The code, when one is discernible.
325
+ *
326
+ * @__NO_SIDE_EFFECTS__
327
+ */
328
+ export declare function openRouterErrorCode(e: unknown): Maybe<string>;
329
+ /**
330
+ * Extracts an error message from a thrown value.
331
+ *
332
+ * @param e - The thrown value.
333
+ * @returns The message.
334
+ *
335
+ * @__NO_SIDE_EFFECTS__
336
+ */
337
+ export declare function openRouterErrorMessage(e: unknown): string;
338
+ /**
339
+ * HTTP statuses a retry cannot fix.
340
+ *
341
+ * 400 is a malformed request (an invalid model id, a JSON schema the provider rejects), 401/403 are a
342
+ * credential problem, 402 is an empty account, and 404 is a route or resource that does not exist. Each of
343
+ * them answers identically on every attempt, so spending the budget on them only delays the FAILED that
344
+ * the owning work is waiting for.
345
+ */
346
+ export declare const OPENROUTER_PERMANENT_ERROR_STATUSES: readonly number[];
347
+ /**
348
+ * Whether a failure is worth another attempt.
349
+ *
350
+ * What this encodes is a whitelist of the KNOWN-PERMANENT, not a whitelist of the retryable: anything
351
+ * unrecognized defaults to RETRYABLE. An unknown failure is far more likely to be a transient upstream blip
352
+ * than a permanent one, and the attempt budget bounds the cost of being wrong either way — whereas
353
+ * defaulting the other way would turn one bad minute at a provider into a definitively failed run.
354
+ *
355
+ * So the retryable side needs no list of its own. 408 / 409 / 429 and every 5xx, socket-level failures
356
+ * (`ECONNRESET`, `ETIMEDOUT`, `ECONNREFUSED`, `EAI_AGAIN`), and the Google-infrastructure transients
357
+ * (`UNAVAILABLE`, `DEADLINE_EXCEEDED`, `ABORTED`) a Firestore or GCS call raises mid-run all reach the
358
+ * default and are retried.
359
+ *
360
+ * Permanent is two cases. {@link OPENROUTER_PERMANENT_ERROR_STATUSES}, read off `status` / `statusCode` /
361
+ * `code` — which covers both routes into `recordFailure`: a thrown SDK/HTTP error, and the numeric
362
+ * `error.code` OpenRouter reports in a response body without throwing at all. And an
363
+ * {@link OpenRouterPromptResolutionError}, which is deterministic by construction: the prompt either exists
364
+ * at that version or it never will, so re-resolving it is guaranteed to fail identically.
365
+ *
366
+ * @param e - The thrown value, or the error reported on a response.
367
+ * @returns True when another attempt could plausibly succeed.
368
+ *
369
+ * @__NO_SIDE_EFFECTS__
370
+ */
371
+ export declare function isRetryableOpenRouterError(e: unknown): boolean;
372
+ /**
373
+ * The deferred-tool resolutions recorded on a task, in the form the core package's resolver consumes.
374
+ *
375
+ * @param task - The run task.
376
+ * @returns The resolutions.
377
+ *
378
+ * @__NO_SIDE_EFFECTS__
379
+ */
380
+ export declare function openRouterDeferredToolResolutionsForRunTask(task: OpenRouterRunTask): OpenRouterDeferredToolResolution[];
@@ -0,0 +1,170 @@
1
+ import { type Maybe, type Milliseconds } from '@dereekb/util';
2
+ import { type OpenRouterRunTaskExecutionResult, type OpenRouterRunTaskService } from './openrouter.runtask.service';
3
+ /**
4
+ * Default number of tasks executed concurrently by one sweep.
5
+ */
6
+ export declare const DEFAULT_OPENROUTER_SWEEP_MAX_PARALLEL_TASKS = 10;
7
+ /**
8
+ * Default wall-clock budget for one sweep.
9
+ */
10
+ export declare const DEFAULT_OPENROUTER_SWEEP_MAX_RUN_TIME: Milliseconds;
11
+ /**
12
+ * Default number of tasks claimed per page.
13
+ */
14
+ export declare const DEFAULT_OPENROUTER_SWEEP_PAGE_SIZE = 20;
15
+ /**
16
+ * Default number of expired tasks deleted per retention page.
17
+ *
18
+ * Well under the 500-write batch ceiling: retention runs on its own far slower schedule, so there is
19
+ * nothing to gain from maximising a single page.
20
+ */
21
+ export declare const DEFAULT_OPENROUTER_EXPIRATION_SWEEP_PAGE_SIZE = 200;
22
+ /**
23
+ * Default wall-clock budget for one retention sweep.
24
+ */
25
+ export declare const DEFAULT_OPENROUTER_EXPIRATION_SWEEP_MAX_RUN_TIME: Milliseconds;
26
+ /**
27
+ * Params for {@link openRouterRunTaskSweep}.
28
+ */
29
+ export interface OpenRouterRunTaskSweepParams {
30
+ /**
31
+ * The run task service to drain.
32
+ */
33
+ readonly service: OpenRouterRunTaskService;
34
+ /**
35
+ * How many tasks run concurrently. Defaults to {@link DEFAULT_OPENROUTER_SWEEP_MAX_PARALLEL_TASKS}.
36
+ *
37
+ * Throughput comes from here, not from a longer wall clock — which is what lets the sweep share a
38
+ * runner with other workloads.
39
+ */
40
+ readonly maxParallelTasks?: Maybe<number>;
41
+ /**
42
+ * Hard wall-clock budget. Defaults to {@link DEFAULT_OPENROUTER_SWEEP_MAX_RUN_TIME}.
43
+ *
44
+ * The sweep stops CLAIMING new pages once this is spent and returns; whatever is left stays QUEUED for
45
+ * the next tick. This is a requirement rather than a tuning knob when the sweep shares a scheduled
46
+ * runner with other work: without it, a deep queue starves every workload behind it.
47
+ *
48
+ * It bounds when a new page is claimed, NOT one inference — a single call is atomic and cannot be
49
+ * interrupted, so an unusually slow one can overrun. Bound that with `requestTimeoutMs` in the prompt
50
+ * config and keep this well inside the runner's remaining share.
51
+ */
52
+ readonly maxRunTimeMs?: Maybe<Milliseconds>;
53
+ /**
54
+ * Tasks claimed per page. Defaults to {@link DEFAULT_OPENROUTER_SWEEP_PAGE_SIZE}.
55
+ */
56
+ readonly pageSize?: Maybe<number>;
57
+ /**
58
+ * Identifier recorded as the lease owner. Defaults to a generated one.
59
+ */
60
+ readonly leaseOwner?: Maybe<string>;
61
+ /**
62
+ * Lease duration override.
63
+ */
64
+ readonly leaseDuration?: Maybe<Milliseconds>;
65
+ /**
66
+ * Maximum number of pages to claim in one sweep. Defaults to unlimited (bounded by the time budget).
67
+ */
68
+ readonly maxPages?: Maybe<number>;
69
+ }
70
+ /**
71
+ * Outcome of one sweep.
72
+ */
73
+ export interface OpenRouterRunTaskSweepResult {
74
+ /**
75
+ * Number of tasks claimed and executed.
76
+ */
77
+ readonly executed: number;
78
+ /**
79
+ * How many reached each terminal or paused state.
80
+ */
81
+ readonly completed: number;
82
+ readonly failed: number;
83
+ readonly requeued: number;
84
+ readonly awaitingAsyncTools: number;
85
+ /**
86
+ * Number of pages claimed.
87
+ */
88
+ readonly pages: number;
89
+ /**
90
+ * Whether the sweep stopped because its time budget ran out rather than because the queue was empty.
91
+ *
92
+ * The signal that the queue is deeper than one tick can drain.
93
+ */
94
+ readonly stoppedForTimeBudget: boolean;
95
+ /**
96
+ * Elapsed wall-clock time.
97
+ */
98
+ readonly durationMs: Milliseconds;
99
+ /**
100
+ * The per-task results, in completion order.
101
+ */
102
+ readonly results: OpenRouterRunTaskExecutionResult[];
103
+ }
104
+ /**
105
+ * Drains the run-task queue within a strict time budget.
106
+ *
107
+ * Claim a page by lease, run `maxParallelTasks` at a time, write results, repeat — until the queue is
108
+ * empty or the budget is spent. Mount it on a schedule the app already runs; it does not need one of its
109
+ * own, and it must not assume it is the only tenant of the one it gets.
110
+ *
111
+ * @param params - The service and budget settings.
112
+ * @returns What the sweep did.
113
+ */
114
+ export declare function openRouterRunTaskSweep(params: OpenRouterRunTaskSweepParams): Promise<OpenRouterRunTaskSweepResult>;
115
+ /**
116
+ * Params for {@link openRouterRunTaskExpirationSweep}.
117
+ */
118
+ export interface OpenRouterRunTaskExpirationSweepParams {
119
+ /**
120
+ * The run task service to delete through.
121
+ */
122
+ readonly service: OpenRouterRunTaskService;
123
+ /**
124
+ * Tasks queued at or before this date are deleted. Defaults to `now - OPENROUTER_RUN_TASK_MAX_AGE`.
125
+ */
126
+ readonly before?: Maybe<Date>;
127
+ /**
128
+ * Tasks deleted per page. Defaults to {@link DEFAULT_OPENROUTER_EXPIRATION_SWEEP_PAGE_SIZE}.
129
+ */
130
+ readonly pageSize?: Maybe<number>;
131
+ /**
132
+ * Hard wall-clock budget. Defaults to {@link DEFAULT_OPENROUTER_EXPIRATION_SWEEP_MAX_RUN_TIME}.
133
+ */
134
+ readonly maxRunTimeMs?: Maybe<Milliseconds>;
135
+ /**
136
+ * Maximum number of pages to delete in one sweep. Defaults to unlimited (bounded by the time budget).
137
+ */
138
+ readonly maxPages?: Maybe<number>;
139
+ }
140
+ /**
141
+ * Outcome of one retention sweep.
142
+ */
143
+ export interface OpenRouterRunTaskExpirationSweepResult {
144
+ /**
145
+ * Number of tasks deleted.
146
+ */
147
+ readonly deleted: number;
148
+ /**
149
+ * Number of pages deleted.
150
+ */
151
+ readonly pages: number;
152
+ /**
153
+ * Whether the sweep stopped because its time budget ran out rather than because nothing was left.
154
+ */
155
+ readonly stoppedForTimeBudget: boolean;
156
+ /**
157
+ * Elapsed wall-clock time.
158
+ */
159
+ readonly durationMs: Milliseconds;
160
+ }
161
+ /**
162
+ * Deletes every run task past its retention age, within a strict time budget.
163
+ *
164
+ * A SEPARATE sweep from {@link openRouterRunTaskSweep}, on a far slower schedule: the drain tick runs every
165
+ * minute and there is nothing a week-old document gains from being looked at that often.
166
+ *
167
+ * @param params - The service and budget settings.
168
+ * @returns What the sweep deleted.
169
+ */
170
+ export declare function openRouterRunTaskExpirationSweep(params: OpenRouterRunTaskExpirationSweepParams): Promise<OpenRouterRunTaskExpirationSweepResult>;