@zhongqian97-code/ecode 0.5.36 → 0.5.37
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.
|
@@ -202,9 +202,229 @@ function createOpenAIProvider(profile) {
|
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
// src/providers/anthropic.ts
|
|
206
|
+
import https from "https";
|
|
207
|
+
import { URL as URL2 } from "url";
|
|
208
|
+
function convertMessagesToAnthropic(messages) {
|
|
209
|
+
let system = "";
|
|
210
|
+
const anthropicMessages = [];
|
|
211
|
+
for (let i = 0; i < messages.length; i++) {
|
|
212
|
+
const msg = messages[i];
|
|
213
|
+
if (msg.role === "system") {
|
|
214
|
+
system = msg.content;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (msg.role === "user") {
|
|
218
|
+
anthropicMessages.push({ role: "user", content: msg.content });
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (msg.role === "tool") {
|
|
222
|
+
const toolResults = [];
|
|
223
|
+
while (i < messages.length && messages[i].role === "tool") {
|
|
224
|
+
const toolMsg = messages[i];
|
|
225
|
+
toolResults.push({
|
|
226
|
+
type: "tool_result",
|
|
227
|
+
tool_use_id: toolMsg.tool_call_id,
|
|
228
|
+
content: toolMsg.content
|
|
229
|
+
});
|
|
230
|
+
i++;
|
|
231
|
+
}
|
|
232
|
+
i--;
|
|
233
|
+
anthropicMessages.push({ role: "user", content: toolResults });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (msg.role === "assistant") {
|
|
237
|
+
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
|
238
|
+
const content = [];
|
|
239
|
+
if (msg.content) content.push({ type: "text", text: msg.content });
|
|
240
|
+
for (const tc of msg.tool_calls) {
|
|
241
|
+
let input = {};
|
|
242
|
+
try {
|
|
243
|
+
input = JSON.parse(tc.function.arguments);
|
|
244
|
+
} catch {
|
|
245
|
+
input = {};
|
|
246
|
+
}
|
|
247
|
+
content.push({ type: "tool_use", id: tc.id, name: tc.function.name, input });
|
|
248
|
+
}
|
|
249
|
+
anthropicMessages.push({ role: "assistant", content });
|
|
250
|
+
} else {
|
|
251
|
+
anthropicMessages.push({ role: "assistant", content: msg.content ?? "" });
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return { system, anthropicMessages };
|
|
256
|
+
}
|
|
257
|
+
function convertToolsToAnthropic(tools) {
|
|
258
|
+
return tools.map((tool) => ({
|
|
259
|
+
name: tool.function.name,
|
|
260
|
+
description: tool.function.description,
|
|
261
|
+
input_schema: tool.function.parameters
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
264
|
+
function createAnthropicProvider(profile) {
|
|
265
|
+
const capabilities = Object.freeze(
|
|
266
|
+
Object.defineProperties({}, {
|
|
267
|
+
supportsTools: { value: true, writable: false, enumerable: true },
|
|
268
|
+
supportsReasoningStream: { value: false, writable: false, enumerable: true },
|
|
269
|
+
supportsImages: { value: true, writable: false, enumerable: true },
|
|
270
|
+
supportsJsonSchema: { value: true, writable: false, enumerable: true }
|
|
271
|
+
})
|
|
272
|
+
);
|
|
273
|
+
return {
|
|
274
|
+
capabilities,
|
|
275
|
+
stream(messages, tools, signal) {
|
|
276
|
+
return streamAnthropicResponse(profile, messages, tools, signal);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
async function* streamAnthropicResponse(profile, messages, tools, signal) {
|
|
281
|
+
const { system, anthropicMessages } = convertMessagesToAnthropic(messages);
|
|
282
|
+
const endpointUrl = new URL2(`${profile.baseUrl.replace(/\/$/, "")}/v1/messages`);
|
|
283
|
+
const requestBody = {
|
|
284
|
+
model: profile.model,
|
|
285
|
+
max_tokens: 8192,
|
|
286
|
+
messages: anthropicMessages,
|
|
287
|
+
stream: true
|
|
288
|
+
};
|
|
289
|
+
if (system) requestBody.system = system;
|
|
290
|
+
if (tools && tools.length > 0) requestBody.tools = convertToolsToAnthropic(tools);
|
|
291
|
+
const bodyStr = JSON.stringify(requestBody);
|
|
292
|
+
yield* makeHttpsStream(endpointUrl, profile.apiKey, bodyStr, signal);
|
|
293
|
+
}
|
|
294
|
+
async function* makeHttpsStream(url, apiKey, body, signal) {
|
|
295
|
+
var _a;
|
|
296
|
+
const queue = [];
|
|
297
|
+
let notify = null;
|
|
298
|
+
function push(item) {
|
|
299
|
+
queue.push(item);
|
|
300
|
+
if (notify) {
|
|
301
|
+
const fn = notify;
|
|
302
|
+
notify = null;
|
|
303
|
+
fn();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const port = url.port ? parseInt(url.port, 10) : 443;
|
|
307
|
+
const req = https.request(
|
|
308
|
+
{
|
|
309
|
+
hostname: url.hostname,
|
|
310
|
+
port,
|
|
311
|
+
path: url.pathname + url.search,
|
|
312
|
+
method: "POST",
|
|
313
|
+
headers: {
|
|
314
|
+
"x-api-key": apiKey,
|
|
315
|
+
"anthropic-version": "2023-06-01",
|
|
316
|
+
"content-type": "application/json",
|
|
317
|
+
accept: "text/event-stream",
|
|
318
|
+
"content-length": String(Buffer.byteLength(body, "utf8"))
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
(res) => {
|
|
322
|
+
const statusCode = res.statusCode;
|
|
323
|
+
if (statusCode !== 200) {
|
|
324
|
+
push(new Error(`Anthropic API error: HTTP ${statusCode}`));
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const r = res;
|
|
328
|
+
r.on("data", (chunk) => push(chunk));
|
|
329
|
+
r.on("end", () => push(null));
|
|
330
|
+
r.on("error", (err) => push(err));
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
req.on("error", (err) => push(err));
|
|
334
|
+
if (signal) {
|
|
335
|
+
signal.addEventListener(
|
|
336
|
+
"abort",
|
|
337
|
+
() => {
|
|
338
|
+
req.destroy();
|
|
339
|
+
push(null);
|
|
340
|
+
},
|
|
341
|
+
{ once: true }
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
req.write(body);
|
|
345
|
+
req.end();
|
|
346
|
+
let buffer = "";
|
|
347
|
+
const toolBlocks = /* @__PURE__ */ new Map();
|
|
348
|
+
let stopReason = null;
|
|
349
|
+
let inputTokens = 0;
|
|
350
|
+
let outputTokens = 0;
|
|
351
|
+
while (true) {
|
|
352
|
+
let item;
|
|
353
|
+
if (queue.length > 0) {
|
|
354
|
+
item = queue.shift();
|
|
355
|
+
} else {
|
|
356
|
+
await new Promise((resolve4) => {
|
|
357
|
+
notify = resolve4;
|
|
358
|
+
});
|
|
359
|
+
item = queue.shift();
|
|
360
|
+
}
|
|
361
|
+
if (item === null) break;
|
|
362
|
+
if (item instanceof Error) throw item;
|
|
363
|
+
buffer += item.toString("utf8");
|
|
364
|
+
const lines = buffer.split("\n");
|
|
365
|
+
buffer = lines.pop() ?? "";
|
|
366
|
+
for (const line of lines) {
|
|
367
|
+
if (!line.startsWith("data: ")) continue;
|
|
368
|
+
const data = line.slice(6).trim();
|
|
369
|
+
if (data === "[DONE]") break;
|
|
370
|
+
let event;
|
|
371
|
+
try {
|
|
372
|
+
event = JSON.parse(data);
|
|
373
|
+
} catch {
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
const eventType = event.type;
|
|
377
|
+
if (eventType === "message_start") {
|
|
378
|
+
const msg = event.message;
|
|
379
|
+
if ((_a = msg == null ? void 0 : msg.usage) == null ? void 0 : _a.input_tokens) inputTokens = msg.usage.input_tokens;
|
|
380
|
+
} else if (eventType === "content_block_start") {
|
|
381
|
+
const block = event.content_block;
|
|
382
|
+
const index = event.index;
|
|
383
|
+
if ((block == null ? void 0 : block.type) === "tool_use" && block.id && block.name) {
|
|
384
|
+
toolBlocks.set(index, { id: block.id, name: block.name, jsonAccum: "" });
|
|
385
|
+
}
|
|
386
|
+
} else if (eventType === "content_block_delta") {
|
|
387
|
+
const delta = event.delta;
|
|
388
|
+
const index = event.index;
|
|
389
|
+
if ((delta == null ? void 0 : delta.type) === "text_delta" && delta.text) {
|
|
390
|
+
yield { text: delta.text, done: false };
|
|
391
|
+
} else if ((delta == null ? void 0 : delta.type) === "input_json_delta" && delta.partial_json) {
|
|
392
|
+
const tool = toolBlocks.get(index);
|
|
393
|
+
if (tool) tool.jsonAccum += delta.partial_json;
|
|
394
|
+
}
|
|
395
|
+
} else if (eventType === "message_delta") {
|
|
396
|
+
const delta = event.delta;
|
|
397
|
+
stopReason = (delta == null ? void 0 : delta.stop_reason) ?? null;
|
|
398
|
+
const usage = event.usage;
|
|
399
|
+
if (usage == null ? void 0 : usage.output_tokens) outputTokens = usage.output_tokens;
|
|
400
|
+
} else if (eventType === "message_stop") {
|
|
401
|
+
const toolCalls = [...toolBlocks.values()].map((t) => ({
|
|
402
|
+
id: t.id,
|
|
403
|
+
name: t.name,
|
|
404
|
+
arguments: t.jsonAccum
|
|
405
|
+
}));
|
|
406
|
+
yield {
|
|
407
|
+
done: true,
|
|
408
|
+
text: "",
|
|
409
|
+
finishReason: stopReason,
|
|
410
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
411
|
+
usage: {
|
|
412
|
+
promptTokens: inputTokens,
|
|
413
|
+
completionTokens: outputTokens,
|
|
414
|
+
totalTokens: inputTokens + outputTokens
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
yield { done: true, text: "", finishReason: stopReason };
|
|
422
|
+
}
|
|
423
|
+
|
|
205
424
|
// src/providers/index.ts
|
|
206
425
|
function createProvider(profile) {
|
|
207
|
-
|
|
426
|
+
const useAnthropic = profile.apiFormat === "anthropic" || profile.baseUrl.includes("anthropic");
|
|
427
|
+
return useAnthropic ? createAnthropicProvider(profile) : createOpenAIProvider(profile);
|
|
208
428
|
}
|
|
209
429
|
function resolveActiveProfile(config, providerName) {
|
|
210
430
|
var _a, _b;
|
|
@@ -646,7 +866,7 @@ async function grepFiles(params) {
|
|
|
646
866
|
|
|
647
867
|
// src/tools/web_fetch.ts
|
|
648
868
|
import * as http from "http";
|
|
649
|
-
import * as
|
|
869
|
+
import * as https2 from "https";
|
|
650
870
|
var WEB_FETCH_TOOL = {
|
|
651
871
|
type: "function",
|
|
652
872
|
function: {
|
|
@@ -807,7 +1027,7 @@ async function nodeHttpFetch(url, signal) {
|
|
|
807
1027
|
return new Promise((resolve4, reject) => {
|
|
808
1028
|
const parsed = new URL(url);
|
|
809
1029
|
const isHttps = parsed.protocol === "https:";
|
|
810
|
-
const lib = isHttps ?
|
|
1030
|
+
const lib = isHttps ? https2 : http;
|
|
811
1031
|
const onAbort = () => {
|
|
812
1032
|
req.destroy();
|
|
813
1033
|
const err = new Error("The user aborted a request.");
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
todo,
|
|
35
35
|
webFetch,
|
|
36
36
|
writeFile
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-7DHMJ6NS.js";
|
|
38
38
|
import {
|
|
39
39
|
createSessionMetadata,
|
|
40
40
|
generateTitle,
|
|
@@ -231,7 +231,10 @@ var EventBus = class {
|
|
|
231
231
|
/** 发布事件,同步调用所有当前订阅者 */
|
|
232
232
|
emit(event) {
|
|
233
233
|
for (const listener of this.listeners) {
|
|
234
|
-
|
|
234
|
+
try {
|
|
235
|
+
listener(event);
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
235
238
|
}
|
|
236
239
|
}
|
|
237
240
|
/** 添加事件监听器,返回取消订阅函数 */
|
|
@@ -902,6 +905,6 @@ Node.js 16/18 \u8BF7\u4F7F\u7528 --web \u6216 --pipe \u6A21\u5F0F\u3002
|
|
|
902
905
|
);
|
|
903
906
|
process.exit(1);
|
|
904
907
|
}
|
|
905
|
-
const { App, React, render } = await import("./ui-
|
|
908
|
+
const { App, React, render } = await import("./ui-XL5IDLH5.js");
|
|
906
909
|
render(React.createElement(App, { config: finalConfig, version: VERSION, autoMode, registry, trustedSkillDirs, initialMessages }));
|
|
907
910
|
}
|