@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.
- package/README.md +5 -1
- package/dist/daemon-wrapper.cjs +47 -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 -46778
- 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 -215
- 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,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration constants for agent execution
|
|
3
|
-
*/
|
|
4
|
-
export const ExecutionConfig = {
|
|
5
|
-
/** Delay in milliseconds after publishing typing indicator */
|
|
6
|
-
TOOL_INDICATOR_DELAY_MS: 100,
|
|
7
|
-
|
|
8
|
-
/** Default duration for tool execution when not tracked */
|
|
9
|
-
DEFAULT_TOOL_DURATION_MS: 1000,
|
|
10
|
-
|
|
11
|
-
/** Default timeout for shell commands in milliseconds (30 seconds) */
|
|
12
|
-
DEFAULT_COMMAND_TIMEOUT_MS: 30000,
|
|
13
|
-
|
|
14
|
-
/** Threshold for considering a phase transition as recent in milliseconds (30 seconds) */
|
|
15
|
-
RECENT_TRANSITION_THRESHOLD_MS: 30000,
|
|
16
|
-
} as const;
|
package/src/agents/index.ts
DELETED
package/src/commands/agent.ts
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs/promises";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import { Command } from "commander";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
import { NDKPrivateKeySigner, NDKEvent } from "@nostr-dev-kit/ndk";
|
|
8
|
-
import { agentStorage, createStoredAgent } from "@/agents/AgentStorage";
|
|
9
|
-
import { installAgentFromNostr, installAgentFromNostrEvent } from "@/agents/agent-installer";
|
|
10
|
-
import { initNDK } from "@/nostr/ndkClient";
|
|
11
|
-
|
|
12
|
-
// ─── OpenClaw discovery ──────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
const OPENCLAW_STATE_DIR_NAMES = [".openclaw", ".clawdbot", ".moldbot", ".moltbot"];
|
|
15
|
-
const OPENCLAW_CONFIG_NAMES = ["openclaw.json", "clawdbot.json", "moldbot.json", "moltbot.json"];
|
|
16
|
-
|
|
17
|
-
function findOpenClawStateDir(): string | undefined {
|
|
18
|
-
// 1. Environment variable
|
|
19
|
-
const envPath = process.env.OPENCLAW_STATE_DIR;
|
|
20
|
-
if (envPath && hasOpenClawConfig(envPath)) {
|
|
21
|
-
return envPath;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 2. Home directory candidates
|
|
25
|
-
const home = homedir();
|
|
26
|
-
for (const name of OPENCLAW_STATE_DIR_NAMES) {
|
|
27
|
-
const candidate = path.join(home, name);
|
|
28
|
-
if (hasOpenClawConfig(candidate)) {
|
|
29
|
-
return candidate;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function hasOpenClawConfig(dir: string): boolean {
|
|
37
|
-
return OPENCLAW_CONFIG_NAMES.some((name) => existsSync(path.join(dir, name)));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Prettify a slug for display: "main" → "Main", "my-agent" → "My Agent" */
|
|
41
|
-
function prettifySlug(slug: string): string {
|
|
42
|
-
return slug
|
|
43
|
-
.replace(/-/g, " ")
|
|
44
|
-
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface OpenClawAgent {
|
|
48
|
-
name: string;
|
|
49
|
-
slug: string;
|
|
50
|
-
role: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function discoverOpenClawAgents(stateDir: string): Promise<OpenClawAgent[]> {
|
|
54
|
-
const agentsDir = path.join(stateDir, "agents");
|
|
55
|
-
try {
|
|
56
|
-
const entries = await fs.readdir(agentsDir, { withFileTypes: true });
|
|
57
|
-
return entries
|
|
58
|
-
.filter((e) => e.isDirectory())
|
|
59
|
-
.map((e) => ({
|
|
60
|
-
name: prettifySlug(e.name),
|
|
61
|
-
slug: e.name,
|
|
62
|
-
role: "",
|
|
63
|
-
}));
|
|
64
|
-
} catch {
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ─── tenex agent import openclaw ────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
async function importOpenClaw(options: {
|
|
72
|
-
dryRun: boolean;
|
|
73
|
-
json: boolean;
|
|
74
|
-
slugs?: string;
|
|
75
|
-
}): Promise<void> {
|
|
76
|
-
const stateDir = findOpenClawStateDir();
|
|
77
|
-
|
|
78
|
-
if (!stateDir) {
|
|
79
|
-
if (options.json) {
|
|
80
|
-
console.log("[]");
|
|
81
|
-
} else {
|
|
82
|
-
console.error(chalk.yellow("OpenClaw installation not found."));
|
|
83
|
-
}
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const agents = await discoverOpenClawAgents(stateDir);
|
|
88
|
-
|
|
89
|
-
// Apply slug filter if provided
|
|
90
|
-
const filtered =
|
|
91
|
-
options.slugs
|
|
92
|
-
? agents.filter((a) => options.slugs!.split(",").map((s) => s.trim()).includes(a.slug))
|
|
93
|
-
: agents;
|
|
94
|
-
|
|
95
|
-
if (options.json) {
|
|
96
|
-
console.log(JSON.stringify(filtered, null, 2));
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (filtered.length === 0) {
|
|
101
|
-
console.log(chalk.yellow("No OpenClaw agents found."));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (options.dryRun) {
|
|
106
|
-
console.log(chalk.blue(`Would import ${filtered.length} OpenClaw agent(s):`));
|
|
107
|
-
for (const agent of filtered) {
|
|
108
|
-
console.log(chalk.gray(` ${agent.slug} → "${agent.name}"`));
|
|
109
|
-
}
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
await agentStorage.initialize();
|
|
114
|
-
|
|
115
|
-
let imported = 0;
|
|
116
|
-
let skipped = 0;
|
|
117
|
-
|
|
118
|
-
for (const agent of filtered) {
|
|
119
|
-
// Check if already exists by slug
|
|
120
|
-
const existing = await agentStorage.getAgentBySlug(agent.slug);
|
|
121
|
-
if (existing) {
|
|
122
|
-
console.log(chalk.gray(` ${agent.slug}: already exists, skipping`));
|
|
123
|
-
skipped++;
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const signer = NDKPrivateKeySigner.generate();
|
|
128
|
-
const stored = createStoredAgent({
|
|
129
|
-
nsec: signer.nsec,
|
|
130
|
-
slug: agent.slug,
|
|
131
|
-
name: agent.name,
|
|
132
|
-
role: agent.role,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
await agentStorage.saveAgent(stored);
|
|
136
|
-
console.log(
|
|
137
|
-
chalk.green(` ✓ ${agent.slug}`) +
|
|
138
|
-
chalk.gray(` → pubkey ${signer.pubkey.substring(0, 8)}...`)
|
|
139
|
-
);
|
|
140
|
-
imported++;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log(chalk.blue(`\nDone: ${imported} imported, ${skipped} skipped`));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ─── tenex agent add ─────────────────────────────────────────────────────────
|
|
147
|
-
|
|
148
|
-
async function readStdin(): Promise<string> {
|
|
149
|
-
return new Promise((resolve, reject) => {
|
|
150
|
-
let data = "";
|
|
151
|
-
process.stdin.setEncoding("utf-8");
|
|
152
|
-
process.stdin.on("data", (chunk) => {
|
|
153
|
-
data += chunk;
|
|
154
|
-
});
|
|
155
|
-
process.stdin.on("end", () => resolve(data.trim()));
|
|
156
|
-
process.stdin.on("error", reject);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async function addAgent(eventId: string | undefined): Promise<void> {
|
|
161
|
-
await agentStorage.initialize();
|
|
162
|
-
|
|
163
|
-
if (!process.stdin.isTTY) {
|
|
164
|
-
const raw = await readStdin();
|
|
165
|
-
const rawEvent = JSON.parse(raw);
|
|
166
|
-
const event = new NDKEvent(undefined, rawEvent);
|
|
167
|
-
const stored = await installAgentFromNostrEvent(event);
|
|
168
|
-
const pubkey = new NDKPrivateKeySigner(stored.nsec).pubkey;
|
|
169
|
-
console.log(chalk.green(`✓ Installed agent "${stored.name}" (${stored.slug})`));
|
|
170
|
-
console.log(chalk.gray(` pubkey: ${pubkey}`));
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!eventId) {
|
|
175
|
-
console.error(chalk.red("Error: provide an event ID or pipe event JSON via stdin"));
|
|
176
|
-
process.exit(1);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
await initNDK();
|
|
180
|
-
const stored = await installAgentFromNostr(eventId);
|
|
181
|
-
const pubkey = new NDKPrivateKeySigner(stored.nsec).pubkey;
|
|
182
|
-
console.log(chalk.green(`✓ Installed agent "${stored.name}" (${stored.slug})`));
|
|
183
|
-
console.log(chalk.gray(` pubkey: ${pubkey}`));
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ─── Command registration ────────────────────────────────────────────────────
|
|
187
|
-
|
|
188
|
-
const importOpenClawCommand = new Command("openclaw")
|
|
189
|
-
.description("Import agents from a local OpenClaw installation")
|
|
190
|
-
.option("--dry-run", "Print what would be imported without making changes")
|
|
191
|
-
.option("--json", "Output as JSON array")
|
|
192
|
-
.option("--slugs <slugs>", "Comma-separated list of slugs to import (default: all)")
|
|
193
|
-
.action(async (options) => {
|
|
194
|
-
await importOpenClaw({
|
|
195
|
-
dryRun: !!options.dryRun,
|
|
196
|
-
json: !!options.json,
|
|
197
|
-
slugs: options.slugs,
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const importCommand = new Command("import")
|
|
202
|
-
.description("Import agents from external sources")
|
|
203
|
-
.addCommand(importOpenClawCommand);
|
|
204
|
-
|
|
205
|
-
const addCommand = new Command("add")
|
|
206
|
-
.description("Install an agent from a Nostr event ID or stdin JSON")
|
|
207
|
-
.argument("[event-id]", "Nostr event ID of the agent definition")
|
|
208
|
-
.action(async (eventId: string | undefined) => {
|
|
209
|
-
await addAgent(eventId);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
export const agentCommand = new Command("agent")
|
|
213
|
-
.description("Manage TENEX agents")
|
|
214
|
-
.addCommand(importCommand)
|
|
215
|
-
.addCommand(addCommand);
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
interface DelegationResponse {
|
|
2
|
-
from: string;
|
|
3
|
-
content: string;
|
|
4
|
-
eventId: string;
|
|
5
|
-
status: "completed" | "error";
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface DelegationInfo {
|
|
9
|
-
id: string;
|
|
10
|
-
from: string;
|
|
11
|
-
recipients: string[];
|
|
12
|
-
phase?: string;
|
|
13
|
-
message: string;
|
|
14
|
-
requestEventId: string;
|
|
15
|
-
responses: DelegationResponse[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Formats delegation information as structured XML for LLM comprehension
|
|
20
|
-
*/
|
|
21
|
-
export class DelegationXmlFormatter {
|
|
22
|
-
/**
|
|
23
|
-
* Render a delegation with its responses as XML
|
|
24
|
-
*/
|
|
25
|
-
static render(delegation: DelegationInfo, debug = false): string {
|
|
26
|
-
const eventPrefix = debug ? `[Event ${delegation.requestEventId.substring(0, 8)}] ` : "";
|
|
27
|
-
const recipientsAttr = delegation.recipients.join(",");
|
|
28
|
-
const phaseAttr = delegation.phase ? ` phase="${delegation.phase}"` : "";
|
|
29
|
-
|
|
30
|
-
let xml = `${eventPrefix}<delegation from="${delegation.from}" recipients="${recipientsAttr}" id="${delegation.id}"${phaseAttr}>`;
|
|
31
|
-
xml += `\n <delegation-request>${DelegationXmlFormatter.escapeXml(delegation.message)}</delegation-request>`;
|
|
32
|
-
|
|
33
|
-
// Add responses
|
|
34
|
-
for (const response of delegation.responses) {
|
|
35
|
-
const statusAttr = response.status === "error" ? ' error="true"' : "";
|
|
36
|
-
const eventIdAttr = debug ? ` event-id="${response.eventId.substring(0, 8)}"` : "";
|
|
37
|
-
xml += `\n <response from="${response.from}"${statusAttr}${eventIdAttr}>${DelegationXmlFormatter.escapeXml(response.content)}</response>`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Add pending placeholders for recipients without responses
|
|
41
|
-
const respondedFrom = new Set(delegation.responses.map((r) => r.from));
|
|
42
|
-
for (const recipient of delegation.recipients) {
|
|
43
|
-
if (!respondedFrom.has(recipient)) {
|
|
44
|
-
xml += `\n <response from="${recipient}" status="pending" />`;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
xml += "\n</delegation>";
|
|
49
|
-
|
|
50
|
-
return xml;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Escape XML special characters
|
|
55
|
-
*/
|
|
56
|
-
private static escapeXml(text: string): string {
|
|
57
|
-
return text
|
|
58
|
-
.replace(/&/g, "&")
|
|
59
|
-
.replace(/</g, "<")
|
|
60
|
-
.replace(/>/g, ">")
|
|
61
|
-
.replace(/"/g, """)
|
|
62
|
-
.replace(/'/g, "'");
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
ThreadedConversationFormatter,
|
|
3
|
-
type ThreadNode,
|
|
4
|
-
type FormatterOptions,
|
|
5
|
-
} from "./ThreadedConversationFormatter";
|
|
6
|
-
export { TreeBuilder } from "./utils/TreeBuilder";
|
|
7
|
-
export { MessageFormatter } from "./utils/MessageFormatter";
|
|
8
|
-
export { TimestampFormatter } from "./utils/TimestampFormatter";
|
|
9
|
-
export { TreeRenderer } from "./utils/TreeRenderer";
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Content utilities for processing conversation messages
|
|
3
|
-
* Purpose: Strip <thinking>...</thinking> blocks from conversation history; skip messages that are purely thinking blocks.
|
|
4
|
-
* Also filter out events with reasoning tags.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Regex pattern to match thinking blocks (case-insensitive, multi-line)
|
|
11
|
-
* Matches: <thinking>, <Thinking>, <THINKING> with any attributes and their closing tags
|
|
12
|
-
*/
|
|
13
|
-
const THINKING_BLOCK_REGEX = /<thinking\b[^>]*>[\s\S]*?<\/thinking>/gi;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Remove all thinking blocks from content
|
|
17
|
-
* @param content - The content to process
|
|
18
|
-
* @returns The content with all thinking blocks removed and normalized whitespace (multiple blank lines collapsed to single newline)
|
|
19
|
-
*/
|
|
20
|
-
export function stripThinkingBlocks(content: string): string {
|
|
21
|
-
if (!content) return "";
|
|
22
|
-
|
|
23
|
-
// Remove all thinking blocks
|
|
24
|
-
let stripped = content.replace(THINKING_BLOCK_REGEX, "");
|
|
25
|
-
|
|
26
|
-
// Normalize whitespace more carefully:
|
|
27
|
-
// 1. Only collapse multiple spaces that aren't at the beginning of a line (preserve indentation)
|
|
28
|
-
// 2. Collapse multiple blank lines to a single newline
|
|
29
|
-
stripped = stripped
|
|
30
|
-
.split("\n")
|
|
31
|
-
.map((line) => {
|
|
32
|
-
// Only collapse spaces in the middle of lines, not at the start (preserve indentation)
|
|
33
|
-
if (line.trimStart() !== line) {
|
|
34
|
-
// Line has leading whitespace - preserve it
|
|
35
|
-
const leadingWhitespace = line.match(/^\s*/)?.[0] || "";
|
|
36
|
-
const rest = line.slice(leadingWhitespace.length);
|
|
37
|
-
return leadingWhitespace + rest.replace(/ {2,}/g, " ");
|
|
38
|
-
}
|
|
39
|
-
// No leading whitespace - collapse all multiple spaces
|
|
40
|
-
return line.replace(/ {2,}/g, " ");
|
|
41
|
-
})
|
|
42
|
-
.join("\n")
|
|
43
|
-
.replace(/\n\s*\n+/g, "\n") // Collapse 2+ newlines to single newline
|
|
44
|
-
.trim(); // Trim leading/trailing whitespace
|
|
45
|
-
|
|
46
|
-
return stripped;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Check if content contains only thinking blocks (no other content)
|
|
51
|
-
* @param content - The content to check
|
|
52
|
-
* @returns True if the content is empty after removing thinking blocks
|
|
53
|
-
*/
|
|
54
|
-
export function isOnlyThinkingBlocks(content: string): boolean {
|
|
55
|
-
if (!content || content.trim().length === 0) return false; // Empty/whitespace content is not "only thinking blocks"
|
|
56
|
-
|
|
57
|
-
const stripped = stripThinkingBlocks(content);
|
|
58
|
-
return stripped.length === 0;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Check if an event has a reasoning tag
|
|
63
|
-
* @param event - The NDK event to check
|
|
64
|
-
* @returns True if the event has a ["reasoning"] tag
|
|
65
|
-
*/
|
|
66
|
-
export function hasReasoningTag(event: NDKEvent): boolean {
|
|
67
|
-
if (!event.tags) return false;
|
|
68
|
-
return event.tags.some((tag) => tag[0] === "reasoning" && tag.length === 1);
|
|
69
|
-
}
|