@directive-run/ai 1.12.0 → 1.14.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/anthropic.cjs +1 -1
- package/dist/anthropic.d.cts +1 -1
- package/dist/anthropic.d.ts +1 -1
- package/dist/anthropic.js +1 -1
- package/dist/anthropic.js.map +1 -1
- package/dist/{chunk-XV2QSBBE.cjs → chunk-2TD4ZSGZ.cjs} +7 -7
- package/dist/{chunk-XV2QSBBE.cjs.map → chunk-2TD4ZSGZ.cjs.map} +1 -1
- package/dist/chunk-3WO4MWJM.cjs +3 -0
- package/dist/chunk-3WO4MWJM.cjs.map +1 -0
- package/dist/chunk-5JQ2A3JK.js +2 -0
- package/dist/chunk-5JQ2A3JK.js.map +1 -0
- package/dist/chunk-A22KLB23.cjs +67 -0
- package/dist/chunk-A22KLB23.cjs.map +1 -0
- package/dist/chunk-A5K77UDX.cjs +4 -0
- package/dist/chunk-A5K77UDX.cjs.map +1 -0
- package/dist/chunk-DN5NAJM6.js +6 -0
- package/dist/chunk-DN5NAJM6.js.map +1 -0
- package/dist/chunk-FABDFT74.cjs +6 -0
- package/dist/chunk-FABDFT74.cjs.map +1 -0
- package/dist/chunk-FBT73WFY.js +2 -0
- package/dist/chunk-FBT73WFY.js.map +1 -0
- package/dist/chunk-FFRWQNK7.cjs +7 -0
- package/dist/chunk-FFRWQNK7.cjs.map +1 -0
- package/dist/chunk-IR3IHBVQ.cjs +2 -0
- package/dist/chunk-IR3IHBVQ.cjs.map +1 -0
- package/dist/chunk-IUGSMTBE.js +16 -0
- package/dist/{chunk-Q3PQLWBR.js.map → chunk-IUGSMTBE.js.map} +1 -1
- package/dist/chunk-J2Q5KKPN.js +37 -0
- package/dist/chunk-J2Q5KKPN.js.map +1 -0
- package/dist/chunk-K64WKZ22.cjs +2 -0
- package/dist/chunk-K64WKZ22.cjs.map +1 -0
- package/dist/chunk-LKY4K5TV.cjs +11 -0
- package/dist/chunk-LKY4K5TV.cjs.map +1 -0
- package/dist/chunk-LXUMJKGJ.js +67 -0
- package/dist/chunk-LXUMJKGJ.js.map +1 -0
- package/dist/chunk-NNAQ4ZH2.js +11 -0
- package/dist/chunk-NNAQ4ZH2.js.map +1 -0
- package/dist/chunk-PD772MSE.cjs +30 -0
- package/dist/chunk-PD772MSE.cjs.map +1 -0
- package/dist/chunk-POBEEJR6.js +30 -0
- package/dist/chunk-POBEEJR6.js.map +1 -0
- package/dist/chunk-QRXWLD6H.js +4 -0
- package/dist/chunk-QRXWLD6H.js.map +1 -0
- package/dist/chunk-UR4ZGO7V.js +7 -0
- package/dist/chunk-UR4ZGO7V.js.map +1 -0
- package/dist/chunk-UR5BMWEN.js +2 -0
- package/dist/chunk-UR5BMWEN.js.map +1 -0
- package/dist/chunk-WOFIBIPW.cjs +2 -0
- package/dist/chunk-WOFIBIPW.cjs.map +1 -0
- package/dist/chunk-XN5LUOVS.cjs +37 -0
- package/dist/chunk-XN5LUOVS.cjs.map +1 -0
- package/dist/chunk-ZFLHWJ56.js +3 -0
- package/dist/chunk-ZFLHWJ56.js.map +1 -0
- package/dist/debug-timeline-DpnRMnLU.d.cts +87 -0
- package/dist/debug-timeline-L13P-U2I.d.ts +87 -0
- package/dist/devtools.cjs +2 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +354 -0
- package/dist/devtools.d.ts +354 -0
- package/dist/devtools.js +2 -0
- package/dist/devtools.js.map +1 -0
- package/dist/evals.cjs +2 -0
- package/dist/evals.cjs.map +1 -0
- package/dist/evals.d.cts +361 -0
- package/dist/evals.d.ts +361 -0
- package/dist/evals.js +2 -0
- package/dist/evals.js.map +1 -0
- package/dist/gemini.cjs +1 -1
- package/dist/gemini.d.cts +1 -1
- package/dist/gemini.d.ts +1 -1
- package/dist/gemini.js +1 -1
- package/dist/gemini.js.map +1 -1
- package/dist/guardrails.cjs +2 -0
- package/dist/guardrails.cjs.map +1 -0
- package/dist/guardrails.d.cts +618 -0
- package/dist/guardrails.d.ts +618 -0
- package/dist/guardrails.js +2 -0
- package/dist/guardrails.js.map +1 -0
- package/dist/health-monitor-C6xoXrQz.d.cts +55 -0
- package/dist/health-monitor-qL9RNMH3.d.ts +55 -0
- package/dist/index.cjs +21 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1202 -4542
- package/dist/index.d.ts +1202 -4542
- package/dist/index.js +21 -99
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +2 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +450 -0
- package/dist/mcp.d.ts +450 -0
- package/dist/mcp.js +2 -0
- package/dist/mcp.js.map +1 -0
- package/dist/multi-agent-orchestrator-QWWQKKGX.js +2 -0
- package/dist/{multi-agent-orchestrator-4PXNYRHB.js.map → multi-agent-orchestrator-QWWQKKGX.js.map} +1 -1
- package/dist/multi-agent-orchestrator-Y5U4JCFO.cjs +2 -0
- package/dist/{multi-agent-orchestrator-KFGTEGE5.cjs.map → multi-agent-orchestrator-Y5U4JCFO.cjs.map} +1 -1
- package/dist/multi-agent.cjs +2 -0
- package/dist/multi-agent.cjs.map +1 -0
- package/dist/multi-agent.d.cts +1429 -0
- package/dist/multi-agent.d.ts +1429 -0
- package/dist/multi-agent.js +2 -0
- package/dist/multi-agent.js.map +1 -0
- package/dist/ollama.cjs +1 -1
- package/dist/ollama.d.cts +1 -1
- package/dist/ollama.d.ts +1 -1
- package/dist/ollama.js +2 -2
- package/dist/ollama.js.map +1 -1
- package/dist/openai.cjs +1 -1
- package/dist/openai.d.cts +2 -2
- package/dist/openai.d.ts +2 -2
- package/dist/openai.js +1 -1
- package/dist/openai.js.map +1 -1
- package/dist/{orchestrator-types-CTfIKk0W.d.ts → orchestrator-types-DGBhL6mc.d.ts} +5 -138
- package/dist/{orchestrator-types-Bh8r3_Sq.d.cts → orchestrator-types-DeIMRLR7.d.cts} +5 -138
- package/dist/predicate.cjs +2 -0
- package/dist/predicate.cjs.map +1 -0
- package/dist/predicate.d.cts +371 -0
- package/dist/predicate.d.ts +371 -0
- package/dist/predicate.js +2 -0
- package/dist/predicate.js.map +1 -0
- package/dist/{semantic-cache-nBpQqILc.d.cts → semantic-cache-DM7ev7NQ.d.cts} +1 -1
- package/dist/{semantic-cache-nBpQqILc.d.ts → semantic-cache-DM7ev7NQ.d.ts} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -2
- package/dist/testing.d.ts +4 -2
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/{types-CRmwFnVk.d.cts → types-DJ09LjZX.d.cts} +1 -1
- package/dist/{types-CRmwFnVk.d.ts → types-DJ09LjZX.d.ts} +1 -1
- package/package.json +32 -2
- package/dist/chunk-Q3PQLWBR.js +0 -16
- package/dist/chunk-RW4R3O5P.js +0 -72
- package/dist/chunk-RW4R3O5P.js.map +0 -1
- package/dist/chunk-W6MVJKWN.cjs +0 -3
- package/dist/chunk-W6MVJKWN.cjs.map +0 -1
- package/dist/chunk-W6WZBQER.js +0 -3
- package/dist/chunk-W6WZBQER.js.map +0 -1
- package/dist/chunk-X3VQ5F7D.cjs +0 -72
- package/dist/chunk-X3VQ5F7D.cjs.map +0 -1
- package/dist/multi-agent-orchestrator-4PXNYRHB.js +0 -2
- package/dist/multi-agent-orchestrator-KFGTEGE5.cjs +0 -2
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { FactPredicate, SchemaValidationError } from '@directive-run/core';
|
|
2
|
+
import { c as AgentRunner, b as AgentLike } from './types-DJ09LjZX.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* predicateFromIntent — let an LLM emit a typed FactPredicate as JSON,
|
|
6
|
+
* structurally + semantically validated before it ever reaches your
|
|
7
|
+
* constraint engine.
|
|
8
|
+
*
|
|
9
|
+
* Pipeline per call attempt:
|
|
10
|
+
*
|
|
11
|
+
* 1. Output-size check (reject before JSON.parse for DoS guard)
|
|
12
|
+
* 2. JSON.parse via extractJsonFromOutput (handles surrounding prose)
|
|
13
|
+
* 3. validatePredicate (structural: closed operator set, depth, JSON safety)
|
|
14
|
+
* 4. Operator-count check
|
|
15
|
+
* 5. validatePredicateAgainstSchema (semantic: operator-on-kind matrix)
|
|
16
|
+
*
|
|
17
|
+
* On any failure: a structured error message — including the offending
|
|
18
|
+
* clause's path, the allowed operators for that fact's kind, and the
|
|
19
|
+
* original schema kinds — is fed back to the LLM in the next attempt.
|
|
20
|
+
*
|
|
21
|
+
* Returns the validated FactPredicate. Throws PredicateFromIntentError
|
|
22
|
+
* on retry exhaustion. NEVER returns a partial / unvalidated predicate.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
interface PredicateFromIntentOptions<_F = Record<string, unknown>> {
|
|
26
|
+
/** Natural-language intent (untrusted user input — sanitize via `redact`). */
|
|
27
|
+
intent: string;
|
|
28
|
+
/**
|
|
29
|
+
* Module schema (must expose builders with `_typeName` or `_kind`).
|
|
30
|
+
* Pass either `{ facts: {...} }` or a bare `Record<string, builder>`.
|
|
31
|
+
*/
|
|
32
|
+
schema: unknown;
|
|
33
|
+
/** AgentRunner from `@directive-run/ai` adapters (createOpenAIRunner, etc.). */
|
|
34
|
+
runner: AgentRunner;
|
|
35
|
+
/**
|
|
36
|
+
* Optional agent override. Default is `{ name: "predicate-emitter" }`
|
|
37
|
+
* with our system prompt; pass `instructions` to append additional
|
|
38
|
+
* context.
|
|
39
|
+
*/
|
|
40
|
+
agent?: AgentLike;
|
|
41
|
+
/**
|
|
42
|
+
* Optional dotted-path namespace; useful for cross-module systems
|
|
43
|
+
* where the LLM should emit a predicate over `auth.token` (default:
|
|
44
|
+
* the schema's root facts).
|
|
45
|
+
*/
|
|
46
|
+
factPath?: string;
|
|
47
|
+
/** Max retries on validation failure. Default 3. */
|
|
48
|
+
maxRetries?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Hard byte cap on the LLM's raw output, BEFORE JSON.parse. Defaults
|
|
51
|
+
* to 64 KiB. A larger predicate is rejected outright; protects
|
|
52
|
+
* against multi-MB-payload DoS where the predicate is technically
|
|
53
|
+
* structurally valid.
|
|
54
|
+
*/
|
|
55
|
+
maxPredicateBytes?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Hard cap on the number of operator clauses in the predicate.
|
|
58
|
+
* Defaults to 256. Protects against `{ $any: [{ x: 1 }, … x100,000 ] }`
|
|
59
|
+
* style operator-count exhaustion.
|
|
60
|
+
*/
|
|
61
|
+
maxOperatorCount?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Optional sanitizer applied to `intent` BEFORE it lands in the
|
|
64
|
+
* system prompt. Useful for stripping or redacting user-controlled
|
|
65
|
+
* content that looks like prompt-injection.
|
|
66
|
+
*/
|
|
67
|
+
redact?: (intent: string) => string;
|
|
68
|
+
/**
|
|
69
|
+
* Hard cap on the length of each `$in` / `$nin` array operand the LLM
|
|
70
|
+
* may emit. Defaults to 1000. Forwarded to
|
|
71
|
+
* `validatePredicateAgainstSchema`'s `maxArrayOperandLength`.
|
|
72
|
+
*/
|
|
73
|
+
maxArrayOperandLength?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Optional `AbortSignal` for cooperative cancellation. (N6)
|
|
76
|
+
*
|
|
77
|
+
* The retry loop checks `signal.aborted` between attempts AND forwards
|
|
78
|
+
* the signal into the runner call itself (`runner(agent, input, { signal })`).
|
|
79
|
+
* Whether the in-flight LLM call honors the signal depends on the runner:
|
|
80
|
+
* fetch-based adapters (the bundled OpenAI / Anthropic / Ollama runners)
|
|
81
|
+
* thread it through to `fetch`, so the network call aborts mid-stream.
|
|
82
|
+
* A custom runner that ignores the signal still delivers cancellation
|
|
83
|
+
* at the next retry boundary.
|
|
84
|
+
*
|
|
85
|
+
* On abort: throws `Error("aborted")`.
|
|
86
|
+
*
|
|
87
|
+
* NOTE: `predicateFromIntent` does NOT limit in-flight calls — callers
|
|
88
|
+
* MUST wrap with a concurrency limiter (e.g. `p-limit`) to bound
|
|
89
|
+
* fan-out under load.
|
|
90
|
+
*/
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
/**
|
|
93
|
+
* When `true`, the {@link PredicateFromIntentProvenance} returned by
|
|
94
|
+
* `predicateFromIntentWithProvenance` omits the raw `intent` string and
|
|
95
|
+
* stores only the SHA-256 `intentHash`. Use this in PII-sensitive
|
|
96
|
+
* contexts where the original intent must not be persisted. (M6)
|
|
97
|
+
*
|
|
98
|
+
* **Default `false` for back-compat.** For PII-sensitive deployments,
|
|
99
|
+
* ALWAYS set `redactIntent: true` — the raw intent may contain
|
|
100
|
+
* user-supplied content (names, emails, medical or financial details,
|
|
101
|
+
* customer messages) that becomes a permanent record in
|
|
102
|
+
* `provenance.intent`. The default is opt-in only because flipping it
|
|
103
|
+
* now would silently strip diagnostic data from existing callers; v2
|
|
104
|
+
* may flip this default (tracked in IDEAS.md).
|
|
105
|
+
*
|
|
106
|
+
* Pair with a `redact:` sanitizer when the intent itself must be
|
|
107
|
+
* scrubbed BEFORE it lands in the LLM prompt — `redactIntent` controls
|
|
108
|
+
* only what enters the provenance record, not what the LLM sees.
|
|
109
|
+
*/
|
|
110
|
+
redactIntent?: boolean;
|
|
111
|
+
}
|
|
112
|
+
interface PredicateFromIntentDiagnostics<F = Record<string, unknown>> {
|
|
113
|
+
/** The validated predicate (`null` if all retries failed). */
|
|
114
|
+
predicate: FactPredicate<F> | null;
|
|
115
|
+
/** Number of LLM calls actually made. */
|
|
116
|
+
attempts: number;
|
|
117
|
+
/** Errors encountered across all attempts (most recent last). */
|
|
118
|
+
errors: ReadonlyArray<{
|
|
119
|
+
attempt: number;
|
|
120
|
+
reason: string;
|
|
121
|
+
details?: readonly SchemaValidationError[];
|
|
122
|
+
}>;
|
|
123
|
+
/** The raw LLM output from the final attempt — useful for debugging. */
|
|
124
|
+
lastRawOutput?: string;
|
|
125
|
+
}
|
|
126
|
+
/** Thrown by `predicateFromIntent` on retry exhaustion. `predicateFromIntentRaw` returns these as a diagnostics payload instead. */
|
|
127
|
+
declare class PredicateFromIntentError extends Error {
|
|
128
|
+
readonly attempts: number;
|
|
129
|
+
readonly errors: ReadonlyArray<{
|
|
130
|
+
attempt: number;
|
|
131
|
+
reason: string;
|
|
132
|
+
details?: readonly SchemaValidationError[];
|
|
133
|
+
}>;
|
|
134
|
+
readonly lastRawOutput: string | undefined;
|
|
135
|
+
readonly name = "PredicateFromIntentError";
|
|
136
|
+
constructor(message: string, attempts: number, errors: ReadonlyArray<{
|
|
137
|
+
attempt: number;
|
|
138
|
+
reason: string;
|
|
139
|
+
details?: readonly SchemaValidationError[];
|
|
140
|
+
}>, lastRawOutput: string | undefined);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Ask an LLM to emit a FactPredicate matching the user's intent, then
|
|
144
|
+
* validate it structurally + semantically before returning. On validation
|
|
145
|
+
* failure, retries with structured error feedback in the next prompt.
|
|
146
|
+
*
|
|
147
|
+
* Throws {@link PredicateFromIntentError} on retry exhaustion. NEVER
|
|
148
|
+
* returns a partial / unvalidated predicate.
|
|
149
|
+
*
|
|
150
|
+
* **Rate limiting:** this function does NOT limit in-flight calls. Wrap
|
|
151
|
+
* with a concurrency limiter (e.g. `p-limit` / `Bottleneck`) before
|
|
152
|
+
* exposing it to user-driven traffic. Pass an `AbortSignal` via `opts.signal`
|
|
153
|
+
* for cooperative cancellation between retry attempts.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* import { createOpenAIRunner } from "@directive-run/ai/openai";
|
|
158
|
+
* import { predicateFromIntent } from "@directive-run/ai";
|
|
159
|
+
*
|
|
160
|
+
* const runner = createOpenAIRunner({ apiKey, model: "gpt-4o-mini" });
|
|
161
|
+
*
|
|
162
|
+
* const predicate = await predicateFromIntent({
|
|
163
|
+
* intent: "checkout is unblocked when the cart total is at least 50",
|
|
164
|
+
* schema: myModule.schema,
|
|
165
|
+
* runner,
|
|
166
|
+
* });
|
|
167
|
+
* // → { cartTotal: { $gte: 50 } }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare function predicateFromIntent<F = Record<string, unknown>>(opts: PredicateFromIntentOptions<F>): Promise<FactPredicate<F>>;
|
|
171
|
+
/**
|
|
172
|
+
* Lower-level variant — returns the validated predicate (or null) plus
|
|
173
|
+
* full diagnostics. Use when you want to surface validation telemetry,
|
|
174
|
+
* preview the LLM's last raw output, or display per-attempt errors in
|
|
175
|
+
* a UI.
|
|
176
|
+
*/
|
|
177
|
+
declare function predicateFromIntentRaw<F = Record<string, unknown>>(opts: PredicateFromIntentOptions<F>): Promise<PredicateFromIntentDiagnostics<F>>;
|
|
178
|
+
interface PredicateToolSpecOptions {
|
|
179
|
+
/** Tool name. Default `"emit_predicate"`. */
|
|
180
|
+
name?: string;
|
|
181
|
+
/** Tool description. Default: a one-liner describing predicate emission. */
|
|
182
|
+
description?: string;
|
|
183
|
+
/** Optional dotted-path namespace to restrict the tool's scope. */
|
|
184
|
+
factPath?: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Anthropic Messages API tool shape. Drop into the `tools: [...]` array.
|
|
188
|
+
* Anthropic's API expects `input_schema` at the top level of the tool.
|
|
189
|
+
*/
|
|
190
|
+
interface PredicateToolSpecAnthropic {
|
|
191
|
+
name: string;
|
|
192
|
+
description: string;
|
|
193
|
+
input_schema: {
|
|
194
|
+
type: "object";
|
|
195
|
+
properties: {
|
|
196
|
+
predicate: {
|
|
197
|
+
type: "object";
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
required: ["predicate"];
|
|
201
|
+
};
|
|
202
|
+
/** Human-readable schema description — embed in your tool's "description" if your provider concatenates them. */
|
|
203
|
+
schemaSummary: string;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* OpenAI Chat Completions / Responses API tool shape. Drop into the
|
|
207
|
+
* `tools: [...]` array. OpenAI nests the function payload under
|
|
208
|
+
* `function: { name, description, parameters }`.
|
|
209
|
+
*/
|
|
210
|
+
interface PredicateToolSpecOpenAI {
|
|
211
|
+
type: "function";
|
|
212
|
+
function: {
|
|
213
|
+
name: string;
|
|
214
|
+
description: string;
|
|
215
|
+
parameters: {
|
|
216
|
+
type: "object";
|
|
217
|
+
properties: {
|
|
218
|
+
predicate: {
|
|
219
|
+
type: "object";
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
required: ["predicate"];
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
/** Human-readable schema description — embed in your tool's "description" if your provider concatenates them. */
|
|
226
|
+
schemaSummary: string;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* @deprecated Use {@link PredicateToolSpecAnthropic} (or
|
|
230
|
+
* {@link PredicateToolSpecOpenAI}) directly. Kept as an alias for the
|
|
231
|
+
* pre-split shape that v1.12.x callers depend on; identical to
|
|
232
|
+
* `PredicateToolSpecAnthropic`.
|
|
233
|
+
*/
|
|
234
|
+
type PredicateToolSpec = PredicateToolSpecAnthropic;
|
|
235
|
+
/**
|
|
236
|
+
* OpenAI Chat Completions / Responses API tool spec for predicate
|
|
237
|
+
* emission. Drop the result into your `tools: [...]` array; the model
|
|
238
|
+
* will be told to emit a predicate matching this schema.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```ts
|
|
242
|
+
* const tool = predicateToolSpecOpenAI(myModule.schema, { name: "set_checkout_rule" });
|
|
243
|
+
*
|
|
244
|
+
* await openai.chat.completions.create({
|
|
245
|
+
* model: "gpt-4o-mini",
|
|
246
|
+
* tools: [tool],
|
|
247
|
+
* messages: [...],
|
|
248
|
+
* });
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
declare function predicateToolSpecOpenAI(schema: unknown, opts?: PredicateToolSpecOptions): PredicateToolSpecOpenAI;
|
|
252
|
+
/**
|
|
253
|
+
* Anthropic Messages API tool spec for predicate emission. Drop the
|
|
254
|
+
* result into your `tools: [...]` array; the model will be told to emit
|
|
255
|
+
* a predicate matching this schema.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* const tool = predicateToolSpecAnthropic(myModule.schema, { name: "set_checkout_rule" });
|
|
260
|
+
*
|
|
261
|
+
* await anthropic.messages.create({
|
|
262
|
+
* model: "claude-3-5-sonnet-latest",
|
|
263
|
+
* tools: [tool],
|
|
264
|
+
* messages: [...],
|
|
265
|
+
* });
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
declare function predicateToolSpecAnthropic(schema: unknown, opts?: PredicateToolSpecOptions): PredicateToolSpecAnthropic;
|
|
269
|
+
/**
|
|
270
|
+
* @deprecated Use {@link predicateToolSpecAnthropic} (or
|
|
271
|
+
* {@link predicateToolSpecOpenAI}) directly. Back-compat alias for
|
|
272
|
+
* v1.12.x callers — emits the Anthropic shape, unchanged.
|
|
273
|
+
*/
|
|
274
|
+
declare function predicateToolSpec(schema: unknown, opts?: PredicateToolSpecOptions): PredicateToolSpec;
|
|
275
|
+
interface PredicateFromIntentProvenance {
|
|
276
|
+
/**
|
|
277
|
+
* Resolved model name when the caller passes `agent: { model }`,
|
|
278
|
+
* otherwise `"unknown"`.
|
|
279
|
+
*
|
|
280
|
+
* NOTE: most callers omit `agent` (the default `predicate-emitter`
|
|
281
|
+
* agent has no model field set), so `model` is `"unknown"` by default.
|
|
282
|
+
* v1 does NOT read provider-detected model strings from `RunResult` —
|
|
283
|
+
* that requires every adapter to surface `runResult.model`, which the
|
|
284
|
+
* current `AgentRunner` contract does not. Tracked for v2; callers who
|
|
285
|
+
* need provider attribution today should pass `agent: { name, model: "..." }`.
|
|
286
|
+
*/
|
|
287
|
+
readonly model: string;
|
|
288
|
+
/**
|
|
289
|
+
* Sanitized intent string actually sent to the LLM (post-redact). When
|
|
290
|
+
* `redactIntent: true` was passed, this field is omitted entirely — only
|
|
291
|
+
* `intentHash` is populated.
|
|
292
|
+
*/
|
|
293
|
+
readonly intent?: string;
|
|
294
|
+
/**
|
|
295
|
+
* SHA-256 hex hash of the sanitized intent string (or djb2 fallback
|
|
296
|
+
* when `crypto.subtle` is unavailable). Always present — even when
|
|
297
|
+
* `intent` is omitted via `redactIntent`. (M6)
|
|
298
|
+
*/
|
|
299
|
+
readonly intentHash: string;
|
|
300
|
+
/** Number of LLM calls that ran before the final predicate was accepted. */
|
|
301
|
+
readonly attemptCount: number;
|
|
302
|
+
/** ISO timestamp when the predicate was returned. */
|
|
303
|
+
readonly emittedAt: string;
|
|
304
|
+
/**
|
|
305
|
+
* Hash of the VALIDATED predicate (canonicalized via stableStringify
|
|
306
|
+
* before hashing). Two semantically-identical predicates emitted with
|
|
307
|
+
* different whitespace or key order produce the SAME `predicateHash`.
|
|
308
|
+
* Sufficient as a tamper-evident pointer alongside the persisted
|
|
309
|
+
* predicate. (N3)
|
|
310
|
+
*
|
|
311
|
+
* Renamed from `rawOutputHash` in v1.13.x — the old name hashed the
|
|
312
|
+
* raw LLM output string, which made two whitespace-different responses
|
|
313
|
+
* for the same logical predicate hash differently. Callers persisting
|
|
314
|
+
* the old `rawOutputHash` value should re-derive it from the stored
|
|
315
|
+
* predicate using `hashObject(predicate)` from `@directive-run/core/internals`.
|
|
316
|
+
*/
|
|
317
|
+
readonly predicateHash: string;
|
|
318
|
+
}
|
|
319
|
+
interface PredicateFromIntentWithProvenanceResult<F = Record<string, unknown>> {
|
|
320
|
+
readonly predicate: FactPredicate<F>;
|
|
321
|
+
readonly provenance: PredicateFromIntentProvenance;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Like {@link predicateFromIntent} but additionally returns a structured
|
|
325
|
+
* provenance record — the model name, sanitized intent (or its hash),
|
|
326
|
+
* attempt count, timestamp, and a canonical hash of the validated
|
|
327
|
+
* predicate.
|
|
328
|
+
*
|
|
329
|
+
* **Production deployments MUST persist the provenance record alongside
|
|
330
|
+
* the predicate.** Without it, auditing "where did this rule come from?"
|
|
331
|
+
* becomes guesswork.
|
|
332
|
+
*
|
|
333
|
+
* Throws {@link PredicateFromIntentError} on retry exhaustion — same
|
|
334
|
+
* semantics as the un-provenanced variant.
|
|
335
|
+
*
|
|
336
|
+
* **PII guidance (M6):** pass `redactIntent: true` to omit the raw
|
|
337
|
+
* intent from the provenance record and persist only the `intentHash`.
|
|
338
|
+
* Useful when the intent itself is sensitive (medical, financial,
|
|
339
|
+
* customer messages, etc.).
|
|
340
|
+
*
|
|
341
|
+
* **Hash semantics (N3):**
|
|
342
|
+
* - `predicateHash` hashes the VALIDATED predicate object via stable
|
|
343
|
+
* stringification — two whitespace-different LLM outputs that parse to
|
|
344
|
+
* the same predicate produce the same hash.
|
|
345
|
+
* - `intentHash` hashes the sanitized intent STRING (SHA-256 when
|
|
346
|
+
* available, djb2 fallback).
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```ts
|
|
350
|
+
* const { predicate, provenance } = await predicateFromIntentWithProvenance({
|
|
351
|
+
* intent: "block checkout when cart > 10k",
|
|
352
|
+
* schema: checkoutModule.schema,
|
|
353
|
+
* runner,
|
|
354
|
+
* agent: { name: "predicate-emitter", model: "gpt-4o-mini" },
|
|
355
|
+
* redactIntent: false, // default: store both intent + intentHash
|
|
356
|
+
* });
|
|
357
|
+
*
|
|
358
|
+
* await db.predicates.insert({
|
|
359
|
+
* predicate,
|
|
360
|
+
* model: provenance.model,
|
|
361
|
+
* intent: provenance.intent, // omitted when redactIntent: true
|
|
362
|
+
* intentHash: provenance.intentHash,
|
|
363
|
+
* emittedAt: provenance.emittedAt,
|
|
364
|
+
* predicateHash: provenance.predicateHash,
|
|
365
|
+
* attempts: provenance.attemptCount,
|
|
366
|
+
* });
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
declare function predicateFromIntentWithProvenance<F = Record<string, unknown>>(opts: PredicateFromIntentOptions<F>): Promise<PredicateFromIntentWithProvenanceResult<F>>;
|
|
370
|
+
|
|
371
|
+
export { type PredicateFromIntentDiagnostics, PredicateFromIntentError, type PredicateFromIntentOptions, type PredicateFromIntentProvenance, type PredicateFromIntentWithProvenanceResult, type PredicateToolSpec, type PredicateToolSpecAnthropic, type PredicateToolSpecOpenAI, type PredicateToolSpecOptions, predicateFromIntent, predicateFromIntentRaw, predicateFromIntentWithProvenance, predicateToolSpec, predicateToolSpecAnthropic, predicateToolSpecOpenAI };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export{a as PredicateFromIntentError,b as predicateFromIntent,c as predicateFromIntentRaw,g as predicateFromIntentWithProvenance,f as predicateToolSpec,e as predicateToolSpecAnthropic,d as predicateToolSpecOpenAI}from'./chunk-POBEEJR6.js';import'./chunk-UR4ZGO7V.js';//# sourceMappingURL=predicate.js.map
|
|
2
|
+
//# sourceMappingURL=predicate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"predicate.js"}
|
|
@@ -268,4 +268,4 @@ declare function createBatchedEmbedder(config: {
|
|
|
268
268
|
maxWaitMs?: number;
|
|
269
269
|
}): BatchedEmbedder;
|
|
270
270
|
|
|
271
|
-
export { type BatchedEmbedder as B, type CacheEntry as C, type
|
|
271
|
+
export { type BatchedEmbedder as B, type CacheEntry as C, type EmbedderFn as E, type SemanticCache as S, type Embedding as a, type CacheLookupResult as b, type CacheStats as c, type SemanticCacheConfig as d, type SemanticCacheStorage as e, createBatchedEmbedder as f, createInMemoryStorage as g, createSemanticCache as h, createSemanticCacheGuardrail as i, createTestEmbedder as j };
|
|
@@ -268,4 +268,4 @@ declare function createBatchedEmbedder(config: {
|
|
|
268
268
|
maxWaitMs?: number;
|
|
269
269
|
}): BatchedEmbedder;
|
|
270
270
|
|
|
271
|
-
export { type BatchedEmbedder as B, type CacheEntry as C, type
|
|
271
|
+
export { type BatchedEmbedder as B, type CacheEntry as C, type EmbedderFn as E, type SemanticCache as S, type Embedding as a, type CacheLookupResult as b, type CacheStats as c, type SemanticCacheConfig as d, type SemanticCacheStorage as e, createBatchedEmbedder as f, createInMemoryStorage as g, createSemanticCache as h, createSemanticCacheGuardrail as i, createTestEmbedder as j };
|
package/dist/testing.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var chunkXV2QSBBE_cjs=require('./chunk-XV2QSBBE.cjs'),chunkX3VQ5F7D_cjs=require('./chunk-X3VQ5F7D.cjs');function b(r={}){let{defaultResponse:e={output:"mock response",totalTokens:10},responses:t={},recordCalls:n=true,onRun:o}=r,s=[],a=new Map(Object.entries(t)),i=e;return {run:async(l,c,g)=>{o?.(l,c),n&&s.push({agent:l,input:c,options:g,timestamp:Date.now()});let d=a.get(l.name)??i;if(d.generate){let p=d.generate(c,l);d={...d,...p};}if(d.error)throw d.error;d.delay&&d.delay>0&&await new Promise(p=>setTimeout(p,d.delay));let f=d.messages??[];for(let p of f)g?.onMessage?.(p);let m=d.toolCalls??[];for(let p of m)g?.onToolCall?.(p);return {output:d.output,messages:f,toolCalls:m,totalTokens:d.totalTokens??10}},getCalls:()=>[...s],getCallsFor:l=>s.filter(c=>c.agent.name===l),clearCalls:()=>s.length=0,setResponse:(l,c)=>a.set(l,c),setDefaultResponse:l=>i=l}}async function T(r,e,t){let n={agentName:"test-agent",input:"",...e},o={agentName:e.agentName??"test-agent",input:e.input??"",facts:t?.facts??{},...t},s=Date.now(),a=await r(n,o),i=Date.now()-s;return {...a,duration:i,testedData:n,assertPassed(){if(!a.passed)throw new Error(`Expected guardrail to pass, but it failed: ${a.reason}`)},assertFailed(u){if(a.passed)throw new Error("Expected guardrail to fail, but it passed");if(u!==void 0){if(typeof u=="string"&&!a.reason?.includes(u))throw new Error(`Expected failure reason to include "${u}", got: ${a.reason}`);if(u instanceof RegExp&&!u.test(a.reason??""))throw new Error(`Expected failure reason to match ${u}, got: ${a.reason}`)}},assertTransformed(u){if(a.transformed===void 0)throw new Error("Expected guardrail to transform input, but no transformation occurred");if(u!==void 0&&a.transformed!==u)throw new Error(`Expected transformation to be ${JSON.stringify(u)}, got: ${JSON.stringify(a.transformed)}`)}}}async function x(r,e){let t=[],n=[];for(let o=0;o<e.length;o++){let s=e[o],a=await T(r,s.input,s.context);t.push(a),(a.passed?a.transformed!==void 0?"transform":"pass":"fail")!==s.expect&&n.push({index:o,expected:s.expect,actual:a});}return {results:t,allPassed:()=>n.length===0,failures:()=>n}}function R(r={}){let{autoApprove:e,autoReject:t,delay:n=0,recordRequests:o=true}=r,s=[],a=new Map,i=[];return {async handle(u){o&&s.push(u);for(let l=i.length-1;l>=0;l--){let c=i[l];c.predicate(u)&&(i.splice(l,1),c.resolve(u));}return n>0&&await new Promise(l=>setTimeout(l,n)),t&&t(u)?"rejected":e?.(u)?"approved":new Promise(l=>{a.set(u.id,{request:u,resolve:l});})},getRequests:()=>[...s],clearRequests:()=>s.length=0,approve(u){let l=a.get(u);l&&(l.resolve("approved"),a.delete(u));},reject(u,l){let c=a.get(u);if(c){c.resolve("rejected"),a.delete(u);let g=s.find(d=>d.id===u);g&&(g.rejectionReason=l);}},waitForRequest(u,l=5e3){let c=s.find(u);return c?Promise.resolve(c):new Promise((g,d)=>{let f={predicate:u,resolve:p=>{clearTimeout(m),g(p);}},m=setTimeout(()=>{let p=i.indexOf(f);p>=0&&i.splice(p,1),d(new Error("Timeout waiting for approval request"));},l);i.push(f);})}}}function C(r={}){let{mockResponses:e,defaultMockResponse:t,...n}=r,o=b({responses:e,defaultResponse:t}),s=R(),a=chunkXV2QSBBE_cjs.a({...n,runner:o.run,onApprovalRequest:u=>{s.handle(u),n.onApprovalRequest?.(u);}}),i=Object.create(a);return i.mockRunner=o,i.approvalSimulator=s,i.getCalls=()=>o.getCalls(),i.getApprovalRequests=()=>s.getRequests(),i.resetAll=()=>{a.reset(),o.clearCalls(),s.clearRequests();},i}function O(){let r=[];return {plugin:{name:"constraint-recorder",onRequirementCreated(e){r.push({constraintId:e.constraintId,triggered:true,requirement:e.requirement,facts:e.facts,timestamp:Date.now()});}},getSnapshots:()=>[...r],clearSnapshots:()=>r.length=0}}function M(r,e){let t=r.facts;if(e.agentStatus!==void 0&&t.agent.status!==e.agentStatus)throw new Error(`Expected agent status to be "${e.agentStatus}", got "${t.agent.status}"`);if(e.tokenUsage!==void 0){let{min:n,max:o,exact:s}=e.tokenUsage;if(s!==void 0&&t.agent.tokenUsage!==s)throw new Error(`Expected token usage to be exactly ${s}, got ${t.agent.tokenUsage}`);if(n!==void 0&&t.agent.tokenUsage<n)throw new Error(`Expected token usage to be at least ${n}, got ${t.agent.tokenUsage}`);if(o!==void 0&&t.agent.tokenUsage>o)throw new Error(`Expected token usage to be at most ${o}, got ${t.agent.tokenUsage}`)}if(e.pendingApprovals!==void 0&&t.approval.pending.length!==e.pendingApprovals)throw new Error(`Expected ${e.pendingApprovals} pending approvals, got ${t.approval.pending.length}`);if(e.conversationLength!==void 0){let{min:n,max:o,exact:s}=e.conversationLength,a=t.conversation.length;if(s!==void 0&&a!==s)throw new Error(`Expected conversation length to be exactly ${s}, got ${a}`);if(n!==void 0&&a<n)throw new Error(`Expected conversation length to be at least ${n}, got ${a}`);if(o!==void 0&&a>o)throw new Error(`Expected conversation length to be at most ${o}, got ${a}`)}}function q(r=Date.now()){let e=r,t=r;return {now:()=>e,advance:n=>{e+=n;},set:n=>{e=n;},reset:()=>{e=t;}}}function D(r){let{mockResponses:e={},defaultMockResponse:t,mockTasks:n,...o}=r;if(n){let c=o.tasks??{};for(let[g,d]of Object.entries(n))c[g]||(c[g]=y(d.output,{delay:d.delay,shouldError:d.shouldError}));o.tasks=c;}let s={};for(let[c,g]of Object.entries(e)){let d=o.agents[c];d&&(s[d.agent.name]=g);}let a=b({responses:s,defaultResponse:t}),i=R(),u=chunkX3VQ5F7D_cjs.Da({...o,runner:a.run,onApprovalRequest:c=>{i.handle(c),o.onApprovalRequest?.(c);}}),l=Object.create(u);return l.mockRunner=a,l.approvalSimulator=i,l.getCalls=()=>a.getCalls(),l.getApprovalRequests=()=>i.getRequests(),l.resetAll=()=>{u.reset(),a.clearCalls(),i.clearRequests();},l}function N(r,e){if(e.taskStatus)for(let[t,n]of Object.entries(e.taskStatus)){let o=r.getTaskState(t);if(!o)throw new Error(`Expected task "${t}" to exist, but it was not found`);if(o.status!==n)throw new Error(`Expected task "${t}" status to be "${n}", got "${o.status}"`)}if(e.agentStatus)for(let[t,n]of Object.entries(e.agentStatus)){let o=r.getAgentState(t);if(!o)throw new Error(`Expected agent "${t}" to exist, but it was not found`);if(o.status!==n)throw new Error(`Expected agent "${t}" status to be "${n}", got "${o.status}"`)}if(e.totalTokens){let{agentId:t,min:n,max:o}=e.totalTokens;if(t){let s=r.getAgentState(t);if(!s)throw new Error(`Expected agent "${t}" to exist, but it was not found`);if(n!==void 0&&s.totalTokens<n)throw new Error(`Expected agent "${t}" tokens to be at least ${n}, got ${s.totalTokens}`);if(o!==void 0&&s.totalTokens>o)throw new Error(`Expected agent "${t}" tokens to be at most ${o}, got ${s.totalTokens}`)}else {let s=r.getAllAgentStates(),a=Object.values(s).reduce((i,u)=>i+u.totalTokens,0);if(n!==void 0&&a<n)throw new Error(`Expected total tokens to be at least ${n}, got ${a}`);if(o!==void 0&&a>o)throw new Error(`Expected total tokens to be at most ${o}, got ${a}`)}}if(e.globalTokens){let{min:t,max:n}=e.globalTokens,o=r.totalTokens;if(t!==void 0&&o<t)throw new Error(`Expected global tokens to be at least ${t}, got ${o}`);if(n!==void 0&&o>n)throw new Error(`Expected global tokens to be at most ${n}, got ${o}`)}if(e.pendingHandoffs!==void 0){let t=r.getPendingHandoffs().length;if(t!==e.pendingHandoffs)throw new Error(`Expected ${e.pendingHandoffs} pending handoffs, got ${t}`)}}function y(r,e){return {run:async(t,n)=>{if(n.aborted)throw new Error("Task aborted");if(e?.delay&&e.delay>0&&await new Promise((o,s)=>{let a=setTimeout(o,e.delay);n.addEventListener("abort",()=>{clearTimeout(a),s(new Error("Task aborted"));},{once:true});}),e?.shouldError)throw new Error("Mock task error");return r},label:e?.label??"Mock Task",description:e?.description}}function P(r,e,t){return chunkX3VQ5F7D_cjs.ga(r,e??(o=>o.outputs),t)}function I(r,e){if(e.nodeStatuses)for(let[t,n]of Object.entries(e.nodeStatuses)){let o=r.statuses[t];if(o!==n)throw new Error(`Expected node "${t}" status to be "${n}", got "${o}"`)}if(e.completedNodes){for(let t of e.completedNodes)if(r.statuses[t]!=="completed")throw new Error(`Expected node "${t}" to be completed, got "${r.statuses[t]}"`)}if(e.skippedNodes){for(let t of e.skippedNodes)if(r.statuses[t]!=="skipped")throw new Error(`Expected node "${t}" to be skipped, got "${r.statuses[t]}"`)}if(e.errorNodes){for(let t of e.errorNodes)if(r.statuses[t]!=="error")throw new Error(`Expected node "${t}" to be error, got "${r.statuses[t]}"`)}if(e.outputContains)for(let[t,n]of Object.entries(e.outputContains)){let o=r.outputs[t];if(o!==n)throw new Error(`Expected node "${t}" output to be ${JSON.stringify(n)}, got ${JSON.stringify(o)}`)}}function B(r,e){let t=chunkX3VQ5F7D_cjs.i({maxEvents:e?.maxEvents??500});if(r)for(let n of r)t.record({timestamp:Date.now(),snapshotId:null,agentId:"",...n});return t}function F(r,e){let t=r.getEvents();if(e.totalEvents!==void 0&&t.length!==e.totalEvents)throw new Error(`Expected ${e.totalEvents} timeline events, got ${t.length}`);if(e.minEvents!==void 0&&t.length<e.minEvents)throw new Error(`Expected at least ${e.minEvents} timeline events, got ${t.length}`);if(e.maxEvents!==void 0&&t.length>e.maxEvents)throw new Error(`Expected at most ${e.maxEvents} timeline events, got ${t.length}`);if(e.eventTypes){for(let n of e.eventTypes)if(!t.some(s=>s.type===n))throw new Error(`Expected timeline to contain event of type "${n}", but none found`)}if(e.agentEvents)for(let[n,o]of Object.entries(e.agentEvents)){let s=r.getEventsForAgent(n).length;if(s!==o)throw new Error(`Expected ${o} events for agent "${n}", got ${s}`)}if(e.hasType&&!t.some(o=>o.type===e.hasType))throw new Error(`Expected timeline to contain event of type "${e.hasType}"`);if(e.doesNotHaveType&&t.some(o=>o.type===e.doesNotHaveType))throw new Error(`Expected timeline NOT to contain event of type "${e.doesNotHaveType}"`)}function H(r,e){let t=0,n=e?.failAfter??0;return async(o,s,a)=>{if(t++,n>0&&t<=n)return {output:"success",messages:[],toolCalls:[],totalTokens:10};throw e?.delay&&e.delay>0&&await new Promise(i=>setTimeout(i,e.delay)),r??new Error("Runner failed")}}function L(r,e){if(r.length===0)throw new Error("Expected at least one reroute event, but none occurred");if(e.minReroutes!==void 0&&r.length<e.minReroutes)throw new Error(`Expected at least ${e.minReroutes} reroute events, got ${r.length}`);if(e.fromAgent&&!r.some(n=>n.originalAgent===e.fromAgent))throw new Error(`Expected reroute from agent "${e.fromAgent}", but no matching event found`);if(e.toAgent&&!r.some(n=>n.reroutedTo===e.toAgent))throw new Error(`Expected reroute to agent "${e.toAgent}", but no matching event found`);if(e.reason&&!r.some(n=>typeof e.reason=="string"?n.reason.includes(e.reason):e.reason.test(n.reason)))throw new Error(`Expected reroute reason matching ${e.reason}, but no matching event found`)}function J(r,e,t){let n=r.getMetrics(e);if(t.minScore!==void 0&&n.healthScore<t.minScore)throw new Error(`Expected agent "${e}" health score to be at least ${t.minScore}, got ${n.healthScore}`);if(t.maxScore!==void 0&&n.healthScore>t.maxScore)throw new Error(`Expected agent "${e}" health score to be at most ${t.maxScore}, got ${n.healthScore}`);if(t.circuitState!==void 0&&n.circuitState!==t.circuitState)throw new Error(`Expected agent "${e}" circuit state to be "${t.circuitState}", got "${n.circuitState}"`);if(t.minSuccessRate!==void 0&&n.successRate<t.minSuccessRate)throw new Error(`Expected agent "${e}" success rate to be at least ${t.minSuccessRate}, got ${n.successRate}`)}function U(r=100){let e=new chunkX3VQ5F7D_cjs.G({maxCheckpoints:r}),t=[];return {inner:e,saved:t,getLatest:()=>t[t.length-1],async save(n){return t.push(n),e.save(n)},load:n=>e.load(n),list:()=>e.list(),delete:n=>e.delete(n),clear:()=>e.clear(),prune:()=>e.prune()}}function _(r,e){if(e.orchestratorType!==void 0&&r.orchestratorType!==e.orchestratorType)throw new Error(`Expected checkpoint orchestratorType "${e.orchestratorType}", got "${r.orchestratorType}"`);if(e.hasSystemExport===true&&(!r.systemExport||r.systemExport===""))throw new Error("Expected checkpoint to have non-empty systemExport, but it was empty");if(e.hasTimeline===true&&r.timelineExport===null)throw new Error("Expected checkpoint to have timeline export, but it was null");if(e.hasTimeline===false&&r.timelineExport!==null)throw new Error("Expected checkpoint to have no timeline export, but it was present");if(e.hasMemory===true&&r.memoryExport===null)throw new Error("Expected checkpoint to have memory export, but it was null");if(e.hasMemory===false&&r.memoryExport!==null)throw new Error("Expected checkpoint to have no memory export, but it was present");if(e.label!==void 0&&r.label!==e.label)throw new Error(`Expected checkpoint label "${e.label}", got "${r.label}"`)}function V(r={}){let e=[],t=null,n=false;return {handler:s=>{if(e.push(s),!n)throw new Error("[Directive] BreakpointSimulator: handler called but attachTo() was never called. Breakpoints will not be resolved. Call simulator.attachTo(orchestrator) after creation.");let a=r.autoResumeDelay??0,i=()=>{t&&(r.cancel?t.cancelBreakpoint(s.id,r.cancelReason):t.resumeBreakpoint(s.id,r.modifications));};a>0?setTimeout(i,a):queueMicrotask(i);},hits:e,attachTo:s=>{t=s,n=true;}}}function W(r,e){if(e.count!==void 0&&r.length!==e.count)throw new Error(`Expected ${e.count} breakpoint hits, got ${r.length}`);if(e.type&&!r.some(n=>n.type===e.type)){let n=r.map(o=>o.type).join(", ");throw new Error(`Expected breakpoint of type "${e.type}", found types: [${n}]`)}if(e.agentId&&!r.some(n=>n.agentId===e.agentId)){let n=r.map(o=>o.agentId).join(", ");throw new Error(`Expected breakpoint for agent "${e.agentId}", found agents: [${n}]`)}}function z(r,e){return {safeParse:t=>r(t)?{success:true,data:t}:{success:false,error:{message:"Validation failed"}},description:e}}async function K(r){let e=[];for await(let t of r)e.push(t);return e}function Q(r,e){if(e.minChunks!==void 0&&r.length<e.minChunks)throw new Error(`Expected at least ${e.minChunks} chunks, got ${r.length}`);if(e.agentIds){let t=new Set(r.map(n=>n.agentId));for(let n of e.agentIds)if(!t.has(n))throw new Error(`Expected chunks from agent "${n}", found agents: [${[...t].join(", ")}]`)}if(e.hasDone===true&&!r.some(n=>n.chunk.type==="done"))throw new Error("Expected at least one 'done' chunk, found none");if(e.hasErrors===true&&!r.some(n=>n.chunk.type==="error"))throw new Error("Expected at least one 'error' chunk, found none");if(e.hasErrors===false&&r.some(n=>n.chunk.type==="error"))throw new Error("Expected no 'error' chunks, but found some")}function X(r){let e=r?.passAfter??1,t=r?.feedback??"Needs improvement",n=r?.score,o=0;return (s,a)=>{o++;let i=o>=e;return {passed:i,feedback:i?void 0:t,score:n??(i?1:.5)}}}function Y(r,e){let t=r.getAll();for(let[n,o]of Object.entries(e)){let s=t[n];if(s!==o)throw new Error(`Expected scratchpad key "${n}" to be ${JSON.stringify(o)}, got ${JSON.stringify(s)}`)}}function Z(r,e){let t=r.derived;for(let[n,o]of Object.entries(e)){let s=t[n];if(typeof o=="object"&&o!==null){let a=i=>JSON.stringify(i,Object.keys(i).sort());if(a(s)!==a(o))throw new Error(`Expected derived value "${n}" to be ${JSON.stringify(o)}, got ${JSON.stringify(s)}`)}else if(s!==o)throw new Error(`Expected derived value "${n}" to be ${JSON.stringify(o)}, got ${JSON.stringify(s)}`)}}exports.assertAgentHealth=J;exports.assertBreakpointHit=W;exports.assertCheckpoint=_;exports.assertDagExecution=I;exports.assertDerivedValues=Z;exports.assertMultiAgentState=N;exports.assertMultiplexedStream=Q;exports.assertOrchestratorState=M;exports.assertRerouted=L;exports.assertScratchpadState=Y;exports.assertTimelineEvents=F;exports.collectMultiplexedStream=K;exports.createApprovalSimulator=R;exports.createBreakpointSimulator=V;exports.createConstraintRecorder=O;exports.createFailingRunner=H;exports.createMockAgentRunner=b;exports.createMockSchema=z;exports.createMockTask=y;exports.createTestCheckpointStore=U;exports.createTestDag=P;exports.createTestMultiAgentOrchestrator=D;exports.createTestOrchestrator=C;exports.createTestReflectionEvaluator=X;exports.createTestTimeline=B;exports.createTimeController=q;exports.testGuardrail=T;exports.testGuardrailBatch=x;//# sourceMappingURL=testing.cjs.map
|
|
1
|
+
'use strict';var chunk2TD4ZSGZ_cjs=require('./chunk-2TD4ZSGZ.cjs'),chunkA22KLB23_cjs=require('./chunk-A22KLB23.cjs');require('./chunk-K64WKZ22.cjs');var chunkWOFIBIPW_cjs=require('./chunk-WOFIBIPW.cjs');require('./chunk-FFRWQNK7.cjs');function b(r={}){let{defaultResponse:e={output:"mock response",totalTokens:10},responses:t={},recordCalls:n=true,onRun:o}=r,s=[],a=new Map(Object.entries(t)),i=e;return {run:async(l,c,g)=>{o?.(l,c),n&&s.push({agent:l,input:c,options:g,timestamp:Date.now()});let d=a.get(l.name)??i;if(d.generate){let p=d.generate(c,l);d={...d,...p};}if(d.error)throw d.error;d.delay&&d.delay>0&&await new Promise(p=>setTimeout(p,d.delay));let f=d.messages??[];for(let p of f)g?.onMessage?.(p);let m=d.toolCalls??[];for(let p of m)g?.onToolCall?.(p);return {output:d.output,messages:f,toolCalls:m,totalTokens:d.totalTokens??10}},getCalls:()=>[...s],getCallsFor:l=>s.filter(c=>c.agent.name===l),clearCalls:()=>s.length=0,setResponse:(l,c)=>a.set(l,c),setDefaultResponse:l=>i=l}}async function T(r,e,t){let n={agentName:"test-agent",input:"",...e},o={agentName:e.agentName??"test-agent",input:e.input??"",facts:t?.facts??{},...t},s=Date.now(),a=await r(n,o),i=Date.now()-s;return {...a,duration:i,testedData:n,assertPassed(){if(!a.passed)throw new Error(`Expected guardrail to pass, but it failed: ${a.reason}`)},assertFailed(u){if(a.passed)throw new Error("Expected guardrail to fail, but it passed");if(u!==void 0){if(typeof u=="string"&&!a.reason?.includes(u))throw new Error(`Expected failure reason to include "${u}", got: ${a.reason}`);if(u instanceof RegExp&&!u.test(a.reason??""))throw new Error(`Expected failure reason to match ${u}, got: ${a.reason}`)}},assertTransformed(u){if(a.transformed===void 0)throw new Error("Expected guardrail to transform input, but no transformation occurred");if(u!==void 0&&a.transformed!==u)throw new Error(`Expected transformation to be ${JSON.stringify(u)}, got: ${JSON.stringify(a.transformed)}`)}}}async function x(r,e){let t=[],n=[];for(let o=0;o<e.length;o++){let s=e[o],a=await T(r,s.input,s.context);t.push(a),(a.passed?a.transformed!==void 0?"transform":"pass":"fail")!==s.expect&&n.push({index:o,expected:s.expect,actual:a});}return {results:t,allPassed:()=>n.length===0,failures:()=>n}}function R(r={}){let{autoApprove:e,autoReject:t,delay:n=0,recordRequests:o=true}=r,s=[],a=new Map,i=[];return {async handle(u){o&&s.push(u);for(let l=i.length-1;l>=0;l--){let c=i[l];c.predicate(u)&&(i.splice(l,1),c.resolve(u));}return n>0&&await new Promise(l=>setTimeout(l,n)),t&&t(u)?"rejected":e?.(u)?"approved":new Promise(l=>{a.set(u.id,{request:u,resolve:l});})},getRequests:()=>[...s],clearRequests:()=>s.length=0,approve(u){let l=a.get(u);l&&(l.resolve("approved"),a.delete(u));},reject(u,l){let c=a.get(u);if(c){c.resolve("rejected"),a.delete(u);let g=s.find(d=>d.id===u);g&&(g.rejectionReason=l);}},waitForRequest(u,l=5e3){let c=s.find(u);return c?Promise.resolve(c):new Promise((g,d)=>{let f={predicate:u,resolve:p=>{clearTimeout(m),g(p);}},m=setTimeout(()=>{let p=i.indexOf(f);p>=0&&i.splice(p,1),d(new Error("Timeout waiting for approval request"));},l);i.push(f);})}}}function C(r={}){let{mockResponses:e,defaultMockResponse:t,...n}=r,o=b({responses:e,defaultResponse:t}),s=R(),a=chunk2TD4ZSGZ_cjs.a({...n,runner:o.run,onApprovalRequest:u=>{s.handle(u),n.onApprovalRequest?.(u);}}),i=Object.create(a);return i.mockRunner=o,i.approvalSimulator=s,i.getCalls=()=>o.getCalls(),i.getApprovalRequests=()=>s.getRequests(),i.resetAll=()=>{a.reset(),o.clearCalls(),s.clearRequests();},i}function O(){let r=[];return {plugin:{name:"constraint-recorder",onRequirementCreated(e){r.push({constraintId:e.constraintId,triggered:true,requirement:e.requirement,facts:e.facts,timestamp:Date.now()});}},getSnapshots:()=>[...r],clearSnapshots:()=>r.length=0}}function M(r,e){let t=r.facts;if(e.agentStatus!==void 0&&t.agent.status!==e.agentStatus)throw new Error(`Expected agent status to be "${e.agentStatus}", got "${t.agent.status}"`);if(e.tokenUsage!==void 0){let{min:n,max:o,exact:s}=e.tokenUsage;if(s!==void 0&&t.agent.tokenUsage!==s)throw new Error(`Expected token usage to be exactly ${s}, got ${t.agent.tokenUsage}`);if(n!==void 0&&t.agent.tokenUsage<n)throw new Error(`Expected token usage to be at least ${n}, got ${t.agent.tokenUsage}`);if(o!==void 0&&t.agent.tokenUsage>o)throw new Error(`Expected token usage to be at most ${o}, got ${t.agent.tokenUsage}`)}if(e.pendingApprovals!==void 0&&t.approval.pending.length!==e.pendingApprovals)throw new Error(`Expected ${e.pendingApprovals} pending approvals, got ${t.approval.pending.length}`);if(e.conversationLength!==void 0){let{min:n,max:o,exact:s}=e.conversationLength,a=t.conversation.length;if(s!==void 0&&a!==s)throw new Error(`Expected conversation length to be exactly ${s}, got ${a}`);if(n!==void 0&&a<n)throw new Error(`Expected conversation length to be at least ${n}, got ${a}`);if(o!==void 0&&a>o)throw new Error(`Expected conversation length to be at most ${o}, got ${a}`)}}function q(r=Date.now()){let e=r,t=r;return {now:()=>e,advance:n=>{e+=n;},set:n=>{e=n;},reset:()=>{e=t;}}}function D(r){let{mockResponses:e={},defaultMockResponse:t,mockTasks:n,...o}=r;if(n){let c=o.tasks??{};for(let[g,d]of Object.entries(n))c[g]||(c[g]=y(d.output,{delay:d.delay,shouldError:d.shouldError}));o.tasks=c;}let s={};for(let[c,g]of Object.entries(e)){let d=o.agents[c];d&&(s[d.agent.name]=g);}let a=b({responses:s,defaultResponse:t}),i=R(),u=chunkA22KLB23_cjs.ra({...o,runner:a.run,onApprovalRequest:c=>{i.handle(c),o.onApprovalRequest?.(c);}}),l=Object.create(u);return l.mockRunner=a,l.approvalSimulator=i,l.getCalls=()=>a.getCalls(),l.getApprovalRequests=()=>i.getRequests(),l.resetAll=()=>{u.reset(),a.clearCalls(),i.clearRequests();},l}function N(r,e){if(e.taskStatus)for(let[t,n]of Object.entries(e.taskStatus)){let o=r.getTaskState(t);if(!o)throw new Error(`Expected task "${t}" to exist, but it was not found`);if(o.status!==n)throw new Error(`Expected task "${t}" status to be "${n}", got "${o.status}"`)}if(e.agentStatus)for(let[t,n]of Object.entries(e.agentStatus)){let o=r.getAgentState(t);if(!o)throw new Error(`Expected agent "${t}" to exist, but it was not found`);if(o.status!==n)throw new Error(`Expected agent "${t}" status to be "${n}", got "${o.status}"`)}if(e.totalTokens){let{agentId:t,min:n,max:o}=e.totalTokens;if(t){let s=r.getAgentState(t);if(!s)throw new Error(`Expected agent "${t}" to exist, but it was not found`);if(n!==void 0&&s.totalTokens<n)throw new Error(`Expected agent "${t}" tokens to be at least ${n}, got ${s.totalTokens}`);if(o!==void 0&&s.totalTokens>o)throw new Error(`Expected agent "${t}" tokens to be at most ${o}, got ${s.totalTokens}`)}else {let s=r.getAllAgentStates(),a=Object.values(s).reduce((i,u)=>i+u.totalTokens,0);if(n!==void 0&&a<n)throw new Error(`Expected total tokens to be at least ${n}, got ${a}`);if(o!==void 0&&a>o)throw new Error(`Expected total tokens to be at most ${o}, got ${a}`)}}if(e.globalTokens){let{min:t,max:n}=e.globalTokens,o=r.totalTokens;if(t!==void 0&&o<t)throw new Error(`Expected global tokens to be at least ${t}, got ${o}`);if(n!==void 0&&o>n)throw new Error(`Expected global tokens to be at most ${n}, got ${o}`)}if(e.pendingHandoffs!==void 0){let t=r.getPendingHandoffs().length;if(t!==e.pendingHandoffs)throw new Error(`Expected ${e.pendingHandoffs} pending handoffs, got ${t}`)}}function y(r,e){return {run:async(t,n)=>{if(n.aborted)throw new Error("Task aborted");if(e?.delay&&e.delay>0&&await new Promise((o,s)=>{let a=setTimeout(o,e.delay);n.addEventListener("abort",()=>{clearTimeout(a),s(new Error("Task aborted"));},{once:true});}),e?.shouldError)throw new Error("Mock task error");return r},label:e?.label??"Mock Task",description:e?.description}}function P(r,e,t){return chunkA22KLB23_cjs.W(r,e??(o=>o.outputs),t)}function I(r,e){if(e.nodeStatuses)for(let[t,n]of Object.entries(e.nodeStatuses)){let o=r.statuses[t];if(o!==n)throw new Error(`Expected node "${t}" status to be "${n}", got "${o}"`)}if(e.completedNodes){for(let t of e.completedNodes)if(r.statuses[t]!=="completed")throw new Error(`Expected node "${t}" to be completed, got "${r.statuses[t]}"`)}if(e.skippedNodes){for(let t of e.skippedNodes)if(r.statuses[t]!=="skipped")throw new Error(`Expected node "${t}" to be skipped, got "${r.statuses[t]}"`)}if(e.errorNodes){for(let t of e.errorNodes)if(r.statuses[t]!=="error")throw new Error(`Expected node "${t}" to be error, got "${r.statuses[t]}"`)}if(e.outputContains)for(let[t,n]of Object.entries(e.outputContains)){let o=r.outputs[t];if(o!==n)throw new Error(`Expected node "${t}" output to be ${JSON.stringify(n)}, got ${JSON.stringify(o)}`)}}function B(r,e){let t=chunkWOFIBIPW_cjs.a({maxEvents:e?.maxEvents??500});if(r)for(let n of r)t.record({timestamp:Date.now(),snapshotId:null,agentId:"",...n});return t}function F(r,e){let t=r.getEvents();if(e.totalEvents!==void 0&&t.length!==e.totalEvents)throw new Error(`Expected ${e.totalEvents} timeline events, got ${t.length}`);if(e.minEvents!==void 0&&t.length<e.minEvents)throw new Error(`Expected at least ${e.minEvents} timeline events, got ${t.length}`);if(e.maxEvents!==void 0&&t.length>e.maxEvents)throw new Error(`Expected at most ${e.maxEvents} timeline events, got ${t.length}`);if(e.eventTypes){for(let n of e.eventTypes)if(!t.some(s=>s.type===n))throw new Error(`Expected timeline to contain event of type "${n}", but none found`)}if(e.agentEvents)for(let[n,o]of Object.entries(e.agentEvents)){let s=r.getEventsForAgent(n).length;if(s!==o)throw new Error(`Expected ${o} events for agent "${n}", got ${s}`)}if(e.hasType&&!t.some(o=>o.type===e.hasType))throw new Error(`Expected timeline to contain event of type "${e.hasType}"`);if(e.doesNotHaveType&&t.some(o=>o.type===e.doesNotHaveType))throw new Error(`Expected timeline NOT to contain event of type "${e.doesNotHaveType}"`)}function H(r,e){let t=0,n=e?.failAfter??0;return async(o,s,a)=>{if(t++,n>0&&t<=n)return {output:"success",messages:[],toolCalls:[],totalTokens:10};throw e?.delay&&e.delay>0&&await new Promise(i=>setTimeout(i,e.delay)),r??new Error("Runner failed")}}function L(r,e){if(r.length===0)throw new Error("Expected at least one reroute event, but none occurred");if(e.minReroutes!==void 0&&r.length<e.minReroutes)throw new Error(`Expected at least ${e.minReroutes} reroute events, got ${r.length}`);if(e.fromAgent&&!r.some(n=>n.originalAgent===e.fromAgent))throw new Error(`Expected reroute from agent "${e.fromAgent}", but no matching event found`);if(e.toAgent&&!r.some(n=>n.reroutedTo===e.toAgent))throw new Error(`Expected reroute to agent "${e.toAgent}", but no matching event found`);if(e.reason&&!r.some(n=>typeof e.reason=="string"?n.reason.includes(e.reason):e.reason.test(n.reason)))throw new Error(`Expected reroute reason matching ${e.reason}, but no matching event found`)}function J(r,e,t){let n=r.getMetrics(e);if(t.minScore!==void 0&&n.healthScore<t.minScore)throw new Error(`Expected agent "${e}" health score to be at least ${t.minScore}, got ${n.healthScore}`);if(t.maxScore!==void 0&&n.healthScore>t.maxScore)throw new Error(`Expected agent "${e}" health score to be at most ${t.maxScore}, got ${n.healthScore}`);if(t.circuitState!==void 0&&n.circuitState!==t.circuitState)throw new Error(`Expected agent "${e}" circuit state to be "${t.circuitState}", got "${n.circuitState}"`);if(t.minSuccessRate!==void 0&&n.successRate<t.minSuccessRate)throw new Error(`Expected agent "${e}" success rate to be at least ${t.minSuccessRate}, got ${n.successRate}`)}function U(r=100){let e=new chunkA22KLB23_cjs.y({maxCheckpoints:r}),t=[];return {inner:e,saved:t,getLatest:()=>t[t.length-1],async save(n){return t.push(n),e.save(n)},load:n=>e.load(n),list:()=>e.list(),delete:n=>e.delete(n),clear:()=>e.clear(),prune:()=>e.prune()}}function _(r,e){if(e.orchestratorType!==void 0&&r.orchestratorType!==e.orchestratorType)throw new Error(`Expected checkpoint orchestratorType "${e.orchestratorType}", got "${r.orchestratorType}"`);if(e.hasSystemExport===true&&(!r.systemExport||r.systemExport===""))throw new Error("Expected checkpoint to have non-empty systemExport, but it was empty");if(e.hasTimeline===true&&r.timelineExport===null)throw new Error("Expected checkpoint to have timeline export, but it was null");if(e.hasTimeline===false&&r.timelineExport!==null)throw new Error("Expected checkpoint to have no timeline export, but it was present");if(e.hasMemory===true&&r.memoryExport===null)throw new Error("Expected checkpoint to have memory export, but it was null");if(e.hasMemory===false&&r.memoryExport!==null)throw new Error("Expected checkpoint to have no memory export, but it was present");if(e.label!==void 0&&r.label!==e.label)throw new Error(`Expected checkpoint label "${e.label}", got "${r.label}"`)}function V(r={}){let e=[],t=null,n=false;return {handler:s=>{if(e.push(s),!n)throw new Error("[Directive] BreakpointSimulator: handler called but attachTo() was never called. Breakpoints will not be resolved. Call simulator.attachTo(orchestrator) after creation.");let a=r.autoResumeDelay??0,i=()=>{t&&(r.cancel?t.cancelBreakpoint(s.id,r.cancelReason):t.resumeBreakpoint(s.id,r.modifications));};a>0?setTimeout(i,a):queueMicrotask(i);},hits:e,attachTo:s=>{t=s,n=true;}}}function W(r,e){if(e.count!==void 0&&r.length!==e.count)throw new Error(`Expected ${e.count} breakpoint hits, got ${r.length}`);if(e.type&&!r.some(n=>n.type===e.type)){let n=r.map(o=>o.type).join(", ");throw new Error(`Expected breakpoint of type "${e.type}", found types: [${n}]`)}if(e.agentId&&!r.some(n=>n.agentId===e.agentId)){let n=r.map(o=>o.agentId).join(", ");throw new Error(`Expected breakpoint for agent "${e.agentId}", found agents: [${n}]`)}}function z(r,e){return {safeParse:t=>r(t)?{success:true,data:t}:{success:false,error:{message:"Validation failed"}},description:e}}async function K(r){let e=[];for await(let t of r)e.push(t);return e}function Q(r,e){if(e.minChunks!==void 0&&r.length<e.minChunks)throw new Error(`Expected at least ${e.minChunks} chunks, got ${r.length}`);if(e.agentIds){let t=new Set(r.map(n=>n.agentId));for(let n of e.agentIds)if(!t.has(n))throw new Error(`Expected chunks from agent "${n}", found agents: [${[...t].join(", ")}]`)}if(e.hasDone===true&&!r.some(n=>n.chunk.type==="done"))throw new Error("Expected at least one 'done' chunk, found none");if(e.hasErrors===true&&!r.some(n=>n.chunk.type==="error"))throw new Error("Expected at least one 'error' chunk, found none");if(e.hasErrors===false&&r.some(n=>n.chunk.type==="error"))throw new Error("Expected no 'error' chunks, but found some")}function X(r){let e=r?.passAfter??1,t=r?.feedback??"Needs improvement",n=r?.score,o=0;return (s,a)=>{o++;let i=o>=e;return {passed:i,feedback:i?void 0:t,score:n??(i?1:.5)}}}function Y(r,e){let t=r.getAll();for(let[n,o]of Object.entries(e)){let s=t[n];if(s!==o)throw new Error(`Expected scratchpad key "${n}" to be ${JSON.stringify(o)}, got ${JSON.stringify(s)}`)}}function Z(r,e){let t=r.derived;for(let[n,o]of Object.entries(e)){let s=t[n];if(typeof o=="object"&&o!==null){let a=i=>JSON.stringify(i,Object.keys(i).sort());if(a(s)!==a(o))throw new Error(`Expected derived value "${n}" to be ${JSON.stringify(o)}, got ${JSON.stringify(s)}`)}else if(s!==o)throw new Error(`Expected derived value "${n}" to be ${JSON.stringify(o)}, got ${JSON.stringify(s)}`)}}exports.assertAgentHealth=J;exports.assertBreakpointHit=W;exports.assertCheckpoint=_;exports.assertDagExecution=I;exports.assertDerivedValues=Z;exports.assertMultiAgentState=N;exports.assertMultiplexedStream=Q;exports.assertOrchestratorState=M;exports.assertRerouted=L;exports.assertScratchpadState=Y;exports.assertTimelineEvents=F;exports.collectMultiplexedStream=K;exports.createApprovalSimulator=R;exports.createBreakpointSimulator=V;exports.createConstraintRecorder=O;exports.createFailingRunner=H;exports.createMockAgentRunner=b;exports.createMockSchema=z;exports.createMockTask=y;exports.createTestCheckpointStore=U;exports.createTestDag=P;exports.createTestMultiAgentOrchestrator=D;exports.createTestOrchestrator=C;exports.createTestReflectionEvaluator=X;exports.createTestTimeline=B;exports.createTimeController=q;exports.testGuardrail=T;exports.testGuardrailBatch=x;//# sourceMappingURL=testing.cjs.map
|
|
2
2
|
//# sourceMappingURL=testing.cjs.map
|