@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.
Files changed (56) hide show
  1. package/README.md +3 -3
  2. package/dist/api/handlers/invoke.handler.js +4 -0
  3. package/dist/api/handlers/stream.handler.js +4 -0
  4. package/dist/contracts/trace-collector.d.ts +1 -1
  5. package/dist/governance/governance-client.js +40 -16
  6. package/dist/governance/index.d.ts +1 -1
  7. package/dist/governance/index.js +1 -1
  8. package/dist/governance/permission-guard.d.ts +1 -0
  9. package/dist/governance/permission-guard.js +13 -4
  10. package/dist/graph/adapters/langgraph.adapter.js +11 -6
  11. package/dist/graph/contracts/executable-graph.d.ts +2 -0
  12. package/dist/graph/hitl/hitl-handler.d.ts +3 -0
  13. package/dist/graph/hitl/hitl-handler.js +4 -1
  14. package/dist/graph/nodes/tool-node.js +27 -2
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/providers/echo-llm-provider.js +2 -2
  18. package/dist/registry/deployment-snapshot.d.ts +14 -2
  19. package/dist/registry/deployment-snapshot.js +56 -30
  20. package/dist/registry/graph-loader.js +4 -4
  21. package/dist/registry/index.d.ts +1 -1
  22. package/dist/registry/index.js +1 -1
  23. package/dist/runtime/agent-runtime.js +18 -4
  24. package/dist/runtime/dev-runtime.d.ts +1 -1
  25. package/dist/runtime/dev-runtime.js +6 -10
  26. package/dist/tool/dev-http-executor.js +9 -6
  27. package/dist/tool/dev-mcp-executor.js +5 -3
  28. package/dist/tool/dev-tool-executor.d.ts +1 -1
  29. package/dist/tool/dev-tool-executor.js +2 -2
  30. package/dist/tool/harness-command.d.ts +32 -0
  31. package/dist/tool/harness-command.js +276 -0
  32. package/dist/tool/harness-primitives.d.ts +25 -3
  33. package/dist/tool/harness-primitives.js +156 -49
  34. package/dist/tool/http-tool-executor.js +15 -20
  35. package/dist/tool/index.d.ts +3 -2
  36. package/dist/tool/index.js +3 -2
  37. package/dist/tool/local-mcp-client.js +54 -23
  38. package/dist/tool/local-tool-executor.js +13 -9
  39. package/dist/tool/mcp-tool-executor.js +14 -6
  40. package/dist/tool/skill-script-refs.d.ts +20 -0
  41. package/dist/tool/skill-script-refs.js +62 -0
  42. package/dist/tool/system-prompt-builder.d.ts +2 -2
  43. package/dist/tool/system-prompt-builder.js +7 -4
  44. package/dist/tool/timeout.d.ts +14 -0
  45. package/dist/tool/timeout.js +36 -0
  46. package/dist/tool/tool-confirmation.js +2 -1
  47. package/dist/tool/tool-executor.interface.d.ts +13 -3
  48. package/dist/tool/tool-orchestrator.d.ts +1 -1
  49. package/dist/tool/tool-orchestrator.js +6 -3
  50. package/package.json +3 -3
  51. package/dist/common/concurrency.d.ts +0 -79
  52. package/dist/common/concurrency.js +0 -121
  53. package/dist/common/queue-consumer.d.ts +0 -125
  54. package/dist/common/queue-consumer.js +0 -159
  55. package/dist/tool/mock-tool-executor.d.ts +0 -28
  56. 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
- | `mock` | 本地默认 | 不调真实 Tool |
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=mock # 或 mcp
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' | 'mock';
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
- if (response.status === 403) {
45
- try {
46
- const errBody = (await response.json());
47
- const errData = errBody.data ?? errBody;
48
- return { allowed: false, reason: errData.reason ?? 'NO_PERMISSION' };
49
- }
50
- catch {
51
- return { allowed: false, reason: 'NO_PERMISSION' };
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
- return {
59
- allowed: data.allowed === true,
60
- reason: data.allowed ? undefined : (data.reason ?? 'NO_PERMISSION'),
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';
@@ -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 = 'Governance service unavailable') {
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
- throw new PermissionDeniedError(result.reason ?? 'NO_PERMISSION');
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
- throw new PermissionDeniedError(result.reason ?? 'NO_PERMISSION');
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 workingDirectory = typeof process.cwd === 'function' ? process.cwd() : undefined;
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: 'hitl_timeout',
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 jailExtraRoots = skillDirs.map((dir) => dir.bundlePath);
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: 'hitl_rejected',
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
- * 仅用于本地闭环 (`EAP_TOOL_EXECUTION_MODE=mock`) 下驱动 ToolNode,
11
- * 让开发者无需接入真实 LLM 即可完成 tool 调用链路验证。
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/name/version/enabledTools 等视为引用。
83
+ * 含 type/execution 的视为内联定义;仅 code/toolset/version/enabled 等视为引用。
79
84
  */
80
85
  export declare function isInlineToolDeclaration(item: unknown): boolean;
81
86
  /**
82
- * 将 agent.manifest.toolsets 上的 enabled/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
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 skillRefsFromManifest(manifest) {
144
- const raw = manifest.skills;
145
- if (!Array.isArray(raw))
146
- return [];
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
- for (const item of raw) {
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
- out.push({ skillId: item });
171
+ if (item)
172
+ upsert({ skillId: item });
151
173
  continue;
152
174
  }
153
- if (item && typeof item === 'object') {
154
- const o = item;
155
- const skillId = String(o.code ?? '');
156
- if (!skillId)
157
- continue;
158
- out.push({
159
- skillId,
160
- name: o.name != null ? String(o.name) : undefined,
161
- version: o.version != null ? String(o.version) : undefined,
162
- description: o.description != null ? String(o.description) : undefined,
163
- sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
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/name/version/enabledTools 等视为引用。
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.name ?? '');
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
- /** 从 agent.manifest.toolsets 收集工具集装配引用。 */
208
- function toolsetsFromManifest(manifest) {
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 Array.isArray(manifest.toolsets) ? manifest.toolsets : []) {
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.toolsets 上的 enabled/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
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 ?? 10000,
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 ?? 30000,
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 ?? 30000,
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({
@@ -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';
@@ -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';