@voltro/ai 0.28.0 → 0.30.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/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ import { QueryDescriptor } from '@voltro/database';
16
16
  import { QueryProcedureDescriptor } from '@voltro/protocol';
17
17
  import { Runtime } from 'effect';
18
18
  import { Schema } from 'effect';
19
+ import { SchemaTable } from '@voltro/database';
20
+ import { SemanticCacheShape } from '@voltro/cache';
19
21
  import { simulateStreamingMiddleware } from 'ai';
20
22
  import { SpeechModelV4 } from '@ai-sdk/provider';
21
23
  import { Stream } from 'effect';
@@ -230,6 +232,8 @@ export declare const agentThreadsTable: Table<typeof AGENT_THREADS_TABLE, Record
230
232
 
231
233
  export declare const AI_BUDGET_TABLE = "_voltro_ai_budget";
232
234
 
235
+ export declare const AI_INFERENCES_TABLE = "_voltro_ai_inferences";
236
+
233
237
  export declare const AI_USAGE_TABLE = "_voltro_ai_usage";
234
238
 
235
239
  /** Thrown when an AI call would push a tenant over its USD budget. */
@@ -298,6 +302,15 @@ declare const AiError_base: Schema.TaggedErrorClass<AiError, "AiError", {
298
302
  message: typeof Schema.String;
299
303
  }>;
300
304
 
305
+ /**
306
+ * One offloaded model call.
307
+ *
308
+ * The row IS the wait. A run parked on `awaitSignalSuspending` holds nothing;
309
+ * everything needed to perform the call, resume the right run, and explain the
310
+ * outcome afterwards is here.
311
+ */
312
+ export declare const aiInferencesTable: SchemaTable;
313
+
301
314
  /** Provider-specific knobs forwarded verbatim to the Vercel AI SDK's
302
315
  * `providerOptions` on generateText / streamText / generateObject. The outer
303
316
  * key is the provider id, the inner record its options. The headline use is
@@ -468,6 +481,11 @@ export declare interface AppToolPolicy {
468
481
  */
469
482
  export declare const appTools: (entries: ReadonlyArray<AppToolEntry>, policy?: AppToolPolicy) => ReadonlyArray<AnyTool>;
470
483
 
484
+ export declare interface AssertionFailure {
485
+ readonly assertion: EvalAssertion;
486
+ readonly detail: string;
487
+ }
488
+
471
489
  /** Render the capability map into a system prompt that enumerates EXACTLY the
472
490
  * tables + columns the model may use — the soft in-grammar steer that pairs
473
491
  * with the hard validator. */
@@ -647,10 +665,45 @@ export declare interface DataCopilotDeps {
647
665
  */
648
666
  export declare const dataStoreResumableStreamStore: (store: DataStore) => ResumableStreamStore;
649
667
 
668
+ export declare const decideInferenceFailure: (input: {
669
+ readonly attempts: number;
670
+ readonly maxAttempts: number;
671
+ readonly baseDelayMs: number;
672
+ readonly maxDelayMs: number;
673
+ /** Milliseconds the provider itself asked us to wait, when it said so. */
674
+ readonly retryAfterMs?: number | undefined;
675
+ }) => InferenceFailureAction;
676
+
677
+ /** Attempts before a queued call is reported as failed to its waiting run. */
678
+ export declare const DEFAULT_INFERENCE_ATTEMPTS = 4;
679
+
680
+ /** How many queued calls one dispatcher performs concurrently.
681
+ *
682
+ * This is the number offloading exists to make explicit: inline, the ceiling
683
+ * is "however many runs happen to be waiting". Here it is declared, and it is
684
+ * the knob to turn when a provider starts rate-limiting. */
685
+ export declare const DEFAULT_INFERENCE_CONCURRENCY = 4;
686
+
687
+ /** How long a dispatcher's claim survives with nothing completing it.
688
+ *
689
+ * Generous relative to a model call, for the asymmetry the admission lease
690
+ * documents: reclaiming early performs a paid call twice, reclaiming late
691
+ * delays one call. */
692
+ export declare const DEFAULT_INFERENCE_LEASE_MS: number;
693
+
694
+ /** How often the dispatcher looks for work. Fast, because it sits directly in
695
+ * the latency of every offloaded call — a suspend/resume round trip already
696
+ * costs one engine wake, and there is no reason to add a second of polling on
697
+ * top of it. */
698
+ export declare const DEFAULT_INFERENCE_POLL_MS = 250;
699
+
650
700
  declare const DEFAULT_INPUT: Schema.Struct<{
651
701
  prompt: typeof Schema.String;
652
702
  }>;
653
703
 
704
+ /** The default judge threshold when a judge is configured without one. */
705
+ export declare const DEFAULT_JUDGE_THRESHOLD = 0.7;
706
+
654
707
  /** Default input schema type when `input` is omitted (`{ prompt: string }`). */
655
708
  export declare type DefaultAgentInputSchema = typeof DEFAULT_INPUT;
656
709
 
@@ -701,6 +754,25 @@ export declare const defineAgent: <S extends Schema.Schema.Any = DefaultAgentInp
701
754
  */
702
755
  export declare const defineAgentExecutor: <S extends Schema.Schema.Any = DefaultAgentInputSchema>(descriptor: AgentDescriptor<S>, config: AgentExecutorConfig<AgentInput<S>>) => AgentExecutor<S>;
703
756
 
757
+ /**
758
+ * Declare an eval suite. Validated at module load — an empty case list, a
759
+ * duplicate case id, or a nonsensical threshold throws loudly so a broken eval
760
+ * fails discovery, never at replay time. Call it as the default export of a
761
+ * `*.eval.ts` file; `voltro eval` discovers + runs it.
762
+ */
763
+ export declare const defineEval: (input: DefineEvalInput) => EvalDefinition;
764
+
765
+ export declare interface DefineEvalInput {
766
+ readonly name: string;
767
+ readonly cases: ReadonlyArray<EvalCase>;
768
+ /** Assertions applied to EVERY case. */
769
+ readonly assert?: ReadonlyArray<EvalAssertion>;
770
+ readonly judge?: EvalJudgeConfig;
771
+ /** Tool names the replay may call (resolved by the runner against the app's
772
+ * registered `*.tool.tsx`). Empty = a bare generate. */
773
+ readonly tools?: ReadonlyArray<string>;
774
+ }
775
+
704
776
  export declare const defineTool: <A, I, O>(def: {
705
777
  readonly name: string;
706
778
  readonly description: string;
@@ -711,6 +783,15 @@ export declare const defineTool: <A, I, O>(def: {
711
783
  readonly timeoutMs?: number;
712
784
  }) => AnyTool;
713
785
 
786
+ /**
787
+ * One dispatch tick. Never throws.
788
+ *
789
+ * A tick that threw would stop every offloaded call in the deployment until
790
+ * somebody noticed, and every run parked on one would sit there. Failures are
791
+ * collected and reported.
792
+ */
793
+ export declare const dispatchInferences: (deps: InferenceDispatchDeps, options?: InferenceDispatchOptions) => Promise<InferenceDispatchResult>;
794
+
714
795
  /**
715
796
  * Embed a single string to a vector. Returns the embedding through Effect's
716
797
  * success channel; provider failures surface as a typed
@@ -760,6 +841,113 @@ export declare const estimateCostUsd: (usage: AiUsage, opts: {
760
841
  readonly actualCostUsd?: number;
761
842
  }) => CostBreakdown;
762
843
 
844
+ /**
845
+ * A HARD assertion over the replayed output — a pure predicate, no model in the
846
+ * loop. These are the deterministic half of the gate: an LLM judge decides "is
847
+ * this answer good", an assertion decides "does it literally contain the order id
848
+ * / never leak the system prompt / come back non-empty within the latency bound".
849
+ */
850
+ export declare type EvalAssertion = {
851
+ readonly kind: 'contains';
852
+ readonly value: string;
853
+ readonly caseInsensitive?: boolean;
854
+ } | {
855
+ readonly kind: 'notContains';
856
+ readonly value: string;
857
+ readonly caseInsensitive?: boolean;
858
+ } | {
859
+ readonly kind: 'matches';
860
+ readonly pattern: string;
861
+ readonly flags?: string;
862
+ } | {
863
+ readonly kind: 'equals';
864
+ readonly value: string;
865
+ readonly trim?: boolean;
866
+ } | {
867
+ readonly kind: 'maxLatencyMs';
868
+ readonly value: number;
869
+ } | {
870
+ readonly kind: 'nonEmpty';
871
+ };
872
+
873
+ export declare interface EvalCase {
874
+ /** Stable id — names the case in the report + the branch. */
875
+ readonly id: string;
876
+ readonly input: EvalInput;
877
+ /** The output the ORIGINAL recorded run produced — the baseline the judge
878
+ * compares the replay against. Optional: a case can gate on assertions alone. */
879
+ readonly golden?: string;
880
+ /** Assertions for THIS case (run in addition to the eval-wide `assert`). */
881
+ readonly assert?: ReadonlyArray<EvalAssertion>;
882
+ }
883
+
884
+ export declare interface EvalCaseResult {
885
+ readonly id: string;
886
+ readonly pass: boolean;
887
+ readonly assertionFailures: ReadonlyArray<AssertionFailure>;
888
+ /** Present when the eval declared a judge. */
889
+ readonly judge?: JudgeVerdict;
890
+ readonly output: EvalReplayOutput;
891
+ }
892
+
893
+ export declare interface EvalDefinition extends DefineEvalInput {
894
+ readonly __eval: true;
895
+ }
896
+
897
+ /** The captured inputs of a recorded run — what the replay re-sends. `messages`
898
+ * carries the full prior conversation for a multi-turn recorded run; `prompt` is
899
+ * the single user turn. */
900
+ export declare interface EvalInput {
901
+ readonly prompt: string;
902
+ readonly system?: string;
903
+ readonly messages?: ReadonlyArray<ModelMessage>;
904
+ }
905
+
906
+ /** Grade one replay. Injected so the pure runner never needs a provider. */
907
+ export declare type EvalJudge = (args: {
908
+ readonly case: EvalCase;
909
+ readonly output: EvalReplayOutput;
910
+ readonly config: EvalJudgeConfig;
911
+ }) => Promise<JudgeVerdict>;
912
+
913
+ /** LLM-judge configuration. The judge scores the replay against the rubric (and,
914
+ * when present, the golden baseline); a score below `threshold` fails the case. */
915
+ export declare interface EvalJudgeConfig {
916
+ /** What "good" means for these cases — the grading rubric handed to the judge. */
917
+ readonly rubric: string;
918
+ /** Minimum score (0..1) to pass. Default 0.7. */
919
+ readonly threshold?: number;
920
+ }
921
+
922
+ /** Re-run a single case. Injected by the caller — the CLI wires the app's
923
+ * provider (against a branched store); a test passes a deterministic fake. */
924
+ export declare type EvalReplay = (args: {
925
+ readonly case: EvalCase;
926
+ readonly def: EvalDefinition;
927
+ }) => Promise<EvalReplayOutput>;
928
+
929
+ /** What one replay produced. `latencyMs` feeds the `maxLatencyMs` assertion. */
930
+ export declare interface EvalReplayOutput {
931
+ readonly text: string;
932
+ readonly latencyMs: number;
933
+ }
934
+
935
+ export declare interface EvalReport {
936
+ readonly name: string;
937
+ readonly ok: boolean;
938
+ readonly passed: number;
939
+ readonly failed: number;
940
+ readonly cases: ReadonlyArray<EvalCaseResult>;
941
+ /** The isolated data branch this suite's replays target — reused branching
942
+ * machinery (`branchNamespaceName`). Set by the CLI when `--branch` is used. */
943
+ readonly branch?: {
944
+ readonly id: string;
945
+ };
946
+ }
947
+
948
+ /** Run every assertion against one output; return only the failures. Pure. */
949
+ export declare const evaluateAssertions: (out: EvalReplayOutput, assertions: ReadonlyArray<EvalAssertion>) => ReadonlyArray<AssertionFailure>;
950
+
763
951
  declare const EXECUTOR_BRAND: "@voltro/ai/AgentExecutor";
764
952
 
765
953
  /** The `exposeAsTool` annotation shape (mirrors @voltro/protocol's, structural
@@ -870,6 +1058,30 @@ export declare interface GenerateImageResult {
870
1058
 
871
1059
  export declare const generateObject: <A, I>(options: GenerateObjectOptions<A, I>) => Effect.Effect<GenerateObjectResult<A>, AiError>;
872
1060
 
1061
+ /**
1062
+ * Structured output against an already-rendered JSON Schema, WITHOUT the decode
1063
+ * step.
1064
+ *
1065
+ * Extracted from `generateObject` rather than written beside it: an offloaded
1066
+ * inference is performed by a dispatcher that has the stored JSON Schema and no
1067
+ * access to the caller's Effect Schema (a closure cannot be journaled), and the
1068
+ * awaiting workflow decodes on resume. Two implementations of "ask the model for
1069
+ * JSON matching this shape" would have been two sets of provider-option
1070
+ * handling, fallback behaviour and span attributes.
1071
+ */
1072
+ export declare const generateObjectJson: (options: GenerateObjectJsonOptions) => Effect.Effect<GenerateObjectResult<unknown>, AiError>;
1073
+
1074
+ export declare interface GenerateObjectJsonOptions {
1075
+ /** A JSON Schema, already rendered. */
1076
+ readonly jsonSchema: Record<string, unknown>;
1077
+ readonly prompt: string;
1078
+ readonly system?: string;
1079
+ readonly provider?: ProviderConfig;
1080
+ readonly fallbacks?: ProviderFallbacks;
1081
+ readonly maxTokens?: number;
1082
+ readonly providerOptions?: AiProviderOptions;
1083
+ }
1084
+
873
1085
  export declare interface GenerateObjectOptions<A, I> {
874
1086
  /** Effect Schema the model output must satisfy. Converted to JSON
875
1087
  * Schema for the SDK, then decoded back through this schema so the
@@ -1110,18 +1322,104 @@ export declare const hashToVector: (text: string, dim: number) => number[];
1110
1322
  */
1111
1323
  export declare const historyToModelMessages: (history: ReadonlyArray<AgentMessage>) => ModelMessage[];
1112
1324
 
1325
+ export declare interface InferenceDispatchDeps {
1326
+ readonly store: DataStore;
1327
+ /**
1328
+ * Resume the parked run with the call's outcome.
1329
+ *
1330
+ * MUST be idempotent — completing an already-resolved durable deferred is a
1331
+ * no-op, which is what makes the perform → resume → mark ordering safe.
1332
+ */
1333
+ readonly resume: (input: {
1334
+ readonly executionId: string;
1335
+ readonly workflowName: string;
1336
+ readonly signalName: string;
1337
+ readonly payload: unknown;
1338
+ }) => Promise<void>;
1339
+ /** Runs an `@voltro/ai` Effect. Injected so this module needs no runtime. */
1340
+ readonly run: <A>(effect: Effect.Effect<A, unknown>) => Promise<A>;
1341
+ readonly now?: () => number;
1342
+ readonly replicaId?: string;
1343
+ readonly log?: {
1344
+ readonly info: (message: string, meta?: Record<string, unknown>) => void;
1345
+ readonly warn: (message: string, meta?: Record<string, unknown>) => void;
1346
+ };
1347
+ }
1348
+
1349
+ export declare interface InferenceDispatchOptions {
1350
+ readonly batch?: number;
1351
+ readonly concurrency?: number;
1352
+ readonly leaseMs?: number;
1353
+ readonly maxAttempts?: number;
1354
+ readonly baseDelayMs?: number;
1355
+ readonly maxDelayMs?: number;
1356
+ }
1357
+
1358
+ export declare interface InferenceDispatchResult {
1359
+ /** `false` when nothing was claimed AND nothing was waiting — so an empty
1360
+ * tick and a tick that could not read are never the same report. */
1361
+ readonly examined: boolean;
1362
+ readonly claimed: number;
1363
+ readonly succeeded: number;
1364
+ readonly failed: number;
1365
+ readonly retried: number;
1366
+ readonly reclaimed: number;
1367
+ readonly failures: ReadonlyArray<{
1368
+ readonly id: string;
1369
+ readonly detail: string;
1370
+ }>;
1371
+ }
1372
+
1373
+ /**
1374
+ * What the dispatcher should do with a call that just failed.
1375
+ *
1376
+ * PURE, and separated for the usual reason: the interesting cases here are
1377
+ * "when do we give up" and "does the waiting run learn about it", and neither
1378
+ * needs a store, a clock or a provider to decide.
1379
+ */
1380
+ export declare type InferenceFailureAction = {
1381
+ readonly kind: 'retry';
1382
+ readonly attempts: number;
1383
+ readonly delayMs: number;
1384
+ } | {
1385
+ readonly kind: 'give-up';
1386
+ readonly attempts: number;
1387
+ };
1388
+
1389
+ /** The signal name a parked run awaits for one queued call. Derived from the
1390
+ * row id, so the run and the dispatcher agree without sharing anything. */
1391
+ export declare const inferenceSignalName: (inferenceId: string) => string;
1392
+
1113
1393
  /** Discovery predicate for `*.agent.tsx` exports. */
1114
1394
  export declare const isAgentDescriptor: (x: unknown) => x is AnyAgentDescriptor;
1115
1395
 
1116
1396
  /** Discovery predicate for `*.agent.server.tsx` default exports. */
1117
1397
  export declare const isAgentExecutor: (x: unknown) => x is AnyAgentExecutor;
1118
1398
 
1399
+ export declare const isEvalDefinition: (value: unknown) => value is EvalDefinition;
1400
+
1119
1401
  /** Whether a stream with this id is currently registered (in flight). */
1120
1402
  export declare const isStreamActive: (streamId: string) => boolean;
1121
1403
 
1122
1404
  /** Is `x` a `defineTool(...)` result? */
1123
1405
  export declare const isTool: (x: unknown) => x is AnyTool;
1124
1406
 
1407
+ export declare interface JudgeVerdict {
1408
+ readonly pass: boolean;
1409
+ /** 0..1. Below `judge.threshold` fails the case even when `pass` is true. */
1410
+ readonly score: number;
1411
+ readonly reason: string;
1412
+ }
1413
+
1414
+ /**
1415
+ * The real LLM judge: asks the model for a structured `{ pass, score, reason }`
1416
+ * verdict via `generateObject` (schema-constrained, so a malformed grade surfaces
1417
+ * as a typed error rather than a parse crash). A judge failure is turned into a
1418
+ * failing verdict rather than throwing, so one flaky grade fails ONE case instead
1419
+ * of aborting the whole eval — the report stays a complete deploy-gate signal.
1420
+ */
1421
+ export declare const llmJudge: EvalJudge;
1422
+
1125
1423
  /** The synthesized `<name>.messages` body — load the thread's messages. */
1126
1424
  export declare const loadAgentMessages: (store: DataStore, threadId: string) => Effect.Effect<ReadonlyArray<AgentMessage>>;
1127
1425
 
@@ -1301,8 +1599,26 @@ export declare const modelPricing: () => Record<string, ModelPrice>;
1301
1599
  */
1302
1600
  export declare const observeStream: (attributes: AiCallAttributes, stream: Stream.Stream<AgentEvent>) => Stream.Stream<AgentEvent>;
1303
1601
 
1602
+ /**
1603
+ * The DETERMINISTIC row id for an offloaded call.
1604
+ *
1605
+ * Keyed on the execution + step, not on a generated id, so a replay that
1606
+ * reaches the enqueue before the first attempt's journal entry is durable
1607
+ * cannot queue — and pay for — the same call twice. `insertIgnore` on this id
1608
+ * is what makes the enqueue idempotent.
1609
+ *
1610
+ * Hashed for LENGTH, exactly like `pendingSlotId`: `id()` is VARCHAR(64) on
1611
+ * MySQL/MariaDB and a step name is app-chosen text.
1612
+ */
1613
+ export declare const offloadedInferenceId: (executionId: string, stepName: string) => string;
1614
+
1304
1615
  export declare type OpenAIModel = 'gpt-5.5' | 'gpt-4o' | 'gpt-4o-mini' | (string & {});
1305
1616
 
1617
+ /** The JSON Schema a `generateObject` output schema renders to. Exported
1618
+ * because an OFFLOADED inference has to store it: a JavaScript Schema object
1619
+ * cannot be journaled, and its JSON rendering can. */
1620
+ export declare const outputJsonSchema: (schema: Schema.Schema.Any, fn: string) => Effect.Effect<Record<string, unknown>, AiError>;
1621
+
1306
1622
  /** Does this tag pass the allow/deny policy? deny wins; allow (when set) gates. */
1307
1623
  export declare const passesPolicy: (tag: string, policy: AppToolPolicy) => boolean;
1308
1624
 
@@ -1410,12 +1726,67 @@ export declare const providerFromEnv: (env?: Record<string, string | undefined>)
1410
1726
 
1411
1727
  export declare type ProviderName = 'mock' | 'anthropic' | 'openai' | 'gateway';
1412
1728
 
1729
+ /** The minimal store surface {@link recordReads} needs — any object with a
1730
+ * `query(descriptor)` that returns rows. Structurally a subset of the
1731
+ * framework `DataStore`, so no `@voltro/runtime` import is required. */
1732
+ export declare interface QueryableStore {
1733
+ query(descriptor: {
1734
+ readonly table: string;
1735
+ } & Record<string, unknown>): Promise<ReadonlyArray<Record<string, unknown>>>;
1736
+ }
1737
+
1738
+ /** A queued call in domain shape. */
1739
+ export declare interface QueuedInference {
1740
+ readonly id: string;
1741
+ readonly tenantId: string | null;
1742
+ readonly executionId: string;
1743
+ readonly workflowName: string;
1744
+ readonly runId: string | null;
1745
+ readonly signalName: string;
1746
+ readonly stepName: string;
1747
+ readonly kind: 'text' | 'object';
1748
+ readonly provider: string;
1749
+ readonly model: string;
1750
+ readonly prompt: string;
1751
+ readonly system: string | null;
1752
+ readonly maxTokens: number | null;
1753
+ readonly providerOptions: unknown;
1754
+ readonly jsonSchema: Record<string, unknown> | null;
1755
+ readonly attempts: number;
1756
+ }
1757
+
1758
+ /** A store wrapper that records the dependency set of everything read through
1759
+ * it — the provenance the semantic cache tags entries with. */
1760
+ export declare interface ReadRecorder<S extends QueryableStore> {
1761
+ /** Pass THIS where the real store would go; every `query()` it serves records
1762
+ * the table + each returned row's id. All other methods pass through. */
1763
+ readonly store: S;
1764
+ /** The accumulated dependency tags (deduped): `table:<t>` for each table
1765
+ * queried + `row:<t>:<id>` for each row returned that carries an `id`. Feed
1766
+ * this to a call's `deps`. */
1767
+ deps(): ReadonlyArray<string>;
1768
+ /** Drop everything recorded so far (reuse the recorder for a new answer). */
1769
+ reset(): void;
1770
+ }
1771
+
1413
1772
  /**
1414
1773
  * Price a usage tally and write a ledger row. Returns the computed
1415
1774
  * `CostBreakdown` so the caller can surface the cost without a re-query.
1416
1775
  */
1417
1776
  export declare const recordAiUsage: (store: DataStore, record: AiUsageRecordInput) => Effect.Effect<CostBreakdown>;
1418
1777
 
1778
+ /**
1779
+ * Wrap a store so the rows it serves become a dependency set — automatic
1780
+ * provenance capture with no runtime edit. Every `query()` records
1781
+ * `tableDep(table)` and, for each returned row with an `id`, `rowDep(table,
1782
+ * id)`. Read your data through `rec.store`, build the prompt from the rows,
1783
+ * then pass `rec.deps()` as the call's dependency set.
1784
+ *
1785
+ * The wrapper is a `Proxy`, so the returned `store` has the SAME type + full
1786
+ * method surface as the input — only `query` is intercepted.
1787
+ */
1788
+ export declare const recordReads: <S extends QueryableStore>(store: S) => ReadRecorder<S>;
1789
+
1419
1790
  /**
1420
1791
  * Redis-backed resumable-stream store — the production "resumable via
1421
1792
  * Redis-Replay" path. The append-only log is a Redis LIST per `streamId`
@@ -1690,6 +2061,102 @@ export declare interface RunAssistantInput {
1690
2061
  */
1691
2062
  export declare const runDataCopilot: (question: string, schema: CopilotSchema, deps: DataCopilotDeps) => Promise<CopilotValidation>;
1692
2063
 
2064
+ /**
2065
+ * Replay + score every case in an eval. The orchestrator is pure over its
2066
+ * injected `replay` / `judge`, so it runs identically under a real provider and
2067
+ * under a deterministic test fake. `ok` is the deploy-gate signal: false iff any
2068
+ * case failed.
2069
+ */
2070
+ export declare const runEval: (def: EvalDefinition, deps: RunEvalDeps) => Promise<EvalReport>;
2071
+
2072
+ export declare interface RunEvalDeps {
2073
+ readonly replay: EvalReplay;
2074
+ /** Omitted → assertions-only gating (no LLM in the loop). */
2075
+ readonly judge?: EvalJudge;
2076
+ readonly branchId?: string;
2077
+ }
2078
+
2079
+ /**
2080
+ * Combine assertion failures + the judge verdict into one pass/fail. Pure. A case
2081
+ * passes iff no assertion failed AND (no judge, or the judge's score clears the
2082
+ * threshold). Assertions are deterministic and always decisive; the judge only
2083
+ * ever ADDS a reason to fail, never rescues an assertion failure.
2084
+ */
2085
+ export declare const scoreCase: (c: EvalCase, out: EvalReplayOutput, evalWideAssertions: ReadonlyArray<EvalAssertion>, judgeConfig: EvalJudgeConfig | undefined, judgeVerdict: JudgeVerdict | undefined) => EvalCaseResult;
2086
+
2087
+ /** Injectable collaborators for a semantic-cached call. */
2088
+ export declare interface SemanticCacheDeps {
2089
+ /** The semantic cache (build with `makeSemanticCache(store)` from
2090
+ * `@voltro/cache` over a memory / RESP `CacheStore`). */
2091
+ readonly cache: SemanticCacheShape;
2092
+ /** Embed a prompt to a vector. Defaults to `@voltro/ai`'s `embed` (the
2093
+ * env-configured provider). Injectable for tests + provider choice. */
2094
+ readonly embed?: (text: string) => Effect.Effect<ReadonlyArray<number>, AiError>;
2095
+ }
2096
+
2097
+ /** Per-call cache policy. */
2098
+ export declare interface SemanticCachePolicy {
2099
+ /** Minimum cosine similarity ([-1, 1]) for a hit. Default 0.95 — high, so
2100
+ * only genuine near-duplicates share an answer. */
2101
+ readonly threshold?: number;
2102
+ /** TTL floor in ms — the answer expires after this even if nothing it
2103
+ * depends on changes. Omit for "live until a dependency changes". */
2104
+ readonly ttlMs?: number;
2105
+ /** The dependency set: the source rows/tables this answer read, as tags
2106
+ * (`rowDep` / `tableDep`, or {@link recordReads}). A change to any of them
2107
+ * evicts the entry. Empty ⇒ cached but TTL-only (never dependency-evicted)
2108
+ * — correct only for an answer that reads no data. */
2109
+ readonly deps: ReadonlyArray<string>;
2110
+ }
2111
+
2112
+ /**
2113
+ * `generateObject`, semantically cached + dependency-evicted. Same contract as
2114
+ * {@link semanticGenerateText} for the structured surface.
2115
+ *
2116
+ * Note on serialization: the DECODED object is stored. With the memory backend
2117
+ * it round-trips by reference; with a RESP backend it is JSON — so a schema
2118
+ * whose decoded form is not JSON-safe (class instances, non-plain branded
2119
+ * carriers) will not survive a cross-process hit. For those, cache the text
2120
+ * form or key on a JSON-safe projection.
2121
+ */
2122
+ export declare const semanticGenerateObject: <A, I>(options: GenerateObjectOptions<A, I>, policy: SemanticCachePolicy, deps: SemanticCacheDeps) => Effect.Effect<SemanticResult<A>, AiError>;
2123
+
2124
+ /**
2125
+ * `generateText`, semantically cached + dependency-evicted.
2126
+ *
2127
+ * On a near-duplicate prompt (embedding within `threshold`) returns the cached
2128
+ * text with `cached: true` and zero usage. On a miss it generates, records the
2129
+ * answer under its dependency set, and returns `cached: false`.
2130
+ *
2131
+ * ```ts
2132
+ * const rec = recordReads(ctx.store)
2133
+ * const docs = yield* Effect.promise(() => rec.store.query(docsQuery))
2134
+ * const res = yield* semanticGenerateText(
2135
+ * { prompt: buildPrompt(docs) },
2136
+ * { deps: rec.deps() },
2137
+ * { cache },
2138
+ * )
2139
+ * // res.cached === true on the next near-identical prompt — until a doc changes.
2140
+ * ```
2141
+ */
2142
+ export declare const semanticGenerateText: (options: GenerateTextOptions, policy: SemanticCachePolicy, deps: SemanticCacheDeps) => Effect.Effect<SemanticResult<string>, AiError>;
2143
+
2144
+ /** The outcome of a semantic-cached generation. */
2145
+ export declare interface SemanticResult<A> {
2146
+ readonly value: A;
2147
+ /** `true` when served from cache (zero tokens spent). */
2148
+ readonly cached: boolean;
2149
+ /** Underlying generation usage — all-zero when `cached`. */
2150
+ readonly usage: SemanticUsage;
2151
+ }
2152
+
2153
+ /** Usage tally shape shared by both generate results; all-zero on a cache hit. */
2154
+ export declare interface SemanticUsage {
2155
+ readonly inputTokens: number | undefined;
2156
+ readonly outputTokens: number | undefined;
2157
+ readonly totalTokens: number | undefined;
2158
+ }
2159
+
1693
2160
  /**
1694
2161
  * One persisted event of a RESUMABLE stream: an `AgentEvent` plus its monotonic
1695
2162
  * 1-based position. `seq` is the resume cursor — a client that has rendered up
@@ -1960,6 +2427,8 @@ export declare interface ToolDef<A, I, O> {
1960
2427
  * a Promise; `buildSdkTools` normalises both. */
1961
2428
  export declare type ToolHandler<A, O> = (input: A, ctx: ToolContext) => Effect.Effect<O, never, unknown> | Promise<O>;
1962
2429
 
2430
+ export declare const toQueuedInference: (row: Record<string, unknown>) => QueuedInference;
2431
+
1963
2432
  /**
1964
2433
  * Drop a stream's controller. `streamText` calls this in its finaliser when the
1965
2434
  * stream ends — success, error, cancel, or consumer interrupt. Idempotent.