@bluehawks/cli 1.0.3 → 1.0.4

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.
Files changed (48) hide show
  1. package/.bluehawks/history.json +3 -12
  2. package/dist/config/constants.d.ts +1 -1
  3. package/dist/config/constants.js +1 -1
  4. package/dist/core/agents/orchestrator.d.ts.map +1 -1
  5. package/dist/core/agents/orchestrator.js +11 -1
  6. package/dist/core/agents/orchestrator.js.map +1 -1
  7. package/dist/core/api/client.d.ts +5 -1
  8. package/dist/core/api/client.d.ts.map +1 -1
  9. package/dist/core/api/client.js +10 -0
  10. package/dist/core/api/client.js.map +1 -1
  11. package/dist/core/api/types.d.ts +19 -0
  12. package/dist/core/api/types.d.ts.map +1 -1
  13. package/dist/core/api/types.js.map +1 -1
  14. package/dist/core/memory/index.d.ts +4 -0
  15. package/dist/core/memory/index.d.ts.map +1 -0
  16. package/dist/core/memory/index.js +4 -0
  17. package/dist/core/memory/index.js.map +1 -0
  18. package/dist/core/memory/manager.d.ts +29 -0
  19. package/dist/core/memory/manager.d.ts.map +1 -0
  20. package/dist/core/memory/manager.js +106 -0
  21. package/dist/core/memory/manager.js.map +1 -0
  22. package/dist/core/memory/storage.d.ts +15 -0
  23. package/dist/core/memory/storage.d.ts.map +1 -0
  24. package/dist/core/memory/storage.js +77 -0
  25. package/dist/core/memory/storage.js.map +1 -0
  26. package/dist/core/memory/types.d.ts +20 -0
  27. package/dist/core/memory/types.d.ts.map +1 -0
  28. package/dist/core/memory/types.js +2 -0
  29. package/dist/core/memory/types.js.map +1 -0
  30. package/dist/core/tools/definitions/index.d.ts +1 -0
  31. package/dist/core/tools/definitions/index.d.ts.map +1 -1
  32. package/dist/core/tools/definitions/index.js +3 -0
  33. package/dist/core/tools/definitions/index.js.map +1 -1
  34. package/dist/core/tools/definitions/memory.d.ts +2 -0
  35. package/dist/core/tools/definitions/memory.d.ts.map +1 -0
  36. package/dist/core/tools/definitions/memory.js +155 -0
  37. package/dist/core/tools/definitions/memory.js.map +1 -0
  38. package/package.json +3 -1
  39. package/src/config/constants.ts +1 -1
  40. package/src/core/agents/orchestrator.ts +13 -2
  41. package/src/core/api/client.ts +17 -0
  42. package/src/core/api/types.ts +23 -0
  43. package/src/core/memory/index.ts +3 -0
  44. package/src/core/memory/manager.ts +120 -0
  45. package/src/core/memory/storage.ts +90 -0
  46. package/src/core/memory/types.ts +22 -0
  47. package/src/core/tools/definitions/index.ts +3 -0
  48. package/src/core/tools/definitions/memory.ts +171 -0
@@ -0,0 +1,155 @@
1
+ import { toolRegistry } from '../registry.js';
2
+ import { memoryManager } from '../../memory/index.js';
3
+ // Remember Tool
4
+ const rememberTool = {
5
+ name: 'remember',
6
+ safeToAutoRun: true,
7
+ definition: {
8
+ type: 'function',
9
+ function: {
10
+ name: 'remember',
11
+ description: 'Store a piece of information, preference, or concept in long-term memory. Use this to remember user choices, project guidelines, or important facts.',
12
+ parameters: {
13
+ type: 'object',
14
+ properties: {
15
+ content: {
16
+ type: 'string',
17
+ description: 'The information to remember.',
18
+ },
19
+ type: {
20
+ type: 'string',
21
+ enum: ['preference', 'mistake', 'knowledge', 'task_context'],
22
+ description: 'The type of memory. Default is knowledge.',
23
+ },
24
+ tags: {
25
+ type: 'array',
26
+ items: { type: 'string' },
27
+ description: 'Tags to categorize this memory.',
28
+ },
29
+ },
30
+ required: ['content'],
31
+ },
32
+ },
33
+ },
34
+ async execute(args) {
35
+ const content = args.content;
36
+ const type = args.type || 'knowledge';
37
+ const tags = args.tags || [];
38
+ const memory = await memoryManager.remember(content, type, { tags });
39
+ return `Remembered: "${content}" (ID: ${memory.id})`;
40
+ },
41
+ };
42
+ // Recall Tool
43
+ const recallTool = {
44
+ name: 'recall',
45
+ safeToAutoRun: true,
46
+ definition: {
47
+ type: 'function',
48
+ function: {
49
+ name: 'recall',
50
+ description: 'Search long-term memory for relevant information. Use this to find past decisions, user preferences, or project guidelines.',
51
+ parameters: {
52
+ type: 'object',
53
+ properties: {
54
+ query: {
55
+ type: 'string',
56
+ description: 'The search query to find relevant memories.',
57
+ },
58
+ limit: {
59
+ type: 'number',
60
+ description: 'Maximum number of results to return. Default is 5.',
61
+ },
62
+ },
63
+ required: ['query'],
64
+ },
65
+ },
66
+ },
67
+ async execute(args) {
68
+ const query = args.query;
69
+ const limit = args.limit || 5;
70
+ const results = await memoryManager.search(query, limit);
71
+ if (results.length === 0) {
72
+ return 'No relevant memories found.';
73
+ }
74
+ return results
75
+ .map((m) => `[${m.type.toUpperCase()}] ${m.content} (Similarity: ${(m.similarity * 100).toFixed(1)}%)`)
76
+ .join('\n');
77
+ },
78
+ };
79
+ // Forget Tool
80
+ const forgetTool = {
81
+ name: 'forget',
82
+ safeToAutoRun: false, // Deletion is unsafe
83
+ definition: {
84
+ type: 'function',
85
+ function: {
86
+ name: 'forget',
87
+ description: 'Delete a memory by its ID.',
88
+ parameters: {
89
+ type: 'object',
90
+ properties: {
91
+ id: {
92
+ type: 'string',
93
+ description: 'The ID of the memory to delete.',
94
+ },
95
+ },
96
+ required: ['id'],
97
+ },
98
+ },
99
+ },
100
+ async execute(args) {
101
+ const id = args.id;
102
+ await memoryManager.forget(id);
103
+ return `Forgot memory with ID: ${id}`;
104
+ },
105
+ };
106
+ // Learn Mistake Tool
107
+ const learnMistakeTool = {
108
+ name: 'learn_mistake',
109
+ safeToAutoRun: true, // Learning is safe
110
+ definition: {
111
+ type: 'function',
112
+ function: {
113
+ name: 'learn_mistake',
114
+ description: 'Record a mistake and its solution to avoid repeating it in the future.',
115
+ parameters: {
116
+ type: 'object',
117
+ properties: {
118
+ error: {
119
+ type: 'string',
120
+ description: 'The error or mistake that occurred.',
121
+ },
122
+ fix: {
123
+ type: 'string',
124
+ description: 'The solution or lesson learned.',
125
+ },
126
+ context: {
127
+ type: 'string',
128
+ description: 'Optional context (e.g., file path, command).',
129
+ },
130
+ },
131
+ required: ['error', 'fix'],
132
+ },
133
+ },
134
+ },
135
+ async execute(args) {
136
+ const error = args.error;
137
+ const fix = args.fix;
138
+ const context = args.context;
139
+ const content = `Mistake: ${error}\nSolution: ${fix}${context ? `\nContext: ${context}` : ''}`;
140
+ const memory = await memoryManager.remember(content, 'mistake', {
141
+ originalError: error,
142
+ fix,
143
+ context,
144
+ });
145
+ return `Recorded mistake and solution (ID: ${memory.id}). I will remember this to avoid it in the future.`;
146
+ },
147
+ };
148
+ // Register all memory tools
149
+ export function registerMemoryTools() {
150
+ toolRegistry.register(rememberTool);
151
+ toolRegistry.register(recallTool);
152
+ toolRegistry.register(forgetTool);
153
+ toolRegistry.register(learnMistakeTool);
154
+ }
155
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../../src/core/tools/definitions/memory.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluehawks/cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "A production-ready multi-agent AI CLI assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,6 +35,7 @@
35
35
  "node": ">=20.0.0"
36
36
  },
37
37
  "dependencies": {
38
+ "better-sqlite3": "^12.6.2",
38
39
  "chalk": "^5.3.0",
39
40
  "commander": "^12.1.0",
40
41
  "eventsource-parser": "^3.0.0",
@@ -50,6 +51,7 @@
50
51
  "zod": "^3.24.1"
51
52
  },
52
53
  "devDependencies": {
54
+ "@types/better-sqlite3": "^7.6.13",
53
55
  "@types/node": "^22.10.5",
54
56
  "@types/react": "^18.3.18",
55
57
  "@typescript-eslint/eslint-plugin": "^8.19.1",
@@ -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.3';
11
+ export const CLI_VERSION = '1.0.4';
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: this.buildSystemPrompt(),
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,
@@ -22,6 +22,8 @@ import {
22
22
  type ToolDefinition,
23
23
  type ToolResult,
24
24
  type StreamDelta,
25
+ type EmbeddingRequest,
26
+ type EmbeddingResponse,
25
27
  APIError,
26
28
  } from './types.js';
27
29
 
@@ -42,6 +44,21 @@ export class APIClient {
42
44
  this.timeout = options.timeout || DEFAULT_TIMEOUT_MS;
43
45
  }
44
46
 
47
+ /**
48
+ * Create embeddings for the given input
49
+ */
50
+ async createEmbeddings(
51
+ input: string | string[],
52
+ model?: string
53
+ ): Promise<EmbeddingResponse> {
54
+ const body: EmbeddingRequest = {
55
+ model: model || 'text-embedding-3-small',
56
+ input,
57
+ };
58
+
59
+ return this.makeRequest<EmbeddingResponse>('/embeddings', body);
60
+ }
61
+
45
62
  /**
46
63
  * Create a chat completion (non-streaming)
47
64
  */
@@ -136,6 +136,29 @@ 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
+
139
162
  // API Error
140
163
  export class APIError extends Error {
141
164
  constructor(
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './storage.js';
3
+ export * from './manager.js';
@@ -0,0 +1,120 @@
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
+ // Calculate similarity for each memory
68
+ const results: SearchResult[] = 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) // Descending
76
+ .slice(0, limit);
77
+
78
+ return results;
79
+ }
80
+
81
+ /**
82
+ * Retrieve a memory by ID
83
+ */
84
+ async get(id: string): Promise<Memory | null> {
85
+ return memoryStorage.get(id);
86
+ }
87
+
88
+ /**
89
+ * Delete a memory
90
+ */
91
+ async forget(id: string): Promise<void> {
92
+ await memoryStorage.delete(id);
93
+ }
94
+
95
+ /**
96
+ * Clear all memories (useful for testing or reset)
97
+ */
98
+ async clear(): Promise<void> {
99
+ await memoryStorage.clear();
100
+ }
101
+
102
+ private cosineSimilarity(vecA: number[], vecB: number[]): number {
103
+ if (vecA.length !== vecB.length) return 0;
104
+
105
+ let dotProduct = 0;
106
+ let normA = 0;
107
+ let normB = 0;
108
+
109
+ for (let i = 0; i < vecA.length; i++) {
110
+ dotProduct += vecA[i] * vecB[i];
111
+ normA += vecA[i] * vecA[i];
112
+ normB += vecB[i] * vecB[i];
113
+ }
114
+
115
+ if (normA === 0 || normB === 0) return 0;
116
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
117
+ }
118
+ }
119
+
120
+ 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';