@gt-fe/eap-runtime 0.0.26 → 0.0.28

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.
@@ -28,7 +28,7 @@ export interface SnapshotSkillRef {
28
28
  name?: string;
29
29
  version?: string;
30
30
  description?: string;
31
- /** 可选:对应 skill 清单文件内容 sha256 */
31
+ /** 可选;Runtime 加载不比对。完整性由 Agent 包 / Hosting 预装负责 */
32
32
  sha256?: string;
33
33
  }
34
34
  export interface AgentSnapshotMeta {
@@ -583,15 +583,6 @@ export class FileSystemDeploymentSnapshot {
583
583
  }
584
584
  if (!manifest || !manifestPath)
585
585
  continue;
586
- const isUserOverridePath = bundlePath.includes('/users/') || bundlePath.includes('\\users\\');
587
- const isAuthorOverlay = extraRoots.some((root) => root && isPathInside(root, bundlePath));
588
- if (ref.sha256 &&
589
- !isUserOverridePath &&
590
- !isAuthorOverlay &&
591
- manifestPath.endsWith('.json')) {
592
- const actual = await sha256OfFile(manifestPath);
593
- await warnIfDigestMismatch(ref.sha256, actual, `skill ${ref.skillId}`, { path: manifestPath }, this.flags.requireChecksum || isRequireChecksum());
594
- }
595
586
  const skillId = String(ref.skillId);
596
587
  return {
597
588
  skillId,
@@ -85,12 +85,14 @@ export function createDevRuntime(options) {
85
85
  llmProvider = createDefaultLLMProvider(turnLog);
86
86
  llmProviderKind = 'echo';
87
87
  }
88
- // ── Tool Executor(dev+mcp 直连,缺配置失败 → 通用路由)──
88
+ // ── Tool Executor(dev+mcp:server MCP 走 Gateway,其余直连)──
89
89
  // overlay 必须在此处捕获:SDK createAgent 返回后会恢复 process.env。
90
90
  const overlayJail = captureOverlayJailOptions();
91
91
  const needsHarnessWrap = toolExecutionMode === 'mcp' && deploymentContext === 'dev';
92
92
  const innerExecutor = toolExecutionMode === 'mcp' && deploymentContext === 'dev'
93
- ? new DevToolExecutor()
93
+ ? new DevToolExecutor({
94
+ foundationUrl: foundationConfigured ? foundationUrl : undefined,
95
+ })
94
96
  : createToolExecutor({ foundationUrl, deploymentContext, jail: overlayJail });
95
97
  const toolExecutor = needsHarnessWrap
96
98
  ? withHarnessPrimitives(innerExecutor, overlayJail)
@@ -4,7 +4,8 @@
4
4
  * 仅在 `EAP_TOOL_EXECUTION_MODE=mcp` 且 `deploymentContext=dev` 装配。
5
5
  * 按清单分流,缺配置则失败,不回落 mock。
6
6
  *
7
- * - execution.protocol=mcp → DevMcpExecutor
7
+ * - execution.protocol=mcp 且 toolRuntime=server → McpToolExecutor(FOUNDATION_SERVICE_URL)
8
+ * - 其余 execution.protocol=mcp → DevMcpExecutor(直连 server.url / stdio)
8
9
  * - execution.protocol=http → DevHttpExecutor
9
10
  * - 能解析出 code handler → LocalToolExecutor
10
11
  * - 其余 → NOT_CONFIGURED
@@ -13,11 +14,14 @@ import { DevMcpExecutor } from './dev-mcp-executor.js';
13
14
  import type { IToolExecutor, McpListedTool, ToolCallRequest, ToolCallResult } from './tool-executor.interface.js';
14
15
  export interface DevToolExecutorOptions {
15
16
  mcp?: ConstructorParameters<typeof DevMcpExecutor>[0];
17
+ /** 绝对 http(s)。仅 toolRuntime=server 的 MCP 使用;缺省不直连 server.url。 */
18
+ foundationUrl?: string;
16
19
  }
17
20
  export declare class DevToolExecutor implements IToolExecutor {
18
21
  private readonly mcp;
19
22
  private readonly http;
20
23
  private readonly local;
24
+ private readonly gateway;
21
25
  constructor(options?: DevToolExecutorOptions);
22
26
  execute(request: ToolCallRequest): Promise<ToolCallResult>;
23
27
  listTools(request: ToolCallRequest): Promise<McpListedTool[]>;
@@ -4,7 +4,8 @@
4
4
  * 仅在 `EAP_TOOL_EXECUTION_MODE=mcp` 且 `deploymentContext=dev` 装配。
5
5
  * 按清单分流,缺配置则失败,不回落 mock。
6
6
  *
7
- * - execution.protocol=mcp → DevMcpExecutor
7
+ * - execution.protocol=mcp 且 toolRuntime=server → McpToolExecutor(FOUNDATION_SERVICE_URL)
8
+ * - 其余 execution.protocol=mcp → DevMcpExecutor(直连 server.url / stdio)
8
9
  * - execution.protocol=http → DevHttpExecutor
9
10
  * - 能解析出 code handler → LocalToolExecutor
10
11
  * - 其余 → NOT_CONFIGURED
@@ -13,16 +14,37 @@ import { EmptyInstallStore } from './create-tool-executor.js';
13
14
  import { DevMcpExecutor } from './dev-mcp-executor.js';
14
15
  import { LocalToolExecutor, resolveCodeExecutionFromRequest, } from './local-tool-executor.js';
15
16
  import { DevHttpExecutor, resolveHttpExecutionFromRequest } from './dev-http-executor.js';
17
+ import { isAbsoluteHttpUrl, McpToolExecutor } from './mcp-tool-executor.js';
16
18
  export class DevToolExecutor {
17
19
  mcp;
18
20
  http;
19
21
  local;
22
+ gateway;
20
23
  constructor(options = {}) {
21
24
  this.mcp = new DevMcpExecutor(options.mcp);
22
25
  this.http = new DevHttpExecutor();
23
26
  this.local = new LocalToolExecutor({ installStore: new EmptyInstallStore() });
27
+ const foundationUrl = options.foundationUrl?.trim();
28
+ this.gateway = foundationUrl && isAbsoluteHttpUrl(foundationUrl)
29
+ ? new McpToolExecutor({ baseUrl: foundationUrl })
30
+ : undefined;
24
31
  }
25
32
  async execute(request) {
33
+ if (hasMcpExecution(request.execution) && request.toolRuntime === 'server') {
34
+ if (!this.gateway) {
35
+ return {
36
+ toolCallId: request.toolCallId,
37
+ toolName: request.toolName,
38
+ content: '',
39
+ success: false,
40
+ error: `Dev MCP: tool "${request.toolName}" is toolRuntime=server and requires ` +
41
+ 'FOUNDATION_SERVICE_URL (absolute http(s)); refusing to dial server.url',
42
+ errorCode: 'NOT_CONFIGURED',
43
+ runtime: 'local',
44
+ };
45
+ }
46
+ return this.gateway.execute(request);
47
+ }
26
48
  if (hasMcpExecution(request.execution)) {
27
49
  return this.mcp.execute(request);
28
50
  }
@@ -48,6 +70,13 @@ export class DevToolExecutor {
48
70
  };
49
71
  }
50
72
  async listTools(request) {
73
+ if (hasMcpExecution(request.execution) && request.toolRuntime === 'server') {
74
+ if (!this.gateway) {
75
+ throw new Error(`Dev MCP: tool "${request.toolName}" is toolRuntime=server and requires ` +
76
+ 'FOUNDATION_SERVICE_URL (absolute http(s)); refusing to dial server.url');
77
+ }
78
+ return this.gateway.listTools(request);
79
+ }
51
80
  if (hasMcpExecution(request.execution)) {
52
81
  return this.mcp.listTools(request);
53
82
  }
@@ -34,16 +34,29 @@ function harnessDefinitions() {
34
34
  manifest: {
35
35
  id: 'builtin:read_file',
36
36
  name: 'read_file',
37
- description: '读取当前用户目录或预装 tools/skills 内的文本。要用某个技能时读该技能文件夹下的 SKILL.md。超限会截断并注明。',
37
+ description: '读取文本文件,成功时工具结果就是文件正文(纯文本,不是 JSON)。可读当前用户目录或预装 tools/skills;要用技能时读该技能目录下的 SKILL.md。大文件先整段读,若被截断(正文末尾会注明 truncated),再用 offset/limit 分段。路径越权或文件不存在会失败。不要用来读图/PDF 等二进制。写文件请用 write_file 或 append_to_file。',
38
38
  ...common,
39
39
  },
40
40
  inputSchema: {
41
41
  type: 'object',
42
+ additionalProperties: false,
42
43
  required: ['path'],
43
44
  properties: {
44
- path: { type: 'string', description: '相对工作目录或技能根的路径' },
45
- offset: { type: 'integer', description: '从第几行开始读,从 1 起。省略则从头。' },
46
- limit: { type: 'integer', description: '最多读多少行。省略则读到末尾或字节上限。' },
45
+ path: {
46
+ type: 'string',
47
+ minLength: 1,
48
+ description: '相对路径,例如 notes/todo.md 或 some-skill/SKILL.md。不能用 .. 跳出允许目录。',
49
+ },
50
+ offset: {
51
+ type: 'integer',
52
+ minimum: 1,
53
+ description: '从第几行开始读,从 1 起。省略则从头。只在大文件分段时用。',
54
+ },
55
+ limit: {
56
+ type: 'integer',
57
+ minimum: 1,
58
+ description: '最多读多少行。省略则读到末尾或字节上限。只在大文件分段时用。',
59
+ },
47
60
  },
48
61
  },
49
62
  },
@@ -53,15 +66,23 @@ function harnessDefinitions() {
53
66
  manifest: {
54
67
  id: 'builtin:write_file',
55
68
  name: 'write_file',
56
- description: '写入当前用户目录(含用户自己的 skills)。预装 tools / skills 只读。覆盖已有文件。',
69
+ description: '把文本整份写入当前用户目录(含用户自己的 skills)。没有该文件则创建;已有文件会整份换成 content,不是改某一行。只要在末尾加内容请用 append_to_file。不能写预装 tools/skills,不能写 .assembly.json 等平台文件。成功时工具结果是 JSON:{"ok":true,"path":"相对用户目录的路径","bytesWritten":字节数}。路径越权或禁写文件名会失败。',
57
70
  ...common,
58
71
  },
59
72
  inputSchema: {
60
73
  type: 'object',
74
+ additionalProperties: false,
61
75
  required: ['path', 'content'],
62
76
  properties: {
63
- path: { type: 'string' },
64
- content: { type: 'string' },
77
+ path: {
78
+ type: 'string',
79
+ minLength: 1,
80
+ description: '相对当前用户目录的路径,例如 notes/todo.md。不能写预装 tools/skills。',
81
+ },
82
+ content: {
83
+ type: 'string',
84
+ description: '文件的完整新内容。会覆盖原文件全部内容。',
85
+ },
65
86
  },
66
87
  },
67
88
  },
@@ -71,15 +92,23 @@ function harnessDefinitions() {
71
92
  manifest: {
72
93
  id: 'builtin:append_to_file',
73
94
  name: 'append_to_file',
74
- description: '向当前用户目录内的文件追加文本。文件不存在则创建。预装 tools / skills 只读。',
95
+ description: '在当前用户目录的文件末尾追加文本,不覆盖已有内容。没有该文件则创建。不要用它整份改写文件,那是 write_file。不能写预装 tools/skills,不能写 .assembly.json 等平台文件。成功时工具结果是 JSON:{"ok":true,"path":"相对用户目录的路径","bytesWritten":本次追加字节数}。路径越权或禁写文件名会失败。',
75
96
  ...common,
76
97
  },
77
98
  inputSchema: {
78
99
  type: 'object',
100
+ additionalProperties: false,
79
101
  required: ['path', 'content'],
80
102
  properties: {
81
- path: { type: 'string' },
82
- content: { type: 'string' },
103
+ path: {
104
+ type: 'string',
105
+ minLength: 1,
106
+ description: '相对当前用户目录的路径,例如 notes/todo.md。不能写预装 tools/skills。',
107
+ },
108
+ content: {
109
+ type: 'string',
110
+ description: '接到文件末尾的文本。不会删除或替换原有内容。',
111
+ },
83
112
  },
84
113
  },
85
114
  },
@@ -441,7 +470,7 @@ export class HarnessPrimitiveExecutor {
441
470
  }
442
471
  }
443
472
  async readFile(request) {
444
- const filePath = String(request.arguments.path ?? request.arguments.file ?? '');
473
+ const filePath = String(request.arguments.path ?? '');
445
474
  const workdir = this.workdirFor(request);
446
475
  const located = locateSkillRelativeRead(filePath, workdir, request.skillDir, this.extraRootsFor(request));
447
476
  const target = resolveJailedPath(located.path, this.rootsFor(request), {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gt-fe/eap-runtime",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "Enterprise Agent Platform — Runtime核心:Graph执行引擎、Task生命周期、Session管理、Checkpoint持久化",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",