@jxburros/ai-nugget 0.3.1 → 0.6.0
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/README.md +134 -271
- package/UPGRADING.md +158 -0
- package/dist/adapters/engines/anthropic.d.ts +7 -1
- package/dist/adapters/engines/anthropic.js +64 -37
- package/dist/adapters/engines/base.d.ts +29 -2
- package/dist/adapters/engines/base.js +52 -8
- package/dist/adapters/engines/google.d.ts +17 -1
- package/dist/adapters/engines/google.js +93 -29
- package/dist/adapters/engines/ollama.d.ts +2 -1
- package/dist/adapters/engines/ollama.js +51 -15
- package/dist/adapters/engines/openaiChat.d.ts +2 -1
- package/dist/adapters/engines/openaiChat.js +60 -30
- package/dist/adapters/profiles.d.ts +21 -1
- package/dist/adapters/profiles.js +12 -2
- package/dist/agent/loop.d.ts +43 -1
- package/dist/agent/loop.js +120 -13
- package/dist/cjs/adapters/engines/anthropic.js +308 -0
- package/dist/cjs/adapters/engines/base.js +147 -0
- package/dist/cjs/adapters/engines/google.js +284 -0
- package/dist/cjs/adapters/engines/ollama.js +199 -0
- package/dist/cjs/adapters/engines/openaiChat.js +261 -0
- package/dist/cjs/adapters/index.js +22 -0
- package/dist/cjs/adapters/profiles.js +125 -0
- package/dist/cjs/agent/index.js +18 -0
- package/dist/cjs/agent/loop.js +372 -0
- package/dist/cjs/agent/tools.js +51 -0
- package/dist/cjs/connect.js +27 -0
- package/dist/cjs/errors.js +110 -0
- package/dist/cjs/handler.js +561 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/json.js +121 -0
- package/dist/cjs/keys.js +81 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/policy.js +42 -0
- package/dist/cjs/redact.js +78 -0
- package/dist/cjs/tokens.js +22 -0
- package/dist/cjs/transport.js +172 -0
- package/dist/cjs/types.js +6 -0
- package/dist/cjs/util.js +112 -0
- package/dist/connect.d.ts +31 -0
- package/dist/connect.js +25 -0
- package/dist/errors.js +25 -1
- package/dist/handler.d.ts +61 -1
- package/dist/handler.js +247 -61
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/keys.js +1 -4
- package/dist/redact.d.ts +18 -0
- package/dist/redact.js +29 -1
- package/dist/transport.d.ts +3 -1
- package/dist/transport.js +21 -1
- package/dist/types.d.ts +96 -2
- package/dist/util.d.ts +16 -0
- package/dist/util.js +50 -0
- package/nugget/VERSION.txt +2 -2
- package/nugget/dist/adapters/engines/anthropic.d.ts +14 -0
- package/nugget/dist/adapters/engines/anthropic.d.ts.map +1 -0
- package/nugget/dist/adapters/engines/anthropic.js +305 -0
- package/nugget/dist/adapters/engines/anthropic.js.map +1 -0
- package/nugget/dist/adapters/engines/base.d.ts +50 -0
- package/nugget/dist/adapters/engines/base.d.ts.map +1 -0
- package/nugget/dist/adapters/engines/base.js +137 -0
- package/nugget/dist/adapters/engines/base.js.map +1 -0
- package/nugget/dist/adapters/engines/google.d.ts +24 -0
- package/nugget/dist/adapters/engines/google.d.ts.map +1 -0
- package/nugget/dist/adapters/engines/google.js +281 -0
- package/nugget/dist/adapters/engines/google.js.map +1 -0
- package/nugget/dist/adapters/engines/ollama.d.ts +11 -0
- package/nugget/dist/adapters/engines/ollama.d.ts.map +1 -0
- package/nugget/dist/adapters/engines/ollama.js +196 -0
- package/nugget/dist/adapters/engines/ollama.js.map +1 -0
- package/nugget/dist/adapters/engines/openaiChat.d.ts +16 -0
- package/nugget/dist/adapters/engines/openaiChat.d.ts.map +1 -0
- package/nugget/dist/adapters/engines/openaiChat.js +258 -0
- package/nugget/dist/adapters/engines/openaiChat.js.map +1 -0
- package/nugget/dist/adapters/index.d.ts +5 -0
- package/nugget/dist/adapters/index.d.ts.map +1 -0
- package/nugget/dist/adapters/index.js +17 -0
- package/nugget/dist/adapters/index.js.map +1 -0
- package/nugget/dist/adapters/profiles.d.ts +62 -0
- package/nugget/dist/adapters/profiles.d.ts.map +1 -0
- package/nugget/dist/adapters/profiles.js +121 -0
- package/nugget/dist/adapters/profiles.js.map +1 -0
- package/nugget/dist/agent/index.d.ts +3 -0
- package/nugget/dist/agent/index.d.ts.map +1 -0
- package/nugget/dist/agent/index.js +3 -0
- package/nugget/dist/agent/index.js.map +1 -0
- package/nugget/dist/agent/loop.d.ts +112 -0
- package/nugget/dist/agent/loop.d.ts.map +1 -0
- package/nugget/dist/agent/loop.js +370 -0
- package/nugget/dist/agent/loop.js.map +1 -0
- package/nugget/dist/agent/tools.d.ts +29 -0
- package/nugget/dist/agent/tools.d.ts.map +1 -0
- package/nugget/dist/agent/tools.js +48 -0
- package/nugget/dist/agent/tools.js.map +1 -0
- package/nugget/dist/cjs/adapters/engines/anthropic.js +308 -0
- package/nugget/dist/cjs/adapters/engines/base.js +147 -0
- package/nugget/dist/cjs/adapters/engines/google.js +284 -0
- package/nugget/dist/cjs/adapters/engines/ollama.js +199 -0
- package/nugget/dist/cjs/adapters/engines/openaiChat.js +261 -0
- package/nugget/dist/cjs/adapters/index.js +22 -0
- package/nugget/dist/cjs/adapters/profiles.js +125 -0
- package/nugget/dist/cjs/agent/index.js +18 -0
- package/nugget/dist/cjs/agent/loop.js +372 -0
- package/nugget/dist/cjs/agent/tools.js +51 -0
- package/nugget/dist/cjs/connect.js +27 -0
- package/nugget/dist/cjs/errors.js +110 -0
- package/nugget/dist/cjs/handler.js +561 -0
- package/nugget/dist/cjs/index.js +27 -0
- package/nugget/dist/cjs/json.js +121 -0
- package/nugget/dist/cjs/keys.js +81 -0
- package/nugget/dist/cjs/package.json +3 -0
- package/nugget/dist/cjs/policy.js +42 -0
- package/nugget/dist/cjs/redact.js +78 -0
- package/nugget/dist/cjs/tokens.js +22 -0
- package/nugget/dist/cjs/transport.js +172 -0
- package/nugget/dist/cjs/types.js +6 -0
- package/nugget/dist/cjs/util.js +112 -0
- package/nugget/dist/connect.d.ts +31 -0
- package/nugget/dist/connect.d.ts.map +1 -0
- package/nugget/dist/connect.js +25 -0
- package/nugget/dist/connect.js.map +1 -0
- package/nugget/dist/errors.d.ts +22 -0
- package/nugget/dist/errors.d.ts.map +1 -0
- package/nugget/dist/errors.js +104 -0
- package/nugget/dist/errors.js.map +1 -0
- package/nugget/dist/handler.d.ts +108 -0
- package/nugget/dist/handler.d.ts.map +1 -0
- package/nugget/dist/handler.js +557 -0
- package/nugget/dist/handler.js.map +1 -0
- package/nugget/dist/index.d.ts +12 -0
- package/nugget/dist/index.d.ts.map +1 -0
- package/nugget/dist/index.js +12 -0
- package/nugget/dist/index.js.map +1 -0
- package/nugget/dist/json.d.ts +7 -0
- package/nugget/dist/json.d.ts.map +1 -0
- package/nugget/dist/json.js +114 -0
- package/nugget/dist/json.js.map +1 -0
- package/nugget/dist/keys.d.ts +7 -0
- package/nugget/dist/keys.d.ts.map +1 -0
- package/nugget/dist/keys.js +75 -0
- package/nugget/dist/keys.js.map +1 -0
- package/nugget/dist/policy.d.ts +6 -0
- package/nugget/dist/policy.d.ts.map +1 -0
- package/nugget/dist/policy.js +37 -0
- package/nugget/dist/policy.js.map +1 -0
- package/nugget/dist/redact.d.ts +26 -0
- package/nugget/dist/redact.d.ts.map +1 -0
- package/nugget/dist/redact.js +74 -0
- package/nugget/dist/redact.js.map +1 -0
- package/nugget/dist/tokens.d.ts +5 -0
- package/nugget/dist/tokens.d.ts.map +1 -0
- package/nugget/dist/tokens.js +18 -0
- package/nugget/dist/tokens.js.map +1 -0
- package/nugget/dist/transport.d.ts +30 -0
- package/nugget/dist/transport.d.ts.map +1 -0
- package/nugget/dist/transport.js +165 -0
- package/nugget/dist/transport.js.map +1 -0
- package/nugget/dist/types.d.ts +285 -0
- package/nugget/dist/types.d.ts.map +1 -0
- package/nugget/dist/types.js +4 -0
- package/nugget/dist/types.js.map +1 -0
- package/nugget/dist/util.d.ts +24 -0
- package/nugget/dist/util.d.ts.map +1 -0
- package/nugget/dist/util.js +101 -0
- package/nugget/dist/util.js.map +1 -0
- package/nugget/src/adapters/engines/anthropic.ts +62 -37
- package/nugget/src/adapters/engines/base.ts +50 -7
- package/nugget/src/adapters/engines/google.ts +92 -29
- package/nugget/src/adapters/engines/ollama.ts +51 -17
- package/nugget/src/adapters/engines/openaiChat.ts +61 -32
- package/nugget/src/adapters/profiles.ts +53 -3
- package/nugget/src/agent/loop.ts +158 -14
- package/nugget/src/connect.ts +48 -0
- package/nugget/src/errors.ts +25 -1
- package/nugget/src/handler.ts +286 -59
- package/nugget/src/index.ts +1 -0
- package/nugget/src/keys.ts +1 -5
- package/nugget/src/redact.ts +32 -1
- package/nugget/src/transport.ts +20 -1
- package/nugget/src/types.ts +96 -1
- package/nugget/src/util.ts +55 -0
- package/package.json +20 -6
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import type { KnownProvider } from './adapters/profiles.js';
|
|
2
|
+
export type { KnownProvider };
|
|
3
|
+
export type Role = 'system' | 'user' | 'assistant' | 'tool';
|
|
4
|
+
export interface ContentPart {
|
|
5
|
+
type: 'text' | 'image';
|
|
6
|
+
text?: string;
|
|
7
|
+
imageBase64?: string;
|
|
8
|
+
mimeType?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ChatMessage {
|
|
11
|
+
role: Role;
|
|
12
|
+
content: string | ContentPart[];
|
|
13
|
+
toolCalls?: ToolCall[];
|
|
14
|
+
toolCallId?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ToolCall {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
arguments: unknown;
|
|
21
|
+
raw?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ToolSchema {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
parameters: object;
|
|
27
|
+
}
|
|
28
|
+
export interface ChatRequest {
|
|
29
|
+
model: string;
|
|
30
|
+
messages: ChatMessage[];
|
|
31
|
+
temperature?: number;
|
|
32
|
+
maxTokens?: number;
|
|
33
|
+
topP?: number;
|
|
34
|
+
responseFormat?: {
|
|
35
|
+
type: 'text';
|
|
36
|
+
} | {
|
|
37
|
+
type: 'json';
|
|
38
|
+
schema?: object;
|
|
39
|
+
};
|
|
40
|
+
tools?: ToolSchema[];
|
|
41
|
+
toolChoice?: 'auto' | 'none' | {
|
|
42
|
+
name: string;
|
|
43
|
+
};
|
|
44
|
+
stopSequences?: string[];
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Provider-native request fields the nugget does not model as first-class
|
|
49
|
+
* options — an escape hatch so a caller can reach a capability without waiting
|
|
50
|
+
* for a library release. Merged into the outgoing provider request body:
|
|
51
|
+
* shallow at the top level, and one level deep into the provider's own nested
|
|
52
|
+
* option container (Ollama `options`, Google `generationConfig`). Examples:
|
|
53
|
+
* `{ options: { num_ctx: 8192 }, keep_alive: '30m' }` (Ollama),
|
|
54
|
+
* `{ reasoning_effort: 'high' }` (OpenAI), `{ thinking: { type: 'enabled' } }`
|
|
55
|
+
* (Anthropic), `{ safetySettings: [...] }` (Google). Values here win over the
|
|
56
|
+
* nugget's own fields on a key collision, so use with care.
|
|
57
|
+
*/
|
|
58
|
+
providerOptions?: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
export interface Connection {
|
|
61
|
+
id: string;
|
|
62
|
+
/**
|
|
63
|
+
* A provider with a profile in the table, or any other string — an unknown
|
|
64
|
+
* key with a `baseUrl` resolves through the `openai-compat` escape hatch.
|
|
65
|
+
* The union is there for autocomplete and typo-catching; the `string & {}`
|
|
66
|
+
* arm keeps the escape hatch open.
|
|
67
|
+
*/
|
|
68
|
+
provider: KnownProvider | (string & {});
|
|
69
|
+
baseUrl?: string;
|
|
70
|
+
keyRef?: KeyRef;
|
|
71
|
+
timeoutMs?: number;
|
|
72
|
+
headers?: Record<string, string>;
|
|
73
|
+
/**
|
|
74
|
+
* Idle timeout for streaming calls: aborts the stream only if no bytes arrive
|
|
75
|
+
* for this many milliseconds, resetting on every chunk. Distinct from
|
|
76
|
+
* `timeoutMs`, which bounds the total call lifetime. Set this (and a generous
|
|
77
|
+
* `timeoutMs`) for long local generations that stream slowly but healthily.
|
|
78
|
+
*/
|
|
79
|
+
idleTimeoutMs?: number;
|
|
80
|
+
}
|
|
81
|
+
export type KeyRef = {
|
|
82
|
+
kind: 'none';
|
|
83
|
+
} | {
|
|
84
|
+
kind: 'env';
|
|
85
|
+
name: string;
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'literal';
|
|
88
|
+
value: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'stored';
|
|
91
|
+
ref: string;
|
|
92
|
+
} | {
|
|
93
|
+
kind: 'brokered';
|
|
94
|
+
ref: string;
|
|
95
|
+
};
|
|
96
|
+
export interface KeySource {
|
|
97
|
+
resolve(ref: KeyRef): Promise<{
|
|
98
|
+
ok: true;
|
|
99
|
+
apiKey: string | null;
|
|
100
|
+
} | {
|
|
101
|
+
ok: false;
|
|
102
|
+
reason: 'missing' | 'locked' | 'denied';
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
105
|
+
export interface ResolvedConnection extends Connection {
|
|
106
|
+
baseUrl: string;
|
|
107
|
+
apiKey: string | null;
|
|
108
|
+
headers: Record<string, string>;
|
|
109
|
+
}
|
|
110
|
+
export interface Usage {
|
|
111
|
+
inputTokens?: number;
|
|
112
|
+
outputTokens?: number;
|
|
113
|
+
estimated: boolean;
|
|
114
|
+
}
|
|
115
|
+
export interface ChatResult {
|
|
116
|
+
text: string;
|
|
117
|
+
toolCalls?: ToolCall[];
|
|
118
|
+
finishReason: 'stop' | 'length' | 'tool' | 'content_filter' | 'error' | 'canceled';
|
|
119
|
+
usage: Usage;
|
|
120
|
+
timing: {
|
|
121
|
+
firstTokenMs: number | null;
|
|
122
|
+
totalMs: number;
|
|
123
|
+
};
|
|
124
|
+
model: string;
|
|
125
|
+
source: ModelSource;
|
|
126
|
+
raw?: unknown;
|
|
127
|
+
}
|
|
128
|
+
export interface ModelSource {
|
|
129
|
+
provider: string;
|
|
130
|
+
connectionId: string;
|
|
131
|
+
baseUrl?: string;
|
|
132
|
+
}
|
|
133
|
+
export interface EmbedRequest {
|
|
134
|
+
model: string;
|
|
135
|
+
/** One string, or a batch of strings embedded in a single call. */
|
|
136
|
+
input: string | string[];
|
|
137
|
+
signal?: AbortSignal;
|
|
138
|
+
metadata?: Record<string, unknown>;
|
|
139
|
+
/** Provider-native passthrough, same contract as {@link ChatRequest.providerOptions}. */
|
|
140
|
+
providerOptions?: Record<string, unknown>;
|
|
141
|
+
}
|
|
142
|
+
export interface EmbedResult {
|
|
143
|
+
/** One vector per input, in input order. */
|
|
144
|
+
embeddings: number[][];
|
|
145
|
+
model: string;
|
|
146
|
+
usage: Usage;
|
|
147
|
+
source: ModelSource;
|
|
148
|
+
raw?: unknown;
|
|
149
|
+
}
|
|
150
|
+
export declare function modelRef(source: ModelSource, model: string): string;
|
|
151
|
+
export type AIErrorKind = 'auth' | 'rate_limit' | 'timeout' | 'network' | 'server' | 'invalid_request' | 'invalid_response'
|
|
152
|
+
/** 404/410 — endpoint, deployment, or model not found (wrong baseUrl/model, or a misrouted edge). */
|
|
153
|
+
| 'not_found' | 'context_length' | 'canceled' | 'policy_blocked' | 'key_unavailable' | 'tool_error' | 'budget_exceeded';
|
|
154
|
+
export type StreamEvent = {
|
|
155
|
+
type: 'start';
|
|
156
|
+
callId: string;
|
|
157
|
+
provider: string;
|
|
158
|
+
model: string;
|
|
159
|
+
} | {
|
|
160
|
+
type: 'delta';
|
|
161
|
+
text: string;
|
|
162
|
+
} | {
|
|
163
|
+
type: 'reasoning';
|
|
164
|
+
text: string;
|
|
165
|
+
} | {
|
|
166
|
+
type: 'tool_call';
|
|
167
|
+
call: ToolCall;
|
|
168
|
+
} | {
|
|
169
|
+
type: 'context';
|
|
170
|
+
kind: string;
|
|
171
|
+
data: unknown;
|
|
172
|
+
} | {
|
|
173
|
+
type: 'retry';
|
|
174
|
+
attempt: number;
|
|
175
|
+
reason: AIErrorKind;
|
|
176
|
+
delayMs: number;
|
|
177
|
+
} | {
|
|
178
|
+
type: 'done';
|
|
179
|
+
result: ChatResult;
|
|
180
|
+
} | {
|
|
181
|
+
type: 'error';
|
|
182
|
+
error: import('./errors.js').AIError;
|
|
183
|
+
};
|
|
184
|
+
export interface ProviderAdapter {
|
|
185
|
+
readonly provider: string;
|
|
186
|
+
chat(conn: ResolvedConnection, req: ChatRequest): Promise<ChatResult>;
|
|
187
|
+
stream(conn: ResolvedConnection, req: ChatRequest): AsyncIterable<StreamEvent>;
|
|
188
|
+
listModels?(conn: ResolvedConnection): Promise<ModelInfo[]>;
|
|
189
|
+
health?(conn: ResolvedConnection): Promise<{
|
|
190
|
+
ok: boolean;
|
|
191
|
+
detail?: string;
|
|
192
|
+
}>;
|
|
193
|
+
embed?(conn: ResolvedConnection, req: EmbedRequest): Promise<EmbedResult>;
|
|
194
|
+
}
|
|
195
|
+
export interface ModelInfo {
|
|
196
|
+
id: string;
|
|
197
|
+
source: ModelSource;
|
|
198
|
+
contextWindow?: number;
|
|
199
|
+
capabilities?: string[];
|
|
200
|
+
}
|
|
201
|
+
export interface GovernancePolicy {
|
|
202
|
+
checkModel(provider: string, model: string): {
|
|
203
|
+
allowed: true;
|
|
204
|
+
} | {
|
|
205
|
+
allowed: false;
|
|
206
|
+
reason: string;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
export interface Redactor {
|
|
210
|
+
redact(text: string): string;
|
|
211
|
+
}
|
|
212
|
+
export interface TelemetrySink {
|
|
213
|
+
record(r: CallRecord): void | Promise<void>;
|
|
214
|
+
}
|
|
215
|
+
export interface CallInfo {
|
|
216
|
+
callId: string;
|
|
217
|
+
connection: Connection;
|
|
218
|
+
provider: string;
|
|
219
|
+
model: string;
|
|
220
|
+
metadata?: Record<string, unknown>;
|
|
221
|
+
/**
|
|
222
|
+
* The fully resolved connection for this call — base URL defaulted from the
|
|
223
|
+
* provider profile and auth headers applied. Present whenever `beforeCall`
|
|
224
|
+
* runs after resolution (chat/stream and probes), letting a hook validate the
|
|
225
|
+
* *effective* endpoint (e.g. a request-time SSRF/DNS-rebinding re-check on the
|
|
226
|
+
* resolved `baseUrl`) without duplicating profile logic. The resolved
|
|
227
|
+
* `apiKey` is intentionally not exposed here.
|
|
228
|
+
*/
|
|
229
|
+
resolved?: Omit<ResolvedConnection, 'apiKey'>;
|
|
230
|
+
}
|
|
231
|
+
export interface CallRecord {
|
|
232
|
+
callId: string;
|
|
233
|
+
connectionId: string;
|
|
234
|
+
provider: string;
|
|
235
|
+
model: string;
|
|
236
|
+
startedAt: number;
|
|
237
|
+
timing: ChatResult['timing'];
|
|
238
|
+
usage: Usage;
|
|
239
|
+
finishReason: ChatResult['finishReason'];
|
|
240
|
+
error?: {
|
|
241
|
+
kind: AIErrorKind;
|
|
242
|
+
status?: number;
|
|
243
|
+
message: string;
|
|
244
|
+
};
|
|
245
|
+
attempts: number;
|
|
246
|
+
metadata?: Record<string, unknown>;
|
|
247
|
+
promptChars: number;
|
|
248
|
+
responseChars: number;
|
|
249
|
+
/**
|
|
250
|
+
* Estimated cost of this call in USD, computed by the optional `pricing` hook
|
|
251
|
+
* passed to the handler. Undefined when no pricing hook is configured or the
|
|
252
|
+
* hook returns nothing for this provider/model.
|
|
253
|
+
*/
|
|
254
|
+
costUsd?: number;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Minimal [Standard Schema](https://standardschema.dev) validator surface. Any
|
|
258
|
+
* Zod / Valibot / ArkType schema (v1+) satisfies this via its `~standard`
|
|
259
|
+
* property, so `chatParsed` can validate model output against a schema the app
|
|
260
|
+
* already owns — with zero dependency added to this library.
|
|
261
|
+
*/
|
|
262
|
+
export interface StandardSchemaV1<Output = unknown> {
|
|
263
|
+
readonly '~standard': {
|
|
264
|
+
readonly version: 1;
|
|
265
|
+
readonly vendor: string;
|
|
266
|
+
readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
export type StandardSchemaResult<Output> = {
|
|
270
|
+
readonly value: Output;
|
|
271
|
+
readonly issues?: undefined;
|
|
272
|
+
} | {
|
|
273
|
+
readonly issues: ReadonlyArray<{
|
|
274
|
+
readonly message: string;
|
|
275
|
+
readonly path?: ReadonlyArray<PropertyKey | {
|
|
276
|
+
readonly key: PropertyKey;
|
|
277
|
+
}>;
|
|
278
|
+
}>;
|
|
279
|
+
};
|
|
280
|
+
/** Output of {@link AIHandler.chatParsed}: the validated value plus the raw chat result. */
|
|
281
|
+
export interface ParsedResult<T> {
|
|
282
|
+
data: T;
|
|
283
|
+
result: ChatResult;
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiJA,MAAM,UAAU,QAAQ,CAAC,MAAmB,EAAE,KAAa;IACzD,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,KAAK,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ChatMessage } from './types.js';
|
|
2
|
+
export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
|
|
3
|
+
export declare function asString(value: unknown): string | undefined;
|
|
4
|
+
export declare function asNumber(value: unknown): number | undefined;
|
|
5
|
+
export declare function promptChars(messages: ChatMessage[]): number;
|
|
6
|
+
export declare function textFromMessages(messages: ChatMessage[]): string;
|
|
7
|
+
export declare function globalEnv(): Record<string, string | undefined>;
|
|
8
|
+
/**
|
|
9
|
+
* Merges app-supplied {@link ChatRequest.providerOptions} into a provider
|
|
10
|
+
* request body: shallow at the top level, and one level deep for each key in
|
|
11
|
+
* `nestedKeys` where both sides are plain objects (Ollama `options`, Google
|
|
12
|
+
* `generationConfig`). Values in `providerOptions` win on collision.
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyProviderOptions(body: Record<string, unknown>, providerOptions: Record<string, unknown> | undefined, nestedKeys?: readonly string[]): Record<string, unknown>;
|
|
15
|
+
/** Joins a base URL and path without producing a double slash, even if `base` ends with `/`. */
|
|
16
|
+
export declare function joinUrl(base: string, path: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Runs `fn` over `items` with at most `limit` in flight at once, preserving
|
|
19
|
+
* input order in the returned array. Used to probe many local models
|
|
20
|
+
* concurrently without opening an unbounded number of sockets.
|
|
21
|
+
*/
|
|
22
|
+
export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
23
|
+
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAE5E;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE3D;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE3D;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAK3D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAKhE;AAED,wBAAgB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAG9D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACpD,UAAU,GAAE,SAAS,MAAM,EAAO,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB;AAED,gGAAgG;AAChG,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAc3I;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBrE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export function asRecord(value) {
|
|
2
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
|
|
3
|
+
}
|
|
4
|
+
export function asString(value) {
|
|
5
|
+
return typeof value === 'string' ? value : undefined;
|
|
6
|
+
}
|
|
7
|
+
export function asNumber(value) {
|
|
8
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function promptChars(messages) {
|
|
11
|
+
return messages.reduce((sum, message) => {
|
|
12
|
+
if (typeof message.content === 'string')
|
|
13
|
+
return sum + message.content.length;
|
|
14
|
+
return sum + message.content.reduce((partSum, part) => partSum + (part.text?.length ?? 0) + (part.imageBase64?.length ?? 0), 0);
|
|
15
|
+
}, 0);
|
|
16
|
+
}
|
|
17
|
+
export function textFromMessages(messages) {
|
|
18
|
+
return messages.map((message) => {
|
|
19
|
+
if (typeof message.content === 'string')
|
|
20
|
+
return message.content;
|
|
21
|
+
return message.content.map((part) => part.text ?? '').join('');
|
|
22
|
+
}).join('\n');
|
|
23
|
+
}
|
|
24
|
+
export function globalEnv() {
|
|
25
|
+
const maybeProcess = globalThis;
|
|
26
|
+
return maybeProcess.process?.env ?? {};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Merges app-supplied {@link ChatRequest.providerOptions} into a provider
|
|
30
|
+
* request body: shallow at the top level, and one level deep for each key in
|
|
31
|
+
* `nestedKeys` where both sides are plain objects (Ollama `options`, Google
|
|
32
|
+
* `generationConfig`). Values in `providerOptions` win on collision.
|
|
33
|
+
*/
|
|
34
|
+
export function applyProviderOptions(body, providerOptions, nestedKeys = []) {
|
|
35
|
+
if (!providerOptions)
|
|
36
|
+
return body;
|
|
37
|
+
const merged = { ...body };
|
|
38
|
+
for (const [key, value] of Object.entries(providerOptions)) {
|
|
39
|
+
const base = asRecord(merged[key]);
|
|
40
|
+
if (nestedKeys.includes(key) && base && asRecord(value)) {
|
|
41
|
+
merged[key] = { ...base, ...value };
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
merged[key] = value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return merged;
|
|
48
|
+
}
|
|
49
|
+
/** Joins a base URL and path without producing a double slash, even if `base` ends with `/`. */
|
|
50
|
+
export function joinUrl(base, path) {
|
|
51
|
+
return `${base.replace(/\/+$/, '')}/${path.replace(/^\/+/, '')}`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Runs `fn` over `items` with at most `limit` in flight at once, preserving
|
|
55
|
+
* input order in the returned array. Used to probe many local models
|
|
56
|
+
* concurrently without opening an unbounded number of sockets.
|
|
57
|
+
*/
|
|
58
|
+
export async function mapWithConcurrency(items, limit, fn) {
|
|
59
|
+
const results = new Array(items.length);
|
|
60
|
+
let next = 0;
|
|
61
|
+
const workerCount = Math.max(1, Math.min(limit, items.length));
|
|
62
|
+
const worker = async () => {
|
|
63
|
+
for (;;) {
|
|
64
|
+
const index = next;
|
|
65
|
+
next += 1;
|
|
66
|
+
if (index >= items.length)
|
|
67
|
+
return;
|
|
68
|
+
results[index] = await fn(items[index], index);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
await Promise.all(Array.from({ length: workerCount }, worker));
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
export function sleep(ms, signal) {
|
|
75
|
+
if (ms <= 0)
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
let settled = false;
|
|
79
|
+
const cleanup = () => signal?.removeEventListener('abort', onAbort);
|
|
80
|
+
const timer = setTimeout(() => {
|
|
81
|
+
settled = true;
|
|
82
|
+
cleanup();
|
|
83
|
+
resolve();
|
|
84
|
+
}, ms);
|
|
85
|
+
const onAbort = () => {
|
|
86
|
+
if (settled)
|
|
87
|
+
return;
|
|
88
|
+
settled = true;
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
cleanup();
|
|
91
|
+
reject(new DOMException('Sleep aborted', 'AbortError'));
|
|
92
|
+
};
|
|
93
|
+
if (signal) {
|
|
94
|
+
if (signal.aborted)
|
|
95
|
+
onAbort();
|
|
96
|
+
else
|
|
97
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AIError } from '../../errors.js';
|
|
2
2
|
import { estimatedUsage } from '../../tokens.js';
|
|
3
|
-
import { postResponse, sseLines } from '../../transport.js';
|
|
4
|
-
import type { ChatMessage, ChatRequest, ChatResult, ProviderAdapter, ResolvedConnection, StreamEvent, ToolCall } from '../../types.js';
|
|
5
|
-
import { asNumber, asRecord, asString, textFromMessages } from '../../util.js';
|
|
6
|
-
import { streamError, streamTimeout } from './base.js';
|
|
3
|
+
import { fetchJson, postResponse, sseLines } from '../../transport.js';
|
|
4
|
+
import type { ChatMessage, ChatRequest, ChatResult, ModelInfo, ProviderAdapter, ResolvedConnection, StreamEvent, ToolCall } from '../../types.js';
|
|
5
|
+
import { applyProviderOptions, asNumber, asRecord, asString, joinUrl, textFromMessages } from '../../util.js';
|
|
6
|
+
import { DEFAULT_TIMEOUT_MS, parseArgs, randomId, safeParse, streamAnomaly, streamError, streamTimeout } from './base.js';
|
|
7
7
|
|
|
8
8
|
const JSON_MODE_TOOL = 'json_output';
|
|
9
9
|
|
|
@@ -31,11 +31,22 @@ export class AnthropicAdapter implements ProviderAdapter {
|
|
|
31
31
|
let inputTokens: number | undefined;
|
|
32
32
|
let outputTokens: number | undefined;
|
|
33
33
|
let stopReason: string | undefined;
|
|
34
|
+
let sawTerminal = false;
|
|
34
35
|
const emittedTools: ToolCall[] = [];
|
|
35
36
|
// Partial tool_use blocks keyed by content-block index (input_json_delta accumulation).
|
|
36
37
|
const blocks = new Map<number, { id: string; name: string; raw: string }>();
|
|
37
38
|
const timeout = streamTimeout(conn, req.signal);
|
|
38
39
|
yield { type: 'start', callId: '', provider: conn.provider, model: req.model };
|
|
40
|
+
// Anthropic JSON mode is implemented as a forced `json_output` tool, which
|
|
41
|
+
// cannot coexist with the caller's own tools — same silent-downgrade shape
|
|
42
|
+
// as Gemini, so it gets the same signal rather than quietly dropping.
|
|
43
|
+
if (req.responseFormat?.type === 'json' && req.tools?.length) {
|
|
44
|
+
yield {
|
|
45
|
+
type: 'context',
|
|
46
|
+
kind: 'json_mode_downgraded',
|
|
47
|
+
data: { reason: 'Anthropic JSON mode uses a forced tool and cannot be combined with caller tools; the request was sent without JSON mode', provider: conn.provider },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
39
50
|
try {
|
|
40
51
|
const res = await postResponse(`${conn.baseUrl}/v1/messages`, body(req, jsonMode), conn.headers, timeout.signal, conn.provider);
|
|
41
52
|
const contentType = res.headers.get('content-type') ?? '';
|
|
@@ -45,6 +56,7 @@ export class AnthropicAdapter implements ProviderAdapter {
|
|
|
45
56
|
inputTokens = parsed.inputTokens;
|
|
46
57
|
outputTokens = parsed.outputTokens;
|
|
47
58
|
stopReason = parsed.stopReason;
|
|
59
|
+
sawTerminal = true;
|
|
48
60
|
if (jsonMode) {
|
|
49
61
|
text = jsonTextFrom(parsed.toolCalls, parsed.text);
|
|
50
62
|
if (text) yield { type: 'delta', text };
|
|
@@ -58,6 +70,7 @@ export class AnthropicAdapter implements ProviderAdapter {
|
|
|
58
70
|
}
|
|
59
71
|
} else {
|
|
60
72
|
for await (const line of sseLines(res)) {
|
|
73
|
+
timeout.bump();
|
|
61
74
|
const record = asRecord(safeParse(line));
|
|
62
75
|
if (!record) continue;
|
|
63
76
|
const type = asString(record.type);
|
|
@@ -81,6 +94,10 @@ export class AnthropicAdapter implements ProviderAdapter {
|
|
|
81
94
|
text += piece;
|
|
82
95
|
yield { type: 'delta', text: piece };
|
|
83
96
|
}
|
|
97
|
+
} else if (delta?.type === 'thinking_delta') {
|
|
98
|
+
// Extended-thinking tokens ride the reasoning channel, kept out of `text`.
|
|
99
|
+
const piece = asString(delta.thinking) ?? '';
|
|
100
|
+
if (piece) yield { type: 'reasoning', text: piece };
|
|
84
101
|
} else if (delta?.type === 'input_json_delta') {
|
|
85
102
|
const partial = blocks.get(index);
|
|
86
103
|
if (partial) partial.raw += asString(delta.partial_json) ?? '';
|
|
@@ -100,14 +117,18 @@ export class AnthropicAdapter implements ProviderAdapter {
|
|
|
100
117
|
yield { type: 'tool_call', call };
|
|
101
118
|
}
|
|
102
119
|
}
|
|
120
|
+
} else if (type === 'message_stop') {
|
|
121
|
+
sawTerminal = true;
|
|
103
122
|
} else if (type === 'message_delta') {
|
|
104
123
|
const delta = asRecord(record.delta);
|
|
124
|
+
if (asString(delta?.stop_reason)) sawTerminal = true;
|
|
105
125
|
stopReason = asString(delta?.stop_reason) ?? stopReason;
|
|
106
126
|
const usage = asRecord(record.usage);
|
|
107
127
|
outputTokens = asNumber(usage?.output_tokens) ?? outputTokens;
|
|
108
128
|
}
|
|
109
129
|
}
|
|
110
130
|
}
|
|
131
|
+
if (!sawTerminal) yield streamAnomaly('stream ended without a stop_reason or message_stop');
|
|
111
132
|
const hasTools = emittedTools.length > 0;
|
|
112
133
|
yield { type: 'done', result: {
|
|
113
134
|
text,
|
|
@@ -124,6 +145,25 @@ export class AnthropicAdapter implements ProviderAdapter {
|
|
|
124
145
|
timeout.done();
|
|
125
146
|
}
|
|
126
147
|
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Lists models from Anthropic's `/v1/models` endpoint (auth + version headers
|
|
151
|
+
* already applied to `conn.headers`). The endpoint does not report a context
|
|
152
|
+
* window, so `contextWindow` is left undefined rather than guessed.
|
|
153
|
+
*/
|
|
154
|
+
async listModels(conn: ResolvedConnection): Promise<ModelInfo[]> {
|
|
155
|
+
const { data } = await fetchJson(joinUrl(conn.baseUrl, '/v1/models'), {
|
|
156
|
+
method: 'GET',
|
|
157
|
+
headers: conn.headers,
|
|
158
|
+
timeoutMs: Math.min(conn.timeoutMs ?? DEFAULT_TIMEOUT_MS, 15_000),
|
|
159
|
+
provider: conn.provider,
|
|
160
|
+
});
|
|
161
|
+
const rows = Array.isArray(asRecord(data)?.data) ? asRecord(data)!.data as unknown[] : [];
|
|
162
|
+
return rows
|
|
163
|
+
.map((row) => asString(asRecord(row)?.id))
|
|
164
|
+
.filter((id): id is string => Boolean(id))
|
|
165
|
+
.map((id) => ({ id, source: { provider: conn.provider, connectionId: conn.id, baseUrl: conn.baseUrl } }));
|
|
166
|
+
}
|
|
127
167
|
}
|
|
128
168
|
|
|
129
169
|
function body(req: ChatRequest, jsonMode: boolean): Record<string, unknown> {
|
|
@@ -149,7 +189,9 @@ function body(req: ChatRequest, jsonMode: boolean): Record<string, unknown> {
|
|
|
149
189
|
else if (req.toolChoice === 'auto') base.tool_choice = { type: 'auto' };
|
|
150
190
|
else if (req.toolChoice === 'none') base.tool_choice = { type: 'none' };
|
|
151
191
|
}
|
|
152
|
-
|
|
192
|
+
// providerOptions carries Anthropic-native fields (`thinking`, `metadata`,
|
|
193
|
+
// top-level `cache_control` extras, `service_tier`, …) without a release.
|
|
194
|
+
return applyProviderOptions(base, req.providerOptions);
|
|
153
195
|
}
|
|
154
196
|
|
|
155
197
|
function toAnthropicMessages(messages: ChatMessage[]): Record<string, unknown>[] {
|
|
@@ -173,28 +215,30 @@ function toAnthropicMessages(messages: ChatMessage[]): Record<string, unknown>[]
|
|
|
173
215
|
}
|
|
174
216
|
|
|
175
217
|
function toAnthropicMessage(m: ChatMessage): Record<string, unknown> {
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
// assistant turns that carried tool calls replay them as tool_use blocks.
|
|
218
|
+
// Tool-role messages are handled by toAnthropicMessages' batching loop and
|
|
219
|
+
// never reach here, so no tool branch is needed.
|
|
220
|
+
|
|
221
|
+
// assistant turns that carried tool calls replay them as tool_use blocks,
|
|
222
|
+
// preserving any text/image content parts that accompanied the calls.
|
|
184
223
|
if (m.role === 'assistant' && m.toolCalls?.length) {
|
|
185
|
-
const content: unknown[] = [];
|
|
186
|
-
if (typeof m.content === 'string' && m.content) content.push({ type: 'text', text: m.content });
|
|
224
|
+
const content: unknown[] = [...contentBlocks(m.content)];
|
|
187
225
|
for (const call of m.toolCalls) content.push({ type: 'tool_use', id: call.id, name: call.name, input: call.arguments ?? {} });
|
|
188
226
|
return { role: 'assistant', content };
|
|
189
227
|
}
|
|
190
228
|
return {
|
|
191
229
|
role: m.role === 'assistant' ? 'assistant' : 'user',
|
|
192
|
-
content: typeof m.content === 'string' ? m.content : m.content
|
|
193
|
-
? { type: 'image', source: { type: 'base64', media_type: part.mimeType ?? 'image/png', data: part.imageBase64 ?? '' } }
|
|
194
|
-
: { type: 'text', text: part.text ?? '' }),
|
|
230
|
+
content: typeof m.content === 'string' ? m.content : contentBlocks(m.content),
|
|
195
231
|
};
|
|
196
232
|
}
|
|
197
233
|
|
|
234
|
+
/** Maps text/image content — a string or a ContentPart[] — onto Anthropic content blocks. */
|
|
235
|
+
function contentBlocks(content: ChatMessage['content']): unknown[] {
|
|
236
|
+
if (typeof content === 'string') return content ? [{ type: 'text', text: content }] : [];
|
|
237
|
+
return content.map((part) => part.type === 'image'
|
|
238
|
+
? { type: 'image', source: { type: 'base64', media_type: part.mimeType ?? 'image/png', data: part.imageBase64 ?? '' } }
|
|
239
|
+
: { type: 'text', text: part.text ?? '' });
|
|
240
|
+
}
|
|
241
|
+
|
|
198
242
|
function textContent(content: ChatMessage['content']): string {
|
|
199
243
|
if (typeof content === 'string') return content;
|
|
200
244
|
if (!content) return '';
|
|
@@ -239,22 +283,3 @@ function mapStop(stop: string | undefined, hasTools: boolean): ChatResult['finis
|
|
|
239
283
|
return 'stop';
|
|
240
284
|
}
|
|
241
285
|
|
|
242
|
-
function parseArgs(raw: string): unknown {
|
|
243
|
-
try {
|
|
244
|
-
return raw ? JSON.parse(raw) as unknown : {};
|
|
245
|
-
} catch {
|
|
246
|
-
return {};
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function safeParse(line: string): unknown {
|
|
251
|
-
try {
|
|
252
|
-
return JSON.parse(line) as unknown;
|
|
253
|
-
} catch {
|
|
254
|
-
return undefined;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function randomId(): string {
|
|
259
|
-
return globalThis.crypto?.randomUUID?.() ?? `tool_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
260
|
-
}
|