@toolpack-sdk/agents 2.0.0-alpha.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 +827 -0
- package/dist/base-agent-CjrUlo6Y.d.cts +189 -0
- package/dist/base-agent-Cx2kWzLF.d.ts +189 -0
- package/dist/capabilities/index.cjs +17 -0
- package/dist/capabilities/index.d.cts +74 -0
- package/dist/capabilities/index.d.ts +74 -0
- package/dist/capabilities/index.js +17 -0
- package/dist/channels/index.cjs +3 -0
- package/dist/channels/index.d.cts +616 -0
- package/dist/channels/index.d.ts +616 -0
- package/dist/channels/index.js +3 -0
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +334 -0
- package/dist/index.d.ts +334 -0
- package/dist/index.js +20 -0
- package/dist/intent-classifier-agent-BLXXcbNJ.d.cts +45 -0
- package/dist/intent-classifier-agent-BLpDwKVf.d.ts +45 -0
- package/dist/interceptors/index.cjs +1 -0
- package/dist/interceptors/index.d.cts +539 -0
- package/dist/interceptors/index.d.ts +539 -0
- package/dist/interceptors/index.js +1 -0
- package/dist/registry/index.cjs +1 -0
- package/dist/registry/index.d.cts +159 -0
- package/dist/registry/index.d.ts +159 -0
- package/dist/registry/index.js +1 -0
- package/dist/testing/index.cjs +3 -0
- package/dist/testing/index.d.cts +389 -0
- package/dist/testing/index.d.ts +389 -0
- package/dist/testing/index.js +3 -0
- package/dist/types-BWoRx1ZE.d.cts +395 -0
- package/dist/types-BWoRx1ZE.d.ts +395 -0
- package/package.json +121 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { C as ChannelInterface, d as AgentOutput, A as AgentInput, B as BaseAgentOptions } from '../types-BWoRx1ZE.js';
|
|
2
|
+
import { Chunk, QueryOptions, QueryResult, Knowledge } from '@toolpack-sdk/knowledge';
|
|
3
|
+
import { Toolpack } from 'toolpack-sdk';
|
|
4
|
+
import { B as BaseAgent } from '../base-agent-Cx2kWzLF.js';
|
|
5
|
+
import 'events';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Mock channel for testing agents without external integrations.
|
|
9
|
+
* Simulates a channel that can receive messages and capture outputs.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const mockChannel = new MockChannel();
|
|
14
|
+
*
|
|
15
|
+
* // Simulate an incoming message
|
|
16
|
+
* await mockChannel.receive({
|
|
17
|
+
* message: 'Analyse this week\'s leads',
|
|
18
|
+
* intent: 'morning_analysis',
|
|
19
|
+
* conversationId: 'test-thread-1',
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Assert what the agent sent back
|
|
23
|
+
* expect(mockChannel.lastOutput?.output).toContain('leads');
|
|
24
|
+
* expect(mockChannel.outputs).toHaveLength(1);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare class MockChannel implements ChannelInterface {
|
|
28
|
+
name: string;
|
|
29
|
+
isTriggerChannel: boolean;
|
|
30
|
+
private _handler?;
|
|
31
|
+
private _outputs;
|
|
32
|
+
private _inputs;
|
|
33
|
+
private _listening;
|
|
34
|
+
/**
|
|
35
|
+
* All outputs sent to this channel.
|
|
36
|
+
*/
|
|
37
|
+
get outputs(): AgentOutput[];
|
|
38
|
+
/**
|
|
39
|
+
* The most recent output sent to this channel, or undefined if none.
|
|
40
|
+
*/
|
|
41
|
+
get lastOutput(): AgentOutput | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* All inputs received by this channel.
|
|
44
|
+
*/
|
|
45
|
+
get inputs(): AgentInput[];
|
|
46
|
+
/**
|
|
47
|
+
* The most recent input received by this channel, or undefined if none.
|
|
48
|
+
*/
|
|
49
|
+
get lastInput(): AgentInput | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Number of messages received.
|
|
52
|
+
*/
|
|
53
|
+
get receivedCount(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Number of outputs sent.
|
|
56
|
+
*/
|
|
57
|
+
get sentCount(): number;
|
|
58
|
+
/**
|
|
59
|
+
* Whether the channel is currently "listening".
|
|
60
|
+
*/
|
|
61
|
+
get isListening(): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Set the message handler. Called by AgentRegistry.
|
|
64
|
+
*/
|
|
65
|
+
onMessage(handler: (input: AgentInput) => Promise<void>): void;
|
|
66
|
+
/**
|
|
67
|
+
* Start listening. Called by AgentRegistry.
|
|
68
|
+
* For MockChannel, this just sets a flag.
|
|
69
|
+
*/
|
|
70
|
+
listen(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Stop listening.
|
|
73
|
+
*/
|
|
74
|
+
stop(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Send output to this channel.
|
|
77
|
+
* Captures the output for later assertions.
|
|
78
|
+
*/
|
|
79
|
+
send(output: AgentOutput): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Normalize an incoming event into AgentInput.
|
|
82
|
+
*/
|
|
83
|
+
normalize(incoming: unknown): AgentInput;
|
|
84
|
+
/**
|
|
85
|
+
* Simulate receiving a message on this channel.
|
|
86
|
+
* Normalizes the input and invokes the registered handler.
|
|
87
|
+
*
|
|
88
|
+
* @param incoming The raw incoming message data
|
|
89
|
+
* @returns A promise that resolves when the handler completes
|
|
90
|
+
* @throws If no handler is registered (channel not wired to agent)
|
|
91
|
+
*/
|
|
92
|
+
receive(incoming: unknown): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Simulate receiving a message with a specific conversation ID.
|
|
95
|
+
*
|
|
96
|
+
* @param message The message text
|
|
97
|
+
* @param conversationId The conversation ID
|
|
98
|
+
* @param intent Optional intent
|
|
99
|
+
* @param context Optional context
|
|
100
|
+
*/
|
|
101
|
+
receiveMessage(message: string, conversationId?: string, intent?: string, context?: Record<string, unknown>): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Clear all captured inputs and outputs.
|
|
104
|
+
*/
|
|
105
|
+
clear(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Assert that an output containing the given text was sent.
|
|
108
|
+
*
|
|
109
|
+
* @param text The text to search for
|
|
110
|
+
* @throws If no matching output is found
|
|
111
|
+
*/
|
|
112
|
+
assertOutputContains(text: string): void;
|
|
113
|
+
/**
|
|
114
|
+
* Assert that the last output matches the expected text.
|
|
115
|
+
*
|
|
116
|
+
* @param expected The expected text
|
|
117
|
+
* @throws If the last output doesn't match
|
|
118
|
+
*/
|
|
119
|
+
assertLastOutput(expected: string): void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Options for creating mock knowledge.
|
|
124
|
+
*/
|
|
125
|
+
interface MockKnowledgeOptions {
|
|
126
|
+
/** Initial chunks to populate the knowledge base */
|
|
127
|
+
initialChunks?: Array<{
|
|
128
|
+
content: string;
|
|
129
|
+
metadata?: Record<string, unknown>;
|
|
130
|
+
}>;
|
|
131
|
+
/** Dimensions for the mock embedder (default: 384) */
|
|
132
|
+
dimensions?: number;
|
|
133
|
+
/** Description for the knowledge tool */
|
|
134
|
+
description?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Creates an in-memory mock Knowledge instance for testing.
|
|
138
|
+
* No embedder, no provider needed — everything is in-memory.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const knowledge = await createMockKnowledge({
|
|
143
|
+
* initialChunks: [
|
|
144
|
+
* { content: 'Lead: Acme Corp, score: 85', metadata: { source: 'crm' } },
|
|
145
|
+
* ],
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* // Use with SDK
|
|
149
|
+
* const toolpack = await Toolpack.init({
|
|
150
|
+
* provider: 'openai',
|
|
151
|
+
* knowledge, // Available to all agents
|
|
152
|
+
* });
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
declare function createMockKnowledge(options?: MockKnowledgeOptions): Promise<Knowledge>;
|
|
156
|
+
/**
|
|
157
|
+
* Synchronous version of createMockKnowledge for simple test cases.
|
|
158
|
+
* Returns a mock knowledge-like object that's not a full Knowledge instance
|
|
159
|
+
* but implements the key methods needed for testing.
|
|
160
|
+
*
|
|
161
|
+
* This is useful when you don't want to deal with async setup in tests.
|
|
162
|
+
*/
|
|
163
|
+
declare function createMockKnowledgeSync(options?: MockKnowledgeOptions): MockKnowledge;
|
|
164
|
+
/**
|
|
165
|
+
* A simplified mock Knowledge for synchronous test setup.
|
|
166
|
+
* Implements the key methods that agents use: query() and add()
|
|
167
|
+
*/
|
|
168
|
+
declare class MockKnowledge {
|
|
169
|
+
private chunks;
|
|
170
|
+
private generateVector;
|
|
171
|
+
private _description;
|
|
172
|
+
constructor(initialChunks: Chunk[] | undefined, generateVector: (text: string) => number[], description?: string);
|
|
173
|
+
/**
|
|
174
|
+
* Query the mock knowledge base using simple keyword matching.
|
|
175
|
+
* This doesn't do real semantic search but is sufficient for most tests.
|
|
176
|
+
*/
|
|
177
|
+
query(text: string, options?: QueryOptions): Promise<QueryResult[]>;
|
|
178
|
+
/**
|
|
179
|
+
* Add content to the mock knowledge base.
|
|
180
|
+
*/
|
|
181
|
+
add(content: string, metadata?: Record<string, unknown>): Promise<string>;
|
|
182
|
+
/**
|
|
183
|
+
* Get all chunks in the knowledge base.
|
|
184
|
+
*/
|
|
185
|
+
getAllChunks(): Chunk[];
|
|
186
|
+
/**
|
|
187
|
+
* Clear all chunks.
|
|
188
|
+
*/
|
|
189
|
+
clear(): void;
|
|
190
|
+
/**
|
|
191
|
+
* Convert to a tool format for use with agents.
|
|
192
|
+
*/
|
|
193
|
+
toTool(): {
|
|
194
|
+
name: string;
|
|
195
|
+
displayName: string;
|
|
196
|
+
description: string;
|
|
197
|
+
category: string;
|
|
198
|
+
cacheable: boolean;
|
|
199
|
+
parameters: {
|
|
200
|
+
type: string;
|
|
201
|
+
properties: Record<string, unknown>;
|
|
202
|
+
required: string[];
|
|
203
|
+
};
|
|
204
|
+
execute: (params: {
|
|
205
|
+
query: string;
|
|
206
|
+
limit?: number;
|
|
207
|
+
threshold?: number;
|
|
208
|
+
filter?: Record<string, unknown>;
|
|
209
|
+
}) => Promise<Array<{
|
|
210
|
+
content: string;
|
|
211
|
+
score: number;
|
|
212
|
+
metadata: Record<string, unknown>;
|
|
213
|
+
}>>;
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Configuration for mock responses in createTestAgent.
|
|
219
|
+
*/
|
|
220
|
+
interface MockResponse {
|
|
221
|
+
/** String or regex to match against the message */
|
|
222
|
+
trigger: string | RegExp;
|
|
223
|
+
/** The response to return when triggered */
|
|
224
|
+
response: string;
|
|
225
|
+
/** Optional usage metadata */
|
|
226
|
+
usage?: {
|
|
227
|
+
prompt_tokens: number;
|
|
228
|
+
completion_tokens: number;
|
|
229
|
+
total_tokens: number;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Options for createTestAgent.
|
|
234
|
+
*/
|
|
235
|
+
interface CreateTestAgentOptions {
|
|
236
|
+
/** Mock responses for the toolpack.generate() call */
|
|
237
|
+
mockResponses?: MockResponse[];
|
|
238
|
+
/** Default response when no trigger matches */
|
|
239
|
+
defaultResponse?: string;
|
|
240
|
+
/** Provider name for the mock toolpack */
|
|
241
|
+
provider?: string;
|
|
242
|
+
/** Model name for the mock toolpack */
|
|
243
|
+
model?: string;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Result from createTestAgent.
|
|
247
|
+
*/
|
|
248
|
+
interface TestAgentResult<TAgent extends BaseAgent> {
|
|
249
|
+
/** The agent instance */
|
|
250
|
+
agent: TAgent;
|
|
251
|
+
/** The mock channel wired to the agent */
|
|
252
|
+
channel: MockChannel;
|
|
253
|
+
/** The mock toolpack instance */
|
|
254
|
+
toolpack: Toolpack;
|
|
255
|
+
/** Helper to add more mock responses */
|
|
256
|
+
addMockResponse: (response: MockResponse) => void;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Creates an agent instance wired to a mock channel and mock toolpack.
|
|
260
|
+
* Perfect for unit testing agents in isolation.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* const { agent, channel, toolpack } = createTestAgent(CustomerSupportAgent, {
|
|
265
|
+
* mockResponses: [
|
|
266
|
+
* { trigger: 'refund', response: 'Refund processed successfully.' },
|
|
267
|
+
* ],
|
|
268
|
+
* });
|
|
269
|
+
*
|
|
270
|
+
* const result = await agent.invokeAgent({
|
|
271
|
+
* intent: 'refund_request',
|
|
272
|
+
* message: 'I want a refund for order #123',
|
|
273
|
+
* });
|
|
274
|
+
*
|
|
275
|
+
* expect(result.output).toBe('Refund processed successfully.');
|
|
276
|
+
* ```
|
|
277
|
+
*
|
|
278
|
+
* @param AgentClass The agent class to instantiate
|
|
279
|
+
* @param options Configuration options
|
|
280
|
+
* @returns Test agent setup with agent, channel, and mock toolpack
|
|
281
|
+
*/
|
|
282
|
+
declare function createTestAgent<TAgent extends BaseAgent>(AgentClass: new (options: BaseAgentOptions) => TAgent, options?: CreateTestAgentOptions): TestAgentResult<TAgent>;
|
|
283
|
+
/**
|
|
284
|
+
* Creates a minimal mock Toolpack for simple test cases.
|
|
285
|
+
* Returns the same response for all generate() calls.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* const toolpack = createMockToolpackSimple('Hello!');
|
|
290
|
+
* const agent = new MyAgent(toolpack);
|
|
291
|
+
* const result = await agent.run('Hi');
|
|
292
|
+
* expect(result.output).toBe('Hello!');
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
declare function createMockToolpackSimple(response?: string): Toolpack;
|
|
296
|
+
/**
|
|
297
|
+
* Creates a mock Toolpack that returns different responses based on a sequence.
|
|
298
|
+
* Useful for testing multi-turn conversations or stateful interactions.
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```ts
|
|
302
|
+
* const toolpack = createMockToolpackSequence([
|
|
303
|
+
* 'First response',
|
|
304
|
+
* 'Second response',
|
|
305
|
+
* 'Third response',
|
|
306
|
+
* ]);
|
|
307
|
+
*
|
|
308
|
+
* // First call returns 'First response', second call 'Second response', etc.
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
declare function createMockToolpackSequence(responses: string[]): Toolpack;
|
|
312
|
+
|
|
313
|
+
type AgentEventName = 'agent:start' | 'agent:complete' | 'agent:error';
|
|
314
|
+
interface CapturedEvent {
|
|
315
|
+
name: AgentEventName;
|
|
316
|
+
data: any;
|
|
317
|
+
timestamp: number;
|
|
318
|
+
}
|
|
319
|
+
interface EventCapture {
|
|
320
|
+
/** All captured events */
|
|
321
|
+
events: CapturedEvent[];
|
|
322
|
+
/** Number of events captured */
|
|
323
|
+
count: number;
|
|
324
|
+
/** Clear all captured events */
|
|
325
|
+
clear(): void;
|
|
326
|
+
/** Stop capturing events and remove listeners */
|
|
327
|
+
stop(): void;
|
|
328
|
+
/** Check if an event with the given name was captured */
|
|
329
|
+
hasEvent(name: AgentEventName): boolean;
|
|
330
|
+
/** Get all events with the given name */
|
|
331
|
+
getEvents(name: AgentEventName): CapturedEvent[];
|
|
332
|
+
/** Get the first event with the given name, or undefined if none */
|
|
333
|
+
getFirstEvent(name: AgentEventName): CapturedEvent | undefined;
|
|
334
|
+
/** Get the last event with the given name, or undefined if none */
|
|
335
|
+
getLastEvent(name: AgentEventName): CapturedEvent | undefined;
|
|
336
|
+
/** Assert that an event was captured (throws if not) */
|
|
337
|
+
assertEvent(name: AgentEventName): void;
|
|
338
|
+
/** Assert that an event was NOT captured (throws if it was) */
|
|
339
|
+
assertNoEvent(name: AgentEventName): void;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Captures events emitted by a BaseAgent during testing.
|
|
343
|
+
* Useful for asserting that certain lifecycle events were fired.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```ts
|
|
347
|
+
* const { agent } = createTestAgent(MyAgent);
|
|
348
|
+
* const events = captureEvents(agent);
|
|
349
|
+
*
|
|
350
|
+
* await agent.invokeAgent({ message: 'Do something' });
|
|
351
|
+
*
|
|
352
|
+
* expect(events.hasEvent('agent:start')).toBe(true);
|
|
353
|
+
* expect(events.hasEvent('agent:complete')).toBe(true);
|
|
354
|
+
* expect(events.hasEvent('agent:error')).toBe(false);
|
|
355
|
+
*
|
|
356
|
+
* // Or use assertion helpers
|
|
357
|
+
* events.assertEvent('agent:start');
|
|
358
|
+
* events.assertEvent('agent:complete');
|
|
359
|
+
* events.assertNoEvent('agent:error');
|
|
360
|
+
* ```
|
|
361
|
+
*
|
|
362
|
+
* @param agent The agent to capture events from
|
|
363
|
+
* @returns Event capture object with assertion helpers
|
|
364
|
+
*/
|
|
365
|
+
declare function captureEvents(agent: BaseAgent): EventCapture;
|
|
366
|
+
/**
|
|
367
|
+
* Custom Vitest/Jest matcher for asserting captured events.
|
|
368
|
+
* Add this to your test setup for more readable assertions.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```ts
|
|
372
|
+
* // In your test setup file
|
|
373
|
+
* import { expect } from 'vitest';
|
|
374
|
+
* import { registerEventMatchers } from '@toolpack-sdk/agents/testing';
|
|
375
|
+
* registerEventMatchers(expect);
|
|
376
|
+
*
|
|
377
|
+
* // In your tests
|
|
378
|
+
* expect(events).toContainEvent('agent:start');
|
|
379
|
+
* expect(events).not.toContainEvent('agent:error');
|
|
380
|
+
* ```
|
|
381
|
+
*/
|
|
382
|
+
declare function registerEventMatchers(expect: {
|
|
383
|
+
extend: (matchers: Record<string, (...args: unknown[]) => {
|
|
384
|
+
message: () => string;
|
|
385
|
+
pass: boolean;
|
|
386
|
+
}>) => void;
|
|
387
|
+
}): void;
|
|
388
|
+
|
|
389
|
+
export { type AgentEventName, type CapturedEvent, type CreateTestAgentOptions, type EventCapture, MockChannel, MockKnowledge, type MockKnowledgeOptions, type MockResponse, type TestAgentResult, captureEvents, createMockKnowledge, createMockKnowledgeSync, createMockToolpackSequence, createMockToolpackSimple, createTestAgent, registerEventMatchers };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var p=class{name="mock-channel";isTriggerChannel=!1;_handler;_outputs=[];_inputs=[];_listening=!1;get outputs(){return[...this._outputs]}get lastOutput(){return this._outputs[this._outputs.length-1]}get inputs(){return[...this._inputs]}get lastInput(){return this._inputs[this._inputs.length-1]}get receivedCount(){return this._inputs.length}get sentCount(){return this._outputs.length}get isListening(){return this._listening}onMessage(e){this._handler=e}listen(){this._listening=!0}stop(){this._listening=!1}async send(e){this._outputs.push(e)}normalize(e){let t=e;return{intent:t.intent,message:t.message,data:t.data,context:t.context||{},conversationId:t.conversationId||"test-conversation-1"}}async receive(e){if(!this._handler)throw new Error("MockChannel: no message handler registered. Call onMessage() first or ensure channel is registered with AgentRegistry.");let t=this.normalize(e);this._inputs.push(t),await this._handler(t)}async receiveMessage(e,t="test-conversation-1",o,i){await this.receive({message:e,conversationId:t,intent:o,context:i})}clear(){this._inputs=[],this._outputs=[]}assertOutputContains(e){if(!this._outputs.some(o=>o.output.includes(e)))throw new Error(`MockChannel: no output containing "${e}" found. Outputs: ${JSON.stringify(this._outputs.map(o=>o.output))}`)}assertLastOutput(e){let t=this.lastOutput;if(!t)throw new Error(`MockChannel: no output sent. Expected: "${e}"`);if(t.output!==e)throw new Error(`MockChannel: last output mismatch.
|
|
2
|
+
Expected: "${e}"
|
|
3
|
+
Actual: "${t.output}"`)}};async function v(c={}){let{Knowledge:e}=await import("@toolpack-sdk/knowledge"),{MemoryProvider:t}=await import("@toolpack-sdk/knowledge"),o=c.dimensions??384,i={dimensions:o,async embed(s){let r=[],u=0;for(let a=0;a<s.length;a++)u=(u+s.charCodeAt(a))%1e3;for(let a=0;a<o;a++){let d=Math.sin(u*(a+1))*.5+.5;r.push(d)}return r},async embedBatch(s){return Promise.all(s.map(r=>this.embed(r)))}},n=new t;if(await n.validateDimensions(o),c.initialChunks&&c.initialChunks.length>0){let s=[];for(let r of c.initialChunks){let u=await i.embed(r.content);s.push({id:`mock-${Date.now()}-${Math.random().toString(36).slice(2)}`,content:r.content,metadata:r.metadata||{},vector:u})}await n.add(s)}return e.create({provider:n,embedder:i,sources:[],description:c.description??"Mock knowledge base for testing",reSync:!1})}function h(c={}){let e=c.dimensions??384,t=[],o=i=>{let n=[],s=0;for(let r=0;r<i.length;r++)s=(s+i.charCodeAt(r))%1e3;for(let r=0;r<e;r++){let u=Math.sin(s*(r+1))*.5+.5;n.push(u)}return n};if(c.initialChunks)for(let i of c.initialChunks)t.push({id:`mock-${Date.now()}-${Math.random().toString(36).slice(2)}`,content:i.content,metadata:i.metadata||{},vector:o(i.content)});return new m(t,o,c.description)}var m=class{chunks;generateVector;_description;constructor(e=[],t,o="Mock knowledge base"){this.chunks=[...e],this.generateVector=t,this._description=o}async query(e,t){let o=t?.limit??10,i=t?.filter,n=e.toLowerCase().split(/\s+/);return this.chunks.filter(r=>{if(i){for(let[u,a]of Object.entries(i))if(r.metadata[u]!==a)return!1}return!0}).map(r=>{let u=r.content.toLowerCase(),a=0;for(let d of n)u.includes(d)&&(a+=.3,new RegExp(`\\b${d}\\b`).test(u)&&(a+=.2));return a=Math.min(a,1),{chunk:{id:r.id,content:r.content,metadata:t?.includeMetadata===!1?{}:r.metadata,vector:t?.includeVectors?r.vector:void 0},score:a,distance:1-a}}).filter(r=>r.score>0).sort((r,u)=>u.score-r.score).slice(0,o)}async add(e,t){let o=`mock-${Date.now()}-${Math.random().toString(36).slice(2)}`;return this.chunks.push({id:o,content:e,metadata:t||{},vector:this.generateVector(e)}),o}getAllChunks(){return[...this.chunks]}clear(){this.chunks=[]}toTool(){return{name:"knowledge_search",displayName:"Knowledge Search",description:this._description,category:"search",cacheable:!1,parameters:{type:"object",properties:{query:{type:"string",description:"Search query to find relevant information"},limit:{type:"number",description:"Maximum number of results to return (default: 10)"},threshold:{type:"number",description:"Minimum similarity threshold 0-1 (default: 0.7)"},filter:{type:"object",description:"Optional metadata filters"}},required:["query"]},execute:async e=>(await this.query(e.query,{limit:e.limit,filter:e.filter})).map(o=>({content:o.chunk.content,score:o.score,metadata:o.chunk.metadata}))}}};function k(c,e={}){let t=[...e.mockResponses??[]],o=e.defaultResponse??"Mock AI response",i=f(t,o,e.provider,e.model),n=new c({toolpack:i}),s=new p;return s.onMessage(async u=>{n._triggeringChannel=s.name,n._conversationId=u.conversationId,n._isTriggerChannel=!1;let a=await n.invokeAgent(u);await s.send({output:a.output,metadata:a.metadata})}),s.listen(),{agent:n,channel:s,toolpack:i,addMockResponse:u=>{t.push(u)}}}function f(c,e,t="openai",o){return{generate:async(i,n)=>{let u=i.messages.filter(a=>a.role==="user").pop()?.content??"";for(let a of c)if(typeof a.trigger=="string"){if(u.toLowerCase().includes(a.trigger.toLowerCase()))return{content:a.response,usage:a.usage??{prompt_tokens:10,completion_tokens:5,total_tokens:15}}}else if(a.trigger instanceof RegExp&&a.trigger.test(u))return{content:a.response,usage:a.usage??{prompt_tokens:10,completion_tokens:5,total_tokens:15}};return{content:e,usage:{prompt_tokens:10,completion_tokens:5,total_tokens:15}}},setMode:()=>{},registerMode:()=>{},setProvider:()=>{},setModel:()=>{},get provider(){return t},get model(){return o||"gpt-4"}}}function w(c="Mock AI response"){return{generate:async()=>({content:c,usage:{prompt_tokens:10,completion_tokens:5,total_tokens:15}}),setMode:()=>{},registerMode:()=>{},setProvider:()=>{},setModel:()=>{}}}function E(c){let e=0;return{generate:async()=>{let t=c[e]??"No more mock responses";return e++,{content:t,usage:{prompt_tokens:10,completion_tokens:5,total_tokens:15}}},setMode:()=>{},registerMode:()=>{},setProvider:()=>{},setModel:()=>{}}}function A(c){let e=[],t=[],o=n=>s=>{e.push({name:n,data:s,timestamp:Date.now()})},i=["agent:start","agent:complete","agent:error"];for(let n of i){let s=o(n);c.on(n,s),t.push({event:n,handler:s})}return{get events(){return[...e]},get count(){return e.length},clear(){e.length=0},stop(){for(let{event:n,handler:s}of t)c.off(n,s);t.length=0},hasEvent(n){return e.some(s=>s.name===n)},getEvents(n){return e.filter(s=>s.name===n)},getFirstEvent(n){return e.find(s=>s.name===n)},getLastEvent(n){let s=e.filter(r=>r.name===n);return s[s.length-1]},assertEvent(n){if(!this.hasEvent(n)){let s=e.map(r=>r.name).join(", ")||"(none)";throw new Error(`captureEvents: expected event "${n}" was not captured. Captured events: ${s}`)}},assertNoEvent(n){if(this.hasEvent(n)){let s=e.filter(r=>r.name===n).length;throw new Error(`captureEvents: unexpected event "${n}" was captured ${s} time(s)`)}}}}function M(c){c.extend({toContainEvent(...e){let t=e[0],o=e[1],i=t.hasEvent(o);return{message:()=>i?`expected events to NOT contain "${o}"`:`expected events to contain "${o}". Captured events: ${t.events.map(n=>n.name).join(", ")||"(none)"}`,pass:i}},toContainEventTimes(...e){let t=e[0],o=e[1],i=e[2],n=t.getEvents(o).length,s=n===i;return{message:()=>s?`expected event "${o}" to NOT be captured ${i} time(s), but it was`:`expected event "${o}" to be captured ${i} time(s), but it was captured ${n} time(s)`,pass:s}}})}export{p as MockChannel,m as MockKnowledge,A as captureEvents,v as createMockKnowledge,h as createMockKnowledgeSync,E as createMockToolpackSequence,w as createMockToolpackSimple,k as createTestAgent,M as registerEventMatchers};
|