@symerian/symi 3.0.17 → 3.0.19

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 (259) hide show
  1. package/dist/{audio-preflight-CBDFctZN.js → audio-preflight-BfmZbg4Y.js} +4 -4
  2. package/dist/{audio-preflight-gsZSpG-6.js → audio-preflight-DcuC-liM.js} +4 -4
  3. package/dist/build-info.json +3 -3
  4. package/dist/bundled/boot-md/handler.js +8 -8
  5. package/dist/bundled/session-memory/handler.js +7 -7
  6. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  7. package/dist/{chrome-nPMY1XTJ.js → chrome-Bo7cbvFK.js} +5 -5
  8. package/dist/{chrome-BjVab8gM.js → chrome-DYp18Q0t.js} +5 -5
  9. package/dist/{deliver-D-QFqm31.js → deliver-ChSIbiMM.js} +1 -1
  10. package/dist/{deliver-B4-bcot9.js → deliver-DEgRQM4J.js} +1 -1
  11. package/dist/extensionAPI.js +7 -7
  12. package/dist/{image-CDwtQjmt.js → image-Bx-hvoNJ.js} +1 -1
  13. package/dist/{image-CcS-vzTA.js → image-CQl_mjWk.js} +1 -1
  14. package/dist/llm-slug-generator.js +7 -7
  15. package/dist/{manager-BnEdHzmO.js → manager-D_pn0urG.js} +1 -1
  16. package/dist/{manager-09r0qPze.js → manager-YQxK2t0C.js} +1 -1
  17. package/dist/{pi-embedded-CWsY69-4.js → pi-embedded-CLw_ZzEZ.js} +16 -16
  18. package/dist/{pi-embedded-helpers-BBMy-lqr.js → pi-embedded-helpers-B5I53aw6.js} +4 -4
  19. package/dist/{pi-embedded-helpers-ChEYbgVj.js → pi-embedded-helpers-sUAEIC9X.js} +4 -4
  20. package/dist/plugin-sdk/{accounts-BfyWsC_i.js → accounts-CWFytwbR.js} +3 -3
  21. package/dist/plugin-sdk/{active-listener-DcJW7xAT.js → active-listener-BkZ4jHrL.js} +2 -2
  22. package/dist/plugin-sdk/{agent-scope-ChbGV6of.js → agent-scope-C9gfY_Gk.js} +2 -2
  23. package/dist/plugin-sdk/{audio-preflight-D3GtNLqW.js → audio-preflight-HKbdzXLZ.js} +21 -21
  24. package/dist/plugin-sdk/{bindings-CN2Qmefj.js → bindings-BaKIqPPy.js} +2 -2
  25. package/dist/plugin-sdk/{channel-web-DTyqujjA.js → channel-web-D5nWiTH1.js} +18 -18
  26. package/dist/plugin-sdk/{chrome-BKzAKr3K.js → chrome-klTSnz-9.js} +3 -3
  27. package/dist/plugin-sdk/{chunk-DhDkBujV.js → chunk-BbrYSny_.js} +1 -1
  28. package/dist/plugin-sdk/{command-format-CVrYFyZS.js → command-format-BN6tyZt6.js} +1 -1
  29. package/dist/plugin-sdk/{commands-registry-17yfZkHZ.js → commands-registry-CTzKKtY6.js} +4 -4
  30. package/dist/plugin-sdk/{config-7wk65zKC.js → config-Crv2qEdJ.js} +9 -9
  31. package/dist/plugin-sdk/{consolidate-exbAW0ml.js → consolidate-DT1QH65Q.js} +2 -2
  32. package/dist/plugin-sdk/{deliver-TxAcw7J5.js → deliver-7rOvAlrc.js} +12 -12
  33. package/dist/plugin-sdk/{diagnostic-Debx4frd.js → diagnostic-0nsxhWp7.js} +1 -1
  34. package/dist/plugin-sdk/{fs-safe-wBYbAkJF.js → fs-safe-DfWYBeWF.js} +1 -1
  35. package/dist/plugin-sdk/{gemini-auth-7U2pm2Ky.js → gemini-auth-C0N0_u49.js} +1 -1
  36. package/dist/plugin-sdk/{image-BtDVmYA5.js → image-WOSl2apK.js} +4 -4
  37. package/dist/plugin-sdk/index.js +43 -43
  38. package/dist/plugin-sdk/{ir-CKMvRrGW.js → ir-9J84MTls.js} +4 -4
  39. package/dist/plugin-sdk/{local-roots-c_gaPs01.js → local-roots-OLRDbvyY.js} +3 -3
  40. package/dist/plugin-sdk/{login-DUym1Jy0.js → login-C7x4q0i2.js} +7 -7
  41. package/dist/plugin-sdk/{login-qr-B-WBdvrX.js → login-qr-Dv5_MoAW.js} +9 -9
  42. package/dist/plugin-sdk/{manager-B71SCzos.js → manager-C83tK17x.js} +8 -8
  43. package/dist/plugin-sdk/{manifest-registry-Dnic6Chh.js → manifest-registry-CJMV-PI7.js} +1 -1
  44. package/dist/plugin-sdk/{markdown-tables-Dur7OTlM.js → markdown-tables-DXNKz5y_.js} +1 -1
  45. package/dist/plugin-sdk/{message-channel-BrAhJJV_.js → message-channel-aGy1HbQQ.js} +1 -1
  46. package/dist/plugin-sdk/{model-selection-B9qaVQSJ.js → model-selection-C-3-tpe7.js} +4 -4
  47. package/dist/plugin-sdk/{outbound-DB1wDM8b.js → outbound-DquCeSy5.js} +6 -6
  48. package/dist/plugin-sdk/{pi-auth-json-ZO118hoy.js → pi-auth-json-D9PDCXGn.js} +1 -1
  49. package/dist/plugin-sdk/{pi-embedded-helpers-s_U0Un7j.js → pi-embedded-helpers-D3ygfH7l.js} +16 -16
  50. package/dist/plugin-sdk/{plugins-DF81oSaI.js → plugins-DOwnSg9D.js} +4 -4
  51. package/dist/plugin-sdk/{pw-ai-CTwP02uv.js → pw-ai-rlengLjb.js} +8 -8
  52. package/dist/plugin-sdk/{qmd-manager-CBaSGant.js → qmd-manager-BzxFjRFa.js} +4 -4
  53. package/dist/plugin-sdk/{registry-CZVURNhF.js → registry-5iFfixlB.js} +2 -2
  54. package/dist/plugin-sdk/{replies-hwRbkU3z.js → replies-BXOzO_H5.js} +7 -7
  55. package/dist/plugin-sdk/{reply-prefix-CaXmzZlx.js → reply-prefix-INAKTqCU.js} +1 -1
  56. package/dist/plugin-sdk/{resolve-outbound-target-fxVSOBmk.js → resolve-outbound-target-DvbxHtqp.js} +2 -2
  57. package/dist/plugin-sdk/{resolve-route-ClCyiOeu.js → resolve-route-URXlY3AK.js} +3 -3
  58. package/dist/plugin-sdk/{runner-Cq5jvwQ7.js → runner-Bv0_DWoH.js} +9 -9
  59. package/dist/plugin-sdk/{session-B_TkB65Y.js → session-C3r8l7ou.js} +4 -4
  60. package/dist/plugin-sdk/{skill-commands-0LF9HTGr.js → skill-commands-KjLUGIdZ.js} +5 -5
  61. package/dist/plugin-sdk/{skills-BIT_O7J0.js → skills-BrsD4L5c.js} +7 -7
  62. package/dist/plugin-sdk/{sqlite-Bx5Y5U5X.js → sqlite-CjW7ME1H.js} +1 -1
  63. package/dist/plugin-sdk/{subsystem-CXqYeDy-.js → subsystem-DcOg1xJr.js} +1 -1
  64. package/dist/plugin-sdk/{synthesis-DtsYAj1E.js → synthesis-CY7YAasV.js} +38 -38
  65. package/dist/plugin-sdk/{target-errors-B8mokOeH.js → target-errors-BVWJGWFq.js} +2 -2
  66. package/dist/plugin-sdk/{thinking-Ca0DhqzO.js → thinking-CtsTDPOi.js} +3 -3
  67. package/dist/plugin-sdk/{tokens-CvlONEqh.js → tokens-8lqOTZCB.js} +1 -1
  68. package/dist/plugin-sdk/{tool-images-DpBaWEHT.js → tool-images-Cl_rGIUZ.js} +2 -2
  69. package/dist/plugin-sdk/{tool-loop-detection-BOvUFa0f.js → tool-loop-detection-Da4WUT_P.js} +2 -2
  70. package/dist/plugin-sdk/{unified-runner-CnM7lyNd.js → unified-runner-nwMnsZyj.js} +60 -60
  71. package/dist/plugin-sdk/web-BlweOZDp.js +54 -0
  72. package/dist/plugin-sdk/{whatsapp-actions-CvnfsFJm.js → whatsapp-actions-DpfaGYs7.js} +21 -21
  73. package/dist/{pw-ai-BW8_KeDf.js → pw-ai-BqxJG-Wh.js} +1 -1
  74. package/dist/{pw-ai-j9IE1K0-.js → pw-ai-C-NSGye0.js} +1 -1
  75. package/dist/{runner-8ALr2UII.js → runner-COGFTeDw.js} +1 -1
  76. package/dist/{runner-C4-9kFdR.js → runner-DhCi2lT1.js} +1 -1
  77. package/dist/{synthesis-Cph3LhA1.js → synthesis-CXZu24Vx.js} +7 -7
  78. package/dist/{synthesis-Cus0A2dL.js → synthesis-DrPxcMlQ.js} +7 -7
  79. package/dist/{unified-runner-CX80YMTk.js → unified-runner-iByUazvW.js} +16 -16
  80. package/dist/{web-ChozvJ7I.js → web-EsMQBIYf.js} +7 -7
  81. package/dist/{web-DFlsbXmQ.js → web-PPg5y6xI.js} +7 -7
  82. package/package.json +1 -1
  83. package/dist/plugin-sdk/web-CIPJBHAU.js +0 -54
  84. package/extensions/copilot-proxy/README.md +0 -24
  85. package/extensions/copilot-proxy/index.ts +0 -154
  86. package/extensions/copilot-proxy/node_modules/.bin/symi +0 -21
  87. package/extensions/copilot-proxy/package.json +0 -15
  88. package/extensions/copilot-proxy/symi.plugin.json +0 -9
  89. package/extensions/device-pair/index.ts +0 -642
  90. package/extensions/device-pair/symi.plugin.json +0 -20
  91. package/extensions/diagnostics-otel/index.ts +0 -15
  92. package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -21
  93. package/extensions/diagnostics-otel/node_modules/.bin/symi +0 -21
  94. package/extensions/diagnostics-otel/package.json +0 -27
  95. package/extensions/diagnostics-otel/src/service.test.ts +0 -290
  96. package/extensions/diagnostics-otel/src/service.ts +0 -666
  97. package/extensions/diagnostics-otel/symi.plugin.json +0 -8
  98. package/extensions/google-antigravity-auth/README.md +0 -24
  99. package/extensions/google-antigravity-auth/index.ts +0 -424
  100. package/extensions/google-antigravity-auth/node_modules/.bin/symi +0 -21
  101. package/extensions/google-antigravity-auth/package.json +0 -15
  102. package/extensions/google-antigravity-auth/symi.plugin.json +0 -9
  103. package/extensions/google-gemini-cli-auth/README.md +0 -35
  104. package/extensions/google-gemini-cli-auth/index.ts +0 -75
  105. package/extensions/google-gemini-cli-auth/node_modules/.bin/symi +0 -21
  106. package/extensions/google-gemini-cli-auth/oauth.test.ts +0 -162
  107. package/extensions/google-gemini-cli-auth/oauth.ts +0 -636
  108. package/extensions/google-gemini-cli-auth/package.json +0 -15
  109. package/extensions/google-gemini-cli-auth/symi.plugin.json +0 -9
  110. package/extensions/learning-loop/index.ts +0 -159
  111. package/extensions/learning-loop/node_modules/.bin/symi +0 -21
  112. package/extensions/learning-loop/package.json +0 -18
  113. package/extensions/learning-loop/src/analytics/gateway-methods.ts +0 -230
  114. package/extensions/learning-loop/src/analytics/metrics-aggregator.ts +0 -153
  115. package/extensions/learning-loop/src/capture/run-tracker.ts +0 -181
  116. package/extensions/learning-loop/src/capture/serializer.ts +0 -74
  117. package/extensions/learning-loop/src/db.ts +0 -583
  118. package/extensions/learning-loop/src/feedback/explicit-feedback.ts +0 -58
  119. package/extensions/learning-loop/src/feedback/implicit-signals.ts +0 -89
  120. package/extensions/learning-loop/src/graph/edge-inference.ts +0 -189
  121. package/extensions/learning-loop/src/graph/graph-retrieval.ts +0 -144
  122. package/extensions/learning-loop/src/graph/graph-store.ts +0 -183
  123. package/extensions/learning-loop/src/hooks.ts +0 -244
  124. package/extensions/learning-loop/src/injection/cache.ts +0 -73
  125. package/extensions/learning-loop/src/injection/context-injector.ts +0 -104
  126. package/extensions/learning-loop/src/injection/prompt-builder.ts +0 -43
  127. package/extensions/learning-loop/src/learning/embedding-bridge.ts +0 -54
  128. package/extensions/learning-loop/src/learning/learning-extractor.ts +0 -217
  129. package/extensions/learning-loop/src/learning/learning-store.ts +0 -158
  130. package/extensions/learning-loop/src/learning/retrieval.ts +0 -87
  131. package/extensions/learning-loop/src/math/confidence-intervals.ts +0 -62
  132. package/extensions/learning-loop/src/math/ewma.ts +0 -51
  133. package/extensions/learning-loop/src/math/weighted-scorer.ts +0 -42
  134. package/extensions/learning-loop/src/schema.ts +0 -176
  135. package/extensions/learning-loop/src/scoring/normalization.ts +0 -32
  136. package/extensions/learning-loop/src/scoring/quality-engine.ts +0 -78
  137. package/extensions/learning-loop/src/scoring/signal-extractors.ts +0 -155
  138. package/extensions/learning-loop/src/test/context-injector.test.ts +0 -142
  139. package/extensions/learning-loop/src/test/fixes.test.ts +0 -1286
  140. package/extensions/learning-loop/src/test/graph.test.ts +0 -711
  141. package/extensions/learning-loop/src/test/integration.test.ts +0 -312
  142. package/extensions/learning-loop/src/test/learning-store.test.ts +0 -191
  143. package/extensions/learning-loop/src/test/math.test.ts +0 -148
  144. package/extensions/learning-loop/src/test/quality-engine.test.ts +0 -231
  145. package/extensions/learning-loop/src/test/run-tracker.test.ts +0 -143
  146. package/extensions/learning-loop/src/types.ts +0 -281
  147. package/extensions/learning-loop/symi.plugin.json +0 -46
  148. package/extensions/llm-task/README.md +0 -97
  149. package/extensions/llm-task/index.ts +0 -6
  150. package/extensions/llm-task/package.json +0 -12
  151. package/extensions/llm-task/src/llm-task-tool.test.ts +0 -138
  152. package/extensions/llm-task/src/llm-task-tool.ts +0 -249
  153. package/extensions/llm-task/symi.plugin.json +0 -21
  154. package/extensions/memory-lancedb/config.ts +0 -161
  155. package/extensions/memory-lancedb/index.test.ts +0 -330
  156. package/extensions/memory-lancedb/index.ts +0 -670
  157. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -21
  158. package/extensions/memory-lancedb/node_modules/.bin/openai +0 -21
  159. package/extensions/memory-lancedb/node_modules/.bin/symi +0 -21
  160. package/extensions/memory-lancedb/package.json +0 -20
  161. package/extensions/memory-lancedb/symi.plugin.json +0 -71
  162. package/extensions/minimax-portal-auth/README.md +0 -33
  163. package/extensions/minimax-portal-auth/index.ts +0 -161
  164. package/extensions/minimax-portal-auth/node_modules/.bin/symi +0 -21
  165. package/extensions/minimax-portal-auth/oauth.ts +0 -247
  166. package/extensions/minimax-portal-auth/package.json +0 -15
  167. package/extensions/minimax-portal-auth/symi.plugin.json +0 -9
  168. package/extensions/model-equalizer/index.ts +0 -80
  169. package/extensions/model-equalizer/skills/model-equalizer/SKILL.md +0 -58
  170. package/extensions/model-equalizer/src/detection.ts +0 -62
  171. package/extensions/model-equalizer/src/enhancer.ts +0 -63
  172. package/extensions/model-equalizer/src/test/detection.test.ts +0 -218
  173. package/extensions/model-equalizer/src/test/enhancer.test.ts +0 -137
  174. package/extensions/model-equalizer/src/test/integration.test.ts +0 -185
  175. package/extensions/model-equalizer/src/types.ts +0 -24
  176. package/extensions/model-equalizer/symi.plugin.json +0 -12
  177. package/extensions/phone-control/index.ts +0 -421
  178. package/extensions/phone-control/symi.plugin.json +0 -10
  179. package/extensions/pipeline/README.md +0 -75
  180. package/extensions/pipeline/SKILL.md +0 -97
  181. package/extensions/pipeline/index.ts +0 -18
  182. package/extensions/pipeline/package.json +0 -11
  183. package/extensions/pipeline/src/pipeline-tool.test.ts +0 -345
  184. package/extensions/pipeline/src/pipeline-tool.ts +0 -266
  185. package/extensions/pipeline/src/windows-spawn.test.ts +0 -148
  186. package/extensions/pipeline/src/windows-spawn.ts +0 -193
  187. package/extensions/pipeline/symi.plugin.json +0 -10
  188. package/extensions/qwen-portal-auth/README.md +0 -24
  189. package/extensions/qwen-portal-auth/index.ts +0 -134
  190. package/extensions/qwen-portal-auth/oauth.ts +0 -190
  191. package/extensions/qwen-portal-auth/symi.plugin.json +0 -9
  192. package/extensions/talk-voice/index.ts +0 -150
  193. package/extensions/talk-voice/symi.plugin.json +0 -10
  194. package/extensions/thread-ownership/index.test.ts +0 -180
  195. package/extensions/thread-ownership/index.ts +0 -133
  196. package/extensions/thread-ownership/symi.plugin.json +0 -28
  197. package/skills/1password/SKILL.md +0 -71
  198. package/skills/1password/references/cli-examples.md +0 -29
  199. package/skills/1password/references/get-started.md +0 -17
  200. package/skills/apple-notes/SKILL.md +0 -78
  201. package/skills/apple-reminders/SKILL.md +0 -119
  202. package/skills/bear-notes/SKILL.md +0 -108
  203. package/skills/blogwatcher/SKILL.md +0 -70
  204. package/skills/blucli/SKILL.md +0 -48
  205. package/skills/bluebubbles/SKILL.md +0 -132
  206. package/skills/camsnap/SKILL.md +0 -46
  207. package/skills/canvas/SKILL.md +0 -204
  208. package/skills/connect-email/SKILL.md +0 -142
  209. package/skills/document-generation/SKILL.md +0 -83
  210. package/skills/eightctl/SKILL.md +0 -51
  211. package/skills/food-order/SKILL.md +0 -49
  212. package/skills/gemini/SKILL.md +0 -44
  213. package/skills/gh-issues/SKILL.md +0 -865
  214. package/skills/gifgrep/SKILL.md +0 -80
  215. package/skills/github/SKILL.md +0 -164
  216. package/skills/gog/SKILL.md +0 -117
  217. package/skills/goplaces/SKILL.md +0 -53
  218. package/skills/healthcheck/SKILL.md +0 -246
  219. package/skills/himalaya/SKILL.md +0 -258
  220. package/skills/himalaya/references/configuration.md +0 -184
  221. package/skills/himalaya/references/message-composition.md +0 -199
  222. package/skills/imsg/SKILL.md +0 -122
  223. package/skills/long-task/SKILL.md +0 -58
  224. package/skills/long-task/scripts/detach-task.sh +0 -187
  225. package/skills/nano-banana-pro/SKILL.md +0 -59
  226. package/skills/nano-banana-pro/scripts/generate_image.py +0 -184
  227. package/skills/nano-pdf/SKILL.md +0 -39
  228. package/skills/notion/SKILL.md +0 -173
  229. package/skills/obsidian/SKILL.md +0 -82
  230. package/skills/openai-image-gen/SKILL.md +0 -90
  231. package/skills/openai-image-gen/scripts/gen.py +0 -240
  232. package/skills/openai-whisper/SKILL.md +0 -39
  233. package/skills/openai-whisper-api/SKILL.md +0 -53
  234. package/skills/openai-whisper-api/scripts/transcribe.sh +0 -85
  235. package/skills/openhue/SKILL.md +0 -113
  236. package/skills/oracle/SKILL.md +0 -126
  237. package/skills/ordercli/SKILL.md +0 -79
  238. package/skills/peekaboo/SKILL.md +0 -191
  239. package/skills/reactions-extensive/SKILL.md +0 -30
  240. package/skills/reactions-minimal/SKILL.md +0 -31
  241. package/skills/safe-edit/SKILL.md +0 -51
  242. package/skills/sag/SKILL.md +0 -88
  243. package/skills/sherpa-onnx-tts/SKILL.md +0 -104
  244. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +0 -178
  245. package/skills/songsee/SKILL.md +0 -50
  246. package/skills/sonoscli/SKILL.md +0 -66
  247. package/skills/spotify-player/SKILL.md +0 -65
  248. package/skills/symihub/SKILL.md +0 -78
  249. package/skills/things-mac/SKILL.md +0 -87
  250. package/skills/tmux/SKILL.md +0 -153
  251. package/skills/tmux/scripts/find-sessions.sh +0 -112
  252. package/skills/tmux/scripts/wait-for-text.sh +0 -83
  253. package/skills/trello/SKILL.md +0 -96
  254. package/skills/video-frames/SKILL.md +0 -47
  255. package/skills/video-frames/scripts/frame.sh +0 -81
  256. package/skills/voice-call/SKILL.md +0 -46
  257. package/skills/wacli/SKILL.md +0 -73
  258. package/skills/weather/SKILL.md +0 -113
  259. package/skills/xurl/SKILL.md +0 -462
@@ -1,89 +0,0 @@
1
- /**
2
- * Implicit feedback detection from user behavior.
3
- *
4
- * Analyzes the message_received hook to detect:
5
- * - Re-ask: next message within 60s with Jaccard similarity > 0.5 => negative signal
6
- * - Topic change: Jaccard similarity < 0.2 => positive signal (user moved on)
7
- * - Follow-up continuation: similarity 0.2-0.5 => neutral
8
- */
9
-
10
- import crypto from "node:crypto";
11
- import { jaccardSimilarity, tokenize } from "../../../../src/memory/mmr.js";
12
- import type { DatabaseManager } from "../db.js";
13
- import type { LearningLoopConfig, FeedbackRecord } from "../types.js";
14
-
15
- export type ImplicitSignals = ReturnType<typeof createImplicitSignals>;
16
-
17
- type RecentPrompt = {
18
- runId: string;
19
- content: string;
20
- tokens: Set<string>;
21
- timestamp: number;
22
- };
23
-
24
- const RE_ASK_WINDOW_MS = 60_000;
25
- const RE_ASK_SIMILARITY_THRESHOLD = 0.5;
26
- const TOPIC_CHANGE_THRESHOLD = 0.2;
27
-
28
- export function createImplicitSignals(params: { db: DatabaseManager; config: LearningLoopConfig }) {
29
- const { db } = params;
30
- const recentPrompts: RecentPrompt[] = [];
31
- const MAX_RECENT = 20;
32
-
33
- /**
34
- * Record a prompt that was just sent to the LLM, for later comparison.
35
- */
36
- function recordPrompt(runId: string, content: string): void {
37
- recentPrompts.push({
38
- runId,
39
- content,
40
- tokens: tokenize(content),
41
- timestamp: Date.now(),
42
- });
43
-
44
- // Keep bounded
45
- while (recentPrompts.length > MAX_RECENT) {
46
- recentPrompts.shift();
47
- }
48
- }
49
-
50
- /**
51
- * Analyze an incoming user message against recent prompts.
52
- * Returns a feedback record if an implicit signal is detected, null otherwise.
53
- */
54
- function analyzeMessage(content: string, timestamp: number): FeedbackRecord | null {
55
- if (recentPrompts.length === 0) return null;
56
-
57
- const messageTokens = tokenize(content);
58
- const lastPrompt = recentPrompts[recentPrompts.length - 1]!;
59
- const timeDelta = timestamp - lastPrompt.timestamp;
60
-
61
- const similarity = jaccardSimilarity(messageTokens, lastPrompt.tokens);
62
-
63
- let score: number | null = null;
64
-
65
- if (timeDelta <= RE_ASK_WINDOW_MS && similarity > RE_ASK_SIMILARITY_THRESHOLD) {
66
- // Re-ask: user is repeating themselves => bad signal
67
- score = 0.0;
68
- } else if (similarity < TOPIC_CHANGE_THRESHOLD) {
69
- // Topic change: user moved on => good signal
70
- score = 1.0;
71
- } else {
72
- // Continuation: neutral, no signal
73
- return null;
74
- }
75
-
76
- const feedback: FeedbackRecord = {
77
- id: `fb_${Date.now()}_${crypto.randomBytes(4).toString("hex")}`,
78
- runId: lastPrompt.runId,
79
- source: "implicit",
80
- score,
81
- createdAt: timestamp,
82
- };
83
-
84
- db.insertFeedback(feedback);
85
- return feedback;
86
- }
87
-
88
- return { recordPrompt, analyzeMessage };
89
- }
@@ -1,189 +0,0 @@
1
- /**
2
- * Automatic edge creation from learning-loop events.
3
- * No manual edge management -- edges are inferred from:
4
- * - Temporal co-occurrence (same run)
5
- * - Semantic similarity (embedding cosine)
6
- * - Supersession (same category, higher confidence)
7
- * - Contradiction (opposing categories with similar content)
8
- * - Reinforcement (co-applied learnings)
9
- * - Causation (injected learnings -> extracted learnings)
10
- */
11
-
12
- import { cosineSimilarity } from "../../../../src/memory/internal.js";
13
- import type { LearningStore } from "../learning/learning-store.js";
14
- import type { LearningRecord } from "../types.js";
15
- import type { GraphStore } from "./graph-store.js";
16
-
17
- export type EdgeInference = ReturnType<typeof createEdgeInference>;
18
-
19
- const NEGATION_TOKENS = new Set([
20
- "not",
21
- "avoid",
22
- "never",
23
- "don't",
24
- "dont",
25
- "fails",
26
- "instead",
27
- "shouldn't",
28
- "shouldnt",
29
- "won't",
30
- "wont",
31
- "cannot",
32
- "can't",
33
- "cant",
34
- ]);
35
-
36
- function tokenize(text: string): string[] {
37
- return text
38
- .toLowerCase()
39
- .replace(/[^\w\s]/g, " ")
40
- .split(/\s+/)
41
- .filter(Boolean);
42
- }
43
-
44
- function jaccardSimilarity(a: Set<string>, b: Set<string>): number {
45
- let intersection = 0;
46
- for (const token of a) {
47
- if (b.has(token)) intersection++;
48
- }
49
- const union = a.size + b.size - intersection;
50
- return union === 0 ? 0 : intersection / union;
51
- }
52
-
53
- export function createEdgeInference(params: {
54
- graphStore: GraphStore;
55
- learningStore: LearningStore;
56
- }) {
57
- const { graphStore, learningStore } = params;
58
-
59
- /**
60
- * Called after a new learning is created. Infers T, S, U, X edges.
61
- */
62
- function onLearningCreated(newLearning: LearningRecord, runId: string): void {
63
- const recentLearnings = learningStore.listLearnings({ limit: 100 });
64
-
65
- // 1. Temporal edges (T): other learnings from same run
66
- for (const existing of recentLearnings) {
67
- if (existing.id === newLearning.id) continue;
68
- if (existing.runId === runId) {
69
- graphStore.addEdge(existing.id, newLearning.id, "T", 0.5);
70
- }
71
- }
72
-
73
- // 2-4 require comparing against recent learnings
74
- for (const existing of recentLearnings) {
75
- if (existing.id === newLearning.id) continue;
76
-
77
- // 2. Semantic edges (S): cosine similarity between embeddings
78
- if (newLearning.embedding && existing.embedding) {
79
- const similarity = cosineSimilarity(newLearning.embedding, existing.embedding);
80
-
81
- if (similarity >= 0.6 && similarity < 0.92) {
82
- // Canonical ordering for bidirectional edges
83
- const [a, b] =
84
- existing.id < newLearning.id
85
- ? [existing.id, newLearning.id]
86
- : [newLearning.id, existing.id];
87
- graphStore.addEdge(a, b, "S", similarity);
88
- }
89
-
90
- // 3. Supersession edges (U): same category + high similarity + higher confidence
91
- if (
92
- similarity >= 0.8 &&
93
- existing.category === newLearning.category &&
94
- newLearning.confidence > existing.confidence
95
- ) {
96
- graphStore.addEdge(existing.id, newLearning.id, "U", 1.0);
97
- }
98
- }
99
-
100
- // 4. Contradiction edges (X)
101
- if (detectContradiction(newLearning, existing)) {
102
- const [a, b] =
103
- existing.id < newLearning.id
104
- ? [existing.id, newLearning.id]
105
- : [newLearning.id, existing.id];
106
- const weight =
107
- newLearning.embedding && existing.embedding
108
- ? Math.max(0.5, cosineSimilarity(newLearning.embedding, existing.embedding))
109
- : 0.7;
110
- graphStore.addEdge(a, b, "X", weight);
111
- }
112
- }
113
- }
114
-
115
- /**
116
- * Called after a run is scored. Infers R and C edges.
117
- * @param runId - The run that was scored
118
- * @param appliedIds - Learning IDs that were injected into this run
119
- * @param extractedIds - Learning IDs that were extracted from this run
120
- */
121
- function onRunScored(runId: string, appliedIds: string[], extractedIds: string[]): void {
122
- // 1. Reinforcement edges (R): between co-applied learnings
123
- for (let i = 0; i < appliedIds.length; i++) {
124
- for (let j = i + 1; j < appliedIds.length; j++) {
125
- const a = appliedIds[i]!;
126
- const b = appliedIds[j]!;
127
- const [source, target] = a < b ? [a, b] : [b, a];
128
-
129
- // Check existing edge weight to increment
130
- const existing = graphStore
131
- .getEdges(source, { typeFilter: ["R"] })
132
- .find((e) => e.sourceId === source && e.targetId === target);
133
-
134
- if (existing) {
135
- const newWeight = Math.min(0.8, existing.weight + 0.1);
136
- graphStore.upsertEdge(source, target, "R", newWeight);
137
- } else {
138
- graphStore.addEdge(source, target, "R", 0.3);
139
- }
140
- }
141
- }
142
-
143
- // 2. Causal edges (C): from injected learnings to extracted learnings
144
- for (const injectedId of appliedIds) {
145
- for (const extractedId of extractedIds) {
146
- graphStore.addEdge(injectedId, extractedId, "C", 0.6);
147
- }
148
- }
149
- }
150
-
151
- /**
152
- * Detect contradiction between two learnings via two heuristics:
153
- * 1. Category opposition (tool_pattern vs anti_pattern) with semantic similarity
154
- * 2. Negation density with high non-negation token overlap
155
- */
156
- function detectContradiction(a: LearningRecord, b: LearningRecord): boolean {
157
- // Heuristic 1: Category opposition
158
- const opposingCategories =
159
- (a.category === "tool_pattern" && b.category === "anti_pattern") ||
160
- (a.category === "anti_pattern" && b.category === "tool_pattern");
161
-
162
- if (opposingCategories && a.embedding && b.embedding) {
163
- const sim = cosineSimilarity(a.embedding, b.embedding);
164
- if (sim >= 0.7) return true;
165
- }
166
-
167
- // Heuristic 2: Negation density
168
- const tokensA = tokenize(a.content);
169
- const tokensB = tokenize(b.content);
170
-
171
- const negationsA = tokensA.filter((t) => NEGATION_TOKENS.has(t));
172
- const negationsB = tokensB.filter((t) => NEGATION_TOKENS.has(t));
173
-
174
- // One has negations, the other doesn't (or significantly fewer)
175
- const hasNegationAsymmetry =
176
- (negationsA.length > 0 && negationsB.length === 0) ||
177
- (negationsB.length > 0 && negationsA.length === 0);
178
-
179
- if (hasNegationAsymmetry) {
180
- const nonNegA = new Set(tokensA.filter((t) => !NEGATION_TOKENS.has(t)));
181
- const nonNegB = new Set(tokensB.filter((t) => !NEGATION_TOKENS.has(t)));
182
- if (jaccardSimilarity(nonNegA, nonNegB) >= 0.5) return true;
183
- }
184
-
185
- return false;
186
- }
187
-
188
- return { onLearningCreated, onRunScored };
189
- }
@@ -1,144 +0,0 @@
1
- /**
2
- * Hop expansion integrated into the retrieval pipeline.
3
- *
4
- * Takes seed results from vector/FTS retrieval, expands via graph neighbors,
5
- * computes expanded scores with hop decay and type multipliers, then merges
6
- * and re-applies MMR for diversity.
7
- */
8
-
9
- import { mmrRerank, type MMRItem } from "../../../../src/memory/mmr.js";
10
- import type { LearningStore } from "../learning/learning-store.js";
11
- import type { RetrievalResult } from "../learning/retrieval.js";
12
- import type { EdgeType, LearningLoopConfig } from "../types.js";
13
- import type { GraphStore } from "./graph-store.js";
14
-
15
- export type GraphRetrieval = ReturnType<typeof createGraphRetrieval>;
16
-
17
- const HOP_DECAY = 0.6;
18
- const CENTRALITY_HIGH_THRESHOLD = 2.0;
19
-
20
- const TYPE_MULTIPLIERS: Record<EdgeType, number> = {
21
- C: 1.0,
22
- S: 0.8,
23
- R: 0.7,
24
- T: 0.5,
25
- U: 0.3,
26
- X: 0.0, // Contradictions excluded from expansion
27
- };
28
-
29
- export function createGraphRetrieval(params: {
30
- graphStore: GraphStore;
31
- learningStore: LearningStore;
32
- config: LearningLoopConfig;
33
- }) {
34
- const { graphStore, learningStore } = params;
35
-
36
- /**
37
- * Expand seed retrieval results with graph neighbors.
38
- *
39
- * 1. Take top-5 seeds
40
- * 2. 1-hop expansion (2-hop for high-centrality seeds)
41
- * 3. Compute expanded scores with decay, type multiplier, centrality boost
42
- * 4. Merge with seeds, dedup, re-apply MMR
43
- * 5. Annotate contested results (X-edges)
44
- */
45
- function expandWithGraph(seeds: RetrievalResult[], limit: number): RetrievalResult[] {
46
- if (seeds.length === 0) return seeds;
47
-
48
- const topSeeds = seeds.slice(0, 5);
49
- const expanded = new Map<string, RetrievalResult>();
50
-
51
- // Keep all original seeds
52
- for (const seed of seeds) {
53
- expanded.set(seed.learning.id, seed);
54
- }
55
-
56
- // Expand each top seed
57
- for (const seed of topSeeds) {
58
- const seedId = seed.learning.id;
59
- const seedCentrality = graphStore.getCentrality(seedId);
60
- const maxHops = seedCentrality > CENTRALITY_HIGH_THRESHOLD ? 2 : 1;
61
-
62
- // Check for contradictions and annotate seed
63
- const contradictions = graphStore.getContradictions(seedId);
64
- if (contradictions.length > 0) {
65
- const existing = expanded.get(seedId)!;
66
- expanded.set(seedId, { ...existing, contested: true });
67
- }
68
-
69
- // Get edges for expansion
70
- const edges = graphStore.getEdges(seedId);
71
-
72
- for (const edge of edges) {
73
- if (TYPE_MULTIPLIERS[edge.edgeType] === 0) continue; // Skip contradictions
74
-
75
- const neighborId = edge.sourceId === seedId ? edge.targetId : edge.sourceId;
76
- const neighborLearning = learningStore.getLearning(neighborId);
77
- if (!neighborLearning) continue;
78
-
79
- const neighborCentrality = graphStore.getCentrality(neighborId);
80
- const centralityBoost = 1.0 + 0.1 * Math.log2(1 + neighborCentrality);
81
- const expandedScore =
82
- seed.decayedScore * HOP_DECAY * TYPE_MULTIPLIERS[edge.edgeType] * centralityBoost;
83
-
84
- const existing = expanded.get(neighborId);
85
- if (!existing || existing.decayedScore < expandedScore) {
86
- expanded.set(neighborId, {
87
- learning: neighborLearning,
88
- score: expandedScore,
89
- decayedScore: expandedScore,
90
- });
91
- }
92
-
93
- // 2-hop expansion for high-centrality seeds
94
- if (maxHops >= 2) {
95
- const hop2Edges = graphStore.getEdges(neighborId);
96
- for (const hop2Edge of hop2Edges) {
97
- if (TYPE_MULTIPLIERS[hop2Edge.edgeType] === 0) continue;
98
-
99
- const hop2Id = hop2Edge.sourceId === neighborId ? hop2Edge.targetId : hop2Edge.sourceId;
100
- if (hop2Id === seedId) continue;
101
-
102
- const hop2Learning = learningStore.getLearning(hop2Id);
103
- if (!hop2Learning) continue;
104
-
105
- const hop2Centrality = graphStore.getCentrality(hop2Id);
106
- const hop2CentralityBoost = 1.0 + 0.1 * Math.log2(1 + hop2Centrality);
107
- const hop2Score =
108
- seed.decayedScore *
109
- HOP_DECAY *
110
- HOP_DECAY *
111
- TYPE_MULTIPLIERS[hop2Edge.edgeType] *
112
- hop2CentralityBoost;
113
-
114
- const existingHop2 = expanded.get(hop2Id);
115
- if (!existingHop2 || existingHop2.decayedScore < hop2Score) {
116
- expanded.set(hop2Id, {
117
- learning: hop2Learning,
118
- score: hop2Score,
119
- decayedScore: hop2Score,
120
- });
121
- }
122
- }
123
- }
124
- }
125
- }
126
-
127
- // Convert to array and sort by score
128
- const allResults = Array.from(expanded.values());
129
- allResults.sort((a, b) => b.decayedScore - a.decayedScore);
130
-
131
- // Re-apply MMR reranking
132
- const mmrItems: (MMRItem & { original: RetrievalResult })[] = allResults.map((r) => ({
133
- id: r.learning.id,
134
- score: r.decayedScore,
135
- content: r.learning.content,
136
- original: r,
137
- }));
138
-
139
- const reranked = mmrRerank(mmrItems, { enabled: true, lambda: 0.7 });
140
- return reranked.slice(0, limit).map((item) => item.original);
141
- }
142
-
143
- return { expandWithGraph };
144
- }
@@ -1,183 +0,0 @@
1
- /**
2
- * Graph store: edge CRUD + incremental centrality tracking.
3
- *
4
- * Centrality model: log-weighted degree centrality.
5
- * centrality(node) = sum over edges(node): log2(1 + weight)
6
- *
7
- * Updated O(1) per edge add via delta. Log dampening prevents
8
- * high-degree nodes from dominating.
9
- */
10
-
11
- import type { DatabaseManager } from "../db.js";
12
- import type { EdgeType, LearningEdge, EdgeRow } from "../types.js";
13
-
14
- export type GraphStore = ReturnType<typeof createGraphStore>;
15
-
16
- function rowToEdge(row: EdgeRow): LearningEdge {
17
- return {
18
- id: row.id,
19
- sourceId: row.source_id,
20
- targetId: row.target_id,
21
- edgeType: row.edge_type as EdgeType,
22
- weight: row.weight,
23
- createdAt: row.created_at,
24
- };
25
- }
26
-
27
- export function createGraphStore(params: { db: DatabaseManager }) {
28
- const { db } = params;
29
-
30
- /**
31
- * Add an edge and incrementally update centrality for both endpoints.
32
- */
33
- function addEdge(source: string, target: string, type: EdgeType, weight: number): void {
34
- db.insertEdge(source, target, type, weight);
35
- const delta = Math.log2(1 + weight);
36
- updateCentralityDelta(source, delta);
37
- updateCentralityDelta(target, delta);
38
- }
39
-
40
- /**
41
- * Upsert an edge (update weight if exists). Adjusts centrality accordingly.
42
- */
43
- function upsertEdge(source: string, target: string, type: EdgeType, newWeight: number): void {
44
- // Check if edge already exists to compute delta
45
- const existing = db
46
- .getEdgesByNode(source)
47
- .find((e) => e.source_id === source && e.target_id === target && e.edge_type === type);
48
-
49
- if (existing) {
50
- const oldDelta = Math.log2(1 + existing.weight);
51
- const newDelta = Math.log2(1 + newWeight);
52
- const diff = newDelta - oldDelta;
53
- db.upsertEdge(source, target, type, newWeight);
54
- updateCentralityDelta(source, diff);
55
- updateCentralityDelta(target, diff);
56
- } else {
57
- db.upsertEdge(source, target, type, newWeight);
58
- const delta = Math.log2(1 + newWeight);
59
- updateCentralityDelta(source, delta);
60
- updateCentralityDelta(target, delta);
61
- }
62
- }
63
-
64
- /**
65
- * Get all edges for a learning, optionally filtered by type.
66
- */
67
- function getEdges(learningId: string, opts?: { typeFilter?: EdgeType[] }): LearningEdge[] {
68
- const rows = db.getEdgesByNode(learningId);
69
- let edges = rows.map(rowToEdge);
70
- if (opts?.typeFilter && opts.typeFilter.length > 0) {
71
- const allowed = new Set(opts.typeFilter);
72
- edges = edges.filter((e) => allowed.has(e.edgeType));
73
- }
74
- return edges;
75
- }
76
-
77
- /**
78
- * Get N-hop neighbors with accumulated weights.
79
- * Returns Map<learningId, accumulatedWeight>.
80
- */
81
- function getNeighbors(
82
- learningId: string,
83
- hops: number = 1,
84
- typeFilter?: EdgeType[],
85
- ): Map<string, number> {
86
- const result = new Map<string, number>();
87
- const visited = new Set<string>([learningId]);
88
- let frontier = new Map<string, number>([[learningId, 1.0]]);
89
-
90
- for (let hop = 0; hop < hops; hop++) {
91
- const nextFrontier = new Map<string, number>();
92
-
93
- for (const [nodeId, parentWeight] of frontier) {
94
- const edges = getEdges(nodeId, { typeFilter });
95
- for (const edge of edges) {
96
- const neighborId = edge.sourceId === nodeId ? edge.targetId : edge.sourceId;
97
- if (visited.has(neighborId)) continue;
98
-
99
- const weight = parentWeight * edge.weight;
100
- const existing = nextFrontier.get(neighborId) ?? 0;
101
- nextFrontier.set(neighborId, Math.max(existing, weight));
102
- }
103
- }
104
-
105
- for (const [nodeId, weight] of nextFrontier) {
106
- visited.add(nodeId);
107
- const existing = result.get(nodeId) ?? 0;
108
- result.set(nodeId, Math.max(existing, weight));
109
- }
110
-
111
- frontier = nextFrontier;
112
- if (frontier.size === 0) break;
113
- }
114
-
115
- return result;
116
- }
117
-
118
- /**
119
- * Get centrality score for a learning.
120
- */
121
- function getCentrality(learningId: string): number {
122
- return db.getCentralityScore(learningId);
123
- }
124
-
125
- /**
126
- * Remove all edges for a learning and recompute affected neighbors' centrality.
127
- */
128
- function removeEdgesFor(learningId: string): void {
129
- const edges = db.getEdgesByNode(learningId);
130
-
131
- // Collect affected neighbors
132
- const affected = new Set<string>();
133
- for (const edge of edges) {
134
- if (edge.source_id !== learningId) affected.add(edge.source_id);
135
- if (edge.target_id !== learningId) affected.add(edge.target_id);
136
- }
137
-
138
- // Delete all edges
139
- db.deleteEdgesForLearning(learningId);
140
- db.deleteCentralityScore(learningId);
141
-
142
- // Recompute centrality for affected neighbors
143
- for (const neighborId of affected) {
144
- recomputeCentrality(neighborId);
145
- }
146
- }
147
-
148
- /**
149
- * Get all contradiction edges, optionally for a specific learning.
150
- */
151
- function getContradictions(learningId?: string): LearningEdge[] {
152
- if (learningId) {
153
- return getEdges(learningId, { typeFilter: ["X"] });
154
- }
155
- return db.getEdgesByType("X").map(rowToEdge);
156
- }
157
-
158
- // --- Internal helpers ---
159
-
160
- function updateCentralityDelta(id: string, delta: number): void {
161
- const current = db.getCentralityScore(id);
162
- db.upsertCentralityScore(id, current + delta);
163
- }
164
-
165
- function recomputeCentrality(id: string): void {
166
- const edges = db.getEdgesByNode(id);
167
- let score = 0;
168
- for (const edge of edges) {
169
- score += Math.log2(1 + edge.weight);
170
- }
171
- db.upsertCentralityScore(id, score);
172
- }
173
-
174
- return {
175
- addEdge,
176
- upsertEdge,
177
- getEdges,
178
- getNeighbors,
179
- getCentrality,
180
- removeEdgesFor,
181
- getContradictions,
182
- };
183
- }