@gt-fe/eap-runtime 0.0.8 → 0.0.10

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 (87) hide show
  1. package/README.md +12 -17
  2. package/dist/api/handlers/invoke.handler.js +3 -3
  3. package/dist/api/handlers/messages.handler.js +0 -1
  4. package/dist/api/handlers/stream.handler.js +3 -3
  5. package/dist/api/routes/agent.routes.js +2 -2
  6. package/dist/checkpoint/checkpoint-ref-notify.d.ts +10 -0
  7. package/dist/checkpoint/checkpoint-ref-notify.js +59 -0
  8. package/dist/checkpoint/index.d.ts +1 -0
  9. package/dist/checkpoint/index.js +1 -0
  10. package/dist/checkpoint/pg-checkpoint-saver.js +25 -2
  11. package/dist/common/agent-code.d.ts +2 -4
  12. package/dist/common/agent-code.js +4 -5
  13. package/dist/contracts/trace-collector.d.ts +15 -1
  14. package/dist/debug/llm-turn-log.d.ts +100 -0
  15. package/dist/debug/llm-turn-log.js +130 -0
  16. package/dist/debug/pg-llm-turn-log.d.ts +22 -0
  17. package/dist/debug/pg-llm-turn-log.js +57 -0
  18. package/dist/graph/adapters/langgraph-checkpointer.js +3 -1
  19. package/dist/graph/adapters/langgraph.adapter.d.ts +1 -0
  20. package/dist/graph/adapters/langgraph.adapter.js +147 -91
  21. package/dist/graph/adapters/skill-read.d.ts +12 -0
  22. package/dist/graph/adapters/skill-read.js +63 -0
  23. package/dist/graph/adapters/subgraph-compiler.js +5 -0
  24. package/dist/graph/contracts/executable-graph.d.ts +3 -3
  25. package/dist/graph/hitl/hitl-handler.d.ts +7 -0
  26. package/dist/graph/hitl/hitl-handler.js +47 -6
  27. package/dist/graph/nodes/llm-node.d.ts +14 -0
  28. package/dist/graph/nodes/skill-bind-node.js +1 -2
  29. package/dist/graph/nodes/tool-node.d.ts +2 -0
  30. package/dist/graph/nodes/tool-node.js +24 -9
  31. package/dist/graph/trace-span.d.ts +22 -0
  32. package/dist/graph/trace-span.js +69 -0
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.js +2 -0
  35. package/dist/memory/compression/compression.repository.d.ts +1 -15
  36. package/dist/providers/echo-llm-provider.d.ts +1 -1
  37. package/dist/providers/echo-llm-provider.js +2 -1
  38. package/dist/providers/http-llm-provider.d.ts +4 -0
  39. package/dist/providers/http-llm-provider.js +129 -4
  40. package/dist/providers/local-llm-provider.d.ts +5 -1
  41. package/dist/providers/local-llm-provider.js +14 -6
  42. package/dist/providers/routing-llm-provider.d.ts +4 -0
  43. package/dist/providers/routing-llm-provider.js +12 -2
  44. package/dist/registry/agent-models.d.ts +1 -1
  45. package/dist/registry/agent-models.js +1 -1
  46. package/dist/registry/agent-registry-client.d.ts +2 -2
  47. package/dist/registry/deployment-snapshot.d.ts +4 -4
  48. package/dist/registry/deployment-snapshot.js +50 -28
  49. package/dist/registry/graph-loader.d.ts +1 -1
  50. package/dist/registry/graph-loader.js +39 -76
  51. package/dist/registry/index.d.ts +1 -1
  52. package/dist/registry/index.js +1 -1
  53. package/dist/registry/skill-tree.d.ts +3 -0
  54. package/dist/registry/skill-tree.js +41 -3
  55. package/dist/runtime/agent-runtime.d.ts +42 -3
  56. package/dist/runtime/agent-runtime.js +110 -34
  57. package/dist/runtime/dev-runtime.d.ts +6 -3
  58. package/dist/runtime/dev-runtime.js +21 -14
  59. package/dist/runtime/index.d.ts +3 -3
  60. package/dist/runtime/index.js +1 -1
  61. package/dist/runtime/storage-profile.d.ts +19 -10
  62. package/dist/runtime/storage-profile.js +42 -29
  63. package/dist/runtime/types.d.ts +15 -17
  64. package/dist/server.js +1 -1
  65. package/dist/session/session.service.d.ts +5 -0
  66. package/dist/session/session.service.js +12 -0
  67. package/dist/sse/events/index.d.ts +5 -3
  68. package/dist/sse/events/index.js +2 -0
  69. package/dist/sse/events/skill-events.d.ts +11 -0
  70. package/dist/sse/trace-collector.d.ts +10 -0
  71. package/dist/sse/trace-collector.js +1 -0
  72. package/dist/token/token-budget.service.d.ts +2 -2
  73. package/dist/token/token-budget.service.js +1 -1
  74. package/dist/tool/create-tool-executor.js +3 -2
  75. package/dist/tool/harness-primitives.d.ts +32 -0
  76. package/dist/tool/harness-primitives.js +385 -0
  77. package/dist/tool/http-tool-executor.js +1 -1
  78. package/dist/tool/index.d.ts +2 -1
  79. package/dist/tool/index.js +2 -1
  80. package/dist/tool/local-tool-executor.d.ts +3 -3
  81. package/dist/tool/local-tool-executor.js +5 -7
  82. package/dist/tool/mcp-tool-executor.js +9 -1
  83. package/dist/tool/system-prompt-builder.d.ts +61 -25
  84. package/dist/tool/system-prompt-builder.js +195 -92
  85. package/dist/tool/tool-execution-router.js +1 -1
  86. package/dist/tool/tool-executor.interface.d.ts +12 -6
  87. package/package.json +2 -2
@@ -30,8 +30,9 @@ import { RoutingLLMProvider } from '../providers/routing-llm-provider.js';
30
30
  import { createToolExecutor } from '../tool/create-tool-executor.js';
31
31
  import { MockToolExecutor } from '../tool/mock-tool-executor.js';
32
32
  import { DevToolExecutor } from '../tool/dev-tool-executor.js';
33
+ import { withHarnessPrimitives } from '../tool/harness-primitives.js';
33
34
  import { AllowAllGovernanceClient, HttpGovernanceClient, } from '../governance/index.js';
34
- import { InvokeOrchestrator, StreamOrchestrator, SessionService, MessageService, SessionContextService, TaskService, LangGraphAdapter, HitlHandler, TokenBudgetService, InMemoryTokenBudgetRepository, TokenStatsService, TokenBudgetGuard, SessionBudgetChecker, createAgentRegistryClient, GraphLoader, } from '../index.js';
35
+ import { InvokeOrchestrator, StreamOrchestrator, SessionService, MessageService, SessionContextService, TaskService, LangGraphAdapter, HitlHandler, TokenBudgetService, TokenStatsService, TokenBudgetGuard, SessionBudgetChecker, createAgentRegistryClient, GraphLoader, } from '../index.js';
35
36
  import { createAgentRuntime } from './agent-runtime.js';
36
37
  import { assembleRuntimeStorage } from './storage-profile.js';
37
38
  import { resolveSkillHotReload, watchPreinstallSkillRoot, watchSkillRoots } from '../registry/skill-tree.js';
@@ -46,43 +47,45 @@ export function createDevRuntime() {
46
47
  const foundationConfigured = Boolean(process.env.FOUNDATION_SERVICE_URL && process.env.FOUNDATION_SERVICE_URL.trim().length > 0);
47
48
  const toolExecutionMode = (process.env.EAP_TOOL_EXECUTION_MODE ?? 'mcp').toLowerCase();
48
49
  const deploymentContext = process.env.EAP_DEPLOYMENT_CONTEXT ?? 'server';
49
- // ── 存储 profile(默认 dev:File Session/Message/Checkpoint)──
50
- // 兼容旧变量:EAP_SESSION_STORE=memory → 强制 test(全内存)
51
- const legacySessionStore = process.env.EAP_SESSION_STORE?.toLowerCase();
50
+ // ── 存储:未配库默认文件;配齐 DATABASE + Redis 则 Redis+PG ──
52
51
  const storage = assembleRuntimeStorage({
53
- defaultProfile: legacySessionStore === 'memory' || legacySessionStore === 'in-memory' ? 'test' : 'dev',
54
- profile: legacySessionStore === 'memory' || legacySessionStore === 'in-memory'
55
- ? 'test'
56
- : undefined,
52
+ defaultProfile: 'dev',
57
53
  });
54
+ const turnLog = process.env.EAP_LLM_TURN_LOG === '0' ? undefined : storage.turnLog;
58
55
  // ── LLM Provider(本地 eap.config runtime.llm 优先,再 Foundation 路由,再环境直连)──
59
56
  let llmProviderKind;
60
57
  let llmProvider;
61
58
  const localLlm = process.env.EAP_LLM_MODE === 'local';
62
59
  if (localLlm || (!foundationConfigured && process.env.OPENAI_API_KEY)) {
63
60
  llmProvider = localLlm
64
- ? createLocalLlmProvider(requireLocalLlmConnections())
61
+ ? createLocalLlmProvider(requireLocalLlmConnections(), turnLog)
65
62
  : new HttpLLMProvider({
66
63
  apiKey: process.env.OPENAI_API_KEY ?? '',
67
64
  baseUrl: process.env.OPENAI_BASE_URL,
68
65
  defaultModel: process.env.EAP_DEFAULT_MODEL,
66
+ turnLog,
69
67
  });
70
68
  llmProviderKind = 'openai-http';
71
69
  }
72
70
  else if (foundationConfigured) {
73
- llmProvider = new RoutingLLMProvider({ foundationUrl });
71
+ llmProvider = new RoutingLLMProvider({ foundationUrl, turnLog });
74
72
  llmProviderKind = 'routing';
75
73
  }
76
74
  else {
77
- llmProvider = createDefaultLLMProvider();
75
+ llmProvider = createDefaultLLMProvider(turnLog);
78
76
  llmProviderKind = 'echo';
79
77
  }
80
78
  // ── Tool Executor(显式 mock → dev+mcp 直连,缺配置失败 → 通用路由)──
81
- const toolExecutor = toolExecutionMode === 'mock'
79
+ const needsHarnessWrap = toolExecutionMode === 'mock' ||
80
+ (toolExecutionMode === 'mcp' && deploymentContext === 'dev');
81
+ const innerExecutor = toolExecutionMode === 'mock'
82
82
  ? new MockToolExecutor({ toolsDir: process.env.EAP_LOCAL_TOOLS_DIR })
83
83
  : toolExecutionMode === 'mcp' && deploymentContext === 'dev'
84
84
  ? new DevToolExecutor()
85
85
  : createToolExecutor({ foundationUrl, deploymentContext });
86
+ const toolExecutor = needsHarnessWrap
87
+ ? withHarnessPrimitives(innerExecutor)
88
+ : innerExecutor;
86
89
  // ── Governance ──
87
90
  const governanceClient = process.env.GOVERNANCE_DISABLED === '1' || !foundationConfigured
88
91
  ? new AllowAllGovernanceClient()
@@ -99,7 +102,7 @@ export function createDevRuntime() {
99
102
  const sessionContextService = new SessionContextService(sessionService, messageService);
100
103
  // ── Task / Token ──
101
104
  const taskService = new TaskService();
102
- const budgetService = new TokenBudgetService(new InMemoryTokenBudgetRepository());
105
+ const budgetService = new TokenBudgetService(storage.tokenBudgetRepository);
103
106
  const tokenStatsService = new TokenStatsService();
104
107
  const tokenBudgetGuard = new TokenBudgetGuard(budgetService);
105
108
  const sessionBudgetChecker = new SessionBudgetChecker(budgetService);
@@ -168,6 +171,8 @@ export function createDevRuntime() {
168
171
  hitlHandler,
169
172
  graphLoader,
170
173
  messageService,
174
+ sessionService,
175
+ turnLog,
171
176
  });
172
177
  return {
173
178
  invokeOrchestrator,
@@ -177,6 +182,7 @@ export function createDevRuntime() {
177
182
  streamResumeHitl: (taskId, response) => agentRuntime.streamResumeHitl(taskId, response),
178
183
  sessionService,
179
184
  messageService,
185
+ turnLog,
180
186
  sessionContextService,
181
187
  taskService,
182
188
  tokenStatsService,
@@ -189,9 +195,10 @@ export function createDevRuntime() {
189
195
  llmDefaultModel: process.env.EAP_DEFAULT_MODEL ?? 'DeepSeek-V4-Pro',
190
196
  governanceKind: governanceClient instanceof AllowAllGovernanceClient ? 'AllowAll' : 'Http',
191
197
  storageProfile: storage.profile,
192
- sessionStoreKind: storage.diagnostics.sessionKind === 'file' ? 'file' : 'in-memory',
198
+ sessionStoreKind: storage.diagnostics.sessionKind,
193
199
  messageStoreKind: storage.diagnostics.messageKind,
194
200
  checkpointKind: storage.diagnostics.checkpointKind,
201
+ llmTurnKind: storage.diagnostics.llmTurnKind,
195
202
  foundationConfigured,
196
203
  skillHotReload,
197
204
  },
@@ -1,4 +1,4 @@
1
- export { AgentRuntime, createAgentRuntime, type AgentRuntimeDeps, type ForkRelationRecord, type RecordForkRelation, } from './agent-runtime.js';
2
- export type { ExecuteParams, ExecuteResult, ForkOverrides, ForkResult, HitlResponse, ResumeHitlResult, SSEEvent, } from './types.js';
1
+ export { AgentRuntime, createAgentRuntime, type AgentRuntimeDeps, type ForkRelationRecord, type RecordForkRelation, type ConversationDetail, } from './agent-runtime.js';
2
+ export type { ExecuteParams, ExecuteResult, ForkParams, ForkOverrides, ForkResult, HitlResponse, ResumeHitlResult, SSEEvent, } from './types.js';
3
3
  export { createDevRuntime, type DevRuntime, } from './dev-runtime.js';
4
- export { assembleRuntimeStorage, resolveRuntimeStorageProfile, type RuntimeStorageProfile, type AssembleRuntimeStorageOptions, type AssembledRuntimeStorage, } from './storage-profile.js';
4
+ export { assembleRuntimeStorage, resolveRuntimeStorageProfile, resolveDevStorageDirs, type RuntimeStorageProfile, type AssembleRuntimeStorageOptions, type AssembledRuntimeStorage, } from './storage-profile.js';
@@ -1,3 +1,3 @@
1
1
  export { AgentRuntime, createAgentRuntime, } from './agent-runtime.js';
2
2
  export { createDevRuntime, } from './dev-runtime.js';
3
- export { assembleRuntimeStorage, resolveRuntimeStorageProfile, } from './storage-profile.js';
3
+ export { assembleRuntimeStorage, resolveRuntimeStorageProfile, resolveDevStorageDirs, } from './storage-profile.js';
@@ -9,11 +9,13 @@ import type { ICheckpointSaver } from '../checkpoint/contracts/checkpoint-saver.
9
9
  import { type IPgPool } from '../checkpoint/pg-checkpoint-saver.js';
10
10
  import type { ISessionRepository } from '../session/session.service.js';
11
11
  import type { IFullMessageRepository } from '../session/message.service.js';
12
+ import type { ILlmTurnLog } from '../debug/llm-turn-log.js';
13
+ import { type ITokenBudgetRepository } from '../token/token-budget.service.js';
12
14
  export type RuntimeStorageProfile = 'test' | 'dev' | 'integration' | 'production';
13
15
  export interface AssembleRuntimeStorageOptions {
14
16
  /** 显式 profile;缺省读 EAP_RUNTIME_STORAGE_PROFILE */
15
17
  profile?: RuntimeStorageProfile;
16
- /** 未指定 profile 时的默认值(dev-runtime → dev;embedded → integration) */
18
+ /** 未指定 profile 且未配库时的默认值(本地 CLI → `dev` 文件) */
17
19
  defaultProfile: RuntimeStorageProfile;
18
20
  /** File Checkpoint / Session / Message 根目录 */
19
21
  checkpointDir?: string;
@@ -31,20 +33,27 @@ export interface AssembledRuntimeStorage {
31
33
  /** undefined = SessionService 默认 InMemory */
32
34
  sessionRepository?: ISessionRepository;
33
35
  messageRepository: IFullMessageRepository;
36
+ turnLog: ILlmTurnLog;
37
+ tokenBudgetRepository: ITokenBudgetRepository;
34
38
  diagnostics: {
35
39
  profile: RuntimeStorageProfile;
36
- checkpointKind: 'memory' | 'file' | 'redis+pg' | 'pg';
37
- sessionKind: 'memory' | 'file';
38
- messageKind: 'memory' | 'file' | 'postgres';
40
+ checkpointKind: 'file' | 'redis+pg';
41
+ sessionKind: 'file' | 'hosting';
42
+ messageKind: 'file' | 'postgres';
43
+ llmTurnKind: 'file' | 'postgres';
44
+ tokenBudgetKind: 'process' | 'postgres';
39
45
  };
40
46
  }
41
47
  export declare function resolveRuntimeStorageProfile(explicit: RuntimeStorageProfile | undefined, defaultProfile: RuntimeStorageProfile, env?: NodeJS.ProcessEnv): RuntimeStorageProfile;
48
+ /** 本地 File 存储默认落工程 `.eap/`,可用 EAP_DATA_DIR / EAP_*_DIR 覆盖。 */
49
+ export declare function resolveDevStorageDirs(env?: NodeJS.ProcessEnv, cwd?: string): {
50
+ checkpointDir: string;
51
+ sessionDir: string;
52
+ messageDir: string;
53
+ };
42
54
  /**
43
- * 按 profile 装配 Checkpoint / Session / Message 存储
44
- *
45
- * - test: 全内存
46
- * - dev: File Checkpoint + File Session + File Message
47
- * - integration/production: Message=PG;Checkpoint=Redis 热 + PG 备;
48
- * Session 仓储不落 PG(sessionId 权威在 Hosting.sessions,Runtime 内存采纳)
55
+ * 按 profile 装配 Checkpoint / Message / Token / LLM 回合存储。
56
+ * `dev`:文件。其余 profile:Redis + PostgreSQL(缺配置则抛错)。
57
+ * 未设 profile 时:已配置 DB 或 Redis 则按 Redis+PostgreSQL;否则使用 defaultProfile。
49
58
  */
50
59
  export declare function assembleRuntimeStorage(options: AssembleRuntimeStorageOptions, env?: NodeJS.ProcessEnv): AssembledRuntimeStorage;
@@ -6,16 +6,19 @@
6
6
  */
7
7
  // @ts-expect-error pg 无内置类型;Hosting 侧同样按 any 使用
8
8
  import pg from 'pg';
9
+ import path from 'node:path';
9
10
  import { Redis } from 'ioredis';
10
11
  import { FileCheckpointSaver } from '../checkpoint/file-checkpoint-saver.js';
11
12
  import { PostgresCheckpointSaver } from '../checkpoint/pg-checkpoint-saver.js';
12
13
  import { RedisCheckpointSaver } from '../checkpoint/redis-checkpoint-saver.js';
13
14
  import { CompositeCheckpointSaver } from '../checkpoint/composite-checkpoint-saver.js';
14
- import { InMemoryCheckpointSaver } from '../checkpoint/in-memory-checkpoint-saver.js';
15
15
  import { FileSessionRepository } from '../session/file-session.repository.js';
16
- import { InMemoryFullMessageRepository } from '../session/message.service.js';
17
16
  import { FileMessageRepository } from '../session/file-message.repository.js';
18
17
  import { PostgresMessageRepository } from '../session/pg-message.repository.js';
18
+ import { FileLlmTurnLog, resolveLlmTurnDir } from '../debug/llm-turn-log.js';
19
+ import { PostgresLlmTurnLog } from '../debug/pg-llm-turn-log.js';
20
+ import { InMemoryTokenBudgetRepository } from '../token/token-budget.service.js';
21
+ import { PostgresTokenBudgetRepository } from '../token/pg-token-budget.repository.js';
19
22
  const { Pool } = pg;
20
23
  const VALID_PROFILES = new Set([
21
24
  'test',
@@ -23,11 +26,20 @@ const VALID_PROFILES = new Set([
23
26
  'integration',
24
27
  'production',
25
28
  ]);
29
+ function hasDbEnv(env) {
30
+ return Boolean(env.DATABASE_URL?.trim() || (env.DB_HOST && env.DB_NAME && env.DB_USER));
31
+ }
32
+ function hasRedisEnv(env) {
33
+ return Boolean(env.REDIS_URL?.trim() || env.REDIS_HOST);
34
+ }
26
35
  export function resolveRuntimeStorageProfile(explicit, defaultProfile, env = process.env) {
27
36
  const raw = explicit ?? env.EAP_RUNTIME_STORAGE_PROFILE;
28
37
  if (raw && VALID_PROFILES.has(raw)) {
29
38
  return raw;
30
39
  }
40
+ if (hasDbEnv(env) || hasRedisEnv(env)) {
41
+ return 'integration';
42
+ }
31
43
  return defaultProfile;
32
44
  }
33
45
  function requireDbEnv(env) {
@@ -39,12 +51,12 @@ function requireDbEnv(env) {
39
51
  if (!env.DB_USER && !env.DATABASE_URL)
40
52
  missing.push('DB_USER 或 DATABASE_URL');
41
53
  if (missing.length > 0) {
42
- throw new Error(`[EAP_RUNTIME_STORAGE_PROFILE] integration/production 缺少数据库配置: ${missing.join(', ')}`);
54
+ throw new Error(`[EAP_RUNTIME_STORAGE_PROFILE] Redis+PostgreSQL 路径缺少数据库配置: ${missing.join(', ')}`);
43
55
  }
44
56
  }
45
57
  function requireRedisEnv(env) {
46
58
  if (!env.REDIS_HOST && !env.REDIS_URL) {
47
- throw new Error('[EAP_RUNTIME_STORAGE_PROFILE] integration/production 缺少 REDIS_HOST 或 REDIS_URL(禁止回退 File Checkpoint)');
59
+ throw new Error('[EAP_RUNTIME_STORAGE_PROFILE] Redis+PostgreSQL 路径缺少 REDIS_HOST 或 REDIS_URL');
48
60
  }
49
61
  }
50
62
  function createPgPoolFromEnv(env) {
@@ -73,44 +85,41 @@ function createRedisFromEnv(env) {
73
85
  maxRetriesPerRequest: 1,
74
86
  });
75
87
  }
88
+ /** 本地 File 存储默认落工程 `.eap/`,可用 EAP_DATA_DIR / EAP_*_DIR 覆盖。 */
89
+ export function resolveDevStorageDirs(env = process.env, cwd = process.cwd()) {
90
+ const root = env.EAP_DATA_DIR?.trim() || path.join(cwd, '.eap');
91
+ const checkpointDir = env.EAP_CHECKPOINT_DIR?.trim() || path.join(root, 'checkpoints');
92
+ const sessionDir = env.EAP_SESSION_DIR?.trim() || path.join(root, 'sessions');
93
+ const messageDir = env.EAP_MESSAGE_DIR?.trim() || path.join(sessionDir, 'messages');
94
+ return { checkpointDir, sessionDir, messageDir };
95
+ }
76
96
  /**
77
- * 按 profile 装配 Checkpoint / Session / Message 存储
78
- *
79
- * - test: 全内存
80
- * - dev: File Checkpoint + File Session + File Message
81
- * - integration/production: Message=PG;Checkpoint=Redis 热 + PG 备;
82
- * Session 仓储不落 PG(sessionId 权威在 Hosting.sessions,Runtime 内存采纳)
97
+ * 按 profile 装配 Checkpoint / Message / Token / LLM 回合存储。
98
+ * `dev`:文件。其余 profile:Redis + PostgreSQL(缺配置则抛错)。
99
+ * 未设 profile 时:已配置 DB 或 Redis 则按 Redis+PostgreSQL;否则使用 defaultProfile。
83
100
  */
84
101
  export function assembleRuntimeStorage(options, env = process.env) {
85
102
  const profile = resolveRuntimeStorageProfile(options.profile, options.defaultProfile, env);
86
- const checkpointDir = options.checkpointDir ?? env.EAP_CHECKPOINT_DIR ?? '/tmp/eap-checkpoints';
87
- const sessionDir = options.sessionDir ?? env.EAP_SESSION_DIR ?? '/tmp/eap-sessions';
88
- const messageDir = options.messageDir ?? env.EAP_MESSAGE_DIR ?? `${sessionDir.replace(/\/$/, '')}/messages`;
89
- if (profile === 'test') {
90
- return {
91
- profile,
92
- checkpointSaver: new InMemoryCheckpointSaver(),
93
- sessionRepository: undefined,
94
- messageRepository: new InMemoryFullMessageRepository(),
95
- diagnostics: {
96
- profile,
97
- checkpointKind: 'memory',
98
- sessionKind: 'memory',
99
- messageKind: 'memory',
100
- },
101
- };
102
- }
103
- if (profile === 'dev') {
103
+ const defaults = resolveDevStorageDirs(env);
104
+ const checkpointDir = options.checkpointDir ?? defaults.checkpointDir;
105
+ const sessionDir = options.sessionDir ?? defaults.sessionDir;
106
+ const messageDir = options.messageDir ?? defaults.messageDir;
107
+ const useFiles = profile === 'dev';
108
+ if (useFiles) {
104
109
  return {
105
110
  profile,
106
111
  checkpointSaver: new FileCheckpointSaver(checkpointDir),
107
112
  sessionRepository: new FileSessionRepository({ baseDir: sessionDir }),
108
113
  messageRepository: new FileMessageRepository({ baseDir: messageDir }),
114
+ turnLog: new FileLlmTurnLog(resolveLlmTurnDir(env)),
115
+ tokenBudgetRepository: new InMemoryTokenBudgetRepository(),
109
116
  diagnostics: {
110
117
  profile,
111
118
  checkpointKind: 'file',
112
119
  sessionKind: 'file',
113
120
  messageKind: 'file',
121
+ llmTurnKind: 'file',
122
+ tokenBudgetKind: 'process',
114
123
  },
115
124
  };
116
125
  }
@@ -128,11 +137,15 @@ export function assembleRuntimeStorage(options, env = process.env) {
128
137
  checkpointSaver,
129
138
  sessionRepository: undefined,
130
139
  messageRepository: new PostgresMessageRepository(pool),
140
+ turnLog: new PostgresLlmTurnLog(pool),
141
+ tokenBudgetRepository: new PostgresTokenBudgetRepository(pool),
131
142
  diagnostics: {
132
143
  profile,
133
144
  checkpointKind: 'redis+pg',
134
- sessionKind: 'memory',
145
+ sessionKind: 'hosting',
135
146
  messageKind: 'postgres',
147
+ llmTurnKind: 'postgres',
148
+ tokenBudgetKind: 'postgres',
136
149
  },
137
150
  };
138
151
  }
@@ -12,12 +12,8 @@ import type { GraphMessage } from '../graph/contracts/executable-graph.js';
12
12
  import type { SSEEvent } from '../sse/contracts/sse-emitter.contract.js';
13
13
  /** 同步/流式执行参数 */
14
14
  export interface ExecuteParams {
15
- /**
16
- * @deprecated 使用 agentCode;保留仅为迁移双读
17
- */
18
- agentId?: string;
19
- /** 对外主键(优先) */
20
- agentCode?: string;
15
+ /** 对外主键 */
16
+ agentCode: string;
21
17
  input: string;
22
18
  /** 平台执行上下文(Hosting / eap dev 注入,对齐 04 R15) */
23
19
  executionContext?: ExecutionContext;
@@ -48,6 +44,16 @@ export interface HitlResponse {
48
44
  */
49
45
  threadId?: string;
50
46
  }
47
+ /** Fork 入参:上层先发 taskId / traceId,Runtime 不再 createFlow */
48
+ export interface ForkParams {
49
+ checkpointId: string;
50
+ /** 上层已发号的 Task ID(Hosting createTask / 本地 UUID) */
51
+ taskId: string;
52
+ /** 上层已创建的 Trace id(Hosting createTrace / 本地 UUID) */
53
+ traceId: string;
54
+ executionContext?: ExecutionContext;
55
+ overrides?: ForkOverrides;
56
+ }
51
57
  /** Fork 参数覆盖 */
52
58
  export interface ForkOverrides {
53
59
  model?: string;
@@ -56,11 +62,7 @@ export interface ForkOverrides {
56
62
  state?: Record<string, unknown>;
57
63
  /** 源 Trace ID(未提供时从 checkpoint 元数据读取) */
58
64
  originalTraceId?: string;
59
- /**
60
- * @deprecated 使用 agentCode
61
- */
62
- agentId?: string;
63
- /** 执行所用 Agent(未提供时从 checkpoint state 读取) */
65
+ /** 执行所用 Agent(未提供时从 checkpoint state.agentCode 读取) */
64
66
  agentCode?: string;
65
67
  /** 预装版本(未提供时从 checkpoint state.agentVersion 读取) */
66
68
  agentVersion?: string;
@@ -95,12 +97,8 @@ export interface ForkResult {
95
97
  * - 该 session 已有历史时,视作已种入,跳过写入(exactly-once 幂等)。
96
98
  */
97
99
  export interface SeedSessionMessagesParams {
98
- /**
99
- * @deprecated 使用 agentCode;保留仅为迁移双读
100
- */
101
- agentId?: string;
102
- /** 对外主键(优先) */
103
- agentCode?: string;
100
+ /** 对外主键 */
101
+ agentCode: string;
104
102
  /** 预装版本(写入 session.metadata.agentVersion,续聊回退) */
105
103
  agentVersion?: string;
106
104
  /** 会话 ID;未提供时新建 session */
package/dist/server.js CHANGED
@@ -49,7 +49,7 @@ const server = createServer(async (req, res) => {
49
49
  if (req.method === 'GET' && url.pathname === '/metrics') {
50
50
  sendJson(res, 200, {
51
51
  mode: 'standalone',
52
- checkpointDir: process.env.EAP_CHECKPOINT_DIR ?? '/tmp/eap-checkpoints',
52
+ checkpointDir: process.env.EAP_CHECKPOINT_DIR ?? '.eap/checkpoints',
53
53
  foundationUrl: process.env.FOUNDATION_SERVICE_URL ?? 'http://localhost:3100',
54
54
  });
55
55
  return;
@@ -102,6 +102,8 @@ export interface ISessionRepository {
102
102
  findById(id: string): Promise<SessionRecord | null>;
103
103
  findByUserId(userId: string, limit?: number, offset?: number): Promise<SessionRecord[]>;
104
104
  update(session: SessionRecord): Promise<void>;
105
+ /** 本地排查:列出全部未删除会话(File / 内存实现;PG 可不提供) */
106
+ listAll?(): Promise<SessionRecord[]>;
105
107
  }
106
108
  /**
107
109
  * IMessageRepository — Message 查询接口(最小定义)
@@ -143,6 +145,7 @@ export declare class InMemorySessionRepository implements ISessionRepository {
143
145
  findById(id: string): Promise<SessionRecord | null>;
144
146
  findByUserId(userId: string, limit?: number, offset?: number): Promise<SessionRecord[]>;
145
147
  update(session: SessionRecord): Promise<void>;
148
+ listAll(): Promise<SessionRecord[]>;
146
149
  }
147
150
  /**
148
151
  * InMemoryMessageRepository — 内存 Message 存储(stub)
@@ -181,6 +184,8 @@ export declare class SessionService {
181
184
  limit?: number;
182
185
  offset?: number;
183
186
  }): Promise<SessionRecord[]>;
187
+ /** 本地排查:列出全部会话(仓储未实现 listAll 时返回空) */
188
+ listAllSessions(): Promise<SessionRecord[]>;
184
189
  /**
185
190
  * 归档 Session(标记为 archived)
186
191
  */
@@ -35,6 +35,11 @@ export class InMemorySessionRepository {
35
35
  async update(session) {
36
36
  this.store.set(session.id, { ...session });
37
37
  }
38
+ async listAll() {
39
+ return Array.from(this.store.values())
40
+ .filter((s) => !s.isDeleted)
41
+ .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
42
+ }
38
43
  }
39
44
  /**
40
45
  * InMemoryMessageRepository — 内存 Message 存储(stub)
@@ -138,6 +143,13 @@ export class SessionService {
138
143
  async listSessions(userId, options) {
139
144
  return this.sessionRepository.findByUserId(userId, options?.limit, options?.offset);
140
145
  }
146
+ /** 本地排查:列出全部会话(仓储未实现 listAll 时返回空) */
147
+ async listAllSessions() {
148
+ if (typeof this.sessionRepository.listAll !== 'function') {
149
+ return [];
150
+ }
151
+ return this.sessionRepository.listAll();
152
+ }
141
153
  /**
142
154
  * 归档 Session(标记为 archived)
143
155
  */
@@ -39,13 +39,13 @@ export declare const CORE_SSE_EVENTS: readonly ["session.created", "task.started
39
39
  /**
40
40
  * 可选事件类型(Agent 按需支持)
41
41
  */
42
- export declare const OPTIONAL_SSE_EVENTS: readonly ["skill.matched", "skill.unmatched", "skill.started", "skill.completed", "skill.failed", "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"];
42
+ export declare const OPTIONAL_SSE_EVENTS: readonly ["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"];
43
43
  /**
44
44
  * SSEEventType — SSE 事件类型字符串联合类型
45
45
  */
46
- 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' | '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';
46
+ 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';
47
47
  import type { SessionCreatedPayload, TaskStartedPayload, TaskCompletedPayload, TaskErrorPayload } from './session-events.js';
48
- import type { SkillMatchedPayload, SkillUnmatchedPayload, SkillStartedPayload, SkillCompletedPayload, SkillFailedPayload } from './skill-events.js';
48
+ import type { SkillMatchedPayload, SkillUnmatchedPayload, SkillStartedPayload, SkillCompletedPayload, SkillFailedPayload, SkillLoadedPayload, SkillResourceReadPayload } from './skill-events.js';
49
49
  import type { ReasoningStartedPayload, ReasoningStepPayload, ResponseChunkPayload } from './reasoning-events.js';
50
50
  import type { ToolCalledPayload, ToolResultPayload, ToolProgressPayload, ToolErrorPayload } from './tool-events.js';
51
51
  import type { FileCreatedPayload, FileUpdatedPayload } from './file-events.js';
@@ -79,6 +79,8 @@ export interface SSEEventPayloadMap {
79
79
  'skill.started': SkillStartedPayload;
80
80
  'skill.completed': SkillCompletedPayload;
81
81
  'skill.failed': SkillFailedPayload;
82
+ 'skill.loaded': SkillLoadedPayload;
83
+ 'skill.resource_read': SkillResourceReadPayload;
82
84
  'reasoning.step': ReasoningStepPayload;
83
85
  'tool.progress': ToolProgressPayload;
84
86
  'file.created': FileCreatedPayload;
@@ -59,6 +59,8 @@ export const OPTIONAL_SSE_EVENTS = [
59
59
  'skill.started',
60
60
  'skill.completed',
61
61
  'skill.failed',
62
+ 'skill.loaded',
63
+ 'skill.resource_read',
62
64
  'reasoning.step',
63
65
  'tool.progress',
64
66
  'file.created',
@@ -46,3 +46,14 @@ export interface SkillFailedPayload {
46
46
  skillName: string;
47
47
  error: string;
48
48
  }
49
+ /** 读入 SKILL.md(Harness,不是业务 Tool) */
50
+ export interface SkillLoadedPayload {
51
+ skillId: string;
52
+ skillName?: string;
53
+ path: string;
54
+ }
55
+ /** 读取 Skill 包内附属文件 */
56
+ export interface SkillResourceReadPayload {
57
+ skillId?: string;
58
+ path: string;
59
+ }
@@ -32,6 +32,16 @@ export declare class InMemoryTraceCollector implements ITraceCollector {
32
32
  status: 'completed' | 'failed';
33
33
  error?: string;
34
34
  }): Promise<void>;
35
+ recordCheckpointRef(_input: {
36
+ checkpointId: string;
37
+ traceId: string;
38
+ spanId: string;
39
+ summary?: {
40
+ nodeId?: string;
41
+ threadId?: string;
42
+ step?: number;
43
+ };
44
+ }): Promise<void>;
35
45
  /** 获取所有会话(调试用) */
36
46
  getAllSessions(): TraceSession[];
37
47
  }
@@ -54,6 +54,7 @@ export class InMemoryTraceCollector {
54
54
  return `link-node-${randomUUID()}`;
55
55
  }
56
56
  async completeLinkNode(_nodeId, _params) { }
57
+ async recordCheckpointRef(_input) { }
57
58
  /** 获取所有会话(调试用) */
58
59
  getAllSessions() {
59
60
  return Array.from(this.sessions.values());
@@ -32,7 +32,7 @@ export interface BudgetRecord {
32
32
  /**
33
33
  * ITokenBudgetRepository — 配额记录持久化抽象
34
34
  *
35
- * 由 InMemoryTokenBudgetRepository(默认)或 MySQL 实现注入。
35
+ * 由 InMemoryTokenBudgetRepository 或 PostgresTokenBudgetRepository 注入。
36
36
  */
37
37
  export interface ITokenBudgetRepository {
38
38
  /**
@@ -47,7 +47,7 @@ export interface ITokenBudgetRepository {
47
47
  /**
48
48
  * InMemoryTokenBudgetRepository — 基于 Map 的内存持久化
49
49
  *
50
- * 适用于单进程/测试场景。生产环境应替换为 MySQL 实现。
50
+ * 用于 `profile=dev` 文件路径及单测。Redis+PostgreSQL 路径使用 PostgresTokenBudgetRepository。
51
51
  */
52
52
  export declare class InMemoryTokenBudgetRepository implements ITokenBudgetRepository {
53
53
  private store;
@@ -15,7 +15,7 @@
15
15
  /**
16
16
  * InMemoryTokenBudgetRepository — 基于 Map 的内存持久化
17
17
  *
18
- * 适用于单进程/测试场景。生产环境应替换为 MySQL 实现。
18
+ * 用于 `profile=dev` 文件路径及单测。Redis+PostgreSQL 路径使用 PostgresTokenBudgetRepository。
19
19
  */
20
20
  export class InMemoryTokenBudgetRepository {
21
21
  store = new Map();
@@ -9,6 +9,7 @@ import { HttpToolExecutor } from './http-tool-executor.js';
9
9
  import { McpToolExecutor } from './mcp-tool-executor.js';
10
10
  import { LocalToolExecutor } from './local-tool-executor.js';
11
11
  import { ToolExecutionRouter, } from './tool-execution-router.js';
12
+ import { withHarnessPrimitives } from './harness-primitives.js';
12
13
  export class EmptyInstallStore {
13
14
  get() {
14
15
  return null;
@@ -48,7 +49,7 @@ export function createToolExecutor(options) {
48
49
  const transport = resolveGatewayTransport(options.gatewayTransport);
49
50
  const serverExecutor = createServerExecutor(options.foundationUrl, transport, options.httpTimeout);
50
51
  const localExecutor = new LocalToolExecutor({ installStore });
51
- return new ToolExecutionRouter({
52
+ return withHarnessPrimitives(new ToolExecutionRouter({
52
53
  httpExecutor: serverExecutor,
53
54
  localExecutor,
54
55
  installStore,
@@ -56,5 +57,5 @@ export function createToolExecutor(options) {
56
57
  toolTypes: options.toolTypes,
57
58
  toolRuntimes: options.toolRuntimes,
58
59
  forceToolServer: options.forceToolServer,
59
- });
60
+ }));
60
61
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 平台默认 Harness 原语:read_file / write_file / execute_command。
3
+ *
4
+ * 不写进 agent.manifest.toolsets。同名业务工具优先(问数 file-io 等)。
5
+ * 读:工作目录 + 技能包 + EAP_LOCAL_SKILLS_DIR + FILE_IO_ROOT。
6
+ * 写:仅工作目录,且不跟随符号链接。
7
+ * 命令:cwd 落在 jail 内;环境变量白名单,不继承 process.env。
8
+ */
9
+ import type { LoadedToolMap } from './loaded-tool-definition.js';
10
+ import type { IToolExecutor, ToolCallRequest, ToolCallResult } from './tool-executor.interface.js';
11
+ export declare function mergeHarnessPrimitives(loadedTools: LoadedToolMap | undefined): LoadedToolMap | undefined;
12
+ /** 装配点:业务 toolsets + 平台 Harness 原语。 */
13
+ export declare function assembleLoadedTools(loadedTools: LoadedToolMap | undefined): LoadedToolMap | undefined;
14
+ export interface HarnessJailOptions {
15
+ workdir?: string;
16
+ extraRoots?: string[];
17
+ }
18
+ export declare function resolveJailRoots(options?: HarnessJailOptions): string[];
19
+ export declare function resolveJailedPath(requested: string, roots: string[], opts?: {
20
+ mustExist?: boolean;
21
+ }): string;
22
+ export declare class HarnessPrimitiveExecutor implements IToolExecutor {
23
+ private readonly workdir?;
24
+ private readonly extraRoots?;
25
+ constructor(options?: HarnessJailOptions);
26
+ private rootsFor;
27
+ execute(request: ToolCallRequest): Promise<ToolCallResult>;
28
+ private readFile;
29
+ private writeFile;
30
+ private executeCommand;
31
+ }
32
+ export declare function withHarnessPrimitives(inner: IToolExecutor, options?: HarnessJailOptions): IToolExecutor;