clawvault 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -16
- package/bin/clawvault.js +0 -2
- package/bin/command-registration.test.js +13 -1
- package/bin/help-contract.test.js +14 -0
- package/bin/register-core-commands.js +88 -0
- package/bin/register-core-commands.test.js +80 -0
- package/bin/register-maintenance-commands.js +57 -6
- package/bin/register-query-commands.js +10 -28
- package/bin/test-helpers/cli-command-fixtures.js +1 -0
- package/dist/chunk-2PKBIKDH.js +130 -0
- package/dist/{chunk-U67V476Y.js → chunk-2ZDO52B4.js} +18 -1
- package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
- package/dist/{chunk-AZYOKJYC.js → chunk-4PY655YM.js} +13 -1
- package/dist/{chunk-2JQ3O2YL.js → chunk-5EFSWZO6.js} +3 -3
- package/dist/{chunk-Y3TIJEBP.js → chunk-7SWP5FKU.js} +34 -613
- package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
- package/dist/{chunk-URXDAUVH.js → chunk-AXSJIFOJ.js} +174 -1
- package/dist/{chunk-4ITRXIVT.js → chunk-BLQXXX7Q.js} +6 -6
- package/dist/chunk-CSHO3PJB.js +684 -0
- package/dist/{chunk-S5OJEGFG.js → chunk-DOIUYIXV.js} +2 -2
- package/dist/{chunk-YXQCA6B7.js → chunk-DVOUSOR3.js} +112 -7
- package/dist/{chunk-YDWHS4LJ.js → chunk-ECGJYWNA.js} +205 -33
- package/dist/{chunk-QMHPQYUV.js → chunk-EL6UBSX5.js} +7 -6
- package/dist/chunk-FZ5I2NF7.js +352 -0
- package/dist/{chunk-WJVWINEM.js → chunk-GFCHWMGD.js} +55 -6
- package/dist/{chunk-GNJL4YGR.js → chunk-GJO3CFUN.js} +30 -6
- package/dist/chunk-H3JZIB5O.js +322 -0
- package/dist/chunk-HEHO7SMV.js +51 -0
- package/dist/{chunk-UCQAOZHW.js → chunk-HGDDW24U.js} +3 -3
- package/dist/chunk-J3YUXVID.js +907 -0
- package/dist/{chunk-Y6VJKXGL.js → chunk-KCYWJDDW.js} +1 -1
- package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
- package/dist/{chunk-YNIPYN4F.js → chunk-OFOCU2V4.js} +6 -5
- package/dist/{chunk-42MXU7A6.js → chunk-P62WHA27.js} +58 -47
- package/dist/chunk-PTWPPVC7.js +972 -0
- package/dist/{chunk-FAKNOB7Y.js → chunk-QFWERBDP.js} +2 -2
- package/dist/{chunk-IIOU45CK.js → chunk-S7N7HI5E.js} +2 -2
- package/dist/{chunk-ECRZL5XR.js → chunk-T7E764W3.js} +23 -7
- package/dist/chunk-TDWFBDAQ.js +1016 -0
- package/dist/{chunk-MNPUYCHQ.js → chunk-TWMI3SNN.js} +6 -5
- package/dist/{chunk-2RAZ4ZFE.js → chunk-VBILES4B.js} +1 -1
- package/dist/{chunk-PI4WMLMG.js → chunk-VXAGOLDP.js} +1 -1
- package/dist/chunk-YCUVAOFC.js +158 -0
- package/dist/{chunk-SS4B7P7V.js → chunk-YIDV4VV2.js} +1 -1
- package/dist/chunk-ZKWPCBYT.js +600 -0
- package/dist/cli/index.js +27 -21
- package/dist/commands/archive.js +3 -3
- package/dist/commands/backlog.js +1 -1
- package/dist/commands/benchmark.d.ts +12 -0
- package/dist/commands/benchmark.js +12 -0
- package/dist/commands/blocked.js +1 -1
- package/dist/commands/canvas.js +2 -2
- package/dist/commands/checkpoint.js +1 -1
- package/dist/commands/compat.js +1 -1
- package/dist/commands/context.js +8 -7
- package/dist/commands/doctor.d.ts +8 -3
- package/dist/commands/doctor.js +8 -22
- package/dist/commands/embed.js +6 -5
- package/dist/commands/entities.js +2 -2
- package/dist/commands/graph.js +4 -4
- package/dist/commands/inbox.d.ts +23 -0
- package/dist/commands/inbox.js +11 -0
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +5 -5
- package/dist/commands/kanban.js +1 -1
- package/dist/commands/link.js +9 -9
- package/dist/commands/maintain.d.ts +32 -0
- package/dist/commands/maintain.js +12 -0
- package/dist/commands/migrate-observations.js +3 -3
- package/dist/commands/observe.js +11 -10
- package/dist/commands/project.js +2 -2
- package/dist/commands/rebuild-embeddings.js +48 -17
- package/dist/commands/rebuild.js +9 -8
- package/dist/commands/recover.js +1 -1
- package/dist/commands/reflect.js +6 -6
- package/dist/commands/repair-session.js +1 -1
- package/dist/commands/replay.js +10 -9
- package/dist/commands/session-recap.js +1 -1
- package/dist/commands/setup.js +4 -3
- package/dist/commands/shell-init.js +1 -1
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +20 -18
- package/dist/commands/status.js +40 -26
- package/dist/commands/sync-bd.js +3 -3
- package/dist/commands/tailscale.js +3 -3
- package/dist/commands/task.js +1 -1
- package/dist/commands/template.js +1 -1
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +10 -9
- package/dist/index.d.ts +175 -16
- package/dist/index.js +277 -108
- package/dist/{inject-DYUrDqQO.d.ts → inject-DEb_jpLi.d.ts} +3 -1
- package/dist/lib/auto-linker.js +2 -2
- package/dist/lib/canvas-layout.js +1 -1
- package/dist/lib/config.js +2 -2
- package/dist/lib/entity-index.js +1 -1
- package/dist/lib/project-utils.js +2 -2
- package/dist/lib/session-repair.js +1 -1
- package/dist/lib/session-utils.js +1 -1
- package/dist/lib/tailscale.js +1 -1
- package/dist/lib/task-utils.js +1 -1
- package/dist/lib/template-engine.js +1 -1
- package/dist/lib/webdav.js +1 -1
- package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
- package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
- package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
- package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
- package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
- package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
- package/dist/openclaw-plugin.d.ts +8 -0
- package/dist/openclaw-plugin.js +14 -0
- package/dist/transformers.node-A2ZRORSQ.js +46775 -0
- package/dist/{types-BbWJoC1c.d.ts → types-DslKvCaj.d.ts} +51 -1
- package/hooks/clawvault/HOOK.md +25 -8
- package/hooks/clawvault/handler.js +215 -78
- package/hooks/clawvault/handler.test.js +109 -43
- package/hooks/clawvault/integrity.js +112 -0
- package/hooks/clawvault/integrity.test.js +32 -0
- package/hooks/clawvault/openclaw.plugin.json +133 -15
- package/openclaw.plugin.json +131 -203
- package/package.json +10 -7
- package/bin/register-workgraph-commands.js +0 -451
- package/dist/chunk-5PJ4STIC.js +0 -465
- package/dist/chunk-ERNE2FZ5.js +0 -189
- package/dist/chunk-HR4KN6S2.js +0 -152
- package/dist/chunk-IJBFGPCS.js +0 -33
- package/dist/chunk-K7PNYS45.js +0 -93
- package/dist/chunk-NTOPJI7W.js +0 -207
- package/dist/chunk-PG56HX5T.js +0 -154
- package/dist/chunk-QPDDIHXE.js +0 -501
- package/dist/chunk-WIOLLGAD.js +0 -190
- package/dist/chunk-WMGIIABP.js +0 -15
- package/dist/ledger-B7g7jhqG.d.ts +0 -44
- package/dist/plugin/index.d.ts +0 -352
- package/dist/plugin/index.js +0 -4264
- package/dist/registry-BR4326o0.d.ts +0 -30
- package/dist/store-CA-6sKCJ.d.ts +0 -34
- package/dist/thread-B9LhXNU0.d.ts +0 -41
- package/dist/workgraph/index.d.ts +0 -5
- package/dist/workgraph/index.js +0 -23
- package/dist/workgraph/ledger.d.ts +0 -2
- package/dist/workgraph/ledger.js +0 -25
- package/dist/workgraph/registry.d.ts +0 -2
- package/dist/workgraph/registry.js +0 -19
- package/dist/workgraph/store.d.ts +0 -2
- package/dist/workgraph/store.js +0 -25
- package/dist/workgraph/thread.d.ts +0 -2
- package/dist/workgraph/thread.js +0 -25
- package/dist/workgraph/types.d.ts +0 -54
- package/dist/workgraph/types.js +0 -7
|
@@ -1,29 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requestLlmCompletion,
|
|
3
|
+
resolveLlmProvider
|
|
4
|
+
} from "./chunk-DVOUSOR3.js";
|
|
1
5
|
import {
|
|
2
6
|
listProjects
|
|
3
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4PY655YM.js";
|
|
8
|
+
import {
|
|
9
|
+
listConfig,
|
|
10
|
+
listRouteRules,
|
|
11
|
+
matchRouteRule
|
|
12
|
+
} from "./chunk-AXSJIFOJ.js";
|
|
4
13
|
import {
|
|
5
14
|
FactStore,
|
|
6
15
|
extractFactsLlm,
|
|
7
16
|
extractFactsRuleBased
|
|
8
17
|
} from "./chunk-BSJ6RIT7.js";
|
|
9
18
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
Compressor
|
|
20
|
+
} from "./chunk-J3YUXVID.js";
|
|
21
|
+
import {
|
|
12
22
|
normalizeObservationContent,
|
|
13
23
|
parseObservationLine,
|
|
14
24
|
parseObservationMarkdown,
|
|
15
25
|
renderObservationMarkdown,
|
|
16
26
|
renderScoredObservationLine
|
|
17
27
|
} from "./chunk-FHFUXL6G.js";
|
|
18
|
-
import {
|
|
19
|
-
listConfig,
|
|
20
|
-
listRouteRules,
|
|
21
|
-
matchRouteRule
|
|
22
|
-
} from "./chunk-URXDAUVH.js";
|
|
23
|
-
import {
|
|
24
|
-
requestLlmCompletion,
|
|
25
|
-
resolveLlmProvider
|
|
26
|
-
} from "./chunk-YXQCA6B7.js";
|
|
27
28
|
import {
|
|
28
29
|
ensureLedgerStructure,
|
|
29
30
|
ensureParentDir,
|
|
@@ -40,591 +41,8 @@ import {
|
|
|
40
41
|
updateTask
|
|
41
42
|
} from "./chunk-QWQ3TIKS.js";
|
|
42
43
|
|
|
43
|
-
// src/observer/compressor.ts
|
|
44
|
-
var OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
45
|
-
var XAI_BASE_URL = "https://api.x.ai/v1";
|
|
46
|
-
var OLLAMA_BASE_URL = "http://localhost:11434/v1";
|
|
47
|
-
var DEFAULT_PROVIDER_MODELS = {
|
|
48
|
-
anthropic: "claude-3-5-haiku-latest",
|
|
49
|
-
openai: "gpt-4o-mini",
|
|
50
|
-
gemini: "gemini-2.0-flash",
|
|
51
|
-
xai: "grok-2-latest",
|
|
52
|
-
"openai-compatible": "gpt-4o-mini",
|
|
53
|
-
ollama: "llama3.2",
|
|
54
|
-
minimax: "MiniMax-M2.1",
|
|
55
|
-
zai: "glm-4.5-air"
|
|
56
|
-
};
|
|
57
|
-
var CRITICAL_RE = /(?:\b(?:decision|decided|chose|chosen|selected|picked|opted|switched to)\s*:?|\bdecid(?:e|ed|ing|ion)\b|\berror\b|\bfail(?:ed|ure|ing)?\b|\bblock(?:ed|er)?\b|\bbreaking(?:\s+change)?s?\b|\bcritical\b|\b\w+\s+chosen\s+(?:for|over|as)\b|\bpublish(?:ed)?\b.*@?\d+\.\d+|\bmerge[d]?\s+(?:PR|pull\s+request)\b|\bshipped\b|\breleased?\b.*v?\d+\.\d+|\bsigned\b.*\b(?:contract|agreement|deal)\b|\bpricing\b.*\$|\bdemo\b.*\b(?:completed?|done|finished)\b|\bmeeting\b.*\b(?:completed?|done|finished)\b|\bstrategy\b.*\b(?:pivot|change|shift)\b)/i;
|
|
58
|
-
var DEADLINE_WITH_DATE_RE = /(?:(?:\bdeadline\b|\bdue(?:\s+date)?\b|\bcutoff\b).*(?:\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}(?:\/\d{2,4})?|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s+\d{1,2})|(?:\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}(?:\/\d{2,4})?|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s+\d{1,2}).*(?:\bdeadline\b|\bdue(?:\s+date)?\b|\bcutoff\b))/i;
|
|
59
|
-
var NOTABLE_RE = /\b(prefer(?:ence|s)?|likes?|dislikes?|context|pattern|architecture|approach|trade[- ]?off|milestone|stakeholder|teammate|collaborat(?:e|ed|ion)|discussion|notable|deadline|due|timeline|deploy(?:ed|ment)?|built|configured|launched|proposal|pitch|onboard(?:ed|ing)?|migrat(?:e|ed|ion)|domain|DNS|infra(?:structure)?)\b/i;
|
|
60
|
-
var TODO_SIGNAL_RE = /(?:\btodo:\s*|\bwe need to\b|\bdon't forget(?: to)?\b|\bremember to\b|\bmake sure to\b)/i;
|
|
61
|
-
var COMMITMENT_TASK_SIGNAL_RE = /\b(?:i'?ll|i will|let me|(?:i'?m\s+)?going to|plan to|should)\b/i;
|
|
62
|
-
var UNRESOLVED_COMMITMENT_RE = /\b(?:need to figure out|tbd|to be determined)\b/i;
|
|
63
|
-
var DEADLINE_SIGNAL_RE = /\b(?:by\s+(?:monday|tuesday|wednesday|thursday|friday|saturday|sunday|tomorrow)|before\s+the\s+\w+|deadline is)\b/i;
|
|
64
|
-
var Compressor = class {
|
|
65
|
-
provider;
|
|
66
|
-
model;
|
|
67
|
-
baseUrl;
|
|
68
|
-
apiKey;
|
|
69
|
-
now;
|
|
70
|
-
fetchImpl;
|
|
71
|
-
constructor(options = {}) {
|
|
72
|
-
this.provider = options.provider;
|
|
73
|
-
this.model = options.model;
|
|
74
|
-
this.baseUrl = options.baseUrl;
|
|
75
|
-
this.apiKey = options.apiKey;
|
|
76
|
-
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
77
|
-
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
78
|
-
}
|
|
79
|
-
async compress(messages, existingObservations) {
|
|
80
|
-
const cleanedMessages = messages.map((message) => message.trim()).filter(Boolean);
|
|
81
|
-
if (cleanedMessages.length === 0) {
|
|
82
|
-
return existingObservations.trim();
|
|
83
|
-
}
|
|
84
|
-
const prompt = this.buildPrompt(cleanedMessages, existingObservations);
|
|
85
|
-
const backend = this.resolveProvider();
|
|
86
|
-
if (backend) {
|
|
87
|
-
try {
|
|
88
|
-
const llmOutput = backend.provider === "anthropic" ? await this.callAnthropic(prompt, backend) : backend.provider === "gemini" ? await this.callGemini(prompt, backend) : backend.provider === "openai" ? await this.callOpenAI(prompt, backend) : backend.provider === "xai" ? await this.callXAI(prompt, backend) : await this.callOpenAICompatible(prompt, backend);
|
|
89
|
-
const normalized = this.normalizeLlmOutput(llmOutput);
|
|
90
|
-
if (normalized) {
|
|
91
|
-
return this.mergeObservations(existingObservations, normalized);
|
|
92
|
-
}
|
|
93
|
-
} catch {
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const fallback = this.fallbackCompression(cleanedMessages);
|
|
97
|
-
return this.mergeObservations(existingObservations, fallback);
|
|
98
|
-
}
|
|
99
|
-
resolveProvider() {
|
|
100
|
-
if (process.env.CLAWVAULT_NO_LLM) return null;
|
|
101
|
-
if (this.provider) {
|
|
102
|
-
const configured = this.resolveConfiguredProvider(this.provider);
|
|
103
|
-
if (configured) {
|
|
104
|
-
return configured;
|
|
105
|
-
}
|
|
106
|
-
return this.resolveProviderFromEnv(false);
|
|
107
|
-
}
|
|
108
|
-
return this.resolveProviderFromEnv(true);
|
|
109
|
-
}
|
|
110
|
-
resolveConfiguredProvider(provider) {
|
|
111
|
-
const model = this.resolveModel(provider);
|
|
112
|
-
if (provider === "anthropic") {
|
|
113
|
-
const apiKey2 = this.resolveApiKey(provider);
|
|
114
|
-
if (!apiKey2) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
provider,
|
|
119
|
-
model,
|
|
120
|
-
apiKey: apiKey2
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
if (provider === "gemini") {
|
|
124
|
-
const apiKey2 = this.resolveApiKey(provider);
|
|
125
|
-
if (!apiKey2) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
provider,
|
|
130
|
-
model,
|
|
131
|
-
apiKey: apiKey2
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
if (provider === "openai") {
|
|
135
|
-
const apiKey2 = this.resolveApiKey(provider);
|
|
136
|
-
if (!apiKey2) {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
provider,
|
|
141
|
-
model,
|
|
142
|
-
apiKey: apiKey2,
|
|
143
|
-
baseUrl: this.resolveBaseUrl(provider)
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
if (provider === "xai") {
|
|
147
|
-
const apiKey2 = this.resolveApiKey(provider);
|
|
148
|
-
if (!apiKey2) {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
return {
|
|
152
|
-
provider,
|
|
153
|
-
model,
|
|
154
|
-
apiKey: apiKey2,
|
|
155
|
-
baseUrl: XAI_BASE_URL
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
const apiKey = this.resolveApiKey(provider) ?? void 0;
|
|
159
|
-
return {
|
|
160
|
-
provider,
|
|
161
|
-
model,
|
|
162
|
-
apiKey,
|
|
163
|
-
baseUrl: this.resolveBaseUrl(provider)
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
resolveProviderFromEnv(allowConfiguredModel) {
|
|
167
|
-
const anthropicApiKey = this.readEnvValue("ANTHROPIC_API_KEY");
|
|
168
|
-
if (anthropicApiKey) {
|
|
169
|
-
return {
|
|
170
|
-
provider: "anthropic",
|
|
171
|
-
model: allowConfiguredModel ? this.resolveModel("anthropic") : DEFAULT_PROVIDER_MODELS.anthropic,
|
|
172
|
-
apiKey: anthropicApiKey
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
const openAiApiKey = this.readEnvValue("OPENAI_API_KEY");
|
|
176
|
-
if (openAiApiKey) {
|
|
177
|
-
return {
|
|
178
|
-
provider: "openai",
|
|
179
|
-
model: allowConfiguredModel ? this.resolveModel("openai") : DEFAULT_PROVIDER_MODELS.openai,
|
|
180
|
-
apiKey: openAiApiKey,
|
|
181
|
-
baseUrl: OPENAI_BASE_URL
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
const geminiApiKey = this.readEnvValue("GEMINI_API_KEY");
|
|
185
|
-
if (geminiApiKey) {
|
|
186
|
-
return {
|
|
187
|
-
provider: "gemini",
|
|
188
|
-
model: allowConfiguredModel ? this.resolveModel("gemini") : DEFAULT_PROVIDER_MODELS.gemini,
|
|
189
|
-
apiKey: geminiApiKey
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
const xaiApiKey = this.readEnvValue("XAI_API_KEY");
|
|
193
|
-
if (xaiApiKey) {
|
|
194
|
-
return {
|
|
195
|
-
provider: "xai",
|
|
196
|
-
model: allowConfiguredModel ? this.resolveModel("xai") : DEFAULT_PROVIDER_MODELS.xai,
|
|
197
|
-
apiKey: xaiApiKey,
|
|
198
|
-
baseUrl: XAI_BASE_URL
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
return null;
|
|
202
|
-
}
|
|
203
|
-
resolveModel(provider) {
|
|
204
|
-
const configuredModel = this.model?.trim();
|
|
205
|
-
if (configuredModel) {
|
|
206
|
-
return configuredModel;
|
|
207
|
-
}
|
|
208
|
-
return DEFAULT_PROVIDER_MODELS[provider];
|
|
209
|
-
}
|
|
210
|
-
resolveApiKey(provider) {
|
|
211
|
-
const configuredApiKey = this.apiKey?.trim();
|
|
212
|
-
if (configuredApiKey) {
|
|
213
|
-
return configuredApiKey;
|
|
214
|
-
}
|
|
215
|
-
if (provider === "anthropic") {
|
|
216
|
-
return this.readEnvValue("ANTHROPIC_API_KEY");
|
|
217
|
-
}
|
|
218
|
-
if (provider === "gemini") {
|
|
219
|
-
return this.readEnvValue("GEMINI_API_KEY");
|
|
220
|
-
}
|
|
221
|
-
if (provider === "xai") {
|
|
222
|
-
return this.readEnvValue("XAI_API_KEY");
|
|
223
|
-
}
|
|
224
|
-
return this.readEnvValue("OPENAI_API_KEY");
|
|
225
|
-
}
|
|
226
|
-
resolveBaseUrl(provider) {
|
|
227
|
-
const configuredBaseUrl = this.baseUrl?.trim();
|
|
228
|
-
if (configuredBaseUrl) {
|
|
229
|
-
return configuredBaseUrl.replace(/\/+$/, "");
|
|
230
|
-
}
|
|
231
|
-
if (provider === "ollama") {
|
|
232
|
-
return OLLAMA_BASE_URL;
|
|
233
|
-
}
|
|
234
|
-
return OPENAI_BASE_URL;
|
|
235
|
-
}
|
|
236
|
-
readEnvValue(name) {
|
|
237
|
-
const value = process.env[name]?.trim();
|
|
238
|
-
return value ? value : null;
|
|
239
|
-
}
|
|
240
|
-
buildPrompt(messages, existingObservations) {
|
|
241
|
-
return [
|
|
242
|
-
"You are an observer that compresses raw AI session messages into durable, human-meaningful observations.",
|
|
243
|
-
"",
|
|
244
|
-
"Rules:",
|
|
245
|
-
"- Output markdown only.",
|
|
246
|
-
"- Group observations by date heading: ## YYYY-MM-DD",
|
|
247
|
-
"- Each observation line MUST follow: - [type|c=<0.00-1.00>|i=<0.00-1.00>] <observation>",
|
|
248
|
-
"- Allowed type tags: decision, preference, fact, commitment, task, todo, commitment-unresolved, milestone, lesson, relationship, project",
|
|
249
|
-
"- i >= 0.80 for structural/persistent observations (major decisions, blockers, releases, commitments)",
|
|
250
|
-
"- i 0.40-0.79 for potentially important observations (notable context, preferences, milestones)",
|
|
251
|
-
"- i < 0.40 for contextual/routine observations",
|
|
252
|
-
"- Confidence c reflects extraction certainty, not importance.",
|
|
253
|
-
"- Preserve source tags when present (e.g., [main], [telegram-dm], [discord], [telegram-group]).",
|
|
254
|
-
"",
|
|
255
|
-
"TASK EXTRACTION (required):",
|
|
256
|
-
`- Emit [todo] for explicit TODO phrasing: "TODO:", "we need to", "don't forget", "remember to", "make sure to".`,
|
|
257
|
-
`- Emit [task] for commitments/action intent: "I'll", "I will", "let me", "going to", "plan to", "should".`,
|
|
258
|
-
'- Emit [commitment-unresolved] for unresolved commitments/questions: "need to figure out", "TBD", "to be determined".',
|
|
259
|
-
'- Deadline language ("by Friday", "before the demo", "deadline is") should increase importance and usually map to [task] unless unresolved.',
|
|
260
|
-
"",
|
|
261
|
-
"QUALITY FILTERS (important):",
|
|
262
|
-
"- DO NOT observe: CLI errors, command failures, tool output parsing issues, retry attempts, debug logs.",
|
|
263
|
-
" These are transient noise, not memories. Only observe errors if they represent a BLOCKER or an unresolved problem.",
|
|
264
|
-
'- DO NOT observe: "acknowledged the conversation", "said okay", routine confirmations.',
|
|
265
|
-
'- MERGE related events into single observations. If 5 images were generated, say "Generated 5 images for X" not 5 separate lines.',
|
|
266
|
-
'- MERGE retry sequences: "Tried X, failed, tried Y, succeeded" \u2192 "Resolved X using Y (after initial failure)"',
|
|
267
|
-
'- Prefer OUTCOMES over PROCESSES: "Deployed v1.2 to Railway" not "Started deploy... build finished... deploy succeeded"',
|
|
268
|
-
"",
|
|
269
|
-
"AGENT ATTRIBUTION:",
|
|
270
|
-
'- If the transcript shows multiple speakers/agents, prefix observations with who did it: "Pedro asked...", "Clawdious deployed...", "Zeca generated..."',
|
|
271
|
-
"- If only one agent is acting, attribution is optional.",
|
|
272
|
-
"",
|
|
273
|
-
"PROJECT MILESTONES (critical \u2014 these are the most valuable observations):",
|
|
274
|
-
"Projects are NOT just code. Milestones include business, strategy, client, and operational events.",
|
|
275
|
-
"- Use milestone/decision/commitment types for strategic events with high importance.",
|
|
276
|
-
"- Use preference/lesson/relationship/project/fact when appropriate.",
|
|
277
|
-
"- Examples:",
|
|
278
|
-
' "- [decision|c=0.95|i=0.90] 14:00 Pricing decision: $33K one-time + $3K/mo for Artemisa"',
|
|
279
|
-
' "- [milestone|c=0.93|i=0.88] 14:00 Published clawvault@2.1.0 to npm"',
|
|
280
|
-
' "- [project|c=0.84|i=0.58] 14:00 Deployed pitch deck to artemisa-pitch-deck.vercel.app"',
|
|
281
|
-
"- Do NOT collapse multiple milestones into one line \u2014 each matters for history.",
|
|
282
|
-
"",
|
|
283
|
-
"COMMITMENT FORMAT (when someone promises/agrees to something):",
|
|
284
|
-
'- Prefer: "- [commitment|c=...|i=...] HH:MM [COMMITMENT] <who> committed to <what> by <when>"',
|
|
285
|
-
"",
|
|
286
|
-
"Keep observations concise and factual. Aim for signal, not completeness.",
|
|
287
|
-
"",
|
|
288
|
-
"Existing observations (may be empty):",
|
|
289
|
-
existingObservations.trim() || "(none)",
|
|
290
|
-
"",
|
|
291
|
-
"Raw messages:",
|
|
292
|
-
...messages.map((message, index) => `[${index + 1}] ${message}`),
|
|
293
|
-
"",
|
|
294
|
-
"Return only the updated observation markdown."
|
|
295
|
-
].join("\n");
|
|
296
|
-
}
|
|
297
|
-
buildOpenAICompatibleUrl(baseUrl) {
|
|
298
|
-
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
299
|
-
return `${normalizedBaseUrl}/chat/completions`;
|
|
300
|
-
}
|
|
301
|
-
buildOpenAICompatibleHeaders(apiKey) {
|
|
302
|
-
const headers = {
|
|
303
|
-
"content-type": "application/json"
|
|
304
|
-
};
|
|
305
|
-
if (apiKey) {
|
|
306
|
-
headers.authorization = `Bearer ${apiKey}`;
|
|
307
|
-
}
|
|
308
|
-
return headers;
|
|
309
|
-
}
|
|
310
|
-
extractOpenAIContent(content) {
|
|
311
|
-
if (typeof content === "string") {
|
|
312
|
-
return content.trim();
|
|
313
|
-
}
|
|
314
|
-
if (!Array.isArray(content)) {
|
|
315
|
-
return "";
|
|
316
|
-
}
|
|
317
|
-
const parts = content.map((part) => {
|
|
318
|
-
if (typeof part === "string") {
|
|
319
|
-
return part;
|
|
320
|
-
}
|
|
321
|
-
if (!part || typeof part !== "object") {
|
|
322
|
-
return "";
|
|
323
|
-
}
|
|
324
|
-
const candidate = part;
|
|
325
|
-
return typeof candidate.text === "string" ? candidate.text : "";
|
|
326
|
-
}).filter((part) => part.trim().length > 0);
|
|
327
|
-
return parts.join("\n").trim();
|
|
328
|
-
}
|
|
329
|
-
async callAnthropic(prompt, backend) {
|
|
330
|
-
if (!backend.apiKey) {
|
|
331
|
-
return "";
|
|
332
|
-
}
|
|
333
|
-
const response = await this.fetchImpl("https://api.anthropic.com/v1/messages", {
|
|
334
|
-
method: "POST",
|
|
335
|
-
headers: {
|
|
336
|
-
"content-type": "application/json",
|
|
337
|
-
"x-api-key": backend.apiKey,
|
|
338
|
-
"anthropic-version": "2023-06-01"
|
|
339
|
-
},
|
|
340
|
-
body: JSON.stringify({
|
|
341
|
-
model: backend.model,
|
|
342
|
-
temperature: 0.1,
|
|
343
|
-
max_tokens: 1400,
|
|
344
|
-
messages: [{ role: "user", content: prompt }]
|
|
345
|
-
})
|
|
346
|
-
});
|
|
347
|
-
if (!response.ok) {
|
|
348
|
-
throw new Error(`Anthropic request failed (${response.status})`);
|
|
349
|
-
}
|
|
350
|
-
const payload = await response.json();
|
|
351
|
-
return payload.content?.filter((part) => part.type === "text" && part.text).map((part) => part.text).join("\n").trim() ?? "";
|
|
352
|
-
}
|
|
353
|
-
async callOpenAI(prompt, backend) {
|
|
354
|
-
return this.callOpenAICompatible(prompt, backend);
|
|
355
|
-
}
|
|
356
|
-
async callXAI(prompt, backend) {
|
|
357
|
-
return this.callOpenAICompatible(prompt, backend);
|
|
358
|
-
}
|
|
359
|
-
async callOpenAICompatible(prompt, backend) {
|
|
360
|
-
const baseUrl = backend.baseUrl ?? this.resolveBaseUrl(backend.provider);
|
|
361
|
-
const response = await this.fetchImpl(this.buildOpenAICompatibleUrl(baseUrl), {
|
|
362
|
-
method: "POST",
|
|
363
|
-
headers: this.buildOpenAICompatibleHeaders(backend.apiKey),
|
|
364
|
-
body: JSON.stringify({
|
|
365
|
-
model: backend.model,
|
|
366
|
-
temperature: 0.1,
|
|
367
|
-
messages: [
|
|
368
|
-
{ role: "system", content: "You transform session logs into concise observations." },
|
|
369
|
-
{ role: "user", content: prompt }
|
|
370
|
-
]
|
|
371
|
-
})
|
|
372
|
-
});
|
|
373
|
-
if (!response.ok) {
|
|
374
|
-
throw new Error(`OpenAI-compatible request failed (${response.status})`);
|
|
375
|
-
}
|
|
376
|
-
const payload = await response.json();
|
|
377
|
-
return this.extractOpenAIContent(payload.choices?.[0]?.message?.content);
|
|
378
|
-
}
|
|
379
|
-
async callGemini(prompt, backend) {
|
|
380
|
-
if (!backend.apiKey) {
|
|
381
|
-
return "";
|
|
382
|
-
}
|
|
383
|
-
const model = encodeURIComponent(backend.model);
|
|
384
|
-
const response = await this.fetchImpl(
|
|
385
|
-
`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${backend.apiKey}`,
|
|
386
|
-
{
|
|
387
|
-
method: "POST",
|
|
388
|
-
headers: { "content-type": "application/json" },
|
|
389
|
-
body: JSON.stringify({
|
|
390
|
-
contents: [{ parts: [{ text: prompt }] }],
|
|
391
|
-
generationConfig: { temperature: 0.1, maxOutputTokens: 1400 }
|
|
392
|
-
})
|
|
393
|
-
}
|
|
394
|
-
);
|
|
395
|
-
if (!response.ok) {
|
|
396
|
-
throw new Error(`Gemini request failed (${response.status})`);
|
|
397
|
-
}
|
|
398
|
-
const payload = await response.json();
|
|
399
|
-
return payload.candidates?.[0]?.content?.parts?.[0]?.text?.trim() ?? "";
|
|
400
|
-
}
|
|
401
|
-
normalizeLlmOutput(output) {
|
|
402
|
-
if (!output.trim()) {
|
|
403
|
-
return "";
|
|
404
|
-
}
|
|
405
|
-
const cleaned = output.replace(/^```(?:markdown)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
406
|
-
const lines = cleaned.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
407
|
-
const hasObservationLine = lines.some((line) => line.startsWith("- [") || /^(?:-\s*)?(🔴|🟡|🟢)\s+/.test(line));
|
|
408
|
-
if (!hasObservationLine) {
|
|
409
|
-
return "";
|
|
410
|
-
}
|
|
411
|
-
const hasDateHeading = lines.some((line) => DATE_HEADING_RE.test(line));
|
|
412
|
-
const result = hasDateHeading ? cleaned : `## ${this.formatDate(this.now())}
|
|
413
|
-
|
|
414
|
-
${cleaned}`;
|
|
415
|
-
const sanitized = this.sanitizeWikiLinks(result);
|
|
416
|
-
return this.enforceImportanceRules(sanitized);
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Fix wiki-link corruption from LLM compression.
|
|
420
|
-
* LLMs often fuse preceding word fragments into wiki-links during rewriting:
|
|
421
|
-
* "reque[[people/pedro]]" → "[[people/pedro]]"
|
|
422
|
-
* "Linke[[agents/zeca]]" → "[[agents/zeca]]"
|
|
423
|
-
* "taske[[people/pedro]]a" → "[[people/pedro]]"
|
|
424
|
-
* Also fixes trailing word fragments fused after closing brackets.
|
|
425
|
-
*/
|
|
426
|
-
sanitizeWikiLinks(markdown) {
|
|
427
|
-
let result = markdown.replace(/\w+\[\[/g, " [[");
|
|
428
|
-
result = result.replace(/\]\]\w+/g, "]]");
|
|
429
|
-
result = result.replace(/ {2,}/g, " ");
|
|
430
|
-
return result;
|
|
431
|
-
}
|
|
432
|
-
enforceImportanceRules(markdown) {
|
|
433
|
-
const parsed = parseObservationMarkdown(markdown);
|
|
434
|
-
if (parsed.length === 0) {
|
|
435
|
-
return "";
|
|
436
|
-
}
|
|
437
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
438
|
-
for (const record of parsed) {
|
|
439
|
-
const adjusted = this.enforceImportanceForRecord(record);
|
|
440
|
-
const bucket = grouped.get(record.date) ?? [];
|
|
441
|
-
bucket.push(adjusted);
|
|
442
|
-
grouped.set(record.date, bucket);
|
|
443
|
-
}
|
|
444
|
-
return renderObservationMarkdown(grouped);
|
|
445
|
-
}
|
|
446
|
-
enforceImportanceForRecord(record) {
|
|
447
|
-
let importance = record.importance;
|
|
448
|
-
let confidence = record.confidence;
|
|
449
|
-
let type = record.type;
|
|
450
|
-
const inferredTaskType = this.inferTaskType(record.content);
|
|
451
|
-
if (this.isCriticalContent(record.content)) {
|
|
452
|
-
importance = Math.max(importance, 0.85);
|
|
453
|
-
confidence = Math.max(confidence, 0.85);
|
|
454
|
-
if (type === "fact") {
|
|
455
|
-
type = inferObservationType(record.content);
|
|
456
|
-
}
|
|
457
|
-
} else if (this.isNotableContent(record.content)) {
|
|
458
|
-
importance = Math.max(importance, 0.5);
|
|
459
|
-
confidence = Math.max(confidence, 0.75);
|
|
460
|
-
}
|
|
461
|
-
if (inferredTaskType) {
|
|
462
|
-
type = type === "fact" || type === "commitment" ? inferredTaskType : type;
|
|
463
|
-
importance = Math.max(importance, inferredTaskType === "commitment-unresolved" ? 0.72 : 0.65);
|
|
464
|
-
confidence = Math.max(confidence, 0.8);
|
|
465
|
-
}
|
|
466
|
-
if (type === "decision" || type === "commitment" || type === "milestone") {
|
|
467
|
-
importance = Math.max(importance, 0.6);
|
|
468
|
-
}
|
|
469
|
-
return {
|
|
470
|
-
type,
|
|
471
|
-
confidence: this.clamp01(confidence),
|
|
472
|
-
importance: this.clamp01(importance),
|
|
473
|
-
content: record.content
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
fallbackCompression(messages) {
|
|
477
|
-
const sections = /* @__PURE__ */ new Map();
|
|
478
|
-
const seen = /* @__PURE__ */ new Set();
|
|
479
|
-
for (const message of messages) {
|
|
480
|
-
const normalized = this.normalizeText(message);
|
|
481
|
-
if (!normalized) continue;
|
|
482
|
-
const date = this.extractDate(message) ?? this.formatDate(this.now());
|
|
483
|
-
const time = this.extractTime(message) ?? this.formatTime(this.now());
|
|
484
|
-
const line = `${time} ${normalized}`;
|
|
485
|
-
const type = inferObservationType(line);
|
|
486
|
-
const importance = this.inferImportance(line, type);
|
|
487
|
-
const confidence = this.inferConfidence(line, type, importance);
|
|
488
|
-
const dedupeKey = `${date}|${type}|${normalizeObservationContent(line)}`;
|
|
489
|
-
if (seen.has(dedupeKey)) continue;
|
|
490
|
-
seen.add(dedupeKey);
|
|
491
|
-
const bucket = sections.get(date) ?? [];
|
|
492
|
-
bucket.push({ type, confidence, importance, content: line });
|
|
493
|
-
sections.set(date, bucket);
|
|
494
|
-
}
|
|
495
|
-
if (sections.size === 0) {
|
|
496
|
-
const date = this.formatDate(this.now());
|
|
497
|
-
sections.set(date, [{
|
|
498
|
-
type: "fact",
|
|
499
|
-
confidence: 0.7,
|
|
500
|
-
importance: 0.2,
|
|
501
|
-
content: `${this.formatTime(this.now())} Processed session updates.`
|
|
502
|
-
}]);
|
|
503
|
-
}
|
|
504
|
-
return this.renderSections(sections);
|
|
505
|
-
}
|
|
506
|
-
mergeObservations(existing, incoming) {
|
|
507
|
-
const existingRecords = parseObservationMarkdown(existing);
|
|
508
|
-
const incomingRecords = parseObservationMarkdown(incoming);
|
|
509
|
-
if (incomingRecords.length === 0) {
|
|
510
|
-
return existing.trim();
|
|
511
|
-
}
|
|
512
|
-
const merged = /* @__PURE__ */ new Map();
|
|
513
|
-
for (const record of existingRecords) {
|
|
514
|
-
this.mergeRecord(merged, {
|
|
515
|
-
date: record.date,
|
|
516
|
-
type: record.type,
|
|
517
|
-
confidence: record.confidence,
|
|
518
|
-
importance: record.importance,
|
|
519
|
-
content: record.content
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
for (const record of incomingRecords) {
|
|
523
|
-
this.mergeRecord(merged, {
|
|
524
|
-
date: record.date,
|
|
525
|
-
type: record.type,
|
|
526
|
-
confidence: record.confidence,
|
|
527
|
-
importance: record.importance,
|
|
528
|
-
content: record.content
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
return this.renderSections(merged);
|
|
532
|
-
}
|
|
533
|
-
mergeRecord(sections, input) {
|
|
534
|
-
const bucket = sections.get(input.date) ?? [];
|
|
535
|
-
const key = normalizeObservationContent(input.content);
|
|
536
|
-
const index = bucket.findIndex((line) => normalizeObservationContent(line.content) === key);
|
|
537
|
-
if (index === -1) {
|
|
538
|
-
bucket.push({
|
|
539
|
-
type: input.type,
|
|
540
|
-
confidence: this.clamp01(input.confidence),
|
|
541
|
-
importance: this.clamp01(input.importance),
|
|
542
|
-
content: input.content.trim()
|
|
543
|
-
});
|
|
544
|
-
sections.set(input.date, bucket);
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
const existing = bucket[index];
|
|
548
|
-
bucket[index] = {
|
|
549
|
-
type: input.importance >= existing.importance ? input.type : existing.type,
|
|
550
|
-
confidence: this.clamp01(Math.max(existing.confidence, input.confidence)),
|
|
551
|
-
importance: this.clamp01(Math.max(existing.importance, input.importance)),
|
|
552
|
-
content: existing.content.length >= input.content.length ? existing.content : input.content
|
|
553
|
-
};
|
|
554
|
-
sections.set(input.date, bucket);
|
|
555
|
-
}
|
|
556
|
-
renderSections(sections) {
|
|
557
|
-
return renderObservationMarkdown(sections);
|
|
558
|
-
}
|
|
559
|
-
inferImportance(text, type) {
|
|
560
|
-
const inferredTaskType = this.inferTaskType(text);
|
|
561
|
-
if (this.isCriticalContent(text)) return 0.9;
|
|
562
|
-
if (inferredTaskType === "commitment-unresolved") return 0.72;
|
|
563
|
-
if (inferredTaskType === "task" || inferredTaskType === "todo") return 0.65;
|
|
564
|
-
if (this.isNotableContent(text)) return 0.6;
|
|
565
|
-
if (type === "decision" || type === "commitment" || type === "milestone") return 0.55;
|
|
566
|
-
if (type === "preference" || type === "lesson" || type === "relationship" || type === "project") return 0.45;
|
|
567
|
-
return 0.2;
|
|
568
|
-
}
|
|
569
|
-
inferConfidence(text, type, importance) {
|
|
570
|
-
const inferredTaskType = this.inferTaskType(text);
|
|
571
|
-
let confidence = 0.72;
|
|
572
|
-
if (importance >= 0.8) confidence += 0.12;
|
|
573
|
-
if (type === "decision" || type === "commitment" || type === "milestone") confidence += 0.06;
|
|
574
|
-
if (inferredTaskType) confidence += 0.06;
|
|
575
|
-
if (/\b(?:decided|chose|committed|deadline|released|merged)\b/i.test(text)) {
|
|
576
|
-
confidence += 0.05;
|
|
577
|
-
}
|
|
578
|
-
return this.clamp01(confidence);
|
|
579
|
-
}
|
|
580
|
-
isCriticalContent(text) {
|
|
581
|
-
return CRITICAL_RE.test(text) || DEADLINE_WITH_DATE_RE.test(text);
|
|
582
|
-
}
|
|
583
|
-
isNotableContent(text) {
|
|
584
|
-
return NOTABLE_RE.test(text);
|
|
585
|
-
}
|
|
586
|
-
inferTaskType(text) {
|
|
587
|
-
if (UNRESOLVED_COMMITMENT_RE.test(text)) {
|
|
588
|
-
return "commitment-unresolved";
|
|
589
|
-
}
|
|
590
|
-
if (TODO_SIGNAL_RE.test(text)) {
|
|
591
|
-
return "todo";
|
|
592
|
-
}
|
|
593
|
-
if (COMMITMENT_TASK_SIGNAL_RE.test(text) || DEADLINE_SIGNAL_RE.test(text)) {
|
|
594
|
-
return "task";
|
|
595
|
-
}
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
normalizeText(text) {
|
|
599
|
-
return text.replace(/\s+/g, " ").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").trim().slice(0, 280);
|
|
600
|
-
}
|
|
601
|
-
extractDate(text) {
|
|
602
|
-
const match = text.match(/\b(\d{4}-\d{2}-\d{2})\b/);
|
|
603
|
-
return match?.[1] ?? null;
|
|
604
|
-
}
|
|
605
|
-
extractTime(text) {
|
|
606
|
-
const match = text.match(/\b([01]\d|2[0-3]):([0-5]\d)\b/);
|
|
607
|
-
if (!match) {
|
|
608
|
-
return null;
|
|
609
|
-
}
|
|
610
|
-
return `${match[1]}:${match[2]}`;
|
|
611
|
-
}
|
|
612
|
-
formatDate(date) {
|
|
613
|
-
return date.toISOString().split("T")[0];
|
|
614
|
-
}
|
|
615
|
-
formatTime(date) {
|
|
616
|
-
return date.toISOString().slice(11, 16);
|
|
617
|
-
}
|
|
618
|
-
clamp01(value) {
|
|
619
|
-
if (!Number.isFinite(value)) return 0;
|
|
620
|
-
if (value < 0) return 0;
|
|
621
|
-
if (value > 1) return 1;
|
|
622
|
-
return value;
|
|
623
|
-
}
|
|
624
|
-
};
|
|
625
|
-
|
|
626
44
|
// src/observer/reflector.ts
|
|
627
|
-
var
|
|
45
|
+
var DATE_HEADING_RE = /^##\s+(\d{4}-\d{2}-\d{2})\s*$/;
|
|
628
46
|
var OBSERVATION_LINE_RE = /^(🔴|🟡|🟢)\s+(.+)$/u;
|
|
629
47
|
var Reflector = class {
|
|
630
48
|
now;
|
|
@@ -684,7 +102,7 @@ var Reflector = class {
|
|
|
684
102
|
const sections = /* @__PURE__ */ new Map();
|
|
685
103
|
let currentDate = null;
|
|
686
104
|
for (const rawLine of markdown.split(/\r?\n/)) {
|
|
687
|
-
const dateMatch = rawLine.match(
|
|
105
|
+
const dateMatch = rawLine.match(DATE_HEADING_RE);
|
|
688
106
|
if (dateMatch) {
|
|
689
107
|
currentDate = dateMatch[1];
|
|
690
108
|
if (!sections.has(currentDate)) {
|
|
@@ -732,9 +150,8 @@ var Reflector = class {
|
|
|
732
150
|
};
|
|
733
151
|
|
|
734
152
|
// src/lib/llm-adapter.ts
|
|
735
|
-
var GEMINI_FLASH_MODEL = "gemini-2.0-flash";
|
|
736
153
|
var OLLAMA_DEFAULT_MODEL = "llama3.1:8b";
|
|
737
|
-
var
|
|
154
|
+
var OLLAMA_BASE_URL = "http://127.0.0.1:11434";
|
|
738
155
|
function createGeminiFlashAdapter(options = {}) {
|
|
739
156
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
740
157
|
return {
|
|
@@ -745,7 +162,8 @@ function createGeminiFlashAdapter(options = {}) {
|
|
|
745
162
|
return requestLlmCompletion({
|
|
746
163
|
prompt,
|
|
747
164
|
provider: "gemini",
|
|
748
|
-
model: options.model
|
|
165
|
+
model: options.model,
|
|
166
|
+
tier: options.tier ?? "complex",
|
|
749
167
|
temperature: options.temperature ?? 0.1,
|
|
750
168
|
maxTokens: options.maxTokens ?? 2e3,
|
|
751
169
|
fetchImpl: options.fetchImpl
|
|
@@ -764,7 +182,7 @@ function createOllamaAdapter(options = {}) {
|
|
|
764
182
|
const fetchFn = options.fetchImpl ?? globalThis.fetch;
|
|
765
183
|
return {
|
|
766
184
|
async call(prompt) {
|
|
767
|
-
const resp = await fetchFn(`${
|
|
185
|
+
const resp = await fetchFn(`${OLLAMA_BASE_URL}/api/generate`, {
|
|
768
186
|
method: "POST",
|
|
769
187
|
headers: { "Content-Type": "application/json" },
|
|
770
188
|
body: JSON.stringify({
|
|
@@ -802,6 +220,7 @@ function createDefaultAdapter(options = {}) {
|
|
|
802
220
|
prompt,
|
|
803
221
|
provider: resolvedProvider,
|
|
804
222
|
model: options.model,
|
|
223
|
+
tier: options.tier ?? "default",
|
|
805
224
|
temperature: options.temperature ?? 0.1,
|
|
806
225
|
maxTokens: options.maxTokens ?? 2e3,
|
|
807
226
|
fetchImpl: options.fetchImpl
|
|
@@ -816,18 +235,22 @@ function createDefaultAdapter(options = {}) {
|
|
|
816
235
|
};
|
|
817
236
|
}
|
|
818
237
|
function createFactExtractionAdapter(options = {}) {
|
|
238
|
+
const factExtractionOptions = {
|
|
239
|
+
...options,
|
|
240
|
+
tier: options.tier ?? "complex"
|
|
241
|
+
};
|
|
819
242
|
if (options.provider) {
|
|
820
|
-
return createDefaultAdapter(
|
|
243
|
+
return createDefaultAdapter(factExtractionOptions);
|
|
821
244
|
}
|
|
822
|
-
const geminiAdapter = createGeminiFlashAdapter(
|
|
245
|
+
const geminiAdapter = createGeminiFlashAdapter(factExtractionOptions);
|
|
823
246
|
if (geminiAdapter.isAvailable()) {
|
|
824
247
|
return geminiAdapter;
|
|
825
248
|
}
|
|
826
|
-
const ollamaAdapter = createOllamaAdapter(
|
|
249
|
+
const ollamaAdapter = createOllamaAdapter(factExtractionOptions);
|
|
827
250
|
if (ollamaAdapter.isAvailable()) {
|
|
828
251
|
return ollamaAdapter;
|
|
829
252
|
}
|
|
830
|
-
return createDefaultAdapter(
|
|
253
|
+
return createDefaultAdapter(factExtractionOptions);
|
|
831
254
|
}
|
|
832
255
|
function createLlmFunction(adapter) {
|
|
833
256
|
if (!adapter.isAvailable()) {
|
|
@@ -1717,14 +1140,13 @@ function readCompressionConfig(vaultPath) {
|
|
|
1717
1140
|
const root = asRecord(config);
|
|
1718
1141
|
const observer = asRecord(root?.observer);
|
|
1719
1142
|
const compression = asRecord(observer?.compression);
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
}
|
|
1143
|
+
const models = asRecord(root?.models);
|
|
1144
|
+
const backgroundTierModel = asNonEmptyString(models?.background);
|
|
1723
1145
|
return {
|
|
1724
|
-
provider: asCompressionProvider(compression
|
|
1725
|
-
model: asNonEmptyString(compression
|
|
1726
|
-
baseUrl: asNonEmptyString(compression
|
|
1727
|
-
apiKey: asNonEmptyString(compression
|
|
1146
|
+
provider: asCompressionProvider(compression?.provider),
|
|
1147
|
+
model: asNonEmptyString(compression?.model) ?? backgroundTierModel,
|
|
1148
|
+
baseUrl: asNonEmptyString(compression?.baseUrl),
|
|
1149
|
+
apiKey: asNonEmptyString(compression?.apiKey)
|
|
1728
1150
|
};
|
|
1729
1151
|
} catch {
|
|
1730
1152
|
return {};
|
|
@@ -1926,7 +1348,6 @@ var Observer = class {
|
|
|
1926
1348
|
};
|
|
1927
1349
|
|
|
1928
1350
|
export {
|
|
1929
|
-
Compressor,
|
|
1930
1351
|
Reflector,
|
|
1931
1352
|
createGeminiFlashAdapter,
|
|
1932
1353
|
createDefaultAdapter,
|