@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
|
@@ -85,10 +85,18 @@ export declare function sessionVisibleAssistantTexts(texts: Array<{
|
|
|
85
85
|
*/
|
|
86
86
|
export declare function sessionVisibleGraphMessages(messages: GraphMessage[], finishPoints?: string[]): GraphMessage[];
|
|
87
87
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
88
|
+
* 从流式事件抽取本事件上的思考字符串。
|
|
89
|
+
* 认 reasoning.completed / reasoning.chunk 的 content,以及 skill.completed 的 reasoningContent。
|
|
90
90
|
*/
|
|
91
91
|
export declare function extractStreamReasoning(eventType: string, payload: unknown): string | undefined;
|
|
92
|
+
/** 本回合思考累加:started 清空;completed 优先,没有 completed 时拼接 chunk */
|
|
93
|
+
export type StreamReasoningState = {
|
|
94
|
+
chunkFallback: string;
|
|
95
|
+
lastCompleted?: string;
|
|
96
|
+
};
|
|
97
|
+
export declare function createStreamReasoningState(): StreamReasoningState;
|
|
98
|
+
export declare function applyStreamReasoningEvent(state: StreamReasoningState, eventType: string, payload: unknown): void;
|
|
99
|
+
export declare function resolvedStreamReasoning(state: StreamReasoningState): string | undefined;
|
|
92
100
|
/** 落盘 / 回填历史只收终态:result,或不会再试的 error。willRetry 的 error 只给直播 UI。 */
|
|
93
101
|
export declare function isTerminalToolStreamEvent(eventType: string, payload: unknown): boolean;
|
|
94
102
|
export declare function appendTerminalToolResult(eventType: string, payload: unknown, bucket: StreamToolResult[]): void;
|
|
@@ -202,20 +202,45 @@ export function sessionVisibleGraphMessages(messages, finishPoints) {
|
|
|
202
202
|
return out;
|
|
203
203
|
}
|
|
204
204
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
205
|
+
* 从流式事件抽取本事件上的思考字符串。
|
|
206
|
+
* 认 reasoning.completed / reasoning.chunk 的 content,以及 skill.completed 的 reasoningContent。
|
|
207
207
|
*/
|
|
208
208
|
export function extractStreamReasoning(eventType, payload) {
|
|
209
|
-
if (eventType !== 'response.chunk' &&
|
|
210
|
-
eventType !== 'response.delta' &&
|
|
211
|
-
eventType !== 'response.final' &&
|
|
212
|
-
eventType !== 'skill.completed') {
|
|
213
|
-
return undefined;
|
|
214
|
-
}
|
|
215
209
|
if (!payload || typeof payload !== 'object')
|
|
216
210
|
return undefined;
|
|
217
|
-
const
|
|
218
|
-
|
|
211
|
+
const p = payload;
|
|
212
|
+
if (eventType === 'reasoning.chunk' || eventType === 'reasoning.completed') {
|
|
213
|
+
return typeof p.content === 'string' && p.content ? p.content : undefined;
|
|
214
|
+
}
|
|
215
|
+
if (eventType === 'skill.completed') {
|
|
216
|
+
return typeof p.reasoningContent === 'string' && p.reasoningContent
|
|
217
|
+
? p.reasoningContent
|
|
218
|
+
: undefined;
|
|
219
|
+
}
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
export function createStreamReasoningState() {
|
|
223
|
+
return { chunkFallback: '' };
|
|
224
|
+
}
|
|
225
|
+
export function applyStreamReasoningEvent(state, eventType, payload) {
|
|
226
|
+
if (eventType === 'reasoning.started') {
|
|
227
|
+
state.chunkFallback = '';
|
|
228
|
+
state.lastCompleted = undefined;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const text = extractStreamReasoning(eventType, payload);
|
|
232
|
+
if (!text)
|
|
233
|
+
return;
|
|
234
|
+
if (eventType === 'reasoning.chunk') {
|
|
235
|
+
state.chunkFallback += text;
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
state.lastCompleted = text;
|
|
239
|
+
}
|
|
240
|
+
export function resolvedStreamReasoning(state) {
|
|
241
|
+
if (state.lastCompleted)
|
|
242
|
+
return state.lastCompleted;
|
|
243
|
+
return state.chunkFallback ? state.chunkFallback : undefined;
|
|
219
244
|
}
|
|
220
245
|
/** 落盘 / 回填历史只收终态:result,或不会再试的 error。willRetry 的 error 只给直播 UI。 */
|
|
221
246
|
export function isTerminalToolStreamEvent(eventType, payload) {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - 时态:过去式(started/completed)或名词(final/heartbeat)
|
|
11
11
|
*
|
|
12
12
|
* 分层设计:
|
|
13
|
-
* - 核心事件(
|
|
13
|
+
* - 核心事件(16 种):所有 Agent 必须支持
|
|
14
14
|
* - 可选事件:Agent 按需支持
|
|
15
15
|
*
|
|
16
16
|
* @see design.md §1.6 SSE事件协议定义
|
|
@@ -36,7 +36,7 @@ export type SseEventLevel = 'core' | 'optional';
|
|
|
36
36
|
/**
|
|
37
37
|
* 核心事件类型(所有 Agent 必须支持)
|
|
38
38
|
*/
|
|
39
|
-
export declare const CORE_SSE_EVENTS: readonly ["session.created", "task.started", "task.completed", "task.error", "reasoning.started", "response.chunk", "tool.called", "tool.result", "tool.error", "hitl.waited", "hitl.resumed", "response.final", "stats.token_usage", "connection.heartbeat"];
|
|
39
|
+
export declare const CORE_SSE_EVENTS: readonly ["session.created", "task.started", "task.completed", "task.error", "reasoning.started", "reasoning.chunk", "reasoning.completed", "response.chunk", "tool.called", "tool.result", "tool.error", "hitl.waited", "hitl.resumed", "response.final", "stats.token_usage", "connection.heartbeat"];
|
|
40
40
|
/**
|
|
41
41
|
* 可选事件类型(Agent 按需支持)
|
|
42
42
|
*/
|
|
@@ -44,10 +44,10 @@ export declare const OPTIONAL_SSE_EVENTS: readonly ["skill.matched", "skill.unma
|
|
|
44
44
|
/**
|
|
45
45
|
* SSEEventType — SSE 事件类型字符串联合类型
|
|
46
46
|
*/
|
|
47
|
-
export type SSEEventType = 'session.created' | 'task.started' | 'task.completed' | 'task.error' | 'reasoning.started' | 'response.chunk' | 'tool.called' | 'tool.result' | 'tool.error' | 'hitl.waited' | 'hitl.resumed' | 'response.final' | 'stats.token_usage' | 'connection.heartbeat' | 'skill.matched' | 'skill.unmatched' | 'skill.started' | 'skill.completed' | 'skill.failed' | 'skill.loaded' | 'skill.resource_read' | 'reasoning.step' | 'tool.progress' | 'file.created' | 'file.updated' | 'code.executed' | 'collaboration.handed_off' | 'collaboration.subtask.started' | 'collaboration.subtask.completed' | 'plan.created' | 'plan.step.started' | 'plan.step.completed' | 'response.max_iterations_reached' | 'stats.node_token_usage' | 'session.compression.started' | 'session.compression.completed' | 'rag.round' | 'rag.search' | 'rag.denoise' | 'rag.rewrite' | 'rag.finish';
|
|
47
|
+
export type SSEEventType = 'session.created' | 'task.started' | 'task.completed' | 'task.error' | 'reasoning.started' | 'reasoning.chunk' | 'reasoning.completed' | 'response.chunk' | 'tool.called' | 'tool.result' | 'tool.error' | 'hitl.waited' | 'hitl.resumed' | 'response.final' | 'stats.token_usage' | 'connection.heartbeat' | 'skill.matched' | 'skill.unmatched' | 'skill.started' | 'skill.completed' | 'skill.failed' | 'skill.loaded' | 'skill.resource_read' | 'reasoning.step' | 'tool.progress' | 'file.created' | 'file.updated' | 'code.executed' | 'collaboration.handed_off' | 'collaboration.subtask.started' | 'collaboration.subtask.completed' | 'plan.created' | 'plan.step.started' | 'plan.step.completed' | 'response.max_iterations_reached' | 'stats.node_token_usage' | 'session.compression.started' | 'session.compression.completed' | 'rag.round' | 'rag.search' | 'rag.denoise' | 'rag.rewrite' | 'rag.finish';
|
|
48
48
|
import type { SessionCreatedPayload, TaskStartedPayload, TaskCompletedPayload, TaskErrorPayload, SessionCompressionStartedPayload, SessionCompressionCompletedPayload } from './session-events.js';
|
|
49
49
|
import type { SkillMatchedPayload, SkillUnmatchedPayload, SkillStartedPayload, SkillCompletedPayload, SkillFailedPayload, SkillLoadedPayload, SkillResourceReadPayload } from './skill-events.js';
|
|
50
|
-
import type { ReasoningStartedPayload, ReasoningStepPayload, ResponseChunkPayload } from './reasoning-events.js';
|
|
50
|
+
import type { ReasoningStartedPayload, ReasoningChunkPayload, ReasoningCompletedPayload, ReasoningStepPayload, ResponseChunkPayload } from './reasoning-events.js';
|
|
51
51
|
import type { ToolCalledPayload, ToolResultPayload, ToolProgressPayload, ToolErrorPayload } from './tool-events.js';
|
|
52
52
|
import type { FileCreatedPayload, FileUpdatedPayload } from './file-events.js';
|
|
53
53
|
import type { CodeExecutedPayload } from './code-events.js';
|
|
@@ -67,6 +67,8 @@ export interface SSEEventPayloadMap {
|
|
|
67
67
|
'task.completed': TaskCompletedPayload;
|
|
68
68
|
'task.error': TaskErrorPayload;
|
|
69
69
|
'reasoning.started': ReasoningStartedPayload;
|
|
70
|
+
'reasoning.chunk': ReasoningChunkPayload;
|
|
71
|
+
'reasoning.completed': ReasoningCompletedPayload;
|
|
70
72
|
'response.chunk': ResponseChunkPayload;
|
|
71
73
|
'tool.called': ToolCalledPayload;
|
|
72
74
|
'tool.result': ToolResultPayload;
|
package/dist/sse/events/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - 时态:过去式(started/completed)或名词(final/heartbeat)
|
|
11
11
|
*
|
|
12
12
|
* 分层设计:
|
|
13
|
-
* - 核心事件(
|
|
13
|
+
* - 核心事件(16 种):所有 Agent 必须支持
|
|
14
14
|
* - 可选事件:Agent 按需支持
|
|
15
15
|
*
|
|
16
16
|
* @see design.md §1.6 SSE事件协议定义
|
|
@@ -41,6 +41,8 @@ export const CORE_SSE_EVENTS = [
|
|
|
41
41
|
'task.completed',
|
|
42
42
|
'task.error',
|
|
43
43
|
'reasoning.started',
|
|
44
|
+
'reasoning.chunk',
|
|
45
|
+
'reasoning.completed',
|
|
44
46
|
'response.chunk',
|
|
45
47
|
'tool.called',
|
|
46
48
|
'tool.result',
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 核心事件:
|
|
5
5
|
* - reasoning.started
|
|
6
|
+
* - reasoning.chunk
|
|
7
|
+
* - reasoning.completed
|
|
6
8
|
* - response.chunk
|
|
7
9
|
*
|
|
8
10
|
* 可选事件:
|
|
9
|
-
* - reasoning.step
|
|
11
|
+
* - reasoning.step(ReAct thought/plan,不是模型 CoT)
|
|
10
12
|
*
|
|
11
13
|
* @see design.md §1.6 SSE事件协议定义
|
|
12
14
|
*/
|
|
@@ -17,7 +19,27 @@ export interface ReasoningStartedPayload {
|
|
|
17
19
|
/** 使用的模型名称(可选;未知时可省略) */
|
|
18
20
|
model?: string;
|
|
19
21
|
}
|
|
20
|
-
/**
|
|
22
|
+
/** 思考增量(与 response.chunk 对称;空增量不发) */
|
|
23
|
+
export interface ReasoningChunkPayload {
|
|
24
|
+
/** 思考片段 */
|
|
25
|
+
content: string;
|
|
26
|
+
/** 片段序号(本轮从 0 开始,与 response.chunk 分开计) */
|
|
27
|
+
index: number;
|
|
28
|
+
/** 发出该增量的 LLM 节点 */
|
|
29
|
+
node?: string;
|
|
30
|
+
/** 所属图 */
|
|
31
|
+
graphId?: string;
|
|
32
|
+
}
|
|
33
|
+
/** 本轮思考全文(有思考才发) */
|
|
34
|
+
export interface ReasoningCompletedPayload {
|
|
35
|
+
/** 本轮思考全文 */
|
|
36
|
+
content: string;
|
|
37
|
+
/** 发出该全文的 LLM 节点 */
|
|
38
|
+
node?: string;
|
|
39
|
+
/** 所属图 */
|
|
40
|
+
graphId?: string;
|
|
41
|
+
}
|
|
42
|
+
/** 推理中间步骤(ReAct thought/plan,不是模型 CoT) */
|
|
21
43
|
export interface ReasoningStepPayload {
|
|
22
44
|
/** 步骤序号 */
|
|
23
45
|
step: number;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Task Manager Contract — 任务生命周期管理接口
|
|
3
3
|
*
|
|
4
4
|
* 定义 Task 的创建、状态流转、查询、Token 消耗记录等核心操作。
|
|
5
|
-
* 状态流转:pending → running → success/failed/timeout/token_exhausted
|
|
5
|
+
* 状态流转:pending → running → success/failed/timeout/token_exhausted/cancelled
|
|
6
6
|
*
|
|
7
7
|
* @see design.md §1.3 数据模型 — tasks 表
|
|
8
8
|
* @see requirements.md Requirement 7 AC1-AC5
|
|
@@ -126,7 +126,7 @@ export interface ITaskManager {
|
|
|
126
126
|
/**
|
|
127
127
|
* 更新 Task 状态
|
|
128
128
|
*
|
|
129
|
-
* 合法流转:pending→running, running→success/failed/timeout/token_exhausted
|
|
129
|
+
* 合法流转:pending→running|cancelled, running→success/failed/timeout/token_exhausted/cancelled/waiting_hitl
|
|
130
130
|
*
|
|
131
131
|
* @param taskId - Task ID
|
|
132
132
|
* @param status - 目标状态
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Task Manager Contract — 任务生命周期管理接口
|
|
3
3
|
*
|
|
4
4
|
* 定义 Task 的创建、状态流转、查询、Token 消耗记录等核心操作。
|
|
5
|
-
* 状态流转:pending → running → success/failed/timeout/token_exhausted
|
|
5
|
+
* 状态流转:pending → running → success/failed/timeout/token_exhausted/cancelled
|
|
6
6
|
*
|
|
7
7
|
* @see design.md §1.3 数据模型 — tasks 表
|
|
8
8
|
* @see requirements.md Requirement 7 AC1-AC5
|
package/dist/task/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { TaskService, InMemoryTaskRepository } from './task.service.js';
|
|
|
3
3
|
export type { ITaskRepository } from './task.service.js';
|
|
4
4
|
export { TaskTimeoutManager } from './task-timeout.js';
|
|
5
5
|
export type { TaskTimeoutManagerOptions } from './task-timeout.js';
|
|
6
|
+
export { TaskAbortError, taskAbortKind, taskAbortKindOf, TASK_CANCELLED_MESSAGE } from './task-abort.js';
|
|
7
|
+
export type { TaskAbortKind } from './task-abort.js';
|
|
6
8
|
export { resolveTaskTimeoutMs } from './resolve-task-timeout.js';
|
|
7
9
|
export { TaskProgressTracker } from './task-progress-tracker.js';
|
|
8
10
|
export type { TaskProgressInfo } from './task-progress-tracker.js';
|
package/dist/task/index.js
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
export * from './contracts/index.js';
|
|
3
3
|
export { TaskService, InMemoryTaskRepository } from './task.service.js';
|
|
4
4
|
export { TaskTimeoutManager } from './task-timeout.js';
|
|
5
|
+
export { TaskAbortError, taskAbortKind, taskAbortKindOf, TASK_CANCELLED_MESSAGE } from './task-abort.js';
|
|
5
6
|
export { resolveTaskTimeoutMs } from './resolve-task-timeout.js';
|
|
6
7
|
export { TaskProgressTracker } from './task-progress-tracker.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一次 Task 一条 AbortSignal。超时和用户停止都 abort 它,用 kind 区分。
|
|
3
|
+
* name 固定 AbortError,节点重试会跳过。
|
|
4
|
+
*/
|
|
5
|
+
export type TaskAbortKind = 'timeout' | 'cancelled';
|
|
6
|
+
export declare const TASK_CANCELLED_MESSAGE = "Task cancelled";
|
|
7
|
+
export declare class TaskAbortError extends Error {
|
|
8
|
+
readonly kind: TaskAbortKind;
|
|
9
|
+
readonly taskId: string;
|
|
10
|
+
constructor(taskId: string, kind: TaskAbortKind, timeoutMs?: number);
|
|
11
|
+
}
|
|
12
|
+
export declare function taskAbortKind(err: unknown): TaskAbortKind | undefined;
|
|
13
|
+
/** 图把 AbortError 包了一层时,回看这一轮 signal 上的 reason。 */
|
|
14
|
+
export declare function taskAbortKindOf(err: unknown, signal?: AbortSignal): TaskAbortKind | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一次 Task 一条 AbortSignal。超时和用户停止都 abort 它,用 kind 区分。
|
|
3
|
+
* name 固定 AbortError,节点重试会跳过。
|
|
4
|
+
*/
|
|
5
|
+
export const TASK_CANCELLED_MESSAGE = 'Task cancelled';
|
|
6
|
+
export class TaskAbortError extends Error {
|
|
7
|
+
kind;
|
|
8
|
+
taskId;
|
|
9
|
+
constructor(taskId, kind, timeoutMs) {
|
|
10
|
+
const message = kind === 'timeout'
|
|
11
|
+
? `Task '${taskId}' timed out after ${timeoutMs ?? 0}ms`
|
|
12
|
+
: `Task '${taskId}' cancelled`;
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'AbortError';
|
|
15
|
+
this.kind = kind;
|
|
16
|
+
this.taskId = taskId;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function taskAbortKind(err) {
|
|
20
|
+
if (err instanceof TaskAbortError)
|
|
21
|
+
return err.kind;
|
|
22
|
+
if (!(err instanceof Error))
|
|
23
|
+
return undefined;
|
|
24
|
+
if (/timed out/i.test(err.message))
|
|
25
|
+
return 'timeout';
|
|
26
|
+
if (err.name === 'AbortError' && /cancell?ed/i.test(err.message))
|
|
27
|
+
return 'cancelled';
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/** 图把 AbortError 包了一层时,回看这一轮 signal 上的 reason。 */
|
|
31
|
+
export function taskAbortKindOf(err, signal) {
|
|
32
|
+
return taskAbortKind(err) ?? (signal?.aborted ? taskAbortKind(signal.reason) : undefined);
|
|
33
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* @see design.md §1.1 任务管理 — Task级超时
|
|
10
10
|
* @see requirements.md Requirement 7 AC4
|
|
11
11
|
*/
|
|
12
|
+
import { type TaskAbortKind } from './task-abort.js';
|
|
12
13
|
/**
|
|
13
14
|
* TaskTimeoutManager 配置选项
|
|
14
15
|
*/
|
|
@@ -27,6 +28,11 @@ export interface TaskTimeoutManagerOptions {
|
|
|
27
28
|
*/
|
|
28
29
|
export declare class TaskTimeoutManager {
|
|
29
30
|
private readonly entries;
|
|
31
|
+
/**
|
|
32
|
+
* startTimer 之前到达的停止。startTimer 消费后返回已 abort 的 signal,且不调用 onTimeout。
|
|
33
|
+
* clearTimer 只在计时器已经启动时清掉残留,避免把还没被 startTimer 看到的停止丢掉。
|
|
34
|
+
*/
|
|
35
|
+
private readonly pendingAborts;
|
|
30
36
|
private readonly defaultTimeoutMs;
|
|
31
37
|
constructor(options?: TaskTimeoutManagerOptions);
|
|
32
38
|
/**
|
|
@@ -39,6 +45,11 @@ export declare class TaskTimeoutManager {
|
|
|
39
45
|
* @throws 如果该 taskId 已存在活跃计时器
|
|
40
46
|
*/
|
|
41
47
|
startTimer(taskId: string, timeoutMs: number | undefined, onTimeout: () => Promise<void>): AbortSignal;
|
|
48
|
+
/**
|
|
49
|
+
* 停止这一轮。清掉计时器,不调用 onTimeout。
|
|
50
|
+
* 计时器还没启动时记下 kind,等 startTimer 返回已 abort 的 signal。
|
|
51
|
+
*/
|
|
52
|
+
abort(taskId: string, kind?: TaskAbortKind): boolean;
|
|
42
53
|
/**
|
|
43
54
|
* 取消超时计时器(Task 正常完成时调用)
|
|
44
55
|
*
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* @see requirements.md Requirement 7 AC4
|
|
11
11
|
*/
|
|
12
12
|
import { DEFAULT_GRAPH_TIMEOUT_MS } from '../common/types.js';
|
|
13
|
+
import { TaskAbortError } from './task-abort.js';
|
|
13
14
|
// ─────────────────────────────────────────────
|
|
14
15
|
// Default Constants
|
|
15
16
|
// ─────────────────────────────────────────────
|
|
@@ -31,6 +32,11 @@ const MAX_TIMEOUT_MS = 3_600_000;
|
|
|
31
32
|
*/
|
|
32
33
|
export class TaskTimeoutManager {
|
|
33
34
|
entries = new Map();
|
|
35
|
+
/**
|
|
36
|
+
* startTimer 之前到达的停止。startTimer 消费后返回已 abort 的 signal,且不调用 onTimeout。
|
|
37
|
+
* clearTimer 只在计时器已经启动时清掉残留,避免把还没被 startTimer 看到的停止丢掉。
|
|
38
|
+
*/
|
|
39
|
+
pendingAborts = new Map();
|
|
34
40
|
defaultTimeoutMs;
|
|
35
41
|
constructor(options) {
|
|
36
42
|
this.defaultTimeoutMs = options?.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
@@ -49,12 +55,22 @@ export class TaskTimeoutManager {
|
|
|
49
55
|
throw new Error(`Timeout timer already exists for task '${taskId}'. Call clearTimer() first.`);
|
|
50
56
|
}
|
|
51
57
|
const effectiveTimeout = Math.min(Math.max(timeoutMs ?? this.defaultTimeoutMs, 0), MAX_TIMEOUT_MS);
|
|
58
|
+
const pendingKind = this.pendingAborts.get(taskId);
|
|
59
|
+
if (pendingKind) {
|
|
60
|
+
this.pendingAborts.delete(taskId);
|
|
61
|
+
const already = new AbortController();
|
|
62
|
+
already.abort(new TaskAbortError(taskId, pendingKind, effectiveTimeout));
|
|
63
|
+
return already.signal;
|
|
64
|
+
}
|
|
52
65
|
const abortController = new AbortController();
|
|
53
66
|
const timer = setTimeout(() => {
|
|
54
|
-
//
|
|
55
|
-
|
|
67
|
+
// abort() 已取走条目时不再标 timeout
|
|
68
|
+
if (!this.entries.has(taskId))
|
|
69
|
+
return;
|
|
56
70
|
this.entries.delete(taskId);
|
|
57
|
-
|
|
71
|
+
if (!abortController.signal.aborted) {
|
|
72
|
+
abortController.abort(new TaskAbortError(taskId, 'timeout', effectiveTimeout));
|
|
73
|
+
}
|
|
58
74
|
void onTimeout().catch(() => {
|
|
59
75
|
// onTimeout 回调的错误由调用方处理,这里静默忽略
|
|
60
76
|
});
|
|
@@ -63,9 +79,27 @@ export class TaskTimeoutManager {
|
|
|
63
79
|
if (timer.unref) {
|
|
64
80
|
timer.unref();
|
|
65
81
|
}
|
|
66
|
-
this.entries.set(taskId, { timer, abortController });
|
|
82
|
+
this.entries.set(taskId, { timer, abortController, timeoutMs: effectiveTimeout });
|
|
67
83
|
return abortController.signal;
|
|
68
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* 停止这一轮。清掉计时器,不调用 onTimeout。
|
|
87
|
+
* 计时器还没启动时记下 kind,等 startTimer 返回已 abort 的 signal。
|
|
88
|
+
*/
|
|
89
|
+
abort(taskId, kind = 'cancelled') {
|
|
90
|
+
this.pendingAborts.delete(taskId);
|
|
91
|
+
const entry = this.entries.get(taskId);
|
|
92
|
+
if (!entry) {
|
|
93
|
+
this.pendingAborts.set(taskId, kind);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
clearTimeout(entry.timer);
|
|
97
|
+
this.entries.delete(taskId);
|
|
98
|
+
if (!entry.abortController.signal.aborted) {
|
|
99
|
+
entry.abortController.abort(new TaskAbortError(taskId, kind, entry.timeoutMs));
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
69
103
|
/**
|
|
70
104
|
* 取消超时计时器(Task 正常完成时调用)
|
|
71
105
|
*
|
|
@@ -79,6 +113,7 @@ export class TaskTimeoutManager {
|
|
|
79
113
|
}
|
|
80
114
|
clearTimeout(entry.timer);
|
|
81
115
|
this.entries.delete(taskId);
|
|
116
|
+
this.pendingAborts.delete(taskId);
|
|
82
117
|
return true;
|
|
83
118
|
}
|
|
84
119
|
/**
|
|
@@ -113,5 +148,6 @@ export class TaskTimeoutManager {
|
|
|
113
148
|
entry.abortController.abort(new Error(`TaskTimeoutManager disposed, task '${taskId}' aborted`));
|
|
114
149
|
}
|
|
115
150
|
this.entries.clear();
|
|
151
|
+
this.pendingAborts.clear();
|
|
116
152
|
}
|
|
117
153
|
}
|
|
@@ -16,16 +16,17 @@ import { TaskProgressTracker } from './task-progress-tracker.js';
|
|
|
16
16
|
* 合法状态流转映射
|
|
17
17
|
*
|
|
18
18
|
* pending → running
|
|
19
|
-
* running → success | failed | timeout | token_exhausted
|
|
19
|
+
* running → success | failed | timeout | token_exhausted | cancelled | waiting_hitl
|
|
20
20
|
*/
|
|
21
21
|
const VALID_TRANSITIONS = {
|
|
22
|
-
pending: ['running'],
|
|
23
|
-
running: ['success', 'failed', 'timeout', 'token_exhausted', 'waiting_hitl'],
|
|
24
|
-
waiting_hitl: ['running', 'timeout', 'failed'],
|
|
22
|
+
pending: ['running', 'cancelled'],
|
|
23
|
+
running: ['success', 'failed', 'timeout', 'token_exhausted', 'cancelled', 'waiting_hitl'],
|
|
24
|
+
waiting_hitl: ['running', 'timeout', 'failed', 'cancelled'],
|
|
25
25
|
success: [],
|
|
26
26
|
failed: [],
|
|
27
27
|
timeout: [],
|
|
28
28
|
token_exhausted: [],
|
|
29
|
+
cancelled: [],
|
|
29
30
|
};
|
|
30
31
|
// ─────────────────────────────────────────────
|
|
31
32
|
// In-Memory Repository (Default)
|
|
@@ -128,7 +129,11 @@ export class TaskService {
|
|
|
128
129
|
if (status === 'waiting_hitl' && output !== undefined) {
|
|
129
130
|
task.output = output;
|
|
130
131
|
}
|
|
131
|
-
if (status === 'success' ||
|
|
132
|
+
if (status === 'success' ||
|
|
133
|
+
status === 'failed' ||
|
|
134
|
+
status === 'timeout' ||
|
|
135
|
+
status === 'token_exhausted' ||
|
|
136
|
+
status === 'cancelled') {
|
|
132
137
|
task.completedAt = now;
|
|
133
138
|
if (output !== undefined) {
|
|
134
139
|
task.output = output;
|
|
@@ -215,6 +220,7 @@ export class TaskService {
|
|
|
215
220
|
case 'failed':
|
|
216
221
|
case 'timeout':
|
|
217
222
|
case 'token_exhausted':
|
|
223
|
+
case 'cancelled':
|
|
218
224
|
return 100;
|
|
219
225
|
default:
|
|
220
226
|
return 0;
|
package/dist/tool/index.d.ts
CHANGED
|
@@ -22,4 +22,4 @@ export { expandSkillScriptRefs, isSkillEntryFile, EAP_SKILL_DIR_ENV, } from './s
|
|
|
22
22
|
export { ToolResultInjector, type ToolMessage, } from './tool-result-injector.js';
|
|
23
23
|
export { ToolEventEmitter } from './tool-event-emitter.js';
|
|
24
24
|
export { ToolConfirmationInterceptor } from './tool-confirmation.js';
|
|
25
|
-
export { SystemPromptBuilder, naturalTimeWindows, loadedToolsToApiTools, toLoadedSkillMap, filterLoadedToolsForSkill, type PromptBuildContext, type PromptSection, type AssembledSystemPrompt, type ApiToolDefinition, type LoadedSkillInfo, type LoadedSkillMap, } from './system-prompt-builder.js';
|
|
25
|
+
export { SystemPromptBuilder, naturalTimeWindows, buildSkillCatalog, catalogEntryTitle, spokenName, loadedToolsToApiTools, toLoadedSkillMap, filterLoadedToolsForSkill, type PromptBuildContext, type PromptSection, type AssembledSystemPrompt, type ApiToolDefinition, type LoadedSkillInfo, type LoadedSkillMap, } from './system-prompt-builder.js';
|
package/dist/tool/index.js
CHANGED
|
@@ -21,4 +21,4 @@ export { expandSkillScriptRefs, isSkillEntryFile, EAP_SKILL_DIR_ENV, } from './s
|
|
|
21
21
|
export { ToolResultInjector, } from './tool-result-injector.js';
|
|
22
22
|
export { ToolEventEmitter } from './tool-event-emitter.js';
|
|
23
23
|
export { ToolConfirmationInterceptor } from './tool-confirmation.js';
|
|
24
|
-
export { SystemPromptBuilder, naturalTimeWindows, loadedToolsToApiTools, toLoadedSkillMap, filterLoadedToolsForSkill, } from './system-prompt-builder.js';
|
|
24
|
+
export { SystemPromptBuilder, naturalTimeWindows, buildSkillCatalog, catalogEntryTitle, spokenName, loadedToolsToApiTools, toLoadedSkillMap, filterLoadedToolsForSkill, } from './system-prompt-builder.js';
|
package/dist/tool/mcp-list.d.ts
CHANGED
|
@@ -53,17 +53,19 @@ export declare function mcpToolsetCode(loaded: {
|
|
|
53
53
|
execution?: unknown;
|
|
54
54
|
};
|
|
55
55
|
} | undefined): string | undefined;
|
|
56
|
-
/** Tool Span:工具集 code +
|
|
56
|
+
/** Tool Span:工具集 code + 声明版本 + 展示名(与函数名不同才写)。 */
|
|
57
57
|
export declare function toolTraceIdentity(loaded: {
|
|
58
58
|
toolId?: string;
|
|
59
59
|
name?: string;
|
|
60
60
|
manifest?: {
|
|
61
61
|
id?: string;
|
|
62
|
+
name?: string;
|
|
62
63
|
version?: string;
|
|
63
64
|
};
|
|
64
65
|
} | undefined, toolName: string): {
|
|
65
66
|
toolset?: string;
|
|
66
67
|
toolVersion?: string;
|
|
68
|
+
toolDisplayName?: string;
|
|
67
69
|
};
|
|
68
70
|
export interface HydrateMcpToolsAuth {
|
|
69
71
|
authContext: AuthContext;
|
package/dist/tool/mcp-list.js
CHANGED
|
@@ -130,13 +130,16 @@ function declaredToolVersion(toolName, version) {
|
|
|
130
130
|
return undefined;
|
|
131
131
|
return raw;
|
|
132
132
|
}
|
|
133
|
-
/** Tool Span:工具集 code +
|
|
133
|
+
/** Tool Span:工具集 code + 声明版本 + 展示名(与函数名不同才写)。 */
|
|
134
134
|
export function toolTraceIdentity(loaded, toolName) {
|
|
135
135
|
const toolset = toolsetCodeFromLoaded(loaded);
|
|
136
136
|
const toolVersion = declaredToolVersion(toolName, loaded?.manifest?.version);
|
|
137
|
+
const display = loaded?.manifest?.name?.trim();
|
|
138
|
+
const toolDisplayName = display && display !== toolName ? display : undefined;
|
|
137
139
|
return {
|
|
138
140
|
...(toolset ? { toolset } : {}),
|
|
139
141
|
...(toolVersion ? { toolVersion } : {}),
|
|
142
|
+
...(toolDisplayName ? { toolDisplayName } : {}),
|
|
140
143
|
};
|
|
141
144
|
}
|
|
142
145
|
/**
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* ```
|
|
8
8
|
* [平台规则常量] ← 代码内置,安全约束 + 行为准则(最高优先级)
|
|
9
9
|
* [当前时间] ← 运行时动态注入(自然周等时间规则的判定基准)
|
|
10
|
-
* [Agent 身份] ← agentName
|
|
11
|
-
* [
|
|
10
|
+
* [Agent 身份] ← 展示名 agentName,缺省 agentCode(对用户说话,不是路由键)
|
|
11
|
+
* [可用技能短目录] ← 展示名 + skillId + SKILL.md 路径(技能不是 function)
|
|
12
12
|
* [Agent 基线] ← agent.manifest.json prompts.system;非 silent LLM
|
|
13
13
|
* [节点提示词] ← Graph LLM 节点 config.systemPrompt / systemPromptFile
|
|
14
14
|
* ```
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* 基线只走 GraphState.agentSystemPrompt,不写进节点 config。无图时节点无增量。
|
|
17
17
|
* silent 节点不带基线。技能正文不灌 system。
|
|
18
18
|
*
|
|
19
|
-
*
|
|
19
|
+
* 工具只走 API 的 tools 参数(见 loadedToolsToApiTools),不写入 system。
|
|
20
20
|
*
|
|
21
21
|
* @see docs/status/module-status-and-backlog.md RT-5
|
|
22
22
|
*/
|
|
@@ -97,8 +97,6 @@ export interface PromptBuildContext {
|
|
|
97
97
|
}>;
|
|
98
98
|
/** 已装配 Skill 短目录;单独成段,不并进 Agent 基线 / 节点提示词 */
|
|
99
99
|
skillCatalog?: string;
|
|
100
|
-
/** 已装配工具短目录(名称 + 用途);schema 仍走 API tools */
|
|
101
|
-
toolCatalog?: string;
|
|
102
100
|
}
|
|
103
101
|
export interface PromptSection {
|
|
104
102
|
id: string;
|
|
@@ -109,6 +107,10 @@ export interface AssembledSystemPrompt {
|
|
|
109
107
|
text: string;
|
|
110
108
|
sections: PromptSection[];
|
|
111
109
|
}
|
|
110
|
+
/** 对人展示的名称。有展示名用展示名,否则用编码。 */
|
|
111
|
+
export declare function spokenName(displayName: string | undefined, code: string | undefined): string | undefined;
|
|
112
|
+
/** 短目录标题:展示名在前,调用键在行内。名称与编码相同则只写编码。 */
|
|
113
|
+
export declare function catalogEntryTitle(code: string, displayName: string | undefined, codePhrase: string): string;
|
|
112
114
|
/**
|
|
113
115
|
* 非 silent LLM 才带 Agent 基线;节点提示词空则省略。
|
|
114
116
|
* silent 只保留节点增量(选技能 / JSON)。
|
|
@@ -125,7 +127,7 @@ export declare function resolveLlmPromptInputs(input: {
|
|
|
125
127
|
* SystemPromptBuilder — 系统提示词拼接
|
|
126
128
|
*
|
|
127
129
|
* 具名段拼接(无模板引擎)。顺序固定,段标题用于排查。
|
|
128
|
-
*
|
|
130
|
+
* 工具只走 API tools 参数,不进 system。技能短目录进 system(技能不是 function)。
|
|
129
131
|
* Agent 基线与节点提示词整段透传,不做 {{ }} 替换。
|
|
130
132
|
*/
|
|
131
133
|
export declare class SystemPromptBuilder {
|
|
@@ -154,6 +156,8 @@ export declare function naturalTimeWindows(now?: Date): {
|
|
|
154
156
|
* 方便 tool 模块的使用者按领域引用。
|
|
155
157
|
*/
|
|
156
158
|
export type ApiToolDefinition = LLMToolDefinition;
|
|
159
|
+
/** 展示名 + skillId,供 system「可用技能」段。read_file 仍用 skillId。 */
|
|
160
|
+
export declare function buildSkillCatalog(defs: LoadedSkillMap | undefined): string | undefined;
|
|
157
161
|
/**
|
|
158
162
|
* 将平台的 LoadedToolMap 转为 OpenAI API 的 tools 参数
|
|
159
163
|
*
|
|
@@ -164,6 +168,4 @@ export type ApiToolDefinition = LLMToolDefinition;
|
|
|
164
168
|
* @param skillTools - 可选,当前 Skill 所需的工具名称列表(过滤子集)
|
|
165
169
|
* @returns OpenAI API tools 参数数组
|
|
166
170
|
*/
|
|
167
|
-
/** 名称 + 一句话用途,供 system「可用工具」段。schema 仍走 loadedToolsToApiTools。 */
|
|
168
|
-
export declare function buildToolCatalog(loadedTools: LoadedToolMap | undefined): string | undefined;
|
|
169
171
|
export declare function loadedToolsToApiTools(loadedTools: LoadedToolMap | undefined, skillTools?: string[]): ApiToolDefinition[];
|