@cachly-dev/mcp-server 0.10.128 → 0.10.130

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 (217) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +1 -7
  3. package/dist/packages/telegram-notify/client.js +2 -75
  4. package/dist/src/ambient-cli.js +7 -253
  5. package/dist/src/ambient-deps.js +1 -55
  6. package/dist/src/ambient-hooks.js +5 -278
  7. package/dist/src/ambient-ledger.js +6 -95
  8. package/dist/src/ambient-memory.js +1 -67
  9. package/dist/src/ambient-recall.js +1 -221
  10. package/dist/src/aussetzer.js +1 -82
  11. package/dist/src/auth.js +9 -140
  12. package/dist/src/autor-abzeichen.js +1 -56
  13. package/dist/src/autor.js +1 -136
  14. package/dist/src/bauabdruck.js +1 -93
  15. package/dist/src/bedeutung.js +2 -323
  16. package/dist/src/bench/cachly-bench.js +4 -249
  17. package/dist/src/bench/external-corpus.js +4 -135
  18. package/dist/src/bench/fixtures.js +1 -225
  19. package/dist/src/brain-export.js +16 -119
  20. package/dist/src/brain-watch-hook.js +8 -86
  21. package/dist/src/cachly-url.js +1 -21
  22. package/dist/src/ckg.js +1 -108
  23. package/dist/src/cls-hook.js +8 -94
  24. package/dist/src/confidence.js +1 -50
  25. package/dist/src/credentials.js +1 -85
  26. package/dist/src/deutsch.js +1 -223
  27. package/dist/src/doctor.js +2 -248
  28. package/dist/src/editor.js +1 -63
  29. package/dist/src/eingaenge-nachruesten.js +1 -290
  30. package/dist/src/eingaenge.js +2 -228
  31. package/dist/src/embeddings.js +13 -223
  32. package/dist/src/feldreparatur.js +3 -0
  33. package/dist/src/first-contact.js +4 -108
  34. package/dist/src/first-recall-proof.js +4 -41
  35. package/dist/src/funnel-milestones.js +2 -48
  36. package/dist/src/geliefert.js +1 -114
  37. package/dist/src/handlers/advanced.js +38 -537
  38. package/dist/src/handlers/brain.js +69 -4181
  39. package/dist/src/handlers/cache.js +59 -638
  40. package/dist/src/handlers/context.js +17 -182
  41. package/dist/src/handlers/fedbrain.js +40 -1436
  42. package/dist/src/handlers/instances.js +16 -201
  43. package/dist/src/handlers/roadmap.js +13 -175
  44. package/dist/src/handlers/share.js +19 -530
  45. package/dist/src/handlers/syndicate.js +38 -904
  46. package/dist/src/handlers/team.js +89 -1850
  47. package/dist/src/handlers/viz.js +3 -148
  48. package/dist/src/index.js +321 -4281
  49. package/dist/src/interferenz.js +1 -0
  50. package/dist/src/kostprobe.js +7 -125
  51. package/dist/src/lesson-preview.js +2 -133
  52. package/dist/src/namespace.js +1 -128
  53. package/dist/src/notifier.js +1 -6
  54. package/dist/src/rangfolge-stellschrauben.js +1 -0
  55. package/dist/src/rangfolge.js +1 -214
  56. package/dist/src/raumkorrektur.js +1 -197
  57. package/dist/src/recall-tiefe.js +1 -42
  58. package/dist/src/rerank.js +1 -154
  59. package/dist/src/resonanz.js +1 -0
  60. package/dist/src/search.js +1 -2104
  61. package/dist/src/seltenheitsbestand.js +1 -92
  62. package/dist/src/speicherlage.js +1 -84
  63. package/dist/src/spuren.js +1 -150
  64. package/dist/src/starter-corpus.js +1 -165
  65. package/dist/src/telemetry-types.js +0 -13
  66. package/dist/src/tools.js +10 -2465
  67. package/dist/src/toolspecs.js +1 -121
  68. package/dist/src/upgrade-nudge.js +1 -29
  69. package/dist/src/utils.js +1 -89
  70. package/dist/src/versuch.js +1 -250
  71. package/dist/src/vorspann.js +1 -146
  72. package/dist/src/wartung/vektoren-verdichten.js +1 -200
  73. package/dist/src/werkzeug-nutzung.js +1 -72
  74. package/dist/src/wertbeitrag.js +1 -73
  75. package/dist/src/wirkungsspur.js +1 -0
  76. package/glama.json +1 -1
  77. package/package.json +8 -7
  78. package/server.json +3 -3
  79. package/dist/index.d.ts +0 -1
  80. package/dist/index.js.map +0 -1
  81. package/dist/packages/telegram-notify/client.d.ts +0 -19
  82. package/dist/packages/telegram-notify/client.js.map +0 -1
  83. package/dist/src/ambient-cli.d.ts +0 -101
  84. package/dist/src/ambient-cli.js.map +0 -1
  85. package/dist/src/ambient-deps.d.ts +0 -26
  86. package/dist/src/ambient-deps.js.map +0 -1
  87. package/dist/src/ambient-hooks.d.ts +0 -137
  88. package/dist/src/ambient-hooks.js.map +0 -1
  89. package/dist/src/ambient-ledger.d.ts +0 -19
  90. package/dist/src/ambient-ledger.js.map +0 -1
  91. package/dist/src/ambient-memory.d.ts +0 -12
  92. package/dist/src/ambient-memory.js.map +0 -1
  93. package/dist/src/ambient-recall.d.ts +0 -127
  94. package/dist/src/ambient-recall.js.map +0 -1
  95. package/dist/src/aussetzer.d.ts +0 -67
  96. package/dist/src/aussetzer.js.map +0 -1
  97. package/dist/src/auth.d.ts +0 -43
  98. package/dist/src/auth.js.map +0 -1
  99. package/dist/src/autor-abzeichen.d.ts +0 -41
  100. package/dist/src/autor-abzeichen.js.map +0 -1
  101. package/dist/src/autor.d.ts +0 -101
  102. package/dist/src/autor.js.map +0 -1
  103. package/dist/src/bauabdruck-daten.generiert.json +0 -5
  104. package/dist/src/bauabdruck.d.ts +0 -38
  105. package/dist/src/bauabdruck.js.map +0 -1
  106. package/dist/src/bedeutung.d.ts +0 -168
  107. package/dist/src/bedeutung.js.map +0 -1
  108. package/dist/src/bench/cachly-bench.d.ts +0 -61
  109. package/dist/src/bench/cachly-bench.js.map +0 -1
  110. package/dist/src/bench/external-corpus.d.ts +0 -44
  111. package/dist/src/bench/external-corpus.js.map +0 -1
  112. package/dist/src/bench/fixtures.d.ts +0 -37
  113. package/dist/src/bench/fixtures.js.map +0 -1
  114. package/dist/src/brain-export.d.ts +0 -64
  115. package/dist/src/brain-export.js.map +0 -1
  116. package/dist/src/brain-watch-hook.d.ts +0 -21
  117. package/dist/src/brain-watch-hook.js.map +0 -1
  118. package/dist/src/cachly-url.d.ts +0 -68
  119. package/dist/src/cachly-url.js.map +0 -1
  120. package/dist/src/ckg.d.ts +0 -54
  121. package/dist/src/ckg.js.map +0 -1
  122. package/dist/src/cls-hook.d.ts +0 -15
  123. package/dist/src/cls-hook.js.map +0 -1
  124. package/dist/src/confidence.d.ts +0 -19
  125. package/dist/src/confidence.js.map +0 -1
  126. package/dist/src/credentials.d.ts +0 -37
  127. package/dist/src/credentials.js.map +0 -1
  128. package/dist/src/deutsch.d.ts +0 -98
  129. package/dist/src/deutsch.js.map +0 -1
  130. package/dist/src/doctor.d.ts +0 -47
  131. package/dist/src/doctor.js.map +0 -1
  132. package/dist/src/editor.d.ts +0 -9
  133. package/dist/src/editor.js.map +0 -1
  134. package/dist/src/eingaenge-nachruesten.d.ts +0 -41
  135. package/dist/src/eingaenge-nachruesten.js.map +0 -1
  136. package/dist/src/eingaenge.d.ts +0 -135
  137. package/dist/src/eingaenge.js.map +0 -1
  138. package/dist/src/embeddings.d.ts +0 -48
  139. package/dist/src/embeddings.js.map +0 -1
  140. package/dist/src/first-contact.d.ts +0 -56
  141. package/dist/src/first-contact.js.map +0 -1
  142. package/dist/src/first-recall-proof.d.ts +0 -19
  143. package/dist/src/first-recall-proof.js.map +0 -1
  144. package/dist/src/funnel-milestones.d.ts +0 -5
  145. package/dist/src/funnel-milestones.js.map +0 -1
  146. package/dist/src/geliefert.d.ts +0 -63
  147. package/dist/src/geliefert.js.map +0 -1
  148. package/dist/src/handlers/advanced.d.ts +0 -6
  149. package/dist/src/handlers/advanced.js.map +0 -1
  150. package/dist/src/handlers/brain.d.ts +0 -41
  151. package/dist/src/handlers/brain.js.map +0 -1
  152. package/dist/src/handlers/cache.d.ts +0 -6
  153. package/dist/src/handlers/cache.js.map +0 -1
  154. package/dist/src/handlers/context.d.ts +0 -6
  155. package/dist/src/handlers/context.js.map +0 -1
  156. package/dist/src/handlers/fedbrain.d.ts +0 -18
  157. package/dist/src/handlers/fedbrain.js.map +0 -1
  158. package/dist/src/handlers/instances.d.ts +0 -33
  159. package/dist/src/handlers/instances.js.map +0 -1
  160. package/dist/src/handlers/roadmap.d.ts +0 -6
  161. package/dist/src/handlers/roadmap.js.map +0 -1
  162. package/dist/src/handlers/share.d.ts +0 -8
  163. package/dist/src/handlers/share.js.map +0 -1
  164. package/dist/src/handlers/syndicate.d.ts +0 -6
  165. package/dist/src/handlers/syndicate.js.map +0 -1
  166. package/dist/src/handlers/team.d.ts +0 -45
  167. package/dist/src/handlers/team.js.map +0 -1
  168. package/dist/src/handlers/viz.d.ts +0 -6
  169. package/dist/src/handlers/viz.js.map +0 -1
  170. package/dist/src/index.d.ts +0 -93
  171. package/dist/src/index.js.map +0 -1
  172. package/dist/src/kostprobe.d.ts +0 -25
  173. package/dist/src/kostprobe.js.map +0 -1
  174. package/dist/src/lesson-preview.d.ts +0 -81
  175. package/dist/src/lesson-preview.js.map +0 -1
  176. package/dist/src/namespace.d.ts +0 -20
  177. package/dist/src/namespace.js.map +0 -1
  178. package/dist/src/notifier.d.ts +0 -5
  179. package/dist/src/notifier.js.map +0 -1
  180. package/dist/src/rangfolge.d.ts +0 -169
  181. package/dist/src/rangfolge.js.map +0 -1
  182. package/dist/src/raumkorrektur.d.ts +0 -100
  183. package/dist/src/raumkorrektur.js.map +0 -1
  184. package/dist/src/recall-tiefe.d.ts +0 -48
  185. package/dist/src/recall-tiefe.js.map +0 -1
  186. package/dist/src/rerank.d.ts +0 -48
  187. package/dist/src/rerank.js.map +0 -1
  188. package/dist/src/search.d.ts +0 -153
  189. package/dist/src/search.js.map +0 -1
  190. package/dist/src/seltenheitsbestand.d.ts +0 -53
  191. package/dist/src/seltenheitsbestand.js.map +0 -1
  192. package/dist/src/speicherlage.d.ts +0 -51
  193. package/dist/src/speicherlage.js.map +0 -1
  194. package/dist/src/spuren.d.ts +0 -97
  195. package/dist/src/spuren.js.map +0 -1
  196. package/dist/src/starter-corpus.d.ts +0 -28
  197. package/dist/src/starter-corpus.js.map +0 -1
  198. package/dist/src/telemetry-types.d.ts +0 -87
  199. package/dist/src/telemetry-types.js.map +0 -1
  200. package/dist/src/tools.d.ts +0 -2933
  201. package/dist/src/tools.js.map +0 -1
  202. package/dist/src/toolspecs.d.ts +0 -43
  203. package/dist/src/toolspecs.js.map +0 -1
  204. package/dist/src/upgrade-nudge.d.ts +0 -15
  205. package/dist/src/upgrade-nudge.js.map +0 -1
  206. package/dist/src/utils.d.ts +0 -34
  207. package/dist/src/utils.js.map +0 -1
  208. package/dist/src/versuch.d.ts +0 -179
  209. package/dist/src/versuch.js.map +0 -1
  210. package/dist/src/vorspann.d.ts +0 -73
  211. package/dist/src/vorspann.js.map +0 -1
  212. package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
  213. package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
  214. package/dist/src/werkzeug-nutzung.d.ts +0 -62
  215. package/dist/src/werkzeug-nutzung.js.map +0 -1
  216. package/dist/src/wertbeitrag.d.ts +0 -57
  217. package/dist/src/wertbeitrag.js.map +0 -1
@@ -1,223 +1,13 @@
1
- /**
2
- * ┌──────────────────────────────────────────────────────────────────────┐
3
- * │ EMBEDDING PROVIDER — pluggable, client-side first │
4
- * │ │
5
- * │ Auto-detects from env vars. To force a provider, set: │
6
- * │ CACHLY_EMBED_PROVIDER=openai (+ OPENAI_API_KEY) │
7
- * │ CACHLY_EMBED_PROVIDER=gemini (+ GEMINI_API_KEY) │
8
- * │ CACHLY_EMBED_PROVIDER=mistral (+ MISTRAL_API_KEY) │
9
- * │ CACHLY_EMBED_PROVIDER=cohere (+ COHERE_API_KEY) │
10
- * │ CACHLY_EMBED_PROVIDER=ollama (+ OLLAMA_BASE_URL, local) │
11
- * │ CACHLY_EMBED_PROVIDER=cachly (server-side fallback, no key) │
12
- * │ │
13
- * │ Priority: openai > gemini > mistral > cohere > ollama > cachly │
14
- * │ Brain works WITHOUT embedding (keyword search + exact key lookup). │
15
- * │ Embedding is an optional boost for semantic_search/index_project. │
16
- * └──────────────────────────────────────────────────────────────────────┘
17
- *
18
- * Mutable config — call setEmbedJwt() when the JWT changes (device flow).
19
- */
20
- // ── Mutable config (synced with index.ts JWT on device-flow auth) ────────────
21
- export const embedConfig = {
22
- apiUrl: process.env.CACHLY_API_URL ?? 'https://api.cachly.dev',
23
- jwt: process.env.CACHLY_JWT ?? '',
24
- model: process.env.CACHLY_EMBED_MODEL ?? '',
25
- };
26
- /** Call this when JWT is refreshed (e.g. after device flow). */
27
- export function setEmbedJwt(jwt) {
28
- embedConfig.jwt = jwt;
29
- }
30
- // Hard timeout for any embedding-provider HTTP call. Embedding is an OPTIONAL boost
31
- // for semantic recall — a slow/unreachable provider must never hang the agent turn.
32
- // Callers already treat embedding failures as non-fatal (keyword search still works).
33
- const EMBED_TIMEOUT_MS = Number(process.env.CACHLY_EMBED_TIMEOUT_MS ?? 8_000);
34
- // ── Provider auto-detection ───────────────────────────────────────────────────
35
- function detectEmbedProvider() {
36
- // Client-side keys first (direct, fast, no server roundtrip)
37
- if (process.env.OPENAI_API_KEY)
38
- return 'openai';
39
- if (process.env.GEMINI_API_KEY)
40
- return 'gemini';
41
- if (process.env.MISTRAL_API_KEY)
42
- return 'mistral';
43
- if (process.env.COHERE_API_KEY)
44
- return 'cohere';
45
- if (process.env.OLLAMA_BASE_URL)
46
- return 'ollama';
47
- // Server-side fallback — no API key needed, but adds latency
48
- if (process.env.CACHLY_JWT)
49
- return 'cachly';
50
- return 'none'; // no provider → embedding disabled, brain still works via exact keys
51
- }
52
- export const EMBED_PROVIDER = (process.env.CACHLY_EMBED_PROVIDER ?? detectEmbedProvider()).toLowerCase();
53
- // ── Multi-provider embedding ─────────────────────────────────────────────────
54
- /**
55
- * Compute an embedding vector for `text` using the configured provider.
56
- *
57
- * Client-side (recommended — set one API key in your .env):
58
- * openai – OPENAI_API_KEY · text-embedding-3-small
59
- * gemini – GEMINI_API_KEY · text-embedding-004
60
- * mistral – MISTRAL_API_KEY · mistral-embed
61
- * cohere – COHERE_API_KEY · embed-english-v3.0
62
- * ollama – OLLAMA_BASE_URL · nomic-embed-text (local, free)
63
- *
64
- * Server-side fallback (no key needed on client):
65
- * cachly – POST /api/v1/embed (requires CACHLY_JWT)
66
- *
67
- * Note: Brain works fully WITHOUT embedding (keyword search + exact keys).
68
- * Embedding is an OPTIONAL boost for semantic_search and index_project.
69
- */
70
- export async function computeEmbedding(text) {
71
- switch (EMBED_PROVIDER) {
72
- case 'cachly': {
73
- // Server-side embedding — the Cachly API computes the embedding
74
- // using whatever provider is configured on the server. No client-side API key needed.
75
- if (!embedConfig.jwt)
76
- throw new Error('CACHLY_JWT not set.\n\n' +
77
- 'The "cachly" provider uses server-side embeddings via the Cachly API.\n' +
78
- 'Set CACHLY_JWT, or use another provider via CACHLY_EMBED_PROVIDER:\n' +
79
- ' openai → OPENAI_API_KEY\n' +
80
- ' gemini → GEMINI_API_KEY\n' +
81
- ' ollama → OLLAMA_BASE_URL (local, no key needed)');
82
- const url = `${embedConfig.apiUrl}/api/v1/embed`;
83
- const body = { text };
84
- if (embedConfig.model)
85
- body.model = embedConfig.model;
86
- const res = await fetch(url, {
87
- method: 'POST',
88
- headers: {
89
- 'Content-Type': 'application/json',
90
- 'Authorization': `Bearer ${embedConfig.jwt}`,
91
- },
92
- body: JSON.stringify(body),
93
- signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
94
- });
95
- if (!res.ok) {
96
- const errBody = await res.text();
97
- throw new Error(`Cachly embed API error ${res.status}: ${errBody}`);
98
- }
99
- const json = (await res.json());
100
- return json.embedding;
101
- }
102
- case 'mistral': {
103
- const key = process.env.MISTRAL_API_KEY;
104
- if (!key)
105
- throw new Error('MISTRAL_API_KEY not set');
106
- const model = embedConfig.model !== 'text-embedding-3-small' ? embedConfig.model : 'mistral-embed';
107
- const res = await fetch('https://api.mistral.ai/v1/embeddings', {
108
- method: 'POST',
109
- headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
110
- body: JSON.stringify({ model, input: [text] }),
111
- signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
112
- });
113
- if (!res.ok)
114
- throw new Error(`Mistral embedding error: ${res.statusText}`);
115
- const json = (await res.json());
116
- if (!json.data?.[0]?.embedding)
117
- throw new Error('Mistral returned empty embedding response');
118
- return json.data[0].embedding;
119
- }
120
- case 'cohere': {
121
- const key = process.env.COHERE_API_KEY;
122
- if (!key)
123
- throw new Error('COHERE_API_KEY not set');
124
- const model = embedConfig.model !== 'text-embedding-3-small' ? embedConfig.model : 'embed-english-v3.0';
125
- const res = await fetch('https://api.cohere.com/v2/embed', {
126
- method: 'POST',
127
- headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
128
- body: JSON.stringify({ model, texts: [text], input_type: 'search_query', embedding_types: ['float'] }),
129
- signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
130
- });
131
- if (!res.ok)
132
- throw new Error(`Cohere embedding error: ${res.statusText}`);
133
- const json = (await res.json());
134
- return json.embeddings.float[0];
135
- }
136
- case 'ollama': {
137
- const base = process.env.OLLAMA_BASE_URL ?? 'http://localhost:11434';
138
- const model = embedConfig.model !== 'text-embedding-3-small' ? embedConfig.model : 'nomic-embed-text';
139
- const res = await fetch(`${base}/api/embeddings`, {
140
- method: 'POST',
141
- headers: { 'Content-Type': 'application/json' },
142
- body: JSON.stringify({ model, prompt: text }),
143
- signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
144
- });
145
- if (!res.ok)
146
- throw new Error(`Ollama embedding error: ${res.statusText}`);
147
- const json = (await res.json());
148
- return json.embedding;
149
- }
150
- case 'gemini': {
151
- const key = process.env.GEMINI_API_KEY;
152
- if (!key)
153
- throw new Error('GEMINI_API_KEY not set');
154
- const model = embedConfig.model !== 'text-embedding-3-small' ? embedConfig.model : 'text-embedding-004';
155
- const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:embedContent?key=${key}`, {
156
- method: 'POST',
157
- headers: { 'Content-Type': 'application/json' },
158
- body: JSON.stringify({ model: `models/${model}`, content: { parts: [{ text }] } }),
159
- signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
160
- });
161
- if (!res.ok)
162
- throw new Error(`Gemini embedding error: ${res.statusText}`);
163
- const json = (await res.json());
164
- return json.embedding.values;
165
- }
166
- case 'openai': {
167
- const key = process.env.OPENAI_API_KEY;
168
- if (!key)
169
- throw new Error('OPENAI_API_KEY not set.\n\n' +
170
- 'Set OPENAI_API_KEY in your .env, or switch provider:\n' +
171
- ' CACHLY_EMBED_PROVIDER=gemini (+ GEMINI_API_KEY)\n' +
172
- ' CACHLY_EMBED_PROVIDER=ollama (local, free)\n' +
173
- ' CACHLY_EMBED_PROVIDER=cachly (server-side, no key needed)');
174
- const model = embedConfig.model || 'text-embedding-3-small';
175
- const res = await fetch('https://api.openai.com/v1/embeddings', {
176
- method: 'POST',
177
- headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
178
- body: JSON.stringify({ model, input: text }),
179
- signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
180
- });
181
- if (!res.ok)
182
- throw new Error(`OpenAI embedding error: ${res.statusText}`);
183
- const json = (await res.json());
184
- if (!json.data?.[0]?.embedding)
185
- throw new Error('OpenAI returned empty embedding response');
186
- return json.data[0].embedding;
187
- }
188
- default: {
189
- throw new Error(`Unknown CACHLY_EMBED_PROVIDER="${EMBED_PROVIDER}".\n` +
190
- 'Supported: cachly (default), openai, mistral, cohere, ollama, gemini');
191
- }
192
- }
193
- }
194
- /** Returns true if the configured embedding provider has its required key/URL set. */
195
- export function hasEmbedProvider() {
196
- switch (EMBED_PROVIDER) {
197
- case 'cachly': return !!embedConfig.jwt;
198
- case 'mistral': return !!process.env.MISTRAL_API_KEY;
199
- case 'cohere': return !!process.env.COHERE_API_KEY;
200
- case 'ollama': return true; // OLLAMA_BASE_URL is optional (defaults to localhost)
201
- case 'gemini': return !!process.env.GEMINI_API_KEY;
202
- case 'openai': return !!process.env.OPENAI_API_KEY;
203
- case 'none': return false;
204
- default: return false;
205
- }
206
- }
207
- /** Returns a human-readable description of the current embed provider/model for error messages. */
208
- export function embedProviderHint() {
209
- const providerKeys = {
210
- cachly: 'CACHLY_JWT (server-side, no extra key needed)',
211
- openai: 'OPENAI_API_KEY',
212
- mistral: 'MISTRAL_API_KEY',
213
- cohere: 'COHERE_API_KEY',
214
- ollama: 'OLLAMA_BASE_URL (optional, default: http://localhost:11434)',
215
- gemini: 'GEMINI_API_KEY',
216
- };
217
- if (EMBED_PROVIDER === 'none') {
218
- return 'No embedding provider configured. Set OPENAI_API_KEY, GEMINI_API_KEY, or another provider key in .env. Brain works without embedding.';
219
- }
220
- const key = providerKeys[EMBED_PROVIDER] ?? 'CACHLY_JWT';
221
- return `CACHLY_EMBED_PROVIDER=${EMBED_PROVIDER} → requires ${key}`;
222
- }
223
- //# sourceMappingURL=embeddings.js.map
1
+ const t={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};function m(r){t.jwt=r}const i=Number(process.env.CACHLY_EMBED_TIMEOUT_MS??8e3);function c(){return process.env.CACHLY_JWT?"cachly":process.env.OLLAMA_BASE_URL?"ollama":"none"}const a=(process.env.CACHLY_EMBED_PROVIDER??c()).toLowerCase();async function l(r){switch(a){case"cachly":{if(!t.jwt)throw new Error(`CACHLY_JWT not set.
2
+
3
+ The "cachly" provider uses server-side embeddings via the Cachly API.
4
+ Set CACHLY_JWT, or use another provider via CACHLY_EMBED_PROVIDER:
5
+ openai \u2192 OPENAI_API_KEY
6
+ gemini \u2192 GEMINI_API_KEY
7
+ ollama \u2192 OLLAMA_BASE_URL (local, no key needed)`);const o=`${t.apiUrl}/api/v1/embed`,n={text:r};t.model&&(n.model=t.model);const e=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.jwt}`},body:JSON.stringify(n),signal:AbortSignal.timeout(i)});if(!e.ok){const d=await e.text();throw new Error(`Cachly embed API error ${e.status}: ${d}`)}return(await e.json()).embedding}case"mistral":{const o=process.env.MISTRAL_API_KEY;if(!o)throw new Error("MISTRAL_API_KEY not set");const n=t.model!=="text-embedding-3-small"?t.model:"mistral-embed",e=await fetch("https://api.mistral.ai/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({model:n,input:[r]}),signal:AbortSignal.timeout(i)});if(!e.ok)throw new Error(`Mistral embedding error: ${e.statusText}`);const s=await e.json();if(!s.data?.[0]?.embedding)throw new Error("Mistral returned empty embedding response");return s.data[0].embedding}case"cohere":{const o=process.env.COHERE_API_KEY;if(!o)throw new Error("COHERE_API_KEY not set");const n=t.model!=="text-embedding-3-small"?t.model:"embed-english-v3.0",e=await fetch("https://api.cohere.com/v2/embed",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({model:n,texts:[r],input_type:"search_query",embedding_types:["float"]}),signal:AbortSignal.timeout(i)});if(!e.ok)throw new Error(`Cohere embedding error: ${e.statusText}`);return(await e.json()).embeddings.float[0]}case"ollama":{const o=process.env.OLLAMA_BASE_URL??"http://localhost:11434",n=t.model!=="text-embedding-3-small"?t.model:"nomic-embed-text",e=await fetch(`${o}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:n,prompt:r}),signal:AbortSignal.timeout(i)});if(!e.ok)throw new Error(`Ollama embedding error: ${e.statusText}`);return(await e.json()).embedding}case"gemini":{const o=process.env.GEMINI_API_KEY;if(!o)throw new Error("GEMINI_API_KEY not set");const n=t.model!=="text-embedding-3-small"?t.model:"text-embedding-004",e=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${n}:embedContent?key=${o}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:`models/${n}`,content:{parts:[{text:r}]}}),signal:AbortSignal.timeout(i)});if(!e.ok)throw new Error(`Gemini embedding error: ${e.statusText}`);return(await e.json()).embedding.values}case"openai":{const o=process.env.OPENAI_API_KEY;if(!o)throw new Error(`OPENAI_API_KEY not set.
8
+
9
+ Set OPENAI_API_KEY in your .env, or switch provider:
10
+ CACHLY_EMBED_PROVIDER=gemini (+ GEMINI_API_KEY)
11
+ CACHLY_EMBED_PROVIDER=ollama (local, free)
12
+ CACHLY_EMBED_PROVIDER=cachly (server-side, no key needed)`);const n=t.model||"text-embedding-3-small",e=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({model:n,input:r}),signal:AbortSignal.timeout(i)});if(!e.ok)throw new Error(`OpenAI embedding error: ${e.statusText}`);const s=await e.json();if(!s.data?.[0]?.embedding)throw new Error("OpenAI returned empty embedding response");return s.data[0].embedding}default:throw new Error(`Unknown CACHLY_EMBED_PROVIDER="${a}".
13
+ Supported: cachly (default), openai, mistral, cohere, ollama, gemini`)}}function E(){switch(a){case"cachly":return!!t.jwt;case"mistral":return!!process.env.MISTRAL_API_KEY;case"cohere":return!!process.env.COHERE_API_KEY;case"ollama":return!0;case"gemini":return!!process.env.GEMINI_API_KEY;case"openai":return!!process.env.OPENAI_API_KEY;case"none":return!1;default:return!1}}function p(){const r={cachly:"CACHLY_JWT (server-side, no extra key needed)",openai:"OPENAI_API_KEY",mistral:"MISTRAL_API_KEY",cohere:"COHERE_API_KEY",ollama:"OLLAMA_BASE_URL (optional, default: http://localhost:11434)",gemini:"GEMINI_API_KEY"};if(a==="none")return"No embedding provider configured. Set OPENAI_API_KEY, GEMINI_API_KEY, or another provider key in .env. Brain works without embedding.";const o=r[a]??"CACHLY_JWT";return`CACHLY_EMBED_PROVIDER=${a} \u2192 requires ${o}`}export{a as EMBED_PROVIDER,l as computeEmbedding,t as embedConfig,p as embedProviderHint,E as hasEmbedProvider,m as setEmbedJwt};
@@ -0,0 +1,3 @@
1
+ const d=["what_worked","what_failed","context"],a=new RegExp(String.raw`<\/?(?:parameter\s+name\s*=\s*["']?)?(${d.join("|")})["']?\s*\/?>`,"gi");function w(t){return t?(a.lastIndex=0,a.test(t)):!1}function x(t){if(!w(t.what_worked)&&!w(t.what_failed)&&!w(t.context))return t;const n={what_worked:"",what_failed:t.what_failed??"",context:t.context??""},o=t.what_worked??"",i=[];let s=0,l="what_worked";a.lastIndex=0;for(let e=a.exec(o);e!==null;e=a.exec(o)){i.push({ziel:l,text:o.slice(s,e.index)});const r=e[1].toLowerCase();l=e[0].startsWith("</")?l:r,s=e.index+e[0].length}i.push({ziel:l,text:o.slice(s)});for(const e of i){const r=e.text.trim();r&&(n[e.ziel]?n[e.ziel]=`${n[e.ziel]}
2
+
3
+ ${r}`:n[e.ziel]=r)}const c=e=>e.replace(a," ").replace(/[ \t]{2,}/g," ").trim();return{what_worked:c(n.what_worked),what_failed:n.what_failed?c(n.what_failed):t.what_failed,context:n.context?c(n.context):t.context}}export{w as hatFeldmarke,x as repariereFelder};
@@ -1,108 +1,4 @@
1
- /**
2
- * First-contact response builder for `brain_from_git` (roadmap P1-5:
3
- * "Onboarding-Magie messen & polieren").
4
- *
5
- * The very first `brain_from_git` run is a new user's first contact with the
6
- * Brain, and it decides whether they ever reach the "aha". The response must,
7
- * in one message:
8
- * (a) summarize what was just learned (counts by category + severity),
9
- * (b) prove recall already works — show the top hit of a real search that
10
- * ran against a topic seeded seconds ago,
11
- * (c) hand the user 2-3 copy-pasteable next queries, and
12
- * (d) degrade gracefully for empty/small repos (clear guidance, not empty stats).
13
- *
14
- * Pure string building — no I/O, no schema/tool changes — so the onboarding
15
- * bench and its CI test can assert the exact first-contact response shape.
16
- */
17
- /** Below this many ingested lessons we treat the repo as "small" and add growth guidance. */
18
- export const SMALL_SEED_THRESHOLD = 5;
19
- export function formatSeedDuration(ms) {
20
- if (ms < 1000)
21
- return `${Math.max(ms, 1)}ms`;
22
- if (ms < 60_000)
23
- return `${(ms / 1000).toFixed(1)}s`;
24
- return `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;
25
- }
26
- /**
27
- * Turn seeded topics (`category:some-domain`) into up to `max` copy-pasteable
28
- * `smart_recall` calls a brand-new user can paste as their literal next message.
29
- * Deduplicates by domain so three "fix:*" topics don't yield three identical queries.
30
- */
31
- export function suggestRecallQueries(topics, instanceId, max = 3) {
32
- const seen = new Set();
33
- const out = [];
34
- for (const topic of topics) {
35
- const domain = (topic.includes(':') ? topic.slice(topic.indexOf(':') + 1) : topic)
36
- .replace(/[-_]+/g, ' ')
37
- .trim();
38
- if (!domain || seen.has(domain))
39
- continue;
40
- seen.add(domain);
41
- out.push(`smart_recall(instance_id="${instanceId}", query="${domain}")`);
42
- if (out.length >= max)
43
- break;
44
- }
45
- return out;
46
- }
47
- /** Steps that take an empty/tiny Brain to a first recall hit in under a minute. */
48
- function growthSteps(instanceId) {
49
- return [
50
- ` 1. \`brain_seed_starter(instance_id="${instanceId}")\` — load 16 curated engineering lessons instantly`,
51
- ` 2. \`smart_recall(instance_id="${instanceId}", query="docker build slow")\` — see your first recall hit`,
52
- ` 3. \`learn_from_attempts(...)\` after your next fix — the Brain grows with every lesson from here on`,
53
- ];
54
- }
55
- export function buildFirstContactReport(r) {
56
- const lines = [];
57
- lines.push(`🔁 **brain_from_git: ${r.repoDir}**`);
58
- if (r.isIncremental && r.lastSha) {
59
- lines.push(`🔄 Incremental mode — only new commits since \`${r.lastSha.slice(0, 8)}\` were processed`);
60
- }
61
- lines.push('');
62
- lines.push(`📂 Branch: \`${r.revRange}\` | Processed: **${r.processed}** commits | ` +
63
- `Ingested: **${r.ingested}** lessons | Skipped: ${r.skipped} | ` +
64
- `⏱️ Seeding took ${formatSeedDuration(r.durationMs)}`);
65
- lines.push('');
66
- // ── Empty repo / nothing ingested — guidance instead of empty stats ─────────
67
- if (r.ingested === 0) {
68
- if (r.emptyReason)
69
- lines.push(`⚠️ ${r.emptyReason}`);
70
- lines.push(`🌱 **Nothing to learn from this git history yet** — normal for fresh, shallow, or squash-only repos.`);
71
- lines.push(`Get to your first recall in under a minute:`);
72
- lines.push(...growthSteps(r.instanceId));
73
- return lines.join('\n');
74
- }
75
- // ── (a) Seeded summary — what the Brain just learned ────────────────────────
76
- lines.push(`**What your Brain just learned (by category):**`);
77
- lines.push(r.categories.map(([k, v]) => ` • **${k}** (${v})`).join('\n'));
78
- if (r.severities && r.severities.length > 0) {
79
- lines.push(`**By severity:** ${r.severities.map(([k, v]) => `${k} ${v}`).join(' · ')}`);
80
- }
81
- // ── (b) Proof of value — a real recall against a just-seeded topic ──────────
82
- if (r.proof) {
83
- lines.push('');
84
- lines.push(`🎯 **Proof — your first recall already works.** We just searched your fresh Brain for:`);
85
- lines.push(` "${r.proof.query}"`);
86
- lines.push(` → Top hit: **${r.proof.topic}** — ${r.proof.snippet}`);
87
- }
88
- // ── (c) Suggested next queries — copy-pasteable ──────────────────────────────
89
- if (r.suggestedQueries.length > 0) {
90
- lines.push('');
91
- lines.push(`**Try these next (copy-paste):**`);
92
- for (const q of r.suggestedQueries)
93
- lines.push(` • \`${q}\``);
94
- }
95
- // ── (d) Small-repo guidance ──────────────────────────────────────────────────
96
- if (r.ingested < SMALL_SEED_THRESHOLD) {
97
- lines.push('');
98
- lines.push(`🌱 **Small git history — only ${r.ingested} lesson${r.ingested === 1 ? '' : 's'} so far.** Top it up:`);
99
- lines.push(...growthSteps(r.instanceId));
100
- }
101
- lines.push('');
102
- lines.push(`💡 New lessons are stored with confidence 0.55 (auto-inferred).`);
103
- lines.push(`💡 As you confirm them via \`learn_from_attempts\`, confidence rises automatically.`);
104
- lines.push(`🔍 Explore: \`brain_search(query="fix")\` | \`ckg_inspect(concept="deploy")\``);
105
- lines.push(`💾 Next run will automatically continue from the latest commit (incremental mode).`);
106
- return lines.join('\n');
107
- }
108
- //# sourceMappingURL=first-contact.js.map
1
+ const p=5;function u(e){return e<1e3?`${Math.max(e,1)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${Math.round(e%6e4/1e3)}s`}function c(e,s,t=3){const o=new Set,r=[];for(const n of e){const i=(n.includes(":")?n.slice(n.indexOf(":")+1):n).replace(/[-_]+/g," ").trim();if(!(!i||o.has(i))&&(o.add(i),r.push(`smart_recall(instance_id="${s}", query="${i}")`),r.length>=t))break}return r}function a(e){return[` 1. \`brain_seed_starter(instance_id="${e}")\` \u2014 load 16 curated engineering lessons instantly`,` 2. \`smart_recall(instance_id="${e}", query="docker build slow")\` \u2014 see your first recall hit`," 3. `learn_from_attempts(...)` after your next fix \u2014 the Brain grows with every lesson from here on"]}function h(e){const s=[];if(s.push(`\u{1F501} **brain_from_git: ${e.repoDir}**`),e.isIncremental&&e.lastSha&&s.push(`\u{1F504} Incremental mode \u2014 only new commits since \`${e.lastSha.slice(0,8)}\` were processed`),s.push(""),s.push(`\u{1F4C2} Branch: \`${e.revRange}\` | Processed: **${e.processed}** commits | Ingested: **${e.ingested}** lessons | Skipped: ${e.skipped} | \u23F1\uFE0F Seeding took ${u(e.durationMs)}`),s.push(""),e.ingested===0)return e.emptyReason&&s.push(`\u26A0\uFE0F ${e.emptyReason}`),s.push("\u{1F331} **Nothing to learn from this git history yet** \u2014 normal for fresh, shallow, or squash-only repos."),s.push("Get to your first recall in under a minute:"),s.push(...a(e.instanceId)),s.join(`
2
+ `);if(s.push("**What your Brain just learned (by category):**"),s.push(e.categories.map(([t,o])=>` \u2022 **${t}** (${o})`).join(`
3
+ `)),e.severities&&e.severities.length>0&&s.push(`**By severity:** ${e.severities.map(([t,o])=>`${t} ${o}`).join(" \xB7 ")}`),e.proof&&(s.push(""),s.push("\u{1F3AF} **Proof \u2014 your first recall already works.** We just searched your fresh Brain for:"),s.push(` "${e.proof.query}"`),s.push(` \u2192 Top hit: **${e.proof.topic}** \u2014 ${e.proof.snippet}`)),e.suggestedQueries.length>0){s.push(""),s.push("**Try these next (copy-paste):**");for(const t of e.suggestedQueries)s.push(` \u2022 \`${t}\``)}return e.ingested<5&&(s.push(""),s.push(`\u{1F331} **Small git history \u2014 only ${e.ingested} lesson${e.ingested===1?"":"s"} so far.** Top it up:`),s.push(...a(e.instanceId))),s.push(""),s.push("\u{1F4A1} New lessons are stored with confidence 0.55 (auto-inferred)."),s.push("\u{1F4A1} As you confirm them via `learn_from_attempts`, confidence rises automatically."),s.push('\u{1F50D} Explore: `brain_search(query="fix")` | `ckg_inspect(concept="deploy")`'),s.push("\u{1F4BE} Next run will automatically continue from the latest commit (incremental mode)."),s.join(`
4
+ `)}export{p as SMALL_SEED_THRESHOLD,h as buildFirstContactReport,u as formatSeedDuration,c as suggestRecallQueries};
@@ -1,41 +1,4 @@
1
- /**
2
- * The Aha-moment of the first minute (GROW-013): a new user must see the
3
- * Brain recall something real from their OWN repo, not just a lesson count.
4
- * Both functions are pure — no I/O, no network, no state — so setup/autopilot
5
- * can call them without risking the 3s onboarding budget.
6
- */
7
- /**
8
- * Finds the "Proof — your first recall already works" block inside a
9
- * `brain_from_git` result text and returns it verbatim (the block runs from
10
- * the matching line up to the next blank line). Returns `null` when the text
11
- * carries no such block — never invents a proof.
12
- */
13
- export function extractFirstRecallProof(text) {
14
- if (!text)
15
- return null;
16
- const lines = text.split('\n');
17
- const startIdx = lines.findIndex((line) => /first recall already works/i.test(line));
18
- if (startIdx === -1)
19
- return null;
20
- const block = [];
21
- for (let i = startIdx; i < lines.length; i++) {
22
- if (i > startIdx && lines[i].trim() === '')
23
- break;
24
- block.push(lines[i]);
25
- }
26
- const joined = block.join('\n').trim();
27
- return joined || null;
28
- }
29
- /**
30
- * Renders the first-recall proof for the seed path: a real recall hit
31
- * against the just-seeded starter corpus, shown as evidence instead of a
32
- * bare "seeded ✓".
33
- */
34
- export function renderFirstRecallProof(topic, what) {
35
- const snippet = what.trim();
36
- return [
37
- '🎯 Proof — your first recall already works.',
38
- ` Top hit: **${topic}** — ${snippet}`,
39
- ].join('\n');
40
- }
41
- //# sourceMappingURL=first-recall-proof.js.map
1
+ function l(o){if(!o)return null;const n=o.split(`
2
+ `),t=n.findIndex(r=>/first recall already works/i.test(r));if(t===-1)return null;const e=[];for(let r=t;r<n.length&&!(r>t&&n[r].trim()==="");r++)e.push(n[r]);return e.join(`
3
+ `).trim()||null}function s(o,n){const t=n.trim();return["\u{1F3AF} Proof \u2014 your first recall already works.",` Top hit: **${o}** \u2014 ${t}`].join(`
4
+ `)}export{l as extractFirstRecallProof,s as renderFirstRecallProof};
@@ -1,48 +1,2 @@
1
- // Persistent once-per-machine funnel milestones.
2
- //
3
- // Milestones like first_call_success were guarded by an in-memory flag only —
4
- // but ambient hooks spawn a FRESH server process per prompt, so every hook
5
- // invocation re-sent "first call" and the backend saw 66 "first" calls from
6
- // one user (and Telegram pinged the founder on every one). Persisting the
7
- // marker in ~/.cachly/ makes "first" mean first-on-this-machine across
8
- // process restarts. Best-effort: any filesystem problem degrades to the old
9
- // in-memory behaviour (the backend now dedupes too), never throws.
10
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
11
- import { homedir } from 'node:os';
12
- import { dirname, join } from 'node:path';
13
- export function defaultMilestonePath() {
14
- return join(homedir(), '.cachly', 'funnel-milestones.json');
15
- }
16
- function readAll(path) {
17
- try {
18
- if (!existsSync(path))
19
- return {};
20
- const parsed = JSON.parse(readFileSync(path, 'utf-8'));
21
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
22
- return parsed;
23
- }
24
- return {};
25
- }
26
- catch {
27
- return {}; // corrupt file → treat as empty, next mark rewrites it
28
- }
29
- }
30
- /** True when this milestone was already sent from this machine. */
31
- export function milestoneSent(name, path = defaultMilestonePath()) {
32
- return name in readAll(path);
33
- }
34
- /** Record a milestone (idempotent). Never throws. */
35
- export function markMilestoneSent(name, path = defaultMilestonePath()) {
36
- try {
37
- const all = readAll(path);
38
- if (name in all)
39
- return;
40
- all[name] = new Date().toISOString();
41
- mkdirSync(dirname(path), { recursive: true });
42
- writeFileSync(path, JSON.stringify(all, null, 2) + '\n', 'utf-8');
43
- }
44
- catch {
45
- /* best-effort — the server-side dedup is the safety net */
46
- }
47
- }
48
- //# sourceMappingURL=funnel-milestones.js.map
1
+ import{existsSync as o,mkdirSync as c,readFileSync as u,writeFileSync as f}from"node:fs";import{homedir as l}from"node:os";import{dirname as s,join as a}from"node:path";function n(){return a(l(),".cachly","funnel-milestones.json")}function i(t){try{if(!o(t))return{};const r=JSON.parse(u(t,"utf-8"));return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}catch{return{}}}function d(t,r=n()){return t in i(r)}function p(t,r=n()){try{const e=i(r);if(t in e)return;e[t]=new Date().toISOString(),c(s(r),{recursive:!0}),f(r,JSON.stringify(e,null,2)+`
2
+ `,"utf-8")}catch{}}export{n as defaultMilestonePath,p as markMilestoneSent,d as milestoneSent};
@@ -1,114 +1 @@
1
- import { estimateTokens } from './ambient-recall.js';
2
- /**
3
- * Wie viel Text kam aus dem Gedaechtnis statt aus dem Modell?
4
- *
5
- * ANLASS 19.08.2026, Heinrich: "Bei der Schaetzung der Tokenersparnis sollten
6
- * wir schauen, dass wir nicht nur schaetzen, denn das nervt Leute sehr stark.
7
- * Vielleicht machen wir eine weitere Metrik rein? Sowas wie Token, die bei den
8
- * Calls aus dem Brain rausgenommen wurden und nicht aus der AI vom Vendor
9
- * kamen?"
10
- *
11
- * ── Warum das die bessere Zahl ist ──────────────────────────────────────────
12
- *
13
- * Die bisherige Zahl "583k Token gespart" ist eine RECHNUNG: 1.200 Token je
14
- * wiederverwendeter Lektion mal 486 Abrufe. Der Faktor 1.200 ist geraten, und
15
- * jeder darf ihn bestreiten. Die Zahl hier ist eine SUMME: die Laenge der
16
- * Antworten, die das Brain wirklich zurueckgegeben hat. Da gibt es nichts zu
17
- * bestreiten — hoechstens die Frage, was sie bedeutet.
18
- *
19
- * ── Was sie NICHT sagt ──────────────────────────────────────────────────────
20
- *
21
- * Sie ist KEIN Beweis, dass das Modell diese Token sonst selbst erzeugt haette.
22
- * Vielleicht haette es die Antwort gar nicht gefunden, vielleicht kuerzer
23
- * geantwortet. Sie sagt genau eines, und das laesst sich nachrechnen: so viel
24
- * Text kam als Antwort aus dem Gedaechtnis. Wer mehr behauptet, schaetzt
25
- * wieder.
26
- *
27
- * Deshalb steht die Schaetzung weiter daneben — aber klein, mit ihrer Annahme
28
- * im selben Satz, und neben einer Zahl, die keine braucht.
29
- */
30
- /**
31
- * Nur ABRUFE zaehlen, nicht jede Antwort.
32
- *
33
- * `learn_from_attempts` gibt eine Bestaetigung zurueck, `create_instance` eine
34
- * Kennung — das ist kein geliefertes Wissen. Gezaehlt wird, was Gespeichertes
35
- * herausgibt. Steht ein Werkzeug nicht auf dieser Liste, zaehlt es nicht mit;
36
- * die Zahl ist dadurch eher zu klein als zu gross, und das ist die richtige
37
- * Richtung fuer eine Zahl, mit der man wirbt.
38
- */
39
- export const LIEFERNDE_WERKZEUGE = new Set([
40
- 'smart_recall',
41
- 'recall_best_solution',
42
- 'recall_context',
43
- 'recall_at',
44
- 'causal_trace',
45
- 'semantic_search',
46
- 'brain_search',
47
- 'team_recall',
48
- 'global_recall',
49
- 'session_start',
50
- 'session_start_summary',
51
- 'brain_briefing',
52
- 'compact_recover',
53
- 'session_handoff',
54
- 'crystal_view',
55
- 'brain_graph',
56
- 'trace_dependency',
57
- 'brain_who_knows',
58
- 'fedbrain_search',
59
- 'syndicate_search',
60
- ]);
61
- export function istLieferung(werkzeugName) {
62
- return LIEFERNDE_WERKZEUGE.has(werkzeugName);
63
- }
64
- /** Redis-Schluessel je Brain: Summe der gelieferten Token. */
65
- export function lieferSchluessel(instanceId) {
66
- return `cachly:stats:delivered_tokens:${instanceId}`;
67
- }
68
- /** Redis-Schluessel je Brain: Abrufe gesamt und davon mit Treffer. */
69
- export function trefferSchluessel(instanceId) {
70
- return `cachly:stats:recall_hits:${instanceId}`;
71
- }
72
- /**
73
- * Hatte dieser Abruf einen Treffer?
74
- *
75
- * Erkannt an dem, was die Antwort SAGT, nicht an ihrer Laenge: eine hoefliche
76
- * Absage ("keine passende Lektion gefunden") ist laenger als mancher Treffer.
77
- * Die Muster stammen aus den Antworttexten der Abruf-Werkzeuge selbst.
78
- */
79
- const LEERE_ANTWORT = /(no (relevant |matching |cached )?(lessons?|results?|context|memory|match)|keine? (passende|relevante)|nothing (found|cached)|0 results|Results \(0\b|empty)/i;
80
- export function hatTreffer(antwort) {
81
- if (!antwort || antwort.trim().length === 0)
82
- return false;
83
- return !LEERE_ANTWORT.test(antwort);
84
- }
85
- /** Die Token dieser Antwort — dieselbe Schaetzfunktion wie beim Einblende-Budget. */
86
- export function tokenDerAntwort(antwort) {
87
- return estimateTokens(antwort);
88
- }
89
- export function lieferBild(roh) {
90
- const zahl = (v) => {
91
- const n = typeof v === 'number' ? v : Number(v ?? 0);
92
- return Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;
93
- };
94
- const token = zahl(roh.token);
95
- const abrufe = zahl(roh.abrufe);
96
- const treffer = Math.min(zahl(roh.treffer), abrufe);
97
- return { token, abrufe, treffer, quote: abrufe > 0 ? treffer / abrufe : 0 };
98
- }
99
- /** Grosse Zahlen so, wie ein Mensch sie liest. */
100
- export function inWorten(bild) {
101
- if (bild.abrufe === 0) {
102
- return 'Aus dem Brain geliefert: noch nichts — es gab bisher keinen Abruf.';
103
- }
104
- const t = bild.token >= 1_000_000
105
- ? `${(bild.token / 1_000_000).toFixed(2)} Mio.`
106
- : bild.token >= 1_000
107
- ? `${Math.round(bild.token / 1_000)}k`
108
- : `${bild.token}`;
109
- const prozent = Math.round(bild.quote * 100);
110
- return (`Aus dem Brain geliefert: ${t} Token in ${bild.abrufe} Abrufen. ` +
111
- `${bild.treffer} davon fanden etwas (${prozent} %). ` +
112
- `Gemessen, nicht gerechnet — es ist die Summe der Antwortlaengen, keine Annahme.`);
113
- }
114
- //# sourceMappingURL=geliefert.js.map
1
+ import{estimateTokens as c}from"./ambient-recall.js";const i=new Set(["smart_recall","recall_best_solution","recall_context","recall_at","causal_trace","semantic_search","brain_search","team_recall","global_recall","session_start","session_start_summary","brain_briefing","compact_recover","session_handoff","crystal_view","brain_graph","trace_dependency","brain_who_knows","fedbrain_search","syndicate_search"]);function l(e){return i.has(e)}function _(e){return`cachly:stats:delivered_tokens:${e}`}function h(e){return`cachly:stats:recall_hits:${e}`}const u=/(no (relevant |matching |cached )?(lessons?|results?|context|memory|match)|keine? (passende|relevante)|nothing (found|cached)|0 results|Results \(0\b|empty)/i;function m(e){return!e||e.trim().length===0?!1:!u.test(e)}function k(e){return c(e)}function p(e){const t=s=>{const o=typeof s=="number"?s:Number(s??0);return Number.isFinite(o)&&o>0?Math.floor(o):0},r=t(e.token),n=t(e.abrufe),a=Math.min(t(e.treffer),n);return{token:r,abrufe:n,treffer:a,quote:n>0?a/n:0}}function d(e){if(e.abrufe===0)return"Aus dem Brain geliefert: noch nichts \u2014 es gab bisher keinen Abruf.";const t=e.token>=1e6?`${(e.token/1e6).toFixed(2)} Mio.`:e.token>=1e3?`${Math.round(e.token/1e3)}k`:`${e.token}`,r=Math.round(e.quote*100);return`Aus dem Brain geliefert: ${t} Token in ${e.abrufe} Abrufen. ${e.treffer} davon fanden etwas (${r} %). Gemessen, nicht gerechnet \u2014 es ist die Summe der Antwortlaengen, keine Annahme.`}export{i as LIEFERNDE_WERKZEUGE,m as hatTreffer,d as inWorten,l as istLieferung,p as lieferBild,_ as lieferSchluessel,k as tokenDerAntwort,h as trefferSchluessel};