@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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +597 -0
  3. package/dist/anthropic/anthropic-driver.d.ts +47 -0
  4. package/dist/anthropic/anthropic-driver.d.ts.map +1 -0
  5. package/dist/anthropic/anthropic-driver.js +217 -0
  6. package/dist/anthropic/anthropic-driver.js.map +1 -0
  7. package/dist/driver-registry/ai-service.d.ts +43 -0
  8. package/dist/driver-registry/ai-service.d.ts.map +1 -0
  9. package/dist/driver-registry/ai-service.js +77 -0
  10. package/dist/driver-registry/ai-service.js.map +1 -0
  11. package/dist/driver-registry/config-based-factory.d.ts +64 -0
  12. package/dist/driver-registry/config-based-factory.d.ts.map +1 -0
  13. package/dist/driver-registry/config-based-factory.js +90 -0
  14. package/dist/driver-registry/config-based-factory.js.map +1 -0
  15. package/dist/driver-registry/factory-helper.d.ts +49 -0
  16. package/dist/driver-registry/factory-helper.d.ts.map +1 -0
  17. package/dist/driver-registry/factory-helper.js +109 -0
  18. package/dist/driver-registry/factory-helper.js.map +1 -0
  19. package/dist/driver-registry/index.d.ts +9 -0
  20. package/dist/driver-registry/index.d.ts.map +1 -0
  21. package/dist/driver-registry/index.js +8 -0
  22. package/dist/driver-registry/index.js.map +1 -0
  23. package/dist/driver-registry/registry.d.ts +50 -0
  24. package/dist/driver-registry/registry.d.ts.map +1 -0
  25. package/dist/driver-registry/registry.js +208 -0
  26. package/dist/driver-registry/registry.js.map +1 -0
  27. package/dist/driver-registry/types.d.ts +108 -0
  28. package/dist/driver-registry/types.d.ts.map +1 -0
  29. package/dist/driver-registry/types.js +6 -0
  30. package/dist/driver-registry/types.js.map +1 -0
  31. package/dist/echo-driver.d.ts +88 -0
  32. package/dist/echo-driver.d.ts.map +1 -0
  33. package/dist/echo-driver.js +198 -0
  34. package/dist/echo-driver.js.map +1 -0
  35. package/dist/formatter/completion-formatter.d.ts +27 -0
  36. package/dist/formatter/completion-formatter.d.ts.map +1 -0
  37. package/dist/formatter/completion-formatter.js +84 -0
  38. package/dist/formatter/completion-formatter.js.map +1 -0
  39. package/dist/formatter/converter.d.ts +20 -0
  40. package/dist/formatter/converter.d.ts.map +1 -0
  41. package/dist/formatter/converter.js +176 -0
  42. package/dist/formatter/converter.js.map +1 -0
  43. package/dist/formatter/element-formatters/base.d.ts +34 -0
  44. package/dist/formatter/element-formatters/base.d.ts.map +1 -0
  45. package/dist/formatter/element-formatters/base.js +36 -0
  46. package/dist/formatter/element-formatters/base.js.map +1 -0
  47. package/dist/formatter/element-formatters/chunk.d.ts +11 -0
  48. package/dist/formatter/element-formatters/chunk.d.ts.map +1 -0
  49. package/dist/formatter/element-formatters/chunk.js +12 -0
  50. package/dist/formatter/element-formatters/chunk.js.map +1 -0
  51. package/dist/formatter/element-formatters/index.d.ts +14 -0
  52. package/dist/formatter/element-formatters/index.d.ts.map +1 -0
  53. package/dist/formatter/element-formatters/index.js +15 -0
  54. package/dist/formatter/element-formatters/index.js.map +1 -0
  55. package/dist/formatter/element-formatters/json.d.ts +11 -0
  56. package/dist/formatter/element-formatters/json.d.ts.map +1 -0
  57. package/dist/formatter/element-formatters/json.js +27 -0
  58. package/dist/formatter/element-formatters/json.js.map +1 -0
  59. package/dist/formatter/element-formatters/material.d.ts +11 -0
  60. package/dist/formatter/element-formatters/material.d.ts.map +1 -0
  61. package/dist/formatter/element-formatters/material.js +35 -0
  62. package/dist/formatter/element-formatters/material.js.map +1 -0
  63. package/dist/formatter/element-formatters/message.d.ts +13 -0
  64. package/dist/formatter/element-formatters/message.d.ts.map +1 -0
  65. package/dist/formatter/element-formatters/message.js +35 -0
  66. package/dist/formatter/element-formatters/message.js.map +1 -0
  67. package/dist/formatter/element-formatters/registry.d.ts +29 -0
  68. package/dist/formatter/element-formatters/registry.d.ts.map +1 -0
  69. package/dist/formatter/element-formatters/registry.js +82 -0
  70. package/dist/formatter/element-formatters/registry.js.map +1 -0
  71. package/dist/formatter/element-formatters/section.d.ts +18 -0
  72. package/dist/formatter/element-formatters/section.d.ts.map +1 -0
  73. package/dist/formatter/element-formatters/section.js +46 -0
  74. package/dist/formatter/element-formatters/section.js.map +1 -0
  75. package/dist/formatter/element-formatters/string-pattern.d.ts +22 -0
  76. package/dist/formatter/element-formatters/string-pattern.d.ts.map +1 -0
  77. package/dist/formatter/element-formatters/string-pattern.js +124 -0
  78. package/dist/formatter/element-formatters/string-pattern.js.map +1 -0
  79. package/dist/formatter/element-formatters/text.d.ts +11 -0
  80. package/dist/formatter/element-formatters/text.d.ts.map +1 -0
  81. package/dist/formatter/element-formatters/text.js +11 -0
  82. package/dist/formatter/element-formatters/text.js.map +1 -0
  83. package/dist/formatter/formatter.d.ts +24 -0
  84. package/dist/formatter/formatter.d.ts.map +1 -0
  85. package/dist/formatter/formatter.js +252 -0
  86. package/dist/formatter/formatter.js.map +1 -0
  87. package/dist/formatter/types.d.ts +91 -0
  88. package/dist/formatter/types.d.ts.map +1 -0
  89. package/dist/formatter/types.js +2 -0
  90. package/dist/formatter/types.js.map +1 -0
  91. package/dist/google-genai/google-genai-driver.d.ts +67 -0
  92. package/dist/google-genai/google-genai-driver.d.ts.map +1 -0
  93. package/dist/google-genai/google-genai-driver.js +351 -0
  94. package/dist/google-genai/google-genai-driver.js.map +1 -0
  95. package/dist/index.d.ts +17 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +23 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/mlx-ml/mlx-driver.d.ts +65 -0
  100. package/dist/mlx-ml/mlx-driver.d.ts.map +1 -0
  101. package/dist/mlx-ml/mlx-driver.js +235 -0
  102. package/dist/mlx-ml/mlx-driver.js.map +1 -0
  103. package/dist/mlx-ml/model-spec/index.d.ts +7 -0
  104. package/dist/mlx-ml/model-spec/index.d.ts.map +1 -0
  105. package/dist/mlx-ml/model-spec/index.js +7 -0
  106. package/dist/mlx-ml/model-spec/index.js.map +1 -0
  107. package/dist/mlx-ml/model-spec/types.d.ts +30 -0
  108. package/dist/mlx-ml/model-spec/types.d.ts.map +1 -0
  109. package/dist/mlx-ml/model-spec/types.js +7 -0
  110. package/dist/mlx-ml/model-spec/types.js.map +1 -0
  111. package/dist/mlx-ml/process/index.d.ts +33 -0
  112. package/dist/mlx-ml/process/index.d.ts.map +1 -0
  113. package/dist/mlx-ml/process/index.js +65 -0
  114. package/dist/mlx-ml/process/index.js.map +1 -0
  115. package/dist/mlx-ml/process/model-handlers.d.ts +58 -0
  116. package/dist/mlx-ml/process/model-handlers.d.ts.map +1 -0
  117. package/dist/mlx-ml/process/model-handlers.js +197 -0
  118. package/dist/mlx-ml/process/model-handlers.js.map +1 -0
  119. package/dist/mlx-ml/process/model-specific.d.ts +35 -0
  120. package/dist/mlx-ml/process/model-specific.d.ts.map +1 -0
  121. package/dist/mlx-ml/process/model-specific.js +35 -0
  122. package/dist/mlx-ml/process/model-specific.js.map +1 -0
  123. package/dist/mlx-ml/process/parameter-mapper.d.ts +17 -0
  124. package/dist/mlx-ml/process/parameter-mapper.d.ts.map +1 -0
  125. package/dist/mlx-ml/process/parameter-mapper.js +91 -0
  126. package/dist/mlx-ml/process/parameter-mapper.js.map +1 -0
  127. package/dist/mlx-ml/process/parameter-validator.d.ts +55 -0
  128. package/dist/mlx-ml/process/parameter-validator.d.ts.map +1 -0
  129. package/dist/mlx-ml/process/parameter-validator.js +203 -0
  130. package/dist/mlx-ml/process/parameter-validator.js.map +1 -0
  131. package/dist/mlx-ml/process/process-communication.d.ts +25 -0
  132. package/dist/mlx-ml/process/process-communication.d.ts.map +1 -0
  133. package/dist/mlx-ml/process/process-communication.js +117 -0
  134. package/dist/mlx-ml/process/process-communication.js.map +1 -0
  135. package/dist/mlx-ml/process/queue.d.ts +30 -0
  136. package/dist/mlx-ml/process/queue.d.ts.map +1 -0
  137. package/dist/mlx-ml/process/queue.js +147 -0
  138. package/dist/mlx-ml/process/queue.js.map +1 -0
  139. package/dist/mlx-ml/process/types.d.ts +97 -0
  140. package/dist/mlx-ml/process/types.d.ts.map +1 -0
  141. package/dist/mlx-ml/process/types.js +2 -0
  142. package/dist/mlx-ml/process/types.js.map +1 -0
  143. package/dist/mlx-ml/types.d.ts +66 -0
  144. package/dist/mlx-ml/types.d.ts.map +1 -0
  145. package/dist/mlx-ml/types.js +7 -0
  146. package/dist/mlx-ml/types.js.map +1 -0
  147. package/dist/ollama/ollama-driver.d.ts +15 -0
  148. package/dist/ollama/ollama-driver.d.ts.map +1 -0
  149. package/dist/ollama/ollama-driver.js +15 -0
  150. package/dist/ollama/ollama-driver.js.map +1 -0
  151. package/dist/openai/openai-driver.d.ts +71 -0
  152. package/dist/openai/openai-driver.d.ts.map +1 -0
  153. package/dist/openai/openai-driver.js +230 -0
  154. package/dist/openai/openai-driver.js.map +1 -0
  155. package/dist/test-driver.d.ts +78 -0
  156. package/dist/test-driver.d.ts.map +1 -0
  157. package/dist/test-driver.js +193 -0
  158. package/dist/test-driver.js.map +1 -0
  159. package/dist/types.d.ts +90 -0
  160. package/dist/types.d.ts.map +1 -0
  161. package/dist/types.js +2 -0
  162. package/dist/types.js.map +1 -0
  163. package/dist/vertexai/vertexai-driver.d.ts +63 -0
  164. package/dist/vertexai/vertexai-driver.d.ts.map +1 -0
  165. package/dist/vertexai/vertexai-driver.js +335 -0
  166. package/dist/vertexai/vertexai-driver.js.map +1 -0
  167. package/package.json +61 -0
  168. package/scripts/download-model.js +40 -0
  169. package/scripts/setup-mlx.js +53 -0
  170. package/src/mlx-ml/python/.python-version +1 -0
  171. package/src/mlx-ml/python/__main__.py +312 -0
  172. package/src/mlx-ml/python/chat_template_constraints.py +164 -0
  173. package/src/mlx-ml/python/pyproject.toml +19 -0
  174. package/src/mlx-ml/python/token_utils.py +262 -0
  175. 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":"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"}
@@ -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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"}