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.
Files changed (221) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +587 -0
  3. package/dist/adapters/opencode/auto-capture-host.d.ts +3 -0
  4. package/dist/adapters/opencode/auto-capture-host.js +29 -0
  5. package/dist/adapters/opencode/auto-capture-summary.d.ts +4 -0
  6. package/dist/adapters/opencode/auto-capture-summary.js +147 -0
  7. package/dist/adapters/opencode/conversation.d.ts +2 -0
  8. package/dist/adapters/opencode/conversation.js +50 -0
  9. package/dist/adapters/opencode/user-prompt.d.ts +9 -0
  10. package/dist/adapters/opencode/user-prompt.js +26 -0
  11. package/dist/adapters/pi/capture.d.ts +41 -0
  12. package/dist/adapters/pi/capture.js +91 -0
  13. package/dist/adapters/pi/conversation.d.ts +38 -0
  14. package/dist/adapters/pi/conversation.js +118 -0
  15. package/dist/adapters/pi/extension.d.ts +18 -0
  16. package/dist/adapters/pi/extension.js +234 -0
  17. package/dist/adapters/pi/import-command.d.ts +29 -0
  18. package/dist/adapters/pi/import-command.js +232 -0
  19. package/dist/adapters/pi/profile.d.ts +39 -0
  20. package/dist/adapters/pi/profile.js +148 -0
  21. package/dist/adapters/pi/provider.d.ts +50 -0
  22. package/dist/adapters/pi/provider.js +77 -0
  23. package/dist/config.d.ts +290 -0
  24. package/dist/config.js +742 -0
  25. package/dist/core/capture-context.d.ts +4 -0
  26. package/dist/core/capture-context.js +132 -0
  27. package/dist/core/capture.d.ts +15 -0
  28. package/dist/core/capture.js +68 -0
  29. package/dist/core/extraction.d.ts +80 -0
  30. package/dist/core/extraction.js +140 -0
  31. package/dist/core/host.d.ts +52 -0
  32. package/dist/core/host.js +1 -0
  33. package/dist/core/memory-operations.d.ts +27 -0
  34. package/dist/core/memory-operations.js +247 -0
  35. package/dist/core/retrieval.d.ts +12 -0
  36. package/dist/core/retrieval.js +72 -0
  37. package/dist/importer/discovery.d.ts +31 -0
  38. package/dist/importer/discovery.js +88 -0
  39. package/dist/importer/importer.d.ts +87 -0
  40. package/dist/importer/importer.js +260 -0
  41. package/dist/importer/ledger.d.ts +44 -0
  42. package/dist/importer/ledger.js +137 -0
  43. package/dist/importer/session-loader.d.ts +19 -0
  44. package/dist/importer/session-loader.js +12 -0
  45. package/dist/index.d.ts +24 -0
  46. package/dist/index.js +601 -0
  47. package/dist/plugin.d.ts +9 -0
  48. package/dist/plugin.js +11 -0
  49. package/dist/services/ai/ai-provider-factory.d.ts +7 -0
  50. package/dist/services/ai/ai-provider-factory.js +41 -0
  51. package/dist/services/ai/api-key-placeholder.d.ts +1 -0
  52. package/dist/services/ai/api-key-placeholder.js +14 -0
  53. package/dist/services/ai/internal-capture-sessions.d.ts +6 -0
  54. package/dist/services/ai/internal-capture-sessions.js +33 -0
  55. package/dist/services/ai/opencode-diagnostics.d.ts +7 -0
  56. package/dist/services/ai/opencode-diagnostics.js +36 -0
  57. package/dist/services/ai/opencode-host-config.d.ts +10 -0
  58. package/dist/services/ai/opencode-host-config.js +51 -0
  59. package/dist/services/ai/opencode-provider-loader.d.ts +3 -0
  60. package/dist/services/ai/opencode-provider-loader.js +4 -0
  61. package/dist/services/ai/opencode-provider.d.ts +92 -0
  62. package/dist/services/ai/opencode-provider.js +419 -0
  63. package/dist/services/ai/opencode-sdk-client.d.ts +6 -0
  64. package/dist/services/ai/opencode-sdk-client.js +38 -0
  65. package/dist/services/ai/profile-llm-client.d.ts +2 -0
  66. package/dist/services/ai/profile-llm-client.js +27 -0
  67. package/dist/services/ai/provider-config.d.ts +17 -0
  68. package/dist/services/ai/provider-config.js +30 -0
  69. package/dist/services/ai/providers/anthropic-messages.d.ts +34 -0
  70. package/dist/services/ai/providers/anthropic-messages.js +220 -0
  71. package/dist/services/ai/providers/base-provider.d.ts +24 -0
  72. package/dist/services/ai/providers/base-provider.js +24 -0
  73. package/dist/services/ai/providers/google-gemini.d.ts +15 -0
  74. package/dist/services/ai/providers/google-gemini.js +228 -0
  75. package/dist/services/ai/providers/minimax.d.ts +35 -0
  76. package/dist/services/ai/providers/minimax.js +55 -0
  77. package/dist/services/ai/providers/openai-chat-completion.d.ts +22 -0
  78. package/dist/services/ai/providers/openai-chat-completion.js +387 -0
  79. package/dist/services/ai/providers/openai-responses.d.ts +13 -0
  80. package/dist/services/ai/providers/openai-responses.js +182 -0
  81. package/dist/services/ai/providers/orcarouter.d.ts +51 -0
  82. package/dist/services/ai/providers/orcarouter.js +66 -0
  83. package/dist/services/ai/session/ai-session-manager.d.ts +24 -0
  84. package/dist/services/ai/session/ai-session-manager.js +211 -0
  85. package/dist/services/ai/session/session-types.d.ts +42 -0
  86. package/dist/services/ai/session/session-types.js +1 -0
  87. package/dist/services/ai/tools/tool-schema.d.ts +40 -0
  88. package/dist/services/ai/tools/tool-schema.js +24 -0
  89. package/dist/services/ai/validators/user-profile-validator.d.ts +12 -0
  90. package/dist/services/ai/validators/user-profile-validator.js +114 -0
  91. package/dist/services/api-handlers.d.ts +186 -0
  92. package/dist/services/api-handlers.js +1284 -0
  93. package/dist/services/auth-token.d.ts +14 -0
  94. package/dist/services/auth-token.js +59 -0
  95. package/dist/services/auto-capture.d.ts +3 -0
  96. package/dist/services/auto-capture.js +127 -0
  97. package/dist/services/cleanup-service.d.ts +22 -0
  98. package/dist/services/cleanup-service.js +109 -0
  99. package/dist/services/client.d.ts +134 -0
  100. package/dist/services/client.js +327 -0
  101. package/dist/services/context.d.ts +10 -0
  102. package/dist/services/context.js +27 -0
  103. package/dist/services/cors.d.ts +12 -0
  104. package/dist/services/cors.js +52 -0
  105. package/dist/services/deduplication-service.d.ts +28 -0
  106. package/dist/services/deduplication-service.js +111 -0
  107. package/dist/services/embedding.d.ts +36 -0
  108. package/dist/services/embedding.js +200 -0
  109. package/dist/services/jsonc.d.ts +6 -0
  110. package/dist/services/jsonc.js +76 -0
  111. package/dist/services/language-detector.d.ts +2 -0
  112. package/dist/services/language-detector.js +33 -0
  113. package/dist/services/legacy-migration.d.ts +77 -0
  114. package/dist/services/legacy-migration.js +343 -0
  115. package/dist/services/logger.d.ts +1 -0
  116. package/dist/services/logger.js +119 -0
  117. package/dist/services/memory-portability-service.d.ts +37 -0
  118. package/dist/services/memory-portability-service.js +340 -0
  119. package/dist/services/memory-scope.d.ts +16 -0
  120. package/dist/services/memory-scope.js +43 -0
  121. package/dist/services/migration-service.d.ts +42 -0
  122. package/dist/services/migration-service.js +307 -0
  123. package/dist/services/onnxruntime-resolve.d.ts +24 -0
  124. package/dist/services/onnxruntime-resolve.js +174 -0
  125. package/dist/services/privacy.d.ts +26 -0
  126. package/dist/services/privacy.js +69 -0
  127. package/dist/services/request-timeouts.d.ts +9 -0
  128. package/dist/services/request-timeouts.js +11 -0
  129. package/dist/services/runtime-require.d.ts +17 -0
  130. package/dist/services/runtime-require.js +75 -0
  131. package/dist/services/secret-resolver.d.ts +1 -0
  132. package/dist/services/secret-resolver.js +65 -0
  133. package/dist/services/shard-inventory-service.d.ts +69 -0
  134. package/dist/services/shard-inventory-service.js +315 -0
  135. package/dist/services/shard-path-migration-service.d.ts +31 -0
  136. package/dist/services/shard-path-migration-service.js +367 -0
  137. package/dist/services/tag-prefix-migration.d.ts +60 -0
  138. package/dist/services/tag-prefix-migration.js +439 -0
  139. package/dist/services/tag-prefix-scan.d.ts +26 -0
  140. package/dist/services/tag-prefix-scan.js +91 -0
  141. package/dist/services/tags.d.ts +29 -0
  142. package/dist/services/tags.js +251 -0
  143. package/dist/services/turso/connection-manager.d.ts +15 -0
  144. package/dist/services/turso/connection-manager.js +163 -0
  145. package/dist/services/turso/cross-process-write-lock.d.ts +1 -0
  146. package/dist/services/turso/cross-process-write-lock.js +89 -0
  147. package/dist/services/turso/legacy-migrator.d.ts +1 -0
  148. package/dist/services/turso/legacy-migrator.js +540 -0
  149. package/dist/services/turso/lifecycle.d.ts +1 -0
  150. package/dist/services/turso/lifecycle.js +14 -0
  151. package/dist/services/turso/operation-lock.d.ts +2 -0
  152. package/dist/services/turso/operation-lock.js +61 -0
  153. package/dist/services/turso/ready.d.ts +2 -0
  154. package/dist/services/turso/ready.js +36 -0
  155. package/dist/services/turso/shard-manager.d.ts +38 -0
  156. package/dist/services/turso/shard-manager.js +496 -0
  157. package/dist/services/turso/sqlite-handle-release.d.ts +16 -0
  158. package/dist/services/turso/sqlite-handle-release.js +56 -0
  159. package/dist/services/turso/turso-db.d.ts +18 -0
  160. package/dist/services/turso/turso-db.js +53 -0
  161. package/dist/services/turso/types.d.ts +42 -0
  162. package/dist/services/turso/types.js +1 -0
  163. package/dist/services/turso/vector-search.d.ts +41 -0
  164. package/dist/services/turso/vector-search.js +384 -0
  165. package/dist/services/turso/vector-utils.d.ts +7 -0
  166. package/dist/services/turso/vector-utils.js +67 -0
  167. package/dist/services/user-memory-learning.d.ts +97 -0
  168. package/dist/services/user-memory-learning.js +673 -0
  169. package/dist/services/user-profile/ai-cleanup.d.ts +58 -0
  170. package/dist/services/user-profile/ai-cleanup.js +486 -0
  171. package/dist/services/user-profile/profile-context.d.ts +1 -0
  172. package/dist/services/user-profile/profile-context.js +105 -0
  173. package/dist/services/user-profile/profile-utils.d.ts +2 -0
  174. package/dist/services/user-profile/profile-utils.js +45 -0
  175. package/dist/services/user-profile/types.d.ts +92 -0
  176. package/dist/services/user-profile/types.js +1 -0
  177. package/dist/services/user-profile/user-profile-manager.d.ts +65 -0
  178. package/dist/services/user-profile/user-profile-manager.js +1660 -0
  179. package/dist/services/user-prompt/user-prompt-manager.d.ts +53 -0
  180. package/dist/services/user-prompt/user-prompt-manager.js +303 -0
  181. package/dist/services/web-api-auth.d.ts +3 -0
  182. package/dist/services/web-api-auth.js +25 -0
  183. package/dist/services/web-auth.d.ts +46 -0
  184. package/dist/services/web-auth.js +105 -0
  185. package/dist/services/web-server.d.ts +57 -0
  186. package/dist/services/web-server.js +659 -0
  187. package/dist/shared/api/index.d.ts +4 -0
  188. package/dist/shared/api/index.js +2 -0
  189. package/dist/shared/api/portability-schemas.d.ts +56 -0
  190. package/dist/shared/api/portability-schemas.js +39 -0
  191. package/dist/shared/api/schemas.d.ts +295 -0
  192. package/dist/shared/api/schemas.js +134 -0
  193. package/dist/shared/api/types.d.ts +28 -0
  194. package/dist/shared/api/types.js +1 -0
  195. package/dist/types/index.d.ts +27 -0
  196. package/dist/types/index.js +1 -0
  197. package/dist/utils/context-limit.d.ts +10 -0
  198. package/dist/utils/context-limit.js +43 -0
  199. package/dist/utils/math.d.ts +7 -0
  200. package/dist/utils/math.js +48 -0
  201. package/dist/utils/profile.d.ts +2 -0
  202. package/dist/utils/profile.js +15 -0
  203. package/dist/v2/adapter.d.ts +5 -0
  204. package/dist/v2/adapter.js +218 -0
  205. package/dist/v2/legacy-client.d.ts +15 -0
  206. package/dist/v2/legacy-client.js +257 -0
  207. package/dist/v2/memory-bridge.d.ts +18 -0
  208. package/dist/v2/memory-bridge.js +29 -0
  209. package/dist/v2/plugin.d.ts +3 -0
  210. package/dist/v2/plugin.js +24 -0
  211. package/dist/web/assets/index-DPjEpD1h.css +2 -0
  212. package/dist/web/assets/index-do26c4JJ.js +122 -0
  213. package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  214. package/dist/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  215. package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  216. package/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  217. package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  218. package/dist/web/favicon.ico +0 -0
  219. package/dist/web/index.html +14 -0
  220. package/dist/web/omms-icon.png +0 -0
  221. package/package.json +138 -0
@@ -0,0 +1,35 @@
1
+ import { type ProviderConfig } from "./base-provider.js";
2
+ import { AISessionManager } from "../session/ai-session-manager.js";
3
+ import { AnthropicMessagesProvider } from "./anthropic-messages.js";
4
+ import type { AIProviderType } from "../session/session-types.js";
5
+ /**
6
+ * MiniMax provider.
7
+ *
8
+ * MiniMax exposes an Anthropic Messages-compatible endpoint for its text
9
+ * models. The global endpoint (https://api.minimax.io) and the China endpoint
10
+ * (https://api.minimaxi.com) both expose the same `/anthropic/v1/messages`
11
+ * path and authenticate with the `x-api-key` header. This provider reuses the
12
+ * Anthropic Messages request/response handling and only overrides the resolved
13
+ * request endpoint URL and the session provider tag, so MiniMax is
14
+ * distinguishable from Anthropic in the session store and diagnostics.
15
+ *
16
+ * Users configure the base URL as `memoryApiUrl`:
17
+ * - global endpoint: "https://api.minimax.io"
18
+ * - China endpoint: "https://api.minimaxi.com"
19
+ */
20
+ export declare class MiniMaxProvider extends AnthropicMessagesProvider {
21
+ constructor(config: ProviderConfig, aiSessionManager: AISessionManager);
22
+ getProviderName(): string;
23
+ /**
24
+ * Resolve the Anthropic Messages endpoint URL for MiniMax.
25
+ *
26
+ * MiniMax's Messages endpoint lives at `<base>/anthropic/v1/messages`. The
27
+ * base URL is normalized so users can supply the host with or without a
28
+ * trailing `/anthropic`, `/anthropic/v1`, or `/anthropic/v1/messages` suffix.
29
+ */
30
+ resolveEndpoint(): string;
31
+ sessionProviderTag(): AIProviderType;
32
+ protected apiErrorLogLabel(): string;
33
+ protected toolValidationErrorLogLabel(): string;
34
+ protected timeoutLabel(): string;
35
+ }
@@ -0,0 +1,55 @@
1
+ import {} from "./base-provider.js";
2
+ import { AISessionManager } from "../session/ai-session-manager.js";
3
+ import { AnthropicMessagesProvider } from "./anthropic-messages.js";
4
+ /**
5
+ * MiniMax provider.
6
+ *
7
+ * MiniMax exposes an Anthropic Messages-compatible endpoint for its text
8
+ * models. The global endpoint (https://api.minimax.io) and the China endpoint
9
+ * (https://api.minimaxi.com) both expose the same `/anthropic/v1/messages`
10
+ * path and authenticate with the `x-api-key` header. This provider reuses the
11
+ * Anthropic Messages request/response handling and only overrides the resolved
12
+ * request endpoint URL and the session provider tag, so MiniMax is
13
+ * distinguishable from Anthropic in the session store and diagnostics.
14
+ *
15
+ * Users configure the base URL as `memoryApiUrl`:
16
+ * - global endpoint: "https://api.minimax.io"
17
+ * - China endpoint: "https://api.minimaxi.com"
18
+ */
19
+ export class MiniMaxProvider extends AnthropicMessagesProvider {
20
+ constructor(config, aiSessionManager) {
21
+ super(config, aiSessionManager);
22
+ }
23
+ getProviderName() {
24
+ return "minimax";
25
+ }
26
+ /**
27
+ * Resolve the Anthropic Messages endpoint URL for MiniMax.
28
+ *
29
+ * MiniMax's Messages endpoint lives at `<base>/anthropic/v1/messages`. The
30
+ * base URL is normalized so users can supply the host with or without a
31
+ * trailing `/anthropic`, `/anthropic/v1`, or `/anthropic/v1/messages` suffix.
32
+ */
33
+ resolveEndpoint() {
34
+ let base = (this.config.apiUrl || "").trim().replace(/\/+$/, "");
35
+ if (!base) {
36
+ throw new Error("MiniMax provider requires a configured memoryApiUrl");
37
+ }
38
+ base = base.replace(/\/anthropic\/v1\/messages\/?$/, "");
39
+ base = base.replace(/\/anthropic\/v1\/?$/, "");
40
+ base = base.replace(/\/anthropic\/?$/, "");
41
+ return `${base}/anthropic/v1/messages`;
42
+ }
43
+ sessionProviderTag() {
44
+ return "minimax";
45
+ }
46
+ apiErrorLogLabel() {
47
+ return "MiniMax Messages API error";
48
+ }
49
+ toolValidationErrorLogLabel() {
50
+ return "MiniMax tool response validation failed";
51
+ }
52
+ timeoutLabel() {
53
+ return "MiniMax API request timeout";
54
+ }
55
+ }
@@ -0,0 +1,22 @@
1
+ import { BaseAIProvider, type ProviderConfig, type ToolCallResult } from "./base-provider.js";
2
+ import type { AISessionManager } from "../session/ai-session-manager.js";
3
+ import type { AIMessage, AIProviderType } from "../session/session-types.js";
4
+ import type { ChatCompletionTool } from "../tools/tool-schema.js";
5
+ export declare class OpenAIChatCompletionProvider extends BaseAIProvider {
6
+ private readonly aiSessionManager;
7
+ constructor(config: ProviderConfig, aiSessionManager: AISessionManager);
8
+ getProviderName(): string;
9
+ supportsSession(): boolean;
10
+ /** Provider tag used for AI session storage and diagnostics. */
11
+ protected sessionProviderTag(): AIProviderType;
12
+ /**
13
+ * Resolve the OpenAI-compatible API base URL.
14
+ * Trailing slashes are stripped so `${base}/chat/completions` is well-formed.
15
+ */
16
+ protected resolveEndpoint(): string;
17
+ /** Resolve the model ID sent in the request body. */
18
+ protected resolveModel(): string;
19
+ private addToolResponse;
20
+ protected filterIncompleteToolCallSequences(messages: AIMessage[]): AIMessage[];
21
+ executeToolCall(systemPrompt: string, userPrompt: string, toolSchema: ChatCompletionTool, sessionId: string): Promise<ToolCallResult>;
22
+ }
@@ -0,0 +1,387 @@
1
+ import { BaseAIProvider, applySafeExtraParams, } from "./base-provider.js";
2
+ import { log } from "../../logger.js";
3
+ import { UserProfileValidator } from "../validators/user-profile-validator.js";
4
+ function isErrorResponseBody(data) {
5
+ return (typeof data === "object" &&
6
+ data !== null &&
7
+ typeof data.status === "string" &&
8
+ typeof data.msg === "string");
9
+ }
10
+ function hasNonEmptyChoices(data) {
11
+ if (typeof data !== "object" || data === null)
12
+ return false;
13
+ const { choices } = data;
14
+ if (!Array.isArray(choices) || choices.length === 0)
15
+ return false;
16
+ const first = choices[0];
17
+ if (typeof first !== "object" || first === null)
18
+ return false;
19
+ if (typeof first.message !== "object" || first.message === null)
20
+ return false;
21
+ const { content, tool_calls } = first.message;
22
+ if (content !== undefined && content !== null && typeof content !== "string")
23
+ return false;
24
+ if (tool_calls !== undefined && !Array.isArray(tool_calls))
25
+ return false;
26
+ return true;
27
+ }
28
+ function extractFirstJSON(raw) {
29
+ let depth = 0;
30
+ let start = -1;
31
+ for (let i = 0; i < raw.length; i++) {
32
+ if (raw[i] === "{" || raw[i] === "[") {
33
+ if (depth === 0)
34
+ start = i;
35
+ depth++;
36
+ }
37
+ else if (raw[i] === "}" || raw[i] === "]") {
38
+ depth--;
39
+ if (depth === 0)
40
+ return raw.slice(start, i + 1);
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ function repairInnerQuotes(json) {
46
+ let result = json.replace(/([\u4e00-\u9fff\u3000-\u303f\uff00-\uffef])"([\u4e00-\u9fff\u3000-\u303f\uff00-\uffef])/g, '$1\\"$2');
47
+ result = result.replace(/([\u4e00-\u9fff\u3000-\u303f\uff00-\uffef])"(?=\s*[,}\]])/g, '$1\\"');
48
+ return result;
49
+ }
50
+ export class OpenAIChatCompletionProvider extends BaseAIProvider {
51
+ aiSessionManager;
52
+ constructor(config, aiSessionManager) {
53
+ super(config);
54
+ this.aiSessionManager = aiSessionManager;
55
+ }
56
+ getProviderName() {
57
+ return "openai-chat";
58
+ }
59
+ supportsSession() {
60
+ return true;
61
+ }
62
+ /** Provider tag used for AI session storage and diagnostics. */
63
+ sessionProviderTag() {
64
+ return "openai-chat";
65
+ }
66
+ /**
67
+ * Resolve the OpenAI-compatible API base URL.
68
+ * Trailing slashes are stripped so `${base}/chat/completions` is well-formed.
69
+ */
70
+ resolveEndpoint() {
71
+ return (this.config.apiUrl || "").trim().replace(/\/+$/, "");
72
+ }
73
+ /** Resolve the model ID sent in the request body. */
74
+ resolveModel() {
75
+ return this.config.model;
76
+ }
77
+ async addToolResponse(sessionId, messages, toolCallId, content) {
78
+ const sequence = (await this.aiSessionManager.getLastSequence(sessionId)) + 1;
79
+ await this.aiSessionManager.addMessage({
80
+ aiSessionId: sessionId,
81
+ sequence,
82
+ role: "tool",
83
+ content,
84
+ toolCallId,
85
+ });
86
+ messages.push({
87
+ role: "tool",
88
+ tool_call_id: toolCallId,
89
+ content,
90
+ });
91
+ }
92
+ filterIncompleteToolCallSequences(messages) {
93
+ const result = [];
94
+ let i = 0;
95
+ while (i < messages.length) {
96
+ const msg = messages[i];
97
+ if (!msg) {
98
+ break;
99
+ }
100
+ if (msg.role === "assistant" && msg.toolCalls && msg.toolCalls.length > 0) {
101
+ const toolCallIds = new Set(msg.toolCalls.map((tc) => tc.id));
102
+ const toolResponses = [];
103
+ let j = i + 1;
104
+ while (j < messages.length && messages[j]?.role === "tool") {
105
+ const toolMessage = messages[j];
106
+ if (toolMessage?.toolCallId && toolCallIds.has(toolMessage.toolCallId)) {
107
+ toolResponses.push(toolMessage);
108
+ toolCallIds.delete(toolMessage.toolCallId);
109
+ }
110
+ j++;
111
+ }
112
+ if (toolCallIds.size === 0) {
113
+ result.push(msg);
114
+ toolResponses.forEach((tr) => result.push(tr));
115
+ i = j;
116
+ }
117
+ else {
118
+ break;
119
+ }
120
+ }
121
+ else {
122
+ result.push(msg);
123
+ i++;
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ async executeToolCall(systemPrompt, userPrompt, toolSchema, sessionId) {
129
+ let session = await this.aiSessionManager.getSession(sessionId, this.sessionProviderTag());
130
+ if (!session) {
131
+ session = await this.aiSessionManager.createSession({
132
+ provider: this.sessionProviderTag(),
133
+ sessionId,
134
+ });
135
+ }
136
+ const existingMessages = await this.aiSessionManager.getMessages(session.id);
137
+ const messages = [];
138
+ const validatedMessages = this.filterIncompleteToolCallSequences(existingMessages);
139
+ for (const msg of validatedMessages) {
140
+ const apiMsg = {
141
+ role: msg.role,
142
+ content: msg.content,
143
+ };
144
+ if (msg.toolCalls) {
145
+ apiMsg.tool_calls = msg.toolCalls;
146
+ }
147
+ if (msg.toolCallId) {
148
+ apiMsg.tool_call_id = msg.toolCallId;
149
+ }
150
+ messages.push(apiMsg);
151
+ }
152
+ if (messages.length === 0) {
153
+ const sequence = (await this.aiSessionManager.getLastSequence(session.id)) + 1;
154
+ await this.aiSessionManager.addMessage({
155
+ aiSessionId: session.id,
156
+ sequence,
157
+ role: "system",
158
+ content: systemPrompt,
159
+ });
160
+ messages.push({ role: "system", content: systemPrompt });
161
+ }
162
+ const userSequence = (await this.aiSessionManager.getLastSequence(session.id)) + 1;
163
+ await this.aiSessionManager.addMessage({
164
+ aiSessionId: session.id,
165
+ sequence: userSequence,
166
+ role: "user",
167
+ content: userPrompt,
168
+ });
169
+ messages.push({ role: "user", content: userPrompt });
170
+ let iterations = 0;
171
+ const maxIterations = this.config.maxIterations ?? 5;
172
+ const iterationTimeout = this.config.iterationTimeout ?? 30000;
173
+ let lastErrorMessage = "";
174
+ while (iterations < maxIterations) {
175
+ iterations++;
176
+ const controller = new AbortController();
177
+ const timeout = setTimeout(() => controller.abort(), iterationTimeout);
178
+ try {
179
+ const requestBody = {
180
+ model: this.resolveModel(),
181
+ messages,
182
+ tools: [toolSchema],
183
+ tool_choice: "auto",
184
+ };
185
+ if (this.config.memoryTemperature !== false) {
186
+ requestBody.temperature = this.config.memoryTemperature ?? 0.3;
187
+ }
188
+ if (this.config.extraParams) {
189
+ applySafeExtraParams(requestBody, this.config.extraParams);
190
+ }
191
+ const headers = {
192
+ "Content-Type": "application/json",
193
+ };
194
+ if (this.config.apiKey) {
195
+ headers.Authorization = `Bearer ${this.config.apiKey}`;
196
+ }
197
+ const response = await fetch(`${this.resolveEndpoint()}/chat/completions`, {
198
+ method: "POST",
199
+ headers,
200
+ body: JSON.stringify(requestBody),
201
+ signal: controller.signal,
202
+ });
203
+ clearTimeout(timeout);
204
+ if (!response.ok) {
205
+ const errorText = await response.text().catch(() => response.statusText);
206
+ log("OpenAI Chat Completion API error", {
207
+ provider: this.getProviderName(),
208
+ model: this.config.model,
209
+ status: response.status,
210
+ error: errorText,
211
+ iteration: iterations,
212
+ });
213
+ let errorMessage = `API error: ${response.status} - ${errorText}`;
214
+ if (response.status === 400 &&
215
+ errorText.includes("unsupported_value") &&
216
+ errorText.includes("temperature")) {
217
+ errorMessage =
218
+ 'Your model does not support the temperature parameter. Add "memoryTemperature": false to your config file to disable it.';
219
+ }
220
+ return {
221
+ success: false,
222
+ error: errorMessage,
223
+ iterations,
224
+ };
225
+ }
226
+ const data = await response.json();
227
+ if (isErrorResponseBody(data)) {
228
+ log("API returned error in response body", {
229
+ provider: this.getProviderName(),
230
+ model: this.config.model,
231
+ status: data.status,
232
+ msg: data.msg,
233
+ });
234
+ return {
235
+ success: false,
236
+ error: `API error: ${data.status} - ${data.msg}`,
237
+ iterations,
238
+ };
239
+ }
240
+ if (!hasNonEmptyChoices(data)) {
241
+ const choices = typeof data === "object" && data !== null
242
+ ? data.choices
243
+ : undefined;
244
+ log("Invalid API response format", {
245
+ provider: this.getProviderName(),
246
+ model: this.config.model,
247
+ response: JSON.stringify(data).slice(0, 1000),
248
+ hasChoices: Array.isArray(choices),
249
+ choicesLength: Array.isArray(choices) ? choices.length : undefined,
250
+ });
251
+ return {
252
+ success: false,
253
+ error: "Invalid API response format",
254
+ iterations,
255
+ };
256
+ }
257
+ const choice = data.choices[0];
258
+ if (!choice) {
259
+ return {
260
+ success: false,
261
+ error: "Invalid API response format",
262
+ iterations,
263
+ };
264
+ }
265
+ const assistantSequence = (await this.aiSessionManager.getLastSequence(session.id)) + 1;
266
+ const assistantMsg = {
267
+ aiSessionId: session.id,
268
+ sequence: assistantSequence,
269
+ role: "assistant",
270
+ content: choice.message.content ?? "",
271
+ };
272
+ if (choice.message.tool_calls) {
273
+ assistantMsg.toolCalls = choice.message.tool_calls;
274
+ }
275
+ await this.aiSessionManager.addMessage(assistantMsg);
276
+ messages.push({
277
+ role: "assistant",
278
+ content: choice.message.content ?? null,
279
+ tool_calls: choice.message.tool_calls,
280
+ });
281
+ if (choice.message.tool_calls && choice.message.tool_calls.length > 0) {
282
+ for (const toolCall of choice.message.tool_calls) {
283
+ const toolCallId = toolCall.id;
284
+ if (toolCall.function.name === toolSchema.function.name) {
285
+ try {
286
+ const parsed = (() => {
287
+ const raw = toolCall.function.arguments;
288
+ if (typeof raw !== "string") {
289
+ return JSON.parse(JSON.stringify(raw));
290
+ }
291
+ try {
292
+ return JSON.parse(raw);
293
+ }
294
+ catch (e1) {
295
+ const fixed = extractFirstJSON(raw);
296
+ if (fixed) {
297
+ try {
298
+ return JSON.parse(fixed);
299
+ }
300
+ catch {
301
+ const repaired = repairInnerQuotes(fixed);
302
+ if (repaired !== fixed) {
303
+ try {
304
+ return JSON.parse(repaired);
305
+ }
306
+ catch {
307
+ // ignore and fall through to the original parse error
308
+ }
309
+ }
310
+ }
311
+ }
312
+ throw e1;
313
+ }
314
+ })();
315
+ const result = UserProfileValidator.validate(parsed);
316
+ if (!result.valid) {
317
+ throw new Error(result.errors.join(", "));
318
+ }
319
+ await this.addToolResponse(session.id, messages, toolCallId, JSON.stringify({ success: true }));
320
+ return {
321
+ success: true,
322
+ data: result.data,
323
+ iterations,
324
+ };
325
+ }
326
+ catch (validationError) {
327
+ const errorStack = validationError instanceof Error ? validationError.stack : undefined;
328
+ log("OpenAI tool response validation failed", {
329
+ error: String(validationError),
330
+ stack: errorStack,
331
+ errorType: validationError instanceof Error
332
+ ? validationError.constructor.name
333
+ : typeof validationError,
334
+ toolName: toolSchema.function.name,
335
+ iteration: iterations,
336
+ rawArguments: toolCall.function.arguments.slice(0, 500),
337
+ });
338
+ const errorMessage = `Validation failed: ${String(validationError)}`;
339
+ lastErrorMessage = errorMessage;
340
+ await this.addToolResponse(session.id, messages, toolCallId, JSON.stringify({ success: false, error: errorMessage }));
341
+ return {
342
+ success: false,
343
+ error: errorMessage,
344
+ iterations,
345
+ };
346
+ }
347
+ }
348
+ const wrongToolMessage = `Wrong tool called. Please use ${toolSchema.function.name} instead.`;
349
+ await this.addToolResponse(session.id, messages, toolCallId, JSON.stringify({ success: false, error: wrongToolMessage }));
350
+ break;
351
+ }
352
+ }
353
+ const retrySequence = (await this.aiSessionManager.getLastSequence(session.id)) + 1;
354
+ const retryPrompt = lastErrorMessage
355
+ ? `Your previous attempt failed. Error: ${lastErrorMessage}. Please fix the JSON in your tool call arguments and try again. Output ONLY valid JSON, no extra text outside the JSON structure.`
356
+ : "Please use the tool to extract and save the data as instructed.";
357
+ await this.aiSessionManager.addMessage({
358
+ aiSessionId: session.id,
359
+ sequence: retrySequence,
360
+ role: "user",
361
+ content: retryPrompt,
362
+ });
363
+ messages.push({ role: "user", content: retryPrompt });
364
+ }
365
+ catch (error) {
366
+ clearTimeout(timeout);
367
+ if (error instanceof Error && error.name === "AbortError") {
368
+ return {
369
+ success: false,
370
+ error: `API request timeout (${iterationTimeout}ms)`,
371
+ iterations,
372
+ };
373
+ }
374
+ return {
375
+ success: false,
376
+ error: String(error),
377
+ iterations,
378
+ };
379
+ }
380
+ }
381
+ return {
382
+ success: false,
383
+ error: `Max iterations (${maxIterations}) reached without tool call`,
384
+ iterations,
385
+ };
386
+ }
387
+ }
@@ -0,0 +1,13 @@
1
+ import { BaseAIProvider, type ToolCallResult } from "./base-provider.js";
2
+ import { AISessionManager } from "../session/ai-session-manager.js";
3
+ import { type ChatCompletionTool } from "../tools/tool-schema.js";
4
+ export declare class OpenAIResponsesProvider extends BaseAIProvider {
5
+ private aiSessionManager;
6
+ constructor(config: any, aiSessionManager: AISessionManager);
7
+ getProviderName(): string;
8
+ supportsSession(): boolean;
9
+ executeToolCall(systemPrompt: string, userPrompt: string, toolSchema: ChatCompletionTool, sessionId: string): Promise<ToolCallResult>;
10
+ private extractToolCall;
11
+ private buildRetryPrompt;
12
+ private validateResponse;
13
+ }