cognitive-modules-cli 1.4.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/cli.js +65 -12
  2. package/dist/commands/compose.d.ts +31 -0
  3. package/dist/commands/compose.js +148 -0
  4. package/dist/commands/index.d.ts +1 -0
  5. package/dist/commands/index.js +1 -0
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js +5 -1
  8. package/dist/modules/composition.d.ts +251 -0
  9. package/dist/modules/composition.js +1265 -0
  10. package/dist/modules/composition.test.d.ts +11 -0
  11. package/dist/modules/composition.test.js +450 -0
  12. package/dist/modules/index.d.ts +2 -0
  13. package/dist/modules/index.js +2 -0
  14. package/dist/modules/loader.d.ts +22 -2
  15. package/dist/modules/loader.js +167 -4
  16. package/dist/modules/policy.test.d.ts +10 -0
  17. package/dist/modules/policy.test.js +369 -0
  18. package/dist/modules/runner.d.ts +348 -34
  19. package/dist/modules/runner.js +1263 -708
  20. package/dist/modules/subagent.js +2 -0
  21. package/dist/modules/validator.d.ts +28 -0
  22. package/dist/modules/validator.js +629 -0
  23. package/dist/providers/base.d.ts +1 -45
  24. package/dist/providers/base.js +0 -67
  25. package/dist/providers/openai.d.ts +3 -27
  26. package/dist/providers/openai.js +3 -175
  27. package/dist/types.d.ts +93 -316
  28. package/dist/types.js +1 -120
  29. package/package.json +2 -1
  30. package/src/cli.ts +73 -12
  31. package/src/commands/compose.ts +185 -0
  32. package/src/commands/index.ts +1 -0
  33. package/src/index.ts +35 -0
  34. package/src/modules/composition.test.ts +558 -0
  35. package/src/modules/composition.ts +1674 -0
  36. package/src/modules/index.ts +2 -0
  37. package/src/modules/loader.ts +196 -6
  38. package/src/modules/policy.test.ts +455 -0
  39. package/src/modules/runner.ts +1692 -998
  40. package/src/modules/subagent.ts +2 -0
  41. package/src/modules/validator.ts +700 -0
  42. package/src/providers/base.ts +1 -86
  43. package/src/providers/openai.ts +4 -226
  44. package/src/types.ts +113 -462
  45. package/tsconfig.json +1 -1
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Base Provider - Abstract class for all LLM providers
3
- * v2.5: Added streaming and multimodal support
4
3
  */
5
- import type { Provider, InvokeParams, InvokeResult, ProviderV25, InvokeParamsV25, StreamingInvokeResult, ModalityType } from '../types.js';
4
+ import type { Provider, InvokeParams, InvokeResult } from '../types.js';
6
5
  export declare abstract class BaseProvider implements Provider {
7
6
  abstract name: string;
8
7
  abstract invoke(params: InvokeParams): Promise<InvokeResult>;
@@ -10,46 +9,3 @@ export declare abstract class BaseProvider implements Provider {
10
9
  protected buildJsonPrompt(schema: object): string;
11
10
  protected parseJsonResponse(content: string): unknown;
12
11
  }
13
- /**
14
- * Base Provider with v2.5 streaming and multimodal support
15
- */
16
- export declare abstract class BaseProviderV25 extends BaseProvider implements ProviderV25 {
17
- /**
18
- * Check if this provider supports streaming
19
- * Override in subclass to enable streaming
20
- */
21
- supportsStreaming(): boolean;
22
- /**
23
- * Check if this provider supports multimodal input/output
24
- * Override in subclass to enable multimodal
25
- */
26
- supportsMultimodal(): {
27
- input: ModalityType[];
28
- output: ModalityType[];
29
- };
30
- /**
31
- * Invoke with streaming response
32
- * Override in subclass to implement streaming
33
- */
34
- invokeStream(params: InvokeParamsV25): Promise<StreamingInvokeResult>;
35
- /**
36
- * Format media inputs for the specific provider API
37
- * Override in subclass for provider-specific formatting
38
- */
39
- protected formatMediaForProvider(images?: Array<{
40
- type: string;
41
- url?: string;
42
- data?: string;
43
- media_type?: string;
44
- }>, _audio?: Array<{
45
- type: string;
46
- url?: string;
47
- data?: string;
48
- media_type?: string;
49
- }>, _video?: Array<{
50
- type: string;
51
- url?: string;
52
- data?: string;
53
- media_type?: string;
54
- }>): unknown[];
55
- }
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Base Provider - Abstract class for all LLM providers
3
- * v2.5: Added streaming and multimodal support
4
3
  */
5
4
  export class BaseProvider {
6
5
  buildJsonPrompt(schema) {
@@ -18,69 +17,3 @@ export class BaseProvider {
18
17
  }
19
18
  }
20
19
  }
21
- /**
22
- * Base Provider with v2.5 streaming and multimodal support
23
- */
24
- export class BaseProviderV25 extends BaseProvider {
25
- /**
26
- * Check if this provider supports streaming
27
- * Override in subclass to enable streaming
28
- */
29
- supportsStreaming() {
30
- return false;
31
- }
32
- /**
33
- * Check if this provider supports multimodal input/output
34
- * Override in subclass to enable multimodal
35
- */
36
- supportsMultimodal() {
37
- return {
38
- input: ['text'],
39
- output: ['text']
40
- };
41
- }
42
- /**
43
- * Invoke with streaming response
44
- * Override in subclass to implement streaming
45
- */
46
- async invokeStream(params) {
47
- // Default: fallback to non-streaming with async generator wrapper
48
- const result = await this.invoke(params);
49
- async function* generateChunks() {
50
- yield result.content;
51
- }
52
- return {
53
- stream: generateChunks(),
54
- usage: result.usage
55
- };
56
- }
57
- /**
58
- * Format media inputs for the specific provider API
59
- * Override in subclass for provider-specific formatting
60
- */
61
- formatMediaForProvider(images, _audio, _video) {
62
- // Default implementation for image-only providers (like OpenAI Vision)
63
- if (!images || images.length === 0) {
64
- return [];
65
- }
66
- return images.map(img => {
67
- if (img.type === 'url' && img.url) {
68
- return {
69
- type: 'image_url',
70
- image_url: {
71
- url: img.url
72
- }
73
- };
74
- }
75
- else if (img.type === 'base64' && img.data && img.media_type) {
76
- return {
77
- type: 'image_url',
78
- image_url: {
79
- url: `data:${img.media_type};base64,${img.data}`
80
- }
81
- };
82
- }
83
- return null;
84
- }).filter(Boolean);
85
- }
86
- }
@@ -1,38 +1,14 @@
1
1
  /**
2
2
  * OpenAI Provider - OpenAI API (and compatible APIs)
3
- * v2.5: Added streaming and multimodal (vision) support
4
3
  */
5
- import { BaseProviderV25 } from './base.js';
6
- import type { InvokeParams, InvokeResult, InvokeParamsV25, StreamingInvokeResult, ModalityType } from '../types.js';
7
- export declare class OpenAIProvider extends BaseProviderV25 {
4
+ import { BaseProvider } from './base.js';
5
+ import type { InvokeParams, InvokeResult } from '../types.js';
6
+ export declare class OpenAIProvider extends BaseProvider {
8
7
  name: string;
9
8
  private apiKey;
10
9
  private model;
11
10
  private baseUrl;
12
11
  constructor(apiKey?: string, model?: string, baseUrl?: string);
13
12
  isConfigured(): boolean;
14
- /**
15
- * Check if streaming is supported (always true for OpenAI)
16
- */
17
- supportsStreaming(): boolean;
18
- /**
19
- * Check multimodal support (vision models)
20
- */
21
- supportsMultimodal(): {
22
- input: ModalityType[];
23
- output: ModalityType[];
24
- };
25
13
  invoke(params: InvokeParams): Promise<InvokeResult>;
26
- /**
27
- * Invoke with streaming response
28
- */
29
- invokeStream(params: InvokeParamsV25): Promise<StreamingInvokeResult>;
30
- /**
31
- * Build messages with multimodal content (images)
32
- */
33
- private buildMessagesWithMedia;
34
- /**
35
- * Convert MediaInput to URL for OpenAI API
36
- */
37
- private mediaInputToUrl;
38
14
  }
@@ -1,14 +1,13 @@
1
1
  /**
2
2
  * OpenAI Provider - OpenAI API (and compatible APIs)
3
- * v2.5: Added streaming and multimodal (vision) support
4
3
  */
5
- import { BaseProviderV25 } from './base.js';
6
- export class OpenAIProvider extends BaseProviderV25 {
4
+ import { BaseProvider } from './base.js';
5
+ export class OpenAIProvider extends BaseProvider {
7
6
  name = 'openai';
8
7
  apiKey;
9
8
  model;
10
9
  baseUrl;
11
- constructor(apiKey, model = 'gpt-4o', baseUrl = 'https://api.openai.com/v1') {
10
+ constructor(apiKey, model = 'gpt-5.2', baseUrl = 'https://api.openai.com/v1') {
12
11
  super();
13
12
  this.apiKey = apiKey || process.env.OPENAI_API_KEY || '';
14
13
  this.model = model;
@@ -17,24 +16,6 @@ export class OpenAIProvider extends BaseProviderV25 {
17
16
  isConfigured() {
18
17
  return !!this.apiKey;
19
18
  }
20
- /**
21
- * Check if streaming is supported (always true for OpenAI)
22
- */
23
- supportsStreaming() {
24
- return true;
25
- }
26
- /**
27
- * Check multimodal support (vision models)
28
- */
29
- supportsMultimodal() {
30
- // Vision models support image input
31
- const visionModels = ['gpt-4o', 'gpt-4-vision', 'gpt-4-turbo', 'gpt-4o-mini'];
32
- const supportsVision = visionModels.some(m => this.model.includes(m));
33
- return {
34
- input: supportsVision ? ['text', 'image'] : ['text'],
35
- output: ['text'] // DALL-E would be separate
36
- };
37
- }
38
19
  async invoke(params) {
39
20
  if (!this.isConfigured()) {
40
21
  throw new Error('OpenAI API key not configured. Set OPENAI_API_KEY environment variable.');
@@ -83,157 +64,4 @@ export class OpenAIProvider extends BaseProviderV25 {
83
64
  } : undefined,
84
65
  };
85
66
  }
86
- /**
87
- * Invoke with streaming response
88
- */
89
- async invokeStream(params) {
90
- if (!this.isConfigured()) {
91
- throw new Error('OpenAI API key not configured. Set OPENAI_API_KEY environment variable.');
92
- }
93
- const url = `${this.baseUrl}/chat/completions`;
94
- // Build messages with multimodal content if present
95
- const messages = this.buildMessagesWithMedia(params);
96
- const body = {
97
- model: this.model,
98
- messages,
99
- temperature: params.temperature ?? 0.7,
100
- max_tokens: params.maxTokens ?? 4096,
101
- stream: true,
102
- };
103
- // Add JSON mode if schema provided
104
- if (params.jsonSchema) {
105
- body.response_format = { type: 'json_object' };
106
- }
107
- const response = await fetch(url, {
108
- method: 'POST',
109
- headers: {
110
- 'Content-Type': 'application/json',
111
- 'Authorization': `Bearer ${this.apiKey}`,
112
- },
113
- body: JSON.stringify(body),
114
- });
115
- if (!response.ok) {
116
- const error = await response.text();
117
- throw new Error(`OpenAI API error: ${response.status} - ${error}`);
118
- }
119
- const bodyReader = response.body?.getReader();
120
- if (!bodyReader) {
121
- throw new Error('No response body');
122
- }
123
- const decoder = new TextDecoder();
124
- let usage;
125
- // Capture reader reference for closure
126
- const reader = bodyReader;
127
- // Create async generator for streaming
128
- async function* streamGenerator() {
129
- let buffer = '';
130
- while (true) {
131
- const { done, value } = await reader.read();
132
- if (done)
133
- break;
134
- buffer += decoder.decode(value, { stream: true });
135
- // Parse SSE events
136
- const lines = buffer.split('\n');
137
- buffer = lines.pop() || '';
138
- for (const line of lines) {
139
- if (line.startsWith('data: ')) {
140
- const data = line.slice(6);
141
- if (data === '[DONE]') {
142
- return;
143
- }
144
- try {
145
- const parsed = JSON.parse(data);
146
- const content = parsed.choices?.[0]?.delta?.content;
147
- if (content) {
148
- yield content;
149
- }
150
- // Capture usage if available
151
- if (parsed.usage) {
152
- usage = {
153
- promptTokens: parsed.usage.prompt_tokens || 0,
154
- completionTokens: parsed.usage.completion_tokens || 0,
155
- totalTokens: parsed.usage.total_tokens || 0,
156
- };
157
- }
158
- }
159
- catch {
160
- // Skip malformed JSON
161
- }
162
- }
163
- }
164
- }
165
- }
166
- return {
167
- stream: streamGenerator(),
168
- usage
169
- };
170
- }
171
- /**
172
- * Build messages with multimodal content (images)
173
- */
174
- buildMessagesWithMedia(params) {
175
- const hasImages = params.images && params.images.length > 0;
176
- if (!hasImages) {
177
- return params.messages;
178
- }
179
- // Find the last user message and add images to it
180
- const messages = [];
181
- const lastUserIdx = params.messages.findLastIndex(m => m.role === 'user');
182
- for (let i = 0; i < params.messages.length; i++) {
183
- const msg = params.messages[i];
184
- if (i === lastUserIdx && hasImages) {
185
- // Convert to multimodal content
186
- const content = [
187
- { type: 'text', text: msg.content }
188
- ];
189
- // Add images
190
- for (const img of params.images) {
191
- const imageUrl = this.mediaInputToUrl(img);
192
- if (imageUrl) {
193
- content.push({
194
- type: 'image_url',
195
- image_url: { url: imageUrl, detail: 'auto' }
196
- });
197
- }
198
- }
199
- messages.push({ role: msg.role, content });
200
- }
201
- else {
202
- messages.push({ role: msg.role, content: msg.content });
203
- }
204
- }
205
- // Add JSON schema instruction if needed
206
- if (params.jsonSchema && lastUserIdx >= 0) {
207
- const lastMsg = messages[lastUserIdx];
208
- if (typeof lastMsg.content === 'string') {
209
- lastMsg.content = lastMsg.content + this.buildJsonPrompt(params.jsonSchema);
210
- }
211
- else {
212
- // Content is array, append to text part
213
- const textPart = lastMsg.content.find(p => p.type === 'text');
214
- if (textPart && textPart.type === 'text') {
215
- textPart.text = textPart.text + this.buildJsonPrompt(params.jsonSchema);
216
- }
217
- }
218
- }
219
- return messages;
220
- }
221
- /**
222
- * Convert MediaInput to URL for OpenAI API
223
- */
224
- mediaInputToUrl(media) {
225
- switch (media.type) {
226
- case 'url':
227
- return media.url;
228
- case 'base64':
229
- return `data:${media.media_type};base64,${media.data}`;
230
- case 'file':
231
- // File paths would need to be loaded first
232
- // This should be handled by the runner before calling the provider
233
- console.warn('[cognitive] File media input not pre-loaded, skipping');
234
- return null;
235
- default:
236
- return null;
237
- }
238
- }
239
67
  }