@matthesketh/utopia-ai 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/anthropic.cjs +3 -0
- package/dist/adapters/anthropic.d.cts +1 -1
- package/dist/adapters/anthropic.d.ts +1 -1
- package/dist/adapters/anthropic.js +3 -0
- package/dist/adapters/google.d.cts +1 -1
- package/dist/adapters/google.d.ts +1 -1
- package/dist/adapters/ollama.cjs +13 -1
- package/dist/adapters/ollama.d.cts +2 -2
- package/dist/adapters/ollama.d.ts +2 -2
- package/dist/adapters/ollama.js +13 -1
- package/dist/adapters/openai.cjs +3 -0
- package/dist/adapters/openai.d.cts +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.js +3 -0
- package/dist/ai-B65XFWfZ.d.ts +66 -0
- package/dist/ai-dyp9MfTz.d.cts +66 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -0
- package/dist/mcp/index.d.cts +2 -2
- package/dist/mcp/index.d.ts +2 -2
- package/dist/types-BcCKlL06.d.cts +157 -0
- package/dist/types-BcCKlL06.d.ts +157 -0
- package/package.json +1 -1
|
@@ -46,6 +46,9 @@ function anthropicAdapter(config) {
|
|
|
46
46
|
'@matthesketh/utopia-ai: "@anthropic-ai/sdk" package is required for the Anthropic adapter. Install it with: npm install @anthropic-ai/sdk'
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
+
if (config.baseURL && !/^https?:$/.test(new URL(config.baseURL).protocol)) {
|
|
50
|
+
throw new Error(`Anthropic baseURL must be http(s): ${config.baseURL}`);
|
|
51
|
+
}
|
|
49
52
|
client = new AnthropicCtor({
|
|
50
53
|
apiKey: config.apiKey,
|
|
51
54
|
...config.baseURL ? { baseURL: config.baseURL } : {}
|
|
@@ -12,6 +12,9 @@ function anthropicAdapter(config) {
|
|
|
12
12
|
'@matthesketh/utopia-ai: "@anthropic-ai/sdk" package is required for the Anthropic adapter. Install it with: npm install @anthropic-ai/sdk'
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
|
+
if (config.baseURL && !/^https?:$/.test(new URL(config.baseURL).protocol)) {
|
|
16
|
+
throw new Error(`Anthropic baseURL must be http(s): ${config.baseURL}`);
|
|
17
|
+
}
|
|
15
18
|
client = new AnthropicCtor({
|
|
16
19
|
apiKey: config.apiKey,
|
|
17
20
|
...config.baseURL ? { baseURL: config.baseURL } : {}
|
package/dist/adapters/ollama.cjs
CHANGED
|
@@ -25,9 +25,18 @@ __export(ollama_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(ollama_exports);
|
|
27
27
|
var TRAILING_SLASH_RE = /\/$/;
|
|
28
|
+
var MAX_STREAM_BUFFER = 1024 * 1024;
|
|
29
|
+
function resolveBaseURL(raw) {
|
|
30
|
+
const baseURL = (raw ?? "http://localhost:11434").replace(TRAILING_SLASH_RE, "");
|
|
31
|
+
const protocol = new URL(baseURL).protocol;
|
|
32
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
33
|
+
throw new Error(`Ollama baseURL must be http(s): ${baseURL}`);
|
|
34
|
+
}
|
|
35
|
+
return baseURL;
|
|
36
|
+
}
|
|
28
37
|
var ollamaToolCallCounter = 0;
|
|
29
38
|
function ollamaAdapter(config = {}) {
|
|
30
|
-
const baseURL = (config.baseURL
|
|
39
|
+
const baseURL = resolveBaseURL(config.baseURL);
|
|
31
40
|
return {
|
|
32
41
|
async chat(request) {
|
|
33
42
|
const model = request.model ?? config.defaultModel ?? "llama3.2";
|
|
@@ -109,6 +118,9 @@ function ollamaAdapter(config = {}) {
|
|
|
109
118
|
const { done, value } = await reader.read();
|
|
110
119
|
if (done) break;
|
|
111
120
|
buffer += decoder.decode(value, { stream: true });
|
|
121
|
+
if (buffer.length > MAX_STREAM_BUFFER) {
|
|
122
|
+
throw new Error("Ollama stream exceeded maximum buffer size without a line delimiter");
|
|
123
|
+
}
|
|
112
124
|
const lines = buffer.split("\n");
|
|
113
125
|
buffer = lines.pop() ?? "";
|
|
114
126
|
for (const line of lines) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { O as OllamaConfig, A as AIAdapter } from '../types-
|
|
1
|
+
import { O as OllamaConfig, A as AIAdapter } from '../types-BcCKlL06.cjs';
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/** matches a trailing slash for URL normalization. */
|
|
4
4
|
declare const TRAILING_SLASH_RE: RegExp;
|
|
5
5
|
/**
|
|
6
6
|
* Create an Ollama adapter for local models.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { O as OllamaConfig, A as AIAdapter } from '../types-
|
|
1
|
+
import { O as OllamaConfig, A as AIAdapter } from '../types-BcCKlL06.js';
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/** matches a trailing slash for URL normalization. */
|
|
4
4
|
declare const TRAILING_SLASH_RE: RegExp;
|
|
5
5
|
/**
|
|
6
6
|
* Create an Ollama adapter for local models.
|
package/dist/adapters/ollama.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
// src/adapters/ollama.ts
|
|
2
2
|
var TRAILING_SLASH_RE = /\/$/;
|
|
3
|
+
var MAX_STREAM_BUFFER = 1024 * 1024;
|
|
4
|
+
function resolveBaseURL(raw) {
|
|
5
|
+
const baseURL = (raw ?? "http://localhost:11434").replace(TRAILING_SLASH_RE, "");
|
|
6
|
+
const protocol = new URL(baseURL).protocol;
|
|
7
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
8
|
+
throw new Error(`Ollama baseURL must be http(s): ${baseURL}`);
|
|
9
|
+
}
|
|
10
|
+
return baseURL;
|
|
11
|
+
}
|
|
3
12
|
var ollamaToolCallCounter = 0;
|
|
4
13
|
function ollamaAdapter(config = {}) {
|
|
5
|
-
const baseURL = (config.baseURL
|
|
14
|
+
const baseURL = resolveBaseURL(config.baseURL);
|
|
6
15
|
return {
|
|
7
16
|
async chat(request) {
|
|
8
17
|
const model = request.model ?? config.defaultModel ?? "llama3.2";
|
|
@@ -84,6 +93,9 @@ function ollamaAdapter(config = {}) {
|
|
|
84
93
|
const { done, value } = await reader.read();
|
|
85
94
|
if (done) break;
|
|
86
95
|
buffer += decoder.decode(value, { stream: true });
|
|
96
|
+
if (buffer.length > MAX_STREAM_BUFFER) {
|
|
97
|
+
throw new Error("Ollama stream exceeded maximum buffer size without a line delimiter");
|
|
98
|
+
}
|
|
87
99
|
const lines = buffer.split("\n");
|
|
88
100
|
buffer = lines.pop() ?? "";
|
|
89
101
|
for (const line of lines) {
|
package/dist/adapters/openai.cjs
CHANGED
|
@@ -46,6 +46,9 @@ function openaiAdapter(config) {
|
|
|
46
46
|
'@matthesketh/utopia-ai: "openai" package is required for the OpenAI adapter. Install it with: npm install openai'
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
+
if (config.baseURL && !/^https?:$/.test(new URL(config.baseURL).protocol)) {
|
|
50
|
+
throw new Error(`OpenAI baseURL must be http(s): ${config.baseURL}`);
|
|
51
|
+
}
|
|
49
52
|
client = new OpenAICtor({
|
|
50
53
|
apiKey: config.apiKey,
|
|
51
54
|
baseURL: config.baseURL,
|
package/dist/adapters/openai.js
CHANGED
|
@@ -12,6 +12,9 @@ function openaiAdapter(config) {
|
|
|
12
12
|
'@matthesketh/utopia-ai: "openai" package is required for the OpenAI adapter. Install it with: npm install openai'
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
|
+
if (config.baseURL && !/^https?:$/.test(new URL(config.baseURL).protocol)) {
|
|
16
|
+
throw new Error(`OpenAI baseURL must be http(s): ${config.baseURL}`);
|
|
17
|
+
}
|
|
15
18
|
client = new OpenAICtor({
|
|
16
19
|
apiKey: config.apiKey,
|
|
17
20
|
baseURL: config.baseURL,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { d as ChatRequest, e as ChatResponse, C as ChatChunk, E as EmbeddingRequest, f as EmbeddingResponse, c as ChatMessage, l as ToolDefinition, j as ToolCall, a as AIHooks, R as RetryConfig, A as AIAdapter } from './types-BcCKlL06.js';
|
|
2
|
+
|
|
3
|
+
interface AI {
|
|
4
|
+
/** Send a chat completion request. */
|
|
5
|
+
chat(request: ChatRequest): Promise<ChatResponse>;
|
|
6
|
+
/** Stream a chat completion. */
|
|
7
|
+
stream(request: ChatRequest): AsyncIterable<ChatChunk>;
|
|
8
|
+
/** Generate embeddings. */
|
|
9
|
+
embeddings(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
10
|
+
/**
|
|
11
|
+
* Run a tool-calling loop: send messages, execute tool calls via the
|
|
12
|
+
* provided handlers, append results, and repeat until the model stops
|
|
13
|
+
* calling tools.
|
|
14
|
+
*/
|
|
15
|
+
run(options: RunOptions): Promise<ChatResponse>;
|
|
16
|
+
}
|
|
17
|
+
interface ToolHandler {
|
|
18
|
+
definition: ToolDefinition;
|
|
19
|
+
handler: (args: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
20
|
+
}
|
|
21
|
+
interface RunOptions {
|
|
22
|
+
messages: ChatMessage[];
|
|
23
|
+
tools: ToolHandler[];
|
|
24
|
+
model?: string;
|
|
25
|
+
temperature?: number;
|
|
26
|
+
maxTokens?: number;
|
|
27
|
+
maxRounds?: number;
|
|
28
|
+
onToolCall?: (call: ToolCall, result: unknown) => void;
|
|
29
|
+
extra?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
interface CreateAIOptions {
|
|
32
|
+
hooks?: AIHooks;
|
|
33
|
+
retry?: RetryConfig;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create an AI instance with the given adapter.
|
|
37
|
+
*
|
|
38
|
+
* Usage:
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { createAI } from '@matthesketh/utopia-ai';
|
|
41
|
+
* import { openaiAdapter } from '@matthesketh/utopia-ai/openai';
|
|
42
|
+
*
|
|
43
|
+
* const ai = createAI(openaiAdapter({ apiKey: process.env.OPENAI_API_KEY }));
|
|
44
|
+
*
|
|
45
|
+
* const res = await ai.chat({
|
|
46
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Streaming
|
|
50
|
+
* for await (const chunk of ai.stream({ messages })) {
|
|
51
|
+
* process.stdout.write(chunk.delta);
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* // Agentic tool loop
|
|
55
|
+
* const result = await ai.run({
|
|
56
|
+
* messages: [{ role: 'user', content: 'What is the weather?' }],
|
|
57
|
+
* tools: [{
|
|
58
|
+
* definition: { name: 'get_weather', description: '...', parameters: { type: 'object', properties: {} } },
|
|
59
|
+
* handler: async ({ city }) => ({ temp: 72 }),
|
|
60
|
+
* }],
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function createAI(adapter: AIAdapter, options?: CreateAIOptions): AI;
|
|
65
|
+
|
|
66
|
+
export { type AI as A, type CreateAIOptions as C, type RunOptions as R, type ToolHandler as T, createAI as c };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { d as ChatRequest, e as ChatResponse, C as ChatChunk, E as EmbeddingRequest, f as EmbeddingResponse, c as ChatMessage, l as ToolDefinition, j as ToolCall, a as AIHooks, R as RetryConfig, A as AIAdapter } from './types-BcCKlL06.cjs';
|
|
2
|
+
|
|
3
|
+
interface AI {
|
|
4
|
+
/** Send a chat completion request. */
|
|
5
|
+
chat(request: ChatRequest): Promise<ChatResponse>;
|
|
6
|
+
/** Stream a chat completion. */
|
|
7
|
+
stream(request: ChatRequest): AsyncIterable<ChatChunk>;
|
|
8
|
+
/** Generate embeddings. */
|
|
9
|
+
embeddings(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
10
|
+
/**
|
|
11
|
+
* Run a tool-calling loop: send messages, execute tool calls via the
|
|
12
|
+
* provided handlers, append results, and repeat until the model stops
|
|
13
|
+
* calling tools.
|
|
14
|
+
*/
|
|
15
|
+
run(options: RunOptions): Promise<ChatResponse>;
|
|
16
|
+
}
|
|
17
|
+
interface ToolHandler {
|
|
18
|
+
definition: ToolDefinition;
|
|
19
|
+
handler: (args: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
20
|
+
}
|
|
21
|
+
interface RunOptions {
|
|
22
|
+
messages: ChatMessage[];
|
|
23
|
+
tools: ToolHandler[];
|
|
24
|
+
model?: string;
|
|
25
|
+
temperature?: number;
|
|
26
|
+
maxTokens?: number;
|
|
27
|
+
maxRounds?: number;
|
|
28
|
+
onToolCall?: (call: ToolCall, result: unknown) => void;
|
|
29
|
+
extra?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
interface CreateAIOptions {
|
|
32
|
+
hooks?: AIHooks;
|
|
33
|
+
retry?: RetryConfig;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create an AI instance with the given adapter.
|
|
37
|
+
*
|
|
38
|
+
* Usage:
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { createAI } from '@matthesketh/utopia-ai';
|
|
41
|
+
* import { openaiAdapter } from '@matthesketh/utopia-ai/openai';
|
|
42
|
+
*
|
|
43
|
+
* const ai = createAI(openaiAdapter({ apiKey: process.env.OPENAI_API_KEY }));
|
|
44
|
+
*
|
|
45
|
+
* const res = await ai.chat({
|
|
46
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Streaming
|
|
50
|
+
* for await (const chunk of ai.stream({ messages })) {
|
|
51
|
+
* process.stdout.write(chunk.delta);
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* // Agentic tool loop
|
|
55
|
+
* const result = await ai.run({
|
|
56
|
+
* messages: [{ role: 'user', content: 'What is the weather?' }],
|
|
57
|
+
* tools: [{
|
|
58
|
+
* definition: { name: 'get_weather', description: '...', parameters: { type: 'object', properties: {} } },
|
|
59
|
+
* handler: async ({ city }) => ({ temp: 72 }),
|
|
60
|
+
* }],
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function createAI(adapter: AIAdapter, options?: CreateAIOptions): AI;
|
|
65
|
+
|
|
66
|
+
export { type AI as A, type CreateAIOptions as C, type RunOptions as R, type ToolHandler as T, createAI as c };
|
package/dist/index.cjs
CHANGED
|
@@ -209,6 +209,7 @@ async function* chatToStream(adapter, request) {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
// src/streaming.ts
|
|
212
|
+
var MAX_SSE_BUFFER = 1024 * 1024;
|
|
212
213
|
async function streamSSE(res, stream, options) {
|
|
213
214
|
res.writeHead(200, {
|
|
214
215
|
"Content-Type": "text/event-stream",
|
|
@@ -247,6 +248,9 @@ async function* parseSSEStream(response) {
|
|
|
247
248
|
const { done, value } = await reader.read();
|
|
248
249
|
if (done) break;
|
|
249
250
|
buffer += decoder.decode(value, { stream: true });
|
|
251
|
+
if (buffer.length > MAX_SSE_BUFFER) {
|
|
252
|
+
throw new Error("SSE stream exceeded maximum buffer size without a line delimiter");
|
|
253
|
+
}
|
|
250
254
|
const lines = buffer.split("\n");
|
|
251
255
|
buffer = lines.pop() ?? "";
|
|
252
256
|
for (const line of lines) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { A as AI, C as CreateAIOptions, R as RunOptions, T as ToolHandler, c as createAI } from './ai-
|
|
1
|
+
export { A as AI, C as CreateAIOptions, R as RunOptions, T as ToolHandler, c as createAI } from './ai-dyp9MfTz.cjs';
|
|
2
2
|
import { ServerResponse } from 'node:http';
|
|
3
|
-
import { C as ChatChunk } from './types-
|
|
4
|
-
export { A as AIAdapter, a as AIHooks, b as AnthropicConfig, c as ChatMessage, d as ChatRequest, e as ChatResponse, E as EmbeddingRequest, f as EmbeddingResponse, G as GoogleConfig, I as ImageContent, J as JsonSchema, M as MessageContent, g as MessageRole, O as OllamaConfig, h as OpenAIConfig, R as RetryConfig, T as TextContent, i as TokenUsage, j as ToolCall, k as ToolCallContent, l as ToolDefinition, m as ToolResultContent } from './types-
|
|
3
|
+
import { C as ChatChunk } from './types-BcCKlL06.cjs';
|
|
4
|
+
export { A as AIAdapter, a as AIHooks, b as AnthropicConfig, c as ChatMessage, d as ChatRequest, e as ChatResponse, E as EmbeddingRequest, f as EmbeddingResponse, G as GoogleConfig, I as ImageContent, J as JsonSchema, M as MessageContent, g as MessageRole, O as OllamaConfig, h as OpenAIConfig, R as RetryConfig, T as TextContent, i as TokenUsage, j as ToolCall, k as ToolCallContent, l as ToolDefinition, m as ToolResultContent } from './types-BcCKlL06.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Stream AI chat chunks as Server-Sent Events (SSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { A as AI, C as CreateAIOptions, R as RunOptions, T as ToolHandler, c as createAI } from './ai-
|
|
1
|
+
export { A as AI, C as CreateAIOptions, R as RunOptions, T as ToolHandler, c as createAI } from './ai-B65XFWfZ.js';
|
|
2
2
|
import { ServerResponse } from 'node:http';
|
|
3
|
-
import { C as ChatChunk } from './types-
|
|
4
|
-
export { A as AIAdapter, a as AIHooks, b as AnthropicConfig, c as ChatMessage, d as ChatRequest, e as ChatResponse, E as EmbeddingRequest, f as EmbeddingResponse, G as GoogleConfig, I as ImageContent, J as JsonSchema, M as MessageContent, g as MessageRole, O as OllamaConfig, h as OpenAIConfig, R as RetryConfig, T as TextContent, i as TokenUsage, j as ToolCall, k as ToolCallContent, l as ToolDefinition, m as ToolResultContent } from './types-
|
|
3
|
+
import { C as ChatChunk } from './types-BcCKlL06.js';
|
|
4
|
+
export { A as AIAdapter, a as AIHooks, b as AnthropicConfig, c as ChatMessage, d as ChatRequest, e as ChatResponse, E as EmbeddingRequest, f as EmbeddingResponse, G as GoogleConfig, I as ImageContent, J as JsonSchema, M as MessageContent, g as MessageRole, O as OllamaConfig, h as OpenAIConfig, R as RetryConfig, T as TextContent, i as TokenUsage, j as ToolCall, k as ToolCallContent, l as ToolDefinition, m as ToolResultContent } from './types-BcCKlL06.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Stream AI chat chunks as Server-Sent Events (SSE).
|
package/dist/index.js
CHANGED
|
@@ -180,6 +180,7 @@ async function* chatToStream(adapter, request) {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
// src/streaming.ts
|
|
183
|
+
var MAX_SSE_BUFFER = 1024 * 1024;
|
|
183
184
|
async function streamSSE(res, stream, options) {
|
|
184
185
|
res.writeHead(200, {
|
|
185
186
|
"Content-Type": "text/event-stream",
|
|
@@ -218,6 +219,9 @@ async function* parseSSEStream(response) {
|
|
|
218
219
|
const { done, value } = await reader.read();
|
|
219
220
|
if (done) break;
|
|
220
221
|
buffer += decoder.decode(value, { stream: true });
|
|
222
|
+
if (buffer.length > MAX_SSE_BUFFER) {
|
|
223
|
+
throw new Error("SSE stream exceeded maximum buffer size without a line delimiter");
|
|
224
|
+
}
|
|
221
225
|
const lines = buffer.split("\n");
|
|
222
226
|
buffer = lines.pop() ?? "";
|
|
223
227
|
for (const line of lines) {
|
package/dist/mcp/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { J as JsonSchema } from '../types-
|
|
2
|
-
import { T as ToolHandler } from '../ai-
|
|
1
|
+
import { J as JsonSchema } from '../types-BcCKlL06.cjs';
|
|
2
|
+
import { T as ToolHandler } from '../ai-dyp9MfTz.cjs';
|
|
3
3
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
4
|
|
|
5
5
|
interface JsonRpcRequest {
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { J as JsonSchema } from '../types-
|
|
2
|
-
import { T as ToolHandler } from '../ai-
|
|
1
|
+
import { J as JsonSchema } from '../types-BcCKlL06.js';
|
|
2
|
+
import { T as ToolHandler } from '../ai-B65XFWfZ.js';
|
|
3
3
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
4
|
|
|
5
5
|
interface JsonRpcRequest {
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
2
|
+
interface TextContent {
|
|
3
|
+
type: 'text';
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
interface ImageContent {
|
|
7
|
+
type: 'image';
|
|
8
|
+
/** Base64-encoded image data or a URL. */
|
|
9
|
+
source: string;
|
|
10
|
+
mediaType?: string;
|
|
11
|
+
}
|
|
12
|
+
interface ToolCallContent {
|
|
13
|
+
type: 'tool_call';
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
arguments: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
interface ToolResultContent {
|
|
19
|
+
type: 'tool_result';
|
|
20
|
+
id: string;
|
|
21
|
+
content: string;
|
|
22
|
+
isError?: boolean;
|
|
23
|
+
}
|
|
24
|
+
type MessageContent = string | TextContent | ImageContent | ToolCallContent | ToolResultContent;
|
|
25
|
+
interface ChatMessage {
|
|
26
|
+
role: MessageRole;
|
|
27
|
+
content: MessageContent | MessageContent[];
|
|
28
|
+
name?: string;
|
|
29
|
+
}
|
|
30
|
+
interface ToolDefinition {
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
parameters: JsonSchema;
|
|
34
|
+
}
|
|
35
|
+
interface JsonSchema {
|
|
36
|
+
type: string;
|
|
37
|
+
properties?: Record<string, JsonSchema & {
|
|
38
|
+
description?: string;
|
|
39
|
+
}>;
|
|
40
|
+
required?: string[];
|
|
41
|
+
items?: JsonSchema;
|
|
42
|
+
enum?: unknown[];
|
|
43
|
+
description?: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
interface ChatRequest {
|
|
47
|
+
messages: ChatMessage[];
|
|
48
|
+
model?: string;
|
|
49
|
+
temperature?: number;
|
|
50
|
+
maxTokens?: number;
|
|
51
|
+
topP?: number;
|
|
52
|
+
stop?: string[];
|
|
53
|
+
tools?: ToolDefinition[];
|
|
54
|
+
toolChoice?: 'auto' | 'none' | 'required' | {
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
57
|
+
/** Adapter-specific options passed through untouched. */
|
|
58
|
+
extra?: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
interface ToolCall {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
arguments: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
interface ChatResponse {
|
|
66
|
+
content: string;
|
|
67
|
+
toolCalls?: ToolCall[];
|
|
68
|
+
finishReason: 'stop' | 'tool_calls' | 'length' | 'error';
|
|
69
|
+
usage?: TokenUsage;
|
|
70
|
+
/** Raw response from the provider for advanced use cases. */
|
|
71
|
+
raw?: unknown;
|
|
72
|
+
}
|
|
73
|
+
interface TokenUsage {
|
|
74
|
+
promptTokens: number;
|
|
75
|
+
completionTokens: number;
|
|
76
|
+
totalTokens: number;
|
|
77
|
+
}
|
|
78
|
+
interface ChatChunk {
|
|
79
|
+
/** Incremental text delta. */
|
|
80
|
+
delta: string;
|
|
81
|
+
/** Incremental tool call delta (partial). */
|
|
82
|
+
toolCallDelta?: Partial<ToolCall> & {
|
|
83
|
+
index?: number;
|
|
84
|
+
};
|
|
85
|
+
/** Set on the final chunk. */
|
|
86
|
+
finishReason?: ChatResponse['finishReason'];
|
|
87
|
+
/** Set on the final chunk. */
|
|
88
|
+
usage?: TokenUsage;
|
|
89
|
+
}
|
|
90
|
+
interface EmbeddingRequest {
|
|
91
|
+
input: string | string[];
|
|
92
|
+
model?: string;
|
|
93
|
+
/** Adapter-specific options. */
|
|
94
|
+
extra?: Record<string, unknown>;
|
|
95
|
+
}
|
|
96
|
+
interface EmbeddingResponse {
|
|
97
|
+
embeddings: number[][];
|
|
98
|
+
usage?: {
|
|
99
|
+
totalTokens: number;
|
|
100
|
+
};
|
|
101
|
+
raw?: unknown;
|
|
102
|
+
}
|
|
103
|
+
interface AIAdapter {
|
|
104
|
+
/** Send a chat completion request. */
|
|
105
|
+
chat(request: ChatRequest): Promise<ChatResponse>;
|
|
106
|
+
/** Stream a chat completion. Adapters may omit this (falls back to chat). */
|
|
107
|
+
stream?(request: ChatRequest): AsyncIterable<ChatChunk>;
|
|
108
|
+
/** Generate embeddings. Optional capability. */
|
|
109
|
+
embeddings?(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
110
|
+
}
|
|
111
|
+
interface OpenAIConfig {
|
|
112
|
+
apiKey: string;
|
|
113
|
+
baseURL?: string;
|
|
114
|
+
organization?: string;
|
|
115
|
+
defaultModel?: string;
|
|
116
|
+
}
|
|
117
|
+
interface AnthropicConfig {
|
|
118
|
+
apiKey: string;
|
|
119
|
+
baseURL?: string;
|
|
120
|
+
defaultModel?: string;
|
|
121
|
+
}
|
|
122
|
+
interface GoogleConfig {
|
|
123
|
+
apiKey: string;
|
|
124
|
+
defaultModel?: string;
|
|
125
|
+
}
|
|
126
|
+
interface OllamaConfig {
|
|
127
|
+
baseURL?: string;
|
|
128
|
+
defaultModel?: string;
|
|
129
|
+
}
|
|
130
|
+
interface AIHooks {
|
|
131
|
+
/** Called before every chat request. Can modify the request. */
|
|
132
|
+
onBeforeChat?: (request: ChatRequest) => ChatRequest | Promise<ChatRequest>;
|
|
133
|
+
/** Called after every chat response. Can modify the response. */
|
|
134
|
+
onAfterChat?: (response: ChatResponse, request: ChatRequest) => ChatResponse | Promise<ChatResponse>;
|
|
135
|
+
/**
|
|
136
|
+
* Called on any adapter error.
|
|
137
|
+
*
|
|
138
|
+
* `context.request` carries the full prompt (and any provider error may
|
|
139
|
+
* originate from the underlying SDK and reference request metadata), so do
|
|
140
|
+
* not forward these verbatim to an untrusted or shared log sink — redact or
|
|
141
|
+
* summarise first.
|
|
142
|
+
*/
|
|
143
|
+
onError?: (error: Error, context: {
|
|
144
|
+
method: string;
|
|
145
|
+
request?: ChatRequest;
|
|
146
|
+
}) => void;
|
|
147
|
+
}
|
|
148
|
+
interface RetryConfig {
|
|
149
|
+
/** Max number of retries (default: 0 = no retry). */
|
|
150
|
+
maxRetries?: number;
|
|
151
|
+
/** Base delay in ms (default: 1000). Doubles on each attempt (exponential backoff). */
|
|
152
|
+
baseDelay?: number;
|
|
153
|
+
/** Whether to retry on this error. Default: retries on network errors and 429/500+ status codes. */
|
|
154
|
+
shouldRetry?: (error: Error) => boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type { AIAdapter as A, ChatChunk as C, EmbeddingRequest as E, GoogleConfig as G, ImageContent as I, JsonSchema as J, MessageContent as M, OllamaConfig as O, RetryConfig as R, TextContent as T, AIHooks as a, AnthropicConfig as b, ChatMessage as c, ChatRequest as d, ChatResponse as e, EmbeddingResponse as f, MessageRole as g, OpenAIConfig as h, TokenUsage as i, ToolCall as j, ToolCallContent as k, ToolDefinition as l, ToolResultContent as m };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
2
|
+
interface TextContent {
|
|
3
|
+
type: 'text';
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
interface ImageContent {
|
|
7
|
+
type: 'image';
|
|
8
|
+
/** Base64-encoded image data or a URL. */
|
|
9
|
+
source: string;
|
|
10
|
+
mediaType?: string;
|
|
11
|
+
}
|
|
12
|
+
interface ToolCallContent {
|
|
13
|
+
type: 'tool_call';
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
arguments: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
interface ToolResultContent {
|
|
19
|
+
type: 'tool_result';
|
|
20
|
+
id: string;
|
|
21
|
+
content: string;
|
|
22
|
+
isError?: boolean;
|
|
23
|
+
}
|
|
24
|
+
type MessageContent = string | TextContent | ImageContent | ToolCallContent | ToolResultContent;
|
|
25
|
+
interface ChatMessage {
|
|
26
|
+
role: MessageRole;
|
|
27
|
+
content: MessageContent | MessageContent[];
|
|
28
|
+
name?: string;
|
|
29
|
+
}
|
|
30
|
+
interface ToolDefinition {
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
parameters: JsonSchema;
|
|
34
|
+
}
|
|
35
|
+
interface JsonSchema {
|
|
36
|
+
type: string;
|
|
37
|
+
properties?: Record<string, JsonSchema & {
|
|
38
|
+
description?: string;
|
|
39
|
+
}>;
|
|
40
|
+
required?: string[];
|
|
41
|
+
items?: JsonSchema;
|
|
42
|
+
enum?: unknown[];
|
|
43
|
+
description?: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
interface ChatRequest {
|
|
47
|
+
messages: ChatMessage[];
|
|
48
|
+
model?: string;
|
|
49
|
+
temperature?: number;
|
|
50
|
+
maxTokens?: number;
|
|
51
|
+
topP?: number;
|
|
52
|
+
stop?: string[];
|
|
53
|
+
tools?: ToolDefinition[];
|
|
54
|
+
toolChoice?: 'auto' | 'none' | 'required' | {
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
57
|
+
/** Adapter-specific options passed through untouched. */
|
|
58
|
+
extra?: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
interface ToolCall {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
arguments: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
interface ChatResponse {
|
|
66
|
+
content: string;
|
|
67
|
+
toolCalls?: ToolCall[];
|
|
68
|
+
finishReason: 'stop' | 'tool_calls' | 'length' | 'error';
|
|
69
|
+
usage?: TokenUsage;
|
|
70
|
+
/** Raw response from the provider for advanced use cases. */
|
|
71
|
+
raw?: unknown;
|
|
72
|
+
}
|
|
73
|
+
interface TokenUsage {
|
|
74
|
+
promptTokens: number;
|
|
75
|
+
completionTokens: number;
|
|
76
|
+
totalTokens: number;
|
|
77
|
+
}
|
|
78
|
+
interface ChatChunk {
|
|
79
|
+
/** Incremental text delta. */
|
|
80
|
+
delta: string;
|
|
81
|
+
/** Incremental tool call delta (partial). */
|
|
82
|
+
toolCallDelta?: Partial<ToolCall> & {
|
|
83
|
+
index?: number;
|
|
84
|
+
};
|
|
85
|
+
/** Set on the final chunk. */
|
|
86
|
+
finishReason?: ChatResponse['finishReason'];
|
|
87
|
+
/** Set on the final chunk. */
|
|
88
|
+
usage?: TokenUsage;
|
|
89
|
+
}
|
|
90
|
+
interface EmbeddingRequest {
|
|
91
|
+
input: string | string[];
|
|
92
|
+
model?: string;
|
|
93
|
+
/** Adapter-specific options. */
|
|
94
|
+
extra?: Record<string, unknown>;
|
|
95
|
+
}
|
|
96
|
+
interface EmbeddingResponse {
|
|
97
|
+
embeddings: number[][];
|
|
98
|
+
usage?: {
|
|
99
|
+
totalTokens: number;
|
|
100
|
+
};
|
|
101
|
+
raw?: unknown;
|
|
102
|
+
}
|
|
103
|
+
interface AIAdapter {
|
|
104
|
+
/** Send a chat completion request. */
|
|
105
|
+
chat(request: ChatRequest): Promise<ChatResponse>;
|
|
106
|
+
/** Stream a chat completion. Adapters may omit this (falls back to chat). */
|
|
107
|
+
stream?(request: ChatRequest): AsyncIterable<ChatChunk>;
|
|
108
|
+
/** Generate embeddings. Optional capability. */
|
|
109
|
+
embeddings?(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
110
|
+
}
|
|
111
|
+
interface OpenAIConfig {
|
|
112
|
+
apiKey: string;
|
|
113
|
+
baseURL?: string;
|
|
114
|
+
organization?: string;
|
|
115
|
+
defaultModel?: string;
|
|
116
|
+
}
|
|
117
|
+
interface AnthropicConfig {
|
|
118
|
+
apiKey: string;
|
|
119
|
+
baseURL?: string;
|
|
120
|
+
defaultModel?: string;
|
|
121
|
+
}
|
|
122
|
+
interface GoogleConfig {
|
|
123
|
+
apiKey: string;
|
|
124
|
+
defaultModel?: string;
|
|
125
|
+
}
|
|
126
|
+
interface OllamaConfig {
|
|
127
|
+
baseURL?: string;
|
|
128
|
+
defaultModel?: string;
|
|
129
|
+
}
|
|
130
|
+
interface AIHooks {
|
|
131
|
+
/** Called before every chat request. Can modify the request. */
|
|
132
|
+
onBeforeChat?: (request: ChatRequest) => ChatRequest | Promise<ChatRequest>;
|
|
133
|
+
/** Called after every chat response. Can modify the response. */
|
|
134
|
+
onAfterChat?: (response: ChatResponse, request: ChatRequest) => ChatResponse | Promise<ChatResponse>;
|
|
135
|
+
/**
|
|
136
|
+
* Called on any adapter error.
|
|
137
|
+
*
|
|
138
|
+
* `context.request` carries the full prompt (and any provider error may
|
|
139
|
+
* originate from the underlying SDK and reference request metadata), so do
|
|
140
|
+
* not forward these verbatim to an untrusted or shared log sink — redact or
|
|
141
|
+
* summarise first.
|
|
142
|
+
*/
|
|
143
|
+
onError?: (error: Error, context: {
|
|
144
|
+
method: string;
|
|
145
|
+
request?: ChatRequest;
|
|
146
|
+
}) => void;
|
|
147
|
+
}
|
|
148
|
+
interface RetryConfig {
|
|
149
|
+
/** Max number of retries (default: 0 = no retry). */
|
|
150
|
+
maxRetries?: number;
|
|
151
|
+
/** Base delay in ms (default: 1000). Doubles on each attempt (exponential backoff). */
|
|
152
|
+
baseDelay?: number;
|
|
153
|
+
/** Whether to retry on this error. Default: retries on network errors and 429/500+ status codes. */
|
|
154
|
+
shouldRetry?: (error: Error) => boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type { AIAdapter as A, ChatChunk as C, EmbeddingRequest as E, GoogleConfig as G, ImageContent as I, JsonSchema as J, MessageContent as M, OllamaConfig as O, RetryConfig as R, TextContent as T, AIHooks as a, AnthropicConfig as b, ChatMessage as c, ChatRequest as d, ChatResponse as e, EmbeddingResponse as f, MessageRole as g, OpenAIConfig as h, TokenUsage as i, ToolCall as j, ToolCallContent as k, ToolDefinition as l, ToolResultContent as m };
|