Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- Add Butler types (PainPoint, Proposal, DelegationResult) to viking-client.ts - Add butler API functions: getButlerInsights, getButlerProposals, recordButlerPainPoint, generateButlerSolution, updateButlerProposalStatus, butlerDelegateTask - Create ButlerPanel with three sections: - InsightsSection: pain point cards with evidence chain, severity, confidence - ProposalsSection: solution cards with accept/reject actions - MemorySection: Viking memory entries per agent - Create useButlerInsights hook for data fetching - Add "管家" tab to RightPanel with ConciergeBell icon Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
317 lines
7.1 KiB
TypeScript
317 lines
7.1 KiB
TypeScript
/**
|
|
* OpenViking Client - Semantic Memory Operations
|
|
*
|
|
* Client for interacting with OpenViking CLI sidecar.
|
|
* Provides semantic search, resource management, and knowledge base operations.
|
|
*/
|
|
|
|
import { invoke } from '@tauri-apps/api/core';
|
|
|
|
// === Types ===
|
|
|
|
export interface VikingStatus {
|
|
available: boolean;
|
|
version?: string;
|
|
dataDir?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export interface VikingResource {
|
|
uri: string;
|
|
name: string;
|
|
resourceType: string;
|
|
size?: number;
|
|
modifiedAt?: string;
|
|
}
|
|
|
|
export interface VikingFindResult {
|
|
uri: string;
|
|
score: number;
|
|
content: string;
|
|
level: string;
|
|
overview?: string;
|
|
}
|
|
|
|
export interface VikingGrepResult {
|
|
uri: string;
|
|
line: number;
|
|
content: string;
|
|
matchStart: number;
|
|
matchEnd: number;
|
|
}
|
|
|
|
export interface VikingAddResult {
|
|
uri: string;
|
|
status: string;
|
|
}
|
|
|
|
// === Client Functions ===
|
|
|
|
/**
|
|
* Check if OpenViking CLI is available
|
|
*/
|
|
export async function getVikingStatus(): Promise<VikingStatus> {
|
|
return invoke<VikingStatus>('viking_status');
|
|
}
|
|
|
|
/**
|
|
* Add a resource to OpenViking from file
|
|
*/
|
|
export async function addVikingResource(
|
|
uri: string,
|
|
content: string
|
|
): Promise<VikingAddResult> {
|
|
return invoke<VikingAddResult>('viking_add', { uri, content });
|
|
}
|
|
|
|
/**
|
|
* Add a resource with metadata (keywords + importance)
|
|
*/
|
|
export async function addVikingResourceWithMetadata(
|
|
uri: string,
|
|
content: string,
|
|
keywords: string[],
|
|
importance?: number
|
|
): Promise<VikingAddResult> {
|
|
return invoke<VikingAddResult>('viking_add_with_metadata', { uri, content, keywords, importance });
|
|
}
|
|
|
|
/**
|
|
* Find resources by semantic search
|
|
*/
|
|
export async function findVikingResources(
|
|
query: string,
|
|
scope?: string,
|
|
limit?: number
|
|
): Promise<VikingFindResult[]> {
|
|
return invoke<VikingFindResult[]>('viking_find', { query, scope, limit });
|
|
}
|
|
|
|
/**
|
|
* Grep resources by pattern
|
|
*/
|
|
export async function grepVikingResources(
|
|
pattern: string,
|
|
uri?: string,
|
|
caseSensitive?: boolean,
|
|
limit?: number
|
|
): Promise<VikingGrepResult[]> {
|
|
return invoke<VikingGrepResult[]>('viking_grep', {
|
|
pattern,
|
|
uri,
|
|
caseSensitive,
|
|
limit,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* List resources at a path
|
|
*/
|
|
export async function listVikingResources(path: string): Promise<VikingResource[]> {
|
|
return invoke<VikingResource[]>('viking_ls', { path });
|
|
}
|
|
|
|
/**
|
|
* Read resource content
|
|
*/
|
|
export async function readVikingResource(
|
|
uri: string,
|
|
level?: string
|
|
): Promise<string> {
|
|
return invoke<string>('viking_read', { uri, level });
|
|
}
|
|
|
|
/**
|
|
* Remove a resource
|
|
*/
|
|
export async function removeVikingResource(uri: string): Promise<void> {
|
|
return invoke<void>('viking_remove', { uri });
|
|
}
|
|
|
|
/**
|
|
* Get resource tree
|
|
*/
|
|
export async function getVikingTree(
|
|
path: string,
|
|
depth?: number
|
|
): Promise<Record<string, unknown>> {
|
|
return invoke<Record<string, unknown>>('viking_tree', { path, depth });
|
|
}
|
|
|
|
// === Summary Generation Functions ===
|
|
|
|
/**
|
|
* Store a resource and auto-generate L0/L1 summaries via configured LLM driver
|
|
*/
|
|
export async function storeWithSummaries(
|
|
uri: string,
|
|
content: string
|
|
): Promise<VikingAddResult> {
|
|
return invoke<VikingAddResult>('viking_store_with_summaries', { uri, content });
|
|
}
|
|
|
|
// === Memory Extraction Functions ===
|
|
|
|
export interface ChatMessageForExtraction {
|
|
role: string;
|
|
content: string;
|
|
timestamp?: string;
|
|
}
|
|
|
|
export interface ExtractedMemory {
|
|
category: 'user_preference' | 'user_fact' | 'agent_lesson' | 'agent_pattern' | 'task';
|
|
content: string;
|
|
tags: string[];
|
|
importance: number;
|
|
suggestedUri: string;
|
|
reasoning?: string;
|
|
}
|
|
|
|
export interface ExtractionResult {
|
|
memories: ExtractedMemory[];
|
|
summary: string;
|
|
tokensSaved?: number;
|
|
extractionTimeMs: number;
|
|
}
|
|
|
|
/**
|
|
* Extract memories from conversation session
|
|
*/
|
|
export async function extractSessionMemories(
|
|
messages: ChatMessageForExtraction[],
|
|
agentId: string
|
|
): Promise<ExtractionResult> {
|
|
return invoke<ExtractionResult>('extract_session_memories', { messages, agentId });
|
|
}
|
|
|
|
/**
|
|
* Extract memories and store to SqliteStorage in one call
|
|
*/
|
|
export async function extractAndStoreMemories(
|
|
messages: ChatMessageForExtraction[],
|
|
agentId: string,
|
|
llmEndpoint?: string,
|
|
llmApiKey?: string
|
|
): Promise<ExtractionResult> {
|
|
return invoke<ExtractionResult>('extract_and_store_memories', {
|
|
messages,
|
|
agentId,
|
|
llmEndpoint,
|
|
llmApiKey,
|
|
});
|
|
}
|
|
|
|
// === Butler Insights Functions ===
|
|
|
|
export interface ButlerPainPoint {
|
|
id: string;
|
|
agent_id: string;
|
|
user_id: string;
|
|
summary: string;
|
|
category: string;
|
|
severity: 'low' | 'medium' | 'high';
|
|
evidence: Array<{ when: string; user_said: string; why_flagged: string }>;
|
|
occurrence_count: number;
|
|
first_seen: string;
|
|
last_seen: string;
|
|
confidence: number;
|
|
status: 'detected' | 'confirmed' | 'solving' | 'solved' | 'dismissed';
|
|
}
|
|
|
|
export interface ButlerProposalStep {
|
|
index: number;
|
|
action: string;
|
|
detail: string;
|
|
skill_hint: string | null;
|
|
}
|
|
|
|
export interface ButlerProposal {
|
|
id: string;
|
|
pain_point_id: string;
|
|
title: string;
|
|
description: string;
|
|
steps: ButlerProposalStep[];
|
|
status: 'pending' | 'accepted' | 'rejected' | 'completed';
|
|
evidence_chain: Array<{ when: string; user_said: string; why_flagged: string }>;
|
|
confidence_at_creation: number;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface ButlerDelegationTask {
|
|
id: string;
|
|
description: string;
|
|
category: string;
|
|
priority: number;
|
|
status: 'pending' | 'assigned' | 'in_progress' | 'completed' | 'failed';
|
|
assigned_expert: { id: string; name: string; role: string } | null;
|
|
}
|
|
|
|
export interface ButlerDelegationResult {
|
|
request: string;
|
|
tasks: ButlerDelegationTask[];
|
|
success: boolean;
|
|
summary: string;
|
|
}
|
|
|
|
/**
|
|
* Get butler pain points for an agent
|
|
*/
|
|
export async function getButlerInsights(agentId: string): Promise<ButlerPainPoint[]> {
|
|
return invoke<ButlerPainPoint[]>('butler_list_pain_points', { agentId });
|
|
}
|
|
|
|
/**
|
|
* Get butler proposals for an agent
|
|
*/
|
|
export async function getButlerProposals(agentId: string): Promise<ButlerProposal[]> {
|
|
return invoke<ButlerProposal[]>('butler_list_proposals', { agentId });
|
|
}
|
|
|
|
/**
|
|
* Record a new pain point from conversation analysis
|
|
*/
|
|
export async function recordButlerPainPoint(
|
|
agentId: string,
|
|
userId: string,
|
|
summary: string,
|
|
category: string,
|
|
severity: string,
|
|
userSaid: string,
|
|
whyFlagged: string
|
|
): Promise<ButlerPainPoint> {
|
|
return invoke<ButlerPainPoint>('butler_record_pain_point', {
|
|
agentId,
|
|
userId,
|
|
summary,
|
|
category,
|
|
severity,
|
|
userSaid,
|
|
whyFlagged,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate a solution for a high-confidence pain point
|
|
*/
|
|
export async function generateButlerSolution(painId: string): Promise<ButlerProposal> {
|
|
return invoke<ButlerProposal>('butler_generate_solution', { painId });
|
|
}
|
|
|
|
/**
|
|
* Update the status of a proposal
|
|
*/
|
|
export async function updateButlerProposalStatus(
|
|
proposalId: string,
|
|
status: string
|
|
): Promise<void> {
|
|
return invoke<void>('butler_update_proposal_status', { proposalId, status });
|
|
}
|
|
|
|
/**
|
|
* Butler delegates a user request to expert agents
|
|
*/
|
|
export async function butlerDelegateTask(request: string): Promise<ButlerDelegationResult> {
|
|
return invoke<ButlerDelegationResult>('butler_delegate_task', { request });
|
|
}
|