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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # octaflow
2
2
 
3
- [![CI](https://github.com/octabits-io/octaflow/actions/workflows/ci.yml/badge.svg)](https://github.com/octabits-io/octaflow/actions/workflows/ci.yml)
3
+ [![CI](https://github.com/octabits-io/octabits/actions/workflows/ci.yml/badge.svg)](https://github.com/octabits-io/octabits/actions/workflows/ci.yml)
4
4
  [![npm](https://img.shields.io/npm/v/octaflow.svg)](https://www.npmjs.com/package/octaflow)
5
5
  [![docs](https://img.shields.io/badge/docs-octaflow.octabits.io-16794a.svg)](https://octaflow.octabits.io/)
6
6
  [![license](https://img.shields.io/npm/l/octaflow.svg)](./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-io/octaflow](https://github.com/octabits-io/octaflow) (extracted from the
303
- [octabits platform monorepo](https://github.com/octabits-io/platform), where its earlier history lives).
304
- The API is stable but may still see breaking changes in 0.x minors.
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.
@@ -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
- /** Default pricing (USD per million tokens), as of 2026-04. */
75
- declare const DEFAULT_MODEL_PRICING: Record<string, ModelPricing>;
76
- interface CostEstimatorOptions {
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 { AccumulatedUsage, AiContext, AiModelResolver, AiQuotaConfig, AiQuotaConfigResolver, AiQuotaExceededError, AiQuotaExceededReason, AiQuotaPolicy, AiQuotaService, AiQuotaStore, AiTypedStep, AiUsageAggregationService, AiUsageCountQuery, AiUsageError, AiUsageRangeQuery, AiUsageRecorder, AiUsageStore, CostEstimator, CostEstimatorOptions, CreateAiQuotaServiceDeps, CreateAiUsageAggregationServiceDeps, CreateAiWorkflowHooksDeps, CurrentQuotaUsage, DEFAULT_AI_QUOTA, DEFAULT_MODEL_PRICING, DailyUsageDelta, EmbeddingAccumulatedUsage, EmbeddingUsageAccumulator, EmbeddingUsageInput, ModelPricing, TokenUsage, UsageAccumulator, UsageByTypeRow, UsageSummaryRow, WorkflowUsageInput, buildAiWorkflow, createAiQuotaService, createAiUsageAggregationService, createAiWorkflowHooks, createCostEstimator, createEmbeddingUsageAccumulator, createInstrumentedEmbeddingModel, createInstrumentedModel, createUsageAccumulator, defineAiStep, estimateCostMicros };
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 };