@migor/agentia 0.2.1 → 0.2.2
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/LICENSE +21 -0
- package/README.en.md +144 -0
- package/README.md +202 -76
- package/dist/AGENTS.md +811 -0
- package/dist/container/container.d.ts +10 -2
- package/dist/container/container.js +27 -3
- package/dist/container/container.js.map +1 -1
- package/dist/core/abort.d.ts +10 -0
- package/dist/core/abort.js +28 -0
- package/dist/core/abort.js.map +1 -0
- package/dist/core/blackboard.d.ts +37 -0
- package/dist/core/blackboard.js +2 -0
- package/dist/core/blackboard.js.map +1 -0
- package/dist/core/json.d.ts +2 -0
- package/dist/core/json.js +4 -0
- package/dist/core/json.js.map +1 -1
- package/dist/core/run.d.ts +18 -0
- package/dist/core/run.js +2 -0
- package/dist/core/run.js.map +1 -0
- package/dist/core/schema.js +2 -2
- package/dist/core/schema.js.map +1 -1
- package/dist/core/tool.d.ts +62 -7
- package/dist/core/trace.d.ts +20 -4
- package/dist/engine/budget.d.ts +49 -0
- package/dist/engine/budget.js +30 -0
- package/dist/engine/budget.js.map +1 -0
- package/dist/engine/concurrency.d.ts +43 -0
- package/dist/engine/concurrency.js +95 -0
- package/dist/engine/concurrency.js.map +1 -0
- package/dist/engine/errors.d.ts +2 -0
- package/dist/engine/errors.js +7 -0
- package/dist/engine/errors.js.map +1 -1
- package/dist/engine/loop.d.ts +35 -10
- package/dist/engine/loop.js +336 -66
- package/dist/engine/loop.js.map +1 -1
- package/dist/engine/policy.d.ts +9 -1
- package/dist/engine/policy.js +8 -5
- package/dist/engine/policy.js.map +1 -1
- package/dist/engine/replay.d.ts +8 -5
- package/dist/engine/replay.js +30 -29
- package/dist/engine/replay.js.map +1 -1
- package/dist/engine/retry.d.ts +47 -0
- package/dist/engine/retry.js +51 -0
- package/dist/engine/retry.js.map +1 -0
- package/dist/engine/spec.d.ts +61 -0
- package/dist/{run → engine}/spec.js +4 -1
- package/dist/engine/spec.js.map +1 -0
- package/dist/engine/tracer.d.ts +9 -0
- package/dist/engine/tracer.js +57 -1
- package/dist/engine/tracer.js.map +1 -1
- package/dist/engine/{context.d.ts → trimming.d.ts} +19 -20
- package/dist/engine/trimming.js +238 -0
- package/dist/engine/trimming.js.map +1 -0
- package/dist/engine/types.d.ts +109 -13
- package/dist/engine/types.js +9 -1
- package/dist/engine/types.js.map +1 -1
- package/dist/engine/usage.d.ts +28 -2
- package/dist/engine/usage.js +39 -6
- package/dist/engine/usage.js.map +1 -1
- package/dist/eval/defineEval.d.ts +73 -0
- package/dist/eval/defineEval.js +44 -0
- package/dist/eval/defineEval.js.map +1 -0
- package/dist/eval/scripted.d.ts +26 -0
- package/dist/eval/scripted.js +43 -0
- package/dist/eval/scripted.js.map +1 -0
- package/dist/index.d.ts +60 -35
- package/dist/index.js +38 -20
- package/dist/index.js.map +1 -1
- package/dist/integrations/anthropic.d.ts +53 -0
- package/dist/integrations/anthropic.js +24 -0
- package/dist/integrations/anthropic.js.map +1 -0
- package/dist/integrations/mcp.d.ts +79 -0
- package/dist/integrations/mcp.js +108 -0
- package/dist/integrations/mcp.js.map +1 -0
- package/dist/integrations/metrics.d.ts +131 -0
- package/dist/integrations/metrics.js +488 -0
- package/dist/integrations/metrics.js.map +1 -0
- package/dist/{run → integrations}/openai.d.ts +12 -5
- package/dist/integrations/openai.js +386 -0
- package/dist/integrations/openai.js.map +1 -0
- package/dist/integrations/otlp.js.map +1 -0
- package/dist/integrations/report.d.ts +78 -0
- package/dist/integrations/report.js +257 -0
- package/dist/integrations/report.js.map +1 -0
- package/dist/runtime/context.d.ts +25 -0
- package/dist/{run → runtime}/context.js +8 -1
- package/dist/runtime/context.js.map +1 -0
- package/dist/{run → runtime}/memory.d.ts +1 -1
- package/dist/{run → runtime}/memory.js +3 -1
- package/dist/runtime/memory.js.map +1 -0
- package/dist/{run → runtime}/run.d.ts +22 -5
- package/dist/runtime/run.js +218 -0
- package/dist/runtime/run.js.map +1 -0
- package/dist/runtime/session.d.ts +27 -0
- package/dist/runtime/session.js +16 -0
- package/dist/runtime/session.js.map +1 -0
- package/dist/{run → runtime}/spec.d.ts +16 -2
- package/dist/runtime/spec.js +28 -0
- package/dist/runtime/spec.js.map +1 -0
- package/dist/{run → runtime}/systemPrompt.d.ts +12 -0
- package/dist/{run → runtime}/systemPrompt.js +16 -3
- package/dist/runtime/systemPrompt.js.map +1 -0
- package/dist/{run → runtime}/types.js.map +1 -1
- package/dist/{run → store}/fsStore.d.ts +15 -0
- package/dist/{run → store}/fsStore.js +43 -1
- package/dist/store/fsStore.js.map +1 -0
- package/dist/{run → store}/redisStore.d.ts +19 -1
- package/dist/{run → store}/redisStore.js +33 -6
- package/dist/store/redisStore.js.map +1 -0
- package/dist/{run → store}/sqliteStore.js +22 -1
- package/dist/store/sqliteStore.js.map +1 -0
- package/dist/{run → store}/store.d.ts +25 -3
- package/dist/store/store.js +63 -0
- package/dist/store/store.js.map +1 -0
- package/dist/toolkit/asset.d.ts +7 -6
- package/dist/toolkit/asset.js +7 -6
- package/dist/toolkit/asset.js.map +1 -1
- package/dist/toolkit/collect.d.ts +20 -7
- package/dist/toolkit/collect.js +21 -7
- package/dist/toolkit/collect.js.map +1 -1
- package/dist/toolkit/discover.d.ts +21 -1
- package/dist/toolkit/discover.js +59 -12
- package/dist/toolkit/discover.js.map +1 -1
- package/dist/toolkit/middleware.d.ts +10 -10
- package/dist/toolkit/middleware.js +17 -4
- package/dist/toolkit/middleware.js.map +1 -1
- package/dist/toolkit/module.d.ts +100 -34
- package/dist/toolkit/module.js +112 -36
- package/dist/toolkit/module.js.map +1 -1
- package/dist/toolkit/prompt.d.ts +4 -6
- package/dist/toolkit/prompt.js +11 -10
- package/dist/toolkit/prompt.js.map +1 -1
- package/dist/toolkit/skill.d.ts +14 -16
- package/dist/toolkit/skill.js +32 -25
- package/dist/toolkit/skill.js.map +1 -1
- package/dist/toolkit/subagent.d.ts +10 -12
- package/dist/toolkit/subagent.js +23 -21
- package/dist/toolkit/subagent.js.map +1 -1
- package/dist/toolkit/tool.d.ts +19 -11
- package/dist/toolkit/tool.js +11 -8
- package/dist/toolkit/tool.js.map +1 -1
- package/dist/toolkit/zod.d.ts +4 -3
- package/dist/toolkit/zod.js +2 -1
- package/dist/toolkit/zod.js.map +1 -1
- package/dist/transport/async.d.ts +133 -0
- package/dist/transport/async.js +415 -0
- package/dist/transport/async.js.map +1 -0
- package/dist/transport/http.d.ts +146 -0
- package/dist/transport/http.js +387 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/{run → transport}/scheduler.d.ts +9 -1
- package/dist/transport/scheduler.js +133 -0
- package/dist/transport/scheduler.js.map +1 -0
- package/dist/transport/sse.d.ts +43 -0
- package/dist/transport/sse.js +51 -0
- package/dist/transport/sse.js.map +1 -0
- package/dist/{run → transport}/transport.d.ts +1 -1
- package/dist/{run → transport}/transport.js +1 -1
- package/dist/transport/transport.js.map +1 -0
- package/package.json +24 -9
- package/dist/engine/context.js +0 -146
- package/dist/engine/context.js.map +0 -1
- package/dist/run/async.d.ts +0 -59
- package/dist/run/async.js +0 -201
- package/dist/run/async.js.map +0 -1
- package/dist/run/context.d.ts +0 -16
- package/dist/run/context.js.map +0 -1
- package/dist/run/fsStore.js.map +0 -1
- package/dist/run/http.d.ts +0 -47
- package/dist/run/http.js +0 -119
- package/dist/run/http.js.map +0 -1
- package/dist/run/memory.js.map +0 -1
- package/dist/run/openai.js +0 -181
- package/dist/run/openai.js.map +0 -1
- package/dist/run/otlp.js.map +0 -1
- package/dist/run/redisStore.js.map +0 -1
- package/dist/run/run.js +0 -129
- package/dist/run/run.js.map +0 -1
- package/dist/run/scheduler.js +0 -85
- package/dist/run/scheduler.js.map +0 -1
- package/dist/run/spec.js.map +0 -1
- package/dist/run/sqliteStore.js.map +0 -1
- package/dist/run/store.js +0 -28
- package/dist/run/store.js.map +0 -1
- package/dist/run/systemPrompt.js.map +0 -1
- package/dist/run/transport.js.map +0 -1
- /package/dist/{run → integrations}/otlp.d.ts +0 -0
- /package/dist/{run → integrations}/otlp.js +0 -0
- /package/dist/{run → runtime}/types.d.ts +0 -0
- /package/dist/{run → runtime}/types.js +0 -0
- /package/dist/{run → store}/sqliteStore.d.ts +0 -0
package/dist/engine/policy.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
import { compactMessages,
|
|
1
|
+
import { compactMessages, createTokenCounter, defaultEstimateTokens, trimToolPairs, } from './trimming.js';
|
|
2
2
|
export function createBudgetPolicy(opts = {}) {
|
|
3
3
|
const budgetTokens = opts.budgetTokens ?? 60_000;
|
|
4
4
|
const keepRecent = Math.max(1, opts.keepRecent ?? 20);
|
|
5
|
+
const keepToolPairs = Math.max(0, opts.keepToolPairs ?? 1);
|
|
5
6
|
const estimate = opts.estimateTokens ?? defaultEstimateTokens;
|
|
6
7
|
const editBeforeCompact = opts.editBeforeCompact ?? true;
|
|
7
8
|
const summarize = opts.summarize;
|
|
8
9
|
const compactEvery = Math.max(1, opts.compactEvery ?? 1);
|
|
9
10
|
let lastCompactAt = Number.NEGATIVE_INFINITY;
|
|
11
|
+
// 增量计数:历史只追加时只估新增部分,把 O(回合 × 上下文) 压成 O(上下文)
|
|
12
|
+
const countTokens = createTokenCounter(estimate);
|
|
10
13
|
return {
|
|
11
14
|
budgetTokens,
|
|
12
15
|
async beforeTurn(messages, info) {
|
|
13
|
-
if (
|
|
16
|
+
if (countTokens(messages) <= budgetTokens)
|
|
14
17
|
return messages;
|
|
15
|
-
// 1) context editing
|
|
18
|
+
// 1) context editing:先丢旧工具对(按「对数」计,见 keepToolPairs)
|
|
16
19
|
let current = messages;
|
|
17
20
|
if (editBeforeCompact) {
|
|
18
|
-
const trimmed = trimToolPairs(current, {
|
|
21
|
+
const trimmed = trimToolPairs(current, { keepToolPairs });
|
|
19
22
|
if (trimmed.length < current.length) {
|
|
20
23
|
current = trimmed;
|
|
21
|
-
if (
|
|
24
|
+
if (countTokens(current) <= budgetTokens)
|
|
22
25
|
return current;
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/engine/policy.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/engine/policy.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,aAAa,GACd,MAAM,eAAe,CAAC;AAuCvB,MAAM,UAAU,kBAAkB,CAAC,IAAI,GAAwB,EAAE;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,MAAM,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,IAAI,qBAAqB,CAAC;IAC9D,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IACjC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;IACzD,IAAI,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC7C,4CAA4C;IAC5C,MAAM,WAAW,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAEjD,OAAO;QACL,YAAY;QACZ,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI;YAC7B,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,YAAY;gBAAE,OAAO,QAAQ,CAAC;YAE3D,oDAAoD;YACpD,IAAI,OAAO,GAAG,QAAQ,CAAC;YACvB,IAAI,iBAAiB,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC;gBAC1D,IAAI,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;oBACpC,OAAO,GAAG,OAAO,CAAC;oBAClB,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,YAAY;wBAAE,OAAO,OAAO,CAAC;gBAC3D,CAAC;YACH,CAAC;YAED,0BAA0B;YAC1B,IAAI,CAAC,SAAS;gBAAE,OAAO,OAAO,CAAC;YAC/B,IAAI,IAAI,CAAC,SAAS,GAAG,aAAa,GAAG,YAAY;gBAAE,OAAO,OAAO,CAAC;YAClE,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC;YAC/B,OAAO,eAAe,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/engine/replay.d.ts
CHANGED
|
@@ -10,17 +10,20 @@ import type { Trace } from '../core/trace.js';
|
|
|
10
10
|
* 还原规则:
|
|
11
11
|
* - 全部 llm.turn 按 startedAt 时序线性展开(稳定排序,同刻保插入序)——
|
|
12
12
|
* 子 agent 的嵌套回合与主 agent 回合交错进同一序列,每回合以 text 块标注
|
|
13
|
-
* 来源(model / 所属
|
|
13
|
+
* 来源(model / 所属 capability span 名 / spanId);
|
|
14
14
|
* - 每回合 → 一条 assistant 消息:标注文本 + 各 tool.input 事件还原的 tool_use 块
|
|
15
15
|
* (id 由重放合成 `replay_tu_<n>`,trace 不记原始 id);
|
|
16
16
|
* - tool.output 事件 → 紧随其后一条 user 消息里的 tool_result 块,与 tool_use
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* 配对:优先按 tool_use_id 精确匹配(同名工具并行是本框架的常态 —— 完成序 ≠
|
|
18
|
+
* 发起序,只有 id 能把入参出参对上),老 trace 无 id 时回落到「同名最早未配对」,
|
|
19
|
+
* 再兜底「最早未配对」;缺失输出的 tool_use 补一条 is_error 占位 ——
|
|
20
|
+
* 保证 role 交替与配对合法;
|
|
19
21
|
* - 事件负载(工具入参/出参)已是 engine 截断后的字符串;入参尝试 JSON.parse
|
|
20
22
|
* 还原为对象,失败(或非 object)包 `{ _raw }` —— tool_use.input 必须是 object;
|
|
21
23
|
* 所有串按 maxEventChars 再截断(缺省 2000);
|
|
22
|
-
* - 产出经 normalizeForApi 规整:连续同 role
|
|
23
|
-
* 可直接作为 Messages API 的 messages
|
|
24
|
+
* - 产出经 normalizeForApi 规整:连续同 role 合并、首尾都确保为 user ——
|
|
25
|
+
* 可直接作为 Messages API 的 messages 喂回模型(末条为 user 是硬要求:
|
|
26
|
+
* 以 assistant 收尾即 prefill,缺省模型上 400)。
|
|
24
27
|
*
|
|
25
28
|
* 注意:trace 不记录 assistant 文本(llm.turn 只记 usage/事件),还原的
|
|
26
29
|
* assistant 消息以标注文本占位,非逐字原文。
|
package/dist/engine/replay.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stringifySafe, truncateWithMark } from '../core/json.js';
|
|
1
2
|
const DEFAULT_MAX_EVENT_CHARS = 2000;
|
|
2
3
|
export function traceToMessages(trace, opts = {}) {
|
|
3
4
|
const includeToolIO = opts.includeToolIO ?? true;
|
|
@@ -9,9 +10,9 @@ export function traceToMessages(trace, opts = {}) {
|
|
|
9
10
|
const messages = [];
|
|
10
11
|
let seq = 0;
|
|
11
12
|
turns.forEach((turn, i) => {
|
|
12
|
-
const
|
|
13
|
+
const capability = nearestCapabilityName(turn, byId);
|
|
13
14
|
const note = `[replay turn ${i + 1}/${turns.length}] model=${turn.name} ` +
|
|
14
|
-
`
|
|
15
|
+
`capability=${capability ?? '(主 agent run)'} span=${turn.spanId}`;
|
|
15
16
|
const content = [{ type: 'text', text: note }];
|
|
16
17
|
const pairs = [];
|
|
17
18
|
if (includeToolIO) {
|
|
@@ -19,8 +20,13 @@ export function traceToMessages(trace, opts = {}) {
|
|
|
19
20
|
const outputs = eventsOf(turn, 'tool.output');
|
|
20
21
|
const used = new Set();
|
|
21
22
|
for (const input of inputs) {
|
|
22
|
-
//
|
|
23
|
-
|
|
23
|
+
// 配对优先级:同 id 精确匹配 > 同名最早未配对 > 最早未配对。
|
|
24
|
+
// 同名工具并行时同名的那个回落会把入参出参张冠李戴,id 才是唯一可靠的锚。
|
|
25
|
+
let idx = input.toolUseId === undefined
|
|
26
|
+
? -1
|
|
27
|
+
: outputs.findIndex((o, j) => !used.has(j) && o.toolUseId === input.toolUseId);
|
|
28
|
+
if (idx < 0)
|
|
29
|
+
idx = outputs.findIndex((o, j) => !used.has(j) && o.tool === input.tool);
|
|
24
30
|
if (idx < 0)
|
|
25
31
|
idx = outputs.findIndex((_, j) => !used.has(j));
|
|
26
32
|
const output = idx >= 0 ? outputs[idx] : undefined;
|
|
@@ -45,7 +51,7 @@ export function traceToMessages(trace, opts = {}) {
|
|
|
45
51
|
type: 'tool_result',
|
|
46
52
|
tool_use_id: id,
|
|
47
53
|
content: output
|
|
48
|
-
?
|
|
54
|
+
? truncateWithMark(output.content ?? '', maxChars)
|
|
49
55
|
: '[replay] trace 中缺失对应 tool.output 事件',
|
|
50
56
|
is_error: output ? output.ok === false : true,
|
|
51
57
|
})),
|
|
@@ -54,11 +60,18 @@ export function traceToMessages(trace, opts = {}) {
|
|
|
54
60
|
});
|
|
55
61
|
return normalizeForApi(messages);
|
|
56
62
|
}
|
|
63
|
+
/** 前置 user 说明(API 要求首条为 user;trace 不含 run 的原始输入) */
|
|
64
|
+
const REPLAY_HEAD = '[replay] 以下是一次已完成 run 的 trace 重放(assistant 文本为标注占位,非逐字原文)。';
|
|
65
|
+
/** 收尾 user 请求:末条为 assistant 会被 API 当作 prefill */
|
|
66
|
+
const REPLAY_TAIL = '[replay] 以上是全部回合,请分析这次 run 的过程与结果。';
|
|
57
67
|
/**
|
|
58
68
|
* 规整为可直接喂回 Messages API 的形态:
|
|
59
69
|
* - 连续同 role 消息合并(无 tool 对的连续 assistant 会合流,交替保持合法;
|
|
60
70
|
* 带 tool_use 的 assistant 之后必有其 tool_result user,配对不受影响);
|
|
61
|
-
* - 首条确保为 user(API 硬要求)——trace 不含 run 的原始输入,前置一条说明性 user
|
|
71
|
+
* - 首条确保为 user(API 硬要求)——trace 不含 run 的原始输入,前置一条说明性 user;
|
|
72
|
+
* - **末条也确保为 user**:多数 run 以 `end_turn` 的 assistant 回合收尾,直接喂回就是
|
|
73
|
+
* assistant prefill —— 缺省模型(claude-opus-5 / claude-sonnet-5)上会 400。
|
|
74
|
+
* 空 trace(无 llm.turn)返回的也是这条前置 user,而非 `[]`(空 messages 同样非法)。
|
|
62
75
|
*/
|
|
63
76
|
function normalizeForApi(messages) {
|
|
64
77
|
const merged = [];
|
|
@@ -71,22 +84,21 @@ function normalizeForApi(messages) {
|
|
|
71
84
|
merged.push({ role: m.role, content: toBlocks(m.content) });
|
|
72
85
|
}
|
|
73
86
|
}
|
|
74
|
-
if (merged
|
|
75
|
-
merged.unshift({
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
87
|
+
if (merged[0]?.role !== 'user')
|
|
88
|
+
merged.unshift({ role: 'user', content: REPLAY_HEAD });
|
|
89
|
+
if (merged[merged.length - 1].role !== 'user') {
|
|
90
|
+
merged.push({ role: 'user', content: REPLAY_TAIL });
|
|
79
91
|
}
|
|
80
92
|
return merged;
|
|
81
93
|
}
|
|
82
94
|
function toBlocks(content) {
|
|
83
95
|
return typeof content === 'string' ? [{ type: 'text', text: content }] : [...content];
|
|
84
96
|
}
|
|
85
|
-
/** 向上找最近的
|
|
86
|
-
function
|
|
97
|
+
/** 向上找最近的 capability span 名(子 agent 嵌套回合的来源标注);直属 run 根则 null */
|
|
98
|
+
function nearestCapabilityName(span, byId) {
|
|
87
99
|
let cur = span.parentSpanId ? byId.get(span.parentSpanId) : undefined;
|
|
88
100
|
while (cur) {
|
|
89
|
-
if (cur.kind === '
|
|
101
|
+
if (cur.kind === 'capability')
|
|
90
102
|
return cur.name;
|
|
91
103
|
cur = cur.parentSpanId ? byId.get(cur.parentSpanId) : undefined;
|
|
92
104
|
}
|
|
@@ -100,6 +112,7 @@ function eventsOf(turn, name) {
|
|
|
100
112
|
const b = (e.body ?? {});
|
|
101
113
|
return {
|
|
102
114
|
tool: typeof b.tool === 'string' ? b.tool : 'unknown',
|
|
115
|
+
toolUseId: typeof b.tool_use_id === 'string' ? b.tool_use_id : undefined,
|
|
103
116
|
input: asString(b.input),
|
|
104
117
|
ok: typeof b.ok === 'boolean' ? b.ok : undefined,
|
|
105
118
|
content: asString(b.content),
|
|
@@ -107,20 +120,12 @@ function eventsOf(turn, name) {
|
|
|
107
120
|
});
|
|
108
121
|
}
|
|
109
122
|
function asString(x) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (typeof x === 'string')
|
|
113
|
-
return x;
|
|
114
|
-
try {
|
|
115
|
-
return JSON.stringify(x) ?? String(x);
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return String(x);
|
|
119
|
-
}
|
|
123
|
+
// 与 core/json.ts 的 stringifySafe 同源;仅额外把 undefined 视作「无值」
|
|
124
|
+
return x === undefined ? undefined : stringifySafe(x);
|
|
120
125
|
}
|
|
121
126
|
/** 入参还原:截断后尝试 JSON.parse 回对象,失败包 {_raw}(tool_use.input 必须是 object,否则 API 400) */
|
|
122
127
|
function parseInput(raw, maxChars) {
|
|
123
|
-
const s =
|
|
128
|
+
const s = truncateWithMark(raw ?? '', maxChars);
|
|
124
129
|
try {
|
|
125
130
|
const parsed = JSON.parse(s);
|
|
126
131
|
return typeof parsed === 'object' && parsed !== null ? parsed : { _raw: s };
|
|
@@ -129,8 +134,4 @@ function parseInput(raw, maxChars) {
|
|
|
129
134
|
return { _raw: s };
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
|
-
/** 截断到上限字符,超长加省略标记(与 engine/loop.ts 的 limit 同款格式) */
|
|
133
|
-
function truncate(s, n) {
|
|
134
|
-
return s.length > n ? `${s.slice(0, n)}…(+${s.length - n})` : s;
|
|
135
|
-
}
|
|
136
137
|
//# sourceMappingURL=replay.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/engine/replay.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/engine/replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { SpanError } from '../core/trace.js';
|
|
2
|
+
/**
|
|
3
|
+
* Agentia —— 模型请求的重试与退避(spec §6.5 确定性工程)。
|
|
4
|
+
*
|
|
5
|
+
* 消费 `classifyError().retryable`(此前该标记只产出、无人消费):429 / 5xx /
|
|
6
|
+
* 连接失败自动重试,400 一类的确定性错误立即失败。
|
|
7
|
+
*
|
|
8
|
+
* **只重试尚未产出任何文本的尝试** —— 已流出一半的文本无法撤回,重试会造成
|
|
9
|
+
* 重复输出。这条约束由 engine/loop.ts 保证(它才知道有没有吐过文本)。
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ 与 SDK 内置重试叠加:Anthropic SDK 自己会对 429/5xx 重试(默认 2 次)。
|
|
12
|
+
* 框架层是更外层的兜底(覆盖 SDK 放弃后、以及 OpenAI 兼容客户端)。两层同时开
|
|
13
|
+
* 最多会打 `(1+sdkAttempts) × maxAttempts` 次请求 —— 建议二选一调(把这里设
|
|
14
|
+
* `maxAttempts: 1`,或把 SDK 的 `maxRetries` 设小)。
|
|
15
|
+
*/
|
|
16
|
+
export interface RetryOptions {
|
|
17
|
+
/** 最大尝试次数(含首次);1 = 关闭。缺省 3 */
|
|
18
|
+
maxAttempts?: number;
|
|
19
|
+
/** 首次退避毫秒,指数增长;缺省 500 */
|
|
20
|
+
baseDelayMs?: number;
|
|
21
|
+
/** 退避上限毫秒;缺省 8000 */
|
|
22
|
+
maxDelayMs?: number;
|
|
23
|
+
/** 抖动比例 0~1(避免并发 run 同时重试打爆上游);缺省 0.2 */
|
|
24
|
+
jitter?: number;
|
|
25
|
+
/** 判定是否可重试;缺省 `(e) => classifyError(e).retryable` */
|
|
26
|
+
isRetryable?: (err: unknown) => boolean;
|
|
27
|
+
/** 重试前回调(观测用;trace 里另有 `llm.retry` 事件) */
|
|
28
|
+
onRetry?: (info: {
|
|
29
|
+
attempt: number;
|
|
30
|
+
delayMs: number;
|
|
31
|
+
error: SpanError;
|
|
32
|
+
}) => void;
|
|
33
|
+
}
|
|
34
|
+
/** 缺省重试参数(不含两个函数字段 —— 它们在 resolveRetry 里注入) */
|
|
35
|
+
export declare const DEFAULT_RETRY: {
|
|
36
|
+
readonly maxAttempts: 3;
|
|
37
|
+
readonly baseDelayMs: 500;
|
|
38
|
+
readonly maxDelayMs: 8000;
|
|
39
|
+
readonly jitter: 0.2;
|
|
40
|
+
};
|
|
41
|
+
export type ResolvedRetry = Required<RetryOptions>;
|
|
42
|
+
/** 归一重试配置:`undefined` → 缺省策略(**缺省开启**);`false` → null(关闭)。 */
|
|
43
|
+
export declare function resolveRetry(o: RetryOptions | false | undefined): ResolvedRetry | null;
|
|
44
|
+
/** 指数退避 + 上限 + 抖动:attempt 从 1 起,`base * 2^(attempt-1)` 封顶 maxDelayMs。 */
|
|
45
|
+
export declare function backoffDelay(attempt: number, r: ResolvedRetry): number;
|
|
46
|
+
/** 可被 signal 中断的 sleep(退避期间收到取消就不必再等) */
|
|
47
|
+
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { classifyError } from './errors.js';
|
|
2
|
+
/** 缺省重试参数(不含两个函数字段 —— 它们在 resolveRetry 里注入) */
|
|
3
|
+
export const DEFAULT_RETRY = {
|
|
4
|
+
maxAttempts: 3,
|
|
5
|
+
baseDelayMs: 500,
|
|
6
|
+
maxDelayMs: 8000,
|
|
7
|
+
jitter: 0.2,
|
|
8
|
+
};
|
|
9
|
+
/** 归一重试配置:`undefined` → 缺省策略(**缺省开启**);`false` → null(关闭)。 */
|
|
10
|
+
export function resolveRetry(o) {
|
|
11
|
+
if (o === false)
|
|
12
|
+
return null;
|
|
13
|
+
const merged = { ...DEFAULT_RETRY, ...(o ?? {}) };
|
|
14
|
+
if (!(merged.maxAttempts >= 1))
|
|
15
|
+
return null; // maxAttempts < 1 等同关闭
|
|
16
|
+
return {
|
|
17
|
+
...merged,
|
|
18
|
+
isRetryable: o?.isRetryable ?? ((e) => classifyError(e).retryable),
|
|
19
|
+
onRetry: o?.onRetry ?? (() => { }),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** 指数退避 + 上限 + 抖动:attempt 从 1 起,`base * 2^(attempt-1)` 封顶 maxDelayMs。 */
|
|
23
|
+
export function backoffDelay(attempt, r) {
|
|
24
|
+
const exp = r.baseDelayMs * 2 ** Math.max(0, attempt - 1);
|
|
25
|
+
const capped = Math.min(exp, r.maxDelayMs);
|
|
26
|
+
const jitter = r.jitter > 0 ? capped * r.jitter * (Math.random() * 2 - 1) : 0;
|
|
27
|
+
return Math.max(0, Math.round(capped + jitter));
|
|
28
|
+
}
|
|
29
|
+
/** 可被 signal 中断的 sleep(退避期间收到取消就不必再等) */
|
|
30
|
+
export function sleep(ms, signal) {
|
|
31
|
+
if (ms <= 0)
|
|
32
|
+
return Promise.resolve();
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const abortError = () => Object.assign(new Error('run 已被取消'), { name: 'AbortError' });
|
|
35
|
+
// 已中止:立即 reject(此处 timer 尚未创建,绝不能去 clear)
|
|
36
|
+
if (signal?.aborted) {
|
|
37
|
+
reject(abortError());
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
function onAbort() {
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
reject(abortError());
|
|
43
|
+
}
|
|
44
|
+
const timer = setTimeout(() => {
|
|
45
|
+
signal?.removeEventListener('abort', onAbort);
|
|
46
|
+
resolve();
|
|
47
|
+
}, ms);
|
|
48
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/engine/retry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA+B5C,+CAA+C;AAC/C,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,WAAW,EAAE,CAAC;IACd,WAAW,EAAE,GAAG;IAChB,UAAU,EAAE,IAAI;IAChB,MAAM,EAAE,GAAG;CACH,CAAC;AAIX,8DAA8D;AAC9D,MAAM,UAAU,YAAY,CAAC,CAAmC;IAC9D,IAAI,CAAC,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,MAAM,GAAG,EAAE,GAAG,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;IAClD,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,uBAAuB;IACpE,OAAO;QACL,GAAG,MAAM;QACT,WAAW,EAAE,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3E,OAAO,EAAE,CAAC,EAAE,OAAO,IAAI,CAAC,GAAS,EAAE,GAAE,CAAC,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,CAAgB;IAC5D,MAAM,GAAG,GAAG,CAAC,CAAC,WAAW,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB;IACpD,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACtC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,UAAU,GAAG,GAAU,EAAE,CAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAC/D,0CAA0C;QAC1C,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,SAAS,OAAO;YACd,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import type { ModelClient, ModelPricing } from '../core/tool.js';
|
|
3
|
+
import type { AgentTool } from '../core/tool.js';
|
|
4
|
+
import type { BlackboardSeed } from '../core/blackboard.js';
|
|
5
|
+
import type { ContextPolicy } from './types.js';
|
|
6
|
+
import type { RetryOptions } from './retry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Agentia —— run 调用契约(spec §6.3 三类触发共用同一份入参形态)。
|
|
9
|
+
* transport 层(同步 RPC / 异步任务 / 定时)只谈 RunInput / RunSpec,
|
|
10
|
+
* 与具体 agent 装配解耦 —— 换宿主(HTTP/队列/DB)不换语义(spec §6.6)。
|
|
11
|
+
*
|
|
12
|
+
* 放在 engine 的理由:这是 transport 与 runtime **共用**的入参契约,而 engine
|
|
13
|
+
* 在两者之下。此前它在 runtime,导致 store 为了 `TaskRecord.spec` 反向依赖
|
|
14
|
+
* runtime(兄弟层)—— 移到 engine 后 store/toolkit/transport 都能合法引用。
|
|
15
|
+
*/
|
|
16
|
+
/** 单次 run 透传给引擎/应用的可选调用参数(与 toolkit/module 的 RunAppOptions 子集对齐) */
|
|
17
|
+
export interface RunInvocationOptions {
|
|
18
|
+
model?: string;
|
|
19
|
+
maxTokens?: number;
|
|
20
|
+
maxIterations?: number;
|
|
21
|
+
client?: ModelClient;
|
|
22
|
+
onText?: (delta: string) => void;
|
|
23
|
+
/** 中断信号:中止则在飞请求被取消,run 以 stopReason='aborted' 收尾 */
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
/** 预置进本次 RunContext.blackboard(扩展过 Blackboard 时键有补全) */
|
|
26
|
+
blackboard?: BlackboardSeed;
|
|
27
|
+
/** 上下文预算策略(compaction / context editing) */
|
|
28
|
+
contextPolicy?: ContextPolicy;
|
|
29
|
+
/** 模型请求重试策略(覆盖应用级缺省);见 RunAgentOptions.retry */
|
|
30
|
+
retry?: RetryOptions | false;
|
|
31
|
+
/** 幂等键:异步宿主的 at-least-once 去重依据 */
|
|
32
|
+
idempotencyKey?: string;
|
|
33
|
+
/** 硬失败是否抛出;缺省 true(异步宿主置 false 落 failed 记录) */
|
|
34
|
+
rethrow?: boolean;
|
|
35
|
+
tools?: AgentTool[];
|
|
36
|
+
/** 成本硬管控:整条 run 累计 token 上限;超限以 stopReason='budget_exceeded' 收尾(算失败) */
|
|
37
|
+
maxTotalTokens?: number;
|
|
38
|
+
/** 成本硬管控:累计成本(美元)上限;依赖模型在价格表内,见 createBudgetGuard */
|
|
39
|
+
maxCostUsd?: number;
|
|
40
|
+
/** 价格表覆盖/追加($/1M tokens);见 RunAgentOptions.priceOverrides */
|
|
41
|
+
priceOverrides?: Record<string, ModelPricing>;
|
|
42
|
+
/** 单个工具执行超时(毫秒);超时该条 tool_result 记 is_error,不杀 run */
|
|
43
|
+
toolTimeoutMs?: number;
|
|
44
|
+
/** 同回合并行工具上限;缺省不限 */
|
|
45
|
+
maxToolConcurrency?: number;
|
|
46
|
+
}
|
|
47
|
+
/** 一次任务的规范化入参:messages(已由 normalizeMessages 规整) */
|
|
48
|
+
export interface RunSpec {
|
|
49
|
+
messages: Anthropic.MessageParam[];
|
|
50
|
+
options?: RunInvocationOptions;
|
|
51
|
+
/** 触发来源标记(sync / async / schedule:<id>),供 run 记录审计 */
|
|
52
|
+
source?: string;
|
|
53
|
+
}
|
|
54
|
+
/** transport 层接受的原始入参形态 */
|
|
55
|
+
export type RunInput = string | Anthropic.MessageParam[] | {
|
|
56
|
+
prompt?: string;
|
|
57
|
+
text?: string;
|
|
58
|
+
messages?: Anthropic.MessageParam[];
|
|
59
|
+
};
|
|
60
|
+
/** 把任意任务入参规范成 messages(首条缺省包成 user)。 */
|
|
61
|
+
export declare function normalizeMessages(input: RunInput | unknown): Anthropic.MessageParam[];
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/** 把任意任务入参规范成 messages(首条缺省包成 user)。 */
|
|
2
2
|
export function normalizeMessages(input) {
|
|
3
3
|
if (typeof input === 'string') {
|
|
4
|
-
|
|
4
|
+
// 空串与 []、{prompt:''} 一致报错:返回 [] 会带着空 messages 去调模型
|
|
5
|
+
if (!input)
|
|
6
|
+
throw new Error('任务 messages 不能为空');
|
|
7
|
+
return [{ role: 'user', content: input }];
|
|
5
8
|
}
|
|
6
9
|
if (Array.isArray(input)) {
|
|
7
10
|
if (input.length === 0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/engine/spec.ts"],"names":[],"mappings":"AA+DA,wCAAwC;AACxC,MAAM,UAAU,iBAAiB,CAAC,KAAyB;IACzD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,mDAAmD;QACnD,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC5D,OAAO,KAAiC,CAAC;IAC3C,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,KAAiE,CAAC;QAC5E,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YACjE,OAAO,CAAC,CAAC,QAAoC,CAAC;QAChD,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM;YAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3F,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC"}
|
package/dist/engine/tracer.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare class TraceRecorder {
|
|
|
8
8
|
readonly traceId: TraceId;
|
|
9
9
|
private readonly spans;
|
|
10
10
|
private readonly index;
|
|
11
|
+
/** parentSpanId → 直接子 span(增量维护,供 capability 结束时就地聚合子孙 usage,O(子孙) 而非每次重建) */
|
|
12
|
+
private readonly children;
|
|
11
13
|
private rootSpanId;
|
|
12
14
|
begin(kind: SpanKind, name: string, parentSpanId: SpanId | null): SpanId;
|
|
13
15
|
get rootStarted(): boolean;
|
|
@@ -15,12 +17,19 @@ export declare class TraceRecorder {
|
|
|
15
17
|
* 结束 span。容错策略:未知 span id 抛错(程序员错误要响亮);
|
|
16
18
|
* 对已结束的 span 幂等忽略(重复 end 视为无害)。event/setAttribute 对未知
|
|
17
19
|
* span 静默忽略 —— 观测不应中断业务,与 end 的严格性刻意区分。
|
|
20
|
+
*
|
|
21
|
+
* `capability` span 收尾时若调用方**未**显式给 usage,就地聚合其**子孙 llm.turn** 的
|
|
22
|
+
* usage 写回该 span —— 兑现 `core/trace.ts` 里「capability.usage = 其子孙聚合,仅供展示」
|
|
23
|
+
* 的已声明语义(此前该字段从不写入,指标/报告拿不到「某个子 agent 花了多少」)。
|
|
24
|
+
* 只累加 llm.turn,故层层嵌套也不会重复计数。
|
|
18
25
|
*/
|
|
19
26
|
end(id: SpanId, patch?: {
|
|
20
27
|
status?: SpanStatus;
|
|
21
28
|
error?: SpanError;
|
|
22
29
|
usage?: Usage;
|
|
23
30
|
}): void;
|
|
31
|
+
/** 子孙里所有 `llm.turn` 的 usage 之和(不含自身);无任何计量时返回 undefined */
|
|
32
|
+
private aggregateDescendantUsage;
|
|
24
33
|
event(id: SpanId, name: string, body: unknown): void;
|
|
25
34
|
setAttribute(id: SpanId, key: string, value: string | number | boolean): void;
|
|
26
35
|
snapshot(status: SpanStatus): Trace;
|
package/dist/engine/tracer.js
CHANGED
|
@@ -8,6 +8,8 @@ export class TraceRecorder {
|
|
|
8
8
|
traceId = randomUUID();
|
|
9
9
|
spans = [];
|
|
10
10
|
index = new Map();
|
|
11
|
+
/** parentSpanId → 直接子 span(增量维护,供 capability 结束时就地聚合子孙 usage,O(子孙) 而非每次重建) */
|
|
12
|
+
children = new Map();
|
|
11
13
|
rootSpanId = null;
|
|
12
14
|
begin(kind, name, parentSpanId) {
|
|
13
15
|
if (kind === 'run') {
|
|
@@ -29,6 +31,11 @@ export class TraceRecorder {
|
|
|
29
31
|
};
|
|
30
32
|
this.spans.push(span);
|
|
31
33
|
this.index.set(id, span);
|
|
34
|
+
const siblings = this.children.get(parentSpanId);
|
|
35
|
+
if (siblings)
|
|
36
|
+
siblings.push(span);
|
|
37
|
+
else
|
|
38
|
+
this.children.set(parentSpanId, [span]);
|
|
32
39
|
return id;
|
|
33
40
|
}
|
|
34
41
|
get rootStarted() {
|
|
@@ -38,6 +45,11 @@ export class TraceRecorder {
|
|
|
38
45
|
* 结束 span。容错策略:未知 span id 抛错(程序员错误要响亮);
|
|
39
46
|
* 对已结束的 span 幂等忽略(重复 end 视为无害)。event/setAttribute 对未知
|
|
40
47
|
* span 静默忽略 —— 观测不应中断业务,与 end 的严格性刻意区分。
|
|
48
|
+
*
|
|
49
|
+
* `capability` span 收尾时若调用方**未**显式给 usage,就地聚合其**子孙 llm.turn** 的
|
|
50
|
+
* usage 写回该 span —— 兑现 `core/trace.ts` 里「capability.usage = 其子孙聚合,仅供展示」
|
|
51
|
+
* 的已声明语义(此前该字段从不写入,指标/报告拿不到「某个子 agent 花了多少」)。
|
|
52
|
+
* 只累加 llm.turn,故层层嵌套也不会重复计数。
|
|
41
53
|
*/
|
|
42
54
|
end(id, patch = {}) {
|
|
43
55
|
const span = this.index.get(id);
|
|
@@ -52,6 +64,47 @@ export class TraceRecorder {
|
|
|
52
64
|
span.error = patch.error;
|
|
53
65
|
if (patch.usage)
|
|
54
66
|
span.usage = patch.usage;
|
|
67
|
+
else if (span.kind === 'capability') {
|
|
68
|
+
const aggregated = this.aggregateDescendantUsage(id);
|
|
69
|
+
if (aggregated)
|
|
70
|
+
span.usage = aggregated;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** 子孙里所有 `llm.turn` 的 usage 之和(不含自身);无任何计量时返回 undefined */
|
|
74
|
+
aggregateDescendantUsage(id) {
|
|
75
|
+
const total = {
|
|
76
|
+
inputTokens: 0,
|
|
77
|
+
outputTokens: 0,
|
|
78
|
+
cacheReadTokens: 0,
|
|
79
|
+
cacheCreationTokens: 0,
|
|
80
|
+
};
|
|
81
|
+
let cost = 0;
|
|
82
|
+
let priced = false;
|
|
83
|
+
let any = false;
|
|
84
|
+
const stack = [...(this.children.get(id) ?? [])];
|
|
85
|
+
while (stack.length > 0) {
|
|
86
|
+
const s = stack.pop();
|
|
87
|
+
if (s.kind === 'llm.turn' && s.usage) {
|
|
88
|
+
any = true;
|
|
89
|
+
total.inputTokens += s.usage.inputTokens;
|
|
90
|
+
total.outputTokens += s.usage.outputTokens;
|
|
91
|
+
total.cacheReadTokens += s.usage.cacheReadTokens;
|
|
92
|
+
total.cacheCreationTokens += s.usage.cacheCreationTokens;
|
|
93
|
+
if (s.usage.costEstimate != null) {
|
|
94
|
+
priced = true;
|
|
95
|
+
cost += s.usage.costEstimate;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const kids = this.children.get(s.spanId);
|
|
99
|
+
if (kids)
|
|
100
|
+
stack.push(...kids);
|
|
101
|
+
}
|
|
102
|
+
if (!any)
|
|
103
|
+
return undefined;
|
|
104
|
+
// 与 usage.ts 的取整口径一致(1e-6 美元),避免浮点尾差进 trace/OTLP
|
|
105
|
+
if (priced)
|
|
106
|
+
total.costEstimate = Math.round(cost * 1e6) / 1e6;
|
|
107
|
+
return total;
|
|
55
108
|
}
|
|
56
109
|
event(id, name, body) {
|
|
57
110
|
this.index.get(id)?.events.push({ time: Date.now(), name, body });
|
|
@@ -70,8 +123,11 @@ export class TraceRecorder {
|
|
|
70
123
|
cacheReadTokens: 0,
|
|
71
124
|
cacheCreationTokens: 0,
|
|
72
125
|
};
|
|
126
|
+
// 只累加「自身计量」的 span(llm.turn 是唯一 token 来源)。
|
|
127
|
+
// capability span 的 usage 语义是**其子孙的聚合**(见 core/trace.ts Span.usage),
|
|
128
|
+
// 若一并求和,skill/subagent 一旦写入聚合值就会把同一批 token 计两遍。
|
|
73
129
|
for (const s of this.spans) {
|
|
74
|
-
if (!s.usage)
|
|
130
|
+
if (!s.usage || s.kind !== 'llm.turn')
|
|
75
131
|
continue;
|
|
76
132
|
totalUsage.inputTokens += s.usage.inputTokens;
|
|
77
133
|
totalUsage.outputTokens += s.usage.outputTokens;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracer.js","sourceRoot":"","sources":["../../src/engine/tracer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAYzC;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACf,OAAO,GAAY,UAAU,EAAE,CAAC;IACxB,KAAK,GAAW,EAAE,CAAC;IACnB,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"tracer.js","sourceRoot":"","sources":["../../src/engine/tracer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,35 +1,34 @@
|
|
|
1
1
|
import type Anthropic from '@anthropic-ai/sdk';
|
|
2
|
-
/**
|
|
3
|
-
* Agentia —— 长上下文策略的纯函数层(spec §5/§6:compaction / context editing 分清)。
|
|
4
|
-
*
|
|
5
|
-
* 三策略不混:
|
|
6
|
-
* - **context editing**(`trimToolPairs`):清旧 tool_use→tool_result 对,不掉内容、不额外调模型;
|
|
7
|
-
* - **compaction**(`compactMessages`):把旧消息前缀做**服务端摘要**(摘要器由上层注入,可走模型),
|
|
8
|
-
* 只保留最近 N 条 + 一段摘要 —— 新的消息数组仍保证角色交替合法;
|
|
9
|
-
* - **客户端剪裁** = 子 agent 的独立上下文(见 toolkit/subagent.ts)。
|
|
10
|
-
*
|
|
11
|
-
* 不在此自研 token 计数黑名单:`estimateMessages` 只是预算策略的默认启发式
|
|
12
|
-
* (CJK 感知估算,明确标注为估算),上层可注入真实 count_tokens 结果。
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* 默认估算(仅预算决策用,非精确记账):CJK 字符按 ~1.5 字/token,
|
|
16
|
-
* 其余(ASCII/拉丁)按 ~4 字符/token。纯字符/4 对中文系统性高估,
|
|
17
|
-
* 会让预算护栏过早触发压缩。
|
|
18
|
-
*/
|
|
19
2
|
export declare function defaultEstimateTokens(text: string): number;
|
|
20
3
|
export declare function isToolResultMessage(msg: Anthropic.MessageParam): boolean;
|
|
21
4
|
/** 整组消息的估算 token(含每条 role 开销)。 */
|
|
22
5
|
export declare function estimateMessages(messages: Anthropic.MessageParam[], estimate?: (text: string) => number): number;
|
|
6
|
+
/**
|
|
7
|
+
* 增量 token 计数器(预算策略专用;**不属公共导出面**,故不进 index.ts)。
|
|
8
|
+
*
|
|
9
|
+
* 为什么需要:`estimateMessages` 是 O(消息数 × 块大小)(每个块还要 stringify),
|
|
10
|
+
* 而预算策略的 `beforeTurn` **每回合都要估一次**。历史只追加,若每回合从零重算,
|
|
11
|
+
* 就是 O(回合 × 上下文)。实测:160 回合时估算吃掉 run 全部框架 CPU 的约 88%、
|
|
12
|
+
* 累计 467ms(10→160 回合之间增长 ×103,明显超线性)。
|
|
13
|
+
*
|
|
14
|
+
* 这里缓存「已计过的前缀」,只对**新增消息**计数 —— 追加场景降为 O(上下文)。
|
|
15
|
+
* 数组引用变了、或长度变短(策略裁剪过 / 换了新数组)→ 自动从零重算,所以
|
|
16
|
+
* 在 `messages.splice(...)` 原地替换后也不会读到脏缓存。
|
|
17
|
+
*/
|
|
18
|
+
export declare function createTokenCounter(estimate?: (text: string) => number): (messages: Anthropic.MessageParam[]) => number;
|
|
23
19
|
/** 把消息渲染成可喂给摘要器的纯文本(role: content)。 */
|
|
24
20
|
export declare function renderMessages(messages: Anthropic.MessageParam[]): string;
|
|
25
21
|
export interface TrimOptions {
|
|
26
|
-
/** 保留最近几对 tool exchange
|
|
27
|
-
|
|
22
|
+
/** 保留最近几对 tool exchange(tool_use→tool_result **对数**);缺省 1 */
|
|
23
|
+
keepToolPairs?: number;
|
|
28
24
|
}
|
|
29
25
|
/**
|
|
30
|
-
* context editing:丢弃旧的 tool_use→tool_result 对(超出
|
|
26
|
+
* context editing:丢弃旧的 tool_use→tool_result 对(超出 keepToolPairs 的),
|
|
31
27
|
* 保留最近 N 对以及所有非工具消息。逐对整体移除,保角色交替合法。
|
|
32
28
|
* 返回原数组引用(若无需裁剪)或新数组。
|
|
29
|
+
*
|
|
30
|
+
* 前置:历史必须是工具块严格成对的(toolBlocksPaired)。畸形历史直接返回原数组
|
|
31
|
+
* —— 宁可少裁剪,也不能切出孤立 tool_use/tool_result 让后续请求 400。
|
|
33
32
|
*/
|
|
34
33
|
export declare function trimToolPairs(messages: Anthropic.MessageParam[], opts?: TrimOptions): Anthropic.MessageParam[];
|
|
35
34
|
export interface CompactOptions {
|