@gt-fe/eap-runtime 0.0.8 → 0.0.11

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 (130) hide show
  1. package/README.md +15 -20
  2. package/dist/api/handlers/invoke.handler.js +7 -3
  3. package/dist/api/handlers/messages.handler.js +0 -1
  4. package/dist/api/handlers/stream.handler.js +8 -4
  5. package/dist/api/routes/agent.routes.d.ts +2 -2
  6. package/dist/api/routes/agent.routes.js +2 -2
  7. package/dist/checkpoint/checkpoint-ref-notify.d.ts +10 -0
  8. package/dist/checkpoint/checkpoint-ref-notify.js +59 -0
  9. package/dist/checkpoint/index.d.ts +1 -0
  10. package/dist/checkpoint/index.js +1 -0
  11. package/dist/checkpoint/pg-checkpoint-saver.js +25 -2
  12. package/dist/common/agent-code.d.ts +2 -4
  13. package/dist/common/agent-code.js +4 -5
  14. package/dist/common/types.d.ts +5 -5
  15. package/dist/common/types.js +2 -2
  16. package/dist/contracts/permission-checker.d.ts +1 -1
  17. package/dist/contracts/trace-collector.d.ts +16 -2
  18. package/dist/debug/llm-turn-log.d.ts +100 -0
  19. package/dist/debug/llm-turn-log.js +130 -0
  20. package/dist/debug/pg-llm-turn-log.d.ts +22 -0
  21. package/dist/debug/pg-llm-turn-log.js +57 -0
  22. package/dist/governance/governance-client.d.ts +1 -1
  23. package/dist/governance/governance-client.js +40 -16
  24. package/dist/governance/index.d.ts +2 -2
  25. package/dist/governance/index.js +1 -1
  26. package/dist/governance/permission-guard.d.ts +2 -1
  27. package/dist/governance/permission-guard.js +13 -4
  28. package/dist/graph/adapters/langgraph-checkpointer.js +3 -1
  29. package/dist/graph/adapters/langgraph.adapter.d.ts +1 -0
  30. package/dist/graph/adapters/langgraph.adapter.js +153 -92
  31. package/dist/graph/adapters/skill-read.d.ts +12 -0
  32. package/dist/graph/adapters/skill-read.js +63 -0
  33. package/dist/graph/adapters/subgraph-compiler.js +5 -0
  34. package/dist/graph/contracts/executable-graph.d.ts +11 -9
  35. package/dist/graph/contracts/executable-graph.js +1 -1
  36. package/dist/graph/hitl/hitl-handler.d.ts +10 -0
  37. package/dist/graph/hitl/hitl-handler.js +50 -6
  38. package/dist/graph/nodes/llm-node.d.ts +14 -0
  39. package/dist/graph/nodes/skill-bind-node.js +1 -2
  40. package/dist/graph/nodes/tool-node.d.ts +2 -0
  41. package/dist/graph/nodes/tool-node.js +50 -10
  42. package/dist/graph/trace-span.d.ts +22 -0
  43. package/dist/graph/trace-span.js +69 -0
  44. package/dist/index.d.ts +5 -2
  45. package/dist/index.js +3 -1
  46. package/dist/memory/compression/compression.repository.d.ts +1 -15
  47. package/dist/providers/echo-llm-provider.d.ts +1 -1
  48. package/dist/providers/echo-llm-provider.js +4 -3
  49. package/dist/providers/http-llm-provider.d.ts +4 -0
  50. package/dist/providers/http-llm-provider.js +129 -4
  51. package/dist/providers/local-llm-provider.d.ts +5 -1
  52. package/dist/providers/local-llm-provider.js +14 -6
  53. package/dist/providers/routing-llm-provider.d.ts +4 -0
  54. package/dist/providers/routing-llm-provider.js +12 -2
  55. package/dist/registry/agent-models.d.ts +1 -1
  56. package/dist/registry/agent-models.js +1 -1
  57. package/dist/registry/agent-registry-client.d.ts +3 -3
  58. package/dist/registry/deployment-snapshot.d.ts +17 -5
  59. package/dist/registry/deployment-snapshot.js +97 -49
  60. package/dist/registry/graph-loader.d.ts +2 -2
  61. package/dist/registry/graph-loader.js +43 -80
  62. package/dist/registry/index.d.ts +2 -2
  63. package/dist/registry/index.js +2 -2
  64. package/dist/registry/preload-errors.d.ts +1 -1
  65. package/dist/registry/preload-errors.js +1 -1
  66. package/dist/registry/skill-io-guard.js +1 -1
  67. package/dist/registry/skill-tree.d.ts +3 -0
  68. package/dist/registry/skill-tree.js +41 -3
  69. package/dist/runtime/agent-runtime.d.ts +42 -3
  70. package/dist/runtime/agent-runtime.js +129 -39
  71. package/dist/runtime/dev-runtime.d.ts +7 -4
  72. package/dist/runtime/dev-runtime.js +24 -21
  73. package/dist/runtime/index.d.ts +3 -3
  74. package/dist/runtime/index.js +1 -1
  75. package/dist/runtime/storage-profile.d.ts +19 -10
  76. package/dist/runtime/storage-profile.js +42 -29
  77. package/dist/runtime/types.d.ts +17 -19
  78. package/dist/server.js +2 -2
  79. package/dist/session/session.service.d.ts +5 -0
  80. package/dist/session/session.service.js +12 -0
  81. package/dist/sse/events/index.d.ts +5 -3
  82. package/dist/sse/events/index.js +2 -0
  83. package/dist/sse/events/skill-events.d.ts +12 -1
  84. package/dist/sse/events/skill-events.js +1 -1
  85. package/dist/sse/trace-collector.d.ts +10 -0
  86. package/dist/sse/trace-collector.js +1 -0
  87. package/dist/token/token-budget.service.d.ts +2 -2
  88. package/dist/token/token-budget.service.js +1 -1
  89. package/dist/tool/create-tool-executor.d.ts +1 -1
  90. package/dist/tool/create-tool-executor.js +3 -2
  91. package/dist/tool/dev-http-executor.d.ts +1 -1
  92. package/dist/tool/dev-http-executor.js +10 -7
  93. package/dist/tool/dev-mcp-executor.js +5 -3
  94. package/dist/tool/dev-tool-executor.d.ts +1 -1
  95. package/dist/tool/dev-tool-executor.js +2 -2
  96. package/dist/tool/harness-command.d.ts +32 -0
  97. package/dist/tool/harness-command.js +276 -0
  98. package/dist/tool/harness-primitives.d.ts +54 -0
  99. package/dist/tool/harness-primitives.js +492 -0
  100. package/dist/tool/http-tool-executor.js +16 -21
  101. package/dist/tool/index.d.ts +4 -2
  102. package/dist/tool/index.js +4 -2
  103. package/dist/tool/local-mcp-client.d.ts +1 -1
  104. package/dist/tool/local-mcp-client.js +54 -23
  105. package/dist/tool/local-tool-executor.d.ts +4 -4
  106. package/dist/tool/local-tool-executor.js +18 -16
  107. package/dist/tool/mcp-tool-executor.js +23 -7
  108. package/dist/tool/skill-script-refs.d.ts +20 -0
  109. package/dist/tool/skill-script-refs.js +62 -0
  110. package/dist/tool/system-prompt-builder.d.ts +61 -25
  111. package/dist/tool/system-prompt-builder.js +198 -92
  112. package/dist/tool/timeout.d.ts +14 -0
  113. package/dist/tool/timeout.js +36 -0
  114. package/dist/tool/tool-confirmation.js +2 -1
  115. package/dist/tool/tool-execution-router.d.ts +1 -1
  116. package/dist/tool/tool-execution-router.js +2 -2
  117. package/dist/tool/tool-executor.interface.d.ts +23 -7
  118. package/dist/tool/tool-orchestrator.d.ts +1 -1
  119. package/dist/tool/tool-orchestrator.js +6 -3
  120. package/dist/utils/format-error.d.ts +2 -2
  121. package/dist/utils/format-error.js +2 -2
  122. package/dist/utils/http-error.d.ts +2 -2
  123. package/dist/utils/http-error.js +2 -2
  124. package/package.json +3 -3
  125. package/dist/common/concurrency.d.ts +0 -79
  126. package/dist/common/concurrency.js +0 -121
  127. package/dist/common/queue-consumer.d.ts +0 -125
  128. package/dist/common/queue-consumer.js +0 -159
  129. package/dist/tool/mock-tool-executor.d.ts +0 -28
  130. package/dist/tool/mock-tool-executor.js +0 -65
@@ -7,12 +7,14 @@
7
7
  * {root}/agents/<agentCode>/<version>/users/<userId>/skills/<skillCode>/
8
8
  *
9
9
  * 命名:agentCode / toolsetCode / skillCode / toolName 均为语义化小写标识;
10
- * Skill 目录无版本层(维护形态为 ZIP 上传整包替换,包内必含 skill.md)。
10
+ * Skill 目录无版本层:包内必含 SKILL.md(Agent Skills)。
11
11
  */
12
12
  import { readdir, readFile, access } from 'node:fs/promises';
13
13
  import { createHash } from 'node:crypto';
14
14
  import path from 'node:path';
15
15
  import { constants as fsConstants } from 'node:fs';
16
+ import { parseSkillMd } from '@eap/contracts';
17
+ import { findSkillEntryFile } from './skill-tree.js';
16
18
  import { preloadMissing, preloadPackageCorrupt, } from './preload-errors.js';
17
19
  import { isRequireChecksum, resolvePreloadBehaviorFlags, } from './preload-flags.js';
18
20
  async function pathExists(p) {
@@ -138,29 +140,51 @@ async function pickLatestVersionDir(parent) {
138
140
  dirs.sort();
139
141
  return path.join(parent, dirs[dirs.length - 1]);
140
142
  }
141
- function skillRefsFromManifest(manifest) {
142
- const raw = manifest.skillRefs ?? manifest.skills;
143
- if (!Array.isArray(raw))
144
- 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) {
145
151
  const out = [];
146
- 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)]) {
147
170
  if (typeof item === 'string') {
148
- out.push({ skillId: item });
171
+ if (item)
172
+ upsert({ skillId: item });
149
173
  continue;
150
174
  }
151
- if (item && typeof item === 'object') {
152
- const o = item;
153
- const skillId = String(o.skill ?? o.skillId ?? o.skillCode ?? o.id ?? '');
154
- if (!skillId)
155
- continue;
156
- out.push({
157
- skillId,
158
- name: o.name != null ? String(o.name) : undefined,
159
- version: o.version != null ? String(o.version) : undefined,
160
- description: o.description != null ? String(o.description) : undefined,
161
- sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
162
- });
163
- }
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
+ });
164
188
  }
165
189
  return out;
166
190
  }
@@ -171,8 +195,8 @@ function parseStringList(value) {
171
195
  return out.length > 0 ? out : undefined;
172
196
  }
173
197
  /**
174
- * 装配引用(toolRefs / 简写 tools[])vs 内联完整 ToolManifest。
175
- * 含 type/execution 的视为内联定义;仅 toolset/name/version/enabledTools 等视为引用。
198
+ * 装配引用 vs 内联完整 ToolManifest。
199
+ * 含 type/execution 的视为内联定义;仅 code/toolset/version/enabled 等视为引用。
176
200
  */
177
201
  export function isInlineToolDeclaration(item) {
178
202
  if (!item || typeof item !== 'object' || Array.isArray(item))
@@ -189,7 +213,7 @@ function parseToolAssemblyRef(item) {
189
213
  if (isInlineToolDeclaration(item))
190
214
  return null;
191
215
  const o = item;
192
- const name = String(o.toolset ?? o.name ?? o.toolId ?? o.id ?? '');
216
+ const name = String(o.code ?? o.toolset ?? '');
193
217
  if (!name)
194
218
  return null;
195
219
  return {
@@ -197,14 +221,17 @@ function parseToolAssemblyRef(item) {
197
221
  toolId: o.toolId != null ? String(o.toolId) : undefined,
198
222
  version: o.version != null ? String(o.version) : undefined,
199
223
  sha256: typeof o.sha256 === 'string' ? o.sha256 : undefined,
200
- enabledTools: parseStringList(o.enabledTools),
224
+ enabledTools: parseStringList(o.enabled) ?? parseStringList(o.enabledTools),
201
225
  autoApprove: parseStringList(o.autoApprove),
202
226
  };
203
227
  }
204
228
  /**
205
- * 从 agent.manifest 收集工具集装配引用:优先 toolRefs[],再合并简写 tools[](非内联项)。
229
+ * 从 Agent 清单收集工具集装配引用。
230
+ * 现行 `toolsets`;兼容 CLI `toolRefs` 与更旧的 `tools`(内联完整 manifest 会跳过)。
231
+ * 项身份:`code` / `toolset`(字符串项即 code)。不用展示名 `name`。白名单:`enabled` / `enabledTools`。
232
+ * 两边都有时现行字段先写入;同名条目的 enabled/autoApprove 以先写入为准。
206
233
  */
207
- function toolRefsFromManifest(manifest) {
234
+ export function toolsetsFromManifest(manifest) {
208
235
  const out = [];
209
236
  const byName = new Map();
210
237
  const upsert = (ref) => {
@@ -214,11 +241,6 @@ function toolRefsFromManifest(manifest) {
214
241
  out.push(ref);
215
242
  return;
216
243
  }
217
- // 后写补全白名单等字段,不覆盖已有显式值
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,12 +248,11 @@ function toolRefsFromManifest(manifest) {
226
248
  if (!prev.toolId && ref.toolId)
227
249
  prev.toolId = ref.toolId;
228
250
  };
229
- for (const item of Array.isArray(manifest.toolRefs) ? manifest.toolRefs : []) {
230
- const ref = parseToolAssemblyRef(item);
231
- if (ref)
232
- upsert(ref);
233
- }
234
- for (const item of Array.isArray(manifest.tools) ? manifest.tools : []) {
251
+ for (const item of [
252
+ ...asArray(manifest.toolsets),
253
+ ...asArray(manifest.toolRefs),
254
+ ...asArray(manifest.tools),
255
+ ]) {
235
256
  const ref = parseToolAssemblyRef(item);
236
257
  if (ref)
237
258
  upsert(ref);
@@ -239,12 +260,12 @@ function toolRefsFromManifest(manifest) {
239
260
  return out;
240
261
  }
241
262
  /**
242
- * 将 agent.manifest.toolRefs 上的 enabledTools/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
263
+ * 将 agent.manifest 装配项上的 enabled/autoApprove 叠到 snapshot.tools[](snapshot 未带时)。
243
264
  */
244
265
  export function overlayToolRefPolicies(snapTools, manifest) {
245
266
  if (!manifest)
246
267
  return snapTools;
247
- const fromManifest = toolRefsFromManifest(manifest);
268
+ const fromManifest = toolsetsFromManifest(manifest);
248
269
  if (fromManifest.length === 0)
249
270
  return snapTools;
250
271
  const byName = new Map(fromManifest.map((r) => [r.name, r]));
@@ -259,6 +280,12 @@ export function overlayToolRefPolicies(snapTools, manifest) {
259
280
  };
260
281
  });
261
282
  }
283
+ function nonemptyRefs(refs) {
284
+ return refs && refs.length > 0 ? refs : undefined;
285
+ }
286
+ function nonemptySkillRefs(refs) {
287
+ return refs && refs.length > 0 ? refs : undefined;
288
+ }
262
289
  function normalizeSnapshotToolRefs(raw) {
263
290
  if (!Array.isArray(raw))
264
291
  return undefined;
@@ -281,7 +308,7 @@ function normalizeSnapshotSkillRefs(raw) {
281
308
  }
282
309
  if (item && typeof item === 'object') {
283
310
  const o = item;
284
- const skillId = String(o.skill ?? o.skillId ?? o.code ?? o.skillCode ?? o.id ?? '');
311
+ const skillId = String(o.code ?? o.skillId ?? '');
285
312
  if (!skillId)
286
313
  continue;
287
314
  out.push({
@@ -417,8 +444,8 @@ export class FileSystemDeploymentSnapshot {
417
444
  return {
418
445
  agentCode,
419
446
  version: String(snap.version ?? resolvedVersion),
420
- tools: normalizeSnapshotToolRefs(snap.tools) ?? toolRefsFromManifest(manifest ?? {}),
421
- skills: normalizeSnapshotSkillRefs(snap.skills) ?? skillRefsFromManifest(manifest ?? {}),
447
+ tools: nonemptyRefs(normalizeSnapshotToolRefs(snap.tools)) ?? toolsetsFromManifest(manifest ?? {}),
448
+ skills: nonemptySkillRefs(normalizeSnapshotSkillRefs(snap.skills)) ?? skillRefsFromManifest(manifest ?? {}),
422
449
  graph,
423
450
  agentDir,
424
451
  manifest: manifest ?? undefined,
@@ -428,7 +455,7 @@ export class FileSystemDeploymentSnapshot {
428
455
  return {
429
456
  agentCode,
430
457
  version: resolvedVersion,
431
- tools: toolRefsFromManifest(manifest ?? {}),
458
+ tools: toolsetsFromManifest(manifest ?? {}),
432
459
  skills: skillRefsFromManifest(manifest ?? {}),
433
460
  graph,
434
461
  agentDir,
@@ -497,10 +524,9 @@ export class FileSystemDeploymentSnapshot {
497
524
  if (!(await pathExists(bundlePath)))
498
525
  continue;
499
526
  await this.assertReadyIfRequired(bundlePath, `skill ${ref.skillId}`);
527
+ const entryFile = await findSkillEntryFile(bundlePath);
500
528
  const manifestPathCandidates = [
501
529
  path.join(bundlePath, 'skill.manifest.json'),
502
- path.join(bundlePath, 'skill.definition.json'),
503
- path.join(bundlePath, 'manifest.json'),
504
530
  ];
505
531
  let manifest = null;
506
532
  let manifestPath = null;
@@ -512,22 +538,44 @@ export class FileSystemDeploymentSnapshot {
512
538
  break;
513
539
  }
514
540
  }
541
+ if (!manifest && entryFile) {
542
+ const parsed = parseSkillMd(await readFile(entryFile, 'utf8'));
543
+ if (!parsed)
544
+ continue;
545
+ manifest = {
546
+ code: parsed.frontmatter.name,
547
+ name: parsed.frontmatter.name,
548
+ description: parsed.frontmatter.description,
549
+ ...(parsed.frontmatter.license ? { license: parsed.frontmatter.license } : {}),
550
+ };
551
+ manifestPath = entryFile;
552
+ }
515
553
  if (!manifest || !manifestPath)
516
554
  continue;
517
- // 用户装配层跳过 sha256 校验(用户覆盖版本与预装快照散列不同是正常行为)
555
+ if (!manifest.description && entryFile) {
556
+ const parsed = parseSkillMd(await readFile(entryFile, 'utf8'));
557
+ if (parsed?.frontmatter.description) {
558
+ manifest = { ...manifest, description: parsed.frontmatter.description };
559
+ if (!manifest.name)
560
+ manifest.name = parsed.frontmatter.name;
561
+ }
562
+ }
518
563
  const isUserOverridePath = bundlePath.includes('/users/') || bundlePath.includes('\\users\\');
519
564
  const isAuthorOverlay = extraRoots.some((root) => root && isPathInside(root, bundlePath));
520
- if (ref.sha256 && !isUserOverridePath && !isAuthorOverlay) {
565
+ if (ref.sha256 && !isUserOverridePath && !isAuthorOverlay && manifestPath.endsWith('.json')) {
521
566
  const actual = await sha256OfFile(manifestPath);
522
567
  await assertDigestMatch(ref.sha256, actual, `skill ${ref.skillId}`, { path: manifestPath });
523
568
  }
524
- const skillId = String(manifest.code ?? manifest.skillId ?? manifest.skillCode ?? manifest.id ?? ref.skillId);
569
+ const skillId = String(manifest.code ?? ref.skillId);
525
570
  return {
526
571
  skillId,
527
572
  name: String(manifest.name ?? ref.name ?? skillId),
528
573
  version: String(manifest.version ?? ref.version ?? path.basename(bundlePath)),
529
574
  description: manifest.description ?? ref.description,
530
- manifest,
575
+ manifest: {
576
+ ...manifest,
577
+ ...(entryFile ? { skillEntryFile: entryFile } : {}),
578
+ },
531
579
  bundlePath,
532
580
  };
533
581
  }
@@ -7,7 +7,7 @@
7
7
  import type { GraphDSL } from '../graph/contracts/executable-graph.js';
8
8
  import type { AgentRegistryClient } from './agent-registry-client.js';
9
9
  import type { DeploymentContext } from '../tool/tool-execution-router.js';
10
- import type { ILocalToolInstallStore } from '@gt-fe/eap-contracts';
10
+ import type { ILocalToolInstallStore } from '@eap/contracts';
11
11
  import { type LoadedToolDefinition } from '../tool/loaded-tool-definition.js';
12
12
  import type { LoadedSkillInfo } from '../tool/system-prompt-builder.js';
13
13
  import { type IDeploymentSnapshot } from './deployment-snapshot.js';
@@ -111,7 +111,7 @@ export declare class GraphLoader {
111
111
  loadToolDefinitions(agentCode: string, options?: LoadToolDefinitionsOptions): Promise<LoadedToolDefinition[]>;
112
112
  private loadToolDefinitionsFromSource;
113
113
  /**
114
- * 从预装快照加载已装配 Skill 完整定义(workflow / prompt / toolRefs)
114
+ * 加载已装配 Skill:SKILL.md 目录(Agent Skills)或可选 skill.manifest.json。
115
115
  * @param options.userId 用于解析 users/<userId>/skills(优先于 preinstall/skills)
116
116
  * @param options.allowMissingSkills 缺失时跳过而非抛错(warm 预热用)
117
117
  */
@@ -6,13 +6,14 @@
6
6
  */
7
7
  import { readFile } from 'node:fs/promises';
8
8
  import path from 'node:path';
9
- import { resolveAgentModelAllowlist, resolveAgentPrimaryModel } from './agent-models.js';
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';
13
- import { inspectAgentSkillTree, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, } from './skill-tree.js';
14
- function applyPrimaryModelToGraph(graph, primary) {
15
- if (!primary)
14
+ import { inspectAgentSkillTree, listSkillDirs, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, } from './skill-tree.js';
15
+ function applyDefaultModelToGraph(graph, defaultModel) {
16
+ if (!defaultModel)
16
17
  return graph;
17
18
  let changed = false;
18
19
  const nodes = graph.nodes.map((node) => {
@@ -22,7 +23,7 @@ function applyPrimaryModelToGraph(graph, primary) {
22
23
  if (current && current.toLowerCase() !== 'default')
23
24
  return node;
24
25
  changed = true;
25
- return { ...node, config: { ...node.config, model: primary } };
26
+ return { ...node, config: { ...node.config, model: defaultModel } };
26
27
  });
27
28
  return changed ? { ...graph, nodes } : graph;
28
29
  }
@@ -41,7 +42,7 @@ function assertGraphModelsAllowed(graph, manifest) {
41
42
  return graph;
42
43
  }
43
44
  function finalizeLoadedGraph(graph, manifest) {
44
- return assertGraphModelsAllowed(applyPrimaryModelToGraph(graph, resolveAgentPrimaryModel((manifest ?? {}))), manifest);
45
+ return assertGraphModelsAllowed(applyDefaultModelToGraph(graph, resolveAgentDefaultModel((manifest ?? {}))), manifest);
45
46
  }
46
47
  function asGraphDsl(value) {
47
48
  if (!value || typeof value !== 'object' || Array.isArray(value))
@@ -94,57 +95,8 @@ async function resolveSkillPrompt(manifest, bundlePath) {
94
95
  }
95
96
  return raw;
96
97
  }
97
- /**
98
- * 解析 Skill scripts[] 为虚拟 Tool 定义。
99
- * scripts 为可选/非标字段:Skill 包仅强制要求 skill.md,其余文件结构不限;
100
- * 存在 scripts 声明时才物化为可调用的本地 Tool。
101
- */
102
- function resolveSkillScripts(manifest, bundlePath) {
103
- const scripts = manifest.scripts;
104
- if (!Array.isArray(scripts))
105
- return [];
106
- const tools = [];
107
- for (const script of scripts) {
108
- if (!script || typeof script !== 'object')
109
- continue;
110
- const s = script;
111
- const name = s.name;
112
- const command = s.command;
113
- if (!name || !command)
114
- continue;
115
- const args = Array.isArray(s.args) ? s.args.map(String) : [];
116
- tools.push({
117
- toolId: `script:${name}`,
118
- name,
119
- manifest: {
120
- id: `script:${name}`,
121
- name,
122
- version: '0.0.0',
123
- type: 'code',
124
- status: 'active',
125
- description: s.description ?? `Skill script: ${name}`,
126
- execution: {
127
- runtime: command === 'python3' || command === 'python' ? 'python'
128
- : command === 'node' ? 'node'
129
- : 'executable',
130
- handler: args[0] ?? command,
131
- args: args.slice(1),
132
- timeout: 30000,
133
- sandbox: false,
134
- bundlePath,
135
- command,
136
- /** 标记为 Skill 虚拟脚本:Router 优先本机执行,不经 Gateway */
137
- localPreferred: true,
138
- source: 'skill-script',
139
- },
140
- },
141
- inputSchema: { type: 'object', properties: {}, additionalProperties: true },
142
- });
143
- }
144
- return tools;
145
- }
146
- function extractSkillToolRefs(manifest) {
147
- const refs = manifest.toolRefs ?? manifest.tools;
98
+ function extractSkillToolsets(manifest) {
99
+ const refs = manifest.toolsets;
148
100
  if (!Array.isArray(refs))
149
101
  return undefined;
150
102
  const out = [];
@@ -156,14 +108,15 @@ function extractSkillToolRefs(manifest) {
156
108
  if (!item || typeof item !== 'object')
157
109
  continue;
158
110
  const o = item;
111
+ const code = o.code != null ? String(o.code) : undefined;
112
+ const enabled = Array.isArray(o.enabled)
113
+ ? o.enabled.filter((x) => typeof x === 'string')
114
+ : undefined;
159
115
  out.push({
160
- toolId: o.toolId != null ? String(o.toolId) : undefined,
161
- name: o.name != null ? String(o.name) : o.toolset != null ? String(o.toolset) : undefined,
116
+ name: o.name != null ? String(o.name) : code,
162
117
  version: o.version != null ? String(o.version) : undefined,
163
- toolset: o.toolset != null ? String(o.toolset) : undefined,
164
- enabledTools: Array.isArray(o.enabledTools)
165
- ? o.enabledTools.filter((x) => typeof x === 'string')
166
- : undefined,
118
+ code,
119
+ enabled,
167
120
  autoApprove: Array.isArray(o.autoApprove)
168
121
  ? o.autoApprove.filter((x) => typeof x === 'string')
169
122
  : undefined,
@@ -305,7 +258,7 @@ function fromPreinstallTool(pre) {
305
258
  * 以工具集为管理单元:单个 MCP 服务 / 单个代码包 = 一个工具集,可含多个子工具;
306
259
  * 子工具继承集级 server/package 配置,合成各自的 execution。
307
260
  * 无 tools[] 时回退为单工具 manifest(tool.manifest.json 结构)。
308
- * enabledTools 为可选白名单(agent.manifest toolRefs);缺省启用全部子工具。
261
+ * enabled 为可选白名单(agent.manifest toolsets[].enabled);缺省启用全部子工具。
309
262
  */
310
263
  function expandPreinstallToolset(pre, options) {
311
264
  const m = pre.manifest;
@@ -348,7 +301,7 @@ function expandPreinstallToolset(pre, options) {
348
301
  baseUrl: st.baseUrl ?? gateway.baseUrl,
349
302
  pathTemplate: st.pathTemplate,
350
303
  allowedHosts: gateway.allowedHosts,
351
- timeout: st.timeout ?? gateway.timeout ?? 10000,
304
+ timeout: st.timeout ?? gateway.timeout ?? DEFAULT_HTTP_TOOL_TIMEOUT_SEC,
352
305
  };
353
306
  }
354
307
  else if (setType === 'mcp') {
@@ -358,7 +311,7 @@ function expandPreinstallToolset(pre, options) {
358
311
  transport: server?.transport ?? (server?.url ? 'streamable_http' : 'stdio'),
359
312
  server,
360
313
  toolName: name,
361
- timeout: st.timeout ?? server?.timeout ?? 30000,
314
+ timeout: st.timeout ?? server?.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
362
315
  };
363
316
  }
364
317
  else {
@@ -367,7 +320,7 @@ function expandPreinstallToolset(pre, options) {
367
320
  runtime: st.runtime ?? 'node',
368
321
  handler: st.handler,
369
322
  args: st.args,
370
- timeout: st.timeout ?? 30000,
323
+ timeout: st.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
371
324
  sandbox: st.sandbox ?? pkg?.sandbox ?? false,
372
325
  bundlePath: pre.bundlePath,
373
326
  };
@@ -659,7 +612,7 @@ export class GraphLoader {
659
612
  if (graphFromManifest && typeof graphFromManifest === 'object') {
660
613
  return finalizeLoadedGraph(yamlGraphToDsl(agentCode, graphFromManifest), manifest);
661
614
  }
662
- const model = resolveAgentPrimaryModel(manifest) ?? 'default';
615
+ const model = resolveAgentDefaultModel(manifest) ?? 'default';
663
616
  return {
664
617
  ...DEFAULT_GRAPH_DSL,
665
618
  name: agentCode,
@@ -851,7 +804,7 @@ export class GraphLoader {
851
804
  return definitions;
852
805
  }
853
806
  /**
854
- * 从预装快照加载已装配 Skill 完整定义(workflow / prompt / toolRefs)
807
+ * 加载已装配 Skill:SKILL.md 目录(Agent Skills)或可选 skill.manifest.json。
855
808
  * @param options.userId 用于解析 users/<userId>/skills(优先于 preinstall/skills)
856
809
  * @param options.allowMissingSkills 缺失时跳过而非抛错(warm 预热用)
857
810
  */
@@ -887,10 +840,8 @@ export class GraphLoader {
887
840
  const workflow = asGraphDsl(pre.manifest.workflow) ??
888
841
  asGraphDsl(pre.manifest.graph) ??
889
842
  asGraphDsl(pre.manifest.definitionSnapshot);
890
- // 解析 prompt:支持文件路径引用(./ 开头)
891
843
  const prompt = await resolveSkillPrompt(pre.manifest, pre.bundlePath);
892
- // 解析 scripts[] 为虚拟 Tool
893
- const scriptTools = resolveSkillScripts(pre.manifest, pre.bundlePath);
844
+ const entryFile = typeof pre.manifest.skillEntryFile === 'string' ? pre.manifest.skillEntryFile : undefined;
894
845
  skills.push({
895
846
  skillId: pre.skillId,
896
847
  name: pre.name,
@@ -898,10 +849,11 @@ export class GraphLoader {
898
849
  version: pre.version,
899
850
  workflow,
900
851
  prompt,
901
- toolRefs: extractSkillToolRefs(pre.manifest),
852
+ bundlePath: pre.bundlePath,
853
+ entryFile,
854
+ toolsets: extractSkillToolsets(pre.manifest),
902
855
  inputDef: pre.manifest.inputDef,
903
856
  outputDef: pre.manifest.outputDef,
904
- scriptTools: scriptTools.length > 0 ? scriptTools : undefined,
905
857
  });
906
858
  }
907
859
  else if (!this.strictPreinstall) {
@@ -940,16 +892,25 @@ export class GraphLoader {
940
892
  * 磁盘多出来的未声明目录不进选择清单;正文热加载仍看已装配目录的 mtime。
941
893
  */
942
894
  async resolveSkillRefs(snap, agentDir, userId) {
895
+ const byId = new Map();
896
+ const add = (ref) => {
897
+ if (ref.skillId && !byId.has(ref.skillId))
898
+ byId.set(ref.skillId, ref);
899
+ };
943
900
  if (agentDir) {
944
901
  const assembly = await readSkillAssembly(agentDir, userId);
945
902
  if (assembly && assembly.skills.length > 0) {
946
- return assembly.skills.map((skillId) => ({ skillId }));
903
+ for (const skillId of assembly.skills)
904
+ add({ skillId });
947
905
  }
948
906
  }
949
- const byId = new Map();
950
- for (const ref of snap?.skills ?? []) {
951
- if (ref.skillId)
952
- byId.set(ref.skillId, ref);
907
+ if (byId.size === 0) {
908
+ for (const ref of snap?.skills ?? [])
909
+ add(ref);
910
+ }
911
+ for (const root of this.localSkillRoots()) {
912
+ for (const skillId of await listSkillDirs(root))
913
+ add({ skillId });
953
914
  }
954
915
  return [...byId.values()];
955
916
  }
@@ -981,5 +942,7 @@ export class GraphLoader {
981
942
  }
982
943
  function resolveLocalSkillsDir(explicit) {
983
944
  const candidate = explicit?.trim() || process.env.EAP_LOCAL_SKILLS_DIR?.trim();
984
- return candidate || undefined;
945
+ if (candidate)
946
+ return path.resolve(candidate);
947
+ return path.resolve(process.cwd(), 'skills');
985
948
  }
@@ -1,9 +1,9 @@
1
- export { resolveAgentPrimaryModel, resolveAgentModelAllowlist, resolveDeclaredModels } from './agent-models.js';
1
+ export { resolveAgentDefaultModel, resolveAgentModelAllowlist, resolveDeclaredModels } from './agent-models.js';
2
2
  export { createAgentRegistryClient, type AgentRegistryClient, type AgentRegistryRecord, type AgentManifest } from './agent-registry-client.js';
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';
@@ -1,9 +1,9 @@
1
- export { resolveAgentPrimaryModel, resolveAgentModelAllowlist, resolveDeclaredModels } from './agent-models.js';
1
+ export { resolveAgentDefaultModel, resolveAgentModelAllowlist, resolveDeclaredModels } from './agent-models.js';
2
2
  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';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 预装加载错误 — 对齐 runtime.preload.* / 联调契约
3
3
  */
4
- import { AppError, type ErrorCode } from '@gt-fe/eap-contracts';
4
+ import { AppError, type ErrorCode } from '@eap/contracts';
5
5
  export declare function preloadError(code: ErrorCode, message: string, details?: unknown): AppError;
6
6
  export declare function preloadMissing(message: string, details?: unknown): AppError;
7
7
  export declare function preloadManifestNotFound(message: string, details?: unknown): AppError;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 预装加载错误 — 对齐 runtime.preload.* / 联调契约
3
3
  */
4
- import { AppError, ErrorCodes } from '@gt-fe/eap-contracts';
4
+ import { AppError, ErrorCodes } from '@eap/contracts';
5
5
  export function preloadError(code, message, details) {
6
6
  return new AppError(code, message, {
7
7
  exposeMessage: true,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Skill inputDef / outputDef 轻量校验(默认开启;EAP_PRELOAD_VALIDATE_SKILL_IO=0 关闭)
3
3
  */
4
- import { AppError, ErrorCodes } from '@gt-fe/eap-contracts';
4
+ import { AppError, ErrorCodes } from '@eap/contracts';
5
5
  import { isValidateSkillIo } from './preload-flags.js';
6
6
  function asRecord(value) {
7
7
  if (value && typeof value === 'object' && !Array.isArray(value)) {
@@ -3,6 +3,9 @@ export interface AgentSkillTree {
3
3
  /** `${count}:${maxMtimeMs}`;增删改任一 skill 文件都会变 */
4
4
  stamp: string;
5
5
  }
6
+ /** Agent Skills 入口:目录内的 SKILL.md(规范名优先)。 */
7
+ export declare function findSkillEntryFile(bundlePath: string): Promise<string | null>;
8
+ export declare function listSkillDirs(root: string): Promise<string[]>;
6
9
  export interface SkillAssembly {
7
10
  skills: string[];
8
11
  source: string;
@@ -10,6 +10,7 @@ import { readdir, stat, access, readFile } from 'node:fs/promises';
10
10
  import { watch } from 'node:fs';
11
11
  import { constants as fsConstants } from 'node:fs';
12
12
  import path from 'node:path';
13
+ import { SKILL_ENTRY_CANDIDATES } from '@eap/contracts';
13
14
  const SKILL_CODE = /^[a-z0-9][a-z0-9-]*$/;
14
15
  async function exists(p) {
15
16
  try {
@@ -20,6 +21,43 @@ async function exists(p) {
20
21
  return false;
21
22
  }
22
23
  }
24
+ /** Agent Skills 入口:目录内的 SKILL.md(规范名优先)。 */
25
+ export async function findSkillEntryFile(bundlePath) {
26
+ for (const name of SKILL_ENTRY_CANDIDATES) {
27
+ const candidate = path.join(bundlePath, name);
28
+ if (await exists(candidate))
29
+ return candidate;
30
+ }
31
+ try {
32
+ const files = await readdir(bundlePath);
33
+ const hit = files.find((file) => file.toLowerCase() === 'skill.md');
34
+ return hit ? path.join(bundlePath, hit) : null;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ export async function listSkillDirs(root) {
41
+ let names = [];
42
+ try {
43
+ names = await readdir(root);
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ const codes = [];
49
+ for (const name of names) {
50
+ if (!SKILL_CODE.test(name))
51
+ continue;
52
+ const bundle = path.join(root, name);
53
+ const info = await stat(bundle).catch(() => undefined);
54
+ if (!info?.isDirectory())
55
+ continue;
56
+ if (await findSkillEntryFile(bundle))
57
+ codes.push(name);
58
+ }
59
+ return codes.sort();
60
+ }
23
61
  async function maxMtime(filePath, fallback = 0) {
24
62
  try {
25
63
  const info = await stat(filePath);
@@ -101,9 +139,9 @@ export async function inspectAgentSkillTree(agentDir, userId, extraRoots = []) {
101
139
  const bundleStat = await stat(bundle).catch(() => undefined);
102
140
  if (!bundleStat?.isDirectory())
103
141
  continue;
104
- const hasMain = (await exists(path.join(bundle, 'skill.md'))) ||
105
- (await exists(path.join(bundle, 'skill.manifest.json')));
106
- if (!hasMain)
142
+ const hasEntry = await findSkillEntryFile(bundle);
143
+ const hasOverlay = await exists(path.join(bundle, 'skill.manifest.json'));
144
+ if (!hasEntry && !hasOverlay)
107
145
  continue;
108
146
  codes.add(name);
109
147
  latest = Math.max(latest, bundleStat.mtimeMs);