@agentxjs/devtools 1.9.6-dev → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +284 -0
- package/dist/bdd/cli.d.ts +1 -0
- package/dist/bdd/cli.js +117 -0
- package/dist/bdd/cli.js.map +1 -0
- package/dist/bdd/index.d.ts +202 -0
- package/dist/bdd/index.js +381 -0
- package/dist/bdd/index.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/{chunk-YRTTCKHM.js → chunk-DR45HEV4.js} +1 -1
- package/dist/chunk-DR45HEV4.js.map +1 -0
- package/dist/{chunk-SQDCFUA3.js → chunk-J6L73HM5.js} +9 -1
- package/dist/chunk-J6L73HM5.js.map +1 -0
- package/dist/chunk-S7J75AXG.js +64 -0
- package/dist/chunk-S7J75AXG.js.map +1 -0
- package/dist/fixtures/index.js +1 -0
- package/dist/index.d.ts +37 -4
- package/dist/index.js +8 -12
- package/dist/index.js.map +1 -1
- package/dist/mock/index.js +2 -1
- package/dist/recorder/index.js +2 -1
- package/package.json +27 -5
- package/src/Devtools.ts +11 -14
- package/src/bdd/agent-doc-tester.ts +130 -0
- package/src/bdd/agent-ui-tester.ts +88 -0
- package/src/bdd/cli.ts +166 -0
- package/src/bdd/cucumber.config.ts +40 -0
- package/src/bdd/dev-server.ts +82 -0
- package/src/bdd/index.ts +41 -0
- package/src/bdd/paths.ts +140 -0
- package/src/bdd/playwright.ts +110 -0
- package/src/env.ts +97 -0
- package/src/index.ts +6 -1
- package/src/mock/MockDriver.ts +21 -12
- package/src/recorder/RecordingDriver.ts +1 -5
- package/dist/chunk-SQDCFUA3.js.map +0 -1
- package/dist/chunk-YRTTCKHM.js.map +0 -1
package/src/mock/MockDriver.ts
CHANGED
|
@@ -22,12 +22,7 @@
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import type {
|
|
26
|
-
Driver,
|
|
27
|
-
DriverConfig,
|
|
28
|
-
DriverState,
|
|
29
|
-
DriverStreamEvent,
|
|
30
|
-
} from "@agentxjs/core/driver";
|
|
25
|
+
import type { Driver, DriverConfig, DriverState, DriverStreamEvent } from "@agentxjs/core/driver";
|
|
31
26
|
import type { UserMessage } from "@agentxjs/core/agent";
|
|
32
27
|
import type { Fixture, FixtureEvent, MockDriverOptions } from "../types";
|
|
33
28
|
import { BUILTIN_FIXTURES } from "../../fixtures";
|
|
@@ -65,10 +60,7 @@ export class MockDriver implements Driver {
|
|
|
65
60
|
* @param options - MockDriverOptions or DriverConfig
|
|
66
61
|
* @param mockOptions - MockDriverOptions if first param is DriverConfig
|
|
67
62
|
*/
|
|
68
|
-
constructor(
|
|
69
|
-
optionsOrConfig: MockDriverOptions | DriverConfig,
|
|
70
|
-
mockOptions?: MockDriverOptions
|
|
71
|
-
) {
|
|
63
|
+
constructor(optionsOrConfig: MockDriverOptions | DriverConfig, mockOptions?: MockDriverOptions) {
|
|
72
64
|
// Detect which constructor form is being used
|
|
73
65
|
if (mockOptions !== undefined || "apiKey" in optionsOrConfig) {
|
|
74
66
|
// Factory mode: (DriverConfig, MockDriverOptions)
|
|
@@ -349,12 +341,27 @@ export class MockDriver implements Driver {
|
|
|
349
341
|
},
|
|
350
342
|
};
|
|
351
343
|
|
|
344
|
+
case "message_delta":
|
|
345
|
+
return {
|
|
346
|
+
type: "message_delta",
|
|
347
|
+
timestamp,
|
|
348
|
+
data: {
|
|
349
|
+
usage: data.usage as { inputTokens: number; outputTokens: number } | undefined,
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
|
|
352
353
|
case "message_stop":
|
|
353
354
|
return {
|
|
354
355
|
type: "message_stop",
|
|
355
356
|
timestamp,
|
|
356
357
|
data: {
|
|
357
|
-
stopReason:
|
|
358
|
+
stopReason:
|
|
359
|
+
(data.stopReason as
|
|
360
|
+
| "end_turn"
|
|
361
|
+
| "tool_use"
|
|
362
|
+
| "max_tokens"
|
|
363
|
+
| "stop_sequence"
|
|
364
|
+
| "other") || "end_turn",
|
|
358
365
|
},
|
|
359
366
|
};
|
|
360
367
|
|
|
@@ -391,6 +398,8 @@ export class MockDriver implements Driver {
|
|
|
391
398
|
* @param mockOptions - Options for all created drivers
|
|
392
399
|
* @returns CreateDriver function
|
|
393
400
|
*/
|
|
394
|
-
export function createMockDriver(
|
|
401
|
+
export function createMockDriver(
|
|
402
|
+
mockOptions: MockDriverOptions = {}
|
|
403
|
+
): (config: DriverConfig) => Driver {
|
|
395
404
|
return (config: DriverConfig) => new MockDriver(config, mockOptions);
|
|
396
405
|
}
|
|
@@ -31,11 +31,7 @@
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
import type {
|
|
35
|
-
Driver,
|
|
36
|
-
DriverState,
|
|
37
|
-
DriverStreamEvent,
|
|
38
|
-
} from "@agentxjs/core/driver";
|
|
34
|
+
import type { Driver, DriverState, DriverStreamEvent } from "@agentxjs/core/driver";
|
|
39
35
|
import type { UserMessage } from "@agentxjs/core/agent";
|
|
40
36
|
import type { Fixture, FixtureEvent } from "../types";
|
|
41
37
|
import { createLogger } from "commonxjs/logger";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mock/MockDriver.ts"],"sourcesContent":["/**\n * MockDriver - Mock Driver for Testing\n *\n * Plays back recorded fixtures when receiving messages.\n * Implements the new Driver interface with receive() returning AsyncIterable.\n *\n * Usage:\n * ```typescript\n * const driver = new MockDriver({\n * fixture: \"simple-reply\",\n * });\n *\n * await driver.initialize();\n *\n * for await (const event of driver.receive({ content: \"Hello\" })) {\n * if (event.type === \"text_delta\") {\n * console.log(event.data.text);\n * }\n * }\n *\n * await driver.dispose();\n * ```\n */\n\nimport type {\n Driver,\n DriverConfig,\n DriverState,\n DriverStreamEvent,\n} from \"@agentxjs/core/driver\";\nimport type { UserMessage } from \"@agentxjs/core/agent\";\nimport type { Fixture, FixtureEvent, MockDriverOptions } from \"../types\";\nimport { BUILTIN_FIXTURES } from \"../../fixtures\";\nimport { createLogger } from \"commonxjs/logger\";\n\nconst logger = createLogger(\"devtools/MockDriver\");\n\n/**\n * MockDriver - Playback driver for testing\n *\n * Implements the new Driver interface:\n * - receive() returns AsyncIterable<DriverStreamEvent>\n * - Clear input/output boundaries for testing\n */\nexport class MockDriver implements Driver {\n readonly name = \"MockDriver\";\n\n private _sessionId: string | null = null;\n private _state: DriverState = \"idle\";\n\n private readonly config: DriverConfig | null;\n private readonly options: MockDriverOptions;\n private readonly fixtures: Map<string, Fixture>;\n private currentFixture: Fixture;\n\n // For interrupt handling\n private isInterrupted = false;\n\n // Event cursor for multi-turn conversations\n private eventCursor = 0;\n\n /**\n * Create a MockDriver\n *\n * @param options - MockDriverOptions or DriverConfig\n * @param mockOptions - MockDriverOptions if first param is DriverConfig\n */\n constructor(\n optionsOrConfig: MockDriverOptions | DriverConfig,\n mockOptions?: MockDriverOptions\n ) {\n // Detect which constructor form is being used\n if (mockOptions !== undefined || \"apiKey\" in optionsOrConfig) {\n // Factory mode: (DriverConfig, MockDriverOptions)\n this.config = optionsOrConfig as DriverConfig;\n const opts = mockOptions || {};\n this.options = {\n defaultDelay: 10,\n speedMultiplier: 0,\n ...opts,\n };\n } else {\n // Simple mode: (MockDriverOptions)\n this.config = null;\n const opts = optionsOrConfig as MockDriverOptions;\n this.options = {\n defaultDelay: 10,\n speedMultiplier: 0,\n ...opts,\n };\n }\n\n // Initialize fixtures\n this.fixtures = new Map(BUILTIN_FIXTURES);\n if (this.options.fixtures) {\n for (const [name, fixture] of this.options.fixtures) {\n this.fixtures.set(name, fixture);\n }\n }\n\n // Set initial fixture\n this.currentFixture = this.resolveFixture(this.options.fixture || \"simple-reply\");\n\n logger.debug(\"MockDriver created\", {\n fixture: this.currentFixture.name,\n agentId: this.config?.agentId,\n });\n }\n\n // ============================================================================\n // Driver Interface Properties\n // ============================================================================\n\n get sessionId(): string | null {\n return this._sessionId;\n }\n\n get state(): DriverState {\n return this._state;\n }\n\n // ============================================================================\n // Lifecycle Methods\n // ============================================================================\n\n /**\n * Initialize the Driver\n */\n async initialize(): Promise<void> {\n if (this._state !== \"idle\") {\n throw new Error(`Cannot initialize: MockDriver is in \"${this._state}\" state`);\n }\n\n // Generate a mock session ID\n this._sessionId = `mock-session-${Date.now()}`;\n\n logger.debug(\"MockDriver initialized\", {\n sessionId: this._sessionId,\n fixture: this.currentFixture.name,\n });\n }\n\n /**\n * Dispose and cleanup resources\n */\n async dispose(): Promise<void> {\n if (this._state === \"disposed\") {\n return;\n }\n\n this._state = \"disposed\";\n this.isInterrupted = true;\n\n logger.debug(\"MockDriver disposed\");\n }\n\n // ============================================================================\n // Core Methods\n // ============================================================================\n\n /**\n * Receive a user message and return stream of events\n *\n * Plays back the current fixture as DriverStreamEvent.\n *\n * @param message - User message (ignored for playback)\n * @returns AsyncIterable of stream events\n */\n async *receive(_message: UserMessage): AsyncIterable<DriverStreamEvent> {\n if (this._state === \"disposed\") {\n throw new Error(\"Cannot receive: MockDriver is disposed\");\n }\n\n if (this._state === \"active\") {\n throw new Error(\"Cannot receive: MockDriver is already processing a message\");\n }\n\n this._state = \"active\";\n this.isInterrupted = false;\n\n const { speedMultiplier = 0, defaultDelay = 10 } = this.options;\n const events = this.currentFixture.events;\n\n try {\n // Start from cursor position and play until message_stop\n while (this.eventCursor < events.length) {\n const fixtureEvent = events[this.eventCursor];\n this.eventCursor++;\n\n // Check for interrupt\n if (this.isInterrupted) {\n yield {\n type: \"interrupted\",\n timestamp: Date.now(),\n data: { reason: \"user\" },\n };\n break;\n }\n\n // Apply delay\n const delay = fixtureEvent.delay || defaultDelay;\n if (delay > 0 && speedMultiplier > 0) {\n await this.sleep(delay * speedMultiplier);\n }\n\n // Convert and yield event\n const event = this.convertFixtureEvent(fixtureEvent);\n if (event) {\n yield event;\n }\n\n // Stop at message_stop (end of one turn)\n if (fixtureEvent.type === \"message_stop\") {\n break;\n }\n }\n } finally {\n this._state = \"idle\";\n }\n }\n\n /**\n * Interrupt current operation\n */\n interrupt(): void {\n if (this._state !== \"active\") {\n logger.debug(\"Interrupt called but no active operation\");\n return;\n }\n\n logger.debug(\"MockDriver interrupted\");\n this.isInterrupted = true;\n }\n\n // ============================================================================\n // Fixture Management\n // ============================================================================\n\n /**\n * Set the fixture to use for next playback\n */\n setFixture(fixture: string | Fixture): void {\n this.currentFixture = this.resolveFixture(fixture);\n this.eventCursor = 0; // Reset cursor when fixture changes\n logger.debug(\"Fixture changed\", { fixture: this.currentFixture.name });\n }\n\n /**\n * Add a custom fixture\n */\n addFixture(fixture: Fixture): void {\n this.fixtures.set(fixture.name, fixture);\n }\n\n /**\n * Get the current fixture\n */\n getFixture(): Fixture {\n return this.currentFixture;\n }\n\n /**\n * Get available fixture names\n */\n getFixtureNames(): string[] {\n return Array.from(this.fixtures.keys());\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Resolve fixture from name or Fixture object\n */\n private resolveFixture(fixture: string | Fixture): Fixture {\n if (typeof fixture === \"string\") {\n const found = this.fixtures.get(fixture);\n if (!found) {\n logger.warn(`Fixture \"${fixture}\" not found, using \"simple-reply\"`);\n return this.fixtures.get(\"simple-reply\")!;\n }\n return found;\n }\n return fixture;\n }\n\n /**\n * Convert FixtureEvent to DriverStreamEvent\n */\n private convertFixtureEvent(fixtureEvent: FixtureEvent): DriverStreamEvent | null {\n const timestamp = Date.now();\n const data = fixtureEvent.data as Record<string, unknown>;\n\n switch (fixtureEvent.type) {\n case \"message_start\":\n return {\n type: \"message_start\",\n timestamp,\n data: {\n messageId: (data.messageId as string) || `msg_${timestamp}`,\n model: (data.model as string) || \"mock-model\",\n },\n };\n\n case \"text_delta\":\n return {\n type: \"text_delta\",\n timestamp,\n data: { text: (data.text as string) || \"\" },\n };\n\n case \"tool_use_start\":\n return {\n type: \"tool_use_start\",\n timestamp,\n data: {\n toolCallId: (data.toolCallId as string) || `tool_${timestamp}`,\n toolName: (data.toolName as string) || \"\",\n },\n };\n\n case \"input_json_delta\":\n return {\n type: \"input_json_delta\",\n timestamp,\n data: { partialJson: (data.partialJson as string) || \"\" },\n };\n\n case \"tool_use_stop\":\n return {\n type: \"tool_use_stop\",\n timestamp,\n data: {\n toolCallId: (data.toolCallId as string) || \"\",\n toolName: (data.toolName as string) || \"\",\n input: (data.input as Record<string, unknown>) || {},\n },\n };\n\n case \"tool_result\":\n return {\n type: \"tool_result\",\n timestamp,\n data: {\n toolCallId: (data.toolCallId as string) || \"\",\n result: data.result,\n isError: data.isError as boolean | undefined,\n },\n };\n\n case \"message_stop\":\n return {\n type: \"message_stop\",\n timestamp,\n data: {\n stopReason: (data.stopReason as \"end_turn\" | \"tool_use\" | \"max_tokens\" | \"stop_sequence\" | \"other\") || \"end_turn\",\n },\n };\n\n case \"error\":\n return {\n type: \"error\",\n timestamp,\n data: {\n message: (data.message as string) || \"Unknown error\",\n errorCode: (data.errorCode as string) || \"mock_error\",\n },\n };\n\n default:\n // Pass through unknown events with generic structure\n logger.debug(`Unknown fixture event type: ${fixtureEvent.type}`);\n return null;\n }\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Create a MockDriver factory function\n *\n * Returns a CreateDriver-compatible function.\n *\n * @param mockOptions - Options for all created drivers\n * @returns CreateDriver function\n */\nexport function createMockDriver(mockOptions: MockDriverOptions = {}): (config: DriverConfig) => Driver {\n return (config: DriverConfig) => new MockDriver(config, mockOptions);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/recorder/RecordingDriver.ts"],"sourcesContent":["/**\n * RecordingDriver - Wraps a real driver to record events\n *\n * Used to capture real LLM API responses and save them as fixtures.\n * These fixtures can then be played back by MockDriver for testing.\n *\n * Usage:\n * ```typescript\n * import { createClaudeDriver } from \"@agentxjs/claude-driver\";\n * import { RecordingDriver } from \"@agentxjs/devtools/recorder\";\n *\n * // Create real driver\n * const realDriver = createClaudeDriver(config);\n *\n * // Wrap with recorder\n * const recorder = new RecordingDriver({\n * driver: realDriver,\n * name: \"my-scenario\",\n * description: \"User asks about weather\",\n * });\n *\n * await recorder.initialize();\n *\n * // Use like a normal driver - events are recorded\n * for await (const event of recorder.receive({ content: \"Hello\" })) {\n * console.log(event);\n * }\n *\n * // Save the fixture\n * await recorder.saveFixture(\"./fixtures/my-scenario.json\");\n * ```\n */\n\nimport type {\n Driver,\n DriverState,\n DriverStreamEvent,\n} from \"@agentxjs/core/driver\";\nimport type { UserMessage } from \"@agentxjs/core/agent\";\nimport type { Fixture, FixtureEvent } from \"../types\";\nimport { createLogger } from \"commonxjs/logger\";\n\nconst logger = createLogger(\"devtools/RecordingDriver\");\n\n/**\n * Options for RecordingDriver\n */\nexport interface RecordingDriverOptions {\n /**\n * The real driver to wrap\n */\n driver: Driver;\n\n /**\n * Fixture name for the recording\n */\n name: string;\n\n /**\n * Description for the recording\n */\n description?: string;\n}\n\n/**\n * Recorded event with timing\n */\ninterface RecordedEvent {\n event: DriverStreamEvent;\n timestamp: number;\n}\n\n/**\n * RecordingDriver - Records events from a real driver\n *\n * Implements the new Driver interface by wrapping a real driver\n * and intercepting events from receive().\n */\nexport class RecordingDriver implements Driver {\n readonly name = \"RecordingDriver\";\n\n private readonly realDriver: Driver;\n private readonly fixtureName: string;\n private readonly fixtureDescription?: string;\n\n private recordedEvents: RecordedEvent[] = [];\n private recordingStartTime: number = 0;\n\n constructor(options: RecordingDriverOptions) {\n this.realDriver = options.driver;\n this.fixtureName = options.name;\n this.fixtureDescription = options.description;\n\n logger.info(\"RecordingDriver created\", { name: this.fixtureName });\n }\n\n // ============================================================================\n // Driver Interface Properties (delegate to real driver)\n // ============================================================================\n\n get sessionId(): string | null {\n return this.realDriver.sessionId;\n }\n\n get state(): DriverState {\n return this.realDriver.state;\n }\n\n // ============================================================================\n // Lifecycle Methods (delegate to real driver)\n // ============================================================================\n\n async initialize(): Promise<void> {\n await this.realDriver.initialize();\n this.recordingStartTime = Date.now();\n this.recordedEvents = [];\n logger.info(\"RecordingDriver initialized, recording started\", {\n name: this.fixtureName,\n });\n }\n\n async dispose(): Promise<void> {\n await this.realDriver.dispose();\n logger.info(\"RecordingDriver disposed\", {\n name: this.fixtureName,\n eventsRecorded: this.recordedEvents.length,\n });\n }\n\n // ============================================================================\n // Core Methods\n // ============================================================================\n\n /**\n * Receive a user message and return stream of events\n *\n * Wraps the real driver's receive() and records all events.\n */\n async *receive(message: UserMessage): AsyncIterable<DriverStreamEvent> {\n logger.debug(\"RecordingDriver receiving message\", {\n name: this.fixtureName,\n });\n\n // Call the real driver and intercept events\n for await (const event of this.realDriver.receive(message)) {\n // Record the event\n this.recordEvent(event);\n\n // Pass through to caller\n yield event;\n }\n\n logger.debug(\"RecordingDriver receive completed\", {\n name: this.fixtureName,\n eventsRecorded: this.recordedEvents.length,\n });\n }\n\n /**\n * Interrupt current operation (delegate to real driver)\n */\n interrupt(): void {\n this.realDriver.interrupt();\n }\n\n // ============================================================================\n // Recording Methods\n // ============================================================================\n\n /**\n * Record an event\n */\n private recordEvent(event: DriverStreamEvent): void {\n this.recordedEvents.push({\n event,\n timestamp: Date.now(),\n });\n\n logger.debug(\"Event recorded\", {\n type: event.type,\n totalEvents: this.recordedEvents.length,\n });\n }\n\n /**\n * Get the recorded fixture\n */\n getFixture(): Fixture {\n const events: FixtureEvent[] = [];\n let lastTimestamp = this.recordingStartTime;\n\n for (const recorded of this.recordedEvents) {\n const delay = recorded.timestamp - lastTimestamp;\n lastTimestamp = recorded.timestamp;\n\n events.push({\n type: recorded.event.type,\n delay: Math.max(0, delay),\n data: recorded.event.data,\n });\n }\n\n return {\n name: this.fixtureName,\n description: this.fixtureDescription,\n recordedAt: this.recordingStartTime,\n events,\n };\n }\n\n /**\n * Save the recorded fixture to a JSON file\n */\n async saveFixture(filePath: string): Promise<void> {\n const fixture = this.getFixture();\n const json = JSON.stringify(fixture, null, 2);\n\n // Use dynamic import for Node.js fs\n const { writeFile } = await import(\"node:fs/promises\");\n await writeFile(filePath, json, \"utf-8\");\n\n logger.info(\"Fixture saved\", {\n path: filePath,\n name: fixture.name,\n eventCount: fixture.events.length,\n });\n }\n\n /**\n * Get the number of recorded events\n */\n get eventCount(): number {\n return this.recordedEvents.length;\n }\n\n /**\n * Clear recorded events (start fresh recording)\n */\n clearRecording(): void {\n this.recordedEvents = [];\n this.recordingStartTime = Date.now();\n logger.debug(\"Recording cleared\");\n }\n\n /**\n * Get raw recorded events (for debugging)\n */\n getRawEvents(): RecordedEvent[] {\n return [...this.recordedEvents];\n }\n}\n\n/**\n * Create a RecordingDriver that wraps a real driver\n */\nexport function createRecordingDriver(options: RecordingDriverOptions): RecordingDriver {\n return new RecordingDriver(options);\n}\n"],"mappings":"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","names":[]}
|