e7b753014c
Implement persistent chat history using a new ChatHistoryManager class. Sessions are saved on view close, restored on open, and selectable via a dropdown in the chat header. Includes delete and clear-all commands, with automatic title generation from the first user message.
488 lines
11 KiB
TypeScript
488 lines
11 KiB
TypeScript
// src/types.ts
|
|
|
|
// ============================================================
|
|
// Error Type Hierarchy
|
|
// ============================================================
|
|
|
|
export enum ErrorType {
|
|
NETWORK_ERROR = 'network_error',
|
|
API_ERROR = 'api_error',
|
|
VALIDATION_ERROR = 'validation_error',
|
|
STREAMING_ERROR = 'streaming_error',
|
|
TOOL_EXECUTION_ERROR = 'tool_execution_error',
|
|
PATH_VALIDATION_ERROR = 'path_validation_error',
|
|
UNKNOWN_ERROR = 'unknown_error',
|
|
}
|
|
|
|
export class OllamaError extends Error {
|
|
public readonly type: ErrorType;
|
|
|
|
constructor(message: string, type: ErrorType) {
|
|
super(message);
|
|
this.type = type;
|
|
Object.setPrototypeOf(this, OllamaError.prototype);
|
|
}
|
|
}
|
|
|
|
export class NetworkError extends OllamaError {
|
|
public readonly statusCode?: number;
|
|
|
|
constructor(message: string, statusCode?: number) {
|
|
super(message, ErrorType.NETWORK_ERROR);
|
|
this.statusCode = statusCode;
|
|
Object.setPrototypeOf(this, NetworkError.prototype);
|
|
}
|
|
}
|
|
|
|
export class ApiError extends OllamaError {
|
|
public readonly statusCode: number;
|
|
|
|
constructor(message: string, statusCode: number) {
|
|
super(message, ErrorType.API_ERROR);
|
|
this.statusCode = statusCode;
|
|
Object.setPrototypeOf(this, ApiError.prototype);
|
|
}
|
|
}
|
|
|
|
export class ValidationError extends OllamaError {
|
|
public readonly details?: { field?: string; message?: string };
|
|
|
|
constructor(message: string, details?: { field?: string; message?: string }) {
|
|
super(message, ErrorType.VALIDATION_ERROR);
|
|
this.details = details;
|
|
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
}
|
|
}
|
|
|
|
export class StreamingError extends OllamaError {
|
|
constructor(message: string) {
|
|
super(message, ErrorType.STREAMING_ERROR);
|
|
Object.setPrototypeOf(this, StreamingError.prototype);
|
|
}
|
|
}
|
|
|
|
export class ToolExecutionError extends OllamaError {
|
|
public readonly toolName: string;
|
|
|
|
constructor(message: string, toolName: string = 'unknown') {
|
|
super(message, ErrorType.TOOL_EXECUTION_ERROR);
|
|
this.toolName = toolName;
|
|
Object.setPrototypeOf(this, ToolExecutionError.prototype);
|
|
}
|
|
}
|
|
|
|
export class PathValidationError extends OllamaError {
|
|
public readonly path: string;
|
|
|
|
constructor(message: string, path: string = '') {
|
|
super(message, ErrorType.PATH_VALIDATION_ERROR);
|
|
this.path = path;
|
|
Object.setPrototypeOf(this, PathValidationError.prototype);
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// Ollama Types
|
|
// ============================================================
|
|
|
|
export interface OllamaMessage {
|
|
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
content: string;
|
|
tool_calls?: OllamaToolCall[];
|
|
tool_call_id?: string;
|
|
prompt_eval_count?: number;
|
|
eval_count?: number;
|
|
}
|
|
|
|
export interface OllamaToolCall {
|
|
id: string;
|
|
type: 'function';
|
|
function: {
|
|
name: string;
|
|
arguments: string;
|
|
};
|
|
}
|
|
|
|
export interface OllamaTool {
|
|
type: 'function';
|
|
function: {
|
|
name: string;
|
|
description: string;
|
|
parameters: {
|
|
type: 'object';
|
|
properties: {
|
|
[key: string]: {
|
|
type: string;
|
|
description?: string;
|
|
enum?: string[];
|
|
};
|
|
};
|
|
required?: string[];
|
|
};
|
|
};
|
|
}
|
|
|
|
export type ToolCall = OllamaToolCall;
|
|
|
|
export interface ToolResult {
|
|
success: boolean;
|
|
message: string;
|
|
data?: unknown;
|
|
id?: string;
|
|
}
|
|
|
|
export interface ProposedAction {
|
|
id: string;
|
|
toolCall: ToolCall;
|
|
operation:
|
|
| 'create'
|
|
| 'read'
|
|
| 'search'
|
|
| 'append'
|
|
| 'replace_section'
|
|
| 'update_frontmatter'
|
|
| 'rename'
|
|
| 'move'
|
|
| 'delete'
|
|
| 'insert_link';
|
|
path: string;
|
|
description: string;
|
|
preview?: {
|
|
before?: string;
|
|
after?: string;
|
|
};
|
|
status: 'pending' | 'applied' | 'rejected';
|
|
}
|
|
|
|
export interface VaultIndexEntry {
|
|
path: string;
|
|
title: string;
|
|
content: string;
|
|
score: number;
|
|
tags?: string;
|
|
mtime?: number;
|
|
}
|
|
|
|
export interface SearchOptions {
|
|
folder?: string;
|
|
tag?: string;
|
|
includeExactPhrase?: boolean;
|
|
recencyBoost?: boolean;
|
|
recencyHalfLifeDays?: number;
|
|
}
|
|
|
|
export interface ChatMessage {
|
|
id: string;
|
|
role: 'user' | 'assistant';
|
|
content: string;
|
|
timestamp: number;
|
|
isStreaming?: boolean;
|
|
isThinking?: boolean;
|
|
tool_calls?: OllamaToolCall[];
|
|
// Refinement tracking
|
|
originalQuery?: string;
|
|
originalAssistantAnswer?: string;
|
|
userCritique?: string;
|
|
isRefinement?: boolean;
|
|
}
|
|
|
|
export interface DependencyGraph {
|
|
nodes: {
|
|
id: string;
|
|
concept: string;
|
|
filePath: string;
|
|
preview: string;
|
|
}[];
|
|
edges: {
|
|
source: string;
|
|
target: string;
|
|
weight?: number;
|
|
}[];
|
|
}
|
|
|
|
// ============================================================
|
|
// Agent Modes
|
|
// ============================================================
|
|
|
|
export type AgentMode = 'ask' | 'edit' | 'organize' | 'research' | 'workflow';
|
|
|
|
// ============================================================
|
|
// Structured Memory
|
|
// ============================================================
|
|
|
|
export interface ConversationSummary {
|
|
id: string;
|
|
timestamp: number;
|
|
topic: string;
|
|
summary: string;
|
|
keyPoints: string[];
|
|
}
|
|
|
|
export interface UserPreference {
|
|
key: string;
|
|
value: string;
|
|
timestamp: number;
|
|
source: 'explicit' | 'inferred';
|
|
}
|
|
|
|
export interface LearnedFact {
|
|
id: string;
|
|
timestamp: number;
|
|
content: string;
|
|
category: 'vault_structure' | 'user_workflow' | 'topic' | 'general';
|
|
confidence: number;
|
|
}
|
|
|
|
export interface StructuredMemoryData {
|
|
conversationSummaries: ConversationSummary[];
|
|
userPreferences: UserPreference[];
|
|
learnedFacts: LearnedFact[];
|
|
}
|
|
|
|
export interface StructuredMemoryConfig {
|
|
enabled: boolean;
|
|
maxSummaries: number;
|
|
maxPreferences: number;
|
|
maxFacts: number;
|
|
}
|
|
|
|
// ============================================================
|
|
// Tool Telemetry
|
|
// ============================================================
|
|
|
|
export interface ToolTelemetryEntry {
|
|
id: string;
|
|
timestamp: number;
|
|
type: 'tool_call';
|
|
toolName: string;
|
|
args: Record<string, unknown>;
|
|
success: boolean;
|
|
resultSummary: string;
|
|
durationMs: number;
|
|
}
|
|
|
|
export interface LlmTelemetryEntry {
|
|
id: string;
|
|
timestamp: number;
|
|
type: 'llm_call';
|
|
model: string;
|
|
promptTokens: number;
|
|
completionTokens: number;
|
|
totalTokens: number;
|
|
durationMs: number;
|
|
}
|
|
|
|
export interface SearchTelemetryEntry {
|
|
id: string;
|
|
timestamp: number;
|
|
type: 'vault_search';
|
|
query: string;
|
|
resultsCount: number;
|
|
resultPaths: string[];
|
|
durationMs: number;
|
|
}
|
|
|
|
export type TelemetryEntry = ToolTelemetryEntry | LlmTelemetryEntry | SearchTelemetryEntry;
|
|
|
|
export interface ToolTelemetryData {
|
|
entries: TelemetryEntry[];
|
|
}
|
|
|
|
export interface ToolTelemetryConfig {
|
|
enabled: boolean;
|
|
maxEntries: number;
|
|
}
|
|
|
|
// ============================================================
|
|
// Plugin Configuration
|
|
// ============================================================
|
|
|
|
export interface CacheConfig {
|
|
enabled: boolean;
|
|
similarityThreshold: number;
|
|
collectionName: string;
|
|
embeddingModel: string;
|
|
chromaURL?: string;
|
|
}
|
|
|
|
export interface VaultIndexConfig {
|
|
enabled: boolean;
|
|
collectionName: string;
|
|
embeddingModel: string;
|
|
chromaURL?: string;
|
|
similarityThreshold: number;
|
|
}
|
|
|
|
export interface ChatSession {
|
|
id: string;
|
|
title: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
messages: ChatMessage[];
|
|
agentMode: AgentMode;
|
|
}
|
|
|
|
export interface ChatHistoryData {
|
|
sessions: ChatSession[];
|
|
activeSessionId?: string;
|
|
}
|
|
|
|
export interface PluginSettings {
|
|
ollamaUrl: string;
|
|
chatModel: string;
|
|
agentModel: string;
|
|
model: string;
|
|
vaultSearchLimit: number;
|
|
maxMessageHistory: number;
|
|
maxContextLength: number;
|
|
lastIndexTime: number;
|
|
agentMode: AgentMode;
|
|
cacheConfig: CacheConfig;
|
|
vaultIndexConfig: VaultIndexConfig;
|
|
autoTagConfig: {
|
|
enabled: boolean;
|
|
maxTagsPerNote: number;
|
|
minNoteLength: number;
|
|
maxNoteLength: number;
|
|
tagPromptTemplate: string;
|
|
dryRun: boolean;
|
|
targetFolder: string;
|
|
normalizeTags: boolean;
|
|
};
|
|
autoLinkConfig: {
|
|
enabled: boolean;
|
|
maxLinksPerNote: number;
|
|
similarityThreshold: number;
|
|
targetFolder: string;
|
|
dryRun: boolean;
|
|
};
|
|
structuredMemoryConfig: StructuredMemoryConfig;
|
|
toolTelemetryConfig: ToolTelemetryConfig;
|
|
}
|
|
|
|
// ============================================================
|
|
// Workflow Engine Types (Multi-Step/Chained Reasoning)
|
|
// ============================================================
|
|
|
|
/**
|
|
* Supported step types in a workflow.
|
|
* - 'llm': Call the LLM with a prompt (supports variable interpolation).
|
|
* - 'vault_search': Search the vault using VaultIndexer.
|
|
* - 'tool': Execute a tool via ToolExecutor.
|
|
* - 'format': Transform/format data using a template string.
|
|
*/
|
|
export type WorkflowStepType = 'llm' | 'vault_search' | 'tool' | 'format';
|
|
|
|
/**
|
|
* Result of executing a single workflow step.
|
|
*/
|
|
export interface WorkflowStepResult {
|
|
stepId: string;
|
|
stepName: string;
|
|
success: boolean;
|
|
data: unknown;
|
|
error?: string;
|
|
timestamp: number;
|
|
}
|
|
|
|
/**
|
|
* Configuration for a single workflow step.
|
|
*/
|
|
export interface WorkflowStep {
|
|
id: string;
|
|
type: WorkflowStepType;
|
|
name: string;
|
|
description?: string;
|
|
config: WorkflowStepConfig;
|
|
/** Optional: if set, this step waits for the named step to complete before running */
|
|
dependsOn?: string;
|
|
}
|
|
|
|
/**
|
|
* Union of all possible step configurations based on step type.
|
|
*/
|
|
export type WorkflowStepConfig =
|
|
| LlmStepConfig
|
|
| VaultSearchStepConfig
|
|
| ToolStepConfig
|
|
| FormatStepConfig;
|
|
|
|
/**
|
|
* Call the LLM with a system prompt and user prompt.
|
|
* Both fields support variable interpolation via {{variable_name}} syntax.
|
|
* Variables can reference prior step outputs as {{stepId.output}}.
|
|
*/
|
|
export interface LlmStepConfig {
|
|
type: 'llm';
|
|
systemPrompt?: string;
|
|
userPrompt: string;
|
|
includeToolCalls?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Search the vault for relevant notes.
|
|
* The query field supports variable interpolation.
|
|
*/
|
|
export interface VaultSearchStepConfig {
|
|
type: 'vault_search';
|
|
query: string;
|
|
limit?: number;
|
|
tagFilter?: string;
|
|
}
|
|
|
|
/**
|
|
* Execute a tool (e.g., read_vault_file, create_file, search_vault_files).
|
|
* The args field supports variable interpolation.
|
|
*/
|
|
export interface ToolStepConfig {
|
|
type: 'tool';
|
|
toolName: string;
|
|
args: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* Format/transform previous step output into a template.
|
|
* The template supports {{stepId.output}} and {{stepId.output.property}} syntax.
|
|
*/
|
|
export interface FormatStepConfig {
|
|
type: 'format';
|
|
template: string;
|
|
outputFormat?: 'markdown' | 'text' | 'json';
|
|
}
|
|
|
|
/**
|
|
* Full definition of a workflow (chain of steps).
|
|
*/
|
|
export interface WorkflowDefinition {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
steps: WorkflowStep[];
|
|
}
|
|
|
|
/**
|
|
* Mutable context passed through workflow execution.
|
|
* Stores intermediate results for variable interpolation.
|
|
*/
|
|
export interface WorkflowExecutionContext {
|
|
/** Keyed by step ID -> step result data */
|
|
variables: Map<string, unknown>;
|
|
/** Full step results for debugging/logging */
|
|
stepResults: WorkflowStepResult[];
|
|
/** Conversation history to pass to LLM steps */
|
|
conversationHistory: OllamaMessage[];
|
|
}
|
|
|
|
/**
|
|
* Final result after executing all workflow steps.
|
|
*/
|
|
export interface WorkflowExecutionResult {
|
|
workflowId: string;
|
|
workflowName: string;
|
|
success: boolean;
|
|
stepResults: WorkflowStepResult[];
|
|
/** Output of the last successfully executed step */
|
|
finalOutput: unknown;
|
|
error?: string;
|
|
}
|