@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,411 @@
|
|
|
1
|
+
import type { ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import { getProjectContext } from "@/services/projects";
|
|
3
|
+
import { getPubkeyService } from "@/services/PubkeyService";
|
|
4
|
+
import type { AISdkTool } from "@/tools/types";
|
|
5
|
+
import { logger } from "@/utils/logger";
|
|
6
|
+
import { createEventContext } from "@/services/event-context";
|
|
7
|
+
import { resolveRecipientToPubkey, resolveEscalationTarget } from "@/services/agents";
|
|
8
|
+
import { ConversationStore } from "@/conversations/ConversationStore";
|
|
9
|
+
import { wouldCreateCircularDelegation } from "@/utils/delegation-chain";
|
|
10
|
+
import { tool } from "ai";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { RALRegistry } from "@/services/ral";
|
|
13
|
+
import type { PendingDelegation } from "@/services/ral/types";
|
|
14
|
+
import { APNsService } from "@/services/apns";
|
|
15
|
+
import { streamPublisher } from "@/llm";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Schema for a single-select question.
|
|
19
|
+
* User picks one option from suggestions, or provides their own answer.
|
|
20
|
+
*/
|
|
21
|
+
const singleSelectQuestionSchema = z.object({
|
|
22
|
+
type: z.literal("question"),
|
|
23
|
+
title: z.string().describe("Short title for the question (displayed as header, max 12 chars recommended)"),
|
|
24
|
+
question: z.string().describe("Full question text with all necessary context"),
|
|
25
|
+
suggestions: z.array(z.string()).optional().describe(
|
|
26
|
+
"Optional suggestions for single-select. If you recommend a specific option, make it the first in the list and add '(Recommended)' suffix. Omit for fully open-ended questions."
|
|
27
|
+
),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Schema for a multi-select question.
|
|
32
|
+
* User can pick multiple options, or provide their own answer.
|
|
33
|
+
*/
|
|
34
|
+
const multiSelectQuestionSchema = z.object({
|
|
35
|
+
type: z.literal("multiselect"),
|
|
36
|
+
title: z.string().describe("Short title for the question (displayed as header, max 12 chars recommended)"),
|
|
37
|
+
question: z.string().describe("Full question text with all necessary context"),
|
|
38
|
+
options: z.array(z.string()).optional().describe(
|
|
39
|
+
"Optional options for multi-select. User can select multiple. Omit for fully open-ended questions."
|
|
40
|
+
),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Union schema for all question types.
|
|
45
|
+
*/
|
|
46
|
+
const questionSchema = z.discriminatedUnion("type", [
|
|
47
|
+
singleSelectQuestionSchema,
|
|
48
|
+
multiSelectQuestionSchema,
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Main schema for the ask tool.
|
|
53
|
+
* Supports multiple questions of different types in a single ask event.
|
|
54
|
+
*/
|
|
55
|
+
const askSchema = z.object({
|
|
56
|
+
title: z.string().describe(
|
|
57
|
+
"A brief title that encompasses all questions being asked (3-5 words). This helps the user quickly understand the topic at a glance."
|
|
58
|
+
),
|
|
59
|
+
context: z.string().describe(
|
|
60
|
+
"Background information the user needs to understand and answer the questions. " +
|
|
61
|
+
"CRITICAL: The user has NO access to your conversation history - include ALL relevant details, " +
|
|
62
|
+
"prior decisions, constraints, and reasoning. Be comprehensive but concise. " +
|
|
63
|
+
"DO NOT include the questions themselves in this field - questions go ONLY in the 'questions' array below. " +
|
|
64
|
+
"This field is for context/background ONLY."
|
|
65
|
+
),
|
|
66
|
+
questions: z.array(questionSchema).min(1).describe(
|
|
67
|
+
"Array of questions to ask. Use 'question' type for single-select, 'multiselect' type for multi-select. " +
|
|
68
|
+
"Can mix types. Keep to 1-4 questions per ask event. " +
|
|
69
|
+
"Questions are rendered separately from the context - do NOT duplicate them in the context field."
|
|
70
|
+
),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
type AskInput = z.infer<typeof askSchema>;
|
|
74
|
+
|
|
75
|
+
interface AskOutput {
|
|
76
|
+
success: boolean;
|
|
77
|
+
message: string;
|
|
78
|
+
delegationConversationId: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Helper: Format questions with their full details for escalation prompt
|
|
83
|
+
*/
|
|
84
|
+
function formatQuestions(questions: AskInput["questions"]): string {
|
|
85
|
+
return questions.map((q, idx) => {
|
|
86
|
+
let formatted = `${idx + 1}. [${q.type}] ${q.title}\n Question: ${q.question}\n`;
|
|
87
|
+
if (q.type === "question" && q.suggestions) {
|
|
88
|
+
formatted += ` Suggestions: ${q.suggestions.join(", ")}\n`;
|
|
89
|
+
} else if (q.type === "multiselect" && q.options) {
|
|
90
|
+
formatted += ` Options: ${q.options.join(", ")}\n`;
|
|
91
|
+
} else {
|
|
92
|
+
formatted += ` Type: Open-ended\n`;
|
|
93
|
+
}
|
|
94
|
+
return formatted;
|
|
95
|
+
}).join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Helper: Build escalation prompt for delegating ask to escalation agent
|
|
100
|
+
*/
|
|
101
|
+
function buildEscalationPrompt(
|
|
102
|
+
input: AskInput,
|
|
103
|
+
context: ToolExecutionContext,
|
|
104
|
+
agentRole: string,
|
|
105
|
+
delegationChain?: Array<{ displayName: string; pubkey: string }>
|
|
106
|
+
): string {
|
|
107
|
+
const { title, context: askContext, questions } = input;
|
|
108
|
+
|
|
109
|
+
let chainDisplay = "";
|
|
110
|
+
if (delegationChain && delegationChain.length > 0) {
|
|
111
|
+
chainDisplay = `\n## Delegation Chain\n${delegationChain.map(e => `- ${e.displayName} (${e.pubkey.substring(0, 8)})`).join("\n")}\n`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const formattedQuestions = formatQuestions(questions);
|
|
115
|
+
|
|
116
|
+
return `# Question Escalation Request
|
|
117
|
+
|
|
118
|
+
## Source
|
|
119
|
+
- Agent: ${context.agent.slug}
|
|
120
|
+
- Role: ${agentRole}
|
|
121
|
+
- Conversation: ${context.conversationId}
|
|
122
|
+
${chainDisplay}
|
|
123
|
+
## Questions Requiring Response
|
|
124
|
+
|
|
125
|
+
### ${title}
|
|
126
|
+
**Context:**
|
|
127
|
+
${askContext}
|
|
128
|
+
|
|
129
|
+
**Questions:**
|
|
130
|
+
${formattedQuestions}
|
|
131
|
+
|
|
132
|
+
## Your Task
|
|
133
|
+
You are acting as the project owner's proxy. Either:
|
|
134
|
+
1. Answer directly if you can make the decision
|
|
135
|
+
2. Use ask() to escalate to the actual human if you need their input
|
|
136
|
+
|
|
137
|
+
When responding, provide your answers in a clear format that addresses each question.`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Helper: Build prompt summary for delegation tracking
|
|
142
|
+
*/
|
|
143
|
+
function buildPromptSummary(input: AskInput): string {
|
|
144
|
+
const { title, context: askContext, questions } = input;
|
|
145
|
+
const questionSummary = questions.map(q => `[${q.title}] ${q.question}`).join("\n");
|
|
146
|
+
return `${title}\n\n${askContext}\n\n---\n\n${questionSummary}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Helper: Get escalation target (agent slug) from config, with validation and auto-add
|
|
151
|
+
*
|
|
152
|
+
* Delegates to EscalationService which handles:
|
|
153
|
+
* - Config reading
|
|
154
|
+
* - Project membership checks
|
|
155
|
+
* - Auto-adding from global storage if needed
|
|
156
|
+
*
|
|
157
|
+
* Returns null if no escalation agent configured, config not loaded, or agent doesn't exist
|
|
158
|
+
*/
|
|
159
|
+
async function getEscalationTarget(): Promise<string | null> {
|
|
160
|
+
const result = await resolveEscalationTarget();
|
|
161
|
+
return result?.slug ?? null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function executeAsk(input: AskInput, context: ToolExecutionContext): Promise<AskOutput> {
|
|
165
|
+
const { title, context: askContext, questions } = input;
|
|
166
|
+
|
|
167
|
+
const projectCtx = getProjectContext();
|
|
168
|
+
const ownerPubkey = projectCtx?.project?.pubkey;
|
|
169
|
+
|
|
170
|
+
if (!ownerPubkey) {
|
|
171
|
+
throw new Error("No project owner configured - cannot determine who to ask");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check for escalation agent configuration using helper
|
|
175
|
+
// This will auto-add the agent to the project if it exists in storage but not in project
|
|
176
|
+
const escalationAgentSlug = await getEscalationTarget();
|
|
177
|
+
|
|
178
|
+
// If escalation agent is configured AND current agent is not the escalation agent,
|
|
179
|
+
// route through escalation agent instead of directly to user
|
|
180
|
+
if (escalationAgentSlug && context.agent.slug !== escalationAgentSlug) {
|
|
181
|
+
const escalationAgentPubkey = resolveRecipientToPubkey(escalationAgentSlug);
|
|
182
|
+
|
|
183
|
+
if (!escalationAgentPubkey) {
|
|
184
|
+
// This shouldn't happen since getEscalationTarget() validates it,
|
|
185
|
+
// but handle gracefully just in case
|
|
186
|
+
logger.warn("[ask] Escalation agent not found, falling back to direct ask", {
|
|
187
|
+
escalationAgentSlug,
|
|
188
|
+
fromAgent: context.agent.slug,
|
|
189
|
+
});
|
|
190
|
+
// Fall through to normal ask flow
|
|
191
|
+
} else {
|
|
192
|
+
// Get delegation chain for circular delegation check
|
|
193
|
+
const conversationStore = ConversationStore.get(context.conversationId);
|
|
194
|
+
const delegationChain = conversationStore?.metadata?.delegationChain;
|
|
195
|
+
|
|
196
|
+
// Check for circular delegation using stored chain
|
|
197
|
+
if (delegationChain && wouldCreateCircularDelegation(delegationChain, escalationAgentPubkey)) {
|
|
198
|
+
const chainDisplay = delegationChain.map(e => e.displayName).join(" → ");
|
|
199
|
+
|
|
200
|
+
logger.warn("[ask] Circular delegation detected, falling back to direct ask", {
|
|
201
|
+
escalationAgent: escalationAgentSlug,
|
|
202
|
+
targetPubkey: escalationAgentPubkey.substring(0, 8),
|
|
203
|
+
chain: chainDisplay,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Fall through to normal ask flow instead of throwing
|
|
207
|
+
// This allows the question to still be asked directly to the user
|
|
208
|
+
} else {
|
|
209
|
+
// Route through escalation agent
|
|
210
|
+
logger.info("[ask] Routing ask through escalation agent", {
|
|
211
|
+
fromAgent: context.agent.slug,
|
|
212
|
+
escalationAgent: escalationAgentSlug,
|
|
213
|
+
toUser: ownerPubkey.substring(0, 8),
|
|
214
|
+
questionCount: questions.length,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Get full agent info for role
|
|
218
|
+
const fullAgent = projectCtx.getAgentByPubkey(context.agent.pubkey);
|
|
219
|
+
const agentRole = fullAgent?.role || "N/A";
|
|
220
|
+
|
|
221
|
+
// Build escalation prompt using helper
|
|
222
|
+
const escalationPrompt = buildEscalationPrompt(input, context, agentRole, delegationChain);
|
|
223
|
+
|
|
224
|
+
// Delegate to escalation agent
|
|
225
|
+
const eventContext = createEventContext(context);
|
|
226
|
+
const eventId = await context.agentPublisher.delegate({
|
|
227
|
+
recipient: escalationAgentPubkey,
|
|
228
|
+
content: escalationPrompt,
|
|
229
|
+
}, eventContext);
|
|
230
|
+
|
|
231
|
+
// Build prompt summary for delegation tracking using helper
|
|
232
|
+
const promptSummary = buildPromptSummary(input);
|
|
233
|
+
|
|
234
|
+
// Register delegation immediately (like delegate() does)
|
|
235
|
+
const pendingDelegations: PendingDelegation[] = [
|
|
236
|
+
{
|
|
237
|
+
type: "ask" as const,
|
|
238
|
+
delegationConversationId: eventId,
|
|
239
|
+
recipientPubkey: escalationAgentPubkey,
|
|
240
|
+
senderPubkey: context.agent.pubkey,
|
|
241
|
+
prompt: promptSummary,
|
|
242
|
+
ralNumber: context.ralNumber,
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
RALRegistry.getInstance().mergePendingDelegations(
|
|
247
|
+
context.agent.pubkey,
|
|
248
|
+
context.conversationId,
|
|
249
|
+
context.ralNumber,
|
|
250
|
+
pendingDelegations
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const conversationStore = ConversationStore.get(context.conversationId);
|
|
254
|
+
if (conversationStore) {
|
|
255
|
+
conversationStore.save();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
success: true,
|
|
260
|
+
message: "Question sent, waiting for response",
|
|
261
|
+
delegationConversationId: eventId,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Get human-readable name for the recipient
|
|
268
|
+
const pubkeyService = getPubkeyService();
|
|
269
|
+
const recipientName = await pubkeyService.getName(ownerPubkey);
|
|
270
|
+
|
|
271
|
+
logger.info("[ask] Publishing ask event", {
|
|
272
|
+
fromAgent: context.agent.slug,
|
|
273
|
+
toUser: recipientName,
|
|
274
|
+
toUserPubkey: ownerPubkey.substring(0, 8),
|
|
275
|
+
questionCount: questions.length,
|
|
276
|
+
questionTypes: questions.map(q => q.type),
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const eventContext = createEventContext(context);
|
|
280
|
+
const askEvent = await context.agentPublisher.ask(
|
|
281
|
+
{
|
|
282
|
+
recipient: ownerPubkey,
|
|
283
|
+
title,
|
|
284
|
+
context: askContext,
|
|
285
|
+
questions,
|
|
286
|
+
},
|
|
287
|
+
eventContext
|
|
288
|
+
);
|
|
289
|
+
const eventId = askEvent.id;
|
|
290
|
+
|
|
291
|
+
// Bug fix: Create ConversationStore for ask conversations to enable transcript retrieval
|
|
292
|
+
// See: naddr1qvzqqqr4gupzqkmm302xww6uyne99rnhl5kjj53wthjypm2qaem9uz9fdf3hzcf0qyghwumn8ghj7ar9dejhstnrdpshgtcqye382emxd9uz6ctndvkhgmm0dskhgunpdeekxunfwp6z6atwv9mxz6tvv93xceg8tzuz2
|
|
293
|
+
try {
|
|
294
|
+
await ConversationStore.create(askEvent);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
// Don't fail the ask tool if transcript storage fails.
|
|
297
|
+
// The ask functionality still works - the delegation is already registered
|
|
298
|
+
// via agentPublisher.ask(). The user will get their question and can respond.
|
|
299
|
+
// Only transcript retrieval will be affected if this fails.
|
|
300
|
+
logger.warn("[ask] Failed to create ConversationStore for ask transcript", {
|
|
301
|
+
eventId: eventId.substring(0, 8),
|
|
302
|
+
error: error instanceof Error ? error.message : String(error),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Send APNs push notification if user is not connected
|
|
307
|
+
try {
|
|
308
|
+
const apnsService = APNsService.getInstance();
|
|
309
|
+
if (apnsService.isEnabled() && !streamPublisher.isConnected()) {
|
|
310
|
+
const bodyPreview = askContext.length > 100 ? askContext.substring(0, 100) + "…" : askContext;
|
|
311
|
+
await apnsService.notifyIfNeeded(ownerPubkey, {
|
|
312
|
+
title: "Agent needs your input",
|
|
313
|
+
body: bodyPreview,
|
|
314
|
+
conversationId: context.conversationId,
|
|
315
|
+
eventId,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
// Don't fail the ask tool if push notification fails
|
|
320
|
+
logger.warn("[ask] Failed to send APNs notification", {
|
|
321
|
+
error: error instanceof Error ? error.message : String(error),
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Build prompt summary for delegation tracking using helper
|
|
326
|
+
const promptSummary = buildPromptSummary(input);
|
|
327
|
+
|
|
328
|
+
// Register delegation immediately (like delegate() does)
|
|
329
|
+
const pendingDelegations: PendingDelegation[] = [
|
|
330
|
+
{
|
|
331
|
+
type: "ask" as const,
|
|
332
|
+
delegationConversationId: eventId,
|
|
333
|
+
recipientPubkey: ownerPubkey,
|
|
334
|
+
senderPubkey: context.agent.pubkey,
|
|
335
|
+
prompt: promptSummary,
|
|
336
|
+
ralNumber: context.ralNumber,
|
|
337
|
+
},
|
|
338
|
+
];
|
|
339
|
+
|
|
340
|
+
RALRegistry.getInstance().mergePendingDelegations(
|
|
341
|
+
context.agent.pubkey,
|
|
342
|
+
context.conversationId,
|
|
343
|
+
context.ralNumber,
|
|
344
|
+
pendingDelegations
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
const conversationStore = ConversationStore.get(context.conversationId);
|
|
348
|
+
if (conversationStore) {
|
|
349
|
+
conversationStore.save();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
success: true,
|
|
354
|
+
message: "Question sent, waiting for response",
|
|
355
|
+
delegationConversationId: eventId,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function createAskTool(context: ToolExecutionContext): AISdkTool {
|
|
360
|
+
const aiTool = tool({
|
|
361
|
+
description: `Ask questions to a human user (the project owner) and wait for their response.
|
|
362
|
+
|
|
363
|
+
PURPOSE: Use this tool ONLY to ask questions to humans. Do NOT use it for any other purpose.
|
|
364
|
+
|
|
365
|
+
When to use:
|
|
366
|
+
1. Gather user preferences or requirements
|
|
367
|
+
2. Clarify ambiguous instructions
|
|
368
|
+
3. Get decisions on implementation choices
|
|
369
|
+
4. Offer choices about what direction to take
|
|
370
|
+
|
|
371
|
+
CRITICAL - Structure your input correctly:
|
|
372
|
+
- "context": Background information ONLY. Do NOT put questions here.
|
|
373
|
+
- "questions": Array of actual questions. Questions are rendered separately by the UI.
|
|
374
|
+
|
|
375
|
+
BAD example (questions in context):
|
|
376
|
+
context: "I found X and Y. Which do you prefer? Also, should I use Z?"
|
|
377
|
+
questions: [...]
|
|
378
|
+
|
|
379
|
+
GOOD example (context is just background):
|
|
380
|
+
context: "I found X and Y while investigating the issue. Here's what each does: ..."
|
|
381
|
+
questions: [{type: "question", title: "Preference", question: "Which approach do you prefer?", suggestions: ["X", "Y"]}]
|
|
382
|
+
|
|
383
|
+
The user sees the context field as explanatory text, then sees each question rendered as a separate UI element.
|
|
384
|
+
DO NOT duplicate questions in the context - they will appear twice to the user.
|
|
385
|
+
|
|
386
|
+
Question types:
|
|
387
|
+
- "question": Single-select. User picks one option or provides their own answer.
|
|
388
|
+
- "multiselect": Multi-select. User can pick multiple options.
|
|
389
|
+
|
|
390
|
+
Tips:
|
|
391
|
+
- If you recommend an option, make it first and add "(Recommended)" suffix
|
|
392
|
+
- Keep titles short (max 12 chars) for clean display
|
|
393
|
+
- Group related questions in a single ask event (1-4 questions)
|
|
394
|
+
- The user has NO access to your conversation history - include all relevant context`,
|
|
395
|
+
inputSchema: askSchema,
|
|
396
|
+
execute: async (input: AskInput) => {
|
|
397
|
+
return await executeAsk(input, context);
|
|
398
|
+
},
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
402
|
+
value: ({ title, questions }: AskInput) => {
|
|
403
|
+
const questionSummary = questions.map(q => q.title).join(", ");
|
|
404
|
+
return `Asking: "${title}" [${questionSummary}]`;
|
|
405
|
+
},
|
|
406
|
+
enumerable: false,
|
|
407
|
+
configurable: true,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
return aiTool as AISdkTool;
|
|
411
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change Model Tool - Dynamic model selection for meta model agents
|
|
3
|
+
*
|
|
4
|
+
* Allows agents using a meta model configuration to switch between
|
|
5
|
+
* variants on-the-fly during a conversation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ConversationToolContext } from "@/tools/types";
|
|
9
|
+
import type { AISdkTool } from "@/tools/types";
|
|
10
|
+
import { config as configService } from "@/services/ConfigService";
|
|
11
|
+
import { isMetaModelConfiguration, type MetaModelConfiguration } from "@/services/config/types";
|
|
12
|
+
import { tool } from "ai";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
|
|
15
|
+
const changeModelSchema = z.object({
|
|
16
|
+
variant: z
|
|
17
|
+
.string()
|
|
18
|
+
.describe("The name of the variant to switch to (e.g., 'fast', 'deep', 'standard')"),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
type ChangeModelInput = z.infer<typeof changeModelSchema>;
|
|
22
|
+
|
|
23
|
+
interface ChangeModelOutput {
|
|
24
|
+
success: boolean;
|
|
25
|
+
message: string;
|
|
26
|
+
previousVariant?: string;
|
|
27
|
+
newVariant: string;
|
|
28
|
+
modelConfig?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the meta model configuration for an agent if available
|
|
33
|
+
*/
|
|
34
|
+
function getAgentMetaModelConfig(agentLlmConfig?: string): MetaModelConfiguration | undefined {
|
|
35
|
+
try {
|
|
36
|
+
const rawConfig = configService.getRawLLMConfig(agentLlmConfig);
|
|
37
|
+
if (isMetaModelConfiguration(rawConfig)) {
|
|
38
|
+
return rawConfig;
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// Config not available or not a meta model
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function executeChangeModel(
|
|
47
|
+
input: ChangeModelInput,
|
|
48
|
+
context: ConversationToolContext
|
|
49
|
+
): Promise<ChangeModelOutput> {
|
|
50
|
+
const { variant } = input;
|
|
51
|
+
const conversation = context.getConversation();
|
|
52
|
+
const agentPubkey = context.agent.pubkey;
|
|
53
|
+
|
|
54
|
+
// Get the meta model configuration for this agent
|
|
55
|
+
const metaConfig = getAgentMetaModelConfig(context.agent.llmConfig);
|
|
56
|
+
|
|
57
|
+
if (!metaConfig) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
message: "This agent is not using a meta model configuration. Model switching is not available.",
|
|
61
|
+
newVariant: variant,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate the variant exists
|
|
66
|
+
if (!metaConfig.variants[variant]) {
|
|
67
|
+
const availableVariants = Object.keys(metaConfig.variants);
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
message: `Unknown variant "${variant}". Available variants: ${availableVariants.join(", ")}`,
|
|
71
|
+
newVariant: variant,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Get previous variant (if any)
|
|
76
|
+
const previousVariant = conversation.getMetaModelVariantOverride(agentPubkey);
|
|
77
|
+
|
|
78
|
+
// Set the new variant override
|
|
79
|
+
conversation.setMetaModelVariantOverride(agentPubkey, variant);
|
|
80
|
+
|
|
81
|
+
// Get info about the new variant
|
|
82
|
+
const variantConfig = metaConfig.variants[variant];
|
|
83
|
+
const modelConfig = variantConfig.model;
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
message: `Switched to "${variant}" variant. The new model is now active and will be used starting from the next step in this run.`,
|
|
88
|
+
previousVariant: previousVariant || metaConfig.default,
|
|
89
|
+
newVariant: variant,
|
|
90
|
+
modelConfig,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Create the change_model tool for agents using meta model configurations.
|
|
96
|
+
* This tool is automatically injected when an agent is configured with a meta model.
|
|
97
|
+
*/
|
|
98
|
+
export function createChangeModelTool(context: ConversationToolContext): AISdkTool {
|
|
99
|
+
// Get the meta model config to build the description dynamically
|
|
100
|
+
const metaConfig = getAgentMetaModelConfig(context.agent.llmConfig);
|
|
101
|
+
|
|
102
|
+
// Build variant descriptions for the tool
|
|
103
|
+
let variantDescriptions = "";
|
|
104
|
+
if (metaConfig) {
|
|
105
|
+
const variants = Object.entries(metaConfig.variants)
|
|
106
|
+
.map(([name, v]) => {
|
|
107
|
+
const desc = v.description ? `: ${v.description}` : "";
|
|
108
|
+
const isDefault = name === metaConfig.default ? " [default]" : "";
|
|
109
|
+
return ` - ${name}${desc}${isDefault}`;
|
|
110
|
+
})
|
|
111
|
+
.join("\n");
|
|
112
|
+
variantDescriptions = `\n\nAvailable variants:\n${variants}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const aiTool = tool({
|
|
116
|
+
description:
|
|
117
|
+
"Switch to a different model variant for the rest of this conversation. " +
|
|
118
|
+
`Use this when you determine a different capability level is needed for the current task.${variantDescriptions}`,
|
|
119
|
+
inputSchema: changeModelSchema,
|
|
120
|
+
execute: async (input: ChangeModelInput) => {
|
|
121
|
+
return await executeChangeModel(input, context);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
126
|
+
value: ({ variant }: ChangeModelInput) => {
|
|
127
|
+
return `Switching to model variant: ${variant}`;
|
|
128
|
+
},
|
|
129
|
+
enumerable: false,
|
|
130
|
+
configurable: true,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Mark as having side effects (changes conversation state)
|
|
134
|
+
Object.defineProperty(aiTool, "hasSideEffects", {
|
|
135
|
+
value: true,
|
|
136
|
+
enumerable: false,
|
|
137
|
+
configurable: true,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return aiTool as AISdkTool;
|
|
141
|
+
}
|