@astack-tech/integrations 0.2.0-beta.7 → 0.2.0-beta.8
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/CHANGELOG.md +11 -0
- package/README.md +22 -1
- package/dist/index.cjs +27 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +27 -9
- package/dist/index.js.map +1 -1
- package/dist/model-provider/index.cjs +29 -10
- package/dist/model-provider/index.cjs.map +1 -1
- package/dist/model-provider/index.d.cts +85 -14
- package/dist/model-provider/index.d.ts +85 -14
- package/dist/model-provider/index.js +27 -9
- package/dist/model-provider/index.js.map +1 -1
- package/package.json +6 -4
- package/src/index.ts +7 -1
- package/src/model-provider/deepseek/index.ts +27 -433
- package/src/model-provider/index.ts +14 -0
- package/src/model-provider/openai-compatible/index.ts +499 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @astack-tech/integrations
|
|
2
2
|
|
|
3
|
+
## 0.2.0-beta.8
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9aab43a: Add `ModelProvider.OpenAICompatible`, a provider for any API that speaks the OpenAI chat completions protocol: OpenAI and the compatible endpoints of DeepSeek, Qwen, Moonshot, Ollama, vLLM and others. Pass `model`, and `baseURL` for providers other than OpenAI; `name` labels errors and logs. `Deepseek` is now this provider with DeepSeek's defaults; its options, methods, ports and exported types are unchanged. The neutral message, tool and usage types are exported next to the `Deepseek*` names.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [1aba97f]
|
|
12
|
+
- @astack-tech/core@0.2.0-beta.3
|
|
13
|
+
|
|
3
14
|
## 0.2.0-beta.7
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ const text = await model.run('What is flow-based programming?');
|
|
|
25
25
|
const reply = await model.chatCompletion([{ role: 'user', content: 'Hello' }]);
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
`Deepseek`
|
|
28
|
+
`Deepseek` and `OpenAICompatible` are also available from the subpath: `import { Deepseek, OpenAICompatible } from '@astack-tech/integrations/model-provider'`.
|
|
29
29
|
|
|
30
30
|
## Deepseek
|
|
31
31
|
|
|
@@ -56,8 +56,29 @@ Uses the OpenAI-compatible DeepSeek API through the official `openai` client.
|
|
|
56
56
|
|
|
57
57
|
`Deepseek` satisfies the `ModelProvider` interface of `@astack-tech/components`, so it can drive `Agent` and `StreamingAgent` directly.
|
|
58
58
|
|
|
59
|
+
## OpenAICompatible
|
|
60
|
+
|
|
61
|
+
Calls any API that speaks the OpenAI chat completions protocol: OpenAI and the compatible endpoints of DeepSeek, Qwen, Moonshot, Ollama, vLLM and others. `Deepseek` is this provider with DeepSeek's defaults, so methods, ports and the other options are the same.
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { ModelProvider } from '@astack-tech/integrations';
|
|
65
|
+
|
|
66
|
+
const model = new ModelProvider.OpenAICompatible({
|
|
67
|
+
apiKey: process.env['OPENAI_API_KEY'] ?? '',
|
|
68
|
+
model: 'gpt-4o-mini',
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
| Option | Default | Description |
|
|
73
|
+
| --------- | --------------------------- | -------------------------------- |
|
|
74
|
+
| `apiKey` | — | API key of the provider |
|
|
75
|
+
| `model` | — | Model name (required) |
|
|
76
|
+
| `baseURL` | `https://api.openai.com/v1` | API base URL |
|
|
77
|
+
| `name` | `The model API` | Provider name in errors and logs |
|
|
78
|
+
|
|
59
79
|
## Learn more
|
|
60
80
|
|
|
81
|
+
- [API reference](https://astack.tech/docs/api/integrations): every export, generated from the source
|
|
61
82
|
- [Model providers](https://astack.tech/docs/model-providers), including how to write your own
|
|
62
83
|
- Example: [chat](https://astack.tech/examples/chat)
|
|
63
84
|
|
package/dist/index.cjs
CHANGED
|
@@ -37,14 +37,15 @@ module.exports = __toCommonJS(src_exports);
|
|
|
37
37
|
// src/model-provider/index.ts
|
|
38
38
|
var model_provider_exports = {};
|
|
39
39
|
__export(model_provider_exports, {
|
|
40
|
-
Deepseek: () => deepseek_default
|
|
40
|
+
Deepseek: () => deepseek_default,
|
|
41
|
+
OpenAICompatible: () => openai_compatible_default
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
// src/model-provider/
|
|
44
|
+
// src/model-provider/openai-compatible/index.ts
|
|
44
45
|
var import_core = require("@astack-tech/core");
|
|
45
46
|
var import_openai = __toESM(require("openai"), 1);
|
|
46
|
-
var DEFAULT_BASE_URL = "https://api.
|
|
47
|
-
var
|
|
47
|
+
var DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
48
|
+
var DEFAULT_NAME = "The model API";
|
|
48
49
|
var DEFAULT_TEMPERATURE = 0.7;
|
|
49
50
|
var FALLBACK_TEXT = "API call failed";
|
|
50
51
|
function isRecord(value) {
|
|
@@ -85,7 +86,7 @@ function mapUsage(usage) {
|
|
|
85
86
|
...usage.prompt_cache_miss_tokens === void 0 ? {} : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
|
-
var
|
|
89
|
+
var OpenAICompatible = class extends import_core.Component {
|
|
89
90
|
client;
|
|
90
91
|
model;
|
|
91
92
|
temperature;
|
|
@@ -94,6 +95,7 @@ var Deepseek = class extends import_core.Component {
|
|
|
94
95
|
systemPrompt;
|
|
95
96
|
tools;
|
|
96
97
|
verbose;
|
|
98
|
+
name;
|
|
97
99
|
constructor(config) {
|
|
98
100
|
super({});
|
|
99
101
|
this.client = new import_openai.default({
|
|
@@ -101,7 +103,8 @@ var Deepseek = class extends import_core.Component {
|
|
|
101
103
|
baseURL: config.baseURL ?? DEFAULT_BASE_URL,
|
|
102
104
|
dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false
|
|
103
105
|
});
|
|
104
|
-
this.model = config.model
|
|
106
|
+
this.model = config.model;
|
|
107
|
+
this.name = config.name ?? DEFAULT_NAME;
|
|
105
108
|
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
106
109
|
this.maxTokens = config.maxTokens;
|
|
107
110
|
this.topP = config.topP;
|
|
@@ -204,7 +207,7 @@ var Deepseek = class extends import_core.Component {
|
|
|
204
207
|
/**
|
|
205
208
|
* Runs the model outside a pipeline.
|
|
206
209
|
*
|
|
207
|
-
* @param input A prompt string or a list of messages.
|
|
210
|
+
* @param input - A prompt string or a list of messages.
|
|
208
211
|
*/
|
|
209
212
|
run(input) {
|
|
210
213
|
return typeof input === "string" ? this.generateCompletion(input) : this.chatCompletion(input);
|
|
@@ -271,16 +274,31 @@ var Deepseek = class extends import_core.Component {
|
|
|
271
274
|
firstMessage(response) {
|
|
272
275
|
const choice = response.choices[0];
|
|
273
276
|
if (choice === void 0) {
|
|
274
|
-
throw new Error(
|
|
277
|
+
throw new Error(`${this.name} returned no choices.`);
|
|
275
278
|
}
|
|
276
279
|
return choice.message;
|
|
277
280
|
}
|
|
278
281
|
logError(error) {
|
|
279
282
|
if (this.verbose) {
|
|
280
|
-
console.error(
|
|
283
|
+
console.error(`[${this.name}] API call failed:`, error);
|
|
281
284
|
}
|
|
282
285
|
}
|
|
283
286
|
};
|
|
287
|
+
var openai_compatible_default = OpenAICompatible;
|
|
288
|
+
|
|
289
|
+
// src/model-provider/deepseek/index.ts
|
|
290
|
+
var DEFAULT_BASE_URL2 = "https://api.deepseek.com/v1";
|
|
291
|
+
var DEFAULT_MODEL = "deepseek-chat";
|
|
292
|
+
var Deepseek = class extends openai_compatible_default {
|
|
293
|
+
constructor(config) {
|
|
294
|
+
super({
|
|
295
|
+
...config,
|
|
296
|
+
model: config.model ?? DEFAULT_MODEL,
|
|
297
|
+
baseURL: config.baseURL ?? DEFAULT_BASE_URL2,
|
|
298
|
+
name: "DeepSeek"
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
};
|
|
284
302
|
var deepseek_default = Deepseek;
|
|
285
303
|
// Annotate the CommonJS export names for ESM import in node:
|
|
286
304
|
0 && (module.exports = {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/model-provider/index.ts","../src/model-provider/deepseek/index.ts"],"sourcesContent":["/**\n * AStack integrations: components that connect pipelines to external services.\n */\nexport * as ModelProvider from './model-provider';\n","export {\n default as Deepseek,\n type AssistantMessage as DeepseekAssistantMessage,\n type ChatCompletionOptions as DeepseekChatCompletionOptions,\n type DeepseekConfig,\n type Message as DeepseekMessage,\n type MessageRole as DeepseekMessageRole,\n type RawTool as DeepseekRawTool,\n type ResponseToolCall as DeepseekResponseToolCall,\n type StreamChunk as DeepseekStreamChunk,\n type StreamToolCall as DeepseekStreamToolCall,\n type TokenUsage as DeepseekTokenUsage,\n type ToolCall as DeepseekToolCall,\n} from './deepseek';\n","import { Component } from '@astack-tech/core';\nimport type { Port } from '@astack-tech/core';\nimport OpenAI from 'openai';\n\n/**\n * Options for the DeepSeek model provider.\n */\nexport interface DeepseekConfig {\n /** DeepSeek API key. */\n apiKey: string;\n /** Model name. Defaults to `deepseek-chat`. */\n model?: string | undefined;\n /** API base URL. Defaults to `https://api.deepseek.com/v1`. */\n baseURL?: string | undefined;\n /** Sampling temperature. Defaults to `0.7`. */\n temperature?: number | undefined;\n /** Maximum number of generated tokens. */\n maxTokens?: number | undefined;\n /** Nucleus sampling probability. */\n topP?: number | undefined;\n /** System prompt added before every request. */\n systemPrompt?: string | undefined;\n /**\n * Tools given as `{ name, description, parameters }` objects.\n * When this list is not empty, it takes precedence over `tools`.\n */\n rawTools?: RawTool[] | undefined;\n /** Tools in the OpenAI-compatible `{ type: 'function', function }` format. */\n tools?: unknown[] | undefined;\n /** Allows the OpenAI client to run in a browser. Defaults to `false`. */\n dangerouslyAllowBrowser?: boolean | undefined;\n /** Logs API errors to the console. Defaults to `false`. */\n verbose?: boolean | undefined;\n}\n\n/**\n * Tool description accepted by `rawTools` and `temporaryTools`.\n */\nexport interface RawTool {\n name: string;\n description: string;\n parameters?: Record<string, unknown> | undefined;\n}\n\n/**\n * Role of a chat message.\n */\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Tool call in the internal format.\n */\nexport interface ToolCall {\n /** Identifier assigned by the API. */\n id?: string | undefined;\n /** Name of the tool. */\n tool_name: string;\n /** Parsed arguments. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Tool call returned by `chatCompletion`. It carries both the OpenAI shape\n * (`type`, `function`) and the internal shape (`tool_name`, `arguments`).\n */\nexport interface ResponseToolCall {\n id: string;\n type: 'function';\n function: { name: string; arguments: string };\n tool_name: string;\n arguments: Record<string, unknown>;\n}\n\n/**\n * Partial tool call emitted while streaming. `arguments` holds the raw JSON fragment.\n */\nexport interface StreamToolCall {\n id: string;\n type: 'function';\n function: { name: string; arguments: string };\n tool_name: string;\n arguments: string;\n}\n\n/**\n * Token usage reported by the API.\n */\nexport interface TokenUsage {\n completion_tokens: number;\n prompt_tokens: number;\n prompt_cache_hit_tokens?: number | undefined;\n prompt_cache_miss_tokens?: number | undefined;\n total_tokens: number;\n}\n\n/**\n * Chat message accepted as input. It matches the agent message contract in\n * `@astack-tech/components`, so agent histories can be passed directly.\n */\nexport interface Message {\n /** One of `system`, `user`, `assistant` or `tool` (see `MessageRole`). */\n role: string;\n content?: string | undefined;\n /** Accepted for compatibility. Assistant tool calls are not forwarded to the API. */\n tool_calls?: readonly unknown[] | undefined;\n /** Identifier of the call that a `tool` message answers. */\n tool_call_id?: string | undefined;\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Assistant message returned by `chatCompletion`.\n */\nexport interface AssistantMessage {\n role: 'assistant';\n content: string;\n tool_calls?: ResponseToolCall[] | undefined;\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Chunk yielded by `streamChatCompletion`.\n */\nexport interface StreamChunk {\n role: 'assistant';\n content: string;\n tool_calls?: StreamToolCall[] | undefined;\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Per-call options.\n */\nexport interface ChatCompletionOptions {\n /** Tools for this call only. They replace the configured tools. */\n temporaryTools?: unknown[] | undefined;\n}\n\ntype ChatMessageParam = OpenAI.Chat.ChatCompletionMessageParam;\ntype ChatTool = OpenAI.Chat.ChatCompletionTool;\n\ninterface DeepseekUsage {\n completion_tokens?: number;\n prompt_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_cache_miss_tokens?: number;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.deepseek.com/v1';\nconst DEFAULT_MODEL = 'deepseek-chat';\nconst DEFAULT_TEMPERATURE = 0.7;\nconst FALLBACK_TEXT = 'API call failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Converts a `{ name, description, parameters }` object to the OpenAI tool format.\n * Objects already in the OpenAI format are returned unchanged.\n */\nfunction toApiTool(tool: unknown): ChatTool {\n if (isRecord(tool) && tool['type'] === 'function') {\n return tool as unknown as ChatTool;\n }\n const raw = isRecord(tool) ? tool : {};\n const { name, description, parameters } = raw;\n return {\n type: 'function',\n function: {\n name: typeof name === 'string' ? name : '',\n description: typeof description === 'string' ? description : '',\n parameters: isRecord(parameters) ? parameters : {},\n },\n };\n}\n\n/**\n * Parses tool-call arguments. Anything that is not a JSON object becomes `{}`.\n */\nfunction parseArguments(raw: string): Record<string, unknown> {\n if (raw.trim().length === 0) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction mapUsage(usage: DeepseekUsage): TokenUsage {\n return {\n completion_tokens: usage.completion_tokens ?? 0,\n prompt_tokens: usage.prompt_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n ...(usage.prompt_cache_hit_tokens === undefined\n ? {}\n : { prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens }),\n ...(usage.prompt_cache_miss_tokens === undefined\n ? {}\n : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }),\n };\n}\n\n/**\n * DeepSeek model provider. It calls the DeepSeek API through the OpenAI-compatible client.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass Deepseek extends Component {\n private readonly client: OpenAI;\n private readonly model: string;\n private readonly temperature: number;\n private readonly maxTokens: number | undefined;\n private readonly topP: number | undefined;\n private readonly systemPrompt: string | undefined;\n private readonly tools: unknown[] | undefined;\n private readonly verbose: boolean;\n\n constructor(config: DeepseekConfig) {\n super({});\n\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false,\n });\n\n this.model = config.model ?? DEFAULT_MODEL;\n this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;\n this.maxTokens = config.maxTokens;\n this.topP = config.topP;\n this.systemPrompt = config.systemPrompt;\n this.verbose = config.verbose ?? false;\n this.tools =\n config.rawTools !== undefined && config.rawTools.length > 0\n ? config.rawTools.map(toApiTool)\n : config.tools;\n\n Component.Port.I('prompt').attach(this);\n Component.Port.I('messages').attach(this);\n Component.Port.O('completion').attach(this);\n Component.Port.O('message').attach(this);\n }\n\n /**\n * Generates a completion for a single prompt.\n *\n * @returns The text answer, or the JSON-encoded assistant message when it contains tool calls.\n */\n async generateCompletion(prompt: string): Promise<string> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: [...this.systemMessages(), { role: 'user', content: prompt }],\n ...this.toolsParam(this.tools),\n });\n\n const message = this.firstMessage(response);\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n return JSON.stringify(message);\n }\n return message.content ?? '';\n }\n\n /**\n * Sends a conversation and returns the assistant reply.\n */\n async chatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): Promise<AssistantMessage> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n });\n\n const message = this.firstMessage(response);\n const result: AssistantMessage = { role: 'assistant', content: message.content ?? '' };\n\n if (response.usage !== undefined) {\n result.usage = mapUsage(response.usage);\n }\n\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n result.tool_calls = message.tool_calls.map(toolCall => {\n if (toolCall.type !== 'function') {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n const rawArguments = toolCall.function.arguments;\n return {\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: rawArguments.length > 0 ? rawArguments : '{}',\n },\n tool_name: toolCall.function.name,\n arguments: parseArguments(rawArguments),\n };\n });\n }\n\n return result;\n }\n\n /**\n * Streams the assistant reply. Each chunk holds a text delta, tool-call deltas, or usage.\n */\n async *streamChatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): AsyncGenerator<StreamChunk> {\n const stream = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n stream: true,\n });\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n\n if (delta?.content) {\n yield { role: 'assistant', content: delta.content };\n }\n\n if (delta?.tool_calls) {\n yield {\n role: 'assistant',\n content: '',\n tool_calls: delta.tool_calls.map(toolCall => {\n const name = toolCall.function?.name ?? '';\n const args = toolCall.function?.arguments ?? '';\n return {\n id: toolCall.id ?? '',\n type: 'function',\n function: { name, arguments: args },\n tool_name: name,\n arguments: args,\n };\n }),\n };\n }\n\n if (chunk.usage) {\n yield { role: 'assistant', content: '', usage: mapUsage(chunk.usage) };\n }\n }\n }\n\n /**\n * Runs the model outside a pipeline.\n *\n * @param input A prompt string or a list of messages.\n */\n override run(input: string | Message[]): Promise<string | AssistantMessage> {\n return typeof input === 'string' ? this.generateCompletion(input) : this.chatCompletion(input);\n }\n\n /**\n * Connects the `prompt` and `messages` input ports to the model.\n * API errors produce a fallback value so the pipeline keeps flowing.\n */\n override _transform($i: Port, $o: Port): void {\n $i('prompt').receive((prompt: string) => {\n this.generateCompletion(prompt).then(\n completion => {\n $o('completion').send(completion);\n },\n (error: unknown) => {\n this.logError(error);\n $o('completion').send(FALLBACK_TEXT);\n }\n );\n });\n\n $i('messages').receive((messages: Message[]) => {\n this.chatCompletion(messages).then(\n message => {\n $o('message').send(message);\n },\n (error: unknown) => {\n this.logError(error);\n $o('message').send({ role: 'assistant', content: FALLBACK_TEXT });\n }\n );\n });\n }\n\n private baseRequest(): {\n model: string;\n temperature: number;\n max_tokens?: number;\n top_p?: number;\n } {\n return {\n model: this.model,\n temperature: this.temperature,\n ...(this.maxTokens === undefined ? {} : { max_tokens: this.maxTokens }),\n ...(this.topP === undefined ? {} : { top_p: this.topP }),\n };\n }\n\n private toolsParam(tools: unknown[] | undefined): { tools?: ChatTool[] } {\n return tools !== undefined && tools.length > 0 ? { tools: tools.map(toApiTool) } : {};\n }\n\n private systemMessages(): ChatMessageParam[] {\n return this.systemPrompt ? [{ role: 'system', content: this.systemPrompt }] : [];\n }\n\n /**\n * Converts input messages to API messages. Assistant `tool_calls` are not forwarded:\n * agents send tool results back as user messages, and the API rejects assistant tool\n * calls that are not followed by tool messages.\n */\n private formatMessages(messages: Message[]): ChatMessageParam[] {\n return [\n ...this.systemMessages(),\n ...messages.map(\n (message): ChatMessageParam =>\n ({\n role: message.role,\n content: message.content,\n ...(message.role === 'tool' && message.tool_call_id\n ? { tool_call_id: message.tool_call_id }\n : {}),\n }) as ChatMessageParam\n ),\n ];\n }\n\n private firstMessage(response: OpenAI.Chat.ChatCompletion): OpenAI.Chat.ChatCompletionMessage {\n const choice = response.choices[0];\n if (choice === undefined) {\n throw new Error('DeepSeek returned no choices.');\n }\n return choice.message;\n }\n\n private logError(error: unknown): void {\n if (this.verbose) {\n // eslint-disable-next-line no-console -- opt-in diagnostics controlled by `verbose`.\n console.error('[Deepseek] API call failed:', error);\n }\n }\n}\n\nexport default Deepseek;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;;;ACAA,kBAA0B;AAE1B,oBAAmB;AAmJnB,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;AAC5B,IAAM,gBAAgB;AAEtB,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAMA,SAAS,UAAU,MAAyB;AAC1C,MAAI,SAAS,IAAI,KAAK,KAAK,MAAM,MAAM,YAAY;AACjD,WAAO;AAAA,EACT;AACA,QAAM,MAAM,SAAS,IAAI,IAAI,OAAO,CAAC;AACrC,QAAM,EAAE,MAAM,aAAa,WAAW,IAAI;AAC1C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,MACR,MAAM,OAAO,SAAS,WAAW,OAAO;AAAA,MACxC,aAAa,OAAO,gBAAgB,WAAW,cAAc;AAAA,MAC7D,YAAY,SAAS,UAAU,IAAI,aAAa,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AAKA,SAAS,eAAe,KAAsC;AAC5D,MAAI,IAAI,KAAK,EAAE,WAAW,GAAG;AAC3B,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,WAAO,SAAS,MAAM,IAAI,SAAS,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,SAAS,OAAkC;AAClD,SAAO;AAAA,IACL,mBAAmB,MAAM,qBAAqB;AAAA,IAC9C,eAAe,MAAM,iBAAiB;AAAA,IACtC,cAAc,MAAM,gBAAgB;AAAA,IACpC,GAAI,MAAM,4BAA4B,SAClC,CAAC,IACD,EAAE,yBAAyB,MAAM,wBAAwB;AAAA,IAC7D,GAAI,MAAM,6BAA6B,SACnC,CAAC,IACD,EAAE,0BAA0B,MAAM,yBAAyB;AAAA,EACjE;AACF;AASA,IAAM,WAAN,cAAuB,sBAAU;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAAwB;AAClC,UAAM,CAAC,CAAC;AAER,SAAK,SAAS,IAAI,cAAAA,QAAO;AAAA,MACvB,QAAQ,OAAO;AAAA,MACf,SAAS,OAAO,WAAW;AAAA,MAC3B,yBAAyB,OAAO,2BAA2B;AAAA,IAC7D,CAAC;AAED,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,cAAc,OAAO,eAAe;AACzC,SAAK,YAAY,OAAO;AACxB,SAAK,OAAO,OAAO;AACnB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,QACH,OAAO,aAAa,UAAa,OAAO,SAAS,SAAS,IACtD,OAAO,SAAS,IAAI,SAAS,IAC7B,OAAO;AAEb,0BAAU,KAAK,EAAE,QAAQ,EAAE,OAAO,IAAI;AACtC,0BAAU,KAAK,EAAE,UAAU,EAAE,OAAO,IAAI;AACxC,0BAAU,KAAK,EAAE,YAAY,EAAE,OAAO,IAAI;AAC1C,0BAAU,KAAK,EAAE,SAAS,EAAE,OAAO,IAAI;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,mBAAmB,QAAiC;AACxD,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,YAAY,OAAO;AAAA,MACzD,GAAG,KAAK,YAAY;AAAA,MACpB,UAAU,CAAC,GAAG,KAAK,eAAe,GAAG,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MACtE,GAAG,KAAK,WAAW,KAAK,KAAK;AAAA,IAC/B,CAAC;AAED,UAAM,UAAU,KAAK,aAAa,QAAQ;AAC1C,QAAI,QAAQ,eAAe,UAAa,QAAQ,WAAW,SAAS,GAAG;AACrE,aAAO,KAAK,UAAU,OAAO;AAAA,IAC/B;AACA,WAAO,QAAQ,WAAW;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,UACA,SAC2B;AAC3B,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,YAAY,OAAO;AAAA,MACzD,GAAG,KAAK,YAAY;AAAA,MACpB,UAAU,KAAK,eAAe,QAAQ;AAAA,MACtC,GAAG,KAAK,WAAW,SAAS,kBAAkB,KAAK,KAAK;AAAA,IAC1D,CAAC;AAED,UAAM,UAAU,KAAK,aAAa,QAAQ;AAC1C,UAAM,SAA2B,EAAE,MAAM,aAAa,SAAS,QAAQ,WAAW,GAAG;AAErF,QAAI,SAAS,UAAU,QAAW;AAChC,aAAO,QAAQ,SAAS,SAAS,KAAK;AAAA,IACxC;AAEA,QAAI,QAAQ,eAAe,UAAa,QAAQ,WAAW,SAAS,GAAG;AACrE,aAAO,aAAa,QAAQ,WAAW,IAAI,cAAY;AACrD,YAAI,SAAS,SAAS,YAAY;AAChC,gBAAM,IAAI,MAAM,+BAA+B,SAAS,IAAI,EAAE;AAAA,QAChE;AACA,cAAM,eAAe,SAAS,SAAS;AACvC,eAAO;AAAA,UACL,IAAI,SAAS;AAAA,UACb,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,SAAS,SAAS;AAAA,YACxB,WAAW,aAAa,SAAS,IAAI,eAAe;AAAA,UACtD;AAAA,UACA,WAAW,SAAS,SAAS;AAAA,UAC7B,WAAW,eAAe,YAAY;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,qBACL,UACA,SAC6B;AAC7B,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK,YAAY,OAAO;AAAA,MACvD,GAAG,KAAK,YAAY;AAAA,MACpB,UAAU,KAAK,eAAe,QAAQ;AAAA,MACtC,GAAG,KAAK,WAAW,SAAS,kBAAkB,KAAK,KAAK;AAAA,MACxD,QAAQ;AAAA,IACV,CAAC;AAED,qBAAiB,SAAS,QAAQ;AAChC,YAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAEhC,UAAI,OAAO,SAAS;AAClB,cAAM,EAAE,MAAM,aAAa,SAAS,MAAM,QAAQ;AAAA,MACpD;AAEA,UAAI,OAAO,YAAY;AACrB,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,YAAY,MAAM,WAAW,IAAI,cAAY;AAC3C,kBAAM,OAAO,SAAS,UAAU,QAAQ;AACxC,kBAAM,OAAO,SAAS,UAAU,aAAa;AAC7C,mBAAO;AAAA,cACL,IAAI,SAAS,MAAM;AAAA,cACnB,MAAM;AAAA,cACN,UAAU,EAAE,MAAM,WAAW,KAAK;AAAA,cAClC,WAAW;AAAA,cACX,WAAW;AAAA,YACb;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,UAAI,MAAM,OAAO;AACf,cAAM,EAAE,MAAM,aAAa,SAAS,IAAI,OAAO,SAAS,MAAM,KAAK,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOS,IAAI,OAA+D;AAC1E,WAAO,OAAO,UAAU,WAAW,KAAK,mBAAmB,KAAK,IAAI,KAAK,eAAe,KAAK;AAAA,EAC/F;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS,WAAW,IAAU,IAAgB;AAC5C,OAAG,QAAQ,EAAE,QAAQ,CAAC,WAAmB;AACvC,WAAK,mBAAmB,MAAM,EAAE;AAAA,QAC9B,gBAAc;AACZ,aAAG,YAAY,EAAE,KAAK,UAAU;AAAA,QAClC;AAAA,QACA,CAAC,UAAmB;AAClB,eAAK,SAAS,KAAK;AACnB,aAAG,YAAY,EAAE,KAAK,aAAa;AAAA,QACrC;AAAA,MACF;AAAA,IACF,CAAC;AAED,OAAG,UAAU,EAAE,QAAQ,CAAC,aAAwB;AAC9C,WAAK,eAAe,QAAQ,EAAE;AAAA,QAC5B,aAAW;AACT,aAAG,SAAS,EAAE,KAAK,OAAO;AAAA,QAC5B;AAAA,QACA,CAAC,UAAmB;AAClB,eAAK,SAAS,KAAK;AACnB,aAAG,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,SAAS,cAAc,CAAC;AAAA,QAClE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,cAKN;AACA,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK;AAAA,MAClB,GAAI,KAAK,cAAc,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,UAAU;AAAA,MACrE,GAAI,KAAK,SAAS,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,KAAK;AAAA,IACxD;AAAA,EACF;AAAA,EAEQ,WAAW,OAAsD;AACvE,WAAO,UAAU,UAAa,MAAM,SAAS,IAAI,EAAE,OAAO,MAAM,IAAI,SAAS,EAAE,IAAI,CAAC;AAAA,EACtF;AAAA,EAEQ,iBAAqC;AAC3C,WAAO,KAAK,eAAe,CAAC,EAAE,MAAM,UAAU,SAAS,KAAK,aAAa,CAAC,IAAI,CAAC;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAe,UAAyC;AAC9D,WAAO;AAAA,MACL,GAAG,KAAK,eAAe;AAAA,MACvB,GAAG,SAAS;AAAA,QACV,CAAC,aACE;AAAA,UACC,MAAM,QAAQ;AAAA,UACd,SAAS,QAAQ;AAAA,UACjB,GAAI,QAAQ,SAAS,UAAU,QAAQ,eACnC,EAAE,cAAc,QAAQ,aAAa,IACrC,CAAC;AAAA,QACP;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,UAAyE;AAC5F,UAAM,SAAS,SAAS,QAAQ,CAAC;AACjC,QAAI,WAAW,QAAW;AACxB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEQ,SAAS,OAAsB;AACrC,QAAI,KAAK,SAAS;AAEhB,cAAQ,MAAM,+BAA+B,KAAK;AAAA,IACpD;AAAA,EACF;AACF;AAEA,IAAO,mBAAQ;","names":["OpenAI"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/model-provider/index.ts","../src/model-provider/openai-compatible/index.ts","../src/model-provider/deepseek/index.ts"],"sourcesContent":["/**\n * Model provider integrations for AStack. `ModelProvider.OpenAICompatible` calls any API\n * that speaks the OpenAI chat completions protocol, and `ModelProvider.Deepseek` is that\n * provider set up for DeepSeek. Both satisfy the `ModelProvider` interface of\n * `@astack-tech/components`.\n *\n * @packageDocumentation\n */\n\nexport * as ModelProvider from './model-provider';\n","export {\n default as Deepseek,\n type AssistantMessage as DeepseekAssistantMessage,\n type ChatCompletionOptions as DeepseekChatCompletionOptions,\n type DeepseekConfig,\n type Message as DeepseekMessage,\n type MessageRole as DeepseekMessageRole,\n type RawTool as DeepseekRawTool,\n type ResponseToolCall as DeepseekResponseToolCall,\n type StreamChunk as DeepseekStreamChunk,\n type StreamToolCall as DeepseekStreamToolCall,\n type TokenUsage as DeepseekTokenUsage,\n type ToolCall as DeepseekToolCall,\n} from './deepseek';\nexport {\n default as OpenAICompatible,\n type AssistantMessage,\n type ChatCompletionOptions,\n type Message,\n type MessageRole,\n type OpenAICompatibleConfig,\n type RawTool,\n type ResponseToolCall,\n type StreamChunk,\n type StreamToolCall,\n type TokenUsage,\n type ToolCall,\n} from './openai-compatible';\n","import { Component } from '@astack-tech/core';\nimport type { Port } from '@astack-tech/core';\nimport OpenAI from 'openai';\n\n/**\n * Options for a provider that speaks the OpenAI chat completions API.\n */\nexport interface OpenAICompatibleConfig {\n /** API key of the provider. */\n apiKey: string;\n /** Model name, for example `gpt-4o-mini`, `qwen-plus` or `llama3.1`. */\n model: string;\n /** API base URL. Defaults to `https://api.openai.com/v1`. */\n baseURL?: string | undefined;\n /** Provider name used in errors and logs. Defaults to `The model API`. */\n name?: string | undefined;\n /** Sampling temperature. Defaults to `0.7`. */\n temperature?: number | undefined;\n /** Maximum number of generated tokens. */\n maxTokens?: number | undefined;\n /** Nucleus sampling probability. */\n topP?: number | undefined;\n /** System prompt added before every request. */\n systemPrompt?: string | undefined;\n /**\n * Tools given as `{ name, description, parameters }` objects.\n * When this list is not empty, it takes precedence over `tools`.\n */\n rawTools?: RawTool[] | undefined;\n /** Tools in the OpenAI-compatible `{ type: 'function', function }` format. */\n tools?: unknown[] | undefined;\n /** Allows the OpenAI client to run in a browser. Defaults to `false`. */\n dangerouslyAllowBrowser?: boolean | undefined;\n /** Logs API errors to the console. Defaults to `false`. */\n verbose?: boolean | undefined;\n}\n\n/**\n * Tool description accepted by `rawTools` and `temporaryTools`.\n */\nexport interface RawTool {\n /** Unique tool name. */\n name: string;\n /** Description that tells the model when to use the tool. */\n description: string;\n /** JSON Schema of the arguments. Defaults to `{}`. */\n parameters?: Record<string, unknown> | undefined;\n}\n\n/**\n * Role of a chat message.\n */\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Tool call in the internal format.\n */\nexport interface ToolCall {\n /** Identifier assigned by the API. */\n id?: string | undefined;\n /** Name of the tool. */\n tool_name: string;\n /** Parsed arguments. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Tool call returned by `chatCompletion`. It carries both the OpenAI shape\n * (`type`, `function`) and the internal shape (`tool_name`, `arguments`).\n */\nexport interface ResponseToolCall {\n /** Identifier assigned by the API. A `tool` message answers the call with it. */\n id: string;\n /** Always `function`. */\n type: 'function';\n /** The call in the OpenAI shape: function name and raw JSON arguments. An empty argument string is sent as `{}`. */\n function: {\n /** Name of the tool to call. */\n name: string;\n /** Arguments as JSON text. */\n arguments: string;\n };\n /** Name of the tool, same as `function.name`. */\n tool_name: string;\n /** Parsed arguments. JSON that is not an object becomes `{}`. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Partial tool call emitted while streaming. `arguments` holds the raw JSON fragment.\n */\nexport interface StreamToolCall {\n /** Identifier assigned by the API. Only the first delta of a call carries it; later deltas have `''`. */\n id: string;\n /** Always `function`. */\n type: 'function';\n /** The delta in the OpenAI shape. `arguments` holds only this delta's JSON fragment. */\n function: {\n /** Name of the tool to call. */\n name: string;\n /** Arguments as JSON text. */\n arguments: string;\n };\n /** Name of the tool when this delta carries it, otherwise `''`. */\n tool_name: string;\n /** Raw JSON fragment of this delta. Concatenate the fragments of a call to get its arguments. */\n arguments: string;\n}\n\n/**\n * Token usage reported by the API.\n */\nexport interface TokenUsage {\n /** Tokens in the generated reply. */\n completion_tokens: number;\n /** Tokens in the request. */\n prompt_tokens: number;\n /** Prompt tokens served from the provider's context cache (reported by DeepSeek). */\n prompt_cache_hit_tokens?: number | undefined;\n /** Prompt tokens not served from the cache. */\n prompt_cache_miss_tokens?: number | undefined;\n /** Sum of prompt and completion tokens. */\n total_tokens: number;\n}\n\n/**\n * Chat message accepted as input. It matches the agent message contract in\n * `@astack-tech/components`, so agent histories can be passed directly.\n */\nexport interface Message {\n /** One of `system`, `user`, `assistant` or `tool` (see `MessageRole`). */\n role: string;\n /** Text content. Omitted content is sent as no content. */\n content?: string | undefined;\n /** Accepted for compatibility. Assistant tool calls are not forwarded to the API. */\n tool_calls?: readonly unknown[] | undefined;\n /** Identifier of the call that a `tool` message answers. */\n tool_call_id?: string | undefined;\n /** Ignored on input. Present so agent histories can be passed unchanged. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Assistant message returned by `chatCompletion`.\n */\nexport interface AssistantMessage {\n /** Always `assistant`. */\n role: 'assistant';\n /** Reply text. Empty when the model only calls tools. */\n content: string;\n /** Tool calls requested by the model, if any. */\n tool_calls?: ResponseToolCall[] | undefined;\n /** Token usage of this request, when the API reports it. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Chunk yielded by `streamChatCompletion`.\n */\nexport interface StreamChunk {\n /** Always `assistant`. */\n role: 'assistant';\n /** Text delta. Empty in chunks that carry tool calls or usage. */\n content: string;\n /** Tool-call deltas in this chunk. */\n tool_calls?: StreamToolCall[] | undefined;\n /** Token usage. Sent once, in the final chunk, when the API reports it. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Per-call options.\n */\nexport interface ChatCompletionOptions {\n /** Tools for this call only. They replace the configured tools. */\n temporaryTools?: unknown[] | undefined;\n}\n\ntype ChatMessageParam = OpenAI.Chat.ChatCompletionMessageParam;\ntype ChatTool = OpenAI.Chat.ChatCompletionTool;\n\ninterface ApiUsage {\n completion_tokens?: number;\n prompt_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_cache_miss_tokens?: number;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.openai.com/v1';\nconst DEFAULT_NAME = 'The model API';\nconst DEFAULT_TEMPERATURE = 0.7;\nconst FALLBACK_TEXT = 'API call failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Converts a `{ name, description, parameters }` object to the OpenAI tool format.\n * Objects already in the OpenAI format are returned unchanged.\n */\nfunction toApiTool(tool: unknown): ChatTool {\n if (isRecord(tool) && tool['type'] === 'function') {\n return tool as unknown as ChatTool;\n }\n const raw = isRecord(tool) ? tool : {};\n const { name, description, parameters } = raw;\n return {\n type: 'function',\n function: {\n name: typeof name === 'string' ? name : '',\n description: typeof description === 'string' ? description : '',\n parameters: isRecord(parameters) ? parameters : {},\n },\n };\n}\n\n/**\n * Parses tool-call arguments. Anything that is not a JSON object becomes `{}`.\n */\nfunction parseArguments(raw: string): Record<string, unknown> {\n if (raw.trim().length === 0) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction mapUsage(usage: ApiUsage): TokenUsage {\n return {\n completion_tokens: usage.completion_tokens ?? 0,\n prompt_tokens: usage.prompt_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n ...(usage.prompt_cache_hit_tokens === undefined\n ? {}\n : { prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens }),\n ...(usage.prompt_cache_miss_tokens === undefined\n ? {}\n : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }),\n };\n}\n\n/**\n * Model provider for any API that speaks the OpenAI chat completions protocol:\n * OpenAI itself, and the compatible endpoints of DeepSeek, Qwen, Moonshot, Ollama,\n * vLLM and others. Set `baseURL` and `model` for the provider you use.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass OpenAICompatible extends Component {\n private readonly client: OpenAI;\n private readonly model: string;\n private readonly temperature: number;\n private readonly maxTokens: number | undefined;\n private readonly topP: number | undefined;\n private readonly systemPrompt: string | undefined;\n private readonly tools: unknown[] | undefined;\n private readonly verbose: boolean;\n private readonly name: string;\n\n constructor(config: OpenAICompatibleConfig) {\n super({});\n\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false,\n });\n\n this.model = config.model;\n this.name = config.name ?? DEFAULT_NAME;\n this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;\n this.maxTokens = config.maxTokens;\n this.topP = config.topP;\n this.systemPrompt = config.systemPrompt;\n this.verbose = config.verbose ?? false;\n this.tools =\n config.rawTools !== undefined && config.rawTools.length > 0\n ? config.rawTools.map(toApiTool)\n : config.tools;\n\n Component.Port.I('prompt').attach(this);\n Component.Port.I('messages').attach(this);\n Component.Port.O('completion').attach(this);\n Component.Port.O('message').attach(this);\n }\n\n /**\n * Generates a completion for a single prompt.\n *\n * @returns The text answer, or the JSON-encoded assistant message when it contains tool calls.\n */\n async generateCompletion(prompt: string): Promise<string> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: [...this.systemMessages(), { role: 'user', content: prompt }],\n ...this.toolsParam(this.tools),\n });\n\n const message = this.firstMessage(response);\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n return JSON.stringify(message);\n }\n return message.content ?? '';\n }\n\n /**\n * Sends a conversation and returns the assistant reply.\n */\n async chatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): Promise<AssistantMessage> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n });\n\n const message = this.firstMessage(response);\n const result: AssistantMessage = { role: 'assistant', content: message.content ?? '' };\n\n if (response.usage !== undefined) {\n result.usage = mapUsage(response.usage);\n }\n\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n result.tool_calls = message.tool_calls.map(toolCall => {\n if (toolCall.type !== 'function') {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n const rawArguments = toolCall.function.arguments;\n return {\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: rawArguments.length > 0 ? rawArguments : '{}',\n },\n tool_name: toolCall.function.name,\n arguments: parseArguments(rawArguments),\n };\n });\n }\n\n return result;\n }\n\n /**\n * Streams the assistant reply. Each chunk holds a text delta, tool-call deltas, or usage.\n */\n async *streamChatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): AsyncGenerator<StreamChunk> {\n const stream = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n stream: true,\n });\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n\n if (delta?.content) {\n yield { role: 'assistant', content: delta.content };\n }\n\n if (delta?.tool_calls) {\n yield {\n role: 'assistant',\n content: '',\n tool_calls: delta.tool_calls.map(toolCall => {\n const name = toolCall.function?.name ?? '';\n const args = toolCall.function?.arguments ?? '';\n return {\n id: toolCall.id ?? '',\n type: 'function',\n function: { name, arguments: args },\n tool_name: name,\n arguments: args,\n };\n }),\n };\n }\n\n if (chunk.usage) {\n yield { role: 'assistant', content: '', usage: mapUsage(chunk.usage) };\n }\n }\n }\n\n /**\n * Runs the model outside a pipeline.\n *\n * @param input - A prompt string or a list of messages.\n */\n override run(input: string | Message[]): Promise<string | AssistantMessage> {\n return typeof input === 'string' ? this.generateCompletion(input) : this.chatCompletion(input);\n }\n\n /**\n * Connects the `prompt` and `messages` input ports to the model.\n * API errors produce a fallback value so the pipeline keeps flowing.\n */\n override _transform($i: Port, $o: Port): void {\n $i('prompt').receive((prompt: string) => {\n this.generateCompletion(prompt).then(\n completion => {\n $o('completion').send(completion);\n },\n (error: unknown) => {\n this.logError(error);\n $o('completion').send(FALLBACK_TEXT);\n }\n );\n });\n\n $i('messages').receive((messages: Message[]) => {\n this.chatCompletion(messages).then(\n message => {\n $o('message').send(message);\n },\n (error: unknown) => {\n this.logError(error);\n $o('message').send({ role: 'assistant', content: FALLBACK_TEXT });\n }\n );\n });\n }\n\n private baseRequest(): {\n model: string;\n temperature: number;\n max_tokens?: number;\n top_p?: number;\n } {\n return {\n model: this.model,\n temperature: this.temperature,\n ...(this.maxTokens === undefined ? {} : { max_tokens: this.maxTokens }),\n ...(this.topP === undefined ? {} : { top_p: this.topP }),\n };\n }\n\n private toolsParam(tools: unknown[] | undefined): { tools?: ChatTool[] } {\n return tools !== undefined && tools.length > 0 ? { tools: tools.map(toApiTool) } : {};\n }\n\n private systemMessages(): ChatMessageParam[] {\n return this.systemPrompt ? [{ role: 'system', content: this.systemPrompt }] : [];\n }\n\n /**\n * Converts input messages to API messages. Assistant `tool_calls` are not forwarded:\n * agents send tool results back as user messages, and the API rejects assistant tool\n * calls that are not followed by tool messages.\n */\n private formatMessages(messages: Message[]): ChatMessageParam[] {\n return [\n ...this.systemMessages(),\n ...messages.map(\n (message): ChatMessageParam =>\n ({\n role: message.role,\n content: message.content,\n ...(message.role === 'tool' && message.tool_call_id\n ? { tool_call_id: message.tool_call_id }\n : {}),\n }) as ChatMessageParam\n ),\n ];\n }\n\n private firstMessage(response: OpenAI.Chat.ChatCompletion): OpenAI.Chat.ChatCompletionMessage {\n const choice = response.choices[0];\n if (choice === undefined) {\n throw new Error(`${this.name} returned no choices.`);\n }\n return choice.message;\n }\n\n private logError(error: unknown): void {\n if (this.verbose) {\n // eslint-disable-next-line no-console -- opt-in diagnostics controlled by `verbose`.\n console.error(`[${this.name}] API call failed:`, error);\n }\n }\n}\n\nexport default OpenAICompatible;\n","import OpenAICompatible from '../openai-compatible';\nimport type { OpenAICompatibleConfig } from '../openai-compatible';\n\nexport type {\n AssistantMessage,\n ChatCompletionOptions,\n Message,\n MessageRole,\n RawTool,\n ResponseToolCall,\n StreamChunk,\n StreamToolCall,\n TokenUsage,\n ToolCall,\n} from '../openai-compatible';\n\nconst DEFAULT_BASE_URL = 'https://api.deepseek.com/v1';\nconst DEFAULT_MODEL = 'deepseek-chat';\n\n/**\n * Options for the DeepSeek model provider. They are the options of\n * `OpenAICompatible`, with DeepSeek's endpoint and model as defaults.\n */\nexport interface DeepseekConfig extends Omit<OpenAICompatibleConfig, 'model' | 'name'> {\n /** Model name. Defaults to `deepseek-chat`. */\n model?: string | undefined;\n /** API base URL. Defaults to `https://api.deepseek.com/v1`. */\n baseURL?: string | undefined;\n}\n\n/**\n * DeepSeek model provider: `OpenAICompatible` set up for the DeepSeek API.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass Deepseek extends OpenAICompatible {\n constructor(config: DeepseekConfig) {\n super({\n ...config,\n model: config.model ?? DEFAULT_MODEL,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n name: 'DeepSeek',\n });\n }\n}\n\nexport default Deepseek;\n"],"mappings":"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","names":["OpenAI","DEFAULT_BASE_URL"]}
|
package/dist/index.js
CHANGED
|
@@ -7,14 +7,15 @@ var __export = (target, all) => {
|
|
|
7
7
|
// src/model-provider/index.ts
|
|
8
8
|
var model_provider_exports = {};
|
|
9
9
|
__export(model_provider_exports, {
|
|
10
|
-
Deepseek: () => deepseek_default
|
|
10
|
+
Deepseek: () => deepseek_default,
|
|
11
|
+
OpenAICompatible: () => openai_compatible_default
|
|
11
12
|
});
|
|
12
13
|
|
|
13
|
-
// src/model-provider/
|
|
14
|
+
// src/model-provider/openai-compatible/index.ts
|
|
14
15
|
import { Component } from "@astack-tech/core";
|
|
15
16
|
import OpenAI from "openai";
|
|
16
|
-
var DEFAULT_BASE_URL = "https://api.
|
|
17
|
-
var
|
|
17
|
+
var DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
18
|
+
var DEFAULT_NAME = "The model API";
|
|
18
19
|
var DEFAULT_TEMPERATURE = 0.7;
|
|
19
20
|
var FALLBACK_TEXT = "API call failed";
|
|
20
21
|
function isRecord(value) {
|
|
@@ -55,7 +56,7 @@ function mapUsage(usage) {
|
|
|
55
56
|
...usage.prompt_cache_miss_tokens === void 0 ? {} : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
|
-
var
|
|
59
|
+
var OpenAICompatible = class extends Component {
|
|
59
60
|
client;
|
|
60
61
|
model;
|
|
61
62
|
temperature;
|
|
@@ -64,6 +65,7 @@ var Deepseek = class extends Component {
|
|
|
64
65
|
systemPrompt;
|
|
65
66
|
tools;
|
|
66
67
|
verbose;
|
|
68
|
+
name;
|
|
67
69
|
constructor(config) {
|
|
68
70
|
super({});
|
|
69
71
|
this.client = new OpenAI({
|
|
@@ -71,7 +73,8 @@ var Deepseek = class extends Component {
|
|
|
71
73
|
baseURL: config.baseURL ?? DEFAULT_BASE_URL,
|
|
72
74
|
dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false
|
|
73
75
|
});
|
|
74
|
-
this.model = config.model
|
|
76
|
+
this.model = config.model;
|
|
77
|
+
this.name = config.name ?? DEFAULT_NAME;
|
|
75
78
|
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
76
79
|
this.maxTokens = config.maxTokens;
|
|
77
80
|
this.topP = config.topP;
|
|
@@ -174,7 +177,7 @@ var Deepseek = class extends Component {
|
|
|
174
177
|
/**
|
|
175
178
|
* Runs the model outside a pipeline.
|
|
176
179
|
*
|
|
177
|
-
* @param input A prompt string or a list of messages.
|
|
180
|
+
* @param input - A prompt string or a list of messages.
|
|
178
181
|
*/
|
|
179
182
|
run(input) {
|
|
180
183
|
return typeof input === "string" ? this.generateCompletion(input) : this.chatCompletion(input);
|
|
@@ -241,16 +244,31 @@ var Deepseek = class extends Component {
|
|
|
241
244
|
firstMessage(response) {
|
|
242
245
|
const choice = response.choices[0];
|
|
243
246
|
if (choice === void 0) {
|
|
244
|
-
throw new Error(
|
|
247
|
+
throw new Error(`${this.name} returned no choices.`);
|
|
245
248
|
}
|
|
246
249
|
return choice.message;
|
|
247
250
|
}
|
|
248
251
|
logError(error) {
|
|
249
252
|
if (this.verbose) {
|
|
250
|
-
console.error(
|
|
253
|
+
console.error(`[${this.name}] API call failed:`, error);
|
|
251
254
|
}
|
|
252
255
|
}
|
|
253
256
|
};
|
|
257
|
+
var openai_compatible_default = OpenAICompatible;
|
|
258
|
+
|
|
259
|
+
// src/model-provider/deepseek/index.ts
|
|
260
|
+
var DEFAULT_BASE_URL2 = "https://api.deepseek.com/v1";
|
|
261
|
+
var DEFAULT_MODEL = "deepseek-chat";
|
|
262
|
+
var Deepseek = class extends openai_compatible_default {
|
|
263
|
+
constructor(config) {
|
|
264
|
+
super({
|
|
265
|
+
...config,
|
|
266
|
+
model: config.model ?? DEFAULT_MODEL,
|
|
267
|
+
baseURL: config.baseURL ?? DEFAULT_BASE_URL2,
|
|
268
|
+
name: "DeepSeek"
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
};
|
|
254
272
|
var deepseek_default = Deepseek;
|
|
255
273
|
export {
|
|
256
274
|
model_provider_exports as ModelProvider
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/model-provider/index.ts","../src/model-provider/deepseek/index.ts"],"sourcesContent":["export {\n default as Deepseek,\n type AssistantMessage as DeepseekAssistantMessage,\n type ChatCompletionOptions as DeepseekChatCompletionOptions,\n type DeepseekConfig,\n type Message as DeepseekMessage,\n type MessageRole as DeepseekMessageRole,\n type RawTool as DeepseekRawTool,\n type ResponseToolCall as DeepseekResponseToolCall,\n type StreamChunk as DeepseekStreamChunk,\n type StreamToolCall as DeepseekStreamToolCall,\n type TokenUsage as DeepseekTokenUsage,\n type ToolCall as DeepseekToolCall,\n} from './deepseek';\n","import { Component } from '@astack-tech/core';\nimport type { Port } from '@astack-tech/core';\nimport OpenAI from 'openai';\n\n/**\n * Options for the DeepSeek model provider.\n */\nexport interface DeepseekConfig {\n /** DeepSeek API key. */\n apiKey: string;\n /** Model name. Defaults to `deepseek-chat`. */\n model?: string | undefined;\n /** API base URL. Defaults to `https://api.deepseek.com/v1`. */\n baseURL?: string | undefined;\n /** Sampling temperature. Defaults to `0.7`. */\n temperature?: number | undefined;\n /** Maximum number of generated tokens. */\n maxTokens?: number | undefined;\n /** Nucleus sampling probability. */\n topP?: number | undefined;\n /** System prompt added before every request. */\n systemPrompt?: string | undefined;\n /**\n * Tools given as `{ name, description, parameters }` objects.\n * When this list is not empty, it takes precedence over `tools`.\n */\n rawTools?: RawTool[] | undefined;\n /** Tools in the OpenAI-compatible `{ type: 'function', function }` format. */\n tools?: unknown[] | undefined;\n /** Allows the OpenAI client to run in a browser. Defaults to `false`. */\n dangerouslyAllowBrowser?: boolean | undefined;\n /** Logs API errors to the console. Defaults to `false`. */\n verbose?: boolean | undefined;\n}\n\n/**\n * Tool description accepted by `rawTools` and `temporaryTools`.\n */\nexport interface RawTool {\n name: string;\n description: string;\n parameters?: Record<string, unknown> | undefined;\n}\n\n/**\n * Role of a chat message.\n */\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Tool call in the internal format.\n */\nexport interface ToolCall {\n /** Identifier assigned by the API. */\n id?: string | undefined;\n /** Name of the tool. */\n tool_name: string;\n /** Parsed arguments. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Tool call returned by `chatCompletion`. It carries both the OpenAI shape\n * (`type`, `function`) and the internal shape (`tool_name`, `arguments`).\n */\nexport interface ResponseToolCall {\n id: string;\n type: 'function';\n function: { name: string; arguments: string };\n tool_name: string;\n arguments: Record<string, unknown>;\n}\n\n/**\n * Partial tool call emitted while streaming. `arguments` holds the raw JSON fragment.\n */\nexport interface StreamToolCall {\n id: string;\n type: 'function';\n function: { name: string; arguments: string };\n tool_name: string;\n arguments: string;\n}\n\n/**\n * Token usage reported by the API.\n */\nexport interface TokenUsage {\n completion_tokens: number;\n prompt_tokens: number;\n prompt_cache_hit_tokens?: number | undefined;\n prompt_cache_miss_tokens?: number | undefined;\n total_tokens: number;\n}\n\n/**\n * Chat message accepted as input. It matches the agent message contract in\n * `@astack-tech/components`, so agent histories can be passed directly.\n */\nexport interface Message {\n /** One of `system`, `user`, `assistant` or `tool` (see `MessageRole`). */\n role: string;\n content?: string | undefined;\n /** Accepted for compatibility. Assistant tool calls are not forwarded to the API. */\n tool_calls?: readonly unknown[] | undefined;\n /** Identifier of the call that a `tool` message answers. */\n tool_call_id?: string | undefined;\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Assistant message returned by `chatCompletion`.\n */\nexport interface AssistantMessage {\n role: 'assistant';\n content: string;\n tool_calls?: ResponseToolCall[] | undefined;\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Chunk yielded by `streamChatCompletion`.\n */\nexport interface StreamChunk {\n role: 'assistant';\n content: string;\n tool_calls?: StreamToolCall[] | undefined;\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Per-call options.\n */\nexport interface ChatCompletionOptions {\n /** Tools for this call only. They replace the configured tools. */\n temporaryTools?: unknown[] | undefined;\n}\n\ntype ChatMessageParam = OpenAI.Chat.ChatCompletionMessageParam;\ntype ChatTool = OpenAI.Chat.ChatCompletionTool;\n\ninterface DeepseekUsage {\n completion_tokens?: number;\n prompt_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_cache_miss_tokens?: number;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.deepseek.com/v1';\nconst DEFAULT_MODEL = 'deepseek-chat';\nconst DEFAULT_TEMPERATURE = 0.7;\nconst FALLBACK_TEXT = 'API call failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Converts a `{ name, description, parameters }` object to the OpenAI tool format.\n * Objects already in the OpenAI format are returned unchanged.\n */\nfunction toApiTool(tool: unknown): ChatTool {\n if (isRecord(tool) && tool['type'] === 'function') {\n return tool as unknown as ChatTool;\n }\n const raw = isRecord(tool) ? tool : {};\n const { name, description, parameters } = raw;\n return {\n type: 'function',\n function: {\n name: typeof name === 'string' ? name : '',\n description: typeof description === 'string' ? description : '',\n parameters: isRecord(parameters) ? parameters : {},\n },\n };\n}\n\n/**\n * Parses tool-call arguments. Anything that is not a JSON object becomes `{}`.\n */\nfunction parseArguments(raw: string): Record<string, unknown> {\n if (raw.trim().length === 0) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction mapUsage(usage: DeepseekUsage): TokenUsage {\n return {\n completion_tokens: usage.completion_tokens ?? 0,\n prompt_tokens: usage.prompt_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n ...(usage.prompt_cache_hit_tokens === undefined\n ? {}\n : { prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens }),\n ...(usage.prompt_cache_miss_tokens === undefined\n ? {}\n : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }),\n };\n}\n\n/**\n * DeepSeek model provider. It calls the DeepSeek API through the OpenAI-compatible client.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass Deepseek extends Component {\n private readonly client: OpenAI;\n private readonly model: string;\n private readonly temperature: number;\n private readonly maxTokens: number | undefined;\n private readonly topP: number | undefined;\n private readonly systemPrompt: string | undefined;\n private readonly tools: unknown[] | undefined;\n private readonly verbose: boolean;\n\n constructor(config: DeepseekConfig) {\n super({});\n\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false,\n });\n\n this.model = config.model ?? DEFAULT_MODEL;\n this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;\n this.maxTokens = config.maxTokens;\n this.topP = config.topP;\n this.systemPrompt = config.systemPrompt;\n this.verbose = config.verbose ?? false;\n this.tools =\n config.rawTools !== undefined && config.rawTools.length > 0\n ? config.rawTools.map(toApiTool)\n : config.tools;\n\n Component.Port.I('prompt').attach(this);\n Component.Port.I('messages').attach(this);\n Component.Port.O('completion').attach(this);\n Component.Port.O('message').attach(this);\n }\n\n /**\n * Generates a completion for a single prompt.\n *\n * @returns The text answer, or the JSON-encoded assistant message when it contains tool calls.\n */\n async generateCompletion(prompt: string): Promise<string> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: [...this.systemMessages(), { role: 'user', content: prompt }],\n ...this.toolsParam(this.tools),\n });\n\n const message = this.firstMessage(response);\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n return JSON.stringify(message);\n }\n return message.content ?? '';\n }\n\n /**\n * Sends a conversation and returns the assistant reply.\n */\n async chatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): Promise<AssistantMessage> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n });\n\n const message = this.firstMessage(response);\n const result: AssistantMessage = { role: 'assistant', content: message.content ?? '' };\n\n if (response.usage !== undefined) {\n result.usage = mapUsage(response.usage);\n }\n\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n result.tool_calls = message.tool_calls.map(toolCall => {\n if (toolCall.type !== 'function') {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n const rawArguments = toolCall.function.arguments;\n return {\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: rawArguments.length > 0 ? rawArguments : '{}',\n },\n tool_name: toolCall.function.name,\n arguments: parseArguments(rawArguments),\n };\n });\n }\n\n return result;\n }\n\n /**\n * Streams the assistant reply. Each chunk holds a text delta, tool-call deltas, or usage.\n */\n async *streamChatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): AsyncGenerator<StreamChunk> {\n const stream = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n stream: true,\n });\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n\n if (delta?.content) {\n yield { role: 'assistant', content: delta.content };\n }\n\n if (delta?.tool_calls) {\n yield {\n role: 'assistant',\n content: '',\n tool_calls: delta.tool_calls.map(toolCall => {\n const name = toolCall.function?.name ?? '';\n const args = toolCall.function?.arguments ?? '';\n return {\n id: toolCall.id ?? '',\n type: 'function',\n function: { name, arguments: args },\n tool_name: name,\n arguments: args,\n };\n }),\n };\n }\n\n if (chunk.usage) {\n yield { role: 'assistant', content: '', usage: mapUsage(chunk.usage) };\n }\n }\n }\n\n /**\n * Runs the model outside a pipeline.\n *\n * @param input A prompt string or a list of messages.\n */\n override run(input: string | Message[]): Promise<string | AssistantMessage> {\n return typeof input === 'string' ? this.generateCompletion(input) : this.chatCompletion(input);\n }\n\n /**\n * Connects the `prompt` and `messages` input ports to the model.\n * API errors produce a fallback value so the pipeline keeps flowing.\n */\n override _transform($i: Port, $o: Port): void {\n $i('prompt').receive((prompt: string) => {\n this.generateCompletion(prompt).then(\n completion => {\n $o('completion').send(completion);\n },\n (error: unknown) => {\n this.logError(error);\n $o('completion').send(FALLBACK_TEXT);\n }\n );\n });\n\n $i('messages').receive((messages: Message[]) => {\n this.chatCompletion(messages).then(\n message => {\n $o('message').send(message);\n },\n (error: unknown) => {\n this.logError(error);\n $o('message').send({ role: 'assistant', content: FALLBACK_TEXT });\n }\n );\n });\n }\n\n private baseRequest(): {\n model: string;\n temperature: number;\n max_tokens?: number;\n top_p?: number;\n } {\n return {\n model: this.model,\n temperature: this.temperature,\n ...(this.maxTokens === undefined ? {} : { max_tokens: this.maxTokens }),\n ...(this.topP === undefined ? {} : { top_p: this.topP }),\n };\n }\n\n private toolsParam(tools: unknown[] | undefined): { tools?: ChatTool[] } {\n return tools !== undefined && tools.length > 0 ? { tools: tools.map(toApiTool) } : {};\n }\n\n private systemMessages(): ChatMessageParam[] {\n return this.systemPrompt ? [{ role: 'system', content: this.systemPrompt }] : [];\n }\n\n /**\n * Converts input messages to API messages. Assistant `tool_calls` are not forwarded:\n * agents send tool results back as user messages, and the API rejects assistant tool\n * calls that are not followed by tool messages.\n */\n private formatMessages(messages: Message[]): ChatMessageParam[] {\n return [\n ...this.systemMessages(),\n ...messages.map(\n (message): ChatMessageParam =>\n ({\n role: message.role,\n content: message.content,\n ...(message.role === 'tool' && message.tool_call_id\n ? { tool_call_id: message.tool_call_id }\n : {}),\n }) as ChatMessageParam\n ),\n ];\n }\n\n private firstMessage(response: OpenAI.Chat.ChatCompletion): OpenAI.Chat.ChatCompletionMessage {\n const choice = response.choices[0];\n if (choice === undefined) {\n throw new Error('DeepSeek returned no choices.');\n }\n return choice.message;\n }\n\n private logError(error: unknown): void {\n if (this.verbose) {\n // eslint-disable-next-line no-console -- opt-in diagnostics controlled by `verbose`.\n console.error('[Deepseek] API call failed:', error);\n }\n }\n}\n\nexport default Deepseek;\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,iBAAiB;AAE1B,OAAO,YAAY;AAmJnB,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;AAC5B,IAAM,gBAAgB;AAEtB,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAMA,SAAS,UAAU,MAAyB;AAC1C,MAAI,SAAS,IAAI,KAAK,KAAK,MAAM,MAAM,YAAY;AACjD,WAAO;AAAA,EACT;AACA,QAAM,MAAM,SAAS,IAAI,IAAI,OAAO,CAAC;AACrC,QAAM,EAAE,MAAM,aAAa,WAAW,IAAI;AAC1C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,MACR,MAAM,OAAO,SAAS,WAAW,OAAO;AAAA,MACxC,aAAa,OAAO,gBAAgB,WAAW,cAAc;AAAA,MAC7D,YAAY,SAAS,UAAU,IAAI,aAAa,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AAKA,SAAS,eAAe,KAAsC;AAC5D,MAAI,IAAI,KAAK,EAAE,WAAW,GAAG;AAC3B,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,WAAO,SAAS,MAAM,IAAI,SAAS,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,SAAS,OAAkC;AAClD,SAAO;AAAA,IACL,mBAAmB,MAAM,qBAAqB;AAAA,IAC9C,eAAe,MAAM,iBAAiB;AAAA,IACtC,cAAc,MAAM,gBAAgB;AAAA,IACpC,GAAI,MAAM,4BAA4B,SAClC,CAAC,IACD,EAAE,yBAAyB,MAAM,wBAAwB;AAAA,IAC7D,GAAI,MAAM,6BAA6B,SACnC,CAAC,IACD,EAAE,0BAA0B,MAAM,yBAAyB;AAAA,EACjE;AACF;AASA,IAAM,WAAN,cAAuB,UAAU;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAAwB;AAClC,UAAM,CAAC,CAAC;AAER,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,QAAQ,OAAO;AAAA,MACf,SAAS,OAAO,WAAW;AAAA,MAC3B,yBAAyB,OAAO,2BAA2B;AAAA,IAC7D,CAAC;AAED,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,cAAc,OAAO,eAAe;AACzC,SAAK,YAAY,OAAO;AACxB,SAAK,OAAO,OAAO;AACnB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,QACH,OAAO,aAAa,UAAa,OAAO,SAAS,SAAS,IACtD,OAAO,SAAS,IAAI,SAAS,IAC7B,OAAO;AAEb,cAAU,KAAK,EAAE,QAAQ,EAAE,OAAO,IAAI;AACtC,cAAU,KAAK,EAAE,UAAU,EAAE,OAAO,IAAI;AACxC,cAAU,KAAK,EAAE,YAAY,EAAE,OAAO,IAAI;AAC1C,cAAU,KAAK,EAAE,SAAS,EAAE,OAAO,IAAI;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,mBAAmB,QAAiC;AACxD,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,YAAY,OAAO;AAAA,MACzD,GAAG,KAAK,YAAY;AAAA,MACpB,UAAU,CAAC,GAAG,KAAK,eAAe,GAAG,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MACtE,GAAG,KAAK,WAAW,KAAK,KAAK;AAAA,IAC/B,CAAC;AAED,UAAM,UAAU,KAAK,aAAa,QAAQ;AAC1C,QAAI,QAAQ,eAAe,UAAa,QAAQ,WAAW,SAAS,GAAG;AACrE,aAAO,KAAK,UAAU,OAAO;AAAA,IAC/B;AACA,WAAO,QAAQ,WAAW;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,UACA,SAC2B;AAC3B,UAAM,WAAW,MAAM,KAAK,OAAO,KAAK,YAAY,OAAO;AAAA,MACzD,GAAG,KAAK,YAAY;AAAA,MACpB,UAAU,KAAK,eAAe,QAAQ;AAAA,MACtC,GAAG,KAAK,WAAW,SAAS,kBAAkB,KAAK,KAAK;AAAA,IAC1D,CAAC;AAED,UAAM,UAAU,KAAK,aAAa,QAAQ;AAC1C,UAAM,SAA2B,EAAE,MAAM,aAAa,SAAS,QAAQ,WAAW,GAAG;AAErF,QAAI,SAAS,UAAU,QAAW;AAChC,aAAO,QAAQ,SAAS,SAAS,KAAK;AAAA,IACxC;AAEA,QAAI,QAAQ,eAAe,UAAa,QAAQ,WAAW,SAAS,GAAG;AACrE,aAAO,aAAa,QAAQ,WAAW,IAAI,cAAY;AACrD,YAAI,SAAS,SAAS,YAAY;AAChC,gBAAM,IAAI,MAAM,+BAA+B,SAAS,IAAI,EAAE;AAAA,QAChE;AACA,cAAM,eAAe,SAAS,SAAS;AACvC,eAAO;AAAA,UACL,IAAI,SAAS;AAAA,UACb,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,SAAS,SAAS;AAAA,YACxB,WAAW,aAAa,SAAS,IAAI,eAAe;AAAA,UACtD;AAAA,UACA,WAAW,SAAS,SAAS;AAAA,UAC7B,WAAW,eAAe,YAAY;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,qBACL,UACA,SAC6B;AAC7B,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK,YAAY,OAAO;AAAA,MACvD,GAAG,KAAK,YAAY;AAAA,MACpB,UAAU,KAAK,eAAe,QAAQ;AAAA,MACtC,GAAG,KAAK,WAAW,SAAS,kBAAkB,KAAK,KAAK;AAAA,MACxD,QAAQ;AAAA,IACV,CAAC;AAED,qBAAiB,SAAS,QAAQ;AAChC,YAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAEhC,UAAI,OAAO,SAAS;AAClB,cAAM,EAAE,MAAM,aAAa,SAAS,MAAM,QAAQ;AAAA,MACpD;AAEA,UAAI,OAAO,YAAY;AACrB,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,YAAY,MAAM,WAAW,IAAI,cAAY;AAC3C,kBAAM,OAAO,SAAS,UAAU,QAAQ;AACxC,kBAAM,OAAO,SAAS,UAAU,aAAa;AAC7C,mBAAO;AAAA,cACL,IAAI,SAAS,MAAM;AAAA,cACnB,MAAM;AAAA,cACN,UAAU,EAAE,MAAM,WAAW,KAAK;AAAA,cAClC,WAAW;AAAA,cACX,WAAW;AAAA,YACb;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,UAAI,MAAM,OAAO;AACf,cAAM,EAAE,MAAM,aAAa,SAAS,IAAI,OAAO,SAAS,MAAM,KAAK,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOS,IAAI,OAA+D;AAC1E,WAAO,OAAO,UAAU,WAAW,KAAK,mBAAmB,KAAK,IAAI,KAAK,eAAe,KAAK;AAAA,EAC/F;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS,WAAW,IAAU,IAAgB;AAC5C,OAAG,QAAQ,EAAE,QAAQ,CAAC,WAAmB;AACvC,WAAK,mBAAmB,MAAM,EAAE;AAAA,QAC9B,gBAAc;AACZ,aAAG,YAAY,EAAE,KAAK,UAAU;AAAA,QAClC;AAAA,QACA,CAAC,UAAmB;AAClB,eAAK,SAAS,KAAK;AACnB,aAAG,YAAY,EAAE,KAAK,aAAa;AAAA,QACrC;AAAA,MACF;AAAA,IACF,CAAC;AAED,OAAG,UAAU,EAAE,QAAQ,CAAC,aAAwB;AAC9C,WAAK,eAAe,QAAQ,EAAE;AAAA,QAC5B,aAAW;AACT,aAAG,SAAS,EAAE,KAAK,OAAO;AAAA,QAC5B;AAAA,QACA,CAAC,UAAmB;AAClB,eAAK,SAAS,KAAK;AACnB,aAAG,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,SAAS,cAAc,CAAC;AAAA,QAClE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,cAKN;AACA,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK;AAAA,MAClB,GAAI,KAAK,cAAc,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,UAAU;AAAA,MACrE,GAAI,KAAK,SAAS,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,KAAK;AAAA,IACxD;AAAA,EACF;AAAA,EAEQ,WAAW,OAAsD;AACvE,WAAO,UAAU,UAAa,MAAM,SAAS,IAAI,EAAE,OAAO,MAAM,IAAI,SAAS,EAAE,IAAI,CAAC;AAAA,EACtF;AAAA,EAEQ,iBAAqC;AAC3C,WAAO,KAAK,eAAe,CAAC,EAAE,MAAM,UAAU,SAAS,KAAK,aAAa,CAAC,IAAI,CAAC;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAe,UAAyC;AAC9D,WAAO;AAAA,MACL,GAAG,KAAK,eAAe;AAAA,MACvB,GAAG,SAAS;AAAA,QACV,CAAC,aACE;AAAA,UACC,MAAM,QAAQ;AAAA,UACd,SAAS,QAAQ;AAAA,UACjB,GAAI,QAAQ,SAAS,UAAU,QAAQ,eACnC,EAAE,cAAc,QAAQ,aAAa,IACrC,CAAC;AAAA,QACP;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,UAAyE;AAC5F,UAAM,SAAS,SAAS,QAAQ,CAAC;AACjC,QAAI,WAAW,QAAW;AACxB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEQ,SAAS,OAAsB;AACrC,QAAI,KAAK,SAAS;AAEhB,cAAQ,MAAM,+BAA+B,KAAK;AAAA,IACpD;AAAA,EACF;AACF;AAEA,IAAO,mBAAQ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/model-provider/index.ts","../src/model-provider/openai-compatible/index.ts","../src/model-provider/deepseek/index.ts"],"sourcesContent":["export {\n default as Deepseek,\n type AssistantMessage as DeepseekAssistantMessage,\n type ChatCompletionOptions as DeepseekChatCompletionOptions,\n type DeepseekConfig,\n type Message as DeepseekMessage,\n type MessageRole as DeepseekMessageRole,\n type RawTool as DeepseekRawTool,\n type ResponseToolCall as DeepseekResponseToolCall,\n type StreamChunk as DeepseekStreamChunk,\n type StreamToolCall as DeepseekStreamToolCall,\n type TokenUsage as DeepseekTokenUsage,\n type ToolCall as DeepseekToolCall,\n} from './deepseek';\nexport {\n default as OpenAICompatible,\n type AssistantMessage,\n type ChatCompletionOptions,\n type Message,\n type MessageRole,\n type OpenAICompatibleConfig,\n type RawTool,\n type ResponseToolCall,\n type StreamChunk,\n type StreamToolCall,\n type TokenUsage,\n type ToolCall,\n} from './openai-compatible';\n","import { Component } from '@astack-tech/core';\nimport type { Port } from '@astack-tech/core';\nimport OpenAI from 'openai';\n\n/**\n * Options for a provider that speaks the OpenAI chat completions API.\n */\nexport interface OpenAICompatibleConfig {\n /** API key of the provider. */\n apiKey: string;\n /** Model name, for example `gpt-4o-mini`, `qwen-plus` or `llama3.1`. */\n model: string;\n /** API base URL. Defaults to `https://api.openai.com/v1`. */\n baseURL?: string | undefined;\n /** Provider name used in errors and logs. Defaults to `The model API`. */\n name?: string | undefined;\n /** Sampling temperature. Defaults to `0.7`. */\n temperature?: number | undefined;\n /** Maximum number of generated tokens. */\n maxTokens?: number | undefined;\n /** Nucleus sampling probability. */\n topP?: number | undefined;\n /** System prompt added before every request. */\n systemPrompt?: string | undefined;\n /**\n * Tools given as `{ name, description, parameters }` objects.\n * When this list is not empty, it takes precedence over `tools`.\n */\n rawTools?: RawTool[] | undefined;\n /** Tools in the OpenAI-compatible `{ type: 'function', function }` format. */\n tools?: unknown[] | undefined;\n /** Allows the OpenAI client to run in a browser. Defaults to `false`. */\n dangerouslyAllowBrowser?: boolean | undefined;\n /** Logs API errors to the console. Defaults to `false`. */\n verbose?: boolean | undefined;\n}\n\n/**\n * Tool description accepted by `rawTools` and `temporaryTools`.\n */\nexport interface RawTool {\n /** Unique tool name. */\n name: string;\n /** Description that tells the model when to use the tool. */\n description: string;\n /** JSON Schema of the arguments. Defaults to `{}`. */\n parameters?: Record<string, unknown> | undefined;\n}\n\n/**\n * Role of a chat message.\n */\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Tool call in the internal format.\n */\nexport interface ToolCall {\n /** Identifier assigned by the API. */\n id?: string | undefined;\n /** Name of the tool. */\n tool_name: string;\n /** Parsed arguments. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Tool call returned by `chatCompletion`. It carries both the OpenAI shape\n * (`type`, `function`) and the internal shape (`tool_name`, `arguments`).\n */\nexport interface ResponseToolCall {\n /** Identifier assigned by the API. A `tool` message answers the call with it. */\n id: string;\n /** Always `function`. */\n type: 'function';\n /** The call in the OpenAI shape: function name and raw JSON arguments. An empty argument string is sent as `{}`. */\n function: {\n /** Name of the tool to call. */\n name: string;\n /** Arguments as JSON text. */\n arguments: string;\n };\n /** Name of the tool, same as `function.name`. */\n tool_name: string;\n /** Parsed arguments. JSON that is not an object becomes `{}`. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Partial tool call emitted while streaming. `arguments` holds the raw JSON fragment.\n */\nexport interface StreamToolCall {\n /** Identifier assigned by the API. Only the first delta of a call carries it; later deltas have `''`. */\n id: string;\n /** Always `function`. */\n type: 'function';\n /** The delta in the OpenAI shape. `arguments` holds only this delta's JSON fragment. */\n function: {\n /** Name of the tool to call. */\n name: string;\n /** Arguments as JSON text. */\n arguments: string;\n };\n /** Name of the tool when this delta carries it, otherwise `''`. */\n tool_name: string;\n /** Raw JSON fragment of this delta. Concatenate the fragments of a call to get its arguments. */\n arguments: string;\n}\n\n/**\n * Token usage reported by the API.\n */\nexport interface TokenUsage {\n /** Tokens in the generated reply. */\n completion_tokens: number;\n /** Tokens in the request. */\n prompt_tokens: number;\n /** Prompt tokens served from the provider's context cache (reported by DeepSeek). */\n prompt_cache_hit_tokens?: number | undefined;\n /** Prompt tokens not served from the cache. */\n prompt_cache_miss_tokens?: number | undefined;\n /** Sum of prompt and completion tokens. */\n total_tokens: number;\n}\n\n/**\n * Chat message accepted as input. It matches the agent message contract in\n * `@astack-tech/components`, so agent histories can be passed directly.\n */\nexport interface Message {\n /** One of `system`, `user`, `assistant` or `tool` (see `MessageRole`). */\n role: string;\n /** Text content. Omitted content is sent as no content. */\n content?: string | undefined;\n /** Accepted for compatibility. Assistant tool calls are not forwarded to the API. */\n tool_calls?: readonly unknown[] | undefined;\n /** Identifier of the call that a `tool` message answers. */\n tool_call_id?: string | undefined;\n /** Ignored on input. Present so agent histories can be passed unchanged. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Assistant message returned by `chatCompletion`.\n */\nexport interface AssistantMessage {\n /** Always `assistant`. */\n role: 'assistant';\n /** Reply text. Empty when the model only calls tools. */\n content: string;\n /** Tool calls requested by the model, if any. */\n tool_calls?: ResponseToolCall[] | undefined;\n /** Token usage of this request, when the API reports it. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Chunk yielded by `streamChatCompletion`.\n */\nexport interface StreamChunk {\n /** Always `assistant`. */\n role: 'assistant';\n /** Text delta. Empty in chunks that carry tool calls or usage. */\n content: string;\n /** Tool-call deltas in this chunk. */\n tool_calls?: StreamToolCall[] | undefined;\n /** Token usage. Sent once, in the final chunk, when the API reports it. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Per-call options.\n */\nexport interface ChatCompletionOptions {\n /** Tools for this call only. They replace the configured tools. */\n temporaryTools?: unknown[] | undefined;\n}\n\ntype ChatMessageParam = OpenAI.Chat.ChatCompletionMessageParam;\ntype ChatTool = OpenAI.Chat.ChatCompletionTool;\n\ninterface ApiUsage {\n completion_tokens?: number;\n prompt_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_cache_miss_tokens?: number;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.openai.com/v1';\nconst DEFAULT_NAME = 'The model API';\nconst DEFAULT_TEMPERATURE = 0.7;\nconst FALLBACK_TEXT = 'API call failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Converts a `{ name, description, parameters }` object to the OpenAI tool format.\n * Objects already in the OpenAI format are returned unchanged.\n */\nfunction toApiTool(tool: unknown): ChatTool {\n if (isRecord(tool) && tool['type'] === 'function') {\n return tool as unknown as ChatTool;\n }\n const raw = isRecord(tool) ? tool : {};\n const { name, description, parameters } = raw;\n return {\n type: 'function',\n function: {\n name: typeof name === 'string' ? name : '',\n description: typeof description === 'string' ? description : '',\n parameters: isRecord(parameters) ? parameters : {},\n },\n };\n}\n\n/**\n * Parses tool-call arguments. Anything that is not a JSON object becomes `{}`.\n */\nfunction parseArguments(raw: string): Record<string, unknown> {\n if (raw.trim().length === 0) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction mapUsage(usage: ApiUsage): TokenUsage {\n return {\n completion_tokens: usage.completion_tokens ?? 0,\n prompt_tokens: usage.prompt_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n ...(usage.prompt_cache_hit_tokens === undefined\n ? {}\n : { prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens }),\n ...(usage.prompt_cache_miss_tokens === undefined\n ? {}\n : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }),\n };\n}\n\n/**\n * Model provider for any API that speaks the OpenAI chat completions protocol:\n * OpenAI itself, and the compatible endpoints of DeepSeek, Qwen, Moonshot, Ollama,\n * vLLM and others. Set `baseURL` and `model` for the provider you use.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass OpenAICompatible extends Component {\n private readonly client: OpenAI;\n private readonly model: string;\n private readonly temperature: number;\n private readonly maxTokens: number | undefined;\n private readonly topP: number | undefined;\n private readonly systemPrompt: string | undefined;\n private readonly tools: unknown[] | undefined;\n private readonly verbose: boolean;\n private readonly name: string;\n\n constructor(config: OpenAICompatibleConfig) {\n super({});\n\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false,\n });\n\n this.model = config.model;\n this.name = config.name ?? DEFAULT_NAME;\n this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;\n this.maxTokens = config.maxTokens;\n this.topP = config.topP;\n this.systemPrompt = config.systemPrompt;\n this.verbose = config.verbose ?? false;\n this.tools =\n config.rawTools !== undefined && config.rawTools.length > 0\n ? config.rawTools.map(toApiTool)\n : config.tools;\n\n Component.Port.I('prompt').attach(this);\n Component.Port.I('messages').attach(this);\n Component.Port.O('completion').attach(this);\n Component.Port.O('message').attach(this);\n }\n\n /**\n * Generates a completion for a single prompt.\n *\n * @returns The text answer, or the JSON-encoded assistant message when it contains tool calls.\n */\n async generateCompletion(prompt: string): Promise<string> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: [...this.systemMessages(), { role: 'user', content: prompt }],\n ...this.toolsParam(this.tools),\n });\n\n const message = this.firstMessage(response);\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n return JSON.stringify(message);\n }\n return message.content ?? '';\n }\n\n /**\n * Sends a conversation and returns the assistant reply.\n */\n async chatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): Promise<AssistantMessage> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n });\n\n const message = this.firstMessage(response);\n const result: AssistantMessage = { role: 'assistant', content: message.content ?? '' };\n\n if (response.usage !== undefined) {\n result.usage = mapUsage(response.usage);\n }\n\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n result.tool_calls = message.tool_calls.map(toolCall => {\n if (toolCall.type !== 'function') {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n const rawArguments = toolCall.function.arguments;\n return {\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: rawArguments.length > 0 ? rawArguments : '{}',\n },\n tool_name: toolCall.function.name,\n arguments: parseArguments(rawArguments),\n };\n });\n }\n\n return result;\n }\n\n /**\n * Streams the assistant reply. Each chunk holds a text delta, tool-call deltas, or usage.\n */\n async *streamChatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): AsyncGenerator<StreamChunk> {\n const stream = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n stream: true,\n });\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n\n if (delta?.content) {\n yield { role: 'assistant', content: delta.content };\n }\n\n if (delta?.tool_calls) {\n yield {\n role: 'assistant',\n content: '',\n tool_calls: delta.tool_calls.map(toolCall => {\n const name = toolCall.function?.name ?? '';\n const args = toolCall.function?.arguments ?? '';\n return {\n id: toolCall.id ?? '',\n type: 'function',\n function: { name, arguments: args },\n tool_name: name,\n arguments: args,\n };\n }),\n };\n }\n\n if (chunk.usage) {\n yield { role: 'assistant', content: '', usage: mapUsage(chunk.usage) };\n }\n }\n }\n\n /**\n * Runs the model outside a pipeline.\n *\n * @param input - A prompt string or a list of messages.\n */\n override run(input: string | Message[]): Promise<string | AssistantMessage> {\n return typeof input === 'string' ? this.generateCompletion(input) : this.chatCompletion(input);\n }\n\n /**\n * Connects the `prompt` and `messages` input ports to the model.\n * API errors produce a fallback value so the pipeline keeps flowing.\n */\n override _transform($i: Port, $o: Port): void {\n $i('prompt').receive((prompt: string) => {\n this.generateCompletion(prompt).then(\n completion => {\n $o('completion').send(completion);\n },\n (error: unknown) => {\n this.logError(error);\n $o('completion').send(FALLBACK_TEXT);\n }\n );\n });\n\n $i('messages').receive((messages: Message[]) => {\n this.chatCompletion(messages).then(\n message => {\n $o('message').send(message);\n },\n (error: unknown) => {\n this.logError(error);\n $o('message').send({ role: 'assistant', content: FALLBACK_TEXT });\n }\n );\n });\n }\n\n private baseRequest(): {\n model: string;\n temperature: number;\n max_tokens?: number;\n top_p?: number;\n } {\n return {\n model: this.model,\n temperature: this.temperature,\n ...(this.maxTokens === undefined ? {} : { max_tokens: this.maxTokens }),\n ...(this.topP === undefined ? {} : { top_p: this.topP }),\n };\n }\n\n private toolsParam(tools: unknown[] | undefined): { tools?: ChatTool[] } {\n return tools !== undefined && tools.length > 0 ? { tools: tools.map(toApiTool) } : {};\n }\n\n private systemMessages(): ChatMessageParam[] {\n return this.systemPrompt ? [{ role: 'system', content: this.systemPrompt }] : [];\n }\n\n /**\n * Converts input messages to API messages. Assistant `tool_calls` are not forwarded:\n * agents send tool results back as user messages, and the API rejects assistant tool\n * calls that are not followed by tool messages.\n */\n private formatMessages(messages: Message[]): ChatMessageParam[] {\n return [\n ...this.systemMessages(),\n ...messages.map(\n (message): ChatMessageParam =>\n ({\n role: message.role,\n content: message.content,\n ...(message.role === 'tool' && message.tool_call_id\n ? { tool_call_id: message.tool_call_id }\n : {}),\n }) as ChatMessageParam\n ),\n ];\n }\n\n private firstMessage(response: OpenAI.Chat.ChatCompletion): OpenAI.Chat.ChatCompletionMessage {\n const choice = response.choices[0];\n if (choice === undefined) {\n throw new Error(`${this.name} returned no choices.`);\n }\n return choice.message;\n }\n\n private logError(error: unknown): void {\n if (this.verbose) {\n // eslint-disable-next-line no-console -- opt-in diagnostics controlled by `verbose`.\n console.error(`[${this.name}] API call failed:`, error);\n }\n }\n}\n\nexport default OpenAICompatible;\n","import OpenAICompatible from '../openai-compatible';\nimport type { OpenAICompatibleConfig } from '../openai-compatible';\n\nexport type {\n AssistantMessage,\n ChatCompletionOptions,\n Message,\n MessageRole,\n RawTool,\n ResponseToolCall,\n StreamChunk,\n StreamToolCall,\n TokenUsage,\n ToolCall,\n} from '../openai-compatible';\n\nconst DEFAULT_BASE_URL = 'https://api.deepseek.com/v1';\nconst DEFAULT_MODEL = 'deepseek-chat';\n\n/**\n * Options for the DeepSeek model provider. They are the options of\n * `OpenAICompatible`, with DeepSeek's endpoint and model as defaults.\n */\nexport interface DeepseekConfig extends Omit<OpenAICompatibleConfig, 'model' | 'name'> {\n /** Model name. Defaults to `deepseek-chat`. */\n model?: string | undefined;\n /** API base URL. Defaults to `https://api.deepseek.com/v1`. */\n baseURL?: string | undefined;\n}\n\n/**\n * DeepSeek model provider: `OpenAICompatible` set up for the DeepSeek API.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass Deepseek extends OpenAICompatible {\n constructor(config: DeepseekConfig) {\n super({\n ...config,\n model: config.model ?? DEFAULT_MODEL,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n name: 'DeepSeek',\n });\n }\n}\n\nexport default Deepseek;\n"],"mappings":"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","names":["DEFAULT_BASE_URL"]}
|
|
@@ -30,15 +30,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/model-provider/index.ts
|
|
31
31
|
var model_provider_exports = {};
|
|
32
32
|
__export(model_provider_exports, {
|
|
33
|
-
Deepseek: () => deepseek_default
|
|
33
|
+
Deepseek: () => deepseek_default,
|
|
34
|
+
OpenAICompatible: () => openai_compatible_default
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(model_provider_exports);
|
|
36
37
|
|
|
37
|
-
// src/model-provider/
|
|
38
|
+
// src/model-provider/openai-compatible/index.ts
|
|
38
39
|
var import_core = require("@astack-tech/core");
|
|
39
40
|
var import_openai = __toESM(require("openai"), 1);
|
|
40
|
-
var DEFAULT_BASE_URL = "https://api.
|
|
41
|
-
var
|
|
41
|
+
var DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
42
|
+
var DEFAULT_NAME = "The model API";
|
|
42
43
|
var DEFAULT_TEMPERATURE = 0.7;
|
|
43
44
|
var FALLBACK_TEXT = "API call failed";
|
|
44
45
|
function isRecord(value) {
|
|
@@ -79,7 +80,7 @@ function mapUsage(usage) {
|
|
|
79
80
|
...usage.prompt_cache_miss_tokens === void 0 ? {} : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }
|
|
80
81
|
};
|
|
81
82
|
}
|
|
82
|
-
var
|
|
83
|
+
var OpenAICompatible = class extends import_core.Component {
|
|
83
84
|
client;
|
|
84
85
|
model;
|
|
85
86
|
temperature;
|
|
@@ -88,6 +89,7 @@ var Deepseek = class extends import_core.Component {
|
|
|
88
89
|
systemPrompt;
|
|
89
90
|
tools;
|
|
90
91
|
verbose;
|
|
92
|
+
name;
|
|
91
93
|
constructor(config) {
|
|
92
94
|
super({});
|
|
93
95
|
this.client = new import_openai.default({
|
|
@@ -95,7 +97,8 @@ var Deepseek = class extends import_core.Component {
|
|
|
95
97
|
baseURL: config.baseURL ?? DEFAULT_BASE_URL,
|
|
96
98
|
dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false
|
|
97
99
|
});
|
|
98
|
-
this.model = config.model
|
|
100
|
+
this.model = config.model;
|
|
101
|
+
this.name = config.name ?? DEFAULT_NAME;
|
|
99
102
|
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
100
103
|
this.maxTokens = config.maxTokens;
|
|
101
104
|
this.topP = config.topP;
|
|
@@ -198,7 +201,7 @@ var Deepseek = class extends import_core.Component {
|
|
|
198
201
|
/**
|
|
199
202
|
* Runs the model outside a pipeline.
|
|
200
203
|
*
|
|
201
|
-
* @param input A prompt string or a list of messages.
|
|
204
|
+
* @param input - A prompt string or a list of messages.
|
|
202
205
|
*/
|
|
203
206
|
run(input) {
|
|
204
207
|
return typeof input === "string" ? this.generateCompletion(input) : this.chatCompletion(input);
|
|
@@ -265,19 +268,35 @@ var Deepseek = class extends import_core.Component {
|
|
|
265
268
|
firstMessage(response) {
|
|
266
269
|
const choice = response.choices[0];
|
|
267
270
|
if (choice === void 0) {
|
|
268
|
-
throw new Error(
|
|
271
|
+
throw new Error(`${this.name} returned no choices.`);
|
|
269
272
|
}
|
|
270
273
|
return choice.message;
|
|
271
274
|
}
|
|
272
275
|
logError(error) {
|
|
273
276
|
if (this.verbose) {
|
|
274
|
-
console.error(
|
|
277
|
+
console.error(`[${this.name}] API call failed:`, error);
|
|
275
278
|
}
|
|
276
279
|
}
|
|
277
280
|
};
|
|
281
|
+
var openai_compatible_default = OpenAICompatible;
|
|
282
|
+
|
|
283
|
+
// src/model-provider/deepseek/index.ts
|
|
284
|
+
var DEFAULT_BASE_URL2 = "https://api.deepseek.com/v1";
|
|
285
|
+
var DEFAULT_MODEL = "deepseek-chat";
|
|
286
|
+
var Deepseek = class extends openai_compatible_default {
|
|
287
|
+
constructor(config) {
|
|
288
|
+
super({
|
|
289
|
+
...config,
|
|
290
|
+
model: config.model ?? DEFAULT_MODEL,
|
|
291
|
+
baseURL: config.baseURL ?? DEFAULT_BASE_URL2,
|
|
292
|
+
name: "DeepSeek"
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
};
|
|
278
296
|
var deepseek_default = Deepseek;
|
|
279
297
|
// Annotate the CommonJS export names for ESM import in node:
|
|
280
298
|
0 && (module.exports = {
|
|
281
|
-
Deepseek
|
|
299
|
+
Deepseek,
|
|
300
|
+
OpenAICompatible
|
|
282
301
|
});
|
|
283
302
|
//# sourceMappingURL=index.cjs.map
|