@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,583 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import type { DatabaseSync } from "node:sqlite";
4
- import { requireNodeSqlite } from "../../../src/memory/sqlite.js";
5
- import type { PluginLogger } from "../../../src/plugins/types.js";
6
- import { type EWMAState, updateEWMA, getEWMAValue } from "./math/ewma.js";
7
- import { initializeSchema } from "./schema.js";
8
- import type {
9
- LearningLoopConfig,
10
- RunRow,
11
- ToolCallRow,
12
- LearningRow,
13
- FeedbackRow,
14
- MetricsBucketRow,
15
- CompletedRun,
16
- QualityScore,
17
- LearningRecord,
18
- FeedbackRecord,
19
- EdgeRow,
20
- } from "./types.js";
21
- import { ALGORITHM_VERSION } from "./types.js";
22
-
23
- export type DatabaseManager = ReturnType<typeof createDatabaseManager>;
24
-
25
- export function createDatabaseManager(params: {
26
- stateDir: string;
27
- config: LearningLoopConfig;
28
- logger: PluginLogger;
29
- }) {
30
- const { stateDir, config, logger } = params;
31
- const dbPath = path.join(stateDir, "learning-loop.db");
32
-
33
- // Ensure state directory exists
34
- fs.mkdirSync(stateDir, { recursive: true });
35
-
36
- const { DatabaseSync } = requireNodeSqlite();
37
- const db = new DatabaseSync(dbPath);
38
- initializeSchema(db);
39
-
40
- // --- Runs ---
41
-
42
- function insertRun(run: CompletedRun, score: QualityScore): void {
43
- db.prepare(`
44
- INSERT INTO runs (
45
- run_id, session_id, session_key, agent_id,
46
- provider, model, prompt_hash, prompt_length,
47
- response_length, response_tool_call_count,
48
- usage_input, usage_output, usage_cache_read, usage_cache_write, usage_total,
49
- success, error, duration_ms,
50
- quality_score, algorithm_version,
51
- started_at, completed_at
52
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
53
- `).run(
54
- run.runId,
55
- run.sessionId,
56
- run.sessionKey,
57
- run.agentId,
58
- run.provider,
59
- run.model,
60
- run.promptHash,
61
- run.promptLength,
62
- run.responseLength,
63
- run.responseToolCallCount,
64
- run.usage.input ?? 0,
65
- run.usage.output ?? 0,
66
- run.usage.cacheRead ?? 0,
67
- run.usage.cacheWrite ?? 0,
68
- run.usage.total ?? 0,
69
- run.success ? 1 : 0,
70
- run.error,
71
- run.durationMs,
72
- score.score,
73
- score.algorithmVersion,
74
- run.startedAt,
75
- run.completedAt,
76
- );
77
-
78
- // Insert tool calls
79
- if (run.toolCalls.length > 0) {
80
- const stmt = db.prepare(`
81
- INSERT INTO tool_calls (run_id, tool_name, duration_ms, success, error, param_hash)
82
- VALUES (?, ?, ?, ?, ?, ?)
83
- `);
84
- for (const tc of run.toolCalls) {
85
- stmt.run(run.runId, tc.toolName, tc.durationMs, tc.success ? 1 : 0, tc.error, tc.paramHash);
86
- }
87
- }
88
-
89
- // Insert quality signals
90
- if (score.signals.length > 0) {
91
- const stmt = db.prepare(`
92
- INSERT INTO quality_signals (run_id, signal_name, value, confidence, weight)
93
- VALUES (?, ?, ?, ?, ?)
94
- `);
95
- for (const sig of score.signals) {
96
- stmt.run(run.runId, sig.name, sig.value, sig.confidence, sig.weight);
97
- }
98
- }
99
- }
100
-
101
- function getRun(runId: string): RunRow | undefined {
102
- return db.prepare(`SELECT * FROM runs WHERE run_id = ?`).get(runId) as RunRow | undefined;
103
- }
104
-
105
- function getRunCount(): number {
106
- const row = db
107
- .prepare(`SELECT COUNT(*) as cnt FROM runs WHERE run_id != '__pruned__'`)
108
- .get() as { cnt: number };
109
- return row.cnt;
110
- }
111
-
112
- function getToolCalls(runId: string): ToolCallRow[] {
113
- return db.prepare(`SELECT * FROM tool_calls WHERE run_id = ?`).all(runId) as ToolCallRow[];
114
- }
115
-
116
- function getRecentRuns(limit: number = 100): RunRow[] {
117
- return db
118
- .prepare(`SELECT * FROM runs ORDER BY completed_at DESC LIMIT ?`)
119
- .all(limit) as RunRow[];
120
- }
121
-
122
- function getRunsByModel(provider: string, model: string, limit: number = 100): RunRow[] {
123
- return db
124
- .prepare(
125
- `SELECT * FROM runs WHERE provider = ? AND model = ? ORDER BY completed_at DESC LIMIT ?`,
126
- )
127
- .all(provider, model, limit) as RunRow[];
128
- }
129
-
130
- // --- EWMA State ---
131
-
132
- function getEwmaState(provider: string, model: string, metric: string): EWMAState {
133
- const row = db
134
- .prepare(
135
- `SELECT value, count FROM ewma_state WHERE provider = ? AND model = ? AND metric = ?`,
136
- )
137
- .get(provider, model, metric) as { value: number; count: number } | undefined;
138
- return row ?? { value: 0, count: 0 };
139
- }
140
-
141
- function updateEwmaState(
142
- provider: string,
143
- model: string,
144
- metric: string,
145
- observation: number,
146
- alpha: number = 0.1,
147
- ): EWMAState {
148
- const current = getEwmaState(provider, model, metric);
149
- const updated = updateEWMA(current, observation, alpha);
150
- db.prepare(`
151
- INSERT INTO ewma_state (provider, model, metric, value, count)
152
- VALUES (?, ?, ?, ?, ?)
153
- ON CONFLICT(provider, model, metric) DO UPDATE SET
154
- value = excluded.value,
155
- count = excluded.count
156
- `).run(provider, model, metric, updated.value, updated.count);
157
- return updated;
158
- }
159
-
160
- // --- Learnings ---
161
-
162
- function insertLearning(learning: LearningRecord): void {
163
- db.prepare(`
164
- INSERT INTO learnings (id, run_id, category, content, embedding, confidence, applied_count, created_at, updated_at)
165
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
166
- `).run(
167
- learning.id,
168
- learning.runId,
169
- learning.category,
170
- learning.content,
171
- learning.embedding ? JSON.stringify(learning.embedding) : null,
172
- learning.confidence,
173
- learning.appliedCount,
174
- learning.createdAt,
175
- learning.updatedAt,
176
- );
177
- }
178
-
179
- function getLearning(id: string): LearningRow | undefined {
180
- return db.prepare(`SELECT * FROM learnings WHERE id = ?`).get(id) as LearningRow | undefined;
181
- }
182
-
183
- function getAllLearnings(limit: number = 1000): LearningRow[] {
184
- return db
185
- .prepare(`SELECT * FROM learnings ORDER BY updated_at DESC LIMIT ?`)
186
- .all(limit) as LearningRow[];
187
- }
188
-
189
- function getLearningsByCategory(category: string, limit: number = 100): LearningRow[] {
190
- return db
191
- .prepare(`SELECT * FROM learnings WHERE category = ? ORDER BY updated_at DESC LIMIT ?`)
192
- .all(category, limit) as LearningRow[];
193
- }
194
-
195
- function searchLearningsFts(query: string, limit: number = 20): LearningRow[] {
196
- return db
197
- .prepare(`
198
- SELECT l.* FROM learnings l
199
- JOIN learnings_fts fts ON l.rowid = fts.rowid
200
- WHERE learnings_fts MATCH ?
201
- ORDER BY rank
202
- LIMIT ?
203
- `)
204
- .all(query, limit) as LearningRow[];
205
- }
206
-
207
- function incrementAppliedCount(id: string): void {
208
- db.prepare(
209
- `UPDATE learnings SET applied_count = applied_count + 1, updated_at = ? WHERE id = ?`,
210
- ).run(Date.now(), id);
211
- }
212
-
213
- function deleteLearning(id: string): void {
214
- db.prepare(`DELETE FROM learnings WHERE id = ?`).run(id);
215
- }
216
-
217
- function getLearningsWithoutEmbeddings(limit: number): LearningRow[] {
218
- return db
219
- .prepare(`SELECT * FROM learnings WHERE embedding IS NULL LIMIT ?`)
220
- .all(limit) as LearningRow[];
221
- }
222
-
223
- function updateLearningEmbedding(id: string, embedding: number[]): void {
224
- db.prepare(`UPDATE learnings SET embedding = ? WHERE id = ?`).run(
225
- JSON.stringify(embedding),
226
- id,
227
- );
228
- }
229
-
230
- // --- Feedback ---
231
-
232
- function insertFeedback(feedback: FeedbackRecord): void {
233
- db.prepare(`
234
- INSERT INTO feedback (id, run_id, source, score, created_at)
235
- VALUES (?, ?, ?, ?, ?)
236
- `).run(feedback.id, feedback.runId, feedback.source, feedback.score, feedback.createdAt);
237
- }
238
-
239
- function getFeedback(runId: string): FeedbackRow[] {
240
- return db.prepare(`SELECT * FROM feedback WHERE run_id = ?`).all(runId) as FeedbackRow[];
241
- }
242
-
243
- // --- Metrics Buckets ---
244
-
245
- function upsertMetricsBucket(
246
- provider: string,
247
- model: string,
248
- completedAt: number,
249
- qualityScore: number,
250
- durationMs: number,
251
- success: boolean,
252
- usageInput: number,
253
- usageOutput: number,
254
- ): void {
255
- const bucketHour = new Date(completedAt).toISOString().slice(0, 13);
256
- db.prepare(`
257
- INSERT INTO metrics_buckets (
258
- provider, model, bucket_hour,
259
- run_count, success_count,
260
- quality_sum, quality_sum_sq,
261
- latency_sum, latency_sum_sq,
262
- token_input_sum, token_output_sum
263
- ) VALUES (?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?)
264
- ON CONFLICT(provider, model, bucket_hour) DO UPDATE SET
265
- run_count = run_count + 1,
266
- success_count = success_count + ?,
267
- quality_sum = quality_sum + ?,
268
- quality_sum_sq = quality_sum_sq + ?,
269
- latency_sum = latency_sum + ?,
270
- latency_sum_sq = latency_sum_sq + ?,
271
- token_input_sum = token_input_sum + ?,
272
- token_output_sum = token_output_sum + ?
273
- `).run(
274
- provider,
275
- model,
276
- bucketHour,
277
- success ? 1 : 0,
278
- qualityScore,
279
- qualityScore * qualityScore,
280
- durationMs,
281
- durationMs * durationMs,
282
- usageInput,
283
- usageOutput,
284
- // ON CONFLICT values
285
- success ? 1 : 0,
286
- qualityScore,
287
- qualityScore * qualityScore,
288
- durationMs,
289
- durationMs * durationMs,
290
- usageInput,
291
- usageOutput,
292
- );
293
- }
294
-
295
- function getMetricsBuckets(
296
- provider?: string,
297
- model?: string,
298
- fromHour?: string,
299
- toHour?: string,
300
- ): MetricsBucketRow[] {
301
- const conditions: string[] = [];
302
- const params: unknown[] = [];
303
-
304
- if (provider) {
305
- conditions.push("provider = ?");
306
- params.push(provider);
307
- }
308
- if (model) {
309
- conditions.push("model = ?");
310
- params.push(model);
311
- }
312
- if (fromHour) {
313
- conditions.push("bucket_hour >= ?");
314
- params.push(fromHour);
315
- }
316
- if (toHour) {
317
- conditions.push("bucket_hour <= ?");
318
- params.push(toHour);
319
- }
320
-
321
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
322
- return db
323
- .prepare(`SELECT * FROM metrics_buckets ${where} ORDER BY bucket_hour DESC`)
324
- .all(...params) as MetricsBucketRow[];
325
- }
326
-
327
- function getModelLeaderboard(): Array<{
328
- provider: string;
329
- model: string;
330
- runCount: number;
331
- successRate: number;
332
- avgQuality: number;
333
- avgLatency: number;
334
- }> {
335
- return db
336
- .prepare(`
337
- SELECT
338
- provider,
339
- model,
340
- SUM(run_count) as runCount,
341
- CASE WHEN SUM(run_count) > 0
342
- THEN CAST(SUM(success_count) AS REAL) / SUM(run_count)
343
- ELSE 0 END as successRate,
344
- CASE WHEN SUM(run_count) > 0
345
- THEN SUM(quality_sum) / SUM(run_count)
346
- ELSE 0 END as avgQuality,
347
- CASE WHEN SUM(run_count) > 0
348
- THEN SUM(latency_sum) / SUM(run_count)
349
- ELSE 0 END as avgLatency
350
- FROM metrics_buckets
351
- GROUP BY provider, model
352
- ORDER BY avgQuality DESC
353
- `)
354
- .all() as Array<{
355
- provider: string;
356
- model: string;
357
- runCount: number;
358
- successRate: number;
359
- avgQuality: number;
360
- avgLatency: number;
361
- }>;
362
- }
363
-
364
- // --- Graph Edges ---
365
-
366
- function insertEdge(sourceId: string, targetId: string, edgeType: string, weight: number): void {
367
- db.prepare(`
368
- INSERT INTO learning_edges (source_id, target_id, edge_type, weight, created_at)
369
- VALUES (?, ?, ?, ?, ?)
370
- `).run(sourceId, targetId, edgeType, weight, Date.now());
371
- }
372
-
373
- function upsertEdge(sourceId: string, targetId: string, edgeType: string, weight: number): void {
374
- db.prepare(`
375
- INSERT INTO learning_edges (source_id, target_id, edge_type, weight, created_at)
376
- VALUES (?, ?, ?, ?, ?)
377
- ON CONFLICT(source_id, target_id, edge_type) DO UPDATE SET
378
- weight = excluded.weight,
379
- created_at = excluded.created_at
380
- `).run(sourceId, targetId, edgeType, weight, Date.now());
381
- }
382
-
383
- function getEdgesBySource(id: string): EdgeRow[] {
384
- return db.prepare(`SELECT * FROM learning_edges WHERE source_id = ?`).all(id) as EdgeRow[];
385
- }
386
-
387
- function getEdgesByTarget(id: string): EdgeRow[] {
388
- return db.prepare(`SELECT * FROM learning_edges WHERE target_id = ?`).all(id) as EdgeRow[];
389
- }
390
-
391
- function getEdgesByNode(id: string): EdgeRow[] {
392
- return db
393
- .prepare(`SELECT * FROM learning_edges WHERE source_id = ? OR target_id = ?`)
394
- .all(id, id) as EdgeRow[];
395
- }
396
-
397
- function getEdgesByType(edgeType: string, limit: number = 1000): EdgeRow[] {
398
- return db
399
- .prepare(`SELECT * FROM learning_edges WHERE edge_type = ? LIMIT ?`)
400
- .all(edgeType, limit) as EdgeRow[];
401
- }
402
-
403
- function deleteEdgesForLearning(id: string): void {
404
- db.prepare(`DELETE FROM learning_edges WHERE source_id = ? OR target_id = ?`).run(id, id);
405
- }
406
-
407
- function getCentralityScore(id: string): number {
408
- const row = db.prepare(`SELECT score FROM centrality_scores WHERE learning_id = ?`).get(id) as
409
- | { score: number }
410
- | undefined;
411
- return row?.score ?? 0;
412
- }
413
-
414
- function upsertCentralityScore(id: string, score: number): void {
415
- db.prepare(`
416
- INSERT INTO centrality_scores (learning_id, score, updated_at)
417
- VALUES (?, ?, ?)
418
- ON CONFLICT(learning_id) DO UPDATE SET
419
- score = excluded.score,
420
- updated_at = excluded.updated_at
421
- `).run(id, score, Date.now());
422
- }
423
-
424
- function deleteCentralityScore(id: string): void {
425
- db.prepare(`DELETE FROM centrality_scores WHERE learning_id = ?`).run(id);
426
- }
427
-
428
- // --- Pruning ---
429
-
430
- function ensurePrunedSentinel(): void {
431
- const exists = db.prepare(`SELECT 1 FROM runs WHERE run_id = '__pruned__'`).get();
432
- if (!exists) {
433
- db.prepare(`
434
- INSERT INTO runs (
435
- run_id, session_id, session_key, agent_id,
436
- provider, model, prompt_hash, prompt_length,
437
- response_length, response_tool_call_count,
438
- usage_input, usage_output, usage_cache_read, usage_cache_write, usage_total,
439
- success, error, duration_ms,
440
- quality_score, algorithm_version,
441
- started_at, completed_at
442
- ) VALUES ('__pruned__','','','','','','',0,0,0,0,0,0,0,0,1,NULL,0,NULL,NULL,0,0)
443
- `).run();
444
- }
445
- }
446
-
447
- function pruneOldRuns(maxRuns: number): number {
448
- const count = getRunCount();
449
- if (count <= maxRuns) return 0;
450
-
451
- const toDelete = count - maxRuns;
452
- const oldestRuns = db
453
- .prepare(
454
- `SELECT run_id FROM runs WHERE run_id != '__pruned__' ORDER BY completed_at ASC LIMIT ?`,
455
- )
456
- .all(toDelete) as Array<{ run_id: string }>;
457
-
458
- if (oldestRuns.length === 0) return 0;
459
-
460
- db.exec("BEGIN");
461
- try {
462
- ensurePrunedSentinel();
463
- for (const row of oldestRuns) {
464
- db.prepare(`DELETE FROM tool_calls WHERE run_id = ?`).run(row.run_id);
465
- db.prepare(`DELETE FROM quality_signals WHERE run_id = ?`).run(row.run_id);
466
- db.prepare(`DELETE FROM feedback WHERE run_id = ?`).run(row.run_id);
467
- db.prepare(`UPDATE learnings SET run_id = '__pruned__' WHERE run_id = ?`).run(row.run_id);
468
- db.prepare(`DELETE FROM runs WHERE run_id = ?`).run(row.run_id);
469
- }
470
- db.exec("COMMIT");
471
- } catch (err) {
472
- db.exec("ROLLBACK");
473
- throw err;
474
- }
475
-
476
- return oldestRuns.length;
477
- }
478
-
479
- /**
480
- * Remove learnings that are genuinely unused: never applied, low confidence,
481
- * and older than maxAge (ms). Also cleans up associated graph edges.
482
- */
483
- function pruneStaleLearnings(maxAge: number): number {
484
- const cutoff = Date.now() - maxAge;
485
- const stale = db
486
- .prepare(
487
- `SELECT id FROM learnings WHERE applied_count = 0 AND confidence < 0.5 AND updated_at < ?`,
488
- )
489
- .all(cutoff) as Array<{ id: string }>;
490
-
491
- if (stale.length === 0) return 0;
492
-
493
- db.exec("BEGIN");
494
- try {
495
- for (const row of stale) {
496
- deleteEdgesForLearning(row.id);
497
- deleteCentralityScore(row.id);
498
- db.prepare(`DELETE FROM learnings WHERE id = ?`).run(row.id);
499
- }
500
- db.exec("COMMIT");
501
- } catch (err) {
502
- db.exec("ROLLBACK");
503
- throw err;
504
- }
505
-
506
- return stale.length;
507
- }
508
-
509
- /**
510
- * Update the stored quality score for a run (used when feedback arrives after initial scoring).
511
- */
512
- function updateRunScore(runId: string, score: number): void {
513
- db.prepare(`UPDATE runs SET quality_score = ? WHERE run_id = ?`).run(score, runId);
514
- }
515
-
516
- // --- Utility ---
517
-
518
- function getStats(): {
519
- runCount: number;
520
- learningCount: number;
521
- feedbackCount: number;
522
- } {
523
- const runs = (db.prepare(`SELECT COUNT(*) as cnt FROM runs`).get() as { cnt: number }).cnt;
524
- const learnings = (db.prepare(`SELECT COUNT(*) as cnt FROM learnings`).get() as { cnt: number })
525
- .cnt;
526
- const feedbacks = (db.prepare(`SELECT COUNT(*) as cnt FROM feedback`).get() as { cnt: number })
527
- .cnt;
528
- return { runCount: runs, learningCount: learnings, feedbackCount: feedbacks };
529
- }
530
-
531
- function close(): void {
532
- try {
533
- db.close();
534
- } catch {
535
- // Already closed
536
- }
537
- }
538
-
539
- function raw(): DatabaseSync {
540
- return db;
541
- }
542
-
543
- return {
544
- insertRun,
545
- getRun,
546
- getRunCount,
547
- getToolCalls,
548
- getRecentRuns,
549
- getRunsByModel,
550
- getEwmaState,
551
- updateEwmaState,
552
- insertLearning,
553
- getLearning,
554
- getAllLearnings,
555
- getLearningsByCategory,
556
- searchLearningsFts,
557
- incrementAppliedCount,
558
- deleteLearning,
559
- getLearningsWithoutEmbeddings,
560
- updateLearningEmbedding,
561
- insertFeedback,
562
- getFeedback,
563
- upsertMetricsBucket,
564
- getMetricsBuckets,
565
- getModelLeaderboard,
566
- pruneOldRuns,
567
- pruneStaleLearnings,
568
- updateRunScore,
569
- getStats,
570
- close,
571
- raw,
572
- insertEdge,
573
- upsertEdge,
574
- getEdgesBySource,
575
- getEdgesByTarget,
576
- getEdgesByNode,
577
- getEdgesByType,
578
- deleteEdgesForLearning,
579
- getCentralityScore,
580
- upsertCentralityScore,
581
- deleteCentralityScore,
582
- };
583
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * Explicit feedback handler for user-submitted ratings.
3
- * Accepts a 1-5 score via gateway RPC and stores it as feedback.
4
- */
5
-
6
- import crypto from "node:crypto";
7
- import { reconstructCompletedRun } from "../capture/serializer.js";
8
- import type { DatabaseManager } from "../db.js";
9
- import type { QualityEngine } from "../scoring/quality-engine.js";
10
- import type { FeedbackRecord } from "../types.js";
11
-
12
- export type ExplicitFeedbackHandler = ReturnType<typeof createExplicitFeedbackHandler>;
13
-
14
- export function createExplicitFeedbackHandler(params: {
15
- db: DatabaseManager;
16
- qualityEngine?: QualityEngine;
17
- }) {
18
- const { db, qualityEngine } = params;
19
-
20
- /**
21
- * Submit explicit user feedback for a run.
22
- *
23
- * @param runId - The run to provide feedback for
24
- * @param score - Rating from 1 to 5
25
- * @returns The created feedback record, or null if the run doesn't exist
26
- */
27
- function submitFeedback(runId: string, score: number): FeedbackRecord | null {
28
- const runRow = db.getRun(runId);
29
- if (!runRow) return null;
30
-
31
- const clampedScore = Math.max(1, Math.min(5, Math.round(score)));
32
-
33
- const feedback: FeedbackRecord = {
34
- id: `fb_${Date.now()}_${crypto.randomBytes(4).toString("hex")}`,
35
- runId,
36
- source: "explicit",
37
- score: clampedScore,
38
- createdAt: Date.now(),
39
- };
40
-
41
- db.insertFeedback(feedback);
42
-
43
- // Close the feedback loop: rescore the run with explicit feedback
44
- if (qualityEngine) {
45
- const toolCalls = db.getToolCalls(runId);
46
- const completedRun = reconstructCompletedRun(runRow, toolCalls);
47
- const newScore = qualityEngine.rescoreWithFeedback(completedRun, {
48
- source: "explicit",
49
- score: clampedScore,
50
- });
51
- db.updateRunScore(runId, newScore.score);
52
- }
53
-
54
- return feedback;
55
- }
56
-
57
- return { submitFeedback };
58
- }