@gt-fe/eap-runtime 0.0.17 → 0.0.18

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/README.md CHANGED
@@ -277,26 +277,28 @@ EAP_TOOL_EXECUTION_MODE=mcp # 仅 createDevRuntime / eap chat
277
277
 
278
278
  ---
279
279
 
280
- ## 11. 发布到公司私有 npm(可选)
280
+ ## 11. 发布 npm 包
281
281
 
282
- 私服:`https://maven.gtcloud.cn/repository/npm-local/`(模板 [`.npmrc.example`](./.npmrc.example))。
282
+ 升版、CHANGELOG、`git commit` / `git push` 不在脚本里,先做完再跑脚本。脚本只做构建、发布、核对 registry 上的版本号。
283
283
 
284
- > `@eap:registry=...` 须写入 `.npmrc` 文件,不可在 shell 中作为命令直接执行。
284
+ | 脚本 | 包 | registry |
285
+ |------|----|----------|
286
+ | [`scripts/publish-intranet.sh`](./scripts/publish-intranet.sh) | `@eap/runtime` | Nexus `https://maven.gtcloud.cn/repository/npm-local/` |
287
+ | [`scripts/publish-public.sh`](./scripts/publish-public.sh) | `@gt-fe/eap-runtime` | npmjs。临时目录改名;dist 里 `@eap/contracts` 改为 `@gt-fe/eap-contracts`。不改源码 `package.json` |
285
288
 
286
289
  ```bash
290
+ # 登录(一次性)
287
291
  cp .npmrc.example .npmrc
288
292
  npm login --registry https://maven.gtcloud.cn/repository/npm-local/
293
+ npm login --registry https://registry.npmjs.org/
289
294
 
290
- # 1) 先发 @eap/contracts(version 改为目标版,如 0.0.1)
291
- cd ../eap-contracts && cp .npmrc.example .npmrc
292
- pnpm run build && npm publish --registry https://maven.gtcloud.cn/repository/npm-local/
293
-
294
- # 2) runtime:package.json 中 @eap/contracts 改为版本号(勿再用 file:)
295
- cd ../runtime && pnpm run build
296
- npm publish --registry https://maven.gtcloud.cn/repository/npm-local/
295
+ ./scripts/publish-intranet.sh
296
+ ./scripts/publish-public.sh
297
297
  ```
298
298
 
299
- 含 `_authToken` 的 `.npmrc` 已 gitignore,勿提交凭证。
299
+ 不要在源码目录对 npmjs 执行 `npm publish`(`publishConfig` 指向 Nexus;公网 dist 必须改写 contracts)。含 `_authToken` 的 `.npmrc` 已 gitignore,勿提交凭证。`@eap:registry=...` 须写入 `.npmrc` 文件,不可在 shell 中当命令执行。
300
+
301
+ UAT Hosting 吃公网包:把 `@eap/runtime` 指到 `npm:@gt-fe/eap-runtime@<本版>` 后重建镜像。
300
302
 
301
303
  ---
302
304
 
@@ -40,13 +40,17 @@ export interface CreateCheckpointParams {
40
40
  * 确保所有必要字段的一致性。
41
41
  */
42
42
  export declare function createCheckpointData(params: CreateCheckpointParams): CheckpointData;
43
+ /**
44
+ * 落盘用快照:可 JSON 往返的数据留下;定时器 / 函数 / 环丢掉。
45
+ * 环用栈判定,同一对象出现两次但不成环(菱形)仍保留。
46
+ */
47
+ export declare function toJsonSafe(value: unknown, stack?: Set<object>): unknown;
48
+ /** 所有 Checkpoint Saver 落盘共用,禁止裸 JSON.stringify(state)。 */
49
+ export declare function stringifyJsonSafe(value: unknown): string;
43
50
  /**
44
51
  * 序列化 CheckpointData 为 JSON 字符串
45
52
  *
46
- * 处理边界情况:
47
- * - Date 对象 → ISO 字符串
48
- * - undefined 值自动剔除(JSON.stringify 默认行为)
49
- * - 循环引用检测(抛出明确错误而非默认 TypeError)
53
+ * Date → ISO;定时器 / 循环引用省略,不抛 TypeError。
50
54
  */
51
55
  export declare function serializeCheckpoint(data: CheckpointData): string;
52
56
  /**
@@ -37,30 +37,69 @@ export function createCheckpointData(params) {
37
37
  // ─────────────────────────────────────────────
38
38
  // 序列化 / 反序列化
39
39
  // ─────────────────────────────────────────────
40
+ function isTimerHandle(value) {
41
+ const name = value.constructor?.name;
42
+ if (name === 'Timeout' || name === 'TimersList' || name === 'Immediate')
43
+ return true;
44
+ return Object.prototype.hasOwnProperty.call(value, '_idlePrev')
45
+ && Object.prototype.hasOwnProperty.call(value, '_idleNext');
46
+ }
47
+ /**
48
+ * 落盘用快照:可 JSON 往返的数据留下;定时器 / 函数 / 环丢掉。
49
+ * 环用栈判定,同一对象出现两次但不成环(菱形)仍保留。
50
+ */
51
+ export function toJsonSafe(value, stack = new Set()) {
52
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
53
+ return value;
54
+ if (typeof value === 'number')
55
+ return Number.isFinite(value) ? value : null;
56
+ if (typeof value === 'bigint')
57
+ return value.toString();
58
+ if (typeof value === 'undefined' || typeof value === 'function' || typeof value === 'symbol') {
59
+ return undefined;
60
+ }
61
+ if (value instanceof Date)
62
+ return value.toISOString();
63
+ if (typeof value !== 'object')
64
+ return undefined;
65
+ if (isTimerHandle(value))
66
+ return undefined;
67
+ if (stack.has(value))
68
+ return undefined;
69
+ const maybeToJSON = value.toJSON;
70
+ if (typeof maybeToJSON === 'function') {
71
+ return toJsonSafe(maybeToJSON.call(value), stack);
72
+ }
73
+ if (Array.isArray(value)) {
74
+ stack.add(value);
75
+ const out = value.map((item) => {
76
+ const next = toJsonSafe(item, stack);
77
+ return next === undefined ? null : next;
78
+ });
79
+ stack.delete(value);
80
+ return out;
81
+ }
82
+ stack.add(value);
83
+ const out = {};
84
+ for (const [key, child] of Object.entries(value)) {
85
+ const next = toJsonSafe(child, stack);
86
+ if (next !== undefined)
87
+ out[key] = next;
88
+ }
89
+ stack.delete(value);
90
+ return out;
91
+ }
92
+ /** 所有 Checkpoint Saver 落盘共用,禁止裸 JSON.stringify(state)。 */
93
+ export function stringifyJsonSafe(value) {
94
+ return JSON.stringify(toJsonSafe(value));
95
+ }
40
96
  /**
41
97
  * 序列化 CheckpointData 为 JSON 字符串
42
98
  *
43
- * 处理边界情况:
44
- * - Date 对象 → ISO 字符串
45
- * - undefined 值自动剔除(JSON.stringify 默认行为)
46
- * - 循环引用检测(抛出明确错误而非默认 TypeError)
99
+ * Date → ISO;定时器 / 循环引用省略,不抛 TypeError。
47
100
  */
48
101
  export function serializeCheckpoint(data) {
49
- const seen = new WeakSet();
50
- return JSON.stringify(data, (_key, value) => {
51
- // Date → ISO 字符串
52
- if (value instanceof Date) {
53
- return value.toISOString();
54
- }
55
- // 循环引用检测
56
- if (typeof value === 'object' && value !== null) {
57
- if (seen.has(value)) {
58
- throw new Error(`[CheckpointSerializer] Circular reference detected during serialization`);
59
- }
60
- seen.add(value);
61
- }
62
- return value;
63
- });
102
+ return stringifyJsonSafe(data);
64
103
  }
65
104
  /**
66
105
  * 反序列化 JSON 字符串为 CheckpointData
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
6
6
  import { join } from 'node:path';
7
+ import { stringifyJsonSafe } from './checkpoint-serializer.js';
7
8
  export class FileCheckpointSaver {
8
9
  baseDir;
9
10
  constructor(baseDir) {
@@ -12,7 +13,7 @@ export class FileCheckpointSaver {
12
13
  async save(threadId, data) {
13
14
  const dir = join(this.baseDir, threadId);
14
15
  await mkdir(dir, { recursive: true });
15
- await writeFile(join(dir, `${data.checkpointId}.json`), JSON.stringify(data));
16
+ await writeFile(join(dir, `${data.checkpointId}.json`), stringifyJsonSafe(data));
16
17
  // 更新 latest 指针
17
18
  await writeFile(join(dir, 'latest.json'), JSON.stringify({ checkpointId: data.checkpointId }));
18
19
  }
@@ -4,7 +4,7 @@ export type { RedisCheckpointSaverOptions } from './redis-checkpoint-saver.js';
4
4
  export { CompositeCheckpointSaver } from './composite-checkpoint-saver.js';
5
5
  export { restoreCheckpoint } from './restore-checkpoint.js';
6
6
  export { notifyCheckpointRef, stripCheckpointCollectors } from './checkpoint-ref-notify.js';
7
- export { createCheckpointData, serializeCheckpoint, deserializeCheckpoint, } from './checkpoint-serializer.js';
7
+ export { createCheckpointData, serializeCheckpoint, deserializeCheckpoint, stringifyJsonSafe, toJsonSafe, } from './checkpoint-serializer.js';
8
8
  export type { CreateCheckpointParams } from './checkpoint-serializer.js';
9
9
  export { FileCheckpointSaver } from './file-checkpoint-saver.js';
10
10
  export { InMemoryCheckpointSaver } from './in-memory-checkpoint-saver.js';
@@ -4,7 +4,7 @@ export { RedisCheckpointSaver } from './redis-checkpoint-saver.js';
4
4
  export { CompositeCheckpointSaver } from './composite-checkpoint-saver.js';
5
5
  export { restoreCheckpoint } from './restore-checkpoint.js';
6
6
  export { notifyCheckpointRef, stripCheckpointCollectors } from './checkpoint-ref-notify.js';
7
- export { createCheckpointData, serializeCheckpoint, deserializeCheckpoint, } from './checkpoint-serializer.js';
7
+ export { createCheckpointData, serializeCheckpoint, deserializeCheckpoint, stringifyJsonSafe, toJsonSafe, } from './checkpoint-serializer.js';
8
8
  export { FileCheckpointSaver } from './file-checkpoint-saver.js';
9
9
  export { InMemoryCheckpointSaver } from './in-memory-checkpoint-saver.js';
10
10
  export { MongoCheckpointSaver } from './mongo-checkpoint-saver.js';
@@ -7,6 +7,7 @@
7
7
  * @see design.md §1.3 checkpoints 数据模型
8
8
  * @see checkpoint-saver.contract.ts ICheckpointSaver 接口定义
9
9
  */
10
+ import { stringifyJsonSafe } from './checkpoint-serializer.js';
10
11
  // ─────────────────────────────────────────────
11
12
  // PostgresCheckpointSaver
12
13
  // ─────────────────────────────────────────────
@@ -38,9 +39,9 @@ export class PostgresCheckpointSaver {
38
39
  threadId,
39
40
  data.checkpointId,
40
41
  data.currentNodeId,
41
- JSON.stringify(data.historyPath),
42
- JSON.stringify(data.state),
43
- data.engineSnapshot == null ? null : JSON.stringify(data.engineSnapshot),
42
+ stringifyJsonSafe(data.historyPath),
43
+ stringifyJsonSafe(data.state),
44
+ data.engineSnapshot == null ? null : stringifyJsonSafe(data.engineSnapshot),
44
45
  data.createdBy || 'system',
45
46
  data.createdAt,
46
47
  data.updatedBy || 'system',
@@ -9,6 +9,7 @@
9
9
  *
10
10
  * @see design.md §1.3 checkpoints 数据模型
11
11
  */
12
+ import { stringifyJsonSafe } from './checkpoint-serializer.js';
12
13
  /**
13
14
  * RedisCheckpointSaver — ICheckpointSaver 的 Redis 实现
14
15
  *
@@ -52,7 +53,7 @@ export class RedisCheckpointSaver {
52
53
  const idxKey = this.threadIndexKey(threadId);
53
54
  const ltKey = this.latestKey(threadId);
54
55
  const revKey = this.reverseIndexKey(data.checkpointId);
55
- const json = JSON.stringify(data);
56
+ const json = stringifyJsonSafe(data);
56
57
  const score = new Date(data.createdAt).getTime();
57
58
  const pipeline = this.redis.pipeline();
58
59
  // 存储 Checkpoint JSON
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gt-fe/eap-runtime",
3
- "version": "0.0.17",
4
- "description": "Enterprise Agent Platform \u2014 Runtime\u6838\u5fc3\uff1aGraph\u6267\u884c\u5f15\u64ce\u3001Task\u751f\u547d\u5468\u671f\u3001Session\u7ba1\u7406\u3001Checkpoint\u6301\u4e45\u5316",
3
+ "version": "0.0.18",
4
+ "description": "Enterprise Agent Platform — Runtime核心:Graph执行引擎、Task生命周期、Session管理、Checkpoint持久化",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",