om-memory-system 3.0.0 → 3.1.0-next.4
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/{LICENSE → LICENSE.md} +4 -2
- package/README.md +108 -532
- package/dist/adapters/opencode/auto-capture-summary.js +23 -17
- package/dist/adapters/opencode/import-command.d.ts +42 -0
- package/dist/adapters/opencode/import-command.js +154 -0
- package/dist/adapters/pi/extension.js +4 -5
- package/dist/adapters/pi/import-command.d.ts +7 -19
- package/dist/adapters/pi/import-command.js +46 -161
- package/dist/adapters/pi/live-model.d.ts +17 -0
- package/dist/adapters/pi/live-model.js +86 -0
- package/dist/adapters/pi/profile.d.ts +7 -17
- package/dist/adapters/pi/profile.js +28 -66
- package/dist/adapters/pi/provider.d.ts +8 -1
- package/dist/adapters/pi/provider.js +34 -6
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +94 -0
- package/dist/config.d.ts +7 -20
- package/dist/config.js +24 -61
- package/dist/core/extraction.d.ts +2 -2
- package/dist/core/extraction.js +8 -3
- package/dist/core/profile-analysis.d.ts +16 -0
- package/dist/core/profile-analysis.js +47 -0
- package/dist/importer/import-args.d.ts +44 -0
- package/dist/importer/import-args.js +219 -0
- package/dist/importer/importer.d.ts +33 -9
- package/dist/importer/importer.js +153 -89
- package/dist/importer/ledger.d.ts +9 -2
- package/dist/importer/ledger.js +16 -2
- package/dist/importer/model-selection.d.ts +16 -0
- package/dist/importer/model-selection.js +84 -0
- package/dist/importer/opencode-import.d.ts +28 -0
- package/dist/importer/opencode-import.js +87 -0
- package/dist/importer/opencode-project.d.ts +11 -0
- package/dist/importer/opencode-project.js +38 -0
- package/dist/importer/opencode-reader.d.ts +19 -0
- package/dist/importer/opencode-reader.js +214 -0
- package/dist/importer/profile-import.d.ts +29 -0
- package/dist/importer/profile-import.js +111 -0
- package/dist/importer/run-import.d.ts +49 -0
- package/dist/importer/run-import.js +123 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +37 -1
- package/dist/services/ai/internal-capture-sessions.d.ts +2 -0
- package/dist/services/ai/internal-capture-sessions.js +7 -0
- package/dist/services/ai/live-model-choice.d.ts +52 -0
- package/dist/services/ai/live-model-choice.js +83 -0
- package/dist/services/ai/profile-llm-client.js +7 -5
- package/dist/services/user-memory-learning.js +9 -8
- package/dist/services/user-profile/ai-cleanup.js +8 -5
- package/dist/services/user-profile/user-profile-manager.js +11 -10
- package/dist/v2/adapter.js +27 -0
- package/package.json +5 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which model live capture and profile learning call, the same rule on both
|
|
3
|
+
* hosts. Pure functions of the config: callers pass CONFIG, so this module
|
|
4
|
+
* has no dependency on config loading.
|
|
5
|
+
*/
|
|
6
|
+
export interface AutoCaptureProviderRuntimeConfig {
|
|
7
|
+
opencodeProvider?: string;
|
|
8
|
+
opencodeModel?: string;
|
|
9
|
+
memoryProvider?: string;
|
|
10
|
+
memoryModel?: string;
|
|
11
|
+
memoryApiUrl?: string;
|
|
12
|
+
memoryApiKey?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Where live capture and profile learning send model calls, the same on both hosts:
|
|
16
|
+
* - `opencode`: the configured host model (`opencodeModel`/`piModel`; "inherit" = session model)
|
|
17
|
+
* - `manual`: no host model, so the external API (`memoryModel`/`memoryApiUrl`/`memoryApiKey`)
|
|
18
|
+
* - `session`: neither is set, so the session's own model through the host's sign-in
|
|
19
|
+
*/
|
|
20
|
+
export type AutoCaptureProviderStatus = {
|
|
21
|
+
ready: true;
|
|
22
|
+
mode: "opencode" | "manual" | "session";
|
|
23
|
+
issues: [];
|
|
24
|
+
} | {
|
|
25
|
+
ready: false;
|
|
26
|
+
issues: string[];
|
|
27
|
+
};
|
|
28
|
+
export declare function getAutoCaptureProviderStatus(config: AutoCaptureProviderRuntimeConfig): AutoCaptureProviderStatus;
|
|
29
|
+
/** OpenCode host model for live calls, or null when the external API should be used. */
|
|
30
|
+
export declare function resolveOpencodeHostModel(config: AutoCaptureProviderRuntimeConfig): {
|
|
31
|
+
providerID: string;
|
|
32
|
+
modelID: string;
|
|
33
|
+
} | null;
|
|
34
|
+
export type PiLiveModelChoice = {
|
|
35
|
+
kind: "pi";
|
|
36
|
+
provider: string;
|
|
37
|
+
model: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "session";
|
|
40
|
+
} | {
|
|
41
|
+
kind: "manual";
|
|
42
|
+
} | {
|
|
43
|
+
kind: "unready";
|
|
44
|
+
issues: string[];
|
|
45
|
+
};
|
|
46
|
+
/** Pi's live model, by the same rule as OpenCode's (`piProvider`/`piModel` in place of `opencode*`). */
|
|
47
|
+
export declare function resolvePiLiveModel(config: AutoCaptureProviderRuntimeConfig & {
|
|
48
|
+
piProvider?: string;
|
|
49
|
+
piModel?: string;
|
|
50
|
+
}): PiLiveModelChoice;
|
|
51
|
+
/** True when the external API is fully configured and can serve as a fallback. */
|
|
52
|
+
export declare function isExternalModelReady(config: AutoCaptureProviderRuntimeConfig): boolean;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { isPlaceholderApiKey } from "./api-key-placeholder.js";
|
|
2
|
+
function hasValue(value) {
|
|
3
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
4
|
+
}
|
|
5
|
+
/** External-API readiness alone; any memory* value set counts as intent to use it. */
|
|
6
|
+
function getManualProviderStatus(config) {
|
|
7
|
+
const hasMemoryModel = hasValue(config.memoryModel);
|
|
8
|
+
const hasMemoryApiUrl = hasValue(config.memoryApiUrl);
|
|
9
|
+
const hasMemoryApiKey = hasValue(config.memoryApiKey);
|
|
10
|
+
const hasPlaceholderMemoryApiKey = isPlaceholderApiKey(config.memoryApiKey);
|
|
11
|
+
const attempted = hasMemoryModel || hasMemoryApiUrl || hasMemoryApiKey;
|
|
12
|
+
const issues = [];
|
|
13
|
+
// The orcarouter provider presets its endpoint and default model, so only
|
|
14
|
+
// an API key is required for the manual fallback path.
|
|
15
|
+
if (config.memoryProvider === "orcarouter") {
|
|
16
|
+
if (!hasMemoryApiKey)
|
|
17
|
+
issues.push("memoryApiKey is not configured");
|
|
18
|
+
if (hasPlaceholderMemoryApiKey)
|
|
19
|
+
issues.push("memoryApiKey contains a placeholder value");
|
|
20
|
+
return { attempted, ready: hasMemoryApiKey && !hasPlaceholderMemoryApiKey, issues };
|
|
21
|
+
}
|
|
22
|
+
if (!hasMemoryModel)
|
|
23
|
+
issues.push("memoryModel is not configured");
|
|
24
|
+
if (!hasMemoryApiUrl)
|
|
25
|
+
issues.push("memoryApiUrl is not configured");
|
|
26
|
+
if (!hasMemoryApiKey)
|
|
27
|
+
issues.push("memoryApiKey is not configured");
|
|
28
|
+
if (hasPlaceholderMemoryApiKey)
|
|
29
|
+
issues.push("memoryApiKey contains a placeholder value");
|
|
30
|
+
return {
|
|
31
|
+
attempted,
|
|
32
|
+
ready: hasMemoryModel && hasMemoryApiUrl && hasMemoryApiKey && !hasPlaceholderMemoryApiKey,
|
|
33
|
+
issues,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function getAutoCaptureProviderStatus(config) {
|
|
37
|
+
const hasOpencodeProvider = hasValue(config.opencodeProvider);
|
|
38
|
+
const hasOpencodeModel = hasValue(config.opencodeModel);
|
|
39
|
+
if (hasOpencodeProvider && hasOpencodeModel) {
|
|
40
|
+
return { ready: true, mode: "opencode", issues: [] };
|
|
41
|
+
}
|
|
42
|
+
const manual = getManualProviderStatus(config);
|
|
43
|
+
if (manual.ready)
|
|
44
|
+
return { ready: true, mode: "manual", issues: [] };
|
|
45
|
+
// Nothing configured at all: follow the session's model, as Pi always has.
|
|
46
|
+
if (!manual.attempted)
|
|
47
|
+
return { ready: true, mode: "session", issues: [] };
|
|
48
|
+
// A half-configured external API is a mistake worth reporting, not a silent switch.
|
|
49
|
+
const issues = [];
|
|
50
|
+
if (!hasOpencodeProvider)
|
|
51
|
+
issues.push("opencodeProvider is not configured");
|
|
52
|
+
if (!hasOpencodeModel)
|
|
53
|
+
issues.push("opencodeModel is not configured");
|
|
54
|
+
return { ready: false, issues: [...issues, ...manual.issues] };
|
|
55
|
+
}
|
|
56
|
+
/** OpenCode host model for live calls, or null when the external API should be used. */
|
|
57
|
+
export function resolveOpencodeHostModel(config) {
|
|
58
|
+
const status = getAutoCaptureProviderStatus(config);
|
|
59
|
+
if (!status.ready || status.mode === "manual")
|
|
60
|
+
return null;
|
|
61
|
+
if (status.mode === "opencode") {
|
|
62
|
+
return { providerID: config.opencodeProvider.trim(), modelID: config.opencodeModel.trim() };
|
|
63
|
+
}
|
|
64
|
+
return { providerID: config.opencodeProvider?.trim() ?? "", modelID: "inherit" };
|
|
65
|
+
}
|
|
66
|
+
/** Pi's live model, by the same rule as OpenCode's (`piProvider`/`piModel` in place of `opencode*`). */
|
|
67
|
+
export function resolvePiLiveModel(config) {
|
|
68
|
+
if (hasValue(config.piProvider) && hasValue(config.piModel)) {
|
|
69
|
+
return config.piModel.trim() === "inherit"
|
|
70
|
+
? { kind: "session" }
|
|
71
|
+
: { kind: "pi", provider: config.piProvider.trim(), model: config.piModel.trim() };
|
|
72
|
+
}
|
|
73
|
+
const manual = getManualProviderStatus(config);
|
|
74
|
+
if (manual.ready)
|
|
75
|
+
return { kind: "manual" };
|
|
76
|
+
if (!manual.attempted)
|
|
77
|
+
return { kind: "session" };
|
|
78
|
+
return { kind: "unready", issues: manual.issues };
|
|
79
|
+
}
|
|
80
|
+
/** True when the external API is fully configured and can serve as a fallback. */
|
|
81
|
+
export function isExternalModelReady(config) {
|
|
82
|
+
return getManualProviderStatus(config).ready;
|
|
83
|
+
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { CONFIG } from "../../config.js";
|
|
2
|
+
import { resolveOpencodeHostModel } from "./live-model-choice.js";
|
|
2
3
|
import { loadOpencodeProvider } from "./opencode-provider-loader.js";
|
|
3
4
|
let _cachedClient = null;
|
|
4
5
|
let _cachedProvider = null;
|
|
5
6
|
let _cachedModel = null;
|
|
6
7
|
export async function getOpenCodeClient() {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
throw new Error("omms: opencodeProvider and opencodeModel must be configured");
|
|
8
|
+
const hostModel = resolveOpencodeHostModel(CONFIG);
|
|
9
|
+
if (!hostModel) {
|
|
10
|
+
throw new Error("omms: live calls use the external API; no OpenCode model is configured");
|
|
11
11
|
}
|
|
12
|
+
const { isProviderConnected, getV2Client, resolveOpencodeModelRef } = await loadOpencodeProvider();
|
|
13
|
+
// "inherit" checks the provider of the model it resolves to.
|
|
14
|
+
const { providerID: provider, modelID: model } = resolveOpencodeModelRef(hostModel);
|
|
12
15
|
if (_cachedClient && _cachedProvider === provider && _cachedModel === model) {
|
|
13
16
|
return _cachedClient;
|
|
14
17
|
}
|
|
15
|
-
const { isProviderConnected, getV2Client } = await loadOpencodeProvider();
|
|
16
18
|
if (!isProviderConnected(provider)) {
|
|
17
19
|
throw new Error(`opencode provider '${provider}' is not connected. Check your opencode provider configuration.`);
|
|
18
20
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getTags } from "./tags.js";
|
|
2
2
|
import { log } from "./logger.js";
|
|
3
3
|
import { CONFIG } from "../config.js";
|
|
4
|
+
import { resolveOpencodeHostModel } from "./ai/live-model-choice.js";
|
|
4
5
|
import { userPromptManager } from "./user-prompt/user-prompt-manager.js";
|
|
5
6
|
import { userProfileManager } from "./user-profile/user-profile-manager.js";
|
|
6
7
|
import { sortProfileItems } from "../utils/profile.js";
|
|
@@ -491,14 +492,14 @@ async function applyValidations(profileData, llmResult, profileId, prefKeys) {
|
|
|
491
492
|
async function analyzeUserProfile(context, existingProfile) {
|
|
492
493
|
log("user-profile-learning: analyze called", { hasProfile: !!existingProfile });
|
|
493
494
|
let opencodeProviderError;
|
|
494
|
-
if (CONFIG
|
|
495
|
+
if (resolveOpencodeHostModel(CONFIG)) {
|
|
495
496
|
log("user-profile-learning: trying opencode provider");
|
|
496
497
|
try {
|
|
497
498
|
const { generateStructuredOutput } = await loadOpencodeProvider();
|
|
498
499
|
const { getOpenCodeClient } = await import("./ai/profile-llm-client.js");
|
|
499
500
|
log("user-profile-learning: opencode provider diag", {
|
|
500
|
-
provider: CONFIG
|
|
501
|
-
model: CONFIG
|
|
501
|
+
provider: resolveOpencodeHostModel(CONFIG)?.providerID,
|
|
502
|
+
model: resolveOpencodeHostModel(CONFIG)?.modelID,
|
|
502
503
|
});
|
|
503
504
|
const v2Client = await getOpenCodeClient();
|
|
504
505
|
const systemPrompt = `You are a user behavior analyst for a coding assistant.
|
|
@@ -516,8 +517,8 @@ Use the update_user_profile tool to save the ${existingProfile ? "updated" : "ne
|
|
|
516
517
|
const result = await Promise.race([
|
|
517
518
|
generateStructuredOutput({
|
|
518
519
|
client: v2Client,
|
|
519
|
-
providerID: CONFIG.
|
|
520
|
-
modelID: CONFIG.
|
|
520
|
+
providerID: resolveOpencodeHostModel(CONFIG).providerID,
|
|
521
|
+
modelID: resolveOpencodeHostModel(CONFIG).modelID,
|
|
521
522
|
systemPrompt,
|
|
522
523
|
userPrompt: context,
|
|
523
524
|
schema,
|
|
@@ -591,7 +592,7 @@ Identify sequences where earlier prompts led to later ones (e.g. "learned X →
|
|
|
591
592
|
{ "paths": [{ "topic": "string", "chain": ["step1", "step2", "step3"], "description": "one sentence summary" }] }
|
|
592
593
|
If no clear chains, return { "paths": [] }.`;
|
|
593
594
|
let result = null;
|
|
594
|
-
if (CONFIG
|
|
595
|
+
if (resolveOpencodeHostModel(CONFIG)) {
|
|
595
596
|
try {
|
|
596
597
|
const { z } = await import("zod");
|
|
597
598
|
const { generateStructuredOutput } = await loadOpencodeProvider();
|
|
@@ -607,8 +608,8 @@ If no clear chains, return { "paths": [] }.`;
|
|
|
607
608
|
result = (await Promise.race([
|
|
608
609
|
generateStructuredOutput({
|
|
609
610
|
client: v2Client,
|
|
610
|
-
providerID: CONFIG.
|
|
611
|
-
modelID: CONFIG.
|
|
611
|
+
providerID: resolveOpencodeHostModel(CONFIG).providerID,
|
|
612
|
+
modelID: resolveOpencodeHostModel(CONFIG).modelID,
|
|
612
613
|
systemPrompt,
|
|
613
614
|
userPrompt,
|
|
614
615
|
schema: z.object({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CONFIG } from "../../config.js";
|
|
2
|
+
import { resolveOpencodeHostModel } from "../ai/live-model-choice.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
import { loadOpencodeProvider } from "../ai/opencode-provider-loader.js";
|
|
4
5
|
import { EXTERNAL_PROFILE_CLEANUP_TIMEOUT_MS, OPENCODE_PROFILE_CLEANUP_TIMEOUT_MS, } from "../request-timeouts.js";
|
|
@@ -151,7 +152,7 @@ async function callAICleanup(prompt) {
|
|
|
151
152
|
// Use opencode internal session when opencodeProvider is configured (same pattern as auto-capture).
|
|
152
153
|
// When the client is available, surface OpenCode errors instead of masking them as
|
|
153
154
|
// "No AI provider configured" via a silent fallback (#177).
|
|
154
|
-
if (CONFIG
|
|
155
|
+
if (resolveOpencodeHostModel(CONFIG)) {
|
|
155
156
|
const { getV2Client } = await loadOpencodeProvider();
|
|
156
157
|
const v2Client = getV2Client();
|
|
157
158
|
if (v2Client) {
|
|
@@ -234,6 +235,11 @@ function raceWithTimeout(promise, ms, message) {
|
|
|
234
235
|
}
|
|
235
236
|
async function callViaOpencodeWithClient(v2Client, prompt) {
|
|
236
237
|
const t0 = Date.now();
|
|
238
|
+
const hostModel = resolveOpencodeHostModel(CONFIG) ?? { providerID: "", modelID: "inherit" };
|
|
239
|
+
// Only "inherit" (or no model configured) needs resolving to the session's recent model.
|
|
240
|
+
const model = hostModel.modelID === "inherit"
|
|
241
|
+
? (await loadOpencodeProvider()).resolveOpencodeModelRef(hostModel)
|
|
242
|
+
: hostModel;
|
|
237
243
|
const systemPrompt = "You are a user profile cleanup assistant. Merge duplicate entries and return only JSON without markdown wrapping.";
|
|
238
244
|
const created = (await raceWithTimeout(v2Client.session.create({
|
|
239
245
|
title: "omms profile cleanup",
|
|
@@ -253,10 +259,7 @@ async function callViaOpencodeWithClient(v2Client, prompt) {
|
|
|
253
259
|
const TIMEOUT_MS = OPENCODE_PROFILE_CLEANUP_TIMEOUT_MS;
|
|
254
260
|
const promptResult = await raceWithTimeout(v2Client.session.prompt({
|
|
255
261
|
sessionID,
|
|
256
|
-
model
|
|
257
|
-
providerID: CONFIG.opencodeProvider || "bs-aigw",
|
|
258
|
-
modelID: CONFIG.opencodeModel || "deepseek-v4-flash",
|
|
259
|
-
},
|
|
262
|
+
model,
|
|
260
263
|
system: systemPrompt,
|
|
261
264
|
parts: [{ type: "text", text: prompt }],
|
|
262
265
|
// `noReply` suppresses assistant generation; cleanup needs the JSON reply (#177).
|
|
@@ -2,6 +2,7 @@ import { join } from "node:path";
|
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tursoConnectionManager } from "../turso/connection-manager.js";
|
|
4
4
|
import { CONFIG } from "../../config.js";
|
|
5
|
+
import { resolveOpencodeHostModel } from "../ai/live-model-choice.js";
|
|
5
6
|
import { safeArray } from "./profile-utils.js";
|
|
6
7
|
import { EmbeddingService } from "../embedding.js";
|
|
7
8
|
import { log } from "../logger.js";
|
|
@@ -1178,7 +1179,7 @@ A: "${descA}"
|
|
|
1178
1179
|
B: "${descB}"
|
|
1179
1180
|
|
|
1180
1181
|
Answer JSON only: { "duplicate": true|false, "reason": "one sentence explanation" }`;
|
|
1181
|
-
if (CONFIG
|
|
1182
|
+
if (resolveOpencodeHostModel(CONFIG)) {
|
|
1182
1183
|
try {
|
|
1183
1184
|
const { z } = await import("zod");
|
|
1184
1185
|
const { generateStructuredOutput } = await loadOpencodeProvider();
|
|
@@ -1194,8 +1195,8 @@ Answer JSON only: { "duplicate": true|false, "reason": "one sentence explanation
|
|
|
1194
1195
|
const result = await Promise.race([
|
|
1195
1196
|
generateStructuredOutput({
|
|
1196
1197
|
client: v2Client,
|
|
1197
|
-
providerID: CONFIG.
|
|
1198
|
-
modelID: CONFIG.
|
|
1198
|
+
providerID: resolveOpencodeHostModel(CONFIG).providerID,
|
|
1199
|
+
modelID: resolveOpencodeHostModel(CONFIG).modelID,
|
|
1199
1200
|
systemPrompt: "You are a semantic duplicate detector. Output valid JSON.",
|
|
1200
1201
|
userPrompt: prompt,
|
|
1201
1202
|
schema: z.object({ duplicate: z.boolean(), reason: z.string() }),
|
|
@@ -1365,7 +1366,7 @@ A: "${descA}"
|
|
|
1365
1366
|
B: "${descB}"
|
|
1366
1367
|
|
|
1367
1368
|
Answer JSON only: { "conflict": true|false, "reason": "one sentence explanation" }`;
|
|
1368
|
-
if (CONFIG
|
|
1369
|
+
if (resolveOpencodeHostModel(CONFIG)) {
|
|
1369
1370
|
try {
|
|
1370
1371
|
const { z } = await import("zod");
|
|
1371
1372
|
const { generateStructuredOutput } = await loadOpencodeProvider();
|
|
@@ -1381,8 +1382,8 @@ Answer JSON only: { "conflict": true|false, "reason": "one sentence explanation"
|
|
|
1381
1382
|
const result = await Promise.race([
|
|
1382
1383
|
generateStructuredOutput({
|
|
1383
1384
|
client: v2Client,
|
|
1384
|
-
providerID: CONFIG.
|
|
1385
|
-
modelID: CONFIG.
|
|
1385
|
+
providerID: resolveOpencodeHostModel(CONFIG).providerID,
|
|
1386
|
+
modelID: resolveOpencodeHostModel(CONFIG).modelID,
|
|
1386
1387
|
systemPrompt: "You are a preference contradiction detector. Output valid JSON.",
|
|
1387
1388
|
userPrompt: prompt,
|
|
1388
1389
|
schema: z.object({ conflict: z.boolean(), reason: z.string() }),
|
|
@@ -1481,7 +1482,7 @@ ${evidenceList}
|
|
|
1481
1482
|
|
|
1482
1483
|
Generate a concise, abstract description of the user's general behavioral tendency.`;
|
|
1483
1484
|
let newDescription = null;
|
|
1484
|
-
if (CONFIG
|
|
1485
|
+
if (resolveOpencodeHostModel(CONFIG)) {
|
|
1485
1486
|
try {
|
|
1486
1487
|
newDescription = await this.callOpencodeProvider(systemPrompt, userPrompt);
|
|
1487
1488
|
}
|
|
@@ -1602,7 +1603,7 @@ Generate a concise, abstract description of the user's general behavioral tenden
|
|
|
1602
1603
|
}
|
|
1603
1604
|
catch (e) {
|
|
1604
1605
|
log("profile description evolution: native provider not connected", {
|
|
1605
|
-
provider: CONFIG
|
|
1606
|
+
provider: resolveOpencodeHostModel(CONFIG)?.providerID,
|
|
1606
1607
|
error: String(e),
|
|
1607
1608
|
});
|
|
1608
1609
|
return null;
|
|
@@ -1612,8 +1613,8 @@ Generate a concise, abstract description of the user's general behavioral tenden
|
|
|
1612
1613
|
const result = await Promise.race([
|
|
1613
1614
|
generateStructuredOutput({
|
|
1614
1615
|
client: v2Client,
|
|
1615
|
-
providerID: CONFIG.
|
|
1616
|
-
modelID: CONFIG.
|
|
1616
|
+
providerID: resolveOpencodeHostModel(CONFIG).providerID,
|
|
1617
|
+
modelID: resolveOpencodeHostModel(CONFIG).modelID,
|
|
1617
1618
|
systemPrompt,
|
|
1618
1619
|
userPrompt,
|
|
1619
1620
|
schema,
|
package/dist/v2/adapter.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OPENCODE_IMPORT_COMMAND, OPENCODE_IMPORT_DESCRIPTION, runOpencodeImportCommand, } from "../adapters/opencode/import-command.js";
|
|
1
2
|
import { log } from "../services/logger.js";
|
|
2
3
|
import { eventBelongsToLocation, legacyToolResult, toLegacyEvent } from "./legacy-client.js";
|
|
3
4
|
const memoryInput = {
|
|
@@ -127,6 +128,32 @@ export async function registerV2Adapter(ctx, legacy, memory) {
|
|
|
127
128
|
async ask() { },
|
|
128
129
|
})),
|
|
129
130
|
}));
|
|
131
|
+
// Same command as V1 and Pi. V2 runs it natively, so no model turn relays the report.
|
|
132
|
+
await ctx.command?.transform?.((editor) => editor.add({
|
|
133
|
+
name: OPENCODE_IMPORT_COMMAND,
|
|
134
|
+
description: OPENCODE_IMPORT_DESCRIPTION,
|
|
135
|
+
execute: async (invocation) => {
|
|
136
|
+
const sessionID = invocation.sessionID;
|
|
137
|
+
const report = await runOpencodeImportCommand({
|
|
138
|
+
argsText: invocation.prompt?.text ?? "",
|
|
139
|
+
directory: ctx.location.directory,
|
|
140
|
+
sessionModel: async () => {
|
|
141
|
+
try {
|
|
142
|
+
const session = await ctx.session.get({ sessionID });
|
|
143
|
+
const model = session?.model ?? session?.data?.model;
|
|
144
|
+
return model?.providerID && model?.id
|
|
145
|
+
? { providerID: String(model.providerID), modelID: String(model.id) }
|
|
146
|
+
: null;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
log("v2 import: could not read the session model", { error: String(error) });
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
await ctx.session.synthetic({ sessionID, text: report, resume: false });
|
|
155
|
+
},
|
|
156
|
+
}));
|
|
130
157
|
await ctx.session.hook("prompt", async (event) => {
|
|
131
158
|
const sessionID = event.sessionID;
|
|
132
159
|
const text = event.prompt.text ?? "";
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "om-memory-system",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.1.0-next.4",
|
|
4
4
|
"description": "Opinionated modular memory system for coding agents (OpenCode + Pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.js",
|
|
7
7
|
"types": "dist/plugin.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"om-memory-system": "dist/cli/index.js"
|
|
10
|
+
},
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"types": "./dist/plugin.d.ts",
|
|
@@ -28,7 +31,7 @@
|
|
|
28
31
|
}
|
|
29
32
|
},
|
|
30
33
|
"scripts": {
|
|
31
|
-
"build": "rm -rf dist && bunx tsc && bun run web:build",
|
|
34
|
+
"build": "rm -rf dist && bunx tsc && chmod +x dist/cli/index.js && bun run web:build",
|
|
32
35
|
"web:dev": "cd web && bun run dev",
|
|
33
36
|
"web:build": "cd web && bun run build",
|
|
34
37
|
"dev": "tsc --watch",
|