@axlsdk/testing 0.1.0 → 0.1.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 CHANGED
@@ -5,7 +5,7 @@ Testing utilities for Axl agentic workflows. Provides deterministic mocks and as
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install axl-testing --save-dev
8
+ npm install @axlsdk/testing --save-dev
9
9
  ```
10
10
 
11
11
  ## API
@@ -15,7 +15,7 @@ npm install axl-testing --save-dev
15
15
  Mock LLM provider with multiple response modes:
16
16
 
17
17
  ```typescript
18
- import { MockProvider } from 'axl-testing';
18
+ import { MockProvider } from '@axlsdk/testing';
19
19
 
20
20
  // Sequence mode — return responses in order
21
21
  const provider = MockProvider.sequence(['Hello!', 'World!']);
@@ -57,7 +57,7 @@ const provider = MockProvider.sequence([
57
57
  Wrap a tool to intercept and record calls:
58
58
 
59
59
  ```typescript
60
- import { MockTool } from 'axl-testing';
60
+ import { MockTool } from '@axlsdk/testing';
61
61
  import { calculator } from './tools';
62
62
 
63
63
  const mock = new MockTool(calculator);
@@ -74,7 +74,7 @@ console.log(mock.calls); // [{ input: { expression: '2+2' }, output: { result: 4
74
74
  Test runtime that mirrors `WorkflowContext` for deterministic testing:
75
75
 
76
76
  ```typescript
77
- import { AxlTestRuntime, MockProvider } from 'axl-testing';
77
+ import { AxlTestRuntime, MockProvider } from '@axlsdk/testing';
78
78
 
79
79
  const provider = MockProvider.sequence(['42']);
80
80
  const runtime = new AxlTestRuntime({ provider });
@@ -119,7 +119,7 @@ runtime.traces(); // All trace events
119
119
 
120
120
  ```typescript
121
121
  import { describe, it, expect } from 'vitest';
122
- import { AxlTestRuntime, MockProvider } from 'axl-testing';
122
+ import { AxlTestRuntime, MockProvider } from '@axlsdk/testing';
123
123
  import { myAgent } from '../agents';
124
124
 
125
125
  describe('my workflow', () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/mock-provider.ts","../src/mock-tool.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 { MockTool } from './mock-tool.js';\n","import { readFileSync } from 'node:fs';\nimport type { ChatMessage, ToolCallMessage, ProviderResponse, StreamChunk, Provider } from '@axlsdk/axl';\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: any): unknown {\n const def = schema?._def;\n if (!def) return {};\n switch (def.typeName) {\n case 'ZodString': {\n const length = 8 + Math.floor(Math.random() * 13); // 8-20 chars\n return randomAlphanumeric(length);\n }\n case 'ZodNumber': {\n const checks: any[] = def.checks ?? [];\n let min = 0;\n let max = 100;\n for (const check of checks) {\n if (check.kind === 'min') min = check.value;\n if (check.kind === 'max') max = check.value;\n }\n return min + Math.random() * (max - min);\n }\n case 'ZodBoolean':\n return Math.random() < 0.5;\n case 'ZodArray': {\n const count = 1 + Math.floor(Math.random() * 3); // 1-3 items\n const items: unknown[] = [];\n for (let i = 0; i < count; i++) {\n items.push(generateFromSchema(def.type));\n }\n return items;\n }\n case 'ZodObject': {\n const shape = def.shape?.() ?? {};\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(shape)) {\n obj[key] = generateFromSchema(value);\n }\n return obj;\n }\n case 'ZodOptional': {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(def.innerType);\n }\n case 'ZodDefault':\n return def.defaultValue();\n case 'ZodEnum': {\n const values: unknown[] = def.values ?? [];\n if (values.length === 0) return '';\n return values[Math.floor(Math.random() * values.length)];\n }\n case 'ZodNullable':\n return null;\n default:\n return {};\n }\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: any }[] = [];\n\n private constructor(\n private responseFn: (messages: ChatMessage[], callIndex: number) => ProviderResponse,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: any): Promise<ProviderResponse> {\n this._calls.push({ messages, options });\n return this.responseFn(messages, this._calls.length - 1);\n }\n\n async *stream(messages: ChatMessage[], options: any): AsyncGenerator<StreamChunk> {\n const response = await this.chat(messages, options);\n yield { type: 'text_delta', content: response.content };\n yield { type: 'done', usage: response.usage };\n }\n\n static sequence(\n responses: Array<{ content: string; tool_calls?: ToolCallMessage[] }>,\n ): MockProvider {\n return 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 return {\n content: responses[callIndex].content,\n tool_calls: responses[callIndex].tool_calls,\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\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?.content ?? '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: any): 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 ) => { content: string; tool_calls?: ToolCallMessage[] },\n ): MockProvider {\n return new MockProvider((messages, callIndex) => ({\n ...handler(messages, callIndex),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: any) => 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: any) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport type { TraceEvent, AwaitHumanOptions, HumanDecision, ProviderResponse } from '@axlsdk/axl';\nimport { WorkflowContext, MemoryStore, ProviderRegistry } from '@axlsdk/axl';\nimport type { WorkflowContextInit } from '@axlsdk/axl';\n\ninterface WorkflowLike {\n readonly name: string;\n readonly inputSchema: any;\n readonly outputSchema: any | undefined;\n readonly handler: (ctx: any) => Promise<any>;\n}\n\nexport type RecordedToolCall = { name: string; args: unknown; result: unknown };\nexport type RecordedAgentCall = {\n agent: string;\n prompt: string;\n response: string;\n model?: string;\n cost?: number;\n duration?: number;\n promptVersion?: string;\n};\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\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, WorkflowLike>();\n private mockProviders = new Map<string, MockProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: TraceEvent[] = [];\n private _totalCost = 0;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n }\n\n register(workflow: WorkflowLike): 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 mockTool(name: string, handler: (input: any) => unknown | Promise<unknown>): void {\n this.mockToolMap.set(name, MockTool.create(name, handler));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: { metadata?: Record<string, unknown> },\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._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 as any);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider as any);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider as any);\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 // Record steps and traces via callbacks\n this._recordStep('workflow_start', { workflow: workflowName, input: validated });\n this._pushTrace({\n type: 'workflow_start',\n workflow: workflowName,\n data: { input: validated },\n });\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n config: {},\n providerRegistry: registry,\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: TraceEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type: event.type, data: event.data });\n\n if (event.type === 'tool_call' && event.data) {\n const { args, result } = event.data as { args: unknown; result: unknown };\n this._toolCalls.push({ name: event.tool!, args, result });\n }\n\n if (event.cost) {\n this._totalCost += event.cost;\n }\n\n // Track provider responses for recording\n if (event.type === 'agent_call' && 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: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n cost: event.cost ?? 0,\n });\n }\n }\n },\n onAgentCallComplete: (call) => {\n this._agentCalls.push({\n agent: call.agent,\n prompt: call.prompt,\n response: call.response,\n model: call.model,\n cost: call.cost,\n duration: call.duration,\n promptVersion: call.promptVersion,\n });\n },\n };\n\n const ctx = new WorkflowContext(init);\n const result = await workflow.handler(ctx);\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n this._recordStep('workflow_end', { workflow: workflowName, result });\n this._pushTrace({\n type: 'workflow_end',\n workflow: workflowName,\n data: { result },\n });\n\n if (this.recordPath) await this._writeRecording();\n return result;\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 steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): TraceEvent[] {\n return this._traceLog;\n }\n\n private _recordStep(type: string, data: unknown): void {\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type, data });\n }\n\n private _pushTrace(partial: Omit<TraceEvent, 'executionId' | 'step' | 'timestamp'>): void {\n this._traceLog.push({\n executionId: this._executionId,\n step: this._stepCounter,\n timestamp: Date.now(),\n ...partial,\n });\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":["result"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/mock-provider.ts","../src/mock-tool.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 { MockTool } from './mock-tool.js';\n","import { readFileSync } from 'node:fs';\nimport type {\n ChatMessage,\n ToolCallMessage,\n ProviderResponse,\n StreamChunk,\n Provider,\n} from '@axlsdk/axl';\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: any): unknown {\n const def = schema?._def;\n if (!def) return {};\n switch (def.typeName) {\n case 'ZodString': {\n const length = 8 + Math.floor(Math.random() * 13); // 8-20 chars\n return randomAlphanumeric(length);\n }\n case 'ZodNumber': {\n const checks: any[] = def.checks ?? [];\n let min = 0;\n let max = 100;\n for (const check of checks) {\n if (check.kind === 'min') min = check.value;\n if (check.kind === 'max') max = check.value;\n }\n return min + Math.random() * (max - min);\n }\n case 'ZodBoolean':\n return Math.random() < 0.5;\n case 'ZodArray': {\n const count = 1 + Math.floor(Math.random() * 3); // 1-3 items\n const items: unknown[] = [];\n for (let i = 0; i < count; i++) {\n items.push(generateFromSchema(def.type));\n }\n return items;\n }\n case 'ZodObject': {\n const shape = def.shape?.() ?? {};\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(shape)) {\n obj[key] = generateFromSchema(value);\n }\n return obj;\n }\n case 'ZodOptional': {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(def.innerType);\n }\n case 'ZodDefault':\n return def.defaultValue();\n case 'ZodEnum': {\n const values: unknown[] = def.values ?? [];\n if (values.length === 0) return '';\n return values[Math.floor(Math.random() * values.length)];\n }\n case 'ZodNullable':\n return null;\n default:\n return {};\n }\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: any }[] = [];\n\n private constructor(\n private responseFn: (messages: ChatMessage[], callIndex: number) => ProviderResponse,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: any): Promise<ProviderResponse> {\n this._calls.push({ messages, options });\n return this.responseFn(messages, this._calls.length - 1);\n }\n\n async *stream(messages: ChatMessage[], options: any): AsyncGenerator<StreamChunk> {\n const response = await this.chat(messages, options);\n yield { type: 'text_delta', content: response.content };\n yield { type: 'done', usage: response.usage };\n }\n\n static sequence(\n responses: Array<{ content: string; tool_calls?: ToolCallMessage[] }>,\n ): MockProvider {\n return 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 return {\n content: responses[callIndex].content,\n tool_calls: responses[callIndex].tool_calls,\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\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?.content ?? '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: any): 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 ) => { content: string; tool_calls?: ToolCallMessage[] },\n ): MockProvider {\n return new MockProvider((messages, callIndex) => ({\n ...handler(messages, callIndex),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: any) => 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: any) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport type { TraceEvent, AwaitHumanOptions, HumanDecision, ProviderResponse } from '@axlsdk/axl';\nimport { WorkflowContext, MemoryStore, ProviderRegistry } from '@axlsdk/axl';\nimport type { WorkflowContextInit } from '@axlsdk/axl';\n\ninterface WorkflowLike {\n readonly name: string;\n readonly inputSchema: any;\n readonly outputSchema: any | undefined;\n readonly handler: (ctx: any) => Promise<any>;\n}\n\nexport type RecordedToolCall = { name: string; args: unknown; result: unknown };\nexport type RecordedAgentCall = {\n agent: string;\n prompt: string;\n response: string;\n model?: string;\n cost?: number;\n duration?: number;\n promptVersion?: string;\n};\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\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, WorkflowLike>();\n private mockProviders = new Map<string, MockProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: TraceEvent[] = [];\n private _totalCost = 0;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n }\n\n register(workflow: WorkflowLike): 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 mockTool(name: string, handler: (input: any) => unknown | Promise<unknown>): void {\n this.mockToolMap.set(name, MockTool.create(name, handler));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: { metadata?: Record<string, unknown> },\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._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 as any);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider as any);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider as any);\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 // Record steps and traces via callbacks\n this._recordStep('workflow_start', { workflow: workflowName, input: validated });\n this._pushTrace({\n type: 'workflow_start',\n workflow: workflowName,\n data: { input: validated },\n });\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n config: {},\n providerRegistry: registry,\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: TraceEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type: event.type, data: event.data });\n\n if (event.type === 'tool_call' && event.data) {\n const { args, result } = event.data as { args: unknown; result: unknown };\n this._toolCalls.push({ name: event.tool!, args, result });\n }\n\n if (event.cost) {\n this._totalCost += event.cost;\n }\n\n // Track provider responses for recording\n if (event.type === 'agent_call' && 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: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n cost: event.cost ?? 0,\n });\n }\n }\n },\n onAgentCallComplete: (call) => {\n this._agentCalls.push({\n agent: call.agent,\n prompt: call.prompt,\n response: call.response,\n model: call.model,\n cost: call.cost,\n duration: call.duration,\n promptVersion: call.promptVersion,\n });\n },\n };\n\n const ctx = new WorkflowContext(init);\n const result = await workflow.handler(ctx);\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n this._recordStep('workflow_end', { workflow: workflowName, result });\n this._pushTrace({\n type: 'workflow_end',\n workflow: workflowName,\n data: { result },\n });\n\n if (this.recordPath) await this._writeRecording();\n return result;\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 steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): TraceEvent[] {\n return this._traceLog;\n }\n\n private _recordStep(type: string, data: unknown): void {\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type, data });\n }\n\n private _pushTrace(partial: Omit<TraceEvent, 'executionId' | 'step' | 'timestamp'>): void {\n this._traceLog.push({\n executionId: this._executionId,\n step: this._stepCounter,\n timestamp: Date.now(),\n ...partial,\n });\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":["result"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mock-provider.ts","../src/mock-tool.ts","../src/test-runtime.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport type { ChatMessage, ToolCallMessage, ProviderResponse, StreamChunk, Provider } from '@axlsdk/axl';\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: any): unknown {\n const def = schema?._def;\n if (!def) return {};\n switch (def.typeName) {\n case 'ZodString': {\n const length = 8 + Math.floor(Math.random() * 13); // 8-20 chars\n return randomAlphanumeric(length);\n }\n case 'ZodNumber': {\n const checks: any[] = def.checks ?? [];\n let min = 0;\n let max = 100;\n for (const check of checks) {\n if (check.kind === 'min') min = check.value;\n if (check.kind === 'max') max = check.value;\n }\n return min + Math.random() * (max - min);\n }\n case 'ZodBoolean':\n return Math.random() < 0.5;\n case 'ZodArray': {\n const count = 1 + Math.floor(Math.random() * 3); // 1-3 items\n const items: unknown[] = [];\n for (let i = 0; i < count; i++) {\n items.push(generateFromSchema(def.type));\n }\n return items;\n }\n case 'ZodObject': {\n const shape = def.shape?.() ?? {};\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(shape)) {\n obj[key] = generateFromSchema(value);\n }\n return obj;\n }\n case 'ZodOptional': {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(def.innerType);\n }\n case 'ZodDefault':\n return def.defaultValue();\n case 'ZodEnum': {\n const values: unknown[] = def.values ?? [];\n if (values.length === 0) return '';\n return values[Math.floor(Math.random() * values.length)];\n }\n case 'ZodNullable':\n return null;\n default:\n return {};\n }\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: any }[] = [];\n\n private constructor(\n private responseFn: (messages: ChatMessage[], callIndex: number) => ProviderResponse,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: any): Promise<ProviderResponse> {\n this._calls.push({ messages, options });\n return this.responseFn(messages, this._calls.length - 1);\n }\n\n async *stream(messages: ChatMessage[], options: any): AsyncGenerator<StreamChunk> {\n const response = await this.chat(messages, options);\n yield { type: 'text_delta', content: response.content };\n yield { type: 'done', usage: response.usage };\n }\n\n static sequence(\n responses: Array<{ content: string; tool_calls?: ToolCallMessage[] }>,\n ): MockProvider {\n return 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 return {\n content: responses[callIndex].content,\n tool_calls: responses[callIndex].tool_calls,\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\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?.content ?? '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: any): 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 ) => { content: string; tool_calls?: ToolCallMessage[] },\n ): MockProvider {\n return new MockProvider((messages, callIndex) => ({\n ...handler(messages, callIndex),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: any) => 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: any) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport type { TraceEvent, AwaitHumanOptions, HumanDecision, ProviderResponse } from '@axlsdk/axl';\nimport { WorkflowContext, MemoryStore, ProviderRegistry } from '@axlsdk/axl';\nimport type { WorkflowContextInit } from '@axlsdk/axl';\n\ninterface WorkflowLike {\n readonly name: string;\n readonly inputSchema: any;\n readonly outputSchema: any | undefined;\n readonly handler: (ctx: any) => Promise<any>;\n}\n\nexport type RecordedToolCall = { name: string; args: unknown; result: unknown };\nexport type RecordedAgentCall = {\n agent: string;\n prompt: string;\n response: string;\n model?: string;\n cost?: number;\n duration?: number;\n promptVersion?: string;\n};\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\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, WorkflowLike>();\n private mockProviders = new Map<string, MockProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: TraceEvent[] = [];\n private _totalCost = 0;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n }\n\n register(workflow: WorkflowLike): 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 mockTool(name: string, handler: (input: any) => unknown | Promise<unknown>): void {\n this.mockToolMap.set(name, MockTool.create(name, handler));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: { metadata?: Record<string, unknown> },\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._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 as any);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider as any);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider as any);\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 // Record steps and traces via callbacks\n this._recordStep('workflow_start', { workflow: workflowName, input: validated });\n this._pushTrace({\n type: 'workflow_start',\n workflow: workflowName,\n data: { input: validated },\n });\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n config: {},\n providerRegistry: registry,\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: TraceEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type: event.type, data: event.data });\n\n if (event.type === 'tool_call' && event.data) {\n const { args, result } = event.data as { args: unknown; result: unknown };\n this._toolCalls.push({ name: event.tool!, args, result });\n }\n\n if (event.cost) {\n this._totalCost += event.cost;\n }\n\n // Track provider responses for recording\n if (event.type === 'agent_call' && 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: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n cost: event.cost ?? 0,\n });\n }\n }\n },\n onAgentCallComplete: (call) => {\n this._agentCalls.push({\n agent: call.agent,\n prompt: call.prompt,\n response: call.response,\n model: call.model,\n cost: call.cost,\n duration: call.duration,\n promptVersion: call.promptVersion,\n });\n },\n };\n\n const ctx = new WorkflowContext(init);\n const result = await workflow.handler(ctx);\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n this._recordStep('workflow_end', { workflow: workflowName, result });\n this._pushTrace({\n type: 'workflow_end',\n workflow: workflowName,\n data: { result },\n });\n\n if (this.recordPath) await this._writeRecording();\n return result;\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 steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): TraceEvent[] {\n return this._traceLog;\n }\n\n private _recordStep(type: string, data: unknown): void {\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type, data });\n }\n\n private _pushTrace(partial: Omit<TraceEvent, 'executionId' | 'step' | 'timestamp'>): void {\n this._traceLog.push({\n executionId: this._executionId,\n step: this._stepCounter,\n timestamp: Date.now(),\n ...partial,\n });\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":["result"]}
1
+ {"version":3,"sources":["../src/mock-provider.ts","../src/mock-tool.ts","../src/test-runtime.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport type {\n ChatMessage,\n ToolCallMessage,\n ProviderResponse,\n StreamChunk,\n Provider,\n} from '@axlsdk/axl';\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: any): unknown {\n const def = schema?._def;\n if (!def) return {};\n switch (def.typeName) {\n case 'ZodString': {\n const length = 8 + Math.floor(Math.random() * 13); // 8-20 chars\n return randomAlphanumeric(length);\n }\n case 'ZodNumber': {\n const checks: any[] = def.checks ?? [];\n let min = 0;\n let max = 100;\n for (const check of checks) {\n if (check.kind === 'min') min = check.value;\n if (check.kind === 'max') max = check.value;\n }\n return min + Math.random() * (max - min);\n }\n case 'ZodBoolean':\n return Math.random() < 0.5;\n case 'ZodArray': {\n const count = 1 + Math.floor(Math.random() * 3); // 1-3 items\n const items: unknown[] = [];\n for (let i = 0; i < count; i++) {\n items.push(generateFromSchema(def.type));\n }\n return items;\n }\n case 'ZodObject': {\n const shape = def.shape?.() ?? {};\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(shape)) {\n obj[key] = generateFromSchema(value);\n }\n return obj;\n }\n case 'ZodOptional': {\n if (Math.random() < 0.5) return undefined;\n return generateFromSchema(def.innerType);\n }\n case 'ZodDefault':\n return def.defaultValue();\n case 'ZodEnum': {\n const values: unknown[] = def.values ?? [];\n if (values.length === 0) return '';\n return values[Math.floor(Math.random() * values.length)];\n }\n case 'ZodNullable':\n return null;\n default:\n return {};\n }\n}\n\nexport class MockProvider implements Provider {\n readonly name = 'mock';\n private _calls: { messages: ChatMessage[]; options: any }[] = [];\n\n private constructor(\n private responseFn: (messages: ChatMessage[], callIndex: number) => ProviderResponse,\n ) {}\n\n get calls() {\n return this._calls;\n }\n\n async chat(messages: ChatMessage[], options: any): Promise<ProviderResponse> {\n this._calls.push({ messages, options });\n return this.responseFn(messages, this._calls.length - 1);\n }\n\n async *stream(messages: ChatMessage[], options: any): AsyncGenerator<StreamChunk> {\n const response = await this.chat(messages, options);\n yield { type: 'text_delta', content: response.content };\n yield { type: 'done', usage: response.usage };\n }\n\n static sequence(\n responses: Array<{ content: string; tool_calls?: ToolCallMessage[] }>,\n ): MockProvider {\n return 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 return {\n content: responses[callIndex].content,\n tool_calls: responses[callIndex].tool_calls,\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\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?.content ?? '',\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n };\n });\n }\n\n static json(schema: any): 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 ) => { content: string; tool_calls?: ToolCallMessage[] },\n ): MockProvider {\n return new MockProvider((messages, callIndex) => ({\n ...handler(messages, callIndex),\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n cost: 0,\n }));\n }\n}\n","export class MockTool {\n private _calls: { input: unknown }[] = [];\n\n constructor(\n readonly name: string,\n private handler: (input: any) => 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: any) => unknown | Promise<unknown>): MockTool {\n return new MockTool(name, handler);\n }\n}\n","import { MockProvider } from './mock-provider.js';\nimport { MockTool } from './mock-tool.js';\nimport type { TraceEvent, AwaitHumanOptions, HumanDecision, ProviderResponse } from '@axlsdk/axl';\nimport { WorkflowContext, MemoryStore, ProviderRegistry } from '@axlsdk/axl';\nimport type { WorkflowContextInit } from '@axlsdk/axl';\n\ninterface WorkflowLike {\n readonly name: string;\n readonly inputSchema: any;\n readonly outputSchema: any | undefined;\n readonly handler: (ctx: any) => Promise<any>;\n}\n\nexport type RecordedToolCall = { name: string; args: unknown; result: unknown };\nexport type RecordedAgentCall = {\n agent: string;\n prompt: string;\n response: string;\n model?: string;\n cost?: number;\n duration?: number;\n promptVersion?: string;\n};\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\nexport type AxlTestRuntimeOptions = {\n record?: string;\n humanDecisions?: (options: AwaitHumanOptions) => HumanDecision;\n};\n\nexport class AxlTestRuntime {\n private workflows = new Map<string, WorkflowLike>();\n private mockProviders = new Map<string, MockProvider>();\n private mockToolMap = new Map<string, MockTool>();\n private _toolCalls: RecordedToolCall[] = [];\n private _agentCalls: RecordedAgentCall[] = [];\n private _steps: RecordedStep[] = [];\n private _traceLog: TraceEvent[] = [];\n private _totalCost = 0;\n private _stepCounter = 0;\n private recordPath?: string;\n private recorded: ProviderResponse[] = [];\n private _executionId: string = generateExecutionId();\n private _humanDecisionHandler?: (options: AwaitHumanOptions) => HumanDecision;\n\n constructor(options?: AxlTestRuntimeOptions) {\n this.recordPath = options?.record;\n this._humanDecisionHandler = options?.humanDecisions;\n }\n\n register(workflow: WorkflowLike): 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 mockTool(name: string, handler: (input: any) => unknown | Promise<unknown>): void {\n this.mockToolMap.set(name, MockTool.create(name, handler));\n }\n\n async execute(\n workflowName: string,\n input: unknown,\n options?: { metadata?: Record<string, unknown> },\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._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 as any);\n }\n // Fallback resolution: 'default' key or single-provider\n const defaultProvider = this.mockProviders.get('default');\n if (defaultProvider) {\n registry.setFallback(defaultProvider as any);\n } else if (this.mockProviders.size === 1) {\n const onlyProvider = this.mockProviders.values().next().value!;\n registry.setFallback(onlyProvider as any);\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 // Record steps and traces via callbacks\n this._recordStep('workflow_start', { workflow: workflowName, input: validated });\n this._pushTrace({\n type: 'workflow_start',\n workflow: workflowName,\n data: { input: validated },\n });\n\n const init: WorkflowContextInit = {\n input: validated,\n executionId: this._executionId,\n metadata: options?.metadata,\n config: {},\n providerRegistry: registry,\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: TraceEvent) => {\n this._traceLog.push(event);\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type: event.type, data: event.data });\n\n if (event.type === 'tool_call' && event.data) {\n const { args, result } = event.data as { args: unknown; result: unknown };\n this._toolCalls.push({ name: event.tool!, args, result });\n }\n\n if (event.cost) {\n this._totalCost += event.cost;\n }\n\n // Track provider responses for recording\n if (event.type === 'agent_call' && 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: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n cost: event.cost ?? 0,\n });\n }\n }\n },\n onAgentCallComplete: (call) => {\n this._agentCalls.push({\n agent: call.agent,\n prompt: call.prompt,\n response: call.response,\n model: call.model,\n cost: call.cost,\n duration: call.duration,\n promptVersion: call.promptVersion,\n });\n },\n };\n\n const ctx = new WorkflowContext(init);\n const result = await workflow.handler(ctx);\n\n // Validate output schema if defined\n if (workflow.outputSchema) workflow.outputSchema.parse(result);\n\n this._recordStep('workflow_end', { workflow: workflowName, result });\n this._pushTrace({\n type: 'workflow_end',\n workflow: workflowName,\n data: { result },\n });\n\n if (this.recordPath) await this._writeRecording();\n return result;\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 steps(): RecordedStep[] {\n return this._steps;\n }\n traceLog(): TraceEvent[] {\n return this._traceLog;\n }\n\n private _recordStep(type: string, data: unknown): void {\n this._stepCounter++;\n this._steps.push({ step: this._stepCounter, type, data });\n }\n\n private _pushTrace(partial: Omit<TraceEvent, 'executionId' | 'step' | 'timestamp'>): void {\n this._traceLog.push({\n executionId: this._executionId,\n step: this._stepCounter,\n timestamp: Date.now(),\n ...partial,\n });\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":["result"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axlsdk/testing",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Testing utilities for Axl agentic workflows",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",