@migor/agentia 0.5.0 → 0.6.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/CHANGELOG.md +248 -0
- package/README.md +1 -2
- package/dist/AGENTS.md +253 -160
- package/dist/core/abort.js +4 -1
- package/dist/core/abort.js.map +1 -1
- package/dist/core/message.d.ts +148 -0
- package/dist/core/message.js +25 -0
- package/dist/core/message.js.map +1 -0
- package/dist/core/timeout.d.ts +72 -0
- package/dist/core/timeout.js +117 -0
- package/dist/core/timeout.js.map +1 -0
- package/dist/core/tool.d.ts +21 -9
- package/dist/engine/concurrency.d.ts +6 -30
- package/dist/engine/concurrency.js +6 -64
- package/dist/engine/concurrency.js.map +1 -1
- package/dist/engine/errors.d.ts +12 -0
- package/dist/engine/errors.js +56 -13
- package/dist/engine/errors.js.map +1 -1
- package/dist/engine/loop.d.ts +17 -11
- package/dist/engine/loop.js +34 -433
- package/dist/engine/loop.js.map +1 -1
- package/dist/engine/replay.d.ts +18 -3
- package/dist/engine/replay.js +53 -9
- package/dist/engine/replay.js.map +1 -1
- package/dist/engine/retry.d.ts +5 -4
- package/dist/engine/retry.js.map +1 -1
- package/dist/engine/spec.d.ts +5 -5
- package/dist/engine/spec.js.map +1 -1
- package/dist/engine/trace-diff.d.ts +57 -0
- package/dist/engine/trace-diff.js +188 -0
- package/dist/engine/trace-diff.js.map +1 -0
- package/dist/engine/trimming.d.ts +7 -7
- package/dist/engine/trimming.js +12 -5
- package/dist/engine/trimming.js.map +1 -1
- package/dist/engine/turn.d.ts +157 -0
- package/dist/engine/turn.js +512 -0
- package/dist/engine/turn.js.map +1 -0
- package/dist/engine/types.d.ts +6 -8
- package/dist/engine/usage.d.ts +2 -2
- package/dist/engine/usage.js +4 -1
- package/dist/engine/usage.js.map +1 -1
- package/dist/eval/defineEval.js.map +1 -1
- package/dist/eval/harvest.d.ts +2 -9
- package/dist/eval/harvest.js +20 -9
- package/dist/eval/harvest.js.map +1 -1
- package/dist/eval/scripted.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/anthropic.d.ts +41 -37
- package/dist/integrations/anthropic.js +408 -17
- package/dist/integrations/anthropic.js.map +1 -1
- package/dist/integrations/mcp.d.ts +13 -4
- package/dist/integrations/mcp.js +27 -24
- package/dist/integrations/mcp.js.map +1 -1
- package/dist/integrations/openai.d.ts +1 -1
- package/dist/integrations/openai.js +3 -3
- package/dist/integrations/openai.js.map +1 -1
- package/dist/integrations/otlp.js +29 -11
- package/dist/integrations/otlp.js.map +1 -1
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/session.d.ts +5 -5
- package/dist/runtime/session.js +5 -1
- package/dist/runtime/session.js.map +1 -1
- package/dist/toolkit/module.d.ts +16 -2
- package/dist/toolkit/module.js +42 -4
- package/dist/toolkit/module.js.map +1 -1
- package/dist/toolkit/skill.d.ts +3 -3
- package/dist/toolkit/subagent.d.ts +2 -2
- package/dist/toolkit/subagent.js +1 -1
- package/dist/transport/async.d.ts +2 -2
- package/package.json +4 -5
|
@@ -1,24 +1,415 @@
|
|
|
1
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* 白盒探查 SDK 内部不现实,但这一步的输入/输出可以钉死(见 `tests/integrations/anthropic.test.ts`)。
|
|
2
|
+
* Anthropic API 错误:非 2xx 响应(读响应体截断进 message)或 200 流内嵌 error 事件。
|
|
3
|
+
* 带数值 `status` —— `engine/errors.ts` 的鸭子类型分类靠它(429 → rate_limit、
|
|
4
|
+
* 5xx → server、其余 4xx → api)。
|
|
7
5
|
*/
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
export class AnthropicApiError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
constructor(status, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'AnthropicApiError';
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
11
13
|
}
|
|
12
|
-
/** 创建默认 ModelClient(Anthropic
|
|
14
|
+
/** 创建默认 ModelClient(Anthropic)。不传则完全走环境变量 + 官方端点。 */
|
|
13
15
|
export function createAnthropicClient(options = {}) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
const apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
17
|
+
const baseURL = (options.baseURL ??
|
|
18
|
+
process.env.ANTHROPIC_BASE_URL ??
|
|
19
|
+
'https://api.anthropic.com').replace(/\/+$/, '');
|
|
20
|
+
const maxRetries = typeof options.maxRetries === 'number' ? options.maxRetries : 2;
|
|
21
|
+
const timeoutMs = typeof options.timeout === 'number' ? options.timeout : undefined;
|
|
22
|
+
return {
|
|
23
|
+
messages: {
|
|
24
|
+
stream(params) {
|
|
25
|
+
const textCallbacks = [];
|
|
26
|
+
// **立即发起请求**(eager,与 SDK 的 stream() 语义一致):调用方可以先等
|
|
27
|
+
// on('text') 分片、后 await finalMessage()(scripts/e2e-live.ts 步骤 ⑤
|
|
28
|
+
// 就是这个形态)—— 若惰性到 finalMessage() 才发请求,那种形态永远等不到
|
|
29
|
+
// 第一个分片。同步注册的回调不会漏分片:网络 I/O 不可能同步完成。
|
|
30
|
+
const work = (async () => {
|
|
31
|
+
// signal 是契约字段,不是 API 字段:摘出后 body 才序列化(残留会污染请求体)
|
|
32
|
+
const { signal: paramsSignal, ...bodyParams } = params;
|
|
33
|
+
const { signal, cleanup } = composeSignal(paramsSignal, timeoutMs);
|
|
34
|
+
try {
|
|
35
|
+
const res = await postWithRetries(`${baseURL}/v1/messages`, {
|
|
36
|
+
'content-type': 'application/json',
|
|
37
|
+
'anthropic-version': '2023-06-01',
|
|
38
|
+
...(apiKey ? { 'x-api-key': apiKey } : {}),
|
|
39
|
+
}, JSON.stringify({ ...bodyParams, stream: true }), signal, maxRetries);
|
|
40
|
+
// 内容协商(与 openai.ts 同款):个别兼容端点会忽略 stream:true 直接回整份 JSON
|
|
41
|
+
const ctype = res.headers.get('content-type') ?? '';
|
|
42
|
+
if (!ctype.includes('event-stream')) {
|
|
43
|
+
const message = (await res.json());
|
|
44
|
+
const full = textOf(message);
|
|
45
|
+
if (full)
|
|
46
|
+
for (const cb of textCallbacks)
|
|
47
|
+
cb(full);
|
|
48
|
+
return message;
|
|
49
|
+
}
|
|
50
|
+
if (!res.body) {
|
|
51
|
+
throw new Error('Anthropic 流式响应没有 body(端点声明了 event-stream 却没给流)');
|
|
52
|
+
}
|
|
53
|
+
return await readAnthropicStream(res.body, params.model, textCallbacks);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
cleanup();
|
|
57
|
+
}
|
|
58
|
+
})();
|
|
59
|
+
// 调用方可能只收分片、从不 await finalMessage():挂个空 catch 防 unhandled rejection
|
|
60
|
+
// (finalMessage 返回的仍是原 promise,await 它的调用方照常拿到 rejection)
|
|
61
|
+
work.catch(() => { });
|
|
62
|
+
return {
|
|
63
|
+
on(event, cb) {
|
|
64
|
+
if (event === 'text')
|
|
65
|
+
textCallbacks.push(cb);
|
|
66
|
+
},
|
|
67
|
+
finalMessage: () => work,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// —— 请求与重试(SDK 缺省语义的手写等价)——
|
|
74
|
+
/**
|
|
75
|
+
* 可重试的 HTTP 状态:408 / 409 / 429 / 5xx —— 与 SDK 缺省一致。
|
|
76
|
+
* 注意这是 **client 内重试**这一层;重试耗尽(或本就不重试)后抛出的
|
|
77
|
+
* `AnthropicApiError` 由 `engine/errors.ts` 的鸭子分类另行归类(408/409 落
|
|
78
|
+
* api/不可重试、429 落 rate_limit、5xx 落 server)—— 那是「这次失败怎么记账、
|
|
79
|
+
* 引擎外层要不要再来一轮」的语义,两层各司其职,不互相替代。
|
|
80
|
+
*/
|
|
81
|
+
function isRetryableStatus(status) {
|
|
82
|
+
return status === 408 || status === 409 || status === 429 || status >= 500;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 带重试的 POST。返回首个 2xx 响应;不可重试错误与重试耗尽都抛
|
|
86
|
+
* `AnthropicApiError`(HTTP 错误)或原始网络错误(fetch reject)。
|
|
87
|
+
* abort(外部 signal 或 timeout 合成信号)原样向上 —— 引擎靠 `name === 'AbortError'` 判。
|
|
88
|
+
*/
|
|
89
|
+
async function postWithRetries(url, headers, body, signal, maxRetries) {
|
|
90
|
+
let retryAfter = null;
|
|
91
|
+
for (let attempt = 0;; attempt++) {
|
|
92
|
+
if (attempt > 0) {
|
|
93
|
+
// 退避期间被中止:以 AbortError 收场(与引擎的 sleep 同语义)
|
|
94
|
+
await interruptibleSleep(backoffMs(attempt, retryAfter), signal);
|
|
95
|
+
retryAfter = null;
|
|
96
|
+
}
|
|
97
|
+
let res;
|
|
98
|
+
try {
|
|
99
|
+
res = await fetch(url, {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers,
|
|
102
|
+
body,
|
|
103
|
+
...(signal ? { signal } : {}),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
// abort 原样向上;signal 已中止时 fetch 的 reject 必为 abort 语义
|
|
108
|
+
if (e?.name === 'AbortError' || signal?.aborted)
|
|
109
|
+
throw e;
|
|
110
|
+
// 其余 reject 是网络失败(undici 的 TypeError: fetch failed,cause 带 errno)
|
|
111
|
+
if (attempt >= maxRetries)
|
|
112
|
+
throw e;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (res.ok)
|
|
116
|
+
return res;
|
|
117
|
+
const text = (await res.text().catch(() => '')).slice(0, 300);
|
|
118
|
+
if (isRetryableStatus(res.status) && attempt < maxRetries) {
|
|
119
|
+
// 429 的 retry-after 尤其要尊重(限流窗口是上游说了算)
|
|
120
|
+
retryAfter = res.headers.get('retry-after');
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
throw new AnthropicApiError(res.status, `Anthropic 请求失败(HTTP ${res.status}):${text}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 退避毫秒:`retry-after`(秒数或 HTTP-date)优先;否则指数退避
|
|
128
|
+
* `min(500 × 2^(attempt-1), 8000)` ±25% 抖动(attempt 从 1 起 = 第一次重试)。
|
|
129
|
+
*/
|
|
130
|
+
function backoffMs(attempt, retryAfter) {
|
|
131
|
+
if (retryAfter) {
|
|
132
|
+
const secs = Number(retryAfter);
|
|
133
|
+
if (Number.isFinite(secs))
|
|
134
|
+
return Math.max(0, Math.round(secs * 1000));
|
|
135
|
+
const at = Date.parse(retryAfter);
|
|
136
|
+
if (Number.isFinite(at))
|
|
137
|
+
return Math.max(0, at - Date.now());
|
|
138
|
+
// 解析不了就回落指数退避
|
|
139
|
+
}
|
|
140
|
+
const base = Math.min(500 * 2 ** Math.max(0, attempt - 1), 8000);
|
|
141
|
+
return Math.round(base * (0.75 + Math.random() * 0.5));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 可被 signal 中断的 sleep。
|
|
145
|
+
* 与 `engine/retry.ts` 的 sleep 同语义但不复用它 —— 分层约束:integrations 只能依赖 core。
|
|
146
|
+
*/
|
|
147
|
+
function interruptibleSleep(ms, signal) {
|
|
148
|
+
if (ms <= 0)
|
|
149
|
+
return Promise.resolve();
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const abortError = () => Object.assign(new Error('请求已被取消'), { name: 'AbortError' });
|
|
152
|
+
if (signal?.aborted) {
|
|
153
|
+
reject(abortError());
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
function onAbort() {
|
|
157
|
+
clearTimeout(timer);
|
|
158
|
+
reject(abortError());
|
|
159
|
+
}
|
|
160
|
+
const timer = setTimeout(() => {
|
|
161
|
+
signal?.removeEventListener('abort', onAbort);
|
|
162
|
+
resolve();
|
|
163
|
+
}, ms);
|
|
164
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
21
165
|
});
|
|
22
|
-
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 合成 params.signal 与 timeout(任一触发即中止)。
|
|
169
|
+
* 不用 `AbortSignal.any`:它 Node 20+ 才有,本包 `engines` 承诺 >=18。
|
|
170
|
+
* cleanup 由调用方在请求结束后调用(清计时器与监听器,防泄漏)。
|
|
171
|
+
*/
|
|
172
|
+
function composeSignal(paramsSignal, timeoutMs) {
|
|
173
|
+
if (timeoutMs == null)
|
|
174
|
+
return { signal: paramsSignal, cleanup: () => { } };
|
|
175
|
+
const controller = new AbortController();
|
|
176
|
+
const timer = setTimeout(() => {
|
|
177
|
+
// 超时以 TimeoutError 收场:分类按连接错误(可重试),与 SDK 的
|
|
178
|
+
// APIConnectionTimeoutError → connection 同语义
|
|
179
|
+
controller.abort(new DOMException(`Anthropic 请求超过 ${timeoutMs}ms`, 'TimeoutError'));
|
|
180
|
+
}, timeoutMs);
|
|
181
|
+
timer.unref(); // 兜底计时器不得拽住进程(spec 2026-09-14 ④ 同条教训)
|
|
182
|
+
const onAbort = () => controller.abort(paramsSignal?.reason);
|
|
183
|
+
if (paramsSignal) {
|
|
184
|
+
if (paramsSignal.aborted)
|
|
185
|
+
controller.abort(paramsSignal.reason);
|
|
186
|
+
else
|
|
187
|
+
paramsSignal.addEventListener('abort', onAbort, { once: true });
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
signal: controller.signal,
|
|
191
|
+
cleanup: () => {
|
|
192
|
+
clearTimeout(timer);
|
|
193
|
+
paramsSignal?.removeEventListener('abort', onAbort);
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 消费 `text/event-stream` 并组装成 Message。事件处理:
|
|
199
|
+
*
|
|
200
|
+
* | 事件 | 动作 |
|
|
201
|
+
* |---|---|
|
|
202
|
+
* | message_start | 拿 id / model / 初始 usage |
|
|
203
|
+
* | content_block_start | 按 index 建块累积器:text / tool_use / thinking 收拼;redacted_thinking 与未知块型原样携带(透出时不丢) |
|
|
204
|
+
* | content_block_delta | text_delta → 拼文本并触发 on('text');input_json_delta → 拼 partialJson;thinking_delta → 拼 thinking;signature_delta → 累积进 thinking 块的 signature |
|
|
205
|
+
* | content_block_stop | 无动作(块按 index 累积,无需收尾) |
|
|
206
|
+
* | message_delta | stop_reason / stop_sequence + 累计 usage 合并(后者覆盖前者出现的字段) |
|
|
207
|
+
* | message_stop / ping | 结束 / 忽略 |
|
|
208
|
+
* | error | 抛 AnthropicApiError(类型映射 status:rate_limit→429、overloaded→529、其余→500) |
|
|
209
|
+
*
|
|
210
|
+
* thinking 块只做「收拼 + signature 累积 + redacted/未知块原样透传」——
|
|
211
|
+
* 框架**从不主动请求 extended thinking**,这些是端点自己开了之后的兜底不丢。
|
|
212
|
+
* 与非流式 `toAnthropicMessage`(openai.ts)的空 choices 守卫同款:
|
|
213
|
+
* 整条流走完都没见 message_start = 上游故障,**抛出**而不是组装成
|
|
214
|
+
* 「stop_reason=null、content=[]、usage 全 0」的假成功。
|
|
215
|
+
*/
|
|
216
|
+
async function readAnthropicStream(body, fallbackModel, textCallbacks) {
|
|
217
|
+
const blocks = [];
|
|
218
|
+
let started = false;
|
|
219
|
+
let id = '';
|
|
220
|
+
let model = '';
|
|
221
|
+
let stopReason = null;
|
|
222
|
+
let stopSequence = null;
|
|
223
|
+
let usage = {};
|
|
224
|
+
for await (const line of sseLines(body)) {
|
|
225
|
+
if (!line.startsWith('data:'))
|
|
226
|
+
continue; // 忽略 event: / 注释 / 空行
|
|
227
|
+
const payload = line.slice('data:'.length).trim();
|
|
228
|
+
if (!payload)
|
|
229
|
+
continue;
|
|
230
|
+
let event;
|
|
231
|
+
try {
|
|
232
|
+
event = JSON.parse(payload);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
continue; // 半截/畸形分片不该毁掉整个流(与 openai.ts 同款)
|
|
236
|
+
}
|
|
237
|
+
switch (event.type) {
|
|
238
|
+
case 'message_start': {
|
|
239
|
+
started = true;
|
|
240
|
+
id = event.message?.id ?? '';
|
|
241
|
+
model = event.message?.model ?? '';
|
|
242
|
+
usage = { ...event.message?.usage };
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
case 'content_block_start': {
|
|
246
|
+
const cb = event.content_block ?? {};
|
|
247
|
+
const type = cb.type ?? 'text';
|
|
248
|
+
const acc = {
|
|
249
|
+
type,
|
|
250
|
+
text: typeof cb.text === 'string' ? cb.text : '',
|
|
251
|
+
thinking: typeof cb.thinking === 'string' ? cb.thinking : '',
|
|
252
|
+
signature: typeof cb.signature === 'string' ? cb.signature : '',
|
|
253
|
+
id: typeof cb.id === 'string' ? cb.id : '',
|
|
254
|
+
name: typeof cb.name === 'string' ? cb.name : '',
|
|
255
|
+
partialJson: '',
|
|
256
|
+
};
|
|
257
|
+
// redacted_thinking(数据在 `data` 字段)与一切未知块型:原始块对象
|
|
258
|
+
// 原样携带 —— 不丢成空文本块,finalMessage 原样透出
|
|
259
|
+
if (type !== 'text' && type !== 'tool_use' && type !== 'thinking') {
|
|
260
|
+
acc.raw = { ...cb, type };
|
|
261
|
+
}
|
|
262
|
+
blocks[event.index ?? blocks.length] = acc;
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case 'content_block_delta': {
|
|
266
|
+
const b = blocks[event.index ?? -1];
|
|
267
|
+
const d = event.delta;
|
|
268
|
+
if (!b || !d)
|
|
269
|
+
break;
|
|
270
|
+
if (d.type === 'text_delta' && typeof d.text === 'string') {
|
|
271
|
+
b.text += d.text;
|
|
272
|
+
// 逐 token 下发 —— 「打字机」效果的全部来源
|
|
273
|
+
for (const cb of textCallbacks)
|
|
274
|
+
cb(d.text);
|
|
275
|
+
}
|
|
276
|
+
else if (d.type === 'input_json_delta' && typeof d.partial_json === 'string') {
|
|
277
|
+
b.partialJson += d.partial_json;
|
|
278
|
+
}
|
|
279
|
+
else if (d.type === 'thinking_delta' && typeof d.thinking === 'string') {
|
|
280
|
+
b.thinking += d.thinking;
|
|
281
|
+
}
|
|
282
|
+
else if (d.type === 'signature_delta' && typeof d.signature === 'string') {
|
|
283
|
+
b.signature += d.signature;
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
case 'message_delta': {
|
|
288
|
+
const d = event.delta;
|
|
289
|
+
if (d?.stop_reason)
|
|
290
|
+
stopReason = d.stop_reason;
|
|
291
|
+
if (d?.stop_sequence !== undefined)
|
|
292
|
+
stopSequence = d.stop_sequence;
|
|
293
|
+
// message_delta 的 usage 是累计口径(output_tokens 为累计值,cache 计量在此回报)
|
|
294
|
+
if (event.usage)
|
|
295
|
+
usage = { ...usage, ...event.usage };
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
case 'error': {
|
|
299
|
+
// 上游故障以错误事件下发(HTTP 仍是 200)—— 不抛出就会被组装成假成功,
|
|
300
|
+
// run 结论与真实相反(openai.ts 处理过同款形态)
|
|
301
|
+
const err = event.error ?? {};
|
|
302
|
+
throw new AnthropicApiError(statusOfStreamError(err.type), `Anthropic 流内错误(${err.type ?? 'unknown'}):${err.message ?? payload.slice(0, 300)}`);
|
|
303
|
+
}
|
|
304
|
+
default:
|
|
305
|
+
break; // content_block_stop / message_stop / ping 及未知事件:忽略
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (!started) {
|
|
309
|
+
throw new Error('Anthropic 流式响应为空(未见 message_start);响应无可用补全,按上游故障处理');
|
|
310
|
+
}
|
|
311
|
+
const content = [];
|
|
312
|
+
for (const b of blocks) {
|
|
313
|
+
if (!b)
|
|
314
|
+
continue; // index 跳号留的洞
|
|
315
|
+
if (b.type === 'tool_use') {
|
|
316
|
+
content.push({
|
|
317
|
+
type: 'tool_use',
|
|
318
|
+
id: b.id,
|
|
319
|
+
name: b.name,
|
|
320
|
+
input: parseToolInput(b.partialJson),
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
else if (b.type === 'thinking') {
|
|
324
|
+
content.push({
|
|
325
|
+
type: 'thinking',
|
|
326
|
+
thinking: b.thinking,
|
|
327
|
+
signature: b.signature,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
else if (b.raw) {
|
|
331
|
+
// redacted_thinking / 未知块型:原样透出(UnknownContentBlock 兜底成员承载,
|
|
332
|
+
// 无需为它新增具体类型 —— `data` 等字段跟着原始对象走,消费方自行收窄读取)
|
|
333
|
+
content.push(b.raw);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
content.push({ type: 'text', text: b.text });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
id: id || 'msg-unknown',
|
|
341
|
+
type: 'message',
|
|
342
|
+
role: 'assistant',
|
|
343
|
+
model: model || fallbackModel,
|
|
344
|
+
content,
|
|
345
|
+
stop_reason: stopReason,
|
|
346
|
+
stop_sequence: stopSequence,
|
|
347
|
+
usage: {
|
|
348
|
+
input_tokens: usage.input_tokens ?? 0,
|
|
349
|
+
output_tokens: usage.output_tokens ?? 0,
|
|
350
|
+
cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
|
|
351
|
+
cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
/** 流内 error 事件的类型 → HTTP status(让引擎的错误分类与重试语义照常工作) */
|
|
356
|
+
function statusOfStreamError(type) {
|
|
357
|
+
switch (type) {
|
|
358
|
+
case 'rate_limit_error':
|
|
359
|
+
return 429;
|
|
360
|
+
case 'overloaded_error':
|
|
361
|
+
return 529;
|
|
362
|
+
default:
|
|
363
|
+
return 500;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/** tool_use 的 input 是分片拼出的 JSON 字符串;非法时原样交给下游 schema 校验(同 openai.ts) */
|
|
367
|
+
function parseToolInput(raw) {
|
|
368
|
+
if (!raw)
|
|
369
|
+
return {};
|
|
370
|
+
try {
|
|
371
|
+
return JSON.parse(raw);
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return raw;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/** 逐行读 SSE(每条事件都是一行 `data:`,不需要处理多行 payload;与 openai.ts 同款) */
|
|
378
|
+
async function* sseLines(body) {
|
|
379
|
+
const reader = body.getReader();
|
|
380
|
+
const decoder = new TextDecoder();
|
|
381
|
+
let buf = '';
|
|
382
|
+
try {
|
|
383
|
+
for (;;) {
|
|
384
|
+
const { done, value } = await reader.read();
|
|
385
|
+
if (done)
|
|
386
|
+
break;
|
|
387
|
+
buf += decoder.decode(value, { stream: true });
|
|
388
|
+
let idx = buf.indexOf('\n');
|
|
389
|
+
while (idx >= 0) {
|
|
390
|
+
yield buf.slice(0, idx).replace(/\r$/, '');
|
|
391
|
+
buf = buf.slice(idx + 1);
|
|
392
|
+
idx = buf.indexOf('\n');
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (buf)
|
|
396
|
+
yield buf.replace(/\r$/, '');
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
// 提前 break(abort 等)时释放读锁,否则流不会被回收
|
|
400
|
+
try {
|
|
401
|
+
await reader.cancel();
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
/* 已结束/已取消 */
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/** 取消息里的全部文本块(非流式回落路径一次性回调用) */
|
|
409
|
+
function textOf(message) {
|
|
410
|
+
return message.content
|
|
411
|
+
.filter((b) => b.type === 'text')
|
|
412
|
+
.map((b) => b.text)
|
|
413
|
+
.join('');
|
|
23
414
|
}
|
|
24
415
|
//# sourceMappingURL=anthropic.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/integrations/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAuC1C;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAA+D;IAIzF,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACnC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACrD,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,qBAAqB,CAAC,OAAO,GAA2B,EAAE;IACxE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,OAAqD,CAAC,CAAC;IACpF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpD,sDAAsD;IACtD,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAA6B,EAAE,cAAwC,EAAE,EAAE;QAC7F,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACtE,OAAO,YAAY,CAAC,SAAkB,EAAE,EAAE,GAAG,cAAc,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC;IACnF,CAAC,CAA2B,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/integrations/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,18 +48,27 @@ export interface McpToolsOptions {
|
|
|
48
48
|
/** server 标识,只用于拼缺省前缀(不会发给 server) */
|
|
49
49
|
server?: string;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* `toolTimeoutMs`
|
|
51
|
+
* **兜底**单次 `callTool` 超时(毫秒),缺省 60000;非正数 = 不限。
|
|
52
|
+
*
|
|
53
|
+
* ⚠️ 语义(见 spec §10 2026-09-17 ①):**引擎设了 `toolTimeoutMs` 时本项不参与判定** ——
|
|
54
|
+
* 一次调用只有一个裁判,否则同一件事会有两个计时器、两种账。它只在两种情况生效:
|
|
55
|
+
* ① 桥脱离引擎单用(直接 `tool.run(...)`,没有 ctx);② 引擎没设 `toolTimeoutMs`。
|
|
56
|
+
*
|
|
57
|
+
* 超时**不杀 run**:该条 tool_result 记 `is_error`、`errorKind='timeout'` 回模型。
|
|
58
|
+
* 与 engine 的 `toolTimeoutMs` **同判定、同账目**(共用 `core/timeout.ts` 的实测耗时兜底)。
|
|
54
59
|
*/
|
|
55
60
|
timeoutMs?: number;
|
|
56
61
|
}
|
|
57
62
|
/** 缺省超时:MCP server 可能去连外部系统,60s 是「明显卡死」与「慢但正常」的分界 */
|
|
58
63
|
export declare const MCP_DEFAULT_TIMEOUT_MS = 60000;
|
|
59
64
|
/**
|
|
60
|
-
* 给一次 MCP 调用套超时。⚠️
|
|
65
|
+
* 给一次 MCP 调用套超时。⚠️ 与引擎的工具超时同样是**放弃等待**而非取消 ——
|
|
61
66
|
* MCP 的 `notifications/cancelled` 属于连接器职责,桥这一层拿不到取消句柄。
|
|
62
67
|
*
|
|
68
|
+
* 实现是 `core/timeout.ts` 共享原语的**薄封装**(2026-09-17 单源化,见 spec §10 2026-09-17 ①):
|
|
69
|
+
* 「一次调用只有一个预算判定」在引擎与桥之间只允许有一份实现。此前桥自带一份**纯竞速**
|
|
70
|
+
* 版本,于是 2026-09-14 的「超时是硬的」收紧只落进引擎,桥继续把**超预算**的调用记成成功。
|
|
71
|
+
*
|
|
63
72
|
* 转导导出(module 级,**不进公共面**)只为可测:`tests/timeoutLiveness.test.ts` 拿它验
|
|
64
73
|
* 「截止计时器不得 unref」—— 那是「被 await 的超时到底会不会触发」的唯一分界点。
|
|
65
74
|
*/
|
package/dist/integrations/mcp.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TIMED_OUT, TimeoutError, withTimeout } from '../core/timeout.js';
|
|
1
2
|
/** 缺省超时:MCP server 可能去连外部系统,60s 是「明显卡死」与「慢但正常」的分界 */
|
|
2
3
|
export const MCP_DEFAULT_TIMEOUT_MS = 60_000;
|
|
3
4
|
/**
|
|
@@ -13,37 +14,24 @@ function normalizeToolName(raw) {
|
|
|
13
14
|
.replace(/^_+|_+$/g, '');
|
|
14
15
|
return cleaned;
|
|
15
16
|
}
|
|
16
|
-
/** 超时哨兵:区分「超时」与「工具恰好返回了 undefined」(同 engine 的 TIMED_OUT) */
|
|
17
|
-
const TIMED_OUT = Symbol('agentia.mcp.timed-out');
|
|
18
17
|
/**
|
|
19
|
-
* 给一次 MCP 调用套超时。⚠️
|
|
18
|
+
* 给一次 MCP 调用套超时。⚠️ 与引擎的工具超时同样是**放弃等待**而非取消 ——
|
|
20
19
|
* MCP 的 `notifications/cancelled` 属于连接器职责,桥这一层拿不到取消句柄。
|
|
21
20
|
*
|
|
21
|
+
* 实现是 `core/timeout.ts` 共享原语的**薄封装**(2026-09-17 单源化,见 spec §10 2026-09-17 ①):
|
|
22
|
+
* 「一次调用只有一个预算判定」在引擎与桥之间只允许有一份实现。此前桥自带一份**纯竞速**
|
|
23
|
+
* 版本,于是 2026-09-14 的「超时是硬的」收紧只落进引擎,桥继续把**超预算**的调用记成成功。
|
|
24
|
+
*
|
|
22
25
|
* 转导导出(module 级,**不进公共面**)只为可测:`tests/timeoutLiveness.test.ts` 拿它验
|
|
23
26
|
* 「截止计时器不得 unref」—— 那是「被 await 的超时到底会不会触发」的唯一分界点。
|
|
24
27
|
*/
|
|
25
28
|
export async function withDeadline(p, timeoutMs, label) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const raced = await Promise.race([
|
|
31
|
-
p,
|
|
32
|
-
new Promise((resolve) => {
|
|
33
|
-
timer = setTimeout(() => resolve(TIMED_OUT), timeoutMs);
|
|
34
|
-
// ⚠️ 不 unref:同 engine 的 `withTimeout` —— 它的触发是「这个 await 得以结束」的条件。
|
|
35
|
-
// unref 过它 ⇒ 空事件循环下进程先退出,挂起的 MCP 调用让整段代码静默消失。
|
|
36
|
-
}),
|
|
37
|
-
]);
|
|
38
|
-
if (raced === TIMED_OUT) {
|
|
39
|
-
throw new Error(`MCP 工具 "${label}" 调用超时(超过 ${timeoutMs}ms)`);
|
|
40
|
-
}
|
|
41
|
-
return raced;
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
if (timer)
|
|
45
|
-
clearTimeout(timer);
|
|
29
|
+
const out = await withTimeout(p, timeoutMs);
|
|
30
|
+
if (out === TIMED_OUT) {
|
|
31
|
+
// 类型化超时(code='timeout')⇒ 引擎记 errorKind='timeout',与它自己判的超时同一类账。
|
|
32
|
+
throw new TimeoutError(`MCP 工具 "${label}" 调用超时(超过 ${timeoutMs}ms)`);
|
|
46
33
|
}
|
|
34
|
+
return out;
|
|
47
35
|
}
|
|
48
36
|
/**
|
|
49
37
|
* 把一个 MCP server 的工具映射成框架的 `AgentTool[]`(可直接进 `tools` / providers)。
|
|
@@ -90,15 +78,22 @@ export async function mcpTools(client, opts = {}) {
|
|
|
90
78
|
const schema = info.inputSchema && typeof info.inputSchema === 'object' && !Array.isArray(info.inputSchema)
|
|
91
79
|
? info.inputSchema
|
|
92
80
|
: { type: 'object' };
|
|
81
|
+
// 外部 server 的 tools/list 是**外部输入**:description 不是 string(数字/对象)时
|
|
82
|
+
// 直接 `.trim()` 会让整个装配期崩 —— 与上面 name / inputSchema 的类型防御保持一致。
|
|
83
|
+
const description = typeof info.description === 'string' ? info.description.trim() : '';
|
|
93
84
|
tools.push({
|
|
94
85
|
name,
|
|
95
|
-
description:
|
|
86
|
+
description: description || `MCP 工具 ${original}`,
|
|
96
87
|
inputSchema: schema,
|
|
97
88
|
run: async (input, ctx) => {
|
|
98
89
|
// 原名先落账再调用:连接器抛错/超时时,trace 里仍留得下「本想调谁」
|
|
99
90
|
if (ctx) {
|
|
100
91
|
try {
|
|
92
|
+
// 两条键:`mcp.tool` 是「本次 turn 最近一次」的兼容键(既有看板/查询照旧);
|
|
93
|
+
// `mcp.tool.<菜单名>` 每次调用各写一条 —— 同回合并行调多个 MCP 工具时单值键会被
|
|
94
|
+
// 后者覆盖,审计/回放就拿不回被覆盖那个(按菜单名分键即无此问题)。
|
|
101
95
|
ctx.recorder.setAttribute(ctx.parentSpanId, 'mcp.tool', original);
|
|
96
|
+
ctx.recorder.setAttribute(ctx.parentSpanId, `mcp.tool.${name}`, original);
|
|
102
97
|
}
|
|
103
98
|
catch {
|
|
104
99
|
/* 观测是辅助动作:记账失败不得把一次正常调用变成失败 */
|
|
@@ -107,6 +102,14 @@ export async function mcpTools(client, opts = {}) {
|
|
|
107
102
|
const args = input && typeof input === 'object' && !Array.isArray(input)
|
|
108
103
|
? input
|
|
109
104
|
: {};
|
|
105
|
+
// 裁判权(2026-09-17,见 spec §10 2026-09-17 ①):引擎设了工具预算时,桥**不启动自己的计时器** ——
|
|
106
|
+
// 两个计时器判同一件事,只会得到两种账(桥那份曾被记成 error(unknown)/errorKind=threw),
|
|
107
|
+
// 而且桥的纯竞速还会把超了预算的调用记成成功。`timeoutMs` 退化为兜底(脱离引擎单用 /
|
|
108
|
+
// 引擎没设 toolTimeoutMs 时生效)。
|
|
109
|
+
const engineBudget = ctx?.toolTimeoutMs;
|
|
110
|
+
if (engineBudget != null && engineBudget > 0) {
|
|
111
|
+
return client.callTool(original, args);
|
|
112
|
+
}
|
|
110
113
|
return withDeadline(client.callTool(original, args), timeoutMs, original);
|
|
111
114
|
},
|
|
112
115
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/integrations/mcp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/integrations/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import type { ModelClient } from '../core/tool.js';
|
|
|
3
3
|
* OpenAI 兼容端点适配器(R4 多模型)。
|
|
4
4
|
*
|
|
5
5
|
* 把 engine 的 Anthropic 形态请求翻译成 OpenAI chat.completions 请求,
|
|
6
|
-
* 响应再翻译回
|
|
6
|
+
* 响应再翻译回 Message —— 产出的 ModelClient 可直接喂给
|
|
7
7
|
* executeRun / runAgent 的 client 选项。兼容端点(DeepSeek 等)换 baseURL 即可。
|
|
8
8
|
*
|
|
9
9
|
* 剩余边界(**协议层面无法对齐**,不是没做):
|
|
@@ -174,7 +174,7 @@ function imageUrlOf(b) {
|
|
|
174
174
|
return null;
|
|
175
175
|
}
|
|
176
176
|
/**
|
|
177
|
-
* 消费 `text/event-stream` 并组装成
|
|
177
|
+
* 消费 `text/event-stream` 并组装成 Message。
|
|
178
178
|
*
|
|
179
179
|
* 关键点(每条都有对应单测):
|
|
180
180
|
* - **`id` / `name` 取首次出现的值**(OpenAI 在第一个分片给全),
|
|
@@ -250,7 +250,7 @@ function applyChunk(acc, chunk, textCallbacks) {
|
|
|
250
250
|
if (choice.finish_reason)
|
|
251
251
|
acc.finish = choice.finish_reason;
|
|
252
252
|
}
|
|
253
|
-
/** 累积器 →
|
|
253
|
+
/** 累积器 → Message */
|
|
254
254
|
function accumulatorToMessage(acc, fallbackModel) {
|
|
255
255
|
const content = [];
|
|
256
256
|
if (acc.text)
|
|
@@ -328,7 +328,7 @@ async function* sseLines(body) {
|
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
|
-
/** OpenAI chat.completions 响应 →
|
|
331
|
+
/** OpenAI chat.completions 响应 → Message */
|
|
332
332
|
function toAnthropicMessage(data, model) {
|
|
333
333
|
const choice = data.choices?.[0];
|
|
334
334
|
if (!choice) {
|