@tenex-chat/backend 0.9.5 → 0.9.7
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 +5 -1
- package/dist/daemon-wrapper.cjs +34 -0
- package/dist/index.js +59268 -0
- package/dist/wrapper.js +171 -0
- package/package.json +19 -27
- package/src/agents/AgentRegistry.ts +9 -7
- package/src/agents/AgentStorage.ts +24 -1
- package/src/agents/agent-installer.ts +6 -0
- package/src/agents/agent-loader.ts +7 -2
- package/src/agents/constants.ts +10 -2
- package/src/agents/execution/AgentExecutor.ts +35 -6
- package/src/agents/execution/StreamCallbacks.ts +53 -13
- package/src/agents/execution/StreamExecutionHandler.ts +110 -16
- package/src/agents/execution/StreamSetup.ts +19 -9
- package/src/agents/execution/ToolEventHandlers.ts +112 -0
- package/src/agents/role-categories.ts +53 -0
- package/src/agents/types/runtime.ts +7 -0
- package/src/agents/types/storage.ts +7 -0
- package/src/commands/agent/import/openclaw-distiller.ts +63 -7
- package/src/commands/agent/import/openclaw-reader.ts +54 -0
- package/src/commands/agent/import/openclaw.ts +120 -29
- package/src/commands/agent/index.ts +83 -2
- package/src/commands/setup/display.ts +123 -0
- package/src/commands/setup/embed.ts +13 -13
- package/src/commands/setup/global-system-prompt.ts +15 -17
- package/src/commands/setup/image.ts +17 -20
- package/src/commands/setup/interactive.ts +37 -20
- package/src/commands/setup/llm.ts +12 -7
- package/src/commands/setup/onboarding.ts +1580 -248
- package/src/commands/setup/providers.ts +3 -3
- package/src/conversations/ConversationStore.ts +23 -2
- package/src/conversations/MessageBuilder.ts +51 -73
- package/src/conversations/formatters/utils/conversation-transcript-formatter.ts +425 -0
- package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +40 -98
- package/src/conversations/search/embeddings/ConversationIndexingJob.ts +40 -52
- package/src/conversations/services/ConversationSummarizer.ts +1 -2
- package/src/conversations/types.ts +11 -0
- package/src/daemon/Daemon.ts +78 -57
- package/src/daemon/ProjectRuntime.ts +6 -12
- package/src/daemon/SubscriptionManager.ts +13 -0
- package/src/daemon/index.ts +0 -1
- package/src/event-handler/index.ts +1 -0
- package/src/index.ts +20 -1
- package/src/llm/ChunkHandler.ts +1 -1
- package/src/llm/FinishHandler.ts +28 -4
- package/src/llm/LLMConfigEditor.ts +218 -106
- package/src/llm/index.ts +0 -4
- package/src/llm/meta/MetaModelResolver.ts +3 -18
- package/src/llm/middleware/message-sanitizer.ts +153 -0
- package/src/llm/providers/ollama-models.ts +0 -38
- package/src/llm/service.ts +50 -15
- package/src/llm/types.ts +0 -12
- package/src/llm/utils/ConfigurationManager.ts +88 -465
- package/src/llm/utils/ConfigurationTester.ts +42 -185
- package/src/llm/utils/ModelSelector.ts +156 -92
- package/src/llm/utils/ProviderConfigUI.ts +10 -141
- package/src/llm/utils/models-dev-cache.ts +102 -23
- package/src/llm/utils/provider-select-prompt.ts +284 -0
- package/src/llm/utils/provider-setup.ts +81 -34
- package/src/llm/utils/variant-list-prompt.ts +361 -0
- package/src/nostr/AgentEventDecoder.ts +1 -0
- package/src/nostr/AgentEventEncoder.ts +37 -0
- package/src/nostr/AgentProfilePublisher.ts +13 -0
- package/src/nostr/AgentPublisher.ts +26 -0
- package/src/nostr/kinds.ts +1 -0
- package/src/nostr/ndkClient.ts +4 -1
- package/src/nostr/types.ts +12 -0
- package/src/prompts/fragments/25-rag-instructions.ts +22 -21
- package/src/prompts/fragments/31-agents-md-guidance.ts +7 -21
- package/src/prompts/fragments/index.ts +2 -0
- package/src/prompts/utils/systemPromptBuilder.ts +18 -28
- package/src/services/AgentDefinitionMonitor.ts +8 -0
- package/src/services/ConfigService.ts +34 -0
- package/src/services/PubkeyService.ts +7 -1
- package/src/services/compression/CompressionService.ts +133 -74
- package/src/services/compression/compression-utils.ts +110 -19
- package/src/services/config/types.ts +0 -6
- package/src/services/dispatch/AgentDispatchService.ts +79 -0
- package/src/services/intervention/InterventionService.ts +78 -5
- package/src/services/nip46/Nip46SigningService.ts +30 -1
- package/src/services/projects/ProjectContext.ts +8 -6
- package/src/services/rag/RAGCollectionRegistry.ts +199 -0
- package/src/services/rag/RAGDatabaseService.ts +2 -7
- package/src/services/rag/RAGOperations.ts +25 -45
- package/src/services/rag/RAGService.ts +0 -31
- package/src/services/rag/RagSubscriptionService.ts +71 -122
- package/src/services/rag/rag-utils.ts +13 -0
- package/src/services/ral/RALRegistry.ts +25 -184
- package/src/services/reports/ReportEmbeddingService.ts +63 -113
- package/src/services/search/UnifiedSearchService.ts +115 -4
- package/src/services/search/index.ts +1 -0
- package/src/services/search/projectFilter.ts +20 -4
- package/src/services/search/providers/ConversationSearchProvider.ts +1 -0
- package/src/services/search/providers/GenericCollectionSearchProvider.ts +81 -0
- package/src/services/search/providers/LessonSearchProvider.ts +1 -8
- package/src/services/search/providers/ReportSearchProvider.ts +1 -0
- package/src/services/search/types.ts +24 -3
- package/src/services/trust-pubkeys/SystemPubkeyListService.ts +148 -0
- package/src/services/trust-pubkeys/TrustPubkeyService.ts +70 -9
- package/src/telemetry/setup.ts +2 -13
- package/src/tools/implementations/ask.ts +3 -3
- package/src/tools/implementations/conversation_get.ts +28 -268
- package/src/tools/implementations/fs_grep.ts +6 -6
- package/src/tools/implementations/fs_read.ts +2 -0
- package/src/tools/implementations/fs_write.ts +2 -0
- package/src/tools/implementations/learn.ts +38 -50
- package/src/tools/implementations/rag_add_documents.ts +6 -4
- package/src/tools/implementations/rag_create_collection.ts +37 -4
- package/src/tools/implementations/rag_delete_collection.ts +9 -0
- package/src/tools/implementations/{search.ts → rag_search.ts} +31 -25
- package/src/tools/registry.ts +7 -8
- package/src/tools/types.ts +11 -2
- package/src/tools/utils/transcript-args.ts +13 -0
- package/src/utils/cli-theme.ts +13 -0
- package/src/utils/logger.ts +55 -0
- package/src/utils/metadataKeys.ts +17 -0
- package/src/utils/sqlEscaping.ts +39 -0
- package/src/wrapper.ts +7 -3
- package/dist/src/index.js +0 -46790
- package/dist/tenex-backend-wrapper.cjs +0 -3
- package/src/agents/execution/constants.ts +0 -16
- package/src/agents/execution/index.ts +0 -3
- package/src/agents/index.ts +0 -4
- package/src/commands/agent.ts +0 -235
- package/src/conversations/formatters/DelegationXmlFormatter.ts +0 -64
- package/src/conversations/formatters/index.ts +0 -9
- package/src/conversations/index.ts +0 -2
- package/src/conversations/utils/content-utils.ts +0 -69
- package/src/daemon/UnixSocketTransport.ts +0 -318
- package/src/event-handler/newConversation.ts +0 -165
- package/src/events/NDKProjectStatus.ts +0 -384
- package/src/events/index.ts +0 -4
- package/src/lib/json-parser.ts +0 -30
- package/src/llm/RecordingState.ts +0 -37
- package/src/llm/StreamPublisher.ts +0 -40
- package/src/llm/middleware/flight-recorder.ts +0 -188
- package/src/llm/utils/claudeCodePromptCompiler.ts +0 -141
- package/src/nostr/constants.ts +0 -38
- package/src/prompts/core/index.ts +0 -3
- package/src/prompts/index.ts +0 -21
- package/src/services/image/index.ts +0 -12
- package/src/services/status/index.ts +0 -11
- package/src/telemetry/diagnostics.ts +0 -27
- package/src/tools/implementations/rag_query.ts +0 -107
- package/src/types/index.ts +0 -46
- package/src/utils/agentFetcher.ts +0 -107
- package/src/utils/conversation-utils.ts +0 -1
- package/src/utils/process.ts +0 -49
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* RAG Search Tool
|
|
3
3
|
*
|
|
4
|
-
* Single search tool that queries across ALL
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Single search tool that queries across ALL accessible RAG collections.
|
|
5
|
+
* Specialized providers handle well-known collections (reports, conversations,
|
|
6
|
+
* lessons) with smart filtering, while dynamically discovered collections are
|
|
7
|
+
* queried via generic providers with basic project-scoped filtering.
|
|
7
8
|
*
|
|
8
9
|
* Supports optional prompt-based LLM extraction for focused information retrieval.
|
|
9
10
|
*/
|
|
@@ -15,11 +16,11 @@ import { logger } from "@/utils/logger";
|
|
|
15
16
|
import { tool } from "ai";
|
|
16
17
|
import { z } from "zod";
|
|
17
18
|
|
|
18
|
-
const
|
|
19
|
+
const ragSearchSchema = z.object({
|
|
19
20
|
query: z.string().describe(
|
|
20
|
-
"Natural language search query. Searches across all project knowledge
|
|
21
|
-
"reports
|
|
22
|
-
"
|
|
21
|
+
"Natural language search query. Searches across all project knowledge " +
|
|
22
|
+
"including reports, conversations, lessons, and any additional RAG collections. " +
|
|
23
|
+
"Use descriptive natural language for best results."
|
|
23
24
|
),
|
|
24
25
|
prompt: z
|
|
25
26
|
.string()
|
|
@@ -36,18 +37,22 @@ const searchSchema = z.object({
|
|
|
36
37
|
.default(10)
|
|
37
38
|
.describe("Maximum number of results to return across all collections. Defaults to 10."),
|
|
38
39
|
collections: z
|
|
39
|
-
.array(z.
|
|
40
|
+
.array(z.string())
|
|
40
41
|
.optional()
|
|
41
42
|
.describe(
|
|
42
|
-
"
|
|
43
|
-
"
|
|
43
|
+
"Filter by provider name. When omitted, searches all collections matching the " +
|
|
44
|
+
"agent's scope (global + project + personal). When provided, searches exactly " +
|
|
45
|
+
"those collections (no scope filtering — the agent explicitly chose them). " +
|
|
46
|
+
"Well-known provider names: 'reports', 'conversations', 'lessons'. " +
|
|
47
|
+
"Dynamically discovered RAG collections use their collection name as the " +
|
|
48
|
+
"provider name (e.g., 'custom_knowledge')."
|
|
44
49
|
),
|
|
45
50
|
});
|
|
46
51
|
|
|
47
|
-
type
|
|
52
|
+
type RAGSearchInput = z.infer<typeof ragSearchSchema>;
|
|
48
53
|
|
|
49
|
-
async function
|
|
50
|
-
input:
|
|
54
|
+
async function executeRAGSearch(
|
|
55
|
+
input: RAGSearchInput,
|
|
51
56
|
context: ToolExecutionContext
|
|
52
57
|
): Promise<Record<string, unknown>> {
|
|
53
58
|
const { query, prompt, limit = 10, collections } = input;
|
|
@@ -70,7 +75,7 @@ async function executeSearch(
|
|
|
70
75
|
};
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
logger.info("🔍 [
|
|
78
|
+
logger.info("🔍 [RAGSearch] Executing unified search", {
|
|
74
79
|
query,
|
|
75
80
|
prompt: prompt ? `${prompt.substring(0, 50)}...` : undefined,
|
|
76
81
|
limit,
|
|
@@ -90,6 +95,7 @@ async function executeSearch(
|
|
|
90
95
|
limit,
|
|
91
96
|
prompt,
|
|
92
97
|
collections,
|
|
98
|
+
agentPubkey: context.agent.pubkey,
|
|
93
99
|
});
|
|
94
100
|
|
|
95
101
|
// Format results for agent consumption
|
|
@@ -118,28 +124,28 @@ async function executeSearch(
|
|
|
118
124
|
};
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
export function
|
|
127
|
+
export function createRAGSearchTool(context: ToolExecutionContext): AISdkTool {
|
|
122
128
|
const aiTool = tool({
|
|
123
129
|
description:
|
|
124
|
-
"Search across ALL project knowledge — reports, conversations,
|
|
125
|
-
"natural language semantic search. Returns ranked
|
|
126
|
-
"instructions. Each result includes a `retrievalTool`
|
|
127
|
-
"use to fetch the full document (e.g., call report_read
|
|
128
|
-
"the event ID, or conversation_get with the conversation ID).\n\n" +
|
|
130
|
+
"Search across ALL project knowledge — reports, conversations, lessons, and any " +
|
|
131
|
+
"additional RAG collections — using natural language semantic search. Returns ranked " +
|
|
132
|
+
"results with metadata and retrieval instructions. Each result includes a `retrievalTool` " +
|
|
133
|
+
"and `retrievalArg` that you can use to fetch the full document (e.g., call report_read " +
|
|
134
|
+
"with the slug, lesson_get with the event ID, or conversation_get with the conversation ID).\n\n" +
|
|
129
135
|
"Optionally provide a `prompt` parameter to have an LLM extract focused information " +
|
|
130
136
|
"from the search results, rather than reviewing them manually.\n\n" +
|
|
131
137
|
"This is the primary discovery tool for finding information across the project. Use " +
|
|
132
138
|
"conversation_search for deep exploration of specific conversation content.",
|
|
133
139
|
|
|
134
|
-
inputSchema:
|
|
140
|
+
inputSchema: ragSearchSchema,
|
|
135
141
|
|
|
136
|
-
execute: async (input:
|
|
137
|
-
return await
|
|
142
|
+
execute: async (input: RAGSearchInput) => {
|
|
143
|
+
return await executeRAGSearch(input, context);
|
|
138
144
|
},
|
|
139
145
|
});
|
|
140
146
|
|
|
141
147
|
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
142
|
-
value: ({ query, prompt, limit, collections }:
|
|
148
|
+
value: ({ query, prompt, limit, collections }: RAGSearchInput) => {
|
|
143
149
|
const parts = [`Searching project knowledge for "${query}"`];
|
|
144
150
|
if (prompt) parts.push(`prompt: "${prompt.substring(0, 40)}..."`);
|
|
145
151
|
if (collections?.length) parts.push(`in: ${collections.join(", ")}`);
|
package/src/tools/registry.ts
CHANGED
|
@@ -52,7 +52,7 @@ import { createRAGAddDocumentsTool } from "./implementations/rag_add_documents";
|
|
|
52
52
|
import { createRAGCreateCollectionTool } from "./implementations/rag_create_collection";
|
|
53
53
|
import { createRAGDeleteCollectionTool } from "./implementations/rag_delete_collection";
|
|
54
54
|
import { createRAGListCollectionsTool } from "./implementations/rag_list_collections";
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
import { createRAGSubscriptionCreateTool } from "./implementations/rag_subscription_create";
|
|
57
57
|
import { createRAGSubscriptionDeleteTool } from "./implementations/rag_subscription_delete";
|
|
58
58
|
import { createRAGSubscriptionGetTool } from "./implementations/rag_subscription_get";
|
|
@@ -83,8 +83,8 @@ import { createWebSearchTool } from "./implementations/web_search";
|
|
|
83
83
|
import { createNostrFetchTool } from "./implementations/nostr_fetch";
|
|
84
84
|
import { createNostrPublishAsUserTool } from "./implementations/nostr_publish_as_user";
|
|
85
85
|
|
|
86
|
-
// Unified search tool
|
|
87
|
-
import {
|
|
86
|
+
// Unified RAG search tool
|
|
87
|
+
import { createRAGSearchTool } from "./implementations/rag_search";
|
|
88
88
|
|
|
89
89
|
// Image generation tools
|
|
90
90
|
import { createGenerateImageTool } from "./implementations/generate_image";
|
|
@@ -124,7 +124,7 @@ const toolMetadata: Partial<Record<ToolName, { hasSideEffects: boolean }>> = {
|
|
|
124
124
|
report_read: { hasSideEffects: false },
|
|
125
125
|
schedule_tasks_list: { hasSideEffects: false },
|
|
126
126
|
rag_list_collections: { hasSideEffects: false },
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
rag_subscription_list: { hasSideEffects: false },
|
|
129
129
|
rag_subscription_get: { hasSideEffects: false },
|
|
130
130
|
mcp_resource_read: { hasSideEffects: false },
|
|
@@ -132,7 +132,7 @@ const toolMetadata: Partial<Record<ToolName, { hasSideEffects: boolean }>> = {
|
|
|
132
132
|
web_fetch: { hasSideEffects: false },
|
|
133
133
|
web_search: { hasSideEffects: false },
|
|
134
134
|
nostr_fetch: { hasSideEffects: false },
|
|
135
|
-
|
|
135
|
+
rag_search: { hasSideEffects: false },
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
/**
|
|
@@ -204,8 +204,8 @@ const toolFactories: Record<ToolName, ToolFactory> = {
|
|
|
204
204
|
// Conversation search
|
|
205
205
|
conversation_search: createConversationSearchTool,
|
|
206
206
|
|
|
207
|
-
// Unified search across all project knowledge
|
|
208
|
-
|
|
207
|
+
// Unified RAG search across all project knowledge
|
|
208
|
+
rag_search: createRAGSearchTool,
|
|
209
209
|
|
|
210
210
|
shell: createShellTool,
|
|
211
211
|
kill: createKillTool,
|
|
@@ -216,7 +216,6 @@ const toolFactories: Record<ToolName, ToolFactory> = {
|
|
|
216
216
|
// RAG tools
|
|
217
217
|
rag_create_collection: createRAGCreateCollectionTool,
|
|
218
218
|
rag_add_documents: createRAGAddDocumentsTool,
|
|
219
|
-
rag_query: createRAGQueryTool,
|
|
220
219
|
rag_delete_collection: createRAGDeleteCollectionTool,
|
|
221
220
|
rag_list_collections: createRAGListCollectionsTool,
|
|
222
221
|
|
package/src/tools/types.ts
CHANGED
|
@@ -5,6 +5,11 @@ import type { MCPManager } from "@/services/mcp/MCPManager";
|
|
|
5
5
|
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
6
6
|
import type { Tool as CoreTool } from "ai";
|
|
7
7
|
|
|
8
|
+
export interface ToolTranscriptArgSpec {
|
|
9
|
+
key: string;
|
|
10
|
+
attribute?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
/**
|
|
9
14
|
* Tool names available in the system.
|
|
10
15
|
* Keep this list in sync with implementations registered in the tool registry.
|
|
@@ -47,7 +52,7 @@ export type ToolName =
|
|
|
47
52
|
| "upload_blob"
|
|
48
53
|
| "rag_create_collection"
|
|
49
54
|
| "rag_add_documents"
|
|
50
|
-
| "
|
|
55
|
+
| "rag_search"
|
|
51
56
|
| "rag_delete_collection"
|
|
52
57
|
| "rag_list_collections"
|
|
53
58
|
| "rag_subscription_create"
|
|
@@ -63,7 +68,6 @@ export type ToolName =
|
|
|
63
68
|
| "web_search"
|
|
64
69
|
| "nostr_fetch"
|
|
65
70
|
| "nostr_publish_as_user"
|
|
66
|
-
| "search"
|
|
67
71
|
| "change_model"
|
|
68
72
|
| "kill"
|
|
69
73
|
| "generate_image";
|
|
@@ -73,6 +77,11 @@ export type ToolName =
|
|
|
73
77
|
*/
|
|
74
78
|
export type AISdkTool<TInput = unknown, TOutput = unknown> = CoreTool<TInput, TOutput> & {
|
|
75
79
|
getHumanReadableContent?: (args: TInput) => string;
|
|
80
|
+
/**
|
|
81
|
+
* Optional list of input argument keys to expose in conversation transcript XML.
|
|
82
|
+
* Keys are read from tool input args at execution time and serialized as XML attributes.
|
|
83
|
+
*/
|
|
84
|
+
transcriptArgsToInclude?: ToolTranscriptArgSpec[];
|
|
76
85
|
/**
|
|
77
86
|
* Whether this tool has side effects (modifies state, writes files, sends messages, etc.)
|
|
78
87
|
* Default is true (assume side effects unless explicitly declared false).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AISdkTool, ToolTranscriptArgSpec } from "@/tools/types";
|
|
2
|
+
|
|
3
|
+
export function attachTranscriptArgs<TInput = unknown, TOutput = unknown>(
|
|
4
|
+
tool: AISdkTool<TInput, TOutput>,
|
|
5
|
+
args: ToolTranscriptArgSpec[]
|
|
6
|
+
): AISdkTool<TInput, TOutput> {
|
|
7
|
+
Object.defineProperty(tool, "transcriptArgsToInclude", {
|
|
8
|
+
value: args,
|
|
9
|
+
enumerable: false,
|
|
10
|
+
configurable: true,
|
|
11
|
+
});
|
|
12
|
+
return tool;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
|
|
3
|
+
export const amber = chalk.hex("#FFC107");
|
|
4
|
+
export const amberBold = chalk.hex("#FFC107").bold;
|
|
5
|
+
|
|
6
|
+
export const inquirerTheme = {
|
|
7
|
+
prefix: { idle: amber("?"), done: chalk.green("✓") },
|
|
8
|
+
icon: { cursor: amber("❯") },
|
|
9
|
+
style: {
|
|
10
|
+
highlight: (text: string) => amber(text),
|
|
11
|
+
answer: (text: string) => amber(text),
|
|
12
|
+
},
|
|
13
|
+
};
|
package/src/utils/logger.ts
CHANGED
|
@@ -40,6 +40,8 @@ const emojis = {
|
|
|
40
40
|
|
|
41
41
|
// File logging state
|
|
42
42
|
let logFilePath: string | null = null;
|
|
43
|
+
let warnLogFilePath: string | null = null;
|
|
44
|
+
const WARN_LOG_MAX_SIZE = 100 * 1024 * 1024; // 100MB
|
|
43
45
|
|
|
44
46
|
// Helper to format timestamp for file output
|
|
45
47
|
function formatTimestamp(): string {
|
|
@@ -64,6 +66,55 @@ function writeToFile(level: string, message: string, args: unknown[]): void {
|
|
|
64
66
|
fs.appendFileSync(logFilePath, logLine);
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Structured entry written to warn.log for operator troubleshooting.
|
|
71
|
+
*/
|
|
72
|
+
export interface WarnLogEntry {
|
|
73
|
+
timestamp: string;
|
|
74
|
+
level: "warn" | "error";
|
|
75
|
+
component: string;
|
|
76
|
+
message: string;
|
|
77
|
+
context?: Record<string, unknown>;
|
|
78
|
+
error?: string;
|
|
79
|
+
stack?: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Rotate warn.log when it exceeds WARN_LOG_MAX_SIZE.
|
|
84
|
+
* Renames current file to warn.log.1, discarding any previous .1.
|
|
85
|
+
*/
|
|
86
|
+
function rotateWarnLogIfNeeded(): void {
|
|
87
|
+
if (!warnLogFilePath) return;
|
|
88
|
+
try {
|
|
89
|
+
const stat = fs.statSync(warnLogFilePath);
|
|
90
|
+
if (stat.size >= WARN_LOG_MAX_SIZE) {
|
|
91
|
+
const rotatedPath = `${warnLogFilePath}.1`;
|
|
92
|
+
try {
|
|
93
|
+
fs.unlinkSync(rotatedPath);
|
|
94
|
+
} catch {
|
|
95
|
+
// .1 doesn't exist, fine
|
|
96
|
+
}
|
|
97
|
+
fs.renameSync(warnLogFilePath, rotatedPath);
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
// File doesn't exist yet, no rotation needed
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Write a structured JSON entry to warn.log.
|
|
106
|
+
* Only writes if warn.log transport has been initialized.
|
|
107
|
+
*/
|
|
108
|
+
function writeToWarnLog(entry: WarnLogEntry): void {
|
|
109
|
+
if (!warnLogFilePath) return;
|
|
110
|
+
try {
|
|
111
|
+
rotateWarnLogIfNeeded();
|
|
112
|
+
fs.appendFileSync(warnLogFilePath, JSON.stringify(entry) + "\n");
|
|
113
|
+
} catch {
|
|
114
|
+
// Swallow — we can't let warn.log failures crash the system
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
67
118
|
// Initialize daemon logging
|
|
68
119
|
async function initDaemonLogging(): Promise<void> {
|
|
69
120
|
// Lazy-load config to avoid circular dependency
|
|
@@ -76,11 +127,15 @@ async function initDaemonLogging(): Promise<void> {
|
|
|
76
127
|
// Ensure directory exists
|
|
77
128
|
const logDir = path.dirname(logFilePath);
|
|
78
129
|
fs.mkdirSync(logDir, { recursive: true });
|
|
130
|
+
|
|
131
|
+
// Initialize warn.log in the same directory
|
|
132
|
+
warnLogFilePath = path.join(logDir, "warn.log");
|
|
79
133
|
}
|
|
80
134
|
|
|
81
135
|
// Main logger object
|
|
82
136
|
export const logger = {
|
|
83
137
|
initDaemonLogging,
|
|
138
|
+
writeToWarnLog,
|
|
84
139
|
|
|
85
140
|
/**
|
|
86
141
|
* Check if a specific log level is enabled
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical metadata key variants for RAG document filtering.
|
|
3
|
+
*
|
|
4
|
+
* Documents ingested via different code-paths use different key conventions:
|
|
5
|
+
* - Specialized services (reports, lessons, conversations) write **camelCase**.
|
|
6
|
+
* - The generic `rag_add_documents` tool historically wrote **snake_case**.
|
|
7
|
+
*
|
|
8
|
+
* Every SQL LIKE filter that matches on these keys must check BOTH variants
|
|
9
|
+
* to avoid silently missing documents. Keeping the pairs here as shared
|
|
10
|
+
* constants prevents the two sets from drifting out of sync.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Tuple of [camelCase, snake_case] key names for project ID metadata. */
|
|
14
|
+
export const PROJECT_ID_KEYS = ["projectId", "project_id"] as const;
|
|
15
|
+
|
|
16
|
+
/** Tuple of [camelCase, snake_case] key names for agent pubkey metadata. */
|
|
17
|
+
export const AGENT_PUBKEY_KEYS = ["agentPubkey", "agent_pubkey"] as const;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQL escaping utilities for LanceDB metadata LIKE queries.
|
|
3
|
+
*
|
|
4
|
+
* Shared across all RAG query builders (project filters, agent stats, etc.)
|
|
5
|
+
* to ensure consistent escaping of user-supplied values in SQL LIKE patterns.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: DataFusion (used by LanceDB) has NO default escape character.
|
|
8
|
+
* Backslash-based escapes only work when paired with an ESCAPE '\\' clause.
|
|
9
|
+
* See: https://github.com/apache/datafusion/issues/13291
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The ESCAPE clause literal required by every LIKE expression that uses
|
|
14
|
+
* the backslash escapes produced by {@link escapeSqlLikeValue}.
|
|
15
|
+
*
|
|
16
|
+
* Usage: `metadata LIKE '…${escaped}…' ${SQL_LIKE_ESCAPE_CLAUSE}`
|
|
17
|
+
*/
|
|
18
|
+
export const SQL_LIKE_ESCAPE_CLAUSE = "ESCAPE '\\\\'";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Escape a string for use inside a SQL LIKE pattern.
|
|
22
|
+
*
|
|
23
|
+
* Escapes: backslashes (\), single quotes ('), double quotes ("),
|
|
24
|
+
* and LIKE wildcards (%, _).
|
|
25
|
+
*
|
|
26
|
+
* The returned value MUST be used together with {@link SQL_LIKE_ESCAPE_CLAUSE}
|
|
27
|
+
* so that DataFusion recognises the backslash as the escape character.
|
|
28
|
+
*
|
|
29
|
+
* @param value - Raw string to escape (e.g. a project ID or agent pubkey).
|
|
30
|
+
* @returns Escaped string safe for interpolation into a LIKE pattern.
|
|
31
|
+
*/
|
|
32
|
+
export function escapeSqlLikeValue(value: string): string {
|
|
33
|
+
return value
|
|
34
|
+
.replace(/\\/g, "\\\\") // Escape backslashes first
|
|
35
|
+
.replace(/'/g, "''") // SQL standard: escape single quote by doubling
|
|
36
|
+
.replace(/"/g, '\\"') // Escape double quotes
|
|
37
|
+
.replace(/%/g, "\\%") // Escape LIKE wildcard %
|
|
38
|
+
.replace(/_/g, "\\_"); // Escape LIKE wildcard _
|
|
39
|
+
}
|
package/src/wrapper.ts
CHANGED
|
@@ -193,13 +193,17 @@ class DaemonWrapper {
|
|
|
193
193
|
*/
|
|
194
194
|
private spawnDaemon(args: string[]): Promise<number> {
|
|
195
195
|
return new Promise((resolve) => {
|
|
196
|
-
// Build command: bun <entry-point> daemon --supervised [args]
|
|
197
196
|
const indexPath = resolveEntryPoint();
|
|
198
197
|
const daemonArgs = [indexPath, "daemon", "--supervised", ...args];
|
|
199
198
|
|
|
200
|
-
|
|
199
|
+
// Use Bun when running TypeScript sources; otherwise run compiled JS via Node.
|
|
200
|
+
const runtimeBinary = indexPath.endsWith(".ts")
|
|
201
|
+
? (process.env.TENEX_BUN_BIN || "bun")
|
|
202
|
+
: process.execPath;
|
|
201
203
|
|
|
202
|
-
|
|
204
|
+
console.log(`[Wrapper] Spawning: ${runtimeBinary} ${daemonArgs.join(" ")}`);
|
|
205
|
+
|
|
206
|
+
this.child = spawn(runtimeBinary, daemonArgs, {
|
|
203
207
|
stdio: "inherit",
|
|
204
208
|
env: process.env,
|
|
205
209
|
});
|