@gt-fe/eap-runtime 0.0.10 → 0.0.12
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/README.md +3 -3
- package/dist/api/handlers/invoke.handler.js +4 -0
- package/dist/api/handlers/stream.handler.js +4 -0
- package/dist/contracts/trace-collector.d.ts +1 -1
- package/dist/governance/governance-client.js +40 -16
- package/dist/governance/index.d.ts +1 -1
- package/dist/governance/index.js +1 -1
- package/dist/governance/permission-guard.d.ts +1 -0
- package/dist/governance/permission-guard.js +13 -4
- package/dist/graph/adapters/langgraph.adapter.js +11 -6
- package/dist/graph/contracts/executable-graph.d.ts +2 -0
- package/dist/graph/hitl/hitl-handler.d.ts +3 -0
- package/dist/graph/hitl/hitl-handler.js +4 -1
- package/dist/graph/nodes/tool-node.js +27 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/providers/echo-llm-provider.js +2 -2
- package/dist/registry/deployment-snapshot.d.ts +14 -2
- package/dist/registry/deployment-snapshot.js +56 -30
- package/dist/registry/graph-loader.js +4 -4
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +1 -1
- package/dist/runtime/agent-runtime.js +18 -4
- package/dist/runtime/dev-runtime.d.ts +1 -1
- package/dist/runtime/dev-runtime.js +6 -10
- package/dist/tool/dev-http-executor.js +9 -6
- package/dist/tool/dev-mcp-executor.js +5 -3
- package/dist/tool/dev-tool-executor.d.ts +1 -1
- package/dist/tool/dev-tool-executor.js +2 -2
- package/dist/tool/harness-command.d.ts +32 -0
- package/dist/tool/harness-command.js +276 -0
- package/dist/tool/harness-primitives.d.ts +25 -3
- package/dist/tool/harness-primitives.js +156 -49
- package/dist/tool/http-tool-executor.js +15 -20
- package/dist/tool/index.d.ts +3 -2
- package/dist/tool/index.js +3 -2
- package/dist/tool/local-mcp-client.js +54 -23
- package/dist/tool/local-tool-executor.js +13 -9
- package/dist/tool/mcp-tool-executor.js +14 -6
- package/dist/tool/skill-script-refs.d.ts +20 -0
- package/dist/tool/skill-script-refs.js +62 -0
- package/dist/tool/system-prompt-builder.d.ts +2 -2
- package/dist/tool/system-prompt-builder.js +7 -4
- package/dist/tool/timeout.d.ts +14 -0
- package/dist/tool/timeout.js +36 -0
- package/dist/tool/tool-confirmation.js +2 -1
- package/dist/tool/tool-executor.interface.d.ts +13 -3
- package/dist/tool/tool-orchestrator.d.ts +1 -1
- package/dist/tool/tool-orchestrator.js +6 -3
- package/package.json +3 -3
- package/dist/common/concurrency.d.ts +0 -79
- package/dist/common/concurrency.js +0 -121
- package/dist/common/queue-consumer.d.ts +0 -125
- package/dist/common/queue-consumer.js +0 -159
- package/dist/tool/mock-tool-executor.d.ts +0 -28
- package/dist/tool/mock-tool-executor.js +0 -65
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ Enterprise Agent Platform **执行引擎**(LangGraph.js):Agent Graph 编
|
|
|
28
28
|
| 环境变量总表 | [`docs/governance/governance-env-config.md`](../docs/governance/governance-env-config.md) |
|
|
29
29
|
| 预装联调契约 | [`docs/contracts/preload-hosting-runtime-contract.md`](../docs/contracts/preload-hosting-runtime-contract.md) |
|
|
30
30
|
| 预装加载与请求流转 | [`docs/contracts/runtime-preinstall-load-flow.md`](../docs/contracts/runtime-preinstall-load-flow.md) |
|
|
31
|
+
| 技能 FS 待办 | [`docs/TODO-skill-fs.md`](./docs/TODO-skill-fs.md) |
|
|
31
32
|
| 本地 Agent 闭环 | [`docs/workflows/local-agent-dev-loop.md`](../docs/workflows/local-agent-dev-loop.md) |
|
|
32
33
|
|
|
33
34
|
---
|
|
@@ -197,8 +198,7 @@ node ../fixtures/eap-preinstall-sample/scripts/seal-snapshot.mjs
|
|
|
197
198
|
|
|
198
199
|
| 模式 | 何时 | 说明 |
|
|
199
200
|
|------|------|------|
|
|
200
|
-
| `
|
|
201
|
-
| `mcp` / DevMcp | `eap chat --tool-mode mcp` | 本机直连 MCP(`EAP_TOOL_EXECUTION_MODE`,仅 createDevRuntime) |
|
|
201
|
+
| `mcp` / DevToolExecutor | 本地默认(`dev` + `mcp`) | 按清单直连 MCP / HTTP / 本机 code |
|
|
202
202
|
| Gateway | 生产 / Hosting | `EAP_TOOL_GATEWAY_TRANSPORT=mcp`(生产);`http` 仅调试 |
|
|
203
203
|
|
|
204
204
|
- 编排:`ToolOrchestrator` + `ToolExecutionRouter`(`deploymentContext`: `server` \| `desktop` \| `dev`)
|
|
@@ -254,7 +254,7 @@ FOUNDATION_SERVICE_URL=...
|
|
|
254
254
|
EAP_DEPLOYMENT_CONTEXT=dev
|
|
255
255
|
EAP_PREINSTALL_ROOT=/abs/path/to/preinstall # 或 Agent 工程内预装树
|
|
256
256
|
EAP_RUNTIME_STORAGE_PROFILE=dev
|
|
257
|
-
EAP_TOOL_EXECUTION_MODE=
|
|
257
|
+
EAP_TOOL_EXECUTION_MODE=mcp # 本地默认;http-debug 走 Gateway 调试口
|
|
258
258
|
# OPENAI_BASE_URL / OPENAI_API_KEY / EAP_DEFAULT_MODEL
|
|
259
259
|
```
|
|
260
260
|
|
|
@@ -178,6 +178,9 @@ export class InvokeOrchestrator {
|
|
|
178
178
|
const promptRoots = this.graphLoader
|
|
179
179
|
? await this.graphLoader.resolvePromptRoots(agentCode, req.agentVersion)
|
|
180
180
|
: [];
|
|
181
|
+
const agentDir = this.graphLoader
|
|
182
|
+
? (await this.graphLoader.resolveAgentDir(agentCode, req.agentVersion)) ?? undefined
|
|
183
|
+
: undefined;
|
|
181
184
|
// 组装 GraphState:有 Checkpoint 历史则只追加本轮 user,避免双重 append
|
|
182
185
|
const history = messageRecordsToGraphMessages(sessionContext.messages);
|
|
183
186
|
const messages = await buildTurnGraphMessages({
|
|
@@ -204,6 +207,7 @@ export class InvokeOrchestrator {
|
|
|
204
207
|
skillDefinitions,
|
|
205
208
|
skillInput,
|
|
206
209
|
promptRoots,
|
|
210
|
+
agentDir,
|
|
207
211
|
traceId: resolveTraceId(req),
|
|
208
212
|
traceCollector: this.traceCollector,
|
|
209
213
|
});
|
|
@@ -200,6 +200,9 @@ export class StreamOrchestrator {
|
|
|
200
200
|
const promptRoots = this.graphLoader
|
|
201
201
|
? await this.graphLoader.resolvePromptRoots(agentCode, req.agentVersion)
|
|
202
202
|
: [];
|
|
203
|
+
const agentDir = this.graphLoader
|
|
204
|
+
? (await this.graphLoader.resolveAgentDir(agentCode, req.agentVersion)) ?? undefined
|
|
205
|
+
: undefined;
|
|
203
206
|
// 组装 GraphState:有 Checkpoint 历史则只追加本轮 user,避免双重 append
|
|
204
207
|
const history = messageRecordsToGraphMessages(sessionContext.messages);
|
|
205
208
|
const messages = await buildTurnGraphMessages({
|
|
@@ -232,6 +235,7 @@ export class StreamOrchestrator {
|
|
|
232
235
|
skillDefinitions,
|
|
233
236
|
skillInput,
|
|
234
237
|
promptRoots,
|
|
238
|
+
agentDir,
|
|
235
239
|
traceId: resolveTraceId(req),
|
|
236
240
|
traceCollector: this.traceCollector,
|
|
237
241
|
});
|
|
@@ -84,7 +84,7 @@ export interface ExecutionNodeEvent {
|
|
|
84
84
|
/** 节点类型 */
|
|
85
85
|
type: 'start' | 'llm' | 'tool' | 'skill' | 'condition' | 'hitl' | 'end';
|
|
86
86
|
/** 工具运行环境(type=tool) */
|
|
87
|
-
toolRuntime?: 'local' | 'server' | 'both'
|
|
87
|
+
toolRuntime?: 'local' | 'server' | 'both';
|
|
88
88
|
/** Agent 对外主键 */
|
|
89
89
|
agentCode?: string;
|
|
90
90
|
/** 输入数据 */
|
|
@@ -40,25 +40,29 @@ export class HttpGovernanceClient {
|
|
|
40
40
|
if (response.status === 503 || response.status >= 500) {
|
|
41
41
|
return { allowed: false, reason: 'GOVERNANCE_UNAVAILABLE' };
|
|
42
42
|
}
|
|
43
|
+
if (response.status === 403) {
|
|
44
|
+
return { allowed: false, reason: await readDenyReason(response, 'NO_PERMISSION') };
|
|
45
|
+
}
|
|
43
46
|
if (!response.ok) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
return { allowed: false, reason: 'NO_PERMISSION' };
|
|
47
|
+
// 401/404/400 等是 Runtime→Foundation hop 失败,不是 C2「没工具权」
|
|
48
|
+
return { allowed: false, reason: 'GOVERNANCE_UNAVAILABLE' };
|
|
49
|
+
}
|
|
50
|
+
let body;
|
|
51
|
+
try {
|
|
52
|
+
body = (await response.json());
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return { allowed: false, reason: 'GOVERNANCE_UNAVAILABLE' };
|
|
55
56
|
}
|
|
56
|
-
const body = (await response.json());
|
|
57
57
|
const data = body.data ?? body;
|
|
58
|
-
|
|
59
|
-
allowed:
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
if (data.allowed === true) {
|
|
59
|
+
return { allowed: true };
|
|
60
|
+
}
|
|
61
|
+
const reason = asDenyReason(data.reason);
|
|
62
|
+
if (data.allowed === false && reason && reason !== 'GOVERNANCE_UNAVAILABLE') {
|
|
63
|
+
return { allowed: false, reason };
|
|
64
|
+
}
|
|
65
|
+
return { allowed: false, reason: 'GOVERNANCE_UNAVAILABLE' };
|
|
62
66
|
}
|
|
63
67
|
catch {
|
|
64
68
|
clearTimeout(timeoutId);
|
|
@@ -66,6 +70,26 @@ export class HttpGovernanceClient {
|
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
}
|
|
73
|
+
const DENY_REASONS = new Set([
|
|
74
|
+
'NO_PERMISSION',
|
|
75
|
+
'DATA_SCOPE_DENIED',
|
|
76
|
+
'GOVERNANCE_UNAVAILABLE',
|
|
77
|
+
]);
|
|
78
|
+
function asDenyReason(value) {
|
|
79
|
+
return typeof value === 'string' && DENY_REASONS.has(value)
|
|
80
|
+
? value
|
|
81
|
+
: undefined;
|
|
82
|
+
}
|
|
83
|
+
async function readDenyReason(response, fallback) {
|
|
84
|
+
try {
|
|
85
|
+
const errBody = (await response.json());
|
|
86
|
+
const errData = errBody.data ?? errBody;
|
|
87
|
+
return asDenyReason(errData.reason) ?? fallback;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return fallback;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
69
93
|
/** 本地/测试:跳过远程校验 */
|
|
70
94
|
export class AllowAllGovernanceClient {
|
|
71
95
|
async checkPermission(_ctx, _params) {
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
export type { CallerType, ExecutionContext, GovernancePermissionCheckParams, GovernancePermissionCheckResult, PermissionAction, PermissionDenyReason, PermissionResourceType, } from '@gt-fe/eap-contracts';
|
|
5
5
|
export type { IGovernanceClient } from './governance-client.js';
|
|
6
6
|
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, } from './governance-client.js';
|
|
7
|
-
export { assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './permission-guard.js';
|
|
7
|
+
export { assertToolPermission, assertSkillPermission, permissionMessage, PermissionDeniedError, GovernanceUnavailableError, } from './permission-guard.js';
|
package/dist/governance/index.js
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* 权限校验 — 对齐 06-governance R16.8
|
|
3
3
|
*/
|
|
4
4
|
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, } from './governance-client.js';
|
|
5
|
-
export { assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './permission-guard.js';
|
|
5
|
+
export { assertToolPermission, assertSkillPermission, permissionMessage, PermissionDeniedError, GovernanceUnavailableError, } from './permission-guard.js';
|
|
@@ -11,6 +11,7 @@ export declare class PermissionDeniedError extends Error {
|
|
|
11
11
|
readonly reason: PermissionDenyReason;
|
|
12
12
|
constructor(reason?: PermissionDenyReason, message?: string);
|
|
13
13
|
}
|
|
14
|
+
export declare function permissionMessage(kind: 'tool' | 'skill', reason: PermissionDenyReason): string;
|
|
14
15
|
export declare function assertToolPermission(client: IGovernanceClient | undefined, ctx: ExecutionContext, toolId: string, options?: {
|
|
15
16
|
dataScope?: 'user-bound' | 'department-bound' | 'global';
|
|
16
17
|
resourceOwnerId?: string;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export class GovernanceUnavailableError extends Error {
|
|
5
5
|
reason = 'GOVERNANCE_UNAVAILABLE';
|
|
6
|
-
constructor(message = '
|
|
6
|
+
constructor(message = '治理服务不可用') {
|
|
7
7
|
super(message);
|
|
8
8
|
this.name = 'GovernanceUnavailableError';
|
|
9
9
|
}
|
|
@@ -11,11 +11,18 @@ export class GovernanceUnavailableError extends Error {
|
|
|
11
11
|
export class PermissionDeniedError extends Error {
|
|
12
12
|
reason;
|
|
13
13
|
constructor(reason = 'NO_PERMISSION', message) {
|
|
14
|
-
super(message ?? reason);
|
|
14
|
+
super(message ?? permissionMessage('tool', reason));
|
|
15
15
|
this.name = 'PermissionDeniedError';
|
|
16
16
|
this.reason = reason;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
export function permissionMessage(kind, reason) {
|
|
20
|
+
if (reason === 'DATA_SCOPE_DENIED')
|
|
21
|
+
return '数据范围不足';
|
|
22
|
+
if (reason === 'GOVERNANCE_UNAVAILABLE')
|
|
23
|
+
return '治理服务不可用';
|
|
24
|
+
return kind === 'skill' ? '用户无该 Skill 使用权限' : '用户无该 Tool 执行权限';
|
|
25
|
+
}
|
|
19
26
|
export async function assertToolPermission(client, ctx, toolId, options) {
|
|
20
27
|
if (!client) {
|
|
21
28
|
return;
|
|
@@ -34,7 +41,8 @@ export async function assertToolPermission(client, ctx, toolId, options) {
|
|
|
34
41
|
throw new GovernanceUnavailableError();
|
|
35
42
|
}
|
|
36
43
|
if (!result.allowed) {
|
|
37
|
-
|
|
44
|
+
const reason = result.reason ?? 'NO_PERMISSION';
|
|
45
|
+
throw new PermissionDeniedError(reason, permissionMessage('tool', reason));
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
/** Skill 激活守卫(04 R15.3) */
|
|
@@ -54,6 +62,7 @@ export async function assertSkillPermission(client, ctx, skillId) {
|
|
|
54
62
|
throw new GovernanceUnavailableError();
|
|
55
63
|
}
|
|
56
64
|
if (!result.allowed) {
|
|
57
|
-
|
|
65
|
+
const reason = result.reason ?? 'NO_PERMISSION';
|
|
66
|
+
throw new PermissionDeniedError(reason, permissionMessage('skill', reason));
|
|
58
67
|
}
|
|
59
68
|
}
|
|
@@ -19,7 +19,7 @@ import { fileArtifactFromToolOutput } from '../../tool/file-artifact.js';
|
|
|
19
19
|
import { EchoLLMProvider } from '../../providers/echo-llm-provider.js';
|
|
20
20
|
import { ConditionEvaluator } from '../condition-evaluator.js';
|
|
21
21
|
import { SystemPromptBuilder, buildToolCatalog, loadedToolsToApiTools } from '../../tool/system-prompt-builder.js';
|
|
22
|
-
import { resolveJailRoots } from '../../tool/harness-primitives.js';
|
|
22
|
+
import { resolveJailFromState, resolveJailRoots } from '../../tool/harness-primitives.js';
|
|
23
23
|
import os from 'node:os';
|
|
24
24
|
import { bindSelectedSkill } from '../nodes/skill-bind-node.js';
|
|
25
25
|
import { resolveGraphPrompt } from '../resolve-graph-prompt.js';
|
|
@@ -305,6 +305,7 @@ export class LangGraphAdapter {
|
|
|
305
305
|
skillRoute: ephemeral(undefined),
|
|
306
306
|
silentOutput: ephemeral(undefined),
|
|
307
307
|
promptRoots: ephemeral(undefined),
|
|
308
|
+
agentDir: ephemeral(undefined),
|
|
308
309
|
executionContext: ephemeral(undefined),
|
|
309
310
|
forceToolServer: ephemeral(undefined),
|
|
310
311
|
traceCollector: ephemeral(undefined),
|
|
@@ -799,7 +800,15 @@ export class LangGraphAdapter {
|
|
|
799
800
|
const toolCatalog = disableTools ? undefined : buildToolCatalog(loadedTools);
|
|
800
801
|
const execCtx = state['executionContext'];
|
|
801
802
|
const userId = (typeof execCtx?.userId === 'string' && execCtx.userId) || state['userId'];
|
|
802
|
-
const
|
|
803
|
+
const jail = resolveJailFromState({
|
|
804
|
+
agentDir: state['agentDir'],
|
|
805
|
+
userId,
|
|
806
|
+
executionContext: execCtx,
|
|
807
|
+
loadedTools,
|
|
808
|
+
skillDefinitions: skillDefs,
|
|
809
|
+
});
|
|
810
|
+
const workingDirectory = jail.workdir;
|
|
811
|
+
const jailRoots = resolveJailRoots(jail);
|
|
803
812
|
const skillDirs = Object.values(skillDefs ?? {})
|
|
804
813
|
.filter((skill) => Boolean(skill.bundlePath))
|
|
805
814
|
.map((skill) => ({
|
|
@@ -807,10 +816,6 @@ export class LangGraphAdapter {
|
|
|
807
816
|
bundlePath: skill.bundlePath,
|
|
808
817
|
entryFile: skill.entryFile,
|
|
809
818
|
}));
|
|
810
|
-
const jailRoots = resolveJailRoots({
|
|
811
|
-
workdir: workingDirectory,
|
|
812
|
-
extraRoots: skillDirs.map((s) => s.bundlePath),
|
|
813
|
-
});
|
|
814
819
|
const assembled = this.systemPromptBuilder.build({
|
|
815
820
|
developerPrompt: resolvedPrompt || undefined,
|
|
816
821
|
skillCatalog: catalog,
|
|
@@ -195,6 +195,8 @@ export interface GraphState {
|
|
|
195
195
|
silentOutput?: string;
|
|
196
196
|
/** 解析 graph 内 ./prompts/*.md 的根目录(agentDir + 工程根) */
|
|
197
197
|
promptRoots?: string[];
|
|
198
|
+
/** 预装 Agent 包目录:`{EAP_PREINSTALL_ROOT}/agents/<code>/<ver>` */
|
|
199
|
+
agentDir?: string;
|
|
198
200
|
activatedSkill?: string | null;
|
|
199
201
|
skillRoute?: string;
|
|
200
202
|
/** bind / invoke 解析出的 Skill 入参;子图 IO 校验读取 */
|
|
@@ -16,6 +16,9 @@ import type { ISSEEmitter } from '../../sse/contracts/sse-emitter.contract.js';
|
|
|
16
16
|
import type { GraphState } from '../contracts/executable-graph.js';
|
|
17
17
|
/** HITL 默认等待时长(毫秒)= 300 秒。SSE `hitl.waited.timeout` 对外用秒。 */
|
|
18
18
|
export declare const DEFAULT_HITL_TIMEOUT_MS = 300000;
|
|
19
|
+
/** 超时收口对外文案(Task / Trace / AppError);枚举走 `hitl_timeout`。 */
|
|
20
|
+
export declare const HITL_TIMEOUT_MESSAGE = "HITL \u786E\u8BA4\u8D85\u65F6";
|
|
21
|
+
export declare const HITL_TIMEOUT_ERROR_CODE = "hitl_timeout";
|
|
19
22
|
/** HITL 超时行为 */
|
|
20
23
|
export type HitlTimeoutBehavior = 'error' | 'cancel' | 'auto-confirm';
|
|
21
24
|
/** HITL 中断配置 */
|
|
@@ -17,6 +17,9 @@ import { startGraphSpan, completeGraphSpan } from '../trace-span.js';
|
|
|
17
17
|
// ─────────────────────────────────────────────
|
|
18
18
|
/** HITL 默认等待时长(毫秒)= 300 秒。SSE `hitl.waited.timeout` 对外用秒。 */
|
|
19
19
|
export const DEFAULT_HITL_TIMEOUT_MS = 300_000;
|
|
20
|
+
/** 超时收口对外文案(Task / Trace / AppError);枚举走 `hitl_timeout`。 */
|
|
21
|
+
export const HITL_TIMEOUT_MESSAGE = 'HITL 确认超时';
|
|
22
|
+
export const HITL_TIMEOUT_ERROR_CODE = 'hitl_timeout';
|
|
20
23
|
/** HITL 超时错误(保留类型;timer 不再 throw,resume 逾期改走 AppError) */
|
|
21
24
|
export class HitlTimeoutError extends Error {
|
|
22
25
|
taskId;
|
|
@@ -444,7 +447,7 @@ export class HitlHandler {
|
|
|
444
447
|
const hitlSpanId = waiting.hitlSpanId ?? persisted.hitlSpanId;
|
|
445
448
|
await completeGraphSpan(checkpoint.state, hitlSpanId, {
|
|
446
449
|
status: 'failed',
|
|
447
|
-
error:
|
|
450
|
+
error: HITL_TIMEOUT_MESSAGE,
|
|
448
451
|
}, liveCollector);
|
|
449
452
|
}
|
|
450
453
|
return timeoutEvent;
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* @see design.md §1.4 ToolNode: LangGraph的ToolNode封装
|
|
10
10
|
* @see requirements.md Requirement 8 AC1, AC3, AC5
|
|
11
11
|
*/
|
|
12
|
+
import { resolveJailFromState } from '../../tool/harness-primitives.js';
|
|
12
13
|
import { isHitlDecision, unwrapHitlPaused } from '../hitl/hitl-handler.js';
|
|
13
14
|
import { ToolConfirmationInterceptor } from '../../tool/tool-confirmation.js';
|
|
14
15
|
import { resolveCheckpointThreadId } from '../../session/persist-turn-messages.js';
|
|
@@ -19,6 +20,19 @@ function skillDirsFromState(state) {
|
|
|
19
20
|
.filter((skill) => Boolean(skill.bundlePath))
|
|
20
21
|
.map((skill) => ({ skillId: skill.skillId, bundlePath: skill.bundlePath }));
|
|
21
22
|
}
|
|
23
|
+
function resolveActiveSkillDir(state) {
|
|
24
|
+
const defs = state['skillDefinitions'];
|
|
25
|
+
if (!defs)
|
|
26
|
+
return undefined;
|
|
27
|
+
const activated = state['activatedSkill'];
|
|
28
|
+
if (typeof activated === 'string' && defs[activated]?.bundlePath) {
|
|
29
|
+
return defs[activated].bundlePath;
|
|
30
|
+
}
|
|
31
|
+
const paths = Object.values(defs)
|
|
32
|
+
.map((skill) => skill.bundlePath)
|
|
33
|
+
.filter((p) => Boolean(p));
|
|
34
|
+
return paths.length === 1 ? paths[0] : undefined;
|
|
35
|
+
}
|
|
22
36
|
export class ToolNode {
|
|
23
37
|
orchestrator;
|
|
24
38
|
injector;
|
|
@@ -53,7 +67,15 @@ export class ToolNode {
|
|
|
53
67
|
}
|
|
54
68
|
const loadedTools = state['loadedTools'];
|
|
55
69
|
const skillDirs = skillDirsFromState(state);
|
|
56
|
-
const
|
|
70
|
+
const jail = resolveJailFromState({
|
|
71
|
+
agentDir: state['agentDir'],
|
|
72
|
+
userId: state['userId'],
|
|
73
|
+
executionContext: state['executionContext'],
|
|
74
|
+
loadedTools,
|
|
75
|
+
skillDefinitions: state['skillDefinitions'],
|
|
76
|
+
});
|
|
77
|
+
const jailExtraRoots = jail.extraRoots ?? [];
|
|
78
|
+
const skillDir = resolveActiveSkillDir(state);
|
|
57
79
|
// 4. 转换为 ToolCallRequest[](附带 manifest 路由字段)
|
|
58
80
|
const requests = lastAssistantMessage.toolCalls.map((tc) => {
|
|
59
81
|
const loaded = loadedTools?.[tc.name];
|
|
@@ -73,7 +95,9 @@ export class ToolNode {
|
|
|
73
95
|
...(loaded?.manifest.version ? { toolVersion: loaded.manifest.version } : {}),
|
|
74
96
|
correlationId,
|
|
75
97
|
taskId,
|
|
98
|
+
...(jail.workdir ? { jailWorkdir: jail.workdir } : {}),
|
|
76
99
|
...(jailExtraRoots.length > 0 ? { jailExtraRoots } : {}),
|
|
100
|
+
...(skillDir ? { skillDir } : {}),
|
|
77
101
|
};
|
|
78
102
|
});
|
|
79
103
|
const executionContext = state['executionContext'];
|
|
@@ -161,7 +185,8 @@ export class ToolNode {
|
|
|
161
185
|
toolName: req.toolName,
|
|
162
186
|
content: `用户拒绝执行工具 ${req.toolName}`,
|
|
163
187
|
success: false,
|
|
164
|
-
error:
|
|
188
|
+
error: `用户拒绝执行工具 ${req.toolName}`,
|
|
189
|
+
errorCode: 'hitl_rejected',
|
|
165
190
|
};
|
|
166
191
|
}
|
|
167
192
|
else {
|
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export * from './registry/index.js';
|
|
|
17
17
|
export * from './providers/index.js';
|
|
18
18
|
export type { ITraceCollector, TraceEvent, TraceSession, ExecutionFlowEvent, ExecutionNodeEvent, TraceLinkEvent, TraceLinkNodeEvent, } from './contracts/trace-collector.js';
|
|
19
19
|
export type { ExecutionContext, CallerType, GovernancePermissionCheckParams, GovernancePermissionCheckResult, PermissionDenyReason, } from '@gt-fe/eap-contracts';
|
|
20
|
-
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
20
|
+
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, permissionMessage, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
21
21
|
export type { IGovernanceClient } from './governance/index.js';
|
|
22
22
|
export { FileLlmTurnLog, InMemoryLlmTurnLog, createFileLlmTurnLogFromEnv, maskApiKey, resolveLlmTurnDir, } from './debug/llm-turn-log.js';
|
|
23
23
|
export { PostgresLlmTurnLog } from './debug/pg-llm-turn-log.js';
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,6 @@ export * from './common/index.js';
|
|
|
29
29
|
export * from './registry/index.js';
|
|
30
30
|
// LLM Providers
|
|
31
31
|
export * from './providers/index.js';
|
|
32
|
-
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
32
|
+
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, permissionMessage, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
33
33
|
export { FileLlmTurnLog, InMemoryLlmTurnLog, createFileLlmTurnLogFromEnv, maskApiKey, resolveLlmTurnDir, } from './debug/llm-turn-log.js';
|
|
34
34
|
export { PostgresLlmTurnLog } from './debug/pg-llm-turn-log.js';
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* - `call:echo-tool {"text":"hi"}` → arguments 使用解析后的 JSON
|
|
8
8
|
* - `call:echo-tool hi` → arguments 兜底为 `{ text: 'hi' }`
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* 仅用于本地闭环(无真实 LLM)下驱动 ToolNode,
|
|
11
|
+
* 让开发者无需接入模型即可完成 tool 调用链路验证。
|
|
12
12
|
*/
|
|
13
13
|
function parseSyntheticToolCall(content) {
|
|
14
14
|
if (!content)
|
|
@@ -73,13 +73,25 @@ export interface IDeploymentSnapshot {
|
|
|
73
73
|
}
|
|
74
74
|
/** 规范化摘要:去 sha256: 前缀、空白,转小写 hex */
|
|
75
75
|
export declare function normalizeDigest(value: unknown): string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Agent 清单装配读取:现行 `skills`,兼容 CLI `skillRefs`。
|
|
78
|
+
* 项身份:`code` / `skill` / `skillId`。两边都有时现行字段先写入;同名只补 version/name 等空位。
|
|
79
|
+
*/
|
|
80
|
+
export declare function skillRefsFromManifest(manifest: Record<string, unknown>): SnapshotSkillRef[];
|
|
76
81
|
/**
|
|
77
82
|
* 装配引用 vs 内联完整 ToolManifest。
|
|
78
|
-
* 含 type/execution 的视为内联定义;仅 toolset/
|
|
83
|
+
* 含 type/execution 的视为内联定义;仅 code/toolset/version/enabled 等视为引用。
|
|
79
84
|
*/
|
|
80
85
|
export declare function isInlineToolDeclaration(item: unknown): boolean;
|
|
81
86
|
/**
|
|
82
|
-
*
|
|
87
|
+
* 从 Agent 清单收集工具集装配引用。
|
|
88
|
+
* 现行 `toolsets`;兼容 CLI `toolRefs` 与更旧的 `tools`(内联完整 manifest 会跳过)。
|
|
89
|
+
* 项身份:`code` / `toolset`(字符串项即 code)。不用展示名 `name`。白名单:`enabled` / `enabledTools`。
|
|
90
|
+
* 两边都有时现行字段先写入;同名条目的 enabled/autoApprove 以先写入为准。
|
|
91
|
+
*/
|
|
92
|
+
export declare function toolsetsFromManifest(manifest: Record<string, unknown>): SnapshotToolRef[];
|
|
93
|
+
/**
|
|
94
|
+
* 将 agent.manifest 装配项上的 enabled/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
|
|
83
95
|
*/
|
|
84
96
|
export declare function overlayToolRefPolicies(snapTools: SnapshotToolRef[], manifest?: Record<string, unknown>): SnapshotToolRef[];
|
|
85
97
|
export declare class FileSystemDeploymentSnapshot implements IDeploymentSnapshot {
|
|
@@ -140,29 +140,51 @@ async function pickLatestVersionDir(parent) {
|
|
|
140
140
|
dirs.sort();
|
|
141
141
|
return path.join(parent, dirs[dirs.length - 1]);
|
|
142
142
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
function asArray(value) {
|
|
144
|
+
return Array.isArray(value) ? value : [];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Agent 清单装配读取:现行 `skills`,兼容 CLI `skillRefs`。
|
|
148
|
+
* 项身份:`code` / `skill` / `skillId`。两边都有时现行字段先写入;同名只补 version/name 等空位。
|
|
149
|
+
*/
|
|
150
|
+
export function skillRefsFromManifest(manifest) {
|
|
147
151
|
const out = [];
|
|
148
|
-
|
|
152
|
+
const byId = new Map();
|
|
153
|
+
const upsert = (ref) => {
|
|
154
|
+
const prev = byId.get(ref.skillId);
|
|
155
|
+
if (!prev) {
|
|
156
|
+
byId.set(ref.skillId, ref);
|
|
157
|
+
out.push(ref);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (!prev.version && ref.version)
|
|
161
|
+
prev.version = ref.version;
|
|
162
|
+
if (!prev.name && ref.name)
|
|
163
|
+
prev.name = ref.name;
|
|
164
|
+
if (!prev.description && ref.description)
|
|
165
|
+
prev.description = ref.description;
|
|
166
|
+
if (!prev.sha256 && ref.sha256)
|
|
167
|
+
prev.sha256 = ref.sha256;
|
|
168
|
+
};
|
|
169
|
+
for (const item of [...asArray(manifest.skills), ...asArray(manifest.skillRefs)]) {
|
|
149
170
|
if (typeof item === 'string') {
|
|
150
|
-
|
|
171
|
+
if (item)
|
|
172
|
+
upsert({ skillId: item });
|
|
151
173
|
continue;
|
|
152
174
|
}
|
|
153
|
-
if (item
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
175
|
+
if (!item || typeof item !== 'object')
|
|
176
|
+
continue;
|
|
177
|
+
const o = item;
|
|
178
|
+
const skillId = String(o.code ?? o.skill ?? o.skillId ?? '');
|
|
179
|
+
if (!skillId)
|
|
180
|
+
continue;
|
|
181
|
+
upsert({
|
|
182
|
+
skillId,
|
|
183
|
+
name: o.name != null ? String(o.name) : undefined,
|
|
184
|
+
version: o.version != null ? String(o.version) : undefined,
|
|
185
|
+
description: o.description != null ? String(o.description) : undefined,
|
|
186
|
+
sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
|
|
187
|
+
});
|
|
166
188
|
}
|
|
167
189
|
return out;
|
|
168
190
|
}
|
|
@@ -174,7 +196,7 @@ function parseStringList(value) {
|
|
|
174
196
|
}
|
|
175
197
|
/**
|
|
176
198
|
* 装配引用 vs 内联完整 ToolManifest。
|
|
177
|
-
* 含 type/execution 的视为内联定义;仅 toolset/
|
|
199
|
+
* 含 type/execution 的视为内联定义;仅 code/toolset/version/enabled 等视为引用。
|
|
178
200
|
*/
|
|
179
201
|
export function isInlineToolDeclaration(item) {
|
|
180
202
|
if (!item || typeof item !== 'object' || Array.isArray(item))
|
|
@@ -191,7 +213,7 @@ function parseToolAssemblyRef(item) {
|
|
|
191
213
|
if (isInlineToolDeclaration(item))
|
|
192
214
|
return null;
|
|
193
215
|
const o = item;
|
|
194
|
-
const name = String(o.code ?? o.
|
|
216
|
+
const name = String(o.code ?? o.toolset ?? '');
|
|
195
217
|
if (!name)
|
|
196
218
|
return null;
|
|
197
219
|
return {
|
|
@@ -199,13 +221,17 @@ function parseToolAssemblyRef(item) {
|
|
|
199
221
|
toolId: o.toolId != null ? String(o.toolId) : undefined,
|
|
200
222
|
version: o.version != null ? String(o.version) : undefined,
|
|
201
223
|
sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
|
|
202
|
-
enabledTools: parseStringList(o.enabled),
|
|
224
|
+
enabledTools: parseStringList(o.enabled) ?? parseStringList(o.enabledTools),
|
|
203
225
|
autoApprove: parseStringList(o.autoApprove),
|
|
204
226
|
};
|
|
205
227
|
}
|
|
206
228
|
/**
|
|
207
|
-
|
|
208
|
-
|
|
229
|
+
* 从 Agent 清单收集工具集装配引用。
|
|
230
|
+
* 现行 `toolsets`;兼容 CLI `toolRefs` 与更旧的 `tools`(内联完整 manifest 会跳过)。
|
|
231
|
+
* 项身份:`code` / `toolset`(字符串项即 code)。不用展示名 `name`。白名单:`enabled` / `enabledTools`。
|
|
232
|
+
* 两边都有时现行字段先写入;同名条目的 enabled/autoApprove 以先写入为准。
|
|
233
|
+
*/
|
|
234
|
+
export function toolsetsFromManifest(manifest) {
|
|
209
235
|
const out = [];
|
|
210
236
|
const byName = new Map();
|
|
211
237
|
const upsert = (ref) => {
|
|
@@ -215,10 +241,6 @@ function toolsetsFromManifest(manifest) {
|
|
|
215
241
|
out.push(ref);
|
|
216
242
|
return;
|
|
217
243
|
}
|
|
218
|
-
if (!prev.enabledTools && ref.enabledTools)
|
|
219
|
-
prev.enabledTools = ref.enabledTools;
|
|
220
|
-
if (!prev.autoApprove && ref.autoApprove)
|
|
221
|
-
prev.autoApprove = ref.autoApprove;
|
|
222
244
|
if (!prev.version && ref.version)
|
|
223
245
|
prev.version = ref.version;
|
|
224
246
|
if (!prev.sha256 && ref.sha256)
|
|
@@ -226,7 +248,11 @@ function toolsetsFromManifest(manifest) {
|
|
|
226
248
|
if (!prev.toolId && ref.toolId)
|
|
227
249
|
prev.toolId = ref.toolId;
|
|
228
250
|
};
|
|
229
|
-
for (const item of
|
|
251
|
+
for (const item of [
|
|
252
|
+
...asArray(manifest.toolsets),
|
|
253
|
+
...asArray(manifest.toolRefs),
|
|
254
|
+
...asArray(manifest.tools),
|
|
255
|
+
]) {
|
|
230
256
|
const ref = parseToolAssemblyRef(item);
|
|
231
257
|
if (ref)
|
|
232
258
|
upsert(ref);
|
|
@@ -234,7 +260,7 @@ function toolsetsFromManifest(manifest) {
|
|
|
234
260
|
return out;
|
|
235
261
|
}
|
|
236
262
|
/**
|
|
237
|
-
* 将 agent.manifest
|
|
263
|
+
* 将 agent.manifest 装配项上的 enabled/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
|
|
238
264
|
*/
|
|
239
265
|
export function overlayToolRefPolicies(snapTools, manifest) {
|
|
240
266
|
if (!manifest)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { readFile } from 'node:fs/promises';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { resolveAgentModelAllowlist, resolveAgentDefaultModel } from './agent-models.js';
|
|
10
|
+
import { DEFAULT_HTTP_TOOL_TIMEOUT_SEC, DEFAULT_TOOL_TIMEOUT_SEC } from '../tool/timeout.js';
|
|
10
11
|
import { createDeploymentSnapshotFromEnv, isInlineToolDeclaration, overlayToolRefPolicies, } from './deployment-snapshot.js';
|
|
11
12
|
import { preloadGraphNotFound, preloadManifestNotFound, preloadSkillNotFound, preloadToolNotFound, } from './preload-errors.js';
|
|
12
13
|
import { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, } from './definition-cache.js';
|
|
@@ -300,7 +301,7 @@ function expandPreinstallToolset(pre, options) {
|
|
|
300
301
|
baseUrl: st.baseUrl ?? gateway.baseUrl,
|
|
301
302
|
pathTemplate: st.pathTemplate,
|
|
302
303
|
allowedHosts: gateway.allowedHosts,
|
|
303
|
-
timeout: st.timeout ?? gateway.timeout ??
|
|
304
|
+
timeout: st.timeout ?? gateway.timeout ?? DEFAULT_HTTP_TOOL_TIMEOUT_SEC,
|
|
304
305
|
};
|
|
305
306
|
}
|
|
306
307
|
else if (setType === 'mcp') {
|
|
@@ -310,7 +311,7 @@ function expandPreinstallToolset(pre, options) {
|
|
|
310
311
|
transport: server?.transport ?? (server?.url ? 'streamable_http' : 'stdio'),
|
|
311
312
|
server,
|
|
312
313
|
toolName: name,
|
|
313
|
-
timeout: st.timeout ?? server?.timeout ??
|
|
314
|
+
timeout: st.timeout ?? server?.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
|
|
314
315
|
};
|
|
315
316
|
}
|
|
316
317
|
else {
|
|
@@ -319,7 +320,7 @@ function expandPreinstallToolset(pre, options) {
|
|
|
319
320
|
runtime: st.runtime ?? 'node',
|
|
320
321
|
handler: st.handler,
|
|
321
322
|
args: st.args,
|
|
322
|
-
timeout: st.timeout ??
|
|
323
|
+
timeout: st.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
|
|
323
324
|
sandbox: st.sandbox ?? pkg?.sandbox ?? false,
|
|
324
325
|
bundlePath: pre.bundlePath,
|
|
325
326
|
};
|
|
@@ -839,7 +840,6 @@ export class GraphLoader {
|
|
|
839
840
|
const workflow = asGraphDsl(pre.manifest.workflow) ??
|
|
840
841
|
asGraphDsl(pre.manifest.graph) ??
|
|
841
842
|
asGraphDsl(pre.manifest.definitionSnapshot);
|
|
842
|
-
// 解析 prompt:支持文件路径引用(./ 开头)
|
|
843
843
|
const prompt = await resolveSkillPrompt(pre.manifest, pre.bundlePath);
|
|
844
844
|
const entryFile = typeof pre.manifest.skillEntryFile === 'string' ? pre.manifest.skillEntryFile : undefined;
|
|
845
845
|
skills.push({
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { createAgentRegistryClient, type AgentRegistryClient, type AgentRegistry
|
|
|
3
3
|
export { GraphLoader, type GraphLoaderConfig, type LoadToolDefinitionsOptions, type LoadAgentOptions } from './graph-loader.js';
|
|
4
4
|
export { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, type CachedAgentDefinitions, } from './definition-cache.js';
|
|
5
5
|
export { inspectAgentSkillTree, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, watchAgentSkillDirs, watchPreinstallSkillRoot, watchSkillRoots, } from './skill-tree.js';
|
|
6
|
-
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, type IDeploymentSnapshot, type AgentSnapshotMeta, type SnapshotToolRef, type SnapshotSkillRef, type PreinstallToolManifest, type PreinstallSkillManifest, type DeploymentSnapshotOptions, } from './deployment-snapshot.js';
|
|
6
|
+
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, toolsetsFromManifest, skillRefsFromManifest, type IDeploymentSnapshot, type AgentSnapshotMeta, type SnapshotToolRef, type SnapshotSkillRef, type PreinstallToolManifest, type PreinstallSkillManifest, type DeploymentSnapshotOptions, } from './deployment-snapshot.js';
|
|
7
7
|
export { preloadError, preloadMissing, preloadManifestNotFound, preloadGraphNotFound, preloadToolNotFound, preloadSkillNotFound, preloadPackageCorrupt, isRequireReady, } from './preload-errors.js';
|
|
8
8
|
export { resolvePreloadBehaviorFlags, isValidateSkillIo, isRequireChecksum, type PreloadBehaviorFlags, } from './preload-flags.js';
|
|
9
9
|
export { assertSkillIoIfEnabled, coerceSkillInputFromMessages, resolveSkillInputFromInvokeInput, } from './skill-io-guard.js';
|
package/dist/registry/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { createAgentRegistryClient } from './agent-registry-client.js';
|
|
|
3
3
|
export { GraphLoader } from './graph-loader.js';
|
|
4
4
|
export { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, } from './definition-cache.js';
|
|
5
5
|
export { inspectAgentSkillTree, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, watchAgentSkillDirs, watchPreinstallSkillRoot, watchSkillRoots, } from './skill-tree.js';
|
|
6
|
-
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, } from './deployment-snapshot.js';
|
|
6
|
+
export { FileSystemDeploymentSnapshot, createDeploymentSnapshotFromEnv, normalizeDigest, isInlineToolDeclaration, overlayToolRefPolicies, toolsetsFromManifest, skillRefsFromManifest, } from './deployment-snapshot.js';
|
|
7
7
|
export { preloadError, preloadMissing, preloadManifestNotFound, preloadGraphNotFound, preloadToolNotFound, preloadSkillNotFound, preloadPackageCorrupt, isRequireReady, } from './preload-errors.js';
|
|
8
8
|
export { resolvePreloadBehaviorFlags, isValidateSkillIo, isRequireChecksum, } from './preload-flags.js';
|
|
9
9
|
export { assertSkillIoIfEnabled, coerceSkillInputFromMessages, resolveSkillInputFromInvokeInput, } from './skill-io-guard.js';
|