@migor/agentia 0.9.3 → 0.9.5
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 +779 -1
- package/README.md +1 -1
- package/dist/AGENTS.md +320 -37
- package/dist/container/container.js +15 -0
- package/dist/container/container.js.map +1 -1
- package/dist/core/limits.d.ts +121 -17
- package/dist/core/limits.js +133 -16
- package/dist/core/limits.js.map +1 -1
- package/dist/core/line-framing.d.ts +36 -0
- package/dist/core/line-framing.js +39 -0
- package/dist/core/line-framing.js.map +1 -0
- package/dist/core/message.d.ts +11 -0
- package/dist/core/run.d.ts +68 -4
- package/dist/core/run.js +27 -1
- package/dist/core/run.js.map +1 -1
- package/dist/core/schema.js +59 -8
- package/dist/core/schema.js.map +1 -1
- package/dist/core/timeout.d.ts +43 -1
- package/dist/core/timeout.js +76 -3
- package/dist/core/timeout.js.map +1 -1
- package/dist/core/tool.d.ts +39 -1
- package/dist/core/trace.d.ts +40 -1
- package/dist/core/trace.js +26 -0
- package/dist/core/trace.js.map +1 -1
- package/dist/engine/defer.d.ts +49 -0
- package/dist/engine/defer.js +72 -0
- package/dist/engine/defer.js.map +1 -0
- package/dist/engine/forwarded.d.ts +14 -5
- package/dist/engine/forwarded.js +4 -1
- package/dist/engine/forwarded.js.map +1 -1
- package/dist/engine/loop-result.d.ts +65 -7
- package/dist/engine/loop-result.js +24 -5
- package/dist/engine/loop-result.js.map +1 -1
- package/dist/engine/loop.d.ts +2 -0
- package/dist/engine/loop.js +157 -17
- package/dist/engine/loop.js.map +1 -1
- package/dist/engine/mcp-server-http.d.ts +2 -0
- package/dist/engine/mcp-server-http.js +215 -0
- package/dist/engine/mcp-server-http.js.map +1 -0
- package/dist/engine/mcp-server-stdio.d.ts +15 -0
- package/dist/engine/mcp-server-stdio.js +106 -0
- package/dist/engine/mcp-server-stdio.js.map +1 -0
- package/dist/engine/mcp-server.d.ts +134 -0
- package/dist/engine/mcp-server.js +232 -0
- package/dist/engine/mcp-server.js.map +1 -0
- package/dist/engine/menu-drift.d.ts +34 -0
- package/dist/engine/menu-drift.js +81 -0
- package/dist/engine/menu-drift.js.map +1 -0
- package/dist/engine/policy.d.ts +2 -1
- package/dist/engine/policy.js +7 -1
- package/dist/engine/policy.js.map +1 -1
- package/dist/engine/replay.d.ts +2 -1
- package/dist/engine/replay.js +3 -2
- package/dist/engine/replay.js.map +1 -1
- package/dist/engine/resume-input.d.ts +10 -0
- package/dist/engine/resume-input.js +11 -0
- package/dist/engine/resume-input.js.map +1 -1
- package/dist/engine/run-config.d.ts +26 -2
- package/dist/engine/run-config.js +60 -0
- package/dist/engine/run-config.js.map +1 -1
- package/dist/engine/spec.d.ts +33 -4
- package/dist/engine/spec.js.map +1 -1
- package/dist/engine/tool-context.d.ts +10 -5
- package/dist/engine/tool-context.js +5 -1
- package/dist/engine/tool-context.js.map +1 -1
- package/dist/engine/tracer.d.ts +43 -5
- package/dist/engine/tracer.js +73 -10
- package/dist/engine/tracer.js.map +1 -1
- package/dist/engine/trimming.js +151 -17
- package/dist/engine/trimming.js.map +1 -1
- package/dist/engine/turn.d.ts +60 -3
- package/dist/engine/turn.js +180 -71
- package/dist/engine/turn.js.map +1 -1
- package/dist/engine/types.d.ts +89 -3
- package/dist/engine/types.js +38 -2
- package/dist/engine/types.js.map +1 -1
- package/dist/engine/usage.d.ts +22 -3
- package/dist/engine/usage.js +47 -6
- package/dist/engine/usage.js.map +1 -1
- package/dist/eval/export.d.ts +48 -0
- package/dist/eval/export.js +146 -0
- package/dist/eval/export.js.map +1 -0
- package/dist/eval/harvest.js +7 -2
- package/dist/eval/harvest.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/adapter-options.d.ts +22 -0
- package/dist/integrations/adapter-options.js +51 -0
- package/dist/integrations/adapter-options.js.map +1 -1
- package/dist/integrations/anthropic.d.ts +4 -2
- package/dist/integrations/anthropic.js +27 -27
- package/dist/integrations/anthropic.js.map +1 -1
- package/dist/integrations/file-sink.d.ts +20 -0
- package/dist/integrations/file-sink.js +27 -0
- package/dist/integrations/file-sink.js.map +1 -0
- package/dist/integrations/mcp-http.d.ts +3 -3
- package/dist/integrations/mcp-http.js +1 -1
- package/dist/integrations/mcp-http.js.map +1 -1
- package/dist/integrations/mcp-protocol.d.ts +115 -0
- package/dist/integrations/mcp-protocol.js +69 -0
- package/dist/integrations/mcp-protocol.js.map +1 -0
- package/dist/integrations/mcp-stdio.d.ts +3 -3
- package/dist/integrations/mcp-stdio.js +17 -3
- package/dist/integrations/mcp-stdio.js.map +1 -1
- package/dist/integrations/mcp.d.ts +6 -95
- package/dist/integrations/mcp.js +24 -66
- package/dist/integrations/mcp.js.map +1 -1
- package/dist/integrations/metrics-otlp.js +52 -7
- package/dist/integrations/metrics-otlp.js.map +1 -1
- package/dist/integrations/metrics-render.d.ts +15 -0
- package/dist/integrations/metrics-render.js +79 -2
- package/dist/integrations/metrics-render.js.map +1 -1
- package/dist/integrations/metrics-state.d.ts +99 -1
- package/dist/integrations/metrics-state.js +128 -4
- package/dist/integrations/metrics-state.js.map +1 -1
- package/dist/integrations/metrics.d.ts +62 -6
- package/dist/integrations/metrics.js +49 -8
- package/dist/integrations/metrics.js.map +1 -1
- package/dist/integrations/openai.js +9 -31
- package/dist/integrations/openai.js.map +1 -1
- package/dist/integrations/otlp.d.ts +3 -3
- package/dist/integrations/report.d.ts +7 -0
- package/dist/integrations/report.js +20 -1
- package/dist/integrations/report.js.map +1 -1
- package/dist/runtime/memory.d.ts +61 -1
- package/dist/runtime/memory.js +47 -7
- package/dist/runtime/memory.js.map +1 -1
- package/dist/runtime/run.d.ts +12 -2
- package/dist/runtime/run.js +112 -15
- package/dist/runtime/run.js.map +1 -1
- package/dist/store/fsStore.js +10 -4
- package/dist/store/fsStore.js.map +1 -1
- package/dist/store/record.d.ts +41 -0
- package/dist/store/record.js +54 -0
- package/dist/store/record.js.map +1 -0
- package/dist/store/redisStore.d.ts +3 -1
- package/dist/store/redisStore.js +21 -7
- package/dist/store/redisStore.js.map +1 -1
- package/dist/store/sqliteStore.d.ts +23 -0
- package/dist/store/sqliteStore.js +103 -8
- package/dist/store/sqliteStore.js.map +1 -1
- package/dist/store/store.d.ts +65 -2
- package/dist/store/store.js +5 -2
- package/dist/store/store.js.map +1 -1
- package/dist/toolkit/capability-cycles.d.ts +50 -0
- package/dist/toolkit/capability-cycles.js +88 -0
- package/dist/toolkit/capability-cycles.js.map +1 -0
- package/dist/toolkit/capability-slice.d.ts +86 -0
- package/dist/toolkit/capability-slice.js +98 -0
- package/dist/toolkit/capability-slice.js.map +1 -0
- package/dist/toolkit/module.d.ts +7 -1
- package/dist/toolkit/module.js +65 -32
- package/dist/toolkit/module.js.map +1 -1
- package/dist/transport/approval-policy.d.ts +1 -1
- package/dist/transport/approval-policy.js +8 -4
- package/dist/transport/approval-policy.js.map +1 -1
- package/dist/transport/async.d.ts +197 -18
- package/dist/transport/async.js +871 -85
- package/dist/transport/async.js.map +1 -1
- package/dist/transport/drain-gate.d.ts +6 -2
- package/dist/transport/drain-gate.js +14 -2
- package/dist/transport/drain-gate.js.map +1 -1
- package/dist/transport/http-endpoints.d.ts +151 -0
- package/dist/transport/http-endpoints.js +480 -0
- package/dist/transport/http-endpoints.js.map +1 -0
- package/dist/transport/http-io.d.ts +66 -0
- package/dist/transport/http-io.js +145 -0
- package/dist/transport/http-io.js.map +1 -0
- package/dist/transport/http-route.d.ts +10 -3
- package/dist/transport/http-route.js +18 -3
- package/dist/transport/http-route.js.map +1 -1
- package/dist/transport/http-shapes.d.ts +11 -0
- package/dist/transport/http-shapes.js +31 -1
- package/dist/transport/http-shapes.js.map +1 -1
- package/dist/transport/http.d.ts +22 -35
- package/dist/transport/http.js +110 -467
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/owner-id.d.ts +29 -0
- package/dist/transport/owner-id.js +46 -0
- package/dist/transport/owner-id.js.map +1 -0
- package/dist/transport/owner-liveness.d.ts +8 -0
- package/dist/transport/owner-liveness.js +56 -0
- package/dist/transport/owner-liveness.js.map +1 -0
- package/dist/transport/resume-policy.d.ts +48 -10
- package/dist/transport/resume-policy.js +25 -10
- package/dist/transport/resume-policy.js.map +1 -1
- package/dist/transport/scheduler.js +23 -24
- package/dist/transport/scheduler.js.map +1 -1
- package/dist/transport/slot-pool.d.ts +9 -1
- package/dist/transport/slot-pool.js +9 -1
- package/dist/transport/slot-pool.js.map +1 -1
- package/dist/transport/sse.js +8 -0
- package/dist/transport/sse.js.map +1 -1
- package/dist/transport/task-events.d.ts +34 -3
- package/dist/transport/task-events.js +86 -5
- package/dist/transport/task-events.js.map +1 -1
- package/dist/transport/wake-policy.d.ts +50 -0
- package/dist/transport/wake-policy.js +43 -0
- package/dist/transport/wake-policy.js.map +1 -0
- package/package.json +6 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentTool } from '../core/tool.js';
|
|
2
|
+
import type { McpClientLike } from './mcp-protocol.js';
|
|
2
3
|
/**
|
|
3
4
|
* Agentia —— MCP 桥(D1)+ 两个内置连接器(spec §10 决策记录)。
|
|
4
5
|
*
|
|
@@ -10,7 +11,9 @@ import type { AgentTool } from '../core/tool.js';
|
|
|
10
11
|
* `createStdioMcpConnector` / `createStreamableHttpMcpConnector`。二者只用标准库
|
|
11
12
|
* (`node:child_process` + 全局 `fetch`),**不新增任何第三方依赖**。
|
|
12
13
|
* 2026-09-20 起两个连接器各居其文件(`mcp-stdio.ts` / `mcp-http.ts`,纯结构拆分、
|
|
13
|
-
*
|
|
14
|
+
* 零行为变化),本文件保留桥并 re-export —— 公共面不变。
|
|
15
|
+
* 2026-09-28 起桥与连接器**共用**的结构类型与 helper 抽到 `mcp-protocol.ts`(为了断开
|
|
16
|
+
* `mcp.ts ↔ mcp-stdio.ts` 那条**值环**,见该文件头注),本文件从那里 import 并继续 re-export。
|
|
14
17
|
*
|
|
15
18
|
* 用法(接入点是 `AppOptions.tools` 这条**裸工具缝**):
|
|
16
19
|
* ```ts
|
|
@@ -25,33 +28,6 @@ import type { AgentTool } from '../core/tool.js';
|
|
|
25
28
|
* 不做(YAGNI,见 spec §10):`sampling`(server 反向请求模型)、`resources` / `prompts`
|
|
26
29
|
* 原语(只做 tools)、连接池。
|
|
27
30
|
*/
|
|
28
|
-
/** MCP server 的 `tools/list` 条目(结构面子集:多出来的字段一律忽略) */
|
|
29
|
-
export interface McpToolInfo {
|
|
30
|
-
name: string;
|
|
31
|
-
description?: string;
|
|
32
|
-
/** MCP 协议里已是 JSON Schema → 直接当框架的 `inputSchema` 用 */
|
|
33
|
-
inputSchema?: unknown;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* MCP client 的最小结构面:任何实现了 `tools/list` + `tools/call` 的客户端都能接,
|
|
37
|
-
* 无需继承、无需 import 任何 SDK(duck-typed,与 `RedisLike` 同款)。
|
|
38
|
-
*
|
|
39
|
-
* 约定:`callTool` 失败请**抛错**(框架会包成 `is_error` 的 tool_result 回给模型,
|
|
40
|
-
* 不中断 run —— 与本地工具抛错同语义)。MCP 协议层的 `isError: true` 请由连接器
|
|
41
|
-
* 转成抛错,否则模型看不到失败。
|
|
42
|
-
*/
|
|
43
|
-
export interface McpClientLike {
|
|
44
|
-
listTools(): Promise<McpToolInfo[]>;
|
|
45
|
-
/**
|
|
46
|
-
* `opts.abandoned`:裁判(引擎 `toolTimeoutMs` / 桥兜底超时)**放弃等待**的通知信号。
|
|
47
|
-
* 放弃 ≠ 取消 —— 但连接器应借此清掉这次调用的簿记(stdio 的 pending 条目、
|
|
48
|
-
* HTTP 的在飞 fetch),否则「server 活着但不回包」时每超时一次就泄漏一条。
|
|
49
|
-
* 只实现两个参数的旧客户端依然兼容(可选参数,鸭子类型)。
|
|
50
|
-
*/
|
|
51
|
-
callTool(name: string, args: Record<string, unknown>, opts?: {
|
|
52
|
-
abandoned?: AbortSignal;
|
|
53
|
-
}): Promise<unknown>;
|
|
54
|
-
}
|
|
55
31
|
export interface McpToolsOptions {
|
|
56
32
|
/**
|
|
57
33
|
* 工具名前缀,避免与本地能力撞名。缺省 `mcp_<server>_`;没给 `server` 时缺省 `mcp_`。
|
|
@@ -72,20 +48,6 @@ export interface McpToolsOptions {
|
|
|
72
48
|
*/
|
|
73
49
|
timeoutMs?: number;
|
|
74
50
|
}
|
|
75
|
-
/** 缺省超时:MCP server 可能去连外部系统,60s 是「明显卡死」与「慢但正常」的分界 */
|
|
76
|
-
export declare const MCP_DEFAULT_TIMEOUT_MS = 60000;
|
|
77
|
-
/**
|
|
78
|
-
* 给一次 MCP 调用套超时。⚠️ 与引擎的工具超时同样是**放弃等待**而非取消 ——
|
|
79
|
-
* MCP 的 `notifications/cancelled` 属于连接器职责,桥这一层拿不到取消句柄。
|
|
80
|
-
*
|
|
81
|
-
* 实现是 `core/timeout.ts` 共享原语的**薄封装**(2026-09-17 单源化,见 spec §10 2026-09-17 ①):
|
|
82
|
-
* 「一次调用只有一个预算判定」在引擎与桥之间只允许有一份实现。此前桥自带一份**纯竞速**
|
|
83
|
-
* 版本,于是 2026-09-14 的「超时是硬的」收紧只落进引擎,桥继续把**超预算**的调用记成成功。
|
|
84
|
-
*
|
|
85
|
-
* 转导导出(module 级,**不进公共面**)只为可测:`tests/timeoutLiveness.test.ts` 拿它验
|
|
86
|
-
* 「截止计时器不得 unref」—— 那是「被 await 的超时到底会不会触发」的唯一分界点。
|
|
87
|
-
*/
|
|
88
|
-
export declare function withDeadline<T>(p: Promise<T>, timeoutMs: number, label: string): Promise<T>;
|
|
89
51
|
/**
|
|
90
52
|
* 把一个 MCP server 的工具映射成框架的 `AgentTool[]`(可直接进 `tools` / providers)。
|
|
91
53
|
*
|
|
@@ -99,59 +61,8 @@ export declare function withDeadline<T>(p: Promise<T>, timeoutMs: number, label:
|
|
|
99
61
|
* 不做「把 content 拼成字符串」这类有损加工 —— 需要塑形请自行包一层工具。
|
|
100
62
|
*/
|
|
101
63
|
export declare function mcpTools(client: McpClientLike, opts?: McpToolsOptions): Promise<AgentTool[]>;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
*
|
|
105
|
-
* 缝的形状没有变化 —— 需要自己的传输(官方 SDK / 远程 server / 复用长连接)时,
|
|
106
|
-
* 实现 `McpClientLike` 两个方法即可,不必碰这里。
|
|
107
|
-
*/
|
|
108
|
-
export interface McpConnector extends McpClientLike {
|
|
109
|
-
/**
|
|
110
|
-
* 释放底层资源,**幂等**;stdio 侧**保证返回时子进程已终止**:
|
|
111
|
-
* 先 SIGTERM,宽限期({@link MCP_CLOSE_GRACE_MS})后 SIGKILL,然后**等真正的 `'exit'`**
|
|
112
|
-
* (2026-09-18 收紧:此前到点即返回、不等 reap,会留下孤儿进程而调用方无从知晓)。
|
|
113
|
-
* HTTP 侧 = 尽力 `DELETE` 终止会话(server 不认也无所谓,失败不抛)。
|
|
114
|
-
*
|
|
115
|
-
* 关闭后再调用 `listTools` / `callTool` 会抛出可读错误(不静默挂死)。
|
|
116
|
-
*/
|
|
117
|
-
close(): Promise<void>;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* 缺省 `clientInfo`(`initialize` 握手要发,协议要求该字段存在)。
|
|
121
|
-
*
|
|
122
|
-
* **刻意不写框架自身版本**:`integrations` 层不 import 公共面(`AGENTIA_VERSION` 在
|
|
123
|
-
* `src/index.ts`),且 `scripts/release-surface.mjs` 的发版面按**精确版本串**计数 ——
|
|
124
|
-
* 这里多一处版本字面量会让它的 count 断言失配。需要真实版本请自行传 `clientInfo`。
|
|
125
|
-
*/
|
|
126
|
-
export declare const DEFAULT_CLIENT_INFO: {
|
|
127
|
-
name: string;
|
|
128
|
-
version: string;
|
|
129
|
-
};
|
|
130
|
-
/** `initialize` 缺省请求的协议版本(e2e 已验证的版本;要对齐新版 server 请显式传) */
|
|
131
|
-
export declare const DEFAULT_PROTOCOL_VERSION = "2024-11-05";
|
|
132
|
-
/**
|
|
133
|
-
* 装配期超时的落点:**握手 + `tools/list`**。
|
|
134
|
-
*
|
|
135
|
-
* 为什么不给 `callTool` 也套一个:一次调用只有一个裁判(见 `McpToolsOptions.timeoutMs`)。
|
|
136
|
-
* 走 `mcpTools` 时 `callTool` 由引擎 / 桥判定;而握手与 `tools/list` 发生在**装配期**,
|
|
137
|
-
* 没有任何别的裁判 —— server 卡住会让 `createApp` 永久挂起,必须在这里兜住。
|
|
138
|
-
*/
|
|
139
|
-
export type Guard = <T>(p: Promise<T>, label: string) => Promise<T>;
|
|
140
|
-
/** 把可能很大的值截成可读片段(错误消息要能进日志,不能是一兆的 JSON) */
|
|
141
|
-
export declare function brief(value: unknown, max?: number): string;
|
|
142
|
-
/** JSON-RPC 错误对象 → `Error`(`code` 进文案:`classifyError` 只认数值 `status`,这里不冒充它) */
|
|
143
|
-
export declare function jsonRpcError(err: unknown): Error;
|
|
144
|
-
/** server 混进 stdout / SSE 的非 JSON 行 */
|
|
145
|
-
export declare function isJsonRpcResponse(msg: unknown): msg is {
|
|
146
|
-
id: number;
|
|
147
|
-
result?: unknown;
|
|
148
|
-
error?: unknown;
|
|
149
|
-
};
|
|
150
|
-
/** 从一条已解析的报文里取结果;带 `error` 则抛 */
|
|
151
|
-
export declare function unwrap(msg: {
|
|
152
|
-
result?: unknown;
|
|
153
|
-
error?: unknown;
|
|
154
|
-
}, method: string): unknown;
|
|
64
|
+
export { DEFAULT_CLIENT_INFO, DEFAULT_PROTOCOL_VERSION, MCP_DEFAULT_TIMEOUT_MS, brief, isJsonRpcResponse, jsonRpcError, unwrap, withDeadline, } from './mcp-protocol.js';
|
|
65
|
+
export type { Guard, McpClientLike, McpConnector, McpToolInfo } from './mcp-protocol.js';
|
|
155
66
|
export { createStdioMcpConnector, MCP_CLOSE_GRACE_MS } from './mcp-stdio.js';
|
|
156
67
|
export type { StdioMcpConnectorOptions } from './mcp-stdio.js';
|
|
157
68
|
export { createStreamableHttpMcpConnector } from './mcp-http.js';
|
package/dist/integrations/mcp.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { TIMED_OUT, TimeoutError, withTimeout } from '../core/timeout.js';
|
|
2
1
|
import { combineSignals, releaseCombinedSignal } from '../core/abort.js';
|
|
3
|
-
|
|
4
|
-
export const MCP_DEFAULT_TIMEOUT_MS = 60_000;
|
|
2
|
+
import { MCP_DEFAULT_TIMEOUT_MS, withDeadline } from './mcp-protocol.js';
|
|
5
3
|
/**
|
|
6
4
|
* 工具名归一化:MCP 名可含 `-` / `.` / `/` / 空格等(对 LLM API 不友好或非法)
|
|
7
5
|
* → 一律转 `_`,并把连续分隔符收成一个(`foo..bar` → `foo_bar`)。
|
|
@@ -15,25 +13,6 @@ function normalizeToolName(raw) {
|
|
|
15
13
|
.replace(/^_+|_+$/g, '');
|
|
16
14
|
return cleaned;
|
|
17
15
|
}
|
|
18
|
-
/**
|
|
19
|
-
* 给一次 MCP 调用套超时。⚠️ 与引擎的工具超时同样是**放弃等待**而非取消 ——
|
|
20
|
-
* MCP 的 `notifications/cancelled` 属于连接器职责,桥这一层拿不到取消句柄。
|
|
21
|
-
*
|
|
22
|
-
* 实现是 `core/timeout.ts` 共享原语的**薄封装**(2026-09-17 单源化,见 spec §10 2026-09-17 ①):
|
|
23
|
-
* 「一次调用只有一个预算判定」在引擎与桥之间只允许有一份实现。此前桥自带一份**纯竞速**
|
|
24
|
-
* 版本,于是 2026-09-14 的「超时是硬的」收紧只落进引擎,桥继续把**超预算**的调用记成成功。
|
|
25
|
-
*
|
|
26
|
-
* 转导导出(module 级,**不进公共面**)只为可测:`tests/timeoutLiveness.test.ts` 拿它验
|
|
27
|
-
* 「截止计时器不得 unref」—— 那是「被 await 的超时到底会不会触发」的唯一分界点。
|
|
28
|
-
*/
|
|
29
|
-
export async function withDeadline(p, timeoutMs, label) {
|
|
30
|
-
const out = await withTimeout(p, timeoutMs);
|
|
31
|
-
if (out === TIMED_OUT) {
|
|
32
|
-
// 类型化超时(code='timeout')⇒ 引擎记 errorKind='timeout',与它自己判的超时同一类账。
|
|
33
|
-
throw new TimeoutError(`MCP 工具 "${label}" 调用超时(超过 ${timeoutMs}ms)`);
|
|
34
|
-
}
|
|
35
|
-
return out;
|
|
36
|
-
}
|
|
37
16
|
/**
|
|
38
17
|
* 把一个 MCP server 的工具映射成框架的 `AgentTool[]`(可直接进 `tools` / providers)。
|
|
39
18
|
*
|
|
@@ -133,52 +112,31 @@ export async function mcpTools(client, opts = {}) {
|
|
|
133
112
|
}
|
|
134
113
|
return tools;
|
|
135
114
|
}
|
|
136
|
-
|
|
137
|
-
*
|
|
115
|
+
/* ═══════════════════════════ 连接器(内置默认件) ═══════════════════════════
|
|
116
|
+
*
|
|
117
|
+
* 2026-09-18 决策(spec §10 同日条):连接器从「独立可选包 `@migor/mcp`」改为**内置**。
|
|
118
|
+
* 判据是仓库自己的两份先例(`store/` 的三层形状):
|
|
119
|
+
*
|
|
120
|
+
* - 只用**标准库**的平台能力 → 直接内置在 `src/`
|
|
121
|
+
* (`transport/http.ts` 的 `node:http`、`store/sqliteStore.ts` 的 `node:sqlite`、
|
|
122
|
+
* `runtime/context.ts` 的 `node:async_hooks`、`engine/tracer.ts` 的 `node:crypto`);
|
|
123
|
+
* - 需要**第三方客户端** → 只留 duck-typed 缝、框架永不 import
|
|
124
|
+
* (`store/redisStore.ts` 的 `RedisLike`,以及 `mcp-protocol.ts` 的 `McpClientLike`)。
|
|
138
125
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
126
|
+
* `spawn`(`node:child_process`)与 `fetch`(Node 18+ 全局)都是标准库 ⇒ 内置**不增加**
|
|
127
|
+
* 任何第三方依赖。「零运行时依赖」那条口径(= 不依赖第三方包,见 `package.json` 三个依赖
|
|
128
|
+
* 字段全空)不受影响 —— 它从来不是「不 import node 内建」的意思,`node:http` 一直在用。
|
|
129
|
+
*
|
|
130
|
+
* 结构面**不变**:`McpClientLike` 仍是最小缝,用户照旧可以接官方 SDK / 远程 server /
|
|
131
|
+
* 自研传输。这里给出的只是**默认件** —— 与 `FileTaskStore` / `SqliteTaskStore` 之于
|
|
132
|
+
* `TaskStore` 完全同构(默认件内置 + 缝保留 + 特殊后端仍由用户带 client)。
|
|
133
|
+
*
|
|
134
|
+
* 2026-09-20 结构拆分:两个连接器实现各居 `mcp-stdio.ts` / `mcp-http.ts`(零行为变化)。
|
|
135
|
+
* 2026-09-28:与桥共用的结构类型与 helper 移居 `mcp-protocol.ts`(断开值环),
|
|
136
|
+
* 下方统一 re-export —— 公共面仍由本文件出口。
|
|
142
137
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
version: '0.0.0',
|
|
146
|
-
};
|
|
147
|
-
/** `initialize` 缺省请求的协议版本(e2e 已验证的版本;要对齐新版 server 请显式传) */
|
|
148
|
-
export const DEFAULT_PROTOCOL_VERSION = '2024-11-05';
|
|
149
|
-
/** 把可能很大的值截成可读片段(错误消息要能进日志,不能是一兆的 JSON) */
|
|
150
|
-
export function brief(value, max = 200) {
|
|
151
|
-
let s;
|
|
152
|
-
try {
|
|
153
|
-
s = typeof value === 'string' ? value : JSON.stringify(value);
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
s = String(value);
|
|
157
|
-
}
|
|
158
|
-
if (typeof s !== 'string')
|
|
159
|
-
s = String(value);
|
|
160
|
-
return s.length > max ? `${s.slice(0, max)}…` : s;
|
|
161
|
-
}
|
|
162
|
-
/** JSON-RPC 错误对象 → `Error`(`code` 进文案:`classifyError` 只认数值 `status`,这里不冒充它) */
|
|
163
|
-
export function jsonRpcError(err) {
|
|
164
|
-
if (typeof err === 'object' && err !== null) {
|
|
165
|
-
const { code, message } = err;
|
|
166
|
-
return new Error(`MCP error ${String(code)}: ${String(message)}`);
|
|
167
|
-
}
|
|
168
|
-
return new Error(`MCP error: ${brief(err)}`);
|
|
169
|
-
}
|
|
170
|
-
/** server 混进 stdout / SSE 的非 JSON 行 */
|
|
171
|
-
export function isJsonRpcResponse(msg) {
|
|
172
|
-
return (typeof msg === 'object' && msg !== null && typeof msg.id === 'number');
|
|
173
|
-
}
|
|
174
|
-
/** 从一条已解析的报文里取结果;带 `error` 则抛 */
|
|
175
|
-
export function unwrap(msg, method) {
|
|
176
|
-
if (msg.error !== undefined)
|
|
177
|
-
throw jsonRpcError(msg.error);
|
|
178
|
-
if (!('result' in msg))
|
|
179
|
-
throw new Error(`MCP ${method}:响应里既没有 result 也没有 error`);
|
|
180
|
-
return msg.result;
|
|
181
|
-
}
|
|
138
|
+
// 与连接器共用的协议面(结构类型 + helper):定义在 mcp-protocol.ts,此处 re-export 保持公共面
|
|
139
|
+
export { DEFAULT_CLIENT_INFO, DEFAULT_PROTOCOL_VERSION, MCP_DEFAULT_TIMEOUT_MS, brief, isJsonRpcResponse, jsonRpcError, unwrap, withDeadline, } from './mcp-protocol.js';
|
|
182
140
|
// 两个内置连接器(2026-09-20 起各居其文件;公共面不变,index.ts 仍从这里取)
|
|
183
141
|
export { createStdioMcpConnector, MCP_CLOSE_GRACE_MS } from './mcp-stdio.js';
|
|
184
142
|
export { createStreamableHttpMcpConnector } from './mcp-http.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/integrations/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/integrations/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { scoreLabels } from './metrics-state.js';
|
|
2
2
|
import { otlpPartialSuccess, readOtlpResponseBody } from './otlp-partial.js';
|
|
3
|
+
import { wireSpanId, wireTraceId } from '../core/trace.js';
|
|
3
4
|
/**
|
|
4
5
|
* metricsSink 的 **OTLP/JSON 导出**(E5):从 `MetricsState` 组装 payload + POST 到
|
|
5
6
|
* `${endpoint}/v1/metrics`。只读状态、不改账。module 级 export,不进公共面(`src/index.ts`)。
|
|
@@ -27,11 +28,21 @@ export class MetricsExportError extends Error {
|
|
|
27
28
|
// epoch 毫秒 ×1e6 ≈ 1.7e18 > 2^53,double 直接乘会丢精度 —— 必须先取整再转 BigInt
|
|
28
29
|
const nanos = (ms) => String(BigInt(Math.round(ms)) * 1000000n);
|
|
29
30
|
const strAttr = (key, v) => ({ key, value: { stringValue: v } });
|
|
31
|
+
/**
|
|
32
|
+
* exemplar(指标 → trace 的桥):OTLP 数据点的原生字段。
|
|
33
|
+
* trace_id/span_id 走 core/trace.ts 的 hex 投影(单一真源,与 traces 导出同一份);
|
|
34
|
+
* filteredAttributes 为空 —— 我们的 exemplar 没有额外 label(两个槽位都是无 label 的数据点)。
|
|
35
|
+
*/
|
|
36
|
+
const exemplarOf = (ex, value) => ({
|
|
37
|
+
timeUnixNano: nanos(ex.at),
|
|
38
|
+
...value,
|
|
39
|
+
spanId: wireSpanId(ex.spanId),
|
|
40
|
+
traceId: wireTraceId(ex.traceId),
|
|
41
|
+
});
|
|
30
42
|
export function buildOtlpPayload(state, opts) {
|
|
31
43
|
const p = opts.prefix;
|
|
32
44
|
const now = nanos(Date.now());
|
|
33
45
|
const start = nanos(opts.startedAtMs);
|
|
34
|
-
const s = state.snapshot();
|
|
35
46
|
const metricTable = new Map();
|
|
36
47
|
/** 查表取已建 Metric,没有则建;同名只保留首次的 description(冲突描述本身是 semantic error) */
|
|
37
48
|
const takeMetric = (name, help) => {
|
|
@@ -42,7 +53,7 @@ export function buildOtlpPayload(state, opts) {
|
|
|
42
53
|
}
|
|
43
54
|
return m;
|
|
44
55
|
};
|
|
45
|
-
const sum = (name, value, help, attrs, monotonic = true) => {
|
|
56
|
+
const sum = (name, value, help, attrs, monotonic = true, exemplars) => {
|
|
46
57
|
const m = takeMetric(name, help);
|
|
47
58
|
m.sum ??= { aggregationTemporality: 2, isMonotonic: monotonic, dataPoints: [] };
|
|
48
59
|
m.sum.dataPoints.push({
|
|
@@ -50,6 +61,7 @@ export function buildOtlpPayload(state, opts) {
|
|
|
50
61
|
startTimeUnixNano: start,
|
|
51
62
|
timeUnixNano: now,
|
|
52
63
|
asInt: String(value),
|
|
64
|
+
...(exemplars !== undefined ? { exemplars } : {}),
|
|
53
65
|
});
|
|
54
66
|
};
|
|
55
67
|
// 浮点指标(成本)必须走 asDouble —— OTLP 的 asInt 是 string 编码 int64,
|
|
@@ -75,7 +87,7 @@ export function buildOtlpPayload(state, opts) {
|
|
|
75
87
|
asDouble: value,
|
|
76
88
|
});
|
|
77
89
|
};
|
|
78
|
-
const hist = (name, stat, help, attrs) => {
|
|
90
|
+
const hist = (name, stat, help, attrs, exemplars) => {
|
|
79
91
|
const m = takeMetric(name, help);
|
|
80
92
|
m.histogram ??= { aggregationTemporality: 2, dataPoints: [] };
|
|
81
93
|
m.histogram.dataPoints.push({
|
|
@@ -87,10 +99,15 @@ export function buildOtlpPayload(state, opts) {
|
|
|
87
99
|
// OTLP 的 bucketCounts 是每桶**非累积**计数(Prometheus 文本才是累积语义)
|
|
88
100
|
bucketCounts: stat.perBucket(),
|
|
89
101
|
explicitBounds: [...stat.boundsList],
|
|
102
|
+
...(exemplars !== undefined ? { exemplars } : {}),
|
|
90
103
|
});
|
|
91
104
|
};
|
|
92
|
-
sum(`${p}runs_total`,
|
|
93
|
-
sum(`${p}runs_failed_total`,
|
|
105
|
+
sum(`${p}runs_total`, state.runs, 'run 总数', []);
|
|
106
|
+
sum(`${p}runs_failed_total`, state.failed, '失败的 run 数', [], true,
|
|
107
|
+
// exemplar:最近一次失败的 run(counter 语义 → asInt=该次增量 1)
|
|
108
|
+
state.failedExemplar !== undefined
|
|
109
|
+
? [exemplarOf(state.failedExemplar, { asInt: '1' })]
|
|
110
|
+
: undefined);
|
|
94
111
|
// tokens_total:四类 kind 分项收进**同一个** Metric;description 与 Prometheus 侧
|
|
95
112
|
// render() 的 family() 统一成同一句总述(同名 Metric 各带一份描述是 semantic error)
|
|
96
113
|
const tokensHelp = 'token 累计(kind 分项:input / output / cache_read / cache_creation)';
|
|
@@ -100,8 +117,23 @@ export function buildOtlpPayload(state, opts) {
|
|
|
100
117
|
sum(`${p}tokens_total`, state.tokens.cacheCreation, tokensHelp, [
|
|
101
118
|
strAttr('kind', 'cache_creation'),
|
|
102
119
|
]);
|
|
103
|
-
sumDouble(`${p}cost_usd_total`,
|
|
104
|
-
|
|
120
|
+
sumDouble(`${p}cost_usd_total`, state.costUsd, '累计成本估算(美元)', []);
|
|
121
|
+
// 归因标签(R8-P4):与 Prometheus 侧同四个家族,dataPoint 自带 attributes;
|
|
122
|
+
// 同名数据点收进同一个 Metric(takeMetric 的职责),这里只管逐 combo 发点
|
|
123
|
+
for (const combo of [...state.runLabels.keys()].sort()) {
|
|
124
|
+
const acc = state.runLabels.get(combo);
|
|
125
|
+
const attrs = acc.pairs.map(([k, v]) => strAttr(k, v));
|
|
126
|
+
sum(`${p}runs_total`, acc.runs, 'run 总数', attrs);
|
|
127
|
+
sum(`${p}runs_failed_total`, acc.failed, '失败的 run 数', attrs);
|
|
128
|
+
// 带标签的 token 点是四类之和(与 Prometheus 侧同口径:combo 标签不再拆 kind)
|
|
129
|
+
sum(`${p}tokens_total`, acc.tokens, tokensHelp, attrs);
|
|
130
|
+
sumDouble(`${p}cost_usd_total`, acc.costUsd, '累计成本估算(美元)', attrs);
|
|
131
|
+
}
|
|
132
|
+
hist(`${p}run_duration_ms`, state.runStat, 'run 时长(毫秒)', [],
|
|
133
|
+
// exemplar:迄今最慢的一次 run(histogram 语义 → asDouble=观测到的时长)
|
|
134
|
+
state.slowestExemplar !== undefined
|
|
135
|
+
? [exemplarOf(state.slowestExemplar, { asDouble: state.slowestExemplar.durationMs })]
|
|
136
|
+
: undefined);
|
|
105
137
|
for (const label of [...state.capabilities.keys()].sort()) {
|
|
106
138
|
const acc = state.capabilities.get(label);
|
|
107
139
|
const attrs = [strAttr('capability', label)];
|
|
@@ -122,6 +154,9 @@ export function buildOtlpPayload(state, opts) {
|
|
|
122
154
|
if (acc.unpricedTurns > 0) {
|
|
123
155
|
sum(`${p}model_unpriced_turns_total`, acc.unpricedTurns, '未定价 turn 数', attrs);
|
|
124
156
|
}
|
|
157
|
+
if (acc.usageMissingTurns > 0) {
|
|
158
|
+
sum(`${p}model_usage_missing_turns_total`, acc.usageMissingTurns, '上游未回报 usage 的 turn 数', attrs);
|
|
159
|
+
}
|
|
125
160
|
hist(`${p}model_duration_ms`, acc.stat, '模型往返耗时(毫秒)', attrs);
|
|
126
161
|
}
|
|
127
162
|
for (const key of [...state.scores.keys()].sort()) {
|
|
@@ -137,6 +172,16 @@ export function buildOtlpPayload(state, opts) {
|
|
|
137
172
|
gauge(`${p}dropped_keys`, state.capBudget.dropped, droppedHelp, [strAttr('kind', 'capability')]);
|
|
138
173
|
gauge(`${p}dropped_keys`, state.modelBudget.dropped, droppedHelp, [strAttr('kind', 'model')]);
|
|
139
174
|
gauge(`${p}dropped_keys`, state.scoreBudget.dropped, droppedHelp, [strAttr('kind', 'score')]);
|
|
175
|
+
// 归因标签每键一点(kind 取 `label:<key>`,与 Prometheus 侧同形)
|
|
176
|
+
for (const [key, budget] of state.labelBudgets) {
|
|
177
|
+
gauge(`${p}dropped_keys`, budget.dropped, droppedHelp, [strAttr('kind', `label:${key}`)]);
|
|
178
|
+
}
|
|
179
|
+
// 组合数的折叠(`maxLabelCombos`):与 Prometheus 侧同一行,未配置 labelKeys 时不发
|
|
180
|
+
if (state.labelBudgets.size > 0) {
|
|
181
|
+
gauge(`${p}dropped_keys`, state.comboBudget.dropped, droppedHelp, [
|
|
182
|
+
strAttr('kind', 'label:combos'),
|
|
183
|
+
]);
|
|
184
|
+
}
|
|
140
185
|
const metrics = [...metricTable.values()];
|
|
141
186
|
const resourceAttrs = [
|
|
142
187
|
strAttr('service.name', opts.serviceName),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics-otlp.js","sourceRoot":"","sources":["../../src/integrations/metrics-otlp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"metrics-otlp.js","sourceRoot":"","sources":["../../src/integrations/metrics-otlp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE3D;;;GAGG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,MAAM,CAAS;IACxB,YAAY,MAAc,EAAE,OAAe;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAwBD,wBAAwB;AACxB,iEAAiE;AACjE,MAAM,KAAK,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,QAAU,CAAC,CAAC;AAElF,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,CAAS,EAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AAE3F;;;;GAIG;AACH,MAAM,UAAU,GAAG,CACjB,EAAe,EACf,KAA+C,EACtB,EAAE,CAAC,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1B,GAAG,KAAK;IACR,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC;IAC7B,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,UAAU,gBAAgB,CAAC,KAAmB,EAAE,IAAwB;IAC5E,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAsBtC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;IAClD,qEAAqE;IACrE,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,IAAY,EAAc,EAAE;QAC5D,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;YAChC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,CACV,IAAY,EACZ,KAAa,EACb,IAAY,EACZ,KAAiB,EACjB,SAAS,GAAG,IAAI,EAChB,SAAqC,EAC/B,EAAE;QACR,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CAAC,GAAG,KAAK,EAAE,sBAAsB,EAAE,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAChF,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YACpB,UAAU,EAAE,KAAK;YACjB,iBAAiB,EAAE,KAAK;YACxB,YAAY,EAAE,GAAG;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;YACpB,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD,CAAC,CAAC;IACL,CAAC,CAAC;IACF,0DAA0D;IAC1D,mCAAmC;IACnC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,IAAY,EAAE,KAAiB,EAAQ,EAAE;QACvF,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CAAC,GAAG,KAAK,EAAE,sBAAsB,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC3E,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YACpB,UAAU,EAAE,KAAK;YACjB,iBAAiB,EAAE,KAAK;YACxB,YAAY,EAAE,GAAG;YACjB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC,CAAC;IACF,uCAAuC;IACvC,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,IAAY,EAAE,KAAiB,EAAQ,EAAE;QACnF,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CAAC,KAAK,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YACtB,UAAU,EAAE,KAAK;YACjB,iBAAiB,EAAE,KAAK;YACxB,YAAY,EAAE,GAAG;YACjB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CACX,IAAY,EACZ,IAAkB,EAClB,IAAY,EACZ,KAAiB,EACjB,SAAqC,EAC/B,EAAE;QACR,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CAAC,SAAS,KAAK,EAAE,sBAAsB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC9D,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,UAAU,EAAE,KAAK;YACjB,iBAAiB,EAAE,KAAK;YACxB,YAAY,EAAE,GAAG;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,KAAK;YACf,wDAAwD;YACxD,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE;YAC9B,cAAc,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YACpC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChD,GAAG,CACD,GAAG,CAAC,mBAAmB,EACvB,KAAK,CAAC,MAAM,EACZ,WAAW,EACX,EAAE,EACF,IAAI;IACJ,kDAAkD;IAClD,KAAK,CAAC,cAAc,KAAK,SAAS;QAChC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC,CAAC,SAAS,CACd,CAAC;IACF,qEAAqE;IACrE,iEAAiE;IACjE,MAAM,UAAU,GAAG,gEAAgE,CAAC;IACpF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtF,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC7F,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE;QAC9D,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC;KAClC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;IACjE,2DAA2D;IAC3D,mDAAmD;IACnD,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;QACxC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACvD,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACjD,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7D,wDAAwD;QACxD,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACvD,SAAS,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,CACF,GAAG,CAAC,iBAAiB,EACrB,KAAK,CAAC,OAAO,EACb,YAAY,EACZ,EAAE;IACF,uDAAuD;IACvD,KAAK,CAAC,eAAe,KAAK,SAAS;QACjC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC,CAAC;QACrF,CAAC,CAAC,SAAS,CACd,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1D,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7C,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC9D,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChE,IAAI,CAAC,GAAG,CAAC,wBAAwB,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;QAClE,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;YACrB,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;QACvE,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI;YACtB,SAAS,CAAC,GAAG,CAAC,2BAA2B,EAAE,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IAC/E,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;QACrC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACxC,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACzD,GAAG,CAAC,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;QAChE,SAAS,CAAC,GAAG,CAAC,sBAAsB,EAAE,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;QACxE,IAAI,GAAG,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YAC1B,GAAG,CAAC,GAAG,CAAC,4BAA4B,EAAE,GAAG,CAAC,aAAa,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;QAChF,CAAC;QACD,IAAI,GAAG,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC;YAC9B,GAAG,CACD,GAAG,CAAC,iCAAiC,EACrC,GAAG,CAAC,iBAAiB,EACrB,sBAAsB,EACtB,KAAK,CACN,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;QACnC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACjE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/C,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,yDAAyD;IACzD,6BAA6B;IAC7B,MAAM,WAAW,GAAG,eAAe,CAAC;IACpC,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IACjG,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9F,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9F,kDAAkD;IAClD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QAC/C,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5F,CAAC;IACD,+DAA+D;IAC/D,IAAI,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE;YAChE,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAE1C,MAAM,aAAa,GAAe;QAChC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC;QACzC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAChF,CAAC;IACF,OAAO;QACL,eAAe,EAAE;YACf;gBACE,QAAQ,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE;gBACvC,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC;aACxD;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAmB,EAAE,IAAsB;IAChF,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,aAAa,EAAE;YACrD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/E,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC9C,MAAM,IAAI,kBAAkB,CAAC,GAAG,CAAC,MAAM,EAAE,2BAA2B,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,6EAA6E;QAC7E,kDAAkD;QAClD,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,oBAAoB,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;QAClF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,kBAAkB,CAAC,GAAG,EAAE,mCAAmC,OAAO,EAAE,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;IACxC,CAAC;AACH,CAAC"}
|
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
import type { MetricsState } from './metrics-state.js';
|
|
2
2
|
export declare function renderPrometheus(state: MetricsState, p: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* **OpenMetrics 文本渲染**(`application/openmetrics-text`)—— exemplars 的出口。
|
|
5
|
+
*
|
|
6
|
+
* Prometheus 原文格式(0.0.4)**不支持** exemplar(样本行尾 `# {…}` 那段语法只有
|
|
7
|
+
* OpenMetrics 有),所以要「指标尖峰 → 那条 trace」就必须换这一个格式。
|
|
8
|
+
*
|
|
9
|
+
* 实现 = `renderPrometheus` 的输出 + 两处样本行尾追加 exemplar + `# EOF` 收尾,
|
|
10
|
+
* 其余内容**逐字节同源**(两条输出共用同一份渲染,永远不会漂)。三个编辑点:
|
|
11
|
+
* - `runs_failed_total` 样本行尾挂最近一次失败 run(counter 的 exemplar 值 = 该次增量 1);
|
|
12
|
+
* - `run_duration_ms` 的 exemplar 挂在**最慢那次落入的 bucket** 行上
|
|
13
|
+
* (OpenMetrics 规定 histogram 的 exemplar 必须挂 bucket,不能挂 sum/count);
|
|
14
|
+
* - 文件末尾 `# EOF`(OpenMetrics 的强制收尾)。
|
|
15
|
+
* trace_id 走 `wireTraceId` 投影(hex,Tempo/Grafana 的 exemplar 跳转按它查)。
|
|
16
|
+
*/
|
|
17
|
+
export declare function renderOpenMetrics(state: MetricsState, p: string): string;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { scoreLabels } from './metrics-state.js';
|
|
2
|
+
import { wireTraceId } from '../core/trace.js';
|
|
2
3
|
/**
|
|
3
|
-
* metricsSink 的 **Prometheus 文本渲染**(`text/plain; version=0.0.4
|
|
4
|
-
*
|
|
4
|
+
* metricsSink 的 **Prometheus 文本渲染**(`text/plain; version=0.0.4`,零依赖手写)
|
|
5
|
+
* 与 **OpenMetrics 渲染**(exemplars 的唯一文本出口)。只读 `MetricsState`,不改账。
|
|
6
|
+
* module 级 export,不进公共面(`src/index.ts`)。
|
|
5
7
|
*/
|
|
6
8
|
/**
|
|
7
9
|
* 一个指标家族的完整块:HELP/TYPE 各**恰好一行**,后接全部样本行。
|
|
@@ -26,22 +28,47 @@ const histogramSamples = (name, stat, labels = '') => {
|
|
|
26
28
|
out.push(`${name}_count${labels} ${stat.count}`);
|
|
27
29
|
return out;
|
|
28
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* 归因标签对的 label 文本(`{tenant="acme",plan="pro"}`)。键已过 Prometheus 标签名
|
|
33
|
+
* 校验(metrics.ts 构造期),只需转义**值**。不从 combo 键反解 —— 值里含 `,`/`=` 时反解会碎。
|
|
34
|
+
*/
|
|
35
|
+
const labelPairsText = (pairs) => `{${pairs.map(([k, v]) => `${k}="${escLabel(v)}"`).join(',')}}`;
|
|
36
|
+
/** 归因标签维度的样本(按 combo 键排序,确定性输出);未配置 labelKeys 时为空表 */
|
|
37
|
+
const labeledSamples = (state, pick) => {
|
|
38
|
+
const out = [];
|
|
39
|
+
for (const combo of [...state.runLabels.keys()].sort()) {
|
|
40
|
+
const acc = state.runLabels.get(combo);
|
|
41
|
+
out.push({ text: labelPairsText(acc.pairs), value: pick(acc) });
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
};
|
|
29
45
|
export function renderPrometheus(state, p) {
|
|
30
46
|
const out = [];
|
|
47
|
+
// 归因标签(R8-P4):四个 run 级家族在全局样本之外追加带标签的样本;
|
|
48
|
+
// 全局那行(无 label)保持**第一个** —— renderOpenMetrics 靠精确匹配它挂 exemplar。
|
|
49
|
+
const labelRuns = labeledSamples(state, (a) => a.runs);
|
|
31
50
|
out.push(family(`${p}runs_total`, 'counter', 'run 总数(成功 + 失败)', [
|
|
32
51
|
`${p}runs_total ${state.runs}`,
|
|
52
|
+
...labelRuns.map((s) => `${p}runs_total${s.text} ${s.value}`),
|
|
33
53
|
]));
|
|
54
|
+
const labelFailed = labeledSamples(state, (a) => a.failed);
|
|
34
55
|
out.push(family(`${p}runs_failed_total`, 'counter', '失败的 run 数(trace.status=error)', [
|
|
35
56
|
`${p}runs_failed_total ${state.failed}`,
|
|
57
|
+
...labelFailed.map((s) => `${p}runs_failed_total${s.text} ${s.value}`),
|
|
36
58
|
]));
|
|
59
|
+
// 带标签的 token 样本是**四类之和**(combo 标签不再拆 kind —— 两类标签叉乘会把序列数打飞)
|
|
60
|
+
const labelTokens = labeledSamples(state, (a) => a.tokens);
|
|
37
61
|
out.push(family(`${p}tokens_total`, 'counter', 'token 累计(kind 分项:input / output / cache_read / cache_creation)', [
|
|
38
62
|
`${p}tokens_total{kind="input"} ${state.tokens.input}`,
|
|
39
63
|
`${p}tokens_total{kind="output"} ${state.tokens.output}`,
|
|
40
64
|
`${p}tokens_total{kind="cache_read"} ${state.tokens.cacheRead}`,
|
|
41
65
|
`${p}tokens_total{kind="cache_creation"} ${state.tokens.cacheCreation}`,
|
|
66
|
+
...labelTokens.map((s) => `${p}tokens_total${s.text} ${s.value}`),
|
|
42
67
|
]));
|
|
68
|
+
const labelCost = labeledSamples(state, (a) => a.costUsd);
|
|
43
69
|
out.push(family(`${p}cost_usd_total`, 'counter', '累计成本估算(美元)', [
|
|
44
70
|
`${p}cost_usd_total ${state.costUsd}`,
|
|
71
|
+
...labelCost.map((s) => `${p}cost_usd_total${s.text} ${s.value}`),
|
|
45
72
|
]));
|
|
46
73
|
// 基数上限的**可见性**:被折叠掉的不同键数。与 `snapshot()` 的同名字段一一对应 ——
|
|
47
74
|
// 此前只有 snapshot() 有、render() 没有,于是「按文档把 metricsSink 接到 /metrics」的部署
|
|
@@ -52,6 +79,14 @@ export function renderPrometheus(state, p) {
|
|
|
52
79
|
`${p}dropped_keys{kind="capability"} ${state.capBudget.dropped}`,
|
|
53
80
|
`${p}dropped_keys{kind="model"} ${state.modelBudget.dropped}`,
|
|
54
81
|
`${p}dropped_keys{kind="score"} ${state.scoreBudget.dropped}`,
|
|
82
|
+
// 归因标签每键一行(kind 取 `label:<key>`,与能力标签的 `kind:name` 同款拼法);
|
|
83
|
+
// 未配置 labelKeys 时一行都没有(不是 0 —— 那个维度压根没开)
|
|
84
|
+
...[...state.labelBudgets.entries()].map(([key, budget]) => `${p}dropped_keys{kind="label:${key}"} ${budget.dropped}`),
|
|
85
|
+
// 组合数有自己的上限(`maxLabelCombos`):每键折叠数是**看不见**叉乘爆炸的
|
|
86
|
+
// (2026-09-27 ⑧),所以这一行与上面每键那几行并存、单列一个 kind
|
|
87
|
+
...(state.labelBudgets.size > 0
|
|
88
|
+
? [`${p}dropped_keys{kind="label:combos"} ${state.comboBudget.dropped}`]
|
|
89
|
+
: []),
|
|
55
90
|
]));
|
|
56
91
|
// 时长:histogram(可跨实例聚合)+ 窗口内精确分位(单实例好读),两种口径并存。
|
|
57
92
|
// 分位 gauge 必须用另一个名字 `*_last` —— 同名指标只允许一种 TYPE,
|
|
@@ -103,6 +138,7 @@ export function renderPrometheus(state, p) {
|
|
|
103
138
|
const modelTokens = [];
|
|
104
139
|
const modelCosts = [];
|
|
105
140
|
const unpriced = [];
|
|
141
|
+
const usageMissing = [];
|
|
106
142
|
const durations = [];
|
|
107
143
|
const durationQuantiles = [];
|
|
108
144
|
for (const model of modelNames) {
|
|
@@ -114,6 +150,8 @@ export function renderPrometheus(state, p) {
|
|
|
114
150
|
modelCosts.push(`${p}model_cost_usd_total${l} ${acc.costUsd}`);
|
|
115
151
|
if (acc.unpricedTurns > 0)
|
|
116
152
|
unpriced.push(`${p}model_unpriced_turns_total${l} ${acc.unpricedTurns}`);
|
|
153
|
+
if (acc.usageMissingTurns > 0)
|
|
154
|
+
usageMissing.push(`${p}model_usage_missing_turns_total${l} ${acc.usageMissingTurns}`);
|
|
117
155
|
durations.push(...histogramSamples(`${p}model_duration_ms`, acc.stat, l));
|
|
118
156
|
durationQuantiles.push(`${p}model_duration_ms_last{model="${mv}",quantile="0.5"} ${acc.stat.percentile(0.5)}`, `${p}model_duration_ms_last{model="${mv}",quantile="0.95"} ${acc.stat.percentile(0.95)}`);
|
|
119
157
|
}
|
|
@@ -123,6 +161,11 @@ export function renderPrometheus(state, p) {
|
|
|
123
161
|
if (unpriced.length > 0) {
|
|
124
162
|
out.push(family(`${p}model_unpriced_turns_total`, 'counter', '算不出成本的 turn 数(模型不在价格表内)', unpriced));
|
|
125
163
|
}
|
|
164
|
+
// S2:上游没回报 usage ⇒ 成本看起来是 0(`maxCostUsd` 静默失效)。这条与 unpriced
|
|
165
|
+
// **分开**发:两者都让成本像 0,但一个是换模型、一个是查端点/网关。
|
|
166
|
+
if (usageMissing.length > 0) {
|
|
167
|
+
out.push(family(`${p}model_usage_missing_turns_total`, 'counter', '上游未回报 usage 的 turn 数(成本会看起来是 0,护栏因此不可用)', usageMissing));
|
|
168
|
+
}
|
|
126
169
|
out.push(family(`${p}model_duration_ms`, 'histogram', '模型往返耗时(毫秒)', durations));
|
|
127
170
|
out.push(family(`${p}model_duration_ms_last`, 'gauge', '模型往返耗时分位(窗口内精确值)', durationQuantiles));
|
|
128
171
|
}
|
|
@@ -142,4 +185,38 @@ export function renderPrometheus(state, p) {
|
|
|
142
185
|
}
|
|
143
186
|
return out.join('');
|
|
144
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* **OpenMetrics 文本渲染**(`application/openmetrics-text`)—— exemplars 的出口。
|
|
190
|
+
*
|
|
191
|
+
* Prometheus 原文格式(0.0.4)**不支持** exemplar(样本行尾 `# {…}` 那段语法只有
|
|
192
|
+
* OpenMetrics 有),所以要「指标尖峰 → 那条 trace」就必须换这一个格式。
|
|
193
|
+
*
|
|
194
|
+
* 实现 = `renderPrometheus` 的输出 + 两处样本行尾追加 exemplar + `# EOF` 收尾,
|
|
195
|
+
* 其余内容**逐字节同源**(两条输出共用同一份渲染,永远不会漂)。三个编辑点:
|
|
196
|
+
* - `runs_failed_total` 样本行尾挂最近一次失败 run(counter 的 exemplar 值 = 该次增量 1);
|
|
197
|
+
* - `run_duration_ms` 的 exemplar 挂在**最慢那次落入的 bucket** 行上
|
|
198
|
+
* (OpenMetrics 规定 histogram 的 exemplar 必须挂 bucket,不能挂 sum/count);
|
|
199
|
+
* - 文件末尾 `# EOF`(OpenMetrics 的强制收尾)。
|
|
200
|
+
* trace_id 走 `wireTraceId` 投影(hex,Tempo/Grafana 的 exemplar 跳转按它查)。
|
|
201
|
+
*/
|
|
202
|
+
export function renderOpenMetrics(state, p) {
|
|
203
|
+
let text = renderPrometheus(state, p);
|
|
204
|
+
const failed = state.failedExemplar;
|
|
205
|
+
if (failed) {
|
|
206
|
+
const plain = `${p}runs_failed_total ${state.failed}\n`;
|
|
207
|
+
// renderPrometheus 恒定输出这行(failed ≥ 1 是 failedExemplar 存在的前提)
|
|
208
|
+
text = text.replace(plain, `${plain.trimEnd()} # {trace_id="${wireTraceId(failed.traceId)}"} 1 ${failed.at / 1000}\n`);
|
|
209
|
+
}
|
|
210
|
+
const slowest = state.slowestExemplar;
|
|
211
|
+
if (slowest) {
|
|
212
|
+
const le = state.runStat.boundsList.find((b) => slowest.durationMs <= b);
|
|
213
|
+
const head = `${p}run_duration_ms_bucket{le="${le === undefined ? '+Inf' : le}"} `;
|
|
214
|
+
const i = text.indexOf(head);
|
|
215
|
+
if (i >= 0) {
|
|
216
|
+
const eol = text.indexOf('\n', i);
|
|
217
|
+
text = `${text.slice(0, eol)} # {trace_id="${wireTraceId(slowest.traceId)}"} ${slowest.durationMs} ${slowest.at / 1000}${text.slice(eol)}`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return `${text}# EOF\n`;
|
|
221
|
+
}
|
|
145
222
|
//# sourceMappingURL=metrics-render.js.map
|