@gt-fe/eap-runtime 0.0.32 → 0.0.34
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/dist/api/handlers/invoke.handler.d.ts +0 -1
- package/dist/api/handlers/invoke.handler.js +25 -6
- package/dist/api/handlers/stream.handler.d.ts +0 -1
- package/dist/api/handlers/stream.handler.js +22 -18
- package/dist/common/types.d.ts +4 -3
- package/dist/graph/adapters/langgraph.adapter.d.ts +0 -1
- package/dist/graph/adapters/langgraph.adapter.js +117 -82
- package/dist/graph/adapters/skill-entry-span.js +4 -1
- package/dist/graph/adapters/subgraph-compiler.js +11 -9
- package/dist/graph/contracts/executable-graph.d.ts +2 -0
- package/dist/graph/execution-trace-context.d.ts +3 -0
- package/dist/graph/nodes/llm-node.d.ts +7 -2
- package/dist/graph/nodes/llm-node.js +8 -3
- package/dist/graph/nodes/skill-bind-node.d.ts +1 -1
- package/dist/graph/nodes/skill-bind-node.js +6 -1
- package/dist/graph/nodes/tool-node.js +1 -0
- package/dist/providers/http-llm-provider.js +27 -10
- package/dist/registry/graph-loader.d.ts +11 -0
- package/dist/registry/graph-loader.js +28 -4
- package/dist/runtime/agent-runtime.d.ts +7 -0
- package/dist/runtime/agent-runtime.js +69 -38
- package/dist/runtime/types.d.ts +1 -1
- package/dist/session/persist-turn-messages.d.ts +10 -2
- package/dist/session/persist-turn-messages.js +35 -10
- package/dist/sse/events/index.d.ts +6 -4
- package/dist/sse/events/index.js +3 -1
- package/dist/sse/events/reasoning-events.d.ts +24 -2
- package/dist/sse/events/reasoning-events.js +3 -1
- package/dist/sse/events/skill-events.d.ts +2 -0
- package/dist/task/contracts/task-manager.contract.d.ts +2 -2
- package/dist/task/contracts/task-manager.contract.js +1 -1
- package/dist/task/index.d.ts +2 -0
- package/dist/task/index.js +1 -0
- package/dist/task/task-abort.d.ts +14 -0
- package/dist/task/task-abort.js +33 -0
- package/dist/task/task-timeout.d.ts +11 -0
- package/dist/task/task-timeout.js +40 -4
- package/dist/task/task.service.js +11 -5
- package/dist/tool/index.d.ts +1 -1
- package/dist/tool/index.js +1 -1
- package/dist/tool/mcp-list.d.ts +3 -1
- package/dist/tool/mcp-list.js +4 -1
- package/dist/tool/system-prompt-builder.d.ts +10 -8
- package/dist/tool/system-prompt-builder.js +36 -26
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@ import { LangGraphAdapter } from './langgraph.adapter.js';
|
|
|
13
13
|
import { assertSkillGraphHasNoSubgraphNodes } from './graph-nesting.js';
|
|
14
14
|
import { resolveExecutionTrace, warnTraceSpanFailure, } from '../execution-trace-context.js';
|
|
15
15
|
import { skillSpanFields, skillTraceIdentity } from './skill-entry-span.js';
|
|
16
|
-
import { filterLoadedToolsForSkill, } from '../../tool/system-prompt-builder.js';
|
|
16
|
+
import { filterLoadedToolsForSkill, spokenName, } from '../../tool/system-prompt-builder.js';
|
|
17
17
|
import { unwrapHitlPaused } from '../hitl/hitl-handler.js';
|
|
18
18
|
import { pickContextFields } from '../../token/context-window.js';
|
|
19
19
|
import { assertSkillIoIfEnabled, coerceSkillInputFromMessages, } from '../../registry/skill-io-guard.js';
|
|
@@ -65,11 +65,14 @@ export class SubGraphCompiler {
|
|
|
65
65
|
? state['skillSpanId']
|
|
66
66
|
: '';
|
|
67
67
|
const resuming = Boolean(existingSpanId);
|
|
68
|
+
const identity = skillTraceIdentity(state, resolvedSkillId);
|
|
69
|
+
const spanName = resolvedSkillId || dsl.name || 'skill';
|
|
70
|
+
const skillName = spokenName(identity.skillName, resolvedSkillId) ?? spanName;
|
|
68
71
|
const auditCtx = resuming
|
|
69
72
|
? undefined
|
|
70
73
|
: this.skillAuditRecorder?.startInvocation({
|
|
71
74
|
skillId: resolvedSkillId,
|
|
72
|
-
skillName
|
|
75
|
+
skillName,
|
|
73
76
|
agentCode: (state['agentCode'] ?? state['agentId']),
|
|
74
77
|
userId: state['userId'] ?? '',
|
|
75
78
|
taskId: state['taskId'],
|
|
@@ -77,8 +80,6 @@ export class SubGraphCompiler {
|
|
|
77
80
|
});
|
|
78
81
|
// 用父图这次调用上的 collector;内层 invoke 只补 collector/traceId,沿用外层流式袋。
|
|
79
82
|
const { collector: traceCollector, traceId } = resolveExecutionTrace(state);
|
|
80
|
-
const skillName = dsl.name || resolvedSkillId;
|
|
81
|
-
const identity = skillTraceIdentity(state, resolvedSkillId);
|
|
82
83
|
if (!resuming) {
|
|
83
84
|
adapter.emitStreamEvent({
|
|
84
85
|
type: 'skill.started',
|
|
@@ -87,7 +88,7 @@ export class SubGraphCompiler {
|
|
|
87
88
|
timestamp: new Date().toISOString(),
|
|
88
89
|
payload: {
|
|
89
90
|
skillId: resolvedSkillId,
|
|
90
|
-
skillName
|
|
91
|
+
skillName,
|
|
91
92
|
...(identity.skillSpace ? { skillSpace: identity.skillSpace } : {}),
|
|
92
93
|
...(identity.skillVersion ? { skillVersion: identity.skillVersion } : {}),
|
|
93
94
|
},
|
|
@@ -99,7 +100,7 @@ export class SubGraphCompiler {
|
|
|
99
100
|
const fields = skillSpanFields(identity, { source: 'subgraph' });
|
|
100
101
|
skillSpanId = await traceCollector.createNode({
|
|
101
102
|
traceId,
|
|
102
|
-
name:
|
|
103
|
+
name: spanName,
|
|
103
104
|
type: 'skill',
|
|
104
105
|
agentCode: state['agentCode'] ?? state['agentId'],
|
|
105
106
|
...(fields.version ? { version: fields.version } : {}),
|
|
@@ -111,7 +112,7 @@ export class SubGraphCompiler {
|
|
|
111
112
|
});
|
|
112
113
|
}
|
|
113
114
|
catch (err) {
|
|
114
|
-
warnTraceSpanFailure('createNode', { type: 'skill', name:
|
|
115
|
+
warnTraceSpanFailure('createNode', { type: 'skill', name: spanName, traceId }, err);
|
|
115
116
|
skillSpanId = null;
|
|
116
117
|
}
|
|
117
118
|
}
|
|
@@ -154,6 +155,7 @@ export class SubGraphCompiler {
|
|
|
154
155
|
userId,
|
|
155
156
|
delegationToken,
|
|
156
157
|
agentCode,
|
|
158
|
+
agentName: typeof state['agentName'] === 'string' ? state['agentName'] : undefined,
|
|
157
159
|
taskId: state['taskId'],
|
|
158
160
|
correlationId: state['correlationId'],
|
|
159
161
|
sessionId: state['sessionId'],
|
|
@@ -194,7 +196,7 @@ export class SubGraphCompiler {
|
|
|
194
196
|
});
|
|
195
197
|
}
|
|
196
198
|
catch (err) {
|
|
197
|
-
warnTraceSpanFailure('completeNode', { type: 'skill', name:
|
|
199
|
+
warnTraceSpanFailure('completeNode', { type: 'skill', name: spanName, traceId, spanId: skillSpanId }, err);
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
// 4. 只回写子图本步新增消息(含内部 tool 回合),禁止把入口历史再 append
|
|
@@ -269,7 +271,7 @@ export class SubGraphCompiler {
|
|
|
269
271
|
});
|
|
270
272
|
}
|
|
271
273
|
catch (completeErr) {
|
|
272
|
-
warnTraceSpanFailure('completeNode', { type: 'skill', name:
|
|
274
|
+
warnTraceSpanFailure('completeNode', { type: 'skill', name: spanName, traceId, spanId: skillSpanId }, completeErr);
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
adapter.emitStreamEvent({
|
|
@@ -181,6 +181,8 @@ export interface GraphState {
|
|
|
181
181
|
agentId?: string;
|
|
182
182
|
/** Agent 对外主键 */
|
|
183
183
|
agentCode?: string;
|
|
184
|
+
/** Agent 展示名(manifest.name);身份段对用户说话用,缺省回退 agentCode */
|
|
185
|
+
agentName?: string;
|
|
184
186
|
/** Hosting 路由选定的预装版本(AR-3b;写入 Checkpoint 供 HITL/Fork 恢复) */
|
|
185
187
|
agentVersion?: string;
|
|
186
188
|
correlationId?: string;
|
|
@@ -8,9 +8,12 @@ export interface ExecutionStreamBag {
|
|
|
8
8
|
correlationId?: string;
|
|
9
9
|
};
|
|
10
10
|
chunkIndex: number;
|
|
11
|
+
/** 本轮 reasoning.chunk 序号,与 chunkIndex 分开从 0 计 */
|
|
12
|
+
reasoningChunkIndex: number;
|
|
11
13
|
iteration: number;
|
|
12
14
|
reasoningStartedThisTurn: boolean;
|
|
13
15
|
streamedTextThisTurn: boolean;
|
|
16
|
+
graphId?: string;
|
|
14
17
|
}
|
|
15
18
|
export interface ExecutionRunContext {
|
|
16
19
|
collector?: ITraceCollector;
|
|
@@ -107,6 +107,11 @@ export interface LLMChunk {
|
|
|
107
107
|
/** thinking 增量;最终聚合后写入 assistant 消息 */
|
|
108
108
|
reasoningContent?: string;
|
|
109
109
|
}
|
|
110
|
+
/** 流式旁路增量:思考与正文分字段,空字段不传 */
|
|
111
|
+
export type LLMStreamDelta = {
|
|
112
|
+
content?: string;
|
|
113
|
+
reasoningContent?: string;
|
|
114
|
+
};
|
|
110
115
|
/**
|
|
111
116
|
* ILLMProvider — LLM 调用提供者接口
|
|
112
117
|
*
|
|
@@ -145,9 +150,9 @@ export declare class LLMNode {
|
|
|
145
150
|
* @param config - LLM 节点配置
|
|
146
151
|
* @param provider - LLM 调用提供者
|
|
147
152
|
* @param streaming - 是否启用流式输出(默认 false)
|
|
148
|
-
* @param onChunk -
|
|
153
|
+
* @param onChunk - 流式旁路:思考走 reasoningContent,正文走 content
|
|
149
154
|
*/
|
|
150
|
-
constructor(nodeId: string, config: LLMNodeConfig, provider: ILLMProvider, streaming?: boolean, onChunk?: (
|
|
155
|
+
constructor(nodeId: string, config: LLMNodeConfig, provider: ILLMProvider, streaming?: boolean, onChunk?: (delta: LLMStreamDelta) => void, interceptors?: Pick<ExecutionInterceptors, "beforeModel" | "afterModel"> | undefined);
|
|
151
156
|
/**
|
|
152
157
|
* execute — StateGraph 节点函数
|
|
153
158
|
*
|
|
@@ -52,7 +52,7 @@ export class LLMNode {
|
|
|
52
52
|
* @param config - LLM 节点配置
|
|
53
53
|
* @param provider - LLM 调用提供者
|
|
54
54
|
* @param streaming - 是否启用流式输出(默认 false)
|
|
55
|
-
* @param onChunk -
|
|
55
|
+
* @param onChunk - 流式旁路:思考走 reasoningContent,正文走 content
|
|
56
56
|
*/
|
|
57
57
|
constructor(nodeId, config, provider, streaming = false, onChunk, interceptors) {
|
|
58
58
|
this.interceptors = interceptors;
|
|
@@ -247,8 +247,13 @@ export class LLMNode {
|
|
|
247
247
|
let toolCalls;
|
|
248
248
|
const iterator = this.provider.stream(messages, this.config);
|
|
249
249
|
for await (const chunk of iterator) {
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
const content = chunk.content || '';
|
|
251
|
+
const reasoningContent = chunk.reasoningContent || '';
|
|
252
|
+
if (this.onChunk && (content || reasoningContent)) {
|
|
253
|
+
this.onChunk({
|
|
254
|
+
...(content ? { content } : {}),
|
|
255
|
+
...(reasoningContent ? { reasoningContent } : {}),
|
|
256
|
+
});
|
|
252
257
|
}
|
|
253
258
|
chunks.push(chunk.content);
|
|
254
259
|
if (chunk.reasoningContent) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 可选图胶水:把 silent LLM 的结构化输出写成 skillRoute / activatedSkill。
|
|
3
3
|
* 不是 Graph 节点类型。技能正文走短目录 + read_file,不灌 system。
|
|
4
4
|
*/
|
|
5
|
-
import type
|
|
5
|
+
import { type LoadedSkillInfo, type LoadedSkillMap } from '../../tool/system-prompt-builder.js';
|
|
6
6
|
export type SkillRoute = 'skill' | 'clarify' | 'none';
|
|
7
7
|
export interface SkillBindPatch {
|
|
8
8
|
skillRoute: SkillRoute;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 可选图胶水:把 silent LLM 的结构化输出写成 skillRoute / activatedSkill。
|
|
3
|
+
* 不是 Graph 节点类型。技能正文走短目录 + read_file,不灌 system。
|
|
4
|
+
*/
|
|
5
|
+
import { spokenName } from '../../tool/system-prompt-builder.js';
|
|
1
6
|
function lastAssistantText(messages) {
|
|
2
7
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3
8
|
const msg = messages[i];
|
|
@@ -89,7 +94,7 @@ export function bindSelectedSkill(state) {
|
|
|
89
94
|
return {
|
|
90
95
|
skillRoute: 'skill',
|
|
91
96
|
activatedSkill: skill.skillId,
|
|
92
|
-
skillName: skill.name
|
|
97
|
+
skillName: spokenName(skill.name, skill.skillId),
|
|
93
98
|
skillInput: params,
|
|
94
99
|
messages: nextMessages(),
|
|
95
100
|
};
|
|
@@ -119,7 +119,7 @@ export class HttpLLMProvider {
|
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
catch (err) {
|
|
122
|
-
|
|
122
|
+
throwIfGraphAborted();
|
|
123
123
|
throw new Error(this.formatNetworkError(url, err));
|
|
124
124
|
}
|
|
125
125
|
if (!response.ok) {
|
|
@@ -170,6 +170,7 @@ export class HttpLLMProvider {
|
|
|
170
170
|
return result;
|
|
171
171
|
}
|
|
172
172
|
catch (err) {
|
|
173
|
+
const propagated = graphAbortOr(err);
|
|
173
174
|
await this.writeTurn({
|
|
174
175
|
url,
|
|
175
176
|
messages,
|
|
@@ -180,10 +181,10 @@ export class HttpLLMProvider {
|
|
|
180
181
|
inputTokens: 0,
|
|
181
182
|
outputTokens: 0,
|
|
182
183
|
finishReason: 'error',
|
|
183
|
-
error:
|
|
184
|
+
error: propagated instanceof Error ? propagated.message : String(propagated),
|
|
184
185
|
},
|
|
185
186
|
});
|
|
186
|
-
throw
|
|
187
|
+
throw propagated;
|
|
187
188
|
}
|
|
188
189
|
finally {
|
|
189
190
|
clearTimeout(timeout);
|
|
@@ -244,7 +245,7 @@ export class HttpLLMProvider {
|
|
|
244
245
|
});
|
|
245
246
|
}
|
|
246
247
|
catch (err) {
|
|
247
|
-
|
|
248
|
+
throwIfGraphAborted();
|
|
248
249
|
throw new Error(this.formatNetworkError(url, err));
|
|
249
250
|
}
|
|
250
251
|
if (!response.ok) {
|
|
@@ -397,6 +398,7 @@ export class HttpLLMProvider {
|
|
|
397
398
|
});
|
|
398
399
|
}
|
|
399
400
|
catch (err) {
|
|
401
|
+
const propagated = graphAbortOr(err);
|
|
400
402
|
await this.writeTurn({
|
|
401
403
|
url,
|
|
402
404
|
messages,
|
|
@@ -411,10 +413,10 @@ export class HttpLLMProvider {
|
|
|
411
413
|
inputTokens,
|
|
412
414
|
outputTokens,
|
|
413
415
|
finishReason: 'error',
|
|
414
|
-
error:
|
|
416
|
+
error: propagated instanceof Error ? propagated.message : String(propagated),
|
|
415
417
|
},
|
|
416
418
|
});
|
|
417
|
-
throw
|
|
419
|
+
throw propagated;
|
|
418
420
|
}
|
|
419
421
|
finally {
|
|
420
422
|
clearTimeout(timeout);
|
|
@@ -528,11 +530,26 @@ function linkGraphAbort(controller) {
|
|
|
528
530
|
graphSignal.addEventListener('abort', onAbort, { once: true });
|
|
529
531
|
return () => graphSignal.removeEventListener('abort', onAbort);
|
|
530
532
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
533
|
+
/** 这一轮 signal 已 abort 就抛出 reason。超时和用户停止都走这里,不再只认 timed out。 */
|
|
534
|
+
function throwIfGraphAborted() {
|
|
535
|
+
const reason = graphAbortReason();
|
|
536
|
+
if (reason)
|
|
534
537
|
throw reason;
|
|
535
|
-
|
|
538
|
+
}
|
|
539
|
+
/** 流式 read 抛出的 DOMException 换成这一轮 signal 上的 reason。 */
|
|
540
|
+
function graphAbortOr(err) {
|
|
541
|
+
return graphAbortReason() ?? err;
|
|
542
|
+
}
|
|
543
|
+
function graphAbortReason() {
|
|
544
|
+
const signal = getExecutionTrace()?.abortSignal;
|
|
545
|
+
if (!signal?.aborted)
|
|
546
|
+
return undefined;
|
|
547
|
+
const reason = signal.reason;
|
|
548
|
+
if (reason instanceof Error)
|
|
549
|
+
return reason;
|
|
550
|
+
const err = new Error(reason == null ? 'Task aborted' : String(reason));
|
|
551
|
+
err.name = 'AbortError';
|
|
552
|
+
return err;
|
|
536
553
|
}
|
|
537
554
|
function formatNetworkDetail(error, depth = 0) {
|
|
538
555
|
if (depth > 5)
|
|
@@ -20,8 +20,13 @@ export interface LoadAgentOptions {
|
|
|
20
20
|
export declare function resolveAgentSystemPromptFromLoader(loader: {
|
|
21
21
|
resolveAgentSystemPrompt?: (agentCode: string, version?: string) => Promise<string | undefined>;
|
|
22
22
|
} | undefined, agentCode: string, version?: string): Promise<string | undefined>;
|
|
23
|
+
export declare function resolveAgentDisplayNameFromLoader(loader: {
|
|
24
|
+
resolveAgentDisplayName?: (agentCode: string, version?: string) => Promise<string | undefined>;
|
|
25
|
+
} | undefined, agentCode: string, version?: string): Promise<string | undefined>;
|
|
23
26
|
/** manifest.prompts.system;空白视为缺省。 */
|
|
24
27
|
export declare function extractAgentSystemPrompt(manifest: unknown): string | undefined;
|
|
28
|
+
/** manifest.name;空白视为缺省。身份段对用户说话用,不当路由键。 */
|
|
29
|
+
export declare function extractAgentDisplayName(manifest: unknown): string | undefined;
|
|
25
30
|
export interface GraphLoaderConfig {
|
|
26
31
|
registryClient?: AgentRegistryClient;
|
|
27
32
|
deploymentContext?: DeploymentContext;
|
|
@@ -116,6 +121,12 @@ export declare class GraphLoader {
|
|
|
116
121
|
* 每轮 execute/stream 注入 GraphState.agentSystemPrompt;不写进节点 config。
|
|
117
122
|
*/
|
|
118
123
|
resolveAgentSystemPrompt(agentCode: string, version?: string): Promise<string | undefined>;
|
|
124
|
+
/**
|
|
125
|
+
* Agent 展示名(manifest.name)。
|
|
126
|
+
* 每轮 execute/stream 注入 GraphState.agentName;身份段对用户说话用。
|
|
127
|
+
*/
|
|
128
|
+
resolveAgentDisplayName(agentCode: string, version?: string): Promise<string | undefined>;
|
|
129
|
+
private fromAgentManifest;
|
|
119
130
|
/**
|
|
120
131
|
* 解析 agent tools[] + graph tool 节点 union;
|
|
121
132
|
* server+预装:以预装 manifest 为准;desktop 合并 ILocalToolInstallStore。
|
|
@@ -64,6 +64,11 @@ export async function resolveAgentSystemPromptFromLoader(loader, agentCode, vers
|
|
|
64
64
|
return undefined;
|
|
65
65
|
return loader.resolveAgentSystemPrompt(agentCode, version);
|
|
66
66
|
}
|
|
67
|
+
export async function resolveAgentDisplayNameFromLoader(loader, agentCode, version) {
|
|
68
|
+
if (!loader || typeof loader.resolveAgentDisplayName !== 'function')
|
|
69
|
+
return undefined;
|
|
70
|
+
return loader.resolveAgentDisplayName(agentCode, version);
|
|
71
|
+
}
|
|
67
72
|
/** manifest.prompts.system;空白视为缺省。 */
|
|
68
73
|
export function extractAgentSystemPrompt(manifest) {
|
|
69
74
|
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest))
|
|
@@ -77,6 +82,16 @@ export function extractAgentSystemPrompt(manifest) {
|
|
|
77
82
|
const trimmed = system.trim();
|
|
78
83
|
return trimmed ? trimmed : undefined;
|
|
79
84
|
}
|
|
85
|
+
/** manifest.name;空白视为缺省。身份段对用户说话用,不当路由键。 */
|
|
86
|
+
export function extractAgentDisplayName(manifest) {
|
|
87
|
+
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest))
|
|
88
|
+
return undefined;
|
|
89
|
+
const name = manifest.name;
|
|
90
|
+
if (typeof name !== 'string')
|
|
91
|
+
return undefined;
|
|
92
|
+
const trimmed = name.trim();
|
|
93
|
+
return trimmed ? trimmed : undefined;
|
|
94
|
+
}
|
|
80
95
|
function extractSkillPrompt(manifest) {
|
|
81
96
|
const prompt = manifest.prompt;
|
|
82
97
|
if (typeof prompt === 'string' && prompt.trim())
|
|
@@ -769,18 +784,27 @@ export class GraphLoader {
|
|
|
769
784
|
* 每轮 execute/stream 注入 GraphState.agentSystemPrompt;不写进节点 config。
|
|
770
785
|
*/
|
|
771
786
|
async resolveAgentSystemPrompt(agentCode, version) {
|
|
787
|
+
return this.fromAgentManifest(agentCode, version, extractAgentSystemPrompt);
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Agent 展示名(manifest.name)。
|
|
791
|
+
* 每轮 execute/stream 注入 GraphState.agentName;身份段对用户说话用。
|
|
792
|
+
*/
|
|
793
|
+
async resolveAgentDisplayName(agentCode, version) {
|
|
794
|
+
return this.fromAgentManifest(agentCode, version, extractAgentDisplayName);
|
|
795
|
+
}
|
|
796
|
+
async fromAgentManifest(agentCode, version, extract) {
|
|
772
797
|
if (this.deploymentSnapshot) {
|
|
773
798
|
const snap = await this.deploymentSnapshot.loadAgentSnapshot(agentCode, version);
|
|
774
|
-
if (snap)
|
|
775
|
-
return
|
|
776
|
-
}
|
|
799
|
+
if (snap)
|
|
800
|
+
return extract(snap.manifest);
|
|
777
801
|
if (this.blockRegistryDefinitions)
|
|
778
802
|
return undefined;
|
|
779
803
|
}
|
|
780
804
|
if (this.blockRegistryDefinitions || !this.registryClient)
|
|
781
805
|
return undefined;
|
|
782
806
|
const record = await this.registryClient.getAgent(agentCode);
|
|
783
|
-
return
|
|
807
|
+
return extract(record?.manifest);
|
|
784
808
|
}
|
|
785
809
|
/**
|
|
786
810
|
* 解析 agent tools[] + graph tool 节点 union;
|
|
@@ -11,6 +11,7 @@ import type { ICheckpointSaver } from '../checkpoint/contracts/checkpoint-saver.
|
|
|
11
11
|
import type { ITraceCollector } from '../contracts/trace-collector.js';
|
|
12
12
|
import type { IStateGraphEngine } from '../graph/contracts/state-graph.contract.js';
|
|
13
13
|
import type { TaskTimeoutManager } from '../task/task-timeout.js';
|
|
14
|
+
import { type TaskAbortKind } from '../task/task-abort.js';
|
|
14
15
|
import { HitlHandler } from '../graph/hitl/hitl-handler.js';
|
|
15
16
|
import { type GraphLoader } from '../registry/graph-loader.js';
|
|
16
17
|
import type { SessionContextService } from '../session/session-context.service.js';
|
|
@@ -88,6 +89,12 @@ export interface ConversationDetail {
|
|
|
88
89
|
export declare class AgentRuntime {
|
|
89
90
|
private readonly deps;
|
|
90
91
|
constructor(deps: AgentRuntimeDeps);
|
|
92
|
+
/**
|
|
93
|
+
* 停止这一轮。超时和用户停止共用 timeoutManager 上的那条 AbortSignal。
|
|
94
|
+
* 计时器还没启动时先记下,startTimer 会返回已 abort 的 signal,且不调用 onTimeout。
|
|
95
|
+
* @returns 已 abort 或已记下。没有 timeoutManager 时返回 false。
|
|
96
|
+
*/
|
|
97
|
+
abort(taskId: string, kind?: TaskAbortKind): boolean;
|
|
91
98
|
/** 从 GraphLoader 解析 tool manifest 映射(invoke/stream/resume/fork 共用) */
|
|
92
99
|
private resolveLoadedTools;
|
|
93
100
|
/** 从预装重载 Skill 定义(HITL/Fork 时 ephemeral 字段可能丢失) */
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
10
|
import { DEFAULT_GRAPH_TIMEOUT_MS } from '../common/types.js';
|
|
11
11
|
import { resolveTaskTimeoutMs } from '../task/resolve-task-timeout.js';
|
|
12
|
+
import { taskAbortKindOf } from '../task/task-abort.js';
|
|
12
13
|
import { runWithExecutionTrace } from '../graph/execution-trace-context.js';
|
|
13
14
|
import { HITL_TIMEOUT_ERROR_CODE, HITL_TIMEOUT_MESSAGE, HitlAlreadyTimedOutError, HitlNotWaitingError, buildHitlWaitedPayload, isHitlDeadlinePassed, loadHitlCheckpoint, readPersistedHitlWaiting, unwrapHitlPaused, } from '../graph/hitl/hitl-handler.js';
|
|
14
|
-
import { resolveAgentSystemPromptFromLoader } from '../registry/graph-loader.js';
|
|
15
|
+
import { resolveAgentDisplayNameFromLoader, resolveAgentSystemPromptFromLoader, } from '../registry/graph-loader.js';
|
|
15
16
|
import { toLoadedSkillMap } from '../tool/system-prompt-builder.js';
|
|
16
17
|
import { assembleLoadedTools } from '../tool/harness-primitives.js';
|
|
17
18
|
import { createFileLlmTurnLogFromEnv, } from '../debug/llm-turn-log.js';
|
|
18
|
-
import { buildHitlWaitingTaskOutput, buildTurnTranscriptFromStreamEvents, loadModelFacingHistory, turnGraphMessagesAfterCompression, extractHitlThreadId,
|
|
19
|
+
import { buildHitlWaitingTaskOutput, buildTurnTranscriptFromStreamEvents, loadModelFacingHistory, turnGraphMessagesAfterCompression, extractHitlThreadId, applyStreamReasoningEvent, applyStreamTextDelta, createStreamAssistantBuckets, createStreamReasoningState, resolvedStreamReasoning, visibleStreamAssistantText, streamAssistantTexts, messageRecordsToGraphMessages, persistHitlWaitingPlaceholder, persistTurnTranscript, persistUserTurnMessage, resolveCheckpointThreadId, appendTerminalToolResult, } from '../session/persist-turn-messages.js';
|
|
19
20
|
import { collectPublicArtifactLinks, collectPublicArtifactLinksFromEvent, injectPublicArtifactLinks, mergeArtifactLinks, } from '../tool/inject-public-artifact-links.js';
|
|
20
21
|
import { iterSessionCompression, withCompressionSummaryModel, } from '../session/apply-session-compression.js';
|
|
21
22
|
import { applySessionMemory } from '../session/apply-session-memory.js';
|
|
@@ -33,7 +34,33 @@ const HITL_TERMINAL_STATUSES = [
|
|
|
33
34
|
'failed',
|
|
34
35
|
'timeout',
|
|
35
36
|
'token_exhausted',
|
|
37
|
+
'cancelled',
|
|
36
38
|
];
|
|
39
|
+
const TASK_CANCELLED_SSE_CODE = 'runtime.task.cancelled';
|
|
40
|
+
function taskAbortSseData(kind) {
|
|
41
|
+
if (kind === 'timeout') {
|
|
42
|
+
return {
|
|
43
|
+
code: ErrorCodes.TASK_TIMEOUT,
|
|
44
|
+
message: 'Task execution timed out',
|
|
45
|
+
recoverable: false,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
code: TASK_CANCELLED_SSE_CODE,
|
|
50
|
+
message: 'Task cancelled',
|
|
51
|
+
recoverable: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function settleAbortedTask(taskService, taskId, kind) {
|
|
55
|
+
if (kind === 'timeout') {
|
|
56
|
+
await taskService.tryUpdateStatus(taskId, 'running', 'timeout');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const moved = await taskService.tryUpdateStatus(taskId, 'running', 'cancelled');
|
|
60
|
+
if (!moved) {
|
|
61
|
+
await taskService.tryUpdateStatus(taskId, 'waiting_hitl', 'cancelled');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
37
64
|
const DEFAULT_GRAPH_DSL = {
|
|
38
65
|
name: 'default-graph',
|
|
39
66
|
version: '1.0.0',
|
|
@@ -57,6 +84,17 @@ export class AgentRuntime {
|
|
|
57
84
|
}
|
|
58
85
|
this.deps.hitlHandler.setTraceCollector?.(this.deps.traceCollector);
|
|
59
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* 停止这一轮。超时和用户停止共用 timeoutManager 上的那条 AbortSignal。
|
|
89
|
+
* 计时器还没启动时先记下,startTimer 会返回已 abort 的 signal,且不调用 onTimeout。
|
|
90
|
+
* @returns 已 abort 或已记下。没有 timeoutManager 时返回 false。
|
|
91
|
+
*/
|
|
92
|
+
abort(taskId, kind = 'cancelled') {
|
|
93
|
+
const manager = this.deps.timeoutManager;
|
|
94
|
+
if (!manager || !taskId.trim())
|
|
95
|
+
return false;
|
|
96
|
+
return manager.abort(taskId, kind);
|
|
97
|
+
}
|
|
60
98
|
/** 从 GraphLoader 解析 tool manifest 映射(invoke/stream/resume/fork 共用) */
|
|
61
99
|
async resolveLoadedTools(agentCode, agentVersion) {
|
|
62
100
|
if (!this.deps.graphLoader)
|
|
@@ -330,6 +368,7 @@ export class AgentRuntime {
|
|
|
330
368
|
? (await this.deps.graphLoader.resolveAgentDir(agentCode, params.agentVersion)) ?? undefined
|
|
331
369
|
: undefined;
|
|
332
370
|
const agentSystemPrompt = await resolveAgentSystemPromptFromLoader(this.deps.graphLoader, agentCode, params.agentVersion);
|
|
371
|
+
const agentName = await resolveAgentDisplayNameFromLoader(this.deps.graphLoader, agentCode, params.agentVersion);
|
|
333
372
|
const facing = await loadModelFacingHistory({
|
|
334
373
|
sessionHistory: messageRecordsToGraphMessages(sessionContext.messages),
|
|
335
374
|
checkpointSaver: this.deps.checkpointSaver,
|
|
@@ -375,8 +414,8 @@ export class AgentRuntime {
|
|
|
375
414
|
});
|
|
376
415
|
const startTime = Date.now();
|
|
377
416
|
const assistantBuckets = createStreamAssistantBuckets();
|
|
417
|
+
const reasoningState = createStreamReasoningState();
|
|
378
418
|
let toolCallReasoningContent;
|
|
379
|
-
let assistantReasoningContent;
|
|
380
419
|
const pendingToolCalls = [];
|
|
381
420
|
const toolResults = [];
|
|
382
421
|
const artifactLinks = [];
|
|
@@ -402,6 +441,7 @@ export class AgentRuntime {
|
|
|
402
441
|
promptRoots,
|
|
403
442
|
agentDir,
|
|
404
443
|
agentSystemPrompt,
|
|
444
|
+
agentName,
|
|
405
445
|
skillInput: resolveSkillInputFromInvokeInput(params.input),
|
|
406
446
|
traceId: resolveTraceId(params),
|
|
407
447
|
traceCollector: this.deps.traceCollector,
|
|
@@ -417,16 +457,12 @@ export class AgentRuntime {
|
|
|
417
457
|
arguments: p.arguments ?? {},
|
|
418
458
|
});
|
|
419
459
|
}
|
|
420
|
-
|
|
421
|
-
toolCallReasoningContent = p.reasoningContent;
|
|
422
|
-
}
|
|
460
|
+
toolCallReasoningContent = resolvedStreamReasoning(reasoningState);
|
|
423
461
|
}
|
|
424
462
|
// 终态 tool.result / tool.error 回填历史;willRetry 的 error 不进 transcript
|
|
425
463
|
appendTerminalToolResult(runtimeEvent.type, runtimeEvent.payload, toolResults);
|
|
426
464
|
collectPublicArtifactLinksFromEvent(runtimeEvent.type, runtimeEvent.payload, artifactLinks);
|
|
427
|
-
|
|
428
|
-
if (streamedReasoning)
|
|
429
|
-
assistantReasoningContent = streamedReasoning;
|
|
465
|
+
applyStreamReasoningEvent(reasoningState, runtimeEvent.type, runtimeEvent.payload);
|
|
430
466
|
applyStreamTextDelta(assistantBuckets, runtimeEvent.type, runtimeEvent.payload);
|
|
431
467
|
collectStreamNodeTokenUsage(runtimeEvent, nodeTokenUsages);
|
|
432
468
|
if (shouldEmitTokenSse(tokenDetail, runtimeEvent.type)) {
|
|
@@ -460,7 +496,7 @@ export class AgentRuntime {
|
|
|
460
496
|
assistantText: injected,
|
|
461
497
|
finishPoints: graph.finishPoints,
|
|
462
498
|
toolCallReasoningContent,
|
|
463
|
-
assistantReasoningContent,
|
|
499
|
+
assistantReasoningContent: resolvedStreamReasoning(reasoningState),
|
|
464
500
|
}),
|
|
465
501
|
assistantTokenCount: tokenSummary.total.output,
|
|
466
502
|
assistantDurationMs: Date.now() - startTime,
|
|
@@ -493,15 +529,11 @@ export class AgentRuntime {
|
|
|
493
529
|
yield this.toSSE('hitl.waited', correlationId, task.id, buildHitlWaitedPayload(hitlPaused));
|
|
494
530
|
return;
|
|
495
531
|
}
|
|
496
|
-
const
|
|
497
|
-
if (
|
|
532
|
+
const abortKind = taskAbortKindOf(err, abortSignal);
|
|
533
|
+
if (abortKind) {
|
|
498
534
|
await recordTaskTokenUsages(this.deps.taskService, task.id, nodeTokenUsages);
|
|
499
|
-
await this.deps.taskService
|
|
500
|
-
yield this.toSSE('task.error', correlationId, task.id,
|
|
501
|
-
code: ErrorCodes.TASK_TIMEOUT,
|
|
502
|
-
message: 'Task execution timed out',
|
|
503
|
-
recoverable: false,
|
|
504
|
-
});
|
|
535
|
+
await settleAbortedTask(this.deps.taskService, task.id, abortKind);
|
|
536
|
+
yield this.toSSE('task.error', correlationId, task.id, taskAbortSseData(abortKind));
|
|
505
537
|
return;
|
|
506
538
|
}
|
|
507
539
|
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
@@ -617,6 +649,9 @@ export class AgentRuntime {
|
|
|
617
649
|
agentSystemPrompt: (await resolveAgentSystemPromptFromLoader(this.deps.graphLoader, agentCode, agentVersion)) ?? (typeof resumedState.agentSystemPrompt === 'string'
|
|
618
650
|
? resumedState.agentSystemPrompt
|
|
619
651
|
: undefined),
|
|
652
|
+
agentName: (await resolveAgentDisplayNameFromLoader(this.deps.graphLoader, agentCode, agentVersion)) ?? (typeof resumedState.agentName === 'string' && resumedState.agentName.trim()
|
|
653
|
+
? resumedState.agentName.trim()
|
|
654
|
+
: undefined),
|
|
620
655
|
activatedSkill: resumedState.activatedSkill,
|
|
621
656
|
skillRoute: resumedState.skillRoute ??
|
|
622
657
|
(typeof resumedState.activatedSkill === 'string' && resumedState.activatedSkill
|
|
@@ -633,8 +668,8 @@ export class AgentRuntime {
|
|
|
633
668
|
};
|
|
634
669
|
const startTime = Date.now();
|
|
635
670
|
const assistantBuckets = createStreamAssistantBuckets();
|
|
671
|
+
const reasoningState = createStreamReasoningState();
|
|
636
672
|
let toolCallReasoningContent;
|
|
637
|
-
let assistantReasoningContent;
|
|
638
673
|
const pendingToolCalls = [];
|
|
639
674
|
const toolResults = [];
|
|
640
675
|
const artifactLinks = [];
|
|
@@ -650,15 +685,11 @@ export class AgentRuntime {
|
|
|
650
685
|
arguments: p.arguments ?? {},
|
|
651
686
|
});
|
|
652
687
|
}
|
|
653
|
-
|
|
654
|
-
toolCallReasoningContent = p.reasoningContent;
|
|
655
|
-
}
|
|
688
|
+
toolCallReasoningContent = resolvedStreamReasoning(reasoningState);
|
|
656
689
|
}
|
|
657
690
|
appendTerminalToolResult(runtimeEvent.type, runtimeEvent.payload, toolResults);
|
|
658
691
|
collectPublicArtifactLinksFromEvent(runtimeEvent.type, runtimeEvent.payload, artifactLinks);
|
|
659
|
-
|
|
660
|
-
if (streamedReasoning)
|
|
661
|
-
assistantReasoningContent = streamedReasoning;
|
|
692
|
+
applyStreamReasoningEvent(reasoningState, runtimeEvent.type, runtimeEvent.payload);
|
|
662
693
|
applyStreamTextDelta(assistantBuckets, runtimeEvent.type, runtimeEvent.payload);
|
|
663
694
|
collectStreamNodeTokenUsage(runtimeEvent, nodeTokenUsages);
|
|
664
695
|
if (shouldEmitTokenSse(tokenDetail, runtimeEvent.type)) {
|
|
@@ -693,7 +724,7 @@ export class AgentRuntime {
|
|
|
693
724
|
assistantText: injected,
|
|
694
725
|
finishPoints: graph.finishPoints,
|
|
695
726
|
toolCallReasoningContent,
|
|
696
|
-
assistantReasoningContent,
|
|
727
|
+
assistantReasoningContent: resolvedStreamReasoning(reasoningState),
|
|
697
728
|
}),
|
|
698
729
|
assistantTokenCount: tokenSummary.total.output,
|
|
699
730
|
assistantDurationMs: Date.now() - startTime,
|
|
@@ -729,15 +760,11 @@ export class AgentRuntime {
|
|
|
729
760
|
yield this.toSSE('hitl.waited', correlationId, taskId, buildHitlWaitedPayload(hitlPaused));
|
|
730
761
|
return;
|
|
731
762
|
}
|
|
732
|
-
const
|
|
733
|
-
if (
|
|
763
|
+
const abortKind = taskAbortKindOf(err, abortSignal);
|
|
764
|
+
if (abortKind) {
|
|
734
765
|
await recordTaskTokenUsages(this.deps.taskService, taskId, nodeTokenUsages);
|
|
735
|
-
await this.deps.taskService
|
|
736
|
-
yield this.toSSE('task.error', correlationId, taskId,
|
|
737
|
-
code: ErrorCodes.TASK_TIMEOUT,
|
|
738
|
-
message: 'Task execution timed out',
|
|
739
|
-
recoverable: false,
|
|
740
|
-
});
|
|
766
|
+
await settleAbortedTask(this.deps.taskService, taskId, abortKind);
|
|
767
|
+
yield this.toSSE('task.error', correlationId, taskId, taskAbortSseData(abortKind));
|
|
741
768
|
return;
|
|
742
769
|
}
|
|
743
770
|
const appErr = err instanceof AppError ? err : AppError.fromUnknown(err);
|
|
@@ -814,6 +841,9 @@ export class AgentRuntime {
|
|
|
814
841
|
const agentSystemPrompt = (await resolveAgentSystemPromptFromLoader(this.deps.graphLoader, agentCode, agentVersion)) ?? (typeof forkedCheckpoint.state.agentSystemPrompt === 'string'
|
|
815
842
|
? forkedCheckpoint.state.agentSystemPrompt
|
|
816
843
|
: undefined);
|
|
844
|
+
const agentName = (await resolveAgentDisplayNameFromLoader(this.deps.graphLoader, agentCode, agentVersion)) ?? (typeof forkedCheckpoint.state.agentName === 'string' && forkedCheckpoint.state.agentName.trim()
|
|
845
|
+
? forkedCheckpoint.state.agentName.trim()
|
|
846
|
+
: undefined);
|
|
817
847
|
const abortDeadlineMs = Date.now() + timeout;
|
|
818
848
|
try {
|
|
819
849
|
const forkState = { ...forkedCheckpoint.state };
|
|
@@ -827,6 +857,7 @@ export class AgentRuntime {
|
|
|
827
857
|
agentVersion,
|
|
828
858
|
agentDir,
|
|
829
859
|
agentSystemPrompt,
|
|
860
|
+
agentName,
|
|
830
861
|
userId,
|
|
831
862
|
delegationToken: overrides.executionContext?.delegationToken,
|
|
832
863
|
executionContext: overrides.executionContext,
|
|
@@ -896,15 +927,15 @@ export class AgentRuntime {
|
|
|
896
927
|
await recordTaskTokenUsages(this.deps.taskService, task.id, usages);
|
|
897
928
|
const input_tokens = usages.reduce((sum, row) => sum + row.inputTokens, 0);
|
|
898
929
|
const output_tokens = usages.reduce((sum, row) => sum + row.outputTokens, 0);
|
|
899
|
-
const
|
|
900
|
-
if (
|
|
901
|
-
await this.deps.taskService
|
|
930
|
+
const abortKind = taskAbortKindOf(err, abortSignal);
|
|
931
|
+
if (abortKind) {
|
|
932
|
+
await settleAbortedTask(this.deps.taskService, task.id, abortKind);
|
|
902
933
|
return {
|
|
903
934
|
newTraceId: traceId,
|
|
904
935
|
originalTraceId,
|
|
905
936
|
newTaskId: task.id,
|
|
906
937
|
checkpointId,
|
|
907
|
-
status: 'timeout',
|
|
938
|
+
status: abortKind === 'timeout' ? 'timeout' : 'cancelled',
|
|
908
939
|
output: message,
|
|
909
940
|
tokenUsage: {
|
|
910
941
|
input_tokens,
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -91,7 +91,7 @@ export interface ForkResult {
|
|
|
91
91
|
originalTraceId: string;
|
|
92
92
|
newTaskId: string;
|
|
93
93
|
checkpointId: string;
|
|
94
|
-
status: 'completed' | 'failed' | 'timeout';
|
|
94
|
+
status: 'completed' | 'failed' | 'timeout' | 'cancelled';
|
|
95
95
|
output: unknown;
|
|
96
96
|
tokenUsage: {
|
|
97
97
|
input_tokens: number;
|