@tenex-chat/backend 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +5 -1
  2. package/dist/daemon-wrapper.cjs +47 -0
  3. package/dist/index.js +59268 -0
  4. package/dist/wrapper.js +171 -0
  5. package/package.json +19 -27
  6. package/src/agents/AgentRegistry.ts +9 -7
  7. package/src/agents/AgentStorage.ts +24 -1
  8. package/src/agents/agent-installer.ts +6 -0
  9. package/src/agents/agent-loader.ts +7 -2
  10. package/src/agents/constants.ts +10 -2
  11. package/src/agents/execution/AgentExecutor.ts +35 -6
  12. package/src/agents/execution/StreamCallbacks.ts +53 -13
  13. package/src/agents/execution/StreamExecutionHandler.ts +110 -16
  14. package/src/agents/execution/StreamSetup.ts +19 -9
  15. package/src/agents/execution/ToolEventHandlers.ts +112 -0
  16. package/src/agents/role-categories.ts +53 -0
  17. package/src/agents/types/runtime.ts +7 -0
  18. package/src/agents/types/storage.ts +7 -0
  19. package/src/commands/agent/import/openclaw-distiller.ts +63 -7
  20. package/src/commands/agent/import/openclaw-reader.ts +54 -0
  21. package/src/commands/agent/import/openclaw.ts +120 -29
  22. package/src/commands/agent/index.ts +83 -2
  23. package/src/commands/setup/display.ts +123 -0
  24. package/src/commands/setup/embed.ts +13 -13
  25. package/src/commands/setup/global-system-prompt.ts +15 -17
  26. package/src/commands/setup/image.ts +17 -20
  27. package/src/commands/setup/interactive.ts +37 -20
  28. package/src/commands/setup/llm.ts +12 -7
  29. package/src/commands/setup/onboarding.ts +1580 -248
  30. package/src/commands/setup/providers.ts +3 -3
  31. package/src/conversations/ConversationStore.ts +23 -2
  32. package/src/conversations/MessageBuilder.ts +51 -73
  33. package/src/conversations/formatters/utils/conversation-transcript-formatter.ts +425 -0
  34. package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +40 -98
  35. package/src/conversations/search/embeddings/ConversationIndexingJob.ts +40 -52
  36. package/src/conversations/services/ConversationSummarizer.ts +1 -2
  37. package/src/conversations/types.ts +11 -0
  38. package/src/daemon/Daemon.ts +78 -57
  39. package/src/daemon/ProjectRuntime.ts +6 -12
  40. package/src/daemon/SubscriptionManager.ts +13 -0
  41. package/src/daemon/index.ts +0 -1
  42. package/src/event-handler/index.ts +1 -0
  43. package/src/index.ts +20 -1
  44. package/src/llm/ChunkHandler.ts +1 -1
  45. package/src/llm/FinishHandler.ts +28 -4
  46. package/src/llm/LLMConfigEditor.ts +218 -106
  47. package/src/llm/index.ts +0 -4
  48. package/src/llm/meta/MetaModelResolver.ts +3 -18
  49. package/src/llm/middleware/message-sanitizer.ts +153 -0
  50. package/src/llm/providers/ollama-models.ts +0 -38
  51. package/src/llm/service.ts +50 -15
  52. package/src/llm/types.ts +0 -12
  53. package/src/llm/utils/ConfigurationManager.ts +88 -465
  54. package/src/llm/utils/ConfigurationTester.ts +42 -185
  55. package/src/llm/utils/ModelSelector.ts +156 -92
  56. package/src/llm/utils/ProviderConfigUI.ts +10 -141
  57. package/src/llm/utils/models-dev-cache.ts +102 -23
  58. package/src/llm/utils/provider-select-prompt.ts +284 -0
  59. package/src/llm/utils/provider-setup.ts +81 -34
  60. package/src/llm/utils/variant-list-prompt.ts +361 -0
  61. package/src/nostr/AgentEventDecoder.ts +1 -0
  62. package/src/nostr/AgentEventEncoder.ts +37 -0
  63. package/src/nostr/AgentProfilePublisher.ts +13 -0
  64. package/src/nostr/AgentPublisher.ts +26 -0
  65. package/src/nostr/kinds.ts +1 -0
  66. package/src/nostr/ndkClient.ts +4 -1
  67. package/src/nostr/types.ts +12 -0
  68. package/src/prompts/fragments/25-rag-instructions.ts +22 -21
  69. package/src/prompts/fragments/31-agents-md-guidance.ts +7 -21
  70. package/src/prompts/fragments/index.ts +2 -0
  71. package/src/prompts/utils/systemPromptBuilder.ts +18 -28
  72. package/src/services/AgentDefinitionMonitor.ts +8 -0
  73. package/src/services/ConfigService.ts +34 -0
  74. package/src/services/PubkeyService.ts +7 -1
  75. package/src/services/compression/CompressionService.ts +133 -74
  76. package/src/services/compression/compression-utils.ts +110 -19
  77. package/src/services/config/types.ts +0 -6
  78. package/src/services/dispatch/AgentDispatchService.ts +79 -0
  79. package/src/services/intervention/InterventionService.ts +78 -5
  80. package/src/services/nip46/Nip46SigningService.ts +30 -1
  81. package/src/services/projects/ProjectContext.ts +8 -6
  82. package/src/services/rag/RAGCollectionRegistry.ts +199 -0
  83. package/src/services/rag/RAGDatabaseService.ts +2 -7
  84. package/src/services/rag/RAGOperations.ts +25 -45
  85. package/src/services/rag/RAGService.ts +0 -31
  86. package/src/services/rag/RagSubscriptionService.ts +71 -122
  87. package/src/services/rag/rag-utils.ts +13 -0
  88. package/src/services/ral/RALRegistry.ts +25 -184
  89. package/src/services/reports/ReportEmbeddingService.ts +63 -113
  90. package/src/services/search/UnifiedSearchService.ts +115 -4
  91. package/src/services/search/index.ts +1 -0
  92. package/src/services/search/projectFilter.ts +20 -4
  93. package/src/services/search/providers/ConversationSearchProvider.ts +1 -0
  94. package/src/services/search/providers/GenericCollectionSearchProvider.ts +81 -0
  95. package/src/services/search/providers/LessonSearchProvider.ts +1 -8
  96. package/src/services/search/providers/ReportSearchProvider.ts +1 -0
  97. package/src/services/search/types.ts +24 -3
  98. package/src/services/trust-pubkeys/SystemPubkeyListService.ts +148 -0
  99. package/src/services/trust-pubkeys/TrustPubkeyService.ts +70 -9
  100. package/src/telemetry/setup.ts +2 -13
  101. package/src/tools/implementations/ask.ts +3 -3
  102. package/src/tools/implementations/conversation_get.ts +28 -268
  103. package/src/tools/implementations/fs_grep.ts +6 -6
  104. package/src/tools/implementations/fs_read.ts +2 -0
  105. package/src/tools/implementations/fs_write.ts +2 -0
  106. package/src/tools/implementations/learn.ts +38 -50
  107. package/src/tools/implementations/rag_add_documents.ts +6 -4
  108. package/src/tools/implementations/rag_create_collection.ts +37 -4
  109. package/src/tools/implementations/rag_delete_collection.ts +9 -0
  110. package/src/tools/implementations/{search.ts → rag_search.ts} +31 -25
  111. package/src/tools/registry.ts +7 -8
  112. package/src/tools/types.ts +11 -2
  113. package/src/tools/utils/transcript-args.ts +13 -0
  114. package/src/utils/cli-theme.ts +13 -0
  115. package/src/utils/logger.ts +55 -0
  116. package/src/utils/metadataKeys.ts +17 -0
  117. package/src/utils/sqlEscaping.ts +39 -0
  118. package/src/wrapper.ts +7 -3
  119. package/dist/src/index.js +0 -46778
  120. package/dist/tenex-backend-wrapper.cjs +0 -3
  121. package/src/agents/execution/constants.ts +0 -16
  122. package/src/agents/execution/index.ts +0 -3
  123. package/src/agents/index.ts +0 -4
  124. package/src/commands/agent.ts +0 -215
  125. package/src/conversations/formatters/DelegationXmlFormatter.ts +0 -64
  126. package/src/conversations/formatters/index.ts +0 -9
  127. package/src/conversations/index.ts +0 -2
  128. package/src/conversations/utils/content-utils.ts +0 -69
  129. package/src/daemon/UnixSocketTransport.ts +0 -318
  130. package/src/event-handler/newConversation.ts +0 -165
  131. package/src/events/NDKProjectStatus.ts +0 -384
  132. package/src/events/index.ts +0 -4
  133. package/src/lib/json-parser.ts +0 -30
  134. package/src/llm/RecordingState.ts +0 -37
  135. package/src/llm/StreamPublisher.ts +0 -40
  136. package/src/llm/middleware/flight-recorder.ts +0 -188
  137. package/src/llm/utils/claudeCodePromptCompiler.ts +0 -141
  138. package/src/nostr/constants.ts +0 -38
  139. package/src/prompts/core/index.ts +0 -3
  140. package/src/prompts/index.ts +0 -21
  141. package/src/services/image/index.ts +0 -12
  142. package/src/services/status/index.ts +0 -11
  143. package/src/telemetry/diagnostics.ts +0 -27
  144. package/src/tools/implementations/rag_query.ts +0 -107
  145. package/src/types/index.ts +0 -46
  146. package/src/utils/agentFetcher.ts +0 -107
  147. package/src/utils/conversation-utils.ts +0 -1
  148. package/src/utils/process.ts +0 -49
@@ -1,141 +0,0 @@
1
- import type { ModelMessage, TextPart, ImagePart } from "ai";
2
-
3
- /**
4
- * Extract text content from a message content field.
5
- * Handles both string content and multimodal content (TextPart + ImagePart arrays).
6
- *
7
- * For multimodal content, extracts the text part and notes any images.
8
- */
9
- function extractTextContent(content: ModelMessage["content"]): string {
10
- if (typeof content === "string") {
11
- return content;
12
- }
13
-
14
- if (!Array.isArray(content)) {
15
- return JSON.stringify(content);
16
- }
17
-
18
- // Handle multimodal content (arrays of parts)
19
- const parts: string[] = [];
20
- let imageCount = 0;
21
-
22
- for (const part of content) {
23
- if ((part as TextPart).type === "text") {
24
- parts.push((part as TextPart).text);
25
- } else if ((part as ImagePart).type === "image") {
26
- imageCount++;
27
- }
28
- }
29
-
30
- // If there were images, note them at the end
31
- if (imageCount > 0) {
32
- parts.push(`[${imageCount} image${imageCount > 1 ? "s" : ""} attached]`);
33
- }
34
-
35
- return parts.join("\n");
36
- }
37
-
38
- /**
39
- * System prompt type for Claude Code.
40
- * Can be a string for custom system prompt, or use preset with append for
41
- * Claude Code's built-in instructions plus custom content.
42
- */
43
- export type ClaudeCodeSystemPrompt = string | {
44
- type: "preset";
45
- preset: "claude_code";
46
- append?: string;
47
- };
48
-
49
- /**
50
- * Compiles system messages for Claude Code's systemPrompt.append.
51
- * Uses the new systemPrompt API (replacing deprecated customSystemPrompt/appendSystemPrompt).
52
- *
53
- * IMPORTANT: Only system messages are included in systemPrompt.append.
54
- * User/assistant messages are passed separately via the messages array to streamText().
55
- * This separation is critical for session resumption to work correctly - if conversation
56
- * history is duplicated in both systemPrompt.append AND messages, it creates a session
57
- * state that can't be reconstructed on resume.
58
- *
59
- * Note: Multimodal content (images) is converted to text descriptions since
60
- * Claude Code uses a text-based prompt compilation approach.
61
- */
62
- export function compileMessagesForClaudeCode(messages: ModelMessage[]): {
63
- systemPrompt?: ClaudeCodeSystemPrompt;
64
- } {
65
- if (messages.length === 0) {
66
- return { systemPrompt: undefined };
67
- }
68
-
69
- // Extract only system messages - user/assistant go in messages array
70
- const systemMessages = messages.filter((m) => m.role === "system");
71
-
72
- if (systemMessages.length === 0) {
73
- return { systemPrompt: undefined };
74
- }
75
-
76
- // Combine all system messages into the append content
77
- const appendParts: string[] = [];
78
-
79
- for (const msg of systemMessages) {
80
- const content =
81
- typeof msg.content === "string"
82
- ? msg.content
83
- : extractTextContent(msg.content);
84
- appendParts.push(content);
85
- }
86
-
87
- const appendContent = appendParts.join("\n\n");
88
-
89
- // Use Claude Code's built-in preset with our system content appended
90
- return {
91
- systemPrompt: {
92
- type: "preset",
93
- preset: "claude_code",
94
- append: appendContent,
95
- },
96
- };
97
- }
98
-
99
- /**
100
- * Converts system messages to user messages for active Claude Code sessions.
101
- * When resuming a session, Claude Code doesn't receive new system messages,
102
- * so we convert them to user messages to ensure they're delivered.
103
- *
104
- * Note: Multimodal content is preserved for user messages (they support images),
105
- * but system messages with multimodal content are converted to text descriptions.
106
- */
107
- export function convertSystemMessagesForResume(messages: ModelMessage[]): ModelMessage[] {
108
- // For resuming sessions, we need to convert system messages that appear
109
- // after the conversation started into user messages
110
-
111
- // Find the first non-system message (start of conversation)
112
- const conversationStartIndex = messages.findIndex((m) => m.role !== "system");
113
-
114
- if (conversationStartIndex === -1) {
115
- // All messages are system messages, no conversion needed
116
- return messages;
117
- }
118
-
119
- // Convert messages, preserving order
120
- const convertedMessages = messages.map((msg, index) => {
121
- // Keep initial system messages as-is (they were part of initial prompt)
122
- if (index < conversationStartIndex) {
123
- return msg;
124
- }
125
-
126
- // Convert subsequent system messages to user messages with clear marker
127
- if (msg.role === "system") {
128
- // Use extractTextContent to handle multimodal content gracefully
129
- const content = extractTextContent(msg.content);
130
- return {
131
- role: "user" as const,
132
- content: `[System Context]: ${content}`,
133
- };
134
- }
135
-
136
- // Keep user and assistant messages as-is (preserving multimodal content)
137
- return msg;
138
- });
139
-
140
- return convertedMessages as ModelMessage[];
141
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Nostr event kinds used in the application
3
- */
4
- export enum NostrKind {
5
- // Standard kinds
6
- TEXT_NOTE = 1,
7
- REACTION = 7,
8
- ARTICLE = 30023,
9
- }
10
-
11
- /**
12
- * Standard Nostr tag names
13
- */
14
- export enum NostrTag {
15
- // Standard tags
16
- EVENT = "e",
17
- PUBKEY = "p",
18
- REPLACEABLE = "a",
19
-
20
- // Application-specific tags
21
- MODE = "mode",
22
- PARTICIPANT = "participant",
23
- REASON = "reason",
24
- TOOL = "tool",
25
- }
26
-
27
- /**
28
- * Tag values for specific application modes
29
- */
30
- export enum TagValue {
31
- REACTION_POSITIVE = "+",
32
- DELEGATE = "delegate",
33
- }
34
-
35
- /**
36
- * Maximum lengths for various fields
37
- */
38
- export const MAX_REASON_LENGTH = 200;
@@ -1,3 +0,0 @@
1
- export { FragmentRegistry, fragmentRegistry } from "./FragmentRegistry";
2
- export { PromptBuilder } from "./PromptBuilder";
3
- export type { FragmentConfig, PromptFragment } from "./types";
@@ -1,21 +0,0 @@
1
- // Export core functionality
2
-
3
- export { FragmentRegistry, fragmentRegistry } from "./core/FragmentRegistry";
4
- export { PromptBuilder } from "./core/PromptBuilder";
5
- export type { FragmentConfig, PromptFragment } from "./core/types";
6
-
7
- // Import all fragments to ensure they're registered when the module is imported
8
- // Priority 01 - Identity
9
- import "./fragments/01-agent-identity";
10
-
11
- // Priority 10 - Early context
12
- import "./fragments/10-referenced-article"; // Conditional
13
-
14
- // Priority 15 - Available agents
15
- import "./fragments/15-available-agents";
16
-
17
- // Priority 20 - Mode context
18
- import "./fragments/20-voice-mode"; // Conditional
19
-
20
- // Priority 24 - Lessons
21
- import "./fragments/24-retrieved-lessons"; // Shared
@@ -1,12 +0,0 @@
1
- export {
2
- ImageGenerationService,
3
- type ImageConfig,
4
- type ImageGenerationOptions,
5
- type ImageResult,
6
- type ImageConfigOptions,
7
- type AspectRatio,
8
- type ImageSize,
9
- OPENROUTER_IMAGE_MODELS,
10
- ASPECT_RATIOS,
11
- IMAGE_SIZES,
12
- } from "./ImageGenerationService";
@@ -1,11 +0,0 @@
1
- /**
2
- * Status Publishing Services
3
- *
4
- * Handles broadcasting of status events for daemon, projects, and operations
5
- */
6
-
7
- // Project status (single project context)
8
- export { ProjectStatusService } from "./ProjectStatusService";
9
-
10
- // Operations status (LLM operations)
11
- export { OperationsStatusService } from "./OperationsStatusService";
@@ -1,27 +0,0 @@
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
- }
@@ -1,107 +0,0 @@
1
- import type { ToolExecutionContext } from "@/tools/types";
2
- import { type RAGQueryResult, RAGService } from "@/services/rag/RAGService";
3
- import type { AISdkTool } from "@/tools/types";
4
- import { type ToolResponse, executeToolWithErrorHandling } from "@/tools/utils";
5
- import { tool } from "ai";
6
- import { z } from "zod";
7
-
8
- const ragQuerySchema = z.object({
9
- description: z
10
- .string()
11
- .trim()
12
- .min(1, "Description is required and cannot be empty")
13
- .describe(
14
- "REQUIRED: A clear, concise description of why you're querying this collection (5-10 words). Helps provide human-readable context for the operation."
15
- ),
16
- collection: z.string().describe("Name of the collection to query"),
17
- query_text: z.string().describe("The text query for semantic search"),
18
- top_k: z
19
- .number()
20
- .int()
21
- .min(1)
22
- .max(100)
23
- .optional()
24
- .describe("Number of top results to return (default: 5, range: 1-100)"),
25
- include_metadata: z
26
- .boolean()
27
- .optional()
28
- .describe("Whether to include document metadata in results (default: true)"),
29
- });
30
-
31
- /**
32
- * Formatted result for tool response
33
- */
34
- interface FormattedQueryResult {
35
- rank: number;
36
- score: number;
37
- content: string;
38
- metadata?: Record<string, unknown>;
39
- source?: string;
40
- id?: string;
41
- timestamp?: string;
42
- }
43
-
44
- /**
45
- * Format query results for response
46
- */
47
- function formatResults(
48
- results: RAGQueryResult[],
49
- includeMetadata: boolean
50
- ): FormattedQueryResult[] {
51
- return results.map((result, index) => ({
52
- rank: index + 1,
53
- score: result.score,
54
- content:
55
- result.document.content.length > 500
56
- ? `${result.document.content.substring(0, 500)}...`
57
- : result.document.content,
58
- ...(includeMetadata && {
59
- metadata: result.document.metadata,
60
- source: result.document.source,
61
- id: result.document.id,
62
- timestamp: result.document.timestamp
63
- ? new Date(result.document.timestamp).toISOString()
64
- : undefined,
65
- }),
66
- }));
67
- }
68
-
69
- /**
70
- * Core implementation of RAG semantic search
71
- */
72
- async function executeQuery(
73
- input: z.infer<typeof ragQuerySchema>,
74
- _context: ToolExecutionContext
75
- ): Promise<ToolResponse> {
76
- const { collection, query_text } = input;
77
-
78
- // Use provided top_k or default to 5
79
- // The schema already validates the range (1-100) and integer constraint
80
- const topK = input.top_k ?? 5;
81
- const includeMetadata = input.include_metadata ?? true;
82
-
83
- const ragService = RAGService.getInstance();
84
- const results = await ragService.query(collection, query_text, topK);
85
-
86
- return {
87
- success: true,
88
- collection: collection,
89
- query: query_text,
90
- results_count: results.length,
91
- results: formatResults(results, includeMetadata),
92
- };
93
- }
94
-
95
- /**
96
- * Query a RAG collection using semantic search
97
- */
98
- export function createRAGQueryTool(context: ToolExecutionContext): AISdkTool {
99
- return tool({
100
- description:
101
- "Perform semantic search on a RAG collection. Returns the most relevant documents based on vector similarity to the query.",
102
- inputSchema: ragQuerySchema,
103
- execute: async (input: unknown) => {
104
- return executeToolWithErrorHandling("rag_query", input as z.infer<typeof ragQuerySchema>, context, executeQuery);
105
- },
106
- }) as AISdkTool;
107
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * Types barrel export
3
- *
4
- * Centralized exports for all custom types used throughout the system.
5
- */
6
-
7
- // Event ID types and utilities
8
- export {
9
- // Branded types
10
- type FullEventId,
11
- type ShortEventId,
12
- type ShellTaskId,
13
- type AnyEventId,
14
- type AnyTaskId,
15
-
16
- // Constants
17
- FULL_EVENT_ID_LENGTH,
18
- SHORT_EVENT_ID_LENGTH,
19
- SHELL_TASK_ID_LENGTH,
20
-
21
- // Type guards
22
- isFullEventId,
23
- isShortEventId,
24
- isShellTaskId,
25
- detectIdType,
26
-
27
- // Factory functions
28
- createFullEventId,
29
- createShortEventId,
30
- createShellTaskId,
31
- tryCreateFullEventId,
32
- tryCreateShortEventId,
33
- tryCreateShellTaskId,
34
-
35
- // Conversion functions
36
- shortenEventId,
37
- toRawString,
38
-
39
- // Assertion functions
40
- assertFullEventId,
41
- assertShortEventId,
42
- assertShellTaskId,
43
-
44
- // Utility functions
45
- parseEventId,
46
- } from "./event-ids";
@@ -1,107 +0,0 @@
1
- import type NDK from "@nostr-dev-kit/ndk";
2
- import type { NDKEvent } from "@nostr-dev-kit/ndk";
3
- import { NDKAgentDefinition, type ETagReference } from "@/events/NDKAgentDefinition";
4
- import { logger } from "./logger";
5
-
6
- /**
7
- * Represents the parsed data from an agent definition event.
8
- * Contains all fields needed to instantiate or display an agent.
9
- */
10
- export interface AgentDefinitionData {
11
- /** The Nostr event ID of the agent definition */
12
- id: string;
13
- /** The slug identifier (d-tag) for versioning */
14
- slug: string | undefined;
15
- /** Display name of the agent */
16
- title: string;
17
- /** Short one-liner description */
18
- description: string;
19
- /** Extended markdown description from content field */
20
- markdownDescription: string | undefined;
21
- /** The agent's role/personality */
22
- role: string;
23
- /** Detailed operational instructions */
24
- instructions: string;
25
- /** Criteria for when to use this agent */
26
- useCriteria: string;
27
- /** Version number of the agent definition */
28
- version: number;
29
- /** Unix timestamp when the event was created */
30
- created_at: number | undefined;
31
- /** Pubkey of the agent definition author */
32
- pubkey: string;
33
- /** References to bundled file metadata events */
34
- fileETags: ETagReference[];
35
- /** Reference to the source agent if this is a fork */
36
- forkSource: ETagReference | undefined;
37
- }
38
-
39
- /**
40
- * Fetches an agent event from Nostr
41
- * @param eventId - The ID of the event containing the agent
42
- * @param ndk - The NDK instance to use for fetching
43
- * @returns The agent event or null if not found
44
- */
45
- export async function fetchAgent(eventId: string, ndk: NDK): Promise<NDKEvent | null> {
46
- try {
47
- // Strip "nostr:" prefix if present
48
- const cleanEventId = eventId.startsWith("nostr:") ? eventId.substring(6) : eventId;
49
-
50
- const event = await ndk.fetchEvent(cleanEventId, { groupable: false });
51
-
52
- if (!event) {
53
- logger.debug(`Agent event not found: ${cleanEventId}`);
54
- return null;
55
- }
56
-
57
- return event;
58
- } catch (error) {
59
- logger.error(`Failed to fetch agent event: ${eventId}`, error);
60
- return null;
61
- }
62
- }
63
-
64
- /**
65
- * Fetches an agent definition from a Nostr event
66
- * @param eventId - The ID of the event containing the agent definition
67
- * @param ndk - The NDK instance to use for fetching
68
- * @returns The agent definition data or null if not found
69
- */
70
- export async function fetchAgentDefinition(
71
- eventId: string,
72
- ndk: NDK
73
- ): Promise<AgentDefinitionData | null> {
74
- try {
75
- // Strip "nostr:" prefix if present
76
- const cleanEventId = eventId.startsWith("nostr:") ? eventId.substring(6) : eventId;
77
-
78
- const event = await ndk.fetchEvent(cleanEventId, { groupable: false });
79
-
80
- if (!event) {
81
- logger.warning(`Agent event not found: ${cleanEventId}`);
82
- return null;
83
- }
84
-
85
- // Use NDKAgentDefinition for proper parsing
86
- const agentDef = NDKAgentDefinition.from(event);
87
-
88
- return {
89
- id: event.id,
90
- slug: agentDef.slug,
91
- title: agentDef.title || "Unnamed Agent",
92
- description: agentDef.description || "",
93
- markdownDescription: agentDef.markdownDescription,
94
- role: agentDef.role || "assistant",
95
- instructions: agentDef.instructions || "",
96
- useCriteria: agentDef.useCriteria || "",
97
- version: agentDef.version,
98
- created_at: event.created_at,
99
- pubkey: event.pubkey,
100
- fileETags: agentDef.getFileETags(),
101
- forkSource: agentDef.getForkSource(),
102
- };
103
- } catch (error) {
104
- logger.error(`Failed to fetch agent event: ${eventId}`, error);
105
- return null;
106
- }
107
- }
@@ -1 +0,0 @@
1
- // Conversation utility functions
@@ -1,49 +0,0 @@
1
- import { logger } from "@/utils/logger";
2
-
3
- /**
4
- * Handler function called during graceful shutdown
5
- */
6
- export type ShutdownHandler = (signal: string) => Promise<void>;
7
-
8
- /**
9
- * Sets up graceful shutdown handlers for various termination signals
10
- * @param shutdownHandler - Async function to handle cleanup during shutdown
11
- * @description Handles SIGTERM, SIGINT, SIGHUP signals and uncaught exceptions/rejections
12
- */
13
- export function setupGracefulShutdown(shutdownHandler: ShutdownHandler): void {
14
- let isShuttingDown = false;
15
-
16
- const shutdown = async (signal: string): Promise<void> => {
17
- if (isShuttingDown) return;
18
- isShuttingDown = true;
19
-
20
- logger.info(`Received ${signal}, shutting down gracefully...`);
21
-
22
- try {
23
- await shutdownHandler(signal);
24
- logger.info("Shutdown complete");
25
- process.exit(0);
26
- } catch (error) {
27
- logger.error("Error during shutdown", { error });
28
- process.exit(1);
29
- }
30
- };
31
-
32
- // Handle various termination signals
33
- process.on("SIGTERM", () => shutdown("SIGTERM"));
34
- process.on("SIGINT", () => shutdown("SIGINT"));
35
- process.on("SIGHUP", () => shutdown("SIGHUP"));
36
-
37
- // Handle uncaught errors
38
- process.on("uncaughtException", (error) => {
39
- logger.error("Uncaught exception", { error });
40
- shutdown("uncaughtException");
41
- });
42
-
43
- process.on("unhandledRejection", (reason, promise) => {
44
- logger.error("Unhandled rejection", { reason, promise });
45
- // Don't shutdown for unhandled rejections - they're usually not critical
46
- // e.g., relay rejections like "replaced: have newer event"
47
- // Let the daemon's handler deal with these instead
48
- });
49
- }