@gt-fe/eap-runtime 0.0.23 → 0.0.25

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.
Files changed (39) hide show
  1. package/README.md +1 -0
  2. package/dist/api/handlers/invoke.handler.d.ts +4 -0
  3. package/dist/api/handlers/invoke.handler.js +69 -37
  4. package/dist/api/handlers/stream.handler.d.ts +4 -0
  5. package/dist/api/handlers/stream.handler.js +40 -21
  6. package/dist/api/routes/agent.routes.js +6 -5
  7. package/dist/checkpoint/checkpoint-ref-notify.js +1 -1
  8. package/dist/common/types.d.ts +6 -2
  9. package/dist/common/types.js +3 -1
  10. package/dist/graph/adapters/langgraph.adapter.d.ts +6 -4
  11. package/dist/graph/adapters/langgraph.adapter.js +103 -18
  12. package/dist/graph/contracts/executable-graph.d.ts +11 -2
  13. package/dist/graph/execution-trace-context.d.ts +4 -0
  14. package/dist/graph/execution-trace-context.js +3 -1
  15. package/dist/graph/nodes/rag/types.d.ts +4 -1
  16. package/dist/providers/http-llm-provider.js +25 -0
  17. package/dist/registry/graph-loader.js +5 -4
  18. package/dist/runtime/agent-runtime.d.ts +4 -1
  19. package/dist/runtime/agent-runtime.js +110 -20
  20. package/dist/runtime/dev-runtime.d.ts +1 -0
  21. package/dist/runtime/dev-runtime.js +9 -2
  22. package/dist/runtime/types.d.ts +1 -1
  23. package/dist/session/apply-session-compression.d.ts +6 -4
  24. package/dist/session/apply-session-compression.js +24 -11
  25. package/dist/session/index.d.ts +1 -1
  26. package/dist/session/index.js +1 -1
  27. package/dist/session/persist-turn-messages.d.ts +50 -9
  28. package/dist/session/persist-turn-messages.js +133 -15
  29. package/dist/sse/events/response-events.d.ts +2 -2
  30. package/dist/sse/events/response-events.js +1 -1
  31. package/dist/task/contracts/task-manager.contract.d.ts +2 -0
  32. package/dist/task/index.d.ts +1 -0
  33. package/dist/task/index.js +1 -0
  34. package/dist/task/resolve-task-timeout.d.ts +6 -0
  35. package/dist/task/resolve-task-timeout.js +16 -0
  36. package/dist/task/task-timeout.d.ts +1 -1
  37. package/dist/task/task-timeout.js +3 -2
  38. package/dist/task/task.service.js +1 -0
  39. package/package.json +2 -2
@@ -305,31 +305,149 @@ function extractReasoningContent(reasoning) {
305
305
  * - Session 级 Checkpoint 持有图内 messages(含 reasoning)
306
306
  * - 当 Checkpoint 已有历史时,只追加本轮 user,避免双重 append
307
307
  * - Checkpoint 缺失/无 messages 时,回退 Session 全量历史
308
+ * - 压缩针对 Checkpoint(无则 Session)中的模型上下文;压成功且来自 Checkpoint 时由调用方设 `replaceCheckpointMessages`
308
309
  */
309
310
  export async function buildTurnGraphMessages(params) {
310
- const newUser = { role: 'user', content: params.input };
311
- const history = params.history;
312
- if (!params.checkpointSaver || !params.threadId || history.length === 0) {
313
- return [...history, newUser];
311
+ const facing = await loadModelFacingHistory({
312
+ sessionHistory: params.history,
313
+ checkpointSaver: params.checkpointSaver,
314
+ threadId: params.threadId,
315
+ });
316
+ return turnGraphMessagesAfterCompression({
317
+ history: facing.messages,
318
+ input: params.input,
319
+ fromCheckpoint: facing.fromCheckpoint,
320
+ compressed: false,
321
+ }).messages;
322
+ }
323
+ /**
324
+ * 模型上下文:Checkpoint 已有 messages 用它,否则用 Session 历史。
325
+ * 压缩必须压这份列表,不能只压 Session 再在有 Checkpoint 时丢掉。
326
+ */
327
+ export async function loadModelFacingHistory(params) {
328
+ const sessionHistory = params.sessionHistory ?? [];
329
+ if (!params.checkpointSaver || !params.threadId) {
330
+ return { messages: sessionHistory, fromCheckpoint: false };
314
331
  }
315
332
  const cp = await params.checkpointSaver.load(params.threadId);
316
- if (checkpointHasMessages(cp)) {
317
- return [newUser];
333
+ const checkpointMessages = graphMessagesFromCheckpoint(cp);
334
+ if (checkpointMessages.length > 0) {
335
+ return { messages: checkpointMessages, fromCheckpoint: true };
318
336
  }
319
- return [...history, newUser];
337
+ return { messages: sessionHistory, fromCheckpoint: false };
320
338
  }
321
- function checkpointHasMessages(cp) {
339
+ /**
340
+ * 压缩后的入图列表。来自 Checkpoint 且本轮压成功:整表 `__set` 覆盖,写入最新 Checkpoint。
341
+ * 未压且来自 Checkpoint:只追加本轮 user。无 Checkpoint:历史 + 本轮 user。
342
+ */
343
+ export function turnGraphMessagesAfterCompression(params) {
344
+ const newUser = { role: 'user', content: params.input };
345
+ if (params.fromCheckpoint && params.compressed) {
346
+ return {
347
+ messages: [...params.history, newUser],
348
+ replaceCheckpointMessages: true,
349
+ };
350
+ }
351
+ if (params.fromCheckpoint) {
352
+ return { messages: [newUser], replaceCheckpointMessages: false };
353
+ }
354
+ return {
355
+ messages: [...params.history, newUser],
356
+ replaceCheckpointMessages: false,
357
+ };
358
+ }
359
+ /**
360
+ * invoke 从 Graph 最终 messages 切本轮增量的起点。
361
+ * 覆盖(`__set`)或无 Checkpoint:入图数组长度(已含本轮 user)。
362
+ * 追加到已有 Checkpoint:模型上下文条数 + 入图条数(通常 1 条 user)。
363
+ */
364
+ export function persistGraphMessageBaseline(params) {
365
+ if (params.replaceCheckpointMessages || !params.fromCheckpoint) {
366
+ return params.graphInputCount;
367
+ }
368
+ return params.modelFacingCount + params.graphInputCount;
369
+ }
370
+ export function graphMessagesFromCheckpoint(cp) {
322
371
  if (!cp)
323
- return false;
324
- if (Array.isArray(cp.state?.messages) && cp.state.messages.length > 0)
325
- return true;
372
+ return [];
326
373
  const channelValues = cp.engineSnapshot?.['channel_values'];
327
374
  if (channelValues && typeof channelValues === 'object') {
328
375
  const messages = channelValues['messages'];
329
- if (Array.isArray(messages) && messages.length > 0)
330
- return true;
376
+ if (Array.isArray(messages) && messages.length > 0) {
377
+ return unknownListToGraphMessages(messages);
378
+ }
379
+ }
380
+ if (Array.isArray(cp.state?.messages) && cp.state.messages.length > 0) {
381
+ return unknownListToGraphMessages(cp.state.messages);
382
+ }
383
+ return [];
384
+ }
385
+ function unknownListToGraphMessages(raw) {
386
+ return raw.map((msg) => unknownToGraphMessage(msg));
387
+ }
388
+ function unknownToGraphMessage(msg) {
389
+ if (typeof msg !== 'object' || msg === null) {
390
+ return { role: 'user', content: String(msg) };
331
391
  }
332
- return false;
392
+ const m = msg;
393
+ const nested = m.kwargs && typeof m.kwargs === 'object' ? m.kwargs : undefined;
394
+ const lcName = Array.isArray(m.id) ? m.id[m.id.length - 1] : undefined;
395
+ const typeHint = m.type === 'constructor' ? undefined : m.type;
396
+ const role = graphRoleFromUnknown(m.role ?? nested?.role ?? nested?.type ?? typeHint ?? lcName);
397
+ const content = messageContentToString(m.content ?? nested?.content);
398
+ const toolCalls = (m.toolCalls ?? m.tool_calls ?? nested?.tool_calls);
399
+ const toolCallId = (typeof m.toolCallId === 'string' && m.toolCallId) ||
400
+ (typeof m.tool_call_id === 'string' && m.tool_call_id) ||
401
+ (typeof nested?.tool_call_id === 'string' && nested.tool_call_id) ||
402
+ undefined;
403
+ const toolName = (typeof m.toolName === 'string' && m.toolName) ||
404
+ (typeof nested?.name === 'string' && nested.name) ||
405
+ undefined;
406
+ const success = typeof m.success === 'boolean' ? m.success : undefined;
407
+ const reasoningContent = (typeof m.reasoningContent === 'string' && m.reasoningContent) ||
408
+ (typeof m.reasoning_content === 'string' && m.reasoning_content) ||
409
+ undefined;
410
+ return {
411
+ role,
412
+ content,
413
+ ...(toolCalls ? { toolCalls } : {}),
414
+ ...(toolCallId ? { toolCallId } : {}),
415
+ ...(toolName ? { toolName } : {}),
416
+ ...(success !== undefined ? { success } : {}),
417
+ ...(reasoningContent ? { reasoningContent } : {}),
418
+ };
419
+ }
420
+ function graphRoleFromUnknown(raw) {
421
+ if (raw === 'user' || raw === 'assistant' || raw === 'system' || raw === 'tool')
422
+ return raw;
423
+ if (raw === 'human' || raw === 'HumanMessage')
424
+ return 'user';
425
+ if (raw === 'ai' || raw === 'AIMessage')
426
+ return 'assistant';
427
+ if (raw === 'system' || raw === 'SystemMessage')
428
+ return 'system';
429
+ if (raw === 'tool' || raw === 'ToolMessage')
430
+ return 'tool';
431
+ return 'user';
432
+ }
433
+ function messageContentToString(content) {
434
+ if (typeof content === 'string')
435
+ return content;
436
+ if (Array.isArray(content)) {
437
+ return content
438
+ .map((part) => {
439
+ if (typeof part === 'string')
440
+ return part;
441
+ if (part && typeof part === 'object' && typeof part.text === 'string') {
442
+ return part.text;
443
+ }
444
+ return '';
445
+ })
446
+ .join('');
447
+ }
448
+ if (content == null)
449
+ return '';
450
+ return String(content);
333
451
  }
334
452
  export function buildHitlWaitingTaskOutput(params) {
335
453
  return {
@@ -362,7 +480,7 @@ export function extractHitlThreadId(output) {
362
480
  * 与 LangGraph put / 子图内 HITL interrupt 同一把钥匙。
363
481
  *
364
482
  * 注意:session 级 thread + 全量 Session 历史同时注入会导致 messages 双重 append。
365
- * 组装本轮 Graph 输入请用 {@link buildTurnGraphMessages}(有 Checkpoint 历史则只追加 user)。
483
+ * 组装本轮 Graph 输入请用 {@link loadModelFacingHistory} 与 {@link turnGraphMessagesAfterCompression}。
366
484
  */
367
485
  export function resolveCheckpointThreadId(params) {
368
486
  if (params.sessionId)
@@ -5,7 +5,7 @@
5
5
  * - response.final
6
6
  *
7
7
  * 可选事件:
8
- * - response.max_iterations_reached
8
+ * - response.max_iterations_reached(契约保留;调度步上限走 task.error / runtime.graph.max_iterations,不发本事件)
9
9
  *
10
10
  * @see design.md §1.6 SSE事件协议定义
11
11
  */
@@ -16,7 +16,7 @@ export interface ResponseFinalPayload {
16
16
  /** 回复格式(如 text, markdown, json) */
17
17
  format: string;
18
18
  }
19
- /** 达到最大迭代次数 */
19
+ /** 契约保留。整图调度步上限不发此事件。 */
20
20
  export interface ResponseMaxIterationsReachedPayload {
21
21
  /** 最大迭代次数 */
22
22
  maxIterations: number;
@@ -5,7 +5,7 @@
5
5
  * - response.final
6
6
  *
7
7
  * 可选事件:
8
- * - response.max_iterations_reached
8
+ * - response.max_iterations_reached(契约保留;调度步上限走 task.error / runtime.graph.max_iterations,不发本事件)
9
9
  *
10
10
  * @see design.md §1.6 SSE事件协议定义
11
11
  */
@@ -46,6 +46,8 @@ export interface TaskRecord {
46
46
  correlationId: string;
47
47
  /** 用户输入 */
48
48
  input: unknown;
49
+ /** 整图超时(毫秒)。未写入旧记录时 resume 用平台缺省 */
50
+ timeout?: number;
49
51
  /** 执行输出 */
50
52
  output: unknown | null;
51
53
  /** 当前状态 */
@@ -3,5 +3,6 @@ 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 { resolveTaskTimeoutMs } from './resolve-task-timeout.js';
6
7
  export { TaskProgressTracker } from './task-progress-tracker.js';
7
8
  export type { TaskProgressInfo } from './task-progress-tracker.js';
@@ -2,4 +2,5 @@
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 { resolveTaskTimeoutMs } from './resolve-task-timeout.js';
5
6
  export { TaskProgressTracker } from './task-progress-tracker.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 整图超时:请求 config.timeout,否则图 config.timeout,否则平台缺省 1200000 毫秒(20 分钟)。
3
+ * 官方模板图上不写 timeout,用平台缺省。LLM HTTP 超时、HITL 等待另算。
4
+ */
5
+ /** 请求显式值优先,否则图配置,否则 {@link DEFAULT_GRAPH_TIMEOUT_MS}。 */
6
+ export declare function resolveTaskTimeoutMs(requestTimeout?: number, graphTimeout?: number): number;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 整图超时:请求 config.timeout,否则图 config.timeout,否则平台缺省 1200000 毫秒(20 分钟)。
3
+ * 官方模板图上不写 timeout,用平台缺省。LLM HTTP 超时、HITL 等待另算。
4
+ */
5
+ import { DEFAULT_GRAPH_TIMEOUT_MS } from '../common/types.js';
6
+ function positiveMs(value) {
7
+ if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0)
8
+ return undefined;
9
+ return Math.trunc(value);
10
+ }
11
+ /** 请求显式值优先,否则图配置,否则 {@link DEFAULT_GRAPH_TIMEOUT_MS}。 */
12
+ export function resolveTaskTimeoutMs(requestTimeout, graphTimeout) {
13
+ return (positiveMs(requestTimeout) ??
14
+ positiveMs(graphTimeout) ??
15
+ DEFAULT_GRAPH_TIMEOUT_MS);
16
+ }
@@ -13,7 +13,7 @@
13
13
  * TaskTimeoutManager 配置选项
14
14
  */
15
15
  export interface TaskTimeoutManagerOptions {
16
- /** 默认超时时间(毫秒),默认 60000 (60s) */
16
+ /** 默认超时时间(毫秒),默认 {@link DEFAULT_GRAPH_TIMEOUT_MS} */
17
17
  defaultTimeoutMs?: number;
18
18
  }
19
19
  /**
@@ -9,11 +9,12 @@
9
9
  * @see design.md §1.1 任务管理 — Task级超时
10
10
  * @see requirements.md Requirement 7 AC4
11
11
  */
12
+ import { DEFAULT_GRAPH_TIMEOUT_MS } from '../common/types.js';
12
13
  // ─────────────────────────────────────────────
13
14
  // Default Constants
14
15
  // ─────────────────────────────────────────────
15
- /** 默认超时:60 秒 */
16
- const DEFAULT_TIMEOUT_MS = 60_000;
16
+ /** 默认超时:与图/请求缺省同一常数 */
17
+ const DEFAULT_TIMEOUT_MS = DEFAULT_GRAPH_TIMEOUT_MS;
17
18
  /** 最大允许超时:3600 秒(1 小时) */
18
19
  const MAX_TIMEOUT_MS = 3_600_000;
19
20
  // ─────────────────────────────────────────────
@@ -84,6 +84,7 @@ export class TaskService {
84
84
  userId: params.userId,
85
85
  correlationId: params.correlationId,
86
86
  input: params.input,
87
+ timeout: params.timeout,
87
88
  output: null,
88
89
  status: 'pending',
89
90
  traceId: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gt-fe/eap-runtime",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "Enterprise Agent Platform — Runtime核心:Graph执行引擎、Task生命周期、Session管理、Checkpoint持久化",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "ioredis": "^5.4.0",
21
21
  "pg": "^8.13.0",
22
22
  "yaml": "^2.6.1",
23
- "@gt-fe/eap-contracts": "0.0.13"
23
+ "@gt-fe/eap-contracts": "0.0.14"
24
24
  },
25
25
  "publishConfig": {
26
26
  "registry": "https://registry.npmjs.org/",