@gt-fe/eap-runtime 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/api/handlers/invoke.handler.d.ts +1 -1
- package/dist/api/handlers/invoke.handler.js +3 -0
- package/dist/api/handlers/stream.handler.d.ts +1 -1
- package/dist/api/handlers/stream.handler.js +3 -0
- package/dist/common/index.d.ts +1 -0
- package/dist/common/index.js +1 -0
- package/dist/common/logger.d.ts +16 -4
- package/dist/common/logger.js +82 -16
- package/dist/common/runtime-package-version.d.ts +2 -0
- package/dist/common/runtime-package-version.js +5 -0
- package/dist/debug/llm-turn-log.d.ts +12 -0
- package/dist/debug/llm-turn-log.js +1 -0
- package/dist/graph/adapters/langgraph.adapter.d.ts +3 -1
- package/dist/graph/adapters/langgraph.adapter.js +66 -13
- package/dist/graph/adapters/subgraph-compiler.js +5 -2
- package/dist/graph/contracts/executable-graph.d.ts +13 -2
- package/dist/graph/nodes/llm-node.d.ts +3 -0
- package/dist/graph/nodes/llm-node.js +8 -0
- package/dist/graph/nodes/skill-bind-node.d.ts +3 -4
- package/dist/graph/nodes/skill-bind-node.js +1 -20
- package/dist/graph/nodes/tool-node.d.ts +2 -0
- package/dist/graph/nodes/tool-node.js +20 -14
- package/dist/memory/compression/index.d.ts +1 -1
- package/dist/memory/compression/index.js +1 -1
- package/dist/memory/compression/sliding-window.compression.js +7 -7
- package/dist/memory/index.d.ts +1 -1
- package/dist/memory/index.js +1 -1
- package/dist/memory/message-compression.service.d.ts +12 -1
- package/dist/memory/message-compression.service.js +29 -1
- package/dist/providers/http-llm-provider.d.ts +1 -0
- package/dist/providers/http-llm-provider.js +4 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +1 -1
- package/dist/providers/local-llm-provider.d.ts +3 -0
- package/dist/providers/local-llm-provider.js +14 -2
- package/dist/providers/routing-llm-provider.js +12 -3
- package/dist/registry/deployment-snapshot.js +18 -16
- package/dist/registry/graph-loader.d.ts +10 -0
- package/dist/registry/graph-loader.js +115 -66
- package/dist/runtime/agent-runtime.d.ts +3 -3
- package/dist/runtime/agent-runtime.js +13 -3
- package/dist/runtime/dev-runtime.d.ts +2 -0
- package/dist/runtime/dev-runtime.js +2 -0
- package/dist/runtime/types.d.ts +2 -2
- package/dist/session/compression-middleware.d.ts +2 -1
- package/dist/session/compression-middleware.js +7 -4
- package/dist/sse/events/stats-events.d.ts +9 -0
- package/dist/token/compression-budget-integration.d.ts +1 -1
- package/dist/token/compression-budget-integration.js +18 -10
- package/dist/token/context-window.d.ts +42 -0
- package/dist/token/context-window.js +73 -0
- package/dist/token/index.d.ts +1 -0
- package/dist/token/index.js +1 -0
- package/dist/tool/dev-http-executor.d.ts +1 -0
- package/dist/tool/dev-http-executor.js +12 -0
- package/dist/tool/dev-mcp-executor.d.ts +11 -1
- package/dist/tool/dev-mcp-executor.js +26 -0
- package/dist/tool/dev-tool-executor.d.ts +2 -1
- package/dist/tool/dev-tool-executor.js +6 -0
- package/dist/tool/harness-command.js +1 -1
- package/dist/tool/harness-primitives.d.ts +7 -0
- package/dist/tool/harness-primitives.js +56 -5
- package/dist/tool/index.d.ts +2 -1
- package/dist/tool/index.js +1 -0
- package/dist/tool/local-mcp-client.d.ts +4 -1
- package/dist/tool/local-mcp-client.js +130 -3
- package/dist/tool/local-tool-executor.d.ts +2 -1
- package/dist/tool/local-tool-executor.js +15 -0
- package/dist/tool/mcp-list.d.ts +53 -0
- package/dist/tool/mcp-list.js +199 -0
- package/dist/tool/mcp-tool-executor.d.ts +6 -1
- package/dist/tool/mcp-tool-executor.js +52 -0
- package/dist/tool/skill-dir-infer.d.ts +17 -0
- package/dist/tool/skill-dir-infer.js +81 -0
- package/dist/tool/skill-script-refs.d.ts +1 -8
- package/dist/tool/skill-script-refs.js +32 -20
- package/dist/tool/system-prompt-builder.d.ts +35 -16
- package/dist/tool/system-prompt-builder.js +30 -58
- package/dist/tool/timeout.js +4 -1
- package/dist/tool/tool-execution-router.d.ts +2 -1
- package/dist/tool/tool-execution-router.js +7 -0
- package/dist/tool/tool-executor.interface.d.ts +11 -0
- package/package.json +6 -33
- package/dist/registry/mcp-stdio-cwd.d.ts +0 -5
- package/dist/registry/mcp-stdio-cwd.js +0 -13
|
@@ -8,11 +8,12 @@ import { readFile } from 'node:fs/promises';
|
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { resolveAgentModelAllowlist, resolveAgentDefaultModel } from './agent-models.js';
|
|
10
10
|
import { DEFAULT_HTTP_TOOL_TIMEOUT_SEC, DEFAULT_TOOL_TIMEOUT_SEC } from '../tool/timeout.js';
|
|
11
|
-
import {
|
|
11
|
+
import { isMcpDiscoverStub } from '../tool/mcp-list.js';
|
|
12
12
|
import { createDeploymentSnapshotFromEnv, isInlineToolDeclaration, overlayToolRefPolicies, } from './deployment-snapshot.js';
|
|
13
13
|
import { preloadGraphNotFound, preloadManifestNotFound, preloadSkillNotFound, preloadToolNotFound, } from './preload-errors.js';
|
|
14
14
|
import { PreinstallDefinitionCache, resolveDefinitionCacheEnabled, } from './definition-cache.js';
|
|
15
15
|
import { inspectAgentSkillTree, listSkillDirs, readSkillAssembly, resolveSkillHotReload, skillAssemblyStamp, } from './skill-tree.js';
|
|
16
|
+
import { emitRuntimeLog } from '../common/logger.js';
|
|
16
17
|
function applyDefaultModelToGraph(graph, defaultModel) {
|
|
17
18
|
if (!defaultModel)
|
|
18
19
|
return graph;
|
|
@@ -57,6 +58,24 @@ function asGraphDsl(value) {
|
|
|
57
58
|
}
|
|
58
59
|
return undefined;
|
|
59
60
|
}
|
|
61
|
+
export async function resolveAgentSystemPromptFromLoader(loader, agentCode, version) {
|
|
62
|
+
if (!loader || typeof loader.resolveAgentSystemPrompt !== 'function')
|
|
63
|
+
return undefined;
|
|
64
|
+
return loader.resolveAgentSystemPrompt(agentCode, version);
|
|
65
|
+
}
|
|
66
|
+
/** manifest.prompts.system;空白视为缺省。 */
|
|
67
|
+
export function extractAgentSystemPrompt(manifest) {
|
|
68
|
+
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest))
|
|
69
|
+
return undefined;
|
|
70
|
+
const prompts = manifest.prompts;
|
|
71
|
+
if (!prompts || typeof prompts !== 'object' || Array.isArray(prompts))
|
|
72
|
+
return undefined;
|
|
73
|
+
const system = prompts.system;
|
|
74
|
+
if (typeof system !== 'string')
|
|
75
|
+
return undefined;
|
|
76
|
+
const trimmed = system.trim();
|
|
77
|
+
return trimmed ? trimmed : undefined;
|
|
78
|
+
}
|
|
60
79
|
function extractSkillPrompt(manifest) {
|
|
61
80
|
const prompt = manifest.prompt;
|
|
62
81
|
if (typeof prompt === 'string' && prompt.trim())
|
|
@@ -96,35 +115,6 @@ async function resolveSkillPrompt(manifest, bundlePath) {
|
|
|
96
115
|
}
|
|
97
116
|
return raw;
|
|
98
117
|
}
|
|
99
|
-
function extractSkillToolsets(manifest) {
|
|
100
|
-
const refs = manifest.toolsets;
|
|
101
|
-
if (!Array.isArray(refs))
|
|
102
|
-
return undefined;
|
|
103
|
-
const out = [];
|
|
104
|
-
for (const item of refs) {
|
|
105
|
-
if (typeof item === 'string') {
|
|
106
|
-
out.push(item);
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (!item || typeof item !== 'object')
|
|
110
|
-
continue;
|
|
111
|
-
const o = item;
|
|
112
|
-
const code = o.code != null ? String(o.code) : undefined;
|
|
113
|
-
const enabled = Array.isArray(o.enabled)
|
|
114
|
-
? o.enabled.filter((x) => typeof x === 'string')
|
|
115
|
-
: undefined;
|
|
116
|
-
out.push({
|
|
117
|
-
name: o.name != null ? String(o.name) : code,
|
|
118
|
-
version: o.version != null ? String(o.version) : undefined,
|
|
119
|
-
code,
|
|
120
|
-
enabled,
|
|
121
|
-
autoApprove: Array.isArray(o.autoApprove)
|
|
122
|
-
? o.autoApprove.filter((x) => typeof x === 'string')
|
|
123
|
-
: undefined,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
return out.length > 0 ? out : undefined;
|
|
127
|
-
}
|
|
128
118
|
function extractEmbeddedGraph(manifest) {
|
|
129
119
|
const candidates = [
|
|
130
120
|
manifest.graph,
|
|
@@ -224,6 +214,67 @@ function toLoadedToolDefinition(record) {
|
|
|
224
214
|
inputSchema: m.input,
|
|
225
215
|
};
|
|
226
216
|
}
|
|
217
|
+
function resolveMcpServer(manifest) {
|
|
218
|
+
if (manifest.server && typeof manifest.server === 'object' && !Array.isArray(manifest.server)) {
|
|
219
|
+
return manifest.server;
|
|
220
|
+
}
|
|
221
|
+
const execution = manifest.execution;
|
|
222
|
+
if (execution && typeof execution === 'object' && !Array.isArray(execution)) {
|
|
223
|
+
const exec = execution;
|
|
224
|
+
if (exec.server && typeof exec.server === 'object' && !Array.isArray(exec.server)) {
|
|
225
|
+
return exec.server;
|
|
226
|
+
}
|
|
227
|
+
const mcp = exec.mcp;
|
|
228
|
+
if (mcp && typeof mcp === 'object' && !Array.isArray(mcp)) {
|
|
229
|
+
const nested = mcp.server;
|
|
230
|
+
if (nested && typeof nested === 'object' && !Array.isArray(nested)) {
|
|
231
|
+
return nested;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
function mcpDiscoverStub(pre, options) {
|
|
238
|
+
const m = pre.manifest;
|
|
239
|
+
const server = resolveMcpServer(m);
|
|
240
|
+
const toolRuntime = (m.toolRuntime ?? m.runtime);
|
|
241
|
+
const timeout = (typeof server?.timeout === 'number' ? server.timeout : undefined)
|
|
242
|
+
?? DEFAULT_TOOL_TIMEOUT_SEC;
|
|
243
|
+
const transport = (typeof server?.transport === 'string' && server.transport)
|
|
244
|
+
|| (server?.url ? 'streamable_http' : 'stdio');
|
|
245
|
+
const execution = {
|
|
246
|
+
protocol: 'mcp',
|
|
247
|
+
transport,
|
|
248
|
+
server,
|
|
249
|
+
timeout,
|
|
250
|
+
discover: true,
|
|
251
|
+
bundlePath: pre.bundlePath,
|
|
252
|
+
};
|
|
253
|
+
if (options?.enabledTools && options.enabledTools.length > 0) {
|
|
254
|
+
execution.enabledTools = options.enabledTools;
|
|
255
|
+
}
|
|
256
|
+
if (options?.autoApprove && options.autoApprove.length > 0) {
|
|
257
|
+
execution.autoApprove = options.autoApprove;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
toolId: pre.toolId,
|
|
261
|
+
name: pre.name,
|
|
262
|
+
manifest: {
|
|
263
|
+
id: pre.toolId,
|
|
264
|
+
name: pre.name,
|
|
265
|
+
version: pre.version,
|
|
266
|
+
type: 'mcp',
|
|
267
|
+
status: 'active',
|
|
268
|
+
description: m.description,
|
|
269
|
+
toolRuntime,
|
|
270
|
+
dataScope: normalizeDataScope(m.permissions && typeof m.permissions === 'object' && !Array.isArray(m.permissions)
|
|
271
|
+
? m.permissions.dataScope
|
|
272
|
+
: m.dataScope),
|
|
273
|
+
requireConfirmation: false,
|
|
274
|
+
execution,
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
}
|
|
227
278
|
function fromPreinstallTool(pre) {
|
|
228
279
|
const m = pre.manifest;
|
|
229
280
|
const permissions = m.permissions;
|
|
@@ -255,14 +306,16 @@ function fromPreinstallTool(pre) {
|
|
|
255
306
|
};
|
|
256
307
|
}
|
|
257
308
|
/**
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
* 无 tools[] 时回退为单工具 manifest(tool.manifest.json 结构)。
|
|
309
|
+
* 展开预装工具集为 LoadedToolDefinition。
|
|
310
|
+
* - type=mcp:忽略清单 tools[],产出一条 discover stub;子工具在执行期 tools/list。
|
|
311
|
+
* - type=code/http:展开 tools[];无 tools[] 时回退单工具 manifest。
|
|
262
312
|
* enabled 为可选白名单(agent.manifest toolsets[].enabled);缺省启用全部子工具。
|
|
263
313
|
*/
|
|
264
314
|
function expandPreinstallToolset(pre, options) {
|
|
265
315
|
const m = pre.manifest;
|
|
316
|
+
if (m.type === 'mcp') {
|
|
317
|
+
return [mcpDiscoverStub(pre, options)];
|
|
318
|
+
}
|
|
266
319
|
const tools = m.tools;
|
|
267
320
|
const enabled = options?.enabledTools;
|
|
268
321
|
const enabledSet = enabled && enabled.length > 0 ? new Set(enabled) : null;
|
|
@@ -281,7 +334,6 @@ function expandPreinstallToolset(pre, options) {
|
|
|
281
334
|
}
|
|
282
335
|
const setType = m.type;
|
|
283
336
|
const toolRuntime = (m.toolRuntime ?? m.runtime);
|
|
284
|
-
const server = m.server;
|
|
285
337
|
const pkg = m.package;
|
|
286
338
|
const out = [];
|
|
287
339
|
for (const raw of tools) {
|
|
@@ -302,28 +354,10 @@ function expandPreinstallToolset(pre, options) {
|
|
|
302
354
|
baseUrl: st.baseUrl ?? gateway.baseUrl,
|
|
303
355
|
pathTemplate: st.pathTemplate,
|
|
304
356
|
allowedHosts: gateway.allowedHosts,
|
|
357
|
+
header: gateway.header,
|
|
305
358
|
timeout: st.timeout ?? gateway.timeout ?? DEFAULT_HTTP_TOOL_TIMEOUT_SEC,
|
|
306
359
|
};
|
|
307
360
|
}
|
|
308
|
-
else if (setType === 'mcp') {
|
|
309
|
-
type = 'mcp';
|
|
310
|
-
const transport = server?.transport ?? (server?.url ? 'streamable_http' : 'stdio');
|
|
311
|
-
const resolvedServer = server
|
|
312
|
-
? {
|
|
313
|
-
...server,
|
|
314
|
-
...(transport === 'stdio'
|
|
315
|
-
? { cwd: resolveStdioMcpCwd(pre.bundlePath, server.cwd) }
|
|
316
|
-
: {}),
|
|
317
|
-
}
|
|
318
|
-
: server;
|
|
319
|
-
execution = {
|
|
320
|
-
protocol: 'mcp',
|
|
321
|
-
transport,
|
|
322
|
-
server: resolvedServer,
|
|
323
|
-
toolName: name,
|
|
324
|
-
timeout: st.timeout ?? server?.timeout ?? DEFAULT_TOOL_TIMEOUT_SEC,
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
361
|
else {
|
|
328
362
|
type = 'code';
|
|
329
363
|
execution = {
|
|
@@ -522,28 +556,24 @@ export class GraphLoader {
|
|
|
522
556
|
catch (err) {
|
|
523
557
|
const message = err instanceof Error ? err.message : String(err);
|
|
524
558
|
skillWarnings.push(message);
|
|
525
|
-
|
|
559
|
+
emitRuntimeLog('warn', 'graph-loader', message, {
|
|
526
560
|
event: 'runtime.warmAgent.skills_failed',
|
|
527
|
-
level: 'warn',
|
|
528
561
|
agentCode,
|
|
529
562
|
agentVersion: version ?? null,
|
|
530
|
-
|
|
531
|
-
}));
|
|
563
|
+
});
|
|
532
564
|
}
|
|
533
565
|
// 预期跳过(无 userId 的 users 层 Skill)用 debug,避免单测/生产噪音
|
|
534
566
|
if (skippedSkills.length > 0) {
|
|
535
|
-
|
|
567
|
+
emitRuntimeLog('debug', 'graph-loader', 'warmAgent skipped user skills', {
|
|
536
568
|
event: 'runtime.warmAgent.skills_skipped',
|
|
537
|
-
level: 'debug',
|
|
538
569
|
agentCode,
|
|
539
570
|
agentVersion: version ?? null,
|
|
540
571
|
userId: options?.userId ?? null,
|
|
541
572
|
skippedSkillIds: skippedSkills,
|
|
542
|
-
})
|
|
573
|
+
});
|
|
543
574
|
}
|
|
544
|
-
|
|
575
|
+
emitRuntimeLog('info', 'graph-loader', 'warmAgent ok', {
|
|
545
576
|
event: 'runtime.warmAgent.ok',
|
|
546
|
-
level: 'info',
|
|
547
577
|
agentCode,
|
|
548
578
|
agentVersion: version ?? null,
|
|
549
579
|
graph: true,
|
|
@@ -551,7 +581,7 @@ export class GraphLoader {
|
|
|
551
581
|
skills: skillsOk,
|
|
552
582
|
skillWarningCount: skillWarnings.length,
|
|
553
583
|
skillWarnings,
|
|
554
|
-
})
|
|
584
|
+
});
|
|
555
585
|
return {
|
|
556
586
|
graph: true,
|
|
557
587
|
tools: true,
|
|
@@ -632,7 +662,6 @@ export class GraphLoader {
|
|
|
632
662
|
type: 'llm',
|
|
633
663
|
config: {
|
|
634
664
|
model,
|
|
635
|
-
systemPrompt: manifest.prompts?.system,
|
|
636
665
|
},
|
|
637
666
|
},
|
|
638
667
|
],
|
|
@@ -642,6 +671,24 @@ export class GraphLoader {
|
|
|
642
671
|
},
|
|
643
672
|
};
|
|
644
673
|
}
|
|
674
|
+
/**
|
|
675
|
+
* Agent 基线系统提示词(manifest.prompts.system)。
|
|
676
|
+
* 每轮 execute/stream 注入 GraphState.agentSystemPrompt;不写进节点 config。
|
|
677
|
+
*/
|
|
678
|
+
async resolveAgentSystemPrompt(agentCode, version) {
|
|
679
|
+
if (this.deploymentSnapshot) {
|
|
680
|
+
const snap = await this.deploymentSnapshot.loadAgentSnapshot(agentCode, version);
|
|
681
|
+
if (snap) {
|
|
682
|
+
return extractAgentSystemPrompt(snap.manifest);
|
|
683
|
+
}
|
|
684
|
+
if (this.blockRegistryDefinitions)
|
|
685
|
+
return undefined;
|
|
686
|
+
}
|
|
687
|
+
if (this.blockRegistryDefinitions || !this.registryClient)
|
|
688
|
+
return undefined;
|
|
689
|
+
const record = await this.registryClient.getAgent(agentCode);
|
|
690
|
+
return extractAgentSystemPrompt(record?.manifest);
|
|
691
|
+
}
|
|
645
692
|
/**
|
|
646
693
|
* 解析 agent tools[] + graph tool 节点 union;
|
|
647
694
|
* server+预装:以预装 manifest 为准;desktop 合并 ILocalToolInstallStore。
|
|
@@ -753,6 +800,9 @@ export class GraphLoader {
|
|
|
753
800
|
continue;
|
|
754
801
|
const pre = await this.deploymentSnapshot.loadToolManifest({ name: toolName }, agentDir);
|
|
755
802
|
if (!pre) {
|
|
803
|
+
// MCP 子工具名在 tools/list 后才出现,图内 type:tool 节点不必对应预装目录
|
|
804
|
+
if (definitions.some(isMcpDiscoverStub))
|
|
805
|
+
continue;
|
|
756
806
|
missing.push(toolName);
|
|
757
807
|
continue;
|
|
758
808
|
}
|
|
@@ -861,7 +911,6 @@ export class GraphLoader {
|
|
|
861
911
|
prompt,
|
|
862
912
|
bundlePath: pre.bundlePath,
|
|
863
913
|
entryFile,
|
|
864
|
-
toolsets: extractSkillToolsets(pre.manifest),
|
|
865
914
|
inputDef: pre.manifest.inputDef,
|
|
866
915
|
outputDef: pre.manifest.outputDef,
|
|
867
916
|
});
|
|
@@ -11,7 +11,7 @@ import type { ICheckpointSaver } from '../checkpoint/contracts/checkpoint-saver.
|
|
|
11
11
|
import type { ITraceCollector } from '../contracts/trace-collector.js';
|
|
12
12
|
import type { IStateGraphEngine } from '../graph/contracts/state-graph.contract.js';
|
|
13
13
|
import { HitlHandler } from '../graph/hitl/hitl-handler.js';
|
|
14
|
-
import type
|
|
14
|
+
import { type GraphLoader } from '../registry/graph-loader.js';
|
|
15
15
|
import type { SessionContextService } from '../session/session-context.service.js';
|
|
16
16
|
import type { MessageService } from '../session/message.service.js';
|
|
17
17
|
import type { SessionService, SessionRecord, MessageRecord } from '../session/session.service.js';
|
|
@@ -86,8 +86,8 @@ export declare class AgentRuntime {
|
|
|
86
86
|
* “Session 历史 + 当前输入”途径。
|
|
87
87
|
*
|
|
88
88
|
* 行为:
|
|
89
|
-
* - `role` 仅接受 `user` / `assistant`;`system`
|
|
90
|
-
* `
|
|
89
|
+
* - `role` 仅接受 `user` / `assistant`;`system` 由 SystemPromptBuilder 拼
|
|
90
|
+
* (平台规则 + `prompts.system` 基线 + 节点 `systemPrompt`);
|
|
91
91
|
* `tool` 必须与前置 assistant.toolCalls 严格配对,不得单独作为种子。
|
|
92
92
|
* - 幂等语义(exactly-once):当 session 已存在任何历史消息时,直接返回
|
|
93
93
|
* `seeded: false`,不重复写入。
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
10
|
import { HITL_TIMEOUT_ERROR_CODE, HITL_TIMEOUT_MESSAGE, HitlAlreadyTimedOutError, HitlNotWaitingError, buildHitlWaitedPayload, isHitlDeadlinePassed, readPersistedHitlWaiting, unwrapHitlPaused, } from '../graph/hitl/hitl-handler.js';
|
|
11
|
+
import { resolveAgentSystemPromptFromLoader } from '../registry/graph-loader.js';
|
|
11
12
|
import { toLoadedSkillMap } from '../tool/system-prompt-builder.js';
|
|
12
13
|
import { assembleLoadedTools } from '../tool/harness-primitives.js';
|
|
13
14
|
import { createFileLlmTurnLogFromEnv, } from '../debug/llm-turn-log.js';
|
|
@@ -71,8 +72,8 @@ export class AgentRuntime {
|
|
|
71
72
|
* “Session 历史 + 当前输入”途径。
|
|
72
73
|
*
|
|
73
74
|
* 行为:
|
|
74
|
-
* - `role` 仅接受 `user` / `assistant`;`system`
|
|
75
|
-
* `
|
|
75
|
+
* - `role` 仅接受 `user` / `assistant`;`system` 由 SystemPromptBuilder 拼
|
|
76
|
+
* (平台规则 + `prompts.system` 基线 + 节点 `systemPrompt`);
|
|
76
77
|
* `tool` 必须与前置 assistant.toolCalls 严格配对,不得单独作为种子。
|
|
77
78
|
* - 幂等语义(exactly-once):当 session 已存在任何历史消息时,直接返回
|
|
78
79
|
* `seeded: false`,不重复写入。
|
|
@@ -100,7 +101,7 @@ export class AgentRuntime {
|
|
|
100
101
|
throw new AppError(ErrorCodes.PARAMS_INVALID, `seedSessionMessages messages[${index}] must be an object`, { exposeMessage: true });
|
|
101
102
|
}
|
|
102
103
|
if (message.role !== 'user' && message.role !== 'assistant') {
|
|
103
|
-
throw new AppError(ErrorCodes.PARAMS_INVALID, `seedSessionMessages messages[${index}].role "${String(message.role)}" is not allowed; only 'user' and 'assistant' are accepted (system belongs to
|
|
104
|
+
throw new AppError(ErrorCodes.PARAMS_INVALID, `seedSessionMessages messages[${index}].role "${String(message.role)}" is not allowed; only 'user' and 'assistant' are accepted (system belongs to SystemPromptBuilder: platform rules + prompts.system + node systemPrompt; tool must pair with prior assistant.toolCalls)`, { exposeMessage: true });
|
|
104
105
|
}
|
|
105
106
|
if (typeof message.content !== 'string' || message.content.length === 0) {
|
|
106
107
|
throw new AppError(ErrorCodes.PARAMS_INVALID, `seedSessionMessages messages[${index}].content must be a non-empty string`, { exposeMessage: true });
|
|
@@ -271,6 +272,7 @@ export class AgentRuntime {
|
|
|
271
272
|
const agentDir = this.deps.graphLoader
|
|
272
273
|
? (await this.deps.graphLoader.resolveAgentDir(agentCode, params.agentVersion)) ?? undefined
|
|
273
274
|
: undefined;
|
|
275
|
+
const agentSystemPrompt = await resolveAgentSystemPromptFromLoader(this.deps.graphLoader, agentCode, params.agentVersion);
|
|
274
276
|
const history = messageRecordsToGraphMessages(sessionContext.messages);
|
|
275
277
|
const messages = await buildTurnGraphMessages({
|
|
276
278
|
history,
|
|
@@ -301,6 +303,7 @@ export class AgentRuntime {
|
|
|
301
303
|
skillDefinitions,
|
|
302
304
|
promptRoots,
|
|
303
305
|
agentDir,
|
|
306
|
+
agentSystemPrompt,
|
|
304
307
|
skillInput: resolveSkillInputFromInvokeInput(params.input),
|
|
305
308
|
traceId: resolveTraceId(params),
|
|
306
309
|
traceCollector: this.deps.traceCollector,
|
|
@@ -490,6 +493,9 @@ export class AgentRuntime {
|
|
|
490
493
|
(this.deps.graphLoader
|
|
491
494
|
? (await this.deps.graphLoader.resolveAgentDir(agentCode, agentVersion)) ?? undefined
|
|
492
495
|
: undefined),
|
|
496
|
+
agentSystemPrompt: (await resolveAgentSystemPromptFromLoader(this.deps.graphLoader, agentCode, agentVersion)) ?? (typeof resumedState.agentSystemPrompt === 'string'
|
|
497
|
+
? resumedState.agentSystemPrompt
|
|
498
|
+
: undefined),
|
|
493
499
|
activatedSkill: resumedState.activatedSkill,
|
|
494
500
|
skillRoute: resumedState.skillRoute ??
|
|
495
501
|
(typeof resumedState.activatedSkill === 'string' && resumedState.activatedSkill
|
|
@@ -652,11 +658,15 @@ export class AgentRuntime {
|
|
|
652
658
|
(this.deps.graphLoader
|
|
653
659
|
? (await this.deps.graphLoader.resolveAgentDir(agentCode, agentVersion)) ?? undefined
|
|
654
660
|
: undefined);
|
|
661
|
+
const agentSystemPrompt = (await resolveAgentSystemPromptFromLoader(this.deps.graphLoader, agentCode, agentVersion)) ?? (typeof forkedCheckpoint.state.agentSystemPrompt === 'string'
|
|
662
|
+
? forkedCheckpoint.state.agentSystemPrompt
|
|
663
|
+
: undefined);
|
|
655
664
|
try {
|
|
656
665
|
const result = await this.deps.graphEngine.invoke(graph, {
|
|
657
666
|
...forkedCheckpoint.state,
|
|
658
667
|
agentVersion,
|
|
659
668
|
agentDir,
|
|
669
|
+
agentSystemPrompt,
|
|
660
670
|
userId,
|
|
661
671
|
delegationToken: overrides.executionContext?.delegationToken,
|
|
662
672
|
executionContext: overrides.executionContext,
|
|
@@ -49,6 +49,8 @@ export interface DevRuntime {
|
|
|
49
49
|
dispose: () => void;
|
|
50
50
|
/** 装配期诊断摘要(CLI 启动时打印,便于排查环境问题) */
|
|
51
51
|
diagnostics: {
|
|
52
|
+
/** 当前加载的 Runtime 包 version */
|
|
53
|
+
packageVersion: string;
|
|
52
54
|
deploymentContext: string;
|
|
53
55
|
toolExecutionMode: string;
|
|
54
56
|
llmProviderKind: 'routing' | 'openai-http' | 'echo';
|
|
@@ -35,6 +35,7 @@ import { InvokeOrchestrator, StreamOrchestrator, SessionService, MessageService,
|
|
|
35
35
|
import { createAgentRuntime } from './agent-runtime.js';
|
|
36
36
|
import { assembleRuntimeStorage } from './storage-profile.js';
|
|
37
37
|
import { resolveSkillHotReload, watchPreinstallSkillRoot, watchSkillRoots } from '../registry/skill-tree.js';
|
|
38
|
+
import { RUNTIME_PACKAGE_VERSION } from '../common/runtime-package-version.js';
|
|
38
39
|
/**
|
|
39
40
|
* 装配本地 dev 模式所需的全部 Runtime 依赖
|
|
40
41
|
*
|
|
@@ -185,6 +186,7 @@ export function createDevRuntime() {
|
|
|
185
186
|
graphLoader,
|
|
186
187
|
dispose: stopSkillWatch,
|
|
187
188
|
diagnostics: {
|
|
189
|
+
packageVersion: RUNTIME_PACKAGE_VERSION,
|
|
188
190
|
deploymentContext,
|
|
189
191
|
toolExecutionMode,
|
|
190
192
|
llmProviderKind,
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -91,8 +91,8 @@ export interface ForkResult {
|
|
|
91
91
|
* 开发者提供的对话上下文(开场白 / few-shot)。
|
|
92
92
|
*
|
|
93
93
|
* 约束(AgentRuntime.seedSessionMessages 强制校验):
|
|
94
|
-
* - `role` 白名单为 `user` / `assistant`,`system`
|
|
95
|
-
* `
|
|
94
|
+
* - `role` 白名单为 `user` / `assistant`,`system` 由 SystemPromptBuilder 拼
|
|
95
|
+
* (平台规则 + `prompts.system` + 节点 `systemPrompt`),`tool` 必须与
|
|
96
96
|
* 前置 assistant.toolCalls 严格配对,两者禁止作为种子;
|
|
97
97
|
* - 该 session 已有历史时,视作已种入,跳过写入(exactly-once 幂等)。
|
|
98
98
|
*/
|
|
@@ -65,11 +65,12 @@ export declare class CompressionMiddleware {
|
|
|
65
65
|
sessionId: string;
|
|
66
66
|
taskId?: string;
|
|
67
67
|
userId: string;
|
|
68
|
+
maxContextTokens?: number;
|
|
68
69
|
}): Promise<MessageRecord[]>;
|
|
69
70
|
/**
|
|
70
71
|
* 检查是否需要压缩(不执行)
|
|
71
72
|
*/
|
|
72
|
-
checkCompression(messages: MessageRecord[]): {
|
|
73
|
+
checkCompression(messages: MessageRecord[], maxContextTokens?: number): {
|
|
73
74
|
needsCompression: boolean;
|
|
74
75
|
currentTokens: number;
|
|
75
76
|
currentRounds: number;
|
|
@@ -65,13 +65,16 @@ export class CompressionMiddleware {
|
|
|
65
65
|
// 转换为 GraphMessage 格式进行检查
|
|
66
66
|
const graphMessages = this.toGraphMessages(messages);
|
|
67
67
|
// 检查是否需要压缩
|
|
68
|
-
const
|
|
68
|
+
const windowOverride = context.maxContextTokens
|
|
69
|
+
? { maxContextTokens: context.maxContextTokens }
|
|
70
|
+
: undefined;
|
|
71
|
+
const checkResult = this.compression.checkCompression(graphMessages, windowOverride);
|
|
69
72
|
if (!checkResult.needsCompression) {
|
|
70
73
|
return messages;
|
|
71
74
|
}
|
|
72
75
|
// 执行压缩
|
|
73
76
|
const startTime = Date.now();
|
|
74
|
-
const compressedMessages = await this.compression.compress(graphMessages);
|
|
77
|
+
const compressedMessages = await this.compression.compress(graphMessages, windowOverride);
|
|
75
78
|
const duration = Date.now() - startTime;
|
|
76
79
|
// 转换回 MessageRecord 格式
|
|
77
80
|
const compressedRecords = this.toMessageRecords(compressedMessages, messages);
|
|
@@ -106,9 +109,9 @@ export class CompressionMiddleware {
|
|
|
106
109
|
/**
|
|
107
110
|
* 检查是否需要压缩(不执行)
|
|
108
111
|
*/
|
|
109
|
-
checkCompression(messages) {
|
|
112
|
+
checkCompression(messages, maxContextTokens) {
|
|
110
113
|
const graphMessages = this.toGraphMessages(messages);
|
|
111
|
-
return this.compression.checkCompression(graphMessages);
|
|
114
|
+
return this.compression.checkCompression(graphMessages, maxContextTokens ? { maxContextTokens } : undefined);
|
|
112
115
|
}
|
|
113
116
|
/**
|
|
114
117
|
* 获取配置
|
|
@@ -41,4 +41,13 @@ export interface StatsNodeTokenUsagePayload {
|
|
|
41
41
|
costEstimate: number;
|
|
42
42
|
/** 该节点本次调用耗时(毫秒),可选 */
|
|
43
43
|
durationMs?: number;
|
|
44
|
+
/** 本轮 prompt 占用的上下文窗 used/window;缺 window 则省略 */
|
|
45
|
+
used?: number;
|
|
46
|
+
window?: number;
|
|
47
|
+
/** 按字符比例把 used 拆到 system/messages/tools;合计 = used */
|
|
48
|
+
parts?: {
|
|
49
|
+
system: number;
|
|
50
|
+
messages: number;
|
|
51
|
+
tools: number;
|
|
52
|
+
};
|
|
44
53
|
}
|
|
@@ -18,7 +18,7 @@ import type { IMessageRepository } from '../session/session.service.js';
|
|
|
18
18
|
export interface CompressionBudgetConfig {
|
|
19
19
|
/** 模型 context window 大小 */
|
|
20
20
|
modelContextWindow: number;
|
|
21
|
-
/**
|
|
21
|
+
/** 相对模型窗口的触发系数(默认 0.7,与滑动窗口同一公式) */
|
|
22
22
|
historyThreshold?: number;
|
|
23
23
|
/** 压缩后目标占比(默认 0.5) */
|
|
24
24
|
targetRatio?: number;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { createContextBudget } from './context-window-budget.js';
|
|
11
11
|
import { CompressionMiddleware, createCompressionMiddlewareWithLLM, } from '../session/compression-middleware.js';
|
|
12
|
-
import { estimateMessagesTokens } from '../memory/message-compression.service.js';
|
|
12
|
+
import { estimateMessagesTokens, resolveCompressionMaxTokens, } from '../memory/message-compression.service.js';
|
|
13
13
|
// ─────────────────────────────────────────────
|
|
14
14
|
// CompressionBudgetIntegration
|
|
15
15
|
// ─────────────────────────────────────────────
|
|
@@ -28,7 +28,7 @@ export class CompressionBudgetIntegration {
|
|
|
28
28
|
constructor(config, repository, messageRepository) {
|
|
29
29
|
this.config = {
|
|
30
30
|
modelContextWindow: config.modelContextWindow,
|
|
31
|
-
historyThreshold: config.historyThreshold ?? 0.
|
|
31
|
+
historyThreshold: config.historyThreshold ?? 0.7,
|
|
32
32
|
targetRatio: config.targetRatio ?? 0.5,
|
|
33
33
|
autoCompress: config.autoCompress ?? true,
|
|
34
34
|
llmConfig: config.llmConfig,
|
|
@@ -36,13 +36,17 @@ export class CompressionBudgetIntegration {
|
|
|
36
36
|
// 创建预算管理器
|
|
37
37
|
this.budget = createContextBudget(this.config.modelContextWindow);
|
|
38
38
|
// 创建压缩中间件
|
|
39
|
+
const compressionConfig = {
|
|
40
|
+
maxContextTokens: this.config.modelContextWindow,
|
|
41
|
+
};
|
|
39
42
|
if (this.config.llmConfig?.provider) {
|
|
40
43
|
this.compression = createCompressionMiddlewareWithLLM(this.config.llmConfig.provider, {
|
|
41
44
|
llmConfig: this.config.llmConfig,
|
|
45
|
+
compressionConfig,
|
|
42
46
|
}, repository, messageRepository);
|
|
43
47
|
}
|
|
44
48
|
else {
|
|
45
|
-
this.compression = new CompressionMiddleware({}, undefined, repository, messageRepository);
|
|
49
|
+
this.compression = new CompressionMiddleware({ compressionConfig }, undefined, repository, messageRepository);
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
@@ -55,12 +59,13 @@ export class CompressionBudgetIntegration {
|
|
|
55
59
|
// 估算当前 Token 数
|
|
56
60
|
const graphMessages = this.toGraphMessages(messages);
|
|
57
61
|
const currentTokens = estimateMessagesTokens(graphMessages);
|
|
58
|
-
//
|
|
59
|
-
const maxTokens = this.
|
|
60
|
-
//
|
|
61
|
-
const usageRatio =
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// 与滑动窗口同一阈值:window × 系数(默认 0.7);historyThreshold 作为系数覆盖
|
|
63
|
+
const maxTokens = resolveCompressionMaxTokens(this.config.modelContextWindow, this.config.historyThreshold);
|
|
64
|
+
// 计算使用率(相对窗口,不是相对阈值)
|
|
65
|
+
const usageRatio = this.config.modelContextWindow > 0
|
|
66
|
+
? currentTokens / this.config.modelContextWindow
|
|
67
|
+
: 0;
|
|
68
|
+
const needsCompression = currentTokens > maxTokens;
|
|
64
69
|
// 计算压缩目标
|
|
65
70
|
const targetTokens = needsCompression
|
|
66
71
|
? Math.floor(maxTokens * this.config.targetRatio)
|
|
@@ -96,7 +101,10 @@ export class CompressionBudgetIntegration {
|
|
|
96
101
|
}
|
|
97
102
|
// 执行压缩
|
|
98
103
|
const startTime = Date.now();
|
|
99
|
-
const compressedMessages = await this.compression.processMessages(messages,
|
|
104
|
+
const compressedMessages = await this.compression.processMessages(messages, {
|
|
105
|
+
...context,
|
|
106
|
+
maxContextTokens: this.config.modelContextWindow,
|
|
107
|
+
});
|
|
100
108
|
const duration = Date.now() - startTime;
|
|
101
109
|
// 计算压缩后的 Token 数
|
|
102
110
|
const compressedGraphMessages = this.toGraphMessages(compressedMessages);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本轮 prompt 占用的上下文窗:used = 本轮 inputTokens,window = ModelRecord.capabilities.maxContextTokens。
|
|
3
|
+
* 不是账单合计,也不是 max_tokens。
|
|
4
|
+
* parts 按本轮 system / messages / tools 字符比例把 used 拆开(无独立 tokenizer)。
|
|
5
|
+
*/
|
|
6
|
+
export interface ContextUsageParts {
|
|
7
|
+
system: number;
|
|
8
|
+
messages: number;
|
|
9
|
+
tools: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ContextWindowUsage {
|
|
12
|
+
used: number;
|
|
13
|
+
window?: number;
|
|
14
|
+
parts?: ContextUsageParts;
|
|
15
|
+
}
|
|
16
|
+
export declare function contextWindowUsage(used: number, window: number | undefined): ContextWindowUsage | undefined;
|
|
17
|
+
export declare function splitContextUsage(used: number, sections: {
|
|
18
|
+
systemChars: number;
|
|
19
|
+
messageChars: number;
|
|
20
|
+
toolChars: number;
|
|
21
|
+
}): ContextUsageParts | undefined;
|
|
22
|
+
export declare function turnSectionChars(config: {
|
|
23
|
+
systemPrompt?: string;
|
|
24
|
+
tools?: unknown[];
|
|
25
|
+
}, messages: Array<{
|
|
26
|
+
content?: string;
|
|
27
|
+
toolCalls?: unknown;
|
|
28
|
+
}>): {
|
|
29
|
+
systemChars: number;
|
|
30
|
+
messageChars: number;
|
|
31
|
+
toolChars: number;
|
|
32
|
+
};
|
|
33
|
+
export declare function buildContextUsage(used: number, window: number | undefined, sections?: {
|
|
34
|
+
systemChars: number;
|
|
35
|
+
messageChars: number;
|
|
36
|
+
toolChars: number;
|
|
37
|
+
}): ContextWindowUsage | undefined;
|
|
38
|
+
export declare function pickContextFields(raw: {
|
|
39
|
+
used?: unknown;
|
|
40
|
+
window?: unknown;
|
|
41
|
+
parts?: unknown;
|
|
42
|
+
}): Partial<ContextWindowUsage>;
|