@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,111 @@
|
|
|
1
|
+
import { logger } from "@/utils/logger";
|
|
2
|
+
import type { Span } from "@opentelemetry/api";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Manages conversation-level metadata for tracing.
|
|
6
|
+
*
|
|
7
|
+
* Instead of long-lived parent spans, this tracks conversation message counts
|
|
8
|
+
* and adds conversation.id attributes to all spans. This allows querying Jaeger
|
|
9
|
+
* for all traces with the same conversation.id to see the full timeline.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: Conversation IDs in Jaeger spans are shortened to 12 characters (PREFIX_LENGTH)
|
|
12
|
+
* for better readability in the Jaeger UI with low collision risk.
|
|
13
|
+
* Use shortenConversationId() from @/utils/conversation-id for consistency.
|
|
14
|
+
*
|
|
15
|
+
* Benefits:
|
|
16
|
+
* - No long-lived spans (avoids OTEL issues with spans that never end)
|
|
17
|
+
* - Immediate visibility in Jaeger (spans export as soon as they complete)
|
|
18
|
+
* - Easy querying: Search for conversation.id tag in Jaeger
|
|
19
|
+
* - Readable UI: Shortened IDs reduce visual clutter
|
|
20
|
+
*/
|
|
21
|
+
export class ConversationSpanManager {
|
|
22
|
+
private conversationMessageCounts = new Map<string, number>();
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
this.startCleanupTimer();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Increment message count for a conversation and add to span attributes
|
|
30
|
+
*/
|
|
31
|
+
incrementMessageCount(conversationId: string, span: Span): void {
|
|
32
|
+
const currentCount = (this.conversationMessageCounts.get(conversationId) || 0) + 1;
|
|
33
|
+
this.conversationMessageCounts.set(conversationId, currentCount);
|
|
34
|
+
|
|
35
|
+
span.setAttributes({
|
|
36
|
+
"conversation.message_sequence": currentCount,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
logger.debug("Incremented conversation message count", {
|
|
40
|
+
conversationId: conversationId.substring(0, 8),
|
|
41
|
+
messageSequence: currentCount,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get total message count for a conversation
|
|
47
|
+
*/
|
|
48
|
+
getMessageCount(conversationId: string): number {
|
|
49
|
+
return this.conversationMessageCounts.get(conversationId) || 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Start automatic cleanup timer (not used in this implementation but kept for future)
|
|
54
|
+
*/
|
|
55
|
+
private startCleanupTimer(): void {
|
|
56
|
+
// Cleanup not needed with attribute-based approach
|
|
57
|
+
// Message counts are lightweight and don't need cleanup
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Shutdown (no-op for this implementation)
|
|
62
|
+
*/
|
|
63
|
+
shutdown(): void {
|
|
64
|
+
logger.info("Shutting down ConversationSpanManager", {
|
|
65
|
+
trackedConversations: this.conversationMessageCounts.size,
|
|
66
|
+
});
|
|
67
|
+
this.conversationMessageCounts.clear();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get stats about tracked conversations
|
|
72
|
+
*/
|
|
73
|
+
getStats(): {
|
|
74
|
+
trackedConversations: number;
|
|
75
|
+
totalMessages: number;
|
|
76
|
+
} {
|
|
77
|
+
let totalMessages = 0;
|
|
78
|
+
|
|
79
|
+
for (const count of this.conversationMessageCounts.values()) {
|
|
80
|
+
totalMessages += count;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
trackedConversations: this.conversationMessageCounts.size,
|
|
85
|
+
totalMessages,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Singleton instance
|
|
91
|
+
let conversationSpanManager: ConversationSpanManager | null = null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get or create the conversation span manager instance
|
|
95
|
+
*/
|
|
96
|
+
export function getConversationSpanManager(): ConversationSpanManager {
|
|
97
|
+
if (!conversationSpanManager) {
|
|
98
|
+
conversationSpanManager = new ConversationSpanManager();
|
|
99
|
+
}
|
|
100
|
+
return conversationSpanManager;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Reset the conversation span manager (for testing)
|
|
105
|
+
*/
|
|
106
|
+
export function resetConversationSpanManager(): void {
|
|
107
|
+
if (conversationSpanManager) {
|
|
108
|
+
conversationSpanManager.shutdown();
|
|
109
|
+
}
|
|
110
|
+
conversationSpanManager = null;
|
|
111
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventLoopMonitor - Tracks event loop lag to identify blocking operations
|
|
3
|
+
*
|
|
4
|
+
* This module monitors the Node.js event loop for blocking/slow operations
|
|
5
|
+
* that could cause unresponsiveness when multiple agents are streaming.
|
|
6
|
+
*
|
|
7
|
+
* DIAGNOSTIC: This is part of the concurrent streaming bottleneck investigation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { trace } from "@opentelemetry/api";
|
|
11
|
+
import { logger } from "@/utils/logger";
|
|
12
|
+
|
|
13
|
+
interface LagSample {
|
|
14
|
+
timestamp: number;
|
|
15
|
+
lagMs: number;
|
|
16
|
+
activeOperations: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface EventLoopStats {
|
|
20
|
+
samples: LagSample[];
|
|
21
|
+
peakLagMs: number;
|
|
22
|
+
avgLagMs: number;
|
|
23
|
+
sampleCount: number;
|
|
24
|
+
blockedCount: number; // samples where lag > threshold
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const DEFAULT_SAMPLE_INTERVAL_MS = 100; // Sample every 100ms
|
|
28
|
+
const DEFAULT_LAG_THRESHOLD_MS = 50; // Consider >50ms as "blocked"
|
|
29
|
+
const MAX_SAMPLES = 1000; // Keep last 1000 samples
|
|
30
|
+
|
|
31
|
+
class EventLoopMonitor {
|
|
32
|
+
private static instance: EventLoopMonitor;
|
|
33
|
+
private isRunning = false;
|
|
34
|
+
private samples: LagSample[] = [];
|
|
35
|
+
private peakLagMs = 0;
|
|
36
|
+
private totalLagMs = 0;
|
|
37
|
+
private sampleCount = 0;
|
|
38
|
+
private blockedCount = 0;
|
|
39
|
+
private intervalHandle: ReturnType<typeof setInterval> | null = null;
|
|
40
|
+
private lastCheckTime = 0;
|
|
41
|
+
private getActiveOperationsCount: () => number = () => 0;
|
|
42
|
+
|
|
43
|
+
private constructor() {}
|
|
44
|
+
|
|
45
|
+
static getInstance(): EventLoopMonitor {
|
|
46
|
+
if (!EventLoopMonitor.instance) {
|
|
47
|
+
EventLoopMonitor.instance = new EventLoopMonitor();
|
|
48
|
+
}
|
|
49
|
+
return EventLoopMonitor.instance;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Start monitoring the event loop.
|
|
54
|
+
* @param getActiveOperationsCount - Function to get current active LLM operations count
|
|
55
|
+
* @param sampleIntervalMs - How often to sample (default 100ms)
|
|
56
|
+
* @param lagThresholdMs - What lag value is considered "blocked" (default 50ms)
|
|
57
|
+
*/
|
|
58
|
+
start(
|
|
59
|
+
getActiveOperationsCount: () => number,
|
|
60
|
+
sampleIntervalMs = DEFAULT_SAMPLE_INTERVAL_MS,
|
|
61
|
+
lagThresholdMs = DEFAULT_LAG_THRESHOLD_MS
|
|
62
|
+
): void {
|
|
63
|
+
if (this.isRunning) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.getActiveOperationsCount = getActiveOperationsCount;
|
|
68
|
+
this.isRunning = true;
|
|
69
|
+
this.lastCheckTime = Date.now();
|
|
70
|
+
|
|
71
|
+
// Use setInterval but measure actual elapsed time vs expected
|
|
72
|
+
this.intervalHandle = setInterval(() => {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
const expectedElapsed = sampleIntervalMs;
|
|
75
|
+
const actualElapsed = now - this.lastCheckTime;
|
|
76
|
+
const lag = actualElapsed - expectedElapsed;
|
|
77
|
+
|
|
78
|
+
// Only record positive lag (negative would mean timer fired early)
|
|
79
|
+
const lagMs = Math.max(0, lag);
|
|
80
|
+
const activeOps = this.getActiveOperationsCount();
|
|
81
|
+
|
|
82
|
+
const sample: LagSample = {
|
|
83
|
+
timestamp: now,
|
|
84
|
+
lagMs,
|
|
85
|
+
activeOperations: activeOps,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
this.samples.push(sample);
|
|
89
|
+
if (this.samples.length > MAX_SAMPLES) {
|
|
90
|
+
this.samples.shift();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.sampleCount++;
|
|
94
|
+
this.totalLagMs += lagMs;
|
|
95
|
+
if (lagMs > this.peakLagMs) {
|
|
96
|
+
this.peakLagMs = lagMs;
|
|
97
|
+
}
|
|
98
|
+
if (lagMs > lagThresholdMs) {
|
|
99
|
+
this.blockedCount++;
|
|
100
|
+
|
|
101
|
+
// Log significant lag events
|
|
102
|
+
if (lagMs > lagThresholdMs * 2) {
|
|
103
|
+
const activeSpan = trace.getActiveSpan();
|
|
104
|
+
activeSpan?.addEvent("event_loop.significant_lag", {
|
|
105
|
+
"lag.ms": lagMs,
|
|
106
|
+
"lag.threshold_ms": lagThresholdMs,
|
|
107
|
+
"concurrent.active_operations": activeOps,
|
|
108
|
+
"process.memory_heap_used_mb": Math.round(
|
|
109
|
+
process.memoryUsage().heapUsed / 1024 / 1024
|
|
110
|
+
),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
logger.warn("[EventLoopMonitor] Significant event loop lag detected", {
|
|
114
|
+
lagMs,
|
|
115
|
+
activeOperations: activeOps,
|
|
116
|
+
threshold: lagThresholdMs,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.lastCheckTime = now;
|
|
122
|
+
}, sampleIntervalMs);
|
|
123
|
+
|
|
124
|
+
logger.info("[EventLoopMonitor] Started monitoring", {
|
|
125
|
+
sampleIntervalMs,
|
|
126
|
+
lagThresholdMs,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Stop monitoring
|
|
132
|
+
*/
|
|
133
|
+
stop(): void {
|
|
134
|
+
if (!this.isRunning || !this.intervalHandle) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
clearInterval(this.intervalHandle);
|
|
139
|
+
this.intervalHandle = null;
|
|
140
|
+
this.isRunning = false;
|
|
141
|
+
|
|
142
|
+
logger.info("[EventLoopMonitor] Stopped monitoring");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get current statistics
|
|
147
|
+
*/
|
|
148
|
+
getStats(): EventLoopStats {
|
|
149
|
+
return {
|
|
150
|
+
samples: [...this.samples],
|
|
151
|
+
peakLagMs: this.peakLagMs,
|
|
152
|
+
avgLagMs: this.sampleCount > 0 ? this.totalLagMs / this.sampleCount : 0,
|
|
153
|
+
sampleCount: this.sampleCount,
|
|
154
|
+
blockedCount: this.blockedCount,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get recent samples where lag was above threshold
|
|
160
|
+
*/
|
|
161
|
+
getRecentBlockedSamples(thresholdMs = DEFAULT_LAG_THRESHOLD_MS, maxCount = 10): LagSample[] {
|
|
162
|
+
return this.samples
|
|
163
|
+
.filter((s) => s.lagMs > thresholdMs)
|
|
164
|
+
.slice(-maxCount);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Emit current stats as an OTL span event
|
|
169
|
+
*/
|
|
170
|
+
emitStatsEvent(contextLabel: string): void {
|
|
171
|
+
const stats = this.getStats();
|
|
172
|
+
const activeSpan = trace.getActiveSpan();
|
|
173
|
+
|
|
174
|
+
activeSpan?.addEvent("event_loop.stats_snapshot", {
|
|
175
|
+
"stats.context": contextLabel,
|
|
176
|
+
"stats.peak_lag_ms": stats.peakLagMs,
|
|
177
|
+
"stats.avg_lag_ms": Math.round(stats.avgLagMs * 100) / 100,
|
|
178
|
+
"stats.sample_count": stats.sampleCount,
|
|
179
|
+
"stats.blocked_count": stats.blockedCount,
|
|
180
|
+
"stats.blocked_percentage":
|
|
181
|
+
stats.sampleCount > 0
|
|
182
|
+
? Math.round((stats.blockedCount / stats.sampleCount) * 10000) / 100
|
|
183
|
+
: 0,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Reset all metrics (for testing)
|
|
189
|
+
*/
|
|
190
|
+
reset(): void {
|
|
191
|
+
this.samples = [];
|
|
192
|
+
this.peakLagMs = 0;
|
|
193
|
+
this.totalLagMs = 0;
|
|
194
|
+
this.sampleCount = 0;
|
|
195
|
+
this.blockedCount = 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Check if monitoring is currently active
|
|
200
|
+
*/
|
|
201
|
+
isActive(): boolean {
|
|
202
|
+
return this.isRunning;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export const eventLoopMonitor = EventLoopMonitor.getInstance();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry to track LLM execution span IDs by trace ID.
|
|
3
|
+
* Allows published events to reference the LLM span that generated their content.
|
|
4
|
+
*
|
|
5
|
+
* When an ai.streamText.doStream span ends, its span ID is stored here keyed by trace ID.
|
|
6
|
+
* When publishing events, we look up the LLM span ID to link directly to the LLM execution.
|
|
7
|
+
*/
|
|
8
|
+
const llmSpansByTrace = new Map<string, string>();
|
|
9
|
+
|
|
10
|
+
export function setLLMSpanId(traceId: string, spanId: string): void {
|
|
11
|
+
llmSpansByTrace.set(traceId, spanId);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getLLMSpanId(traceId: string): string | undefined {
|
|
15
|
+
return llmSpansByTrace.get(traceId);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function clearLLMSpanId(traceId: string): void {
|
|
19
|
+
llmSpansByTrace.delete(traceId);
|
|
20
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Context } from "@opentelemetry/api";
|
|
2
|
+
import type { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Internal OTEL Span structure - accessing private fields to rewrite span IDs
|
|
6
|
+
* This is necessary because OTEL doesn't expose a way to set spanId after creation
|
|
7
|
+
*/
|
|
8
|
+
interface SpanInternals {
|
|
9
|
+
_spanContext?: { spanId: string };
|
|
10
|
+
_parentSpanId?: string;
|
|
11
|
+
_parentSpanContext?: { spanId: string };
|
|
12
|
+
parentSpanContext?: { spanId: string };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert a Nostr hex ID to OpenTelemetry spanID (16 hex chars)
|
|
17
|
+
*/
|
|
18
|
+
function nostrIdToSpanId(nostrId: string): string {
|
|
19
|
+
return nostrId.substring(0, 16);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* SpanProcessor that rewrites span IDs for Nostr event processing spans.
|
|
24
|
+
*
|
|
25
|
+
* Problem: OpenTelemetry generates random spanIds, but we derive parentSpanId
|
|
26
|
+
* from Nostr event IDs (e-tags). This causes parent-child relationships to break
|
|
27
|
+
* because the random spanId doesn't match the derived parentSpanId.
|
|
28
|
+
*
|
|
29
|
+
* Solution: For spans with event.id attribute, rewrite their spanId to be
|
|
30
|
+
* deterministically derived from the event ID. This ensures that when another
|
|
31
|
+
* span references this event via e-tag, the parentSpanId will match.
|
|
32
|
+
*/
|
|
33
|
+
export class NostrSpanProcessor implements SpanProcessor {
|
|
34
|
+
forceFlush(): Promise<void> {
|
|
35
|
+
return Promise.resolve();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
shutdown(): Promise<void> {
|
|
39
|
+
return Promise.resolve();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onStart(_span: Span, _parentContext: Context): void {
|
|
43
|
+
// Nothing to do on start
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onEnd(span: ReadableSpan): void {
|
|
47
|
+
// Only rewrite spanIDs for tenex.event.process spans
|
|
48
|
+
// Other spans (tenex.dispatch.chat_message, tenex.delegation.completion_check) share
|
|
49
|
+
// event.id attribute but should NOT have their spanIDs rewritten to avoid collisions
|
|
50
|
+
if (span.name !== "tenex.event.process") {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Only process spans that have event.id attribute (Nostr event processing spans)
|
|
55
|
+
const eventId = span.attributes["event.id"];
|
|
56
|
+
if (typeof eventId !== "string" || !eventId) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Rewrite spanId to be derived from event.id
|
|
61
|
+
const derivedSpanId = nostrIdToSpanId(eventId);
|
|
62
|
+
|
|
63
|
+
// Access internal state - the Span class stores context in _spanContext
|
|
64
|
+
const spanInternal = span as unknown as SpanInternals;
|
|
65
|
+
|
|
66
|
+
// Modify the spanContext's spanId
|
|
67
|
+
if (spanInternal._spanContext) {
|
|
68
|
+
spanInternal._spanContext.spanId = derivedSpanId;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Fix parentSpanId based on event.reply_to
|
|
72
|
+
const replyTo = span.attributes["event.reply_to"];
|
|
73
|
+
if (typeof replyTo === "string" && replyTo) {
|
|
74
|
+
// This is a reply - set parent to the event being replied to
|
|
75
|
+
const derivedParentSpanId = nostrIdToSpanId(replyTo);
|
|
76
|
+
|
|
77
|
+
// Modify the parent span context
|
|
78
|
+
if (spanInternal._parentSpanContext) {
|
|
79
|
+
spanInternal._parentSpanContext.spanId = derivedParentSpanId;
|
|
80
|
+
} else if (spanInternal.parentSpanContext) {
|
|
81
|
+
spanInternal.parentSpanContext.spanId = derivedParentSpanId;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
// This is a root message - clear parent context so it becomes a true root span
|
|
85
|
+
spanInternal._parentSpanContext = undefined;
|
|
86
|
+
spanInternal.parentSpanContext = undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Context } from "@opentelemetry/api";
|
|
2
|
+
import type { ReadableSpan, SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
3
|
+
import type { Span } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
import { setLLMSpanId } from "./LLMSpanRegistry";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Span processor that enriches tool call span names with the actual tool name.
|
|
8
|
+
* Transforms generic "ai.toolCall" spans into "ai.toolCall.{toolName}" for better visibility.
|
|
9
|
+
*/
|
|
10
|
+
export class ToolCallSpanProcessor implements SpanProcessor {
|
|
11
|
+
onStart(_span: Span, _parentContext: Context): void {
|
|
12
|
+
// This is called when a span starts, but we can't modify the name here
|
|
13
|
+
// because the attributes might not be set yet
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
onEnd(span: ReadableSpan): void {
|
|
17
|
+
// Extract agent context if available
|
|
18
|
+
const agentName = span.attributes?.["agent.name"];
|
|
19
|
+
const agentSlug = span.attributes?.["agent.slug"];
|
|
20
|
+
const agentPrefix = agentSlug || agentName;
|
|
21
|
+
|
|
22
|
+
// Check if this is a tool call span
|
|
23
|
+
if (span.name === "ai.toolCall" && span.attributes) {
|
|
24
|
+
const toolName = span.attributes["ai.toolCall.name"];
|
|
25
|
+
|
|
26
|
+
if (toolName && typeof toolName === "string") {
|
|
27
|
+
// Include agent slug in the span name for better visibility
|
|
28
|
+
const prefix = agentPrefix ? `[${agentPrefix}] ` : "";
|
|
29
|
+
// ReadableSpan has readonly name, but we can mutate it via the underlying object
|
|
30
|
+
(span as ReadableSpan & { name: string }).name = `${prefix}ai.toolCall.${toolName}`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Also enhance other AI operation spans with more context if available
|
|
35
|
+
if (span.name === "ai.streamText" || span.name === "ai.generateText") {
|
|
36
|
+
const model = span.attributes?.["ai.model.id"];
|
|
37
|
+
if (model && typeof model === "string") {
|
|
38
|
+
const shortModel = model.split("/").pop() || model;
|
|
39
|
+
const prefix = agentPrefix ? `[${agentPrefix}] ` : "";
|
|
40
|
+
(span as ReadableSpan & { name: string }).name = `${prefix}${span.name}.${shortModel}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Enhance agent execution spans
|
|
45
|
+
if (span.name === "tenex.agent.execute" && agentPrefix) {
|
|
46
|
+
const phase = span.attributes?.["conversation.phase"];
|
|
47
|
+
const phaseStr = phase ? `.${phase}` : "";
|
|
48
|
+
(span as ReadableSpan & { name: string }).name = `[${agentPrefix}] agent.execute${phaseStr}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Capture ai.streamText.doStream span IDs for event linking
|
|
52
|
+
// This allows published events to reference the LLM span that generated their content
|
|
53
|
+
if (span.name === "ai.streamText.doStream") {
|
|
54
|
+
const spanContext = span.spanContext();
|
|
55
|
+
setLLMSpanId(spanContext.traceId, spanContext.spanId);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
shutdown(): Promise<void> {
|
|
60
|
+
return Promise.resolve();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
forceFlush(): Promise<void> {
|
|
64
|
+
return Promise.resolve();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostics Configuration - Feature flag for diagnostic instrumentation
|
|
3
|
+
*
|
|
4
|
+
* Controls whether detailed diagnostic telemetry is collected.
|
|
5
|
+
* Disable in production for performance; enable when investigating issues.
|
|
6
|
+
*
|
|
7
|
+
* Set TENEX_DIAGNOSTICS=true to enable all diagnostic instrumentation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if diagnostics are enabled via environment variable.
|
|
12
|
+
* Caches the result at module load time.
|
|
13
|
+
*/
|
|
14
|
+
export function isDiagnosticsEnabled(): boolean {
|
|
15
|
+
return process.env.TENEX_DIAGNOSTICS === "true";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get the diagnostics enabled state (for logging/tracing).
|
|
20
|
+
*/
|
|
21
|
+
export function getDiagnosticsState(): { enabled: boolean; source: string } {
|
|
22
|
+
const enabled = isDiagnosticsEnabled();
|
|
23
|
+
return {
|
|
24
|
+
enabled,
|
|
25
|
+
source: enabled ? "TENEX_DIAGNOSTICS=true" : "default (disabled)",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { ExportResult } from "@opentelemetry/core";
|
|
2
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
3
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
4
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
5
|
+
import type { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
|
|
6
|
+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
|
|
7
|
+
import {
|
|
8
|
+
SEMRESATTRS_SERVICE_NAME,
|
|
9
|
+
SEMRESATTRS_SERVICE_VERSION,
|
|
10
|
+
} from "@opentelemetry/semantic-conventions";
|
|
11
|
+
import { ToolCallSpanProcessor } from "./ToolCallSpanProcessor.js";
|
|
12
|
+
import { NostrSpanProcessor } from "./NostrSpanProcessor.js";
|
|
13
|
+
|
|
14
|
+
const DEFAULT_SERVICE_NAME = "tenex-daemon";
|
|
15
|
+
const DEFAULT_ENDPOINT = "http://localhost:4318/v1/traces";
|
|
16
|
+
|
|
17
|
+
class ErrorHandlingExporterWrapper implements SpanExporter {
|
|
18
|
+
private disabled = false;
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
private traceExporter: OTLPTraceExporter,
|
|
22
|
+
private exporterUrl: string
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {
|
|
26
|
+
// Once disabled, drop all spans silently
|
|
27
|
+
if (this.disabled) {
|
|
28
|
+
resultCallback({ code: 0 }); // ExportResultCode.SUCCESS
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.traceExporter.export(spans, (result) => {
|
|
33
|
+
if (result.error && !this.disabled) {
|
|
34
|
+
const errorMessage = result.error?.message || String(result.error);
|
|
35
|
+
const isConnectionError = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("connect");
|
|
36
|
+
if (isConnectionError) {
|
|
37
|
+
console.warn(`[Telemetry] ⚠️ Collector not available at ${this.exporterUrl}`);
|
|
38
|
+
} else {
|
|
39
|
+
console.error("[Telemetry] Export error:", errorMessage);
|
|
40
|
+
}
|
|
41
|
+
console.warn("[Telemetry] Disabling trace export");
|
|
42
|
+
this.disabled = true;
|
|
43
|
+
}
|
|
44
|
+
resultCallback(result);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
shutdown(): Promise<void> {
|
|
49
|
+
return this.traceExporter.shutdown();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Create a wrapper processor that enriches span names and fixes Nostr IDs before exporting
|
|
54
|
+
class EnrichedBatchSpanProcessor extends BatchSpanProcessor {
|
|
55
|
+
private enricher = new ToolCallSpanProcessor();
|
|
56
|
+
private nostrProcessor = new NostrSpanProcessor();
|
|
57
|
+
|
|
58
|
+
onEnd(span: ReadableSpan): void {
|
|
59
|
+
// First fix Nostr span IDs (must happen before export)
|
|
60
|
+
this.nostrProcessor.onEnd(span);
|
|
61
|
+
// Then enrich tool call spans
|
|
62
|
+
this.enricher.onEnd(span);
|
|
63
|
+
// Then pass to batch processor
|
|
64
|
+
super.onEnd(span);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let sdk: NodeSDK | null = null;
|
|
69
|
+
|
|
70
|
+
function createSDK(serviceName: string, wrappedExporter: SpanExporter): NodeSDK {
|
|
71
|
+
const resource = resourceFromAttributes({
|
|
72
|
+
[SEMRESATTRS_SERVICE_NAME]: serviceName,
|
|
73
|
+
[SEMRESATTRS_SERVICE_VERSION]: process.env.npm_package_version || "0.8.0",
|
|
74
|
+
"deployment.environment": process.env.NODE_ENV || "development",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const spanProcessor = new EnrichedBatchSpanProcessor(wrappedExporter, {
|
|
78
|
+
maxQueueSize: 2048,
|
|
79
|
+
maxExportBatchSize: 512,
|
|
80
|
+
scheduledDelayMillis: 5000, // Send every 5 seconds
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return new NodeSDK({
|
|
84
|
+
resource,
|
|
85
|
+
spanProcessor,
|
|
86
|
+
// NO sampling - capture everything (100%)
|
|
87
|
+
// NO instrumentation filters - capture all
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function initializeTelemetry(
|
|
92
|
+
enabled = true,
|
|
93
|
+
serviceName = DEFAULT_SERVICE_NAME,
|
|
94
|
+
endpoint = DEFAULT_ENDPOINT
|
|
95
|
+
): void {
|
|
96
|
+
if (!enabled) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Use environment variable if set, otherwise use config endpoint
|
|
101
|
+
const exporterUrl = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || endpoint;
|
|
102
|
+
|
|
103
|
+
// Create exporter with the configured URL
|
|
104
|
+
const traceExporter = new OTLPTraceExporter({
|
|
105
|
+
url: exporterUrl,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Wrap the exporter with error handling
|
|
109
|
+
const wrappedExporter = new ErrorHandlingExporterWrapper(traceExporter, exporterUrl);
|
|
110
|
+
|
|
111
|
+
sdk = createSDK(serviceName, wrappedExporter);
|
|
112
|
+
sdk.start();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function shutdownTelemetry(): Promise<void> {
|
|
116
|
+
if (!sdk) {
|
|
117
|
+
return Promise.resolve();
|
|
118
|
+
}
|
|
119
|
+
return sdk.shutdown();
|
|
120
|
+
}
|