@4onstudios/iris-agent 0.1.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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +690 -0
  3. package/dist/api/acp/acpServer.d.ts +23 -0
  4. package/dist/api/acp/acpServer.js +814 -0
  5. package/dist/api/acp/index.d.ts +2 -0
  6. package/dist/api/acp/index.js +2 -0
  7. package/dist/api/acp/irisClient.d.ts +58 -0
  8. package/dist/api/acp/irisClient.js +214 -0
  9. package/dist/api/agent.d.ts +14 -0
  10. package/dist/api/agent.js +4171 -0
  11. package/dist/api/backendService.d.ts +4 -0
  12. package/dist/api/backendService.js +14 -0
  13. package/dist/api/core/agent/host/AgentContract.d.ts +82 -0
  14. package/dist/api/core/agent/host/AgentContract.js +1 -0
  15. package/dist/api/core/agent/host/AgentRegistry.d.ts +24 -0
  16. package/dist/api/core/agent/host/AgentRegistry.js +125 -0
  17. package/dist/api/core/agent/host/defaultRegistry.d.ts +15 -0
  18. package/dist/api/core/agent/host/defaultRegistry.js +46 -0
  19. package/dist/api/core/agent/host/externalAgentLifecycle.d.ts +65 -0
  20. package/dist/api/core/agent/host/externalAgentLifecycle.js +117 -0
  21. package/dist/api/core/agent/host/hostSessionManager.d.ts +111 -0
  22. package/dist/api/core/agent/host/hostSessionManager.js +352 -0
  23. package/dist/api/core/agent/host/index.d.ts +5 -0
  24. package/dist/api/core/agent/host/index.js +5 -0
  25. package/dist/api/core/agent/index.d.ts +87 -0
  26. package/dist/api/core/agent/index.js +1024 -0
  27. package/dist/api/core/agent/publicContracts.d.ts +35 -0
  28. package/dist/api/core/agent/publicContracts.js +103 -0
  29. package/dist/api/core/agent/tools/applyDiff.d.ts +51 -0
  30. package/dist/api/core/agent/tools/applyDiff.js +131 -0
  31. package/dist/api/core/agent/tools/backgroundTasks.d.ts +240 -0
  32. package/dist/api/core/agent/tools/backgroundTasks.js +313 -0
  33. package/dist/api/core/agent/tools/createDirectory.d.ts +43 -0
  34. package/dist/api/core/agent/tools/createDirectory.js +77 -0
  35. package/dist/api/core/agent/tools/deleteFile.d.ts +37 -0
  36. package/dist/api/core/agent/tools/deleteFile.js +66 -0
  37. package/dist/api/core/agent/tools/editFile.d.ts +73 -0
  38. package/dist/api/core/agent/tools/editFile.js +173 -0
  39. package/dist/api/core/agent/tools/executeCommand.d.ts +59 -0
  40. package/dist/api/core/agent/tools/executeCommand.js +250 -0
  41. package/dist/api/core/agent/tools/fileContent.d.ts +54 -0
  42. package/dist/api/core/agent/tools/fileContent.js +227 -0
  43. package/dist/api/core/agent/tools/findDefinition.d.ts +72 -0
  44. package/dist/api/core/agent/tools/findDefinition.js +109 -0
  45. package/dist/api/core/agent/tools/findReferences.d.ts +86 -0
  46. package/dist/api/core/agent/tools/findReferences.js +135 -0
  47. package/dist/api/core/agent/tools/formatDocument.d.ts +67 -0
  48. package/dist/api/core/agent/tools/formatDocument.js +90 -0
  49. package/dist/api/core/agent/tools/getCodeActions.d.ts +77 -0
  50. package/dist/api/core/agent/tools/getCodeActions.js +97 -0
  51. package/dist/api/core/agent/tools/getCodeCompletion.d.ts +77 -0
  52. package/dist/api/core/agent/tools/getCodeCompletion.js +174 -0
  53. package/dist/api/core/agent/tools/getCodeContext.d.ts +14 -0
  54. package/dist/api/core/agent/tools/getCodeContext.js +282 -0
  55. package/dist/api/core/agent/tools/getSignatureHelp.d.ts +61 -0
  56. package/dist/api/core/agent/tools/getSignatureHelp.js +85 -0
  57. package/dist/api/core/agent/tools/getSymbols.d.ts +50 -0
  58. package/dist/api/core/agent/tools/getSymbols.js +164 -0
  59. package/dist/api/core/agent/tools/getSymbolsLSP.d.ts +58 -0
  60. package/dist/api/core/agent/tools/getSymbolsLSP.js +147 -0
  61. package/dist/api/core/agent/tools/getTypeInfo.d.ts +70 -0
  62. package/dist/api/core/agent/tools/getTypeInfo.js +84 -0
  63. package/dist/api/core/agent/tools/getWorkspaceInfo.d.ts +80 -0
  64. package/dist/api/core/agent/tools/getWorkspaceInfo.js +281 -0
  65. package/dist/api/core/agent/tools/getWorkspaceSymbols.d.ts +53 -0
  66. package/dist/api/core/agent/tools/getWorkspaceSymbols.js +97 -0
  67. package/dist/api/core/agent/tools/grepSearch.d.ts +100 -0
  68. package/dist/api/core/agent/tools/grepSearch.js +211 -0
  69. package/dist/api/core/agent/tools/languageModelToolsIntegration.d.ts +13 -0
  70. package/dist/api/core/agent/tools/languageModelToolsIntegration.js +22 -0
  71. package/dist/api/core/agent/tools/listDirectory.d.ts +66 -0
  72. package/dist/api/core/agent/tools/listDirectory.js +161 -0
  73. package/dist/api/core/agent/tools/mcpTools.d.ts +48 -0
  74. package/dist/api/core/agent/tools/mcpTools.js +442 -0
  75. package/dist/api/core/agent/tools/queryKnowledgeGraph.d.ts +120 -0
  76. package/dist/api/core/agent/tools/queryKnowledgeGraph.js +306 -0
  77. package/dist/api/core/agent/tools/readFile.d.ts +92 -0
  78. package/dist/api/core/agent/tools/readFile.js +337 -0
  79. package/dist/api/core/agent/tools/renameFile.d.ts +49 -0
  80. package/dist/api/core/agent/tools/renameFile.js +86 -0
  81. package/dist/api/core/agent/tools/renameSymbol.d.ts +70 -0
  82. package/dist/api/core/agent/tools/renameSymbol.js +106 -0
  83. package/dist/api/core/agent/tools/runTerminalCommand.d.ts +72 -0
  84. package/dist/api/core/agent/tools/runTerminalCommand.js +69 -0
  85. package/dist/api/core/agent/tools/searchFiles.d.ts +82 -0
  86. package/dist/api/core/agent/tools/searchFiles.js +280 -0
  87. package/dist/api/core/agent/tools/terminalAutoApprove.d.ts +3 -0
  88. package/dist/api/core/agent/tools/terminalAutoApprove.js +676 -0
  89. package/dist/api/core/agent/tools/treeTraversal.d.ts +60 -0
  90. package/dist/api/core/agent/tools/treeTraversal.js +217 -0
  91. package/dist/api/core/agent/tools/webSearch.d.ts +37 -0
  92. package/dist/api/core/agent/tools/webSearch.js +80 -0
  93. package/dist/api/core/agent/tools/writeFile.d.ts +59 -0
  94. package/dist/api/core/agent/tools/writeFile.js +97 -0
  95. package/dist/api/core/agent/utils/capturedWorkspaceMutationBridge.d.ts +12 -0
  96. package/dist/api/core/agent/utils/capturedWorkspaceMutationBridge.js +67 -0
  97. package/dist/api/core/agent/utils/diffUtils.d.ts +14 -0
  98. package/dist/api/core/agent/utils/diffUtils.js +39 -0
  99. package/dist/api/core/agent/utils/environmentSnapshot.d.ts +42 -0
  100. package/dist/api/core/agent/utils/environmentSnapshot.js +213 -0
  101. package/dist/api/core/agent/utils/errorRecovery.d.ts +49 -0
  102. package/dist/api/core/agent/utils/errorRecovery.js +229 -0
  103. package/dist/api/core/agent/utils/multimodalTokenLimiter.d.ts +8 -0
  104. package/dist/api/core/agent/utils/multimodalTokenLimiter.js +238 -0
  105. package/dist/api/core/agent/utils/openRouterModelSettings.d.ts +12 -0
  106. package/dist/api/core/agent/utils/openRouterModelSettings.js +34 -0
  107. package/dist/api/core/agent/utils/pathRecovery.d.ts +1 -0
  108. package/dist/api/core/agent/utils/pathRecovery.js +29 -0
  109. package/dist/api/core/agent/utils/repoMapIndex.d.ts +3 -0
  110. package/dist/api/core/agent/utils/repoMapIndex.js +197 -0
  111. package/dist/api/core/agent/utils/skillsDiscovery.d.ts +10 -0
  112. package/dist/api/core/agent/utils/skillsDiscovery.js +50 -0
  113. package/dist/api/core/agent/utils/toolCallBudget.d.ts +9 -0
  114. package/dist/api/core/agent/utils/toolCallBudget.js +55 -0
  115. package/dist/api/core/agent/utils/toolLifecycle.d.ts +30 -0
  116. package/dist/api/core/agent/utils/toolLifecycle.js +361 -0
  117. package/dist/api/core/agent/utils/toolResultSafetyProcessor.d.ts +12 -0
  118. package/dist/api/core/agent/utils/toolResultSafetyProcessor.js +57 -0
  119. package/dist/api/core/agent/utils/workspaceMutationBridge.d.ts +13 -0
  120. package/dist/api/core/agent/utils/workspaceMutationBridge.js +149 -0
  121. package/dist/api/core/agent/utils/workspacePathGuard.d.ts +7 -0
  122. package/dist/api/core/agent/utils/workspacePathGuard.js +79 -0
  123. package/dist/api/core/containers/chat/toolResultSerialization.d.ts +8 -0
  124. package/dist/api/core/containers/chat/toolResultSerialization.js +71 -0
  125. package/dist/api/core/library/BrowserManager.d.ts +11 -0
  126. package/dist/api/core/library/BrowserManager.js +66 -0
  127. package/dist/api/core/library/desktopWorkspace.d.ts +1 -0
  128. package/dist/api/core/library/desktopWorkspace.js +3 -0
  129. package/dist/api/core/library/extensionManager.d.ts +10 -0
  130. package/dist/api/core/library/extensionManager.js +27 -0
  131. package/dist/api/core/library/knowledgeGraph.d.ts +268 -0
  132. package/dist/api/core/library/knowledgeGraph.js +989 -0
  133. package/dist/api/core/library/languageModelTools.d.ts +141 -0
  134. package/dist/api/core/library/languageModelTools.js +207 -0
  135. package/dist/api/core/library/localRuntime.d.ts +23 -0
  136. package/dist/api/core/library/localRuntime.js +144 -0
  137. package/dist/api/core/library/lsp/coreLsp.d.ts +367 -0
  138. package/dist/api/core/library/lsp/coreLsp.js +2076 -0
  139. package/dist/api/core/library/lsp/protocol.d.ts +25 -0
  140. package/dist/api/core/library/lsp/protocol.js +1 -0
  141. package/dist/api/core/library/lsp/serverManager.d.ts +37 -0
  142. package/dist/api/core/library/lsp/serverManager.js +427 -0
  143. package/dist/api/core/library/mcpServerProvider.d.ts +69 -0
  144. package/dist/api/core/library/mcpServerProvider.js +152 -0
  145. package/dist/api/core/library/mcpSettings.d.ts +20 -0
  146. package/dist/api/core/library/mcpSettings.js +131 -0
  147. package/dist/api/core/library/patternMatcher.d.ts +66 -0
  148. package/dist/api/core/library/patternMatcher.js +284 -0
  149. package/dist/api/core/library/regexEscape.d.ts +4 -0
  150. package/dist/api/core/library/regexEscape.js +4 -0
  151. package/dist/api/core/library/runtimeEventBus.d.ts +27 -0
  152. package/dist/api/core/library/runtimeEventBus.js +78 -0
  153. package/dist/api/core/library/safetyMiddleware.d.ts +98 -0
  154. package/dist/api/core/library/safetyMiddleware.js +215 -0
  155. package/dist/api/core/library/tauri.d.ts +71 -0
  156. package/dist/api/core/library/tauri.js +222 -0
  157. package/dist/api/core/library/tauriImport.d.ts +5 -0
  158. package/dist/api/core/library/tauriImport.js +7 -0
  159. package/dist/api/core/library/terminalAutoApproveSettings.d.ts +32 -0
  160. package/dist/api/core/library/terminalAutoApproveSettings.js +529 -0
  161. package/dist/api/core/library/workspaceIdentity.d.ts +10 -0
  162. package/dist/api/core/library/workspaceIdentity.js +49 -0
  163. package/dist/api/core/library/workspaceSummary.d.ts +19 -0
  164. package/dist/api/core/library/workspaceSummary.js +35 -0
  165. package/dist/api/core/skills/agent-customization/SKILL.md +27 -0
  166. package/dist/api/core/skills/bug-fix/SKILL.md +21 -0
  167. package/dist/api/core/skills/create-pr/SKILL.md +32 -0
  168. package/dist/api/core/skills/dev-server/SKILL.md +20 -0
  169. package/dist/api/core/skills/fix-suggestions/SKILL.md +21 -0
  170. package/dist/api/core/skills/github-search/SKILL.md +21 -0
  171. package/dist/api/core/skills/github-summary/SKILL.md +25 -0
  172. package/dist/api/core/skills/integration-tests/SKILL.md +29 -0
  173. package/dist/api/core/skills/pr-comments/SKILL.md +23 -0
  174. package/dist/api/core/skills/project-setup/SKILL.md +20 -0
  175. package/dist/api/core/skills/search-integration/SKILL.md +19 -0
  176. package/dist/api/core/skills/search-results/SKILL.md +19 -0
  177. package/dist/api/core/skills/typescript-upgrade/SKILL.md +21 -0
  178. package/dist/api/data/runStore.d.ts +46 -0
  179. package/dist/api/data/runStore.js +244 -0
  180. package/dist/api/helpers/agentUtils.d.ts +11 -0
  181. package/dist/api/helpers/agentUtils.js +23 -0
  182. package/dist/api/helpers/modelTokenLimits.d.ts +2 -0
  183. package/dist/api/helpers/modelTokenLimits.js +158 -0
  184. package/dist/api/helpers/observationalMemory.d.ts +10 -0
  185. package/dist/api/helpers/observationalMemory.js +36 -0
  186. package/dist/api/helpers/promptBudget.d.ts +30 -0
  187. package/dist/api/helpers/promptBudget.js +216 -0
  188. package/dist/api/helpers/resolveImageMessageParts.d.ts +9 -0
  189. package/dist/api/helpers/resolveImageMessageParts.js +140 -0
  190. package/dist/api/helpers/slashCommands.d.ts +31 -0
  191. package/dist/api/helpers/slashCommands.js +129 -0
  192. package/dist/api/helpers/tokenUsage.d.ts +19 -0
  193. package/dist/api/helpers/tokenUsage.js +81 -0
  194. package/dist/api/routes/fileRoutes.d.ts +2 -0
  195. package/dist/api/routes/fileRoutes.js +108 -0
  196. package/dist/api/routes/lspDocumentRoutes.d.ts +4 -0
  197. package/dist/api/routes/lspDocumentRoutes.js +84 -0
  198. package/dist/api/routes/lspHierarchyRoutes.d.ts +4 -0
  199. package/dist/api/routes/lspHierarchyRoutes.js +122 -0
  200. package/dist/api/routes/lspPositionRoutes.d.ts +4 -0
  201. package/dist/api/routes/lspPositionRoutes.js +263 -0
  202. package/dist/api/routes/lspQueryRoutes.d.ts +4 -0
  203. package/dist/api/routes/lspQueryRoutes.js +679 -0
  204. package/dist/api/routes/lspResolveRoutes.d.ts +4 -0
  205. package/dist/api/routes/lspResolveRoutes.js +143 -0
  206. package/dist/api/routes/lspSemanticDocumentRoutes.d.ts +4 -0
  207. package/dist/api/routes/lspSemanticDocumentRoutes.js +98 -0
  208. package/dist/api/routes/semanticRoutes.d.ts +2 -0
  209. package/dist/api/routes/semanticRoutes.js +126 -0
  210. package/dist/cli.d.ts +8 -0
  211. package/dist/cli.js +160 -0
  212. package/dist/index.d.ts +1 -0
  213. package/dist/index.js +1 -0
  214. package/dist/server.d.ts +2 -0
  215. package/dist/server.js +38 -0
  216. package/package.json +100 -0
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Language Model Tools API
3
+ * VS Code-compatible API for registering and managing language model tools
4
+ */
5
+ import { EventEmitter } from "events";
6
+ import type { McpServerConfig } from "./mcpSettings.js";
7
+ /**
8
+ * Represents a tool that can be invoked by a language model
9
+ */
10
+ export interface LanguageModelToolInformation {
11
+ /** Unique tool name */
12
+ readonly name: string;
13
+ /** Description for language model */
14
+ readonly description: string;
15
+ /** JSON schema for input validation */
16
+ readonly inputSchema?: object;
17
+ /** Tags for categorization */
18
+ readonly tags: readonly string[];
19
+ /** Source of the tool (mcp, native, etc.) */
20
+ readonly source: string;
21
+ }
22
+ /**
23
+ * Options for tool invocation
24
+ */
25
+ export interface LanguageModelToolInvocationOptions<T = unknown> {
26
+ /** Tool input matching the schema */
27
+ input: T;
28
+ /** Optional token budget hints */
29
+ tokenizationOptions?: {
30
+ tokenBudget: number;
31
+ countTokens: (text: string) => Promise<number>;
32
+ };
33
+ /** Context from chat request (for UI integration) */
34
+ toolInvocationToken?: unknown;
35
+ }
36
+ /**
37
+ * Result from tool invocation
38
+ */
39
+ export interface LanguageModelToolResult {
40
+ /** Content parts from the tool */
41
+ content: Array<{
42
+ type: "text" | "data" | "error";
43
+ value: string;
44
+ mimeType?: string;
45
+ }>;
46
+ }
47
+ /**
48
+ * A tool that can be registered and invoked
49
+ */
50
+ export interface LanguageModelTool<T = unknown> {
51
+ /**
52
+ * Invoke the tool with the given input
53
+ */
54
+ invoke(options: LanguageModelToolInvocationOptions<T>, signal?: AbortSignal): Promise<LanguageModelToolResult>;
55
+ /**
56
+ * Optional preparation before invocation (for progress/confirmation)
57
+ */
58
+ prepareInvocation?(options: {
59
+ input: T;
60
+ }, signal?: AbortSignal): Promise<{
61
+ invocationMessage?: string;
62
+ confirmationMessages?: {
63
+ title: string;
64
+ message: string;
65
+ };
66
+ }>;
67
+ }
68
+ /**
69
+ * MCP Server Definition Provider
70
+ * Provides available MCP servers dynamically
71
+ */
72
+ export interface McpServerDefinitionProvider {
73
+ /**
74
+ * Provide available MCP servers
75
+ */
76
+ provideMcpServerDefinitions(signal?: AbortSignal): Promise<McpServerConfig[]>;
77
+ /**
78
+ * Optional: resolve server before starting (e.g., for authentication)
79
+ */
80
+ resolveMcpServerDefinition?(server: McpServerConfig, signal?: AbortSignal): Promise<McpServerConfig>;
81
+ /**
82
+ * Optional: event when servers change
83
+ */
84
+ onDidChangeMcpServerDefinitions?: (listener: () => void) => () => void;
85
+ }
86
+ /**
87
+ * Disposable pattern for cleanup
88
+ */
89
+ export interface Disposable {
90
+ dispose(): void;
91
+ }
92
+ /**
93
+ * Language Model Tools Manager
94
+ * Manages tool registration and discovery
95
+ */
96
+ export declare class LanguageModelToolsManager extends EventEmitter {
97
+ private tools;
98
+ private toolInfo;
99
+ private mcpProviders;
100
+ private mcpServerCache;
101
+ private workspacePath;
102
+ constructor();
103
+ /**
104
+ * Set workspace path for MCP servers
105
+ */
106
+ setWorkspacePath(path: string | null): void;
107
+ /**
108
+ * Register a native tool
109
+ */
110
+ registerTool<T = unknown>(name: string, tool: LanguageModelTool<T>, info: Omit<LanguageModelToolInformation, "name" | "source">): Disposable;
111
+ /**
112
+ * Register an MCP server definition provider
113
+ */
114
+ registerMcpServerDefinitionProvider(id: string, provider: McpServerDefinitionProvider): Disposable;
115
+ /**
116
+ * Get all available tools (native + MCP)
117
+ */
118
+ getAvailableTools(signal?: AbortSignal): Promise<LanguageModelToolInformation[]>;
119
+ /**
120
+ * Invoke a tool by name
121
+ */
122
+ invokeTool(name: string, options: LanguageModelToolInvocationOptions, signal?: AbortSignal): Promise<LanguageModelToolResult>;
123
+ /**
124
+ * Invoke an MCP tool
125
+ */
126
+ private invokeMcpTool;
127
+ /**
128
+ * Get all MCP servers from all providers
129
+ */
130
+ private getAllMcpServers;
131
+ /**
132
+ * Generate MCP tool key (matches mcpTools.ts format)
133
+ */
134
+ private getMcpToolKey;
135
+ /**
136
+ * Listen for tool changes
137
+ */
138
+ onDidChangeTools(listener: () => void): Disposable;
139
+ }
140
+ export declare const languageModelTools: LanguageModelToolsManager;
141
+ export default LanguageModelToolsManager;
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Language Model Tools API
3
+ * VS Code-compatible API for registering and managing language model tools
4
+ */
5
+ import { EventEmitter } from "events";
6
+ import { listMcpServerTools, executeMcpToolByKey } from "../agent/tools/mcpTools.js";
7
+ /**
8
+ * Language Model Tools Manager
9
+ * Manages tool registration and discovery
10
+ */
11
+ export class LanguageModelToolsManager extends EventEmitter {
12
+ tools = new Map();
13
+ toolInfo = new Map();
14
+ mcpProviders = new Map();
15
+ mcpServerCache = new Map();
16
+ workspacePath = null;
17
+ constructor() {
18
+ super();
19
+ }
20
+ /**
21
+ * Set workspace path for MCP servers
22
+ */
23
+ setWorkspacePath(path) {
24
+ this.workspacePath = path;
25
+ // Clear cache when workspace changes
26
+ this.mcpServerCache.clear();
27
+ this.emit("toolsChanged");
28
+ }
29
+ /**
30
+ * Register a native tool
31
+ */
32
+ registerTool(name, tool, info) {
33
+ this.tools.set(name, tool);
34
+ this.toolInfo.set(name, {
35
+ name,
36
+ description: info.description,
37
+ inputSchema: info.inputSchema,
38
+ tags: info.tags,
39
+ source: "native",
40
+ });
41
+ this.emit("toolsChanged");
42
+ return {
43
+ dispose: () => {
44
+ this.tools.delete(name);
45
+ this.toolInfo.delete(name);
46
+ this.emit("toolsChanged");
47
+ },
48
+ };
49
+ }
50
+ /**
51
+ * Register an MCP server definition provider
52
+ */
53
+ registerMcpServerDefinitionProvider(id, provider) {
54
+ this.mcpProviders.set(id, provider);
55
+ // Listen for changes if provider supports it
56
+ let unsubscribe;
57
+ if (provider.onDidChangeMcpServerDefinitions) {
58
+ unsubscribe = provider.onDidChangeMcpServerDefinitions(() => {
59
+ this.mcpServerCache.delete(id);
60
+ this.emit("toolsChanged");
61
+ });
62
+ }
63
+ this.emit("toolsChanged");
64
+ return {
65
+ dispose: () => {
66
+ this.mcpProviders.delete(id);
67
+ this.mcpServerCache.delete(id);
68
+ if (unsubscribe)
69
+ unsubscribe();
70
+ this.emit("toolsChanged");
71
+ },
72
+ };
73
+ }
74
+ /**
75
+ * Get all available tools (native + MCP)
76
+ */
77
+ async getAvailableTools(signal) {
78
+ const tools = [];
79
+ // Add native tools
80
+ tools.push(...Array.from(this.toolInfo.values()));
81
+ // Add MCP tools from all providers
82
+ const mcpServers = await this.getAllMcpServers(signal);
83
+ const workspacePath = this.workspacePath || process.cwd();
84
+ for (const server of mcpServers) {
85
+ if (!server.enabled)
86
+ continue;
87
+ try {
88
+ const serverTools = await listMcpServerTools(server, workspacePath);
89
+ for (const tool of serverTools) {
90
+ const toolKey = this.getMcpToolKey(server.name, tool.name);
91
+ tools.push({
92
+ name: toolKey,
93
+ description: tool.description || `MCP tool: ${tool.name}`,
94
+ inputSchema: tool.inputSchema,
95
+ tags: ["mcp", server.name],
96
+ source: `mcp:${server.name}`,
97
+ });
98
+ }
99
+ }
100
+ catch (error) {
101
+ console.error(`Failed to list tools from ${server.name}:`, error);
102
+ }
103
+ }
104
+ return tools;
105
+ }
106
+ /**
107
+ * Invoke a tool by name
108
+ */
109
+ async invokeTool(name, options, signal) {
110
+ // Check if it's a native tool
111
+ const nativeTool = this.tools.get(name);
112
+ if (nativeTool) {
113
+ return nativeTool.invoke(options, signal);
114
+ }
115
+ // Check if it's an MCP tool
116
+ if (name.startsWith("mcp_")) {
117
+ return this.invokeMcpTool(name, options, signal);
118
+ }
119
+ throw new Error(`Tool '${name}' not found`);
120
+ }
121
+ /**
122
+ * Invoke an MCP tool
123
+ */
124
+ async invokeMcpTool(toolKey, options, signal) {
125
+ const mcpServers = await this.getAllMcpServers(signal);
126
+ const workspacePath = this.workspacePath || process.cwd();
127
+ const result = await executeMcpToolByKey(mcpServers, workspacePath, toolKey, options.input);
128
+ if (!result.success) {
129
+ return {
130
+ content: [
131
+ {
132
+ type: "error",
133
+ value: result.error || "MCP tool execution failed",
134
+ },
135
+ ],
136
+ };
137
+ }
138
+ // At this point, result.success is true, so we can safely access optional content
139
+ // TypeScript can't narrow the union type properly, so we explicitly cast
140
+ const successResult = result;
141
+ // Convert MCP result to LanguageModelToolResult format
142
+ const content = [];
143
+ if (Array.isArray(successResult.content)) {
144
+ for (const item of successResult.content) {
145
+ if (typeof item === "object" && item !== null) {
146
+ const mcpItem = item;
147
+ if (mcpItem.text) {
148
+ content.push({
149
+ type: "text",
150
+ value: mcpItem.text,
151
+ });
152
+ }
153
+ else if (mcpItem.message) {
154
+ content.push({
155
+ type: "text",
156
+ value: mcpItem.message,
157
+ });
158
+ }
159
+ }
160
+ }
161
+ }
162
+ if (content.length === 0 && successResult.content !== undefined) {
163
+ content.push({
164
+ type: "text",
165
+ value: JSON.stringify(successResult.content, null, 2),
166
+ });
167
+ }
168
+ return { content };
169
+ }
170
+ /**
171
+ * Get all MCP servers from all providers
172
+ */
173
+ async getAllMcpServers(signal) {
174
+ const allServers = [];
175
+ for (const [id, provider] of this.mcpProviders.entries()) {
176
+ // Check cache first
177
+ let servers = this.mcpServerCache.get(id);
178
+ if (!servers) {
179
+ servers = await provider.provideMcpServerDefinitions(signal);
180
+ this.mcpServerCache.set(id, servers);
181
+ }
182
+ allServers.push(...servers);
183
+ }
184
+ return allServers;
185
+ }
186
+ /**
187
+ * Generate MCP tool key (matches mcpTools.ts format)
188
+ */
189
+ getMcpToolKey(serverName, toolName) {
190
+ const safeToken = (value) => value.replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 80);
191
+ return `mcp_${safeToken(serverName)}_${safeToken(toolName)}`;
192
+ }
193
+ /**
194
+ * Listen for tool changes
195
+ */
196
+ onDidChangeTools(listener) {
197
+ this.on("toolsChanged", listener);
198
+ return {
199
+ dispose: () => {
200
+ this.off("toolsChanged", listener);
201
+ },
202
+ };
203
+ }
204
+ }
205
+ // Singleton instance
206
+ export const languageModelTools = new LanguageModelToolsManager();
207
+ export default LanguageModelToolsManager;
@@ -0,0 +1,23 @@
1
+ export declare const API_KEYS_STORAGE_KEY = "settings.apiKeys";
2
+ export declare const DEFAULT_LOCAL_RUNTIME_BASE_URL = "http://127.0.0.1:11434/v1";
3
+ export declare const DEFAULT_LOCAL_RUNTIME_API_KEY = "ollama";
4
+ export type LocalRuntimeHealthResult = {
5
+ ok: boolean;
6
+ message: string;
7
+ probeUrl: string;
8
+ /** True when the probe was aborted due to timeout (as opposed to a hard connection error). */
9
+ timedOut?: boolean;
10
+ };
11
+ export declare const isLocalModelId: (modelId: string) => boolean;
12
+ export declare const getLocalRuntimeConfigFromStorage: () => {
13
+ baseUrl: string;
14
+ apiKey: string;
15
+ };
16
+ export declare const checkLocalRuntimeConnection: (baseUrl: string, apiKey?: string, timeoutMs?: number) => Promise<LocalRuntimeHealthResult>;
17
+ /**
18
+ * Check local runtime connection with built-in caching to avoid repeated probes.
19
+ * Uses a short TTL (60s for successful, 5s for failed) to prevent latency regressions
20
+ * during repeated chat invocations while still allowing quick error recovery.
21
+ * All probes use HEALTH_CHECK_TIMEOUT_MS regardless of host.
22
+ */
23
+ export declare const checkLocalRuntimeConnectionCached: (baseUrl: string, apiKey?: string) => Promise<LocalRuntimeHealthResult>;
@@ -0,0 +1,144 @@
1
+ export const API_KEYS_STORAGE_KEY = "settings.apiKeys";
2
+ export const DEFAULT_LOCAL_RUNTIME_BASE_URL = "http://127.0.0.1:11434/v1";
3
+ export const DEFAULT_LOCAL_RUNTIME_API_KEY = "ollama";
4
+ // Cache for health check results to avoid repeated probes.
5
+ // Keyed by normalized baseUrl + a non-reversible fingerprint of apiKey.
6
+ // This avoids storing raw secrets in memory while preventing cache collisions
7
+ // across different keys for the same endpoint.
8
+ const HEALTH_CHECK_CACHE = new Map();
9
+ const HEALTH_CHECK_CACHE_MAX_SIZE = 8; // evict oldest entry when exceeded
10
+ const HEALTH_CHECK_TTL_MS = 60000; // Cache for 60 seconds
11
+ const HEALTH_CHECK_FAILED_TTL_MS = 5000; // Cache failures for 5 seconds only
12
+ const HEALTH_CHECK_TIMEOUT_MS = 1500; // 1500ms balances cold-start tolerance vs. latency
13
+ export const isLocalModelId = (modelId) => modelId.startsWith("ollama/") || modelId.startsWith("local/");
14
+ const trimTrailingSlash = (value) => value.replace(/\/$/, "");
15
+ // Produces a short, non-reversible fingerprint of the API key so that cache
16
+ // entries for different keys on the same baseUrl are not conflated, without
17
+ // retaining the raw secret in the Map key.
18
+ const fingerprintApiKey = (apiKey) => {
19
+ if (!apiKey)
20
+ return "";
21
+ let hash = 5381;
22
+ for (let i = 0; i < apiKey.length; i++) {
23
+ hash = (((hash << 5) + hash) ^ apiKey.charCodeAt(i)) >>> 0;
24
+ }
25
+ return hash.toString(36);
26
+ };
27
+ const normalizeBaseUrl = (value) => {
28
+ const trimmed = (value || "").trim();
29
+ if (!trimmed)
30
+ return DEFAULT_LOCAL_RUNTIME_BASE_URL;
31
+ const candidate = trimTrailingSlash(trimmed);
32
+ try {
33
+ const parsed = new URL(candidate);
34
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
35
+ return DEFAULT_LOCAL_RUNTIME_BASE_URL;
36
+ }
37
+ return candidate;
38
+ }
39
+ catch {
40
+ return DEFAULT_LOCAL_RUNTIME_BASE_URL;
41
+ }
42
+ };
43
+ const buildProbeUrl = (baseUrl) => {
44
+ const normalized = normalizeBaseUrl(baseUrl);
45
+ return `${normalized}/models`;
46
+ };
47
+ export const getLocalRuntimeConfigFromStorage = () => {
48
+ if (typeof window === "undefined") {
49
+ return {
50
+ baseUrl: DEFAULT_LOCAL_RUNTIME_BASE_URL,
51
+ apiKey: DEFAULT_LOCAL_RUNTIME_API_KEY,
52
+ };
53
+ }
54
+ try {
55
+ const raw = localStorage.getItem(API_KEYS_STORAGE_KEY);
56
+ const parsed = raw ? JSON.parse(raw) : {};
57
+ return {
58
+ baseUrl: normalizeBaseUrl(parsed?.OLLAMA_BASE_URL),
59
+ apiKey: (parsed?.OLLAMA_API_KEY || DEFAULT_LOCAL_RUNTIME_API_KEY).trim(),
60
+ };
61
+ }
62
+ catch {
63
+ return {
64
+ baseUrl: DEFAULT_LOCAL_RUNTIME_BASE_URL,
65
+ apiKey: DEFAULT_LOCAL_RUNTIME_API_KEY,
66
+ };
67
+ }
68
+ };
69
+ export const checkLocalRuntimeConnection = async (baseUrl, apiKey, timeoutMs = 3000) => {
70
+ const probeUrl = buildProbeUrl(baseUrl);
71
+ const controller = new AbortController();
72
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
73
+ try {
74
+ const headers = {};
75
+ if (apiKey && apiKey.trim().length > 0) {
76
+ headers.Authorization = `Bearer ${apiKey.trim()}`;
77
+ }
78
+ const res = await fetch(probeUrl, {
79
+ method: "GET",
80
+ headers,
81
+ signal: controller.signal,
82
+ });
83
+ if (!res.ok) {
84
+ return {
85
+ ok: false,
86
+ message: `Runtime responded with HTTP ${res.status}`,
87
+ probeUrl,
88
+ };
89
+ }
90
+ const payload = (await res.json().catch(() => ({})));
91
+ const modelCount = Array.isArray(payload?.data) ? payload.data.length : undefined;
92
+ return {
93
+ ok: true,
94
+ message: modelCount !== undefined ? `Connected (${modelCount} model${modelCount === 1 ? "" : "s"} available)` : "Connected",
95
+ probeUrl,
96
+ };
97
+ }
98
+ catch (err) {
99
+ const timedOut = err instanceof Error && err.name === "AbortError";
100
+ const message = timedOut ? "Connection timed out" : err instanceof Error ? err.message : "Connection failed";
101
+ return {
102
+ ok: false,
103
+ message,
104
+ probeUrl,
105
+ timedOut,
106
+ };
107
+ }
108
+ finally {
109
+ clearTimeout(timeout);
110
+ }
111
+ };
112
+ /**
113
+ * Check local runtime connection with built-in caching to avoid repeated probes.
114
+ * Uses a short TTL (60s for successful, 5s for failed) to prevent latency regressions
115
+ * during repeated chat invocations while still allowing quick error recovery.
116
+ * All probes use HEALTH_CHECK_TIMEOUT_MS regardless of host.
117
+ */
118
+ export const checkLocalRuntimeConnectionCached = async (baseUrl, apiKey) => {
119
+ const cacheKey = `${normalizeBaseUrl(baseUrl)}:${fingerprintApiKey(apiKey)}`;
120
+ const cached = HEALTH_CHECK_CACHE.get(cacheKey);
121
+ // Return cached result if still valid
122
+ if (cached) {
123
+ const age = Date.now() - cached.timestamp;
124
+ const ttl = cached.result.ok ? HEALTH_CHECK_TTL_MS : HEALTH_CHECK_FAILED_TTL_MS;
125
+ if (age < ttl) {
126
+ return cached.result;
127
+ }
128
+ }
129
+ // Cache miss or expired - perform fresh check
130
+ const result = await checkLocalRuntimeConnection(baseUrl, apiKey, HEALTH_CHECK_TIMEOUT_MS);
131
+ // Don't cache timeout failures — the runtime may just be slow to start;
132
+ // the next invocation should retry immediately rather than hitting a stale negative.
133
+ if (!result.timedOut) {
134
+ // Evict the oldest entry before inserting when the cache is at capacity.
135
+ if (!HEALTH_CHECK_CACHE.has(cacheKey) && HEALTH_CHECK_CACHE.size >= HEALTH_CHECK_CACHE_MAX_SIZE) {
136
+ const oldestKey = HEALTH_CHECK_CACHE.keys().next().value;
137
+ if (oldestKey !== undefined) {
138
+ HEALTH_CHECK_CACHE.delete(oldestKey);
139
+ }
140
+ }
141
+ HEALTH_CHECK_CACHE.set(cacheKey, { result, timestamp: Date.now() });
142
+ }
143
+ return result;
144
+ };