@bluehawks/cli 1.0.3 ā 1.0.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/.bluehawks/history.json +3 -12
- package/dist/cli/app.d.ts.map +1 -1
- package/dist/cli/app.js +13 -2
- package/dist/cli/app.js.map +1 -1
- package/dist/config/constants.d.ts +1 -1
- package/dist/config/constants.js +1 -1
- package/dist/config/schema.d.ts +2 -2
- package/dist/core/agents/orchestrator.d.ts.map +1 -1
- package/dist/core/agents/orchestrator.js +11 -1
- package/dist/core/agents/orchestrator.js.map +1 -1
- package/dist/core/api/client.d.ts +9 -1
- package/dist/core/api/client.d.ts.map +1 -1
- package/dist/core/api/client.js +16 -0
- package/dist/core/api/client.js.map +1 -1
- package/dist/core/api/types.d.ts +38 -0
- package/dist/core/api/types.d.ts.map +1 -1
- package/dist/core/api/types.js.map +1 -1
- package/dist/core/memory/index.d.ts +4 -0
- package/dist/core/memory/index.d.ts.map +1 -0
- package/dist/core/memory/index.js +4 -0
- package/dist/core/memory/index.js.map +1 -0
- package/dist/core/memory/manager.d.ts +29 -0
- package/dist/core/memory/manager.d.ts.map +1 -0
- package/dist/core/memory/manager.js +130 -0
- package/dist/core/memory/manager.js.map +1 -0
- package/dist/core/memory/storage.d.ts +15 -0
- package/dist/core/memory/storage.d.ts.map +1 -0
- package/dist/core/memory/storage.js +77 -0
- package/dist/core/memory/storage.js.map +1 -0
- package/dist/core/memory/types.d.ts +20 -0
- package/dist/core/memory/types.d.ts.map +1 -0
- package/dist/core/memory/types.js +2 -0
- package/dist/core/memory/types.js.map +1 -0
- package/dist/core/tools/definitions/index.d.ts +1 -0
- package/dist/core/tools/definitions/index.d.ts.map +1 -1
- package/dist/core/tools/definitions/index.js +3 -0
- package/dist/core/tools/definitions/index.js.map +1 -1
- package/dist/core/tools/definitions/memory.d.ts +2 -0
- package/dist/core/tools/definitions/memory.d.ts.map +1 -0
- package/dist/core/tools/definitions/memory.js +155 -0
- package/dist/core/tools/definitions/memory.js.map +1 -0
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/src/cli/app.tsx +123 -49
- package/src/config/constants.ts +1 -1
- package/src/core/agents/orchestrator.ts +13 -2
- package/src/core/api/client.ts +28 -0
- package/src/core/api/types.ts +46 -0
- package/src/core/memory/index.ts +3 -0
- package/src/core/memory/manager.ts +146 -0
- package/src/core/memory/storage.ts +90 -0
- package/src/core/memory/types.ts +22 -0
- package/src/core/tools/definitions/index.ts +3 -0
- package/src/core/tools/definitions/memory.ts +171 -0
- package/src/index.ts +0 -3
package/src/config/constants.ts
CHANGED
|
@@ -8,7 +8,7 @@ export const DEFAULT_MODEL = 'Qwen/Qwen3-0.6B';
|
|
|
8
8
|
|
|
9
9
|
// CLI Metadata
|
|
10
10
|
export const CLI_NAME = 'bluehawks';
|
|
11
|
-
export const CLI_VERSION = '1.0.
|
|
11
|
+
export const CLI_VERSION = '1.0.6';
|
|
12
12
|
export const CLI_DESCRIPTION = 'A production-ready multi-agent AI CLI assistant';
|
|
13
13
|
|
|
14
14
|
// Configuration Paths
|
|
@@ -9,6 +9,7 @@ import { Agent, type AgentResponse } from './agent.js';
|
|
|
9
9
|
import { CONTEXT_FILE } from '../../config/constants.js';
|
|
10
10
|
import * as fs from 'node:fs/promises';
|
|
11
11
|
import * as path from 'node:path';
|
|
12
|
+
import { memoryManager } from '../memory/index.js'; // Corrected path
|
|
12
13
|
|
|
13
14
|
export interface SubAgentConfig {
|
|
14
15
|
name: string;
|
|
@@ -178,17 +179,27 @@ Before making any changes, first:
|
|
|
178
179
|
onToolEnd?: (name: string, result: string) => void;
|
|
179
180
|
}
|
|
180
181
|
): Promise<AgentResponse> {
|
|
182
|
+
// Retrieve relevant memories
|
|
183
|
+
const memories = await memoryManager.search(userMessage, 5);
|
|
184
|
+
let systemPrompt = this.buildSystemPrompt();
|
|
185
|
+
|
|
186
|
+
if (memories.length > 0) {
|
|
187
|
+
const memoryContext = memories
|
|
188
|
+
.map(m => `- [${m.type.toUpperCase()}] ${m.content}`)
|
|
189
|
+
.join('\n');
|
|
190
|
+
systemPrompt += `\n\n## Long-Term Memory (Relevant Context)\n${memoryContext}\n\nUse this information to guide your decisions and avoid past mistakes.`;
|
|
191
|
+
}
|
|
192
|
+
|
|
181
193
|
const mainAgent = new Agent(
|
|
182
194
|
{
|
|
183
195
|
name: 'main',
|
|
184
|
-
systemPrompt
|
|
196
|
+
systemPrompt,
|
|
185
197
|
maxIterations: this.maxTurns,
|
|
186
198
|
},
|
|
187
199
|
this.apiClient,
|
|
188
200
|
this.toolExecutor
|
|
189
201
|
);
|
|
190
202
|
|
|
191
|
-
|
|
192
203
|
return mainAgent.run(
|
|
193
204
|
userMessage,
|
|
194
205
|
callbacks?.onChunk,
|
package/src/core/api/client.ts
CHANGED
|
@@ -22,6 +22,10 @@ import {
|
|
|
22
22
|
type ToolDefinition,
|
|
23
23
|
type ToolResult,
|
|
24
24
|
type StreamDelta,
|
|
25
|
+
type EmbeddingRequest,
|
|
26
|
+
type EmbeddingResponse,
|
|
27
|
+
type RerankRequest,
|
|
28
|
+
type RerankResponse,
|
|
25
29
|
APIError,
|
|
26
30
|
} from './types.js';
|
|
27
31
|
|
|
@@ -42,6 +46,30 @@ export class APIClient {
|
|
|
42
46
|
this.timeout = options.timeout || DEFAULT_TIMEOUT_MS;
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Create embeddings for the given input
|
|
51
|
+
*/
|
|
52
|
+
async createEmbeddings(
|
|
53
|
+
input: string | string[],
|
|
54
|
+
model?: string
|
|
55
|
+
): Promise<EmbeddingResponse> {
|
|
56
|
+
const body: EmbeddingRequest = {
|
|
57
|
+
model: model || 'text-embedding-3-small',
|
|
58
|
+
input,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return this.makeRequest<EmbeddingResponse>('/embeddings', body);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Rerank documents based on query relevance
|
|
66
|
+
*/
|
|
67
|
+
async rerank(request: RerankRequest): Promise<RerankResponse> {
|
|
68
|
+
return this.makeRequest<RerankResponse>('/rerank', request);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
45
73
|
/**
|
|
46
74
|
* Create a chat completion (non-streaming)
|
|
47
75
|
*/
|
package/src/core/api/types.ts
CHANGED
|
@@ -136,6 +136,52 @@ export interface APIClientOptions {
|
|
|
136
136
|
export type StreamCallback = (chunk: string) => void;
|
|
137
137
|
export type ToolCallCallback = (toolCalls: ToolCall[]) => void;
|
|
138
138
|
|
|
139
|
+
// Embedding Types
|
|
140
|
+
export interface EmbeddingRequest {
|
|
141
|
+
model: string;
|
|
142
|
+
input: string | string[];
|
|
143
|
+
user?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface EmbeddingResponse {
|
|
147
|
+
object: 'list';
|
|
148
|
+
data: EmbeddingObject[];
|
|
149
|
+
model: string;
|
|
150
|
+
usage: {
|
|
151
|
+
prompt_tokens: number;
|
|
152
|
+
total_tokens: number;
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface EmbeddingObject {
|
|
157
|
+
object: 'embedding';
|
|
158
|
+
index: number;
|
|
159
|
+
embedding: number[];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Rerank Types
|
|
163
|
+
export interface RerankRequest {
|
|
164
|
+
model?: string;
|
|
165
|
+
query: string;
|
|
166
|
+
documents: string[];
|
|
167
|
+
top_n?: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface RerankResult {
|
|
171
|
+
index: number;
|
|
172
|
+
score: number;
|
|
173
|
+
document: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface RerankResponse {
|
|
177
|
+
model: string;
|
|
178
|
+
results: RerankResult[];
|
|
179
|
+
usage?: {
|
|
180
|
+
total_tokens: number;
|
|
181
|
+
prompt_tokens?: number;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
139
185
|
// API Error
|
|
140
186
|
export class APIError extends Error {
|
|
141
187
|
constructor(
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { apiClient } from '../api/client.js';
|
|
2
|
+
import { memoryStorage } from './storage.js';
|
|
3
|
+
import type { Memory, MemoryType, SearchResult } from './types.js';
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
|
|
6
|
+
export class MemoryManager {
|
|
7
|
+
private static instance: MemoryManager;
|
|
8
|
+
|
|
9
|
+
private constructor() { }
|
|
10
|
+
|
|
11
|
+
static getInstance(): MemoryManager {
|
|
12
|
+
if (!MemoryManager.instance) {
|
|
13
|
+
MemoryManager.instance = new MemoryManager();
|
|
14
|
+
}
|
|
15
|
+
return MemoryManager.instance;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Store a new memory
|
|
20
|
+
*/
|
|
21
|
+
async remember(content: string, type: MemoryType = 'knowledge', metadata: Record<string, any> = {}): Promise<Memory> {
|
|
22
|
+
// Generate embedding
|
|
23
|
+
let embedding: number[] = [];
|
|
24
|
+
try {
|
|
25
|
+
const response = await apiClient.createEmbeddings(content);
|
|
26
|
+
if (response.data && response.data.length > 0) {
|
|
27
|
+
embedding = response.data[0].embedding;
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('Failed to generate embedding for memory:', error);
|
|
31
|
+
// We still save the memory without embedding, it just won't be searchable by vector
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const memory: Memory = {
|
|
35
|
+
id: crypto.randomUUID(),
|
|
36
|
+
content,
|
|
37
|
+
type,
|
|
38
|
+
metadata,
|
|
39
|
+
embedding,
|
|
40
|
+
created_at: Date.now(),
|
|
41
|
+
updated_at: Date.now(),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
await memoryStorage.save(memory);
|
|
45
|
+
return memory;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Search memories by semantic similarity
|
|
50
|
+
*/
|
|
51
|
+
async search(query: string, limit: number = 5, minSimilarity: number = 0.7): Promise<SearchResult[]> {
|
|
52
|
+
// Generate query embedding
|
|
53
|
+
let queryEmbedding: number[] = [];
|
|
54
|
+
try {
|
|
55
|
+
const response = await apiClient.createEmbeddings(query);
|
|
56
|
+
if (response.data && response.data.length > 0) {
|
|
57
|
+
queryEmbedding = response.data[0].embedding;
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Failed to generate embedding for search query:', error);
|
|
61
|
+
// Fallback to keyword search? For now just return empty if vector search fails
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const allMemories = await memoryStorage.getAll();
|
|
66
|
+
|
|
67
|
+
// Stage 1: Vector Search (Fetch 50 candidates)
|
|
68
|
+
const candidates = allMemories
|
|
69
|
+
.filter(m => m.embedding && m.embedding.length > 0)
|
|
70
|
+
.map(memory => {
|
|
71
|
+
const similarity = this.cosineSimilarity(queryEmbedding, memory.embedding!);
|
|
72
|
+
return { ...memory, similarity };
|
|
73
|
+
})
|
|
74
|
+
.filter(r => r.similarity >= minSimilarity)
|
|
75
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
76
|
+
.slice(0, 50); // increased limit for reranking
|
|
77
|
+
|
|
78
|
+
if (candidates.length === 0) return [];
|
|
79
|
+
|
|
80
|
+
// Stage 2: Reranking
|
|
81
|
+
try {
|
|
82
|
+
// Rerank candidates
|
|
83
|
+
const rerankResponse = await apiClient.rerank({
|
|
84
|
+
query,
|
|
85
|
+
documents: candidates.map(c => c.content),
|
|
86
|
+
top_n: limit
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Map reranked results back to memory objects
|
|
90
|
+
const rerankedResults = rerankResponse.results.map(result => {
|
|
91
|
+
const candidate = candidates[result.index];
|
|
92
|
+
return {
|
|
93
|
+
...candidate,
|
|
94
|
+
similarity: result.score // Update similarity with reranker score
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return rerankedResults;
|
|
99
|
+
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn('Reranking failed, falling back to vector similarity:', error);
|
|
102
|
+
// Fallback: return top K from vector search
|
|
103
|
+
return candidates.slice(0, limit);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Retrieve a memory by ID
|
|
109
|
+
*/
|
|
110
|
+
async get(id: string): Promise<Memory | null> {
|
|
111
|
+
return memoryStorage.get(id);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Delete a memory
|
|
116
|
+
*/
|
|
117
|
+
async forget(id: string): Promise<void> {
|
|
118
|
+
await memoryStorage.delete(id);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Clear all memories (useful for testing or reset)
|
|
123
|
+
*/
|
|
124
|
+
async clear(): Promise<void> {
|
|
125
|
+
await memoryStorage.clear();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private cosineSimilarity(vecA: number[], vecB: number[]): number {
|
|
129
|
+
if (vecA.length !== vecB.length) return 0;
|
|
130
|
+
|
|
131
|
+
let dotProduct = 0;
|
|
132
|
+
let normA = 0;
|
|
133
|
+
let normB = 0;
|
|
134
|
+
|
|
135
|
+
for (let i = 0; i < vecA.length; i++) {
|
|
136
|
+
dotProduct += vecA[i] * vecB[i];
|
|
137
|
+
normA += vecA[i] * vecA[i];
|
|
138
|
+
normB += vecB[i] * vecB[i];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (normA === 0 || normB === 0) return 0;
|
|
142
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const memoryManager = MemoryManager.getInstance();
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import { CONFIG_DIR_NAME } from '../../config/constants.js';
|
|
6
|
+
import type { Memory, MemoryType } from './types.js';
|
|
7
|
+
|
|
8
|
+
export class MemoryStorage {
|
|
9
|
+
private db: Database.Database;
|
|
10
|
+
private dbPath: string;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
const homeDir = os.homedir();
|
|
14
|
+
const configDir = path.join(homeDir, CONFIG_DIR_NAME);
|
|
15
|
+
|
|
16
|
+
// Ensure directory exists
|
|
17
|
+
if (!fs.existsSync(configDir)) {
|
|
18
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.dbPath = path.join(configDir, 'memory.db');
|
|
22
|
+
this.db = new Database(this.dbPath);
|
|
23
|
+
this.initialize();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private initialize(): void {
|
|
27
|
+
this.db.exec(`
|
|
28
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
29
|
+
id TEXT PRIMARY KEY,
|
|
30
|
+
content TEXT NOT NULL,
|
|
31
|
+
type TEXT NOT NULL,
|
|
32
|
+
metadata TEXT,
|
|
33
|
+
embedding TEXT,
|
|
34
|
+
created_at INTEGER NOT NULL,
|
|
35
|
+
updated_at INTEGER NOT NULL
|
|
36
|
+
);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async save(memory: Memory): Promise<void> {
|
|
42
|
+
const stmt = this.db.prepare(`
|
|
43
|
+
INSERT OR REPLACE INTO memories (id, content, type, metadata, embedding, created_at, updated_at)
|
|
44
|
+
VALUES (@id, @content, @type, @metadata, @embedding, @created_at, @updated_at)
|
|
45
|
+
`);
|
|
46
|
+
|
|
47
|
+
stmt.run({
|
|
48
|
+
...memory,
|
|
49
|
+
metadata: JSON.stringify(memory.metadata || {}),
|
|
50
|
+
embedding: JSON.stringify(memory.embedding || []),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async get(id: string): Promise<Memory | null> {
|
|
55
|
+
const stmt = this.db.prepare('SELECT * FROM memories WHERE id = ?');
|
|
56
|
+
const row = stmt.get(id) as any;
|
|
57
|
+
|
|
58
|
+
if (!row) return null;
|
|
59
|
+
return this.mapRowToMemory(row);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async getAll(): Promise<Memory[]> {
|
|
63
|
+
const stmt = this.db.prepare('SELECT * FROM memories');
|
|
64
|
+
const rows = stmt.all() as any[];
|
|
65
|
+
return rows.map(r => this.mapRowToMemory(r));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async delete(id: string): Promise<void> {
|
|
69
|
+
const stmt = this.db.prepare('DELETE FROM memories WHERE id = ?');
|
|
70
|
+
stmt.run(id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async clear(): Promise<void> {
|
|
74
|
+
this.db.exec('DELETE FROM memories');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private mapRowToMemory(row: any): Memory {
|
|
78
|
+
return {
|
|
79
|
+
id: row.id,
|
|
80
|
+
content: row.content,
|
|
81
|
+
type: row.type as MemoryType,
|
|
82
|
+
metadata: JSON.parse(row.metadata),
|
|
83
|
+
embedding: JSON.parse(row.embedding),
|
|
84
|
+
created_at: row.created_at,
|
|
85
|
+
updated_at: row.updated_at,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const memoryStorage = new MemoryStorage();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Memory {
|
|
2
|
+
id: string;
|
|
3
|
+
content: string;
|
|
4
|
+
type: MemoryType;
|
|
5
|
+
metadata?: Record<string, any>;
|
|
6
|
+
embedding?: number[];
|
|
7
|
+
created_at: number;
|
|
8
|
+
updated_at: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type MemoryType = 'preference' | 'mistake' | 'knowledge' | 'task_context';
|
|
12
|
+
|
|
13
|
+
export interface MemoryMetadata {
|
|
14
|
+
source?: string;
|
|
15
|
+
confidence?: number;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SearchResult extends Memory {
|
|
21
|
+
similarity: number;
|
|
22
|
+
}
|
|
@@ -8,6 +8,7 @@ import { registerShellTools } from './shell.js';
|
|
|
8
8
|
import { registerSearchTools } from './search.js';
|
|
9
9
|
import { registerGitTools } from './git.js';
|
|
10
10
|
import { registerWebTools } from './web.js';
|
|
11
|
+
import { registerMemoryTools } from './memory.js';
|
|
11
12
|
|
|
12
13
|
export function registerAllTools(): void {
|
|
13
14
|
registerFileTools();
|
|
@@ -15,6 +16,7 @@ export function registerAllTools(): void {
|
|
|
15
16
|
registerSearchTools();
|
|
16
17
|
registerGitTools();
|
|
17
18
|
registerWebTools();
|
|
19
|
+
registerMemoryTools();
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export * from './file.js';
|
|
@@ -22,3 +24,4 @@ export * from './shell.js';
|
|
|
22
24
|
export * from './search.js';
|
|
23
25
|
export * from './git.js';
|
|
24
26
|
export * from './web.js';
|
|
27
|
+
export * from './memory.js';
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { toolRegistry, type ToolHandler } from '../registry.js';
|
|
2
|
+
import { memoryManager } from '../../memory/index.js';
|
|
3
|
+
|
|
4
|
+
// Remember Tool
|
|
5
|
+
const rememberTool: ToolHandler = {
|
|
6
|
+
name: 'remember',
|
|
7
|
+
safeToAutoRun: true,
|
|
8
|
+
definition: {
|
|
9
|
+
type: 'function',
|
|
10
|
+
function: {
|
|
11
|
+
name: 'remember',
|
|
12
|
+
description:
|
|
13
|
+
'Store a piece of information, preference, or concept in long-term memory. Use this to remember user choices, project guidelines, or important facts.',
|
|
14
|
+
parameters: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
content: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The information to remember.',
|
|
20
|
+
},
|
|
21
|
+
type: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
enum: ['preference', 'mistake', 'knowledge', 'task_context'],
|
|
24
|
+
description: 'The type of memory. Default is knowledge.',
|
|
25
|
+
},
|
|
26
|
+
tags: {
|
|
27
|
+
type: 'array',
|
|
28
|
+
items: { type: 'string' },
|
|
29
|
+
description: 'Tags to categorize this memory.',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ['content'],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
async execute(args) {
|
|
37
|
+
const content = args.content as string;
|
|
38
|
+
const type = (args.type as any) || 'knowledge';
|
|
39
|
+
const tags = (args.tags as string[]) || [];
|
|
40
|
+
|
|
41
|
+
const memory = await memoryManager.remember(content, type, { tags });
|
|
42
|
+
return `Remembered: "${content}" (ID: ${memory.id})`;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Recall Tool
|
|
47
|
+
const recallTool: ToolHandler = {
|
|
48
|
+
name: 'recall',
|
|
49
|
+
safeToAutoRun: true,
|
|
50
|
+
definition: {
|
|
51
|
+
type: 'function',
|
|
52
|
+
function: {
|
|
53
|
+
name: 'recall',
|
|
54
|
+
description:
|
|
55
|
+
'Search long-term memory for relevant information. Use this to find past decisions, user preferences, or project guidelines.',
|
|
56
|
+
parameters: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
query: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
description: 'The search query to find relevant memories.',
|
|
62
|
+
},
|
|
63
|
+
limit: {
|
|
64
|
+
type: 'number',
|
|
65
|
+
description: 'Maximum number of results to return. Default is 5.',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
required: ['query'],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
async execute(args) {
|
|
73
|
+
const query = args.query as string;
|
|
74
|
+
const limit = (args.limit as number) || 5;
|
|
75
|
+
|
|
76
|
+
const results = await memoryManager.search(query, limit);
|
|
77
|
+
if (results.length === 0) {
|
|
78
|
+
return 'No relevant memories found.';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return results
|
|
82
|
+
.map(
|
|
83
|
+
(m) =>
|
|
84
|
+
`[${m.type.toUpperCase()}] ${m.content} (Similarity: ${(m.similarity * 100).toFixed(1)}%)`
|
|
85
|
+
)
|
|
86
|
+
.join('\n');
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Forget Tool
|
|
91
|
+
const forgetTool: ToolHandler = {
|
|
92
|
+
name: 'forget',
|
|
93
|
+
safeToAutoRun: false, // Deletion is unsafe
|
|
94
|
+
definition: {
|
|
95
|
+
type: 'function',
|
|
96
|
+
function: {
|
|
97
|
+
name: 'forget',
|
|
98
|
+
description: 'Delete a memory by its ID.',
|
|
99
|
+
parameters: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
id: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
description: 'The ID of the memory to delete.',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
required: ['id'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
async execute(args) {
|
|
112
|
+
const id = args.id as string;
|
|
113
|
+
await memoryManager.forget(id);
|
|
114
|
+
return `Forgot memory with ID: ${id}`;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Learn Mistake Tool
|
|
119
|
+
const learnMistakeTool: ToolHandler = {
|
|
120
|
+
name: 'learn_mistake',
|
|
121
|
+
safeToAutoRun: true, // Learning is safe
|
|
122
|
+
definition: {
|
|
123
|
+
type: 'function',
|
|
124
|
+
function: {
|
|
125
|
+
name: 'learn_mistake',
|
|
126
|
+
description:
|
|
127
|
+
'Record a mistake and its solution to avoid repeating it in the future.',
|
|
128
|
+
parameters: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {
|
|
131
|
+
error: {
|
|
132
|
+
type: 'string',
|
|
133
|
+
description: 'The error or mistake that occurred.',
|
|
134
|
+
},
|
|
135
|
+
fix: {
|
|
136
|
+
type: 'string',
|
|
137
|
+
description: 'The solution or lesson learned.',
|
|
138
|
+
},
|
|
139
|
+
context: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: 'Optional context (e.g., file path, command).',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
required: ['error', 'fix'],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
async execute(args) {
|
|
149
|
+
const error = args.error as string;
|
|
150
|
+
const fix = args.fix as string;
|
|
151
|
+
const context = args.context as string | undefined;
|
|
152
|
+
|
|
153
|
+
const content = `Mistake: ${error}\nSolution: ${fix}${context ? `\nContext: ${context}` : ''}`;
|
|
154
|
+
|
|
155
|
+
const memory = await memoryManager.remember(content, 'mistake', {
|
|
156
|
+
originalError: error,
|
|
157
|
+
fix,
|
|
158
|
+
context,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return `Recorded mistake and solution (ID: ${memory.id}). I will remember this to avoid it in the future.`;
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Register all memory tools
|
|
166
|
+
export function registerMemoryTools(): void {
|
|
167
|
+
toolRegistry.register(rememberTool);
|
|
168
|
+
toolRegistry.register(recallTool);
|
|
169
|
+
toolRegistry.register(forgetTool);
|
|
170
|
+
toolRegistry.register(learnMistakeTool);
|
|
171
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -192,9 +192,6 @@ program
|
|
|
192
192
|
|
|
193
193
|
|
|
194
194
|
// Interactive mode
|
|
195
|
-
console.log(`\nš¦
${CLI_NAME} v${CLI_VERSION}`);
|
|
196
|
-
console.log(` API: ${API_BASE_URL}`);
|
|
197
|
-
console.log(` Model: ${DEFAULT_MODEL}\n`);
|
|
198
195
|
|
|
199
196
|
const { waitUntilExit } = render(
|
|
200
197
|
React.createElement(App, {
|