@gt-fe/eap-runtime 0.0.8
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 +323 -0
- package/dist/api/handlers/index.d.ts +3 -0
- package/dist/api/handlers/index.js +4 -0
- package/dist/api/handlers/invoke.handler.d.ts +77 -0
- package/dist/api/handlers/invoke.handler.js +411 -0
- package/dist/api/handlers/messages.handler.d.ts +53 -0
- package/dist/api/handlers/messages.handler.js +80 -0
- package/dist/api/handlers/stream.handler.d.ts +92 -0
- package/dist/api/handlers/stream.handler.js +432 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +4 -0
- package/dist/api/middleware/auth.middleware.d.ts +96 -0
- package/dist/api/middleware/auth.middleware.js +158 -0
- package/dist/api/middleware/index.d.ts +1 -0
- package/dist/api/middleware/index.js +2 -0
- package/dist/api/routes/agent.routes.d.ts +44 -0
- package/dist/api/routes/agent.routes.js +204 -0
- package/dist/api/routes/index.d.ts +3 -0
- package/dist/api/routes/index.js +4 -0
- package/dist/api/routes/session.routes.d.ts +82 -0
- package/dist/api/routes/session.routes.js +169 -0
- package/dist/api/routes/task.routes.d.ts +75 -0
- package/dist/api/routes/task.routes.js +108 -0
- package/dist/checkpoint/checkpoint-serializer.d.ts +58 -0
- package/dist/checkpoint/checkpoint-serializer.js +81 -0
- package/dist/checkpoint/composite-checkpoint-saver.d.ts +42 -0
- package/dist/checkpoint/composite-checkpoint-saver.js +118 -0
- package/dist/checkpoint/contracts/checkpoint-saver.contract.d.ts +65 -0
- package/dist/checkpoint/contracts/checkpoint-saver.contract.js +12 -0
- package/dist/checkpoint/contracts/index.d.ts +1 -0
- package/dist/checkpoint/contracts/index.js +1 -0
- package/dist/checkpoint/file-checkpoint-saver.d.ts +19 -0
- package/dist/checkpoint/file-checkpoint-saver.js +98 -0
- package/dist/checkpoint/hybrid-checkpoint-saver.d.ts +130 -0
- package/dist/checkpoint/hybrid-checkpoint-saver.js +211 -0
- package/dist/checkpoint/in-memory-checkpoint-saver.d.ts +14 -0
- package/dist/checkpoint/in-memory-checkpoint-saver.js +46 -0
- package/dist/checkpoint/index.d.ts +16 -0
- package/dist/checkpoint/index.js +13 -0
- package/dist/checkpoint/mongo-checkpoint-saver.d.ts +38 -0
- package/dist/checkpoint/mongo-checkpoint-saver.js +56 -0
- package/dist/checkpoint/pg-checkpoint-saver.d.ts +59 -0
- package/dist/checkpoint/pg-checkpoint-saver.js +140 -0
- package/dist/checkpoint/redis-checkpoint-saver.d.ts +68 -0
- package/dist/checkpoint/redis-checkpoint-saver.js +173 -0
- package/dist/checkpoint/restore-checkpoint.d.ts +33 -0
- package/dist/checkpoint/restore-checkpoint.js +33 -0
- package/dist/common/agent-code.d.ts +10 -0
- package/dist/common/agent-code.js +12 -0
- package/dist/common/concurrency.d.ts +79 -0
- package/dist/common/concurrency.js +121 -0
- package/dist/common/health.d.ts +40 -0
- package/dist/common/health.js +37 -0
- package/dist/common/index.d.ts +5 -0
- package/dist/common/index.js +5 -0
- package/dist/common/logger.d.ts +34 -0
- package/dist/common/logger.js +38 -0
- package/dist/common/queue-consumer.d.ts +125 -0
- package/dist/common/queue-consumer.js +159 -0
- package/dist/common/trace-id.d.ts +2 -0
- package/dist/common/trace-id.js +8 -0
- package/dist/common/types.d.ts +104 -0
- package/dist/common/types.js +14 -0
- package/dist/contracts/index.d.ts +11 -0
- package/dist/contracts/index.js +10 -0
- package/dist/contracts/permission-checker.d.ts +10 -0
- package/dist/contracts/permission-checker.js +4 -0
- package/dist/contracts/trace-collector.d.ts +211 -0
- package/dist/contracts/trace-collector.js +13 -0
- package/dist/governance/governance-client.d.ts +38 -0
- package/dist/governance/governance-client.js +95 -0
- package/dist/governance/index.d.ts +7 -0
- package/dist/governance/index.js +5 -0
- package/dist/governance/permission-guard.d.ts +19 -0
- package/dist/governance/permission-guard.js +59 -0
- package/dist/graph/adapters/index.d.ts +3 -0
- package/dist/graph/adapters/index.js +3 -0
- package/dist/graph/adapters/langgraph-checkpointer.d.ts +40 -0
- package/dist/graph/adapters/langgraph-checkpointer.js +211 -0
- package/dist/graph/adapters/langgraph.adapter.d.ts +190 -0
- package/dist/graph/adapters/langgraph.adapter.js +1303 -0
- package/dist/graph/adapters/subgraph-compiler.d.ts +39 -0
- package/dist/graph/adapters/subgraph-compiler.js +248 -0
- package/dist/graph/condition-evaluator.d.ts +57 -0
- package/dist/graph/condition-evaluator.js +162 -0
- package/dist/graph/contracts/executable-graph.d.ts +340 -0
- package/dist/graph/contracts/executable-graph.js +10 -0
- package/dist/graph/contracts/index.d.ts +2 -0
- package/dist/graph/contracts/index.js +2 -0
- package/dist/graph/contracts/state-graph.contract.d.ts +76 -0
- package/dist/graph/contracts/state-graph.contract.js +11 -0
- package/dist/graph/hitl/hitl-handler.d.ts +199 -0
- package/dist/graph/hitl/hitl-handler.js +480 -0
- package/dist/graph/hitl/index.d.ts +1 -0
- package/dist/graph/hitl/index.js +1 -0
- package/dist/graph/index.d.ts +7 -0
- package/dist/graph/index.js +7 -0
- package/dist/graph/nodes/index.d.ts +2 -0
- package/dist/graph/nodes/index.js +2 -0
- package/dist/graph/nodes/llm-node.d.ts +182 -0
- package/dist/graph/nodes/llm-node.js +281 -0
- package/dist/graph/nodes/skill-bind-node.d.ts +32 -0
- package/dist/graph/nodes/skill-bind-node.js +116 -0
- package/dist/graph/nodes/tool-node.d.ts +75 -0
- package/dist/graph/nodes/tool-node.js +324 -0
- package/dist/graph/resolve-graph-prompt.d.ts +5 -0
- package/dist/graph/resolve-graph-prompt.js +75 -0
- package/dist/graph/retry/budget-aware-retry.d.ts +91 -0
- package/dist/graph/retry/budget-aware-retry.js +126 -0
- package/dist/graph/retry/index.d.ts +9 -0
- package/dist/graph/retry/index.js +8 -0
- package/dist/graph/retry/node-retry.d.ts +123 -0
- package/dist/graph/retry/node-retry.js +235 -0
- package/dist/graph/skill-audit-recorder.d.ts +126 -0
- package/dist/graph/skill-audit-recorder.js +114 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +32 -0
- package/dist/memory/compression/compression-stats.d.ts +109 -0
- package/dist/memory/compression/compression-stats.js +144 -0
- package/dist/memory/compression/compression.repository.d.ts +62 -0
- package/dist/memory/compression/compression.repository.js +71 -0
- package/dist/memory/compression/index.d.ts +10 -0
- package/dist/memory/compression/index.js +15 -0
- package/dist/memory/compression/llm-summarize.d.ts +58 -0
- package/dist/memory/compression/llm-summarize.js +192 -0
- package/dist/memory/compression/sliding-window.compression.d.ts +60 -0
- package/dist/memory/compression/sliding-window.compression.js +175 -0
- package/dist/memory/index.d.ts +4 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/long-term-memory.service.d.ts +94 -0
- package/dist/memory/long-term-memory.service.js +120 -0
- package/dist/memory/message-compression.service.d.ts +128 -0
- package/dist/memory/message-compression.service.js +69 -0
- package/dist/memory/pg-memory.repository.d.ts +44 -0
- package/dist/memory/pg-memory.repository.js +108 -0
- package/dist/memory/semantic-retrieval.service.d.ts +148 -0
- package/dist/memory/semantic-retrieval.service.js +238 -0
- package/dist/providers/echo-llm-provider.d.ts +10 -0
- package/dist/providers/echo-llm-provider.js +87 -0
- package/dist/providers/http-llm-provider.d.ts +35 -0
- package/dist/providers/http-llm-provider.js +404 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +5 -0
- package/dist/providers/local-llm-provider.d.ts +27 -0
- package/dist/providers/local-llm-provider.js +105 -0
- package/dist/providers/resolve-llm-model.d.ts +13 -0
- package/dist/providers/resolve-llm-model.js +30 -0
- package/dist/providers/routing-llm-provider.d.ts +28 -0
- package/dist/providers/routing-llm-provider.js +79 -0
- package/dist/registry/agent-models.d.ts +1 -0
- package/dist/registry/agent-models.js +1 -0
- package/dist/registry/agent-registry-client.d.ts +56 -0
- package/dist/registry/agent-registry-client.js +36 -0
- package/dist/registry/definition-cache.d.ts +37 -0
- package/dist/registry/definition-cache.js +82 -0
- package/dist/registry/deployment-snapshot.d.ts +99 -0
- package/dist/registry/deployment-snapshot.js +542 -0
- package/dist/registry/graph-loader.d.ts +134 -0
- package/dist/registry/graph-loader.js +985 -0
- package/dist/registry/index.d.ts +9 -0
- package/dist/registry/index.js +9 -0
- package/dist/registry/preload-errors.d.ts +13 -0
- package/dist/registry/preload-errors.js +35 -0
- package/dist/registry/preload-flags.d.ts +22 -0
- package/dist/registry/preload-flags.js +44 -0
- package/dist/registry/skill-io-guard.d.ts +25 -0
- package/dist/registry/skill-io-guard.js +98 -0
- package/dist/registry/skill-tree.d.ts +27 -0
- package/dist/registry/skill-tree.js +183 -0
- package/dist/runtime/agent-runtime.d.ts +106 -0
- package/dist/runtime/agent-runtime.js +777 -0
- package/dist/runtime/dev-runtime.d.ts +69 -0
- package/dist/runtime/dev-runtime.js +199 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/storage-profile.d.ts +50 -0
- package/dist/runtime/storage-profile.js +138 -0
- package/dist/runtime/types.d.ts +120 -0
- package/dist/runtime/types.js +9 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +161 -0
- package/dist/session/compression-middleware.d.ts +126 -0
- package/dist/session/compression-middleware.js +230 -0
- package/dist/session/file-message.repository.d.ts +25 -0
- package/dist/session/file-message.repository.js +78 -0
- package/dist/session/file-session.repository.d.ts +72 -0
- package/dist/session/file-session.repository.js +212 -0
- package/dist/session/index.d.ts +13 -0
- package/dist/session/index.js +12 -0
- package/dist/session/message.service.d.ts +80 -0
- package/dist/session/message.service.js +128 -0
- package/dist/session/persist-turn-messages.d.ts +145 -0
- package/dist/session/persist-turn-messages.js +325 -0
- package/dist/session/pg-message.repository.d.ts +49 -0
- package/dist/session/pg-message.repository.js +149 -0
- package/dist/session/pg-session.repository.d.ts +46 -0
- package/dist/session/pg-session.repository.js +117 -0
- package/dist/session/session-context.service.d.ts +49 -0
- package/dist/session/session-context.service.js +66 -0
- package/dist/session/session.service.d.ts +194 -0
- package/dist/session/session.service.js +166 -0
- package/dist/sse/connection-event-logger.d.ts +21 -0
- package/dist/sse/connection-event-logger.js +33 -0
- package/dist/sse/contracts/index.d.ts +1 -0
- package/dist/sse/contracts/index.js +1 -0
- package/dist/sse/contracts/sse-emitter.contract.d.ts +74 -0
- package/dist/sse/contracts/sse-emitter.contract.js +11 -0
- package/dist/sse/event-buffer.d.ts +20 -0
- package/dist/sse/event-buffer.js +45 -0
- package/dist/sse/events/code-events.d.ts +19 -0
- package/dist/sse/events/code-events.js +9 -0
- package/dist/sse/events/collaboration-events.d.ts +37 -0
- package/dist/sse/events/collaboration-events.js +11 -0
- package/dist/sse/events/connection-events.d.ts +13 -0
- package/dist/sse/events/connection-events.js +9 -0
- package/dist/sse/events/file-events.d.ts +29 -0
- package/dist/sse/events/file-events.js +10 -0
- package/dist/sse/events/hitl-events.d.ts +33 -0
- package/dist/sse/events/hitl-events.js +10 -0
- package/dist/sse/events/index.d.ts +107 -0
- package/dist/sse/events/index.js +96 -0
- package/dist/sse/events/plan-events.d.ts +38 -0
- package/dist/sse/events/plan-events.js +11 -0
- package/dist/sse/events/reasoning-events.d.ts +35 -0
- package/dist/sse/events/reasoning-events.js +13 -0
- package/dist/sse/events/response-events.d.ts +25 -0
- package/dist/sse/events/response-events.js +12 -0
- package/dist/sse/events/session-events.d.ts +43 -0
- package/dist/sse/events/session-events.js +12 -0
- package/dist/sse/events/skill-events.d.ts +48 -0
- package/dist/sse/events/skill-events.js +11 -0
- package/dist/sse/events/stats-events.d.ts +44 -0
- package/dist/sse/events/stats-events.js +12 -0
- package/dist/sse/events/tool-events.d.ts +68 -0
- package/dist/sse/events/tool-events.js +14 -0
- package/dist/sse/index.d.ts +8 -0
- package/dist/sse/index.js +8 -0
- package/dist/sse/sse-connection-manager.d.ts +116 -0
- package/dist/sse/sse-connection-manager.js +185 -0
- package/dist/sse/sse-emitter.d.ts +108 -0
- package/dist/sse/sse-emitter.js +210 -0
- package/dist/sse/sse-heartbeat.d.ts +58 -0
- package/dist/sse/sse-heartbeat.js +76 -0
- package/dist/sse/trace-collector.d.ts +60 -0
- package/dist/sse/trace-collector.js +107 -0
- package/dist/task/contracts/index.d.ts +2 -0
- package/dist/task/contracts/index.js +1 -0
- package/dist/task/contracts/task-manager.contract.d.ts +160 -0
- package/dist/task/contracts/task-manager.contract.js +10 -0
- package/dist/task/index.d.ts +7 -0
- package/dist/task/index.js +5 -0
- package/dist/task/pg-task.repository.d.ts +47 -0
- package/dist/task/pg-task.repository.js +131 -0
- package/dist/task/task-progress-tracker.d.ts +67 -0
- package/dist/task/task-progress-tracker.js +80 -0
- package/dist/task/task-timeout.d.ts +70 -0
- package/dist/task/task-timeout.js +116 -0
- package/dist/task/task.service.d.ts +84 -0
- package/dist/task/task.service.js +233 -0
- package/dist/token/compression-budget-integration.d.ts +145 -0
- package/dist/token/compression-budget-integration.js +185 -0
- package/dist/token/context-window-budget.d.ts +113 -0
- package/dist/token/context-window-budget.js +134 -0
- package/dist/token/contracts/index.d.ts +1 -0
- package/dist/token/contracts/index.js +1 -0
- package/dist/token/contracts/token-budget.contract.d.ts +77 -0
- package/dist/token/contracts/token-budget.contract.js +11 -0
- package/dist/token/index.d.ts +12 -0
- package/dist/token/index.js +10 -0
- package/dist/token/pg-token-budget.repository.d.ts +39 -0
- package/dist/token/pg-token-budget.repository.js +116 -0
- package/dist/token/session-budget-checker.d.ts +54 -0
- package/dist/token/session-budget-checker.js +72 -0
- package/dist/token/token-budget-guard.d.ts +66 -0
- package/dist/token/token-budget-guard.js +97 -0
- package/dist/token/token-budget.service.d.ts +86 -0
- package/dist/token/token-budget.service.js +130 -0
- package/dist/token/token-detail-mode.d.ts +73 -0
- package/dist/token/token-detail-mode.js +107 -0
- package/dist/token/token-estimator.d.ts +80 -0
- package/dist/token/token-estimator.js +134 -0
- package/dist/token/token-stats.service.d.ts +88 -0
- package/dist/token/token-stats.service.js +94 -0
- package/dist/tool/create-tool-executor.d.ts +33 -0
- package/dist/tool/create-tool-executor.js +60 -0
- package/dist/tool/dev-http-executor.d.ts +18 -0
- package/dist/tool/dev-http-executor.js +96 -0
- package/dist/tool/dev-mcp-executor.d.ts +29 -0
- package/dist/tool/dev-mcp-executor.js +84 -0
- package/dist/tool/dev-tool-executor.d.ts +23 -0
- package/dist/tool/dev-tool-executor.js +55 -0
- package/dist/tool/file-artifact.d.ts +11 -0
- package/dist/tool/file-artifact.js +90 -0
- package/dist/tool/http-tool-executor.d.ts +17 -0
- package/dist/tool/http-tool-executor.js +158 -0
- package/dist/tool/index.d.ts +18 -0
- package/dist/tool/index.js +17 -0
- package/dist/tool/loaded-tool-definition.d.ts +35 -0
- package/dist/tool/loaded-tool-definition.js +9 -0
- package/dist/tool/local-mcp-client.d.ts +23 -0
- package/dist/tool/local-mcp-client.js +225 -0
- package/dist/tool/local-tool-executor.d.ts +37 -0
- package/dist/tool/local-tool-executor.js +249 -0
- package/dist/tool/mcp-tool-executor.d.ts +23 -0
- package/dist/tool/mcp-tool-executor.js +160 -0
- package/dist/tool/mock-tool-executor.d.ts +28 -0
- package/dist/tool/mock-tool-executor.js +65 -0
- package/dist/tool/system-prompt-builder.d.ts +114 -0
- package/dist/tool/system-prompt-builder.js +213 -0
- package/dist/tool/tool-confirmation.d.ts +29 -0
- package/dist/tool/tool-confirmation.js +81 -0
- package/dist/tool/tool-event-emitter.d.ts +58 -0
- package/dist/tool/tool-event-emitter.js +154 -0
- package/dist/tool/tool-execution-router.d.ts +25 -0
- package/dist/tool/tool-execution-router.js +50 -0
- package/dist/tool/tool-executor.interface.d.ts +85 -0
- package/dist/tool/tool-executor.interface.js +7 -0
- package/dist/tool/tool-orchestrator.d.ts +22 -0
- package/dist/tool/tool-orchestrator.js +104 -0
- package/dist/tool/tool-result-injector.d.ts +64 -0
- package/dist/tool/tool-result-injector.js +65 -0
- package/dist/utils/format-error.d.ts +4 -0
- package/dist/utils/format-error.js +4 -0
- package/dist/utils/http-error.d.ts +11 -0
- package/dist/utils/http-error.js +24 -0
- package/package.json +56 -0
|
@@ -0,0 +1,985 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphLoader — 从 Agent Registry / Deployment 预装快照加载 Graph DSL 与 Tool/Skill 定义
|
|
3
|
+
*
|
|
4
|
+
* 生产(server + EAP_PREINSTALL_ROOT):以预装为准,缺失则失败(04 Req 8.1)。
|
|
5
|
+
* 开发态:Registry + 可选 ./tools 本地 manifest。
|
|
6
|
+
*/
|
|
7
|
+
import { readFile } from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { resolveAgentModelAllowlist, resolveAgentPrimaryModel } from './agent-models.js';
|
|
10
|
+
import { createDeploymentSnapshotFromEnv, isInlineToolDeclaration, overlayToolRefPolicies, } from './deployment-snapshot.js';
|
|
11
|
+
import { preloadGraphNotFound, preloadManifestNotFound, preloadSkillNotFound, preloadToolNotFound, } from './preload-errors.js';
|
|
12
|
+
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)
|
|
16
|
+
return graph;
|
|
17
|
+
let changed = false;
|
|
18
|
+
const nodes = graph.nodes.map((node) => {
|
|
19
|
+
if (node.type !== 'llm')
|
|
20
|
+
return node;
|
|
21
|
+
const current = typeof node.config?.model === 'string' ? node.config.model.trim() : '';
|
|
22
|
+
if (current && current.toLowerCase() !== 'default')
|
|
23
|
+
return node;
|
|
24
|
+
changed = true;
|
|
25
|
+
return { ...node, config: { ...node.config, model: primary } };
|
|
26
|
+
});
|
|
27
|
+
return changed ? { ...graph, nodes } : graph;
|
|
28
|
+
}
|
|
29
|
+
function assertGraphModelsAllowed(graph, manifest) {
|
|
30
|
+
const allowlist = resolveAgentModelAllowlist((manifest ?? {}));
|
|
31
|
+
if (allowlist.length === 0)
|
|
32
|
+
return graph;
|
|
33
|
+
for (const node of graph.nodes) {
|
|
34
|
+
if (node.type !== 'llm')
|
|
35
|
+
continue;
|
|
36
|
+
const model = typeof node.config?.model === 'string' ? node.config.model.trim() : '';
|
|
37
|
+
if (model && !allowlist.includes(model)) {
|
|
38
|
+
throw new Error(`Graph llm node "${node.id}" uses undeclared model "${model}". Allowed: ${allowlist.join(', ')}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return graph;
|
|
42
|
+
}
|
|
43
|
+
function finalizeLoadedGraph(graph, manifest) {
|
|
44
|
+
return assertGraphModelsAllowed(applyPrimaryModelToGraph(graph, resolveAgentPrimaryModel((manifest ?? {}))), manifest);
|
|
45
|
+
}
|
|
46
|
+
function asGraphDsl(value) {
|
|
47
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
48
|
+
return undefined;
|
|
49
|
+
const obj = value;
|
|
50
|
+
if (Array.isArray(obj.nodes))
|
|
51
|
+
return obj;
|
|
52
|
+
const nested = obj.graph;
|
|
53
|
+
if (nested && typeof nested === 'object' && !Array.isArray(nested) && Array.isArray(nested.nodes)) {
|
|
54
|
+
return nested;
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
function extractSkillPrompt(manifest) {
|
|
59
|
+
const prompt = manifest.prompt;
|
|
60
|
+
if (typeof prompt === 'string' && prompt.trim())
|
|
61
|
+
return prompt;
|
|
62
|
+
if (prompt && typeof prompt === 'object' && !Array.isArray(prompt)) {
|
|
63
|
+
const system = prompt.system;
|
|
64
|
+
if (typeof system === 'string' && system.trim())
|
|
65
|
+
return system;
|
|
66
|
+
}
|
|
67
|
+
if (typeof manifest.systemPrompt === 'string' && manifest.systemPrompt.trim()) {
|
|
68
|
+
return manifest.systemPrompt;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 解析 Skill prompt:如果以 ./ 开头则视为相对 bundlePath 的文件路径,同步读取内容。
|
|
74
|
+
* .md 文件含 YAML frontmatter 时剔除,只取正文(frontmatter 仅供构建期生成 manifest)。
|
|
75
|
+
* 在 loadSkillDefinitions 中调用(异步版本)。
|
|
76
|
+
*/
|
|
77
|
+
async function resolveSkillPrompt(manifest, bundlePath) {
|
|
78
|
+
const raw = extractSkillPrompt(manifest);
|
|
79
|
+
if (!raw)
|
|
80
|
+
return undefined;
|
|
81
|
+
if (raw.startsWith('./') || raw.startsWith('.\\')) {
|
|
82
|
+
try {
|
|
83
|
+
let content = await readFile(path.resolve(bundlePath, raw), 'utf-8');
|
|
84
|
+
// 剔除 YAML frontmatter(--- ... --- 头部块)
|
|
85
|
+
const fmMatch = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/);
|
|
86
|
+
if (fmMatch)
|
|
87
|
+
content = content.slice(fmMatch[0].length);
|
|
88
|
+
return content.trim() || undefined;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// 文件不存在时回退为原始字符串
|
|
92
|
+
return raw;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return raw;
|
|
96
|
+
}
|
|
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;
|
|
148
|
+
if (!Array.isArray(refs))
|
|
149
|
+
return undefined;
|
|
150
|
+
const out = [];
|
|
151
|
+
for (const item of refs) {
|
|
152
|
+
if (typeof item === 'string') {
|
|
153
|
+
out.push(item);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!item || typeof item !== 'object')
|
|
157
|
+
continue;
|
|
158
|
+
const o = item;
|
|
159
|
+
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,
|
|
162
|
+
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,
|
|
167
|
+
autoApprove: Array.isArray(o.autoApprove)
|
|
168
|
+
? o.autoApprove.filter((x) => typeof x === 'string')
|
|
169
|
+
: undefined,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return out.length > 0 ? out : undefined;
|
|
173
|
+
}
|
|
174
|
+
function extractEmbeddedGraph(manifest) {
|
|
175
|
+
const candidates = [
|
|
176
|
+
manifest.graph,
|
|
177
|
+
manifest.graphYaml,
|
|
178
|
+
manifest.metadata?.graph,
|
|
179
|
+
manifest.metadata?.graphYaml,
|
|
180
|
+
];
|
|
181
|
+
for (const candidate of candidates) {
|
|
182
|
+
if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {
|
|
183
|
+
return candidate;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
const DEFAULT_GRAPH_DSL = {
|
|
189
|
+
name: 'default-agent-graph',
|
|
190
|
+
version: '1.0.0',
|
|
191
|
+
state: { messages: 'array' },
|
|
192
|
+
nodes: [
|
|
193
|
+
{ id: 'llm', type: 'llm', config: { model: 'default' } },
|
|
194
|
+
],
|
|
195
|
+
edges: [
|
|
196
|
+
{ from: '__start__', to: 'llm' },
|
|
197
|
+
{ from: 'llm', to: '__end__' },
|
|
198
|
+
],
|
|
199
|
+
entryPoint: 'llm',
|
|
200
|
+
finishPoints: ['__end__'],
|
|
201
|
+
config: { timeout: 60000 },
|
|
202
|
+
};
|
|
203
|
+
function yamlGraphToDsl(agentCode, graph) {
|
|
204
|
+
const nodes = graph.nodes ?? [];
|
|
205
|
+
const edges = graph.edges ?? [];
|
|
206
|
+
return {
|
|
207
|
+
name: agentCode,
|
|
208
|
+
version: '1.0.0',
|
|
209
|
+
state: { messages: 'array' },
|
|
210
|
+
nodes,
|
|
211
|
+
edges,
|
|
212
|
+
conditionalEdges: graph.conditionalEdges,
|
|
213
|
+
entryPoint: graph.entryPoint ?? nodes[0]?.id ?? 'llm',
|
|
214
|
+
finishPoints: ['__end__'],
|
|
215
|
+
config: { timeout: 60000 },
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function collectToolNames(agent, graphDsl) {
|
|
219
|
+
const rawTools = agent?.manifest?.tools ?? [];
|
|
220
|
+
// 支持 string[] (ID 引用) 和 object[] (完整 ToolManifest 内联声明)
|
|
221
|
+
const fromAgent = rawTools.map((t) => typeof t === 'string' ? t : t?.name ?? t?.id);
|
|
222
|
+
const fromGraph = graphDsl.nodes
|
|
223
|
+
.filter((n) => n.type === 'tool')
|
|
224
|
+
.map((n) => n.config?.['tool'] ?? n.id);
|
|
225
|
+
return [...new Set([...fromAgent, ...fromGraph].filter(Boolean))];
|
|
226
|
+
}
|
|
227
|
+
function normalizeDataScope(raw) {
|
|
228
|
+
if (raw === 'user-bound' || raw === 'department-bound' || raw === 'global')
|
|
229
|
+
return raw;
|
|
230
|
+
if (raw === 'department')
|
|
231
|
+
return 'department-bound';
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
/** 跨 toolset 子工具同名时保留先到者并告警,避免静默丢弃 */
|
|
235
|
+
function warnDuplicateToolSkip(existing, incoming) {
|
|
236
|
+
console.warn(`[preload] duplicate tool name "${incoming.name}": keep toolId=${existing.toolId}, skip toolId=${incoming.toolId}`);
|
|
237
|
+
}
|
|
238
|
+
function tryAddLoadedTool(definitions, byName, def) {
|
|
239
|
+
const existing = byName.get(def.name);
|
|
240
|
+
if (existing) {
|
|
241
|
+
if (existing.toolId !== def.toolId) {
|
|
242
|
+
warnDuplicateToolSkip(existing, def);
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
definitions.push(def);
|
|
247
|
+
byName.set(def.name, def);
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
function toLoadedToolDefinition(record) {
|
|
251
|
+
const manifest = record.manifest;
|
|
252
|
+
const m = manifest;
|
|
253
|
+
const permissions = m.permissions;
|
|
254
|
+
const metadata = m.metadata;
|
|
255
|
+
const manifestRef = {
|
|
256
|
+
id: String(m.id ?? record.id),
|
|
257
|
+
name: String(m.name ?? record.name),
|
|
258
|
+
version: String(m.version ?? record.version),
|
|
259
|
+
type: m.type ?? 'code',
|
|
260
|
+
status: record.status,
|
|
261
|
+
toolRuntime: (m.toolRuntime ?? m.runtime),
|
|
262
|
+
dataScope: normalizeDataScope(permissions?.dataScope),
|
|
263
|
+
requireConfirmation: Boolean(metadata?.require_confirmation ?? m.require_confirmation),
|
|
264
|
+
execution: m.execution,
|
|
265
|
+
};
|
|
266
|
+
return {
|
|
267
|
+
toolId: record.id,
|
|
268
|
+
name: record.name,
|
|
269
|
+
manifest: manifestRef,
|
|
270
|
+
inputSchema: m.input,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function fromPreinstallTool(pre) {
|
|
274
|
+
const m = pre.manifest;
|
|
275
|
+
const permissions = m.permissions;
|
|
276
|
+
const metadata = m.metadata;
|
|
277
|
+
return {
|
|
278
|
+
toolId: pre.toolId,
|
|
279
|
+
name: pre.name,
|
|
280
|
+
manifest: {
|
|
281
|
+
id: pre.toolId,
|
|
282
|
+
name: pre.name,
|
|
283
|
+
version: pre.version,
|
|
284
|
+
type: m.type ?? 'code',
|
|
285
|
+
status: 'active',
|
|
286
|
+
description: m.description,
|
|
287
|
+
toolRuntime: (m.toolRuntime ?? m.runtime),
|
|
288
|
+
dataScope: normalizeDataScope(permissions?.dataScope),
|
|
289
|
+
requireConfirmation: Boolean(metadata?.require_confirmation ?? m.require_confirmation),
|
|
290
|
+
execution: {
|
|
291
|
+
...((() => {
|
|
292
|
+
const raw = m.execution;
|
|
293
|
+
return raw && typeof raw === 'object' && !Array.isArray(raw)
|
|
294
|
+
? raw
|
|
295
|
+
: {};
|
|
296
|
+
})()),
|
|
297
|
+
bundlePath: pre.bundlePath,
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
inputSchema: m.input,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 展开预装工具集(toolset.manifest.json,含 tools[])为多个 LoadedToolDefinition。
|
|
305
|
+
* 以工具集为管理单元:单个 MCP 服务 / 单个代码包 = 一个工具集,可含多个子工具;
|
|
306
|
+
* 子工具继承集级 server/package 配置,合成各自的 execution。
|
|
307
|
+
* 无 tools[] 时回退为单工具 manifest(tool.manifest.json 结构)。
|
|
308
|
+
* enabledTools 为可选白名单(agent.manifest toolRefs);缺省启用全部子工具。
|
|
309
|
+
*/
|
|
310
|
+
function expandPreinstallToolset(pre, options) {
|
|
311
|
+
const m = pre.manifest;
|
|
312
|
+
const tools = m.tools;
|
|
313
|
+
const enabled = options?.enabledTools;
|
|
314
|
+
const enabledSet = enabled && enabled.length > 0 ? new Set(enabled) : null;
|
|
315
|
+
const autoApproveSet = options?.autoApprove && options.autoApprove.length > 0
|
|
316
|
+
? new Set(options.autoApprove)
|
|
317
|
+
: null;
|
|
318
|
+
if (!Array.isArray(tools) || tools.length === 0 || typeof tools[0] !== 'object') {
|
|
319
|
+
if (enabledSet && !enabledSet.has(pre.name) && !enabledSet.has(pre.toolId)) {
|
|
320
|
+
return [];
|
|
321
|
+
}
|
|
322
|
+
const single = fromPreinstallTool(pre);
|
|
323
|
+
if (autoApproveSet?.has(single.name)) {
|
|
324
|
+
single.manifest.requireConfirmation = false;
|
|
325
|
+
}
|
|
326
|
+
return [single];
|
|
327
|
+
}
|
|
328
|
+
const setType = m.type;
|
|
329
|
+
const toolRuntime = (m.toolRuntime ?? m.runtime);
|
|
330
|
+
const server = m.server;
|
|
331
|
+
const pkg = m.package;
|
|
332
|
+
const out = [];
|
|
333
|
+
for (const raw of tools) {
|
|
334
|
+
const st = raw;
|
|
335
|
+
const name = typeof st.name === 'string' ? st.name : '';
|
|
336
|
+
if (!name)
|
|
337
|
+
continue;
|
|
338
|
+
if (enabledSet && !enabledSet.has(name))
|
|
339
|
+
continue;
|
|
340
|
+
let type;
|
|
341
|
+
let execution;
|
|
342
|
+
if (setType === 'http') {
|
|
343
|
+
const gateway = (m.gateway ?? {});
|
|
344
|
+
type = 'http';
|
|
345
|
+
execution = {
|
|
346
|
+
protocol: 'http',
|
|
347
|
+
method: st.method ?? 'GET',
|
|
348
|
+
baseUrl: st.baseUrl ?? gateway.baseUrl,
|
|
349
|
+
pathTemplate: st.pathTemplate,
|
|
350
|
+
allowedHosts: gateway.allowedHosts,
|
|
351
|
+
timeout: st.timeout ?? gateway.timeout ?? 10000,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
else if (setType === 'mcp') {
|
|
355
|
+
type = 'mcp';
|
|
356
|
+
execution = {
|
|
357
|
+
protocol: 'mcp',
|
|
358
|
+
transport: server?.transport ?? (server?.url ? 'streamable_http' : 'stdio'),
|
|
359
|
+
server,
|
|
360
|
+
toolName: name,
|
|
361
|
+
timeout: st.timeout ?? server?.timeout ?? 30000,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
type = 'code';
|
|
366
|
+
execution = {
|
|
367
|
+
runtime: st.runtime ?? 'node',
|
|
368
|
+
handler: st.handler,
|
|
369
|
+
args: st.args,
|
|
370
|
+
timeout: st.timeout ?? 30000,
|
|
371
|
+
sandbox: st.sandbox ?? pkg?.sandbox ?? false,
|
|
372
|
+
bundlePath: pre.bundlePath,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
const requireConfirmation = autoApproveSet?.has(name)
|
|
376
|
+
? false
|
|
377
|
+
: Boolean(st.requireConfirmation);
|
|
378
|
+
out.push({
|
|
379
|
+
toolId: `${pre.toolId}:${name}`,
|
|
380
|
+
name,
|
|
381
|
+
manifest: {
|
|
382
|
+
id: `${pre.toolId}:${name}`,
|
|
383
|
+
name,
|
|
384
|
+
version: pre.version,
|
|
385
|
+
type,
|
|
386
|
+
status: 'active',
|
|
387
|
+
description: st.description,
|
|
388
|
+
toolRuntime,
|
|
389
|
+
dataScope: normalizeDataScope(st.dataScope),
|
|
390
|
+
requireConfirmation,
|
|
391
|
+
execution,
|
|
392
|
+
},
|
|
393
|
+
inputSchema: st.input,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
398
|
+
function fromLocalManifestFile(toolName, manifest) {
|
|
399
|
+
const permissions = manifest.permissions;
|
|
400
|
+
const metadata = manifest.metadata;
|
|
401
|
+
const manifestRef = {
|
|
402
|
+
id: String(manifest.id ?? toolName),
|
|
403
|
+
name: String(manifest.name ?? toolName),
|
|
404
|
+
version: String(manifest.version ?? '0.0.0'),
|
|
405
|
+
type: manifest.type ?? 'code',
|
|
406
|
+
status: 'active',
|
|
407
|
+
toolRuntime: (manifest.toolRuntime ?? manifest.runtime),
|
|
408
|
+
dataScope: normalizeDataScope(permissions?.dataScope),
|
|
409
|
+
requireConfirmation: Boolean(metadata?.require_confirmation),
|
|
410
|
+
execution: manifest.execution,
|
|
411
|
+
};
|
|
412
|
+
return {
|
|
413
|
+
toolId: String(manifest.id ?? toolName),
|
|
414
|
+
name: String(manifest.name ?? toolName),
|
|
415
|
+
manifest: manifestRef,
|
|
416
|
+
inputSchema: manifest.input,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* 从内联 Tool 声明(manifest.tools 中的完整 ToolManifest 对象)
|
|
421
|
+
* 转为 LoadedToolDefinition。
|
|
422
|
+
*
|
|
423
|
+
* 支持 eap.yaml / agent.manifest.json 中直接嵌入工具完整定义(含 execution、input 等),
|
|
424
|
+
* 适用于本地开发无 Registry / 无预装快照的场景。
|
|
425
|
+
*/
|
|
426
|
+
function fromInlineToolDeclaration(tool) {
|
|
427
|
+
const permissions = tool.permissions;
|
|
428
|
+
const metadata = tool.metadata;
|
|
429
|
+
const id = String(tool.id ?? tool.name ?? 'unknown');
|
|
430
|
+
const name = String(tool.name ?? tool.id ?? 'unknown');
|
|
431
|
+
return {
|
|
432
|
+
toolId: id,
|
|
433
|
+
name,
|
|
434
|
+
manifest: {
|
|
435
|
+
id,
|
|
436
|
+
name,
|
|
437
|
+
version: String(tool.version ?? '0.0.0'),
|
|
438
|
+
type: tool.type ?? 'code',
|
|
439
|
+
description: tool.description,
|
|
440
|
+
status: 'active',
|
|
441
|
+
toolRuntime: (tool.toolRuntime ?? tool.runtime),
|
|
442
|
+
dataScope: normalizeDataScope(permissions?.dataScope),
|
|
443
|
+
requireConfirmation: Boolean(metadata?.require_confirmation),
|
|
444
|
+
execution: tool.execution,
|
|
445
|
+
},
|
|
446
|
+
inputSchema: tool.input,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
async function loadDevLocalManifest(toolName, toolsDir) {
|
|
450
|
+
const manifestPath = path.join(toolsDir, toolName, 'tool.manifest.json');
|
|
451
|
+
try {
|
|
452
|
+
const raw = await readFile(manifestPath, 'utf-8');
|
|
453
|
+
const manifest = JSON.parse(raw);
|
|
454
|
+
return fromLocalManifestFile(toolName, manifest);
|
|
455
|
+
}
|
|
456
|
+
catch {
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
function fromLocalInstall(install) {
|
|
461
|
+
return {
|
|
462
|
+
toolId: install.toolId,
|
|
463
|
+
name: install.toolName,
|
|
464
|
+
manifest: {
|
|
465
|
+
id: install.toolId,
|
|
466
|
+
name: install.toolName,
|
|
467
|
+
version: install.version,
|
|
468
|
+
type: install.type,
|
|
469
|
+
status: install.installStatus === 'ready' ? 'active' : install.installStatus,
|
|
470
|
+
toolRuntime: 'both',
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
export class GraphLoader {
|
|
475
|
+
registryClient;
|
|
476
|
+
deploymentContext;
|
|
477
|
+
localInstallStore;
|
|
478
|
+
localToolsDir;
|
|
479
|
+
localSkillsDir;
|
|
480
|
+
deploymentSnapshot;
|
|
481
|
+
strictPreinstall;
|
|
482
|
+
agentVersion;
|
|
483
|
+
definitionCacheEnabled;
|
|
484
|
+
definitionCache = new PreinstallDefinitionCache();
|
|
485
|
+
skillHotReload;
|
|
486
|
+
constructor(config = {}) {
|
|
487
|
+
this.registryClient = config.registryClient;
|
|
488
|
+
this.deploymentContext = config.deploymentContext ?? 'server';
|
|
489
|
+
this.localInstallStore = config.localInstallStore;
|
|
490
|
+
this.localToolsDir = config.localToolsDir;
|
|
491
|
+
this.localSkillsDir = resolveLocalSkillsDir(config.localSkillsDir);
|
|
492
|
+
this.deploymentSnapshot =
|
|
493
|
+
config.deploymentSnapshot ??
|
|
494
|
+
createDeploymentSnapshotFromEnv(config.preinstallRoot, {
|
|
495
|
+
requireReady: config.requireReady,
|
|
496
|
+
requireChecksum: config.requireChecksum,
|
|
497
|
+
});
|
|
498
|
+
this.agentVersion = config.agentVersion ?? process.env.EAP_AGENT_VERSION;
|
|
499
|
+
const hasPreinstall = Boolean(this.deploymentSnapshot);
|
|
500
|
+
this.strictPreinstall =
|
|
501
|
+
config.strictPreinstall ??
|
|
502
|
+
(this.deploymentContext === 'server' && hasPreinstall);
|
|
503
|
+
this.definitionCacheEnabled = resolveDefinitionCacheEnabled(hasPreinstall, config.definitionCache);
|
|
504
|
+
this.skillHotReload = resolveSkillHotReload(this.deploymentContext, config.skillHotReload);
|
|
505
|
+
}
|
|
506
|
+
/** 严格预装:禁止用 Registry 拉可执行定义 */
|
|
507
|
+
get blockRegistryDefinitions() {
|
|
508
|
+
return this.strictPreinstall && Boolean(this.deploymentSnapshot);
|
|
509
|
+
}
|
|
510
|
+
resolveVersion(options) {
|
|
511
|
+
return options?.agentVersion ?? this.agentVersion;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* 缓存主键版本:显式 version 优先;未传时落到 snapshot.version,
|
|
515
|
+
* 避免 warm(`1.0.0`) 与 load(无 version→@auto) 分属两个键。
|
|
516
|
+
*/
|
|
517
|
+
async pinCacheVersion(agentCode, requested) {
|
|
518
|
+
if (requested)
|
|
519
|
+
return requested;
|
|
520
|
+
if (!this.deploymentSnapshot)
|
|
521
|
+
return undefined;
|
|
522
|
+
try {
|
|
523
|
+
const snap = await this.deploymentSnapshot.loadAgentSnapshot(agentCode, undefined);
|
|
524
|
+
return snap?.version;
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
return undefined;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
useCache(options) {
|
|
531
|
+
return this.definitionCacheEnabled && !options?.bypassCache;
|
|
532
|
+
}
|
|
533
|
+
/** 上线 / 发版后预热进程内定义(模型 C) */
|
|
534
|
+
async warmAgent(agentCode, options) {
|
|
535
|
+
const loadOpts = { ...options, bypassCache: true };
|
|
536
|
+
const version = await this.pinCacheVersion(agentCode, this.resolveVersion(options));
|
|
537
|
+
const skillWarnings = [];
|
|
538
|
+
const skippedSkills = [];
|
|
539
|
+
// 分步落缓存:skills 失败不得拖垮 graph/tools 预热(Hosting 预热通常无 userId)
|
|
540
|
+
const graph = await this.loadGraph(agentCode, loadOpts);
|
|
541
|
+
this.definitionCache.setGraph(agentCode, version, graph);
|
|
542
|
+
const tools = await this.loadToolDefinitions(agentCode, { ...loadOpts, activeOnly: true });
|
|
543
|
+
this.definitionCache.setTools(agentCode, version, tools);
|
|
544
|
+
let skillsOk = false;
|
|
545
|
+
try {
|
|
546
|
+
const skills = await this.loadSkillDefinitions(agentCode, {
|
|
547
|
+
...loadOpts,
|
|
548
|
+
userId: options?.userId,
|
|
549
|
+
allowMissingSkills: true,
|
|
550
|
+
onMissingSkill: (skillId) => {
|
|
551
|
+
skippedSkills.push(skillId);
|
|
552
|
+
skillWarnings.push(skillId);
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
const stamp = await this.skillTreeStamp(agentCode, version, options?.userId);
|
|
556
|
+
this.definitionCache.setSkills(agentCode, version, options?.userId, skills, stamp);
|
|
557
|
+
skillsOk = true;
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
561
|
+
skillWarnings.push(message);
|
|
562
|
+
console.warn(JSON.stringify({
|
|
563
|
+
event: 'runtime.warmAgent.skills_failed',
|
|
564
|
+
level: 'warn',
|
|
565
|
+
agentCode,
|
|
566
|
+
agentVersion: version ?? null,
|
|
567
|
+
message,
|
|
568
|
+
}));
|
|
569
|
+
}
|
|
570
|
+
// 预期跳过(无 userId 的 users 层 Skill)用 debug,避免单测/生产噪音
|
|
571
|
+
if (skippedSkills.length > 0) {
|
|
572
|
+
console.debug(JSON.stringify({
|
|
573
|
+
event: 'runtime.warmAgent.skills_skipped',
|
|
574
|
+
level: 'debug',
|
|
575
|
+
agentCode,
|
|
576
|
+
agentVersion: version ?? null,
|
|
577
|
+
userId: options?.userId ?? null,
|
|
578
|
+
skippedSkillIds: skippedSkills,
|
|
579
|
+
}));
|
|
580
|
+
}
|
|
581
|
+
console.info(JSON.stringify({
|
|
582
|
+
event: 'runtime.warmAgent.ok',
|
|
583
|
+
level: 'info',
|
|
584
|
+
agentCode,
|
|
585
|
+
agentVersion: version ?? null,
|
|
586
|
+
graph: true,
|
|
587
|
+
tools: true,
|
|
588
|
+
skills: skillsOk,
|
|
589
|
+
skillWarningCount: skillWarnings.length,
|
|
590
|
+
skillWarnings,
|
|
591
|
+
}));
|
|
592
|
+
return {
|
|
593
|
+
graph: true,
|
|
594
|
+
tools: true,
|
|
595
|
+
skills: skillsOk,
|
|
596
|
+
skillWarnings,
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
/** 版本切换 / 下线时失效缓存 */
|
|
600
|
+
invalidateAgent(agentCode, agentVersion) {
|
|
601
|
+
this.definitionCache.invalidate(agentCode, agentVersion);
|
|
602
|
+
}
|
|
603
|
+
invalidateAllDefinitions() {
|
|
604
|
+
this.definitionCache.invalidateAll();
|
|
605
|
+
}
|
|
606
|
+
definitionCacheSize() {
|
|
607
|
+
return this.definitionCache.size();
|
|
608
|
+
}
|
|
609
|
+
cloneCached(value) {
|
|
610
|
+
if (typeof globalThis.structuredClone === 'function') {
|
|
611
|
+
return globalThis.structuredClone(value);
|
|
612
|
+
}
|
|
613
|
+
return JSON.parse(JSON.stringify(value));
|
|
614
|
+
}
|
|
615
|
+
async loadGraph(agentCode, options) {
|
|
616
|
+
const requested = this.resolveVersion(options);
|
|
617
|
+
const version = await this.pinCacheVersion(agentCode, requested);
|
|
618
|
+
if (this.useCache(options)) {
|
|
619
|
+
const hit = this.definitionCache.get(agentCode, version);
|
|
620
|
+
if (hit?.graph) {
|
|
621
|
+
return this.cloneCached(hit.graph);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
const graph = await this.loadGraphFromSource(agentCode, requested);
|
|
625
|
+
if (this.useCache(options)) {
|
|
626
|
+
this.definitionCache.setGraph(agentCode, version, graph);
|
|
627
|
+
}
|
|
628
|
+
return this.cloneCached(graph);
|
|
629
|
+
}
|
|
630
|
+
async loadGraphFromSource(agentCode, version) {
|
|
631
|
+
if (this.deploymentSnapshot) {
|
|
632
|
+
const snap = await this.deploymentSnapshot.loadAgentSnapshot(agentCode, version);
|
|
633
|
+
if (!snap) {
|
|
634
|
+
if (this.blockRegistryDefinitions) {
|
|
635
|
+
throw preloadManifestNotFound(`预装 Agent 目录不存在: ${agentCode}${version ? `@${version}` : ''}`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
if (snap.graph && typeof snap.graph === 'object') {
|
|
640
|
+
return finalizeLoadedGraph(yamlGraphToDsl(agentCode, snap.graph), snap.manifest ?? {});
|
|
641
|
+
}
|
|
642
|
+
if (this.blockRegistryDefinitions) {
|
|
643
|
+
throw preloadGraphNotFound(`预装 Graph 定义缺失: agent=${agentCode}`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (this.blockRegistryDefinitions) {
|
|
648
|
+
throw preloadGraphNotFound(`严格预装模式下无法加载 Graph: agent=${agentCode}`);
|
|
649
|
+
}
|
|
650
|
+
if (!this.registryClient) {
|
|
651
|
+
return { ...DEFAULT_GRAPH_DSL, name: agentCode };
|
|
652
|
+
}
|
|
653
|
+
const record = await this.registryClient.getAgent(agentCode);
|
|
654
|
+
if (!record?.manifest) {
|
|
655
|
+
return { ...DEFAULT_GRAPH_DSL, name: agentCode };
|
|
656
|
+
}
|
|
657
|
+
const manifest = record.manifest;
|
|
658
|
+
const graphFromManifest = extractEmbeddedGraph(manifest);
|
|
659
|
+
if (graphFromManifest && typeof graphFromManifest === 'object') {
|
|
660
|
+
return finalizeLoadedGraph(yamlGraphToDsl(agentCode, graphFromManifest), manifest);
|
|
661
|
+
}
|
|
662
|
+
const model = resolveAgentPrimaryModel(manifest) ?? 'default';
|
|
663
|
+
return {
|
|
664
|
+
...DEFAULT_GRAPH_DSL,
|
|
665
|
+
name: agentCode,
|
|
666
|
+
nodes: [
|
|
667
|
+
{
|
|
668
|
+
id: 'llm',
|
|
669
|
+
type: 'llm',
|
|
670
|
+
config: {
|
|
671
|
+
model,
|
|
672
|
+
systemPrompt: manifest.prompts?.system,
|
|
673
|
+
},
|
|
674
|
+
},
|
|
675
|
+
],
|
|
676
|
+
config: {
|
|
677
|
+
timeout: manifest.config?.timeout ?? 60000,
|
|
678
|
+
maxRetries: manifest.config?.retryCount,
|
|
679
|
+
},
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* 解析 agent tools[] + graph tool 节点 union;
|
|
684
|
+
* server+预装:以预装 manifest 为准;desktop 合并 ILocalToolInstallStore。
|
|
685
|
+
*/
|
|
686
|
+
async loadToolDefinitions(agentCode, options = {}) {
|
|
687
|
+
const requested = this.resolveVersion(options);
|
|
688
|
+
const version = await this.pinCacheVersion(agentCode, requested);
|
|
689
|
+
if (this.useCache(options)) {
|
|
690
|
+
const hit = this.definitionCache.get(agentCode, version);
|
|
691
|
+
if (hit?.tools !== undefined) {
|
|
692
|
+
return this.cloneCached(hit.tools);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const tools = await this.loadToolDefinitionsFromSource(agentCode, options, requested);
|
|
696
|
+
if (this.useCache(options)) {
|
|
697
|
+
this.definitionCache.setTools(agentCode, version, tools);
|
|
698
|
+
}
|
|
699
|
+
return this.cloneCached(tools);
|
|
700
|
+
}
|
|
701
|
+
async loadToolDefinitionsFromSource(agentCode, options, version) {
|
|
702
|
+
const activeOnly = options.activeOnly !== false;
|
|
703
|
+
const graphDsl = await this.loadGraph(agentCode, {
|
|
704
|
+
agentVersion: version,
|
|
705
|
+
bypassCache: options.bypassCache,
|
|
706
|
+
});
|
|
707
|
+
const definitions = [];
|
|
708
|
+
const byName = new Map();
|
|
709
|
+
const snap = this.deploymentSnapshot
|
|
710
|
+
? await this.deploymentSnapshot.loadAgentSnapshot(agentCode, version)
|
|
711
|
+
: null;
|
|
712
|
+
const agentDir = snap?.agentDir
|
|
713
|
+
?? (this.deploymentSnapshot
|
|
714
|
+
? await this.deploymentSnapshot.resolveAgentDir(agentCode, version)
|
|
715
|
+
: null);
|
|
716
|
+
// 本地 agent.manifest 内联完整 ToolManifest(含 type/execution);装配引用走预装展开
|
|
717
|
+
const localManifestTools = snap?.manifest?.tools;
|
|
718
|
+
if (Array.isArray(localManifestTools) && localManifestTools.length > 0) {
|
|
719
|
+
for (const tool of localManifestTools) {
|
|
720
|
+
if (!isInlineToolDeclaration(tool))
|
|
721
|
+
continue;
|
|
722
|
+
const def = fromInlineToolDeclaration(tool);
|
|
723
|
+
tryAddLoadedTool(definitions, byName, def);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
const agent = !this.blockRegistryDefinitions && this.registryClient
|
|
727
|
+
? await this.registryClient.getAgent(agentCode)
|
|
728
|
+
: null;
|
|
729
|
+
// ── 提取 Registry manifest 内联 tools(非严格预装)──
|
|
730
|
+
const manifestTools = agent?.manifest?.tools;
|
|
731
|
+
if (Array.isArray(manifestTools) && manifestTools.length > 0) {
|
|
732
|
+
for (const tool of manifestTools) {
|
|
733
|
+
if (!isInlineToolDeclaration(tool))
|
|
734
|
+
continue;
|
|
735
|
+
const def = fromInlineToolDeclaration(tool);
|
|
736
|
+
tryAddLoadedTool(definitions, byName, def);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
// [DEBUG] 加载链路诊断
|
|
740
|
+
if (process.env.EAP_LLM_DEBUG === '1') {
|
|
741
|
+
console.log('[LLM-DEBUG] loadToolDefinitions trace:', JSON.stringify({
|
|
742
|
+
agentCode,
|
|
743
|
+
agentVersion: version,
|
|
744
|
+
deploymentContext: this.deploymentContext,
|
|
745
|
+
preinstallRoot: process.env.EAP_PREINSTALL_ROOT,
|
|
746
|
+
localToolsDir: this.localToolsDir,
|
|
747
|
+
EAP_LOCAL_TOOLS_DIR: process.env.EAP_LOCAL_TOOLS_DIR,
|
|
748
|
+
hasDeploymentSnapshot: Boolean(this.deploymentSnapshot),
|
|
749
|
+
snapIsNull: !snap,
|
|
750
|
+
snapToolsCount: snap?.tools?.length ?? 0,
|
|
751
|
+
snapTools: (snap?.tools ?? []).map(t => ({ name: t.name, version: t.version })),
|
|
752
|
+
agentDir,
|
|
753
|
+
}, null, 2));
|
|
754
|
+
}
|
|
755
|
+
const snapToolRefs = overlayToolRefPolicies(snap?.tools ?? [], snap?.manifest);
|
|
756
|
+
const toolNamesFromSnap = snapToolRefs.map((t) => t.name).filter(Boolean);
|
|
757
|
+
const collectedFromGraph = collectToolNames(agent, graphDsl);
|
|
758
|
+
const toolNames = [...new Set([...collectedFromGraph, ...toolNamesFromSnap])];
|
|
759
|
+
// [DEBUG] 最终 toolNames 决策
|
|
760
|
+
if (process.env.EAP_LLM_DEBUG === '1') {
|
|
761
|
+
console.log('[LLM-DEBUG] toolNames:', JSON.stringify({
|
|
762
|
+
fromGraph: collectedFromGraph,
|
|
763
|
+
fromSnap: toolNamesFromSnap,
|
|
764
|
+
final: toolNames,
|
|
765
|
+
}));
|
|
766
|
+
}
|
|
767
|
+
if (this.deploymentSnapshot && (snapToolRefs.length > 0 || toolNames.length > 0)) {
|
|
768
|
+
const missing = [];
|
|
769
|
+
const processedToolsetNames = new Set(snapToolRefs.map((r) => r.name));
|
|
770
|
+
// 1) snapshot 引用的工具集全部加载并展开(enabledTools 白名单过滤)
|
|
771
|
+
for (const ref of snapToolRefs) {
|
|
772
|
+
const pre = await this.deploymentSnapshot.loadToolManifest(ref, agentDir);
|
|
773
|
+
if (!pre) {
|
|
774
|
+
missing.push(ref.name);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
for (const def of expandPreinstallToolset(pre, {
|
|
778
|
+
enabledTools: ref.enabledTools,
|
|
779
|
+
autoApprove: ref.autoApprove,
|
|
780
|
+
})) {
|
|
781
|
+
tryAddLoadedTool(definitions, byName, def);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
// 2) Graph 声明但尚未命中的工具名:按名直查。
|
|
785
|
+
// 已在步骤 1 处理过的工具集名不再二次展开(避免丢掉 enabledTools 白名单)。
|
|
786
|
+
for (const toolName of toolNames) {
|
|
787
|
+
if (byName.has(toolName))
|
|
788
|
+
continue;
|
|
789
|
+
if (processedToolsetNames.has(toolName))
|
|
790
|
+
continue;
|
|
791
|
+
const pre = await this.deploymentSnapshot.loadToolManifest({ name: toolName }, agentDir);
|
|
792
|
+
if (!pre) {
|
|
793
|
+
missing.push(toolName);
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
for (const def of expandPreinstallToolset(pre)) {
|
|
797
|
+
tryAddLoadedTool(definitions, byName, def);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (this.strictPreinstall && missing.length > 0) {
|
|
801
|
+
throw preloadToolNotFound(`预装快照缺失 Tool: ${missing.join(', ')}(agent=${agentCode})`, { missing, agentCode });
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if (this.registryClient && !this.blockRegistryDefinitions) {
|
|
805
|
+
for (const toolName of toolNames) {
|
|
806
|
+
if (byName.has(toolName))
|
|
807
|
+
continue;
|
|
808
|
+
const record = await this.registryClient.getToolByName(toolName);
|
|
809
|
+
if (!record)
|
|
810
|
+
continue;
|
|
811
|
+
if (activeOnly && record.status !== 'active')
|
|
812
|
+
continue;
|
|
813
|
+
tryAddLoadedTool(definitions, byName, toLoadedToolDefinition(record));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
if (this.deploymentContext === 'dev') {
|
|
817
|
+
const toolsDir = this.localToolsDir ?? process.env.EAP_LOCAL_TOOLS_DIR ?? './tools';
|
|
818
|
+
for (const toolName of toolNames) {
|
|
819
|
+
if (byName.has(toolName))
|
|
820
|
+
continue;
|
|
821
|
+
const localDef = await loadDevLocalManifest(toolName, toolsDir);
|
|
822
|
+
if (localDef) {
|
|
823
|
+
tryAddLoadedTool(definitions, byName, localDef);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
if (this.deploymentContext === 'desktop' && this.localInstallStore) {
|
|
828
|
+
const localRecords = this.localInstallStore.listReady();
|
|
829
|
+
for (const install of localRecords) {
|
|
830
|
+
if (install.installStatus !== 'ready')
|
|
831
|
+
continue;
|
|
832
|
+
const existing = byName.get(install.toolName);
|
|
833
|
+
if (existing) {
|
|
834
|
+
if (!existing.manifest.toolRuntime || existing.manifest.toolRuntime === 'server') {
|
|
835
|
+
existing.manifest.toolRuntime = 'both';
|
|
836
|
+
}
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
const localDef = fromLocalInstall(install);
|
|
840
|
+
definitions.push(localDef);
|
|
841
|
+
byName.set(localDef.name, localDef);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
// [DEBUG] 最终 definitions 汇总
|
|
845
|
+
if (process.env.EAP_LLM_DEBUG === '1') {
|
|
846
|
+
console.log('[LLM-DEBUG] loadToolDefinitions result:', JSON.stringify({
|
|
847
|
+
count: definitions.length,
|
|
848
|
+
names: definitions.map(d => d.name),
|
|
849
|
+
}));
|
|
850
|
+
}
|
|
851
|
+
return definitions;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* 从预装快照加载已装配 Skill 完整定义(workflow / prompt / toolRefs)
|
|
855
|
+
* @param options.userId 用于解析 users/<userId>/skills(优先于 preinstall/skills)
|
|
856
|
+
* @param options.allowMissingSkills 缺失时跳过而非抛错(warm 预热用)
|
|
857
|
+
*/
|
|
858
|
+
async loadSkillDefinitions(agentCode, options) {
|
|
859
|
+
const requested = this.resolveVersion(options);
|
|
860
|
+
const version = await this.pinCacheVersion(agentCode, requested);
|
|
861
|
+
const stamp = await this.skillTreeStamp(agentCode, version, options?.userId);
|
|
862
|
+
if (this.useCache(options) && !options?.allowMissingSkills) {
|
|
863
|
+
const hit = this.definitionCache.getSkills(agentCode, version, options?.userId, stamp);
|
|
864
|
+
if (hit)
|
|
865
|
+
return this.cloneCached(hit);
|
|
866
|
+
}
|
|
867
|
+
const skills = await this.loadSkillDefinitionsFromSource(agentCode, options, requested);
|
|
868
|
+
if (this.useCache(options)) {
|
|
869
|
+
this.definitionCache.setSkills(agentCode, version, options?.userId, skills, stamp);
|
|
870
|
+
}
|
|
871
|
+
return this.cloneCached(skills);
|
|
872
|
+
}
|
|
873
|
+
async loadSkillDefinitionsFromSource(agentCode, options, version) {
|
|
874
|
+
if (!this.deploymentSnapshot)
|
|
875
|
+
return [];
|
|
876
|
+
const snap = await this.deploymentSnapshot.loadAgentSnapshot(agentCode, version);
|
|
877
|
+
const agentDir = await this.deploymentSnapshot.resolveAgentDir(agentCode, version);
|
|
878
|
+
const refs = await this.resolveSkillRefs(snap, agentDir, options?.userId);
|
|
879
|
+
if (!refs.length)
|
|
880
|
+
return [];
|
|
881
|
+
const skills = [];
|
|
882
|
+
const userId = options?.userId;
|
|
883
|
+
const allowMissing = options?.allowMissingSkills === true;
|
|
884
|
+
for (const ref of refs) {
|
|
885
|
+
const pre = await this.deploymentSnapshot.loadSkillManifest(ref, agentDir, userId, this.localSkillRoots());
|
|
886
|
+
if (pre) {
|
|
887
|
+
const workflow = asGraphDsl(pre.manifest.workflow) ??
|
|
888
|
+
asGraphDsl(pre.manifest.graph) ??
|
|
889
|
+
asGraphDsl(pre.manifest.definitionSnapshot);
|
|
890
|
+
// 解析 prompt:支持文件路径引用(./ 开头)
|
|
891
|
+
const prompt = await resolveSkillPrompt(pre.manifest, pre.bundlePath);
|
|
892
|
+
// 解析 scripts[] 为虚拟 Tool
|
|
893
|
+
const scriptTools = resolveSkillScripts(pre.manifest, pre.bundlePath);
|
|
894
|
+
skills.push({
|
|
895
|
+
skillId: pre.skillId,
|
|
896
|
+
name: pre.name,
|
|
897
|
+
description: pre.description,
|
|
898
|
+
version: pre.version,
|
|
899
|
+
workflow,
|
|
900
|
+
prompt,
|
|
901
|
+
toolRefs: extractSkillToolRefs(pre.manifest),
|
|
902
|
+
inputDef: pre.manifest.inputDef,
|
|
903
|
+
outputDef: pre.manifest.outputDef,
|
|
904
|
+
scriptTools: scriptTools.length > 0 ? scriptTools : undefined,
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
else if (!this.strictPreinstall) {
|
|
908
|
+
skills.push({
|
|
909
|
+
skillId: ref.skillId,
|
|
910
|
+
name: ref.name ?? ref.skillId,
|
|
911
|
+
description: ref.description,
|
|
912
|
+
version: ref.version,
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
else if (allowMissing) {
|
|
916
|
+
options?.onMissingSkill?.(ref.skillId);
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
throw preloadSkillNotFound(`预装快照缺失 Skill: ${ref.skillId}(agent=${agentCode})`, {
|
|
920
|
+
skillId: ref.skillId,
|
|
921
|
+
agentCode,
|
|
922
|
+
userId,
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return skills;
|
|
927
|
+
}
|
|
928
|
+
async skillTreeStamp(agentCode, version, userId) {
|
|
929
|
+
if (!this.skillHotReload || !this.deploymentSnapshot)
|
|
930
|
+
return '';
|
|
931
|
+
const agentDir = await this.deploymentSnapshot.resolveAgentDir(agentCode, version);
|
|
932
|
+
if (!agentDir)
|
|
933
|
+
return '';
|
|
934
|
+
const tree = await inspectAgentSkillTree(agentDir, userId, this.localSkillRoots());
|
|
935
|
+
const assembly = await skillAssemblyStamp(agentDir, userId);
|
|
936
|
+
return `${tree.stamp}:${assembly}`;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* 候选集 = 装配白名单,否则 snapshot/manifest 声明。
|
|
940
|
+
* 磁盘多出来的未声明目录不进选择清单;正文热加载仍看已装配目录的 mtime。
|
|
941
|
+
*/
|
|
942
|
+
async resolveSkillRefs(snap, agentDir, userId) {
|
|
943
|
+
if (agentDir) {
|
|
944
|
+
const assembly = await readSkillAssembly(agentDir, userId);
|
|
945
|
+
if (assembly && assembly.skills.length > 0) {
|
|
946
|
+
return assembly.skills.map((skillId) => ({ skillId }));
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
const byId = new Map();
|
|
950
|
+
for (const ref of snap?.skills ?? []) {
|
|
951
|
+
if (ref.skillId)
|
|
952
|
+
byId.set(ref.skillId, ref);
|
|
953
|
+
}
|
|
954
|
+
return [...byId.values()];
|
|
955
|
+
}
|
|
956
|
+
localSkillRoots() {
|
|
957
|
+
return this.localSkillsDir ? [this.localSkillsDir] : [];
|
|
958
|
+
}
|
|
959
|
+
async resolveAgentDir(agentCode, version) {
|
|
960
|
+
if (!this.deploymentSnapshot)
|
|
961
|
+
return null;
|
|
962
|
+
return this.deploymentSnapshot.resolveAgentDir(agentCode, this.resolveVersion({ agentVersion: version }));
|
|
963
|
+
}
|
|
964
|
+
/** Agent 包目录 + 工程 prompts/(dev 作者源,与 EAP_LOCAL_SKILLS_DIR 同级) */
|
|
965
|
+
async resolvePromptRoots(agentCode, version) {
|
|
966
|
+
const roots = [];
|
|
967
|
+
const agentDir = await this.resolveAgentDir(agentCode, version);
|
|
968
|
+
if (agentDir)
|
|
969
|
+
roots.push(agentDir);
|
|
970
|
+
if (this.deploymentContext === 'dev' || this.deploymentContext === 'desktop') {
|
|
971
|
+
const explicit = process.env.EAP_LOCAL_PROMPTS_DIR?.trim();
|
|
972
|
+
if (explicit) {
|
|
973
|
+
roots.push(explicit);
|
|
974
|
+
return roots;
|
|
975
|
+
}
|
|
976
|
+
if (this.localSkillsDir)
|
|
977
|
+
roots.push(path.resolve(this.localSkillsDir, '..'));
|
|
978
|
+
}
|
|
979
|
+
return roots;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
function resolveLocalSkillsDir(explicit) {
|
|
983
|
+
const candidate = explicit?.trim() || process.env.EAP_LOCAL_SKILLS_DIR?.trim();
|
|
984
|
+
return candidate || undefined;
|
|
985
|
+
}
|