@hailer/mcp 0.1.8 → 0.1.9

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 (135) hide show
  1. package/.claude/agents/agent-dmitri-activity-crud.md +3 -1
  2. package/.claude/agents/agent-giuseppe-app-builder.md +11 -12
  3. package/.claude/agents/agent-kenji-data-reader.md +5 -3
  4. package/.claude/skills/hailer-app-builder/SKILL.md +506 -0
  5. package/.claude/skills/publish-hailer-app/SKILL.md +169 -0
  6. package/.claude/skills/tool-parameter-usage/SKILL.md +112 -0
  7. package/CLAUDE.md +6 -2
  8. package/REFACTOR_STATUS.md +127 -0
  9. package/dist/cli.js +0 -0
  10. package/dist/client/agents/base.d.ts +202 -0
  11. package/dist/client/agents/base.js +737 -0
  12. package/dist/client/agents/definitions.d.ts +53 -0
  13. package/dist/client/agents/definitions.js +178 -0
  14. package/dist/client/agents/orchestrator.d.ts +119 -0
  15. package/dist/client/agents/orchestrator.js +760 -0
  16. package/dist/client/agents/specialist.d.ts +86 -0
  17. package/dist/client/agents/specialist.js +340 -0
  18. package/dist/client/bot-manager.d.ts +44 -0
  19. package/dist/client/bot-manager.js +173 -0
  20. package/dist/client/chat-agent-daemon.d.ts +464 -0
  21. package/dist/client/chat-agent-daemon.js +1774 -0
  22. package/dist/client/daemon-factory.d.ts +106 -0
  23. package/dist/client/daemon-factory.js +301 -0
  24. package/dist/client/factory.d.ts +107 -0
  25. package/dist/client/factory.js +304 -0
  26. package/dist/client/index.d.ts +17 -0
  27. package/dist/client/index.js +38 -0
  28. package/dist/client/multi-bot-manager.d.ts +18 -0
  29. package/dist/client/multi-bot-manager.js +88 -1
  30. package/dist/client/orchestrator-daemon.d.ts +87 -0
  31. package/dist/client/orchestrator-daemon.js +444 -0
  32. package/dist/client/services/agent-registry.d.ts +108 -0
  33. package/dist/client/services/agent-registry.js +630 -0
  34. package/dist/client/services/conversation-manager.d.ts +50 -0
  35. package/dist/client/services/conversation-manager.js +136 -0
  36. package/dist/client/services/mcp-client.d.ts +48 -0
  37. package/dist/client/services/mcp-client.js +105 -0
  38. package/dist/client/services/message-classifier.d.ts +37 -0
  39. package/dist/client/services/message-classifier.js +187 -0
  40. package/dist/client/services/message-formatter.d.ts +84 -0
  41. package/dist/client/services/message-formatter.js +353 -0
  42. package/dist/client/services/session-logger.d.ts +106 -0
  43. package/dist/client/services/session-logger.js +446 -0
  44. package/dist/client/services/tool-executor.d.ts +41 -0
  45. package/dist/client/services/tool-executor.js +169 -0
  46. package/dist/client/services/workspace-schema-cache.d.ts +149 -0
  47. package/dist/client/services/workspace-schema-cache.js +732 -0
  48. package/dist/client/specialist-daemon.d.ts +77 -0
  49. package/dist/client/specialist-daemon.js +197 -0
  50. package/dist/client/specialists.d.ts +53 -0
  51. package/dist/client/specialists.js +178 -0
  52. package/dist/client/tool-schema-loader.d.ts +4 -3
  53. package/dist/client/tool-schema-loader.js +54 -8
  54. package/dist/client/types.d.ts +283 -55
  55. package/dist/client/types.js +113 -2
  56. package/dist/config.d.ts +1 -1
  57. package/dist/config.js +1 -1
  58. package/dist/core.d.ts +10 -2
  59. package/dist/core.js +43 -27
  60. package/dist/lib/logger.js +15 -3
  61. package/dist/mcp/UserContextCache.js +2 -2
  62. package/dist/mcp/hailer-clients.js +5 -5
  63. package/dist/mcp/signal-handler.js +27 -5
  64. package/dist/mcp/tools/activity.js +137 -65
  65. package/dist/mcp/tools/app-core.js +4 -140
  66. package/dist/mcp/tools/app-marketplace.js +15 -260
  67. package/dist/mcp/tools/app-member.js +2 -73
  68. package/dist/mcp/tools/app-scaffold.js +146 -87
  69. package/dist/mcp/tools/discussion.js +348 -73
  70. package/dist/mcp/tools/insight.js +74 -190
  71. package/dist/mcp/tools/workflow.js +20 -94
  72. package/dist/mcp/utils/hailer-api-client.d.ts +4 -2
  73. package/dist/mcp/utils/hailer-api-client.js +24 -10
  74. package/dist/mcp-server.d.ts +4 -0
  75. package/dist/mcp-server.js +24 -4
  76. package/dist/routes/agents.d.ts +44 -0
  77. package/dist/routes/agents.js +311 -0
  78. package/dist/services/agent-credential-store.d.ts +73 -0
  79. package/dist/services/agent-credential-store.js +212 -0
  80. package/lineup-manager/dist/assets/index-8ce6041d.css +1 -0
  81. package/lineup-manager/dist/assets/index-e168f265.js +600 -0
  82. package/lineup-manager/dist/index.html +15 -0
  83. package/lineup-manager/dist/manifest.json +17 -0
  84. package/lineup-manager/dist/vite.svg +1 -0
  85. package/package.json +1 -1
  86. package/dist/client/adaptive-documentation-bot.d.ts +0 -106
  87. package/dist/client/adaptive-documentation-bot.js +0 -464
  88. package/dist/client/adaptive-documentation-types.d.ts +0 -66
  89. package/dist/client/adaptive-documentation-types.js +0 -9
  90. package/dist/client/agent-activity-bot.d.ts +0 -51
  91. package/dist/client/agent-activity-bot.js +0 -166
  92. package/dist/client/agent-tracker.d.ts +0 -499
  93. package/dist/client/agent-tracker.js +0 -659
  94. package/dist/client/description-updater.d.ts +0 -56
  95. package/dist/client/description-updater.js +0 -259
  96. package/dist/client/log-parser.d.ts +0 -72
  97. package/dist/client/log-parser.js +0 -387
  98. package/dist/client/mcp-assistant.d.ts +0 -21
  99. package/dist/client/mcp-assistant.js +0 -58
  100. package/dist/client/mcp-client.d.ts +0 -50
  101. package/dist/client/mcp-client.js +0 -538
  102. package/dist/client/message-processor.d.ts +0 -35
  103. package/dist/client/message-processor.js +0 -357
  104. package/dist/client/providers/anthropic-provider.d.ts +0 -19
  105. package/dist/client/providers/anthropic-provider.js +0 -645
  106. package/dist/client/providers/assistant-provider.d.ts +0 -17
  107. package/dist/client/providers/assistant-provider.js +0 -51
  108. package/dist/client/providers/llm-provider.d.ts +0 -47
  109. package/dist/client/providers/llm-provider.js +0 -367
  110. package/dist/client/providers/openai-provider.d.ts +0 -23
  111. package/dist/client/providers/openai-provider.js +0 -630
  112. package/dist/client/simple-llm-caller.d.ts +0 -19
  113. package/dist/client/simple-llm-caller.js +0 -100
  114. package/dist/client/skill-generator.d.ts +0 -81
  115. package/dist/client/skill-generator.js +0 -386
  116. package/dist/client/test-adaptive-bot.d.ts +0 -9
  117. package/dist/client/test-adaptive-bot.js +0 -82
  118. package/dist/client/token-pricing.d.ts +0 -38
  119. package/dist/client/token-pricing.js +0 -127
  120. package/dist/client/token-tracker.d.ts +0 -232
  121. package/dist/client/token-tracker.js +0 -457
  122. package/dist/client/token-usage-bot.d.ts +0 -53
  123. package/dist/client/token-usage-bot.js +0 -153
  124. package/dist/client/tool-executor.d.ts +0 -69
  125. package/dist/client/tool-executor.js +0 -159
  126. package/dist/lib/materialize.d.ts +0 -3
  127. package/dist/lib/materialize.js +0 -101
  128. package/dist/lib/normalizedName.d.ts +0 -7
  129. package/dist/lib/normalizedName.js +0 -48
  130. package/dist/lib/terminal-prompt.d.ts +0 -9
  131. package/dist/lib/terminal-prompt.js +0 -108
  132. package/dist/mcp/tools/skill.d.ts +0 -10
  133. package/dist/mcp/tools/skill.js +0 -279
  134. package/dist/mcp/tools/workflow-template.d.ts +0 -19
  135. package/dist/mcp/tools/workflow-template.js +0 -822
@@ -1,645 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AnthropicProvider = void 0;
7
- const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
- const llm_provider_1 = require("./llm-provider");
9
- const context_manager_1 = require("../../lib/context-manager");
10
- const token_pricing_1 = require("../token-pricing");
11
- const tool_registry_1 = require("../../mcp/tool-registry");
12
- const tool_schema_loader_1 = require("../tool-schema-loader");
13
- const tool_executor_1 = require("../tool-executor");
14
- class AnthropicProvider extends llm_provider_1.LlmProvider {
15
- client;
16
- contextManager;
17
- toolSchemaLoader = new tool_schema_loader_1.ToolSchemaLoader();
18
- toolExecutor = new tool_executor_1.ToolExecutor();
19
- // Deprecated - kept for backwards compatibility during migration
20
- toolSchemaCache = new Map();
21
- constructor(config) {
22
- super(config);
23
- this.client = new sdk_1.default({
24
- apiKey: config.apiKey,
25
- });
26
- this.contextManager = (0, context_manager_1.getContextManager)({
27
- anthropicApiKey: config.apiKey,
28
- safetyMarginPercent: 25,
29
- enableAutoSummarization: true,
30
- maxSummarizationChunks: 10,
31
- });
32
- }
33
- async generateConfirmationMessage(userMessage) {
34
- if (!this.isEnabled()) {
35
- return `🤖 Processing your request with ${this.name}...`;
36
- }
37
- try {
38
- const confirmationPrompt = this.getConfirmationPrompt(userMessage);
39
- const response = await this.client.messages.create({
40
- model: this.config.model || "claude-sonnet-4-20250514",
41
- max_tokens: 100,
42
- temperature: 0.7,
43
- messages: [
44
- {
45
- role: "user",
46
- content: confirmationPrompt,
47
- },
48
- ],
49
- });
50
- const confirmationText = response.content
51
- .filter((content) => content.type === "text")
52
- .map((content) => content.text)
53
- .join("\n")
54
- .trim() ||
55
- `🤖 Processing your request with ${this.name}...`;
56
- return confirmationText;
57
- }
58
- catch (error) {
59
- this.logError(error, "generateConfirmationMessage");
60
- return `🤖 Processing your request with ${this.name}...`;
61
- }
62
- }
63
- async processMessage(userMessage, mcpServerUrl, botMcpApiKey, botEmail) {
64
- if (!this.isEnabled()) {
65
- this.logger.error("Anthropic provider is not enabled or missing API key");
66
- return {
67
- success: false,
68
- error: "Anthropic provider is not enabled or missing API key",
69
- };
70
- }
71
- try {
72
- const systemPrompt = await this.createSystemPrompt({
73
- userMessage,
74
- mcpServerUrl,
75
- mcpServerApiKey: botMcpApiKey,
76
- botEmail,
77
- });
78
- const startTime = Date.now();
79
- // Load lightweight tool index with automatic filtering
80
- // Chat bot only gets READ + WRITE tools (no PLAYGROUND tools)
81
- const allowedGroups = [tool_registry_1.ToolGroup.READ, tool_registry_1.ToolGroup.WRITE];
82
- const toolIndex = await this.toolSchemaLoader.loadToolIndex({
83
- mcpServerUrl,
84
- mcpServerApiKey: botMcpApiKey,
85
- allowedGroups
86
- });
87
- // Convert to minimal tool stubs (full schemas loaded on-demand)
88
- const minimalTools = this.toolSchemaLoader.toMinimalToolDefinitions(toolIndex);
89
- // Track which tools have been loaded with full schemas
90
- const loadedToolSchemas = new Map();
91
- this.logger.info("Connected to MCP server (on-demand mode)", {
92
- toolsForChatBot: toolIndex.length,
93
- allowedGroups: allowedGroups.join(', '),
94
- initialTokensSaved: "~28,000 tokens (95% reduction)"
95
- });
96
- // Initial prompt is simple and unlikely to need truncation, let Claude 4 handle it
97
- const finalSystemPrompt = systemPrompt;
98
- const finalUserContent = this.removeMentions(userMessage);
99
- // Check token count before initial API call (with minimal tools)
100
- const initialMessages = [{ role: "user", content: finalUserContent }];
101
- const initialTokenCount = this.contextManager.countTokens(finalSystemPrompt, initialMessages, minimalTools, 'anthropic');
102
- this.logger.info("Initial prompt token count (on-demand mode)", {
103
- totalTokens: initialTokenCount.totalTokens,
104
- systemPromptTokens: initialTokenCount.systemPromptTokens,
105
- messagesTokens: initialTokenCount.messagesTokens,
106
- toolsTokens: initialTokenCount.toolsTokens,
107
- safeLimit: initialTokenCount.limit.safeTokens,
108
- exceedsLimit: initialTokenCount.exceedsLimit,
109
- note: "Using minimal tool stubs - full schemas loaded on-demand"
110
- });
111
- if (initialTokenCount.exceedsLimit) {
112
- this.logger.error("Initial prompt exceeds token limit", {
113
- totalTokens: initialTokenCount.totalTokens,
114
- safeLimit: initialTokenCount.limit.safeTokens,
115
- });
116
- return {
117
- success: false,
118
- error: `Initial prompt too long: ${initialTokenCount.totalTokens} tokens exceeds safe limit of ${initialTokenCount.limit.safeTokens} tokens`,
119
- };
120
- }
121
- // Enable structured outputs with strict mode for schema validation
122
- const strictTools = minimalTools.map(tool => ({
123
- ...tool,
124
- strict: true
125
- }));
126
- let response = await this.client.beta.messages.create({
127
- model: this.config.model || "claude-sonnet-4-20250514",
128
- max_tokens: this.config.maxTokens || 2000,
129
- temperature: this.config.temperature || 0.7,
130
- betas: ['structured-outputs-2025-11-13'],
131
- system: [
132
- {
133
- type: "text",
134
- text: finalSystemPrompt,
135
- cache_control: { type: "ephemeral" }
136
- }
137
- ],
138
- messages: [
139
- {
140
- role: "user",
141
- content: finalUserContent,
142
- },
143
- ],
144
- tools: strictTools,
145
- });
146
- const toolCalls = [];
147
- // No conversation history - process each message independently
148
- const currentUserContent = this.removeMentions(userMessage);
149
- const conversationMessages = [{
150
- role: "user",
151
- content: currentUserContent,
152
- }];
153
- // Track token usage across all API calls
154
- let totalInputTokens = 0;
155
- let totalOutputTokens = 0;
156
- let totalCacheCreation = 0;
157
- let totalCacheRead = 0;
158
- // Accumulate tokens from initial response
159
- if (response.usage) {
160
- totalInputTokens += response.usage.input_tokens;
161
- totalOutputTokens += response.usage.output_tokens;
162
- totalCacheCreation += response.usage.cache_creation_input_tokens || 0;
163
- totalCacheRead += response.usage.cache_read_input_tokens || 0;
164
- }
165
- let maxIterations = 25;
166
- while (maxIterations > 0 &&
167
- response.content.some((content) => content.type === "tool_use")) {
168
- maxIterations--;
169
- if (maxIterations === 0) {
170
- this.logger.warn("Max iteration limit reached, generating final response with current tool results", {
171
- botId: userMessage.mentionedOrDirectMessagedBotId,
172
- totalIterations: 25,
173
- });
174
- break; // Exit the loop but continue to generate response
175
- }
176
- // Add assistant's response to conversation
177
- conversationMessages.push({
178
- role: "assistant",
179
- content: response.content,
180
- });
181
- // Build optimized tool set: full schemas for used tools, minimal stubs for others
182
- const optimizedTools = minimalTools.map((tool, index) => {
183
- let toolDef = tool;
184
- if (loadedToolSchemas.has(tool.name)) {
185
- toolDef = loadedToolSchemas.get(tool.name);
186
- }
187
- // Add cache control to last tool in array for maximum caching
188
- if (index === minimalTools.length - 1) {
189
- toolDef = { ...toolDef, cache_control: { type: "ephemeral" } };
190
- }
191
- return toolDef;
192
- });
193
- const toolResults = [];
194
- const schemasJustLoaded = [];
195
- // First pass: Check if any tools need schema loading
196
- for (const content of response.content) {
197
- if (content.type === "tool_use") {
198
- if (!loadedToolSchemas.has(content.name)) {
199
- this.logger.info("Tool schema needed - loading before execution", { toolName: content.name });
200
- const fullSchema = await this.fetchMcpToolSchema(mcpServerUrl, botMcpApiKey, content.name);
201
- loadedToolSchemas.set(content.name, fullSchema);
202
- schemasJustLoaded.push(content.name);
203
- this.logger.debug("Tool schema loaded and will be sent to Claude", {
204
- toolName: content.name,
205
- totalLoaded: loadedToolSchemas.size
206
- });
207
- }
208
- }
209
- }
210
- // If we just loaded schemas, don't execute yet - let Claude see them first
211
- if (schemasJustLoaded.length > 0) {
212
- this.logger.info("Loaded new tool schemas - giving Claude another iteration to see parameters", {
213
- schemasLoaded: schemasJustLoaded,
214
- tokensAdded: schemasJustLoaded.length * 200
215
- });
216
- // IMPORTANT: Anthropic requires tool_result for every tool_use
217
- // Add stub results telling Claude to retry with full schemas
218
- const stubResults = response.content
219
- .filter(content => content.type === "tool_use")
220
- .map(content => ({
221
- type: "tool_result",
222
- tool_use_id: content.id,
223
- content: `Schema loaded. Full parameter details are now available. Please retry this tool call with the correct parameters based on the schema.`
224
- }));
225
- conversationMessages.push({
226
- role: "user",
227
- content: stubResults,
228
- });
229
- // Continue to next iteration - Claude will now see full schemas in optimizedTools
230
- continue;
231
- }
232
- // Second pass: Execute tools (schemas are already loaded)
233
- for (const content of response.content) {
234
- if (content.type === "tool_use") {
235
- const toolCallStart = Date.now();
236
- try {
237
- this.logToolCall(content.name, content.input);
238
- const result = await this.callMcpTool(mcpServerUrl, botMcpApiKey, {
239
- name: content.name,
240
- arguments: content.input ?? undefined,
241
- });
242
- const toolCallDuration = Date.now() - toolCallStart;
243
- toolCalls.push({
244
- toolName: content.name,
245
- args: content.input,
246
- result: result?.content,
247
- duration: toolCallDuration,
248
- });
249
- // Note: Individual tool truncation removed - now handled at prompt level
250
- const resultContent = JSON.stringify(result?.content || {});
251
- toolResults.push({
252
- type: "tool_result",
253
- tool_use_id: content.id,
254
- content: resultContent,
255
- });
256
- this.logToolCall(content.name, content.input, toolCallDuration);
257
- // Log detailed tool call to activity logger
258
- this.agentTracker.logToolCall({
259
- toolName: content.name,
260
- provider: "Anthropic",
261
- request: {
262
- arguments: content.input,
263
- endpoint: mcpServerUrl,
264
- method: "POST",
265
- },
266
- response: {
267
- success: true,
268
- data: result?.content,
269
- },
270
- duration: toolCallDuration,
271
- botId: userMessage.mentionedOrDirectMessagedBotId,
272
- discussionId: userMessage.discussionId,
273
- workspaceId: userMessage.workspaceId,
274
- });
275
- }
276
- catch (error) {
277
- const toolCallDuration = Date.now() - toolCallStart;
278
- this.logger.toolError(content.name, this.name, error, toolCallDuration);
279
- toolCalls.push({
280
- toolName: content.name,
281
- args: content.input,
282
- error: error instanceof Error ? error.message : String(error),
283
- });
284
- toolResults.push({
285
- type: "tool_result",
286
- tool_use_id: content.id,
287
- content: `Error: ${error instanceof Error ? error.message : String(error)}`,
288
- is_error: true,
289
- });
290
- // Log failed tool call to activity logger
291
- this.agentTracker.logToolCall({
292
- toolName: content.name,
293
- provider: "Anthropic",
294
- request: {
295
- arguments: content.input,
296
- endpoint: mcpServerUrl,
297
- method: "POST",
298
- },
299
- response: {
300
- success: false,
301
- error: error instanceof Error ? error.message : String(error),
302
- },
303
- duration: toolCallDuration,
304
- botId: userMessage.mentionedOrDirectMessagedBotId,
305
- discussionId: userMessage.discussionId,
306
- workspaceId: userMessage.workspaceId,
307
- });
308
- }
309
- }
310
- }
311
- if (toolResults.length > 0) {
312
- conversationMessages.push({
313
- role: "user",
314
- content: toolResults,
315
- });
316
- // Check token count before API call with tool results
317
- const tokenCount = this.contextManager.countTokens(finalSystemPrompt, conversationMessages, optimizedTools, 'anthropic');
318
- this.logger.info("Token count after tool results (on-demand mode)", {
319
- totalTokens: tokenCount.totalTokens,
320
- messagesTokens: tokenCount.messagesTokens,
321
- toolsTokens: tokenCount.toolsTokens,
322
- safeLimit: tokenCount.limit.safeTokens,
323
- exceedsLimit: tokenCount.exceedsLimit,
324
- messageCount: conversationMessages.length,
325
- loadedSchemas: loadedToolSchemas.size,
326
- note: `${loadedToolSchemas.size} tools with full schemas, ${minimalTools.length - loadedToolSchemas.size} minimal stubs`
327
- });
328
- // Check if approaching limit (80%)
329
- if (this.contextManager.approachingLimit(tokenCount.totalTokens, 'anthropic')) {
330
- this.logger.warn("Approaching token limit", {
331
- totalTokens: tokenCount.totalTokens,
332
- safeLimit: tokenCount.limit.safeTokens,
333
- percentUsed: Math.round((tokenCount.totalTokens / tokenCount.limit.safeTokens) * 100),
334
- });
335
- }
336
- // If exceeds limit, summarize context
337
- let messagesToSend = conversationMessages;
338
- if (tokenCount.exceedsLimit) {
339
- this.logger.warn("Context exceeds token limit, starting summarization", {
340
- totalTokens: tokenCount.totalTokens,
341
- safeLimit: tokenCount.limit.safeTokens,
342
- messageCount: conversationMessages.length,
343
- });
344
- try {
345
- const summarizationResult = await this.contextManager.summarizeContext(finalSystemPrompt, conversationMessages, 'anthropic', finalUserContent);
346
- this.logger.info("Context summarization successful", {
347
- originalTokens: summarizationResult.originalTokens,
348
- summarizedTokens: summarizationResult.summarizedTokens,
349
- reductionPercent: summarizationResult.reductionPercent,
350
- chunksProcessed: summarizationResult.chunksProcessed,
351
- originalMessages: conversationMessages.length,
352
- summarizedMessages: summarizationResult.summarizedMessages.length,
353
- });
354
- // Replace conversation messages with summarized version
355
- // Keep first user message, add summarized results
356
- messagesToSend = [
357
- conversationMessages[0], // Original user query
358
- ...summarizationResult.summarizedMessages,
359
- ];
360
- // Verify summarized context is within limits
361
- const summarizedTokenCount = this.contextManager.countTokens(finalSystemPrompt, messagesToSend, optimizedTools, 'anthropic');
362
- if (summarizedTokenCount.exceedsLimit) {
363
- this.logger.error("Summarized context still exceeds limit", {
364
- summarizedTokens: summarizedTokenCount.totalTokens,
365
- safeLimit: summarizedTokenCount.limit.safeTokens,
366
- });
367
- return {
368
- success: false,
369
- error: `Context too large even after summarization: ${summarizedTokenCount.totalTokens} tokens exceeds safe limit of ${summarizedTokenCount.limit.safeTokens} tokens`,
370
- };
371
- }
372
- }
373
- catch (error) {
374
- this.logger.error("Summarization failed", error, {
375
- originalTokens: tokenCount.totalTokens,
376
- safeLimit: tokenCount.limit.safeTokens,
377
- });
378
- return {
379
- success: false,
380
- error: `Context too large and summarization failed: ${error instanceof Error ? error.message : String(error)}`,
381
- };
382
- }
383
- }
384
- // Make API call with potentially summarized messages and optimized tools
385
- // Add strict mode for structured outputs
386
- const strictOptimizedTools = optimizedTools.map(tool => ({
387
- ...tool,
388
- strict: true
389
- }));
390
- response = await this.client.beta.messages.create({
391
- model: this.config.model || "claude-sonnet-4-20250514",
392
- max_tokens: this.config.maxTokens || 2000,
393
- temperature: this.config.temperature || 0.7,
394
- betas: ['structured-outputs-2025-11-13'],
395
- system: [
396
- {
397
- type: "text",
398
- text: finalSystemPrompt,
399
- cache_control: { type: "ephemeral" }
400
- }
401
- ],
402
- messages: messagesToSend,
403
- tools: strictOptimizedTools,
404
- });
405
- // Accumulate tokens from this API call
406
- if (response.usage) {
407
- totalInputTokens += response.usage.input_tokens;
408
- totalOutputTokens += response.usage.output_tokens;
409
- totalCacheCreation += response.usage.cache_creation_input_tokens || 0;
410
- totalCacheRead += response.usage.cache_read_input_tokens || 0;
411
- }
412
- }
413
- }
414
- // If we hit the iteration limit, force a final response without tool calls
415
- if (maxIterations === 0 && response.content.some((content) => content.type === "tool_use")) {
416
- this.logger.info("Forcing final response without tool calls after hitting iteration limit", {
417
- botId: userMessage.mentionedOrDirectMessagedBotId,
418
- });
419
- // Add final instruction (centralized truncation will handle limits)
420
- const finalMessages = [...conversationMessages, {
421
- role: "user",
422
- content: "Please provide a summary response based on the information gathered from the tools above. Do not call any more tools."
423
- }];
424
- // Check token count before final API call
425
- const finalTokenCount = this.contextManager.countTokens(finalSystemPrompt, finalMessages, [], // No tools in final call
426
- 'anthropic');
427
- this.logger.info("Final forced response token count", {
428
- totalTokens: finalTokenCount.totalTokens,
429
- safeLimit: finalTokenCount.limit.safeTokens,
430
- exceedsLimit: finalTokenCount.exceedsLimit,
431
- });
432
- let finalMessagesToSend = finalMessages;
433
- if (finalTokenCount.exceedsLimit) {
434
- this.logger.warn("Final context exceeds limit, summarizing", {
435
- totalTokens: finalTokenCount.totalTokens,
436
- safeLimit: finalTokenCount.limit.safeTokens,
437
- });
438
- try {
439
- const summarizationResult = await this.contextManager.summarizeContext(finalSystemPrompt, conversationMessages, // Summarize conversation before final instruction
440
- 'anthropic', finalUserContent);
441
- finalMessagesToSend = [
442
- conversationMessages[0], // Original user query
443
- ...summarizationResult.summarizedMessages,
444
- {
445
- role: "user",
446
- content: "Please provide a summary response based on the information gathered from the tools above. Do not call any more tools."
447
- }
448
- ];
449
- this.logger.info("Final context summarized", {
450
- originalTokens: summarizationResult.originalTokens,
451
- summarizedTokens: summarizationResult.summarizedTokens,
452
- reductionPercent: summarizationResult.reductionPercent,
453
- });
454
- }
455
- catch (error) {
456
- this.logger.error("Final summarization failed", error);
457
- // Continue with truncated messages as fallback
458
- }
459
- }
460
- // Make final call without tools (no strict mode needed - no tools)
461
- response = await this.client.beta.messages.create({
462
- model: this.config.model || "claude-sonnet-4-20250514",
463
- max_tokens: this.config.maxTokens || 2000,
464
- temperature: this.config.temperature || 0.7,
465
- betas: ['structured-outputs-2025-11-13'],
466
- system: [
467
- {
468
- type: "text",
469
- text: finalSystemPrompt,
470
- cache_control: { type: "ephemeral" }
471
- }
472
- ],
473
- messages: finalMessagesToSend,
474
- // No tools - force text response only
475
- });
476
- // Accumulate tokens from final API call
477
- if (response.usage) {
478
- totalInputTokens += response.usage.input_tokens;
479
- totalOutputTokens += response.usage.output_tokens;
480
- totalCacheCreation += response.usage.cache_creation_input_tokens || 0;
481
- totalCacheRead += response.usage.cache_read_input_tokens || 0;
482
- }
483
- }
484
- // No cleanup needed for HTTP-based MCP calls
485
- const duration = Date.now() - startTime;
486
- const responseText = response.content
487
- .filter((content) => content.type === "text")
488
- .map((content) => content.text)
489
- .join("\n")
490
- .trim();
491
- // Calculate total cost
492
- const model = this.config.model || "claude-sonnet-4-20250514";
493
- const cost = (0, token_pricing_1.calculateTokenCost)({
494
- input_tokens: totalInputTokens,
495
- output_tokens: totalOutputTokens,
496
- cache_creation_input_tokens: totalCacheCreation,
497
- cache_read_input_tokens: totalCacheRead,
498
- }, model);
499
- this.logger.info("Processed request", {
500
- duration,
501
- toolCallCount: toolCalls.length,
502
- maxIterationsReached: maxIterations === 0,
503
- tokens: {
504
- input: totalInputTokens,
505
- output: totalOutputTokens,
506
- total: totalInputTokens + totalOutputTokens,
507
- cacheCreation: totalCacheCreation,
508
- cacheRead: totalCacheRead,
509
- cost: cost,
510
- }
511
- });
512
- return {
513
- success: true,
514
- toolCalls,
515
- response: responseText || "Task completed successfully.",
516
- tokens: {
517
- input: totalInputTokens,
518
- output: totalOutputTokens,
519
- total: totalInputTokens + totalOutputTokens,
520
- cacheCreation: totalCacheCreation,
521
- cacheRead: totalCacheRead,
522
- cost: cost,
523
- },
524
- };
525
- }
526
- catch (error) {
527
- this.logError(error, "processMessage");
528
- return {
529
- success: false,
530
- error: `Anthropic processing failed: ${error.message || error}`,
531
- };
532
- }
533
- }
534
- /**
535
- * Fetch specific tool schema on-demand
536
- * Token-efficient: ~690 tokens per tool vs loading all tools upfront
537
- */
538
- async fetchMcpToolSchema(mcpServerUrl, mcpServerApiKey, toolName) {
539
- // Check cache first
540
- const cacheKey = `${mcpServerUrl}:${toolName}`;
541
- if (this.toolSchemaCache.has(cacheKey)) {
542
- this.logger.debug('Using cached tool schema', { toolName });
543
- return this.toolSchemaCache.get(cacheKey);
544
- }
545
- const url = `${mcpServerUrl}${mcpServerUrl.includes("?") ? "&" : "?"}apiKey=${mcpServerApiKey}`;
546
- const response = await fetch(url, {
547
- method: "POST",
548
- headers: {
549
- "Content-Type": "application/json",
550
- Accept: "application/json, text/event-stream",
551
- },
552
- body: JSON.stringify({
553
- jsonrpc: "2.0",
554
- id: Math.random().toString(36).substring(2),
555
- method: "tools/get_schema",
556
- params: { name: toolName },
557
- }),
558
- });
559
- if (!response.ok) {
560
- throw new Error(`MCP server responded with ${response.status}: ${response.statusText}`);
561
- }
562
- // Parse SSE response format
563
- const responseText = await response.text();
564
- const lines = responseText.split("\n");
565
- let jsonData = null;
566
- for (const line of lines) {
567
- if (line.startsWith("data: ")) {
568
- try {
569
- jsonData = JSON.parse(line.substring(6));
570
- break;
571
- }
572
- catch (e) {
573
- // Skip non-JSON lines
574
- }
575
- }
576
- }
577
- if (!jsonData) {
578
- throw new Error("Failed to parse MCP server response");
579
- }
580
- if (jsonData.error) {
581
- throw new Error(`MCP tool schema error: ${jsonData.error.message || jsonData.error}`);
582
- }
583
- // Convert MCP tool format to Anthropic tool format with strict mode
584
- const toolSchema = {
585
- name: jsonData.result.name,
586
- description: jsonData.result.description || `Tool: ${jsonData.result.name}`,
587
- input_schema: jsonData.result.inputSchema || {
588
- type: "object",
589
- properties: {},
590
- required: [],
591
- },
592
- strict: true, // Enable structured outputs validation
593
- };
594
- // Cache the schema
595
- this.toolSchemaCache.set(cacheKey, toolSchema);
596
- this.logger.debug('Cached tool schema', { toolName });
597
- return toolSchema;
598
- }
599
- async callMcpTool(mcpServerUrl, mcpServerApiKey, request) {
600
- const url = `${mcpServerUrl}${mcpServerUrl.includes("?") ? "&" : "?"}apiKey=${mcpServerApiKey}`;
601
- const response = await fetch(url, {
602
- method: "POST",
603
- headers: {
604
- "Content-Type": "application/json",
605
- Accept: "application/json, text/event-stream",
606
- },
607
- body: JSON.stringify({
608
- jsonrpc: "2.0",
609
- id: Math.random().toString(36).substring(2),
610
- method: "tools/call",
611
- params: {
612
- name: request.name,
613
- arguments: request.arguments || {},
614
- },
615
- }),
616
- });
617
- if (!response.ok) {
618
- throw new Error(`MCP tool call failed with ${response.status}: ${response.statusText}`);
619
- }
620
- // Parse SSE response format
621
- const responseText = await response.text();
622
- const lines = responseText.split("\n");
623
- let jsonData = null;
624
- for (const line of lines) {
625
- if (line.startsWith("data: ")) {
626
- try {
627
- jsonData = JSON.parse(line.substring(6));
628
- break;
629
- }
630
- catch (e) {
631
- // Skip non-JSON lines
632
- }
633
- }
634
- }
635
- if (!jsonData) {
636
- throw new Error("Failed to parse MCP tool response");
637
- }
638
- if (jsonData.error) {
639
- throw new Error(`MCP tool error: ${jsonData.error.message || jsonData.error}`);
640
- }
641
- return jsonData.result;
642
- }
643
- }
644
- exports.AnthropicProvider = AnthropicProvider;
645
- //# sourceMappingURL=anthropic-provider.js.map
@@ -1,17 +0,0 @@
1
- /**
2
- * Assistant Provider
3
- *
4
- * Pure pass-through chatbot. No tools, no local system prompt.
5
- * System prompt is loaded on AI PC side via llama-server.
6
- */
7
- import { ChatMessage, McpResponse } from "../types";
8
- import { LlmProvider } from "./llm-provider";
9
- import { LlmProviderConfig } from "../types";
10
- export declare class AssistantProvider extends LlmProvider {
11
- private assistant;
12
- constructor(config: LlmProviderConfig);
13
- generateConfirmationMessage(_userMessage: ChatMessage): Promise<string>;
14
- processMessage(userMessage: ChatMessage, _mcpServerUrl: string, _botMcpApiKey: string, _botEmail: string): Promise<McpResponse>;
15
- protected callMcpTool(): Promise<any>;
16
- }
17
- //# sourceMappingURL=assistant-provider.d.ts.map