@tenex-chat/backend 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -0
- package/dist/backend-wrapper.cjs +3 -0
- package/dist/src/index.js +331928 -0
- package/package.json +103 -0
- package/src/agents/AgentRegistry.ts +418 -0
- package/src/agents/AgentStorage.ts +1133 -0
- package/src/agents/ConfigResolver.ts +229 -0
- package/src/agents/agent-installer.ts +236 -0
- package/src/agents/agent-loader.ts +241 -0
- package/src/agents/constants.ts +82 -0
- package/src/agents/errors.ts +48 -0
- package/src/agents/execution/AgentExecutor.ts +561 -0
- package/src/agents/execution/ExecutionContextFactory.ts +112 -0
- package/src/agents/execution/MessageCompiler.ts +597 -0
- package/src/agents/execution/MessageSyncer.ts +100 -0
- package/src/agents/execution/PostCompletionChecker.ts +278 -0
- package/src/agents/execution/ProgressMonitor.ts +50 -0
- package/src/agents/execution/RALResolver.ts +177 -0
- package/src/agents/execution/SessionManager.ts +181 -0
- package/src/agents/execution/StreamCallbacks.ts +312 -0
- package/src/agents/execution/StreamExecutionHandler.ts +579 -0
- package/src/agents/execution/StreamSetup.ts +313 -0
- package/src/agents/execution/ToolEventHandlers.ts +239 -0
- package/src/agents/execution/ToolExecutionTracker.ts +498 -0
- package/src/agents/execution/ToolResultUtils.ts +97 -0
- package/src/agents/execution/ToolSupervisionWrapper.ts +174 -0
- package/src/agents/execution/constants.ts +16 -0
- package/src/agents/execution/index.ts +3 -0
- package/src/agents/execution/types.ts +96 -0
- package/src/agents/execution/utils.ts +26 -0
- package/src/agents/index.ts +4 -0
- package/src/agents/script-installer.ts +266 -0
- package/src/agents/supervision/SupervisorLLMService.ts +253 -0
- package/src/agents/supervision/SupervisorOrchestrator.ts +471 -0
- package/src/agents/supervision/heuristics/ConsecutiveToolsWithoutTodoHeuristic.ts +73 -0
- package/src/agents/supervision/heuristics/DelegationClaimHeuristic.ts +80 -0
- package/src/agents/supervision/heuristics/HeuristicRegistry.ts +114 -0
- package/src/agents/supervision/heuristics/PendingTodosHeuristic.ts +93 -0
- package/src/agents/supervision/heuristics/SilentAgentHeuristic.ts +54 -0
- package/src/agents/supervision/heuristics/index.ts +5 -0
- package/src/agents/supervision/index.ts +28 -0
- package/src/agents/supervision/registerHeuristics.ts +110 -0
- package/src/agents/supervision/supervisionHealthCheck.ts +123 -0
- package/src/agents/supervision/types.ts +171 -0
- package/src/agents/tool-names.ts +46 -0
- package/src/agents/tool-normalization.ts +184 -0
- package/src/agents/types/index.ts +2 -0
- package/src/agents/types/runtime.ts +74 -0
- package/src/agents/types/storage.ts +145 -0
- package/src/commands/agent/import/index.ts +6 -0
- package/src/commands/agent/import/openclaw-distiller.ts +57 -0
- package/src/commands/agent/import/openclaw-reader.ts +141 -0
- package/src/commands/agent/import/openclaw.ts +154 -0
- package/src/commands/agent/index.ts +6 -0
- package/src/commands/agent.ts +215 -0
- package/src/commands/daemon.ts +198 -0
- package/src/commands/doctor.ts +134 -0
- package/src/commands/setup/embed.ts +228 -0
- package/src/commands/setup/global-system-prompt.ts +223 -0
- package/src/commands/setup/image.ts +179 -0
- package/src/commands/setup/index.ts +16 -0
- package/src/commands/setup/interactive.ts +95 -0
- package/src/commands/setup/llm.ts +38 -0
- package/src/commands/setup/onboarding.ts +294 -0
- package/src/commands/setup/providers.ts +27 -0
- package/src/constants.ts +34 -0
- package/src/conversations/ConversationDiskReader.ts +148 -0
- package/src/conversations/ConversationRegistry.ts +728 -0
- package/src/conversations/ConversationStore.ts +868 -0
- package/src/conversations/MessageBuilder.ts +866 -0
- package/src/conversations/executionTime.ts +62 -0
- package/src/conversations/formatters/DelegationXmlFormatter.ts +64 -0
- package/src/conversations/formatters/ThreadedConversationFormatter.ts +303 -0
- package/src/conversations/formatters/index.ts +9 -0
- package/src/conversations/formatters/utils/MessageFormatter.ts +46 -0
- package/src/conversations/formatters/utils/TimestampFormatter.ts +56 -0
- package/src/conversations/formatters/utils/TreeBuilder.ts +131 -0
- package/src/conversations/formatters/utils/TreeRenderer.ts +49 -0
- package/src/conversations/index.ts +2 -0
- package/src/conversations/persistence/ToolMessageStorage.ts +143 -0
- package/src/conversations/search/ConversationIndexManager.ts +393 -0
- package/src/conversations/search/QueryParser.ts +114 -0
- package/src/conversations/search/SearchEngine.ts +175 -0
- package/src/conversations/search/SnippetExtractor.ts +345 -0
- package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +484 -0
- package/src/conversations/search/embeddings/ConversationIndexingJob.ts +320 -0
- package/src/conversations/search/embeddings/IndexingStateManager.ts +338 -0
- package/src/conversations/search/embeddings/index.ts +18 -0
- package/src/conversations/search/index.ts +49 -0
- package/src/conversations/search/types.ts +124 -0
- package/src/conversations/services/CategoryManager.ts +160 -0
- package/src/conversations/services/ConversationResolver.ts +296 -0
- package/src/conversations/services/ConversationSummarizer.ts +234 -0
- package/src/conversations/services/MetadataDebounceManager.ts +188 -0
- package/src/conversations/services/index.ts +2 -0
- package/src/conversations/types.ts +148 -0
- package/src/conversations/utils/content-utils.ts +69 -0
- package/src/conversations/utils/image-placeholder.ts +281 -0
- package/src/conversations/utils/image-url-utils.ts +171 -0
- package/src/conversations/utils/multimodal-content.ts +90 -0
- package/src/conversations/utils/tool-result-truncator.ts +159 -0
- package/src/daemon/Daemon.ts +1883 -0
- package/src/daemon/ProjectRuntime.ts +657 -0
- package/src/daemon/RestartState.ts +152 -0
- package/src/daemon/RuntimeLifecycle.ts +268 -0
- package/src/daemon/SubscriptionManager.ts +305 -0
- package/src/daemon/UnixSocketTransport.ts +318 -0
- package/src/daemon/filters/SubscriptionFilterBuilder.ts +119 -0
- package/src/daemon/index.ts +9 -0
- package/src/daemon/routing/DaemonRouter.ts +491 -0
- package/src/daemon/types.ts +150 -0
- package/src/daemon/utils/routing-log.ts +76 -0
- package/src/daemon/utils/telemetry.ts +173 -0
- package/src/event-handler/agentDeletion.ts +383 -0
- package/src/event-handler/index.ts +749 -0
- package/src/event-handler/newConversation.ts +165 -0
- package/src/event-handler/project.ts +166 -0
- package/src/event-handler/reply.ts +18 -0
- package/src/events/NDKAgentDefinition.ts +292 -0
- package/src/events/NDKAgentLesson.ts +106 -0
- package/src/events/NDKEventMetadata.ts +34 -0
- package/src/events/NDKMCPTool.ts +60 -0
- package/src/events/NDKProjectStatus.ts +384 -0
- package/src/events/index.ts +4 -0
- package/src/index.ts +126 -0
- package/src/lib/agent-home.ts +334 -0
- package/src/lib/error-formatter.ts +200 -0
- package/src/lib/fs/filesystem.ts +128 -0
- package/src/lib/fs/index.ts +1 -0
- package/src/lib/json-parser.ts +30 -0
- package/src/lib/string.ts +15 -0
- package/src/lib/time.ts +74 -0
- package/src/llm/ChunkHandler.ts +277 -0
- package/src/llm/FinishHandler.ts +250 -0
- package/src/llm/LLMConfigEditor.ts +154 -0
- package/src/llm/LLMServiceFactory.ts +230 -0
- package/src/llm/MessageProcessor.ts +90 -0
- package/src/llm/RecordingState.ts +37 -0
- package/src/llm/StreamPublisher.ts +40 -0
- package/src/llm/TracingUtils.ts +77 -0
- package/src/llm/chunk-validators.ts +57 -0
- package/src/llm/constants.ts +6 -0
- package/src/llm/index.ts +12 -0
- package/src/llm/meta/MetaModelResolver.ts +352 -0
- package/src/llm/meta/index.ts +11 -0
- package/src/llm/middleware/flight-recorder.ts +188 -0
- package/src/llm/providers/MockProvider.ts +332 -0
- package/src/llm/providers/agent/ClaudeCodeProvider.ts +343 -0
- package/src/llm/providers/agent/ClaudeCodeToolsAdapter.ts +203 -0
- package/src/llm/providers/agent/CodexAppServerProvider.ts +214 -0
- package/src/llm/providers/agent/CodexAppServerToolsAdapter.ts +91 -0
- package/src/llm/providers/agent/index.ts +10 -0
- package/src/llm/providers/base/AgentProvider.ts +107 -0
- package/src/llm/providers/base/BaseProvider.ts +114 -0
- package/src/llm/providers/base/StandardProvider.ts +38 -0
- package/src/llm/providers/base/index.ts +9 -0
- package/src/llm/providers/index.ts +106 -0
- package/src/llm/providers/key-manager.ts +238 -0
- package/src/llm/providers/ollama-models.ts +105 -0
- package/src/llm/providers/openrouter-models.ts +102 -0
- package/src/llm/providers/provider-ids.ts +18 -0
- package/src/llm/providers/registry/ProviderRegistry.ts +414 -0
- package/src/llm/providers/registry/index.ts +7 -0
- package/src/llm/providers/standard/AnthropicProvider.ts +71 -0
- package/src/llm/providers/standard/OllamaProvider.ts +59 -0
- package/src/llm/providers/standard/OpenAIProvider.ts +44 -0
- package/src/llm/providers/standard/OpenRouterProvider.ts +103 -0
- package/src/llm/providers/standard/index.ts +10 -0
- package/src/llm/providers/types.ts +194 -0
- package/src/llm/providers/usage-metadata.ts +78 -0
- package/src/llm/service.ts +713 -0
- package/src/llm/types.ts +167 -0
- package/src/llm/utils/ConfigurationManager.ts +650 -0
- package/src/llm/utils/ConfigurationTester.ts +229 -0
- package/src/llm/utils/ModelSelector.ts +212 -0
- package/src/llm/utils/ProviderConfigUI.ts +177 -0
- package/src/llm/utils/claudeCodePromptCompiler.ts +141 -0
- package/src/llm/utils/codex-models.ts +53 -0
- package/src/llm/utils/context-window-cache.ts +30 -0
- package/src/llm/utils/models-dev-cache.ts +267 -0
- package/src/llm/utils/provider-setup.ts +50 -0
- package/src/llm/utils/tool-errors.ts +78 -0
- package/src/llm/utils/usage.ts +74 -0
- package/src/logging/EventRoutingLogger.ts +205 -0
- package/src/nostr/AgentEventDecoder.ts +357 -0
- package/src/nostr/AgentEventEncoder.ts +677 -0
- package/src/nostr/AgentProfilePublisher.ts +657 -0
- package/src/nostr/AgentPublisher.ts +437 -0
- package/src/nostr/BlossomService.ts +226 -0
- package/src/nostr/InterventionPublisher.ts +132 -0
- package/src/nostr/TagExtractor.ts +228 -0
- package/src/nostr/collectEvents.ts +83 -0
- package/src/nostr/constants.ts +38 -0
- package/src/nostr/encryption.ts +26 -0
- package/src/nostr/index.ts +31 -0
- package/src/nostr/keys.ts +17 -0
- package/src/nostr/kinds.ts +37 -0
- package/src/nostr/ndkClient.ts +72 -0
- package/src/nostr/relays.ts +43 -0
- package/src/nostr/trace-context.ts +39 -0
- package/src/nostr/types.ts +227 -0
- package/src/nostr/utils.ts +84 -0
- package/src/prompts/core/FragmentRegistry.ts +30 -0
- package/src/prompts/core/PromptBuilder.ts +98 -0
- package/src/prompts/core/index.ts +3 -0
- package/src/prompts/core/types.ts +13 -0
- package/src/prompts/fragments/00-global-system-prompt.ts +44 -0
- package/src/prompts/fragments/01-agent-identity.ts +69 -0
- package/src/prompts/fragments/02-agent-home-directory.ts +114 -0
- package/src/prompts/fragments/03-system-reminders-explanation.ts +14 -0
- package/src/prompts/fragments/04-relay-configuration.ts +38 -0
- package/src/prompts/fragments/05-delegation-chain.ts +45 -0
- package/src/prompts/fragments/06-agent-todos.ts +74 -0
- package/src/prompts/fragments/06-todo-usage-guidance.ts +34 -0
- package/src/prompts/fragments/07-meta-project-context.ts +234 -0
- package/src/prompts/fragments/08-active-conversations.ts +382 -0
- package/src/prompts/fragments/09-recent-conversations.ts +153 -0
- package/src/prompts/fragments/10-referenced-article.ts +21 -0
- package/src/prompts/fragments/11-nudges.ts +134 -0
- package/src/prompts/fragments/12-skills.ts +127 -0
- package/src/prompts/fragments/13-available-nudges.ts +122 -0
- package/src/prompts/fragments/15-available-agents.ts +53 -0
- package/src/prompts/fragments/16-stay-in-your-lane.ts +41 -0
- package/src/prompts/fragments/17-todo-before-delegation.ts +39 -0
- package/src/prompts/fragments/20-voice-mode.ts +62 -0
- package/src/prompts/fragments/22-scheduled-tasks.ts +175 -0
- package/src/prompts/fragments/24-retrieved-lessons.ts +26 -0
- package/src/prompts/fragments/25-rag-instructions.ts +333 -0
- package/src/prompts/fragments/26-mcp-resources.ts +237 -0
- package/src/prompts/fragments/27-memorized-reports.ts +77 -0
- package/src/prompts/fragments/28-agent-directed-monitoring.ts +32 -0
- package/src/prompts/fragments/29-rag-collections.ts +50 -0
- package/src/prompts/fragments/30-worktree-context.ts +98 -0
- package/src/prompts/fragments/31-agents-md-guidance.ts +96 -0
- package/src/prompts/fragments/32-process-metrics.ts +72 -0
- package/src/prompts/fragments/debug-mode.ts +48 -0
- package/src/prompts/fragments/delegation-completion.ts +44 -0
- package/src/prompts/fragments/index.ts +91 -0
- package/src/prompts/index.ts +21 -0
- package/src/prompts/utils/systemPromptBuilder.ts +777 -0
- package/src/scripts/migrate-prefix-index.ts +157 -0
- package/src/services/AgentDefinitionMonitor.ts +701 -0
- package/src/services/ConfigService.ts +723 -0
- package/src/services/CooldownRegistry.ts +199 -0
- package/src/services/LLMOperationsRegistry.ts +424 -0
- package/src/services/OwnerAgentListService.ts +354 -0
- package/src/services/PubkeyService.ts +308 -0
- package/src/services/agents/AgentMetadataStore.ts +72 -0
- package/src/services/agents/AgentResolution.ts +59 -0
- package/src/services/agents/EscalationService.ts +281 -0
- package/src/services/agents/NDKAgentDiscovery.ts +95 -0
- package/src/services/agents/index.ts +7 -0
- package/src/services/agents-md/AgentsMdService.ts +184 -0
- package/src/services/agents-md/SystemReminderInjector.ts +238 -0
- package/src/services/agents-md/index.ts +11 -0
- package/src/services/apns/APNsClient.ts +203 -0
- package/src/services/apns/APNsService.ts +358 -0
- package/src/services/apns/index.ts +11 -0
- package/src/services/apns/types.ts +80 -0
- package/src/services/compression/CompressionService.ts +445 -0
- package/src/services/compression/compression-schema.ts +28 -0
- package/src/services/compression/compression-types.ts +74 -0
- package/src/services/compression/compression-utils.ts +587 -0
- package/src/services/config/types.ts +394 -0
- package/src/services/dispatch/AgentDispatchService.ts +937 -0
- package/src/services/dispatch/AgentRouter.ts +181 -0
- package/src/services/dispatch/DelegationCompletionHandler.ts +232 -0
- package/src/services/embedding/EmbeddingProvider.ts +188 -0
- package/src/services/embedding/index.ts +5 -0
- package/src/services/event-context/EventContextService.ts +108 -0
- package/src/services/event-context/index.ts +2 -0
- package/src/services/heuristics/ContextBuilder.ts +106 -0
- package/src/services/heuristics/HeuristicEngine.ts +200 -0
- package/src/services/heuristics/formatters.ts +58 -0
- package/src/services/heuristics/index.ts +12 -0
- package/src/services/heuristics/rules/index.ts +25 -0
- package/src/services/heuristics/rules/todoBeforeDelegation.ts +69 -0
- package/src/services/heuristics/rules/todoReminderOnToolUse.ts +63 -0
- package/src/services/heuristics/types.ts +144 -0
- package/src/services/image/ImageGenerationService.ts +389 -0
- package/src/services/image/index.ts +12 -0
- package/src/services/intervention/InterventionService.ts +1352 -0
- package/src/services/intervention/index.ts +7 -0
- package/src/services/mcp/MCPManager.ts +683 -0
- package/src/services/mcp/McpNotificationDelivery.ts +139 -0
- package/src/services/mcp/McpSubscriptionService.ts +653 -0
- package/src/services/mcp/mcpInstaller.ts +130 -0
- package/src/services/nip46/Nip46SigningLog.ts +81 -0
- package/src/services/nip46/Nip46SigningService.ts +467 -0
- package/src/services/nip46/index.ts +4 -0
- package/src/services/nudge/NudgeService.ts +224 -0
- package/src/services/nudge/NudgeWhitelistService.ts +382 -0
- package/src/services/nudge/index.ts +5 -0
- package/src/services/nudge/types.ts +83 -0
- package/src/services/projects/ProjectContext.ts +672 -0
- package/src/services/projects/ProjectContextStore.ts +102 -0
- package/src/services/projects/index.ts +6 -0
- package/src/services/prompt-compiler/index.ts +15 -0
- package/src/services/prompt-compiler/prompt-compiler-service.ts +1143 -0
- package/src/services/pubkey-gate/PubkeyGateService.ts +93 -0
- package/src/services/pubkey-gate/index.ts +1 -0
- package/src/services/rag/EmbeddingProviderFactory.ts +292 -0
- package/src/services/rag/LanceDBMaintenanceService.ts +211 -0
- package/src/services/rag/RAGDatabaseService.ts +173 -0
- package/src/services/rag/RAGOperations.ts +682 -0
- package/src/services/rag/RAGService.ts +240 -0
- package/src/services/rag/RagSubscriptionService.ts +618 -0
- package/src/services/rag/rag-utils.ts +174 -0
- package/src/services/ral/PendingDelegationsRegistry.ts +168 -0
- package/src/services/ral/RALRegistry.ts +2782 -0
- package/src/services/ral/index.ts +4 -0
- package/src/services/ral/types.ts +292 -0
- package/src/services/reports/LocalReportStore.ts +380 -0
- package/src/services/reports/ReportEmbeddingService.ts +430 -0
- package/src/services/reports/ReportService.ts +440 -0
- package/src/services/reports/articleUtils.ts +52 -0
- package/src/services/reports/index.ts +7 -0
- package/src/services/scheduling/SchedulerService.ts +1057 -0
- package/src/services/scheduling/errors.ts +14 -0
- package/src/services/scheduling/index.ts +7 -0
- package/src/services/scheduling/utils.ts +77 -0
- package/src/services/search/SearchProviderRegistry.ts +78 -0
- package/src/services/search/UnifiedSearchService.ts +218 -0
- package/src/services/search/index.ts +47 -0
- package/src/services/search/projectFilter.ts +22 -0
- package/src/services/search/providers/ConversationSearchProvider.ts +48 -0
- package/src/services/search/providers/LessonSearchProvider.ts +75 -0
- package/src/services/search/providers/ReportSearchProvider.ts +49 -0
- package/src/services/search/types.ts +144 -0
- package/src/services/skill/SkillService.ts +482 -0
- package/src/services/skill/index.ts +2 -0
- package/src/services/skill/types.ts +70 -0
- package/src/services/status/OperationsStatusService.ts +276 -0
- package/src/services/status/ProjectStatusService.ts +522 -0
- package/src/services/status/index.ts +11 -0
- package/src/services/storage/PrefixKVStore.ts +242 -0
- package/src/services/storage/index.ts +1 -0
- package/src/services/system-reminder/SystemReminderUtils.ts +96 -0
- package/src/services/system-reminder/index.ts +7 -0
- package/src/services/trust-pubkeys/TrustPubkeyService.ts +325 -0
- package/src/services/trust-pubkeys/index.ts +2 -0
- package/src/telemetry/ConversationSpanManager.ts +111 -0
- package/src/telemetry/EventLoopMonitor.ts +206 -0
- package/src/telemetry/LLMSpanRegistry.ts +20 -0
- package/src/telemetry/NostrSpanProcessor.ts +89 -0
- package/src/telemetry/ToolCallSpanProcessor.ts +66 -0
- package/src/telemetry/diagnostics.ts +27 -0
- package/src/telemetry/setup.ts +120 -0
- package/src/tools/implementations/agents_discover.ts +121 -0
- package/src/tools/implementations/agents_hire.ts +127 -0
- package/src/tools/implementations/agents_list.ts +96 -0
- package/src/tools/implementations/agents_publish.ts +611 -0
- package/src/tools/implementations/agents_read.ts +173 -0
- package/src/tools/implementations/agents_write.ts +200 -0
- package/src/tools/implementations/ask.ts +411 -0
- package/src/tools/implementations/change_model.ts +141 -0
- package/src/tools/implementations/conversation_get.ts +661 -0
- package/src/tools/implementations/conversation_list.ts +377 -0
- package/src/tools/implementations/conversation_search.ts +370 -0
- package/src/tools/implementations/delegate.ts +327 -0
- package/src/tools/implementations/delegate_crossproject.ts +209 -0
- package/src/tools/implementations/delegate_followup.ts +300 -0
- package/src/tools/implementations/fs_edit.ts +162 -0
- package/src/tools/implementations/fs_glob.ts +182 -0
- package/src/tools/implementations/fs_grep.ts +513 -0
- package/src/tools/implementations/fs_read.ts +332 -0
- package/src/tools/implementations/fs_write.ts +113 -0
- package/src/tools/implementations/generate_image.ts +259 -0
- package/src/tools/implementations/home_fs.ts +515 -0
- package/src/tools/implementations/kill.ts +651 -0
- package/src/tools/implementations/learn.ts +166 -0
- package/src/tools/implementations/lesson-formatter.ts +38 -0
- package/src/tools/implementations/lesson_delete.ts +164 -0
- package/src/tools/implementations/lesson_get.ts +105 -0
- package/src/tools/implementations/lessons_list.ts +153 -0
- package/src/tools/implementations/mcp_resource_read.ts +161 -0
- package/src/tools/implementations/mcp_subscribe.ts +158 -0
- package/src/tools/implementations/mcp_subscription_stop.ts +85 -0
- package/src/tools/implementations/nostr_fetch.ts +149 -0
- package/src/tools/implementations/nostr_publish_as_user.ts +353 -0
- package/src/tools/implementations/project_list.ts +146 -0
- package/src/tools/implementations/rag_add_documents.ts +573 -0
- package/src/tools/implementations/rag_create_collection.ts +65 -0
- package/src/tools/implementations/rag_delete_collection.ts +68 -0
- package/src/tools/implementations/rag_list_collections.ts +77 -0
- package/src/tools/implementations/rag_query.ts +107 -0
- package/src/tools/implementations/rag_subscription_create.ts +105 -0
- package/src/tools/implementations/rag_subscription_delete.ts +80 -0
- package/src/tools/implementations/rag_subscription_get.ts +123 -0
- package/src/tools/implementations/rag_subscription_list.ts +128 -0
- package/src/tools/implementations/report_delete.ts +79 -0
- package/src/tools/implementations/report_read.ts +160 -0
- package/src/tools/implementations/report_write.ts +278 -0
- package/src/tools/implementations/reports_list.ts +77 -0
- package/src/tools/implementations/schedule_task.ts +104 -0
- package/src/tools/implementations/schedule_task_cancel.ts +62 -0
- package/src/tools/implementations/schedule_task_once.ts +128 -0
- package/src/tools/implementations/schedule_tasks_list.ts +79 -0
- package/src/tools/implementations/search.ts +160 -0
- package/src/tools/implementations/shell.ts +553 -0
- package/src/tools/implementations/todo.ts +260 -0
- package/src/tools/implementations/upload_blob.ts +381 -0
- package/src/tools/implementations/web_fetch.ts +153 -0
- package/src/tools/implementations/web_search.ts +250 -0
- package/src/tools/registry.ts +670 -0
- package/src/tools/types.ts +177 -0
- package/src/tools/utils.ts +256 -0
- package/src/types/event-ids.ts +320 -0
- package/src/types/index.ts +46 -0
- package/src/utils/agentFetcher.ts +107 -0
- package/src/utils/cli-error.ts +29 -0
- package/src/utils/conversation-id.ts +27 -0
- package/src/utils/conversation-utils.ts +1 -0
- package/src/utils/delegation-chain.ts +357 -0
- package/src/utils/error-handler.ts +42 -0
- package/src/utils/git/gitignore.ts +69 -0
- package/src/utils/git/index.ts +2 -0
- package/src/utils/git/initializeGitRepo.ts +204 -0
- package/src/utils/git/worktree.ts +260 -0
- package/src/utils/lessonFormatter.ts +70 -0
- package/src/utils/lessonTrust.ts +24 -0
- package/src/utils/lockfile.ts +123 -0
- package/src/utils/logger.ts +149 -0
- package/src/utils/nostr-entity-parser.ts +365 -0
- package/src/utils/process.ts +49 -0
- package/src/wrapper.ts +262 -0
- package/tsconfig.json +41 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Provider
|
|
3
|
+
*
|
|
4
|
+
* Claude Code is a specialized agent-based provider that runs Claude
|
|
5
|
+
* with built-in coding tools and MCP server support.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { type ClaudeCodeSettings, type McpServerConfig, createClaudeCode } from "ai-sdk-provider-claude-code";
|
|
9
|
+
import type { LanguageModelUsage } from "ai";
|
|
10
|
+
import { logger } from "@/utils/logger";
|
|
11
|
+
import { trace } from "@opentelemetry/api";
|
|
12
|
+
import type { LanguageModelUsageWithCostUsd } from "../../types";
|
|
13
|
+
import type {
|
|
14
|
+
ProviderInitConfig,
|
|
15
|
+
ProviderMetadata,
|
|
16
|
+
ProviderRuntimeContext,
|
|
17
|
+
} from "../types";
|
|
18
|
+
import { AgentProvider, type AgentProviderFunction } from "../base/AgentProvider";
|
|
19
|
+
import { ClaudeCodeToolsAdapter } from "./ClaudeCodeToolsAdapter";
|
|
20
|
+
import { PROVIDER_IDS } from "../provider-ids";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Claude Code-specific metadata structure
|
|
24
|
+
*/
|
|
25
|
+
interface ClaudeCodeProviderMetadata {
|
|
26
|
+
costUsd?: number;
|
|
27
|
+
sessionId?: string;
|
|
28
|
+
durationMs?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Mapping between Claude Code built-in tools and their TENEX/MCP equivalents.
|
|
33
|
+
* Used to determine which built-in tools to disable when TENEX provides alternatives.
|
|
34
|
+
*/
|
|
35
|
+
interface ToolMapping {
|
|
36
|
+
tenex?: string;
|
|
37
|
+
mcpPatterns?: RegExp[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Claude Code built-in tools and their TENEX/MCP equivalents.
|
|
41
|
+
* Note: Read is deliberately absent. Claude Code saves large MCP tool results
|
|
42
|
+
* to files and expects the model to use its built-in Read to access them.
|
|
43
|
+
* Disabling Read leaves agents unable to retrieve any large tool result. */
|
|
44
|
+
const TOOL_MAPPINGS: Readonly<Record<string, ToolMapping>> = {
|
|
45
|
+
// File system tools (Read excluded — see comment above)
|
|
46
|
+
Write: { tenex: "fs_write", mcpPatterns: [/^mcp__.*__fs_write$/, /^mcp__.*__write_file$/] },
|
|
47
|
+
Edit: { tenex: "fs_edit", mcpPatterns: [/^mcp__.*__fs_edit$/, /^mcp__.*__edit_file$/] },
|
|
48
|
+
Glob: { tenex: "fs_glob", mcpPatterns: [/^mcp__.*__fs_glob$/, /^mcp__.*__glob$/] },
|
|
49
|
+
Grep: { tenex: "fs_grep", mcpPatterns: [/^mcp__.*__fs_grep$/, /^mcp__.*__grep$/] },
|
|
50
|
+
LS: { tenex: "fs_glob", mcpPatterns: [/^mcp__.*__fs_glob$/, /^mcp__.*__list_directory$/] },
|
|
51
|
+
// Web tools
|
|
52
|
+
WebFetch: { tenex: "web_fetch", mcpPatterns: [/^mcp__.*__web_fetch$/, /^mcp__.*__fetch$/] },
|
|
53
|
+
WebSearch: { tenex: "web_search", mcpPatterns: [/^mcp__.*__web_search$/, /^mcp__.*__search$/] },
|
|
54
|
+
// Shell tools (Bash is controlled via TENEX's shell tool)
|
|
55
|
+
Bash: { tenex: "shell", mcpPatterns: [/^mcp__.*__shell$/, /^mcp__.*__bash$/, /^mcp__.*__execute$/] },
|
|
56
|
+
// Notebook tools
|
|
57
|
+
NotebookEdit: { tenex: undefined, mcpPatterns: [/^mcp__.*__notebook_edit$/] },
|
|
58
|
+
// Task/agent tools (TENEX uses delegate)
|
|
59
|
+
Task: { tenex: "delegate", mcpPatterns: [/^mcp__.*__delegate$/] },
|
|
60
|
+
// Todo tools (TENEX uses its own conversation-scoped todo_write)
|
|
61
|
+
TodoWrite: { tenex: "todo_write", mcpPatterns: [/^mcp__.*__todo_write$/, /^mcp__.*__write_todos$/] },
|
|
62
|
+
} as const;
|
|
63
|
+
|
|
64
|
+
/** File system tool names that indicate FS capability */
|
|
65
|
+
const FS_TOOL_NAMES = ["fs_read", "fs_write", "fs_edit", "fs_glob", "fs_grep"] as const;
|
|
66
|
+
|
|
67
|
+
/** Built-in tools that TENEX always controls — agents get these only via TENEX's equivalents.
|
|
68
|
+
* Read is excluded: Claude Code saves large MCP tool results to files and needs
|
|
69
|
+
* its built-in Read to let the model access them. */
|
|
70
|
+
const ALWAYS_DISABLED_BUILTINS = ["Write", "Edit", "Glob", "Grep", "LS", "NotebookEdit", "Bash", "TaskOutput"] as const;
|
|
71
|
+
|
|
72
|
+
/** Pattern to detect MCP tools that provide FS capability */
|
|
73
|
+
const MCP_FS_CAPABILITY_PATTERN = /mcp__.*__(fs_read|fs_write|fs_edit|fs_glob|fs_grep|read_file|write_file|edit_file|list_directory)/;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* AI SDK usage with optional extended fields
|
|
77
|
+
*/
|
|
78
|
+
interface ExtendedUsage extends LanguageModelUsage {
|
|
79
|
+
cachedInputTokens?: number;
|
|
80
|
+
reasoningTokens?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
type ClaudeCodeSettingsWithStreamStart = ClaudeCodeSettings & {
|
|
84
|
+
onStreamStart?: ProviderRuntimeContext["onStreamStart"];
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Claude Code provider implementation
|
|
89
|
+
*/
|
|
90
|
+
export class ClaudeCodeProvider extends AgentProvider {
|
|
91
|
+
static readonly METADATA: ProviderMetadata = AgentProvider.createMetadata(
|
|
92
|
+
PROVIDER_IDS.CLAUDE_CODE,
|
|
93
|
+
"Claude Code",
|
|
94
|
+
"Claude with built-in coding tools and MCP support",
|
|
95
|
+
"agent",
|
|
96
|
+
"claude-sonnet-4-20250514",
|
|
97
|
+
{
|
|
98
|
+
streaming: true,
|
|
99
|
+
toolCalling: true,
|
|
100
|
+
builtInTools: true,
|
|
101
|
+
sessionResumption: false,
|
|
102
|
+
requiresApiKey: false,
|
|
103
|
+
mcpSupport: true,
|
|
104
|
+
},
|
|
105
|
+
"https://docs.anthropic.com/en/docs/claude-code"
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
get metadata(): ProviderMetadata {
|
|
109
|
+
return ClaudeCodeProvider.METADATA;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create the Claude Code provider function
|
|
114
|
+
*/
|
|
115
|
+
protected createProviderFunction(_config: ProviderInitConfig): AgentProviderFunction {
|
|
116
|
+
// Return a function that creates providers with the right settings
|
|
117
|
+
// The actual settings are applied in createAgentSettings
|
|
118
|
+
return createClaudeCode({
|
|
119
|
+
defaultSettings: {},
|
|
120
|
+
}) as AgentProviderFunction;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create the agent settings for Claude Code
|
|
125
|
+
*/
|
|
126
|
+
protected createAgentSettings(
|
|
127
|
+
context: ProviderRuntimeContext,
|
|
128
|
+
_modelId: string
|
|
129
|
+
): ClaudeCodeSettingsWithStreamStart {
|
|
130
|
+
// Extract tool names from the provided tools
|
|
131
|
+
const toolNames = context.tools ? Object.keys(context.tools) : [];
|
|
132
|
+
const regularTools = toolNames.filter((name) => !name.startsWith("mcp__"));
|
|
133
|
+
const mcpTools = toolNames.filter((name) => name.startsWith("mcp__"));
|
|
134
|
+
|
|
135
|
+
// Determine which built-in tools to disable based on TENEX configuration
|
|
136
|
+
const disallowedTools = this.computeDisallowedBuiltinTools(regularTools, mcpTools);
|
|
137
|
+
|
|
138
|
+
trace.getActiveSpan()?.addEvent("llm_factory.creating_claude_code", {
|
|
139
|
+
"agent.name": context.agentName ?? "",
|
|
140
|
+
"session.id": context.sessionId ?? "",
|
|
141
|
+
"tools.count": regularTools.length,
|
|
142
|
+
"mcp_tools.count": mcpTools.length,
|
|
143
|
+
"tenex_tools.enabled": true,
|
|
144
|
+
"cwd.from_context": context.workingDirectory ?? "(undefined)",
|
|
145
|
+
"disallowed_builtins": disallowedTools.join(", "),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Create SDK MCP server for local TENEX tools
|
|
149
|
+
const tenexSdkServer =
|
|
150
|
+
regularTools.length > 0 && context.tools
|
|
151
|
+
? ClaudeCodeToolsAdapter.createSdkMcpServer(context.tools)
|
|
152
|
+
: undefined;
|
|
153
|
+
|
|
154
|
+
// Build mcpServers configuration
|
|
155
|
+
const mcpServersConfig: Record<string, McpServerConfig> = {};
|
|
156
|
+
|
|
157
|
+
// Add TENEX tools wrapper if enabled
|
|
158
|
+
if (tenexSdkServer) {
|
|
159
|
+
mcpServersConfig.tenex = tenexSdkServer;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Add MCP servers from context (passed from services layer)
|
|
163
|
+
const mcpConfig = context.mcpConfig;
|
|
164
|
+
if (mcpConfig?.enabled && mcpConfig.servers) {
|
|
165
|
+
for (const [serverName, serverConfig] of Object.entries(mcpConfig.servers)) {
|
|
166
|
+
mcpServersConfig[serverName] = {
|
|
167
|
+
type: "stdio" as const,
|
|
168
|
+
command: serverConfig.command,
|
|
169
|
+
args: serverConfig.args,
|
|
170
|
+
env: serverConfig.env,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
trace.getActiveSpan()?.addEvent("llm_factory.mcp_servers_added", {
|
|
175
|
+
"mcp.server_count": Object.keys(mcpConfig.servers).length,
|
|
176
|
+
"mcp.servers": Object.keys(mcpConfig.servers).join(", "),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Build the settings
|
|
181
|
+
const settings: ClaudeCodeSettingsWithStreamStart = {
|
|
182
|
+
permissionMode: "bypassPermissions",
|
|
183
|
+
verbose: true,
|
|
184
|
+
cwd: context.workingDirectory,
|
|
185
|
+
// Ensure Bash tool uses the project working directory, not the session's stored cwd
|
|
186
|
+
env: {
|
|
187
|
+
CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR: "1",
|
|
188
|
+
},
|
|
189
|
+
mcpServers: mcpServersConfig,
|
|
190
|
+
disallowedTools,
|
|
191
|
+
persistSession: false,
|
|
192
|
+
// Enable streaming input for mid-execution message injection
|
|
193
|
+
streamingInput: "always",
|
|
194
|
+
logger: {
|
|
195
|
+
warn: (message: string) => logger.warn("[ClaudeCode]", message),
|
|
196
|
+
error: (message: string) => logger.error("[ClaudeCode]", message),
|
|
197
|
+
info: (message: string) => logger.info("[ClaudeCode]", message),
|
|
198
|
+
debug: (message: string) => logger.debug("[ClaudeCode]", message),
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Pass through onStreamStart callback if provided
|
|
203
|
+
// The callback receives a MessageInjector when the stream starts, allowing mid-execution message injection
|
|
204
|
+
if (context.onStreamStart) {
|
|
205
|
+
settings.onStreamStart = context.onStreamStart;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return settings;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Compute which Claude Code built-in tools should be disabled.
|
|
213
|
+
*
|
|
214
|
+
* FS and shell built-in tools (Read, Write, Edit, Glob, Grep, LS,
|
|
215
|
+
* NotebookEdit, Bash) are ALWAYS disabled. TENEX controls filesystem
|
|
216
|
+
* and shell access exclusively through its fs_* and shell tools,
|
|
217
|
+
* provided conditionally based on agent configuration.
|
|
218
|
+
*
|
|
219
|
+
* Other built-in tools (WebFetch, etc.) are disabled when TENEX
|
|
220
|
+
* provides an equivalent.
|
|
221
|
+
*/
|
|
222
|
+
private computeDisallowedBuiltinTools(regularTools: string[], mcpTools: string[]): string[] {
|
|
223
|
+
const { disallowed, hasAnyFsCapability } = this.computeDisallowedToolsCore(regularTools, mcpTools);
|
|
224
|
+
|
|
225
|
+
// Log the decision for debugging (separate from pure computation)
|
|
226
|
+
this.logDisallowedToolsDecision(disallowed, regularTools, hasAnyFsCapability);
|
|
227
|
+
|
|
228
|
+
return disallowed;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Pure computation of disallowed tools without side effects.
|
|
233
|
+
*/
|
|
234
|
+
private computeDisallowedToolsCore(
|
|
235
|
+
regularTools: string[],
|
|
236
|
+
mcpTools: string[]
|
|
237
|
+
): { disallowed: string[]; hasAnyFsCapability: boolean } {
|
|
238
|
+
// Always disallow AskUserQuestion - TENEX has its own ask tool
|
|
239
|
+
// Always disallow FS built-in tools — TENEX controls filesystem access
|
|
240
|
+
// exclusively through its fs_* tools. Agents get fs_* only when their
|
|
241
|
+
// tool configuration includes them.
|
|
242
|
+
const disallowed: string[] = ["AskUserQuestion", ...ALWAYS_DISABLED_BUILTINS];
|
|
243
|
+
|
|
244
|
+
const hasTenexFsTools = FS_TOOL_NAMES.some(tool => regularTools.includes(tool));
|
|
245
|
+
const hasMcpFsTools = mcpTools.some(tool => MCP_FS_CAPABILITY_PATTERN.test(tool));
|
|
246
|
+
const hasAnyFsCapability = hasTenexFsTools || hasMcpFsTools;
|
|
247
|
+
|
|
248
|
+
// Check each non-FS built-in tool and disable if TENEX/MCP provides equivalent
|
|
249
|
+
for (const [builtinTool, mapping] of Object.entries(TOOL_MAPPINGS)) {
|
|
250
|
+
if (disallowed.includes(builtinTool)) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const hasEquivalent = this.hasToolEquivalent(mapping, regularTools, mcpTools);
|
|
255
|
+
|
|
256
|
+
if (hasEquivalent) {
|
|
257
|
+
disallowed.push(builtinTool);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return { disallowed, hasAnyFsCapability };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Check if TENEX or MCP provides an equivalent for a built-in tool.
|
|
266
|
+
*/
|
|
267
|
+
private hasToolEquivalent(
|
|
268
|
+
mapping: ToolMapping,
|
|
269
|
+
regularTools: string[],
|
|
270
|
+
mcpTools: string[]
|
|
271
|
+
): boolean {
|
|
272
|
+
// Check for TENEX tool equivalent
|
|
273
|
+
if (mapping.tenex && regularTools.includes(mapping.tenex)) {
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Check for MCP tool equivalent
|
|
278
|
+
if (mapping.mcpPatterns) {
|
|
279
|
+
for (const pattern of mapping.mcpPatterns) {
|
|
280
|
+
if (mcpTools.some(tool => pattern.test(tool))) {
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Log the disallowed tools decision for debugging.
|
|
291
|
+
*/
|
|
292
|
+
private logDisallowedToolsDecision(
|
|
293
|
+
disallowed: string[],
|
|
294
|
+
regularTools: string[],
|
|
295
|
+
hasAnyFsCapability: boolean
|
|
296
|
+
): void {
|
|
297
|
+
const relevantTools = [...FS_TOOL_NAMES, "shell", "web_fetch", "web_search", "delegate", "todo_write"] as const;
|
|
298
|
+
logger.info("[ClaudeCodeProvider] Disabling built-in tools", {
|
|
299
|
+
disallowed,
|
|
300
|
+
tenexTools: regularTools.filter(t =>
|
|
301
|
+
(relevantTools as readonly string[]).includes(t)
|
|
302
|
+
),
|
|
303
|
+
hasFsCapability: hasAnyFsCapability,
|
|
304
|
+
hasShell: regularTools.includes("shell"),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Claude Code is always available (no API key required)
|
|
310
|
+
*/
|
|
311
|
+
isAvailable(): boolean {
|
|
312
|
+
return this._initialized;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Extract usage metadata from Claude Code provider response
|
|
317
|
+
*/
|
|
318
|
+
static extractUsageMetadata(
|
|
319
|
+
model: string,
|
|
320
|
+
totalUsage: LanguageModelUsage | undefined,
|
|
321
|
+
providerMetadata: Record<string, unknown> | undefined
|
|
322
|
+
): LanguageModelUsageWithCostUsd {
|
|
323
|
+
const metadata = providerMetadata?.[PROVIDER_IDS.CLAUDE_CODE] as ClaudeCodeProviderMetadata | undefined;
|
|
324
|
+
const extendedUsage = totalUsage as ExtendedUsage | undefined;
|
|
325
|
+
|
|
326
|
+
const inputTokens = totalUsage?.inputTokens;
|
|
327
|
+
const outputTokens = totalUsage?.outputTokens;
|
|
328
|
+
const totalTokens = totalUsage?.totalTokens ??
|
|
329
|
+
(inputTokens !== undefined && outputTokens !== undefined
|
|
330
|
+
? inputTokens + outputTokens
|
|
331
|
+
: undefined);
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
model,
|
|
335
|
+
inputTokens,
|
|
336
|
+
outputTokens,
|
|
337
|
+
totalTokens,
|
|
338
|
+
costUsd: metadata?.costUsd,
|
|
339
|
+
cachedInputTokens: extendedUsage?.cachedInputTokens,
|
|
340
|
+
reasoningTokens: extendedUsage?.reasoningTokens,
|
|
341
|
+
} as LanguageModelUsageWithCostUsd;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { AISdkTool } from "@/tools/types";
|
|
2
|
+
import { logger } from "@/utils/logger";
|
|
3
|
+
import { createSdkMcpServer, tool } from "ai-sdk-provider-claude-code";
|
|
4
|
+
import type { ToolExecutionOptions } from "@ai-sdk/provider-utils";
|
|
5
|
+
import { z, type ZodRawShape } from "zod";
|
|
6
|
+
|
|
7
|
+
// Infer the return type since SdkMcpServer is not exported
|
|
8
|
+
type SdkMcpServer = ReturnType<typeof createSdkMcpServer>;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Converts TENEX tools to Claude Code SDK MCP server format.
|
|
12
|
+
*
|
|
13
|
+
* This adapter is EXCLUSIVE to Claude Code - it uses createSdkMcpServer from
|
|
14
|
+
* the Claude Agent SDK which creates in-process MCP servers that only Claude Code
|
|
15
|
+
* can consume. Other providers (like Codex CLI) require different MCP formats.
|
|
16
|
+
*/
|
|
17
|
+
export class ClaudeCodeToolsAdapter {
|
|
18
|
+
/**
|
|
19
|
+
* Check if a tool is an external MCP tool (from external MCP servers).
|
|
20
|
+
* External MCP tools have JSON Schema format (not Zod), so they cannot be
|
|
21
|
+
* wrapped with the Claude SDK's tool() function which expects Zod schemas.
|
|
22
|
+
* These tools are passed directly to Claude Code as MCP servers instead.
|
|
23
|
+
*
|
|
24
|
+
* Detection is metadata-based (checking for Zod schema characteristics)
|
|
25
|
+
* rather than name-based, to avoid collisions if a user names their
|
|
26
|
+
* external MCP server "tenex".
|
|
27
|
+
*/
|
|
28
|
+
private static isExternalMcpTool(toolName: string, tool: AISdkTool): boolean {
|
|
29
|
+
// External MCP tools follow the pattern: mcp__<servername>__<toolname>
|
|
30
|
+
if (!toolName.startsWith("mcp__")) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Use metadata-based detection: check if the schema is a Zod object (has safeParseAsync)
|
|
35
|
+
// External MCP tools have JSON Schema format, TENEX tools have Zod schemas
|
|
36
|
+
const schema = tool.inputSchema;
|
|
37
|
+
if (schema && typeof schema === "object" && "safeParseAsync" in schema) {
|
|
38
|
+
// Has Zod schema - this is a TENEX tool (not external)
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// No Zod schema detected - treat as external MCP tool
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Convert TENEX tools to SDK MCP tools for Claude Code
|
|
48
|
+
* Only converts non-MCP tools (MCP tools are handled separately)
|
|
49
|
+
*/
|
|
50
|
+
static createSdkMcpServer(
|
|
51
|
+
tools: Record<string, AISdkTool>
|
|
52
|
+
): SdkMcpServer | undefined {
|
|
53
|
+
// Filter out tools that Claude Code has its own version of:
|
|
54
|
+
// - web_fetch (Claude Code has WebFetch)
|
|
55
|
+
// - web_search (Claude Code has WebSearch)
|
|
56
|
+
// fs_* and shell tools are NOT filtered — they pass through so TENEX controls access.
|
|
57
|
+
// Claude Code's built-in equivalents are always disabled via disallowedTools.
|
|
58
|
+
const claudeCodeBuiltinTools = new Set([
|
|
59
|
+
"web_fetch",
|
|
60
|
+
"web_search",
|
|
61
|
+
]);
|
|
62
|
+
// CRITICAL: Filter out external MCP tools - they have JSON Schema format (no .safeParseAsync())
|
|
63
|
+
// and will crash if we try to wrap them with tool() from Claude SDK.
|
|
64
|
+
// External MCP servers are passed directly to Claude Code via mcpConfig.servers instead.
|
|
65
|
+
const localTools = Object.entries(tools).filter(([name, tool]) =>
|
|
66
|
+
!claudeCodeBuiltinTools.has(name) &&
|
|
67
|
+
!this.isExternalMcpTool(name, tool)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Log external MCP tools that were filtered out (for debugging)
|
|
71
|
+
const externalMcpTools = Object.entries(tools)
|
|
72
|
+
.filter(([name, tool]) => this.isExternalMcpTool(name, tool))
|
|
73
|
+
.map(([name]) => name);
|
|
74
|
+
|
|
75
|
+
if (externalMcpTools.length > 0) {
|
|
76
|
+
logger.debug("[ClaudeCodeToolsAdapter] Filtered out external MCP tools (passed directly to Claude Code):", {
|
|
77
|
+
count: externalMcpTools.length,
|
|
78
|
+
tools: externalMcpTools,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (localTools.length === 0) {
|
|
83
|
+
logger.debug("[ClaudeCodeToolsAdapter] No local tools to wrap after filtering", {
|
|
84
|
+
totalTools: Object.keys(tools).length,
|
|
85
|
+
externalMcpCount: externalMcpTools.length,
|
|
86
|
+
builtinFilteredCount: Object.keys(tools).filter(name =>
|
|
87
|
+
claudeCodeBuiltinTools.has(name)
|
|
88
|
+
).length,
|
|
89
|
+
});
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Convert each TENEX tool to an SDK MCP tool
|
|
94
|
+
const sdkTools = localTools.map(([name, tenexTool]) => {
|
|
95
|
+
// The Claude SDK's tool() function expects a ZodRawShape (plain object like { a: z.number() })
|
|
96
|
+
// NOT a ZodObject (result of z.object({...})). We need to extract the .shape property.
|
|
97
|
+
// tenexTool.inputSchema from AI SDK is a ZodObject, so we extract its shape.
|
|
98
|
+
let rawShape: ZodRawShape = {};
|
|
99
|
+
|
|
100
|
+
if (tenexTool.inputSchema) {
|
|
101
|
+
// Check if it's a ZodObject with a shape property
|
|
102
|
+
const schema = tenexTool.inputSchema;
|
|
103
|
+
if (schema && typeof schema === "object" && "shape" in schema) {
|
|
104
|
+
// It's a ZodObject - extract the raw shape
|
|
105
|
+
rawShape = (schema as z.ZodObject<ZodRawShape>).shape;
|
|
106
|
+
} else if (schema && typeof schema === "object" && !("_def" in schema)) {
|
|
107
|
+
// It might already be a raw shape object (plain object with Zod types)
|
|
108
|
+
rawShape = schema as unknown as ZodRawShape;
|
|
109
|
+
} else if (schema !== null && typeof schema === "object") {
|
|
110
|
+
// DEFENSIVE GUARD: Log warning if we encounter an unexpected schema type
|
|
111
|
+
// This helps catch future regressions where non-Zod schemas slip through
|
|
112
|
+
logger.warn(`[ClaudeCodeToolsAdapter] Tool '${name}' has unexpected schema type - using empty schema`, {
|
|
113
|
+
hasShape: "shape" in schema,
|
|
114
|
+
hasDef: "_def" in schema,
|
|
115
|
+
hasSafeParseAsync: typeof (schema as { safeParseAsync?: unknown }).safeParseAsync === "function",
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
// Primitive schema (e.g., z.string()) - log warning but don't crash
|
|
119
|
+
logger.warn(`[ClaudeCodeToolsAdapter] Tool '${name}' has primitive or non-object schema type - using empty schema`, {
|
|
120
|
+
schemaType: typeof schema,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// If it's some other Zod type, leave rawShape as empty object
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return tool(name, tenexTool.description || `Execute ${name}`, rawShape, async (args: Record<string, unknown>, extra: unknown) => {
|
|
127
|
+
try {
|
|
128
|
+
// Check if the tool has an execute method
|
|
129
|
+
if (!tenexTool.execute) {
|
|
130
|
+
throw new Error(`Tool ${name} does not have an execute function`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Execute the TENEX tool
|
|
134
|
+
// If extra contains execution context, pass it; otherwise use minimal fallback
|
|
135
|
+
const isToolExecutionOptions = (value: unknown): value is ToolExecutionOptions =>
|
|
136
|
+
typeof value === "object" &&
|
|
137
|
+
value !== null &&
|
|
138
|
+
"toolCallId" in value &&
|
|
139
|
+
"messages" in value &&
|
|
140
|
+
Array.isArray((value as { messages?: unknown }).messages);
|
|
141
|
+
|
|
142
|
+
let result;
|
|
143
|
+
if (isToolExecutionOptions(extra)) {
|
|
144
|
+
// Try to use the extra context from Claude Code
|
|
145
|
+
result = await tenexTool.execute(args, extra);
|
|
146
|
+
} else {
|
|
147
|
+
// Fallback to minimal context (should rarely happen)
|
|
148
|
+
result = await tenexTool.execute(args, {
|
|
149
|
+
abortSignal: new AbortController().signal,
|
|
150
|
+
toolCallId: "tool-call-" + Date.now(),
|
|
151
|
+
messages: [],
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Convert result to MCP format
|
|
156
|
+
// CallToolResult expects: { content: [{ type: "text", text: string }], isError?: boolean }
|
|
157
|
+
if (typeof result === "string") {
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: "text", text: result }],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (result && typeof result === "object") {
|
|
163
|
+
return {
|
|
164
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
content: [{ type: "text", text: String(result) }],
|
|
169
|
+
};
|
|
170
|
+
} catch (error) {
|
|
171
|
+
logger.error(`[ClaudeCodeToolsAdapter] Error executing tool ${name}:`, error);
|
|
172
|
+
return {
|
|
173
|
+
content: [
|
|
174
|
+
{
|
|
175
|
+
type: "text",
|
|
176
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
isError: true,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Create and return the SDK MCP server
|
|
186
|
+
try {
|
|
187
|
+
const server = createSdkMcpServer({
|
|
188
|
+
name: "tenex",
|
|
189
|
+
tools: sdkTools,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
logger.info("[ClaudeCodeToolsAdapter] SDK MCP server created successfully", {
|
|
193
|
+
serverName: "tenex",
|
|
194
|
+
toolCount: sdkTools.length,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return server;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
logger.warn("[ClaudeCodeToolsAdapter] Could not create SDK MCP server:", error);
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|