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,182 @@
|
|
|
1
|
+
import { BaseAIProvider, applySafeExtraParams } from "./base-provider.js";
|
|
2
|
+
import { AISessionManager } from "../session/ai-session-manager.js";
|
|
3
|
+
import { ToolSchemaConverter } from "../tools/tool-schema.js";
|
|
4
|
+
import { log } from "../../logger.js";
|
|
5
|
+
export class OpenAIResponsesProvider extends BaseAIProvider {
|
|
6
|
+
aiSessionManager;
|
|
7
|
+
constructor(config, aiSessionManager) {
|
|
8
|
+
super(config);
|
|
9
|
+
this.aiSessionManager = aiSessionManager;
|
|
10
|
+
}
|
|
11
|
+
getProviderName() {
|
|
12
|
+
return "openai-responses";
|
|
13
|
+
}
|
|
14
|
+
supportsSession() {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
async executeToolCall(systemPrompt, userPrompt, toolSchema, sessionId) {
|
|
18
|
+
let session = await this.aiSessionManager.getSession(sessionId, "openai-responses");
|
|
19
|
+
if (!session) {
|
|
20
|
+
session = await this.aiSessionManager.createSession({
|
|
21
|
+
provider: "openai-responses",
|
|
22
|
+
sessionId,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
let conversationId = session.conversationId;
|
|
26
|
+
let currentPrompt = userPrompt;
|
|
27
|
+
let iterations = 0;
|
|
28
|
+
const maxIterations = this.config.maxIterations ?? 5;
|
|
29
|
+
const iterationTimeout = this.config.iterationTimeout ?? 30000;
|
|
30
|
+
while (iterations < maxIterations) {
|
|
31
|
+
iterations++;
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timeout = setTimeout(() => controller.abort(), iterationTimeout);
|
|
34
|
+
try {
|
|
35
|
+
const tool = ToolSchemaConverter.toResponsesAPI(toolSchema);
|
|
36
|
+
const requestBody = {
|
|
37
|
+
model: this.config.model,
|
|
38
|
+
input: currentPrompt,
|
|
39
|
+
tools: [tool],
|
|
40
|
+
};
|
|
41
|
+
if (conversationId) {
|
|
42
|
+
requestBody.conversation = conversationId;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
requestBody.instructions = systemPrompt;
|
|
46
|
+
}
|
|
47
|
+
if (this.config.extraParams) {
|
|
48
|
+
applySafeExtraParams(requestBody, this.config.extraParams);
|
|
49
|
+
}
|
|
50
|
+
const response = await fetch(`${this.config.apiUrl}/responses`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify(requestBody),
|
|
57
|
+
signal: controller.signal,
|
|
58
|
+
});
|
|
59
|
+
clearTimeout(timeout);
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const errorText = await response.text().catch(() => response.statusText);
|
|
62
|
+
log("OpenAI Responses API error", {
|
|
63
|
+
provider: this.getProviderName(),
|
|
64
|
+
model: this.config.model,
|
|
65
|
+
status: response.status,
|
|
66
|
+
error: errorText,
|
|
67
|
+
iteration: iterations,
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
error: `API error: ${response.status} - ${errorText}`,
|
|
72
|
+
iterations,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const data = (await response.json());
|
|
76
|
+
conversationId = data.conversation || conversationId;
|
|
77
|
+
if (iterations === 1) {
|
|
78
|
+
const userSeq = (await this.aiSessionManager.getLastSequence(session.id)) + 1;
|
|
79
|
+
await this.aiSessionManager.addMessage({
|
|
80
|
+
aiSessionId: session.id,
|
|
81
|
+
sequence: userSeq,
|
|
82
|
+
role: "user",
|
|
83
|
+
content: userPrompt,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const toolCall = this.extractToolCall(data, toolSchema.function.name);
|
|
87
|
+
if (toolCall) {
|
|
88
|
+
await this.aiSessionManager.updateSession(sessionId, "openai-responses", {
|
|
89
|
+
conversationId,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
data: this.validateResponse(toolCall),
|
|
94
|
+
iterations,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
currentPrompt = this.buildRetryPrompt(data);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
clearTimeout(timeout);
|
|
101
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: `API request timeout (${this.config.iterationTimeout}ms)`,
|
|
105
|
+
iterations,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: String(error),
|
|
111
|
+
iterations,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
success: false,
|
|
117
|
+
error: `Max iterations (${this.config.maxIterations}) reached without tool call`,
|
|
118
|
+
iterations,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
extractToolCall(data, expectedToolName) {
|
|
122
|
+
if (!data.output || !Array.isArray(data.output)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
for (const item of data.output) {
|
|
126
|
+
if (item.type === "function_call" && item.name === expectedToolName) {
|
|
127
|
+
if (item.arguments) {
|
|
128
|
+
try {
|
|
129
|
+
const parsed = JSON.parse(item.arguments);
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
log("Failed to parse function call arguments", {
|
|
134
|
+
error: String(error),
|
|
135
|
+
toolName: item.name,
|
|
136
|
+
arguments: item.arguments,
|
|
137
|
+
});
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
log("Function call found but no arguments", {
|
|
143
|
+
toolName: item.name,
|
|
144
|
+
callId: item.call_id,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
buildRetryPrompt(data) {
|
|
152
|
+
let assistantResponse = "";
|
|
153
|
+
if (data.output && Array.isArray(data.output)) {
|
|
154
|
+
for (const item of data.output) {
|
|
155
|
+
if (item.type === "message" && item.content) {
|
|
156
|
+
assistantResponse =
|
|
157
|
+
typeof item.content === "string" ? item.content : JSON.stringify(item.content);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return `Previous response: ${assistantResponse}\n\nPlease use the save_memories tool to extract and save the memories from the conversation as instructed.`;
|
|
163
|
+
}
|
|
164
|
+
validateResponse(data) {
|
|
165
|
+
if (!data || typeof data !== "object") {
|
|
166
|
+
throw new Error("Response is not an object");
|
|
167
|
+
}
|
|
168
|
+
if (Array.isArray(data)) {
|
|
169
|
+
throw new Error("Response cannot be an array");
|
|
170
|
+
}
|
|
171
|
+
const keys = Object.keys(data);
|
|
172
|
+
if (keys.length === 0) {
|
|
173
|
+
throw new Error("Response object is empty");
|
|
174
|
+
}
|
|
175
|
+
for (const key of keys) {
|
|
176
|
+
if (data[key] === undefined || data[key] === null) {
|
|
177
|
+
throw new Error(`Response field '${key}' is null or undefined`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { OpenAIChatCompletionProvider } from "./openai-chat-completion.js";
|
|
2
|
+
import type { ProviderConfig } from "./base-provider.js";
|
|
3
|
+
import type { AISessionManager } from "../session/ai-session-manager.js";
|
|
4
|
+
import type { AIProviderType } from "../session/session-types.js";
|
|
5
|
+
/** OrcaRouter OpenAI-compatible endpoint used when `memoryApiUrl` is omitted. */
|
|
6
|
+
export declare const ORCAROUTER_API_URL = "https://api.orcarouter.ai/v1";
|
|
7
|
+
/**
|
|
8
|
+
* Default model when `memoryModel` is omitted. `orcarouter/auto` is the
|
|
9
|
+
* gateway's routing alias — it picks a capable upstream model per request
|
|
10
|
+
* (including structured / tool-call output, which auto-capture relies on).
|
|
11
|
+
*/
|
|
12
|
+
export declare const ORCAROUTER_DEFAULT_MODEL = "orcarouter/auto";
|
|
13
|
+
/**
|
|
14
|
+
* OrcaRouter provider.
|
|
15
|
+
*
|
|
16
|
+
* [OrcaRouter](https://www.orcarouter.ai) is an OpenAI-compatible model
|
|
17
|
+
* gateway. It rejects bare model names, so the gateway requires namespaced
|
|
18
|
+
* model IDs such as `orcarouter/auto`, `deepseek/deepseek-v4-flash`, or
|
|
19
|
+
* `openai/gpt-5.5`. This provider reuses the OpenAI Chat Completions request
|
|
20
|
+
* handling and only overrides the resolved endpoint, the model resolution
|
|
21
|
+
* (validating the namespace), and the session provider tag, so OrcaRouter is
|
|
22
|
+
* distinguishable in the session store and diagnostics.
|
|
23
|
+
*
|
|
24
|
+
* Users configure it as:
|
|
25
|
+
* "memoryProvider": "orcarouter"
|
|
26
|
+
* "memoryApiKey": "<OrcaRouter API key>"
|
|
27
|
+
*
|
|
28
|
+
* `memoryApiUrl` and `memoryModel` are optional — they default to the gateway
|
|
29
|
+
* endpoint and `orcarouter/auto` respectively.
|
|
30
|
+
*/
|
|
31
|
+
export declare class OrcaRouterProvider extends OpenAIChatCompletionProvider {
|
|
32
|
+
constructor(config: ProviderConfig, aiSessionManager: AISessionManager);
|
|
33
|
+
getProviderName(): string;
|
|
34
|
+
protected sessionProviderTag(): AIProviderType;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the OpenAI-compatible endpoint.
|
|
37
|
+
*
|
|
38
|
+
* Defaults to the OrcaRouter gateway when `memoryApiUrl` is not configured,
|
|
39
|
+
* so a minimal config only needs `memoryProvider` + `memoryApiKey`.
|
|
40
|
+
*/
|
|
41
|
+
resolveEndpoint(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the model ID to send to the gateway.
|
|
44
|
+
*
|
|
45
|
+
* Defaults to the `orcarouter/auto` routing alias when `memoryModel` is not
|
|
46
|
+
* configured. OrcaRouter rejects bare model names (e.g. `gpt-4o-mini`), so a
|
|
47
|
+
* namespaced ID is required — fail with a helpful message instead of a
|
|
48
|
+
* gateway-side `model_not_found` error.
|
|
49
|
+
*/
|
|
50
|
+
resolveModel(): string;
|
|
51
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { OpenAIChatCompletionProvider } from "./openai-chat-completion.js";
|
|
2
|
+
/** OrcaRouter OpenAI-compatible endpoint used when `memoryApiUrl` is omitted. */
|
|
3
|
+
export const ORCAROUTER_API_URL = "https://api.orcarouter.ai/v1";
|
|
4
|
+
/**
|
|
5
|
+
* Default model when `memoryModel` is omitted. `orcarouter/auto` is the
|
|
6
|
+
* gateway's routing alias — it picks a capable upstream model per request
|
|
7
|
+
* (including structured / tool-call output, which auto-capture relies on).
|
|
8
|
+
*/
|
|
9
|
+
export const ORCAROUTER_DEFAULT_MODEL = "orcarouter/auto";
|
|
10
|
+
/**
|
|
11
|
+
* OrcaRouter provider.
|
|
12
|
+
*
|
|
13
|
+
* [OrcaRouter](https://www.orcarouter.ai) is an OpenAI-compatible model
|
|
14
|
+
* gateway. It rejects bare model names, so the gateway requires namespaced
|
|
15
|
+
* model IDs such as `orcarouter/auto`, `deepseek/deepseek-v4-flash`, or
|
|
16
|
+
* `openai/gpt-5.5`. This provider reuses the OpenAI Chat Completions request
|
|
17
|
+
* handling and only overrides the resolved endpoint, the model resolution
|
|
18
|
+
* (validating the namespace), and the session provider tag, so OrcaRouter is
|
|
19
|
+
* distinguishable in the session store and diagnostics.
|
|
20
|
+
*
|
|
21
|
+
* Users configure it as:
|
|
22
|
+
* "memoryProvider": "orcarouter"
|
|
23
|
+
* "memoryApiKey": "<OrcaRouter API key>"
|
|
24
|
+
*
|
|
25
|
+
* `memoryApiUrl` and `memoryModel` are optional — they default to the gateway
|
|
26
|
+
* endpoint and `orcarouter/auto` respectively.
|
|
27
|
+
*/
|
|
28
|
+
export class OrcaRouterProvider extends OpenAIChatCompletionProvider {
|
|
29
|
+
constructor(config, aiSessionManager) {
|
|
30
|
+
super(config, aiSessionManager);
|
|
31
|
+
}
|
|
32
|
+
getProviderName() {
|
|
33
|
+
return "orcarouter";
|
|
34
|
+
}
|
|
35
|
+
sessionProviderTag() {
|
|
36
|
+
return "orcarouter";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the OpenAI-compatible endpoint.
|
|
40
|
+
*
|
|
41
|
+
* Defaults to the OrcaRouter gateway when `memoryApiUrl` is not configured,
|
|
42
|
+
* so a minimal config only needs `memoryProvider` + `memoryApiKey`.
|
|
43
|
+
*/
|
|
44
|
+
resolveEndpoint() {
|
|
45
|
+
const base = (this.config.apiUrl || "").trim().replace(/\/+$/, "");
|
|
46
|
+
return base || ORCAROUTER_API_URL;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the model ID to send to the gateway.
|
|
50
|
+
*
|
|
51
|
+
* Defaults to the `orcarouter/auto` routing alias when `memoryModel` is not
|
|
52
|
+
* configured. OrcaRouter rejects bare model names (e.g. `gpt-4o-mini`), so a
|
|
53
|
+
* namespaced ID is required — fail with a helpful message instead of a
|
|
54
|
+
* gateway-side `model_not_found` error.
|
|
55
|
+
*/
|
|
56
|
+
resolveModel() {
|
|
57
|
+
const model = (this.config.model || "").trim();
|
|
58
|
+
if (!model) {
|
|
59
|
+
return ORCAROUTER_DEFAULT_MODEL;
|
|
60
|
+
}
|
|
61
|
+
if (!model.includes("/")) {
|
|
62
|
+
throw new Error(`OrcaRouter requires a namespaced memoryModel (e.g. "orcarouter/auto", "openai/gpt-5.5", "deepseek/deepseek-v4-flash"). Got: ${model}`);
|
|
63
|
+
}
|
|
64
|
+
return model;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AISession, SessionCreateParams, SessionUpdateParams, AIProviderType, AIMessage } from "./session-types.js";
|
|
2
|
+
export declare class AISessionManager {
|
|
3
|
+
private db;
|
|
4
|
+
private dbPath;
|
|
5
|
+
private readonly sessionRetentionMs;
|
|
6
|
+
private initPromise;
|
|
7
|
+
constructor();
|
|
8
|
+
reset(): void;
|
|
9
|
+
private initialize;
|
|
10
|
+
private ready;
|
|
11
|
+
private initDatabase;
|
|
12
|
+
getSession(sessionId: string, provider: AIProviderType): Promise<AISession | null>;
|
|
13
|
+
createSession(params: SessionCreateParams): Promise<AISession>;
|
|
14
|
+
updateSession(sessionId: string, provider: AIProviderType, updates: SessionUpdateParams): Promise<void>;
|
|
15
|
+
cleanupExpiredSessions(): Promise<number>;
|
|
16
|
+
deleteSession(sessionId: string, provider: AIProviderType): Promise<void>;
|
|
17
|
+
addMessage(message: Omit<AIMessage, "id" | "createdAt">): Promise<void>;
|
|
18
|
+
getMessages(aiSessionId: string): Promise<AIMessage[]>;
|
|
19
|
+
getLastSequence(aiSessionId: string): Promise<number>;
|
|
20
|
+
clearMessages(aiSessionId: string): Promise<void>;
|
|
21
|
+
private rowToSession;
|
|
22
|
+
private rowToMessage;
|
|
23
|
+
}
|
|
24
|
+
export declare const aiSessionManager: AISessionManager;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { tursoConnectionManager } from "../../turso/connection-manager.js";
|
|
3
|
+
import { CONFIG } from "../../../config.js";
|
|
4
|
+
const AI_SESSIONS_DB_NAME = "ai-sessions.db";
|
|
5
|
+
export class AISessionManager {
|
|
6
|
+
db = null;
|
|
7
|
+
dbPath;
|
|
8
|
+
sessionRetentionMs;
|
|
9
|
+
initPromise = null;
|
|
10
|
+
constructor() {
|
|
11
|
+
this.dbPath = join(CONFIG.storagePath, AI_SESSIONS_DB_NAME);
|
|
12
|
+
this.sessionRetentionMs = CONFIG.aiSessionRetentionDays * 24 * 60 * 60 * 1000;
|
|
13
|
+
}
|
|
14
|
+
reset() {
|
|
15
|
+
this.db = null;
|
|
16
|
+
this.initPromise = null;
|
|
17
|
+
this.dbPath = join(CONFIG.storagePath, AI_SESSIONS_DB_NAME);
|
|
18
|
+
}
|
|
19
|
+
async initialize() {
|
|
20
|
+
if (this.initPromise) {
|
|
21
|
+
return this.initPromise;
|
|
22
|
+
}
|
|
23
|
+
this.dbPath = join(CONFIG.storagePath, AI_SESSIONS_DB_NAME);
|
|
24
|
+
this.initPromise = (async () => {
|
|
25
|
+
try {
|
|
26
|
+
this.db = await tursoConnectionManager.getConnection(this.dbPath);
|
|
27
|
+
await this.initDatabase();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
this.initPromise = null;
|
|
31
|
+
this.db = null;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
35
|
+
return this.initPromise;
|
|
36
|
+
}
|
|
37
|
+
async ready() {
|
|
38
|
+
if (!this.db || !this.initPromise) {
|
|
39
|
+
await this.initialize();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
await this.initPromise;
|
|
43
|
+
}
|
|
44
|
+
if (!this.db) {
|
|
45
|
+
throw new Error("AISessionManager: database not initialized");
|
|
46
|
+
}
|
|
47
|
+
return this.db;
|
|
48
|
+
}
|
|
49
|
+
async initDatabase() {
|
|
50
|
+
const db = this.db;
|
|
51
|
+
await db.batch([
|
|
52
|
+
{
|
|
53
|
+
sql: `
|
|
54
|
+
CREATE TABLE IF NOT EXISTS ai_sessions (
|
|
55
|
+
id TEXT PRIMARY KEY,
|
|
56
|
+
provider TEXT NOT NULL,
|
|
57
|
+
session_id TEXT NOT NULL,
|
|
58
|
+
conversation_id TEXT,
|
|
59
|
+
metadata TEXT,
|
|
60
|
+
created_at INTEGER NOT NULL,
|
|
61
|
+
updated_at INTEGER NOT NULL,
|
|
62
|
+
expires_at INTEGER NOT NULL
|
|
63
|
+
)
|
|
64
|
+
`,
|
|
65
|
+
},
|
|
66
|
+
{ sql: "CREATE INDEX IF NOT EXISTS idx_ai_sessions_session_id ON ai_sessions(session_id)" },
|
|
67
|
+
{ sql: "CREATE INDEX IF NOT EXISTS idx_ai_sessions_expires_at ON ai_sessions(expires_at)" },
|
|
68
|
+
{ sql: "CREATE INDEX IF NOT EXISTS idx_ai_sessions_provider ON ai_sessions(provider)" },
|
|
69
|
+
{
|
|
70
|
+
sql: `
|
|
71
|
+
CREATE TABLE IF NOT EXISTS ai_messages (
|
|
72
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
73
|
+
ai_session_id TEXT NOT NULL,
|
|
74
|
+
sequence INTEGER NOT NULL,
|
|
75
|
+
role TEXT NOT NULL,
|
|
76
|
+
content TEXT NOT NULL,
|
|
77
|
+
tool_calls TEXT,
|
|
78
|
+
tool_call_id TEXT,
|
|
79
|
+
content_blocks TEXT,
|
|
80
|
+
created_at INTEGER NOT NULL,
|
|
81
|
+
FOREIGN KEY (ai_session_id) REFERENCES ai_sessions(id) ON DELETE CASCADE
|
|
82
|
+
)
|
|
83
|
+
`,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
sql: "CREATE INDEX IF NOT EXISTS idx_ai_messages_session ON ai_messages(ai_session_id, sequence)",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
sql: "CREATE INDEX IF NOT EXISTS idx_ai_messages_role ON ai_messages(ai_session_id, role)",
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
async getSession(sessionId, provider) {
|
|
94
|
+
const db = await this.ready();
|
|
95
|
+
const row = await db.get(`
|
|
96
|
+
SELECT * FROM ai_sessions
|
|
97
|
+
WHERE session_id = ? AND provider = ? AND expires_at > ?
|
|
98
|
+
`, [sessionId, provider, Date.now()]);
|
|
99
|
+
return row ? this.rowToSession(row) : null;
|
|
100
|
+
}
|
|
101
|
+
async createSession(params) {
|
|
102
|
+
const db = await this.ready();
|
|
103
|
+
const id = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const expiresAt = now + this.sessionRetentionMs;
|
|
106
|
+
await db.run(`
|
|
107
|
+
INSERT INTO ai_sessions (
|
|
108
|
+
id, provider, session_id, conversation_id,
|
|
109
|
+
metadata, created_at, updated_at, expires_at
|
|
110
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
111
|
+
`, [
|
|
112
|
+
id,
|
|
113
|
+
params.provider,
|
|
114
|
+
params.sessionId,
|
|
115
|
+
params.conversationId || null,
|
|
116
|
+
JSON.stringify(params.metadata || {}),
|
|
117
|
+
now,
|
|
118
|
+
now,
|
|
119
|
+
expiresAt,
|
|
120
|
+
]);
|
|
121
|
+
return (await this.getSession(params.sessionId, params.provider));
|
|
122
|
+
}
|
|
123
|
+
async updateSession(sessionId, provider, updates) {
|
|
124
|
+
const db = await this.ready();
|
|
125
|
+
const fields = [];
|
|
126
|
+
const values = [];
|
|
127
|
+
if (updates.conversationId !== undefined) {
|
|
128
|
+
fields.push("conversation_id = ?");
|
|
129
|
+
values.push(updates.conversationId);
|
|
130
|
+
}
|
|
131
|
+
if (updates.metadata !== undefined) {
|
|
132
|
+
fields.push("metadata = ?");
|
|
133
|
+
values.push(JSON.stringify(updates.metadata));
|
|
134
|
+
}
|
|
135
|
+
fields.push("updated_at = ?");
|
|
136
|
+
values.push(Date.now());
|
|
137
|
+
values.push(sessionId, provider);
|
|
138
|
+
await db.run(`
|
|
139
|
+
UPDATE ai_sessions
|
|
140
|
+
SET ${fields.join(", ")}
|
|
141
|
+
WHERE session_id = ? AND provider = ?
|
|
142
|
+
`, values);
|
|
143
|
+
}
|
|
144
|
+
async cleanupExpiredSessions() {
|
|
145
|
+
const db = await this.ready();
|
|
146
|
+
return db.run(`DELETE FROM ai_sessions WHERE expires_at < ?`, [Date.now()]);
|
|
147
|
+
}
|
|
148
|
+
async deleteSession(sessionId, provider) {
|
|
149
|
+
const db = await this.ready();
|
|
150
|
+
await db.run(`DELETE FROM ai_sessions WHERE session_id = ? AND provider = ?`, [
|
|
151
|
+
sessionId,
|
|
152
|
+
provider,
|
|
153
|
+
]);
|
|
154
|
+
}
|
|
155
|
+
async addMessage(message) {
|
|
156
|
+
const db = await this.ready();
|
|
157
|
+
await db.run(`INSERT INTO ai_messages (
|
|
158
|
+
ai_session_id, sequence, role, content,
|
|
159
|
+
tool_calls, tool_call_id, content_blocks, created_at
|
|
160
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
161
|
+
message.aiSessionId,
|
|
162
|
+
message.sequence,
|
|
163
|
+
message.role,
|
|
164
|
+
message.content,
|
|
165
|
+
message.toolCalls ? JSON.stringify(message.toolCalls) : null,
|
|
166
|
+
message.toolCallId || null,
|
|
167
|
+
message.contentBlocks ? JSON.stringify(message.contentBlocks) : null,
|
|
168
|
+
Date.now(),
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
async getMessages(aiSessionId) {
|
|
172
|
+
const db = await this.ready();
|
|
173
|
+
const rows = await db.all("SELECT * FROM ai_messages WHERE ai_session_id = ? ORDER BY sequence ASC", [aiSessionId]);
|
|
174
|
+
return rows.map((row) => this.rowToMessage(row));
|
|
175
|
+
}
|
|
176
|
+
async getLastSequence(aiSessionId) {
|
|
177
|
+
const db = await this.ready();
|
|
178
|
+
const row = await db.get("SELECT MAX(sequence) as max_seq FROM ai_messages WHERE ai_session_id = ?", [aiSessionId]);
|
|
179
|
+
return row?.max_seq != null ? Number(row.max_seq) : -1;
|
|
180
|
+
}
|
|
181
|
+
async clearMessages(aiSessionId) {
|
|
182
|
+
const db = await this.ready();
|
|
183
|
+
await db.run("DELETE FROM ai_messages WHERE ai_session_id = ?", [aiSessionId]);
|
|
184
|
+
}
|
|
185
|
+
rowToSession(row) {
|
|
186
|
+
return {
|
|
187
|
+
id: String(row.id),
|
|
188
|
+
provider: row.provider,
|
|
189
|
+
sessionId: String(row.session_id),
|
|
190
|
+
conversationId: row.conversation_id ? String(row.conversation_id) : undefined,
|
|
191
|
+
metadata: row.metadata ? JSON.parse(String(row.metadata)) : undefined,
|
|
192
|
+
createdAt: Number(row.created_at),
|
|
193
|
+
updatedAt: Number(row.updated_at),
|
|
194
|
+
expiresAt: Number(row.expires_at),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
rowToMessage(row) {
|
|
198
|
+
return {
|
|
199
|
+
id: Number(row.id),
|
|
200
|
+
aiSessionId: String(row.ai_session_id),
|
|
201
|
+
sequence: Number(row.sequence),
|
|
202
|
+
role: row.role,
|
|
203
|
+
content: String(row.content),
|
|
204
|
+
toolCalls: row.tool_calls ? JSON.parse(String(row.tool_calls)) : undefined,
|
|
205
|
+
toolCallId: row.tool_call_id ? String(row.tool_call_id) : undefined,
|
|
206
|
+
contentBlocks: row.content_blocks ? JSON.parse(String(row.content_blocks)) : undefined,
|
|
207
|
+
createdAt: Number(row.created_at),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
export const aiSessionManager = new AISessionManager();
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type AIProviderType = "openai-chat" | "openai-responses" | "anthropic" | "minimax" | "google-gemini" | "orcarouter";
|
|
2
|
+
export interface AIMessage {
|
|
3
|
+
id?: number;
|
|
4
|
+
aiSessionId: string;
|
|
5
|
+
sequence: number;
|
|
6
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
7
|
+
content: string;
|
|
8
|
+
toolCalls?: Array<{
|
|
9
|
+
id: string;
|
|
10
|
+
type: "function";
|
|
11
|
+
function: {
|
|
12
|
+
name: string;
|
|
13
|
+
arguments: string;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
toolCallId?: string;
|
|
17
|
+
contentBlocks?: Array<{
|
|
18
|
+
type: string;
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}>;
|
|
21
|
+
createdAt: number;
|
|
22
|
+
}
|
|
23
|
+
export interface AISession {
|
|
24
|
+
id: string;
|
|
25
|
+
provider: AIProviderType;
|
|
26
|
+
sessionId: string;
|
|
27
|
+
conversationId?: string;
|
|
28
|
+
metadata?: Record<string, any>;
|
|
29
|
+
createdAt: number;
|
|
30
|
+
updatedAt: number;
|
|
31
|
+
expiresAt: number;
|
|
32
|
+
}
|
|
33
|
+
export interface SessionCreateParams {
|
|
34
|
+
provider: AIProviderType;
|
|
35
|
+
sessionId: string;
|
|
36
|
+
conversationId?: string;
|
|
37
|
+
metadata?: Record<string, any>;
|
|
38
|
+
}
|
|
39
|
+
export interface SessionUpdateParams {
|
|
40
|
+
conversationId?: string;
|
|
41
|
+
metadata?: Record<string, any>;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ChatCompletionTool {
|
|
2
|
+
type: "function";
|
|
3
|
+
function: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
parameters: {
|
|
7
|
+
type: string;
|
|
8
|
+
properties: Record<string, any>;
|
|
9
|
+
required: string[];
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface ResponsesAPITool {
|
|
14
|
+
type: "function";
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
parameters: {
|
|
18
|
+
type: string;
|
|
19
|
+
properties: Record<string, any>;
|
|
20
|
+
required: string[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface AnthropicTool {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
input_schema: {
|
|
27
|
+
type: string;
|
|
28
|
+
properties: Record<string, any>;
|
|
29
|
+
required: string[];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare class ToolSchemaConverter {
|
|
33
|
+
static toResponsesAPI(chatCompletionTool: ChatCompletionTool): ResponsesAPITool;
|
|
34
|
+
static toAnthropic(chatCompletionTool: ChatCompletionTool): AnthropicTool;
|
|
35
|
+
static fromChatCompletion(tool: ChatCompletionTool): {
|
|
36
|
+
chatCompletion: ChatCompletionTool;
|
|
37
|
+
responsesAPI: ResponsesAPITool;
|
|
38
|
+
anthropic: AnthropicTool;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class ToolSchemaConverter {
|
|
2
|
+
static toResponsesAPI(chatCompletionTool) {
|
|
3
|
+
return {
|
|
4
|
+
type: "function",
|
|
5
|
+
name: chatCompletionTool.function.name,
|
|
6
|
+
description: chatCompletionTool.function.description,
|
|
7
|
+
parameters: chatCompletionTool.function.parameters,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
static toAnthropic(chatCompletionTool) {
|
|
11
|
+
return {
|
|
12
|
+
name: chatCompletionTool.function.name,
|
|
13
|
+
description: chatCompletionTool.function.description,
|
|
14
|
+
input_schema: chatCompletionTool.function.parameters,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
static fromChatCompletion(tool) {
|
|
18
|
+
return {
|
|
19
|
+
chatCompletion: tool,
|
|
20
|
+
responsesAPI: this.toResponsesAPI(tool),
|
|
21
|
+
anthropic: this.toAnthropic(tool),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { UserProfileData } from "../../user-profile/types.js";
|
|
2
|
+
export interface ValidationResult {
|
|
3
|
+
valid: boolean;
|
|
4
|
+
errors: string[];
|
|
5
|
+
data?: UserProfileData;
|
|
6
|
+
}
|
|
7
|
+
export declare class UserProfileValidator {
|
|
8
|
+
static validate(data: any): ValidationResult;
|
|
9
|
+
private static validatePreferences;
|
|
10
|
+
private static validatePatterns;
|
|
11
|
+
private static validateWorkflows;
|
|
12
|
+
}
|