@gt-fe/eap-runtime 0.0.33 → 0.0.35
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 +22 -5
- package/dist/api/handlers/stream.handler.d.ts +0 -1
- package/dist/api/handlers/stream.handler.js +30 -23
- package/dist/common/types.d.ts +4 -3
- package/dist/graph/adapters/langgraph.adapter.js +181 -86
- package/dist/graph/adapters/subgraph-compiler.js +25 -0
- package/dist/graph/contracts/executable-graph.d.ts +9 -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 +11 -4
- package/dist/graph/nodes/tool-node.d.ts +4 -0
- package/dist/graph/nodes/tool-node.js +132 -4
- package/dist/providers/http-llm-provider.js +27 -10
- package/dist/registry/graph-loader.js +10 -1
- package/dist/runtime/agent-runtime.d.ts +7 -0
- package/dist/runtime/agent-runtime.js +91 -50
- 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 +2 -1
- package/dist/tool/index.js +2 -1
- package/dist/tool/mcp-tool-exposure.d.ts +113 -0
- package/dist/tool/mcp-tool-exposure.js +479 -0
- package/dist/tool/system-prompt-builder.d.ts +13 -10
- package/dist/tool/system-prompt-builder.js +18 -32
- package/package.json +1 -1
|
@@ -9,14 +9,16 @@
|
|
|
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
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';
|
|
21
|
+
import { correctEmployeeVisibleReply, employeeStreamClose, takeEmployeeVisibleEvents, } from '../tool/mcp-tool-exposure.js';
|
|
20
22
|
import { iterSessionCompression, withCompressionSummaryModel, } from '../session/apply-session-compression.js';
|
|
21
23
|
import { applySessionMemory } from '../session/apply-session-memory.js';
|
|
22
24
|
import { buildSessionTitleUserPayload, invokeSessionTitle, } from '../session/session-title.js';
|
|
@@ -33,7 +35,33 @@ const HITL_TERMINAL_STATUSES = [
|
|
|
33
35
|
'failed',
|
|
34
36
|
'timeout',
|
|
35
37
|
'token_exhausted',
|
|
38
|
+
'cancelled',
|
|
36
39
|
];
|
|
40
|
+
const TASK_CANCELLED_SSE_CODE = 'runtime.task.cancelled';
|
|
41
|
+
function taskAbortSseData(kind) {
|
|
42
|
+
if (kind === 'timeout') {
|
|
43
|
+
return {
|
|
44
|
+
code: ErrorCodes.TASK_TIMEOUT,
|
|
45
|
+
message: 'Task execution timed out',
|
|
46
|
+
recoverable: false,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
code: TASK_CANCELLED_SSE_CODE,
|
|
51
|
+
message: 'Task cancelled',
|
|
52
|
+
recoverable: false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async function settleAbortedTask(taskService, taskId, kind) {
|
|
56
|
+
if (kind === 'timeout') {
|
|
57
|
+
await taskService.tryUpdateStatus(taskId, 'running', 'timeout');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const moved = await taskService.tryUpdateStatus(taskId, 'running', 'cancelled');
|
|
61
|
+
if (!moved) {
|
|
62
|
+
await taskService.tryUpdateStatus(taskId, 'waiting_hitl', 'cancelled');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
37
65
|
const DEFAULT_GRAPH_DSL = {
|
|
38
66
|
name: 'default-graph',
|
|
39
67
|
version: '1.0.0',
|
|
@@ -57,6 +85,17 @@ export class AgentRuntime {
|
|
|
57
85
|
}
|
|
58
86
|
this.deps.hitlHandler.setTraceCollector?.(this.deps.traceCollector);
|
|
59
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* 停止这一轮。超时和用户停止共用 timeoutManager 上的那条 AbortSignal。
|
|
90
|
+
* 计时器还没启动时先记下,startTimer 会返回已 abort 的 signal,且不调用 onTimeout。
|
|
91
|
+
* @returns 已 abort 或已记下。没有 timeoutManager 时返回 false。
|
|
92
|
+
*/
|
|
93
|
+
abort(taskId, kind = 'cancelled') {
|
|
94
|
+
const manager = this.deps.timeoutManager;
|
|
95
|
+
if (!manager || !taskId.trim())
|
|
96
|
+
return false;
|
|
97
|
+
return manager.abort(taskId, kind);
|
|
98
|
+
}
|
|
60
99
|
/** 从 GraphLoader 解析 tool manifest 映射(invoke/stream/resume/fork 共用) */
|
|
61
100
|
async resolveLoadedTools(agentCode, agentVersion) {
|
|
62
101
|
if (!this.deps.graphLoader)
|
|
@@ -376,8 +415,8 @@ export class AgentRuntime {
|
|
|
376
415
|
});
|
|
377
416
|
const startTime = Date.now();
|
|
378
417
|
const assistantBuckets = createStreamAssistantBuckets();
|
|
418
|
+
const reasoningState = createStreamReasoningState();
|
|
379
419
|
let toolCallReasoningContent;
|
|
380
|
-
let assistantReasoningContent;
|
|
381
420
|
const pendingToolCalls = [];
|
|
382
421
|
const toolResults = [];
|
|
383
422
|
const artifactLinks = [];
|
|
@@ -419,31 +458,31 @@ export class AgentRuntime {
|
|
|
419
458
|
arguments: p.arguments ?? {},
|
|
420
459
|
});
|
|
421
460
|
}
|
|
422
|
-
|
|
423
|
-
toolCallReasoningContent = p.reasoningContent;
|
|
424
|
-
}
|
|
461
|
+
toolCallReasoningContent = resolvedStreamReasoning(reasoningState);
|
|
425
462
|
}
|
|
426
463
|
// 终态 tool.result / tool.error 回填历史;willRetry 的 error 不进 transcript
|
|
427
464
|
appendTerminalToolResult(runtimeEvent.type, runtimeEvent.payload, toolResults);
|
|
428
465
|
collectPublicArtifactLinksFromEvent(runtimeEvent.type, runtimeEvent.payload, artifactLinks);
|
|
429
|
-
|
|
430
|
-
if (streamedReasoning)
|
|
431
|
-
assistantReasoningContent = streamedReasoning;
|
|
466
|
+
applyStreamReasoningEvent(reasoningState, runtimeEvent.type, runtimeEvent.payload);
|
|
432
467
|
applyStreamTextDelta(assistantBuckets, runtimeEvent.type, runtimeEvent.payload);
|
|
433
468
|
collectStreamNodeTokenUsage(runtimeEvent, nodeTokenUsages);
|
|
434
|
-
|
|
435
|
-
|
|
469
|
+
for (const visibleEvent of takeEmployeeVisibleEvents(runtimeEvent.type, runtimeEvent.payload)) {
|
|
470
|
+
if (shouldEmitTokenSse(tokenDetail, visibleEvent.type)) {
|
|
471
|
+
yield this.runtimeEventToSSE({ ...runtimeEvent, type: visibleEvent.type, payload: visibleEvent.payload }, correlationId, task.id);
|
|
472
|
+
}
|
|
436
473
|
}
|
|
437
474
|
}
|
|
438
475
|
await recordTaskTokenUsages(this.deps.taskService, task.id, nodeTokenUsages);
|
|
439
476
|
await this.deps.taskService.updateStatus(task.id, 'success');
|
|
440
477
|
const tokenSummary = summarizeTokenUsages(nodeTokenUsages);
|
|
441
|
-
const
|
|
478
|
+
const rawVisible = visibleStreamAssistantText(assistantBuckets);
|
|
479
|
+
const visible = correctEmployeeVisibleReply(rawVisible, toolResults);
|
|
442
480
|
const links = mergeArtifactLinks(artifactLinks, collectPublicArtifactLinks(toolResults));
|
|
443
481
|
const { injected, suffix } = injectPublicArtifactLinks(visible, links);
|
|
444
|
-
|
|
482
|
+
const close = employeeStreamClose({ raw: rawVisible, tools: toolResults, suffix });
|
|
483
|
+
for (const content of close.chunks) {
|
|
445
484
|
yield this.toSSE('response.chunk', correlationId, task.id, {
|
|
446
|
-
content
|
|
485
|
+
content,
|
|
447
486
|
format: 'text',
|
|
448
487
|
});
|
|
449
488
|
}
|
|
@@ -458,11 +497,11 @@ export class AgentRuntime {
|
|
|
458
497
|
messages: buildTurnTranscriptFromStreamEvents({
|
|
459
498
|
pendingToolCalls,
|
|
460
499
|
toolResults,
|
|
461
|
-
assistantTexts:
|
|
500
|
+
assistantTexts: close.persistCorrected ? undefined : streamAssistantTexts(assistantBuckets),
|
|
462
501
|
assistantText: injected,
|
|
463
502
|
finishPoints: graph.finishPoints,
|
|
464
503
|
toolCallReasoningContent,
|
|
465
|
-
assistantReasoningContent,
|
|
504
|
+
assistantReasoningContent: resolvedStreamReasoning(reasoningState),
|
|
466
505
|
}),
|
|
467
506
|
assistantTokenCount: tokenSummary.total.output,
|
|
468
507
|
assistantDurationMs: Date.now() - startTime,
|
|
@@ -495,15 +534,11 @@ export class AgentRuntime {
|
|
|
495
534
|
yield this.toSSE('hitl.waited', correlationId, task.id, buildHitlWaitedPayload(hitlPaused));
|
|
496
535
|
return;
|
|
497
536
|
}
|
|
498
|
-
const
|
|
499
|
-
if (
|
|
537
|
+
const abortKind = taskAbortKindOf(err, abortSignal);
|
|
538
|
+
if (abortKind) {
|
|
500
539
|
await recordTaskTokenUsages(this.deps.taskService, task.id, nodeTokenUsages);
|
|
501
|
-
await this.deps.taskService
|
|
502
|
-
yield this.toSSE('task.error', correlationId, task.id,
|
|
503
|
-
code: ErrorCodes.TASK_TIMEOUT,
|
|
504
|
-
message: 'Task execution timed out',
|
|
505
|
-
recoverable: false,
|
|
506
|
-
});
|
|
540
|
+
await settleAbortedTask(this.deps.taskService, task.id, abortKind);
|
|
541
|
+
yield this.toSSE('task.error', correlationId, task.id, taskAbortSseData(abortKind));
|
|
507
542
|
return;
|
|
508
543
|
}
|
|
509
544
|
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
@@ -528,6 +563,7 @@ export class AgentRuntime {
|
|
|
528
563
|
*/
|
|
529
564
|
async resumeHitl(taskId, response) {
|
|
530
565
|
let output = '';
|
|
566
|
+
let finalText = '';
|
|
531
567
|
let waiting;
|
|
532
568
|
let sawWait = false;
|
|
533
569
|
const assistantBuckets = createStreamAssistantBuckets();
|
|
@@ -542,12 +578,21 @@ export class AgentRuntime {
|
|
|
542
578
|
};
|
|
543
579
|
output = waiting.question;
|
|
544
580
|
}
|
|
581
|
+
if (event.type === 'response.final') {
|
|
582
|
+
const content = event.data?.content;
|
|
583
|
+
if (typeof content === 'string')
|
|
584
|
+
finalText = content;
|
|
585
|
+
}
|
|
545
586
|
applyStreamTextDelta(assistantBuckets, event.type, event.data);
|
|
546
587
|
}
|
|
547
588
|
if (sawWait) {
|
|
548
589
|
return { taskId, status: 'waiting_hitl', output, hitl: waiting };
|
|
549
590
|
}
|
|
550
|
-
return {
|
|
591
|
+
return {
|
|
592
|
+
taskId,
|
|
593
|
+
status: 'success',
|
|
594
|
+
output: finalText || visibleStreamAssistantText(assistantBuckets) || output,
|
|
595
|
+
};
|
|
551
596
|
}
|
|
552
597
|
/**
|
|
553
598
|
* HITL 恢复的流式入口:新开一条 SSE(第一条 stream 在 `hitl.waited` 后已结束)。
|
|
@@ -638,8 +683,8 @@ export class AgentRuntime {
|
|
|
638
683
|
};
|
|
639
684
|
const startTime = Date.now();
|
|
640
685
|
const assistantBuckets = createStreamAssistantBuckets();
|
|
686
|
+
const reasoningState = createStreamReasoningState();
|
|
641
687
|
let toolCallReasoningContent;
|
|
642
|
-
let assistantReasoningContent;
|
|
643
688
|
const pendingToolCalls = [];
|
|
644
689
|
const toolResults = [];
|
|
645
690
|
const artifactLinks = [];
|
|
@@ -655,27 +700,27 @@ export class AgentRuntime {
|
|
|
655
700
|
arguments: p.arguments ?? {},
|
|
656
701
|
});
|
|
657
702
|
}
|
|
658
|
-
|
|
659
|
-
toolCallReasoningContent = p.reasoningContent;
|
|
660
|
-
}
|
|
703
|
+
toolCallReasoningContent = resolvedStreamReasoning(reasoningState);
|
|
661
704
|
}
|
|
662
705
|
appendTerminalToolResult(runtimeEvent.type, runtimeEvent.payload, toolResults);
|
|
663
706
|
collectPublicArtifactLinksFromEvent(runtimeEvent.type, runtimeEvent.payload, artifactLinks);
|
|
664
|
-
|
|
665
|
-
if (streamedReasoning)
|
|
666
|
-
assistantReasoningContent = streamedReasoning;
|
|
707
|
+
applyStreamReasoningEvent(reasoningState, runtimeEvent.type, runtimeEvent.payload);
|
|
667
708
|
applyStreamTextDelta(assistantBuckets, runtimeEvent.type, runtimeEvent.payload);
|
|
668
709
|
collectStreamNodeTokenUsage(runtimeEvent, nodeTokenUsages);
|
|
669
|
-
|
|
670
|
-
|
|
710
|
+
for (const visibleEvent of takeEmployeeVisibleEvents(runtimeEvent.type, runtimeEvent.payload)) {
|
|
711
|
+
if (shouldEmitTokenSse(tokenDetail, visibleEvent.type)) {
|
|
712
|
+
yield this.runtimeEventToSSE({ ...runtimeEvent, type: visibleEvent.type, payload: visibleEvent.payload }, correlationId, taskId);
|
|
713
|
+
}
|
|
671
714
|
}
|
|
672
715
|
}
|
|
673
|
-
const
|
|
716
|
+
const rawVisible = visibleStreamAssistantText(assistantBuckets);
|
|
717
|
+
const visible = correctEmployeeVisibleReply(rawVisible, toolResults);
|
|
674
718
|
const links = mergeArtifactLinks(artifactLinks, collectPublicArtifactLinks(toolResults));
|
|
675
719
|
const { injected, suffix } = injectPublicArtifactLinks(visible, links);
|
|
676
|
-
|
|
720
|
+
const close = employeeStreamClose({ raw: rawVisible, tools: toolResults, suffix });
|
|
721
|
+
for (const content of close.chunks) {
|
|
677
722
|
yield this.toSSE('response.chunk', correlationId, taskId, {
|
|
678
|
-
content
|
|
723
|
+
content,
|
|
679
724
|
format: 'text',
|
|
680
725
|
});
|
|
681
726
|
}
|
|
@@ -694,11 +739,11 @@ export class AgentRuntime {
|
|
|
694
739
|
messages: buildTurnTranscriptFromStreamEvents({
|
|
695
740
|
pendingToolCalls,
|
|
696
741
|
toolResults,
|
|
697
|
-
assistantTexts:
|
|
742
|
+
assistantTexts: close.persistCorrected ? undefined : streamAssistantTexts(assistantBuckets),
|
|
698
743
|
assistantText: injected,
|
|
699
744
|
finishPoints: graph.finishPoints,
|
|
700
745
|
toolCallReasoningContent,
|
|
701
|
-
assistantReasoningContent,
|
|
746
|
+
assistantReasoningContent: resolvedStreamReasoning(reasoningState),
|
|
702
747
|
}),
|
|
703
748
|
assistantTokenCount: tokenSummary.total.output,
|
|
704
749
|
assistantDurationMs: Date.now() - startTime,
|
|
@@ -734,15 +779,11 @@ export class AgentRuntime {
|
|
|
734
779
|
yield this.toSSE('hitl.waited', correlationId, taskId, buildHitlWaitedPayload(hitlPaused));
|
|
735
780
|
return;
|
|
736
781
|
}
|
|
737
|
-
const
|
|
738
|
-
if (
|
|
782
|
+
const abortKind = taskAbortKindOf(err, abortSignal);
|
|
783
|
+
if (abortKind) {
|
|
739
784
|
await recordTaskTokenUsages(this.deps.taskService, taskId, nodeTokenUsages);
|
|
740
|
-
await this.deps.taskService
|
|
741
|
-
yield this.toSSE('task.error', correlationId, taskId,
|
|
742
|
-
code: ErrorCodes.TASK_TIMEOUT,
|
|
743
|
-
message: 'Task execution timed out',
|
|
744
|
-
recoverable: false,
|
|
745
|
-
});
|
|
785
|
+
await settleAbortedTask(this.deps.taskService, taskId, abortKind);
|
|
786
|
+
yield this.toSSE('task.error', correlationId, taskId, taskAbortSseData(abortKind));
|
|
746
787
|
return;
|
|
747
788
|
}
|
|
748
789
|
const appErr = err instanceof AppError ? err : AppError.fromUnknown(err);
|
|
@@ -905,15 +946,15 @@ export class AgentRuntime {
|
|
|
905
946
|
await recordTaskTokenUsages(this.deps.taskService, task.id, usages);
|
|
906
947
|
const input_tokens = usages.reduce((sum, row) => sum + row.inputTokens, 0);
|
|
907
948
|
const output_tokens = usages.reduce((sum, row) => sum + row.outputTokens, 0);
|
|
908
|
-
const
|
|
909
|
-
if (
|
|
910
|
-
await this.deps.taskService
|
|
949
|
+
const abortKind = taskAbortKindOf(err, abortSignal);
|
|
950
|
+
if (abortKind) {
|
|
951
|
+
await settleAbortedTask(this.deps.taskService, task.id, abortKind);
|
|
911
952
|
return {
|
|
912
953
|
newTraceId: traceId,
|
|
913
954
|
originalTraceId,
|
|
914
955
|
newTaskId: task.id,
|
|
915
956
|
checkpointId,
|
|
916
|
-
status: 'timeout',
|
|
957
|
+
status: abortKind === 'timeout' ? 'timeout' : 'cancelled',
|
|
917
958
|
output: message,
|
|
918
959
|
tokenUsage: {
|
|
919
960
|
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;
|
|
@@ -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
|
*
|