@gt-fe/eap-runtime 0.0.8 → 0.0.10
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 +12 -17
- package/dist/api/handlers/invoke.handler.js +3 -3
- package/dist/api/handlers/messages.handler.js +0 -1
- package/dist/api/handlers/stream.handler.js +3 -3
- package/dist/api/routes/agent.routes.js +2 -2
- package/dist/checkpoint/checkpoint-ref-notify.d.ts +10 -0
- package/dist/checkpoint/checkpoint-ref-notify.js +59 -0
- package/dist/checkpoint/index.d.ts +1 -0
- package/dist/checkpoint/index.js +1 -0
- package/dist/checkpoint/pg-checkpoint-saver.js +25 -2
- package/dist/common/agent-code.d.ts +2 -4
- package/dist/common/agent-code.js +4 -5
- package/dist/contracts/trace-collector.d.ts +15 -1
- package/dist/debug/llm-turn-log.d.ts +100 -0
- package/dist/debug/llm-turn-log.js +130 -0
- package/dist/debug/pg-llm-turn-log.d.ts +22 -0
- package/dist/debug/pg-llm-turn-log.js +57 -0
- package/dist/graph/adapters/langgraph-checkpointer.js +3 -1
- package/dist/graph/adapters/langgraph.adapter.d.ts +1 -0
- package/dist/graph/adapters/langgraph.adapter.js +147 -91
- package/dist/graph/adapters/skill-read.d.ts +12 -0
- package/dist/graph/adapters/skill-read.js +63 -0
- package/dist/graph/adapters/subgraph-compiler.js +5 -0
- package/dist/graph/contracts/executable-graph.d.ts +3 -3
- package/dist/graph/hitl/hitl-handler.d.ts +7 -0
- package/dist/graph/hitl/hitl-handler.js +47 -6
- package/dist/graph/nodes/llm-node.d.ts +14 -0
- package/dist/graph/nodes/skill-bind-node.js +1 -2
- package/dist/graph/nodes/tool-node.d.ts +2 -0
- package/dist/graph/nodes/tool-node.js +24 -9
- package/dist/graph/trace-span.d.ts +22 -0
- package/dist/graph/trace-span.js +69 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/memory/compression/compression.repository.d.ts +1 -15
- package/dist/providers/echo-llm-provider.d.ts +1 -1
- package/dist/providers/echo-llm-provider.js +2 -1
- package/dist/providers/http-llm-provider.d.ts +4 -0
- package/dist/providers/http-llm-provider.js +129 -4
- package/dist/providers/local-llm-provider.d.ts +5 -1
- package/dist/providers/local-llm-provider.js +14 -6
- package/dist/providers/routing-llm-provider.d.ts +4 -0
- package/dist/providers/routing-llm-provider.js +12 -2
- package/dist/registry/agent-models.d.ts +1 -1
- package/dist/registry/agent-models.js +1 -1
- package/dist/registry/agent-registry-client.d.ts +2 -2
- package/dist/registry/deployment-snapshot.d.ts +4 -4
- package/dist/registry/deployment-snapshot.js +50 -28
- package/dist/registry/graph-loader.d.ts +1 -1
- package/dist/registry/graph-loader.js +39 -76
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +1 -1
- package/dist/registry/skill-tree.d.ts +3 -0
- package/dist/registry/skill-tree.js +41 -3
- package/dist/runtime/agent-runtime.d.ts +42 -3
- package/dist/runtime/agent-runtime.js +110 -34
- package/dist/runtime/dev-runtime.d.ts +6 -3
- package/dist/runtime/dev-runtime.js +21 -14
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/storage-profile.d.ts +19 -10
- package/dist/runtime/storage-profile.js +42 -29
- package/dist/runtime/types.d.ts +15 -17
- package/dist/server.js +1 -1
- package/dist/session/session.service.d.ts +5 -0
- package/dist/session/session.service.js +12 -0
- package/dist/sse/events/index.d.ts +5 -3
- package/dist/sse/events/index.js +2 -0
- package/dist/sse/events/skill-events.d.ts +11 -0
- package/dist/sse/trace-collector.d.ts +10 -0
- package/dist/sse/trace-collector.js +1 -0
- package/dist/token/token-budget.service.d.ts +2 -2
- package/dist/token/token-budget.service.js +1 -1
- package/dist/tool/create-tool-executor.js +3 -2
- package/dist/tool/harness-primitives.d.ts +32 -0
- package/dist/tool/harness-primitives.js +385 -0
- package/dist/tool/http-tool-executor.js +1 -1
- package/dist/tool/index.d.ts +2 -1
- package/dist/tool/index.js +2 -1
- package/dist/tool/local-tool-executor.d.ts +3 -3
- package/dist/tool/local-tool-executor.js +5 -7
- package/dist/tool/mcp-tool-executor.js +9 -1
- package/dist/tool/system-prompt-builder.d.ts +61 -25
- package/dist/tool/system-prompt-builder.js +195 -92
- package/dist/tool/tool-execution-router.js +1 -1
- package/dist/tool/tool-executor.interface.d.ts +12 -6
- package/package.json +2 -2
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* @see design.md §1.6 hitl.waiting / hitl.resumed 事件
|
|
11
11
|
* @see tasks.md Task 14
|
|
12
12
|
*/
|
|
13
|
+
import { notifyCheckpointRef, stripCheckpointCollectors, } from '../../checkpoint/checkpoint-ref-notify.js';
|
|
14
|
+
import { startGraphSpan, completeGraphSpan } from '../trace-span.js';
|
|
13
15
|
// ─────────────────────────────────────────────
|
|
14
16
|
// Types
|
|
15
17
|
// ─────────────────────────────────────────────
|
|
@@ -151,8 +153,9 @@ export function buildHitlWaitedPayload(paused) {
|
|
|
151
153
|
*/
|
|
152
154
|
function prepareHitlCheckpointState(state) {
|
|
153
155
|
const raw = state;
|
|
156
|
+
const { traceCollector: _drop, ...rest } = raw;
|
|
154
157
|
return {
|
|
155
|
-
...
|
|
158
|
+
...rest,
|
|
156
159
|
userId: state.userId ?? raw.userId ?? '',
|
|
157
160
|
loadedTools: state.loadedTools ?? raw.loadedTools,
|
|
158
161
|
forceToolServer: state.forceToolServer ?? raw.forceToolServer,
|
|
@@ -162,6 +165,7 @@ function prepareHitlCheckpointState(state) {
|
|
|
162
165
|
delegationToken: state.delegationToken ?? raw.delegationToken,
|
|
163
166
|
skillSpanId: state.skillSpanId ?? raw.skillSpanId,
|
|
164
167
|
traceId: state.traceId ?? (typeof raw.traceId === 'string' ? raw.traceId : undefined),
|
|
168
|
+
lastSpanId: state.lastSpanId ?? (typeof raw.lastSpanId === 'string' ? raw.lastSpanId : undefined),
|
|
165
169
|
};
|
|
166
170
|
}
|
|
167
171
|
function toTimeoutEvent(waiting) {
|
|
@@ -193,6 +197,7 @@ function waitingFromPersisted(persisted, taskId) {
|
|
|
193
197
|
toolName: persisted.toolName,
|
|
194
198
|
toolSpanId: persisted.toolSpanId,
|
|
195
199
|
skillSpanId: persisted.skillSpanId,
|
|
200
|
+
hitlSpanId: persisted.hitlSpanId,
|
|
196
201
|
};
|
|
197
202
|
}
|
|
198
203
|
// ─────────────────────────────────────────────
|
|
@@ -216,6 +221,9 @@ export class HitlHandler {
|
|
|
216
221
|
timeoutListener;
|
|
217
222
|
/** 同一 taskId 上串行化 resume 与 timeout,避免双边占用 */
|
|
218
223
|
taskLocks = new Map();
|
|
224
|
+
traceCollector;
|
|
225
|
+
/** 进程内 interrupt 的 collector,不进 Checkpoint */
|
|
226
|
+
waitingCollectors = new Map();
|
|
219
227
|
constructor(checkpointSaver, sseEmitter, timeoutListener) {
|
|
220
228
|
this.checkpointSaver = checkpointSaver;
|
|
221
229
|
this.sseEmitter = sseEmitter;
|
|
@@ -224,6 +232,9 @@ export class HitlHandler {
|
|
|
224
232
|
setTimeoutListener(listener) {
|
|
225
233
|
this.timeoutListener = listener;
|
|
226
234
|
}
|
|
235
|
+
setTraceCollector(collector) {
|
|
236
|
+
this.traceCollector = collector;
|
|
237
|
+
}
|
|
227
238
|
/**
|
|
228
239
|
* 中断 Graph 执行,等待人工确认
|
|
229
240
|
*
|
|
@@ -237,6 +248,11 @@ export class HitlHandler {
|
|
|
237
248
|
const deadlineAt = new Date(Date.now() + timeoutMs).toISOString();
|
|
238
249
|
const skillSpanId = extras.skillSpanId ??
|
|
239
250
|
(typeof state.skillSpanId === 'string' ? state.skillSpanId : undefined);
|
|
251
|
+
const hitlSpanId = await startGraphSpan(state, {
|
|
252
|
+
name: extras.toolName ?? 'hitl',
|
|
253
|
+
type: 'hitl',
|
|
254
|
+
parentSpanId: extras.toolSpanId ?? skillSpanId,
|
|
255
|
+
});
|
|
240
256
|
const persisted = {
|
|
241
257
|
taskId,
|
|
242
258
|
threadId,
|
|
@@ -247,11 +263,16 @@ export class HitlHandler {
|
|
|
247
263
|
toolName: extras.toolName,
|
|
248
264
|
toolSpanId: extras.toolSpanId,
|
|
249
265
|
skillSpanId,
|
|
266
|
+
hitlSpanId,
|
|
250
267
|
};
|
|
251
268
|
const existing = await this.checkpointSaver.load(threadId);
|
|
269
|
+
const lastSpanId = hitlSpanId ??
|
|
270
|
+
extras.toolSpanId ??
|
|
271
|
+
(typeof state.lastSpanId === 'string' ? state.lastSpanId : undefined);
|
|
252
272
|
const persistedState = {
|
|
253
273
|
...(existing?.state ?? {}),
|
|
254
274
|
...prepareHitlCheckpointState(state),
|
|
275
|
+
...(lastSpanId ? { lastSpanId } : {}),
|
|
255
276
|
[HITL_WAITING_STATE_KEY]: persisted,
|
|
256
277
|
};
|
|
257
278
|
const checkpointData = {
|
|
@@ -266,7 +287,13 @@ export class HitlHandler {
|
|
|
266
287
|
updatedAt: now,
|
|
267
288
|
isDeleted: false,
|
|
268
289
|
};
|
|
269
|
-
|
|
290
|
+
const persistedCheckpoint = stripCheckpointCollectors(checkpointData);
|
|
291
|
+
await this.checkpointSaver.save(threadId, persistedCheckpoint);
|
|
292
|
+
const liveCollector = state.traceCollector;
|
|
293
|
+
if (liveCollector) {
|
|
294
|
+
this.waitingCollectors.set(taskId, liveCollector);
|
|
295
|
+
}
|
|
296
|
+
await notifyCheckpointRef(persistedCheckpoint, liveCollector);
|
|
270
297
|
const event = {
|
|
271
298
|
type: 'hitl.waiting',
|
|
272
299
|
data: {
|
|
@@ -300,6 +327,7 @@ export class HitlHandler {
|
|
|
300
327
|
toolName: extras.toolName,
|
|
301
328
|
toolSpanId: extras.toolSpanId,
|
|
302
329
|
skillSpanId,
|
|
330
|
+
hitlSpanId,
|
|
303
331
|
});
|
|
304
332
|
}
|
|
305
333
|
/**
|
|
@@ -335,6 +363,7 @@ export class HitlHandler {
|
|
|
335
363
|
if (!waiting) {
|
|
336
364
|
throw new HitlNotWaitingError(taskId);
|
|
337
365
|
}
|
|
366
|
+
const liveCollector = this.waitingCollectors.get(taskId) ?? this.traceCollector;
|
|
338
367
|
this.clearWaiting(taskId);
|
|
339
368
|
this.resolvedChoices.set(taskId, choice);
|
|
340
369
|
const baseState = prepareHitlCheckpointState(checkpoint.state);
|
|
@@ -346,13 +375,18 @@ export class HitlHandler {
|
|
|
346
375
|
hitlRespondedBy: userId,
|
|
347
376
|
};
|
|
348
377
|
const now = new Date().toISOString();
|
|
349
|
-
await this.checkpointSaver.save(waiting.threadId, {
|
|
378
|
+
await this.checkpointSaver.save(waiting.threadId, stripCheckpointCollectors({
|
|
350
379
|
...checkpoint,
|
|
351
380
|
engineSnapshot: undefined,
|
|
352
381
|
state: resumedState,
|
|
353
382
|
updatedBy: userId,
|
|
354
383
|
updatedAt: now,
|
|
355
|
-
});
|
|
384
|
+
}));
|
|
385
|
+
const hitlSpanId = waiting.hitlSpanId ?? persisted?.hitlSpanId;
|
|
386
|
+
await completeGraphSpan(resumedState, hitlSpanId, {
|
|
387
|
+
status: 'completed',
|
|
388
|
+
output: { choice, userId },
|
|
389
|
+
}, liveCollector);
|
|
356
390
|
const event = {
|
|
357
391
|
type: 'hitl.resumed',
|
|
358
392
|
data: { choice, userId },
|
|
@@ -390,6 +424,7 @@ export class HitlHandler {
|
|
|
390
424
|
toolSpanId: waiting.toolSpanId ?? persisted.toolSpanId,
|
|
391
425
|
skillSpanId: waiting.skillSpanId ?? persisted.skillSpanId,
|
|
392
426
|
});
|
|
427
|
+
const liveCollector = this.waitingCollectors.get(taskId) ?? this.traceCollector;
|
|
393
428
|
this.clearWaiting(taskId);
|
|
394
429
|
if (timeoutEvent.behavior !== 'auto-confirm' && checkpoint) {
|
|
395
430
|
const marked = {
|
|
@@ -400,12 +435,17 @@ export class HitlHandler {
|
|
|
400
435
|
timeoutBehavior: timeoutEvent.behavior,
|
|
401
436
|
},
|
|
402
437
|
};
|
|
403
|
-
await this.checkpointSaver.save(waiting.threadId, {
|
|
438
|
+
await this.checkpointSaver.save(waiting.threadId, stripCheckpointCollectors({
|
|
404
439
|
...checkpoint,
|
|
405
440
|
engineSnapshot: undefined,
|
|
406
441
|
state: marked,
|
|
407
442
|
updatedAt: new Date().toISOString(),
|
|
408
|
-
});
|
|
443
|
+
}));
|
|
444
|
+
const hitlSpanId = waiting.hitlSpanId ?? persisted.hitlSpanId;
|
|
445
|
+
await completeGraphSpan(checkpoint.state, hitlSpanId, {
|
|
446
|
+
status: 'failed',
|
|
447
|
+
error: 'hitl_timeout',
|
|
448
|
+
}, liveCollector);
|
|
409
449
|
}
|
|
410
450
|
return timeoutEvent;
|
|
411
451
|
});
|
|
@@ -439,6 +479,7 @@ export class HitlHandler {
|
|
|
439
479
|
clearTimeout(waiting.timer);
|
|
440
480
|
}
|
|
441
481
|
this.waitingTasks.delete(taskId);
|
|
482
|
+
this.waitingCollectors.delete(taskId);
|
|
442
483
|
}
|
|
443
484
|
async withTaskLock(taskId, fn) {
|
|
444
485
|
const prev = this.taskLocks.get(taskId) ?? Promise.resolve();
|
|
@@ -44,6 +44,20 @@ export interface LLMNodeConfig {
|
|
|
44
44
|
name: string;
|
|
45
45
|
};
|
|
46
46
|
};
|
|
47
|
+
/** 具名 system 段(落盘排查,不另发给模型) */
|
|
48
|
+
systemSections?: Array<{
|
|
49
|
+
id: string;
|
|
50
|
+
title: string;
|
|
51
|
+
body: string;
|
|
52
|
+
}>;
|
|
53
|
+
/** 本轮调用定位(session / task / node) */
|
|
54
|
+
turn?: {
|
|
55
|
+
sessionId?: string;
|
|
56
|
+
taskId?: string;
|
|
57
|
+
nodeId?: string;
|
|
58
|
+
agentCode?: string;
|
|
59
|
+
correlationId?: string;
|
|
60
|
+
};
|
|
47
61
|
}
|
|
48
62
|
/**
|
|
49
63
|
* LLMResponse — LLM 完整响应
|
|
@@ -62,8 +62,7 @@ function buildSkillPrompt(skill, params) {
|
|
|
62
62
|
*/
|
|
63
63
|
export function bindSelectedSkill(state) {
|
|
64
64
|
const incoming = Array.isArray(state.messages) ? [...state.messages] : [];
|
|
65
|
-
const fromState =
|
|
66
|
-
|| (typeof state.skillSelectRaw === 'string' ? state.skillSelectRaw : '');
|
|
65
|
+
const fromState = typeof state.silentOutput === 'string' ? state.silentOutput : '';
|
|
67
66
|
const lastText = lastAssistantText(incoming);
|
|
68
67
|
const lastIsSelector = extractJsonObject(lastText) !== null;
|
|
69
68
|
const parsed = extractJsonObject(fromState) ?? extractJsonObject(lastText);
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import type { AuthContext } from '../../tool/tool-executor.interface.js';
|
|
13
13
|
import type { ToolOrchestrator } from '../../tool/tool-orchestrator.js';
|
|
14
14
|
import type { ToolResultInjector } from '../../tool/tool-result-injector.js';
|
|
15
|
+
import type { SkillDirRef } from '../adapters/skill-read.js';
|
|
15
16
|
import type { HitlHandler } from '../hitl/hitl-handler.js';
|
|
16
17
|
/**
|
|
17
18
|
* LangGraphState — LangGraph 内部状态(与 LLMNode 对齐)
|
|
@@ -39,6 +40,7 @@ export interface ToolNodeProgress {
|
|
|
39
40
|
executionTime?: number;
|
|
40
41
|
node?: string;
|
|
41
42
|
skillId?: string;
|
|
43
|
+
skillDirs?: SkillDirRef[];
|
|
42
44
|
}
|
|
43
45
|
export declare class ToolNode {
|
|
44
46
|
private readonly orchestrator;
|
|
@@ -13,6 +13,12 @@ import { isHitlDecision, unwrapHitlPaused } from '../hitl/hitl-handler.js';
|
|
|
13
13
|
import { ToolConfirmationInterceptor } from '../../tool/tool-confirmation.js';
|
|
14
14
|
import { resolveCheckpointThreadId } from '../../session/persist-turn-messages.js';
|
|
15
15
|
import { resolveTraceId } from '../../common/trace-id.js';
|
|
16
|
+
function skillDirsFromState(state) {
|
|
17
|
+
const defs = state['skillDefinitions'];
|
|
18
|
+
return Object.values(defs ?? {})
|
|
19
|
+
.filter((skill) => Boolean(skill.bundlePath))
|
|
20
|
+
.map((skill) => ({ skillId: skill.skillId, bundlePath: skill.bundlePath }));
|
|
21
|
+
}
|
|
16
22
|
export class ToolNode {
|
|
17
23
|
orchestrator;
|
|
18
24
|
injector;
|
|
@@ -46,6 +52,8 @@ export class ToolNode {
|
|
|
46
52
|
return state;
|
|
47
53
|
}
|
|
48
54
|
const loadedTools = state['loadedTools'];
|
|
55
|
+
const skillDirs = skillDirsFromState(state);
|
|
56
|
+
const jailExtraRoots = skillDirs.map((dir) => dir.bundlePath);
|
|
49
57
|
// 4. 转换为 ToolCallRequest[](附带 manifest 路由字段)
|
|
50
58
|
const requests = lastAssistantMessage.toolCalls.map((tc) => {
|
|
51
59
|
const loaded = loadedTools?.[tc.name];
|
|
@@ -62,20 +70,27 @@ export class ToolNode {
|
|
|
62
70
|
dataScope: loaded?.manifest.dataScope,
|
|
63
71
|
// dev 上下文 DevMcpExecutor 直连所需;server 上下文会忽略
|
|
64
72
|
execution: loaded?.manifest.execution,
|
|
73
|
+
...(loaded?.manifest.version ? { toolVersion: loaded.manifest.version } : {}),
|
|
65
74
|
correlationId,
|
|
66
75
|
taskId,
|
|
76
|
+
...(jailExtraRoots.length > 0 ? { jailExtraRoots } : {}),
|
|
67
77
|
};
|
|
68
78
|
});
|
|
69
79
|
const executionContext = state['executionContext'];
|
|
70
80
|
const traceCollector = state['traceCollector'];
|
|
71
81
|
const traceId = resolveTraceId(state);
|
|
72
|
-
const agentCode = String(state['agentCode'] ??
|
|
82
|
+
const agentCode = String(state['agentCode'] ?? '');
|
|
73
83
|
const nodeId = this.nodeId ?? 'tool-node';
|
|
74
84
|
const skillId = typeof state['activatedSkill'] === 'string' && state['activatedSkill']
|
|
75
85
|
? state['activatedSkill']
|
|
76
86
|
: undefined;
|
|
77
87
|
const emitProgress = (data) => {
|
|
78
|
-
this.onProgress?.({
|
|
88
|
+
this.onProgress?.({
|
|
89
|
+
...data,
|
|
90
|
+
node: nodeId,
|
|
91
|
+
...(skillId ? { skillId } : {}),
|
|
92
|
+
...(skillDirs.length > 0 ? { skillDirs } : {}),
|
|
93
|
+
});
|
|
79
94
|
};
|
|
80
95
|
// 5. 并行执行所有 Tool 调用(附 Trace span)
|
|
81
96
|
const spanIds = await Promise.all(requests.map(async (req) => {
|
|
@@ -158,6 +173,7 @@ export class ToolNode {
|
|
|
158
173
|
toolCallId: result.toolCallId,
|
|
159
174
|
toolName: result.toolName,
|
|
160
175
|
status: 'completed',
|
|
176
|
+
arguments: req.arguments,
|
|
161
177
|
content: result.content,
|
|
162
178
|
executionTime,
|
|
163
179
|
});
|
|
@@ -167,6 +183,7 @@ export class ToolNode {
|
|
|
167
183
|
toolCallId: result.toolCallId,
|
|
168
184
|
toolName: result.toolName,
|
|
169
185
|
status: 'error',
|
|
186
|
+
arguments: req.arguments,
|
|
170
187
|
error: result.error ?? 'unknown error',
|
|
171
188
|
executionTime,
|
|
172
189
|
});
|
|
@@ -202,6 +219,7 @@ export class ToolNode {
|
|
|
202
219
|
toolCallId: req.toolCallId,
|
|
203
220
|
toolName: req.toolName,
|
|
204
221
|
status: 'error',
|
|
222
|
+
arguments: req.arguments,
|
|
205
223
|
error: message,
|
|
206
224
|
executionTime,
|
|
207
225
|
});
|
|
@@ -240,10 +258,11 @@ export class ToolNode {
|
|
|
240
258
|
success: result.success,
|
|
241
259
|
...('file' in result && result.file ? { file: result.file } : {}),
|
|
242
260
|
}));
|
|
243
|
-
|
|
261
|
+
const lastSpanId = [...spanIds].reverse().find((id) => Boolean(id));
|
|
244
262
|
return {
|
|
245
263
|
messages: toolMessages,
|
|
246
264
|
currentNode: nodeId,
|
|
265
|
+
...(lastSpanId ? { lastSpanId } : {}),
|
|
247
266
|
};
|
|
248
267
|
}
|
|
249
268
|
// ─────────────────────────────────────────────
|
|
@@ -282,11 +301,7 @@ export class ToolNode {
|
|
|
282
301
|
}
|
|
283
302
|
buildAuthContext(state) {
|
|
284
303
|
const executionContext = state['executionContext'];
|
|
285
|
-
|
|
286
|
-
const agentCode = String(state['agentCode'] ??
|
|
287
|
-
state['agentId'] ??
|
|
288
|
-
this.defaultAuthContext.agentCode ??
|
|
289
|
-
this.defaultAuthContext.agentId);
|
|
304
|
+
const agentCode = String(state['agentCode'] ?? this.defaultAuthContext.agentCode ?? '');
|
|
290
305
|
// 优先 ExecutionContext(invoke Token.sub),保证所有 Tool/MCP 出站同一身份
|
|
291
306
|
const userId = String(executionContext?.userId ?? state['userId'] ?? this.defaultAuthContext.userId);
|
|
292
307
|
const delegationToken = String(executionContext?.delegationToken ??
|
|
@@ -315,7 +330,7 @@ export class ToolNode {
|
|
|
315
330
|
loadedTools: state['loadedTools'],
|
|
316
331
|
forceToolServer: state['forceToolServer'],
|
|
317
332
|
executionContext: state['executionContext'],
|
|
318
|
-
agentCode:
|
|
333
|
+
agentCode: state['agentCode'],
|
|
319
334
|
correlationId: state['correlationId'],
|
|
320
335
|
taskId: state['taskId'],
|
|
321
336
|
sessionId: state['sessionId'],
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph 节点 Span 辅助:createNode / completeNode 失败不挡主路径。
|
|
3
|
+
*/
|
|
4
|
+
import type { ITraceCollector, ExecutionNodeEvent } from '../contracts/trace-collector.js';
|
|
5
|
+
export declare function startGraphSpan(state: Record<string, unknown>, input: {
|
|
6
|
+
name: string;
|
|
7
|
+
type: ExecutionNodeEvent['type'];
|
|
8
|
+
parentSpanId?: string;
|
|
9
|
+
extra?: Partial<Omit<ExecutionNodeEvent, 'traceId' | 'name' | 'type' | 'parentNodeId'>>;
|
|
10
|
+
}): Promise<string | undefined>;
|
|
11
|
+
export declare function completeGraphSpan(state: Record<string, unknown>, spanId: string | undefined, params: {
|
|
12
|
+
status: 'completed' | 'failed';
|
|
13
|
+
output?: unknown;
|
|
14
|
+
error?: string;
|
|
15
|
+
inputTokens?: number;
|
|
16
|
+
outputTokens?: number;
|
|
17
|
+
totalTokens?: number;
|
|
18
|
+
}, collectorOverride?: ITraceCollector): Promise<void>;
|
|
19
|
+
export declare function withGraphSpan(state: Record<string, unknown>, spec: {
|
|
20
|
+
name: string;
|
|
21
|
+
type: ExecutionNodeEvent['type'];
|
|
22
|
+
}, run: () => Promise<Record<string, unknown>>): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph 节点 Span 辅助:createNode / completeNode 失败不挡主路径。
|
|
3
|
+
*/
|
|
4
|
+
import { resolveTraceId } from '../common/trace-id.js';
|
|
5
|
+
export async function startGraphSpan(state, input) {
|
|
6
|
+
const collector = state['traceCollector'];
|
|
7
|
+
const traceId = resolveTraceId(state);
|
|
8
|
+
if (!collector || !traceId)
|
|
9
|
+
return undefined;
|
|
10
|
+
const parentNodeId = input.parentSpanId ??
|
|
11
|
+
(typeof state['skillSpanId'] === 'string' && state['skillSpanId']
|
|
12
|
+
? state['skillSpanId']
|
|
13
|
+
: undefined);
|
|
14
|
+
try {
|
|
15
|
+
return await collector.createNode({
|
|
16
|
+
traceId,
|
|
17
|
+
name: input.name,
|
|
18
|
+
type: input.type,
|
|
19
|
+
parentNodeId,
|
|
20
|
+
agentCode: (typeof state['agentCode'] === 'string' && state['agentCode']) ||
|
|
21
|
+
(typeof state['agentId'] === 'string' ? state['agentId'] : undefined),
|
|
22
|
+
...input.extra,
|
|
23
|
+
metadata: {
|
|
24
|
+
taskId: state['taskId'],
|
|
25
|
+
correlationId: state['correlationId'],
|
|
26
|
+
...(input.extra?.metadata ?? {}),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function completeGraphSpan(state, spanId, params, collectorOverride) {
|
|
35
|
+
const collector = collectorOverride ?? state['traceCollector'];
|
|
36
|
+
if (!collector?.completeNode || !spanId)
|
|
37
|
+
return;
|
|
38
|
+
try {
|
|
39
|
+
await collector.completeNode(spanId, params);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Trace 失败不影响主路径
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function withGraphSpan(state, spec, run) {
|
|
46
|
+
const spanId = await startGraphSpan(state, spec);
|
|
47
|
+
try {
|
|
48
|
+
const result = await run();
|
|
49
|
+
const usage = Array.isArray(result['__llmTokenUsage'])
|
|
50
|
+
? result['__llmTokenUsage'].at(-1)
|
|
51
|
+
: undefined;
|
|
52
|
+
await completeGraphSpan(state, spanId, {
|
|
53
|
+
status: 'completed',
|
|
54
|
+
inputTokens: usage?.inputTokens,
|
|
55
|
+
outputTokens: usage?.outputTokens,
|
|
56
|
+
totalTokens: usage?.inputTokens != null || usage?.outputTokens != null
|
|
57
|
+
? (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
|
|
58
|
+
: undefined,
|
|
59
|
+
});
|
|
60
|
+
return spanId ? { ...result, lastSpanId: spanId } : result;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
await completeGraphSpan(state, spanId, {
|
|
64
|
+
status: 'failed',
|
|
65
|
+
error: err instanceof Error ? err.message : String(err),
|
|
66
|
+
});
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,3 +19,6 @@ export type { ITraceCollector, TraceEvent, TraceSession, ExecutionFlowEvent, Exe
|
|
|
19
19
|
export type { ExecutionContext, CallerType, GovernancePermissionCheckParams, GovernancePermissionCheckResult, PermissionDenyReason, } from '@gt-fe/eap-contracts';
|
|
20
20
|
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
21
21
|
export type { IGovernanceClient } from './governance/index.js';
|
|
22
|
+
export { FileLlmTurnLog, InMemoryLlmTurnLog, createFileLlmTurnLogFromEnv, maskApiKey, resolveLlmTurnDir, } from './debug/llm-turn-log.js';
|
|
23
|
+
export { PostgresLlmTurnLog } from './debug/pg-llm-turn-log.js';
|
|
24
|
+
export type { ILlmTurnLog, LlmTurnRecord, LlmTurnIndexEntry, LlmTurnContext, LlmTurnLogKind, } from './debug/llm-turn-log.js';
|
package/dist/index.js
CHANGED
|
@@ -30,3 +30,5 @@ export * from './registry/index.js';
|
|
|
30
30
|
// LLM Providers
|
|
31
31
|
export * from './providers/index.js';
|
|
32
32
|
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
33
|
+
export { FileLlmTurnLog, InMemoryLlmTurnLog, createFileLlmTurnLogFromEnv, maskApiKey, resolveLlmTurnDir, } from './debug/llm-turn-log.js';
|
|
34
|
+
export { PostgresLlmTurnLog } from './debug/pg-llm-turn-log.js';
|
|
@@ -13,21 +13,7 @@ export interface IPgPool {
|
|
|
13
13
|
}>;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* id VARCHAR(36) PRIMARY KEY,
|
|
18
|
-
* session_id VARCHAR(36) NOT NULL,
|
|
19
|
-
* task_id VARCHAR(36) NULL,
|
|
20
|
-
* original_message_count INT NOT NULL,
|
|
21
|
-
* compressed_message_count INT NOT NULL,
|
|
22
|
-
* original_tokens INT NOT NULL,
|
|
23
|
-
* compressed_tokens INT NOT NULL,
|
|
24
|
-
* strategy VARCHAR(20) NOT NULL,
|
|
25
|
-
* summary_content TEXT NOT NULL,
|
|
26
|
-
* created_by VARCHAR(36) NOT NULL DEFAULT 'system',
|
|
27
|
-
* created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
28
|
-
* INDEX idx_compression_session (session_id),
|
|
29
|
-
* INDEX idx_compression_task (task_id)
|
|
30
|
-
* );
|
|
16
|
+
* `compression_records` 不在现行 Runtime DDL 内。见 runtime/docs/ddl.md。
|
|
31
17
|
*/
|
|
32
18
|
/**
|
|
33
19
|
* ICompressionRepository — 压缩记录持久化接口
|
|
@@ -7,4 +7,4 @@ export declare class EchoLLMProvider implements ILLMProvider {
|
|
|
7
7
|
invoke(messages: GraphMessage[], config: LLMNodeConfig): Promise<LLMResponse>;
|
|
8
8
|
stream(messages: GraphMessage[], config: LLMNodeConfig): AsyncIterableIterator<LLMChunk>;
|
|
9
9
|
}
|
|
10
|
-
export declare function createDefaultLLMProvider(): ILLMProvider;
|
|
10
|
+
export declare function createDefaultLLMProvider(turnLog?: import('../debug/llm-turn-log.js').ILlmTurnLog): ILLMProvider;
|
|
@@ -75,12 +75,13 @@ export class EchoLLMProvider {
|
|
|
75
75
|
* - 否则 → EchoLLMProvider
|
|
76
76
|
*/
|
|
77
77
|
import { HttpLLMProvider } from './http-llm-provider.js';
|
|
78
|
-
export function createDefaultLLMProvider() {
|
|
78
|
+
export function createDefaultLLMProvider(turnLog) {
|
|
79
79
|
if (process.env.OPENAI_API_KEY) {
|
|
80
80
|
return new HttpLLMProvider({
|
|
81
81
|
apiKey: process.env.OPENAI_API_KEY,
|
|
82
82
|
baseUrl: process.env.OPENAI_BASE_URL ?? 'https://api.openai.com/v1',
|
|
83
83
|
defaultModel: process.env.EAP_DEFAULT_MODEL ?? 'DeepSeek-V4-Pro',
|
|
84
|
+
turnLog,
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
return new EchoLLMProvider();
|
|
@@ -8,18 +8,22 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { GraphMessage } from '../graph/contracts/executable-graph.js';
|
|
10
10
|
import type { ILLMProvider, LLMNodeConfig, LLMResponse, LLMChunk } from '../graph/nodes/llm-node.js';
|
|
11
|
+
import { type ILlmTurnLog } from '../debug/llm-turn-log.js';
|
|
11
12
|
export interface HttpLLMProviderConfig {
|
|
12
13
|
apiKey: string;
|
|
13
14
|
baseUrl?: string;
|
|
14
15
|
defaultModel?: string;
|
|
15
16
|
timeoutMs?: number;
|
|
17
|
+
turnLog?: ILlmTurnLog;
|
|
16
18
|
}
|
|
17
19
|
export declare class HttpLLMProvider implements ILLMProvider {
|
|
18
20
|
private readonly apiKey;
|
|
19
21
|
private readonly baseUrl;
|
|
20
22
|
private readonly defaultModel;
|
|
21
23
|
private readonly timeoutMs;
|
|
24
|
+
private readonly turnLog?;
|
|
22
25
|
constructor(config: HttpLLMProviderConfig);
|
|
26
|
+
private writeTurn;
|
|
23
27
|
invoke(messages: GraphMessage[], config: LLMNodeConfig): Promise<LLMResponse>;
|
|
24
28
|
stream(messages: GraphMessage[], config: LLMNodeConfig): AsyncIterableIterator<LLMChunk>;
|
|
25
29
|
private buildRequestBody;
|