@ddlqhd/agent-sdk 0.1.0 → 0.2.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 +4 -2
- package/dist/{chunk-5QMA2YBY.cjs → chunk-6X7EYQLS.cjs} +782 -114
- package/dist/chunk-6X7EYQLS.cjs.map +1 -0
- package/dist/{chunk-NDSL7NPN.js → chunk-D3UZNLZO.js} +769 -71
- package/dist/chunk-D3UZNLZO.js.map +1 -0
- package/dist/{chunk-Q3SOMX26.js → chunk-EQ5CXH44.js} +772 -111
- package/dist/chunk-EQ5CXH44.js.map +1 -0
- package/dist/chunk-LOYIGOBZ.js +54 -0
- package/dist/chunk-LOYIGOBZ.js.map +1 -0
- package/dist/{chunk-OHXW2YM6.js → chunk-MEJHTQJM.js} +289 -166
- package/dist/chunk-MEJHTQJM.js.map +1 -0
- package/dist/chunk-NYZD3THB.cjs +1521 -0
- package/dist/chunk-NYZD3THB.cjs.map +1 -0
- package/dist/chunk-OZO7D77N.cjs +59 -0
- package/dist/chunk-OZO7D77N.cjs.map +1 -0
- package/dist/{chunk-JF5AJQMU.cjs → chunk-Z45DHTDX.cjs} +291 -170
- package/dist/chunk-Z45DHTDX.cjs.map +1 -0
- package/dist/cli/index.cjs +47 -39
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +22 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/{index-DPsZ1zat.d.ts → index-Cw3SfEAB.d.ts} +20 -34
- package/dist/{index-RTPmFjMp.d.cts → index-D2Qntkn_.d.cts} +20 -34
- package/dist/index.cjs +125 -89
- package/dist/index.d.cts +62 -22
- package/dist/index.d.ts +62 -22
- package/dist/index.js +4 -4
- package/dist/models/index.cjs +19 -15
- package/dist/models/index.d.cts +55 -6
- package/dist/models/index.d.ts +55 -6
- package/dist/models/index.js +2 -2
- package/dist/tools/index.cjs +53 -61
- package/dist/tools/index.d.cts +3 -3
- package/dist/tools/index.d.ts +3 -3
- package/dist/tools/index.js +2 -2
- package/dist/{types-C0aX_Qdp.d.cts → types-CWPAYWzr.d.cts} +307 -61
- package/dist/{types-C0aX_Qdp.d.ts → types-CWPAYWzr.d.ts} +307 -61
- package/package.json +25 -14
- package/dist/chunk-5QMA2YBY.cjs.map +0 -1
- package/dist/chunk-CNSGZVRN.cjs +0 -152
- package/dist/chunk-CNSGZVRN.cjs.map +0 -1
- package/dist/chunk-JF5AJQMU.cjs.map +0 -1
- package/dist/chunk-NDSL7NPN.js.map +0 -1
- package/dist/chunk-OHXW2YM6.js.map +0 -1
- package/dist/chunk-Q3SOMX26.js.map +0 -1
- package/dist/chunk-WH3APNQ5.js +0 -147
- package/dist/chunk-WH3APNQ5.js.map +0 -1
- package/dist/chunk-X35MHWXE.cjs +0 -817
- package/dist/chunk-X35MHWXE.cjs.map +0 -1
|
@@ -1,14 +1,358 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { BaseModelAdapter, toolsToModelSchema } from './chunk-
|
|
2
|
+
import { BaseModelAdapter, toolsToModelSchema } from './chunk-LOYIGOBZ.js';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
3
4
|
|
|
4
|
-
// src/models/
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
// src/models/default-capabilities.ts
|
|
6
|
+
var DEFAULT_ADAPTER_CAPABILITIES = {
|
|
7
|
+
contextLength: 2e5,
|
|
8
|
+
maxOutputTokens: 32e3
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/core/logger.ts
|
|
12
|
+
var TRUTHY = /^(1|true|yes)$/i;
|
|
13
|
+
var DEFAULT_MAX_BODY_CHARS = 4e3;
|
|
14
|
+
var DEFAULT_REDACT_KEYS = [
|
|
15
|
+
"authorization",
|
|
16
|
+
"proxy-authorization",
|
|
17
|
+
"x-api-key",
|
|
18
|
+
"api-key",
|
|
19
|
+
"apikey",
|
|
20
|
+
"api_key",
|
|
21
|
+
"cookie",
|
|
22
|
+
"set-cookie",
|
|
23
|
+
"token",
|
|
24
|
+
"access_token",
|
|
25
|
+
"refresh_token",
|
|
26
|
+
"password",
|
|
27
|
+
"secret"
|
|
28
|
+
];
|
|
29
|
+
var LEVEL_PRIORITY = {
|
|
30
|
+
debug: 10,
|
|
31
|
+
info: 20,
|
|
32
|
+
warn: 30,
|
|
33
|
+
error: 40,
|
|
34
|
+
silent: 99
|
|
11
35
|
};
|
|
36
|
+
function parseEnvLogLevel(raw) {
|
|
37
|
+
switch ((raw ?? "").trim().toLowerCase()) {
|
|
38
|
+
case "debug":
|
|
39
|
+
case "info":
|
|
40
|
+
case "warn":
|
|
41
|
+
case "error":
|
|
42
|
+
case "silent":
|
|
43
|
+
return (raw ?? "").trim().toLowerCase();
|
|
44
|
+
default:
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function parseBooleanEnv(name) {
|
|
49
|
+
const raw = process.env[name];
|
|
50
|
+
if (raw == null || raw === "") {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
if (TRUTHY.test(raw.trim())) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (/^(0|false|no)$/i.test(raw.trim())) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
function parseNumericEnv(name) {
|
|
62
|
+
const raw = process.env[name];
|
|
63
|
+
if (raw == null || raw === "") {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
const value = Number(raw);
|
|
67
|
+
return Number.isFinite(value) ? value : void 0;
|
|
68
|
+
}
|
|
69
|
+
function resolveSDKLogLevel(level, hasLogger = false) {
|
|
70
|
+
if (level != null) {
|
|
71
|
+
return level;
|
|
72
|
+
}
|
|
73
|
+
const fromEnv = parseEnvLogLevel(process.env.AGENT_SDK_LOG_LEVEL);
|
|
74
|
+
if (fromEnv != null) {
|
|
75
|
+
return fromEnv;
|
|
76
|
+
}
|
|
77
|
+
if (hasLogger) {
|
|
78
|
+
return "info";
|
|
79
|
+
}
|
|
80
|
+
return "silent";
|
|
81
|
+
}
|
|
82
|
+
function resolveLogRedaction(config) {
|
|
83
|
+
const envIncludeBodies = parseBooleanEnv("AGENT_SDK_LOG_BODIES");
|
|
84
|
+
const envIncludeToolArgs = parseBooleanEnv("AGENT_SDK_LOG_INCLUDE_TOOL_ARGS");
|
|
85
|
+
const envMaxBodyChars = parseNumericEnv("AGENT_SDK_LOG_MAX_BODY_CHARS");
|
|
86
|
+
return {
|
|
87
|
+
includeBodies: config?.includeBodies ?? envIncludeBodies ?? false,
|
|
88
|
+
includeToolArguments: config?.includeToolArguments ?? envIncludeToolArgs ?? false,
|
|
89
|
+
maxBodyChars: Math.max(
|
|
90
|
+
0,
|
|
91
|
+
Math.floor(config?.maxBodyChars ?? envMaxBodyChars ?? DEFAULT_MAX_BODY_CHARS)
|
|
92
|
+
),
|
|
93
|
+
redactKeys: [
|
|
94
|
+
...DEFAULT_REDACT_KEYS,
|
|
95
|
+
...config?.redactKeys ?? []
|
|
96
|
+
]
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function shouldEmitLog(configuredLevel, hasLogger, eventLevel) {
|
|
100
|
+
const effectiveLevel = resolveSDKLogLevel(configuredLevel, hasLogger);
|
|
101
|
+
return LEVEL_PRIORITY[eventLevel] >= LEVEL_PRIORITY[effectiveLevel];
|
|
102
|
+
}
|
|
103
|
+
function truncateString(value, maxChars) {
|
|
104
|
+
if (maxChars <= 0 || value.length <= maxChars) {
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
return `${value.slice(0, maxChars)}... [truncated ${value.length - maxChars} chars]`;
|
|
108
|
+
}
|
|
109
|
+
function isSensitiveKey(key, redaction) {
|
|
110
|
+
if (key == null || redaction == null) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const normalized = key.toLowerCase();
|
|
114
|
+
return redaction.redactKeys.some((candidate) => candidate.toLowerCase() === normalized);
|
|
115
|
+
}
|
|
116
|
+
function sanitizeObjectEntries(entries, redaction) {
|
|
117
|
+
const output = {};
|
|
118
|
+
for (const [key, value] of entries) {
|
|
119
|
+
if (isSensitiveKey(key, redaction)) {
|
|
120
|
+
output[key] = "[REDACTED]";
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (key === "messages" && !redaction.includeBodies && Array.isArray(value)) {
|
|
124
|
+
output[key] = `[REDACTED_MESSAGES:${value.length}]`;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if ((key === "arguments" || key === "input") && !redaction.includeToolArguments) {
|
|
128
|
+
output[key] = "[REDACTED_TOOL_ARGUMENTS]";
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
output[key] = sanitizeForLogging(value, redaction, key);
|
|
132
|
+
}
|
|
133
|
+
return output;
|
|
134
|
+
}
|
|
135
|
+
function sanitizeForLogging(value, redaction, key) {
|
|
136
|
+
if (isSensitiveKey(key, redaction)) {
|
|
137
|
+
return "[REDACTED]";
|
|
138
|
+
}
|
|
139
|
+
if (typeof value === "string") {
|
|
140
|
+
if (!redaction.includeBodies && (key === "content" || key === "text" || key === "thinking")) {
|
|
141
|
+
return "[REDACTED_BODY]";
|
|
142
|
+
}
|
|
143
|
+
return truncateString(value, redaction.maxBodyChars);
|
|
144
|
+
}
|
|
145
|
+
if (typeof value === "number" || typeof value === "boolean" || value == null) {
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
if (Array.isArray(value)) {
|
|
149
|
+
if (!redaction.includeBodies && key === "messages") {
|
|
150
|
+
return `[REDACTED_MESSAGES:${value.length}]`;
|
|
151
|
+
}
|
|
152
|
+
return value.map((item) => sanitizeForLogging(item, redaction));
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === "object") {
|
|
155
|
+
return sanitizeObjectEntries(Object.entries(value), redaction);
|
|
156
|
+
}
|
|
157
|
+
return String(value);
|
|
158
|
+
}
|
|
159
|
+
function formatSDKLog(event) {
|
|
160
|
+
const prefix = `[agent-sdk][${event.component}][${event.event}]`;
|
|
161
|
+
const details = [];
|
|
162
|
+
if (event.provider) details.push(`provider=${event.provider}`);
|
|
163
|
+
if (event.model) details.push(`model=${event.model}`);
|
|
164
|
+
if (event.sessionId) details.push(`sessionId=${event.sessionId}`);
|
|
165
|
+
if (event.iteration !== void 0) details.push(`iteration=${event.iteration}`);
|
|
166
|
+
if (event.statusCode !== void 0) details.push(`statusCode=${event.statusCode}`);
|
|
167
|
+
if (event.durationMs !== void 0) details.push(`durationMs=${event.durationMs}`);
|
|
168
|
+
if (event.toolName) details.push(`tool=${event.toolName}`);
|
|
169
|
+
if (event.requestId) details.push(`requestId=${event.requestId}`);
|
|
170
|
+
if (event.clientRequestId) details.push(`clientRequestId=${event.clientRequestId}`);
|
|
171
|
+
const suffix = details.length > 0 ? ` ${details.join(" ")}` : "";
|
|
172
|
+
return event.message ? `${prefix} ${event.message}${suffix}` : `${prefix}${suffix}`;
|
|
173
|
+
}
|
|
174
|
+
function consoleMethod(level) {
|
|
175
|
+
if (level === "error") return console.error.bind(console);
|
|
176
|
+
if (level === "warn") return console.warn.bind(console);
|
|
177
|
+
if (level === "info") return console.info.bind(console);
|
|
178
|
+
return console.debug.bind(console);
|
|
179
|
+
}
|
|
180
|
+
function createConsoleSDKLogger() {
|
|
181
|
+
const write = (level, event) => {
|
|
182
|
+
const line = formatSDKLog(event);
|
|
183
|
+
const logFn = consoleMethod(level);
|
|
184
|
+
if (event.metadata != null) {
|
|
185
|
+
logFn(line, event.metadata);
|
|
186
|
+
} else {
|
|
187
|
+
logFn(line);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
debug(event) {
|
|
192
|
+
write("debug", event);
|
|
193
|
+
},
|
|
194
|
+
info(event) {
|
|
195
|
+
write("info", event);
|
|
196
|
+
},
|
|
197
|
+
warn(event) {
|
|
198
|
+
write("warn", event);
|
|
199
|
+
},
|
|
200
|
+
error(event) {
|
|
201
|
+
write("error", event);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function emitSDKLog(args) {
|
|
206
|
+
if (!shouldEmitLog(args.logLevel, args.logger != null, args.level)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const logger = args.logger ?? createConsoleSDKLogger();
|
|
210
|
+
const payload = {
|
|
211
|
+
source: "agent-sdk",
|
|
212
|
+
...args.event
|
|
213
|
+
};
|
|
214
|
+
logger[args.level]?.(payload);
|
|
215
|
+
}
|
|
216
|
+
function extractProviderRequestId(headers) {
|
|
217
|
+
if (headers == null) {
|
|
218
|
+
return void 0;
|
|
219
|
+
}
|
|
220
|
+
return headers.get("x-request-id") ?? headers.get("request-id") ?? headers.get("x-amzn-requestid") ?? void 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/models/model-request-log.ts
|
|
224
|
+
function countMessages(body) {
|
|
225
|
+
if (body == null || typeof body !== "object" || !("messages" in body)) {
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
const messages = body.messages;
|
|
229
|
+
return Array.isArray(messages) ? messages.length : void 0;
|
|
230
|
+
}
|
|
231
|
+
function countTools(body) {
|
|
232
|
+
if (body == null || typeof body !== "object" || !("tools" in body)) {
|
|
233
|
+
return void 0;
|
|
234
|
+
}
|
|
235
|
+
const tools = body.tools;
|
|
236
|
+
return Array.isArray(tools) ? tools.length : void 0;
|
|
237
|
+
}
|
|
238
|
+
function buildRequestMetadata(body, params) {
|
|
239
|
+
const redaction = resolveLogRedaction(params?.redaction);
|
|
240
|
+
const metadata = {};
|
|
241
|
+
const messageCount = countMessages(body);
|
|
242
|
+
const toolCount = countTools(body);
|
|
243
|
+
if (messageCount !== void 0) metadata.messageCount = messageCount;
|
|
244
|
+
if (toolCount !== void 0) metadata.toolCount = toolCount;
|
|
245
|
+
if (redaction.includeBodies) {
|
|
246
|
+
metadata.requestBody = sanitizeForLogging(body, redaction);
|
|
247
|
+
}
|
|
248
|
+
return metadata;
|
|
249
|
+
}
|
|
250
|
+
function logModelRequestStart(context, body, extraMetadata) {
|
|
251
|
+
const state = {
|
|
252
|
+
clientRequestId: randomUUID(),
|
|
253
|
+
startedAt: Date.now()
|
|
254
|
+
};
|
|
255
|
+
emitSDKLog({
|
|
256
|
+
logger: context.params?.logger,
|
|
257
|
+
logLevel: context.params?.logLevel,
|
|
258
|
+
level: "info",
|
|
259
|
+
event: {
|
|
260
|
+
component: "model",
|
|
261
|
+
event: "model.request.start",
|
|
262
|
+
message: `Starting ${context.operation} request`,
|
|
263
|
+
provider: context.provider,
|
|
264
|
+
model: context.model,
|
|
265
|
+
operation: context.operation,
|
|
266
|
+
sessionId: context.params?.sessionId,
|
|
267
|
+
iteration: context.iteration,
|
|
268
|
+
clientRequestId: state.clientRequestId,
|
|
269
|
+
metadata: {
|
|
270
|
+
path: context.path,
|
|
271
|
+
...buildRequestMetadata(body, context.params),
|
|
272
|
+
...extraMetadata
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
return state;
|
|
277
|
+
}
|
|
278
|
+
function logModelRequestEnd(context, state, response, extraMetadata) {
|
|
279
|
+
emitSDKLog({
|
|
280
|
+
logger: context.params?.logger,
|
|
281
|
+
logLevel: context.params?.logLevel,
|
|
282
|
+
level: response.ok ? "info" : "warn",
|
|
283
|
+
event: {
|
|
284
|
+
component: "model",
|
|
285
|
+
event: response.ok ? "model.request.end" : "model.request.error",
|
|
286
|
+
message: response.ok ? "Model request completed" : "Model request returned error response",
|
|
287
|
+
provider: context.provider,
|
|
288
|
+
model: context.model,
|
|
289
|
+
operation: context.operation,
|
|
290
|
+
sessionId: context.params?.sessionId,
|
|
291
|
+
iteration: context.iteration,
|
|
292
|
+
clientRequestId: state.clientRequestId,
|
|
293
|
+
requestId: extractProviderRequestId(response.headers),
|
|
294
|
+
statusCode: response.status,
|
|
295
|
+
durationMs: Date.now() - state.startedAt,
|
|
296
|
+
metadata: {
|
|
297
|
+
path: context.path,
|
|
298
|
+
...extraMetadata
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
function logModelRequestFailure(context, state, error, extraMetadata) {
|
|
304
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
305
|
+
emitSDKLog({
|
|
306
|
+
logger: context.params?.logger,
|
|
307
|
+
logLevel: context.params?.logLevel,
|
|
308
|
+
level: err.name === "AbortError" ? "info" : "error",
|
|
309
|
+
event: {
|
|
310
|
+
component: "model",
|
|
311
|
+
event: err.name === "AbortError" ? "model.request.aborted" : "model.request.error",
|
|
312
|
+
message: err.name === "AbortError" ? "Model request aborted" : "Model request failed",
|
|
313
|
+
provider: context.provider,
|
|
314
|
+
model: context.model,
|
|
315
|
+
operation: context.operation,
|
|
316
|
+
sessionId: context.params?.sessionId,
|
|
317
|
+
iteration: context.iteration,
|
|
318
|
+
clientRequestId: state.clientRequestId,
|
|
319
|
+
durationMs: Date.now() - state.startedAt,
|
|
320
|
+
errorName: err.name,
|
|
321
|
+
errorMessage: err.message,
|
|
322
|
+
metadata: {
|
|
323
|
+
path: context.path,
|
|
324
|
+
...extraMetadata
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function logModelStreamParseError(context, rawChunk, error) {
|
|
330
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
331
|
+
const redaction = resolveLogRedaction(context.params?.redaction);
|
|
332
|
+
emitSDKLog({
|
|
333
|
+
logger: context.params?.logger,
|
|
334
|
+
logLevel: context.params?.logLevel,
|
|
335
|
+
level: "warn",
|
|
336
|
+
event: {
|
|
337
|
+
component: "streaming",
|
|
338
|
+
event: "model.stream.parse_error",
|
|
339
|
+
message: "Failed to parse provider stream chunk",
|
|
340
|
+
provider: context.provider,
|
|
341
|
+
model: context.model,
|
|
342
|
+
operation: context.operation,
|
|
343
|
+
sessionId: context.params?.sessionId,
|
|
344
|
+
iteration: context.iteration,
|
|
345
|
+
errorName: err.name,
|
|
346
|
+
errorMessage: err.message,
|
|
347
|
+
metadata: {
|
|
348
|
+
path: context.path,
|
|
349
|
+
rawChunk: sanitizeForLogging(rawChunk, redaction)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/models/openai.ts
|
|
12
356
|
var OpenAIAdapter = class extends BaseModelAdapter {
|
|
13
357
|
name;
|
|
14
358
|
apiKey;
|
|
@@ -25,11 +369,11 @@ var OpenAIAdapter = class extends BaseModelAdapter {
|
|
|
25
369
|
throw new Error("OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass apiKey in config.");
|
|
26
370
|
}
|
|
27
371
|
this.name = `openai/${this.model}`;
|
|
28
|
-
this.capabilities = config.capabilities ??
|
|
372
|
+
this.capabilities = config.capabilities ?? DEFAULT_ADAPTER_CAPABILITIES;
|
|
29
373
|
}
|
|
30
374
|
async *stream(params) {
|
|
31
375
|
const body = this.buildRequestBody(params, true);
|
|
32
|
-
const response = await this.fetch("/chat/completions", body, params
|
|
376
|
+
const response = await this.fetch("/chat/completions", body, "stream", params);
|
|
33
377
|
if (!response.ok) {
|
|
34
378
|
const error = await response.text();
|
|
35
379
|
throw new Error(`OpenAI API error: ${response.status} - ${error}`);
|
|
@@ -128,7 +472,18 @@ var OpenAIAdapter = class extends BaseModelAdapter {
|
|
|
128
472
|
...raw
|
|
129
473
|
};
|
|
130
474
|
}
|
|
131
|
-
} catch {
|
|
475
|
+
} catch (error) {
|
|
476
|
+
logModelStreamParseError(
|
|
477
|
+
{
|
|
478
|
+
provider: "openai",
|
|
479
|
+
model: this.model,
|
|
480
|
+
path: "/chat/completions",
|
|
481
|
+
operation: "stream",
|
|
482
|
+
params
|
|
483
|
+
},
|
|
484
|
+
trimmed,
|
|
485
|
+
error
|
|
486
|
+
);
|
|
132
487
|
}
|
|
133
488
|
}
|
|
134
489
|
}
|
|
@@ -150,7 +505,7 @@ var OpenAIAdapter = class extends BaseModelAdapter {
|
|
|
150
505
|
}
|
|
151
506
|
async complete(params) {
|
|
152
507
|
const body = this.buildRequestBody(params, false);
|
|
153
|
-
const response = await this.fetch("/chat/completions", body);
|
|
508
|
+
const response = await this.fetch("/chat/completions", body, "complete", params);
|
|
154
509
|
if (!response.ok) {
|
|
155
510
|
const error = await response.text();
|
|
156
511
|
throw new Error(`OpenAI API error: ${response.status} - ${error}`);
|
|
@@ -181,13 +536,14 @@ var OpenAIAdapter = class extends BaseModelAdapter {
|
|
|
181
536
|
}
|
|
182
537
|
buildRequestBody(params, stream) {
|
|
183
538
|
const messages = this.transformMessages(params.messages);
|
|
539
|
+
const defaultMaxTokens = this.capabilities?.maxOutputTokens ?? DEFAULT_ADAPTER_CAPABILITIES.maxOutputTokens;
|
|
184
540
|
const body = {
|
|
185
541
|
model: this.model,
|
|
186
542
|
messages,
|
|
187
543
|
stream,
|
|
188
544
|
...stream && { stream_options: { include_usage: true } },
|
|
189
545
|
...params.temperature !== void 0 && { temperature: params.temperature },
|
|
190
|
-
|
|
546
|
+
max_tokens: params.maxTokens ?? defaultMaxTokens,
|
|
191
547
|
...params.stopSequences && { stop: params.stopSequences }
|
|
192
548
|
};
|
|
193
549
|
if (params.tools && params.tools.length > 0) {
|
|
@@ -198,20 +554,55 @@ var OpenAIAdapter = class extends BaseModelAdapter {
|
|
|
198
554
|
}
|
|
199
555
|
return body;
|
|
200
556
|
}
|
|
201
|
-
async fetch(path, body,
|
|
557
|
+
async fetch(path, body, operation, params) {
|
|
558
|
+
const requestLog = logModelRequestStart({
|
|
559
|
+
provider: "openai",
|
|
560
|
+
model: this.model,
|
|
561
|
+
path,
|
|
562
|
+
operation,
|
|
563
|
+
params
|
|
564
|
+
}, body);
|
|
202
565
|
const headers = {
|
|
203
566
|
"Content-Type": "application/json",
|
|
204
|
-
"Authorization": `Bearer ${this.apiKey}
|
|
567
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
568
|
+
"X-Client-Request-Id": requestLog.clientRequestId
|
|
205
569
|
};
|
|
206
570
|
if (this.organization) {
|
|
207
571
|
headers["OpenAI-Organization"] = this.organization;
|
|
208
572
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
573
|
+
try {
|
|
574
|
+
const response = await globalThis.fetch(`${this.baseUrl}${path}`, {
|
|
575
|
+
method: "POST",
|
|
576
|
+
headers,
|
|
577
|
+
body: JSON.stringify(body),
|
|
578
|
+
signal: params.signal
|
|
579
|
+
});
|
|
580
|
+
logModelRequestEnd(
|
|
581
|
+
{
|
|
582
|
+
provider: "openai",
|
|
583
|
+
model: this.model,
|
|
584
|
+
path,
|
|
585
|
+
operation,
|
|
586
|
+
params
|
|
587
|
+
},
|
|
588
|
+
requestLog,
|
|
589
|
+
response
|
|
590
|
+
);
|
|
591
|
+
return response;
|
|
592
|
+
} catch (error) {
|
|
593
|
+
logModelRequestFailure(
|
|
594
|
+
{
|
|
595
|
+
provider: "openai",
|
|
596
|
+
model: this.model,
|
|
597
|
+
path,
|
|
598
|
+
operation,
|
|
599
|
+
params
|
|
600
|
+
},
|
|
601
|
+
requestLog,
|
|
602
|
+
error
|
|
603
|
+
);
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
215
606
|
}
|
|
216
607
|
safeParseJSON(str) {
|
|
217
608
|
try {
|
|
@@ -226,33 +617,114 @@ function createOpenAI(config) {
|
|
|
226
617
|
}
|
|
227
618
|
|
|
228
619
|
// src/models/anthropic.ts
|
|
229
|
-
var
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"claude-3-haiku-20240307": { contextLength: 2e5, maxOutputTokens: 4096 }
|
|
620
|
+
var DEFAULT_FETCH_RETRY = {
|
|
621
|
+
maxAttempts: 2,
|
|
622
|
+
baseDelayMs: 200,
|
|
623
|
+
maxDelayMs: 2e3
|
|
234
624
|
};
|
|
625
|
+
function normalizeFetchRetry(options) {
|
|
626
|
+
if (options == null) {
|
|
627
|
+
return { ...DEFAULT_FETCH_RETRY };
|
|
628
|
+
}
|
|
629
|
+
const maxAttempts = Math.max(1, Math.floor(options.maxAttempts ?? DEFAULT_FETCH_RETRY.maxAttempts));
|
|
630
|
+
const baseDelayMs = Math.max(0, options.baseDelayMs ?? DEFAULT_FETCH_RETRY.baseDelayMs);
|
|
631
|
+
const maxDelayMs = Math.max(baseDelayMs, options.maxDelayMs ?? DEFAULT_FETCH_RETRY.maxDelayMs);
|
|
632
|
+
return { maxAttempts, baseDelayMs, maxDelayMs };
|
|
633
|
+
}
|
|
634
|
+
function isAbortError(e) {
|
|
635
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
636
|
+
return true;
|
|
637
|
+
}
|
|
638
|
+
return typeof e === "object" && e !== null && e.name === "AbortError";
|
|
639
|
+
}
|
|
640
|
+
function isRetriableFetchError(e) {
|
|
641
|
+
if (isAbortError(e)) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
if (e instanceof TypeError) {
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
const cause = typeof e === "object" && e !== null && "cause" in e ? e.cause : void 0;
|
|
648
|
+
const code = cause?.code;
|
|
649
|
+
return code === "ECONNRESET" || code === "ETIMEDOUT" || code === "EPIPE" || code === "UND_ERR_SOCKET";
|
|
650
|
+
}
|
|
651
|
+
function isRetriableHttpStatus(status) {
|
|
652
|
+
return status === 429 || status === 502 || status === 503 || status === 504;
|
|
653
|
+
}
|
|
654
|
+
function parseRetryAfterMs(header) {
|
|
655
|
+
if (header == null || header === "") {
|
|
656
|
+
return void 0;
|
|
657
|
+
}
|
|
658
|
+
const trimmed = header.trim();
|
|
659
|
+
const asNum = Number(trimmed);
|
|
660
|
+
if (Number.isFinite(asNum) && asNum >= 0) {
|
|
661
|
+
return asNum * 1e3;
|
|
662
|
+
}
|
|
663
|
+
const parsed = Date.parse(trimmed);
|
|
664
|
+
if (!Number.isNaN(parsed)) {
|
|
665
|
+
const delta = parsed - Date.now();
|
|
666
|
+
return delta > 0 ? delta : 0;
|
|
667
|
+
}
|
|
668
|
+
return void 0;
|
|
669
|
+
}
|
|
670
|
+
function computeBackoffMs(attemptIndex, baseDelayMs, maxDelayMs) {
|
|
671
|
+
const exp = Math.min(maxDelayMs, baseDelayMs * 2 ** attemptIndex);
|
|
672
|
+
const jitter = 0.5 + Math.random() * 0.5;
|
|
673
|
+
return Math.min(maxDelayMs, Math.floor(exp * jitter));
|
|
674
|
+
}
|
|
675
|
+
async function delay(ms, signal) {
|
|
676
|
+
if (ms <= 0) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
await new Promise((resolve, reject) => {
|
|
680
|
+
if (signal?.aborted) {
|
|
681
|
+
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const id = setTimeout(() => {
|
|
685
|
+
if (signal) {
|
|
686
|
+
signal.removeEventListener("abort", onAbort);
|
|
687
|
+
}
|
|
688
|
+
resolve();
|
|
689
|
+
}, ms);
|
|
690
|
+
const onAbort = () => {
|
|
691
|
+
clearTimeout(id);
|
|
692
|
+
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
693
|
+
};
|
|
694
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
async function drainResponseBody(response) {
|
|
698
|
+
try {
|
|
699
|
+
await response.arrayBuffer();
|
|
700
|
+
} catch {
|
|
701
|
+
}
|
|
702
|
+
}
|
|
235
703
|
var AnthropicAdapter = class extends BaseModelAdapter {
|
|
236
704
|
name;
|
|
237
705
|
apiKey;
|
|
238
706
|
baseUrl;
|
|
239
707
|
model;
|
|
240
708
|
version;
|
|
709
|
+
requestMetadata;
|
|
710
|
+
fetchRetry;
|
|
241
711
|
constructor(config = {}) {
|
|
242
712
|
super();
|
|
243
713
|
this.apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY || "";
|
|
244
714
|
this.baseUrl = config.baseUrl || process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
245
715
|
this.model = config.model || "claude-sonnet-4-20250514";
|
|
246
716
|
this.version = config.version || "2023-06-01";
|
|
717
|
+
this.requestMetadata = config.metadata;
|
|
718
|
+
this.fetchRetry = normalizeFetchRetry(config.fetchRetry);
|
|
247
719
|
if (!this.apiKey) {
|
|
248
720
|
throw new Error("Anthropic API key is required. Set ANTHROPIC_API_KEY environment variable or pass apiKey in config.");
|
|
249
721
|
}
|
|
250
722
|
this.name = `anthropic/${this.model}`;
|
|
251
|
-
this.capabilities = config.capabilities ??
|
|
723
|
+
this.capabilities = config.capabilities ?? DEFAULT_ADAPTER_CAPABILITIES;
|
|
252
724
|
}
|
|
253
725
|
async *stream(params) {
|
|
254
726
|
const body = this.buildRequestBody(params, true);
|
|
255
|
-
const response = await this.fetch("/v1/messages", body, params
|
|
727
|
+
const response = await this.fetch("/v1/messages", body, "stream", params);
|
|
256
728
|
if (!response.ok) {
|
|
257
729
|
const error = await response.text();
|
|
258
730
|
throw new Error(`Anthropic API error: ${response.status} - ${error}`);
|
|
@@ -350,6 +822,7 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
350
822
|
currentToolCall = null;
|
|
351
823
|
}
|
|
352
824
|
if (currentThinkingBlock) {
|
|
825
|
+
yield { type: "thinking_block_end", ...raw };
|
|
353
826
|
currentThinkingBlock = null;
|
|
354
827
|
}
|
|
355
828
|
break;
|
|
@@ -391,7 +864,18 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
391
864
|
}
|
|
392
865
|
break;
|
|
393
866
|
}
|
|
394
|
-
} catch {
|
|
867
|
+
} catch (error) {
|
|
868
|
+
logModelStreamParseError(
|
|
869
|
+
{
|
|
870
|
+
provider: "anthropic",
|
|
871
|
+
model: this.model,
|
|
872
|
+
path: "/v1/messages",
|
|
873
|
+
operation: "stream",
|
|
874
|
+
params
|
|
875
|
+
},
|
|
876
|
+
jsonStr,
|
|
877
|
+
error
|
|
878
|
+
);
|
|
395
879
|
}
|
|
396
880
|
}
|
|
397
881
|
}
|
|
@@ -402,7 +886,7 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
402
886
|
}
|
|
403
887
|
async complete(params) {
|
|
404
888
|
const body = this.buildRequestBody(params, false);
|
|
405
|
-
const response = await this.fetch("/v1/messages", body);
|
|
889
|
+
const response = await this.fetch("/v1/messages", body, "complete", params);
|
|
406
890
|
if (!response.ok) {
|
|
407
891
|
const error = await response.text();
|
|
408
892
|
throw new Error(`Anthropic API error: ${response.status} - ${error}`);
|
|
@@ -440,9 +924,10 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
440
924
|
buildRequestBody(params, stream) {
|
|
441
925
|
const { system, messages } = this.extractSystemMessage(params.messages);
|
|
442
926
|
const transformedMessages = this.transformAnthropicMessages(messages);
|
|
927
|
+
const defaultMaxTokens = this.capabilities?.maxOutputTokens ?? DEFAULT_ADAPTER_CAPABILITIES.maxOutputTokens;
|
|
443
928
|
const body = {
|
|
444
929
|
model: this.model,
|
|
445
|
-
max_tokens: params.maxTokens
|
|
930
|
+
max_tokens: params.maxTokens ?? defaultMaxTokens,
|
|
446
931
|
messages: transformedMessages,
|
|
447
932
|
stream,
|
|
448
933
|
...system && { system },
|
|
@@ -455,8 +940,48 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
455
940
|
input_schema: tool.parameters
|
|
456
941
|
}));
|
|
457
942
|
}
|
|
943
|
+
const mergedMetadata = this.mergeAnthropicMetadata(params);
|
|
944
|
+
if (mergedMetadata && Object.keys(mergedMetadata).length > 0) {
|
|
945
|
+
body.metadata = mergedMetadata;
|
|
946
|
+
}
|
|
458
947
|
return body;
|
|
459
948
|
}
|
|
949
|
+
/**
|
|
950
|
+
* Build Messages API `metadata`: `sessionId` → `user_id`, merged with resolved adapter `metadata` (dict or fn).
|
|
951
|
+
* Config `metadata` keys override `user_id` when duplicated.
|
|
952
|
+
*/
|
|
953
|
+
mergeAnthropicMetadata(params) {
|
|
954
|
+
const extra = this.resolveMetadataExtra(params);
|
|
955
|
+
const hasSession = params.sessionId !== void 0 && params.sessionId !== "";
|
|
956
|
+
if (!hasSession && extra === void 0) {
|
|
957
|
+
return void 0;
|
|
958
|
+
}
|
|
959
|
+
const merged = {};
|
|
960
|
+
if (hasSession) {
|
|
961
|
+
merged.user_id = params.sessionId;
|
|
962
|
+
}
|
|
963
|
+
if (extra !== void 0) {
|
|
964
|
+
Object.assign(merged, extra);
|
|
965
|
+
}
|
|
966
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
967
|
+
}
|
|
968
|
+
resolveMetadataExtra(params) {
|
|
969
|
+
const raw = this.requestMetadata;
|
|
970
|
+
if (raw == null) {
|
|
971
|
+
return void 0;
|
|
972
|
+
}
|
|
973
|
+
if (typeof raw === "function") {
|
|
974
|
+
const v = raw(params);
|
|
975
|
+
if (typeof v !== "object" || v === null || Array.isArray(v) || Object.keys(v).length === 0) {
|
|
976
|
+
return void 0;
|
|
977
|
+
}
|
|
978
|
+
return { ...v };
|
|
979
|
+
}
|
|
980
|
+
if (typeof raw === "object" && !Array.isArray(raw) && Object.keys(raw).length > 0) {
|
|
981
|
+
return { ...raw };
|
|
982
|
+
}
|
|
983
|
+
return void 0;
|
|
984
|
+
}
|
|
460
985
|
extractSystemMessage(messages) {
|
|
461
986
|
const systemMessages = messages.filter((m) => m.role === "system");
|
|
462
987
|
const otherMessages = messages.filter((m) => m.role !== "system");
|
|
@@ -511,8 +1036,23 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
511
1036
|
return transformed;
|
|
512
1037
|
});
|
|
513
1038
|
}
|
|
514
|
-
|
|
515
|
-
|
|
1039
|
+
/**
|
|
1040
|
+
* 发起 POST;按 `fetchRetry` 对网络错误与 429/502/503/504 重试(不含响应体已开始消费后的 SSE 读失败)。
|
|
1041
|
+
*/
|
|
1042
|
+
async fetch(path, body, operation, params) {
|
|
1043
|
+
const requestLog = logModelRequestStart(
|
|
1044
|
+
{
|
|
1045
|
+
provider: "anthropic",
|
|
1046
|
+
model: this.model,
|
|
1047
|
+
path,
|
|
1048
|
+
operation,
|
|
1049
|
+
params
|
|
1050
|
+
},
|
|
1051
|
+
body,
|
|
1052
|
+
{ httpMaxAttempts: this.fetchRetry.maxAttempts }
|
|
1053
|
+
);
|
|
1054
|
+
const url = `${this.baseUrl}${path}`;
|
|
1055
|
+
const init = {
|
|
516
1056
|
method: "POST",
|
|
517
1057
|
headers: {
|
|
518
1058
|
"Content-Type": "application/json",
|
|
@@ -520,8 +1060,104 @@ var AnthropicAdapter = class extends BaseModelAdapter {
|
|
|
520
1060
|
"anthropic-version": this.version
|
|
521
1061
|
},
|
|
522
1062
|
body: JSON.stringify(body),
|
|
523
|
-
signal
|
|
524
|
-
}
|
|
1063
|
+
signal: params.signal
|
|
1064
|
+
};
|
|
1065
|
+
for (let attempt = 0; attempt < this.fetchRetry.maxAttempts; attempt++) {
|
|
1066
|
+
const httpAttemptMeta = {
|
|
1067
|
+
httpAttempt: attempt + 1,
|
|
1068
|
+
httpMaxAttempts: this.fetchRetry.maxAttempts
|
|
1069
|
+
};
|
|
1070
|
+
if (params.signal?.aborted) {
|
|
1071
|
+
logModelRequestFailure(
|
|
1072
|
+
{
|
|
1073
|
+
provider: "anthropic",
|
|
1074
|
+
model: this.model,
|
|
1075
|
+
path,
|
|
1076
|
+
operation,
|
|
1077
|
+
params
|
|
1078
|
+
},
|
|
1079
|
+
requestLog,
|
|
1080
|
+
new DOMException("The operation was aborted.", "AbortError"),
|
|
1081
|
+
{ httpMaxAttempts: this.fetchRetry.maxAttempts }
|
|
1082
|
+
);
|
|
1083
|
+
throw new DOMException("The operation was aborted.", "AbortError");
|
|
1084
|
+
}
|
|
1085
|
+
try {
|
|
1086
|
+
const response = await globalThis.fetch(url, init);
|
|
1087
|
+
if (response.ok) {
|
|
1088
|
+
logModelRequestEnd(
|
|
1089
|
+
{
|
|
1090
|
+
provider: "anthropic",
|
|
1091
|
+
model: this.model,
|
|
1092
|
+
path,
|
|
1093
|
+
operation,
|
|
1094
|
+
params
|
|
1095
|
+
},
|
|
1096
|
+
requestLog,
|
|
1097
|
+
response,
|
|
1098
|
+
httpAttemptMeta
|
|
1099
|
+
);
|
|
1100
|
+
return response;
|
|
1101
|
+
}
|
|
1102
|
+
const canRetryHttp = attempt < this.fetchRetry.maxAttempts - 1 && isRetriableHttpStatus(response.status);
|
|
1103
|
+
if (canRetryHttp) {
|
|
1104
|
+
await drainResponseBody(response);
|
|
1105
|
+
const fromHeader = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
1106
|
+
const backoff = computeBackoffMs(attempt, this.fetchRetry.baseDelayMs, this.fetchRetry.maxDelayMs);
|
|
1107
|
+
const waitMs = fromHeader != null ? Math.min(fromHeader, this.fetchRetry.maxDelayMs) : backoff;
|
|
1108
|
+
await delay(waitMs, params.signal);
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
logModelRequestEnd(
|
|
1112
|
+
{
|
|
1113
|
+
provider: "anthropic",
|
|
1114
|
+
model: this.model,
|
|
1115
|
+
path,
|
|
1116
|
+
operation,
|
|
1117
|
+
params
|
|
1118
|
+
},
|
|
1119
|
+
requestLog,
|
|
1120
|
+
response,
|
|
1121
|
+
httpAttemptMeta
|
|
1122
|
+
);
|
|
1123
|
+
return response;
|
|
1124
|
+
} catch (e) {
|
|
1125
|
+
if (isAbortError(e) || params.signal?.aborted) {
|
|
1126
|
+
logModelRequestFailure(
|
|
1127
|
+
{
|
|
1128
|
+
provider: "anthropic",
|
|
1129
|
+
model: this.model,
|
|
1130
|
+
path,
|
|
1131
|
+
operation,
|
|
1132
|
+
params
|
|
1133
|
+
},
|
|
1134
|
+
requestLog,
|
|
1135
|
+
e,
|
|
1136
|
+
httpAttemptMeta
|
|
1137
|
+
);
|
|
1138
|
+
throw e;
|
|
1139
|
+
}
|
|
1140
|
+
if (attempt < this.fetchRetry.maxAttempts - 1 && isRetriableFetchError(e)) {
|
|
1141
|
+
const backoff = computeBackoffMs(attempt, this.fetchRetry.baseDelayMs, this.fetchRetry.maxDelayMs);
|
|
1142
|
+
await delay(backoff, params.signal);
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
logModelRequestFailure(
|
|
1146
|
+
{
|
|
1147
|
+
provider: "anthropic",
|
|
1148
|
+
model: this.model,
|
|
1149
|
+
path,
|
|
1150
|
+
operation,
|
|
1151
|
+
params
|
|
1152
|
+
},
|
|
1153
|
+
requestLog,
|
|
1154
|
+
e,
|
|
1155
|
+
httpAttemptMeta
|
|
1156
|
+
);
|
|
1157
|
+
throw e;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
throw new Error("Anthropic fetch: unexpected retry loop exit");
|
|
525
1161
|
}
|
|
526
1162
|
safeParseJSON(str) {
|
|
527
1163
|
try {
|
|
@@ -536,12 +1172,6 @@ function createAnthropic(config) {
|
|
|
536
1172
|
}
|
|
537
1173
|
|
|
538
1174
|
// src/models/ollama.ts
|
|
539
|
-
var OLLAMA_CAPABILITIES = {
|
|
540
|
-
"qwen3.5:0.8b": { contextLength: 32768, maxOutputTokens: 4096 },
|
|
541
|
-
"minimax-m2.7:cloud": { contextLength: 128e3, maxOutputTokens: 16384 },
|
|
542
|
-
"nemotron-3-super:cloud": { contextLength: 128e3, maxOutputTokens: 16384 },
|
|
543
|
-
"glm-5:cloud": { contextLength: 128e3, maxOutputTokens: 16384 }
|
|
544
|
-
};
|
|
545
1175
|
function ollamaStreamChunksFromChatData(data, parseToolArguments, nextToolCallId) {
|
|
546
1176
|
const chunks = [];
|
|
547
1177
|
const msg = data.message;
|
|
@@ -596,11 +1226,11 @@ var OllamaAdapter = class extends BaseModelAdapter {
|
|
|
596
1226
|
this.model = config.model || "qwen3.5:0.8b";
|
|
597
1227
|
this.think = config.think;
|
|
598
1228
|
this.name = `ollama/${this.model}`;
|
|
599
|
-
this.capabilities = config.capabilities ??
|
|
1229
|
+
this.capabilities = config.capabilities ?? DEFAULT_ADAPTER_CAPABILITIES;
|
|
600
1230
|
}
|
|
601
1231
|
async *stream(params) {
|
|
602
1232
|
const body = this.buildRequestBody(params, true);
|
|
603
|
-
const response = await this.fetch("/api/chat", body, params
|
|
1233
|
+
const response = await this.fetch("/api/chat", body, "stream", params);
|
|
604
1234
|
if (!response.ok) {
|
|
605
1235
|
const error = await response.text();
|
|
606
1236
|
throw new Error(`Ollama API error: ${response.status} - ${error}`);
|
|
@@ -654,7 +1284,18 @@ var OllamaAdapter = class extends BaseModelAdapter {
|
|
|
654
1284
|
}
|
|
655
1285
|
yield { type: "done", ...raw };
|
|
656
1286
|
}
|
|
657
|
-
} catch {
|
|
1287
|
+
} catch (error) {
|
|
1288
|
+
logModelStreamParseError(
|
|
1289
|
+
{
|
|
1290
|
+
provider: "ollama",
|
|
1291
|
+
model: this.model,
|
|
1292
|
+
path: "/api/chat",
|
|
1293
|
+
operation: "stream",
|
|
1294
|
+
params
|
|
1295
|
+
},
|
|
1296
|
+
trimmed,
|
|
1297
|
+
error
|
|
1298
|
+
);
|
|
658
1299
|
}
|
|
659
1300
|
}
|
|
660
1301
|
}
|
|
@@ -664,7 +1305,7 @@ var OllamaAdapter = class extends BaseModelAdapter {
|
|
|
664
1305
|
}
|
|
665
1306
|
async complete(params) {
|
|
666
1307
|
const body = this.buildRequestBody(params, false);
|
|
667
|
-
const response = await this.fetch("/api/chat", body);
|
|
1308
|
+
const response = await this.fetch("/api/chat", body, "complete", params);
|
|
668
1309
|
if (!response.ok) {
|
|
669
1310
|
const error = await response.text();
|
|
670
1311
|
throw new Error(`Ollama API error: ${response.status} - ${error}`);
|
|
@@ -744,11 +1385,18 @@ var OllamaAdapter = class extends BaseModelAdapter {
|
|
|
744
1385
|
});
|
|
745
1386
|
}
|
|
746
1387
|
buildRequestBody(params, stream) {
|
|
1388
|
+
const defaultMaxTokens = this.capabilities?.maxOutputTokens ?? DEFAULT_ADAPTER_CAPABILITIES.maxOutputTokens;
|
|
1389
|
+
const options = {
|
|
1390
|
+
num_predict: params.maxTokens ?? defaultMaxTokens
|
|
1391
|
+
};
|
|
1392
|
+
if (params.temperature !== void 0) {
|
|
1393
|
+
options.temperature = params.temperature;
|
|
1394
|
+
}
|
|
747
1395
|
const body = {
|
|
748
1396
|
model: this.model,
|
|
749
1397
|
messages: this.transformMessages(params.messages),
|
|
750
1398
|
stream,
|
|
751
|
-
|
|
1399
|
+
options
|
|
752
1400
|
};
|
|
753
1401
|
if (this.think !== void 0) {
|
|
754
1402
|
body.think = this.think;
|
|
@@ -761,47 +1409,97 @@ var OllamaAdapter = class extends BaseModelAdapter {
|
|
|
761
1409
|
}
|
|
762
1410
|
return body;
|
|
763
1411
|
}
|
|
764
|
-
async fetch(path, body,
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
1412
|
+
async fetch(path, body, operation, params) {
|
|
1413
|
+
const requestLog = logModelRequestStart({
|
|
1414
|
+
provider: "ollama",
|
|
1415
|
+
model: this.model,
|
|
1416
|
+
path,
|
|
1417
|
+
operation,
|
|
1418
|
+
params
|
|
1419
|
+
}, body);
|
|
1420
|
+
try {
|
|
1421
|
+
const response = await globalThis.fetch(`${this.baseUrl}${path}`, {
|
|
1422
|
+
method: "POST",
|
|
1423
|
+
headers: {
|
|
1424
|
+
"Content-Type": "application/json"
|
|
1425
|
+
},
|
|
1426
|
+
body: JSON.stringify(body),
|
|
1427
|
+
signal: params.signal
|
|
1428
|
+
});
|
|
1429
|
+
logModelRequestEnd(
|
|
1430
|
+
{
|
|
1431
|
+
provider: "ollama",
|
|
1432
|
+
model: this.model,
|
|
1433
|
+
path,
|
|
1434
|
+
operation,
|
|
1435
|
+
params
|
|
1436
|
+
},
|
|
1437
|
+
requestLog,
|
|
1438
|
+
response
|
|
1439
|
+
);
|
|
1440
|
+
return response;
|
|
1441
|
+
} catch (error) {
|
|
1442
|
+
logModelRequestFailure(
|
|
1443
|
+
{
|
|
1444
|
+
provider: "ollama",
|
|
1445
|
+
model: this.model,
|
|
1446
|
+
path,
|
|
1447
|
+
operation,
|
|
1448
|
+
params
|
|
1449
|
+
},
|
|
1450
|
+
requestLog,
|
|
1451
|
+
error
|
|
1452
|
+
);
|
|
1453
|
+
throw error;
|
|
1454
|
+
}
|
|
773
1455
|
}
|
|
774
1456
|
};
|
|
775
1457
|
function createOllama(config) {
|
|
776
1458
|
return new OllamaAdapter(config);
|
|
777
1459
|
}
|
|
778
1460
|
|
|
1461
|
+
// src/core/process-env-merge.ts
|
|
1462
|
+
function mergeProcessEnv(overrides) {
|
|
1463
|
+
const base = {};
|
|
1464
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
1465
|
+
if (typeof value === "string") {
|
|
1466
|
+
base[key] = value;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
1470
|
+
}
|
|
1471
|
+
function mergeMcpStdioEnv(agentEnv, serverEnv) {
|
|
1472
|
+
const merged = mergeProcessEnv(agentEnv);
|
|
1473
|
+
return serverEnv ? { ...merged, ...serverEnv } : merged;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
779
1476
|
// src/models/index.ts
|
|
780
|
-
function createModel(
|
|
781
|
-
|
|
1477
|
+
function createModel(modelConfig, agentEnv) {
|
|
1478
|
+
const merged = mergeProcessEnv(agentEnv);
|
|
1479
|
+
switch (modelConfig.provider) {
|
|
782
1480
|
case "openai":
|
|
783
1481
|
return new OpenAIAdapter({
|
|
784
|
-
apiKey:
|
|
785
|
-
baseUrl:
|
|
786
|
-
model:
|
|
1482
|
+
apiKey: modelConfig.apiKey || merged.OPENAI_API_KEY || "",
|
|
1483
|
+
baseUrl: modelConfig.baseUrl || merged.OPENAI_BASE_URL,
|
|
1484
|
+
model: modelConfig.model,
|
|
1485
|
+
organization: merged.OPENAI_ORG_ID
|
|
787
1486
|
});
|
|
788
1487
|
case "anthropic":
|
|
789
1488
|
return new AnthropicAdapter({
|
|
790
|
-
apiKey:
|
|
791
|
-
baseUrl:
|
|
792
|
-
model:
|
|
1489
|
+
apiKey: modelConfig.apiKey || merged.ANTHROPIC_API_KEY || "",
|
|
1490
|
+
baseUrl: modelConfig.baseUrl || merged.ANTHROPIC_BASE_URL,
|
|
1491
|
+
model: modelConfig.model
|
|
793
1492
|
});
|
|
794
1493
|
case "ollama":
|
|
795
1494
|
return new OllamaAdapter({
|
|
796
|
-
baseUrl:
|
|
797
|
-
model:
|
|
798
|
-
think:
|
|
1495
|
+
baseUrl: modelConfig.baseUrl || merged.OLLAMA_BASE_URL,
|
|
1496
|
+
model: modelConfig.model,
|
|
1497
|
+
think: modelConfig.think
|
|
799
1498
|
});
|
|
800
|
-
default:
|
|
801
|
-
throw new Error(`Unknown model provider: ${config.provider}`);
|
|
802
1499
|
}
|
|
1500
|
+
throw new Error(`Unknown model provider: ${modelConfig.provider}`);
|
|
803
1501
|
}
|
|
804
1502
|
|
|
805
|
-
export { AnthropicAdapter, OllamaAdapter, OpenAIAdapter, createAnthropic, createModel, createOllama, createOpenAI, ollamaMessageContentToApiString, ollamaStreamChunksFromChatData };
|
|
806
|
-
//# sourceMappingURL=chunk-
|
|
807
|
-
//# sourceMappingURL=chunk-
|
|
1503
|
+
export { AnthropicAdapter, DEFAULT_ADAPTER_CAPABILITIES, OllamaAdapter, OpenAIAdapter, createAnthropic, createConsoleSDKLogger, createModel, createOllama, createOpenAI, emitSDKLog, formatSDKLog, mergeMcpStdioEnv, mergeProcessEnv, ollamaMessageContentToApiString, ollamaStreamChunksFromChatData };
|
|
1504
|
+
//# sourceMappingURL=chunk-D3UZNLZO.js.map
|
|
1505
|
+
//# sourceMappingURL=chunk-D3UZNLZO.js.map
|