@gt-fe/eap-runtime 0.0.8 → 0.0.11
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 +15 -20
- package/dist/api/handlers/invoke.handler.js +7 -3
- package/dist/api/handlers/messages.handler.js +0 -1
- package/dist/api/handlers/stream.handler.js +8 -4
- package/dist/api/routes/agent.routes.d.ts +2 -2
- 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/common/types.d.ts +5 -5
- package/dist/common/types.js +2 -2
- package/dist/contracts/permission-checker.d.ts +1 -1
- package/dist/contracts/trace-collector.d.ts +16 -2
- 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/governance/governance-client.d.ts +1 -1
- package/dist/governance/governance-client.js +40 -16
- package/dist/governance/index.d.ts +2 -2
- package/dist/governance/index.js +1 -1
- package/dist/governance/permission-guard.d.ts +2 -1
- package/dist/governance/permission-guard.js +13 -4
- 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 +153 -92
- 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 +11 -9
- package/dist/graph/contracts/executable-graph.js +1 -1
- package/dist/graph/hitl/hitl-handler.d.ts +10 -0
- package/dist/graph/hitl/hitl-handler.js +50 -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 +50 -10
- package/dist/graph/trace-span.d.ts +22 -0
- package/dist/graph/trace-span.js +69 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- 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 +4 -3
- 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 +3 -3
- package/dist/registry/deployment-snapshot.d.ts +17 -5
- package/dist/registry/deployment-snapshot.js +97 -49
- package/dist/registry/graph-loader.d.ts +2 -2
- package/dist/registry/graph-loader.js +43 -80
- package/dist/registry/index.d.ts +2 -2
- package/dist/registry/index.js +2 -2
- package/dist/registry/preload-errors.d.ts +1 -1
- package/dist/registry/preload-errors.js +1 -1
- package/dist/registry/skill-io-guard.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 +129 -39
- package/dist/runtime/dev-runtime.d.ts +7 -4
- package/dist/runtime/dev-runtime.js +24 -21
- 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 +17 -19
- package/dist/server.js +2 -2
- 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 +12 -1
- package/dist/sse/events/skill-events.js +1 -1
- 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.d.ts +1 -1
- package/dist/tool/create-tool-executor.js +3 -2
- package/dist/tool/dev-http-executor.d.ts +1 -1
- package/dist/tool/dev-http-executor.js +10 -7
- package/dist/tool/dev-mcp-executor.js +5 -3
- package/dist/tool/dev-tool-executor.d.ts +1 -1
- package/dist/tool/dev-tool-executor.js +2 -2
- package/dist/tool/harness-command.d.ts +32 -0
- package/dist/tool/harness-command.js +276 -0
- package/dist/tool/harness-primitives.d.ts +54 -0
- package/dist/tool/harness-primitives.js +492 -0
- package/dist/tool/http-tool-executor.js +16 -21
- package/dist/tool/index.d.ts +4 -2
- package/dist/tool/index.js +4 -2
- package/dist/tool/local-mcp-client.d.ts +1 -1
- package/dist/tool/local-mcp-client.js +54 -23
- package/dist/tool/local-tool-executor.d.ts +4 -4
- package/dist/tool/local-tool-executor.js +18 -16
- package/dist/tool/mcp-tool-executor.js +23 -7
- package/dist/tool/skill-script-refs.d.ts +20 -0
- package/dist/tool/skill-script-refs.js +62 -0
- package/dist/tool/system-prompt-builder.d.ts +61 -25
- package/dist/tool/system-prompt-builder.js +198 -92
- package/dist/tool/timeout.d.ts +14 -0
- package/dist/tool/timeout.js +36 -0
- package/dist/tool/tool-confirmation.js +2 -1
- package/dist/tool/tool-execution-router.d.ts +1 -1
- package/dist/tool/tool-execution-router.js +2 -2
- package/dist/tool/tool-executor.interface.d.ts +23 -7
- package/dist/tool/tool-orchestrator.d.ts +1 -1
- package/dist/tool/tool-orchestrator.js +6 -3
- package/dist/utils/format-error.d.ts +2 -2
- package/dist/utils/format-error.js +2 -2
- package/dist/utils/http-error.d.ts +2 -2
- package/dist/utils/http-error.js +2 -2
- package/package.json +3 -3
- package/dist/common/concurrency.d.ts +0 -79
- package/dist/common/concurrency.js +0 -121
- package/dist/common/queue-consumer.d.ts +0 -125
- package/dist/common/queue-consumer.js +0 -159
- package/dist/tool/mock-tool-executor.d.ts +0 -28
- package/dist/tool/mock-tool-executor.js +0 -65
|
@@ -10,11 +10,16 @@
|
|
|
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
|
// ─────────────────────────────────────────────
|
|
16
18
|
/** HITL 默认等待时长(毫秒)= 300 秒。SSE `hitl.waited.timeout` 对外用秒。 */
|
|
17
19
|
export const DEFAULT_HITL_TIMEOUT_MS = 300_000;
|
|
20
|
+
/** 超时收口对外文案(Task / Trace / AppError);枚举走 `hitl_timeout`。 */
|
|
21
|
+
export const HITL_TIMEOUT_MESSAGE = 'HITL 确认超时';
|
|
22
|
+
export const HITL_TIMEOUT_ERROR_CODE = 'hitl_timeout';
|
|
18
23
|
/** HITL 超时错误(保留类型;timer 不再 throw,resume 逾期改走 AppError) */
|
|
19
24
|
export class HitlTimeoutError extends Error {
|
|
20
25
|
taskId;
|
|
@@ -151,8 +156,9 @@ export function buildHitlWaitedPayload(paused) {
|
|
|
151
156
|
*/
|
|
152
157
|
function prepareHitlCheckpointState(state) {
|
|
153
158
|
const raw = state;
|
|
159
|
+
const { traceCollector: _drop, ...rest } = raw;
|
|
154
160
|
return {
|
|
155
|
-
...
|
|
161
|
+
...rest,
|
|
156
162
|
userId: state.userId ?? raw.userId ?? '',
|
|
157
163
|
loadedTools: state.loadedTools ?? raw.loadedTools,
|
|
158
164
|
forceToolServer: state.forceToolServer ?? raw.forceToolServer,
|
|
@@ -162,6 +168,7 @@ function prepareHitlCheckpointState(state) {
|
|
|
162
168
|
delegationToken: state.delegationToken ?? raw.delegationToken,
|
|
163
169
|
skillSpanId: state.skillSpanId ?? raw.skillSpanId,
|
|
164
170
|
traceId: state.traceId ?? (typeof raw.traceId === 'string' ? raw.traceId : undefined),
|
|
171
|
+
lastSpanId: state.lastSpanId ?? (typeof raw.lastSpanId === 'string' ? raw.lastSpanId : undefined),
|
|
165
172
|
};
|
|
166
173
|
}
|
|
167
174
|
function toTimeoutEvent(waiting) {
|
|
@@ -193,6 +200,7 @@ function waitingFromPersisted(persisted, taskId) {
|
|
|
193
200
|
toolName: persisted.toolName,
|
|
194
201
|
toolSpanId: persisted.toolSpanId,
|
|
195
202
|
skillSpanId: persisted.skillSpanId,
|
|
203
|
+
hitlSpanId: persisted.hitlSpanId,
|
|
196
204
|
};
|
|
197
205
|
}
|
|
198
206
|
// ─────────────────────────────────────────────
|
|
@@ -216,6 +224,9 @@ export class HitlHandler {
|
|
|
216
224
|
timeoutListener;
|
|
217
225
|
/** 同一 taskId 上串行化 resume 与 timeout,避免双边占用 */
|
|
218
226
|
taskLocks = new Map();
|
|
227
|
+
traceCollector;
|
|
228
|
+
/** 进程内 interrupt 的 collector,不进 Checkpoint */
|
|
229
|
+
waitingCollectors = new Map();
|
|
219
230
|
constructor(checkpointSaver, sseEmitter, timeoutListener) {
|
|
220
231
|
this.checkpointSaver = checkpointSaver;
|
|
221
232
|
this.sseEmitter = sseEmitter;
|
|
@@ -224,6 +235,9 @@ export class HitlHandler {
|
|
|
224
235
|
setTimeoutListener(listener) {
|
|
225
236
|
this.timeoutListener = listener;
|
|
226
237
|
}
|
|
238
|
+
setTraceCollector(collector) {
|
|
239
|
+
this.traceCollector = collector;
|
|
240
|
+
}
|
|
227
241
|
/**
|
|
228
242
|
* 中断 Graph 执行,等待人工确认
|
|
229
243
|
*
|
|
@@ -237,6 +251,11 @@ export class HitlHandler {
|
|
|
237
251
|
const deadlineAt = new Date(Date.now() + timeoutMs).toISOString();
|
|
238
252
|
const skillSpanId = extras.skillSpanId ??
|
|
239
253
|
(typeof state.skillSpanId === 'string' ? state.skillSpanId : undefined);
|
|
254
|
+
const hitlSpanId = await startGraphSpan(state, {
|
|
255
|
+
name: extras.toolName ?? 'hitl',
|
|
256
|
+
type: 'hitl',
|
|
257
|
+
parentSpanId: extras.toolSpanId ?? skillSpanId,
|
|
258
|
+
});
|
|
240
259
|
const persisted = {
|
|
241
260
|
taskId,
|
|
242
261
|
threadId,
|
|
@@ -247,11 +266,16 @@ export class HitlHandler {
|
|
|
247
266
|
toolName: extras.toolName,
|
|
248
267
|
toolSpanId: extras.toolSpanId,
|
|
249
268
|
skillSpanId,
|
|
269
|
+
hitlSpanId,
|
|
250
270
|
};
|
|
251
271
|
const existing = await this.checkpointSaver.load(threadId);
|
|
272
|
+
const lastSpanId = hitlSpanId ??
|
|
273
|
+
extras.toolSpanId ??
|
|
274
|
+
(typeof state.lastSpanId === 'string' ? state.lastSpanId : undefined);
|
|
252
275
|
const persistedState = {
|
|
253
276
|
...(existing?.state ?? {}),
|
|
254
277
|
...prepareHitlCheckpointState(state),
|
|
278
|
+
...(lastSpanId ? { lastSpanId } : {}),
|
|
255
279
|
[HITL_WAITING_STATE_KEY]: persisted,
|
|
256
280
|
};
|
|
257
281
|
const checkpointData = {
|
|
@@ -266,7 +290,13 @@ export class HitlHandler {
|
|
|
266
290
|
updatedAt: now,
|
|
267
291
|
isDeleted: false,
|
|
268
292
|
};
|
|
269
|
-
|
|
293
|
+
const persistedCheckpoint = stripCheckpointCollectors(checkpointData);
|
|
294
|
+
await this.checkpointSaver.save(threadId, persistedCheckpoint);
|
|
295
|
+
const liveCollector = state.traceCollector;
|
|
296
|
+
if (liveCollector) {
|
|
297
|
+
this.waitingCollectors.set(taskId, liveCollector);
|
|
298
|
+
}
|
|
299
|
+
await notifyCheckpointRef(persistedCheckpoint, liveCollector);
|
|
270
300
|
const event = {
|
|
271
301
|
type: 'hitl.waiting',
|
|
272
302
|
data: {
|
|
@@ -300,6 +330,7 @@ export class HitlHandler {
|
|
|
300
330
|
toolName: extras.toolName,
|
|
301
331
|
toolSpanId: extras.toolSpanId,
|
|
302
332
|
skillSpanId,
|
|
333
|
+
hitlSpanId,
|
|
303
334
|
});
|
|
304
335
|
}
|
|
305
336
|
/**
|
|
@@ -335,6 +366,7 @@ export class HitlHandler {
|
|
|
335
366
|
if (!waiting) {
|
|
336
367
|
throw new HitlNotWaitingError(taskId);
|
|
337
368
|
}
|
|
369
|
+
const liveCollector = this.waitingCollectors.get(taskId) ?? this.traceCollector;
|
|
338
370
|
this.clearWaiting(taskId);
|
|
339
371
|
this.resolvedChoices.set(taskId, choice);
|
|
340
372
|
const baseState = prepareHitlCheckpointState(checkpoint.state);
|
|
@@ -346,13 +378,18 @@ export class HitlHandler {
|
|
|
346
378
|
hitlRespondedBy: userId,
|
|
347
379
|
};
|
|
348
380
|
const now = new Date().toISOString();
|
|
349
|
-
await this.checkpointSaver.save(waiting.threadId, {
|
|
381
|
+
await this.checkpointSaver.save(waiting.threadId, stripCheckpointCollectors({
|
|
350
382
|
...checkpoint,
|
|
351
383
|
engineSnapshot: undefined,
|
|
352
384
|
state: resumedState,
|
|
353
385
|
updatedBy: userId,
|
|
354
386
|
updatedAt: now,
|
|
355
|
-
});
|
|
387
|
+
}));
|
|
388
|
+
const hitlSpanId = waiting.hitlSpanId ?? persisted?.hitlSpanId;
|
|
389
|
+
await completeGraphSpan(resumedState, hitlSpanId, {
|
|
390
|
+
status: 'completed',
|
|
391
|
+
output: { choice, userId },
|
|
392
|
+
}, liveCollector);
|
|
356
393
|
const event = {
|
|
357
394
|
type: 'hitl.resumed',
|
|
358
395
|
data: { choice, userId },
|
|
@@ -390,6 +427,7 @@ export class HitlHandler {
|
|
|
390
427
|
toolSpanId: waiting.toolSpanId ?? persisted.toolSpanId,
|
|
391
428
|
skillSpanId: waiting.skillSpanId ?? persisted.skillSpanId,
|
|
392
429
|
});
|
|
430
|
+
const liveCollector = this.waitingCollectors.get(taskId) ?? this.traceCollector;
|
|
393
431
|
this.clearWaiting(taskId);
|
|
394
432
|
if (timeoutEvent.behavior !== 'auto-confirm' && checkpoint) {
|
|
395
433
|
const marked = {
|
|
@@ -400,12 +438,17 @@ export class HitlHandler {
|
|
|
400
438
|
timeoutBehavior: timeoutEvent.behavior,
|
|
401
439
|
},
|
|
402
440
|
};
|
|
403
|
-
await this.checkpointSaver.save(waiting.threadId, {
|
|
441
|
+
await this.checkpointSaver.save(waiting.threadId, stripCheckpointCollectors({
|
|
404
442
|
...checkpoint,
|
|
405
443
|
engineSnapshot: undefined,
|
|
406
444
|
state: marked,
|
|
407
445
|
updatedAt: new Date().toISOString(),
|
|
408
|
-
});
|
|
446
|
+
}));
|
|
447
|
+
const hitlSpanId = waiting.hitlSpanId ?? persisted.hitlSpanId;
|
|
448
|
+
await completeGraphSpan(checkpoint.state, hitlSpanId, {
|
|
449
|
+
status: 'failed',
|
|
450
|
+
error: HITL_TIMEOUT_MESSAGE,
|
|
451
|
+
}, liveCollector);
|
|
409
452
|
}
|
|
410
453
|
return timeoutEvent;
|
|
411
454
|
});
|
|
@@ -439,6 +482,7 @@ export class HitlHandler {
|
|
|
439
482
|
clearTimeout(waiting.timer);
|
|
440
483
|
}
|
|
441
484
|
this.waitingTasks.delete(taskId);
|
|
485
|
+
this.waitingCollectors.delete(taskId);
|
|
442
486
|
}
|
|
443
487
|
async withTaskLock(taskId, fn) {
|
|
444
488
|
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;
|
|
@@ -9,10 +9,30 @@
|
|
|
9
9
|
* @see design.md §1.4 ToolNode: LangGraph的ToolNode封装
|
|
10
10
|
* @see requirements.md Requirement 8 AC1, AC3, AC5
|
|
11
11
|
*/
|
|
12
|
+
import { resolveJailFromState } from '../../tool/harness-primitives.js';
|
|
12
13
|
import { isHitlDecision, unwrapHitlPaused } from '../hitl/hitl-handler.js';
|
|
13
14
|
import { ToolConfirmationInterceptor } from '../../tool/tool-confirmation.js';
|
|
14
15
|
import { resolveCheckpointThreadId } from '../../session/persist-turn-messages.js';
|
|
15
16
|
import { resolveTraceId } from '../../common/trace-id.js';
|
|
17
|
+
function skillDirsFromState(state) {
|
|
18
|
+
const defs = state['skillDefinitions'];
|
|
19
|
+
return Object.values(defs ?? {})
|
|
20
|
+
.filter((skill) => Boolean(skill.bundlePath))
|
|
21
|
+
.map((skill) => ({ skillId: skill.skillId, bundlePath: skill.bundlePath }));
|
|
22
|
+
}
|
|
23
|
+
function resolveActiveSkillDir(state) {
|
|
24
|
+
const defs = state['skillDefinitions'];
|
|
25
|
+
if (!defs)
|
|
26
|
+
return undefined;
|
|
27
|
+
const activated = state['activatedSkill'];
|
|
28
|
+
if (typeof activated === 'string' && defs[activated]?.bundlePath) {
|
|
29
|
+
return defs[activated].bundlePath;
|
|
30
|
+
}
|
|
31
|
+
const paths = Object.values(defs)
|
|
32
|
+
.map((skill) => skill.bundlePath)
|
|
33
|
+
.filter((p) => Boolean(p));
|
|
34
|
+
return paths.length === 1 ? paths[0] : undefined;
|
|
35
|
+
}
|
|
16
36
|
export class ToolNode {
|
|
17
37
|
orchestrator;
|
|
18
38
|
injector;
|
|
@@ -46,6 +66,16 @@ export class ToolNode {
|
|
|
46
66
|
return state;
|
|
47
67
|
}
|
|
48
68
|
const loadedTools = state['loadedTools'];
|
|
69
|
+
const skillDirs = skillDirsFromState(state);
|
|
70
|
+
const jail = resolveJailFromState({
|
|
71
|
+
agentDir: state['agentDir'],
|
|
72
|
+
userId: state['userId'],
|
|
73
|
+
executionContext: state['executionContext'],
|
|
74
|
+
loadedTools,
|
|
75
|
+
skillDefinitions: state['skillDefinitions'],
|
|
76
|
+
});
|
|
77
|
+
const jailExtraRoots = jail.extraRoots ?? [];
|
|
78
|
+
const skillDir = resolveActiveSkillDir(state);
|
|
49
79
|
// 4. 转换为 ToolCallRequest[](附带 manifest 路由字段)
|
|
50
80
|
const requests = lastAssistantMessage.toolCalls.map((tc) => {
|
|
51
81
|
const loaded = loadedTools?.[tc.name];
|
|
@@ -62,20 +92,29 @@ export class ToolNode {
|
|
|
62
92
|
dataScope: loaded?.manifest.dataScope,
|
|
63
93
|
// dev 上下文 DevMcpExecutor 直连所需;server 上下文会忽略
|
|
64
94
|
execution: loaded?.manifest.execution,
|
|
95
|
+
...(loaded?.manifest.version ? { toolVersion: loaded.manifest.version } : {}),
|
|
65
96
|
correlationId,
|
|
66
97
|
taskId,
|
|
98
|
+
...(jail.workdir ? { jailWorkdir: jail.workdir } : {}),
|
|
99
|
+
...(jailExtraRoots.length > 0 ? { jailExtraRoots } : {}),
|
|
100
|
+
...(skillDir ? { skillDir } : {}),
|
|
67
101
|
};
|
|
68
102
|
});
|
|
69
103
|
const executionContext = state['executionContext'];
|
|
70
104
|
const traceCollector = state['traceCollector'];
|
|
71
105
|
const traceId = resolveTraceId(state);
|
|
72
|
-
const agentCode = String(state['agentCode'] ??
|
|
106
|
+
const agentCode = String(state['agentCode'] ?? '');
|
|
73
107
|
const nodeId = this.nodeId ?? 'tool-node';
|
|
74
108
|
const skillId = typeof state['activatedSkill'] === 'string' && state['activatedSkill']
|
|
75
109
|
? state['activatedSkill']
|
|
76
110
|
: undefined;
|
|
77
111
|
const emitProgress = (data) => {
|
|
78
|
-
this.onProgress?.({
|
|
112
|
+
this.onProgress?.({
|
|
113
|
+
...data,
|
|
114
|
+
node: nodeId,
|
|
115
|
+
...(skillId ? { skillId } : {}),
|
|
116
|
+
...(skillDirs.length > 0 ? { skillDirs } : {}),
|
|
117
|
+
});
|
|
79
118
|
};
|
|
80
119
|
// 5. 并行执行所有 Tool 调用(附 Trace span)
|
|
81
120
|
const spanIds = await Promise.all(requests.map(async (req) => {
|
|
@@ -146,7 +185,8 @@ export class ToolNode {
|
|
|
146
185
|
toolName: req.toolName,
|
|
147
186
|
content: `用户拒绝执行工具 ${req.toolName}`,
|
|
148
187
|
success: false,
|
|
149
|
-
error:
|
|
188
|
+
error: `用户拒绝执行工具 ${req.toolName}`,
|
|
189
|
+
errorCode: 'hitl_rejected',
|
|
150
190
|
};
|
|
151
191
|
}
|
|
152
192
|
else {
|
|
@@ -158,6 +198,7 @@ export class ToolNode {
|
|
|
158
198
|
toolCallId: result.toolCallId,
|
|
159
199
|
toolName: result.toolName,
|
|
160
200
|
status: 'completed',
|
|
201
|
+
arguments: req.arguments,
|
|
161
202
|
content: result.content,
|
|
162
203
|
executionTime,
|
|
163
204
|
});
|
|
@@ -167,6 +208,7 @@ export class ToolNode {
|
|
|
167
208
|
toolCallId: result.toolCallId,
|
|
168
209
|
toolName: result.toolName,
|
|
169
210
|
status: 'error',
|
|
211
|
+
arguments: req.arguments,
|
|
170
212
|
error: result.error ?? 'unknown error',
|
|
171
213
|
executionTime,
|
|
172
214
|
});
|
|
@@ -202,6 +244,7 @@ export class ToolNode {
|
|
|
202
244
|
toolCallId: req.toolCallId,
|
|
203
245
|
toolName: req.toolName,
|
|
204
246
|
status: 'error',
|
|
247
|
+
arguments: req.arguments,
|
|
205
248
|
error: message,
|
|
206
249
|
executionTime,
|
|
207
250
|
});
|
|
@@ -240,10 +283,11 @@ export class ToolNode {
|
|
|
240
283
|
success: result.success,
|
|
241
284
|
...('file' in result && result.file ? { file: result.file } : {}),
|
|
242
285
|
}));
|
|
243
|
-
|
|
286
|
+
const lastSpanId = [...spanIds].reverse().find((id) => Boolean(id));
|
|
244
287
|
return {
|
|
245
288
|
messages: toolMessages,
|
|
246
289
|
currentNode: nodeId,
|
|
290
|
+
...(lastSpanId ? { lastSpanId } : {}),
|
|
247
291
|
};
|
|
248
292
|
}
|
|
249
293
|
// ─────────────────────────────────────────────
|
|
@@ -282,11 +326,7 @@ export class ToolNode {
|
|
|
282
326
|
}
|
|
283
327
|
buildAuthContext(state) {
|
|
284
328
|
const executionContext = state['executionContext'];
|
|
285
|
-
|
|
286
|
-
const agentCode = String(state['agentCode'] ??
|
|
287
|
-
state['agentId'] ??
|
|
288
|
-
this.defaultAuthContext.agentCode ??
|
|
289
|
-
this.defaultAuthContext.agentId);
|
|
329
|
+
const agentCode = String(state['agentCode'] ?? this.defaultAuthContext.agentCode ?? '');
|
|
290
330
|
// 优先 ExecutionContext(invoke Token.sub),保证所有 Tool/MCP 出站同一身份
|
|
291
331
|
const userId = String(executionContext?.userId ?? state['userId'] ?? this.defaultAuthContext.userId);
|
|
292
332
|
const delegationToken = String(executionContext?.delegationToken ??
|
|
@@ -315,7 +355,7 @@ export class ToolNode {
|
|
|
315
355
|
loadedTools: state['loadedTools'],
|
|
316
356
|
forceToolServer: state['forceToolServer'],
|
|
317
357
|
executionContext: state['executionContext'],
|
|
318
|
-
agentCode:
|
|
358
|
+
agentCode: state['agentCode'],
|
|
319
359
|
correlationId: state['correlationId'],
|
|
320
360
|
taskId: state['taskId'],
|
|
321
361
|
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
|
@@ -16,6 +16,9 @@ export * from './common/index.js';
|
|
|
16
16
|
export * from './registry/index.js';
|
|
17
17
|
export * from './providers/index.js';
|
|
18
18
|
export type { ITraceCollector, TraceEvent, TraceSession, ExecutionFlowEvent, ExecutionNodeEvent, TraceLinkEvent, TraceLinkNodeEvent, } from './contracts/trace-collector.js';
|
|
19
|
-
export type { ExecutionContext, CallerType, GovernancePermissionCheckParams, GovernancePermissionCheckResult, PermissionDenyReason, } from '@
|
|
20
|
-
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
19
|
+
export type { ExecutionContext, CallerType, GovernancePermissionCheckParams, GovernancePermissionCheckResult, PermissionDenyReason, } from '@eap/contracts';
|
|
20
|
+
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, permissionMessage, 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
|
@@ -29,4 +29,6 @@ export * from './common/index.js';
|
|
|
29
29
|
export * from './registry/index.js';
|
|
30
30
|
// LLM Providers
|
|
31
31
|
export * from './providers/index.js';
|
|
32
|
-
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
|
|
32
|
+
export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, permissionMessage, 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;
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* - `call:echo-tool {"text":"hi"}` → arguments 使用解析后的 JSON
|
|
8
8
|
* - `call:echo-tool hi` → arguments 兜底为 `{ text: 'hi' }`
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* 仅用于本地闭环(无真实 LLM)下驱动 ToolNode,
|
|
11
|
+
* 让开发者无需接入模型即可完成 tool 调用链路验证。
|
|
12
12
|
*/
|
|
13
13
|
function parseSyntheticToolCall(content) {
|
|
14
14
|
if (!content)
|
|
@@ -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;
|