@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
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Enterprise Agent Platform **执行引擎**(LangGraph.js):Agent Graph 编
|
|
|
8
8
|
|
|
9
9
|
| 日期 | 摘要 |
|
|
10
10
|
|------|------|
|
|
11
|
+
| 2026-08-29 | 待办收口:[`docs/TODO.md`](./docs/TODO.md)。压缩主路径未接;窗口展示不在 Runtime;Gateway 须 `tools/list` |
|
|
11
12
|
| 2026-08-24 | 0.0.10:官方 Skill / Harness、`ForkParams`、对话详情、存储两档。依赖 `@eap/contracts@0.0.9`。详见 [CHANGELOG.md](./CHANGELOG.md) |
|
|
12
13
|
| 2026-08-21 | 0.0.9:Gateway `/mcp` JSON-RPC 补 `Accept`;`tools/call` 透传工具版本。详见 [CHANGELOG.md](./CHANGELOG.md) |
|
|
13
14
|
| 2026-08-19 | 0.0.8:Skill 子图 SSE 闭环;`ExecuteParams.traceId`;`tool.called` 改为 Tool 节点开始执行。依赖 `@eap/contracts@0.0.8`。详见 [CHANGELOG.md](./CHANGELOG.md) |
|
|
@@ -28,6 +29,7 @@ Enterprise Agent Platform **执行引擎**(LangGraph.js):Agent Graph 编
|
|
|
28
29
|
| 环境变量总表 | [`docs/governance/governance-env-config.md`](../docs/governance/governance-env-config.md) |
|
|
29
30
|
| 预装联调契约 | [`docs/contracts/preload-hosting-runtime-contract.md`](../docs/contracts/preload-hosting-runtime-contract.md) |
|
|
30
31
|
| 预装加载与请求流转 | [`docs/contracts/runtime-preinstall-load-flow.md`](../docs/contracts/runtime-preinstall-load-flow.md) |
|
|
32
|
+
| Runtime 待办 | [`docs/TODO.md`](./docs/TODO.md) | 压缩主路径、窗口展示、Gateway `tools/list` |
|
|
31
33
|
| 技能 FS 待办 | [`docs/TODO-skill-fs.md`](./docs/TODO-skill-fs.md) |
|
|
32
34
|
| 本地 Agent 闭环 | [`docs/workflows/local-agent-dev-loop.md`](../docs/workflows/local-agent-dev-loop.md) |
|
|
33
35
|
|
|
@@ -131,7 +133,7 @@ dev-tools (eap chat / eap dev)
|
|
|
131
133
|
|
|
132
134
|
- **引擎**:`LangGraphAdapter`(`IStateGraphEngine`)将平台 Graph DSL 编成 LangGraph StateGraph
|
|
133
135
|
- **节点**:`llm`、`tool`、`subgraph`(Skill)、并行/条件边、HITL 等待
|
|
134
|
-
- **Skill 子图**:节点可带内嵌 `subgraphDsl`;或仅 `skillId`,从 state.`skillDefinitions` 取 `workflow`
|
|
136
|
+
- **Skill 子图**:节点可带内嵌 `subgraphDsl`;或仅 `skillId`,从 state.`skillDefinitions` 取 `workflow` 执行。技能正文用短目录 + `read_file`,不灌 system
|
|
135
137
|
- **权限**:子图执行前 `skill:{skillId}:use`(Governance)
|
|
136
138
|
- **流式**:`stream()` 产出 RuntimeEvent,再映射为 SSE(`response.chunk`、`tool.*`、`task.*` 等)
|
|
137
139
|
|
|
@@ -22,7 +22,7 @@ import type { TokenStatsService } from '../../token/token-stats.service.js';
|
|
|
22
22
|
import type { TokenBudgetGuard } from '../../token/token-budget-guard.js';
|
|
23
23
|
import type { SessionBudgetChecker } from '../../token/session-budget-checker.js';
|
|
24
24
|
import type { InvokeRequest, InvokeResponse } from '../routes/agent.routes.js';
|
|
25
|
-
import type
|
|
25
|
+
import { type GraphLoader } from '../../registry/graph-loader.js';
|
|
26
26
|
import type { ICheckpointSaver } from '../../checkpoint/contracts/checkpoint-saver.contract.js';
|
|
27
27
|
import type { ITraceCollector } from '../../contracts/trace-collector.js';
|
|
28
28
|
/**
|
|
@@ -20,6 +20,7 @@ import { SessionBudgetExhaustedError } from '../../token/session-budget-checker.
|
|
|
20
20
|
import { TokenBudgetExhaustedError } from '../../token/token-budget-guard.js';
|
|
21
21
|
import { resolveExecutionContext } from '../../governance/governance-client.js';
|
|
22
22
|
import { resolveSkillInputFromInvokeInput } from '../../registry/skill-io-guard.js';
|
|
23
|
+
import { resolveAgentSystemPromptFromLoader } from '../../registry/graph-loader.js';
|
|
23
24
|
import { toLoadedToolMap } from '../../tool/loaded-tool-definition.js';
|
|
24
25
|
import { toLoadedSkillMap } from '../../tool/system-prompt-builder.js';
|
|
25
26
|
import { assembleLoadedTools } from '../../tool/harness-primitives.js';
|
|
@@ -181,6 +182,7 @@ export class InvokeOrchestrator {
|
|
|
181
182
|
const agentDir = this.graphLoader
|
|
182
183
|
? (await this.graphLoader.resolveAgentDir(agentCode, req.agentVersion)) ?? undefined
|
|
183
184
|
: undefined;
|
|
185
|
+
const agentSystemPrompt = await resolveAgentSystemPromptFromLoader(this.graphLoader, agentCode, req.agentVersion);
|
|
184
186
|
// 组装 GraphState:有 Checkpoint 历史则只追加本轮 user,避免双重 append
|
|
185
187
|
const history = messageRecordsToGraphMessages(sessionContext.messages);
|
|
186
188
|
const messages = await buildTurnGraphMessages({
|
|
@@ -208,6 +210,7 @@ export class InvokeOrchestrator {
|
|
|
208
210
|
skillInput,
|
|
209
211
|
promptRoots,
|
|
210
212
|
agentDir,
|
|
213
|
+
agentSystemPrompt,
|
|
211
214
|
traceId: resolveTraceId(req),
|
|
212
215
|
traceCollector: this.traceCollector,
|
|
213
216
|
});
|
|
@@ -28,7 +28,7 @@ import type { TokenStatsService } from '../../token/token-stats.service.js';
|
|
|
28
28
|
import type { TokenBudgetGuard } from '../../token/token-budget-guard.js';
|
|
29
29
|
import type { SessionBudgetChecker } from '../../token/session-budget-checker.js';
|
|
30
30
|
import type { StreamRequest } from '../routes/agent.routes.js';
|
|
31
|
-
import type
|
|
31
|
+
import { type GraphLoader } from '../../registry/graph-loader.js';
|
|
32
32
|
import type { ICheckpointSaver } from '../../checkpoint/contracts/checkpoint-saver.contract.js';
|
|
33
33
|
import type { ITraceCollector } from '../../contracts/trace-collector.js';
|
|
34
34
|
/**
|
|
@@ -26,6 +26,7 @@ import { SSEEmitter } from '../../sse/sse-emitter.js';
|
|
|
26
26
|
import { resolveExecutionContext } from '../../governance/governance-client.js';
|
|
27
27
|
import { resolveSkillInputFromInvokeInput } from '../../registry/skill-io-guard.js';
|
|
28
28
|
import { ErrorCodes } from '@gt-fe/eap-contracts';
|
|
29
|
+
import { resolveAgentSystemPromptFromLoader } from '../../registry/graph-loader.js';
|
|
29
30
|
import { classifyRuntimeError } from '../../utils/http-error.js';
|
|
30
31
|
import { toLoadedToolMap } from '../../tool/loaded-tool-definition.js';
|
|
31
32
|
import { toLoadedSkillMap } from '../../tool/system-prompt-builder.js';
|
|
@@ -203,6 +204,7 @@ export class StreamOrchestrator {
|
|
|
203
204
|
const agentDir = this.graphLoader
|
|
204
205
|
? (await this.graphLoader.resolveAgentDir(agentCode, req.agentVersion)) ?? undefined
|
|
205
206
|
: undefined;
|
|
207
|
+
const agentSystemPrompt = await resolveAgentSystemPromptFromLoader(this.graphLoader, agentCode, req.agentVersion);
|
|
206
208
|
// 组装 GraphState:有 Checkpoint 历史则只追加本轮 user,避免双重 append
|
|
207
209
|
const history = messageRecordsToGraphMessages(sessionContext.messages);
|
|
208
210
|
const messages = await buildTurnGraphMessages({
|
|
@@ -236,6 +238,7 @@ export class StreamOrchestrator {
|
|
|
236
238
|
skillInput,
|
|
237
239
|
promptRoots,
|
|
238
240
|
agentDir,
|
|
241
|
+
agentSystemPrompt,
|
|
239
242
|
traceId: resolveTraceId(req),
|
|
240
243
|
traceCollector: this.traceCollector,
|
|
241
244
|
});
|
package/dist/common/index.d.ts
CHANGED
package/dist/common/index.js
CHANGED
package/dist/common/logger.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 结构化 stdout JSON 日志。
|
|
3
|
+
*
|
|
4
|
+
* EAP_LOG_LEVEL=debug|info|warn|error,默认 info。
|
|
5
|
+
* info 不写 prompt / messages / systemPrompt;正文在 llm_turns。
|
|
6
|
+
* 关联字段:correlationId、taskId、sessionId、agentCode。
|
|
3
7
|
*/
|
|
4
8
|
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
5
9
|
export interface LogEntry {
|
|
@@ -7,8 +11,13 @@ export interface LogEntry {
|
|
|
7
11
|
timestamp: string;
|
|
8
12
|
module: string;
|
|
9
13
|
message: string;
|
|
14
|
+
correlationId?: string;
|
|
15
|
+
taskId?: string;
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
agentCode?: string;
|
|
18
|
+
userId?: string;
|
|
19
|
+
event?: string;
|
|
10
20
|
context?: Record<string, unknown>;
|
|
11
|
-
error?: Error;
|
|
12
21
|
}
|
|
13
22
|
export interface ILogger {
|
|
14
23
|
debug(message: string, context?: Record<string, unknown>): void;
|
|
@@ -16,6 +25,10 @@ export interface ILogger {
|
|
|
16
25
|
warn(message: string, context?: Record<string, unknown>): void;
|
|
17
26
|
error(message: string, context?: Record<string, unknown>): void;
|
|
18
27
|
}
|
|
28
|
+
export declare function resolveLogLevel(env?: NodeJS.ProcessEnv): LogLevel;
|
|
29
|
+
export declare function shouldLog(level: LogLevel, min?: LogLevel): boolean;
|
|
30
|
+
export declare function formatLogEntry(level: LogLevel, module: string, message: string, context?: Record<string, unknown>): LogEntry;
|
|
31
|
+
export declare function emitRuntimeLog(level: LogLevel, module: string, message: string, context?: Record<string, unknown>): void;
|
|
19
32
|
export declare class ConsoleLogger implements ILogger {
|
|
20
33
|
private readonly module;
|
|
21
34
|
constructor(module: string);
|
|
@@ -23,9 +36,8 @@ export declare class ConsoleLogger implements ILogger {
|
|
|
23
36
|
info(message: string, context?: Record<string, unknown>): void;
|
|
24
37
|
warn(message: string, context?: Record<string, unknown>): void;
|
|
25
38
|
error(message: string, context?: Record<string, unknown>): void;
|
|
26
|
-
private log;
|
|
27
39
|
}
|
|
28
|
-
/**
|
|
40
|
+
/** 测试用空实现 */
|
|
29
41
|
export declare class NoopLogger implements ILogger {
|
|
30
42
|
debug(): void;
|
|
31
43
|
info(): void;
|
package/dist/common/logger.js
CHANGED
|
@@ -1,35 +1,101 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 结构化 stdout JSON 日志。
|
|
3
|
+
*
|
|
4
|
+
* EAP_LOG_LEVEL=debug|info|warn|error,默认 info。
|
|
5
|
+
* info 不写 prompt / messages / systemPrompt;正文在 llm_turns。
|
|
6
|
+
* 关联字段:correlationId、taskId、sessionId、agentCode。
|
|
3
7
|
*/
|
|
8
|
+
const LEVEL_RANK = {
|
|
9
|
+
debug: 10,
|
|
10
|
+
info: 20,
|
|
11
|
+
warn: 30,
|
|
12
|
+
error: 40,
|
|
13
|
+
};
|
|
14
|
+
const PROMPT_KEYS = new Set([
|
|
15
|
+
'systemPrompt',
|
|
16
|
+
'systemSections',
|
|
17
|
+
'messages',
|
|
18
|
+
'prompt',
|
|
19
|
+
'developerPrompt',
|
|
20
|
+
'agentPrompt',
|
|
21
|
+
'nodePrompt',
|
|
22
|
+
'agentSystemPrompt',
|
|
23
|
+
'apiKey',
|
|
24
|
+
'content',
|
|
25
|
+
'body',
|
|
26
|
+
]);
|
|
27
|
+
const ID_KEYS = ['correlationId', 'taskId', 'sessionId', 'agentCode', 'userId'];
|
|
28
|
+
export function resolveLogLevel(env = process.env) {
|
|
29
|
+
const raw = env.EAP_LOG_LEVEL?.trim().toLowerCase();
|
|
30
|
+
if (raw === 'debug' || raw === 'info' || raw === 'warn' || raw === 'error')
|
|
31
|
+
return raw;
|
|
32
|
+
return 'info';
|
|
33
|
+
}
|
|
34
|
+
export function shouldLog(level, min = resolveLogLevel()) {
|
|
35
|
+
return LEVEL_RANK[level] >= LEVEL_RANK[min];
|
|
36
|
+
}
|
|
37
|
+
function asId(value) {
|
|
38
|
+
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
39
|
+
}
|
|
40
|
+
function stripPromptFields(context, level) {
|
|
41
|
+
if (!context)
|
|
42
|
+
return undefined;
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [key, value] of Object.entries(context)) {
|
|
45
|
+
if (key === 'event' || ID_KEYS.includes(key))
|
|
46
|
+
continue;
|
|
47
|
+
if (level !== 'debug' && PROMPT_KEYS.has(key))
|
|
48
|
+
continue;
|
|
49
|
+
out[key] = value;
|
|
50
|
+
}
|
|
51
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
52
|
+
}
|
|
53
|
+
export function formatLogEntry(level, module, message, context) {
|
|
54
|
+
const safe = stripPromptFields(context, level);
|
|
55
|
+
const event = asId(context?.event) ?? asId(safe?.event);
|
|
56
|
+
const entry = {
|
|
57
|
+
level,
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
module,
|
|
60
|
+
message,
|
|
61
|
+
correlationId: asId(context?.correlationId),
|
|
62
|
+
taskId: asId(context?.taskId),
|
|
63
|
+
sessionId: asId(context?.sessionId),
|
|
64
|
+
agentCode: asId(context?.agentCode),
|
|
65
|
+
userId: asId(context?.userId),
|
|
66
|
+
...(event ? { event } : {}),
|
|
67
|
+
...(safe ? { context: safe } : {}),
|
|
68
|
+
};
|
|
69
|
+
return entry;
|
|
70
|
+
}
|
|
71
|
+
export function emitRuntimeLog(level, module, message, context) {
|
|
72
|
+
if (!shouldLog(level))
|
|
73
|
+
return;
|
|
74
|
+
const line = JSON.stringify(formatLogEntry(level, module, message, context));
|
|
75
|
+
if (level === 'error')
|
|
76
|
+
console.error(line);
|
|
77
|
+
else
|
|
78
|
+
console.log(line);
|
|
79
|
+
}
|
|
4
80
|
export class ConsoleLogger {
|
|
5
81
|
module;
|
|
6
82
|
constructor(module) {
|
|
7
83
|
this.module = module;
|
|
8
84
|
}
|
|
9
85
|
debug(message, context) {
|
|
10
|
-
|
|
86
|
+
emitRuntimeLog('debug', this.module, message, context);
|
|
11
87
|
}
|
|
12
88
|
info(message, context) {
|
|
13
|
-
|
|
89
|
+
emitRuntimeLog('info', this.module, message, context);
|
|
14
90
|
}
|
|
15
91
|
warn(message, context) {
|
|
16
|
-
|
|
92
|
+
emitRuntimeLog('warn', this.module, message, context);
|
|
17
93
|
}
|
|
18
94
|
error(message, context) {
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
log(level, message, context) {
|
|
22
|
-
const entry = {
|
|
23
|
-
level,
|
|
24
|
-
timestamp: new Date().toISOString(),
|
|
25
|
-
module: this.module,
|
|
26
|
-
message,
|
|
27
|
-
...(context && { context }),
|
|
28
|
-
};
|
|
29
|
-
console[level](JSON.stringify(entry));
|
|
95
|
+
emitRuntimeLog('error', this.module, message, context);
|
|
30
96
|
}
|
|
31
97
|
}
|
|
32
|
-
/**
|
|
98
|
+
/** 测试用空实现 */
|
|
33
99
|
export class NoopLogger {
|
|
34
100
|
debug() { }
|
|
35
101
|
info() { }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
const pkg = require('../../package.json');
|
|
4
|
+
/** 当前加载的 Runtime 包版本(`package.json`;overlay 为 `@gt-fe/eap-runtime` 的 version) */
|
|
5
|
+
export const RUNTIME_PACKAGE_VERSION = typeof pkg.version === 'string' && pkg.version.trim() ? pkg.version.trim() : 'unknown';
|
|
@@ -41,6 +41,16 @@ export interface LlmTurnRecord extends LlmTurnContext {
|
|
|
41
41
|
error?: string;
|
|
42
42
|
};
|
|
43
43
|
latencyMs: number;
|
|
44
|
+
/** 本轮 prompt inputTokens / 模型上下文窗;parts 为字符比例拆分;缺 window 则省略 window */
|
|
45
|
+
context?: {
|
|
46
|
+
used: number;
|
|
47
|
+
window?: number;
|
|
48
|
+
parts?: {
|
|
49
|
+
system: number;
|
|
50
|
+
messages: number;
|
|
51
|
+
tools: number;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
44
54
|
}
|
|
45
55
|
export interface LlmTurnIndexEntry {
|
|
46
56
|
id: string;
|
|
@@ -53,6 +63,8 @@ export interface LlmTurnIndexEntry {
|
|
|
53
63
|
file: string;
|
|
54
64
|
inputTokens: number;
|
|
55
65
|
outputTokens: number;
|
|
66
|
+
used?: number;
|
|
67
|
+
window?: number;
|
|
56
68
|
}
|
|
57
69
|
export type LlmTurnLogKind = 'memory' | 'file' | 'postgres';
|
|
58
70
|
export interface ILlmTurnLog {
|
|
@@ -21,6 +21,7 @@ export function toLlmTurnIndexEntry(record, file) {
|
|
|
21
21
|
file: file ?? `${sanitize(record.id)}.json`,
|
|
22
22
|
inputTokens: record.response.inputTokens,
|
|
23
23
|
outputTokens: record.response.outputTokens,
|
|
24
|
+
...(record.context ?? {}),
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
export function maskApiKey(key) {
|
|
@@ -15,6 +15,8 @@ import { type ILLMProvider } from '../nodes/llm-node.js';
|
|
|
15
15
|
import type { IToolExecutor } from '../../tool/tool-executor.interface.js';
|
|
16
16
|
import type { IGovernanceClient } from '../../governance/governance-client.js';
|
|
17
17
|
import { type ConditionEvaluatorFn } from '../condition-evaluator.js';
|
|
18
|
+
/** 图未写 `config.maxIterations` 时的 recursionLimit。`agent ⇄ tools` 一圈约 2,50 ≈ 24 次工具往返。 */
|
|
19
|
+
export declare const DEFAULT_GRAPH_RECURSION_LIMIT = 50;
|
|
18
20
|
/**
|
|
19
21
|
* LangGraphAdapter — 基于 @langchain/langgraph 的 IStateGraphEngine 实现
|
|
20
22
|
*
|
|
@@ -118,7 +120,7 @@ export declare class LangGraphAdapter implements IStateGraphEngine {
|
|
|
118
120
|
private createLLMNodeFunction;
|
|
119
121
|
/**
|
|
120
122
|
* 子图节点:优先 config.subgraphDsl;否则按 skillId 从 state.skillDefinitions.workflow 解析。
|
|
121
|
-
*
|
|
123
|
+
* 技能正文用短目录 + read_file,不灌 system。
|
|
122
124
|
*/
|
|
123
125
|
private createSubGraphNodeFunction;
|
|
124
126
|
/**
|
|
@@ -18,17 +18,35 @@ import { ToolResultInjector } from '../../tool/tool-result-injector.js';
|
|
|
18
18
|
import { fileArtifactFromToolOutput } from '../../tool/file-artifact.js';
|
|
19
19
|
import { EchoLLMProvider } from '../../providers/echo-llm-provider.js';
|
|
20
20
|
import { ConditionEvaluator } from '../condition-evaluator.js';
|
|
21
|
-
import { SystemPromptBuilder, buildToolCatalog, loadedToolsToApiTools } from '../../tool/system-prompt-builder.js';
|
|
21
|
+
import { SystemPromptBuilder, buildToolCatalog, loadedToolsToApiTools, resolveLlmPromptInputs } from '../../tool/system-prompt-builder.js';
|
|
22
22
|
import { resolveJailFromState, resolveJailRoots } from '../../tool/harness-primitives.js';
|
|
23
23
|
import os from 'node:os';
|
|
24
24
|
import { bindSelectedSkill } from '../nodes/skill-bind-node.js';
|
|
25
25
|
import { resolveGraphPrompt } from '../resolve-graph-prompt.js';
|
|
26
|
+
import { hydrateMcpTools, MCP_LIST_TOOL_NAME } from '../../tool/mcp-list.js';
|
|
26
27
|
import { SkillAuditRecorder } from '../skill-audit-recorder.js';
|
|
27
28
|
import { preloadSkillNotFound } from '../../registry/preload-errors.js';
|
|
28
29
|
import { AppError, ErrorCodes } from '@gt-fe/eap-contracts';
|
|
30
|
+
import { pickContextFields } from '../../token/context-window.js';
|
|
29
31
|
import { isHitlDecision, lastAssistantHasUnansweredToolCalls } from '../hitl/hitl-handler.js';
|
|
30
32
|
import { classifySkillRead } from './skill-read.js';
|
|
31
33
|
import { withGraphSpan } from '../trace-span.js';
|
|
34
|
+
/** 图未写 `config.maxIterations` 时的 recursionLimit。`agent ⇄ tools` 一圈约 2,50 ≈ 24 次工具往返。 */
|
|
35
|
+
export const DEFAULT_GRAPH_RECURSION_LIMIT = 50;
|
|
36
|
+
/**
|
|
37
|
+
* LangGraph `recursionLimit` 计 superstep(每进一个节点 +1),不是 ReAct 圈数。
|
|
38
|
+
* 图上 `config.maxIterations` 优先;缺省 {@link DEFAULT_GRAPH_RECURSION_LIMIT}。
|
|
39
|
+
*/
|
|
40
|
+
function langGraphRunOptions(dsl, extra) {
|
|
41
|
+
const raw = dsl.config?.maxIterations;
|
|
42
|
+
const recursionLimit = typeof raw === 'number' && Number.isFinite(raw) && raw > 0
|
|
43
|
+
? Math.trunc(raw)
|
|
44
|
+
: DEFAULT_GRAPH_RECURSION_LIMIT;
|
|
45
|
+
return {
|
|
46
|
+
...extra,
|
|
47
|
+
recursionLimit,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
32
50
|
// ─────────────────────────────────────────────
|
|
33
51
|
// LangGraphAdapter
|
|
34
52
|
// ─────────────────────────────────────────────
|
|
@@ -196,6 +214,7 @@ export class LangGraphAdapter {
|
|
|
196
214
|
payload: {
|
|
197
215
|
toolCallId: progress.toolCallId,
|
|
198
216
|
toolName: progress.toolName,
|
|
217
|
+
...(progress.toolset ? { toolset: progress.toolset } : {}),
|
|
199
218
|
arguments: progress.arguments ?? {},
|
|
200
219
|
...loc,
|
|
201
220
|
},
|
|
@@ -217,6 +236,7 @@ export class LangGraphAdapter {
|
|
|
217
236
|
payload: {
|
|
218
237
|
toolCallId: progress.toolCallId,
|
|
219
238
|
toolName: progress.toolName,
|
|
239
|
+
...(progress.toolset ? { toolset: progress.toolset } : {}),
|
|
220
240
|
content: progress.content,
|
|
221
241
|
success: true,
|
|
222
242
|
...loc,
|
|
@@ -232,6 +252,7 @@ export class LangGraphAdapter {
|
|
|
232
252
|
payload: {
|
|
233
253
|
toolCallId: progress.toolCallId,
|
|
234
254
|
toolName: progress.toolName,
|
|
255
|
+
...(progress.toolset ? { toolset: progress.toolset } : {}),
|
|
235
256
|
error: progress.error ?? 'Unknown error',
|
|
236
257
|
willRetry: false,
|
|
237
258
|
...loc,
|
|
@@ -300,7 +321,7 @@ export class LangGraphAdapter {
|
|
|
300
321
|
loadedSkills: ephemeral(undefined),
|
|
301
322
|
skillDefinitions: ephemeral(undefined),
|
|
302
323
|
skillInput: ephemeral(undefined),
|
|
303
|
-
|
|
324
|
+
agentSystemPrompt: ephemeral(undefined),
|
|
304
325
|
activatedSkill: ephemeral(undefined),
|
|
305
326
|
skillRoute: ephemeral(undefined),
|
|
306
327
|
silentOutput: ephemeral(undefined),
|
|
@@ -421,7 +442,7 @@ export class LangGraphAdapter {
|
|
|
421
442
|
this.streamedTextThisTurn = false;
|
|
422
443
|
const producer = (async () => {
|
|
423
444
|
try {
|
|
424
|
-
const streamIterator = await ref.compiled.stream(input, {
|
|
445
|
+
const streamIterator = await ref.compiled.stream(input, langGraphRunOptions(ref.dsl, {
|
|
425
446
|
configurable: {
|
|
426
447
|
thread_id: resolveCheckpointThreadId({
|
|
427
448
|
sessionId: typeof state.sessionId === 'string' ? state.sessionId : undefined,
|
|
@@ -430,7 +451,7 @@ export class LangGraphAdapter {
|
|
|
430
451
|
}),
|
|
431
452
|
},
|
|
432
453
|
streamMode: 'updates',
|
|
433
|
-
});
|
|
454
|
+
}));
|
|
434
455
|
for await (const update of streamIterator) {
|
|
435
456
|
for (const event of this.convertUpdatesToEvents(update, graph.id, () => this.streamChunkIndex++, ref.silentNodeIds, ref.subgraphNodeIds)) {
|
|
436
457
|
enqueue(event);
|
|
@@ -467,7 +488,7 @@ export class LangGraphAdapter {
|
|
|
467
488
|
const ref = this.getCompiledRef(graph);
|
|
468
489
|
const input = this.graphStateToLangGraphInput(state);
|
|
469
490
|
const startTime = Date.now();
|
|
470
|
-
const result = await ref.compiled.invoke(input, {
|
|
491
|
+
const result = await ref.compiled.invoke(input, langGraphRunOptions(ref.dsl, {
|
|
471
492
|
configurable: {
|
|
472
493
|
thread_id: resolveCheckpointThreadId({
|
|
473
494
|
sessionId: typeof state.sessionId === 'string' ? state.sessionId : undefined,
|
|
@@ -475,7 +496,7 @@ export class LangGraphAdapter {
|
|
|
475
496
|
graphId: graph.id,
|
|
476
497
|
}),
|
|
477
498
|
},
|
|
478
|
-
});
|
|
499
|
+
}));
|
|
479
500
|
const duration = Date.now() - startTime;
|
|
480
501
|
const messages = Array.isArray(result['messages']) ? result['messages'] : [];
|
|
481
502
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -492,6 +513,7 @@ export class LangGraphAdapter {
|
|
|
492
513
|
model: u.model ?? 'unknown',
|
|
493
514
|
inputTokens: u.inputTokens ?? 0,
|
|
494
515
|
outputTokens: u.outputTokens ?? 0,
|
|
516
|
+
...pickContextFields(u),
|
|
495
517
|
}));
|
|
496
518
|
const inputTokens = perNode.reduce((s, u) => s + u.inputTokens, 0);
|
|
497
519
|
const outputTokens = perNode.reduce((s, u) => s + u.outputTokens, 0);
|
|
@@ -655,7 +677,6 @@ export class LangGraphAdapter {
|
|
|
655
677
|
currentNode: node.id,
|
|
656
678
|
skillRoute: patch.skillRoute,
|
|
657
679
|
activatedSkill: patch.activatedSkill,
|
|
658
|
-
activeSkillPrompt: patch.activeSkillPrompt,
|
|
659
680
|
skillInput: patch.skillInput,
|
|
660
681
|
messages: { __set: patch.messages },
|
|
661
682
|
};
|
|
@@ -788,9 +809,34 @@ export class LangGraphAdapter {
|
|
|
788
809
|
return withGraphSpan(state, { name: node.id, type: 'llm' }, async () => {
|
|
789
810
|
const promptRoots = Array.isArray(state['promptRoots']) ? state['promptRoots'] : [];
|
|
790
811
|
const resolvedPrompt = resolveGraphPrompt(baseConfig.systemPrompt, promptRoots);
|
|
791
|
-
const
|
|
812
|
+
const loadedToolsBase = state['loadedTools'];
|
|
792
813
|
const agentCode = typeof state['agentCode'] === 'string' ? state['agentCode'] : undefined;
|
|
793
814
|
const skillDefs = state['skillDefinitions'];
|
|
815
|
+
const execCtx = state['executionContext'];
|
|
816
|
+
const userId = (typeof execCtx?.userId === 'string' && execCtx.userId) || state['userId'];
|
|
817
|
+
const loadedTools = disableTools
|
|
818
|
+
? loadedToolsBase
|
|
819
|
+
: await hydrateMcpTools(loadedToolsBase, this.toolExecutor, {
|
|
820
|
+
authContext: {
|
|
821
|
+
userId: String(userId ?? ''),
|
|
822
|
+
delegationToken: String(execCtx?.delegationToken ?? state['delegationToken'] ?? ''),
|
|
823
|
+
agentCode: String(agentCode ?? ''),
|
|
824
|
+
},
|
|
825
|
+
correlationId: typeof state['correlationId'] === 'string' ? state['correlationId'] : undefined,
|
|
826
|
+
taskId: typeof state['taskId'] === 'string' ? state['taskId'] : undefined,
|
|
827
|
+
onListFailure: ({ toolset, error }) => {
|
|
828
|
+
this.emitToolExecutionEvents({
|
|
829
|
+
toolCallId: `mcp-list:${toolset}`,
|
|
830
|
+
toolName: MCP_LIST_TOOL_NAME,
|
|
831
|
+
toolset,
|
|
832
|
+
status: 'error',
|
|
833
|
+
error,
|
|
834
|
+
});
|
|
835
|
+
},
|
|
836
|
+
});
|
|
837
|
+
if (loadedTools && loadedTools !== loadedToolsBase) {
|
|
838
|
+
state['loadedTools'] = loadedTools;
|
|
839
|
+
}
|
|
794
840
|
// [DEBUG] 打印 loadedTools 实际状态
|
|
795
841
|
if (process.env.EAP_LLM_DEBUG === '1') {
|
|
796
842
|
const toolNames = loadedTools ? Object.keys(loadedTools) : [];
|
|
@@ -798,8 +844,6 @@ export class LangGraphAdapter {
|
|
|
798
844
|
}
|
|
799
845
|
const catalog = includeSkillCatalog ? this.buildSkillCatalog(skillDefs) : undefined;
|
|
800
846
|
const toolCatalog = disableTools ? undefined : buildToolCatalog(loadedTools);
|
|
801
|
-
const execCtx = state['executionContext'];
|
|
802
|
-
const userId = (typeof execCtx?.userId === 'string' && execCtx.userId) || state['userId'];
|
|
803
847
|
const jail = resolveJailFromState({
|
|
804
848
|
agentDir: state['agentDir'],
|
|
805
849
|
userId,
|
|
@@ -816,8 +860,14 @@ export class LangGraphAdapter {
|
|
|
816
860
|
bundlePath: skill.bundlePath,
|
|
817
861
|
entryFile: skill.entryFile,
|
|
818
862
|
}));
|
|
863
|
+
const promptInputs = resolveLlmPromptInputs({
|
|
864
|
+
silent,
|
|
865
|
+
agentSystemPrompt: state['agentSystemPrompt'],
|
|
866
|
+
nodePrompt: resolvedPrompt,
|
|
867
|
+
});
|
|
819
868
|
const assembled = this.systemPromptBuilder.build({
|
|
820
|
-
|
|
869
|
+
agentPrompt: promptInputs.agentPrompt,
|
|
870
|
+
nodePrompt: promptInputs.nodePrompt,
|
|
821
871
|
skillCatalog: catalog,
|
|
822
872
|
toolCatalog,
|
|
823
873
|
agentCode,
|
|
@@ -880,8 +930,9 @@ export class LangGraphAdapter {
|
|
|
880
930
|
}
|
|
881
931
|
: undefined);
|
|
882
932
|
const next = await llmNode.execute(state);
|
|
933
|
+
const hydratedUpdate = loadedTools && loadedTools !== loadedToolsBase ? { loadedTools } : {};
|
|
883
934
|
if (!silent)
|
|
884
|
-
return next;
|
|
935
|
+
return { ...next, ...hydratedUpdate };
|
|
885
936
|
const added = Array.isArray(next.messages) ? next.messages[0] : undefined;
|
|
886
937
|
const raw = added && typeof added === 'object' && typeof added.content === 'string'
|
|
887
938
|
? added.content
|
|
@@ -890,13 +941,14 @@ export class LangGraphAdapter {
|
|
|
890
941
|
...next,
|
|
891
942
|
messages: [],
|
|
892
943
|
silentOutput: raw,
|
|
944
|
+
...hydratedUpdate,
|
|
893
945
|
};
|
|
894
946
|
});
|
|
895
947
|
};
|
|
896
948
|
}
|
|
897
949
|
/**
|
|
898
950
|
* 子图节点:优先 config.subgraphDsl;否则按 skillId 从 state.skillDefinitions.workflow 解析。
|
|
899
|
-
*
|
|
951
|
+
* 技能正文用短目录 + read_file,不灌 system。
|
|
900
952
|
*/
|
|
901
953
|
createSubGraphNodeFunction(node) {
|
|
902
954
|
const embeddedDsl = node.config?.['subgraphDsl'];
|
|
@@ -1199,6 +1251,7 @@ export class LangGraphAdapter {
|
|
|
1199
1251
|
costEstimate: Number(u['costEstimate'] ?? 0),
|
|
1200
1252
|
durationMs: typeof u['durationMs'] === 'number' ? u['durationMs'] : undefined,
|
|
1201
1253
|
graphId,
|
|
1254
|
+
...pickContextFields(u),
|
|
1202
1255
|
},
|
|
1203
1256
|
};
|
|
1204
1257
|
}
|
|
@@ -12,6 +12,7 @@ import { LangGraphAdapter } from './langgraph.adapter.js';
|
|
|
12
12
|
import { resolveTraceId } from '../../common/trace-id.js';
|
|
13
13
|
import { filterLoadedToolsForSkill, } from '../../tool/system-prompt-builder.js';
|
|
14
14
|
import { unwrapHitlPaused } from '../hitl/hitl-handler.js';
|
|
15
|
+
import { pickContextFields } from '../../token/context-window.js';
|
|
15
16
|
import { assertSkillIoIfEnabled, coerceSkillInputFromMessages, } from '../../registry/skill-io-guard.js';
|
|
16
17
|
/**
|
|
17
18
|
* SubGraphCompiler — 子图编译器
|
|
@@ -99,7 +100,6 @@ export class SubGraphCompiler {
|
|
|
99
100
|
const agentCode = state['agentCode'] ?? state['agentId'];
|
|
100
101
|
const defs = state['skillDefinitions'];
|
|
101
102
|
const skillInfo = resolvedSkillId ? defs?.[resolvedSkillId] : undefined;
|
|
102
|
-
const skillPrompt = skillInfo?.prompt;
|
|
103
103
|
const parentTools = state['loadedTools'];
|
|
104
104
|
const scopedTools = filterLoadedToolsForSkill(parentTools, skillInfo);
|
|
105
105
|
const skillInput = skillInfo
|
|
@@ -132,7 +132,9 @@ export class SubGraphCompiler {
|
|
|
132
132
|
loadedTools: scopedTools,
|
|
133
133
|
loadedSkills: state['loadedSkills'],
|
|
134
134
|
skillDefinitions: defs,
|
|
135
|
-
|
|
135
|
+
agentSystemPrompt: typeof state['agentSystemPrompt'] === 'string'
|
|
136
|
+
? state['agentSystemPrompt']
|
|
137
|
+
: undefined,
|
|
136
138
|
activatedSkill: resolvedSkillId || undefined,
|
|
137
139
|
skillInput,
|
|
138
140
|
traceId,
|
|
@@ -200,6 +202,7 @@ export class SubGraphCompiler {
|
|
|
200
202
|
model: u.model,
|
|
201
203
|
inputTokens: u.inputTokens,
|
|
202
204
|
outputTokens: u.outputTokens,
|
|
205
|
+
...pickContextFields(u),
|
|
203
206
|
})),
|
|
204
207
|
}
|
|
205
208
|
: {}),
|
|
@@ -189,14 +189,18 @@ export interface GraphState {
|
|
|
189
189
|
loadedSkills?: import('../../tool/system-prompt-builder.js').LoadedSkillInfo[];
|
|
190
190
|
/** GraphLoader 注入:skillId → 完整定义(子图解析 / prompt) */
|
|
191
191
|
skillDefinitions?: import('../../tool/system-prompt-builder.js').LoadedSkillMap;
|
|
192
|
-
/**
|
|
193
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Agent 基线系统提示词(manifest.prompts.system)。
|
|
194
|
+
* execute/stream 每轮注入;非 silent LLM 拼入 system 的 agent 段。
|
|
195
|
+
*/
|
|
196
|
+
agentSystemPrompt?: string;
|
|
194
197
|
/** silent LLM 的原始输出;不入对话 messages */
|
|
195
198
|
silentOutput?: string;
|
|
196
199
|
/** 解析 graph 内 ./prompts/*.md 的根目录(agentDir + 工程根) */
|
|
197
200
|
promptRoots?: string[];
|
|
198
201
|
/** 预装 Agent 包目录:`{EAP_PREINSTALL_ROOT}/agents/<code>/<ver>` */
|
|
199
202
|
agentDir?: string;
|
|
203
|
+
/** bind / 子图选中的技能;harness 路径解析不写此字段 */
|
|
200
204
|
activatedSkill?: string | null;
|
|
201
205
|
skillRoute?: string;
|
|
202
206
|
/** bind / invoke 解析出的 Skill 入参;子图 IO 校验读取 */
|
|
@@ -331,6 +335,13 @@ export interface GraphTokenUsage {
|
|
|
331
335
|
model: string;
|
|
332
336
|
inputTokens: number;
|
|
333
337
|
outputTokens: number;
|
|
338
|
+
used?: number;
|
|
339
|
+
window?: number;
|
|
340
|
+
parts?: {
|
|
341
|
+
system: number;
|
|
342
|
+
messages: number;
|
|
343
|
+
tools: number;
|
|
344
|
+
};
|
|
334
345
|
}>;
|
|
335
346
|
/** 当前会话跨请求累计消耗(可选;由 session 层服务填充) */
|
|
336
347
|
conversationTotal?: {
|
|
@@ -58,6 +58,8 @@ export interface LLMNodeConfig {
|
|
|
58
58
|
agentCode?: string;
|
|
59
59
|
correlationId?: string;
|
|
60
60
|
};
|
|
61
|
+
/** ModelRecord.capabilities.maxContextTokens;缺省则不写 used/window */
|
|
62
|
+
maxContextTokens?: number;
|
|
61
63
|
}
|
|
62
64
|
/**
|
|
63
65
|
* LLMResponse — LLM 完整响应
|
|
@@ -178,6 +180,7 @@ export declare class LLMNode {
|
|
|
178
180
|
*
|
|
179
181
|
* 根据 streaming 配置选择 invoke 或 stream 模式。
|
|
180
182
|
* 失败时按 backoff 策略重试,最多重试 maxRetries 次。
|
|
183
|
+
* AbortError / 「This operation was aborted」(含 LLM HTTP 超时包装)立即失败,不重试。
|
|
181
184
|
*/
|
|
182
185
|
private invokeWithRetry;
|
|
183
186
|
/**
|