recallnest 3.0.0 → 4.0.0

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 (246) hide show
  1. package/CHANGELOG.md +304 -0
  2. package/README.md +251 -258
  3. package/README_CN.md +226 -247
  4. package/assets/ui/app.js +6 -1
  5. package/bin/recallnest.mjs +20 -37
  6. package/docs/api-reference.md +8 -0
  7. package/docs/architecture.md +18 -13
  8. package/eval/cases-canary.json +107 -9
  9. package/integrations/examples/claude-agent-sdk/memory-agent.ts +2 -0
  10. package/integrations/examples/langchain/memory-chain.py +4 -0
  11. package/integrations/examples/openai-agents-sdk/memory-agent.py +4 -0
  12. package/package.json +12 -3
  13. package/src/activity-counter.ts +1 -0
  14. package/src/adaptive-retrieval.ts +23 -0
  15. package/src/api-server.ts +13 -11
  16. package/src/asset-sync.ts +26 -2
  17. package/src/audit-log.ts +2 -0
  18. package/src/auto-gc.ts +4 -3
  19. package/src/belief-history.ts +137 -31
  20. package/src/capture-engine.ts +459 -71
  21. package/src/cascade-forget.ts +7 -3
  22. package/src/checkpoint-mirror.ts +417 -0
  23. package/src/cli.ts +574 -54
  24. package/src/conflict-engine.ts +43 -15
  25. package/src/consolidation-engine.ts +24 -3
  26. package/src/context-collapse-renderer.ts +8 -1
  27. package/src/context-composer-stable.ts +5 -1
  28. package/src/context-composer.ts +11 -2
  29. package/src/distill-lock.ts +246 -74
  30. package/src/dream-pipeline.ts +3 -1
  31. package/src/embedder.ts +24 -0
  32. package/src/env-config.ts +136 -0
  33. package/src/flock.ts +97 -0
  34. package/src/forget-engine.ts +342 -58
  35. package/src/gateway-server.ts +4 -0
  36. package/src/ingest-plan.ts +56 -0
  37. package/src/ingest.ts +294 -121
  38. package/src/kg-contradiction.ts +753 -0
  39. package/src/kg-extractor.ts +17 -0
  40. package/src/kg-store.ts +1 -1
  41. package/src/known-item-eval.ts +455 -0
  42. package/src/llm-client.ts +13 -26
  43. package/src/llm-consolidation.ts +2 -2
  44. package/src/mcp-tool-deps.ts +6 -0
  45. package/src/mcp-tools-advanced.ts +80 -45
  46. package/src/mcp-tools-core.ts +23 -17
  47. package/src/mcp-tools-governance.ts +13 -7
  48. package/src/memory-assets.ts +144 -8
  49. package/src/memory-boundaries.ts +19 -0
  50. package/src/memory-evolution.ts +9 -0
  51. package/src/memory-lint.ts +1 -1
  52. package/src/memory-output.ts +311 -14
  53. package/src/memory-reconcile.ts +1437 -0
  54. package/src/memory-schema.ts +11 -0
  55. package/src/memory-store-port.ts +1 -0
  56. package/src/minis-archive.ts +151 -0
  57. package/src/noise-filter.ts +15 -2
  58. package/src/pii-detector.ts +31 -1
  59. package/src/pivot-apply.ts +55 -5
  60. package/src/pivot-evidence.ts +128 -0
  61. package/src/ppr-traversal.ts +25 -1
  62. package/src/preference-matcher.ts +40 -28
  63. package/src/prospective-memory.ts +7 -4
  64. package/src/retriever.ts +297 -57
  65. package/src/retroactive-boost.ts +3 -2
  66. package/src/runtime-config.ts +15 -1
  67. package/src/scope-policy.ts +1 -0
  68. package/src/session-distiller.ts +6 -2
  69. package/src/session-engine.ts +11 -4
  70. package/src/session-output.ts +20 -1
  71. package/src/session-schema.ts +5 -2
  72. package/src/session-store.ts +59 -12
  73. package/src/skill-promotion.ts +67 -1
  74. package/src/store-receipts.ts +109 -0
  75. package/src/store-write-budget.ts +37 -0
  76. package/src/store.ts +298 -57
  77. package/src/text-fingerprint.ts +25 -0
  78. package/src/trigger-store.ts +443 -0
  79. package/src/ui-server.ts +22 -21
  80. package/src/version-manager.ts +19 -5
  81. package/src/write-verifier.ts +16 -11
  82. package/src/__tests__/access-tracker-novelty.test.ts +0 -324
  83. package/src/__tests__/activity-counter.test.ts +0 -125
  84. package/src/__tests__/adaptive-fidelity.test.ts +0 -102
  85. package/src/__tests__/admission-control.test.ts +0 -206
  86. package/src/__tests__/age-label.test.ts +0 -33
  87. package/src/__tests__/anchor-generator.test.ts +0 -67
  88. package/src/__tests__/api-server-security.test.ts +0 -102
  89. package/src/__tests__/auto-consolidation.test.ts +0 -168
  90. package/src/__tests__/auto-recall.test.ts +0 -131
  91. package/src/__tests__/babel-integration.test.ts +0 -144
  92. package/src/__tests__/batch-dedup.test.ts +0 -65
  93. package/src/__tests__/belief-history.test.ts +0 -220
  94. package/src/__tests__/canary-eval.test.ts +0 -114
  95. package/src/__tests__/capture-engine.test.ts +0 -1328
  96. package/src/__tests__/capture-heuristic.test.ts +0 -171
  97. package/src/__tests__/cascade-forget.test.ts +0 -210
  98. package/src/__tests__/category-min-scores.test.ts +0 -116
  99. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  100. package/src/__tests__/circuit-breaker.test.ts +0 -99
  101. package/src/__tests__/cluster-consolidation.test.ts +0 -1236
  102. package/src/__tests__/confidence-metadata.test.ts +0 -125
  103. package/src/__tests__/confidence-tracker.test.ts +0 -261
  104. package/src/__tests__/conflict-advisor.test.ts +0 -206
  105. package/src/__tests__/conflict-escalation.test.ts +0 -149
  106. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  107. package/src/__tests__/conflict-output.test.ts +0 -85
  108. package/src/__tests__/conflict-store.test.ts +0 -418
  109. package/src/__tests__/connector-v1.test.ts +0 -181
  110. package/src/__tests__/consolidation-engine.test.ts +0 -520
  111. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  112. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  113. package/src/__tests__/context-composer-pins.test.ts +0 -64
  114. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  115. package/src/__tests__/context-reconstructor.test.ts +0 -65
  116. package/src/__tests__/context-renderer.test.ts +0 -91
  117. package/src/__tests__/continuity-eval.test.ts +0 -275
  118. package/src/__tests__/continuity-schema.test.ts +0 -97
  119. package/src/__tests__/contracts.test.ts +0 -262
  120. package/src/__tests__/conversation-importer.test.ts +0 -692
  121. package/src/__tests__/core-recall-eval.test.ts +0 -235
  122. package/src/__tests__/core-summary.test.ts +0 -109
  123. package/src/__tests__/data-checkup.test.ts +0 -304
  124. package/src/__tests__/decay-exemption.test.ts +0 -129
  125. package/src/__tests__/dedup-actions.test.ts +0 -58
  126. package/src/__tests__/dedup-guard.test.ts +0 -39
  127. package/src/__tests__/deterministic-id.test.ts +0 -39
  128. package/src/__tests__/distill-lock.test.ts +0 -305
  129. package/src/__tests__/distill-session-argshape.test.ts +0 -79
  130. package/src/__tests__/doctor.test.ts +0 -319
  131. package/src/__tests__/dream-pipeline.test.ts +0 -820
  132. package/src/__tests__/dream-scope-isolation.test.ts +0 -386
  133. package/src/__tests__/dream-write-batching.test.ts +0 -211
  134. package/src/__tests__/drill-down.test.ts +0 -108
  135. package/src/__tests__/embedder.test.ts +0 -122
  136. package/src/__tests__/emotion-decay.test.ts +0 -46
  137. package/src/__tests__/emotion-detector.test.ts +0 -56
  138. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  139. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  140. package/src/__tests__/entity-resolver.test.ts +0 -58
  141. package/src/__tests__/env-config-invariant.test.ts +0 -80
  142. package/src/__tests__/env-config.test.ts +0 -211
  143. package/src/__tests__/error-signature-boost.test.ts +0 -87
  144. package/src/__tests__/error-signature.test.ts +0 -95
  145. package/src/__tests__/error-taxonomy.test.ts +0 -129
  146. package/src/__tests__/ethics-layer.test.ts +0 -476
  147. package/src/__tests__/event-segmenter.test.ts +0 -153
  148. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  149. package/src/__tests__/frequency-tracker.test.ts +0 -113
  150. package/src/__tests__/freshness.test.ts +0 -186
  151. package/src/__tests__/graph-export.test.ts +0 -489
  152. package/src/__tests__/hotness-blend.test.ts +0 -283
  153. package/src/__tests__/ingest-chunking.test.ts +0 -44
  154. package/src/__tests__/ingest-scope-prefix.test.ts +0 -69
  155. package/src/__tests__/ingest.test.ts +0 -360
  156. package/src/__tests__/interference-detector.test.ts +0 -203
  157. package/src/__tests__/kg-extractor.test.ts +0 -192
  158. package/src/__tests__/kg-store.test.ts +0 -300
  159. package/src/__tests__/llm-client-pivot.test.ts +0 -628
  160. package/src/__tests__/llm-consolidation.test.ts +0 -226
  161. package/src/__tests__/maintenance-locks.test.ts +0 -197
  162. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  163. package/src/__tests__/mcp-related-scopes.test.ts +0 -151
  164. package/src/__tests__/memory-boundaries.test.ts +0 -282
  165. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -362
  166. package/src/__tests__/memory-evolution.test.ts +0 -271
  167. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  168. package/src/__tests__/memory-lint.test.ts +0 -421
  169. package/src/__tests__/memory-output.test.ts +0 -224
  170. package/src/__tests__/memory-promotion.test.ts +0 -315
  171. package/src/__tests__/memory-utility.test.ts +0 -256
  172. package/src/__tests__/migrate-dedup-ids.test.ts +0 -65
  173. package/src/__tests__/multi-vector.test.ts +0 -242
  174. package/src/__tests__/narrative-architecture.test.ts +0 -456
  175. package/src/__tests__/noise-filter.test.ts +0 -205
  176. package/src/__tests__/noise-prototype-bank.test.ts +0 -280
  177. package/src/__tests__/obsidian-connector.test.ts +0 -363
  178. package/src/__tests__/omitted-reporting.test.ts +0 -98
  179. package/src/__tests__/openai-contract.test.ts +0 -513
  180. package/src/__tests__/pending-review.test.ts +0 -77
  181. package/src/__tests__/pii-redact.test.ts +0 -333
  182. package/src/__tests__/pivot-apply.test.ts +0 -373
  183. package/src/__tests__/pivot-distill-supervisor.test.ts +0 -457
  184. package/src/__tests__/pivot-distill.test.ts +0 -1178
  185. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  186. package/src/__tests__/ppr-traversal.test.ts +0 -256
  187. package/src/__tests__/prediction-engine.test.ts +0 -349
  188. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  189. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  190. package/src/__tests__/preference-matcher.test.ts +0 -282
  191. package/src/__tests__/preference-slots.test.ts +0 -205
  192. package/src/__tests__/promotion-distinct-sources.test.ts +0 -162
  193. package/src/__tests__/prospective-memory.test.ts +0 -283
  194. package/src/__tests__/pull-from-macbook-sync-only.test.ts +0 -679
  195. package/src/__tests__/query-entity-detector.test.ts +0 -171
  196. package/src/__tests__/query-expander-alias.test.ts +0 -146
  197. package/src/__tests__/query-expander.test.ts +0 -34
  198. package/src/__tests__/recall-gate.test.ts +0 -266
  199. package/src/__tests__/recall-governor.test.ts +0 -227
  200. package/src/__tests__/recall-mode.test.ts +0 -64
  201. package/src/__tests__/resolve-db-path.test.ts +0 -130
  202. package/src/__tests__/resolve-tier.test.ts +0 -64
  203. package/src/__tests__/result-synthesizer.test.ts +0 -198
  204. package/src/__tests__/resume-context.test.ts +0 -4898
  205. package/src/__tests__/retrieval-eval.test.ts +0 -163
  206. package/src/__tests__/retrieval-trace.test.ts +0 -213
  207. package/src/__tests__/retrieve-audit-revision.test.ts +0 -255
  208. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  209. package/src/__tests__/retriever-lazy-init-dispatch.test.ts +0 -123
  210. package/src/__tests__/retroactive-boost.test.ts +0 -223
  211. package/src/__tests__/salience-scoring.test.ts +0 -106
  212. package/src/__tests__/scope-inventory.test.ts +0 -200
  213. package/src/__tests__/scope-policy.test.ts +0 -69
  214. package/src/__tests__/scope-suggester.test.ts +0 -80
  215. package/src/__tests__/session-checkpoint.test.ts +0 -291
  216. package/src/__tests__/session-distiller.test.ts +0 -640
  217. package/src/__tests__/session-gc.test.ts +0 -215
  218. package/src/__tests__/skill-engine.test.ts +0 -552
  219. package/src/__tests__/skill-promotion.test.ts +0 -654
  220. package/src/__tests__/skill-verifier.test.ts +0 -122
  221. package/src/__tests__/source-heartbeat.test.ts +0 -254
  222. package/src/__tests__/stable-context-length-contract.test.ts +0 -62
  223. package/src/__tests__/store-patch-metadata.test.ts +0 -235
  224. package/src/__tests__/store-read-consistency.test.ts +0 -122
  225. package/src/__tests__/store-schema-migration.test.ts +0 -87
  226. package/src/__tests__/store-scope-audit.test.ts +0 -81
  227. package/src/__tests__/store-upsert.test.ts +0 -201
  228. package/src/__tests__/supersede-chain.test.ts +0 -154
  229. package/src/__tests__/synthesis-contract.test.ts +0 -252
  230. package/src/__tests__/synthesis-promotion.test.ts +0 -369
  231. package/src/__tests__/temporal-parser.test.ts +0 -241
  232. package/src/__tests__/temporal-validity.test.ts +0 -160
  233. package/src/__tests__/term-registry-terminal-roster.test.ts +0 -127
  234. package/src/__tests__/term-registry.test.ts +0 -121
  235. package/src/__tests__/tool-error-surfacing.test.ts +0 -98
  236. package/src/__tests__/tool-output-compressor.test.ts +0 -160
  237. package/src/__tests__/topic-tag.test.ts +0 -113
  238. package/src/__tests__/trusted-memory.test.ts +0 -867
  239. package/src/__tests__/ui-server-security.test.ts +0 -93
  240. package/src/__tests__/usage-tracker.test.ts +0 -287
  241. package/src/__tests__/utility-weight.test.ts +0 -57
  242. package/src/__tests__/verbatim-self-recall.test.ts +0 -279
  243. package/src/__tests__/version-manager.test.ts +0 -248
  244. package/src/__tests__/workflow-observation-skill-outcome.test.ts +0 -352
  245. package/src/__tests__/workflow-observation.test.ts +0 -433
  246. package/src/__tests__/write-verifier.test.ts +0 -122
@@ -1,98 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
-
3
- import { registerAdvancedTools } from "../mcp-tools-advanced.js";
4
- import { registerGovernanceTools } from "../mcp-tools-governance.js";
5
- import { runToolSafely } from "../error-taxonomy.js";
6
-
7
- /**
8
- * P1-7 第二阶段回归:验证「主操作错误」与「C 类逻辑失败」经 registerTool 的
9
- * runToolSafely 包装后带 isError + reason_code,而不是被 handler 自吞成「看起来成功」的文本。
10
- *
11
- * 手法:用注入式 registerTool 捕获真实 handler,并复刻生产 registerTool 的 runToolSafely
12
- * 包装,使测试看到与生产一致的 isError 行为(无需起 MCP server)。
13
- */
14
-
15
- interface ToolResult {
16
- content: { type: string; text: string }[];
17
- isError?: boolean;
18
- }
19
- type CapturedHandler = (args: Record<string, unknown>) => Promise<ToolResult>;
20
-
21
- function captureTools(
22
- register: (deps: any) => void,
23
- getComponents: () => unknown,
24
- ): Map<string, CapturedHandler> {
25
- const handlers = new Map<string, CapturedHandler>();
26
- const deps = {
27
- registerTool: (
28
- name: string,
29
- _desc: string,
30
- _schema: unknown,
31
- handler: (...a: unknown[]) => unknown,
32
- ) => {
33
- // 复刻 mcp-server.ts registerTool 的兜底:把 handler 交给 runToolSafely。
34
- handlers.set(name, (args) => runToolSafely(name, async () => handler(args)) as Promise<ToolResult>);
35
- },
36
- getComponents,
37
- conflictStore: {},
38
- workflowObservationStore: {},
39
- getKGExtractor: () => null,
40
- getKGStore: () => null,
41
- };
42
- register(deps as any);
43
- return handlers;
44
- }
45
-
46
- describe("memory_drill_down error surfacing (P1-7)", () => {
47
- it("surfaces a store error as isError with store_error reason (no swallow)", async () => {
48
- const handlers = captureTools(registerAdvancedTools, () => ({
49
- store: {
50
- getById: async () => {
51
- throw new Error("lancedb table read failed");
52
- },
53
- },
54
- }));
55
- const drill = handlers.get("memory_drill_down");
56
- expect(drill).toBeDefined();
57
- const r = await drill!({ id: "abcd1234", level: "full" });
58
- expect(r.isError).toBe(true);
59
- expect(r.content[0].text).toContain("store_error");
60
- });
61
-
62
- it("still returns plain not-found text (read-only, no isError)", async () => {
63
- const handlers = captureTools(registerAdvancedTools, () => ({
64
- store: { getById: async () => null },
65
- }));
66
- const r = await handlers.get("memory_drill_down")!({ id: "abcd1234", level: "full" });
67
- expect(r.isError).toBeUndefined();
68
- expect(r.content[0].text).toContain("No memory found");
69
- });
70
- });
71
-
72
- describe("forget_memory error surfacing (P1-7 C 类)", () => {
73
- it("throws logic failure into the taxonomy layer (isError) not fake-success text", async () => {
74
- const handlers = captureTools(registerAdvancedTools, () => ({
75
- // store.get → null ⇒ forgetMemory 早返回 success:false(不触碰 kg/audit)
76
- store: { get: async () => null },
77
- }));
78
- const r = await handlers.get("forget_memory")!({ memoryId: "abcd1234", confirm: false });
79
- expect(r.isError).toBe(true);
80
- expect(r.content[0].text).toContain("not found");
81
- });
82
- });
83
-
84
- describe("manage_alias error surfacing (P1-7 C 类)", () => {
85
- it("throws invalid_input on missing add params (not returned as success text)", async () => {
86
- const handlers = captureTools(registerGovernanceTools, () => ({}));
87
- const r = await handlers.get("manage_alias")!({ action: "add" });
88
- expect(r.isError).toBe(true);
89
- expect(r.content[0].text).toContain("invalid_input");
90
- });
91
-
92
- it("throws invalid_input on missing remove trigger", async () => {
93
- const handlers = captureTools(registerGovernanceTools, () => ({}));
94
- const r = await handlers.get("manage_alias")!({ action: "remove" });
95
- expect(r.isError).toBe(true);
96
- expect(r.content[0].text).toContain("invalid_input");
97
- });
98
- });
@@ -1,160 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import { compressToolOutput } from "../tool-output-compressor.js";
3
-
4
- describe("compressToolOutput", () => {
5
- // ========================================================================
6
- // Base64 replacement
7
- // ========================================================================
8
-
9
- it("replaces large base64 blocks with size placeholder", () => {
10
- const base64 = "A".repeat(2000);
11
- const text = `Here is a screenshot:\n${base64}\nEnd of screenshot.`;
12
- const result = compressToolOutput(text);
13
- expect(result).toContain("[image:");
14
- expect(result).toContain("base64");
15
- expect(result).not.toContain("AAAA");
16
- });
17
-
18
- it("preserves short base64-like strings", () => {
19
- const text = "The hash is abc123==";
20
- expect(compressToolOutput(text)).toBe(text);
21
- });
22
-
23
- // ========================================================================
24
- // Git output compression
25
- // ========================================================================
26
-
27
- it("compresses git push boilerplate", () => {
28
- const text = `$ git push origin main
29
- Enumerating objects: 5, done.
30
- Counting objects: 100% (5/5), done.
31
- Delta compression using up to 8 threads
32
- Compressing objects: 100% (3/3), done.
33
- Writing objects: 100% (3/3), 450 bytes | 450.00 KiB/s, done.
34
- Total 3 (delta 2), reused 0 (delta 0)
35
- remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
36
- To github.com:user/repo.git
37
- abc1234..def5678 main -> main
38
-
39
- Next I'll check the status.`;
40
-
41
- const result = compressToolOutput(text);
42
- expect(result).toContain("[git: ok");
43
- expect(result).toContain("main");
44
- expect(result).not.toContain("Enumerating objects");
45
- expect(result).toContain("Next I'll check the status");
46
- });
47
-
48
- it("preserves git push failures", () => {
49
- const text = `$ git push
50
- Enumerating objects: 5, done.
51
- error: failed to push some refs to 'origin'
52
- hint: Updates were rejected because the tip of your branch is behind -> main`;
53
-
54
- const result = compressToolOutput(text);
55
- expect(result).toContain("error");
56
- expect(result).toContain("rejected");
57
- });
58
-
59
- // ========================================================================
60
- // Test output compression
61
- // ========================================================================
62
-
63
- it("compresses passing test summary", () => {
64
- const text = `$ bun test
65
- running 15 tests
66
- test a ... ok
67
- test b ... ok
68
- test c ... ok
69
- test result: ok. 15 passed; 0 failed; 0 ignored
70
-
71
- All tests passed.`;
72
-
73
- const result = compressToolOutput(text);
74
- expect(result.length).toBeLessThanOrEqual(text.length);
75
- expect(result).toContain("All tests passed");
76
- });
77
-
78
- it("preserves failing test output", () => {
79
- const text = `$ npm test
80
- Tests: 2 failed, 8 passed
81
- FAIL src/main.test.ts
82
- ✕ should handle edge case`;
83
-
84
- const result = compressToolOutput(text);
85
- expect(result).toContain("failed");
86
- expect(result).toContain("FAIL");
87
- });
88
-
89
- // ========================================================================
90
- // Safety: user/AI content untouched
91
- // ========================================================================
92
-
93
- it("never modifies plain conversation text", () => {
94
- const text = "User: How do I fix this git push error?\n\nAssistant: You need to pull first.";
95
- expect(compressToolOutput(text)).toBe(text);
96
- });
97
-
98
- it("preserves AI reasoning about tool results", () => {
99
- const text = "The test result shows 15 passed, which means our fix works.";
100
- expect(compressToolOutput(text)).toBe(text);
101
- });
102
-
103
- // ========================================================================
104
- // Edge cases
105
- // ========================================================================
106
-
107
- it("handles empty input", () => {
108
- expect(compressToolOutput("")).toBe("");
109
- });
110
-
111
- it("handles short input", () => {
112
- expect(compressToolOutput("hi")).toBe("hi");
113
- });
114
-
115
- it("handles text without tool outputs", () => {
116
- const text = "This is a normal conversation.\nNo tool outputs here.";
117
- expect(compressToolOutput(text)).toBe(text);
118
- });
119
-
120
- // ========================================================================
121
- // Large output truncation
122
- // ========================================================================
123
-
124
- it("truncates large unmatched tool output", () => {
125
- // Use content with spaces/special chars to avoid base64 regex match
126
- const largeOutput = Array.from({ length: 150 }, (_, i) => `line ${i}: some detailed output here`).join("\n");
127
- const text = `$ some-command\n${largeOutput}\n\nNext step.`;
128
- const result = compressToolOutput(text);
129
- expect(result).toContain("[...");
130
- expect(result).toContain("chars truncated");
131
- expect(result.length).toBeLessThan(text.length);
132
- });
133
-
134
- // ========================================================================
135
- // 回归:工具输出块位于字符串结尾(原 \z 锚点 bug)
136
- // 旧实现 lookahead 末项是 \z(JS 无此锚点 → 当字面字符 z):
137
- // - 块结尾无字面 z 时整块漏匹配 → 末尾大输出逃过截断
138
- // - 块含字面 z 时惰性匹配在第一个 z 处误截断
139
- // 修复为 (?![\s\S])(字符串绝对结尾)后两种都应正确处理。
140
- // ========================================================================
141
-
142
- it("truncates a large tool output block that ends the string (no trailing marker)", () => {
143
- // 末尾块、无字母 z、后面没有下一个命令/空行大写/## → 旧 \z 实现整块漏匹配
144
- const largeOutput = Array.from({ length: 150 }, (_, i) => `line ${i}: detailed output here`).join("\n");
145
- const text = `$ some-command\n${largeOutput}`;
146
- const result = compressToolOutput(text);
147
- expect(result).toContain("chars truncated");
148
- expect(result.length).toBeLessThan(text.length);
149
- });
150
-
151
- it("does not cut a trailing tool output block at a literal 'z'", () => {
152
- // 末尾大块含字母 z → 旧 \z 实现在第一个 z 处截断匹配,导致块太短逃过截断
153
- const largeOutput = Array.from({ length: 150 }, (_, i) => `line ${i}: zebra output zone`).join("\n");
154
- const text = `$ some-command\n${largeOutput}`;
155
- const result = compressToolOutput(text);
156
- expect(result).toContain("chars truncated");
157
- // 截断尾部应保留块真正的结尾,而不是停在某个 z 之前
158
- expect(result).toContain("zone");
159
- });
160
- });
@@ -1,113 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { detectTopicTag, extractTopicTag, injectTopicTag } from "../topic-tag.js";
3
-
4
- describe("detectTopicTag", () => {
5
- it("detects auth-related content", () => {
6
- expect(detectTopicTag("Implement JWT authentication with OAuth2 flow")).toBe("auth");
7
- });
8
-
9
- it("detects deploy-related content", () => {
10
- expect(detectTopicTag("Set up CI/CD pipeline with GitHub Actions for production deployment")).toBe("deploy");
11
- });
12
-
13
- it("detects infra-related content", () => {
14
- expect(detectTopicTag("Configure Docker containers and Kubernetes cluster")).toBe("infra");
15
- });
16
-
17
- it("detects testing-related content", () => {
18
- expect(detectTopicTag("Write unit tests with bun test and add coverage for the new module")).toBe("testing");
19
- });
20
-
21
- it("detects database-related content", () => {
22
- expect(detectTopicTag("Run SQL migration to add new columns to postgres users table")).toBe("database");
23
- });
24
-
25
- it("detects api-related content", () => {
26
- expect(detectTopicTag("Design REST API endpoints for the new webhook integration")).toBe("api");
27
- });
28
-
29
- it("detects ui-related content", () => {
30
- expect(detectTopicTag("Build React component with Tailwind CSS for the dashboard layout")).toBe("ui");
31
- });
32
-
33
- it("detects performance-related content", () => {
34
- expect(detectTopicTag("Profile cache hit rates and optimize latency bottleneck")).toBe("perf");
35
- });
36
-
37
- it("detects security-related content", () => {
38
- expect(detectTopicTag("Fix XSS vulnerability and add CSRF protection")).toBe("security");
39
- });
40
-
41
- it("detects memory-related content", () => {
42
- expect(detectTopicTag("Improve recall retrieval with better embedding vectors for LanceDB")).toBe("memory");
43
- });
44
-
45
- it("detects mcp-related content", () => {
46
- expect(detectTopicTag("Register new MCP tool in the Model Context Protocol server")).toBe("mcp");
47
- });
48
-
49
- it("detects llm-related content", () => {
50
- expect(detectTopicTag("Optimize prompt engineering for better token efficiency with Claude")).toBe("llm");
51
- });
52
-
53
- it("returns undefined for generic text", () => {
54
- expect(detectTopicTag("Had a great day today")).toBeUndefined();
55
- });
56
-
57
- it("returns undefined for empty text", () => {
58
- expect(detectTopicTag("")).toBeUndefined();
59
- });
60
-
61
- it("picks strongest match when multiple topics present", () => {
62
- const tag = detectTopicTag("Deploy the authentication service to production using Docker");
63
- expect(tag).toBeDefined();
64
- // Multiple topics present; strongest wins
65
- expect(["auth", "deploy", "infra"]).toContain(tag);
66
- });
67
-
68
- it("handles Chinese text with English tech terms", () => {
69
- expect(detectTopicTag("配置 Docker 容器编排和 Kubernetes 集群")).toBe("infra");
70
- });
71
-
72
- it("truncates very long text for efficiency", () => {
73
- const longText = "Fix authentication bug. ".repeat(500);
74
- expect(detectTopicTag(longText)).toBe("auth");
75
- });
76
- });
77
-
78
- describe("extractTopicTag", () => {
79
- it("extracts topicTag from metadata JSON", () => {
80
- expect(extractTopicTag('{"topicTag":"auth","source":"manual"}')).toBe("auth");
81
- });
82
-
83
- it("returns undefined when no topicTag", () => {
84
- expect(extractTopicTag('{"source":"manual"}')).toBeUndefined();
85
- });
86
-
87
- it("returns undefined for invalid JSON", () => {
88
- expect(extractTopicTag("not json")).toBeUndefined();
89
- });
90
-
91
- it("returns undefined for undefined/null metadata", () => {
92
- expect(extractTopicTag(undefined)).toBeUndefined();
93
- expect(extractTopicTag("")).toBeUndefined();
94
- });
95
- });
96
-
97
- describe("injectTopicTag", () => {
98
- it("injects topicTag into metadata JSON", () => {
99
- const result = injectTopicTag('{"source":"manual"}', "deploy");
100
- const parsed = JSON.parse(result);
101
- expect(parsed.topicTag).toBe("deploy");
102
- expect(parsed.source).toBe("manual");
103
- });
104
-
105
- it("overwrites existing topicTag", () => {
106
- const result = injectTopicTag('{"topicTag":"old","source":"manual"}', "new");
107
- expect(JSON.parse(result).topicTag).toBe("new");
108
- });
109
-
110
- it("returns original on invalid JSON", () => {
111
- expect(injectTopicTag("broken", "tag")).toBe("broken");
112
- });
113
- });