cognitive-modules-cli 2.2.1 → 2.2.7

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 (101) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +35 -29
  4. package/dist/cli.js +519 -23
  5. package/dist/commands/add.d.ts +33 -14
  6. package/dist/commands/add.js +383 -16
  7. package/dist/commands/compose.js +60 -23
  8. package/dist/commands/index.d.ts +4 -0
  9. package/dist/commands/index.js +4 -0
  10. package/dist/commands/init.js +23 -1
  11. package/dist/commands/migrate.d.ts +30 -0
  12. package/dist/commands/migrate.js +650 -0
  13. package/dist/commands/pipe.d.ts +1 -0
  14. package/dist/commands/pipe.js +31 -11
  15. package/dist/commands/remove.js +33 -2
  16. package/dist/commands/run.d.ts +2 -0
  17. package/dist/commands/run.js +61 -28
  18. package/dist/commands/search.d.ts +28 -0
  19. package/dist/commands/search.js +143 -0
  20. package/dist/commands/test.d.ts +65 -0
  21. package/dist/commands/test.js +454 -0
  22. package/dist/commands/update.d.ts +1 -0
  23. package/dist/commands/update.js +106 -14
  24. package/dist/commands/validate.d.ts +36 -0
  25. package/dist/commands/validate.js +97 -0
  26. package/dist/errors/index.d.ts +225 -0
  27. package/dist/errors/index.js +420 -0
  28. package/dist/mcp/server.js +84 -79
  29. package/dist/modules/composition.js +97 -32
  30. package/dist/modules/loader.js +4 -2
  31. package/dist/modules/runner.d.ts +72 -5
  32. package/dist/modules/runner.js +306 -59
  33. package/dist/modules/subagent.d.ts +6 -1
  34. package/dist/modules/subagent.js +18 -13
  35. package/dist/modules/validator.js +14 -6
  36. package/dist/providers/anthropic.d.ts +15 -0
  37. package/dist/providers/anthropic.js +147 -5
  38. package/dist/providers/base.d.ts +11 -0
  39. package/dist/providers/base.js +18 -0
  40. package/dist/providers/gemini.d.ts +15 -0
  41. package/dist/providers/gemini.js +122 -5
  42. package/dist/providers/ollama.d.ts +15 -0
  43. package/dist/providers/ollama.js +111 -3
  44. package/dist/providers/openai.d.ts +11 -0
  45. package/dist/providers/openai.js +133 -0
  46. package/dist/registry/client.d.ts +212 -0
  47. package/dist/registry/client.js +359 -0
  48. package/dist/registry/index.d.ts +4 -0
  49. package/dist/registry/index.js +4 -0
  50. package/dist/registry/tar.d.ts +8 -0
  51. package/dist/registry/tar.js +353 -0
  52. package/dist/server/http.js +301 -45
  53. package/dist/server/index.d.ts +2 -0
  54. package/dist/server/index.js +1 -0
  55. package/dist/server/sse.d.ts +13 -0
  56. package/dist/server/sse.js +22 -0
  57. package/dist/types.d.ts +32 -1
  58. package/dist/types.js +4 -1
  59. package/dist/version.d.ts +1 -0
  60. package/dist/version.js +4 -0
  61. package/package.json +31 -7
  62. package/dist/modules/composition.test.d.ts +0 -11
  63. package/dist/modules/composition.test.js +0 -450
  64. package/dist/modules/policy.test.d.ts +0 -10
  65. package/dist/modules/policy.test.js +0 -369
  66. package/src/cli.ts +0 -471
  67. package/src/commands/add.ts +0 -315
  68. package/src/commands/compose.ts +0 -185
  69. package/src/commands/index.ts +0 -13
  70. package/src/commands/init.ts +0 -94
  71. package/src/commands/list.ts +0 -33
  72. package/src/commands/pipe.ts +0 -76
  73. package/src/commands/remove.ts +0 -57
  74. package/src/commands/run.ts +0 -80
  75. package/src/commands/update.ts +0 -130
  76. package/src/commands/versions.ts +0 -79
  77. package/src/index.ts +0 -90
  78. package/src/mcp/index.ts +0 -5
  79. package/src/mcp/server.ts +0 -403
  80. package/src/modules/composition.test.ts +0 -558
  81. package/src/modules/composition.ts +0 -1674
  82. package/src/modules/index.ts +0 -9
  83. package/src/modules/loader.ts +0 -508
  84. package/src/modules/policy.test.ts +0 -455
  85. package/src/modules/runner.ts +0 -1983
  86. package/src/modules/subagent.ts +0 -277
  87. package/src/modules/validator.ts +0 -700
  88. package/src/providers/anthropic.ts +0 -89
  89. package/src/providers/base.ts +0 -29
  90. package/src/providers/deepseek.ts +0 -83
  91. package/src/providers/gemini.ts +0 -117
  92. package/src/providers/index.ts +0 -78
  93. package/src/providers/minimax.ts +0 -81
  94. package/src/providers/moonshot.ts +0 -82
  95. package/src/providers/ollama.ts +0 -83
  96. package/src/providers/openai.ts +0 -84
  97. package/src/providers/qwen.ts +0 -82
  98. package/src/server/http.ts +0 -316
  99. package/src/server/index.ts +0 -6
  100. package/src/types.ts +0 -599
  101. package/tsconfig.json +0 -17
@@ -1,89 +0,0 @@
1
- /**
2
- * Anthropic Provider - Claude API
3
- */
4
-
5
- import { BaseProvider } from './base.js';
6
- import type { InvokeParams, InvokeResult } from '../types.js';
7
-
8
- export class AnthropicProvider extends BaseProvider {
9
- name = 'anthropic';
10
- private apiKey: string;
11
- private model: string;
12
- private baseUrl = 'https://api.anthropic.com/v1';
13
-
14
- constructor(apiKey?: string, model = 'claude-sonnet-4-5-20250929') {
15
- super();
16
- this.apiKey = apiKey || process.env.ANTHROPIC_API_KEY || '';
17
- this.model = model;
18
- }
19
-
20
- isConfigured(): boolean {
21
- return !!this.apiKey;
22
- }
23
-
24
- async invoke(params: InvokeParams): Promise<InvokeResult> {
25
- if (!this.isConfigured()) {
26
- throw new Error('Anthropic API key not configured. Set ANTHROPIC_API_KEY environment variable.');
27
- }
28
-
29
- const url = `${this.baseUrl}/messages`;
30
-
31
- // Extract system message
32
- const systemMessage = params.messages.find(m => m.role === 'system');
33
- const otherMessages = params.messages.filter(m => m.role !== 'system');
34
-
35
- // Add JSON schema instruction if provided
36
- let messages = otherMessages;
37
- if (params.jsonSchema) {
38
- const lastUserIdx = messages.findLastIndex(m => m.role === 'user');
39
- if (lastUserIdx >= 0) {
40
- messages = [...messages];
41
- messages[lastUserIdx] = {
42
- ...messages[lastUserIdx],
43
- content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
44
- };
45
- }
46
- }
47
-
48
- const body: Record<string, unknown> = {
49
- model: this.model,
50
- messages: messages.map(m => ({ role: m.role, content: m.content })),
51
- max_tokens: params.maxTokens ?? 4096,
52
- };
53
-
54
- if (systemMessage) {
55
- body.system = systemMessage.content;
56
- }
57
-
58
- const response = await fetch(url, {
59
- method: 'POST',
60
- headers: {
61
- 'Content-Type': 'application/json',
62
- 'x-api-key': this.apiKey,
63
- 'anthropic-version': '2023-06-01',
64
- },
65
- body: JSON.stringify(body),
66
- });
67
-
68
- if (!response.ok) {
69
- const error = await response.text();
70
- throw new Error(`Anthropic API error: ${response.status} - ${error}`);
71
- }
72
-
73
- const data = await response.json() as {
74
- content?: Array<{ text?: string }>;
75
- usage?: { input_tokens?: number; output_tokens?: number };
76
- };
77
-
78
- const content = data.content?.[0]?.text || '';
79
-
80
- return {
81
- content,
82
- usage: data.usage ? {
83
- promptTokens: data.usage.input_tokens || 0,
84
- completionTokens: data.usage.output_tokens || 0,
85
- totalTokens: (data.usage.input_tokens || 0) + (data.usage.output_tokens || 0),
86
- } : undefined,
87
- };
88
- }
89
- }
@@ -1,29 +0,0 @@
1
- /**
2
- * Base Provider - Abstract class for all LLM providers
3
- */
4
-
5
- import type { Provider, InvokeParams, InvokeResult } from '../types.js';
6
-
7
- export abstract class BaseProvider implements Provider {
8
- abstract name: string;
9
-
10
- abstract invoke(params: InvokeParams): Promise<InvokeResult>;
11
-
12
- abstract isConfigured(): boolean;
13
-
14
- protected buildJsonPrompt(schema: object): string {
15
- return `\n\nYou MUST respond with valid JSON matching this schema:\n${JSON.stringify(schema, null, 2)}\n\nRespond with ONLY the JSON, no markdown code blocks.`;
16
- }
17
-
18
- protected parseJsonResponse(content: string): unknown {
19
- // Try to extract JSON from markdown code blocks
20
- const jsonMatch = content.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
21
- const jsonStr = jsonMatch ? jsonMatch[1] : content;
22
-
23
- try {
24
- return JSON.parse(jsonStr.trim());
25
- } catch {
26
- throw new Error(`Failed to parse JSON response: ${content.substring(0, 200)}`);
27
- }
28
- }
29
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * DeepSeek Provider - DeepSeek API
3
- */
4
-
5
- import { BaseProvider } from './base.js';
6
- import type { InvokeParams, InvokeResult } from '../types.js';
7
-
8
- export class DeepSeekProvider extends BaseProvider {
9
- name = 'deepseek';
10
- private apiKey: string;
11
- private model: string;
12
- private baseUrl = 'https://api.deepseek.com/v1';
13
-
14
- constructor(apiKey?: string, model = 'deepseek-chat') {
15
- // deepseek-chat 自动映射到最新的 DeepSeek-V3.2
16
- super();
17
- this.apiKey = apiKey || process.env.DEEPSEEK_API_KEY || '';
18
- this.model = model;
19
- }
20
-
21
- isConfigured(): boolean {
22
- return !!this.apiKey;
23
- }
24
-
25
- async invoke(params: InvokeParams): Promise<InvokeResult> {
26
- if (!this.isConfigured()) {
27
- throw new Error('DeepSeek API key not configured. Set DEEPSEEK_API_KEY environment variable.');
28
- }
29
-
30
- const url = `${this.baseUrl}/chat/completions`;
31
-
32
- const body: Record<string, unknown> = {
33
- model: this.model,
34
- messages: params.messages.map(m => ({ role: m.role, content: m.content })),
35
- temperature: params.temperature ?? 0.7,
36
- max_tokens: params.maxTokens ?? 4096,
37
- };
38
-
39
- // Add JSON mode if schema provided
40
- if (params.jsonSchema) {
41
- body.response_format = { type: 'json_object' };
42
- const lastUserIdx = params.messages.findLastIndex(m => m.role === 'user');
43
- if (lastUserIdx >= 0) {
44
- const messages = [...params.messages];
45
- messages[lastUserIdx] = {
46
- ...messages[lastUserIdx],
47
- content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
48
- };
49
- body.messages = messages.map(m => ({ role: m.role, content: m.content }));
50
- }
51
- }
52
-
53
- const response = await fetch(url, {
54
- method: 'POST',
55
- headers: {
56
- 'Content-Type': 'application/json',
57
- 'Authorization': `Bearer ${this.apiKey}`,
58
- },
59
- body: JSON.stringify(body),
60
- });
61
-
62
- if (!response.ok) {
63
- const error = await response.text();
64
- throw new Error(`DeepSeek API error: ${response.status} - ${error}`);
65
- }
66
-
67
- const data = await response.json() as {
68
- choices?: Array<{ message?: { content?: string } }>;
69
- usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
70
- };
71
-
72
- const content = data.choices?.[0]?.message?.content || '';
73
-
74
- return {
75
- content,
76
- usage: data.usage ? {
77
- promptTokens: data.usage.prompt_tokens || 0,
78
- completionTokens: data.usage.completion_tokens || 0,
79
- totalTokens: data.usage.total_tokens || 0,
80
- } : undefined,
81
- };
82
- }
83
- }
@@ -1,117 +0,0 @@
1
- /**
2
- * Gemini Provider - Google Gemini API
3
- */
4
-
5
- import { BaseProvider } from './base.js';
6
- import type { InvokeParams, InvokeResult } from '../types.js';
7
-
8
- export class GeminiProvider extends BaseProvider {
9
- name = 'gemini';
10
- private apiKey: string;
11
- private model: string;
12
- private baseUrl = 'https://generativelanguage.googleapis.com/v1beta';
13
-
14
- constructor(apiKey?: string, model = 'gemini-3-flash') {
15
- super();
16
- this.apiKey = apiKey || process.env.GEMINI_API_KEY || '';
17
- this.model = model;
18
- }
19
-
20
- isConfigured(): boolean {
21
- return !!this.apiKey;
22
- }
23
-
24
- /**
25
- * Clean JSON Schema for Gemini API compatibility
26
- * Removes unsupported fields like additionalProperties
27
- */
28
- private cleanSchemaForGemini(schema: object): object {
29
- const unsupportedFields = ['additionalProperties', '$schema', 'default', 'examples'];
30
-
31
- const clean = (obj: unknown): unknown => {
32
- if (Array.isArray(obj)) {
33
- return obj.map(clean);
34
- }
35
- if (obj && typeof obj === 'object') {
36
- const result: Record<string, unknown> = {};
37
- for (const [key, value] of Object.entries(obj)) {
38
- if (!unsupportedFields.includes(key)) {
39
- result[key] = clean(value);
40
- }
41
- }
42
- return result;
43
- }
44
- return obj;
45
- };
46
-
47
- return clean(schema) as object;
48
- }
49
-
50
- async invoke(params: InvokeParams): Promise<InvokeResult> {
51
- if (!this.isConfigured()) {
52
- throw new Error('Gemini API key not configured. Set GEMINI_API_KEY environment variable.');
53
- }
54
-
55
- const url = `${this.baseUrl}/models/${this.model}:generateContent?key=${this.apiKey}`;
56
-
57
- // Convert messages to Gemini format
58
- const contents = params.messages
59
- .filter(m => m.role !== 'system')
60
- .map(m => ({
61
- role: m.role === 'assistant' ? 'model' : 'user',
62
- parts: [{ text: m.content }]
63
- }));
64
-
65
- // Add system instruction if present
66
- const systemMessage = params.messages.find(m => m.role === 'system');
67
-
68
- const body: Record<string, unknown> = {
69
- contents,
70
- generationConfig: {
71
- temperature: params.temperature ?? 0.7,
72
- maxOutputTokens: params.maxTokens ?? 8192,
73
- }
74
- };
75
-
76
- if (systemMessage) {
77
- body.systemInstruction = { parts: [{ text: systemMessage.content }] };
78
- }
79
-
80
- // Add JSON schema constraint if provided
81
- if (params.jsonSchema) {
82
- const cleanedSchema = this.cleanSchemaForGemini(params.jsonSchema);
83
- body.generationConfig = {
84
- ...body.generationConfig as object,
85
- responseMimeType: 'application/json',
86
- responseSchema: cleanedSchema,
87
- };
88
- }
89
-
90
- const response = await fetch(url, {
91
- method: 'POST',
92
- headers: { 'Content-Type': 'application/json' },
93
- body: JSON.stringify(body),
94
- });
95
-
96
- if (!response.ok) {
97
- const error = await response.text();
98
- throw new Error(`Gemini API error: ${response.status} - ${error}`);
99
- }
100
-
101
- const data = await response.json() as {
102
- candidates?: Array<{ content?: { parts?: Array<{ text?: string }> } }>;
103
- usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number; totalTokenCount?: number };
104
- };
105
-
106
- const content = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
107
-
108
- return {
109
- content,
110
- usage: data.usageMetadata ? {
111
- promptTokens: data.usageMetadata.promptTokenCount || 0,
112
- completionTokens: data.usageMetadata.candidatesTokenCount || 0,
113
- totalTokens: data.usageMetadata.totalTokenCount || 0,
114
- } : undefined,
115
- };
116
- }
117
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * Provider Registry
3
- */
4
-
5
- import type { Provider } from '../types.js';
6
- import { GeminiProvider } from './gemini.js';
7
- import { OpenAIProvider } from './openai.js';
8
- import { AnthropicProvider } from './anthropic.js';
9
- import { MiniMaxProvider } from './minimax.js';
10
- import { DeepSeekProvider } from './deepseek.js';
11
- import { MoonshotProvider } from './moonshot.js';
12
- import { QwenProvider } from './qwen.js';
13
- import { OllamaProvider } from './ollama.js';
14
-
15
- export { BaseProvider } from './base.js';
16
- export { GeminiProvider } from './gemini.js';
17
- export { OpenAIProvider } from './openai.js';
18
- export { AnthropicProvider } from './anthropic.js';
19
- export { MiniMaxProvider } from './minimax.js';
20
- export { DeepSeekProvider } from './deepseek.js';
21
- export { MoonshotProvider } from './moonshot.js';
22
- export { QwenProvider } from './qwen.js';
23
- export { OllamaProvider } from './ollama.js';
24
-
25
- type ProviderFactory = (model?: string) => Provider;
26
-
27
- const providers: Record<string, ProviderFactory> = {
28
- gemini: (model) => new GeminiProvider(undefined, model),
29
- openai: (model) => new OpenAIProvider(undefined, model),
30
- anthropic: (model) => new AnthropicProvider(undefined, model),
31
- minimax: (model) => new MiniMaxProvider(undefined, model),
32
- deepseek: (model) => new DeepSeekProvider(undefined, model),
33
- moonshot: (model) => new MoonshotProvider(undefined, model),
34
- kimi: (model) => new MoonshotProvider(undefined, model), // Alias
35
- qwen: (model) => new QwenProvider(undefined, model),
36
- tongyi: (model) => new QwenProvider(undefined, model), // Alias
37
- dashscope: (model) => new QwenProvider(undefined, model), // Alias
38
- ollama: (model) => new OllamaProvider(model),
39
- local: (model) => new OllamaProvider(model), // Alias
40
- };
41
-
42
- export function getProvider(name?: string, model?: string): Provider {
43
- // Check for model override from environment
44
- const modelOverride = model || process.env.COG_MODEL;
45
-
46
- // Auto-detect if not specified
47
- if (!name) {
48
- if (process.env.GEMINI_API_KEY) return new GeminiProvider(undefined, modelOverride);
49
- if (process.env.OPENAI_API_KEY) return new OpenAIProvider(undefined, modelOverride);
50
- if (process.env.ANTHROPIC_API_KEY) return new AnthropicProvider(undefined, modelOverride);
51
- if (process.env.DEEPSEEK_API_KEY) return new DeepSeekProvider(undefined, modelOverride);
52
- if (process.env.MINIMAX_API_KEY) return new MiniMaxProvider(undefined, modelOverride);
53
- if (process.env.MOONSHOT_API_KEY) return new MoonshotProvider(undefined, modelOverride);
54
- if (process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY) return new QwenProvider(undefined, modelOverride);
55
- // Ollama is always available as fallback if nothing else is configured
56
- return new OllamaProvider(modelOverride);
57
- }
58
-
59
- const factory = providers[name.toLowerCase()];
60
- if (!factory) {
61
- throw new Error(`Unknown provider: ${name}. Available: ${Object.keys(providers).join(', ')}`);
62
- }
63
-
64
- return factory(modelOverride);
65
- }
66
-
67
- export function listProviders(): Array<{ name: string; configured: boolean; model: string }> {
68
- return [
69
- { name: 'gemini', configured: !!process.env.GEMINI_API_KEY, model: 'gemini-3-flash' },
70
- { name: 'openai', configured: !!process.env.OPENAI_API_KEY, model: 'gpt-5.2' },
71
- { name: 'anthropic', configured: !!process.env.ANTHROPIC_API_KEY, model: 'claude-sonnet-4.5' },
72
- { name: 'deepseek', configured: !!process.env.DEEPSEEK_API_KEY, model: 'deepseek-v3.2' },
73
- { name: 'minimax', configured: !!process.env.MINIMAX_API_KEY, model: 'MiniMax-M2.1' },
74
- { name: 'moonshot', configured: !!process.env.MOONSHOT_API_KEY, model: 'kimi-k2.5' },
75
- { name: 'qwen', configured: !!(process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY), model: 'qwen3-max' },
76
- { name: 'ollama', configured: true, model: 'llama4 (local)' },
77
- ];
78
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * MiniMax Provider - MiniMax API
3
- */
4
-
5
- import { BaseProvider } from './base.js';
6
- import type { InvokeParams, InvokeResult } from '../types.js';
7
-
8
- export class MiniMaxProvider extends BaseProvider {
9
- name = 'minimax';
10
- private apiKey: string;
11
- private model: string;
12
- private baseUrl = 'https://api.minimax.chat/v1';
13
-
14
- constructor(apiKey?: string, model = 'MiniMax-M2.1') {
15
- super();
16
- this.apiKey = apiKey || process.env.MINIMAX_API_KEY || '';
17
- this.model = model;
18
- }
19
-
20
- isConfigured(): boolean {
21
- return !!this.apiKey;
22
- }
23
-
24
- async invoke(params: InvokeParams): Promise<InvokeResult> {
25
- if (!this.isConfigured()) {
26
- throw new Error('MiniMax API key not configured. Set MINIMAX_API_KEY environment variable.');
27
- }
28
-
29
- const url = `${this.baseUrl}/text/chatcompletion_v2`;
30
-
31
- const body: Record<string, unknown> = {
32
- model: this.model,
33
- messages: params.messages.map(m => ({ role: m.role, content: m.content })),
34
- temperature: params.temperature ?? 0.7,
35
- max_tokens: params.maxTokens ?? 4096,
36
- };
37
-
38
- // Add JSON mode if schema provided
39
- if (params.jsonSchema) {
40
- const lastUserIdx = params.messages.findLastIndex(m => m.role === 'user');
41
- if (lastUserIdx >= 0) {
42
- const messages = [...params.messages];
43
- messages[lastUserIdx] = {
44
- ...messages[lastUserIdx],
45
- content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
46
- };
47
- body.messages = messages.map(m => ({ role: m.role, content: m.content }));
48
- }
49
- }
50
-
51
- const response = await fetch(url, {
52
- method: 'POST',
53
- headers: {
54
- 'Content-Type': 'application/json',
55
- 'Authorization': `Bearer ${this.apiKey}`,
56
- },
57
- body: JSON.stringify(body),
58
- });
59
-
60
- if (!response.ok) {
61
- const error = await response.text();
62
- throw new Error(`MiniMax API error: ${response.status} - ${error}`);
63
- }
64
-
65
- const data = await response.json() as {
66
- choices?: Array<{ message?: { content?: string } }>;
67
- usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
68
- };
69
-
70
- const content = data.choices?.[0]?.message?.content || '';
71
-
72
- return {
73
- content,
74
- usage: data.usage ? {
75
- promptTokens: data.usage.prompt_tokens || 0,
76
- completionTokens: data.usage.completion_tokens || 0,
77
- totalTokens: data.usage.total_tokens || 0,
78
- } : undefined,
79
- };
80
- }
81
- }
@@ -1,82 +0,0 @@
1
- /**
2
- * Moonshot Provider - Moonshot AI (Kimi) API
3
- */
4
-
5
- import { BaseProvider } from './base.js';
6
- import type { InvokeParams, InvokeResult } from '../types.js';
7
-
8
- export class MoonshotProvider extends BaseProvider {
9
- name = 'moonshot';
10
- private apiKey: string;
11
- private model: string;
12
- private baseUrl = 'https://api.moonshot.cn/v1';
13
-
14
- constructor(apiKey?: string, model = 'kimi-k2.5') {
15
- super();
16
- this.apiKey = apiKey || process.env.MOONSHOT_API_KEY || '';
17
- this.model = model;
18
- }
19
-
20
- isConfigured(): boolean {
21
- return !!this.apiKey;
22
- }
23
-
24
- async invoke(params: InvokeParams): Promise<InvokeResult> {
25
- if (!this.isConfigured()) {
26
- throw new Error('Moonshot API key not configured. Set MOONSHOT_API_KEY environment variable.');
27
- }
28
-
29
- const url = `${this.baseUrl}/chat/completions`;
30
-
31
- const body: Record<string, unknown> = {
32
- model: this.model,
33
- messages: params.messages.map(m => ({ role: m.role, content: m.content })),
34
- temperature: params.temperature ?? 0.7,
35
- max_tokens: params.maxTokens ?? 4096,
36
- };
37
-
38
- // Add JSON mode if schema provided
39
- if (params.jsonSchema) {
40
- body.response_format = { type: 'json_object' };
41
- const lastUserIdx = params.messages.findLastIndex(m => m.role === 'user');
42
- if (lastUserIdx >= 0) {
43
- const messages = [...params.messages];
44
- messages[lastUserIdx] = {
45
- ...messages[lastUserIdx],
46
- content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
47
- };
48
- body.messages = messages.map(m => ({ role: m.role, content: m.content }));
49
- }
50
- }
51
-
52
- const response = await fetch(url, {
53
- method: 'POST',
54
- headers: {
55
- 'Content-Type': 'application/json',
56
- 'Authorization': `Bearer ${this.apiKey}`,
57
- },
58
- body: JSON.stringify(body),
59
- });
60
-
61
- if (!response.ok) {
62
- const error = await response.text();
63
- throw new Error(`Moonshot API error: ${response.status} - ${error}`);
64
- }
65
-
66
- const data = await response.json() as {
67
- choices?: Array<{ message?: { content?: string } }>;
68
- usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
69
- };
70
-
71
- const content = data.choices?.[0]?.message?.content || '';
72
-
73
- return {
74
- content,
75
- usage: data.usage ? {
76
- promptTokens: data.usage.prompt_tokens || 0,
77
- completionTokens: data.usage.completion_tokens || 0,
78
- totalTokens: data.usage.total_tokens || 0,
79
- } : undefined,
80
- };
81
- }
82
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * Ollama Provider - Local LLM via Ollama
3
- */
4
-
5
- import { BaseProvider } from './base.js';
6
- import type { InvokeParams, InvokeResult } from '../types.js';
7
-
8
- export class OllamaProvider extends BaseProvider {
9
- name = 'ollama';
10
- private model: string;
11
- private baseUrl: string;
12
-
13
- constructor(model = 'llama4', baseUrl = 'http://localhost:11434') {
14
- super();
15
- this.model = process.env.OLLAMA_MODEL || model;
16
- this.baseUrl = process.env.OLLAMA_HOST || baseUrl;
17
- }
18
-
19
- isConfigured(): boolean {
20
- return true; // Ollama doesn't need API key
21
- }
22
-
23
- async invoke(params: InvokeParams): Promise<InvokeResult> {
24
- const url = `${this.baseUrl}/api/chat`;
25
-
26
- let messages = params.messages.map(m => ({ role: m.role, content: m.content }));
27
-
28
- // Add JSON mode if schema provided
29
- if (params.jsonSchema) {
30
- const lastUserIdx = messages.findLastIndex(m => m.role === 'user');
31
- if (lastUserIdx >= 0) {
32
- messages = [...messages];
33
- messages[lastUserIdx] = {
34
- ...messages[lastUserIdx],
35
- content: messages[lastUserIdx].content + this.buildJsonPrompt(params.jsonSchema),
36
- };
37
- }
38
- }
39
-
40
- const body: Record<string, unknown> = {
41
- model: this.model,
42
- messages,
43
- stream: false,
44
- options: {
45
- temperature: params.temperature ?? 0.7,
46
- num_predict: params.maxTokens ?? 4096,
47
- },
48
- };
49
-
50
- // Request JSON format
51
- if (params.jsonSchema) {
52
- body.format = 'json';
53
- }
54
-
55
- const response = await fetch(url, {
56
- method: 'POST',
57
- headers: { 'Content-Type': 'application/json' },
58
- body: JSON.stringify(body),
59
- });
60
-
61
- if (!response.ok) {
62
- const error = await response.text();
63
- throw new Error(`Ollama API error: ${response.status} - ${error}`);
64
- }
65
-
66
- const data = await response.json() as {
67
- message?: { content?: string };
68
- prompt_eval_count?: number;
69
- eval_count?: number;
70
- };
71
-
72
- const content = data.message?.content || '';
73
-
74
- return {
75
- content,
76
- usage: {
77
- promptTokens: data.prompt_eval_count || 0,
78
- completionTokens: data.eval_count || 0,
79
- totalTokens: (data.prompt_eval_count || 0) + (data.eval_count || 0),
80
- },
81
- };
82
- }
83
- }