sync: features from private repo (2025-12-24)

Synced from ra-h private repo:
- Collapsible chat panel (Cmd+\)
- FolderViewOverlay with Kanban/Grid/List views
- Updated agent prompts
- Improved executor and quickAdd services
- New views.ts types

Files kept at OS versions (auth/backend deps):
- SettingsModal, RAHChat, useSSEChat
- Delegation tools and wiseRAHExecutor
- openExternalUrl (no Tauri)

Added stub: supabaseTokenRegistry.ts for compatibility
This commit is contained in:
“BeeRad”
2025-12-24 09:57:32 +11:00
parent 52602a06c4
commit ce5bee826c
16 changed files with 2973 additions and 650 deletions
+1 -6
View File
@@ -8,7 +8,6 @@ import { calculateCost } from '@/services/analytics/pricing';
import { UsageData } from '@/types/analytics';
import { summarizeToolExecution } from '@/services/agents/toolResultUtils';
import { edgeService } from '@/services/database/edges';
import { RequestContext } from '@/services/context/requestContext';
interface CapsuleNodeJSON {
id: number;
@@ -121,11 +120,7 @@ export interface MiniRAHExecutionInput {
export class MiniRAHExecutor {
static async execute({ sessionId, task, context, expectedOutcome, traceId, parentChatId, workflowKey, workflowNodeId }: MiniRAHExecutionInput) {
try {
const requestContext = RequestContext.get();
const delegateKey =
requestContext.apiKeys?.openai ||
process.env.RAH_DELEGATE_OPENAI_API_KEY ||
process.env.OPENAI_API_KEY;
const delegateKey = process.env.RAH_DELEGATE_OPENAI_API_KEY || process.env.OPENAI_API_KEY;
if (!delegateKey) {
throw new Error('RAH_DELEGATE_OPENAI_API_KEY (or OPENAI_API_KEY) is not set.');
}
-2
View File
@@ -210,7 +210,6 @@ async function handleNoteQuickAdd(rawInput: string, task: string): Promise<strin
body: JSON.stringify({
title,
content,
dimensions: [],
metadata: {
source: 'quick-add-note',
refined_at: new Date().toISOString(),
@@ -307,7 +306,6 @@ async function handleChatTranscriptQuickAdd(rawInput: string, task: string): Pro
title,
content,
chunk: transcript,
dimensions: [],
metadata,
}),
});
@@ -0,0 +1,22 @@
/**
* Stub for SupabaseTokenRegistry - not used in open source version
* The private version uses this for backend API authentication.
* In open source mode, all API calls go directly to OpenAI/Anthropic.
*/
export class SupabaseTokenRegistry {
static async get(_key: string): Promise<string | null> {
return null;
}
static getLast(_key: string): string | null {
return null;
}
static set(_key: string, _value: string): void {
// No-op in OS version
}
static delete(_key: string): void {
// No-op in OS version
}
}
+2
View File
@@ -19,6 +19,8 @@ export interface ContextBuilderOptions {
const BASE_CONTEXT = `=== RA-H BASE CONTEXT ===
- Nodes store content (title, content, dimensions, metadata, link, chunk)
- Edges capture directed relationships between nodes
- Dimensions organize nodes; locked dimensions (isPriority=true) auto-assign to new nodes
- You can create and manage dimensions using dimension tools (createDimension, updateDimension, lockDimension, unlockDimension, deleteDimension)
- When auto-context is enabled you'll see BACKGROUND CONTEXT with the 10 most-connected nodes (ID + title only)
- Focused nodes show truncated content; use queryNodes, searchContentEmbeddings, or queryEdge when you need full detail
- Node references must use [NODE:id:"title"] so the UI renders clickable labels
+15 -16
View File
@@ -32,12 +32,6 @@ export class ApiKeyService {
this.loadKeys();
}
private notifyUpdate(): void {
if (typeof window !== 'undefined') {
window.dispatchEvent(new CustomEvent('api-keys:updated'));
}
}
// Load keys from localStorage
private loadKeys(): void {
try {
@@ -81,7 +75,6 @@ export class ApiKeyService {
if (this.validateOpenAiKey(key)) {
this.keys.openai = key;
this.saveKeys();
this.notifyUpdate();
} else {
throw new Error('Invalid OpenAI API key format');
}
@@ -92,7 +85,6 @@ export class ApiKeyService {
if (this.validateAnthropicKey(key)) {
this.keys.anthropic = key;
this.saveKeys();
this.notifyUpdate();
} else {
throw new Error('Invalid Anthropic API key format');
}
@@ -103,14 +95,12 @@ export class ApiKeyService {
delete this.keys.openai;
this.saveKeys();
this.status.openai = 'not-set';
this.notifyUpdate();
}
clearAnthropicKey(): void {
delete this.keys.anthropic;
this.saveKeys();
this.status.anthropic = 'not-set';
this.notifyUpdate();
}
// Clear all keys
@@ -121,7 +111,6 @@ export class ApiKeyService {
openai: 'not-set',
anthropic: 'not-set'
};
this.notifyUpdate();
}
// Get masked key for display (show only last 4 characters)
@@ -184,16 +173,26 @@ export class ApiKeyService {
async testAnthropicConnection(key?: string): Promise<boolean> {
const testKey = key || this.getAnthropicKey();
if (!testKey) return false;
this.status.anthropic = 'testing';
try {
const response = await fetch('/api/local/test-anthropic', {
// Simple test call to Anthropic API
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: testKey }),
headers: {
'x-api-key': testKey,
'Content-Type': 'application/json',
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-3-haiku-20240307',
max_tokens: 1,
messages: [{ role: 'user', content: 'test' }]
})
});
const data = await response.json();
const isConnected = Boolean(data?.ok);
const isConnected = response.ok;
this.status.anthropic = isConnected ? 'connected' : 'failed';
return isConnected;
} catch (error) {