octaflow 0.17.2 → 0.18.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.
- package/README.md +6 -4
- package/dist/ai/index.d.ts +198 -49
- package/dist/ai/index.js +196 -10
- package/dist/ai/providers/index.d.ts +69 -0
- package/dist/ai/providers/index.js +106 -0
- package/dist/dispatcher-pgboss/index.d.ts +26 -27
- package/dist/index.d.ts +14 -14
- package/dist/provider-registry-DhNXw_CC.js +224 -0
- package/dist/provider-registry-bXGOmyeh.d.ts +81 -0
- package/dist/store-pg/index.d.ts +27 -28
- package/package.json +31 -22
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# octaflow
|
|
2
2
|
|
|
3
|
-
[](https://github.com/octabits-io/octabits/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/octaflow)
|
|
5
5
|
[](https://octaflow.octabits.io/)
|
|
6
6
|
[](./LICENSE)
|
|
@@ -299,6 +299,8 @@ enforces, and the correctness requirements a custom `WorkflowStore` has to meet.
|
|
|
299
299
|
|
|
300
300
|
## Status
|
|
301
301
|
|
|
302
|
-
Pre-1.0 — developed in [octabits
|
|
303
|
-
[
|
|
304
|
-
|
|
302
|
+
Pre-1.0 — developed in the [octabits platform monorepo](https://github.com/octabits-io/octabits)
|
|
303
|
+
under [`packages/octaflow`](https://github.com/octabits-io/octabits/tree/main/packages/octaflow)
|
|
304
|
+
(a standalone repository from 2026-07-14 to 2026-09-06; that history is merged in).
|
|
305
|
+
Independently versioned and published as the unscoped `octaflow`. The API is stable but may
|
|
306
|
+
still see breaking changes in 0.x minors.
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { E as RetryPolicy, g as TypedWorkflow, h as TypedStepContext, m as TypedStep, nt as Result, tt as FlowErrorShape } from "../index-BURAYZui.js";
|
|
2
2
|
import { n as Logger } from "../logger-BCus3AOa.js";
|
|
3
3
|
import { i as BuildStepContextArgs, o as WorkflowHooks } from "../hooks-BdxIcc92.js";
|
|
4
|
+
import { a as AiProviderMeta, c as DEFAULT_AI_PROVIDER, d as EMBEDDING_PROVIDER_IDS, f as EmbeddingProviderId, i as AiProviderId, l as DEFAULT_EMBEDDING_PROVIDER, m as embeddingDimensionsFor, n as AI_PROVIDER_IDS, o as AiProviderModelOption, p as EmbeddingProviderMeta, r as AiProcessingRegion, s as AiVendorResidency, t as AI_PROVIDERS, u as EMBEDDING_PROVIDERS } from "../provider-registry-bXGOmyeh.js";
|
|
4
5
|
import { z } from "zod";
|
|
5
|
-
import { EmbeddingModelV4, LanguageModelV4 } from "@ai-sdk/provider";
|
|
6
|
+
import { EmbeddingModelV4, LanguageModelV4, SharedV4ProviderMetadata } from "@ai-sdk/provider";
|
|
6
7
|
//#region src/ai/instrumented-model.d.ts
|
|
7
|
-
interface AccumulatedUsage {
|
|
8
|
+
export interface AccumulatedUsage {
|
|
8
9
|
inputTokens: number;
|
|
9
10
|
outputTokens: number;
|
|
10
11
|
cacheReadTokens: number;
|
|
11
12
|
cacheWriteTokens: number;
|
|
12
13
|
modelId: string;
|
|
13
14
|
}
|
|
14
|
-
interface UsageAccumulator {
|
|
15
|
+
export interface UsageAccumulator {
|
|
15
16
|
/** Record usage from a single LLM call (additive — supports multiple calls per step). */
|
|
16
17
|
record(usage: AccumulatedUsage): void;
|
|
17
18
|
/** Total accumulated usage across all calls. */
|
|
@@ -19,20 +20,20 @@ interface UsageAccumulator {
|
|
|
19
20
|
/** Whether any usage was recorded. */
|
|
20
21
|
hasUsage(): boolean;
|
|
21
22
|
}
|
|
22
|
-
declare function createUsageAccumulator(): UsageAccumulator;
|
|
23
|
+
export declare function createUsageAccumulator(): UsageAccumulator;
|
|
23
24
|
/**
|
|
24
25
|
* Wrap a language model with usage-tracking middleware. The accumulator collects
|
|
25
26
|
* token usage from every doGenerate/doStream call routed through the wrapped model.
|
|
26
27
|
*/
|
|
27
|
-
declare function createInstrumentedModel(model: LanguageModelV4, accumulator: UsageAccumulator): LanguageModelV4;
|
|
28
|
+
export declare function createInstrumentedModel(model: LanguageModelV4, accumulator: UsageAccumulator): LanguageModelV4;
|
|
28
29
|
//#endregion
|
|
29
30
|
//#region src/ai/instrumented-embedding-model.d.ts
|
|
30
|
-
interface EmbeddingAccumulatedUsage {
|
|
31
|
+
export interface EmbeddingAccumulatedUsage {
|
|
31
32
|
inputTokens: number;
|
|
32
33
|
callCount: number;
|
|
33
34
|
modelId: string;
|
|
34
35
|
}
|
|
35
|
-
interface EmbeddingUsageAccumulator {
|
|
36
|
+
export interface EmbeddingUsageAccumulator {
|
|
36
37
|
/** Record usage from a single doEmbed call (additive — supports multiple calls per batch). */
|
|
37
38
|
record(tokens: number, modelId: string): void;
|
|
38
39
|
/** Total accumulated usage across all calls. */
|
|
@@ -42,14 +43,14 @@ interface EmbeddingUsageAccumulator {
|
|
|
42
43
|
/** Clear all accumulated state — used when a long-lived accumulator is reused across flushes. */
|
|
43
44
|
reset(): void;
|
|
44
45
|
}
|
|
45
|
-
declare function createEmbeddingUsageAccumulator(): EmbeddingUsageAccumulator;
|
|
46
|
+
export declare function createEmbeddingUsageAccumulator(): EmbeddingUsageAccumulator;
|
|
46
47
|
/**
|
|
47
48
|
* Wrap an embedding model with usage-tracking middleware. The accumulator collects
|
|
48
49
|
* token usage from every doEmbed call routed through the wrapped model — both
|
|
49
50
|
* `embed()` (single value) and `embedMany()` (batched values) invoke doEmbed one or
|
|
50
51
|
* more times, and each invocation is recorded.
|
|
51
52
|
*/
|
|
52
|
-
declare function createInstrumentedEmbeddingModel(model: EmbeddingModelV4, accumulator: EmbeddingUsageAccumulator): EmbeddingModelV4;
|
|
53
|
+
export declare function createInstrumentedEmbeddingModel(model: EmbeddingModelV4, accumulator: EmbeddingUsageAccumulator): EmbeddingModelV4;
|
|
53
54
|
//#endregion
|
|
54
55
|
//#region src/ai/cost.d.ts
|
|
55
56
|
/**
|
|
@@ -59,31 +60,39 @@ declare function createInstrumentedEmbeddingModel(model: EmbeddingModelV4, accum
|
|
|
59
60
|
* The pricing table is injectable: pass your own to `createCostEstimator` for a
|
|
60
61
|
* different provider/model set. A default Anthropic/OpenAI-embedding table ships.
|
|
61
62
|
*/
|
|
62
|
-
interface ModelPricing {
|
|
63
|
+
export interface ModelPricing {
|
|
63
64
|
inputPerMillion: number;
|
|
64
65
|
outputPerMillion: number;
|
|
65
66
|
cacheReadPerMillion: number;
|
|
66
67
|
cacheWritePerMillion: number;
|
|
67
68
|
}
|
|
68
|
-
interface TokenUsage {
|
|
69
|
+
export interface TokenUsage {
|
|
69
70
|
inputTokens: number;
|
|
70
71
|
outputTokens: number;
|
|
71
72
|
cacheReadTokens: number;
|
|
72
73
|
cacheWriteTokens: number;
|
|
73
74
|
}
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Default pricing, USD per million tokens — Anthropic as of 2026-09, Mistral and
|
|
77
|
+
* the OpenAI embeddings as of 2026-08. A best-effort estimate, not a billing
|
|
78
|
+
* record: a BYOK caller can name any model id, and an unknown id prices at the
|
|
79
|
+
* priciest row (safe overcounting — see {@link createCostEstimator}). Retired ids
|
|
80
|
+
* are kept rather than deleted: dropping one silently reprices every historical
|
|
81
|
+
* usage row at the fallback rate. Only the Mistral `-latest` aliases are listed;
|
|
82
|
+
* pinned ids (`mistral-medium-2508`) fall to the fallback.
|
|
83
|
+
*/
|
|
84
|
+
export declare const DEFAULT_MODEL_PRICING: Record<string, ModelPricing>;
|
|
85
|
+
export interface CostEstimatorOptions {
|
|
77
86
|
/** Pricing table keyed by model id. Defaults to `DEFAULT_MODEL_PRICING`. */
|
|
78
87
|
pricing?: Record<string, ModelPricing>;
|
|
79
88
|
/** Pricing used for unknown model ids. Defaults to the priciest entry in the table (safe overcounting). */
|
|
80
89
|
fallback?: ModelPricing;
|
|
81
90
|
}
|
|
82
|
-
type CostEstimator = (usage: TokenUsage, modelId: string) => number;
|
|
91
|
+
export type CostEstimator = (usage: TokenUsage, modelId: string) => number;
|
|
83
92
|
/** Build a cost estimator returning microdollars. */
|
|
84
|
-
declare function createCostEstimator(options?: CostEstimatorOptions): CostEstimator;
|
|
93
|
+
export declare function createCostEstimator(options?: CostEstimatorOptions): CostEstimator;
|
|
85
94
|
/** Convenience estimator using the default pricing table. */
|
|
86
|
-
declare const estimateCostMicros: CostEstimator;
|
|
95
|
+
export declare const estimateCostMicros: CostEstimator;
|
|
87
96
|
//#endregion
|
|
88
97
|
//#region src/ai/context.d.ts
|
|
89
98
|
/**
|
|
@@ -91,7 +100,7 @@ declare const estimateCostMicros: CostEstimator;
|
|
|
91
100
|
* `buildStepContext` hook in `createAiWorkflowHooks` and consumed by AI step
|
|
92
101
|
* handlers (which read `ctx.context.model` / `ctx.context.host`).
|
|
93
102
|
*/
|
|
94
|
-
interface AiContext<THost = unknown> {
|
|
103
|
+
export interface AiContext<THost = unknown> {
|
|
95
104
|
/** Instrumented language model — token usage is captured automatically. */
|
|
96
105
|
model: LanguageModelV4;
|
|
97
106
|
/** Host-provided per-step context (DI scope, domain services, …). */
|
|
@@ -105,7 +114,7 @@ interface AiContext<THost = unknown> {
|
|
|
105
114
|
//#endregion
|
|
106
115
|
//#region src/ai/define-ai-step.d.ts
|
|
107
116
|
/** An AI workflow step — a flow-core `TypedStep` whose context is an `AiContext`. */
|
|
108
|
-
type AiTypedStep<TInput extends Record<string, unknown> = Record<string, unknown>, TOutput extends Record<string, unknown> = Record<string, unknown>, THost = unknown, TDeps extends Record<string, TypedStep<any, any, any, AiContext<THost>>> = {}> = TypedStep<TInput, TOutput, TDeps, AiContext<THost>>;
|
|
117
|
+
export type AiTypedStep<TInput extends Record<string, unknown> = Record<string, unknown>, TOutput extends Record<string, unknown> = Record<string, unknown>, THost = unknown, TDeps extends Record<string, TypedStep<any, any, any, AiContext<THost>>> = {}> = TypedStep<TInput, TOutput, TDeps, AiContext<THost>>;
|
|
109
118
|
interface DefineAiStepConfig<TInput extends Record<string, unknown>, TOutput extends Record<string, unknown>, THost, TDeps extends Record<string, TypedStep<any, any, any, AiContext<THost>>>> {
|
|
110
119
|
type: string;
|
|
111
120
|
workflowInputSchema: z.ZodType<TInput>;
|
|
@@ -124,16 +133,16 @@ interface DefineAiStepConfig<TInput extends Record<string, unknown>, TOutput ext
|
|
|
124
133
|
* except the handler context is fixed to `AiContext<THost>`, so handlers get a
|
|
125
134
|
* ready-to-use `ctx.context.model` (instrumented) and `ctx.context.host`.
|
|
126
135
|
*/
|
|
127
|
-
declare function defineAiStep<TInput extends Record<string, unknown>, TOutput extends Record<string, unknown>, THost = unknown, TDeps extends Record<string, TypedStep<any, any, any, AiContext<THost>>> = {}>(config: DefineAiStepConfig<TInput, TOutput, THost, TDeps>): AiTypedStep<TInput, TOutput, THost, TDeps>;
|
|
136
|
+
export declare function defineAiStep<TInput extends Record<string, unknown>, TOutput extends Record<string, unknown>, THost = unknown, TDeps extends Record<string, TypedStep<any, any, any, AiContext<THost>>> = {}>(config: DefineAiStepConfig<TInput, TOutput, THost, TDeps>): AiTypedStep<TInput, TOutput, THost, TDeps>;
|
|
128
137
|
/** Build a typed AI workflow from `defineAiStep` definitions. */
|
|
129
|
-
declare function buildAiWorkflow<TInput extends Record<string, unknown>, THost = unknown, TSteps extends Record<string, TypedStep<any, any, any, AiContext<THost>>> = {}>(config: {
|
|
138
|
+
export declare function buildAiWorkflow<TInput extends Record<string, unknown>, THost = unknown, TSteps extends Record<string, TypedStep<any, any, any, AiContext<THost>>> = {}>(config: {
|
|
130
139
|
type: string;
|
|
131
140
|
inputSchema: z.ZodType<TInput>;
|
|
132
141
|
steps: TSteps;
|
|
133
142
|
}): TypedWorkflow<TInput, AiContext<THost>>;
|
|
134
143
|
//#endregion
|
|
135
144
|
//#region src/ai/hooks.d.ts
|
|
136
|
-
interface AiModelResolver<THost = unknown> {
|
|
145
|
+
export interface AiModelResolver<THost = unknown> {
|
|
137
146
|
/** Resolve the base (uninstrumented) model for a step. */
|
|
138
147
|
resolveModel(args: BuildStepContextArgs): Promise<LanguageModelV4> | LanguageModelV4;
|
|
139
148
|
/** Optional host context (DI scope, services) exposed to handlers as `ctx.context.host`. */
|
|
@@ -145,7 +154,7 @@ interface AiModelResolver<THost = unknown> {
|
|
|
145
154
|
*/
|
|
146
155
|
resolveKeySource?(): Promise<string> | string;
|
|
147
156
|
}
|
|
148
|
-
interface AiUsageRecorder {
|
|
157
|
+
export interface AiUsageRecorder {
|
|
149
158
|
/** Persist per-step token usage + cost (e.g. onto the step row). */
|
|
150
159
|
recordStepUsage(args: {
|
|
151
160
|
workflowId: number;
|
|
@@ -170,11 +179,11 @@ interface AiUsageRecorder {
|
|
|
170
179
|
date: string;
|
|
171
180
|
}): Promise<void>;
|
|
172
181
|
}
|
|
173
|
-
interface AiQuotaPolicy {
|
|
182
|
+
export interface AiQuotaPolicy {
|
|
174
183
|
/** Return an error (e.g. `ai_quota_exceeded`) to reject a workflow start. */
|
|
175
184
|
checkQuota(): Promise<Result<void, FlowErrorShape>>;
|
|
176
185
|
}
|
|
177
|
-
interface CreateAiWorkflowHooksDeps<THost = unknown> {
|
|
186
|
+
export interface CreateAiWorkflowHooksDeps<THost = unknown> {
|
|
178
187
|
modelResolver: AiModelResolver<THost>;
|
|
179
188
|
usageRecorder: AiUsageRecorder;
|
|
180
189
|
/** Optional quota guard. BYOK exemption etc. is the policy's concern. */
|
|
@@ -189,7 +198,7 @@ interface CreateAiWorkflowHooksDeps<THost = unknown> {
|
|
|
189
198
|
* usage rollups) into a set of flow-core lifecycle hooks. Pass the result as the
|
|
190
199
|
* engine's `hooks`. flow-core stays AI-free; everything AI lives here.
|
|
191
200
|
*/
|
|
192
|
-
declare function createAiWorkflowHooks<THost = unknown>(deps: CreateAiWorkflowHooksDeps<THost>): WorkflowHooks<AiContext<THost>>;
|
|
201
|
+
export declare function createAiWorkflowHooks<THost = unknown>(deps: CreateAiWorkflowHooksDeps<THost>): WorkflowHooks<AiContext<THost>>;
|
|
193
202
|
//#endregion
|
|
194
203
|
//#region src/ai/quota.d.ts
|
|
195
204
|
/**
|
|
@@ -198,7 +207,7 @@ declare function createAiWorkflowHooks<THost = unknown>(deps: CreateAiWorkflowHo
|
|
|
198
207
|
* return `null` for the whole config to exempt a scope entirely (e.g. a
|
|
199
208
|
* bring-your-own-key caller that shouldn't be metered against platform quota).
|
|
200
209
|
*/
|
|
201
|
-
interface AiQuotaConfig {
|
|
210
|
+
export interface AiQuotaConfig {
|
|
202
211
|
/** Max simultaneously-running workflows. `null` = unlimited. */
|
|
203
212
|
maxConcurrentWorkflows: number | null;
|
|
204
213
|
/** Max workflows started per calendar day (UTC). `null` = unlimited. */
|
|
@@ -211,14 +220,14 @@ interface AiQuotaConfig {
|
|
|
211
220
|
* flow does **not** apply these automatically — resolution policy lives in the
|
|
212
221
|
* injected {@link AiQuotaConfigResolver}.
|
|
213
222
|
*/
|
|
214
|
-
declare const DEFAULT_AI_QUOTA: AiQuotaConfig;
|
|
223
|
+
export declare const DEFAULT_AI_QUOTA: AiQuotaConfig;
|
|
215
224
|
/**
|
|
216
225
|
* Resolves the quota limits for a scope. Returning `null` exempts the scope
|
|
217
226
|
* from all quota enforcement (the check short-circuits to success).
|
|
218
227
|
*/
|
|
219
|
-
type AiQuotaConfigResolver = (partitionKey: string) => AiQuotaConfig | null | Promise<AiQuotaConfig | null>;
|
|
228
|
+
export type AiQuotaConfigResolver = (partitionKey: string) => AiQuotaConfig | null | Promise<AiQuotaConfig | null>;
|
|
220
229
|
/** A `[startDate, endDate]` inclusive query over the daily-usage rollup (dates are `YYYY-MM-DD`). */
|
|
221
|
-
interface AiUsageCountQuery {
|
|
230
|
+
export interface AiUsageCountQuery {
|
|
222
231
|
partitionKey: string;
|
|
223
232
|
/** Inclusive lower bound, `YYYY-MM-DD`. */
|
|
224
233
|
startDate: string;
|
|
@@ -232,16 +241,16 @@ interface AiUsageCountQuery {
|
|
|
232
241
|
* (e.g. excluding synthetic embedding rows from the count) lives in the
|
|
233
242
|
* consumer's SQL, keeping this layer policy-agnostic.
|
|
234
243
|
*/
|
|
235
|
-
interface AiQuotaStore {
|
|
244
|
+
export interface AiQuotaStore {
|
|
236
245
|
/** Number of workflows currently `running` for the scope. */
|
|
237
246
|
countRunningWorkflows(partitionKey: string): Promise<number>;
|
|
238
247
|
/** Sum of `workflowCount` in the daily rollup over the inclusive date range. */
|
|
239
248
|
sumWorkflowCount(query: AiUsageCountQuery): Promise<number>;
|
|
240
249
|
}
|
|
241
250
|
/** Reason a start was rejected — which window tripped. */
|
|
242
|
-
type AiQuotaExceededReason = 'concurrent_limit' | 'daily_limit' | 'monthly_limit';
|
|
251
|
+
export type AiQuotaExceededReason = 'concurrent_limit' | 'daily_limit' | 'monthly_limit';
|
|
243
252
|
/** Expected error value when a start is rejected by quota. Extends flow's structural error. */
|
|
244
|
-
interface AiQuotaExceededError {
|
|
253
|
+
export interface AiQuotaExceededError {
|
|
245
254
|
key: 'ai_quota_exceeded';
|
|
246
255
|
reason: AiQuotaExceededReason;
|
|
247
256
|
message: string;
|
|
@@ -250,7 +259,7 @@ interface AiQuotaExceededError {
|
|
|
250
259
|
/** The observed count at rejection (includes in-flight runs for the day/month windows). */
|
|
251
260
|
current: number;
|
|
252
261
|
}
|
|
253
|
-
interface CreateAiQuotaServiceDeps {
|
|
262
|
+
export interface CreateAiQuotaServiceDeps {
|
|
254
263
|
/** Count reads over the in-flight workflow table + daily rollup. */
|
|
255
264
|
store: AiQuotaStore;
|
|
256
265
|
/** Per-scope limit resolver. Return `null` to exempt the scope. */
|
|
@@ -258,7 +267,7 @@ interface CreateAiQuotaServiceDeps {
|
|
|
258
267
|
/** Clock injection for window computation (tests). Defaults to `() => new Date()`. */
|
|
259
268
|
now?: () => Date;
|
|
260
269
|
}
|
|
261
|
-
interface AiQuotaService {
|
|
270
|
+
export interface AiQuotaService {
|
|
262
271
|
/**
|
|
263
272
|
* Check all quota windows for the scope. Resolves `ok` when the start is
|
|
264
273
|
* allowed, or an {@link AiQuotaExceededError} naming the window that tripped.
|
|
@@ -271,11 +280,11 @@ interface AiQuotaService {
|
|
|
271
280
|
* Build a store-agnostic AI quota service. Enforcement order is concurrent →
|
|
272
281
|
* day → month; the first tripped window short-circuits with its error.
|
|
273
282
|
*/
|
|
274
|
-
declare function createAiQuotaService(deps: CreateAiQuotaServiceDeps): AiQuotaService;
|
|
283
|
+
export declare function createAiQuotaService(deps: CreateAiQuotaServiceDeps): AiQuotaService;
|
|
275
284
|
//#endregion
|
|
276
285
|
//#region src/ai/usage-aggregation.d.ts
|
|
277
286
|
/** An additive write into the daily-usage rollup for one run (workflow completion or embedding batch). */
|
|
278
|
-
interface DailyUsageDelta {
|
|
287
|
+
export interface DailyUsageDelta {
|
|
279
288
|
partitionKey: string;
|
|
280
289
|
/** Calendar day of the run, `YYYY-MM-DD`. */
|
|
281
290
|
date: string;
|
|
@@ -290,13 +299,13 @@ interface DailyUsageDelta {
|
|
|
290
299
|
estimatedCostMicros: number;
|
|
291
300
|
}
|
|
292
301
|
/** Inclusive `[startDate, endDate]` range query for the aggregate reads (`YYYY-MM-DD`). */
|
|
293
|
-
interface AiUsageRangeQuery {
|
|
302
|
+
export interface AiUsageRangeQuery {
|
|
294
303
|
partitionKey: string;
|
|
295
304
|
startDate: string;
|
|
296
305
|
endDate: string;
|
|
297
306
|
}
|
|
298
307
|
/** One row of the per-day aggregate (GROUP BY date). */
|
|
299
|
-
interface UsageSummaryRow {
|
|
308
|
+
export interface UsageSummaryRow {
|
|
300
309
|
date: string;
|
|
301
310
|
workflowCount: number;
|
|
302
311
|
inputTokens: number;
|
|
@@ -306,7 +315,7 @@ interface UsageSummaryRow {
|
|
|
306
315
|
estimatedCostMicros: number;
|
|
307
316
|
}
|
|
308
317
|
/** One row of the per-type aggregate (GROUP BY workflowType, keySource). */
|
|
309
|
-
interface UsageByTypeRow {
|
|
318
|
+
export interface UsageByTypeRow {
|
|
310
319
|
workflowType: string;
|
|
311
320
|
keySource: string;
|
|
312
321
|
workflowCount: number;
|
|
@@ -320,7 +329,7 @@ interface UsageByTypeRow {
|
|
|
320
329
|
* and aggregation engines. The `addDailyUsage` UPSERT and the two aggregate
|
|
321
330
|
* reads are the consumer's SQL; flow owns everything above the seam.
|
|
322
331
|
*/
|
|
323
|
-
interface AiUsageStore extends AiQuotaStore {
|
|
332
|
+
export interface AiUsageStore extends AiQuotaStore {
|
|
324
333
|
/** UPSERT-add a run's usage into the daily rollup (unique on partition+date+type+keySource). */
|
|
325
334
|
addDailyUsage(delta: DailyUsageDelta): Promise<void>;
|
|
326
335
|
/** Per-day totals over the range, ascending by date. */
|
|
@@ -329,7 +338,7 @@ interface AiUsageStore extends AiQuotaStore {
|
|
|
329
338
|
aggregateByWorkflowType(query: AiUsageRangeQuery): Promise<UsageByTypeRow[]>;
|
|
330
339
|
}
|
|
331
340
|
/** A completed LLM workflow's usage to roll up. */
|
|
332
|
-
interface WorkflowUsageInput {
|
|
341
|
+
export interface WorkflowUsageInput {
|
|
333
342
|
partitionKey: string;
|
|
334
343
|
/** Calendar day of completion, `YYYY-MM-DD`. */
|
|
335
344
|
date: string;
|
|
@@ -343,7 +352,7 @@ interface WorkflowUsageInput {
|
|
|
343
352
|
* tokens (no output, no cache); `workflowCount` increments once per flushed
|
|
344
353
|
* batch, not per inner embed call.
|
|
345
354
|
*/
|
|
346
|
-
interface EmbeddingUsageInput {
|
|
355
|
+
export interface EmbeddingUsageInput {
|
|
347
356
|
partitionKey: string;
|
|
348
357
|
/** Calendar day of the flush, `YYYY-MM-DD`. */
|
|
349
358
|
date: string;
|
|
@@ -354,7 +363,7 @@ interface EmbeddingUsageInput {
|
|
|
354
363
|
estimatedCostMicros: number;
|
|
355
364
|
}
|
|
356
365
|
/** Current-window usage snapshot for a scope. */
|
|
357
|
-
interface CurrentQuotaUsage {
|
|
366
|
+
export interface CurrentQuotaUsage {
|
|
358
367
|
today: {
|
|
359
368
|
workflowCount: number;
|
|
360
369
|
};
|
|
@@ -366,18 +375,18 @@ interface CurrentQuotaUsage {
|
|
|
366
375
|
};
|
|
367
376
|
}
|
|
368
377
|
/** Expected error value from aggregation reads/writes. Extends flow's structural error. */
|
|
369
|
-
interface AiUsageError {
|
|
378
|
+
export interface AiUsageError {
|
|
370
379
|
key: 'ai_usage_error';
|
|
371
380
|
message: string;
|
|
372
381
|
}
|
|
373
|
-
interface CreateAiUsageAggregationServiceDeps {
|
|
382
|
+
export interface CreateAiUsageAggregationServiceDeps {
|
|
374
383
|
store: AiUsageStore;
|
|
375
384
|
/** Clock injection for the current-window computation (tests). Defaults to `() => new Date()`. */
|
|
376
385
|
now?: () => Date;
|
|
377
386
|
/** Optional logger for write failures. Defaults to a no-op. */
|
|
378
387
|
logger?: Logger;
|
|
379
388
|
}
|
|
380
|
-
interface AiUsageAggregationService {
|
|
389
|
+
export interface AiUsageAggregationService {
|
|
381
390
|
/** Roll a completed LLM workflow's totals into the daily aggregate (UPSERT +1). */
|
|
382
391
|
recordWorkflowCompletion(data: WorkflowUsageInput): Promise<Result<void, AiUsageError>>;
|
|
383
392
|
/** Roll a flushed embedding batch into the daily aggregate (output/cache tokens = 0). */
|
|
@@ -392,6 +401,146 @@ interface AiUsageAggregationService {
|
|
|
392
401
|
}): Promise<Result<CurrentQuotaUsage, AiUsageError>>;
|
|
393
402
|
}
|
|
394
403
|
/** Build a store-agnostic AI usage-aggregation service. */
|
|
395
|
-
declare function createAiUsageAggregationService(deps: CreateAiUsageAggregationServiceDeps): AiUsageAggregationService;
|
|
404
|
+
export declare function createAiUsageAggregationService(deps: CreateAiUsageAggregationServiceDeps): AiUsageAggregationService;
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/ai/refusal.d.ts
|
|
407
|
+
/** The unified finish reason the AI SDK reports for a declined generation. */
|
|
408
|
+
export declare const REFUSAL_FINISH_REASON = "content-filter";
|
|
409
|
+
/**
|
|
410
|
+
* What the provider said about a refusal. Every field is optional except the
|
|
411
|
+
* model: providers other than Anthropic report the refusal without the
|
|
412
|
+
* `stop_details` breakdown, and Anthropic itself only sends `category` and
|
|
413
|
+
* `explanation` for some categories.
|
|
414
|
+
*/
|
|
415
|
+
export interface AiRefusalDetails {
|
|
416
|
+
/** The model that declined. */
|
|
417
|
+
modelId: string;
|
|
418
|
+
/** Provider's refusal category — Anthropic's `stop_details.category`. */
|
|
419
|
+
category?: string;
|
|
420
|
+
/** Provider's prose reason, when it sends one. */
|
|
421
|
+
explanation?: string;
|
|
422
|
+
/** The model the provider suggests retrying on (`stop_details.recommended_model`). */
|
|
423
|
+
recommendedModel?: string;
|
|
424
|
+
/** The provider's own stop reason (`refusal` on Anthropic), before unification. */
|
|
425
|
+
rawFinishReason?: string;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* A generation the model declined to produce.
|
|
429
|
+
*
|
|
430
|
+
* Distinct from a transport failure on purpose: it is deterministic, so
|
|
431
|
+
* retrying the same prompt on the same model produces the same refusal. Callers
|
|
432
|
+
* that classify retryability must treat it as terminal — `defineAiStep` does
|
|
433
|
+
* this for every AI workflow step.
|
|
434
|
+
*/
|
|
435
|
+
export declare class AiRefusalError extends Error {
|
|
436
|
+
readonly name = "AiRefusalError";
|
|
437
|
+
readonly details: AiRefusalDetails;
|
|
438
|
+
constructor(details: AiRefusalDetails);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* True when `error` is an {@link AiRefusalError}, or wraps one as its `cause`.
|
|
442
|
+
*
|
|
443
|
+
* Walks the chain because the SDK layer between the middleware and the caller
|
|
444
|
+
* may re-wrap: `generateObject`, for instance, reports parse failures as
|
|
445
|
+
* `NoObjectGeneratedError` with the original as `cause`. Depth-capped and
|
|
446
|
+
* cycle-safe.
|
|
447
|
+
*/
|
|
448
|
+
export declare function isAiRefusalError(error: unknown): error is AiRefusalError;
|
|
449
|
+
/**
|
|
450
|
+
* Pull the provider's refusal breakdown out of `providerMetadata`.
|
|
451
|
+
*
|
|
452
|
+
* Scans every provider namespace for a `stopDetails` record rather than reading
|
|
453
|
+
* `providerMetadata.anthropic` directly — the shape is Anthropic's today, and
|
|
454
|
+
* the surrounding module is deliberately provider-agnostic. A provider that
|
|
455
|
+
* reports a refusal with no breakdown simply yields no fields.
|
|
456
|
+
*/
|
|
457
|
+
export declare function readRefusalDetails(providerMetadata: SharedV4ProviderMetadata | undefined): Omit<AiRefusalDetails, 'modelId'>;
|
|
458
|
+
/**
|
|
459
|
+
* Wrap a model so a declined generation throws {@link AiRefusalError} instead
|
|
460
|
+
* of returning empty content.
|
|
461
|
+
*
|
|
462
|
+
* **`doGenerate` only, on purpose.** One-shot calls — every AI workflow step,
|
|
463
|
+
* every ad-hoc generation service, both classifiers — have no way to present a
|
|
464
|
+
* refusal to anyone: their contract is "return the value or fail", so a refusal
|
|
465
|
+
* that does not throw becomes an empty field or an unparseable object several
|
|
466
|
+
* frames away from its cause. The streaming path is the opposite case: the help
|
|
467
|
+
* chat is a conversation, where a decline is a legitimate turn the operator
|
|
468
|
+
* should *read*, and it already has a refusal surface (the `refusal` data part)
|
|
469
|
+
* for exactly that. `ChatAgentService` branches on the finish reason in
|
|
470
|
+
* `onFinish` instead, so the stream stays a stream.
|
|
471
|
+
*/
|
|
472
|
+
export declare function createRefusalAwareModel(model: LanguageModelV4): LanguageModelV4;
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region src/ai/capabilities.d.ts
|
|
475
|
+
/**
|
|
476
|
+
* Per-model API capability switches.
|
|
477
|
+
*
|
|
478
|
+
* Claude 4.6+ models (Opus 4.6/4.7/4.8/5, Sonnet 4.6/5, Fable/Mythos 5) use
|
|
479
|
+
* adaptive thinking; on 4.7+ the legacy `thinking: { type: 'enabled',
|
|
480
|
+
* budget_tokens }` shape and non-default sampling params (`temperature`,
|
|
481
|
+
* `top_p`, `top_k`) are rejected with a 400. Older models (Haiku 4.5,
|
|
482
|
+
* Sonnet 4.5, …) still require `enabled` + budgetTokens for extended
|
|
483
|
+
* thinking and accept `temperature`.
|
|
484
|
+
*
|
|
485
|
+
* A BYOK deployment lets a caller name any model id, so call sites must
|
|
486
|
+
* branch on the resolved id rather than assume one API shape — these
|
|
487
|
+
* functions are that branch, written once. `providerId` is a plain string:
|
|
488
|
+
* only `'anthropic'` has provider-specific shapes today.
|
|
489
|
+
*/
|
|
490
|
+
/** True for Claude 4.6+ / 5-family models: adaptive thinking, no budgetTokens, no sampling params. */
|
|
491
|
+
export declare function supportsAdaptiveThinking(modelId: string): boolean;
|
|
492
|
+
export interface AnthropicThinkingSettings {
|
|
493
|
+
temperature?: number;
|
|
494
|
+
headers?: Record<string, string>;
|
|
495
|
+
providerOptions: {
|
|
496
|
+
anthropic: {
|
|
497
|
+
thinking: {
|
|
498
|
+
type: 'adaptive';
|
|
499
|
+
display: 'summarized';
|
|
500
|
+
} | {
|
|
501
|
+
type: 'enabled';
|
|
502
|
+
budgetTokens: number;
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Spreadable `streamText`/`generateText` settings for a thinking-enabled
|
|
509
|
+
* agent loop, shaped for the target model's API generation.
|
|
510
|
+
*
|
|
511
|
+
* - Adaptive models: `thinking: { type: 'adaptive' }` with summarized display
|
|
512
|
+
* (the default `omitted` streams empty reasoning parts to the client).
|
|
513
|
+
* Interleaved thinking is implicit — no beta header, no temperature.
|
|
514
|
+
* - Legacy models: extended thinking with a token budget, the interleaved
|
|
515
|
+
* thinking beta header, and the caller's temperature.
|
|
516
|
+
*/
|
|
517
|
+
export declare function anthropicThinkingSettings(modelId: string, opts: {
|
|
518
|
+
temperature: number;
|
|
519
|
+
budgetTokens: number;
|
|
520
|
+
}): AnthropicThinkingSettings;
|
|
521
|
+
/**
|
|
522
|
+
* True when the provider+model pair supports Anthropic's tool search tool.
|
|
523
|
+
* Anthropic-only — like the thinking/beta-header shapes, `deferLoading`
|
|
524
|
+
* provider options and the search tool must never be emitted for another
|
|
525
|
+
* vendor. Unknown or pre-4.5 Anthropic model ids return false so callers
|
|
526
|
+
* fall back to shipping the full tool registry undeferred.
|
|
527
|
+
*/
|
|
528
|
+
export declare function supportsToolSearch(providerId: string, modelId: string): boolean;
|
|
529
|
+
export interface ThinkingSettings {
|
|
530
|
+
temperature?: number;
|
|
531
|
+
headers?: Record<string, string>;
|
|
532
|
+
providerOptions?: AnthropicThinkingSettings['providerOptions'];
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Provider-neutral wrapper around {@link anthropicThinkingSettings}. Other
|
|
536
|
+
* providers have no thinking/beta-header surface — they just get the caller's
|
|
537
|
+
* temperature. Never emit `providerOptions.anthropic` (or the beta header) for
|
|
538
|
+
* another vendor's model, even though it would be ignored on the wire — it
|
|
539
|
+
* pollutes request logs and breaks request-shape tests.
|
|
540
|
+
*/
|
|
541
|
+
export declare function thinkingSettingsFor(providerId: string, modelId: string, opts: {
|
|
542
|
+
temperature: number;
|
|
543
|
+
budgetTokens: number;
|
|
544
|
+
}): ThinkingSettings;
|
|
396
545
|
//#endregion
|
|
397
|
-
export {
|
|
546
|
+
export { AI_PROVIDERS, AI_PROVIDER_IDS, AiProcessingRegion, AiProviderId, AiProviderMeta, AiProviderModelOption, AiVendorResidency, DEFAULT_AI_PROVIDER, DEFAULT_EMBEDDING_PROVIDER, EMBEDDING_PROVIDERS, EMBEDDING_PROVIDER_IDS, EmbeddingProviderId, EmbeddingProviderMeta, embeddingDimensionsFor };
|