om-memory-system 3.0.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/LICENSE +21 -0
- package/README.md +587 -0
- package/dist/adapters/opencode/auto-capture-host.d.ts +3 -0
- package/dist/adapters/opencode/auto-capture-host.js +29 -0
- package/dist/adapters/opencode/auto-capture-summary.d.ts +4 -0
- package/dist/adapters/opencode/auto-capture-summary.js +147 -0
- package/dist/adapters/opencode/conversation.d.ts +2 -0
- package/dist/adapters/opencode/conversation.js +50 -0
- package/dist/adapters/opencode/user-prompt.d.ts +9 -0
- package/dist/adapters/opencode/user-prompt.js +26 -0
- package/dist/adapters/pi/capture.d.ts +41 -0
- package/dist/adapters/pi/capture.js +91 -0
- package/dist/adapters/pi/conversation.d.ts +38 -0
- package/dist/adapters/pi/conversation.js +118 -0
- package/dist/adapters/pi/extension.d.ts +18 -0
- package/dist/adapters/pi/extension.js +234 -0
- package/dist/adapters/pi/import-command.d.ts +29 -0
- package/dist/adapters/pi/import-command.js +232 -0
- package/dist/adapters/pi/profile.d.ts +39 -0
- package/dist/adapters/pi/profile.js +148 -0
- package/dist/adapters/pi/provider.d.ts +50 -0
- package/dist/adapters/pi/provider.js +77 -0
- package/dist/config.d.ts +290 -0
- package/dist/config.js +742 -0
- package/dist/core/capture-context.d.ts +4 -0
- package/dist/core/capture-context.js +132 -0
- package/dist/core/capture.d.ts +15 -0
- package/dist/core/capture.js +68 -0
- package/dist/core/extraction.d.ts +80 -0
- package/dist/core/extraction.js +140 -0
- package/dist/core/host.d.ts +52 -0
- package/dist/core/host.js +1 -0
- package/dist/core/memory-operations.d.ts +27 -0
- package/dist/core/memory-operations.js +247 -0
- package/dist/core/retrieval.d.ts +12 -0
- package/dist/core/retrieval.js +72 -0
- package/dist/importer/discovery.d.ts +31 -0
- package/dist/importer/discovery.js +88 -0
- package/dist/importer/importer.d.ts +87 -0
- package/dist/importer/importer.js +260 -0
- package/dist/importer/ledger.d.ts +44 -0
- package/dist/importer/ledger.js +137 -0
- package/dist/importer/session-loader.d.ts +19 -0
- package/dist/importer/session-loader.js +12 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +601 -0
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.js +11 -0
- package/dist/services/ai/ai-provider-factory.d.ts +7 -0
- package/dist/services/ai/ai-provider-factory.js +41 -0
- package/dist/services/ai/api-key-placeholder.d.ts +1 -0
- package/dist/services/ai/api-key-placeholder.js +14 -0
- package/dist/services/ai/internal-capture-sessions.d.ts +6 -0
- package/dist/services/ai/internal-capture-sessions.js +33 -0
- package/dist/services/ai/opencode-diagnostics.d.ts +7 -0
- package/dist/services/ai/opencode-diagnostics.js +36 -0
- package/dist/services/ai/opencode-host-config.d.ts +10 -0
- package/dist/services/ai/opencode-host-config.js +51 -0
- package/dist/services/ai/opencode-provider-loader.d.ts +3 -0
- package/dist/services/ai/opencode-provider-loader.js +4 -0
- package/dist/services/ai/opencode-provider.d.ts +92 -0
- package/dist/services/ai/opencode-provider.js +419 -0
- package/dist/services/ai/opencode-sdk-client.d.ts +6 -0
- package/dist/services/ai/opencode-sdk-client.js +38 -0
- package/dist/services/ai/profile-llm-client.d.ts +2 -0
- package/dist/services/ai/profile-llm-client.js +27 -0
- package/dist/services/ai/provider-config.d.ts +17 -0
- package/dist/services/ai/provider-config.js +30 -0
- package/dist/services/ai/providers/anthropic-messages.d.ts +34 -0
- package/dist/services/ai/providers/anthropic-messages.js +220 -0
- package/dist/services/ai/providers/base-provider.d.ts +24 -0
- package/dist/services/ai/providers/base-provider.js +24 -0
- package/dist/services/ai/providers/google-gemini.d.ts +15 -0
- package/dist/services/ai/providers/google-gemini.js +228 -0
- package/dist/services/ai/providers/minimax.d.ts +35 -0
- package/dist/services/ai/providers/minimax.js +55 -0
- package/dist/services/ai/providers/openai-chat-completion.d.ts +22 -0
- package/dist/services/ai/providers/openai-chat-completion.js +387 -0
- package/dist/services/ai/providers/openai-responses.d.ts +13 -0
- package/dist/services/ai/providers/openai-responses.js +182 -0
- package/dist/services/ai/providers/orcarouter.d.ts +51 -0
- package/dist/services/ai/providers/orcarouter.js +66 -0
- package/dist/services/ai/session/ai-session-manager.d.ts +24 -0
- package/dist/services/ai/session/ai-session-manager.js +211 -0
- package/dist/services/ai/session/session-types.d.ts +42 -0
- package/dist/services/ai/session/session-types.js +1 -0
- package/dist/services/ai/tools/tool-schema.d.ts +40 -0
- package/dist/services/ai/tools/tool-schema.js +24 -0
- package/dist/services/ai/validators/user-profile-validator.d.ts +12 -0
- package/dist/services/ai/validators/user-profile-validator.js +114 -0
- package/dist/services/api-handlers.d.ts +186 -0
- package/dist/services/api-handlers.js +1284 -0
- package/dist/services/auth-token.d.ts +14 -0
- package/dist/services/auth-token.js +59 -0
- package/dist/services/auto-capture.d.ts +3 -0
- package/dist/services/auto-capture.js +127 -0
- package/dist/services/cleanup-service.d.ts +22 -0
- package/dist/services/cleanup-service.js +109 -0
- package/dist/services/client.d.ts +134 -0
- package/dist/services/client.js +327 -0
- package/dist/services/context.d.ts +10 -0
- package/dist/services/context.js +27 -0
- package/dist/services/cors.d.ts +12 -0
- package/dist/services/cors.js +52 -0
- package/dist/services/deduplication-service.d.ts +28 -0
- package/dist/services/deduplication-service.js +111 -0
- package/dist/services/embedding.d.ts +36 -0
- package/dist/services/embedding.js +200 -0
- package/dist/services/jsonc.d.ts +6 -0
- package/dist/services/jsonc.js +76 -0
- package/dist/services/language-detector.d.ts +2 -0
- package/dist/services/language-detector.js +33 -0
- package/dist/services/legacy-migration.d.ts +77 -0
- package/dist/services/legacy-migration.js +343 -0
- package/dist/services/logger.d.ts +1 -0
- package/dist/services/logger.js +119 -0
- package/dist/services/memory-portability-service.d.ts +37 -0
- package/dist/services/memory-portability-service.js +340 -0
- package/dist/services/memory-scope.d.ts +16 -0
- package/dist/services/memory-scope.js +43 -0
- package/dist/services/migration-service.d.ts +42 -0
- package/dist/services/migration-service.js +307 -0
- package/dist/services/onnxruntime-resolve.d.ts +24 -0
- package/dist/services/onnxruntime-resolve.js +174 -0
- package/dist/services/privacy.d.ts +26 -0
- package/dist/services/privacy.js +69 -0
- package/dist/services/request-timeouts.d.ts +9 -0
- package/dist/services/request-timeouts.js +11 -0
- package/dist/services/runtime-require.d.ts +17 -0
- package/dist/services/runtime-require.js +75 -0
- package/dist/services/secret-resolver.d.ts +1 -0
- package/dist/services/secret-resolver.js +65 -0
- package/dist/services/shard-inventory-service.d.ts +69 -0
- package/dist/services/shard-inventory-service.js +315 -0
- package/dist/services/shard-path-migration-service.d.ts +31 -0
- package/dist/services/shard-path-migration-service.js +367 -0
- package/dist/services/tag-prefix-migration.d.ts +60 -0
- package/dist/services/tag-prefix-migration.js +439 -0
- package/dist/services/tag-prefix-scan.d.ts +26 -0
- package/dist/services/tag-prefix-scan.js +91 -0
- package/dist/services/tags.d.ts +29 -0
- package/dist/services/tags.js +251 -0
- package/dist/services/turso/connection-manager.d.ts +15 -0
- package/dist/services/turso/connection-manager.js +163 -0
- package/dist/services/turso/cross-process-write-lock.d.ts +1 -0
- package/dist/services/turso/cross-process-write-lock.js +89 -0
- package/dist/services/turso/legacy-migrator.d.ts +1 -0
- package/dist/services/turso/legacy-migrator.js +540 -0
- package/dist/services/turso/lifecycle.d.ts +1 -0
- package/dist/services/turso/lifecycle.js +14 -0
- package/dist/services/turso/operation-lock.d.ts +2 -0
- package/dist/services/turso/operation-lock.js +61 -0
- package/dist/services/turso/ready.d.ts +2 -0
- package/dist/services/turso/ready.js +36 -0
- package/dist/services/turso/shard-manager.d.ts +38 -0
- package/dist/services/turso/shard-manager.js +496 -0
- package/dist/services/turso/sqlite-handle-release.d.ts +16 -0
- package/dist/services/turso/sqlite-handle-release.js +56 -0
- package/dist/services/turso/turso-db.d.ts +18 -0
- package/dist/services/turso/turso-db.js +53 -0
- package/dist/services/turso/types.d.ts +42 -0
- package/dist/services/turso/types.js +1 -0
- package/dist/services/turso/vector-search.d.ts +41 -0
- package/dist/services/turso/vector-search.js +384 -0
- package/dist/services/turso/vector-utils.d.ts +7 -0
- package/dist/services/turso/vector-utils.js +67 -0
- package/dist/services/user-memory-learning.d.ts +97 -0
- package/dist/services/user-memory-learning.js +673 -0
- package/dist/services/user-profile/ai-cleanup.d.ts +58 -0
- package/dist/services/user-profile/ai-cleanup.js +486 -0
- package/dist/services/user-profile/profile-context.d.ts +1 -0
- package/dist/services/user-profile/profile-context.js +105 -0
- package/dist/services/user-profile/profile-utils.d.ts +2 -0
- package/dist/services/user-profile/profile-utils.js +45 -0
- package/dist/services/user-profile/types.d.ts +92 -0
- package/dist/services/user-profile/types.js +1 -0
- package/dist/services/user-profile/user-profile-manager.d.ts +65 -0
- package/dist/services/user-profile/user-profile-manager.js +1660 -0
- package/dist/services/user-prompt/user-prompt-manager.d.ts +53 -0
- package/dist/services/user-prompt/user-prompt-manager.js +303 -0
- package/dist/services/web-api-auth.d.ts +3 -0
- package/dist/services/web-api-auth.js +25 -0
- package/dist/services/web-auth.d.ts +46 -0
- package/dist/services/web-auth.js +105 -0
- package/dist/services/web-server.d.ts +57 -0
- package/dist/services/web-server.js +659 -0
- package/dist/shared/api/index.d.ts +4 -0
- package/dist/shared/api/index.js +2 -0
- package/dist/shared/api/portability-schemas.d.ts +56 -0
- package/dist/shared/api/portability-schemas.js +39 -0
- package/dist/shared/api/schemas.d.ts +295 -0
- package/dist/shared/api/schemas.js +134 -0
- package/dist/shared/api/types.d.ts +28 -0
- package/dist/shared/api/types.js +1 -0
- package/dist/types/index.d.ts +27 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/context-limit.d.ts +10 -0
- package/dist/utils/context-limit.js +43 -0
- package/dist/utils/math.d.ts +7 -0
- package/dist/utils/math.js +48 -0
- package/dist/utils/profile.d.ts +2 -0
- package/dist/utils/profile.js +15 -0
- package/dist/v2/adapter.d.ts +5 -0
- package/dist/v2/adapter.js +218 -0
- package/dist/v2/legacy-client.d.ts +15 -0
- package/dist/v2/legacy-client.js +257 -0
- package/dist/v2/memory-bridge.d.ts +18 -0
- package/dist/v2/memory-bridge.js +29 -0
- package/dist/v2/plugin.d.ts +3 -0
- package/dist/v2/plugin.js +24 -0
- package/dist/web/assets/index-DPjEpD1h.css +2 -0
- package/dist/web/assets/index-do26c4JJ.js +122 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/index.html +14 -0
- package/dist/web/omms-icon.png +0 -0
- package/package.json +138 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CaptureToolCall } from "./host.js";
|
|
2
|
+
export declare function getAutoCaptureMarkdownBudget(totalRequestBytes?: number): number;
|
|
3
|
+
export declare function buildBoundedSummaryPrompt(context: string, systemPrompt: string, schema: unknown, totalRequestBytes?: number): string;
|
|
4
|
+
export declare function buildMarkdownContext(userPrompt: string, textResponses: string[], toolCalls: CaptureToolCall[], latestMemory: string | null, maxContextBytes?: number): string;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { CONFIG } from "../config.js";
|
|
2
|
+
import { truncateToMaxBytes, utf8ByteLength } from "../utils/context-limit.js";
|
|
3
|
+
const DEFAULT_AUTO_CAPTURE_MAX_CONTEXT_BYTES = 131072;
|
|
4
|
+
const CONTEXT_TRUNCATION_MARKER = "\n[... truncated to autoCaptureMaxContextBytes ...]\n";
|
|
5
|
+
const SUMMARY_REQUEST_OVERHEAD_BYTES = 1024;
|
|
6
|
+
const SUMMARY_OUTPUT_RESERVE_BYTES = 16384;
|
|
7
|
+
const SUMMARY_ANALYSIS_SUFFIX = 'Analyze this conversation. If it contains technical work (code, bugs, features, decisions), create a concise summary and relevant tags. If it\'s non-technical (greetings, casual chat, incomplete requests), return type="skip" with empty summary.';
|
|
8
|
+
function fitTextResponses(textResponses, maxBytes) {
|
|
9
|
+
if (textResponses.length === 0 || maxBytes <= 0)
|
|
10
|
+
return "";
|
|
11
|
+
const separator = "\n\n";
|
|
12
|
+
const separatorBytes = utf8ByteLength(separator);
|
|
13
|
+
const joined = textResponses.join(separator);
|
|
14
|
+
if (utf8ByteLength(joined) <= maxBytes)
|
|
15
|
+
return joined;
|
|
16
|
+
const kept = [];
|
|
17
|
+
let usedBytes = 0;
|
|
18
|
+
for (let i = textResponses.length - 1; i >= 0; i--) {
|
|
19
|
+
const response = textResponses[i] ?? "";
|
|
20
|
+
const responseBytes = utf8ByteLength(response);
|
|
21
|
+
const extraSeparator = kept.length > 0 ? separatorBytes : 0;
|
|
22
|
+
const needed = responseBytes + extraSeparator;
|
|
23
|
+
if (usedBytes + needed <= maxBytes) {
|
|
24
|
+
kept.unshift(response);
|
|
25
|
+
usedBytes += needed;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const remaining = maxBytes - usedBytes - extraSeparator;
|
|
29
|
+
if (remaining > utf8ByteLength(CONTEXT_TRUNCATION_MARKER)) {
|
|
30
|
+
kept.unshift(truncateToMaxBytes(response, remaining, CONTEXT_TRUNCATION_MARKER));
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
return kept.join(separator);
|
|
35
|
+
}
|
|
36
|
+
function joinSections(sections) {
|
|
37
|
+
return sections.join("\n");
|
|
38
|
+
}
|
|
39
|
+
export function getAutoCaptureMarkdownBudget(totalRequestBytes = CONFIG.autoCaptureMaxContextBytes ??
|
|
40
|
+
DEFAULT_AUTO_CAPTURE_MAX_CONTEXT_BYTES) {
|
|
41
|
+
const requestReserve = Math.min(24576, Math.floor(totalRequestBytes * 0.25));
|
|
42
|
+
return Math.max(4096, totalRequestBytes - requestReserve);
|
|
43
|
+
}
|
|
44
|
+
export function buildBoundedSummaryPrompt(context, systemPrompt, schema, totalRequestBytes = CONFIG.autoCaptureMaxContextBytes ??
|
|
45
|
+
DEFAULT_AUTO_CAPTURE_MAX_CONTEXT_BYTES) {
|
|
46
|
+
const schemaBytes = utf8ByteLength(JSON.stringify(schema));
|
|
47
|
+
const outputReserve = Math.min(SUMMARY_OUTPUT_RESERVE_BYTES, Math.floor(totalRequestBytes * 0.125));
|
|
48
|
+
const userBudget = Math.max(0, totalRequestBytes -
|
|
49
|
+
utf8ByteLength(systemPrompt) -
|
|
50
|
+
schemaBytes -
|
|
51
|
+
outputReserve -
|
|
52
|
+
SUMMARY_REQUEST_OVERHEAD_BYTES);
|
|
53
|
+
return truncateToMaxBytes(`${context}\n\n${SUMMARY_ANALYSIS_SUFFIX}`, userBudget, CONTEXT_TRUNCATION_MARKER);
|
|
54
|
+
}
|
|
55
|
+
export function buildMarkdownContext(userPrompt, textResponses, toolCalls, latestMemory, maxContextBytes = CONFIG.autoCaptureMaxContextBytes ??
|
|
56
|
+
DEFAULT_AUTO_CAPTURE_MAX_CONTEXT_BYTES) {
|
|
57
|
+
const memorySections = [];
|
|
58
|
+
if (latestMemory) {
|
|
59
|
+
memorySections.push("## Previous Memory Context");
|
|
60
|
+
memorySections.push("---");
|
|
61
|
+
memorySections.push(latestMemory);
|
|
62
|
+
memorySections.push("---\n");
|
|
63
|
+
}
|
|
64
|
+
const toolsSections = [];
|
|
65
|
+
if (toolCalls.length > 0) {
|
|
66
|
+
toolsSections.push("## Tools Used");
|
|
67
|
+
toolsSections.push("---");
|
|
68
|
+
for (const tool of toolCalls) {
|
|
69
|
+
toolsSections.push(tool.input ? `- ${tool.name}(${tool.input})` : `- ${tool.name}`);
|
|
70
|
+
}
|
|
71
|
+
toolsSections.push("---\n");
|
|
72
|
+
}
|
|
73
|
+
const userWrapper = ["## User Request", "---", "", "---\n"];
|
|
74
|
+
const aiWrapper = textResponses.length > 0 ? ["## AI Response", "---", "", "---\n"] : [];
|
|
75
|
+
const skeletonWithoutBodies = joinSections([
|
|
76
|
+
...memorySections,
|
|
77
|
+
...userWrapper,
|
|
78
|
+
...aiWrapper,
|
|
79
|
+
...toolsSections,
|
|
80
|
+
]);
|
|
81
|
+
const skeletonBytes = utf8ByteLength(skeletonWithoutBodies);
|
|
82
|
+
let userBudget = Math.max(0, maxContextBytes - skeletonBytes);
|
|
83
|
+
if (textResponses.length > 0 && userBudget > 1024) {
|
|
84
|
+
const preferredAiFloor = Math.min(4096, Math.floor(maxContextBytes * 0.25));
|
|
85
|
+
userBudget = Math.max(256, userBudget - preferredAiFloor);
|
|
86
|
+
}
|
|
87
|
+
const boundedUser = utf8ByteLength(userPrompt) <= userBudget
|
|
88
|
+
? userPrompt
|
|
89
|
+
: truncateToMaxBytes(userPrompt, userBudget, CONTEXT_TRUNCATION_MARKER);
|
|
90
|
+
const prefix = joinSections([
|
|
91
|
+
...memorySections,
|
|
92
|
+
"## User Request",
|
|
93
|
+
"---",
|
|
94
|
+
boundedUser,
|
|
95
|
+
"---\n",
|
|
96
|
+
...toolsSections,
|
|
97
|
+
]);
|
|
98
|
+
if (textResponses.length === 0) {
|
|
99
|
+
if (utf8ByteLength(prefix) <= maxContextBytes)
|
|
100
|
+
return prefix;
|
|
101
|
+
return truncateToMaxBytes(prefix, maxContextBytes, CONTEXT_TRUNCATION_MARKER);
|
|
102
|
+
}
|
|
103
|
+
const prefixWithoutTools = joinSections([
|
|
104
|
+
...memorySections,
|
|
105
|
+
"## User Request",
|
|
106
|
+
"---",
|
|
107
|
+
boundedUser,
|
|
108
|
+
"---\n",
|
|
109
|
+
]);
|
|
110
|
+
const toolsBlock = toolsSections.length > 0 ? "\n" + joinSections(toolsSections) : "";
|
|
111
|
+
const aiWrapperBytes = utf8ByteLength(joinSections(["## AI Response", "---", "", "---\n"]));
|
|
112
|
+
const aiBudget = Math.max(0, maxContextBytes -
|
|
113
|
+
utf8ByteLength(prefixWithoutTools) -
|
|
114
|
+
utf8ByteLength(toolsBlock) -
|
|
115
|
+
aiWrapperBytes);
|
|
116
|
+
const boundedAi = fitTextResponses(textResponses, aiBudget);
|
|
117
|
+
const result = joinSections([
|
|
118
|
+
...memorySections,
|
|
119
|
+
"## User Request",
|
|
120
|
+
"---",
|
|
121
|
+
boundedUser,
|
|
122
|
+
"---\n",
|
|
123
|
+
"## AI Response",
|
|
124
|
+
"---",
|
|
125
|
+
boundedAi,
|
|
126
|
+
"---\n",
|
|
127
|
+
...toolsSections,
|
|
128
|
+
]);
|
|
129
|
+
if (utf8ByteLength(result) <= maxContextBytes)
|
|
130
|
+
return result;
|
|
131
|
+
return truncateToMaxBytes(result, maxContextBytes, CONTEXT_TRUNCATION_MARKER);
|
|
132
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CaptureConversation, CapturePromptContext, CaptureProvenance, CaptureSummaryProvider } from "./host.js";
|
|
2
|
+
export interface CaptureWorkUnit extends CaptureProvenance, CaptureConversation {
|
|
3
|
+
projectDirectory: string;
|
|
4
|
+
userPrompt: string;
|
|
5
|
+
promptId?: string;
|
|
6
|
+
prompt?: CapturePromptContext;
|
|
7
|
+
}
|
|
8
|
+
export type CaptureResult = {
|
|
9
|
+
status: "captured";
|
|
10
|
+
memoryId: string;
|
|
11
|
+
} | {
|
|
12
|
+
status: "skipped";
|
|
13
|
+
type?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function captureConversation(workUnit: CaptureWorkUnit, provider: CaptureSummaryProvider): Promise<CaptureResult>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { memoryClient } from "../services/client.js";
|
|
2
|
+
import { getTags } from "../services/tags.js";
|
|
3
|
+
import { buildMarkdownContext, getAutoCaptureMarkdownBudget } from "./capture-context.js";
|
|
4
|
+
async function getLatestProjectMemory(containerTag) {
|
|
5
|
+
try {
|
|
6
|
+
const result = await memoryClient.listMemories(containerTag, 1);
|
|
7
|
+
if (!result.success || result.memories.length === 0)
|
|
8
|
+
return null;
|
|
9
|
+
const latest = result.memories[0];
|
|
10
|
+
if (!latest)
|
|
11
|
+
return null;
|
|
12
|
+
return latest.summary.length <= 500 ? latest.summary : latest.summary.substring(0, 500) + "...";
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function captureConversation(workUnit, provider) {
|
|
19
|
+
const tags = getTags(workUnit.projectDirectory);
|
|
20
|
+
const latestMemory = await getLatestProjectMemory(tags.project.tag);
|
|
21
|
+
const context = buildMarkdownContext(workUnit.userPrompt, workUnit.textResponses, workUnit.toolCalls, latestMemory, getAutoCaptureMarkdownBudget());
|
|
22
|
+
let summaryResult;
|
|
23
|
+
try {
|
|
24
|
+
summaryResult = await provider.summarize({
|
|
25
|
+
context,
|
|
26
|
+
sessionId: workUnit.hostSessionId,
|
|
27
|
+
projectDirectory: workUnit.projectDirectory,
|
|
28
|
+
userPrompt: workUnit.userPrompt,
|
|
29
|
+
prompt: workUnit.prompt,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
+
throw new Error(`Summary generation failed: ${message}`, { cause: error });
|
|
35
|
+
}
|
|
36
|
+
if (!summaryResult || summaryResult.type === "skip") {
|
|
37
|
+
return { status: "skipped", type: summaryResult?.type };
|
|
38
|
+
}
|
|
39
|
+
const summaryWithTags = summaryResult.tags.length > 0
|
|
40
|
+
? `${summaryResult.summary}\n\nTags: ${summaryResult.tags.join(", ")}`
|
|
41
|
+
: summaryResult.summary;
|
|
42
|
+
const source = workUnit.sourceType === "history-import" ? "import" : "auto-capture";
|
|
43
|
+
const result = await memoryClient.addMemory(summaryWithTags, tags.project.tag, {
|
|
44
|
+
source,
|
|
45
|
+
type: summaryResult.type,
|
|
46
|
+
tags: summaryResult.tags,
|
|
47
|
+
sessionID: workUnit.hostSessionId,
|
|
48
|
+
promptId: workUnit.promptId,
|
|
49
|
+
captureTimestamp: Date.now(),
|
|
50
|
+
host: workUnit.host,
|
|
51
|
+
hostSessionId: workUnit.hostSessionId,
|
|
52
|
+
sourceType: workUnit.sourceType,
|
|
53
|
+
sourceEntryIds: workUnit.sourceEntryIds,
|
|
54
|
+
sourceTimestamp: workUnit.sourceTimestamp,
|
|
55
|
+
sourceFile: workUnit.sourceFile,
|
|
56
|
+
importId: workUnit.importId,
|
|
57
|
+
displayName: tags.project.displayName,
|
|
58
|
+
userName: tags.project.userName,
|
|
59
|
+
userEmail: tags.project.userEmail,
|
|
60
|
+
projectPath: tags.project.projectPath,
|
|
61
|
+
projectName: tags.project.projectName,
|
|
62
|
+
gitRepoUrl: tags.project.gitRepoUrl,
|
|
63
|
+
});
|
|
64
|
+
if (!result.success) {
|
|
65
|
+
throw new Error(`Memory persistence failed: ${result.error || "database write failed"}`);
|
|
66
|
+
}
|
|
67
|
+
return { status: "captured", memoryId: result.id };
|
|
68
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CaptureSummary } from "./host.js";
|
|
3
|
+
/**
|
|
4
|
+
* Shared structured-extraction contract for automatic capture.
|
|
5
|
+
*
|
|
6
|
+
* Both host adapters (OpenCode provider path and the Pi model bridge) request
|
|
7
|
+
* the same summary shape and validate model output against this schema so the
|
|
8
|
+
* downstream capture pipeline always receives well-formed results.
|
|
9
|
+
*/
|
|
10
|
+
export declare const captureSummarySchema: z.ZodObject<{
|
|
11
|
+
summary: z.ZodString;
|
|
12
|
+
type: z.ZodString;
|
|
13
|
+
tags: z.ZodArray<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
/**
|
|
16
|
+
* JSON schema description embedded into the summary request prompt. Kept as a
|
|
17
|
+
* plain object so it can be passed to hosts that take a tool-schema style
|
|
18
|
+
* description (OpenCode fallback path, Pi bridge prompt).
|
|
19
|
+
*/
|
|
20
|
+
export declare const captureSummaryToolSchema: {
|
|
21
|
+
type: "object";
|
|
22
|
+
properties: {
|
|
23
|
+
summary: {
|
|
24
|
+
type: string;
|
|
25
|
+
description: string;
|
|
26
|
+
};
|
|
27
|
+
type: {
|
|
28
|
+
type: string;
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
tags: {
|
|
32
|
+
type: string;
|
|
33
|
+
items: {
|
|
34
|
+
type: string;
|
|
35
|
+
};
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
required: string[];
|
|
40
|
+
};
|
|
41
|
+
export declare function buildCaptureSystemPrompt(languageName: string): string;
|
|
42
|
+
/** Upper bound for LLM-inferred preference confidence (0–1 scale). */
|
|
43
|
+
export declare const USER_PROFILE_LLM_CONFIDENCE_MAX = 1;
|
|
44
|
+
/**
|
|
45
|
+
* Shared user-profile analysis schema used by OpenCode structured output,
|
|
46
|
+
* the external fallback provider, and the Pi model bridge.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createUserProfileAnalysisSchema(z: typeof import("zod").z): z.ZodObject<{
|
|
49
|
+
preferences: z.ZodArray<z.ZodObject<{
|
|
50
|
+
category: z.ZodString;
|
|
51
|
+
description: z.ZodString;
|
|
52
|
+
confidence: z.ZodNumber;
|
|
53
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
54
|
+
}, z.core.$strip>>;
|
|
55
|
+
patterns: z.ZodArray<z.ZodObject<{
|
|
56
|
+
category: z.ZodString;
|
|
57
|
+
description: z.ZodString;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
workflows: z.ZodArray<z.ZodObject<{
|
|
60
|
+
description: z.ZodString;
|
|
61
|
+
steps: z.ZodArray<z.ZodString>;
|
|
62
|
+
}, z.core.$strip>>;
|
|
63
|
+
validations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
64
|
+
index: z.ZodNumber;
|
|
65
|
+
verdict: z.ZodEnum<{
|
|
66
|
+
confirmed: "confirmed";
|
|
67
|
+
contradicted: "contradicted";
|
|
68
|
+
no_evidence: "no_evidence";
|
|
69
|
+
inaccurate: "inaccurate";
|
|
70
|
+
oversimplified: "oversimplified";
|
|
71
|
+
}>;
|
|
72
|
+
reason: z.ZodString;
|
|
73
|
+
}, z.core.$strip>>>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
export declare function extractJsonObject(raw: string): unknown;
|
|
76
|
+
/**
|
|
77
|
+
* Parse and validate a model reply as a capture summary. Tolerates fenced code
|
|
78
|
+
* blocks and surrounding prose. Returns null when no valid payload is present.
|
|
79
|
+
*/
|
|
80
|
+
export declare function parseCaptureSummary(raw: string): CaptureSummary | null;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Shared structured-extraction contract for automatic capture.
|
|
4
|
+
*
|
|
5
|
+
* Both host adapters (OpenCode provider path and the Pi model bridge) request
|
|
6
|
+
* the same summary shape and validate model output against this schema so the
|
|
7
|
+
* downstream capture pipeline always receives well-formed results.
|
|
8
|
+
*/
|
|
9
|
+
export const captureSummarySchema = z.object({
|
|
10
|
+
summary: z.string(),
|
|
11
|
+
type: z.string(),
|
|
12
|
+
tags: z.array(z.string()),
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* JSON schema description embedded into the summary request prompt. Kept as a
|
|
16
|
+
* plain object so it can be passed to hosts that take a tool-schema style
|
|
17
|
+
* description (OpenCode fallback path, Pi bridge prompt).
|
|
18
|
+
*/
|
|
19
|
+
export const captureSummaryToolSchema = {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
summary: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Markdown-formatted summary of the conversation",
|
|
25
|
+
},
|
|
26
|
+
type: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Type of memory: 'skip' for non-technical conversations, or technical type (feature, bug-fix, refactor, analysis, configuration, discussion, other)",
|
|
29
|
+
},
|
|
30
|
+
tags: {
|
|
31
|
+
type: "array",
|
|
32
|
+
items: { type: "string" },
|
|
33
|
+
description: "List of 2-4 technical tags related to the memory",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
required: ["summary", "type", "tags"],
|
|
37
|
+
};
|
|
38
|
+
export function buildCaptureSystemPrompt(languageName) {
|
|
39
|
+
return `You are a technical memory recorder for a software development project.
|
|
40
|
+
|
|
41
|
+
RULES:
|
|
42
|
+
1. ONLY capture technical work (code, bugs, features, architecture, config)
|
|
43
|
+
2. SKIP non-technical by returning type="skip"
|
|
44
|
+
3. NO meta-commentary or behavior analysis
|
|
45
|
+
4. Include specific file names, functions, technical details
|
|
46
|
+
5. Generate 2-4 technical tags (e.g., "react", "auth", "bug-fix")
|
|
47
|
+
6. You MUST write the summary in ${languageName}.
|
|
48
|
+
|
|
49
|
+
FORMAT:
|
|
50
|
+
## Request
|
|
51
|
+
[1-2 sentences: what was requested, in ${languageName}]
|
|
52
|
+
|
|
53
|
+
## Outcome
|
|
54
|
+
[1-2 sentences: what was done, include files/functions, in ${languageName}]
|
|
55
|
+
|
|
56
|
+
SKIP if: greetings, casual chat, no code/decisions made
|
|
57
|
+
CAPTURE if: code changed, bug fixed, feature added, decision made`;
|
|
58
|
+
}
|
|
59
|
+
/** Upper bound for LLM-inferred preference confidence (0–1 scale). */
|
|
60
|
+
export const USER_PROFILE_LLM_CONFIDENCE_MAX = 1;
|
|
61
|
+
/**
|
|
62
|
+
* Shared user-profile analysis schema used by OpenCode structured output,
|
|
63
|
+
* the external fallback provider, and the Pi model bridge.
|
|
64
|
+
*/
|
|
65
|
+
export function createUserProfileAnalysisSchema(z) {
|
|
66
|
+
return z.object({
|
|
67
|
+
preferences: z.array(z.object({
|
|
68
|
+
category: z.string(),
|
|
69
|
+
description: z.string(),
|
|
70
|
+
confidence: z.number().min(0).max(USER_PROFILE_LLM_CONFIDENCE_MAX),
|
|
71
|
+
evidence: z.array(z.string()),
|
|
72
|
+
})),
|
|
73
|
+
patterns: z.array(z.object({
|
|
74
|
+
category: z.string(),
|
|
75
|
+
description: z.string(),
|
|
76
|
+
})),
|
|
77
|
+
workflows: z.array(z.object({
|
|
78
|
+
description: z.string(),
|
|
79
|
+
steps: z.array(z.string()),
|
|
80
|
+
})),
|
|
81
|
+
validations: z
|
|
82
|
+
.array(z.object({
|
|
83
|
+
index: z.number(),
|
|
84
|
+
verdict: z.enum([
|
|
85
|
+
"confirmed",
|
|
86
|
+
"contradicted",
|
|
87
|
+
"no_evidence",
|
|
88
|
+
"inaccurate",
|
|
89
|
+
"oversimplified",
|
|
90
|
+
]),
|
|
91
|
+
reason: z.string(),
|
|
92
|
+
}))
|
|
93
|
+
.optional(),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
export function extractJsonObject(raw) {
|
|
97
|
+
const trimmed = raw.trim();
|
|
98
|
+
if (trimmed.startsWith("{")) {
|
|
99
|
+
try {
|
|
100
|
+
return JSON.parse(trimmed);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// fall through to fenced-block extraction
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
107
|
+
if (fenced?.[1]) {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(fenced[1].trim());
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const braceStart = trimmed.indexOf("{");
|
|
116
|
+
const braceEnd = trimmed.lastIndexOf("}");
|
|
117
|
+
if (braceStart !== -1 && braceEnd > braceStart) {
|
|
118
|
+
try {
|
|
119
|
+
return JSON.parse(trimmed.slice(braceStart, braceEnd + 1));
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Parse and validate a model reply as a capture summary. Tolerates fenced code
|
|
129
|
+
* blocks and surrounding prose. Returns null when no valid payload is present.
|
|
130
|
+
*/
|
|
131
|
+
export function parseCaptureSummary(raw) {
|
|
132
|
+
const parsed = captureSummarySchema.safeParse(extractJsonObject(raw));
|
|
133
|
+
if (!parsed.success)
|
|
134
|
+
return null;
|
|
135
|
+
return {
|
|
136
|
+
summary: parsed.data.summary,
|
|
137
|
+
type: parsed.data.type,
|
|
138
|
+
tags: parsed.data.tags.map((tag) => tag.toLowerCase().trim()).filter(Boolean),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { MemoryHost, MemorySourceType } from "../types/index.js";
|
|
2
|
+
export interface CaptureToolCall {
|
|
3
|
+
name: string;
|
|
4
|
+
input: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CaptureConversation {
|
|
7
|
+
textResponses: string[];
|
|
8
|
+
toolCalls: CaptureToolCall[];
|
|
9
|
+
sourceEntryIds?: string[];
|
|
10
|
+
sourceTimestamp?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface CapturePromptContext {
|
|
13
|
+
id?: string;
|
|
14
|
+
providerId?: string | null;
|
|
15
|
+
modelId?: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface CaptureSummary {
|
|
18
|
+
summary: string;
|
|
19
|
+
type: string;
|
|
20
|
+
tags: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface CaptureSummaryRequest {
|
|
23
|
+
context: string;
|
|
24
|
+
sessionId: string;
|
|
25
|
+
projectDirectory: string;
|
|
26
|
+
userPrompt: string;
|
|
27
|
+
prompt?: CapturePromptContext;
|
|
28
|
+
}
|
|
29
|
+
export interface CaptureSummaryProvider {
|
|
30
|
+
summarize(request: CaptureSummaryRequest): Promise<CaptureSummary | null>;
|
|
31
|
+
}
|
|
32
|
+
export interface AutoCaptureNotification {
|
|
33
|
+
title: string;
|
|
34
|
+
message: string;
|
|
35
|
+
variant: "success" | "warning" | "error" | "info";
|
|
36
|
+
duration: number;
|
|
37
|
+
}
|
|
38
|
+
export interface AutoCaptureHost extends CaptureSummaryProvider {
|
|
39
|
+
readonly host: MemoryHost;
|
|
40
|
+
isCaptureReady(): boolean;
|
|
41
|
+
getConversation(sessionId: string, promptMessageId: string): Promise<CaptureConversation | null>;
|
|
42
|
+
notify?(notification: AutoCaptureNotification): Promise<void> | void;
|
|
43
|
+
}
|
|
44
|
+
export interface CaptureProvenance {
|
|
45
|
+
host: MemoryHost;
|
|
46
|
+
hostSessionId: string;
|
|
47
|
+
sourceType: MemorySourceType;
|
|
48
|
+
sourceEntryIds?: string[];
|
|
49
|
+
sourceTimestamp?: number;
|
|
50
|
+
sourceFile?: string;
|
|
51
|
+
importId?: string;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type MemoryScope } from "../services/client.js";
|
|
2
|
+
import { getTags } from "../services/tags.js";
|
|
3
|
+
import type { MemoryHost, MemoryType } from "../types/index.js";
|
|
4
|
+
export type MemoryOperationMode = "add" | "search" | "profile" | "list" | "forget" | "help" | "migrate" | "list-shards" | "export" | "import";
|
|
5
|
+
export interface MemoryOperationArgs {
|
|
6
|
+
mode?: MemoryOperationMode;
|
|
7
|
+
content?: string;
|
|
8
|
+
query?: string;
|
|
9
|
+
tags?: string;
|
|
10
|
+
type?: MemoryType;
|
|
11
|
+
memoryId?: string;
|
|
12
|
+
limit?: number;
|
|
13
|
+
scope?: MemoryScope;
|
|
14
|
+
fromPath?: string;
|
|
15
|
+
fromHash?: string;
|
|
16
|
+
outputPath?: string;
|
|
17
|
+
inputPath?: string;
|
|
18
|
+
dryRun?: boolean;
|
|
19
|
+
allowLinkedSource?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface MemoryOperationContext {
|
|
22
|
+
directory: string;
|
|
23
|
+
tags?: ReturnType<typeof getTags>;
|
|
24
|
+
host?: MemoryHost;
|
|
25
|
+
hostSessionId?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function executeMemoryOperation(args: MemoryOperationArgs, context: MemoryOperationContext): Promise<Record<string, unknown>>;
|