@modular-prompt/driver 0.4.5
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/LICENSE +21 -0
- package/README.md +597 -0
- package/dist/anthropic/anthropic-driver.d.ts +47 -0
- package/dist/anthropic/anthropic-driver.d.ts.map +1 -0
- package/dist/anthropic/anthropic-driver.js +217 -0
- package/dist/anthropic/anthropic-driver.js.map +1 -0
- package/dist/driver-registry/ai-service.d.ts +43 -0
- package/dist/driver-registry/ai-service.d.ts.map +1 -0
- package/dist/driver-registry/ai-service.js +77 -0
- package/dist/driver-registry/ai-service.js.map +1 -0
- package/dist/driver-registry/config-based-factory.d.ts +64 -0
- package/dist/driver-registry/config-based-factory.d.ts.map +1 -0
- package/dist/driver-registry/config-based-factory.js +90 -0
- package/dist/driver-registry/config-based-factory.js.map +1 -0
- package/dist/driver-registry/factory-helper.d.ts +49 -0
- package/dist/driver-registry/factory-helper.d.ts.map +1 -0
- package/dist/driver-registry/factory-helper.js +109 -0
- package/dist/driver-registry/factory-helper.js.map +1 -0
- package/dist/driver-registry/index.d.ts +9 -0
- package/dist/driver-registry/index.d.ts.map +1 -0
- package/dist/driver-registry/index.js +8 -0
- package/dist/driver-registry/index.js.map +1 -0
- package/dist/driver-registry/registry.d.ts +50 -0
- package/dist/driver-registry/registry.d.ts.map +1 -0
- package/dist/driver-registry/registry.js +208 -0
- package/dist/driver-registry/registry.js.map +1 -0
- package/dist/driver-registry/types.d.ts +108 -0
- package/dist/driver-registry/types.d.ts.map +1 -0
- package/dist/driver-registry/types.js +6 -0
- package/dist/driver-registry/types.js.map +1 -0
- package/dist/echo-driver.d.ts +88 -0
- package/dist/echo-driver.d.ts.map +1 -0
- package/dist/echo-driver.js +198 -0
- package/dist/echo-driver.js.map +1 -0
- package/dist/formatter/completion-formatter.d.ts +27 -0
- package/dist/formatter/completion-formatter.d.ts.map +1 -0
- package/dist/formatter/completion-formatter.js +84 -0
- package/dist/formatter/completion-formatter.js.map +1 -0
- package/dist/formatter/converter.d.ts +20 -0
- package/dist/formatter/converter.d.ts.map +1 -0
- package/dist/formatter/converter.js +176 -0
- package/dist/formatter/converter.js.map +1 -0
- package/dist/formatter/element-formatters/base.d.ts +34 -0
- package/dist/formatter/element-formatters/base.d.ts.map +1 -0
- package/dist/formatter/element-formatters/base.js +36 -0
- package/dist/formatter/element-formatters/base.js.map +1 -0
- package/dist/formatter/element-formatters/chunk.d.ts +11 -0
- package/dist/formatter/element-formatters/chunk.d.ts.map +1 -0
- package/dist/formatter/element-formatters/chunk.js +12 -0
- package/dist/formatter/element-formatters/chunk.js.map +1 -0
- package/dist/formatter/element-formatters/index.d.ts +14 -0
- package/dist/formatter/element-formatters/index.d.ts.map +1 -0
- package/dist/formatter/element-formatters/index.js +15 -0
- package/dist/formatter/element-formatters/index.js.map +1 -0
- package/dist/formatter/element-formatters/json.d.ts +11 -0
- package/dist/formatter/element-formatters/json.d.ts.map +1 -0
- package/dist/formatter/element-formatters/json.js +27 -0
- package/dist/formatter/element-formatters/json.js.map +1 -0
- package/dist/formatter/element-formatters/material.d.ts +11 -0
- package/dist/formatter/element-formatters/material.d.ts.map +1 -0
- package/dist/formatter/element-formatters/material.js +35 -0
- package/dist/formatter/element-formatters/material.js.map +1 -0
- package/dist/formatter/element-formatters/message.d.ts +13 -0
- package/dist/formatter/element-formatters/message.d.ts.map +1 -0
- package/dist/formatter/element-formatters/message.js +35 -0
- package/dist/formatter/element-formatters/message.js.map +1 -0
- package/dist/formatter/element-formatters/registry.d.ts +29 -0
- package/dist/formatter/element-formatters/registry.d.ts.map +1 -0
- package/dist/formatter/element-formatters/registry.js +82 -0
- package/dist/formatter/element-formatters/registry.js.map +1 -0
- package/dist/formatter/element-formatters/section.d.ts +18 -0
- package/dist/formatter/element-formatters/section.d.ts.map +1 -0
- package/dist/formatter/element-formatters/section.js +46 -0
- package/dist/formatter/element-formatters/section.js.map +1 -0
- package/dist/formatter/element-formatters/string-pattern.d.ts +22 -0
- package/dist/formatter/element-formatters/string-pattern.d.ts.map +1 -0
- package/dist/formatter/element-formatters/string-pattern.js +124 -0
- package/dist/formatter/element-formatters/string-pattern.js.map +1 -0
- package/dist/formatter/element-formatters/text.d.ts +11 -0
- package/dist/formatter/element-formatters/text.d.ts.map +1 -0
- package/dist/formatter/element-formatters/text.js +11 -0
- package/dist/formatter/element-formatters/text.js.map +1 -0
- package/dist/formatter/formatter.d.ts +24 -0
- package/dist/formatter/formatter.d.ts.map +1 -0
- package/dist/formatter/formatter.js +252 -0
- package/dist/formatter/formatter.js.map +1 -0
- package/dist/formatter/types.d.ts +91 -0
- package/dist/formatter/types.d.ts.map +1 -0
- package/dist/formatter/types.js +2 -0
- package/dist/formatter/types.js.map +1 -0
- package/dist/google-genai/google-genai-driver.d.ts +67 -0
- package/dist/google-genai/google-genai-driver.d.ts.map +1 -0
- package/dist/google-genai/google-genai-driver.js +351 -0
- package/dist/google-genai/google-genai-driver.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mlx-ml/mlx-driver.d.ts +65 -0
- package/dist/mlx-ml/mlx-driver.d.ts.map +1 -0
- package/dist/mlx-ml/mlx-driver.js +235 -0
- package/dist/mlx-ml/mlx-driver.js.map +1 -0
- package/dist/mlx-ml/model-spec/index.d.ts +7 -0
- package/dist/mlx-ml/model-spec/index.d.ts.map +1 -0
- package/dist/mlx-ml/model-spec/index.js +7 -0
- package/dist/mlx-ml/model-spec/index.js.map +1 -0
- package/dist/mlx-ml/model-spec/types.d.ts +30 -0
- package/dist/mlx-ml/model-spec/types.d.ts.map +1 -0
- package/dist/mlx-ml/model-spec/types.js +7 -0
- package/dist/mlx-ml/model-spec/types.js.map +1 -0
- package/dist/mlx-ml/process/index.d.ts +33 -0
- package/dist/mlx-ml/process/index.d.ts.map +1 -0
- package/dist/mlx-ml/process/index.js +65 -0
- package/dist/mlx-ml/process/index.js.map +1 -0
- package/dist/mlx-ml/process/model-handlers.d.ts +58 -0
- package/dist/mlx-ml/process/model-handlers.d.ts.map +1 -0
- package/dist/mlx-ml/process/model-handlers.js +197 -0
- package/dist/mlx-ml/process/model-handlers.js.map +1 -0
- package/dist/mlx-ml/process/model-specific.d.ts +35 -0
- package/dist/mlx-ml/process/model-specific.d.ts.map +1 -0
- package/dist/mlx-ml/process/model-specific.js +35 -0
- package/dist/mlx-ml/process/model-specific.js.map +1 -0
- package/dist/mlx-ml/process/parameter-mapper.d.ts +17 -0
- package/dist/mlx-ml/process/parameter-mapper.d.ts.map +1 -0
- package/dist/mlx-ml/process/parameter-mapper.js +91 -0
- package/dist/mlx-ml/process/parameter-mapper.js.map +1 -0
- package/dist/mlx-ml/process/parameter-validator.d.ts +55 -0
- package/dist/mlx-ml/process/parameter-validator.d.ts.map +1 -0
- package/dist/mlx-ml/process/parameter-validator.js +203 -0
- package/dist/mlx-ml/process/parameter-validator.js.map +1 -0
- package/dist/mlx-ml/process/process-communication.d.ts +25 -0
- package/dist/mlx-ml/process/process-communication.d.ts.map +1 -0
- package/dist/mlx-ml/process/process-communication.js +117 -0
- package/dist/mlx-ml/process/process-communication.js.map +1 -0
- package/dist/mlx-ml/process/queue.d.ts +30 -0
- package/dist/mlx-ml/process/queue.d.ts.map +1 -0
- package/dist/mlx-ml/process/queue.js +147 -0
- package/dist/mlx-ml/process/queue.js.map +1 -0
- package/dist/mlx-ml/process/types.d.ts +97 -0
- package/dist/mlx-ml/process/types.d.ts.map +1 -0
- package/dist/mlx-ml/process/types.js +2 -0
- package/dist/mlx-ml/process/types.js.map +1 -0
- package/dist/mlx-ml/types.d.ts +66 -0
- package/dist/mlx-ml/types.d.ts.map +1 -0
- package/dist/mlx-ml/types.js +7 -0
- package/dist/mlx-ml/types.js.map +1 -0
- package/dist/ollama/ollama-driver.d.ts +15 -0
- package/dist/ollama/ollama-driver.d.ts.map +1 -0
- package/dist/ollama/ollama-driver.js +15 -0
- package/dist/ollama/ollama-driver.js.map +1 -0
- package/dist/openai/openai-driver.d.ts +71 -0
- package/dist/openai/openai-driver.d.ts.map +1 -0
- package/dist/openai/openai-driver.js +230 -0
- package/dist/openai/openai-driver.js.map +1 -0
- package/dist/test-driver.d.ts +78 -0
- package/dist/test-driver.d.ts.map +1 -0
- package/dist/test-driver.js +193 -0
- package/dist/test-driver.js.map +1 -0
- package/dist/types.d.ts +90 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/vertexai/vertexai-driver.d.ts +63 -0
- package/dist/vertexai/vertexai-driver.d.ts.map +1 -0
- package/dist/vertexai/vertexai-driver.js +335 -0
- package/dist/vertexai/vertexai-driver.js.map +1 -0
- package/package.json +61 -0
- package/scripts/download-model.js +40 -0
- package/scripts/setup-mlx.js +53 -0
- package/src/mlx-ml/python/.python-version +1 -0
- package/src/mlx-ml/python/__main__.py +312 -0
- package/src/mlx-ml/python/chat_template_constraints.py +164 -0
- package/src/mlx-ml/python/pyproject.toml +19 -0
- package/src/mlx-ml/python/token_utils.py +262 -0
- package/src/mlx-ml/python/uv.lock +1029 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { CompiledPrompt } from '@modular-prompt/core';
|
|
2
|
+
import type { AIDriver, QueryOptions, QueryResult, StreamResult } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAI driver configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface OpenAIDriverConfig {
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
baseURL?: string;
|
|
9
|
+
model?: string;
|
|
10
|
+
organization?: string;
|
|
11
|
+
defaultOptions?: Partial<OpenAIQueryOptions>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* OpenAI-specific query options
|
|
15
|
+
*/
|
|
16
|
+
export interface OpenAIQueryOptions extends QueryOptions {
|
|
17
|
+
model?: string;
|
|
18
|
+
temperature?: number;
|
|
19
|
+
maxTokens?: number;
|
|
20
|
+
topP?: number;
|
|
21
|
+
frequencyPenalty?: number;
|
|
22
|
+
presencePenalty?: number;
|
|
23
|
+
stop?: string | string[];
|
|
24
|
+
n?: number;
|
|
25
|
+
logprobs?: boolean;
|
|
26
|
+
topLogprobs?: number;
|
|
27
|
+
responseFormat?: {
|
|
28
|
+
type: 'json_object' | 'text';
|
|
29
|
+
};
|
|
30
|
+
seed?: number;
|
|
31
|
+
tools?: Array<{
|
|
32
|
+
type: 'function';
|
|
33
|
+
function: {
|
|
34
|
+
name: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
parameters?: Record<string, unknown>;
|
|
37
|
+
};
|
|
38
|
+
}>;
|
|
39
|
+
toolChoice?: 'none' | 'auto' | {
|
|
40
|
+
type: 'function';
|
|
41
|
+
function: {
|
|
42
|
+
name: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* OpenAI API driver
|
|
48
|
+
*/
|
|
49
|
+
export declare class OpenAIDriver implements AIDriver {
|
|
50
|
+
private client;
|
|
51
|
+
private defaultModel;
|
|
52
|
+
private defaultOptions;
|
|
53
|
+
constructor(config?: OpenAIDriverConfig);
|
|
54
|
+
/**
|
|
55
|
+
* Convert CompiledPrompt to OpenAI messages
|
|
56
|
+
*/
|
|
57
|
+
private compiledPromptToMessages;
|
|
58
|
+
/**
|
|
59
|
+
* Query the AI model
|
|
60
|
+
*/
|
|
61
|
+
query(prompt: CompiledPrompt, options?: QueryOptions): Promise<QueryResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Stream query implementation with both stream and result
|
|
64
|
+
*/
|
|
65
|
+
streamQuery(prompt: CompiledPrompt, options?: QueryOptions): Promise<StreamResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Close the client
|
|
68
|
+
*/
|
|
69
|
+
close(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=openai-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-driver.d.ts","sourceRoot":"","sources":["../../src/openai/openai-driver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMrF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE;QAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAAA;KAAE,CAAC;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACtC,CAAC;KACH,CAAC,CAAC;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACjF;AAED;;GAEG;AACH,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAA8B;gBAExC,MAAM,GAAE,kBAAuB;IAW3C;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8EhC;;OAEG;IACG,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAMjF;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IA4HxF;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI API driver
|
|
4
|
+
*/
|
|
5
|
+
export class OpenAIDriver {
|
|
6
|
+
client;
|
|
7
|
+
defaultModel;
|
|
8
|
+
defaultOptions;
|
|
9
|
+
constructor(config = {}) {
|
|
10
|
+
this.client = new OpenAI({
|
|
11
|
+
apiKey: config.apiKey || process.env.OPENAI_API_KEY,
|
|
12
|
+
baseURL: config.baseURL,
|
|
13
|
+
organization: config.organization
|
|
14
|
+
});
|
|
15
|
+
this.defaultModel = config.model || 'gpt-4o-mini';
|
|
16
|
+
this.defaultOptions = config.defaultOptions || {};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert CompiledPrompt to OpenAI messages
|
|
20
|
+
*/
|
|
21
|
+
compiledPromptToMessages(prompt) {
|
|
22
|
+
const messages = [];
|
|
23
|
+
// Helper to process elements
|
|
24
|
+
const processElements = (elements) => {
|
|
25
|
+
const content = [];
|
|
26
|
+
for (const element of elements) {
|
|
27
|
+
if (typeof element === 'string') {
|
|
28
|
+
content.push(element);
|
|
29
|
+
}
|
|
30
|
+
else if (typeof element === 'object' && element !== null && 'type' in element) {
|
|
31
|
+
const el = element;
|
|
32
|
+
if (el.type === 'text') {
|
|
33
|
+
content.push(el.content);
|
|
34
|
+
}
|
|
35
|
+
else if (el.type === 'message') {
|
|
36
|
+
// Handle message elements separately
|
|
37
|
+
messages.push({
|
|
38
|
+
role: el.role,
|
|
39
|
+
content: typeof el.content === 'string' ? el.content : JSON.stringify(el.content)
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else if (el.type === 'section' || el.type === 'subsection') {
|
|
43
|
+
// Process section content
|
|
44
|
+
if (el.title)
|
|
45
|
+
content.push(`## ${el.title}`);
|
|
46
|
+
if (el.items) {
|
|
47
|
+
for (const item of el.items) {
|
|
48
|
+
if (typeof item === 'string') {
|
|
49
|
+
content.push(item);
|
|
50
|
+
}
|
|
51
|
+
else if (typeof item === 'object' && item !== null && 'type' in item && item.type === 'subsection') {
|
|
52
|
+
if (item.title)
|
|
53
|
+
content.push(`### ${item.title}`);
|
|
54
|
+
if ('items' in item && item.items) {
|
|
55
|
+
content.push(...item.items.filter((i) => typeof i === 'string'));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Default formatting for other elements
|
|
63
|
+
content.push(JSON.stringify(el));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return content.join('\n');
|
|
68
|
+
};
|
|
69
|
+
// Process instructions as system message
|
|
70
|
+
if (prompt.instructions && prompt.instructions.length > 0) {
|
|
71
|
+
const instructionContent = processElements(prompt.instructions);
|
|
72
|
+
if (instructionContent) {
|
|
73
|
+
messages.push({ role: 'system', content: instructionContent });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Process data as user message
|
|
77
|
+
if (prompt.data && prompt.data.length > 0) {
|
|
78
|
+
const dataContent = processElements(prompt.data);
|
|
79
|
+
if (dataContent) {
|
|
80
|
+
messages.push({ role: 'user', content: dataContent });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Process output as user message (continuation)
|
|
84
|
+
if (prompt.output && prompt.output.length > 0) {
|
|
85
|
+
const outputContent = processElements(prompt.output);
|
|
86
|
+
if (outputContent) {
|
|
87
|
+
messages.push({ role: 'user', content: outputContent });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Ensure at least one message
|
|
91
|
+
if (messages.length === 0) {
|
|
92
|
+
messages.push({ role: 'user', content: 'Please respond.' });
|
|
93
|
+
}
|
|
94
|
+
return messages;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Query the AI model
|
|
98
|
+
*/
|
|
99
|
+
async query(prompt, options) {
|
|
100
|
+
// Use streamQuery for consistency
|
|
101
|
+
const { result } = await this.streamQuery(prompt, options);
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Stream query implementation with both stream and result
|
|
106
|
+
*/
|
|
107
|
+
async streamQuery(prompt, options) {
|
|
108
|
+
try {
|
|
109
|
+
const openaiOptions = options || {};
|
|
110
|
+
const mergedOptions = { ...this.defaultOptions, ...openaiOptions };
|
|
111
|
+
const messages = this.compiledPromptToMessages(prompt);
|
|
112
|
+
const params = {
|
|
113
|
+
model: mergedOptions.model || this.defaultModel,
|
|
114
|
+
messages,
|
|
115
|
+
temperature: mergedOptions.temperature,
|
|
116
|
+
max_tokens: mergedOptions.maxTokens,
|
|
117
|
+
top_p: mergedOptions.topP,
|
|
118
|
+
frequency_penalty: mergedOptions.frequencyPenalty,
|
|
119
|
+
presence_penalty: mergedOptions.presencePenalty,
|
|
120
|
+
stop: mergedOptions.stop,
|
|
121
|
+
response_format: prompt.metadata?.outputSchema ? { type: 'json_object' } : undefined,
|
|
122
|
+
stream: true
|
|
123
|
+
};
|
|
124
|
+
// Remove undefined values
|
|
125
|
+
Object.keys(params).forEach(key => {
|
|
126
|
+
if (params[key] === undefined) {
|
|
127
|
+
delete params[key];
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
const openaiStream = await this.client.chat.completions.create(params);
|
|
131
|
+
// Shared state for accumulating content and metadata
|
|
132
|
+
let fullContent = '';
|
|
133
|
+
let usage;
|
|
134
|
+
let finishReason = 'stop';
|
|
135
|
+
let streamConsumed = false;
|
|
136
|
+
const chunks = [];
|
|
137
|
+
// Process the OpenAI stream and cache chunks
|
|
138
|
+
const processStream = async () => {
|
|
139
|
+
try {
|
|
140
|
+
for await (const chunk of openaiStream) {
|
|
141
|
+
const content = chunk.choices[0]?.delta?.content;
|
|
142
|
+
if (content) {
|
|
143
|
+
fullContent += content;
|
|
144
|
+
chunks.push(content);
|
|
145
|
+
}
|
|
146
|
+
// Update finish reason if provided
|
|
147
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
148
|
+
const reason = chunk.choices[0].finish_reason;
|
|
149
|
+
if (reason === 'length') {
|
|
150
|
+
finishReason = 'length';
|
|
151
|
+
}
|
|
152
|
+
else if (reason === 'content_filter') {
|
|
153
|
+
finishReason = 'error';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Accumulate usage if provided (usually in the final chunk)
|
|
157
|
+
if (chunk.usage) {
|
|
158
|
+
usage = {
|
|
159
|
+
promptTokens: chunk.usage.prompt_tokens,
|
|
160
|
+
completionTokens: chunk.usage.completion_tokens,
|
|
161
|
+
totalTokens: chunk.usage.total_tokens
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
finishReason = 'error';
|
|
168
|
+
}
|
|
169
|
+
streamConsumed = true;
|
|
170
|
+
};
|
|
171
|
+
// Start processing the stream
|
|
172
|
+
const processingPromise = processStream();
|
|
173
|
+
// Create the stream generator that yields cached chunks
|
|
174
|
+
const streamGenerator = async function* () {
|
|
175
|
+
let index = 0;
|
|
176
|
+
while (!streamConsumed || index < chunks.length) {
|
|
177
|
+
if (index < chunks.length) {
|
|
178
|
+
yield chunks[index++];
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// Wait a bit for more chunks
|
|
182
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
// Create result promise
|
|
187
|
+
const resultPromise = processingPromise.then(() => {
|
|
188
|
+
// If response_format was used, the content should already be JSON
|
|
189
|
+
let structuredOutput;
|
|
190
|
+
if (prompt.metadata?.outputSchema && params.response_format?.type === 'json_object') {
|
|
191
|
+
try {
|
|
192
|
+
structuredOutput = JSON.parse(fullContent);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Keep as undefined if parsing fails
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
content: fullContent,
|
|
200
|
+
structuredOutput,
|
|
201
|
+
usage,
|
|
202
|
+
finishReason
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
stream: streamGenerator(),
|
|
207
|
+
result: resultPromise
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Return error state
|
|
212
|
+
return {
|
|
213
|
+
stream: (async function* () {
|
|
214
|
+
// Empty stream
|
|
215
|
+
})(),
|
|
216
|
+
result: Promise.resolve({
|
|
217
|
+
content: '',
|
|
218
|
+
finishReason: 'error'
|
|
219
|
+
})
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Close the client
|
|
225
|
+
*/
|
|
226
|
+
async close() {
|
|
227
|
+
// OpenAI client doesn't need explicit closing
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=openai-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-driver.js","sourceRoot":"","sources":["../../src/openai/openai-driver.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AA8C5B;;GAEG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,CAAS;IACf,YAAY,CAAS;IACrB,cAAc,CAA8B;IAEpD,YAAY,SAA6B,EAAE;QACzC,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;YACnD,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,KAAK,IAAI,aAAa,CAAC;QAClD,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;IACpD,CAAC;IAED;;OAEG;IACK,wBAAwB,CAAC,MAAsB;QACrD,MAAM,QAAQ,GAAiC,EAAE,CAAC;QAElD,6BAA6B;QAC7B,MAAM,eAAe,GAAG,CAAC,QAAmB,EAAE,EAAE;YAC9C,MAAM,OAAO,GAAa,EAAE,CAAC;YAE7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;oBAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACxB,CAAC;qBAAM,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;oBAChF,MAAM,EAAE,GAAG,OAAkB,CAAC;oBAE9B,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;wBACvB,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;oBAC3B,CAAC;yBAAM,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;wBACjC,qCAAqC;wBACrC,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,EAAE,CAAC,IAAuC;4BAChD,OAAO,EAAE,OAAO,EAAE,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC;yBAClF,CAAC,CAAC;oBACL,CAAC;yBAAM,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBAC7D,0BAA0B;wBAC1B,IAAI,EAAE,CAAC,KAAK;4BAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;wBAC7C,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;4BACb,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;gCAC5B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oCAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gCACrB,CAAC;qCAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oCACrG,IAAI,IAAI,CAAC,KAAK;wCAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;oCAClD,IAAI,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;wCAClC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;oCACnE,CAAC;gCACH,CAAC;4BACH,CAAC;wBACH,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,wCAAwC;wBACxC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC;QAEF,yCAAyC;QACzC,IAAI,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1D,MAAM,kBAAkB,GAAG,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAChE,IAAI,kBAAkB,EAAE,CAAC;gBACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,WAAW,EAAE,CAAC;gBAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAED,gDAAgD;QAChD,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,aAAa,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,MAAsB,EAAE,OAAsB;QACxD,kCAAkC;QAClC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,MAAsB,EAAE,OAAsB;QAC9D,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,OAA6B,IAAI,EAAE,CAAC;YAC1D,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,GAAG,aAAa,EAAE,CAAC;YACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC;YAEvD,MAAM,MAAM,GAA+B;gBACzC,KAAK,EAAE,aAAa,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY;gBAC/C,QAAQ;gBACR,WAAW,EAAE,aAAa,CAAC,WAAW;gBACtC,UAAU,EAAE,aAAa,CAAC,SAAS;gBACnC,KAAK,EAAE,aAAa,CAAC,IAAI;gBACzB,iBAAiB,EAAE,aAAa,CAAC,gBAAgB;gBACjD,gBAAgB,EAAE,aAAa,CAAC,eAAe;gBAC/C,IAAI,EAAE,aAAa,CAAC,IAAI;gBACxB,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS;gBACpF,MAAM,EAAE,IAAI;aACb,CAAC;YAEF,0BAA0B;YAC1B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;gBAChC,IAAI,MAAM,CAAC,GAA0B,CAAC,KAAK,SAAS,EAAE,CAAC;oBACrD,OAAO,MAAM,CAAC,GAA0B,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAEvE,qDAAqD;YACrD,IAAI,WAAW,GAAG,EAAE,CAAC;YACrB,IAAI,KAAuC,CAAC;YAC5C,IAAI,YAAY,GAAgC,MAAM,CAAC;YACvD,IAAI,cAAc,GAAG,KAAK,CAAC;YAC3B,MAAM,MAAM,GAAa,EAAE,CAAC;YAE5B,6CAA6C;YAC7C,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;gBAC/B,IAAI,CAAC;oBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;wBACvC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC;wBACjD,IAAI,OAAO,EAAE,CAAC;4BACZ,WAAW,IAAI,OAAO,CAAC;4BACvB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACvB,CAAC;wBAED,mCAAmC;wBACnC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC;4BACpC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;4BAC9C,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gCACxB,YAAY,GAAG,QAAQ,CAAC;4BAC1B,CAAC;iCAAM,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;gCACvC,YAAY,GAAG,OAAO,CAAC;4BACzB,CAAC;wBACH,CAAC;wBAED,4DAA4D;wBAC5D,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;4BAChB,KAAK,GAAG;gCACN,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa;gCACvC,gBAAgB,EAAE,KAAK,CAAC,KAAK,CAAC,iBAAiB;gCAC/C,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;6BACtC,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,YAAY,GAAG,OAAO,CAAC;gBACzB,CAAC;gBACD,cAAc,GAAG,IAAI,CAAC;YACxB,CAAC,CAAC;YAEF,8BAA8B;YAC9B,MAAM,iBAAiB,GAAG,aAAa,EAAE,CAAC;YAE1C,wDAAwD;YACxD,MAAM,eAAe,GAAG,KAAK,SAAS,CAAC;gBACrC,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,OAAO,CAAC,cAAc,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;oBAChD,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;wBAC1B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;oBACxB,CAAC;yBAAM,CAAC;wBACN,6BAA6B;wBAC7B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;oBACxD,CAAC;gBACH,CAAC;YACH,CAAC,CAAC;YAEF,wBAAwB;YACxB,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE;gBAChD,kEAAkE;gBAClE,IAAI,gBAAqC,CAAC;gBAC1C,IAAI,MAAM,CAAC,QAAQ,EAAE,YAAY,IAAI,MAAM,CAAC,eAAe,EAAE,IAAI,KAAK,aAAa,EAAE,CAAC;oBACpF,IAAI,CAAC;wBACH,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;oBAC7C,CAAC;oBAAC,MAAM,CAAC;wBACP,qCAAqC;oBACvC,CAAC;gBACH,CAAC;gBAED,OAAO;oBACL,OAAO,EAAE,WAAW;oBACpB,gBAAgB;oBAChB,KAAK;oBACL,YAAY;iBACb,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,OAAO;gBACL,MAAM,EAAE,eAAe,EAAE;gBACzB,MAAM,EAAE,aAAa;aACtB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;YACrB,OAAO;gBACL,MAAM,EAAE,CAAC,KAAK,SAAS,CAAC;oBACtB,eAAe;gBACjB,CAAC,CAAC,EAAE;gBACJ,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC;oBACtB,OAAO,EAAE,EAAE;oBACX,YAAY,EAAE,OAAgB;iBAC/B,CAAC;aACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,8CAA8C;IAChD,CAAC;CACF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { CompiledPrompt } from '@modular-prompt/core';
|
|
2
|
+
import type { AIDriver, QueryOptions, QueryResult, StreamResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Mock response configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface MockResponse {
|
|
7
|
+
content: string;
|
|
8
|
+
finishReason?: 'stop' | 'length' | 'error';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Response provider function type
|
|
12
|
+
* A function that generates responses dynamically based on the prompt and options.
|
|
13
|
+
* Called each time query() or streamQuery() is invoked.
|
|
14
|
+
*
|
|
15
|
+
* @param prompt - The compiled prompt being executed
|
|
16
|
+
* @param options - Query options (temperature, maxTokens, etc.)
|
|
17
|
+
* @returns The response string or MockResponse object
|
|
18
|
+
*/
|
|
19
|
+
export type ResponseProvider = (prompt: CompiledPrompt, options?: QueryOptions) => string | MockResponse | Promise<string | MockResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* Test driver options
|
|
22
|
+
*/
|
|
23
|
+
export interface TestDriverOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Mock responses for the driver.
|
|
26
|
+
* Can be either:
|
|
27
|
+
* - An array of strings: responses are consumed sequentially (queue pattern)
|
|
28
|
+
* - An array of MockResponse objects: responses with finishReason control
|
|
29
|
+
* - A function: called for each query to generate dynamic responses
|
|
30
|
+
*/
|
|
31
|
+
responses?: (string | MockResponse)[] | ResponseProvider;
|
|
32
|
+
/**
|
|
33
|
+
* Delay in milliseconds to simulate API latency.
|
|
34
|
+
* Applied before returning each response.
|
|
35
|
+
*/
|
|
36
|
+
delay?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Test driver for unit testing and mocking AI responses.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Using response queue (array)
|
|
43
|
+
* const driver = new TestDriver({
|
|
44
|
+
* responses: ['First', 'Second', 'Third']
|
|
45
|
+
* });
|
|
46
|
+
* await driver.query(prompt); // Returns 'First'
|
|
47
|
+
* await driver.query(prompt); // Returns 'Second'
|
|
48
|
+
* await driver.query(prompt); // Returns 'Third'
|
|
49
|
+
* await driver.query(prompt); // Throws: No more responses available
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // Using response provider (function)
|
|
53
|
+
* const driver = new TestDriver({
|
|
54
|
+
* responses: (prompt, options) => {
|
|
55
|
+
* if (prompt.metadata?.outputSchema) {
|
|
56
|
+
* return JSON.stringify({ result: 'structured' });
|
|
57
|
+
* }
|
|
58
|
+
* return 'Plain text';
|
|
59
|
+
* }
|
|
60
|
+
* });
|
|
61
|
+
*/
|
|
62
|
+
export declare class TestDriver implements AIDriver {
|
|
63
|
+
/** Queue of responses when using array mode */
|
|
64
|
+
private responseQueue;
|
|
65
|
+
/** Function to generate responses dynamically */
|
|
66
|
+
private responseProvider?;
|
|
67
|
+
/** Delay in milliseconds to simulate latency */
|
|
68
|
+
private delay;
|
|
69
|
+
constructor(options?: TestDriverOptions);
|
|
70
|
+
query(prompt: CompiledPrompt, options?: QueryOptions): Promise<QueryResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Stream a response character by character.
|
|
73
|
+
* Consumes one response from the queue or calls the provider function.
|
|
74
|
+
*/
|
|
75
|
+
streamQuery(prompt: CompiledPrompt, options?: QueryOptions): Promise<StreamResult>;
|
|
76
|
+
close(): Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=test-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-driver.d.ts","sourceRoot":"","sources":["../src/test-driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGpF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CAC5C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;AAE1I;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,GAAG,YAAY,CAAC,EAAE,GAAG,gBAAgB,CAAC;IAEzD;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AASD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,UAAW,YAAW,QAAQ;IACzC,+CAA+C;IAC/C,OAAO,CAAC,aAAa,CAAiB;IACtC,iDAAiD;IACjD,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,gDAAgD;IAChD,OAAO,CAAC,KAAK,CAAS;gBAEV,OAAO,GAAE,iBAAsB;IAgBrC,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAiFjF;;;OAGG;IACG,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAkElF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { extractJSON } from '@modular-prompt/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Simple token estimation (roughly 4 characters per token)
|
|
4
|
+
*/
|
|
5
|
+
function estimateTokens(text) {
|
|
6
|
+
return Math.ceil(text.length / 4);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Test driver for unit testing and mocking AI responses.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Using response queue (array)
|
|
13
|
+
* const driver = new TestDriver({
|
|
14
|
+
* responses: ['First', 'Second', 'Third']
|
|
15
|
+
* });
|
|
16
|
+
* await driver.query(prompt); // Returns 'First'
|
|
17
|
+
* await driver.query(prompt); // Returns 'Second'
|
|
18
|
+
* await driver.query(prompt); // Returns 'Third'
|
|
19
|
+
* await driver.query(prompt); // Throws: No more responses available
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Using response provider (function)
|
|
23
|
+
* const driver = new TestDriver({
|
|
24
|
+
* responses: (prompt, options) => {
|
|
25
|
+
* if (prompt.metadata?.outputSchema) {
|
|
26
|
+
* return JSON.stringify({ result: 'structured' });
|
|
27
|
+
* }
|
|
28
|
+
* return 'Plain text';
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
*/
|
|
32
|
+
export class TestDriver {
|
|
33
|
+
/** Queue of responses when using array mode */
|
|
34
|
+
responseQueue;
|
|
35
|
+
/** Function to generate responses dynamically */
|
|
36
|
+
responseProvider;
|
|
37
|
+
/** Delay in milliseconds to simulate latency */
|
|
38
|
+
delay;
|
|
39
|
+
constructor(options = {}) {
|
|
40
|
+
if (typeof options.responses === 'function') {
|
|
41
|
+
// Function mode: generate responses dynamically
|
|
42
|
+
this.responseProvider = options.responses;
|
|
43
|
+
this.responseQueue = [];
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Array mode: use responses as a queue (FIFO)
|
|
47
|
+
// Normalize string responses to MockResponse objects
|
|
48
|
+
this.responseQueue = options.responses
|
|
49
|
+
? options.responses.map(r => typeof r === 'string' ? { content: r, finishReason: 'stop' } : r)
|
|
50
|
+
: [];
|
|
51
|
+
this.responseProvider = undefined;
|
|
52
|
+
}
|
|
53
|
+
this.delay = options.delay || 0;
|
|
54
|
+
}
|
|
55
|
+
async query(prompt, options) {
|
|
56
|
+
// Create a simple formatted prompt for token counting
|
|
57
|
+
const formattedPrompt = [
|
|
58
|
+
prompt.instructions,
|
|
59
|
+
prompt.data,
|
|
60
|
+
prompt.output
|
|
61
|
+
].filter(Boolean).join('\n\n');
|
|
62
|
+
// If we have a response provider function, use it
|
|
63
|
+
if (this.responseProvider) {
|
|
64
|
+
// Dynamic response generation mode
|
|
65
|
+
const response = await this.responseProvider(prompt, options);
|
|
66
|
+
// Normalize response to MockResponse
|
|
67
|
+
const mockResponse = typeof response === 'string'
|
|
68
|
+
? { content: response, finishReason: 'stop' }
|
|
69
|
+
: response;
|
|
70
|
+
// Simulate API latency if configured
|
|
71
|
+
if (this.delay > 0) {
|
|
72
|
+
await new Promise(resolve => setTimeout(resolve, this.delay));
|
|
73
|
+
}
|
|
74
|
+
// Handle structured outputs if schema is provided
|
|
75
|
+
// This attempts to extract JSON from the response if outputSchema is defined
|
|
76
|
+
let structuredOutput;
|
|
77
|
+
if (prompt.metadata?.outputSchema && mockResponse.content) {
|
|
78
|
+
const extracted = extractJSON(mockResponse.content, { multiple: false });
|
|
79
|
+
if (extracted.source !== 'none' && extracted.data !== null) {
|
|
80
|
+
structuredOutput = extracted.data;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
content: mockResponse.content,
|
|
85
|
+
structuredOutput,
|
|
86
|
+
usage: {
|
|
87
|
+
promptTokens: estimateTokens(formattedPrompt),
|
|
88
|
+
completionTokens: estimateTokens(mockResponse.content),
|
|
89
|
+
totalTokens: estimateTokens(formattedPrompt) + estimateTokens(mockResponse.content)
|
|
90
|
+
},
|
|
91
|
+
finishReason: mockResponse.finishReason || 'stop'
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Queue mode: consume responses sequentially
|
|
95
|
+
if (this.responseQueue.length === 0) {
|
|
96
|
+
throw new Error('No more responses available');
|
|
97
|
+
}
|
|
98
|
+
// Simulate API latency if configured
|
|
99
|
+
if (this.delay > 0) {
|
|
100
|
+
await new Promise(resolve => setTimeout(resolve, this.delay));
|
|
101
|
+
}
|
|
102
|
+
// Take the first response from the queue (FIFO pattern)
|
|
103
|
+
const mockResponse = this.responseQueue.shift();
|
|
104
|
+
// Handle structured outputs if schema is provided
|
|
105
|
+
// This attempts to extract JSON from the response if outputSchema is defined
|
|
106
|
+
let structuredOutput;
|
|
107
|
+
if (prompt.metadata?.outputSchema && mockResponse.content) {
|
|
108
|
+
const extracted = extractJSON(mockResponse.content, { multiple: false });
|
|
109
|
+
if (extracted.source !== 'none' && extracted.data !== null) {
|
|
110
|
+
structuredOutput = extracted.data;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
content: mockResponse.content,
|
|
115
|
+
structuredOutput,
|
|
116
|
+
usage: {
|
|
117
|
+
promptTokens: estimateTokens(formattedPrompt),
|
|
118
|
+
completionTokens: estimateTokens(mockResponse.content),
|
|
119
|
+
totalTokens: estimateTokens(formattedPrompt) + estimateTokens(mockResponse.content)
|
|
120
|
+
},
|
|
121
|
+
finishReason: mockResponse.finishReason || 'stop'
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Stream a response character by character.
|
|
126
|
+
* Consumes one response from the queue or calls the provider function.
|
|
127
|
+
*/
|
|
128
|
+
async streamQuery(prompt, options) {
|
|
129
|
+
// Create a simple formatted prompt for token counting
|
|
130
|
+
const formattedPrompt = [
|
|
131
|
+
prompt.instructions,
|
|
132
|
+
prompt.data,
|
|
133
|
+
prompt.output
|
|
134
|
+
].filter(Boolean).join('\n\n');
|
|
135
|
+
// Get the response (either from provider function or queue)
|
|
136
|
+
let mockResponse;
|
|
137
|
+
if (this.responseProvider) {
|
|
138
|
+
// Dynamic mode: generate response
|
|
139
|
+
const response = await this.responseProvider(prompt, options);
|
|
140
|
+
mockResponse = typeof response === 'string'
|
|
141
|
+
? { content: response, finishReason: 'stop' }
|
|
142
|
+
: response;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// Queue mode: consume one response
|
|
146
|
+
if (this.responseQueue.length === 0) {
|
|
147
|
+
throw new Error('No more responses available');
|
|
148
|
+
}
|
|
149
|
+
mockResponse = this.responseQueue.shift();
|
|
150
|
+
}
|
|
151
|
+
// Create stream generator that yields characters one by one
|
|
152
|
+
const delay = this.delay;
|
|
153
|
+
const content = mockResponse.content;
|
|
154
|
+
async function* streamGenerator() {
|
|
155
|
+
// Stream response character by character to simulate streaming
|
|
156
|
+
for (const char of content) {
|
|
157
|
+
if (delay > 0) {
|
|
158
|
+
// Distribute delay across all characters
|
|
159
|
+
await new Promise(resolve => setTimeout(resolve, delay / content.length));
|
|
160
|
+
}
|
|
161
|
+
yield char;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Handle structured outputs if schema is provided
|
|
165
|
+
// Extract JSON from the complete response (not streamed)
|
|
166
|
+
let structuredOutput;
|
|
167
|
+
if (prompt.metadata?.outputSchema && mockResponse.content) {
|
|
168
|
+
const extracted = extractJSON(mockResponse.content, { multiple: false });
|
|
169
|
+
if (extracted.source !== 'none' && extracted.data !== null) {
|
|
170
|
+
structuredOutput = extracted.data;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Create result promise
|
|
174
|
+
const resultPromise = Promise.resolve({
|
|
175
|
+
content: mockResponse.content,
|
|
176
|
+
structuredOutput,
|
|
177
|
+
usage: {
|
|
178
|
+
promptTokens: estimateTokens(formattedPrompt),
|
|
179
|
+
completionTokens: estimateTokens(mockResponse.content),
|
|
180
|
+
totalTokens: estimateTokens(formattedPrompt) + estimateTokens(mockResponse.content)
|
|
181
|
+
},
|
|
182
|
+
finishReason: mockResponse.finishReason || 'stop'
|
|
183
|
+
});
|
|
184
|
+
return {
|
|
185
|
+
stream: streamGenerator(),
|
|
186
|
+
result: resultPromise
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async close() {
|
|
190
|
+
// No resources to clean up
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=test-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-driver.js","sourceRoot":"","sources":["../src/test-driver.ts"],"names":[],"mappings":"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"}
|