@migor/agentia 0.10.4 → 0.10.6
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 +281 -1
- package/README.en.md +1 -1
- package/README.md +2 -2
- package/dist/AGENTS.md +93 -11
- package/dist/container/container.js +3 -0
- package/dist/container/container.js.map +1 -1
- package/dist/core/abort.js +6 -1
- package/dist/core/abort.js.map +1 -1
- package/dist/core/json.js +4 -0
- package/dist/core/json.js.map +1 -1
- package/dist/core/limits.d.ts +13 -5
- package/dist/core/limits.js +14 -5
- package/dist/core/limits.js.map +1 -1
- package/dist/core/sse.d.ts +0 -13
- package/dist/core/sse.js +28 -2
- package/dist/core/sse.js.map +1 -1
- package/dist/core/timeout.d.ts +8 -0
- package/dist/core/timeout.js +19 -1
- package/dist/core/timeout.js.map +1 -1
- package/dist/core/tool.d.ts +18 -0
- package/dist/core/trace.d.ts +9 -0
- package/dist/core/trace.js +21 -0
- package/dist/core/trace.js.map +1 -1
- package/dist/engine/forwarded.d.ts +3 -1
- package/dist/engine/forwarded.js +5 -0
- package/dist/engine/forwarded.js.map +1 -1
- package/dist/engine/loop.d.ts +5 -1
- package/dist/engine/loop.js +45 -12
- package/dist/engine/loop.js.map +1 -1
- package/dist/engine/mcp-server.d.ts +17 -1
- package/dist/engine/mcp-server.js +36 -2
- package/dist/engine/mcp-server.js.map +1 -1
- package/dist/engine/policy.js +5 -1
- package/dist/engine/policy.js.map +1 -1
- package/dist/engine/replay.js +63 -1
- package/dist/engine/replay.js.map +1 -1
- package/dist/engine/run-config.d.ts +6 -0
- package/dist/engine/run-config.js +18 -6
- package/dist/engine/run-config.js.map +1 -1
- package/dist/engine/spec.d.ts +11 -1
- package/dist/engine/spec.js.map +1 -1
- package/dist/engine/stop-reason.js +19 -1
- package/dist/engine/stop-reason.js.map +1 -1
- package/dist/engine/tool-context.d.ts +3 -1
- package/dist/engine/tool-context.js +3 -1
- package/dist/engine/tool-context.js.map +1 -1
- package/dist/engine/tool-events.d.ts +7 -2
- package/dist/engine/tool-events.js +24 -3
- package/dist/engine/tool-events.js.map +1 -1
- package/dist/engine/tracer.js +10 -3
- package/dist/engine/tracer.js.map +1 -1
- package/dist/engine/turn.d.ts +9 -13
- package/dist/engine/turn.js +96 -10
- package/dist/engine/turn.js.map +1 -1
- package/dist/engine/types.d.ts +19 -2
- package/dist/engine/types.js +1 -0
- package/dist/engine/types.js.map +1 -1
- package/dist/engine/usage.js +12 -4
- package/dist/engine/usage.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/anthropic.d.ts +9 -1
- package/dist/integrations/anthropic.js +42 -7
- package/dist/integrations/anthropic.js.map +1 -1
- package/dist/integrations/file-sink.d.ts +1 -0
- package/dist/integrations/file-sink.js +35 -32
- package/dist/integrations/file-sink.js.map +1 -1
- package/dist/integrations/mcp-http.js +33 -9
- package/dist/integrations/mcp-http.js.map +1 -1
- package/dist/integrations/mcp-protocol.js +33 -16
- package/dist/integrations/mcp-protocol.js.map +1 -1
- package/dist/integrations/metrics-otlp.js +4 -0
- package/dist/integrations/metrics-otlp.js.map +1 -1
- package/dist/integrations/metrics.js +17 -2
- package/dist/integrations/metrics.js.map +1 -1
- package/dist/integrations/openai.d.ts +6 -1
- package/dist/integrations/openai.js +45 -8
- package/dist/integrations/openai.js.map +1 -1
- package/dist/integrations/otlp.js +6 -0
- package/dist/integrations/otlp.js.map +1 -1
- package/dist/runtime/memory.d.ts +0 -8
- package/dist/runtime/memory.js +24 -2
- package/dist/runtime/memory.js.map +1 -1
- package/dist/runtime/run.js +34 -9
- package/dist/runtime/run.js.map +1 -1
- package/dist/store/fsStore.d.ts +2 -0
- package/dist/store/fsStore.js +38 -5
- package/dist/store/fsStore.js.map +1 -1
- package/dist/store/record.d.ts +40 -0
- package/dist/store/record.js +72 -0
- package/dist/store/record.js.map +1 -1
- package/dist/store/redisStore.js +15 -4
- package/dist/store/redisStore.js.map +1 -1
- package/dist/store/sqliteStore.js +39 -14
- package/dist/store/sqliteStore.js.map +1 -1
- package/dist/store/store.d.ts +6 -1
- package/dist/store/store.js +10 -4
- package/dist/store/store.js.map +1 -1
- package/dist/toolkit/capability-loop.d.ts +92 -0
- package/dist/toolkit/capability-loop.js +81 -0
- package/dist/toolkit/capability-loop.js.map +1 -0
- package/dist/toolkit/manifest.d.ts +21 -0
- package/dist/toolkit/manifest.js +38 -0
- package/dist/toolkit/manifest.js.map +1 -0
- package/dist/toolkit/module.d.ts +5 -0
- package/dist/toolkit/module.js +9 -0
- package/dist/toolkit/module.js.map +1 -1
- package/dist/toolkit/prompt.d.ts +3 -1
- package/dist/toolkit/prompt.js +22 -3
- package/dist/toolkit/prompt.js.map +1 -1
- package/dist/toolkit/skill.d.ts +3 -1
- package/dist/toolkit/skill.js +2 -0
- package/dist/toolkit/skill.js.map +1 -1
- package/dist/toolkit/subagent.d.ts +3 -1
- package/dist/toolkit/subagent.js +2 -0
- package/dist/toolkit/subagent.js.map +1 -1
- package/dist/toolkit/tool.d.ts +3 -1
- package/dist/toolkit/tool.js +2 -0
- package/dist/toolkit/tool.js.map +1 -1
- package/dist/transport/approval-policy.d.ts +1 -1
- package/dist/transport/approval-policy.js +18 -3
- package/dist/transport/approval-policy.js.map +1 -1
- package/dist/transport/approval-supervisor.d.ts +15 -3
- package/dist/transport/approval-supervisor.js +37 -11
- package/dist/transport/approval-supervisor.js.map +1 -1
- package/dist/transport/async.d.ts +3 -4
- package/dist/transport/async.js +157 -30
- package/dist/transport/async.js.map +1 -1
- package/dist/transport/drain-gate.js +13 -1
- package/dist/transport/drain-gate.js.map +1 -1
- package/dist/transport/http-endpoints.d.ts +13 -0
- package/dist/transport/http-endpoints.js +108 -28
- package/dist/transport/http-endpoints.js.map +1 -1
- package/dist/transport/http-shapes.d.ts +26 -3
- package/dist/transport/http-shapes.js +12 -2
- package/dist/transport/http-shapes.js.map +1 -1
- package/dist/transport/http.d.ts +46 -2
- package/dist/transport/http.js +43 -18
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/resume-scanner.d.ts +3 -0
- package/dist/transport/resume-scanner.js +10 -1
- package/dist/transport/resume-scanner.js.map +1 -1
- package/dist/transport/run-call-options.js +46 -1
- package/dist/transport/run-call-options.js.map +1 -1
- package/dist/transport/run-options.d.ts +98 -0
- package/dist/transport/run-options.js +121 -0
- package/dist/transport/run-options.js.map +1 -0
- package/dist/transport/run-outcome.js +21 -1
- package/dist/transport/run-outcome.js.map +1 -1
- package/dist/transport/serve.js +10 -0
- package/dist/transport/serve.js.map +1 -1
- package/dist/transport/signal-supervisor.d.ts +3 -0
- package/dist/transport/signal-supervisor.js +5 -1
- package/dist/transport/signal-supervisor.js.map +1 -1
- package/dist/transport/stream-janitor.d.ts +45 -0
- package/dist/transport/stream-janitor.js +137 -0
- package/dist/transport/stream-janitor.js.map +1 -0
- package/dist/transport/task-wake-gate.d.ts +40 -0
- package/dist/transport/task-wake-gate.js +69 -0
- package/dist/transport/task-wake-gate.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-shapes.js","sourceRoot":"","sources":["../../src/transport/http-shapes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http-shapes.js","sourceRoot":"","sources":["../../src/transport/http-shapes.ts"],"names":[],"mappings":"AA6DA,4DAA4D;AAC5D,MAAM,UAAU,UAAU,CACxB,GAGC,EACD,IAAI,GAAyB,EAAE;IAE/B,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK;QACpB,gDAAgD;QAChD,wCAAwC;QACxC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM;QACtB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU;QACjC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS;QAC/B,KAAK,EAAG,GAAG,CAAC,MAA8B,CAAC,KAAK;QAChD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACnD,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK;KACxB,CAAC;AACJ,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,cAAc,CAAC,GAAe,EAAE,IAAI,GAAyB,EAAE;IAC7E,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,GAAG,CAAC;IAC7B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;IACvF,IAAI,CAAC,GAAG,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,GAAG,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;IACvF,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC5C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,OAAO,IAAsB,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAa;IAEb,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,MAAM,CAAC,GAAG,IAAoD,CAAC;IAC/D,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;QAClF,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACnF,MAAM,SAAS,GAAsB,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QACtE,MAAM,CAAC,GAAG,CAA6C,CAAC;QACxD,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACtD,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QAC7E,SAAS,CAAC,EAAE,CAAC,GAAG;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,SAAS;QACT,GAAG,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3E,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa;IAC1C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;IACjF,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACpD,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,EAAE,CAAC;QACnF,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC"}
|
package/dist/transport/http.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
import { AsyncRunner } from './async.js';
|
|
3
3
|
import type { AppCallable } from './async.js';
|
|
4
|
+
import type { ResolveRunOptionsHook } from './run-options.js';
|
|
4
5
|
/**
|
|
5
6
|
* Agentia —— HTTP 宿主(spec §6.6:换宿主不换语义,roadmap R3)。
|
|
6
7
|
*
|
|
@@ -32,6 +33,15 @@ export type { RunHttpResponse, TaskSubmitBody } from './http-shapes.js';
|
|
|
32
33
|
* 与上面两个形状类型同一个理由(`src/index.ts` 一行未改,公开面逐字不变)。
|
|
33
34
|
*/
|
|
34
35
|
export type { HealthResponse } from './http-endpoints.js';
|
|
36
|
+
export type HttpResponseMode = 'full' | 'public';
|
|
37
|
+
export type TaskControlAction = 'poll' | 'approve' | 'cancel' | 'event' | 'stream';
|
|
38
|
+
export type TaskAuthorizationHook = (req: IncomingMessage, info: {
|
|
39
|
+
action: TaskControlAction;
|
|
40
|
+
taskId: string;
|
|
41
|
+
task: import('../store/store.js').TaskRecord;
|
|
42
|
+
principal: unknown;
|
|
43
|
+
}) => unknown | Promise<unknown>;
|
|
44
|
+
export type ApprovalActorHook = (req: IncomingMessage, principal: unknown) => string | undefined | Promise<string | undefined>;
|
|
35
45
|
export interface HttpHandlerOptions {
|
|
36
46
|
/** 异步任务宿主;缺省 new AsyncRunner(app)(InMemoryTaskStore) */
|
|
37
47
|
runner?: AsyncRunner;
|
|
@@ -61,8 +71,10 @@ export interface HttpHandlerOptions {
|
|
|
61
71
|
/**
|
|
62
72
|
* 入口鉴权钩子。请求进入时调用,**除 /healthz 与 /metrics 外所有路径**都过它,且**在读 body 之前**
|
|
63
73
|
* (未通过就不接收 body,省资源)。/metrics 与 /healthz 同档不鉴权(见 `metrics` 选项)。
|
|
64
|
-
* -
|
|
65
|
-
*
|
|
74
|
+
* - 正常返回 → 视为通过。**返回值不再丢弃**:它作为 `principal` 交给
|
|
75
|
+
* `resolveRunOptions(req, { route, principal })`(2026-11-04 起;此前注释写的是
|
|
76
|
+
* 「返回值框架不转交,请存在钩子自己的闭包里」—— 那条路走不通:闭包与 run 之间
|
|
77
|
+
* 没有任何关联手段,runId 是 run 开始后才有的。身份入 run 的唯一可信通道就是这一条)。
|
|
66
78
|
* - 抛出 `HttpException` → 按其 `status` / `body` 回响应(想回 403 就抛 `status: 403`);
|
|
67
79
|
* - 抛出其它错误 → 回 401 `{ error: '未通过鉴权' }`,原文只进服务端日志
|
|
68
80
|
* (与 `exposeErrors` 同理:不把内部拓扑回给未鉴权的调用方)。
|
|
@@ -72,6 +84,38 @@ export interface HttpHandlerOptions {
|
|
|
72
84
|
* 而鉴权要拦的是 **run 入口**,且必须早于 body 读取。
|
|
73
85
|
*/
|
|
74
86
|
authenticate?: (req: IncomingMessage) => unknown | Promise<unknown>;
|
|
87
|
+
/**
|
|
88
|
+
* 按请求给 run 选项(**身份 / 租户 / 配额封顶的唯一可信通道**)。与 `authenticate` 配对使用:
|
|
89
|
+
* 后者的返回值会作为 `principal` 传进来。
|
|
90
|
+
*
|
|
91
|
+
* 为什么需要它:`POST /tasks` 的 `body.options` 此前整体透传给引擎 —— 任何能调它的人都能
|
|
92
|
+
* 自填 `blackboard: { tenant: '别人的租户' }`(而 usage-guide §6.6 的多租户配方正是
|
|
93
|
+
* 「用黑板存 tenant」),于是配额记到别人头上。现在客户端选项走**白名单**
|
|
94
|
+
* (见 `run-options.ts`),身份只能从这里进,且服务端值**覆盖**客户端值。
|
|
95
|
+
*
|
|
96
|
+
* 两条口径:`blackboard` 整体替换、`labels` 按键盘合并(服务端胜)、预算与客户端值
|
|
97
|
+
* 取**更严者**(上限不能由叫价方抬高)。抛 `HttpException` 按其状态码回。
|
|
98
|
+
*/
|
|
99
|
+
resolveRunOptions?: ResolveRunOptionsHook;
|
|
100
|
+
/**
|
|
101
|
+
* 任务控制面的对象级授权。`authenticate` 只回答「你是谁」,本钩子回答
|
|
102
|
+
* 「你能不能对这个 task 做这件事」。在读取审批/事件 body 之前执行;
|
|
103
|
+
* 返回 `false` 回 403,抛 `HttpException` 按其状态码回,其余异常走 500。
|
|
104
|
+
*/
|
|
105
|
+
authorizeTask?: TaskAuthorizationHook;
|
|
106
|
+
/**
|
|
107
|
+
* 从认证结果生成可信审批人。配置后其返回值覆盖审批 body 的 `decidedBy`;
|
|
108
|
+
* 返回 `undefined` 表示不记审批人。空字符串是宿主配置错误,按 500 处理。
|
|
109
|
+
*/
|
|
110
|
+
resolveApprovalActor?: ApprovalActorHook;
|
|
111
|
+
/**
|
|
112
|
+
* HTTP 响应暴露面。`full`(缺省)保留历史形状;`public` 去掉 run/task 响应里的
|
|
113
|
+
* trace、任务消息、挂起历史和内部 ownerId,并默认关闭 SSE 的 trace.event 帧。
|
|
114
|
+
* 它只影响 HTTP 输出,不影响 TaskStore 与 TraceSink 的完整记录。
|
|
115
|
+
*/
|
|
116
|
+
responseMode?: HttpResponseMode;
|
|
117
|
+
/** 是否开放 `/run` 与 `/tasks/:id/stream` 的 trace 事件;缺省 = responseMode 为 full */
|
|
118
|
+
exposeTraceEvents?: boolean;
|
|
75
119
|
/**
|
|
76
120
|
* 指标出口(G4):提供后 `GET /metrics` 输出其 `render()` 的文本。
|
|
77
121
|
* 通常直接传 `metricsSink()`(它有 `render()`)。
|
package/dist/transport/http.js
CHANGED
|
@@ -86,8 +86,16 @@ export function createHttpHandler(app, opts = {}) {
|
|
|
86
86
|
throw new Error(`maxConcurrentRuns 必须为正数(${zeroClauseOf('HttpHandlerOptions.maxConcurrentRuns')}),收到 ${opts.maxConcurrentRuns}`);
|
|
87
87
|
}
|
|
88
88
|
const exposeErrors = opts.exposeErrors ?? false;
|
|
89
|
+
const responseMode = opts.responseMode ?? 'full';
|
|
90
|
+
if (responseMode !== 'full' && responseMode !== 'public') {
|
|
91
|
+
throw new TypeError(`responseMode 只接受 'full' | 'public',收到 ${String(opts.responseMode)}`);
|
|
92
|
+
}
|
|
93
|
+
const exposeTraceEvents = opts.exposeTraceEvents ?? responseMode === 'full';
|
|
89
94
|
const sseMaxBufferedBytes = opts.sseMaxBufferedBytes;
|
|
90
95
|
const authenticate = opts.authenticate;
|
|
96
|
+
const resolveRunOptions = opts.resolveRunOptions;
|
|
97
|
+
const authorizeTask = opts.authorizeTask;
|
|
98
|
+
const resolveApprovalActor = opts.resolveApprovalActor;
|
|
91
99
|
const metrics = opts.metrics;
|
|
92
100
|
const startedAt = Date.now();
|
|
93
101
|
/**
|
|
@@ -169,41 +177,58 @@ export function createHttpHandler(app, opts = {}) {
|
|
|
169
177
|
// 顺序陷阱写在那边的头注里,最要命的一条:免鉴权组(/healthz、/metrics)
|
|
170
178
|
// 连同它们自己的 405 都在鉴权**之前**回,其余一律**先鉴权再判方法/路径**。
|
|
171
179
|
const route = routeRequest(pathname, method, metrics !== undefined);
|
|
172
|
-
// 一个请求一份 ctx:`state` 按引用共享,其余是构造期已解析好的值(不再有 `?? 缺省`)
|
|
173
|
-
const ctx = {
|
|
174
|
-
req,
|
|
175
|
-
res,
|
|
176
|
-
pathname,
|
|
177
|
-
method,
|
|
178
|
-
route,
|
|
179
|
-
app,
|
|
180
|
-
runner,
|
|
181
|
-
state,
|
|
182
|
-
maxBodyBytes,
|
|
183
|
-
maxConcurrentRuns,
|
|
184
|
-
sseMaxBufferedBytes,
|
|
185
|
-
exposeErrors,
|
|
186
|
-
startedAt,
|
|
187
|
-
metrics,
|
|
188
|
-
};
|
|
189
180
|
try {
|
|
190
181
|
// 鉴权缝:必须在读 body 之前(未通过即断开,body 一个字节都不收)。
|
|
191
182
|
// 写成**否定条件**(「不是免鉴权组才过闸」)而不是「先 if (免鉴权组) { 一大段应答 }」:
|
|
192
183
|
// 这样 `handler` 里只剩「谁被豁免」这一处判据可读,而被豁免者**回什么**在端点表里 ——
|
|
193
184
|
// 豁免名单只有一份真源(`http-route.ts` 的 `isPreAuthRoute`)。
|
|
185
|
+
let principal;
|
|
194
186
|
if (!isPreAuthRoute(route) && authenticate) {
|
|
195
187
|
try {
|
|
196
|
-
|
|
188
|
+
// 返回值**不再是丢弃的**:它就是 `principal`,交给 `resolveRunOptions`。
|
|
189
|
+
// 身份 → run 只该有这一条路(见 `HttpHandlerOptions.authenticate` 的注释)。
|
|
190
|
+
principal = await authenticate(req);
|
|
197
191
|
}
|
|
198
192
|
catch (e) {
|
|
199
193
|
sendUnauthorized(req, res, e, exposeErrors);
|
|
200
194
|
return;
|
|
201
195
|
}
|
|
202
196
|
}
|
|
197
|
+
// 一个请求一份 ctx:`state` 按引用共享,其余是构造期已解析好的值(不再有 `?? 缺省`)。
|
|
198
|
+
// 放在鉴权之后建,是因为 `principal` 是 ctx 的字段(身份随请求走,不存闭包)。
|
|
199
|
+
const ctx = {
|
|
200
|
+
req,
|
|
201
|
+
res,
|
|
202
|
+
pathname,
|
|
203
|
+
method,
|
|
204
|
+
route,
|
|
205
|
+
app,
|
|
206
|
+
runner,
|
|
207
|
+
state,
|
|
208
|
+
maxBodyBytes,
|
|
209
|
+
maxConcurrentRuns,
|
|
210
|
+
sseMaxBufferedBytes,
|
|
211
|
+
exposeErrors,
|
|
212
|
+
startedAt,
|
|
213
|
+
metrics,
|
|
214
|
+
principal,
|
|
215
|
+
resolveRunOptions,
|
|
216
|
+
authorizeTask,
|
|
217
|
+
resolveApprovalActor,
|
|
218
|
+
responseMode,
|
|
219
|
+
exposeTraceEvents,
|
|
220
|
+
};
|
|
203
221
|
// 至此路由已定、鉴权已过 —— 剩下的全是「走到这条路上做什么」,在 http-endpoints.ts
|
|
204
222
|
await handleRoute(route, ctx);
|
|
205
223
|
}
|
|
206
224
|
catch (e) {
|
|
225
|
+
// 端点(或 `resolveRunOptions` 钩子)抛 `HttpException` ⇒ 它自带状态码与响应体。
|
|
226
|
+
// 认领点刻意放在**宿主**这一层:端点模块不 import 宿主的值(依赖方向单向,
|
|
227
|
+
// 见 http-endpoints.ts 文件头),而钩子的错误语义属于宿主契约。
|
|
228
|
+
if (e instanceof HttpException) {
|
|
229
|
+
sendJson(res, e.status, e.body);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
207
232
|
sendInternalError(res, e, exposeErrors);
|
|
208
233
|
}
|
|
209
234
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TaskRecord, TaskStore } from '../store/store.js';
|
|
2
2
|
import type { ApprovalSupervisor } from './approval-supervisor.js';
|
|
3
|
+
import { TaskWakeGate } from './task-wake-gate.js';
|
|
3
4
|
/** resumePending 的启动扫描选项 */
|
|
4
5
|
export interface ResumePendingOptions {
|
|
5
6
|
/**
|
|
@@ -29,6 +30,8 @@ export interface ResumeScannerDeps {
|
|
|
29
30
|
approvals: ApprovalSupervisor;
|
|
30
31
|
/** 派发入口(`AsyncRunner.#dispatch`:停机闸 + 唯一派发点 + 停机窗口里的一次告警) */
|
|
31
32
|
dispatch(rec: TaskRecord): void;
|
|
33
|
+
/** 跨唤醒路径的 per-task 互斥闸(2026-11-07 深评 P1,与 approve / signalTask 共用) */
|
|
34
|
+
wakeGate?: TaskWakeGate;
|
|
32
35
|
/** 停机闸读数(`wakeDue` 的配套 5:drain 之后不唤醒,见 `drain-gate.ts`) */
|
|
33
36
|
isDraining(): boolean;
|
|
34
37
|
/**
|
|
@@ -25,6 +25,7 @@ import { isThenable } from '../store/store.js';
|
|
|
25
25
|
import { timerDue } from './wake-policy.js';
|
|
26
26
|
import { resumeSkipReason } from './resume-policy.js';
|
|
27
27
|
import { ownerAlive } from './owner-liveness.js';
|
|
28
|
+
import { TaskWakeGate } from './task-wake-gate.js';
|
|
28
29
|
export class ResumeScanner {
|
|
29
30
|
/**
|
|
30
31
|
* 在飞的 `resumePending`(重入闸,见 `resumePending` 的注释)。
|
|
@@ -34,8 +35,11 @@ export class ResumeScanner {
|
|
|
34
35
|
/** 在飞的到期唤醒(同一任务的重入闸,理由与审批那条同款 —— 见 `approval-supervisor.ts` 的 `#inflight`:两条路径都「落库 + 派发」)。 */
|
|
35
36
|
#inflightWakes = new Map();
|
|
36
37
|
#deps;
|
|
38
|
+
/** 共享闸;单测可省略(省略时本件自建一把,跨路径互斥只在 AsyncRunner 注入时生效) */
|
|
39
|
+
#wakeGate;
|
|
37
40
|
constructor(deps) {
|
|
38
41
|
this.#deps = deps;
|
|
42
|
+
this.#wakeGate = deps.wakeGate ?? new TaskWakeGate();
|
|
39
43
|
}
|
|
40
44
|
resumePending(opts = {}) {
|
|
41
45
|
// 重入闸:**并发**调用共享同一次扫描的结果,而不是各自再扫一遍。
|
|
@@ -102,7 +106,12 @@ export class ResumeScanner {
|
|
|
102
106
|
return false;
|
|
103
107
|
if (this.#inflightWakes.has(rec.taskId))
|
|
104
108
|
return false;
|
|
105
|
-
|
|
109
|
+
// 跨路径互斥(2026-11-07 深评 P1):approve / signalTask 在飞 ⇒ 跳过本轮。
|
|
110
|
+
if (this.#wakeGate.busy(rec.taskId))
|
|
111
|
+
return false;
|
|
112
|
+
const run = this.#wakeGate
|
|
113
|
+
.run(rec.taskId, () => this.#wakeDueInner(rec, now))
|
|
114
|
+
.finally(() => {
|
|
106
115
|
this.#inflightWakes.delete(rec.taskId);
|
|
107
116
|
});
|
|
108
117
|
this.#inflightWakes.set(rec.taskId, run);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resume-scanner.js","sourceRoot":"","sources":["../../src/transport/resume-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"resume-scanner.js","sourceRoot":"","sources":["../../src/transport/resume-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DROPPED_REFS_KEY, droppedRuntimeRefsOf } from '../store/record.js';
|
|
1
2
|
/**
|
|
2
3
|
* 装配交给 `app.run(messages, opts)` 的选项。
|
|
3
4
|
*
|
|
@@ -7,11 +8,23 @@
|
|
|
7
8
|
*/
|
|
8
9
|
export function buildRunCallOptions(input) {
|
|
9
10
|
const { rec, isResume, sessionStore, client, signal, bridgeTraceEvents } = input;
|
|
11
|
+
// 落库时被剥掉的进程内引用(2026-11-09 深评 P1):标记只出现在「从 store 读回」的记录上,
|
|
12
|
+
// 因此这里命中就一定是跨进程/重启的那一段。**不论是不是续跑段都要说**:重启后认领的
|
|
13
|
+
// `queued` 任务同样会丢 per-task client(`isResume` 的判据只看 approvals / suspendedSince,
|
|
14
|
+
// 那种记录两者皆无 ⇒ 会被判成首段)。
|
|
15
|
+
const dropped = droppedRuntimeRefsOf(rec.spec.options);
|
|
16
|
+
// 三个都没命中就别出声:`serializeTaskRecord` 只在真剥了东西时写这个键,但手改过的记录
|
|
17
|
+
// 或将来换了键的形状都可能读到一个空清单 —— 那时打一条「被剥离:。」的日志还不如不打。
|
|
18
|
+
if (dropped !== undefined && (dropped.client || dropped.tools || dropped.fallbacks)) {
|
|
19
|
+
warnDroppedRuntimeRefs(rec.taskId, dropped);
|
|
20
|
+
}
|
|
10
21
|
// sessionId 在本层**已被消费**(下面换成 session 注入;没配 sessionStore 的在 submit /
|
|
11
22
|
// 派发处已响亮失败),**不随选项透传**:续跑段刻意不注入 session(见下),若让它原样
|
|
12
23
|
// 进 app.run,会撞上那边「程序内直传 sessionId 不生效」的告警 —— 那是给外部调用方的
|
|
13
24
|
// 出声闸(toolkit/module.ts),内部路径不该踩。
|
|
14
25
|
const { sessionId, ...restOptions } = rec.spec.options ?? {};
|
|
26
|
+
// 剥离标记是本层的一次性提示,不进引擎(它不是 `RunInvocationOptions` 的字段)
|
|
27
|
+
delete restOptions[DROPPED_REFS_KEY];
|
|
15
28
|
return {
|
|
16
29
|
...restOptions,
|
|
17
30
|
// HITL 恢复段**不注入 session**(2026-09-20,spec §10 当日条):恢复段的
|
|
@@ -31,8 +44,13 @@ export function buildRunCallOptions(input) {
|
|
|
31
44
|
: client !== undefined
|
|
32
45
|
? { client }
|
|
33
46
|
: {}),
|
|
34
|
-
//
|
|
47
|
+
// 恢复段预算按整任务累计:此前各段的 trace 已在挂起/终态出口折进 usageTotal。
|
|
48
|
+
...(isResume && rec.usageTotal !== undefined ? { usageOffset: rec.usageTotal } : {}),
|
|
49
|
+
// HITL 恢复段:审批决定随任务落库,重跑时原样进引擎(进程重启不丢)。
|
|
50
|
+
// `approvalEpoch` 取**本次挂起**的时刻:旧挂起留下的决定(requestedAt 不同)不会被
|
|
51
|
+
// 新一次同名 tool_use 复用(2026-11-07 深评)。
|
|
35
52
|
...(rec.approvals !== undefined ? { approvals: rec.approvals } : {}),
|
|
53
|
+
...(isResume && rec.suspendedSince !== undefined ? { approvalEpoch: rec.suspendedSince } : {}),
|
|
36
54
|
// 事件投入口(2026-09-28 ref-run-event-input):挂起期间投递的事件随记录进引擎,由它在
|
|
37
55
|
// 未决 tool_use 解决之后注入消息流(为什么不能由宿主直接追加进
|
|
38
56
|
// spec.messages 的末尾:见 signalTask 与 engine/loop.ts 的注入点纪律)
|
|
@@ -69,8 +87,35 @@ export function adoptSucceededOutcome(rec, existing) {
|
|
|
69
87
|
rec.status = 'succeeded';
|
|
70
88
|
rec.runId = existing.runId;
|
|
71
89
|
rec.result = existing.result;
|
|
90
|
+
rec.usageTotal = existing.usageTotal;
|
|
72
91
|
rec.error = existing.error;
|
|
73
92
|
rec.finishedAt = Date.now();
|
|
74
93
|
return true;
|
|
75
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* 「落库时剥掉了可执行选项」的一次性告警(2026-11-09 深评 P1)。
|
|
97
|
+
*
|
|
98
|
+
* 为什么按 taskId 去重:同一条带标记的记录会在每条唤醒路径上被 `store.get` 读回
|
|
99
|
+
* (approve / signalTask / 到期唤醒 / poll),逐次打会把日志刷满,而这件事对同一个任务
|
|
100
|
+
* 只说一次就够。**上限 1000 后整体清空**:有界比「记过就永远记着」重要 —— 漏一次重复
|
|
101
|
+
* 告警远好于一个随任务数无界增长的 Set。
|
|
102
|
+
*/
|
|
103
|
+
const warnedDroppedRefs = new Set();
|
|
104
|
+
function warnDroppedRuntimeRefs(taskId, dropped) {
|
|
105
|
+
if (warnedDroppedRefs.has(taskId))
|
|
106
|
+
return;
|
|
107
|
+
if (warnedDroppedRefs.size >= 1000)
|
|
108
|
+
warnedDroppedRefs.clear();
|
|
109
|
+
warnedDroppedRefs.add(taskId);
|
|
110
|
+
const what = [];
|
|
111
|
+
if (dropped.client)
|
|
112
|
+
what.push('任务级 client(本段已退回 runner 级 / 默认 client)');
|
|
113
|
+
if (dropped.tools)
|
|
114
|
+
what.push('任务级 tools 菜单(本段已退回装配菜单 app.tools)');
|
|
115
|
+
if (dropped.fallbacks)
|
|
116
|
+
what.push('fallback 环的 client(只保留了 model)');
|
|
117
|
+
console.warn(`[agentia] task ${taskId} 的可执行选项在落库时被剥离:${what.join(';')}。` +
|
|
118
|
+
'这些是进程内对象,不能跨重启 —— 要让同一任务跨重启仍用同一份配置,' +
|
|
119
|
+
'请把它们配在 AsyncRunner 或装配层(对齐「client 由 runner/应用级配置兜住」的口径)。');
|
|
120
|
+
}
|
|
76
121
|
//# sourceMappingURL=run-call-options.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-call-options.js","sourceRoot":"","sources":["../../src/transport/run-call-options.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-call-options.js","sourceRoot":"","sources":["../../src/transport/run-call-options.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
2
|
+
import type { RunInvocationOptions } from '../engine/spec.js';
|
|
3
|
+
/**
|
|
4
|
+
* Agentia —— HTTP 入口的 **run 选项可信边界**(spec §10 2026-11-04 run-options-trust-boundary)。
|
|
5
|
+
*
|
|
6
|
+
* ## 这个文件解决的两个不对称
|
|
7
|
+
*
|
|
8
|
+
* `POST /tasks` 的 body 里有一个 `options`,此前**整体透传**给 `runner.submit`(`...body.options`),
|
|
9
|
+
* 而 `options` 是引擎的**全部旋钮**(`RunInvocationOptions`:`blackboard` / `tools` /
|
|
10
|
+
* `fallbacks` / `maxIterations` / `priceOverrides` …)。后果不是"繁琐",是**能冒充**:
|
|
11
|
+
*
|
|
12
|
+
* - `blackboard: { tenant: '别人的租户' }` ⇒ 工具方法体里读到的就是别人的租户。
|
|
13
|
+
* usage-guide §6.6 的多租户配额配方第一步正是「用黑板存 tenant」—— 照抄即被绕过;
|
|
14
|
+
* - `tools: [...]` ⇒ 客户端能把整个工具菜单换掉;
|
|
15
|
+
* - `priceOverrides: { '<模型>': { in: 0, out: 0 } }` ⇒ 成本恒 0,`maxCostUsd` 静默失效。
|
|
16
|
+
*
|
|
17
|
+
* 另一头,`POST /run` **完全不收 options**(连 `traceContext` 都只认 header)—— 需要身份的那条
|
|
18
|
+
* 拿不到,拿得到的那条不可信。这就是那个不对称。
|
|
19
|
+
*
|
|
20
|
+
* ## 两半各自的职责
|
|
21
|
+
*
|
|
22
|
+
* | 谁 | 管什么 | 为什么 |
|
|
23
|
+
* |---|---|---|
|
|
24
|
+
* | `pickClientRunOptions` | **白名单**:客户端只能设这几个键 | 外部输入不配拥有引擎旋钮(与 `parseEventBody` 的「多一个字段即拒」同一条纪律) |
|
|
25
|
+
* | `ResolveRunOptionsHook` | **可信注入**:宿主按请求给的 `blackboard` / `labels` / 预算封顶 | 身份只能来自宿主(鉴权结果),不能来自 body |
|
|
26
|
+
*
|
|
27
|
+
* 客户端**仍然可以**设 `maxCostUsd` / `maxTotalTokens`(给自己这单设个花钱上限是合理诉求),
|
|
28
|
+
* 但合取时取**更严的那一个** —— 「上限」不能由不受信的一方放宽。这不是策略,是「上限」的
|
|
29
|
+
* 定义本身:能被叫价方抬高的上限不叫上限。
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* 客户端可自填的键(`POST /tasks` 的 `body.options`)。
|
|
33
|
+
*
|
|
34
|
+
* 加键的判据:**这个键被客户端设错时,损失只落在他自己这一单上**。
|
|
35
|
+
* - `traceContext`:链路关联(他愿意把自己的请求挂到哪棵树上是他的事);
|
|
36
|
+
* - `maxCostUsd` / `maxTotalTokens`:愿意花多少。
|
|
37
|
+
*
|
|
38
|
+
* 反例(永远不该进来):`blackboard`(身份)/ `labels`(归因与配额)/
|
|
39
|
+
* `tools`(换菜单)/ `model` + `fallbacks`(替服务端选厂商与价目)/
|
|
40
|
+
* `priceOverrides`(改账本口径 ⇒ 让预算闸失效)/ `client` / `signal`(进程内对象)。
|
|
41
|
+
*/
|
|
42
|
+
export declare const CLIENT_RUN_OPTION_KEYS: readonly ['traceContext', 'maxCostUsd', 'maxTotalTokens'];
|
|
43
|
+
export type ClientRunOptionKey = (typeof CLIENT_RUN_OPTION_KEYS)[number];
|
|
44
|
+
/**
|
|
45
|
+
* 客户端能设的那几个选项的**类型面**(`TaskSubmitBody.options`)。
|
|
46
|
+
*
|
|
47
|
+
* 它刻意是 `Pick` 出来的窄类型而不是 `RunInvocationOptions`:后者会让「写 `blackboard`
|
|
48
|
+
* 能通过编译、到运行期才 400」—— 把一次编译期就能说清的事推到线上。
|
|
49
|
+
*/
|
|
50
|
+
export type ClientRunOptions = Pick<RunInvocationOptions, ClientRunOptionKey>;
|
|
51
|
+
/**
|
|
52
|
+
* 宿主按请求注入的选项(`HttpHandlerOptions.resolveRunOptions` 的返回值)。
|
|
53
|
+
*
|
|
54
|
+
* 刻意**窄**:只放「客户端不该有能力决定、而宿主一定知道」的三样。
|
|
55
|
+
* 想调 `model` / `tools` 这类就说明它该在应用配置里,不该跟着某个用户走。
|
|
56
|
+
*/
|
|
57
|
+
export interface RunOptionOverrides {
|
|
58
|
+
/** 请求身份 / 租户等(**整体替换**客户端的同名值 —— 客户端本来就设不了它) */
|
|
59
|
+
blackboard?: RunInvocationOptions['blackboard'];
|
|
60
|
+
/** 归因标签(与客户端同名键**合并**,服务端键胜出) */
|
|
61
|
+
labels?: Record<string, string>;
|
|
62
|
+
/** 服务端封顶:与客户端值取**更严**者(防止客户端把上限抬高) */
|
|
63
|
+
maxCostUsd?: number;
|
|
64
|
+
/** 同 `maxCostUsd` */
|
|
65
|
+
maxTotalTokens?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* per-request run 选项的来源(宿主给、框架透传)。与 `authenticate` 配对:
|
|
69
|
+
* 后者的返回值作为 `principal` 传进来 —— 身份只走这一条,别去读 body。
|
|
70
|
+
*
|
|
71
|
+
* 抛 `HttpException` ⇒ 按其 `status` / `body` 回响应(校验失败想回 403 就抛它);
|
|
72
|
+
* 抛别的错误 ⇒ 走 500 路径(与其它内部异常同一个出口)。
|
|
73
|
+
*/
|
|
74
|
+
export type ResolveRunOptionsHook = (req: IncomingMessage, info: {
|
|
75
|
+
route: 'run' | 'tasks';
|
|
76
|
+
principal: unknown;
|
|
77
|
+
}) => RunOptionOverrides | undefined | Promise<RunOptionOverrides | undefined>;
|
|
78
|
+
export type ClientRunOptionsResult = {
|
|
79
|
+
ok: true;
|
|
80
|
+
options: RunInvocationOptions;
|
|
81
|
+
} | {
|
|
82
|
+
ok: false;
|
|
83
|
+
error: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* 校验并取出客户端选项。**未知键即拒**(不是静默丢弃):一个拼错的 `maxCostUSD`
|
|
87
|
+
* 被悄悄忽略,使用方会以为花销已被封顶 —— 静默降级比 400 危险。
|
|
88
|
+
*/
|
|
89
|
+
export declare function pickClientRunOptions(raw: unknown): ClientRunOptionsResult;
|
|
90
|
+
/**
|
|
91
|
+
* 把宿主注入的选项叠加到(已过白名单的)客户端选项上。
|
|
92
|
+
*
|
|
93
|
+
* 三条合并语义各不相同,各有理由:
|
|
94
|
+
* - `blackboard`:**整体替换** —— 它是身份载体,允许客户端键与宿主键"合并"就等于允许覆盖;
|
|
95
|
+
* - `labels`:**按键盘合并、宿主胜** —— 归因是多维度的,宿主只想补自己关心的维度;
|
|
96
|
+
* - 预算:**取更严者** —— 见文件头「上限的定义」。
|
|
97
|
+
*/
|
|
98
|
+
export declare function mergeRunOptions(client: RunInvocationOptions, overrides: RunOptionOverrides | undefined): RunInvocationOptions;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentia —— HTTP 入口的 **run 选项可信边界**(spec §10 2026-11-04 run-options-trust-boundary)。
|
|
3
|
+
*
|
|
4
|
+
* ## 这个文件解决的两个不对称
|
|
5
|
+
*
|
|
6
|
+
* `POST /tasks` 的 body 里有一个 `options`,此前**整体透传**给 `runner.submit`(`...body.options`),
|
|
7
|
+
* 而 `options` 是引擎的**全部旋钮**(`RunInvocationOptions`:`blackboard` / `tools` /
|
|
8
|
+
* `fallbacks` / `maxIterations` / `priceOverrides` …)。后果不是"繁琐",是**能冒充**:
|
|
9
|
+
*
|
|
10
|
+
* - `blackboard: { tenant: '别人的租户' }` ⇒ 工具方法体里读到的就是别人的租户。
|
|
11
|
+
* usage-guide §6.6 的多租户配额配方第一步正是「用黑板存 tenant」—— 照抄即被绕过;
|
|
12
|
+
* - `tools: [...]` ⇒ 客户端能把整个工具菜单换掉;
|
|
13
|
+
* - `priceOverrides: { '<模型>': { in: 0, out: 0 } }` ⇒ 成本恒 0,`maxCostUsd` 静默失效。
|
|
14
|
+
*
|
|
15
|
+
* 另一头,`POST /run` **完全不收 options**(连 `traceContext` 都只认 header)—— 需要身份的那条
|
|
16
|
+
* 拿不到,拿得到的那条不可信。这就是那个不对称。
|
|
17
|
+
*
|
|
18
|
+
* ## 两半各自的职责
|
|
19
|
+
*
|
|
20
|
+
* | 谁 | 管什么 | 为什么 |
|
|
21
|
+
* |---|---|---|
|
|
22
|
+
* | `pickClientRunOptions` | **白名单**:客户端只能设这几个键 | 外部输入不配拥有引擎旋钮(与 `parseEventBody` 的「多一个字段即拒」同一条纪律) |
|
|
23
|
+
* | `ResolveRunOptionsHook` | **可信注入**:宿主按请求给的 `blackboard` / `labels` / 预算封顶 | 身份只能来自宿主(鉴权结果),不能来自 body |
|
|
24
|
+
*
|
|
25
|
+
* 客户端**仍然可以**设 `maxCostUsd` / `maxTotalTokens`(给自己这单设个花钱上限是合理诉求),
|
|
26
|
+
* 但合取时取**更严的那一个** —— 「上限」不能由不受信的一方放宽。这不是策略,是「上限」的
|
|
27
|
+
* 定义本身:能被叫价方抬高的上限不叫上限。
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* 客户端可自填的键(`POST /tasks` 的 `body.options`)。
|
|
31
|
+
*
|
|
32
|
+
* 加键的判据:**这个键被客户端设错时,损失只落在他自己这一单上**。
|
|
33
|
+
* - `traceContext`:链路关联(他愿意把自己的请求挂到哪棵树上是他的事);
|
|
34
|
+
* - `maxCostUsd` / `maxTotalTokens`:愿意花多少。
|
|
35
|
+
*
|
|
36
|
+
* 反例(永远不该进来):`blackboard`(身份)/ `labels`(归因与配额)/
|
|
37
|
+
* `tools`(换菜单)/ `model` + `fallbacks`(替服务端选厂商与价目)/
|
|
38
|
+
* `priceOverrides`(改账本口径 ⇒ 让预算闸失效)/ `client` / `signal`(进程内对象)。
|
|
39
|
+
*/
|
|
40
|
+
export const CLIENT_RUN_OPTION_KEYS = ['traceContext', 'maxCostUsd', 'maxTotalTokens'];
|
|
41
|
+
const ALLOWED = CLIENT_RUN_OPTION_KEYS.join(' / ');
|
|
42
|
+
/** 是不是「有限、非负」的数(`NaN` / `Infinity` / 负数都不是合法上限) */
|
|
43
|
+
function isLimit(v) {
|
|
44
|
+
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 校验并取出客户端选项。**未知键即拒**(不是静默丢弃):一个拼错的 `maxCostUSD`
|
|
48
|
+
* 被悄悄忽略,使用方会以为花销已被封顶 —— 静默降级比 400 危险。
|
|
49
|
+
*/
|
|
50
|
+
export function pickClientRunOptions(raw) {
|
|
51
|
+
if (raw === undefined || raw === null)
|
|
52
|
+
return { ok: true, options: {} };
|
|
53
|
+
if (typeof raw !== 'object' || Array.isArray(raw)) {
|
|
54
|
+
return { ok: false, error: 'options 必须是对象' };
|
|
55
|
+
}
|
|
56
|
+
const o = raw;
|
|
57
|
+
for (const key of Object.keys(o)) {
|
|
58
|
+
if (!CLIENT_RUN_OPTION_KEYS.includes(key)) {
|
|
59
|
+
return { ok: false, error: `options 不接受 "${key}"(可用:${ALLOWED})` };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const options = {};
|
|
63
|
+
if (o.maxCostUsd !== undefined) {
|
|
64
|
+
if (!isLimit(o.maxCostUsd))
|
|
65
|
+
return { ok: false, error: 'options.maxCostUsd 必须是非负有限数' };
|
|
66
|
+
options.maxCostUsd = o.maxCostUsd;
|
|
67
|
+
}
|
|
68
|
+
if (o.maxTotalTokens !== undefined) {
|
|
69
|
+
if (!isLimit(o.maxTotalTokens)) {
|
|
70
|
+
return { ok: false, error: 'options.maxTotalTokens 必须是非负有限数' };
|
|
71
|
+
}
|
|
72
|
+
options.maxTotalTokens = o.maxTotalTokens;
|
|
73
|
+
}
|
|
74
|
+
if (o.traceContext !== undefined) {
|
|
75
|
+
const t = o.traceContext;
|
|
76
|
+
if (!t || typeof t !== 'object' || Array.isArray(t)) {
|
|
77
|
+
return { ok: false, error: 'options.traceContext 必须是 { traceId, spanId? }' };
|
|
78
|
+
}
|
|
79
|
+
const { traceId, spanId } = t;
|
|
80
|
+
if (typeof traceId !== 'string' || traceId === '') {
|
|
81
|
+
return { ok: false, error: 'options.traceContext.traceId 必须是非空字符串' };
|
|
82
|
+
}
|
|
83
|
+
if (spanId !== undefined && (typeof spanId !== 'string' || spanId === '')) {
|
|
84
|
+
return { ok: false, error: 'options.traceContext.spanId 必须是非空字符串' };
|
|
85
|
+
}
|
|
86
|
+
options.traceContext = { traceId, ...(spanId !== undefined ? { spanId } : {}) };
|
|
87
|
+
}
|
|
88
|
+
return { ok: true, options };
|
|
89
|
+
}
|
|
90
|
+
/** 两个上限取更严者(缺席即「这边没设」,另一边说了算) */
|
|
91
|
+
function tighter(a, b) {
|
|
92
|
+
if (a === undefined)
|
|
93
|
+
return b;
|
|
94
|
+
if (b === undefined)
|
|
95
|
+
return a;
|
|
96
|
+
return Math.min(a, b);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 把宿主注入的选项叠加到(已过白名单的)客户端选项上。
|
|
100
|
+
*
|
|
101
|
+
* 三条合并语义各不相同,各有理由:
|
|
102
|
+
* - `blackboard`:**整体替换** —— 它是身份载体,允许客户端键与宿主键"合并"就等于允许覆盖;
|
|
103
|
+
* - `labels`:**按键盘合并、宿主胜** —— 归因是多维度的,宿主只想补自己关心的维度;
|
|
104
|
+
* - 预算:**取更严者** —— 见文件头「上限的定义」。
|
|
105
|
+
*/
|
|
106
|
+
export function mergeRunOptions(client, overrides) {
|
|
107
|
+
if (!overrides)
|
|
108
|
+
return client;
|
|
109
|
+
const maxCostUsd = tighter(client.maxCostUsd, overrides.maxCostUsd);
|
|
110
|
+
const maxTotalTokens = tighter(client.maxTotalTokens, overrides.maxTotalTokens);
|
|
111
|
+
return {
|
|
112
|
+
...client,
|
|
113
|
+
...(overrides.blackboard !== undefined ? { blackboard: overrides.blackboard } : {}),
|
|
114
|
+
...(overrides.labels !== undefined
|
|
115
|
+
? { labels: { ...(client.labels ?? {}), ...overrides.labels } }
|
|
116
|
+
: {}),
|
|
117
|
+
...(maxCostUsd !== undefined ? { maxCostUsd } : {}),
|
|
118
|
+
...(maxTotalTokens !== undefined ? { maxTotalTokens } : {}),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=run-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-options.js","sourceRoot":"","sources":["../../src/transport/run-options.ts"],"names":[],"mappings":"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"}
|