Files
obsidian_ollama/src/types.ts
T
fegger e7b753014c Add chat session history with dropdown UI
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.
2026-05-21 10:36:55 +02:00

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;
}