@gt-fe/eap-runtime 0.0.20 → 0.0.22
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 +4 -3
- package/dist/api/handlers/invoke.handler.d.ts +7 -0
- package/dist/api/handlers/invoke.handler.js +52 -10
- package/dist/api/handlers/stream.handler.d.ts +6 -0
- package/dist/api/handlers/stream.handler.js +60 -39
- package/dist/api/routes/agent.routes.d.ts +8 -1
- package/dist/checkpoint/file-checkpoint-saver.d.ts +4 -0
- package/dist/checkpoint/file-checkpoint-saver.js +51 -22
- package/dist/checkpoint/index.d.ts +1 -1
- package/dist/checkpoint/index.js +1 -1
- package/dist/common/types.d.ts +2 -2
- package/dist/common/types.js +1 -1
- package/dist/execution/index.d.ts +2 -0
- package/dist/execution/index.js +2 -0
- package/dist/execution/interceptors.d.ts +40 -0
- package/dist/execution/interceptors.js +23 -0
- package/dist/execution/ports.d.ts +18 -0
- package/dist/execution/ports.js +13 -0
- package/dist/governance/audit-reporter.d.ts +14 -0
- package/dist/governance/audit-reporter.js +18 -0
- package/dist/governance/index.d.ts +2 -0
- package/dist/governance/index.js +1 -0
- package/dist/governance/permission-guard.d.ts +6 -2
- package/dist/governance/permission-guard.js +38 -5
- package/dist/graph/adapters/graph-nesting.d.ts +12 -0
- package/dist/graph/adapters/graph-nesting.js +29 -0
- package/dist/graph/adapters/index.d.ts +2 -0
- package/dist/graph/adapters/index.js +2 -0
- package/dist/graph/adapters/langgraph-checkpointer.d.ts +11 -0
- package/dist/graph/adapters/langgraph-checkpointer.js +48 -9
- package/dist/graph/adapters/langgraph.adapter.d.ts +33 -11
- package/dist/graph/adapters/langgraph.adapter.js +200 -98
- package/dist/graph/adapters/skill-isolate.d.ts +13 -0
- package/dist/graph/adapters/skill-isolate.js +39 -0
- package/dist/graph/adapters/subgraph-compiler.d.ts +7 -2
- package/dist/graph/adapters/subgraph-compiler.js +63 -30
- package/dist/graph/contracts/executable-graph.d.ts +33 -5
- package/dist/graph/hitl/hitl-handler.d.ts +13 -4
- package/dist/graph/hitl/hitl-handler.js +80 -7
- package/dist/graph/nodes/index.d.ts +1 -0
- package/dist/graph/nodes/index.js +1 -0
- package/dist/graph/nodes/llm-node.d.ts +3 -1
- package/dist/graph/nodes/llm-node.js +26 -2
- package/dist/graph/nodes/rag/dedup.d.ts +20 -0
- package/dist/graph/nodes/rag/dedup.js +77 -0
- package/dist/graph/nodes/rag/denoise.d.ts +58 -0
- package/dist/graph/nodes/rag/denoise.js +220 -0
- package/dist/graph/nodes/rag/fusion/fuse.d.ts +11 -0
- package/dist/graph/nodes/rag/fusion/fuse.js +25 -0
- package/dist/graph/nodes/rag/fusion/normalize.d.ts +9 -0
- package/dist/graph/nodes/rag/fusion/normalize.js +135 -0
- package/dist/graph/nodes/rag/index.d.ts +18 -0
- package/dist/graph/nodes/rag/index.js +17 -0
- package/dist/graph/nodes/rag/prompts.d.ts +12 -0
- package/dist/graph/nodes/rag/prompts.js +40 -0
- package/dist/graph/nodes/rag/rag-node.d.ts +21 -0
- package/dist/graph/nodes/rag/rag-node.js +135 -0
- package/dist/graph/nodes/rag/rag-search-tool.d.ts +48 -0
- package/dist/graph/nodes/rag/rag-search-tool.js +230 -0
- package/dist/graph/nodes/rag/react-loop.d.ts +57 -0
- package/dist/graph/nodes/rag/react-loop.js +467 -0
- package/dist/graph/nodes/rag/retrievers/http-embedder.d.ts +29 -0
- package/dist/graph/nodes/rag/retrievers/http-embedder.js +66 -0
- package/dist/graph/nodes/rag/retrievers/in-memory-retriever.d.ts +17 -0
- package/dist/graph/nodes/rag/retrievers/in-memory-retriever.js +18 -0
- package/dist/graph/nodes/rag/retrievers/local-sqlite-retriever.d.ts +46 -0
- package/dist/graph/nodes/rag/retrievers/local-sqlite-retriever.js +85 -0
- package/dist/graph/nodes/rag/tools.d.ts +90 -0
- package/dist/graph/nodes/rag/tools.js +260 -0
- package/dist/graph/nodes/rag/types.d.ts +226 -0
- package/dist/graph/nodes/rag/types.js +9 -0
- package/dist/graph/nodes/tool-node.d.ts +19 -1
- package/dist/graph/nodes/tool-node.js +158 -33
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/memory/semantic-retrieval.service.d.ts +1 -1
- package/dist/memory/semantic-retrieval.service.js +13 -23
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js +2 -2
- package/dist/providers/local-llm-provider.d.ts +6 -0
- package/dist/providers/local-llm-provider.js +29 -5
- package/dist/providers/routing-llm-provider.d.ts +7 -2
- package/dist/providers/routing-llm-provider.js +71 -16
- package/dist/registry/deployment-snapshot.js +18 -4
- package/dist/registry/graph-loader.d.ts +2 -0
- package/dist/registry/graph-loader.js +39 -2
- package/dist/registry/preload-flags.d.ts +1 -1
- package/dist/registry/preload-flags.js +1 -1
- package/dist/runtime/agent-runtime.d.ts +5 -0
- package/dist/runtime/agent-runtime.js +107 -70
- package/dist/runtime/dev-rag-deps.d.ts +21 -0
- package/dist/runtime/dev-rag-deps.js +186 -0
- package/dist/runtime/dev-runtime.d.ts +18 -2
- package/dist/runtime/dev-runtime.js +68 -8
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/types.d.ts +10 -9
- package/dist/session/apply-session-compression.d.ts +85 -0
- package/dist/session/apply-session-compression.js +281 -0
- package/dist/session/apply-session-memory.d.ts +21 -0
- package/dist/session/apply-session-memory.js +48 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/persist-turn-messages.d.ts +57 -1
- package/dist/session/persist-turn-messages.js +160 -5
- package/dist/sse/events/index.d.ts +13 -4
- package/dist/sse/events/index.js +9 -1
- package/dist/sse/events/rag-events.d.ts +63 -0
- package/dist/sse/events/rag-events.js +9 -0
- package/dist/sse/events/session-events.d.ts +38 -0
- package/dist/sse/events/session-events.js +4 -0
- package/dist/token/index.d.ts +2 -1
- package/dist/token/index.js +2 -1
- package/dist/token/record-task-token-usage.d.ts +25 -0
- package/dist/token/record-task-token-usage.js +44 -0
- package/dist/token/token-detail-mode.d.ts +4 -4
- package/dist/token/token-detail-mode.js +4 -4
- package/dist/token/token-detail.d.ts +8 -0
- package/dist/token/token-detail.js +22 -0
- package/dist/token/token-stats.service.d.ts +2 -2
- package/dist/token/token-stats.service.js +1 -1
- package/dist/tool/create-tool-executor.d.ts +6 -0
- package/dist/tool/create-tool-executor.js +4 -3
- package/dist/tool/harness-primitives.d.ts +9 -1
- package/dist/tool/harness-primitives.js +43 -12
- package/dist/tool/index.d.ts +2 -1
- package/dist/tool/index.js +2 -1
- package/dist/tool/tool-confirmation.js +8 -5
- package/dist/tool/tool-executor.interface.d.ts +27 -0
- package/dist/tool/tool-orchestrator.d.ts +3 -1
- package/dist/tool/tool-orchestrator.js +15 -6
- package/dist/tool/tool-retry.d.ts +15 -0
- package/dist/tool/tool-retry.js +69 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ Enterprise Agent Platform **执行引擎**(LangGraph.js):Agent Graph 编
|
|
|
8
8
|
|
|
9
9
|
| 日期 | 摘要 |
|
|
10
10
|
|------|------|
|
|
11
|
-
| 2026-08
|
|
11
|
+
| 2026-09-08 | [`docs/TODO.md`](./docs/TODO.md) 改为主路径状态(已落地 / 不在本包),不是排期 |
|
|
12
|
+
| 2026-08-29 | 待办收口:[`docs/TODO.md`](./docs/TODO.md)。此后压缩已挂主路径(默认关);窗口展示不在 Runtime;Gateway 须 `tools/list` |
|
|
12
13
|
| 2026-08-24 | 0.0.10:官方 Skill / Harness、`ForkParams`、对话详情、存储两档。依赖 `@eap/contracts@0.0.9`。详见 [CHANGELOG.md](./CHANGELOG.md) |
|
|
13
14
|
| 2026-08-21 | 0.0.9:Gateway `/mcp` JSON-RPC 补 `Accept`;`tools/call` 透传工具版本。详见 [CHANGELOG.md](./CHANGELOG.md) |
|
|
14
15
|
| 2026-08-19 | 0.0.8:Skill 子图 SSE 闭环;`ExecuteParams.traceId`;`tool.called` 改为 Tool 节点开始执行。依赖 `@eap/contracts@0.0.8`。详见 [CHANGELOG.md](./CHANGELOG.md) |
|
|
@@ -29,7 +30,7 @@ Enterprise Agent Platform **执行引擎**(LangGraph.js):Agent Graph 编
|
|
|
29
30
|
| 环境变量总表 | [`docs/governance/governance-env-config.md`](../docs/governance/governance-env-config.md) |
|
|
30
31
|
| 预装联调契约 | [`docs/contracts/preload-hosting-runtime-contract.md`](../docs/contracts/preload-hosting-runtime-contract.md) |
|
|
31
32
|
| 预装加载与请求流转 | [`docs/contracts/runtime-preinstall-load-flow.md`](../docs/contracts/runtime-preinstall-load-flow.md) |
|
|
32
|
-
| Runtime
|
|
33
|
+
| Runtime 主路径状态 | [`docs/TODO.md`](./docs/TODO.md) |
|
|
33
34
|
| 技能 FS 待办 | [`docs/TODO-skill-fs.md`](./docs/TODO-skill-fs.md) |
|
|
34
35
|
| 本地 Agent 闭环 | [`docs/workflows/local-agent-dev-loop.md`](../docs/workflows/local-agent-dev-loop.md) |
|
|
35
36
|
|
|
@@ -163,7 +164,7 @@ DSL / 契约细节见 `.kiro/specs/04-runtime-core/design.md` §1.4 与 `src/gra
|
|
|
163
164
|
|------|------|------|
|
|
164
165
|
| `EAP_PREINSTALL_ROOT` | — | 预装根;也可用 `GraphLoader({ preinstallRoot })` |
|
|
165
166
|
| `EAP_PRELOAD_REQUIRE_READY` | 关 | 缺 `.ready` → `runtime.preload.missing` |
|
|
166
|
-
| `EAP_PRELOAD_REQUIRE_CHECKSUM` | 关 | snapshot 须含 sha256 或 artifacts
|
|
167
|
+
| `EAP_PRELOAD_REQUIRE_CHECKSUM` | 关 | snapshot 须含 sha256 或 artifacts。开启时摘要不匹配抛 `RUNTIME_PRELOAD_PACKAGE_CORRUPT`;未开仍 warn、不中断 |
|
|
167
168
|
| `EAP_PRELOAD_USER_SKILL_OVERRIDE` | 关 | `users` 优先于 `shared` |
|
|
168
169
|
| `EAP_PRELOAD_VALIDATE_SKILL_IO` | 关 | 校验 Skill `inputDef.required`(`state.skillInput`) |
|
|
169
170
|
| `EAP_PRELOAD_DEFINITION_CACHE` | 有预装时开 | 定义缓存;`0`/`false` 关闭,`1`/`true` 强制开 |
|
|
@@ -25,6 +25,8 @@ import type { InvokeRequest, InvokeResponse } from '../routes/agent.routes.js';
|
|
|
25
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
|
+
import { type SessionCompressionOptions } from '../../session/apply-session-compression.js';
|
|
29
|
+
import { type SessionMemoryOptions } from '../../session/apply-session-memory.js';
|
|
28
30
|
/**
|
|
29
31
|
* InvokeOrchestrator 构造器依赖
|
|
30
32
|
*/
|
|
@@ -42,6 +44,8 @@ export interface InvokeOrchestratorDeps {
|
|
|
42
44
|
/** 用于判断 session Checkpoint 是否已有历史,避免双重 append */
|
|
43
45
|
checkpointSaver?: ICheckpointSaver;
|
|
44
46
|
traceCollector?: ITraceCollector;
|
|
47
|
+
sessionCompression?: SessionCompressionOptions;
|
|
48
|
+
sessionMemory?: SessionMemoryOptions;
|
|
45
49
|
}
|
|
46
50
|
/**
|
|
47
51
|
* InvokeOrchestrator — 同步调用全流程编排
|
|
@@ -60,6 +64,8 @@ export declare class InvokeOrchestrator {
|
|
|
60
64
|
private readonly graphLoader?;
|
|
61
65
|
private readonly checkpointSaver?;
|
|
62
66
|
private readonly traceCollector?;
|
|
67
|
+
private readonly sessionCompression?;
|
|
68
|
+
private readonly sessionMemory?;
|
|
63
69
|
constructor(deps: InvokeOrchestratorDeps);
|
|
64
70
|
/**
|
|
65
71
|
* 执行同步调用编排
|
|
@@ -72,6 +78,7 @@ export declare class InvokeOrchestrator {
|
|
|
72
78
|
private buildResponse;
|
|
73
79
|
private buildErrorResponse;
|
|
74
80
|
private isTimeoutError;
|
|
81
|
+
private persistInvokeUsages;
|
|
75
82
|
}
|
|
76
83
|
/** @deprecated 请直接从 `graph/hitl/hitl-handler` 导入;此处保留 re-export 兼容旧测试引用 */
|
|
77
84
|
export { unwrapHitlPaused } from '../../graph/hitl/hitl-handler.js';
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
* @see requirements.md Requirement 11 AC1-AC2
|
|
16
16
|
*/
|
|
17
17
|
import { randomUUID } from 'node:crypto';
|
|
18
|
-
import { buildHitlWaitingTaskOutput, buildTurnGraphMessages, messageRecordsToGraphMessages, persistHitlWaitingPlaceholder, persistTurnTranscript, persistUserTurnMessage, } from '../../session/persist-turn-messages.js';
|
|
18
|
+
import { buildHitlWaitingTaskOutput, buildTurnGraphMessages, messageRecordsToGraphMessages, persistHitlWaitingPlaceholder, persistTurnTranscript, persistUserTurnMessage, resolveCheckpointThreadId, sessionVisibleGraphMessages, } from '../../session/persist-turn-messages.js';
|
|
19
19
|
import { SessionBudgetExhaustedError } from '../../token/session-budget-checker.js';
|
|
20
20
|
import { TokenBudgetExhaustedError } from '../../token/token-budget-guard.js';
|
|
21
|
-
import { recordTaskTokenUsages } from '../../token/record-task-token-usage.js';
|
|
21
|
+
import { recordTaskTokenUsages, tokenUsagesFromLlmChannel, } from '../../token/record-task-token-usage.js';
|
|
22
22
|
import { resolveExecutionContext } from '../../governance/governance-client.js';
|
|
23
23
|
import { resolveSkillInputFromInvokeInput } from '../../registry/skill-io-guard.js';
|
|
24
24
|
import { resolveAgentSystemPromptFromLoader } from '../../registry/graph-loader.js';
|
|
@@ -28,6 +28,8 @@ import { assembleLoadedTools } from '../../tool/harness-primitives.js';
|
|
|
28
28
|
import { resolveAgentCode } from '../../common/agent-code.js';
|
|
29
29
|
import { unwrapHitlPaused } from '../../graph/hitl/hitl-handler.js';
|
|
30
30
|
import { resolveTraceId } from '../../common/trace-id.js';
|
|
31
|
+
import { applySessionCompression, withCompressionSummaryModel, } from '../../session/apply-session-compression.js';
|
|
32
|
+
import { applySessionMemory, } from '../../session/apply-session-memory.js';
|
|
31
33
|
// ─────────────────────────────────────────────
|
|
32
34
|
// Default Graph DSL fallback
|
|
33
35
|
// ─────────────────────────────────────────────
|
|
@@ -64,6 +66,8 @@ export class InvokeOrchestrator {
|
|
|
64
66
|
graphLoader;
|
|
65
67
|
checkpointSaver;
|
|
66
68
|
traceCollector;
|
|
69
|
+
sessionCompression;
|
|
70
|
+
sessionMemory;
|
|
67
71
|
constructor(deps) {
|
|
68
72
|
this.sessionContextService = deps.sessionContextService;
|
|
69
73
|
this.taskService = deps.taskService;
|
|
@@ -75,6 +79,8 @@ export class InvokeOrchestrator {
|
|
|
75
79
|
this.graphLoader = deps.graphLoader;
|
|
76
80
|
this.checkpointSaver = deps.checkpointSaver;
|
|
77
81
|
this.traceCollector = deps.traceCollector;
|
|
82
|
+
this.sessionCompression = deps.sessionCompression;
|
|
83
|
+
this.sessionMemory = deps.sessionMemory;
|
|
78
84
|
}
|
|
79
85
|
/**
|
|
80
86
|
* 执行同步调用编排
|
|
@@ -159,6 +165,7 @@ export class InvokeOrchestrator {
|
|
|
159
165
|
});
|
|
160
166
|
// ─── Step 5: 构建/执行 Graph ───
|
|
161
167
|
let graphResult;
|
|
168
|
+
let finishPoints;
|
|
162
169
|
try {
|
|
163
170
|
// 构建图 — 每次请求创建独立 StateGraph 实例,确保请求间无共享可变状态
|
|
164
171
|
const loadOpts = { agentVersion: req.agentVersion };
|
|
@@ -166,6 +173,7 @@ export class InvokeOrchestrator {
|
|
|
166
173
|
? await this.graphLoader.loadGraph(agentCode, loadOpts)
|
|
167
174
|
: DEFAULT_GRAPH_DSL;
|
|
168
175
|
const graph = await this.graphEngine.buildGraph(graphDsl);
|
|
176
|
+
finishPoints = graph.finishPoints;
|
|
169
177
|
const loadedToolsBase = this.graphLoader
|
|
170
178
|
? toLoadedToolMap(await this.graphLoader.loadToolDefinitions(agentCode, loadOpts))
|
|
171
179
|
: undefined;
|
|
@@ -185,7 +193,21 @@ export class InvokeOrchestrator {
|
|
|
185
193
|
: undefined;
|
|
186
194
|
const agentSystemPrompt = await resolveAgentSystemPromptFromLoader(this.graphLoader, agentCode, req.agentVersion);
|
|
187
195
|
// 组装 GraphState:有 Checkpoint 历史则只追加本轮 user,避免双重 append
|
|
188
|
-
const history =
|
|
196
|
+
const history = await applySessionMemory({
|
|
197
|
+
history: await applySessionCompression({
|
|
198
|
+
history: messageRecordsToGraphMessages(sessionContext.messages),
|
|
199
|
+
sessionId,
|
|
200
|
+
userId: effectiveUserId,
|
|
201
|
+
taskId: task.id,
|
|
202
|
+
options: await withCompressionSummaryModel(this.sessionCompression, () => this.graphLoader
|
|
203
|
+
? this.graphLoader.resolveDefaultModel(agentCode, req.agentVersion)
|
|
204
|
+
: Promise.resolve(undefined)),
|
|
205
|
+
}),
|
|
206
|
+
userId: effectiveUserId,
|
|
207
|
+
agentCode,
|
|
208
|
+
query: typeof req.input === 'string' ? req.input : undefined,
|
|
209
|
+
options: this.sessionMemory,
|
|
210
|
+
});
|
|
189
211
|
const messages = await buildTurnGraphMessages({
|
|
190
212
|
history,
|
|
191
213
|
input: req.input,
|
|
@@ -205,6 +227,8 @@ export class InvokeOrchestrator {
|
|
|
205
227
|
sessionId,
|
|
206
228
|
executionContext: ctx,
|
|
207
229
|
forceToolServer: req.config?.forceToolServer,
|
|
230
|
+
ragScope: req.ragScope,
|
|
231
|
+
ragSources: req.ragSources,
|
|
208
232
|
loadedTools,
|
|
209
233
|
loadedSkills,
|
|
210
234
|
skillDefinitions,
|
|
@@ -217,6 +241,8 @@ export class InvokeOrchestrator {
|
|
|
217
241
|
});
|
|
218
242
|
}
|
|
219
243
|
catch (error) {
|
|
244
|
+
const usages = await this.persistInvokeUsages(task.id, sessionId);
|
|
245
|
+
const tokenUsage = tokenUsageTotals(usages);
|
|
220
246
|
const hitlPaused = unwrapHitlPaused(error);
|
|
221
247
|
if (hitlPaused) {
|
|
222
248
|
await this.taskService.updateStatus(task.id, 'waiting_hitl', buildHitlWaitingTaskOutput({
|
|
@@ -236,7 +262,7 @@ export class InvokeOrchestrator {
|
|
|
236
262
|
taskId: task.id,
|
|
237
263
|
sessionId,
|
|
238
264
|
output: hitlPaused.question,
|
|
239
|
-
tokenUsage
|
|
265
|
+
tokenUsage,
|
|
240
266
|
duration: Date.now() - startTime,
|
|
241
267
|
status: 'waiting_hitl',
|
|
242
268
|
hitl: {
|
|
@@ -253,7 +279,7 @@ export class InvokeOrchestrator {
|
|
|
253
279
|
taskId: task.id,
|
|
254
280
|
sessionId,
|
|
255
281
|
output: error.message,
|
|
256
|
-
tokenUsage
|
|
282
|
+
tokenUsage,
|
|
257
283
|
duration: Date.now() - startTime,
|
|
258
284
|
status: 'token_exhausted',
|
|
259
285
|
});
|
|
@@ -265,7 +291,7 @@ export class InvokeOrchestrator {
|
|
|
265
291
|
taskId: task.id,
|
|
266
292
|
sessionId,
|
|
267
293
|
output: 'Task execution timed out',
|
|
268
|
-
tokenUsage
|
|
294
|
+
tokenUsage,
|
|
269
295
|
duration: Date.now() - startTime,
|
|
270
296
|
status: 'timeout',
|
|
271
297
|
});
|
|
@@ -277,7 +303,7 @@ export class InvokeOrchestrator {
|
|
|
277
303
|
taskId: task.id,
|
|
278
304
|
sessionId,
|
|
279
305
|
output: errorMessage,
|
|
280
|
-
tokenUsage
|
|
306
|
+
tokenUsage,
|
|
281
307
|
duration: Date.now() - startTime,
|
|
282
308
|
status: 'failed',
|
|
283
309
|
});
|
|
@@ -326,11 +352,13 @@ export class InvokeOrchestrator {
|
|
|
326
352
|
// ─── Step 7: 完成 Task (running → success) ───
|
|
327
353
|
await this.taskService.updateStatus(task.id, 'success', graphResult.output);
|
|
328
354
|
// ─── Step 7b: 持久化本轮 transcript(统一顺序:assistant tool_calls → tool → assistant 文本)───
|
|
329
|
-
|
|
355
|
+
// 按 Session 已有行数切 Graph 增量。多段正文收成一条后 Session 比 Graph 短,切点可能提前;finishPoints 只含一个实际节点 id 时靠最后一条纯文本仍落到 merge。
|
|
356
|
+
const initialMessagesCount = sessionContext.messages.length + 1;
|
|
330
357
|
const allMessages = Array.isArray(graphResult.finalState?.messages)
|
|
331
358
|
? graphResult.finalState.messages
|
|
332
359
|
: [];
|
|
333
|
-
const newMessages = allMessages.slice(initialMessagesCount);
|
|
360
|
+
const newMessages = sessionVisibleGraphMessages(allMessages.slice(initialMessagesCount), finishPoints);
|
|
361
|
+
const duration = Date.now() - startTime;
|
|
334
362
|
await persistTurnTranscript(this.messageService, {
|
|
335
363
|
sessionId,
|
|
336
364
|
taskId: task.id,
|
|
@@ -338,9 +366,9 @@ export class InvokeOrchestrator {
|
|
|
338
366
|
messages: newMessages,
|
|
339
367
|
fallbackAssistantContent: graphResult.output ?? '',
|
|
340
368
|
assistantTokenCount: tokenUsage.output,
|
|
369
|
+
assistantDurationMs: duration,
|
|
341
370
|
});
|
|
342
371
|
// ─── Step 8: 返回 InvokeResponse ───
|
|
343
|
-
const duration = Date.now() - startTime;
|
|
344
372
|
// 从本轮 Graph 执行结果中提取 tool 事件明细(供 CLI / UI 渲染 ReAct 循环)
|
|
345
373
|
const toolEvents = extractToolEvents(newMessages);
|
|
346
374
|
return this.buildResponse(traceId, {
|
|
@@ -369,6 +397,20 @@ export class InvokeOrchestrator {
|
|
|
369
397
|
}
|
|
370
398
|
return false;
|
|
371
399
|
}
|
|
400
|
+
async persistInvokeUsages(taskId, sessionId) {
|
|
401
|
+
if (!this.checkpointSaver)
|
|
402
|
+
return [];
|
|
403
|
+
const threadId = resolveCheckpointThreadId({ sessionId, taskId });
|
|
404
|
+
const ck = await this.checkpointSaver.load(threadId);
|
|
405
|
+
const usages = tokenUsagesFromLlmChannel(ck?.state);
|
|
406
|
+
await recordTaskTokenUsages(this.taskService, taskId, usages);
|
|
407
|
+
return usages;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function tokenUsageTotals(usages) {
|
|
411
|
+
const input = usages.reduce((sum, row) => sum + row.inputTokens, 0);
|
|
412
|
+
const output = usages.reduce((sum, row) => sum + row.outputTokens, 0);
|
|
413
|
+
return { input, output, total: input + output };
|
|
372
414
|
}
|
|
373
415
|
// ─────────────────────────────────────────────
|
|
374
416
|
// Module-level Helpers
|
|
@@ -27,6 +27,8 @@ import type { IStateGraphEngine } from '../../graph/contracts/state-graph.contra
|
|
|
27
27
|
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
|
+
import { type SessionCompressionOptions } from '../../session/apply-session-compression.js';
|
|
31
|
+
import { type SessionMemoryOptions } from '../../session/apply-session-memory.js';
|
|
30
32
|
import type { StreamRequest } from '../routes/agent.routes.js';
|
|
31
33
|
import { type GraphLoader } from '../../registry/graph-loader.js';
|
|
32
34
|
import type { ICheckpointSaver } from '../../checkpoint/contracts/checkpoint-saver.contract.js';
|
|
@@ -48,6 +50,8 @@ export interface StreamOrchestratorDeps {
|
|
|
48
50
|
checkpointSaver?: ICheckpointSaver;
|
|
49
51
|
/** Hosting 注入的 Trace 采集器;与 traceId 同时存在时创建 Skill/Tool span */
|
|
50
52
|
traceCollector?: ITraceCollector;
|
|
53
|
+
sessionCompression?: SessionCompressionOptions;
|
|
54
|
+
sessionMemory?: SessionMemoryOptions;
|
|
51
55
|
}
|
|
52
56
|
/**
|
|
53
57
|
* StreamOrchestrator — 流式调用全流程编排
|
|
@@ -66,6 +70,8 @@ export declare class StreamOrchestrator {
|
|
|
66
70
|
private readonly graphLoader?;
|
|
67
71
|
private readonly checkpointSaver?;
|
|
68
72
|
private readonly traceCollector?;
|
|
73
|
+
private readonly sessionCompression?;
|
|
74
|
+
private readonly sessionMemory?;
|
|
69
75
|
constructor(deps: StreamOrchestratorDeps);
|
|
70
76
|
/**
|
|
71
77
|
* 执行流式调用编排
|
|
@@ -19,10 +19,13 @@
|
|
|
19
19
|
* @see design.md §1.5 /stream 内部执行逻辑
|
|
20
20
|
* @see requirements.md Requirement 11 AC2
|
|
21
21
|
*/
|
|
22
|
-
import { buildHitlWaitingTaskOutput, buildTurnGraphMessages, buildTurnTranscriptFromStreamEvents, extractStreamReasoning,
|
|
22
|
+
import { buildHitlWaitingTaskOutput, buildTurnGraphMessages, buildTurnTranscriptFromStreamEvents, extractStreamReasoning, applyStreamTextDelta, createStreamAssistantBuckets, visibleStreamAssistantText, streamAssistantTexts, messageRecordsToGraphMessages, persistHitlWaitingPlaceholder, persistTurnTranscript, persistUserTurnMessage, appendTerminalToolResult, } from '../../session/persist-turn-messages.js';
|
|
23
23
|
import { SessionBudgetExhaustedError } from '../../token/session-budget-checker.js';
|
|
24
24
|
import { TokenBudgetExhaustedError } from '../../token/token-budget-guard.js';
|
|
25
25
|
import { recordTaskTokenUsages } from '../../token/record-task-token-usage.js';
|
|
26
|
+
import { iterSessionCompression, withCompressionSummaryModel, } from '../../session/apply-session-compression.js';
|
|
27
|
+
import { applySessionMemory, } from '../../session/apply-session-memory.js';
|
|
28
|
+
import { resolveTokenDetail, shouldEmitTokenSse } from '../../token/token-detail.js';
|
|
26
29
|
import { SSEEmitter } from '../../sse/sse-emitter.js';
|
|
27
30
|
import { resolveExecutionContext } from '../../governance/governance-client.js';
|
|
28
31
|
import { resolveSkillInputFromInvokeInput } from '../../registry/skill-io-guard.js';
|
|
@@ -72,6 +75,8 @@ export class StreamOrchestrator {
|
|
|
72
75
|
graphLoader;
|
|
73
76
|
checkpointSaver;
|
|
74
77
|
traceCollector;
|
|
78
|
+
sessionCompression;
|
|
79
|
+
sessionMemory;
|
|
75
80
|
constructor(deps) {
|
|
76
81
|
this.sessionContextService = deps.sessionContextService;
|
|
77
82
|
this.taskService = deps.taskService;
|
|
@@ -83,6 +88,8 @@ export class StreamOrchestrator {
|
|
|
83
88
|
this.graphLoader = deps.graphLoader;
|
|
84
89
|
this.checkpointSaver = deps.checkpointSaver;
|
|
85
90
|
this.traceCollector = deps.traceCollector;
|
|
91
|
+
this.sessionCompression = deps.sessionCompression;
|
|
92
|
+
this.sessionMemory = deps.sessionMemory;
|
|
86
93
|
}
|
|
87
94
|
/**
|
|
88
95
|
* 执行流式调用编排
|
|
@@ -207,7 +214,31 @@ export class StreamOrchestrator {
|
|
|
207
214
|
: undefined;
|
|
208
215
|
const agentSystemPrompt = await resolveAgentSystemPromptFromLoader(this.graphLoader, agentCode, req.agentVersion);
|
|
209
216
|
// 组装 GraphState:有 Checkpoint 历史则只追加本轮 user,避免双重 append
|
|
210
|
-
|
|
217
|
+
let history = messageRecordsToGraphMessages(sessionContext.messages);
|
|
218
|
+
const compressionOptions = await withCompressionSummaryModel(this.sessionCompression, () => this.graphLoader
|
|
219
|
+
? this.graphLoader.resolveDefaultModel(agentCode, req.agentVersion)
|
|
220
|
+
: Promise.resolve(undefined));
|
|
221
|
+
for await (const step of iterSessionCompression({
|
|
222
|
+
history,
|
|
223
|
+
sessionId,
|
|
224
|
+
userId,
|
|
225
|
+
taskId,
|
|
226
|
+
options: compressionOptions,
|
|
227
|
+
})) {
|
|
228
|
+
if (step.kind === 'history') {
|
|
229
|
+
history = step.messages;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
emitter.emit(this.buildSSEEvent(step.kind === 'started' ? 'session.compression.started' : 'session.compression.completed', correlationId, taskId, { ...step.payload }));
|
|
233
|
+
}
|
|
234
|
+
history = await applySessionMemory({
|
|
235
|
+
history,
|
|
236
|
+
userId,
|
|
237
|
+
agentCode,
|
|
238
|
+
query: typeof req.input === 'string' ? req.input : undefined,
|
|
239
|
+
options: this.sessionMemory,
|
|
240
|
+
});
|
|
241
|
+
const tokenDetail = resolveTokenDetail(req.config?.tokenDetail);
|
|
211
242
|
const messages = await buildTurnGraphMessages({
|
|
212
243
|
history,
|
|
213
244
|
input: req.input,
|
|
@@ -215,7 +246,7 @@ export class StreamOrchestrator {
|
|
|
215
246
|
threadId: sessionId,
|
|
216
247
|
});
|
|
217
248
|
const skillInput = resolveSkillInputFromInvokeInput(req.input);
|
|
218
|
-
|
|
249
|
+
const assistantBuckets = createStreamAssistantBuckets();
|
|
219
250
|
let toolCallReasoningContent;
|
|
220
251
|
let assistantReasoningContent;
|
|
221
252
|
const pendingToolCalls = [];
|
|
@@ -233,6 +264,8 @@ export class StreamOrchestrator {
|
|
|
233
264
|
sessionId,
|
|
234
265
|
executionContext,
|
|
235
266
|
forceToolServer: req.config?.forceToolServer,
|
|
267
|
+
ragScope: req.ragScope,
|
|
268
|
+
ragSources: req.ragSources,
|
|
236
269
|
loadedTools,
|
|
237
270
|
loadedSkills,
|
|
238
271
|
skillDefinitions,
|
|
@@ -272,33 +305,14 @@ export class StreamOrchestrator {
|
|
|
272
305
|
toolCallReasoningContent = p.reasoningContent;
|
|
273
306
|
}
|
|
274
307
|
}
|
|
275
|
-
|
|
276
|
-
const p = runtimeEvent.payload;
|
|
277
|
-
if (p.toolCallId && p.toolName) {
|
|
278
|
-
toolResults.push({
|
|
279
|
-
toolCallId: p.toolCallId,
|
|
280
|
-
toolName: p.toolName,
|
|
281
|
-
content: p.content,
|
|
282
|
-
success: p.success !== false,
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
308
|
+
appendTerminalToolResult(runtimeEvent.type, runtimeEvent.payload, toolResults);
|
|
286
309
|
const streamedReasoning = extractStreamReasoning(runtimeEvent.type, runtimeEvent.payload);
|
|
287
310
|
if (streamedReasoning)
|
|
288
311
|
assistantReasoningContent = streamedReasoning;
|
|
289
|
-
|
|
290
|
-
if (
|
|
291
|
-
|
|
292
|
-
// final 若带完整文本则覆盖累加,避免与 chunk 重复拼接
|
|
293
|
-
if (delta.trim())
|
|
294
|
-
assistantText = delta;
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
assistantText += delta;
|
|
298
|
-
}
|
|
312
|
+
applyStreamTextDelta(assistantBuckets, runtimeEvent.type, runtimeEvent.payload);
|
|
313
|
+
if (shouldEmitTokenSse(tokenDetail, runtimeEvent.type)) {
|
|
314
|
+
emitter.emit(this.runtimeEventToSSE(runtimeEvent, correlationId, taskId));
|
|
299
315
|
}
|
|
300
|
-
// 将 RuntimeEvent 转为 SSEEvent 并推送
|
|
301
|
-
emitter.emit(this.runtimeEventToSSE(runtimeEvent, correlationId, taskId));
|
|
302
316
|
}
|
|
303
317
|
}
|
|
304
318
|
catch (error) {
|
|
@@ -325,12 +339,14 @@ export class StreamOrchestrator {
|
|
|
325
339
|
}
|
|
326
340
|
// ─── 错误处理:TokenBudgetExhausted ───
|
|
327
341
|
if (error instanceof TokenBudgetExhaustedError) {
|
|
342
|
+
await recordTaskTokenUsages(this.taskService, taskId, this.tokenStatsService.list(taskId));
|
|
328
343
|
await this.taskService.updateStatus(taskId, 'token_exhausted', error.message);
|
|
329
344
|
this.emitErrorAndClose(emitter, correlationId, taskId, error);
|
|
330
345
|
return;
|
|
331
346
|
}
|
|
332
347
|
// ─── 错误处理:Timeout ───
|
|
333
348
|
if (this.isTimeoutError(error)) {
|
|
349
|
+
await recordTaskTokenUsages(this.taskService, taskId, this.tokenStatsService.list(taskId));
|
|
334
350
|
await this.taskService.updateStatus(taskId, 'timeout');
|
|
335
351
|
emitter.emit(this.buildSSEEvent('task.error', correlationId, taskId, {
|
|
336
352
|
code: ErrorCodes.TASK_TIMEOUT,
|
|
@@ -342,6 +358,7 @@ export class StreamOrchestrator {
|
|
|
342
358
|
}
|
|
343
359
|
// ─── 错误处理:通用错误 ───
|
|
344
360
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
361
|
+
await recordTaskTokenUsages(this.taskService, taskId, this.tokenStatsService.list(taskId));
|
|
345
362
|
await this.taskService.updateStatus(taskId, 'failed', errorMessage);
|
|
346
363
|
this.emitErrorAndClose(emitter, correlationId, taskId, error);
|
|
347
364
|
return;
|
|
@@ -350,21 +367,22 @@ export class StreamOrchestrator {
|
|
|
350
367
|
// Emit: response.final(带完整 assistant 文本,供客户端兜底)
|
|
351
368
|
const tokenStats = this.tokenStatsService.getTaskStats(taskId);
|
|
352
369
|
emitter.emit(this.buildSSEEvent('response.final', correlationId, taskId, {
|
|
353
|
-
content:
|
|
370
|
+
content: visibleStreamAssistantText(assistantBuckets),
|
|
354
371
|
format: 'text',
|
|
355
372
|
}));
|
|
356
|
-
// Emit: stats.token_usage
|
|
357
373
|
const totalTokens = (tokenStats.total.input ?? 0) + (tokenStats.total.output ?? 0);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
374
|
+
if (shouldEmitTokenSse(tokenDetail, 'stats.token_usage')) {
|
|
375
|
+
emitter.emit(this.buildSSEEvent('stats.token_usage', correlationId, taskId, {
|
|
376
|
+
total: {
|
|
377
|
+
input: tokenStats.total.input,
|
|
378
|
+
output: tokenStats.total.output,
|
|
379
|
+
total: tokenStats.total.total ?? totalTokens,
|
|
380
|
+
},
|
|
381
|
+
byNode: tokenStats.byNode,
|
|
382
|
+
byModel: tokenStats.byModel,
|
|
383
|
+
costEstimate: tokenStats.costEstimate,
|
|
384
|
+
}));
|
|
385
|
+
}
|
|
368
386
|
// ─── Step 8: 记录 Token + 完成 Task + 关闭 SSE ───
|
|
369
387
|
const duration = Date.now() - startTime;
|
|
370
388
|
// Emit: task.completed
|
|
@@ -383,11 +401,14 @@ export class StreamOrchestrator {
|
|
|
383
401
|
messages: buildTurnTranscriptFromStreamEvents({
|
|
384
402
|
pendingToolCalls,
|
|
385
403
|
toolResults,
|
|
386
|
-
|
|
404
|
+
assistantTexts: streamAssistantTexts(assistantBuckets),
|
|
405
|
+
assistantText: visibleStreamAssistantText(assistantBuckets),
|
|
406
|
+
finishPoints: graph.finishPoints,
|
|
387
407
|
toolCallReasoningContent,
|
|
388
408
|
assistantReasoningContent,
|
|
389
409
|
}),
|
|
390
410
|
assistantTokenCount: tokenStats.total.output ?? 0,
|
|
411
|
+
assistantDurationMs: duration,
|
|
391
412
|
});
|
|
392
413
|
// 关闭 SSE 连接
|
|
393
414
|
emitter.close();
|
|
@@ -11,10 +11,17 @@ import type { IStateGraphEngine } from '../../graph/contracts/executable-graph.j
|
|
|
11
11
|
import type { SSEEmitter } from '../../sse/sse-emitter.js';
|
|
12
12
|
export type { InvokeConfig, InvokeResponseData } from '@gt-fe/eap-contracts';
|
|
13
13
|
/**
|
|
14
|
-
* dev HTTP 层 Invoke 请求(扩展 userId,Hosting 从 auth
|
|
14
|
+
* dev HTTP 层 Invoke 请求(扩展 userId,Hosting 从 auth 注入;ragScope 为请求级
|
|
15
|
+
* 检索范围——前端圈定已向量化文件/目录,仅 rag 节点本地检索源生效)
|
|
15
16
|
*/
|
|
16
17
|
export type InvokeRequest = ContractInvokeRequest & {
|
|
17
18
|
userId?: string;
|
|
19
|
+
ragScope?: {
|
|
20
|
+
fileIds?: string[];
|
|
21
|
+
dirPaths?: string[];
|
|
22
|
+
};
|
|
23
|
+
/** 会话级数据源勾选(数据源 id 列表;缺省 = 智能体预定义目录全部启用) */
|
|
24
|
+
ragSources?: string[];
|
|
18
25
|
};
|
|
19
26
|
export type InvokeResponse = ContractInvokeResponse;
|
|
20
27
|
/** 流式调用请求 — 与 InvokeRequest 相同 */
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FileCheckpointSaver — 本地 JSON 文件存储
|
|
3
3
|
* 适用场景:本地开发、单机部署
|
|
4
|
+
* 目录名对 threadId 做 encodeURIComponent:子图槽 `sessionId#父节点id` 不会变成带 `#` 的目录。
|
|
4
5
|
*/
|
|
5
6
|
import type { ICheckpointSaver } from './contracts/checkpoint-saver.contract.js';
|
|
6
7
|
import type { CheckpointData } from '../graph/contracts/executable-graph.js';
|
|
8
|
+
/** 存储键可含 `#`(子图槽);目录名百分号编码,避免 URL/Markdown 把 `#` 当片段。 */
|
|
9
|
+
export declare function checkpointFileThreadDir(baseDir: string, threadId: string): string;
|
|
7
10
|
export declare class FileCheckpointSaver implements ICheckpointSaver {
|
|
8
11
|
private readonly baseDir;
|
|
9
12
|
constructor(baseDir: string);
|
|
@@ -11,6 +14,7 @@ export declare class FileCheckpointSaver implements ICheckpointSaver {
|
|
|
11
14
|
load(threadId: string): Promise<CheckpointData | null>;
|
|
12
15
|
loadByCheckpointId(checkpointId: string, threadId?: string): Promise<CheckpointData | null>;
|
|
13
16
|
list(threadId: string): Promise<CheckpointData[]>;
|
|
17
|
+
private readLatestId;
|
|
14
18
|
private readCheckpoint;
|
|
15
19
|
/**
|
|
16
20
|
* Fork: 从指定 Checkpoint 创建新的执行线程
|
|
@@ -1,36 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FileCheckpointSaver — 本地 JSON 文件存储
|
|
3
3
|
* 适用场景:本地开发、单机部署
|
|
4
|
+
* 目录名对 threadId 做 encodeURIComponent:子图槽 `sessionId#父节点id` 不会变成带 `#` 的目录。
|
|
4
5
|
*/
|
|
5
6
|
import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
6
7
|
import { join } from 'node:path';
|
|
7
8
|
import { stringifyJsonSafe } from './checkpoint-serializer.js';
|
|
9
|
+
/** 存储键可含 `#`(子图槽);目录名百分号编码,避免 URL/Markdown 把 `#` 当片段。 */
|
|
10
|
+
export function checkpointFileThreadDir(baseDir, threadId) {
|
|
11
|
+
return join(baseDir, encodeURIComponent(threadId));
|
|
12
|
+
}
|
|
13
|
+
function threadDirCandidates(baseDir, threadId) {
|
|
14
|
+
const encoded = checkpointFileThreadDir(baseDir, threadId);
|
|
15
|
+
const raw = join(baseDir, threadId);
|
|
16
|
+
return encoded === raw ? [encoded] : [encoded, raw];
|
|
17
|
+
}
|
|
8
18
|
export class FileCheckpointSaver {
|
|
9
19
|
baseDir;
|
|
10
20
|
constructor(baseDir) {
|
|
11
21
|
this.baseDir = baseDir;
|
|
12
22
|
}
|
|
13
23
|
async save(threadId, data) {
|
|
14
|
-
const dir =
|
|
24
|
+
const dir = checkpointFileThreadDir(this.baseDir, threadId);
|
|
15
25
|
await mkdir(dir, { recursive: true });
|
|
16
26
|
await writeFile(join(dir, `${data.checkpointId}.json`), stringifyJsonSafe(data));
|
|
17
27
|
// 更新 latest 指针
|
|
18
28
|
await writeFile(join(dir, 'latest.json'), JSON.stringify({ checkpointId: data.checkpointId }));
|
|
19
29
|
}
|
|
20
30
|
async load(threadId) {
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
for (const dir of threadDirCandidates(this.baseDir, threadId)) {
|
|
32
|
+
const checkpointId = await this.readLatestId(dir);
|
|
33
|
+
if (!checkpointId)
|
|
34
|
+
continue;
|
|
35
|
+
const data = await this.readCheckpoint(join(dir, `${checkpointId}.json`));
|
|
36
|
+
if (data)
|
|
37
|
+
return data;
|
|
28
38
|
}
|
|
39
|
+
return null;
|
|
29
40
|
}
|
|
30
41
|
async loadByCheckpointId(checkpointId, threadId) {
|
|
31
|
-
// If threadId provided, look directly; otherwise scan all thread dirs
|
|
32
42
|
if (threadId) {
|
|
33
|
-
|
|
43
|
+
for (const dir of threadDirCandidates(this.baseDir, threadId)) {
|
|
44
|
+
const data = await this.readCheckpoint(join(dir, `${checkpointId}.json`));
|
|
45
|
+
if (data)
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
34
49
|
}
|
|
35
50
|
// ponytail: brute scan — upgrade to index file if perf matters
|
|
36
51
|
try {
|
|
@@ -45,21 +60,35 @@ export class FileCheckpointSaver {
|
|
|
45
60
|
return null;
|
|
46
61
|
}
|
|
47
62
|
async list(threadId) {
|
|
48
|
-
const dir
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
for (const dir of threadDirCandidates(this.baseDir, threadId)) {
|
|
64
|
+
try {
|
|
65
|
+
const files = await readdir(dir);
|
|
66
|
+
const results = [];
|
|
67
|
+
for (const f of files) {
|
|
68
|
+
if (f === 'latest.json' || !f.endsWith('.json'))
|
|
69
|
+
continue;
|
|
70
|
+
const data = await this.readCheckpoint(join(dir, f));
|
|
71
|
+
if (data)
|
|
72
|
+
results.push(data);
|
|
73
|
+
}
|
|
74
|
+
if (results.length > 0) {
|
|
75
|
+
return results.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// try next candidate
|
|
58
80
|
}
|
|
59
|
-
|
|
81
|
+
}
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
async readLatestId(dir) {
|
|
85
|
+
try {
|
|
86
|
+
const latestRaw = await readFile(join(dir, 'latest.json'), 'utf-8');
|
|
87
|
+
const { checkpointId } = JSON.parse(latestRaw);
|
|
88
|
+
return typeof checkpointId === 'string' && checkpointId.trim() ? checkpointId : null;
|
|
60
89
|
}
|
|
61
90
|
catch {
|
|
62
|
-
return
|
|
91
|
+
return null;
|
|
63
92
|
}
|
|
64
93
|
}
|
|
65
94
|
async readCheckpoint(filePath) {
|
|
@@ -6,7 +6,7 @@ export { restoreCheckpoint } from './restore-checkpoint.js';
|
|
|
6
6
|
export { notifyCheckpointRef, stripCheckpointCollectors } from './checkpoint-ref-notify.js';
|
|
7
7
|
export { createCheckpointData, serializeCheckpoint, deserializeCheckpoint, stringifyJsonSafe, toJsonSafe, } from './checkpoint-serializer.js';
|
|
8
8
|
export type { CreateCheckpointParams } from './checkpoint-serializer.js';
|
|
9
|
-
export { FileCheckpointSaver } from './file-checkpoint-saver.js';
|
|
9
|
+
export { FileCheckpointSaver, checkpointFileThreadDir } from './file-checkpoint-saver.js';
|
|
10
10
|
export { InMemoryCheckpointSaver } from './in-memory-checkpoint-saver.js';
|
|
11
11
|
export { MongoCheckpointSaver } from './mongo-checkpoint-saver.js';
|
|
12
12
|
export type { IMongoCollection, CheckpointDocument } from './mongo-checkpoint-saver.js';
|
package/dist/checkpoint/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { CompositeCheckpointSaver } from './composite-checkpoint-saver.js';
|
|
|
5
5
|
export { restoreCheckpoint } from './restore-checkpoint.js';
|
|
6
6
|
export { notifyCheckpointRef, stripCheckpointCollectors } from './checkpoint-ref-notify.js';
|
|
7
7
|
export { createCheckpointData, serializeCheckpoint, deserializeCheckpoint, stringifyJsonSafe, toJsonSafe, } from './checkpoint-serializer.js';
|
|
8
|
-
export { FileCheckpointSaver } from './file-checkpoint-saver.js';
|
|
8
|
+
export { FileCheckpointSaver, checkpointFileThreadDir } from './file-checkpoint-saver.js';
|
|
9
9
|
export { InMemoryCheckpointSaver } from './in-memory-checkpoint-saver.js';
|
|
10
10
|
export { MongoCheckpointSaver } from './mongo-checkpoint-saver.js';
|
|
11
11
|
export { PostgresCheckpointSaver } from './pg-checkpoint-saver.js';
|
package/dist/common/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Token 统计输出粒度控制
|
|
10
10
|
* - none: 不输出任何 Token 统计事件
|
|
11
11
|
* - summary: 仅 Task 结束时输出 stats.token_usage 汇总
|
|
12
|
-
* - detail: 每次 LLM 调用输出 stats.
|
|
12
|
+
* - detail: 每次 LLM 调用输出 stats.node_token_usage + 结束时汇总
|
|
13
13
|
*/
|
|
14
14
|
export type TokenDetailLevel = 'none' | 'summary' | 'detail';
|
|
15
15
|
/**
|
|
@@ -79,7 +79,7 @@ export type MessageRole = 'user' | 'assistant' | 'system' | 'tool';
|
|
|
79
79
|
*
|
|
80
80
|
* 与 @gt-fe/eap-contracts.TokenUsage 的区别:
|
|
81
81
|
* - contracts 版本是 Task 级聚合结果(含 byNode/byModel)
|
|
82
|
-
* - 本类型是单次调用粒度的原始记录,用于 Runtime 内部累计和 stats.
|
|
82
|
+
* - 本类型是单次调用粒度的原始记录,用于 Runtime 内部累计和 stats.node_token_usage 事件
|
|
83
83
|
*/
|
|
84
84
|
export interface TokenUsage {
|
|
85
85
|
/** 输入 Token 数 */
|