@axlsdk/testing 0.23.0 → 0.23.1
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 +5 -0
- package/dist/index.cjs +58 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +58 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -140,6 +140,11 @@ second callback declares model capabilities. Inline bytes, provider options,
|
|
|
140
140
|
and results are defensively copied; recorded requests omit `AbortSignal`, while
|
|
141
141
|
the fixture callback receives the original signal so cancellation is testable.
|
|
142
142
|
|
|
143
|
+
Separately, `MockProvider.chat()` and `.stream()` honor `ChatOptions.signal`:
|
|
144
|
+
pre-abort prevents fixture work and an in-flight abort rejects with the exact reason. This supports
|
|
145
|
+
deterministic tests of ask-local `signal` and `stallTimeout`; it is not a
|
|
146
|
+
certification of a real provider's network-abort behavior.
|
|
147
|
+
|
|
143
148
|
### `MockTool`
|
|
144
149
|
|
|
145
150
|
Create a mock tool to intercept and record calls:
|
package/dist/index.cjs
CHANGED
|
@@ -116,6 +116,52 @@ function cloneOptions(options) {
|
|
|
116
116
|
...options.providerOptions ? { providerOptions: cloneValue(options.providerOptions) } : {}
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
+
function throwIfAborted(signal) {
|
|
120
|
+
if (signal?.aborted) throw signal.reason;
|
|
121
|
+
}
|
|
122
|
+
async function awaitWithSignal(value, signal) {
|
|
123
|
+
if (!signal) return await value;
|
|
124
|
+
throwIfAborted(signal);
|
|
125
|
+
return await new Promise((resolve, reject) => {
|
|
126
|
+
const onAbort = () => reject(signal.reason);
|
|
127
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
128
|
+
Promise.resolve(value).then(
|
|
129
|
+
(result) => {
|
|
130
|
+
signal.removeEventListener("abort", onAbort);
|
|
131
|
+
resolve(result);
|
|
132
|
+
},
|
|
133
|
+
(error) => {
|
|
134
|
+
signal.removeEventListener("abort", onAbort);
|
|
135
|
+
reject(error);
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async function abortableDelay(ms, signal) {
|
|
141
|
+
if (ms <= 0) {
|
|
142
|
+
throwIfAborted(signal);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!signal) {
|
|
146
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
throwIfAborted(signal);
|
|
150
|
+
await new Promise((resolve, reject) => {
|
|
151
|
+
let timer = setTimeout(() => {
|
|
152
|
+
timer = void 0;
|
|
153
|
+
signal.removeEventListener("abort", onAbort);
|
|
154
|
+
resolve();
|
|
155
|
+
}, ms);
|
|
156
|
+
const onAbort = () => {
|
|
157
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
158
|
+
timer = void 0;
|
|
159
|
+
signal.removeEventListener("abort", onAbort);
|
|
160
|
+
reject(signal.reason);
|
|
161
|
+
};
|
|
162
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
163
|
+
});
|
|
164
|
+
}
|
|
119
165
|
function richParts(input) {
|
|
120
166
|
return typeof input === "string" ? [] : input;
|
|
121
167
|
}
|
|
@@ -208,8 +254,13 @@ var MockProvider = class _MockProvider {
|
|
|
208
254
|
}
|
|
209
255
|
async chat(messages, options) {
|
|
210
256
|
const recordedMessages = cloneMessages(messages);
|
|
257
|
+
const callIndex = this._calls.length;
|
|
211
258
|
this._calls.push({ messages: recordedMessages, options: cloneOptions(options) });
|
|
212
|
-
|
|
259
|
+
throwIfAborted(options.signal);
|
|
260
|
+
const response = Promise.resolve().then(
|
|
261
|
+
() => this.responseFn(cloneMessages(messages), callIndex)
|
|
262
|
+
);
|
|
263
|
+
return await awaitWithSignal(response, options.signal);
|
|
213
264
|
}
|
|
214
265
|
inputCapabilities(_model) {
|
|
215
266
|
return { image: { sources: ["url", "bytes", "base64", "provider-file"] } };
|
|
@@ -247,6 +298,7 @@ var MockProvider = class _MockProvider {
|
|
|
247
298
|
async *stream(messages, options) {
|
|
248
299
|
const callIndex = this._calls.length;
|
|
249
300
|
const response = await this.chat(messages, options);
|
|
301
|
+
throwIfAborted(options.signal);
|
|
250
302
|
const chunks = this.chunkSequence?.[callIndex];
|
|
251
303
|
if (chunks && chunks.length > 0) {
|
|
252
304
|
const joined = chunks.join("");
|
|
@@ -256,16 +308,19 @@ var MockProvider = class _MockProvider {
|
|
|
256
308
|
);
|
|
257
309
|
}
|
|
258
310
|
for (let i = 0; i < chunks.length; i++) {
|
|
311
|
+
throwIfAborted(options.signal);
|
|
259
312
|
yield { type: "text_delta", content: chunks[i] };
|
|
260
313
|
if (this.chunkDelayMs > 0 && i < chunks.length - 1) {
|
|
261
|
-
await
|
|
314
|
+
await abortableDelay(this.chunkDelayMs, options.signal);
|
|
262
315
|
}
|
|
263
316
|
}
|
|
264
317
|
} else if (response.content) {
|
|
318
|
+
throwIfAborted(options.signal);
|
|
265
319
|
yield { type: "text_delta", content: response.content };
|
|
266
320
|
}
|
|
267
321
|
if (response.tool_calls) {
|
|
268
322
|
for (const tc of response.tool_calls) {
|
|
323
|
+
throwIfAborted(options.signal);
|
|
269
324
|
yield {
|
|
270
325
|
type: "tool_call_delta",
|
|
271
326
|
id: tc.id,
|
|
@@ -274,6 +329,7 @@ var MockProvider = class _MockProvider {
|
|
|
274
329
|
};
|
|
275
330
|
}
|
|
276
331
|
}
|
|
332
|
+
throwIfAborted(options.signal);
|
|
277
333
|
yield {
|
|
278
334
|
type: "done",
|
|
279
335
|
usage: response.usage,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/mock-provider.ts","../src/mock-tool.ts","../src/mock-transcription-provider.ts","../src/test-runtime.ts"],"sourcesContent":["export { AxlTestRuntime } from './test-runtime.js';\nexport type { RecordedToolCall, RecordedAgentCall, RecordedStep } from './test-runtime.js';\nexport { MockProvider } from './mock-provider.js';\nexport { MockTranscriptionProvider } from './mock-transcription-provider.js';\nexport { MockTool } from './mock-tool.js';\n","import { readFileSync } from 'node:fs';\nimport { z } from 'zod';\nimport type {\n CallTiming,\n ChatMessage,\n ChatOptions,\n InputContentPart,\n InputMediaSource,\n ModelInput,\n ToolCallMessage,\n ProviderResponse,\n StreamChunk,\n Provider,\n ProviderInputValidationRequest,\n ProviderInputValidationResult,\n EffortResolution,\n} from '@axlsdk/axl';\nimport { inputText, UnsupportedModelInputError } from '@axlsdk/axl';\n\nfunction cloneValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return value.slice();\n if (Array.isArray(value)) return value.map(cloneValue);\n if (value && typeof value === 'object') {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneValue(item)]));\n }\n return value;\n}\n\nfunction cloneModelInput(input: ModelInput): ModelInput {\n if (typeof input === 'string') return input;\n return input.map((part): InputContentPart => {\n if (part.type === 'text') return { type: 'text', text: part.text };\n const { source } = part;\n switch (source.type) {\n case 'bytes':\n return {\n type: 'image',\n source: { type: 'bytes', data: source.data.slice(), mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'url':\n return {\n type: 'image',\n source: {\n type: 'url',\n url: source.url,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'base64':\n return {\n type: 'image',\n source: { type: 'base64', data: source.data, mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'provider-file':\n return {\n type: 'image',\n source: {\n type: 'provider-file',\n provider: source.provider,\n reference: source.reference,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n }\n });\n}\n\nfunction cloneMessages(messages: readonly ChatMessage[]): ChatMessage[] {\n return messages.map((message) => ({\n ...message,\n content: cloneModelInput(message.content),\n ...(message.tool_calls\n ? {\n tool_calls: message.tool_calls.map((toolCall) => ({\n ...toolCall,\n function: { ...toolCall.function },\n })),\n }\n : {}),\n ...(message.providerMetadata\n ? { providerMetadata: cloneValue(message.providerMetadata) as Record<string, unknown> }\n : {}),\n }));\n}\n\nfunction cloneOptions(options: ChatOptions): ChatOptions {\n return {\n ...options,\n ...(options.tools\n ? {\n tools: options.tools.map((tool) => ({\n ...tool,\n function: { ...tool.function, parameters: cloneValue(tool.function.parameters) },\n })),\n }\n : {}),\n ...(options.providerOptions\n ? { providerOptions: cloneValue(options.providerOptions) as Record<string, unknown> }\n : {}),\n };\n}\n\nfunction richParts(input: ModelInput): readonly InputContentPart[] {\n return typeof input === 'string' ? [] : input;\n}\n\nfunction randomAlphanumeric(length: number): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars[Math.floor(Math.random() * chars.length)];\n }\n return result;\n}\n\nfunction generateFromSchema(schema: unknown): unknown {\n if (schema instanceof z.ZodString) return randomAlphanumeric(8 + Math.floor(Math.random() * 13));\n if (schema instanceof z.ZodNumber) {\n const min = Number.isFinite(schema.minValue) ? schema.minValue! : 0;\n const max = Number.isFinite(schema.maxValue) ? schema.maxValue! : 100;\n return min + Math.random() * (max - min);\n }\n if (schema instanceof z.ZodBoolean) return Math.random() < 0.5;\n if (schema instanceof z.ZodArray) {\n const count = 1 + Math.floor(Math.random() * 3);\n return Array.from({ length: count }, () => generateFromSchema(schema.element));\n }\n if (schema instanceof z.ZodObject) {\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(schema.shape)) obj[key] = generateFromSchema(value);\n return obj;\n }\n if (schema instanceof z.ZodOptional) {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(schema.unwrap());\n }\n if (schema instanceof z.ZodDefault) return schema.parse(undefined);\n if (schema instanceof z.ZodEnum) {\n const values = schema.options;\n return values.length > 0 ? values[Math.floor(Math.random() * values.length)] : '';\n }\n if (schema instanceof z.ZodLiteral) return [...schema.values][0];\n if (schema instanceof z.ZodNullable) return null;\n if (schema instanceof z.ZodUnion) {\n const options = schema.options;\n return generateFromSchema(options[Math.floor(Math.random() * options.length)]);\n }\n return {};\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: ChatOptions }[] = [];\n /** Per-call optional chunk arrays, set by `sequence()` / `chunked()` so\n * `stream()` can yield one `text_delta` per chunk. Per-call indexed\n * alongside the response sequence. */\n private chunkSequence?: Array<string[] | undefined>;\n /** Optional ms delay between successive chunks during `stream()`. Useful\n * for dev fixtures that need to demonstrate streaming UX visually\n * (without a delay, mock chunks fire synchronously and complete in\n * microseconds — invisible to a human watching). Default 0 keeps\n * every existing test fast.\n *\n * Set via `provider.chunkDelayMs = 50` after construction. Not part of\n * any factory's surface to keep the test API minimal. */\n chunkDelayMs = 0;\n\n /** How this mock reports the unified `effort` it was asked for. Undefined (the\n * default) means the mock implements no `effortResolution` at all, so the\n * runtime emits no `provider_diagnostic`. Set it with\n * {@link MockProvider.withEffortResolution} to drive the clamp-reporting path. */\n effortResolution?: (\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined;\n\n /**\n * Make this mock report an effort clamp, so a test can exercise the runtime's\n * `provider_diagnostic` path without a real adapter. Pass a fixed\n * {@link EffortResolution} or a function of the request knobs.\n *\n * ```ts\n * const provider = MockProvider.echo().withEffortResolution({\n * requested: 'none',\n * effective: 'minimal',\n * clamped: true,\n * cause: 'this model cannot disable thinking',\n * });\n * ```\n */\n withEffortResolution(\n resolution:\n | EffortResolution\n | undefined\n | ((\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined),\n ): this {\n this.effortResolution = typeof resolution === 'function' ? resolution : () => resolution;\n return this;\n }\n\n private constructor(\n private responseFn: (\n messages: ChatMessage[],\n callIndex: number,\n ) => ProviderResponse | Promise<ProviderResponse>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: ChatOptions): Promise<ProviderResponse> {\n // Each consumer gets independent ownership: a handler can inspect or mutate\n // its copy without changing the durable assertion record (including bytes).\n const recordedMessages = cloneMessages(messages);\n this._calls.push({ messages: recordedMessages, options: cloneOptions(options) });\n return await this.responseFn(cloneMessages(messages), this._calls.length - 1);\n }\n\n inputCapabilities(_model: string): { image: { sources: readonly InputMediaSource['type'][] } } {\n return { image: { sources: ['url', 'bytes', 'base64', 'provider-file'] } };\n }\n\n validateInput(request: ProviderInputValidationRequest): ProviderInputValidationResult {\n const effectiveModel =\n typeof request.providerOptions?.model === 'string'\n ? request.providerOptions.model\n : request.model;\n const fail = (source?: string, feature?: string): never => {\n throw new UnsupportedModelInputError({\n provider: this.name,\n model: effectiveModel || request.model,\n modality: 'image',\n ...(source ? { source } : {}),\n ...(feature ? { feature } : {}),\n });\n };\n\n if (request.providerOptions && 'input' in request.providerOptions) {\n fail(undefined, 'raw input-container providerOptions');\n }\n for (const message of request.history) {\n if (typeof message.content === 'string') continue;\n if (message.role !== 'user') fail(undefined, 'rich non-user history');\n for (const part of richParts(message.content)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n }\n for (const part of richParts(request.input)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n return { effectiveModel };\n }\n\n async *stream(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamChunk> {\n const callIndex = this._calls.length;\n const response = await this.chat(messages, options);\n const chunks = this.chunkSequence?.[callIndex];\n if (chunks && chunks.length > 0) {\n // Sanity guard — if a caller passes chunks AND content, they MUST\n // match. Otherwise tests pass while the real prod content silently\n // diverges from what the streaming path observes.\n const joined = chunks.join('');\n if (joined !== response.content) {\n throw new Error(\n `MockProvider.stream: chunks.join('') !== content. ` +\n `chunks=\"${joined}\" content=\"${response.content}\"`,\n );\n }\n for (let i = 0; i < chunks.length; i++) {\n yield { type: 'text_delta', content: chunks[i] };\n if (this.chunkDelayMs > 0 && i < chunks.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, this.chunkDelayMs));\n }\n }\n } else if (response.content) {\n yield { type: 'text_delta', content: response.content };\n }\n if (response.tool_calls) {\n for (const tc of response.tool_calls) {\n yield {\n type: 'tool_call_delta',\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n };\n }\n }\n yield {\n type: 'done',\n usage: response.usage,\n // Forwarded like `chat()` does. Without it a streamed mock ask reported no\n // cost at all, so `ctx.budget` and every cost assertion silently saw zero\n // on the streaming path while the same fixture priced correctly on the\n // non-streaming one — a mock that disagrees with itself between paths.\n cost: response.cost,\n providerMetadata: response.providerMetadata,\n // Conditional spread, not `timing: response.timing` — a mock response with\n // no timing must produce a `done` chunk with NO `timing` key at all, so a\n // consumer's `'timing' in chunk` check reads the same as a real adapter's.\n ...(response.timing ? { timing: response.timing } : {}),\n };\n }\n\n static sequence(\n responses: Array<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Deterministic provider-call timing, surfaced on `ProviderResponse.timing`\n * and on the streamed terminal `done` chunk. Lets a test drive\n * `agent_call_end.timing`, the `TimeoutError` breakdown, and the eval\n * per-model rollup without real clocks or a real transport. Omit it and\n * the mock behaves exactly like an uninstrumented custom provider. */\n timing?: CallTiming;\n /** When set, `stream()` yields one `text_delta` per entry instead\n * of one big delta with the full content. Use to exercise\n * partial-JSON parsing, structural-boundary throttling, and\n * cross-attempt token retention in tests. Must satisfy\n * `chunks.join('') === content`. */\n chunks?: string[];\n }>,\n ): MockProvider {\n const provider = new MockProvider((_messages, callIndex) => {\n if (callIndex >= responses.length) {\n throw new Error(\n `MockProvider.sequence: no response for call index ${callIndex}. Only ${responses.length} responses defined.`,\n );\n }\n const resp = responses[callIndex];\n return {\n content: resp.content,\n tool_calls: resp.tool_calls,\n providerMetadata: resp.providerMetadata,\n usage: resp.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: resp.cost ?? 0,\n // Copied, not shared: the caller keeps ownership of the fixture, so a\n // consumer that mutates the returned block cannot corrupt a later call's\n // expectation (same rule the message/options clones follow).\n ...(resp.timing ? { timing: { ...resp.timing } } : {}),\n };\n });\n provider.chunkSequence = responses.map((r) => r.chunks);\n return provider;\n }\n\n /**\n * Convenience: build a `sequence()` from plain content strings, splitting\n * each one into fixed-size chunks for the streaming path. Default\n * `chunkSize` is 4 chars (≈1 token).\n */\n static chunked(contents: string[], chunkSize = 4): MockProvider {\n const responses = contents.map((content) => {\n const chunks: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunks.push(content.slice(i, i + chunkSize));\n }\n return { content, chunks };\n });\n return MockProvider.sequence(responses);\n }\n\n static echo(): MockProvider {\n return new MockProvider((messages) => {\n const lastUser = [...messages].reverse().find((m) => m.role === 'user');\n return {\n content: lastUser ? inputText(lastUser.content) : '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: unknown): MockProvider {\n return new MockProvider(() => ({\n content: JSON.stringify(generateFromSchema(schema)),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n\n static replay(source: string | ProviderResponse[]): MockProvider {\n const data =\n typeof source === 'string'\n ? (JSON.parse(readFileSync(source, 'utf-8')) as ProviderResponse[])\n : source;\n return new MockProvider((_messages, callIndex) => {\n if (callIndex >= data.length) {\n throw new Error(`MockProvider.replay: no recorded response for call index ${callIndex}`);\n }\n return data[callIndex];\n });\n }\n\n static fn(\n handler: (\n messages: ChatMessage[],\n callIndex: number,\n ) =>\n | {\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }\n | Promise<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }>,\n ): MockProvider {\n return new MockProvider(async (messages, callIndex) => {\n const result = await handler(messages, callIndex);\n return {\n ...result,\n usage: result.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: result.cost ?? 0,\n };\n });\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: unknown) => unknown | Promise<unknown>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async execute(input: unknown): Promise<unknown> {\n this._calls.push({ input });\n return this.handler(input);\n }\n\n static create(name: string, handler: (input: unknown) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import type {\n TranscriptionCapabilities,\n TranscriptionProvider,\n TranscriptionProviderRequest,\n TranscriptionProviderResult,\n} from '@axlsdk/axl';\n\nfunction clone<T>(value: T): T {\n return structuredClone(value);\n}\n\nfunction cloneRequest(\n request: TranscriptionProviderRequest,\n includeSignal: boolean,\n): TranscriptionProviderRequest {\n const audio =\n request.audio.type === 'bytes'\n ? { ...request.audio, data: request.audio.data.slice() }\n : { ...request.audio };\n return {\n model: request.model,\n audio,\n ...(request.language !== undefined ? { language: request.language } : {}),\n ...(request.timestamps !== undefined ? { timestamps: request.timestamps } : {}),\n ...(request.diarization !== undefined ? { diarization: request.diarization } : {}),\n ...(request.providerOptions ? { providerOptions: clone(request.providerOptions) } : {}),\n ...(includeSignal && request.signal ? { signal: request.signal } : {}),\n };\n}\n\n/** Dedicated transcription mock. It intentionally does not extend MockProvider,\n * so chat fixtures cannot accidentally become transcription adapters. */\nexport class MockTranscriptionProvider implements TranscriptionProvider {\n private _calls: TranscriptionProviderRequest[] = [];\n\n constructor(\n private readonly response: (\n request: TranscriptionProviderRequest,\n callIndex: number,\n ) => TranscriptionProviderResult | Promise<TranscriptionProviderResult>,\n private readonly capabilitiesFor: (\n model: string,\n ) => TranscriptionCapabilities | undefined = () => ({\n sources: ['bytes', 'base64', 'provider-file'],\n timestamps: ['segment', 'word'],\n diarization: true,\n }),\n ) {}\n\n get calls(): readonly TranscriptionProviderRequest[] {\n return this._calls.map(clone);\n }\n\n capabilities(model: string): TranscriptionCapabilities | undefined {\n return this.capabilitiesFor(model);\n }\n\n async transcribe(request: TranscriptionProviderRequest): Promise<TranscriptionProviderResult> {\n // AbortSignal cannot be structured-cloned. Keep it only on the callback\n // request so fixtures can observe cancellation; recorded calls omit it.\n const snapshot = cloneRequest(request, false);\n this._calls.push(snapshot);\n return clone(await this.response(cloneRequest(request, true), this._calls.length - 1));\n }\n\n static text(text: string): MockTranscriptionProvider {\n return new MockTranscriptionProvider(() => ({ transcript: { text } }));\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport { MockTranscriptionProvider } from './mock-transcription-provider.js';\nimport type {\n AxlEvent,\n AwaitHumanOptions,\n HumanDecision,\n ProviderResponse,\n AgentCallInfo,\n AxlConfig,\n AnyWorkflow,\n ToolCallOutcome,\n ObservationStatus,\n} from '@axlsdk/axl';\nimport {\n WorkflowContext,\n MemoryStore,\n ProviderRegistry,\n TranscriptionProviderRegistry,\n eventCostContribution,\n isUnpricedLeaf,\n} from '@axlsdk/axl';\nimport type { EventStreamOptions, WorkflowContextInit } from '@axlsdk/axl';\n\n// `AnyWorkflow` is a re-exported alias for `Workflow<any, any>` — see\n// the JSDoc on `AnyWorkflow` in `@axlsdk/axl/workflow.ts`. The bivariant\n// `any` is load-bearing for satisfying narrowly-typed handlers (e.g., a\n// `Workflow<TInput=MsgType>` whose handler takes `WorkflowContext<MsgType>`).\n\n/** One accepted provider-issued tool invocation, recorded from its terminal v2 event.\n *\n * Narrow `outcome.status` before reading status-specific fields. Correlation uses\n * `(executionId, askId, callId)`; `name` is the canonical tool name.\n */\nexport type RecordedToolCall = {\n name: string;\n executionId: string;\n askId: string;\n callId: string;\n args: unknown;\n requestedTool?: string;\n outcome: ToolCallOutcome;\n};\nexport type RecordedAgentCall = Partial<AgentCallInfo> &\n Pick<AgentCallInfo, 'agent' | 'prompt' | 'response'>;\nexport type RecordedStep = { step: number; type: string; data: unknown };\n\nfunction generateExecutionId(): string {\n return `test-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction preserveDrainCause(error: Error, cause: unknown): Error {\n if (cause === undefined || cause === error || 'cause' in error) return error;\n Object.defineProperty(error, 'cause', {\n configurable: true,\n enumerable: false,\n value: cause,\n });\n return error;\n}\n\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n /** AxlConfig for the test runtime. Controls trace level/redact, context management, etc.\n * Defaults to `{}`. Set `{ trace: { level: 'full' } }` to verify verbose-mode snapshots\n * in tests, or `{ trace: { redact: true } }` to verify redaction policy in tests. */\n config?: AxlConfig;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, AnyWorkflow>();\n private mockProviders = new Map<string, MockProvider>();\n private mockTranscriptionProviders = new Map<string, MockTranscriptionProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: AxlEvent[] = [];\n private _totalCost = 0;\n private _unpriced = false;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n private _config: AxlConfig;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n this._config = options?.config ?? {};\n }\n\n register(workflow: AnyWorkflow): void {\n this.workflows.set(workflow.name, workflow);\n }\n\n mockProvider(name: string, provider: MockProvider): void {\n this.mockProviders.set(name, provider);\n }\n\n mockTranscriptionProvider(name: string, provider: MockTranscriptionProvider): void {\n this.mockTranscriptionProviders.set(name, provider);\n }\n\n mockTool<TInput = unknown>(\n name: string,\n handler: (input: TInput) => unknown | Promise<unknown>,\n ): void {\n // The MockTool registry is type-erased (`(input: unknown) => unknown`)\n // because the runtime can't statically know each tool's input shape; tests\n // opt in to a typed input via the generic, and we cast on storage.\n this.mockToolMap.set(name, MockTool.create(name, handler as (input: unknown) => unknown));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: {\n metadata?: Record<string, unknown>;\n events?: EventStreamOptions;\n branchDrainTimeoutMs?: number;\n },\n ): Promise<unknown> {\n const workflow = this.workflows.get(workflowName);\n if (!workflow) throw new Error(`Workflow \"${workflowName}\" not registered`);\n\n // Reset state between executions\n this._toolCalls = [];\n this._agentCalls = [];\n this._steps = [];\n this._traceLog = [];\n this._totalCost = 0;\n this._unpriced = false;\n this._stepCounter = 0;\n this.recorded = [];\n this._executionId = generateExecutionId();\n\n const validated = workflow.inputSchema.parse(input);\n\n // Build ProviderRegistry from registered mock providers\n const registry = new ProviderRegistry();\n registry.clearFactories(); // Remove built-in factories; only use explicit mocks\n for (const [name, provider] of this.mockProviders) {\n registry.registerInstance(name, provider);\n }\n const transcriptionRegistry = new TranscriptionProviderRegistry();\n for (const [name, provider] of this.mockTranscriptionProviders) {\n transcriptionRegistry.registerInstance(name, provider);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider);\n }\n\n // Build toolOverrides from mockToolMap\n const toolOverrides = new Map<string, (args: unknown) => Promise<unknown>>();\n for (const [name, mockTool] of this.mockToolMap) {\n toolOverrides.set(name, async (args: unknown) => {\n return mockTool.execute(args);\n });\n }\n\n // Previously `_recordStep('workflow_start', ...)` was called here with\n // raw `{ workflow, input }` data, AND `ctx._emitWorkflowStart` below\n // pushed through the onTrace handler (which also bumps `_stepCounter`\n // and appends to `_steps`). Result: two entries in `steps()` per\n // workflow_start, with the first bypassing `config.trace.redact`.\n // The `_recordStep` call is removed — onTrace is the single source\n // of truth for `_steps`, matching the behavior of every other event\n // type in the test runtime. Reviewer architecture §5.\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n // Thread the constructor-provided config so tests can exercise\n // trace.level === 'full' and trace.redact behavior end-to-end.\n config: this._config,\n // Thread `events` config so tests can exercise the queue cap and\n // overflow policy on `ctx.events`. Mirrors the production runtime.\n eventStreamOptions: options?.events,\n branchDrainTimeoutMs: options?.branchDrainTimeoutMs,\n // Production runtime threads this (see `runtime.ts:594` in\n // `execute()` and `:765` in `stream()`). `emitEvent` auto-stamps\n // `event.workflow` from it, so consumers grouping by workflow\n // (Cost Dashboard `byWorkflow`, `trackExecution.metadata.workflows`,\n // any eval runner) see the same attribution in tests and prod.\n workflowName,\n providerRegistry: registry,\n transcriptionProviderRegistry: transcriptionRegistry,\n stateStore: new MemoryStore(),\n toolOverrides: toolOverrides.size > 0 ? toolOverrides : undefined,\n awaitHumanHandler: this._humanDecisionHandler\n ? (opts: AwaitHumanOptions) => this._humanDecisionHandler!(opts)\n : undefined,\n onTrace: (event: AxlEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({\n step: this._stepCounter,\n type: event.type,\n data: (event as { data?: unknown }).data,\n });\n\n if (event.type === 'tool_call_end') {\n const { args, requestedTool, outcome } = event.data;\n this._toolCalls.push({\n name: event.tool,\n executionId: event.executionId,\n askId: event.askId,\n callId: event.callId,\n args,\n ...(requestedTool !== undefined ? { requestedTool } : {}),\n outcome,\n });\n }\n\n // Single-source-of-truth cost accumulator. Skips ask_end\n // rollups (decision 10) and guards NaN/Infinity.\n this._totalCost += eventCostContribution(event);\n // Honest aggregate: one unpriced leaf makes `totalCost()` a lower bound.\n if (isUnpricedLeaf(event)) this._unpriced = true;\n\n // Track provider responses for recording\n if (event.type === 'agent_call_end' && event.data) {\n const { response } = event.data as { prompt?: string; response?: string };\n if (response !== undefined) {\n this.recorded.push({\n content: response,\n usage: event.tokens\n ? {\n prompt_tokens: event.tokens.input ?? 0,\n completion_tokens: event.tokens.output ?? 0,\n total_tokens:\n (event.tokens.input ?? 0) +\n (event.tokens.output ?? 0) +\n (event.tokens.reasoning ?? 0),\n ...(event.tokens.reasoning !== undefined\n ? { reasoning_tokens: event.tokens.reasoning }\n : {}),\n }\n : { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n ...(event.cost !== undefined ? { cost: event.cost } : {}),\n });\n }\n }\n },\n onAgentCallComplete: (call: AgentCallInfo) => {\n this._agentCalls.push(call);\n },\n };\n\n const ctx = new WorkflowContext(init);\n\n // Emit workflow_start through the same pipeline production uses,\n // AFTER ctx exists so `emitEvent`'s redact/step/timestamp handling\n // applies. Previously emitted via `_pushTrace` which bypassed\n // redaction — `config: { trace: { redact: true } }` on the test\n // runtime would scrub intermediate events but leak `input`/`result`\n // through the synthesized workflow_start/end.\n const startedAt = Date.now();\n ctx._emitWorkflowStart(validated);\n try {\n const result = await workflow.handler(ctx);\n const observation = await ctx._drainBranchWork();\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n ctx._emitWorkflowEnd({\n status: 'completed',\n duration: Date.now() - startedAt,\n result,\n observation,\n });\n // `_steps` is populated by onTrace for every event (including\n // workflow_end); no separate `_recordStep` call needed — that\n // would double-count.\n\n if (this.recordPath) await this._writeRecording();\n return result;\n } catch (err) {\n let workflowError = err;\n let observation: ObservationStatus = { complete: true };\n try {\n observation = await ctx._drainBranchWork();\n } catch (drainError) {\n workflowError =\n drainError instanceof Error ? preserveDrainCause(drainError, workflowError) : drainError;\n }\n // Parity with production: failed workflows get a terminal\n // `workflow_end(status: 'failed')` event so consumers counting\n // workflow_start ↔ workflow_end pairs never see an unclosed one.\n // `aborted` flag mirrors the runtime.ts AbortError detection.\n const aborted =\n typeof workflowError === 'object' &&\n workflowError !== null &&\n (workflowError as { name?: unknown }).name === 'AbortError';\n ctx._emitWorkflowEnd({\n status: 'failed',\n duration: Date.now() - startedAt,\n error: workflowError instanceof Error ? workflowError.message : String(workflowError),\n ...(aborted ? { aborted: true } : {}),\n observation,\n });\n // `_steps` populated by onTrace (see comment on the success path).\n throw workflowError;\n }\n }\n\n toolCalls(name?: string): RecordedToolCall[] {\n return name ? this._toolCalls.filter((c) => c.name === name) : this._toolCalls;\n }\n\n agentCalls(name?: string): RecordedAgentCall[] {\n return name ? this._agentCalls.filter((c) => c.agent === name) : this._agentCalls;\n }\n\n totalCost(): number {\n return this._totalCost;\n }\n /** True when any cost-bearing call was unpriced — `totalCost()` is then a\n * LOWER BOUND. Mirrors `ExecutionInfo.unpriced` / `BudgetResult.unpriced`. */\n unpriced(): boolean {\n return this._unpriced;\n }\n steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): AxlEvent[] {\n return this._traceLog;\n }\n\n private async _writeRecording(): Promise<void> {\n if (!this.recordPath) return;\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(this.recordPath), { recursive: true });\n await writeFile(this.recordPath, JSON.stringify(this.recorded, null, 2), 'utf8');\n }\n}\n"],"mappings":"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","names":["import_axl"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/mock-provider.ts","../src/mock-tool.ts","../src/mock-transcription-provider.ts","../src/test-runtime.ts"],"sourcesContent":["export { AxlTestRuntime } from './test-runtime.js';\nexport type { RecordedToolCall, RecordedAgentCall, RecordedStep } from './test-runtime.js';\nexport { MockProvider } from './mock-provider.js';\nexport { MockTranscriptionProvider } from './mock-transcription-provider.js';\nexport { MockTool } from './mock-tool.js';\n","import { readFileSync } from 'node:fs';\nimport { z } from 'zod';\nimport type {\n CallTiming,\n ChatMessage,\n ChatOptions,\n InputContentPart,\n InputMediaSource,\n ModelInput,\n ToolCallMessage,\n ProviderResponse,\n StreamChunk,\n Provider,\n ProviderInputValidationRequest,\n ProviderInputValidationResult,\n EffortResolution,\n} from '@axlsdk/axl';\nimport { inputText, UnsupportedModelInputError } from '@axlsdk/axl';\n\nfunction cloneValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return value.slice();\n if (Array.isArray(value)) return value.map(cloneValue);\n if (value && typeof value === 'object') {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneValue(item)]));\n }\n return value;\n}\n\nfunction cloneModelInput(input: ModelInput): ModelInput {\n if (typeof input === 'string') return input;\n return input.map((part): InputContentPart => {\n if (part.type === 'text') return { type: 'text', text: part.text };\n const { source } = part;\n switch (source.type) {\n case 'bytes':\n return {\n type: 'image',\n source: { type: 'bytes', data: source.data.slice(), mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'url':\n return {\n type: 'image',\n source: {\n type: 'url',\n url: source.url,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'base64':\n return {\n type: 'image',\n source: { type: 'base64', data: source.data, mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'provider-file':\n return {\n type: 'image',\n source: {\n type: 'provider-file',\n provider: source.provider,\n reference: source.reference,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n }\n });\n}\n\nfunction cloneMessages(messages: readonly ChatMessage[]): ChatMessage[] {\n return messages.map((message) => ({\n ...message,\n content: cloneModelInput(message.content),\n ...(message.tool_calls\n ? {\n tool_calls: message.tool_calls.map((toolCall) => ({\n ...toolCall,\n function: { ...toolCall.function },\n })),\n }\n : {}),\n ...(message.providerMetadata\n ? { providerMetadata: cloneValue(message.providerMetadata) as Record<string, unknown> }\n : {}),\n }));\n}\n\nfunction cloneOptions(options: ChatOptions): ChatOptions {\n return {\n ...options,\n ...(options.tools\n ? {\n tools: options.tools.map((tool) => ({\n ...tool,\n function: { ...tool.function, parameters: cloneValue(tool.function.parameters) },\n })),\n }\n : {}),\n ...(options.providerOptions\n ? { providerOptions: cloneValue(options.providerOptions) as Record<string, unknown> }\n : {}),\n };\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw signal.reason;\n}\n\nasync function awaitWithSignal<T>(\n value: PromiseLike<T> | T,\n signal: AbortSignal | undefined,\n): Promise<T> {\n if (!signal) return await value;\n throwIfAborted(signal);\n\n return await new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason);\n signal.addEventListener('abort', onAbort, { once: true });\n Promise.resolve(value).then(\n (result) => {\n signal.removeEventListener('abort', onAbort);\n resolve(result);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\nasync function abortableDelay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n if (ms <= 0) {\n throwIfAborted(signal);\n return;\n }\n if (!signal) {\n await new Promise<void>((resolve) => setTimeout(resolve, ms));\n return;\n }\n throwIfAborted(signal);\n\n await new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined = setTimeout(() => {\n timer = undefined;\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n signal.removeEventListener('abort', onAbort);\n reject(signal.reason);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction richParts(input: ModelInput): readonly InputContentPart[] {\n return typeof input === 'string' ? [] : input;\n}\n\nfunction randomAlphanumeric(length: number): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars[Math.floor(Math.random() * chars.length)];\n }\n return result;\n}\n\nfunction generateFromSchema(schema: unknown): unknown {\n if (schema instanceof z.ZodString) return randomAlphanumeric(8 + Math.floor(Math.random() * 13));\n if (schema instanceof z.ZodNumber) {\n const min = Number.isFinite(schema.minValue) ? schema.minValue! : 0;\n const max = Number.isFinite(schema.maxValue) ? schema.maxValue! : 100;\n return min + Math.random() * (max - min);\n }\n if (schema instanceof z.ZodBoolean) return Math.random() < 0.5;\n if (schema instanceof z.ZodArray) {\n const count = 1 + Math.floor(Math.random() * 3);\n return Array.from({ length: count }, () => generateFromSchema(schema.element));\n }\n if (schema instanceof z.ZodObject) {\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(schema.shape)) obj[key] = generateFromSchema(value);\n return obj;\n }\n if (schema instanceof z.ZodOptional) {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(schema.unwrap());\n }\n if (schema instanceof z.ZodDefault) return schema.parse(undefined);\n if (schema instanceof z.ZodEnum) {\n const values = schema.options;\n return values.length > 0 ? values[Math.floor(Math.random() * values.length)] : '';\n }\n if (schema instanceof z.ZodLiteral) return [...schema.values][0];\n if (schema instanceof z.ZodNullable) return null;\n if (schema instanceof z.ZodUnion) {\n const options = schema.options;\n return generateFromSchema(options[Math.floor(Math.random() * options.length)]);\n }\n return {};\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: ChatOptions }[] = [];\n /** Per-call optional chunk arrays, set by `sequence()` / `chunked()` so\n * `stream()` can yield one `text_delta` per chunk. Per-call indexed\n * alongside the response sequence. */\n private chunkSequence?: Array<string[] | undefined>;\n /** Optional ms delay between successive chunks during `stream()`. Useful\n * for dev fixtures that need to demonstrate streaming UX visually\n * (without a delay, mock chunks fire synchronously and complete in\n * microseconds — invisible to a human watching). Default 0 keeps\n * every existing test fast.\n *\n * Set via `provider.chunkDelayMs = 50` after construction. Not part of\n * any factory's surface to keep the test API minimal. */\n chunkDelayMs = 0;\n\n /** How this mock reports the unified `effort` it was asked for. Undefined (the\n * default) means the mock implements no `effortResolution` at all, so the\n * runtime emits no `provider_diagnostic`. Set it with\n * {@link MockProvider.withEffortResolution} to drive the clamp-reporting path. */\n effortResolution?: (\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined;\n\n /**\n * Make this mock report an effort clamp, so a test can exercise the runtime's\n * `provider_diagnostic` path without a real adapter. Pass a fixed\n * {@link EffortResolution} or a function of the request knobs.\n *\n * ```ts\n * const provider = MockProvider.echo().withEffortResolution({\n * requested: 'none',\n * effective: 'minimal',\n * clamped: true,\n * cause: 'this model cannot disable thinking',\n * });\n * ```\n */\n withEffortResolution(\n resolution:\n | EffortResolution\n | undefined\n | ((\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined),\n ): this {\n this.effortResolution = typeof resolution === 'function' ? resolution : () => resolution;\n return this;\n }\n\n private constructor(\n private responseFn: (\n messages: ChatMessage[],\n callIndex: number,\n ) => ProviderResponse | Promise<ProviderResponse>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: ChatOptions): Promise<ProviderResponse> {\n // Each consumer gets independent ownership: a handler can inspect or mutate\n // its copy without changing the durable assertion record (including bytes).\n const recordedMessages = cloneMessages(messages);\n const callIndex = this._calls.length;\n this._calls.push({ messages: recordedMessages, options: cloneOptions(options) });\n throwIfAborted(options.signal);\n const response = Promise.resolve().then(() =>\n this.responseFn(cloneMessages(messages), callIndex),\n );\n return await awaitWithSignal(response, options.signal);\n }\n\n inputCapabilities(_model: string): { image: { sources: readonly InputMediaSource['type'][] } } {\n return { image: { sources: ['url', 'bytes', 'base64', 'provider-file'] } };\n }\n\n validateInput(request: ProviderInputValidationRequest): ProviderInputValidationResult {\n const effectiveModel =\n typeof request.providerOptions?.model === 'string'\n ? request.providerOptions.model\n : request.model;\n const fail = (source?: string, feature?: string): never => {\n throw new UnsupportedModelInputError({\n provider: this.name,\n model: effectiveModel || request.model,\n modality: 'image',\n ...(source ? { source } : {}),\n ...(feature ? { feature } : {}),\n });\n };\n\n if (request.providerOptions && 'input' in request.providerOptions) {\n fail(undefined, 'raw input-container providerOptions');\n }\n for (const message of request.history) {\n if (typeof message.content === 'string') continue;\n if (message.role !== 'user') fail(undefined, 'rich non-user history');\n for (const part of richParts(message.content)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n }\n for (const part of richParts(request.input)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n return { effectiveModel };\n }\n\n async *stream(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamChunk> {\n const callIndex = this._calls.length;\n const response = await this.chat(messages, options);\n throwIfAborted(options.signal);\n const chunks = this.chunkSequence?.[callIndex];\n if (chunks && chunks.length > 0) {\n // Sanity guard — if a caller passes chunks AND content, they MUST\n // match. Otherwise tests pass while the real prod content silently\n // diverges from what the streaming path observes.\n const joined = chunks.join('');\n if (joined !== response.content) {\n throw new Error(\n `MockProvider.stream: chunks.join('') !== content. ` +\n `chunks=\"${joined}\" content=\"${response.content}\"`,\n );\n }\n for (let i = 0; i < chunks.length; i++) {\n throwIfAborted(options.signal);\n yield { type: 'text_delta', content: chunks[i] };\n if (this.chunkDelayMs > 0 && i < chunks.length - 1) {\n await abortableDelay(this.chunkDelayMs, options.signal);\n }\n }\n } else if (response.content) {\n throwIfAborted(options.signal);\n yield { type: 'text_delta', content: response.content };\n }\n if (response.tool_calls) {\n for (const tc of response.tool_calls) {\n throwIfAborted(options.signal);\n yield {\n type: 'tool_call_delta',\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n };\n }\n }\n throwIfAborted(options.signal);\n yield {\n type: 'done',\n usage: response.usage,\n // Forwarded like `chat()` does. Without it a streamed mock ask reported no\n // cost at all, so `ctx.budget` and every cost assertion silently saw zero\n // on the streaming path while the same fixture priced correctly on the\n // non-streaming one — a mock that disagrees with itself between paths.\n cost: response.cost,\n providerMetadata: response.providerMetadata,\n // Conditional spread, not `timing: response.timing` — a mock response with\n // no timing must produce a `done` chunk with NO `timing` key at all, so a\n // consumer's `'timing' in chunk` check reads the same as a real adapter's.\n ...(response.timing ? { timing: response.timing } : {}),\n };\n }\n\n static sequence(\n responses: Array<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Deterministic provider-call timing, surfaced on `ProviderResponse.timing`\n * and on the streamed terminal `done` chunk. Lets a test drive\n * `agent_call_end.timing`, the `TimeoutError` breakdown, and the eval\n * per-model rollup without real clocks or a real transport. Omit it and\n * the mock behaves exactly like an uninstrumented custom provider. */\n timing?: CallTiming;\n /** When set, `stream()` yields one `text_delta` per entry instead\n * of one big delta with the full content. Use to exercise\n * partial-JSON parsing, structural-boundary throttling, and\n * cross-attempt token retention in tests. Must satisfy\n * `chunks.join('') === content`. */\n chunks?: string[];\n }>,\n ): MockProvider {\n const provider = new MockProvider((_messages, callIndex) => {\n if (callIndex >= responses.length) {\n throw new Error(\n `MockProvider.sequence: no response for call index ${callIndex}. Only ${responses.length} responses defined.`,\n );\n }\n const resp = responses[callIndex];\n return {\n content: resp.content,\n tool_calls: resp.tool_calls,\n providerMetadata: resp.providerMetadata,\n usage: resp.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: resp.cost ?? 0,\n // Copied, not shared: the caller keeps ownership of the fixture, so a\n // consumer that mutates the returned block cannot corrupt a later call's\n // expectation (same rule the message/options clones follow).\n ...(resp.timing ? { timing: { ...resp.timing } } : {}),\n };\n });\n provider.chunkSequence = responses.map((r) => r.chunks);\n return provider;\n }\n\n /**\n * Convenience: build a `sequence()` from plain content strings, splitting\n * each one into fixed-size chunks for the streaming path. Default\n * `chunkSize` is 4 chars (≈1 token).\n */\n static chunked(contents: string[], chunkSize = 4): MockProvider {\n const responses = contents.map((content) => {\n const chunks: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunks.push(content.slice(i, i + chunkSize));\n }\n return { content, chunks };\n });\n return MockProvider.sequence(responses);\n }\n\n static echo(): MockProvider {\n return new MockProvider((messages) => {\n const lastUser = [...messages].reverse().find((m) => m.role === 'user');\n return {\n content: lastUser ? inputText(lastUser.content) : '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: unknown): MockProvider {\n return new MockProvider(() => ({\n content: JSON.stringify(generateFromSchema(schema)),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n\n static replay(source: string | ProviderResponse[]): MockProvider {\n const data =\n typeof source === 'string'\n ? (JSON.parse(readFileSync(source, 'utf-8')) as ProviderResponse[])\n : source;\n return new MockProvider((_messages, callIndex) => {\n if (callIndex >= data.length) {\n throw new Error(`MockProvider.replay: no recorded response for call index ${callIndex}`);\n }\n return data[callIndex];\n });\n }\n\n static fn(\n handler: (\n messages: ChatMessage[],\n callIndex: number,\n ) =>\n | {\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }\n | Promise<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }>,\n ): MockProvider {\n return new MockProvider(async (messages, callIndex) => {\n const result = await handler(messages, callIndex);\n return {\n ...result,\n usage: result.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: result.cost ?? 0,\n };\n });\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: unknown) => unknown | Promise<unknown>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async execute(input: unknown): Promise<unknown> {\n this._calls.push({ input });\n return this.handler(input);\n }\n\n static create(name: string, handler: (input: unknown) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import type {\n TranscriptionCapabilities,\n TranscriptionProvider,\n TranscriptionProviderRequest,\n TranscriptionProviderResult,\n} from '@axlsdk/axl';\n\nfunction clone<T>(value: T): T {\n return structuredClone(value);\n}\n\nfunction cloneRequest(\n request: TranscriptionProviderRequest,\n includeSignal: boolean,\n): TranscriptionProviderRequest {\n const audio =\n request.audio.type === 'bytes'\n ? { ...request.audio, data: request.audio.data.slice() }\n : { ...request.audio };\n return {\n model: request.model,\n audio,\n ...(request.language !== undefined ? { language: request.language } : {}),\n ...(request.timestamps !== undefined ? { timestamps: request.timestamps } : {}),\n ...(request.diarization !== undefined ? { diarization: request.diarization } : {}),\n ...(request.providerOptions ? { providerOptions: clone(request.providerOptions) } : {}),\n ...(includeSignal && request.signal ? { signal: request.signal } : {}),\n };\n}\n\n/** Dedicated transcription mock. It intentionally does not extend MockProvider,\n * so chat fixtures cannot accidentally become transcription adapters. */\nexport class MockTranscriptionProvider implements TranscriptionProvider {\n private _calls: TranscriptionProviderRequest[] = [];\n\n constructor(\n private readonly response: (\n request: TranscriptionProviderRequest,\n callIndex: number,\n ) => TranscriptionProviderResult | Promise<TranscriptionProviderResult>,\n private readonly capabilitiesFor: (\n model: string,\n ) => TranscriptionCapabilities | undefined = () => ({\n sources: ['bytes', 'base64', 'provider-file'],\n timestamps: ['segment', 'word'],\n diarization: true,\n }),\n ) {}\n\n get calls(): readonly TranscriptionProviderRequest[] {\n return this._calls.map(clone);\n }\n\n capabilities(model: string): TranscriptionCapabilities | undefined {\n return this.capabilitiesFor(model);\n }\n\n async transcribe(request: TranscriptionProviderRequest): Promise<TranscriptionProviderResult> {\n // AbortSignal cannot be structured-cloned. Keep it only on the callback\n // request so fixtures can observe cancellation; recorded calls omit it.\n const snapshot = cloneRequest(request, false);\n this._calls.push(snapshot);\n return clone(await this.response(cloneRequest(request, true), this._calls.length - 1));\n }\n\n static text(text: string): MockTranscriptionProvider {\n return new MockTranscriptionProvider(() => ({ transcript: { text } }));\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport { MockTranscriptionProvider } from './mock-transcription-provider.js';\nimport type {\n AxlEvent,\n AwaitHumanOptions,\n HumanDecision,\n ProviderResponse,\n AgentCallInfo,\n AxlConfig,\n AnyWorkflow,\n ToolCallOutcome,\n ObservationStatus,\n} from '@axlsdk/axl';\nimport {\n WorkflowContext,\n MemoryStore,\n ProviderRegistry,\n TranscriptionProviderRegistry,\n eventCostContribution,\n isUnpricedLeaf,\n} from '@axlsdk/axl';\nimport type { EventStreamOptions, WorkflowContextInit } from '@axlsdk/axl';\n\n// `AnyWorkflow` is a re-exported alias for `Workflow<any, any>` — see\n// the JSDoc on `AnyWorkflow` in `@axlsdk/axl/workflow.ts`. The bivariant\n// `any` is load-bearing for satisfying narrowly-typed handlers (e.g., a\n// `Workflow<TInput=MsgType>` whose handler takes `WorkflowContext<MsgType>`).\n\n/** One accepted provider-issued tool invocation, recorded from its terminal v2 event.\n *\n * Narrow `outcome.status` before reading status-specific fields. Correlation uses\n * `(executionId, askId, callId)`; `name` is the canonical tool name.\n */\nexport type RecordedToolCall = {\n name: string;\n executionId: string;\n askId: string;\n callId: string;\n args: unknown;\n requestedTool?: string;\n outcome: ToolCallOutcome;\n};\nexport type RecordedAgentCall = Partial<AgentCallInfo> &\n Pick<AgentCallInfo, 'agent' | 'prompt' | 'response'>;\nexport type RecordedStep = { step: number; type: string; data: unknown };\n\nfunction generateExecutionId(): string {\n return `test-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction preserveDrainCause(error: Error, cause: unknown): Error {\n if (cause === undefined || cause === error || 'cause' in error) return error;\n Object.defineProperty(error, 'cause', {\n configurable: true,\n enumerable: false,\n value: cause,\n });\n return error;\n}\n\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n /** AxlConfig for the test runtime. Controls trace level/redact, context management, etc.\n * Defaults to `{}`. Set `{ trace: { level: 'full' } }` to verify verbose-mode snapshots\n * in tests, or `{ trace: { redact: true } }` to verify redaction policy in tests. */\n config?: AxlConfig;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, AnyWorkflow>();\n private mockProviders = new Map<string, MockProvider>();\n private mockTranscriptionProviders = new Map<string, MockTranscriptionProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: AxlEvent[] = [];\n private _totalCost = 0;\n private _unpriced = false;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n private _config: AxlConfig;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n this._config = options?.config ?? {};\n }\n\n register(workflow: AnyWorkflow): void {\n this.workflows.set(workflow.name, workflow);\n }\n\n mockProvider(name: string, provider: MockProvider): void {\n this.mockProviders.set(name, provider);\n }\n\n mockTranscriptionProvider(name: string, provider: MockTranscriptionProvider): void {\n this.mockTranscriptionProviders.set(name, provider);\n }\n\n mockTool<TInput = unknown>(\n name: string,\n handler: (input: TInput) => unknown | Promise<unknown>,\n ): void {\n // The MockTool registry is type-erased (`(input: unknown) => unknown`)\n // because the runtime can't statically know each tool's input shape; tests\n // opt in to a typed input via the generic, and we cast on storage.\n this.mockToolMap.set(name, MockTool.create(name, handler as (input: unknown) => unknown));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: {\n metadata?: Record<string, unknown>;\n events?: EventStreamOptions;\n branchDrainTimeoutMs?: number;\n },\n ): Promise<unknown> {\n const workflow = this.workflows.get(workflowName);\n if (!workflow) throw new Error(`Workflow \"${workflowName}\" not registered`);\n\n // Reset state between executions\n this._toolCalls = [];\n this._agentCalls = [];\n this._steps = [];\n this._traceLog = [];\n this._totalCost = 0;\n this._unpriced = false;\n this._stepCounter = 0;\n this.recorded = [];\n this._executionId = generateExecutionId();\n\n const validated = workflow.inputSchema.parse(input);\n\n // Build ProviderRegistry from registered mock providers\n const registry = new ProviderRegistry();\n registry.clearFactories(); // Remove built-in factories; only use explicit mocks\n for (const [name, provider] of this.mockProviders) {\n registry.registerInstance(name, provider);\n }\n const transcriptionRegistry = new TranscriptionProviderRegistry();\n for (const [name, provider] of this.mockTranscriptionProviders) {\n transcriptionRegistry.registerInstance(name, provider);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider);\n }\n\n // Build toolOverrides from mockToolMap\n const toolOverrides = new Map<string, (args: unknown) => Promise<unknown>>();\n for (const [name, mockTool] of this.mockToolMap) {\n toolOverrides.set(name, async (args: unknown) => {\n return mockTool.execute(args);\n });\n }\n\n // Previously `_recordStep('workflow_start', ...)` was called here with\n // raw `{ workflow, input }` data, AND `ctx._emitWorkflowStart` below\n // pushed through the onTrace handler (which also bumps `_stepCounter`\n // and appends to `_steps`). Result: two entries in `steps()` per\n // workflow_start, with the first bypassing `config.trace.redact`.\n // The `_recordStep` call is removed — onTrace is the single source\n // of truth for `_steps`, matching the behavior of every other event\n // type in the test runtime. Reviewer architecture §5.\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n // Thread the constructor-provided config so tests can exercise\n // trace.level === 'full' and trace.redact behavior end-to-end.\n config: this._config,\n // Thread `events` config so tests can exercise the queue cap and\n // overflow policy on `ctx.events`. Mirrors the production runtime.\n eventStreamOptions: options?.events,\n branchDrainTimeoutMs: options?.branchDrainTimeoutMs,\n // Production runtime threads this (see `runtime.ts:594` in\n // `execute()` and `:765` in `stream()`). `emitEvent` auto-stamps\n // `event.workflow` from it, so consumers grouping by workflow\n // (Cost Dashboard `byWorkflow`, `trackExecution.metadata.workflows`,\n // any eval runner) see the same attribution in tests and prod.\n workflowName,\n providerRegistry: registry,\n transcriptionProviderRegistry: transcriptionRegistry,\n stateStore: new MemoryStore(),\n toolOverrides: toolOverrides.size > 0 ? toolOverrides : undefined,\n awaitHumanHandler: this._humanDecisionHandler\n ? (opts: AwaitHumanOptions) => this._humanDecisionHandler!(opts)\n : undefined,\n onTrace: (event: AxlEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({\n step: this._stepCounter,\n type: event.type,\n data: (event as { data?: unknown }).data,\n });\n\n if (event.type === 'tool_call_end') {\n const { args, requestedTool, outcome } = event.data;\n this._toolCalls.push({\n name: event.tool,\n executionId: event.executionId,\n askId: event.askId,\n callId: event.callId,\n args,\n ...(requestedTool !== undefined ? { requestedTool } : {}),\n outcome,\n });\n }\n\n // Single-source-of-truth cost accumulator. Skips ask_end\n // rollups (decision 10) and guards NaN/Infinity.\n this._totalCost += eventCostContribution(event);\n // Honest aggregate: one unpriced leaf makes `totalCost()` a lower bound.\n if (isUnpricedLeaf(event)) this._unpriced = true;\n\n // Track provider responses for recording\n if (event.type === 'agent_call_end' && event.data) {\n const { response } = event.data as { prompt?: string; response?: string };\n if (response !== undefined) {\n this.recorded.push({\n content: response,\n usage: event.tokens\n ? {\n prompt_tokens: event.tokens.input ?? 0,\n completion_tokens: event.tokens.output ?? 0,\n total_tokens:\n (event.tokens.input ?? 0) +\n (event.tokens.output ?? 0) +\n (event.tokens.reasoning ?? 0),\n ...(event.tokens.reasoning !== undefined\n ? { reasoning_tokens: event.tokens.reasoning }\n : {}),\n }\n : { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n ...(event.cost !== undefined ? { cost: event.cost } : {}),\n });\n }\n }\n },\n onAgentCallComplete: (call: AgentCallInfo) => {\n this._agentCalls.push(call);\n },\n };\n\n const ctx = new WorkflowContext(init);\n\n // Emit workflow_start through the same pipeline production uses,\n // AFTER ctx exists so `emitEvent`'s redact/step/timestamp handling\n // applies. Previously emitted via `_pushTrace` which bypassed\n // redaction — `config: { trace: { redact: true } }` on the test\n // runtime would scrub intermediate events but leak `input`/`result`\n // through the synthesized workflow_start/end.\n const startedAt = Date.now();\n ctx._emitWorkflowStart(validated);\n try {\n const result = await workflow.handler(ctx);\n const observation = await ctx._drainBranchWork();\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n ctx._emitWorkflowEnd({\n status: 'completed',\n duration: Date.now() - startedAt,\n result,\n observation,\n });\n // `_steps` is populated by onTrace for every event (including\n // workflow_end); no separate `_recordStep` call needed — that\n // would double-count.\n\n if (this.recordPath) await this._writeRecording();\n return result;\n } catch (err) {\n let workflowError = err;\n let observation: ObservationStatus = { complete: true };\n try {\n observation = await ctx._drainBranchWork();\n } catch (drainError) {\n workflowError =\n drainError instanceof Error ? preserveDrainCause(drainError, workflowError) : drainError;\n }\n // Parity with production: failed workflows get a terminal\n // `workflow_end(status: 'failed')` event so consumers counting\n // workflow_start ↔ workflow_end pairs never see an unclosed one.\n // `aborted` flag mirrors the runtime.ts AbortError detection.\n const aborted =\n typeof workflowError === 'object' &&\n workflowError !== null &&\n (workflowError as { name?: unknown }).name === 'AbortError';\n ctx._emitWorkflowEnd({\n status: 'failed',\n duration: Date.now() - startedAt,\n error: workflowError instanceof Error ? workflowError.message : String(workflowError),\n ...(aborted ? { aborted: true } : {}),\n observation,\n });\n // `_steps` populated by onTrace (see comment on the success path).\n throw workflowError;\n }\n }\n\n toolCalls(name?: string): RecordedToolCall[] {\n return name ? this._toolCalls.filter((c) => c.name === name) : this._toolCalls;\n }\n\n agentCalls(name?: string): RecordedAgentCall[] {\n return name ? this._agentCalls.filter((c) => c.agent === name) : this._agentCalls;\n }\n\n totalCost(): number {\n return this._totalCost;\n }\n /** True when any cost-bearing call was unpriced — `totalCost()` is then a\n * LOWER BOUND. Mirrors `ExecutionInfo.unpriced` / `BudgetResult.unpriced`. */\n unpriced(): boolean {\n return this._unpriced;\n }\n steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): AxlEvent[] {\n return this._traceLog;\n }\n\n private async _writeRecording(): Promise<void> {\n if (!this.recordPath) return;\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(this.recordPath), { recursive: true });\n await writeFile(this.recordPath, JSON.stringify(this.recorded, null, 2), 'utf8');\n }\n}\n"],"mappings":"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","names":["import_axl"]}
|
package/dist/index.js
CHANGED
|
@@ -77,6 +77,52 @@ function cloneOptions(options) {
|
|
|
77
77
|
...options.providerOptions ? { providerOptions: cloneValue(options.providerOptions) } : {}
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
+
function throwIfAborted(signal) {
|
|
81
|
+
if (signal?.aborted) throw signal.reason;
|
|
82
|
+
}
|
|
83
|
+
async function awaitWithSignal(value, signal) {
|
|
84
|
+
if (!signal) return await value;
|
|
85
|
+
throwIfAborted(signal);
|
|
86
|
+
return await new Promise((resolve, reject) => {
|
|
87
|
+
const onAbort = () => reject(signal.reason);
|
|
88
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
89
|
+
Promise.resolve(value).then(
|
|
90
|
+
(result) => {
|
|
91
|
+
signal.removeEventListener("abort", onAbort);
|
|
92
|
+
resolve(result);
|
|
93
|
+
},
|
|
94
|
+
(error) => {
|
|
95
|
+
signal.removeEventListener("abort", onAbort);
|
|
96
|
+
reject(error);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function abortableDelay(ms, signal) {
|
|
102
|
+
if (ms <= 0) {
|
|
103
|
+
throwIfAborted(signal);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!signal) {
|
|
107
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
throwIfAborted(signal);
|
|
111
|
+
await new Promise((resolve, reject) => {
|
|
112
|
+
let timer = setTimeout(() => {
|
|
113
|
+
timer = void 0;
|
|
114
|
+
signal.removeEventListener("abort", onAbort);
|
|
115
|
+
resolve();
|
|
116
|
+
}, ms);
|
|
117
|
+
const onAbort = () => {
|
|
118
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
119
|
+
timer = void 0;
|
|
120
|
+
signal.removeEventListener("abort", onAbort);
|
|
121
|
+
reject(signal.reason);
|
|
122
|
+
};
|
|
123
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
124
|
+
});
|
|
125
|
+
}
|
|
80
126
|
function richParts(input) {
|
|
81
127
|
return typeof input === "string" ? [] : input;
|
|
82
128
|
}
|
|
@@ -169,8 +215,13 @@ var MockProvider = class _MockProvider {
|
|
|
169
215
|
}
|
|
170
216
|
async chat(messages, options) {
|
|
171
217
|
const recordedMessages = cloneMessages(messages);
|
|
218
|
+
const callIndex = this._calls.length;
|
|
172
219
|
this._calls.push({ messages: recordedMessages, options: cloneOptions(options) });
|
|
173
|
-
|
|
220
|
+
throwIfAborted(options.signal);
|
|
221
|
+
const response = Promise.resolve().then(
|
|
222
|
+
() => this.responseFn(cloneMessages(messages), callIndex)
|
|
223
|
+
);
|
|
224
|
+
return await awaitWithSignal(response, options.signal);
|
|
174
225
|
}
|
|
175
226
|
inputCapabilities(_model) {
|
|
176
227
|
return { image: { sources: ["url", "bytes", "base64", "provider-file"] } };
|
|
@@ -208,6 +259,7 @@ var MockProvider = class _MockProvider {
|
|
|
208
259
|
async *stream(messages, options) {
|
|
209
260
|
const callIndex = this._calls.length;
|
|
210
261
|
const response = await this.chat(messages, options);
|
|
262
|
+
throwIfAborted(options.signal);
|
|
211
263
|
const chunks = this.chunkSequence?.[callIndex];
|
|
212
264
|
if (chunks && chunks.length > 0) {
|
|
213
265
|
const joined = chunks.join("");
|
|
@@ -217,16 +269,19 @@ var MockProvider = class _MockProvider {
|
|
|
217
269
|
);
|
|
218
270
|
}
|
|
219
271
|
for (let i = 0; i < chunks.length; i++) {
|
|
272
|
+
throwIfAborted(options.signal);
|
|
220
273
|
yield { type: "text_delta", content: chunks[i] };
|
|
221
274
|
if (this.chunkDelayMs > 0 && i < chunks.length - 1) {
|
|
222
|
-
await
|
|
275
|
+
await abortableDelay(this.chunkDelayMs, options.signal);
|
|
223
276
|
}
|
|
224
277
|
}
|
|
225
278
|
} else if (response.content) {
|
|
279
|
+
throwIfAborted(options.signal);
|
|
226
280
|
yield { type: "text_delta", content: response.content };
|
|
227
281
|
}
|
|
228
282
|
if (response.tool_calls) {
|
|
229
283
|
for (const tc of response.tool_calls) {
|
|
284
|
+
throwIfAborted(options.signal);
|
|
230
285
|
yield {
|
|
231
286
|
type: "tool_call_delta",
|
|
232
287
|
id: tc.id,
|
|
@@ -235,6 +290,7 @@ var MockProvider = class _MockProvider {
|
|
|
235
290
|
};
|
|
236
291
|
}
|
|
237
292
|
}
|
|
293
|
+
throwIfAborted(options.signal);
|
|
238
294
|
yield {
|
|
239
295
|
type: "done",
|
|
240
296
|
usage: response.usage,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mock-provider.ts","../src/mock-tool.ts","../src/mock-transcription-provider.ts","../src/test-runtime.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { z } from 'zod';\nimport type {\n CallTiming,\n ChatMessage,\n ChatOptions,\n InputContentPart,\n InputMediaSource,\n ModelInput,\n ToolCallMessage,\n ProviderResponse,\n StreamChunk,\n Provider,\n ProviderInputValidationRequest,\n ProviderInputValidationResult,\n EffortResolution,\n} from '@axlsdk/axl';\nimport { inputText, UnsupportedModelInputError } from '@axlsdk/axl';\n\nfunction cloneValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return value.slice();\n if (Array.isArray(value)) return value.map(cloneValue);\n if (value && typeof value === 'object') {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneValue(item)]));\n }\n return value;\n}\n\nfunction cloneModelInput(input: ModelInput): ModelInput {\n if (typeof input === 'string') return input;\n return input.map((part): InputContentPart => {\n if (part.type === 'text') return { type: 'text', text: part.text };\n const { source } = part;\n switch (source.type) {\n case 'bytes':\n return {\n type: 'image',\n source: { type: 'bytes', data: source.data.slice(), mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'url':\n return {\n type: 'image',\n source: {\n type: 'url',\n url: source.url,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'base64':\n return {\n type: 'image',\n source: { type: 'base64', data: source.data, mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'provider-file':\n return {\n type: 'image',\n source: {\n type: 'provider-file',\n provider: source.provider,\n reference: source.reference,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n }\n });\n}\n\nfunction cloneMessages(messages: readonly ChatMessage[]): ChatMessage[] {\n return messages.map((message) => ({\n ...message,\n content: cloneModelInput(message.content),\n ...(message.tool_calls\n ? {\n tool_calls: message.tool_calls.map((toolCall) => ({\n ...toolCall,\n function: { ...toolCall.function },\n })),\n }\n : {}),\n ...(message.providerMetadata\n ? { providerMetadata: cloneValue(message.providerMetadata) as Record<string, unknown> }\n : {}),\n }));\n}\n\nfunction cloneOptions(options: ChatOptions): ChatOptions {\n return {\n ...options,\n ...(options.tools\n ? {\n tools: options.tools.map((tool) => ({\n ...tool,\n function: { ...tool.function, parameters: cloneValue(tool.function.parameters) },\n })),\n }\n : {}),\n ...(options.providerOptions\n ? { providerOptions: cloneValue(options.providerOptions) as Record<string, unknown> }\n : {}),\n };\n}\n\nfunction richParts(input: ModelInput): readonly InputContentPart[] {\n return typeof input === 'string' ? [] : input;\n}\n\nfunction randomAlphanumeric(length: number): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars[Math.floor(Math.random() * chars.length)];\n }\n return result;\n}\n\nfunction generateFromSchema(schema: unknown): unknown {\n if (schema instanceof z.ZodString) return randomAlphanumeric(8 + Math.floor(Math.random() * 13));\n if (schema instanceof z.ZodNumber) {\n const min = Number.isFinite(schema.minValue) ? schema.minValue! : 0;\n const max = Number.isFinite(schema.maxValue) ? schema.maxValue! : 100;\n return min + Math.random() * (max - min);\n }\n if (schema instanceof z.ZodBoolean) return Math.random() < 0.5;\n if (schema instanceof z.ZodArray) {\n const count = 1 + Math.floor(Math.random() * 3);\n return Array.from({ length: count }, () => generateFromSchema(schema.element));\n }\n if (schema instanceof z.ZodObject) {\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(schema.shape)) obj[key] = generateFromSchema(value);\n return obj;\n }\n if (schema instanceof z.ZodOptional) {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(schema.unwrap());\n }\n if (schema instanceof z.ZodDefault) return schema.parse(undefined);\n if (schema instanceof z.ZodEnum) {\n const values = schema.options;\n return values.length > 0 ? values[Math.floor(Math.random() * values.length)] : '';\n }\n if (schema instanceof z.ZodLiteral) return [...schema.values][0];\n if (schema instanceof z.ZodNullable) return null;\n if (schema instanceof z.ZodUnion) {\n const options = schema.options;\n return generateFromSchema(options[Math.floor(Math.random() * options.length)]);\n }\n return {};\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: ChatOptions }[] = [];\n /** Per-call optional chunk arrays, set by `sequence()` / `chunked()` so\n * `stream()` can yield one `text_delta` per chunk. Per-call indexed\n * alongside the response sequence. */\n private chunkSequence?: Array<string[] | undefined>;\n /** Optional ms delay between successive chunks during `stream()`. Useful\n * for dev fixtures that need to demonstrate streaming UX visually\n * (without a delay, mock chunks fire synchronously and complete in\n * microseconds — invisible to a human watching). Default 0 keeps\n * every existing test fast.\n *\n * Set via `provider.chunkDelayMs = 50` after construction. Not part of\n * any factory's surface to keep the test API minimal. */\n chunkDelayMs = 0;\n\n /** How this mock reports the unified `effort` it was asked for. Undefined (the\n * default) means the mock implements no `effortResolution` at all, so the\n * runtime emits no `provider_diagnostic`. Set it with\n * {@link MockProvider.withEffortResolution} to drive the clamp-reporting path. */\n effortResolution?: (\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined;\n\n /**\n * Make this mock report an effort clamp, so a test can exercise the runtime's\n * `provider_diagnostic` path without a real adapter. Pass a fixed\n * {@link EffortResolution} or a function of the request knobs.\n *\n * ```ts\n * const provider = MockProvider.echo().withEffortResolution({\n * requested: 'none',\n * effective: 'minimal',\n * clamped: true,\n * cause: 'this model cannot disable thinking',\n * });\n * ```\n */\n withEffortResolution(\n resolution:\n | EffortResolution\n | undefined\n | ((\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined),\n ): this {\n this.effortResolution = typeof resolution === 'function' ? resolution : () => resolution;\n return this;\n }\n\n private constructor(\n private responseFn: (\n messages: ChatMessage[],\n callIndex: number,\n ) => ProviderResponse | Promise<ProviderResponse>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: ChatOptions): Promise<ProviderResponse> {\n // Each consumer gets independent ownership: a handler can inspect or mutate\n // its copy without changing the durable assertion record (including bytes).\n const recordedMessages = cloneMessages(messages);\n this._calls.push({ messages: recordedMessages, options: cloneOptions(options) });\n return await this.responseFn(cloneMessages(messages), this._calls.length - 1);\n }\n\n inputCapabilities(_model: string): { image: { sources: readonly InputMediaSource['type'][] } } {\n return { image: { sources: ['url', 'bytes', 'base64', 'provider-file'] } };\n }\n\n validateInput(request: ProviderInputValidationRequest): ProviderInputValidationResult {\n const effectiveModel =\n typeof request.providerOptions?.model === 'string'\n ? request.providerOptions.model\n : request.model;\n const fail = (source?: string, feature?: string): never => {\n throw new UnsupportedModelInputError({\n provider: this.name,\n model: effectiveModel || request.model,\n modality: 'image',\n ...(source ? { source } : {}),\n ...(feature ? { feature } : {}),\n });\n };\n\n if (request.providerOptions && 'input' in request.providerOptions) {\n fail(undefined, 'raw input-container providerOptions');\n }\n for (const message of request.history) {\n if (typeof message.content === 'string') continue;\n if (message.role !== 'user') fail(undefined, 'rich non-user history');\n for (const part of richParts(message.content)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n }\n for (const part of richParts(request.input)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n return { effectiveModel };\n }\n\n async *stream(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamChunk> {\n const callIndex = this._calls.length;\n const response = await this.chat(messages, options);\n const chunks = this.chunkSequence?.[callIndex];\n if (chunks && chunks.length > 0) {\n // Sanity guard — if a caller passes chunks AND content, they MUST\n // match. Otherwise tests pass while the real prod content silently\n // diverges from what the streaming path observes.\n const joined = chunks.join('');\n if (joined !== response.content) {\n throw new Error(\n `MockProvider.stream: chunks.join('') !== content. ` +\n `chunks=\"${joined}\" content=\"${response.content}\"`,\n );\n }\n for (let i = 0; i < chunks.length; i++) {\n yield { type: 'text_delta', content: chunks[i] };\n if (this.chunkDelayMs > 0 && i < chunks.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, this.chunkDelayMs));\n }\n }\n } else if (response.content) {\n yield { type: 'text_delta', content: response.content };\n }\n if (response.tool_calls) {\n for (const tc of response.tool_calls) {\n yield {\n type: 'tool_call_delta',\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n };\n }\n }\n yield {\n type: 'done',\n usage: response.usage,\n // Forwarded like `chat()` does. Without it a streamed mock ask reported no\n // cost at all, so `ctx.budget` and every cost assertion silently saw zero\n // on the streaming path while the same fixture priced correctly on the\n // non-streaming one — a mock that disagrees with itself between paths.\n cost: response.cost,\n providerMetadata: response.providerMetadata,\n // Conditional spread, not `timing: response.timing` — a mock response with\n // no timing must produce a `done` chunk with NO `timing` key at all, so a\n // consumer's `'timing' in chunk` check reads the same as a real adapter's.\n ...(response.timing ? { timing: response.timing } : {}),\n };\n }\n\n static sequence(\n responses: Array<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Deterministic provider-call timing, surfaced on `ProviderResponse.timing`\n * and on the streamed terminal `done` chunk. Lets a test drive\n * `agent_call_end.timing`, the `TimeoutError` breakdown, and the eval\n * per-model rollup without real clocks or a real transport. Omit it and\n * the mock behaves exactly like an uninstrumented custom provider. */\n timing?: CallTiming;\n /** When set, `stream()` yields one `text_delta` per entry instead\n * of one big delta with the full content. Use to exercise\n * partial-JSON parsing, structural-boundary throttling, and\n * cross-attempt token retention in tests. Must satisfy\n * `chunks.join('') === content`. */\n chunks?: string[];\n }>,\n ): MockProvider {\n const provider = new MockProvider((_messages, callIndex) => {\n if (callIndex >= responses.length) {\n throw new Error(\n `MockProvider.sequence: no response for call index ${callIndex}. Only ${responses.length} responses defined.`,\n );\n }\n const resp = responses[callIndex];\n return {\n content: resp.content,\n tool_calls: resp.tool_calls,\n providerMetadata: resp.providerMetadata,\n usage: resp.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: resp.cost ?? 0,\n // Copied, not shared: the caller keeps ownership of the fixture, so a\n // consumer that mutates the returned block cannot corrupt a later call's\n // expectation (same rule the message/options clones follow).\n ...(resp.timing ? { timing: { ...resp.timing } } : {}),\n };\n });\n provider.chunkSequence = responses.map((r) => r.chunks);\n return provider;\n }\n\n /**\n * Convenience: build a `sequence()` from plain content strings, splitting\n * each one into fixed-size chunks for the streaming path. Default\n * `chunkSize` is 4 chars (≈1 token).\n */\n static chunked(contents: string[], chunkSize = 4): MockProvider {\n const responses = contents.map((content) => {\n const chunks: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunks.push(content.slice(i, i + chunkSize));\n }\n return { content, chunks };\n });\n return MockProvider.sequence(responses);\n }\n\n static echo(): MockProvider {\n return new MockProvider((messages) => {\n const lastUser = [...messages].reverse().find((m) => m.role === 'user');\n return {\n content: lastUser ? inputText(lastUser.content) : '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: unknown): MockProvider {\n return new MockProvider(() => ({\n content: JSON.stringify(generateFromSchema(schema)),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n\n static replay(source: string | ProviderResponse[]): MockProvider {\n const data =\n typeof source === 'string'\n ? (JSON.parse(readFileSync(source, 'utf-8')) as ProviderResponse[])\n : source;\n return new MockProvider((_messages, callIndex) => {\n if (callIndex >= data.length) {\n throw new Error(`MockProvider.replay: no recorded response for call index ${callIndex}`);\n }\n return data[callIndex];\n });\n }\n\n static fn(\n handler: (\n messages: ChatMessage[],\n callIndex: number,\n ) =>\n | {\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }\n | Promise<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }>,\n ): MockProvider {\n return new MockProvider(async (messages, callIndex) => {\n const result = await handler(messages, callIndex);\n return {\n ...result,\n usage: result.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: result.cost ?? 0,\n };\n });\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: unknown) => unknown | Promise<unknown>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async execute(input: unknown): Promise<unknown> {\n this._calls.push({ input });\n return this.handler(input);\n }\n\n static create(name: string, handler: (input: unknown) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import type {\n TranscriptionCapabilities,\n TranscriptionProvider,\n TranscriptionProviderRequest,\n TranscriptionProviderResult,\n} from '@axlsdk/axl';\n\nfunction clone<T>(value: T): T {\n return structuredClone(value);\n}\n\nfunction cloneRequest(\n request: TranscriptionProviderRequest,\n includeSignal: boolean,\n): TranscriptionProviderRequest {\n const audio =\n request.audio.type === 'bytes'\n ? { ...request.audio, data: request.audio.data.slice() }\n : { ...request.audio };\n return {\n model: request.model,\n audio,\n ...(request.language !== undefined ? { language: request.language } : {}),\n ...(request.timestamps !== undefined ? { timestamps: request.timestamps } : {}),\n ...(request.diarization !== undefined ? { diarization: request.diarization } : {}),\n ...(request.providerOptions ? { providerOptions: clone(request.providerOptions) } : {}),\n ...(includeSignal && request.signal ? { signal: request.signal } : {}),\n };\n}\n\n/** Dedicated transcription mock. It intentionally does not extend MockProvider,\n * so chat fixtures cannot accidentally become transcription adapters. */\nexport class MockTranscriptionProvider implements TranscriptionProvider {\n private _calls: TranscriptionProviderRequest[] = [];\n\n constructor(\n private readonly response: (\n request: TranscriptionProviderRequest,\n callIndex: number,\n ) => TranscriptionProviderResult | Promise<TranscriptionProviderResult>,\n private readonly capabilitiesFor: (\n model: string,\n ) => TranscriptionCapabilities | undefined = () => ({\n sources: ['bytes', 'base64', 'provider-file'],\n timestamps: ['segment', 'word'],\n diarization: true,\n }),\n ) {}\n\n get calls(): readonly TranscriptionProviderRequest[] {\n return this._calls.map(clone);\n }\n\n capabilities(model: string): TranscriptionCapabilities | undefined {\n return this.capabilitiesFor(model);\n }\n\n async transcribe(request: TranscriptionProviderRequest): Promise<TranscriptionProviderResult> {\n // AbortSignal cannot be structured-cloned. Keep it only on the callback\n // request so fixtures can observe cancellation; recorded calls omit it.\n const snapshot = cloneRequest(request, false);\n this._calls.push(snapshot);\n return clone(await this.response(cloneRequest(request, true), this._calls.length - 1));\n }\n\n static text(text: string): MockTranscriptionProvider {\n return new MockTranscriptionProvider(() => ({ transcript: { text } }));\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport { MockTranscriptionProvider } from './mock-transcription-provider.js';\nimport type {\n AxlEvent,\n AwaitHumanOptions,\n HumanDecision,\n ProviderResponse,\n AgentCallInfo,\n AxlConfig,\n AnyWorkflow,\n ToolCallOutcome,\n ObservationStatus,\n} from '@axlsdk/axl';\nimport {\n WorkflowContext,\n MemoryStore,\n ProviderRegistry,\n TranscriptionProviderRegistry,\n eventCostContribution,\n isUnpricedLeaf,\n} from '@axlsdk/axl';\nimport type { EventStreamOptions, WorkflowContextInit } from '@axlsdk/axl';\n\n// `AnyWorkflow` is a re-exported alias for `Workflow<any, any>` — see\n// the JSDoc on `AnyWorkflow` in `@axlsdk/axl/workflow.ts`. The bivariant\n// `any` is load-bearing for satisfying narrowly-typed handlers (e.g., a\n// `Workflow<TInput=MsgType>` whose handler takes `WorkflowContext<MsgType>`).\n\n/** One accepted provider-issued tool invocation, recorded from its terminal v2 event.\n *\n * Narrow `outcome.status` before reading status-specific fields. Correlation uses\n * `(executionId, askId, callId)`; `name` is the canonical tool name.\n */\nexport type RecordedToolCall = {\n name: string;\n executionId: string;\n askId: string;\n callId: string;\n args: unknown;\n requestedTool?: string;\n outcome: ToolCallOutcome;\n};\nexport type RecordedAgentCall = Partial<AgentCallInfo> &\n Pick<AgentCallInfo, 'agent' | 'prompt' | 'response'>;\nexport type RecordedStep = { step: number; type: string; data: unknown };\n\nfunction generateExecutionId(): string {\n return `test-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction preserveDrainCause(error: Error, cause: unknown): Error {\n if (cause === undefined || cause === error || 'cause' in error) return error;\n Object.defineProperty(error, 'cause', {\n configurable: true,\n enumerable: false,\n value: cause,\n });\n return error;\n}\n\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n /** AxlConfig for the test runtime. Controls trace level/redact, context management, etc.\n * Defaults to `{}`. Set `{ trace: { level: 'full' } }` to verify verbose-mode snapshots\n * in tests, or `{ trace: { redact: true } }` to verify redaction policy in tests. */\n config?: AxlConfig;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, AnyWorkflow>();\n private mockProviders = new Map<string, MockProvider>();\n private mockTranscriptionProviders = new Map<string, MockTranscriptionProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: AxlEvent[] = [];\n private _totalCost = 0;\n private _unpriced = false;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n private _config: AxlConfig;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n this._config = options?.config ?? {};\n }\n\n register(workflow: AnyWorkflow): void {\n this.workflows.set(workflow.name, workflow);\n }\n\n mockProvider(name: string, provider: MockProvider): void {\n this.mockProviders.set(name, provider);\n }\n\n mockTranscriptionProvider(name: string, provider: MockTranscriptionProvider): void {\n this.mockTranscriptionProviders.set(name, provider);\n }\n\n mockTool<TInput = unknown>(\n name: string,\n handler: (input: TInput) => unknown | Promise<unknown>,\n ): void {\n // The MockTool registry is type-erased (`(input: unknown) => unknown`)\n // because the runtime can't statically know each tool's input shape; tests\n // opt in to a typed input via the generic, and we cast on storage.\n this.mockToolMap.set(name, MockTool.create(name, handler as (input: unknown) => unknown));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: {\n metadata?: Record<string, unknown>;\n events?: EventStreamOptions;\n branchDrainTimeoutMs?: number;\n },\n ): Promise<unknown> {\n const workflow = this.workflows.get(workflowName);\n if (!workflow) throw new Error(`Workflow \"${workflowName}\" not registered`);\n\n // Reset state between executions\n this._toolCalls = [];\n this._agentCalls = [];\n this._steps = [];\n this._traceLog = [];\n this._totalCost = 0;\n this._unpriced = false;\n this._stepCounter = 0;\n this.recorded = [];\n this._executionId = generateExecutionId();\n\n const validated = workflow.inputSchema.parse(input);\n\n // Build ProviderRegistry from registered mock providers\n const registry = new ProviderRegistry();\n registry.clearFactories(); // Remove built-in factories; only use explicit mocks\n for (const [name, provider] of this.mockProviders) {\n registry.registerInstance(name, provider);\n }\n const transcriptionRegistry = new TranscriptionProviderRegistry();\n for (const [name, provider] of this.mockTranscriptionProviders) {\n transcriptionRegistry.registerInstance(name, provider);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider);\n }\n\n // Build toolOverrides from mockToolMap\n const toolOverrides = new Map<string, (args: unknown) => Promise<unknown>>();\n for (const [name, mockTool] of this.mockToolMap) {\n toolOverrides.set(name, async (args: unknown) => {\n return mockTool.execute(args);\n });\n }\n\n // Previously `_recordStep('workflow_start', ...)` was called here with\n // raw `{ workflow, input }` data, AND `ctx._emitWorkflowStart` below\n // pushed through the onTrace handler (which also bumps `_stepCounter`\n // and appends to `_steps`). Result: two entries in `steps()` per\n // workflow_start, with the first bypassing `config.trace.redact`.\n // The `_recordStep` call is removed — onTrace is the single source\n // of truth for `_steps`, matching the behavior of every other event\n // type in the test runtime. Reviewer architecture §5.\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n // Thread the constructor-provided config so tests can exercise\n // trace.level === 'full' and trace.redact behavior end-to-end.\n config: this._config,\n // Thread `events` config so tests can exercise the queue cap and\n // overflow policy on `ctx.events`. Mirrors the production runtime.\n eventStreamOptions: options?.events,\n branchDrainTimeoutMs: options?.branchDrainTimeoutMs,\n // Production runtime threads this (see `runtime.ts:594` in\n // `execute()` and `:765` in `stream()`). `emitEvent` auto-stamps\n // `event.workflow` from it, so consumers grouping by workflow\n // (Cost Dashboard `byWorkflow`, `trackExecution.metadata.workflows`,\n // any eval runner) see the same attribution in tests and prod.\n workflowName,\n providerRegistry: registry,\n transcriptionProviderRegistry: transcriptionRegistry,\n stateStore: new MemoryStore(),\n toolOverrides: toolOverrides.size > 0 ? toolOverrides : undefined,\n awaitHumanHandler: this._humanDecisionHandler\n ? (opts: AwaitHumanOptions) => this._humanDecisionHandler!(opts)\n : undefined,\n onTrace: (event: AxlEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({\n step: this._stepCounter,\n type: event.type,\n data: (event as { data?: unknown }).data,\n });\n\n if (event.type === 'tool_call_end') {\n const { args, requestedTool, outcome } = event.data;\n this._toolCalls.push({\n name: event.tool,\n executionId: event.executionId,\n askId: event.askId,\n callId: event.callId,\n args,\n ...(requestedTool !== undefined ? { requestedTool } : {}),\n outcome,\n });\n }\n\n // Single-source-of-truth cost accumulator. Skips ask_end\n // rollups (decision 10) and guards NaN/Infinity.\n this._totalCost += eventCostContribution(event);\n // Honest aggregate: one unpriced leaf makes `totalCost()` a lower bound.\n if (isUnpricedLeaf(event)) this._unpriced = true;\n\n // Track provider responses for recording\n if (event.type === 'agent_call_end' && event.data) {\n const { response } = event.data as { prompt?: string; response?: string };\n if (response !== undefined) {\n this.recorded.push({\n content: response,\n usage: event.tokens\n ? {\n prompt_tokens: event.tokens.input ?? 0,\n completion_tokens: event.tokens.output ?? 0,\n total_tokens:\n (event.tokens.input ?? 0) +\n (event.tokens.output ?? 0) +\n (event.tokens.reasoning ?? 0),\n ...(event.tokens.reasoning !== undefined\n ? { reasoning_tokens: event.tokens.reasoning }\n : {}),\n }\n : { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n ...(event.cost !== undefined ? { cost: event.cost } : {}),\n });\n }\n }\n },\n onAgentCallComplete: (call: AgentCallInfo) => {\n this._agentCalls.push(call);\n },\n };\n\n const ctx = new WorkflowContext(init);\n\n // Emit workflow_start through the same pipeline production uses,\n // AFTER ctx exists so `emitEvent`'s redact/step/timestamp handling\n // applies. Previously emitted via `_pushTrace` which bypassed\n // redaction — `config: { trace: { redact: true } }` on the test\n // runtime would scrub intermediate events but leak `input`/`result`\n // through the synthesized workflow_start/end.\n const startedAt = Date.now();\n ctx._emitWorkflowStart(validated);\n try {\n const result = await workflow.handler(ctx);\n const observation = await ctx._drainBranchWork();\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n ctx._emitWorkflowEnd({\n status: 'completed',\n duration: Date.now() - startedAt,\n result,\n observation,\n });\n // `_steps` is populated by onTrace for every event (including\n // workflow_end); no separate `_recordStep` call needed — that\n // would double-count.\n\n if (this.recordPath) await this._writeRecording();\n return result;\n } catch (err) {\n let workflowError = err;\n let observation: ObservationStatus = { complete: true };\n try {\n observation = await ctx._drainBranchWork();\n } catch (drainError) {\n workflowError =\n drainError instanceof Error ? preserveDrainCause(drainError, workflowError) : drainError;\n }\n // Parity with production: failed workflows get a terminal\n // `workflow_end(status: 'failed')` event so consumers counting\n // workflow_start ↔ workflow_end pairs never see an unclosed one.\n // `aborted` flag mirrors the runtime.ts AbortError detection.\n const aborted =\n typeof workflowError === 'object' &&\n workflowError !== null &&\n (workflowError as { name?: unknown }).name === 'AbortError';\n ctx._emitWorkflowEnd({\n status: 'failed',\n duration: Date.now() - startedAt,\n error: workflowError instanceof Error ? workflowError.message : String(workflowError),\n ...(aborted ? { aborted: true } : {}),\n observation,\n });\n // `_steps` populated by onTrace (see comment on the success path).\n throw workflowError;\n }\n }\n\n toolCalls(name?: string): RecordedToolCall[] {\n return name ? this._toolCalls.filter((c) => c.name === name) : this._toolCalls;\n }\n\n agentCalls(name?: string): RecordedAgentCall[] {\n return name ? this._agentCalls.filter((c) => c.agent === name) : this._agentCalls;\n }\n\n totalCost(): number {\n return this._totalCost;\n }\n /** True when any cost-bearing call was unpriced — `totalCost()` is then a\n * LOWER BOUND. Mirrors `ExecutionInfo.unpriced` / `BudgetResult.unpriced`. */\n unpriced(): boolean {\n return this._unpriced;\n }\n steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): AxlEvent[] {\n return this._traceLog;\n }\n\n private async _writeRecording(): Promise<void> {\n if (!this.recordPath) return;\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(this.recordPath), { recursive: true });\n await writeFile(this.recordPath, JSON.stringify(this.recorded, null, 2), 'utf8');\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/mock-provider.ts","../src/mock-tool.ts","../src/mock-transcription-provider.ts","../src/test-runtime.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { z } from 'zod';\nimport type {\n CallTiming,\n ChatMessage,\n ChatOptions,\n InputContentPart,\n InputMediaSource,\n ModelInput,\n ToolCallMessage,\n ProviderResponse,\n StreamChunk,\n Provider,\n ProviderInputValidationRequest,\n ProviderInputValidationResult,\n EffortResolution,\n} from '@axlsdk/axl';\nimport { inputText, UnsupportedModelInputError } from '@axlsdk/axl';\n\nfunction cloneValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return value.slice();\n if (Array.isArray(value)) return value.map(cloneValue);\n if (value && typeof value === 'object') {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneValue(item)]));\n }\n return value;\n}\n\nfunction cloneModelInput(input: ModelInput): ModelInput {\n if (typeof input === 'string') return input;\n return input.map((part): InputContentPart => {\n if (part.type === 'text') return { type: 'text', text: part.text };\n const { source } = part;\n switch (source.type) {\n case 'bytes':\n return {\n type: 'image',\n source: { type: 'bytes', data: source.data.slice(), mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'url':\n return {\n type: 'image',\n source: {\n type: 'url',\n url: source.url,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'base64':\n return {\n type: 'image',\n source: { type: 'base64', data: source.data, mediaType: source.mediaType },\n ...(part.label ? { label: part.label } : {}),\n };\n case 'provider-file':\n return {\n type: 'image',\n source: {\n type: 'provider-file',\n provider: source.provider,\n reference: source.reference,\n ...(source.mediaType ? { mediaType: source.mediaType } : {}),\n },\n ...(part.label ? { label: part.label } : {}),\n };\n }\n });\n}\n\nfunction cloneMessages(messages: readonly ChatMessage[]): ChatMessage[] {\n return messages.map((message) => ({\n ...message,\n content: cloneModelInput(message.content),\n ...(message.tool_calls\n ? {\n tool_calls: message.tool_calls.map((toolCall) => ({\n ...toolCall,\n function: { ...toolCall.function },\n })),\n }\n : {}),\n ...(message.providerMetadata\n ? { providerMetadata: cloneValue(message.providerMetadata) as Record<string, unknown> }\n : {}),\n }));\n}\n\nfunction cloneOptions(options: ChatOptions): ChatOptions {\n return {\n ...options,\n ...(options.tools\n ? {\n tools: options.tools.map((tool) => ({\n ...tool,\n function: { ...tool.function, parameters: cloneValue(tool.function.parameters) },\n })),\n }\n : {}),\n ...(options.providerOptions\n ? { providerOptions: cloneValue(options.providerOptions) as Record<string, unknown> }\n : {}),\n };\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw signal.reason;\n}\n\nasync function awaitWithSignal<T>(\n value: PromiseLike<T> | T,\n signal: AbortSignal | undefined,\n): Promise<T> {\n if (!signal) return await value;\n throwIfAborted(signal);\n\n return await new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason);\n signal.addEventListener('abort', onAbort, { once: true });\n Promise.resolve(value).then(\n (result) => {\n signal.removeEventListener('abort', onAbort);\n resolve(result);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\nasync function abortableDelay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n if (ms <= 0) {\n throwIfAborted(signal);\n return;\n }\n if (!signal) {\n await new Promise<void>((resolve) => setTimeout(resolve, ms));\n return;\n }\n throwIfAborted(signal);\n\n await new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined = setTimeout(() => {\n timer = undefined;\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n signal.removeEventListener('abort', onAbort);\n reject(signal.reason);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction richParts(input: ModelInput): readonly InputContentPart[] {\n return typeof input === 'string' ? [] : input;\n}\n\nfunction randomAlphanumeric(length: number): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n let result = '';\n for (let i = 0; i < length; i++) {\n result += chars[Math.floor(Math.random() * chars.length)];\n }\n return result;\n}\n\nfunction generateFromSchema(schema: unknown): unknown {\n if (schema instanceof z.ZodString) return randomAlphanumeric(8 + Math.floor(Math.random() * 13));\n if (schema instanceof z.ZodNumber) {\n const min = Number.isFinite(schema.minValue) ? schema.minValue! : 0;\n const max = Number.isFinite(schema.maxValue) ? schema.maxValue! : 100;\n return min + Math.random() * (max - min);\n }\n if (schema instanceof z.ZodBoolean) return Math.random() < 0.5;\n if (schema instanceof z.ZodArray) {\n const count = 1 + Math.floor(Math.random() * 3);\n return Array.from({ length: count }, () => generateFromSchema(schema.element));\n }\n if (schema instanceof z.ZodObject) {\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(schema.shape)) obj[key] = generateFromSchema(value);\n return obj;\n }\n if (schema instanceof z.ZodOptional) {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(schema.unwrap());\n }\n if (schema instanceof z.ZodDefault) return schema.parse(undefined);\n if (schema instanceof z.ZodEnum) {\n const values = schema.options;\n return values.length > 0 ? values[Math.floor(Math.random() * values.length)] : '';\n }\n if (schema instanceof z.ZodLiteral) return [...schema.values][0];\n if (schema instanceof z.ZodNullable) return null;\n if (schema instanceof z.ZodUnion) {\n const options = schema.options;\n return generateFromSchema(options[Math.floor(Math.random() * options.length)]);\n }\n return {};\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: ChatOptions }[] = [];\n /** Per-call optional chunk arrays, set by `sequence()` / `chunked()` so\n * `stream()` can yield one `text_delta` per chunk. Per-call indexed\n * alongside the response sequence. */\n private chunkSequence?: Array<string[] | undefined>;\n /** Optional ms delay between successive chunks during `stream()`. Useful\n * for dev fixtures that need to demonstrate streaming UX visually\n * (without a delay, mock chunks fire synchronously and complete in\n * microseconds — invisible to a human watching). Default 0 keeps\n * every existing test fast.\n *\n * Set via `provider.chunkDelayMs = 50` after construction. Not part of\n * any factory's surface to keep the test API minimal. */\n chunkDelayMs = 0;\n\n /** How this mock reports the unified `effort` it was asked for. Undefined (the\n * default) means the mock implements no `effortResolution` at all, so the\n * runtime emits no `provider_diagnostic`. Set it with\n * {@link MockProvider.withEffortResolution} to drive the clamp-reporting path. */\n effortResolution?: (\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined;\n\n /**\n * Make this mock report an effort clamp, so a test can exercise the runtime's\n * `provider_diagnostic` path without a real adapter. Pass a fixed\n * {@link EffortResolution} or a function of the request knobs.\n *\n * ```ts\n * const provider = MockProvider.echo().withEffortResolution({\n * requested: 'none',\n * effective: 'minimal',\n * clamped: true,\n * cause: 'this model cannot disable thinking',\n * });\n * ```\n */\n withEffortResolution(\n resolution:\n | EffortResolution\n | undefined\n | ((\n options: Pick<\n ChatOptions,\n 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'\n >,\n ) => EffortResolution | undefined),\n ): this {\n this.effortResolution = typeof resolution === 'function' ? resolution : () => resolution;\n return this;\n }\n\n private constructor(\n private responseFn: (\n messages: ChatMessage[],\n callIndex: number,\n ) => ProviderResponse | Promise<ProviderResponse>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: ChatOptions): Promise<ProviderResponse> {\n // Each consumer gets independent ownership: a handler can inspect or mutate\n // its copy without changing the durable assertion record (including bytes).\n const recordedMessages = cloneMessages(messages);\n const callIndex = this._calls.length;\n this._calls.push({ messages: recordedMessages, options: cloneOptions(options) });\n throwIfAborted(options.signal);\n const response = Promise.resolve().then(() =>\n this.responseFn(cloneMessages(messages), callIndex),\n );\n return await awaitWithSignal(response, options.signal);\n }\n\n inputCapabilities(_model: string): { image: { sources: readonly InputMediaSource['type'][] } } {\n return { image: { sources: ['url', 'bytes', 'base64', 'provider-file'] } };\n }\n\n validateInput(request: ProviderInputValidationRequest): ProviderInputValidationResult {\n const effectiveModel =\n typeof request.providerOptions?.model === 'string'\n ? request.providerOptions.model\n : request.model;\n const fail = (source?: string, feature?: string): never => {\n throw new UnsupportedModelInputError({\n provider: this.name,\n model: effectiveModel || request.model,\n modality: 'image',\n ...(source ? { source } : {}),\n ...(feature ? { feature } : {}),\n });\n };\n\n if (request.providerOptions && 'input' in request.providerOptions) {\n fail(undefined, 'raw input-container providerOptions');\n }\n for (const message of request.history) {\n if (typeof message.content === 'string') continue;\n if (message.role !== 'user') fail(undefined, 'rich non-user history');\n for (const part of richParts(message.content)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n }\n for (const part of richParts(request.input)) {\n if (\n part.type === 'image' &&\n part.source.type === 'provider-file' &&\n part.source.provider !== this.name\n ) {\n fail('provider-file');\n }\n }\n return { effectiveModel };\n }\n\n async *stream(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamChunk> {\n const callIndex = this._calls.length;\n const response = await this.chat(messages, options);\n throwIfAborted(options.signal);\n const chunks = this.chunkSequence?.[callIndex];\n if (chunks && chunks.length > 0) {\n // Sanity guard — if a caller passes chunks AND content, they MUST\n // match. Otherwise tests pass while the real prod content silently\n // diverges from what the streaming path observes.\n const joined = chunks.join('');\n if (joined !== response.content) {\n throw new Error(\n `MockProvider.stream: chunks.join('') !== content. ` +\n `chunks=\"${joined}\" content=\"${response.content}\"`,\n );\n }\n for (let i = 0; i < chunks.length; i++) {\n throwIfAborted(options.signal);\n yield { type: 'text_delta', content: chunks[i] };\n if (this.chunkDelayMs > 0 && i < chunks.length - 1) {\n await abortableDelay(this.chunkDelayMs, options.signal);\n }\n }\n } else if (response.content) {\n throwIfAborted(options.signal);\n yield { type: 'text_delta', content: response.content };\n }\n if (response.tool_calls) {\n for (const tc of response.tool_calls) {\n throwIfAborted(options.signal);\n yield {\n type: 'tool_call_delta',\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n };\n }\n }\n throwIfAborted(options.signal);\n yield {\n type: 'done',\n usage: response.usage,\n // Forwarded like `chat()` does. Without it a streamed mock ask reported no\n // cost at all, so `ctx.budget` and every cost assertion silently saw zero\n // on the streaming path while the same fixture priced correctly on the\n // non-streaming one — a mock that disagrees with itself between paths.\n cost: response.cost,\n providerMetadata: response.providerMetadata,\n // Conditional spread, not `timing: response.timing` — a mock response with\n // no timing must produce a `done` chunk with NO `timing` key at all, so a\n // consumer's `'timing' in chunk` check reads the same as a real adapter's.\n ...(response.timing ? { timing: response.timing } : {}),\n };\n }\n\n static sequence(\n responses: Array<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Deterministic provider-call timing, surfaced on `ProviderResponse.timing`\n * and on the streamed terminal `done` chunk. Lets a test drive\n * `agent_call_end.timing`, the `TimeoutError` breakdown, and the eval\n * per-model rollup without real clocks or a real transport. Omit it and\n * the mock behaves exactly like an uninstrumented custom provider. */\n timing?: CallTiming;\n /** When set, `stream()` yields one `text_delta` per entry instead\n * of one big delta with the full content. Use to exercise\n * partial-JSON parsing, structural-boundary throttling, and\n * cross-attempt token retention in tests. Must satisfy\n * `chunks.join('') === content`. */\n chunks?: string[];\n }>,\n ): MockProvider {\n const provider = new MockProvider((_messages, callIndex) => {\n if (callIndex >= responses.length) {\n throw new Error(\n `MockProvider.sequence: no response for call index ${callIndex}. Only ${responses.length} responses defined.`,\n );\n }\n const resp = responses[callIndex];\n return {\n content: resp.content,\n tool_calls: resp.tool_calls,\n providerMetadata: resp.providerMetadata,\n usage: resp.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: resp.cost ?? 0,\n // Copied, not shared: the caller keeps ownership of the fixture, so a\n // consumer that mutates the returned block cannot corrupt a later call's\n // expectation (same rule the message/options clones follow).\n ...(resp.timing ? { timing: { ...resp.timing } } : {}),\n };\n });\n provider.chunkSequence = responses.map((r) => r.chunks);\n return provider;\n }\n\n /**\n * Convenience: build a `sequence()` from plain content strings, splitting\n * each one into fixed-size chunks for the streaming path. Default\n * `chunkSize` is 4 chars (≈1 token).\n */\n static chunked(contents: string[], chunkSize = 4): MockProvider {\n const responses = contents.map((content) => {\n const chunks: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunks.push(content.slice(i, i + chunkSize));\n }\n return { content, chunks };\n });\n return MockProvider.sequence(responses);\n }\n\n static echo(): MockProvider {\n return new MockProvider((messages) => {\n const lastUser = [...messages].reverse().find((m) => m.role === 'user');\n return {\n content: lastUser ? inputText(lastUser.content) : '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: unknown): MockProvider {\n return new MockProvider(() => ({\n content: JSON.stringify(generateFromSchema(schema)),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n\n static replay(source: string | ProviderResponse[]): MockProvider {\n const data =\n typeof source === 'string'\n ? (JSON.parse(readFileSync(source, 'utf-8')) as ProviderResponse[])\n : source;\n return new MockProvider((_messages, callIndex) => {\n if (callIndex >= data.length) {\n throw new Error(`MockProvider.replay: no recorded response for call index ${callIndex}`);\n }\n return data[callIndex];\n });\n }\n\n static fn(\n handler: (\n messages: ChatMessage[],\n callIndex: number,\n ) =>\n | {\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }\n | Promise<{\n content: string;\n tool_calls?: ToolCallMessage[];\n providerMetadata?: Record<string, unknown>;\n usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n cost?: number;\n /** Per-call timing — see the `timing` note on {@link MockProvider.sequence}. */\n timing?: CallTiming;\n }>,\n ): MockProvider {\n return new MockProvider(async (messages, callIndex) => {\n const result = await handler(messages, callIndex);\n return {\n ...result,\n usage: result.usage ?? { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: result.cost ?? 0,\n };\n });\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: unknown) => unknown | Promise<unknown>,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async execute(input: unknown): Promise<unknown> {\n this._calls.push({ input });\n return this.handler(input);\n }\n\n static create(name: string, handler: (input: unknown) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import type {\n TranscriptionCapabilities,\n TranscriptionProvider,\n TranscriptionProviderRequest,\n TranscriptionProviderResult,\n} from '@axlsdk/axl';\n\nfunction clone<T>(value: T): T {\n return structuredClone(value);\n}\n\nfunction cloneRequest(\n request: TranscriptionProviderRequest,\n includeSignal: boolean,\n): TranscriptionProviderRequest {\n const audio =\n request.audio.type === 'bytes'\n ? { ...request.audio, data: request.audio.data.slice() }\n : { ...request.audio };\n return {\n model: request.model,\n audio,\n ...(request.language !== undefined ? { language: request.language } : {}),\n ...(request.timestamps !== undefined ? { timestamps: request.timestamps } : {}),\n ...(request.diarization !== undefined ? { diarization: request.diarization } : {}),\n ...(request.providerOptions ? { providerOptions: clone(request.providerOptions) } : {}),\n ...(includeSignal && request.signal ? { signal: request.signal } : {}),\n };\n}\n\n/** Dedicated transcription mock. It intentionally does not extend MockProvider,\n * so chat fixtures cannot accidentally become transcription adapters. */\nexport class MockTranscriptionProvider implements TranscriptionProvider {\n private _calls: TranscriptionProviderRequest[] = [];\n\n constructor(\n private readonly response: (\n request: TranscriptionProviderRequest,\n callIndex: number,\n ) => TranscriptionProviderResult | Promise<TranscriptionProviderResult>,\n private readonly capabilitiesFor: (\n model: string,\n ) => TranscriptionCapabilities | undefined = () => ({\n sources: ['bytes', 'base64', 'provider-file'],\n timestamps: ['segment', 'word'],\n diarization: true,\n }),\n ) {}\n\n get calls(): readonly TranscriptionProviderRequest[] {\n return this._calls.map(clone);\n }\n\n capabilities(model: string): TranscriptionCapabilities | undefined {\n return this.capabilitiesFor(model);\n }\n\n async transcribe(request: TranscriptionProviderRequest): Promise<TranscriptionProviderResult> {\n // AbortSignal cannot be structured-cloned. Keep it only on the callback\n // request so fixtures can observe cancellation; recorded calls omit it.\n const snapshot = cloneRequest(request, false);\n this._calls.push(snapshot);\n return clone(await this.response(cloneRequest(request, true), this._calls.length - 1));\n }\n\n static text(text: string): MockTranscriptionProvider {\n return new MockTranscriptionProvider(() => ({ transcript: { text } }));\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport { MockTranscriptionProvider } from './mock-transcription-provider.js';\nimport type {\n AxlEvent,\n AwaitHumanOptions,\n HumanDecision,\n ProviderResponse,\n AgentCallInfo,\n AxlConfig,\n AnyWorkflow,\n ToolCallOutcome,\n ObservationStatus,\n} from '@axlsdk/axl';\nimport {\n WorkflowContext,\n MemoryStore,\n ProviderRegistry,\n TranscriptionProviderRegistry,\n eventCostContribution,\n isUnpricedLeaf,\n} from '@axlsdk/axl';\nimport type { EventStreamOptions, WorkflowContextInit } from '@axlsdk/axl';\n\n// `AnyWorkflow` is a re-exported alias for `Workflow<any, any>` — see\n// the JSDoc on `AnyWorkflow` in `@axlsdk/axl/workflow.ts`. The bivariant\n// `any` is load-bearing for satisfying narrowly-typed handlers (e.g., a\n// `Workflow<TInput=MsgType>` whose handler takes `WorkflowContext<MsgType>`).\n\n/** One accepted provider-issued tool invocation, recorded from its terminal v2 event.\n *\n * Narrow `outcome.status` before reading status-specific fields. Correlation uses\n * `(executionId, askId, callId)`; `name` is the canonical tool name.\n */\nexport type RecordedToolCall = {\n name: string;\n executionId: string;\n askId: string;\n callId: string;\n args: unknown;\n requestedTool?: string;\n outcome: ToolCallOutcome;\n};\nexport type RecordedAgentCall = Partial<AgentCallInfo> &\n Pick<AgentCallInfo, 'agent' | 'prompt' | 'response'>;\nexport type RecordedStep = { step: number; type: string; data: unknown };\n\nfunction generateExecutionId(): string {\n return `test-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction preserveDrainCause(error: Error, cause: unknown): Error {\n if (cause === undefined || cause === error || 'cause' in error) return error;\n Object.defineProperty(error, 'cause', {\n configurable: true,\n enumerable: false,\n value: cause,\n });\n return error;\n}\n\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n /** AxlConfig for the test runtime. Controls trace level/redact, context management, etc.\n * Defaults to `{}`. Set `{ trace: { level: 'full' } }` to verify verbose-mode snapshots\n * in tests, or `{ trace: { redact: true } }` to verify redaction policy in tests. */\n config?: AxlConfig;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, AnyWorkflow>();\n private mockProviders = new Map<string, MockProvider>();\n private mockTranscriptionProviders = new Map<string, MockTranscriptionProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: AxlEvent[] = [];\n private _totalCost = 0;\n private _unpriced = false;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n private _config: AxlConfig;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n this._config = options?.config ?? {};\n }\n\n register(workflow: AnyWorkflow): void {\n this.workflows.set(workflow.name, workflow);\n }\n\n mockProvider(name: string, provider: MockProvider): void {\n this.mockProviders.set(name, provider);\n }\n\n mockTranscriptionProvider(name: string, provider: MockTranscriptionProvider): void {\n this.mockTranscriptionProviders.set(name, provider);\n }\n\n mockTool<TInput = unknown>(\n name: string,\n handler: (input: TInput) => unknown | Promise<unknown>,\n ): void {\n // The MockTool registry is type-erased (`(input: unknown) => unknown`)\n // because the runtime can't statically know each tool's input shape; tests\n // opt in to a typed input via the generic, and we cast on storage.\n this.mockToolMap.set(name, MockTool.create(name, handler as (input: unknown) => unknown));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: {\n metadata?: Record<string, unknown>;\n events?: EventStreamOptions;\n branchDrainTimeoutMs?: number;\n },\n ): Promise<unknown> {\n const workflow = this.workflows.get(workflowName);\n if (!workflow) throw new Error(`Workflow \"${workflowName}\" not registered`);\n\n // Reset state between executions\n this._toolCalls = [];\n this._agentCalls = [];\n this._steps = [];\n this._traceLog = [];\n this._totalCost = 0;\n this._unpriced = false;\n this._stepCounter = 0;\n this.recorded = [];\n this._executionId = generateExecutionId();\n\n const validated = workflow.inputSchema.parse(input);\n\n // Build ProviderRegistry from registered mock providers\n const registry = new ProviderRegistry();\n registry.clearFactories(); // Remove built-in factories; only use explicit mocks\n for (const [name, provider] of this.mockProviders) {\n registry.registerInstance(name, provider);\n }\n const transcriptionRegistry = new TranscriptionProviderRegistry();\n for (const [name, provider] of this.mockTranscriptionProviders) {\n transcriptionRegistry.registerInstance(name, provider);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider);\n }\n\n // Build toolOverrides from mockToolMap\n const toolOverrides = new Map<string, (args: unknown) => Promise<unknown>>();\n for (const [name, mockTool] of this.mockToolMap) {\n toolOverrides.set(name, async (args: unknown) => {\n return mockTool.execute(args);\n });\n }\n\n // Previously `_recordStep('workflow_start', ...)` was called here with\n // raw `{ workflow, input }` data, AND `ctx._emitWorkflowStart` below\n // pushed through the onTrace handler (which also bumps `_stepCounter`\n // and appends to `_steps`). Result: two entries in `steps()` per\n // workflow_start, with the first bypassing `config.trace.redact`.\n // The `_recordStep` call is removed — onTrace is the single source\n // of truth for `_steps`, matching the behavior of every other event\n // type in the test runtime. Reviewer architecture §5.\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n // Thread the constructor-provided config so tests can exercise\n // trace.level === 'full' and trace.redact behavior end-to-end.\n config: this._config,\n // Thread `events` config so tests can exercise the queue cap and\n // overflow policy on `ctx.events`. Mirrors the production runtime.\n eventStreamOptions: options?.events,\n branchDrainTimeoutMs: options?.branchDrainTimeoutMs,\n // Production runtime threads this (see `runtime.ts:594` in\n // `execute()` and `:765` in `stream()`). `emitEvent` auto-stamps\n // `event.workflow` from it, so consumers grouping by workflow\n // (Cost Dashboard `byWorkflow`, `trackExecution.metadata.workflows`,\n // any eval runner) see the same attribution in tests and prod.\n workflowName,\n providerRegistry: registry,\n transcriptionProviderRegistry: transcriptionRegistry,\n stateStore: new MemoryStore(),\n toolOverrides: toolOverrides.size > 0 ? toolOverrides : undefined,\n awaitHumanHandler: this._humanDecisionHandler\n ? (opts: AwaitHumanOptions) => this._humanDecisionHandler!(opts)\n : undefined,\n onTrace: (event: AxlEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({\n step: this._stepCounter,\n type: event.type,\n data: (event as { data?: unknown }).data,\n });\n\n if (event.type === 'tool_call_end') {\n const { args, requestedTool, outcome } = event.data;\n this._toolCalls.push({\n name: event.tool,\n executionId: event.executionId,\n askId: event.askId,\n callId: event.callId,\n args,\n ...(requestedTool !== undefined ? { requestedTool } : {}),\n outcome,\n });\n }\n\n // Single-source-of-truth cost accumulator. Skips ask_end\n // rollups (decision 10) and guards NaN/Infinity.\n this._totalCost += eventCostContribution(event);\n // Honest aggregate: one unpriced leaf makes `totalCost()` a lower bound.\n if (isUnpricedLeaf(event)) this._unpriced = true;\n\n // Track provider responses for recording\n if (event.type === 'agent_call_end' && event.data) {\n const { response } = event.data as { prompt?: string; response?: string };\n if (response !== undefined) {\n this.recorded.push({\n content: response,\n usage: event.tokens\n ? {\n prompt_tokens: event.tokens.input ?? 0,\n completion_tokens: event.tokens.output ?? 0,\n total_tokens:\n (event.tokens.input ?? 0) +\n (event.tokens.output ?? 0) +\n (event.tokens.reasoning ?? 0),\n ...(event.tokens.reasoning !== undefined\n ? { reasoning_tokens: event.tokens.reasoning }\n : {}),\n }\n : { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n ...(event.cost !== undefined ? { cost: event.cost } : {}),\n });\n }\n }\n },\n onAgentCallComplete: (call: AgentCallInfo) => {\n this._agentCalls.push(call);\n },\n };\n\n const ctx = new WorkflowContext(init);\n\n // Emit workflow_start through the same pipeline production uses,\n // AFTER ctx exists so `emitEvent`'s redact/step/timestamp handling\n // applies. Previously emitted via `_pushTrace` which bypassed\n // redaction — `config: { trace: { redact: true } }` on the test\n // runtime would scrub intermediate events but leak `input`/`result`\n // through the synthesized workflow_start/end.\n const startedAt = Date.now();\n ctx._emitWorkflowStart(validated);\n try {\n const result = await workflow.handler(ctx);\n const observation = await ctx._drainBranchWork();\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n ctx._emitWorkflowEnd({\n status: 'completed',\n duration: Date.now() - startedAt,\n result,\n observation,\n });\n // `_steps` is populated by onTrace for every event (including\n // workflow_end); no separate `_recordStep` call needed — that\n // would double-count.\n\n if (this.recordPath) await this._writeRecording();\n return result;\n } catch (err) {\n let workflowError = err;\n let observation: ObservationStatus = { complete: true };\n try {\n observation = await ctx._drainBranchWork();\n } catch (drainError) {\n workflowError =\n drainError instanceof Error ? preserveDrainCause(drainError, workflowError) : drainError;\n }\n // Parity with production: failed workflows get a terminal\n // `workflow_end(status: 'failed')` event so consumers counting\n // workflow_start ↔ workflow_end pairs never see an unclosed one.\n // `aborted` flag mirrors the runtime.ts AbortError detection.\n const aborted =\n typeof workflowError === 'object' &&\n workflowError !== null &&\n (workflowError as { name?: unknown }).name === 'AbortError';\n ctx._emitWorkflowEnd({\n status: 'failed',\n duration: Date.now() - startedAt,\n error: workflowError instanceof Error ? workflowError.message : String(workflowError),\n ...(aborted ? { aborted: true } : {}),\n observation,\n });\n // `_steps` populated by onTrace (see comment on the success path).\n throw workflowError;\n }\n }\n\n toolCalls(name?: string): RecordedToolCall[] {\n return name ? this._toolCalls.filter((c) => c.name === name) : this._toolCalls;\n }\n\n agentCalls(name?: string): RecordedAgentCall[] {\n return name ? this._agentCalls.filter((c) => c.agent === name) : this._agentCalls;\n }\n\n totalCost(): number {\n return this._totalCost;\n }\n /** True when any cost-bearing call was unpriced — `totalCost()` is then a\n * LOWER BOUND. Mirrors `ExecutionInfo.unpriced` / `BudgetResult.unpriced`. */\n unpriced(): boolean {\n return this._unpriced;\n }\n steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): AxlEvent[] {\n return this._traceLog;\n }\n\n private async _writeRecording(): Promise<void> {\n if (!this.recordPath) return;\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(this.recordPath), { recursive: true });\n await writeFile(this.recordPath, JSON.stringify(this.recorded, null, 2), 'utf8');\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axlsdk/testing",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"description": "Testing utilities for Axl agentic workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@axlsdk/axl": "0.23.
|
|
25
|
+
"@axlsdk/axl": "0.23.1"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"zod": "^4.0.0"
|