byterover-cli 2.0.0 → 2.1.0
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/README.md +6 -81
- package/dist/agent/core/domain/llm/index.d.ts +1 -1
- package/dist/agent/core/domain/llm/index.js +1 -1
- package/dist/agent/core/domain/llm/registry.d.ts +8 -0
- package/dist/agent/core/domain/llm/registry.js +34 -0
- package/dist/agent/core/domain/sandbox/types.d.ts +2 -0
- package/dist/agent/core/domain/tools/constants.d.ts +3 -0
- package/dist/agent/core/domain/tools/constants.js +3 -0
- package/dist/agent/core/interfaces/cipher-services.d.ts +2 -4
- package/dist/agent/core/interfaces/i-cipher-agent.d.ts +9 -1
- package/dist/agent/core/interfaces/i-sandbox-service.d.ts +8 -0
- package/dist/agent/core/interfaces/i-tool-provider.d.ts +10 -0
- package/dist/agent/core/interfaces/i-tool-scheduler.d.ts +9 -0
- package/dist/agent/infra/agent/agent-schemas.d.ts +0 -9
- package/dist/agent/infra/agent/agent-schemas.js +0 -3
- package/dist/agent/infra/agent/cipher-agent.d.ts +25 -1
- package/dist/agent/infra/agent/cipher-agent.js +138 -11
- package/dist/agent/infra/agent/provider-update-config.d.ts +0 -2
- package/dist/agent/infra/agent/service-initializer.d.ts +2 -6
- package/dist/agent/infra/agent/service-initializer.js +45 -38
- package/dist/agent/infra/blob/blob-storage-factory.d.ts +2 -2
- package/dist/agent/infra/blob/blob-storage-factory.js +4 -4
- package/dist/agent/infra/blob/file-blob-storage.d.ts +96 -0
- package/dist/agent/infra/blob/file-blob-storage.js +454 -0
- package/dist/agent/infra/blob/index.d.ts +2 -3
- package/dist/agent/infra/blob/index.js +4 -6
- package/dist/agent/infra/llm/agent-llm-service.d.ts +3 -0
- package/dist/agent/infra/llm/agent-llm-service.js +34 -52
- package/dist/agent/infra/llm/context/compression/compression-helpers.d.ts +35 -0
- package/dist/agent/infra/llm/context/compression/compression-helpers.js +124 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.d.ts +62 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.js +144 -0
- package/dist/agent/infra/llm/context/compression/index.d.ts +3 -0
- package/dist/agent/infra/llm/context/compression/index.js +3 -0
- package/dist/agent/infra/llm/context/compression/reactive-overflow.d.ts +0 -27
- package/dist/agent/infra/llm/context/compression/reactive-overflow.js +5 -122
- package/dist/agent/infra/llm/context/context-manager.d.ts +20 -1
- package/dist/agent/infra/llm/context/context-manager.js +37 -7
- package/dist/agent/infra/llm/providers/index.js +0 -2
- package/dist/agent/infra/llm/providers/types.d.ts +1 -5
- package/dist/agent/infra/map/agentic-map-service.d.ts +97 -0
- package/dist/agent/infra/map/agentic-map-service.js +309 -0
- package/dist/agent/infra/map/context-tree-store.d.ts +94 -0
- package/dist/agent/infra/map/context-tree-store.js +278 -0
- package/dist/agent/infra/map/index.d.ts +4 -0
- package/dist/agent/infra/map/index.js +4 -0
- package/dist/agent/infra/map/llm-map-memory.d.ts +59 -0
- package/dist/agent/infra/map/llm-map-memory.js +187 -0
- package/dist/agent/infra/map/llm-map-service.d.ts +36 -0
- package/dist/agent/infra/map/llm-map-service.js +118 -0
- package/dist/agent/infra/map/map-shared.d.ts +140 -0
- package/dist/agent/infra/map/map-shared.js +325 -0
- package/dist/agent/infra/map/worker-pool.d.ts +45 -0
- package/dist/agent/infra/map/worker-pool.js +73 -0
- package/dist/agent/infra/sandbox/curation-helpers.d.ts +62 -0
- package/dist/agent/infra/sandbox/curation-helpers.js +219 -0
- package/dist/agent/infra/sandbox/sandbox-service.d.ts +12 -0
- package/dist/agent/infra/sandbox/sandbox-service.js +39 -7
- package/dist/agent/infra/sandbox/tools-sdk.d.ts +48 -1
- package/dist/agent/infra/sandbox/tools-sdk.js +52 -1
- package/dist/agent/infra/session/session-manager.d.ts +8 -1
- package/dist/agent/infra/session/session-manager.js +24 -4
- package/dist/agent/infra/storage/file-key-storage.d.ts +142 -0
- package/dist/agent/infra/storage/file-key-storage.js +572 -0
- package/dist/agent/infra/storage/granular-history-storage.d.ts +1 -1
- package/dist/agent/infra/storage/granular-history-storage.js +1 -1
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.d.ts +4 -0
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.js +42 -14
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.d.ts +16 -0
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.js +47 -0
- package/dist/agent/infra/tools/core-tool-scheduler.js +3 -1
- package/dist/agent/infra/tools/implementations/agentic-map-tool.d.ts +35 -0
- package/dist/agent/infra/tools/implementations/agentic-map-tool.js +156 -0
- package/dist/agent/infra/tools/implementations/code-exec-tool.js +1 -0
- package/dist/agent/infra/tools/implementations/curate-tool.d.ts +9 -9
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +18 -0
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +43 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.d.ts +24 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.js +87 -0
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +28 -1
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.js +27 -3
- package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -0
- package/dist/agent/infra/tools/implementations/search-knowledge-service.js +83 -12
- package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
- package/dist/agent/infra/tools/tool-manager.js +6 -0
- package/dist/agent/infra/tools/tool-provider.d.ts +12 -0
- package/dist/agent/infra/tools/tool-provider.js +78 -0
- package/dist/agent/infra/tools/tool-registry.d.ts +14 -0
- package/dist/agent/infra/tools/tool-registry.js +32 -0
- package/dist/agent/resources/prompts/system-prompt.yml +48 -74
- package/dist/agent/resources/tools/expand_knowledge.txt +20 -0
- package/dist/oclif/commands/curate/index.js +1 -2
- package/dist/oclif/commands/main.js +1 -0
- package/dist/oclif/commands/providers/connect.d.ts +1 -3
- package/dist/oclif/commands/providers/connect.js +7 -29
- package/dist/oclif/commands/query.js +1 -2
- package/dist/server/constants.d.ts +7 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/core/domain/entities/provider-registry.js +1 -15
- package/dist/server/core/domain/knowledge/memory-scoring.js +1 -1
- package/dist/server/core/domain/knowledge/summary-types.d.ts +126 -0
- package/dist/server/core/domain/knowledge/summary-types.js +7 -0
- package/dist/server/core/domain/transport/schemas.d.ts +0 -4
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.d.ts +29 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.js +1 -0
- package/dist/server/infra/cogit/context-tree-to-push-context-mapper.js +10 -3
- package/dist/server/infra/connectors/skill/skill-connector.d.ts +4 -0
- package/dist/server/infra/connectors/skill/skill-connector.js +4 -0
- package/dist/server/infra/context-tree/children-hash.d.ts +20 -0
- package/dist/server/infra/context-tree/children-hash.js +22 -0
- package/dist/server/infra/context-tree/derived-artifact.d.ts +28 -0
- package/dist/server/infra/context-tree/derived-artifact.js +48 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.d.ts +37 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.js +219 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +50 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +278 -0
- package/dist/server/infra/context-tree/file-context-tree-merger.js +4 -0
- package/dist/server/infra/context-tree/file-context-tree-snapshot-service.js +12 -4
- package/dist/server/infra/context-tree/file-context-tree-summary-service.d.ts +44 -0
- package/dist/server/infra/context-tree/file-context-tree-summary-service.js +313 -0
- package/dist/server/infra/context-tree/file-context-tree-writer-service.js +5 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.d.ts +22 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.js +45 -0
- package/dist/server/infra/context-tree/snapshot-diff.d.ts +19 -0
- package/dist/server/infra/context-tree/snapshot-diff.js +39 -0
- package/dist/server/infra/context-tree/summary-frontmatter.d.ts +24 -0
- package/dist/server/infra/context-tree/summary-frontmatter.js +111 -0
- package/dist/server/infra/daemon/agent-process.js +2 -14
- package/dist/server/infra/executor/curate-executor.d.ts +1 -0
- package/dist/server/infra/executor/curate-executor.js +82 -34
- package/dist/server/infra/executor/folder-pack-executor.js +1 -1
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.d.ts +6 -0
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.js +6 -0
- package/dist/server/infra/executor/pre-compaction/index.d.ts +3 -0
- package/dist/server/infra/executor/pre-compaction/index.js +1 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.d.ts +59 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.js +124 -0
- package/dist/server/infra/executor/pre-compaction/prompts.d.ts +24 -0
- package/dist/server/infra/executor/pre-compaction/prompts.js +47 -0
- package/dist/server/infra/executor/query-executor.d.ts +3 -0
- package/dist/server/infra/executor/query-executor.js +39 -4
- package/dist/server/infra/http/authenticated-http-client.js +4 -0
- package/dist/server/infra/http/provider-model-fetcher-registry.js +1 -5
- package/dist/server/infra/http/provider-model-fetchers.d.ts +0 -14
- package/dist/server/infra/http/provider-model-fetchers.js +0 -132
- package/dist/server/infra/provider/provider-config-resolver.js +0 -55
- package/dist/server/utils/curate-result-parser.d.ts +4 -4
- package/dist/shared/constants/curation.d.ts +6 -0
- package/dist/shared/constants/curation.js +6 -0
- package/dist/shared/utils/escalation-utils.d.ts +59 -0
- package/dist/shared/utils/escalation-utils.js +141 -0
- package/dist/tui/components/command-input.js +1 -1
- package/dist/tui/components/inline-prompts/inline-confirm.js +6 -1
- package/dist/tui/features/commands/definitions/exit.d.ts +2 -0
- package/dist/tui/features/commands/definitions/exit.js +9 -0
- package/dist/tui/features/commands/definitions/index.js +3 -0
- package/dist/tui/features/exit/components/exit-flow.d.ts +10 -0
- package/dist/tui/features/exit/components/exit-flow.js +19 -0
- package/dist/tui/features/provider/components/provider-flow.js +1 -21
- package/oclif.manifest.json +100 -109
- package/package.json +11 -4
- package/dist/agent/infra/blob/migrations.d.ts +0 -63
- package/dist/agent/infra/blob/migrations.js +0 -148
- package/dist/agent/infra/blob/sqlite-blob-storage.d.ts +0 -82
- package/dist/agent/infra/blob/sqlite-blob-storage.js +0 -307
- package/dist/agent/infra/llm/providers/google-vertex.d.ts +0 -15
- package/dist/agent/infra/llm/providers/google-vertex.js +0 -36
- package/dist/agent/infra/storage/blob-history-storage.d.ts +0 -81
- package/dist/agent/infra/storage/blob-history-storage.js +0 -193
- package/dist/agent/infra/storage/dual-format-history-storage.d.ts +0 -83
- package/dist/agent/infra/storage/dual-format-history-storage.js +0 -165
- package/dist/agent/infra/storage/sqlite-key-storage.d.ts +0 -113
- package/dist/agent/infra/storage/sqlite-key-storage.js +0 -438
- package/dist/server/infra/provider/vertex-ai-utils.d.ts +0 -10
- package/dist/server/infra/provider/vertex-ai-utils.js +0 -28
- package/dist/tui/features/provider/components/credential-path-dialog.d.ts +0 -30
- package/dist/tui/features/provider/components/credential-path-dialog.js +0 -85
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import Database from 'better-sqlite3';
|
|
2
|
-
import * as fs from 'node:fs/promises';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
4
|
-
import { BlobError } from '../../core/domain/errors/blob-error.js';
|
|
5
|
-
import { runMigrations } from './migrations.js';
|
|
6
|
-
/**
|
|
7
|
-
* SQLite-based blob storage implementation
|
|
8
|
-
*
|
|
9
|
-
* Stores all blobs in a single SQLite database file:
|
|
10
|
-
* - .brv/storage.db
|
|
11
|
-
*
|
|
12
|
-
* Schema:
|
|
13
|
-
* - blobs: key, content, content_type, original_name, size, tags, created_at, updated_at
|
|
14
|
-
*
|
|
15
|
-
* Benefits over file-based storage:
|
|
16
|
-
* - O(1) lookup for exists/retrieve
|
|
17
|
-
* - Fast listing and filtering
|
|
18
|
-
* - ACID transactions for data integrity
|
|
19
|
-
* - Single file for easy backup/migration
|
|
20
|
-
*/
|
|
21
|
-
export class SqliteBlobStorage {
|
|
22
|
-
db = null;
|
|
23
|
-
dbPath;
|
|
24
|
-
initialized = false;
|
|
25
|
-
inMemory;
|
|
26
|
-
logger;
|
|
27
|
-
maxBlobSize;
|
|
28
|
-
maxTotalSize;
|
|
29
|
-
storageDir;
|
|
30
|
-
constructor(config) {
|
|
31
|
-
this.inMemory = config?.inMemory ?? false;
|
|
32
|
-
this.storageDir = config?.storageDir ?? '';
|
|
33
|
-
if (!this.inMemory && !this.storageDir) {
|
|
34
|
-
throw new Error('SqliteBlobStorage: storageDir is required when inMemory is false');
|
|
35
|
-
}
|
|
36
|
-
this.dbPath = this.inMemory ? ':memory:' : (config?.dbPath ?? join(this.storageDir, 'storage.db'));
|
|
37
|
-
this.maxBlobSize = config?.maxBlobSize ?? 100 * 1024 * 1024; // 100MB default
|
|
38
|
-
this.maxTotalSize = config?.maxTotalSize ?? 1024 * 1024 * 1024; // 1GB default
|
|
39
|
-
this.logger = config?.logger ?? {
|
|
40
|
-
error: (message) => console.error(message),
|
|
41
|
-
info: (message) => console.log(message),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Clear all blobs from storage
|
|
46
|
-
* WARNING: This is a destructive operation
|
|
47
|
-
*/
|
|
48
|
-
async clear() {
|
|
49
|
-
this.ensureInitialized();
|
|
50
|
-
try {
|
|
51
|
-
this.db.exec('DELETE FROM blobs');
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
throw BlobError.deleteError(`Failed to clear storage: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Close the database connection
|
|
59
|
-
*/
|
|
60
|
-
close() {
|
|
61
|
-
if (this.db) {
|
|
62
|
-
this.db.close();
|
|
63
|
-
this.db = null;
|
|
64
|
-
this.initialized = false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Delete a blob by its key
|
|
69
|
-
*/
|
|
70
|
-
async delete(key) {
|
|
71
|
-
this.ensureInitialized();
|
|
72
|
-
this.validateKey(key);
|
|
73
|
-
try {
|
|
74
|
-
const stmt = this.db.prepare('DELETE FROM blobs WHERE key = ?');
|
|
75
|
-
const result = stmt.run(key);
|
|
76
|
-
if (result.changes === 0) {
|
|
77
|
-
throw BlobError.notFound(key);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
if (error instanceof BlobError) {
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
throw BlobError.deleteError(`Failed to delete blob ${key}: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Check if a blob exists
|
|
89
|
-
*/
|
|
90
|
-
async exists(key) {
|
|
91
|
-
this.ensureInitialized();
|
|
92
|
-
this.validateKey(key);
|
|
93
|
-
const stmt = this.db.prepare('SELECT 1 FROM blobs WHERE key = ?');
|
|
94
|
-
const row = stmt.get(key);
|
|
95
|
-
return row !== undefined;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Get metadata for a blob without retrieving its content
|
|
99
|
-
*/
|
|
100
|
-
async getMetadata(key) {
|
|
101
|
-
this.ensureInitialized();
|
|
102
|
-
this.validateKey(key);
|
|
103
|
-
try {
|
|
104
|
-
const stmt = this.db.prepare(`
|
|
105
|
-
SELECT content_type, original_name, size, tags, created_at, updated_at
|
|
106
|
-
FROM blobs WHERE key = ?
|
|
107
|
-
`);
|
|
108
|
-
const row = stmt.get(key);
|
|
109
|
-
if (!row) {
|
|
110
|
-
return undefined;
|
|
111
|
-
}
|
|
112
|
-
return this.rowToMetadata(row);
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
throw BlobError.retrievalError(`Failed to read metadata for blob ${key}: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Get storage statistics
|
|
120
|
-
*/
|
|
121
|
-
async getStats() {
|
|
122
|
-
this.ensureInitialized();
|
|
123
|
-
try {
|
|
124
|
-
const stmt = this.db.prepare(`
|
|
125
|
-
SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size
|
|
126
|
-
FROM blobs
|
|
127
|
-
`);
|
|
128
|
-
const row = stmt.get();
|
|
129
|
-
return {
|
|
130
|
-
lastUpdated: Date.now(),
|
|
131
|
-
totalBlobs: row.count,
|
|
132
|
-
totalSize: row.total_size,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
throw BlobError.retrievalError(`Failed to get storage stats: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Initialize storage by creating the database and running migrations
|
|
141
|
-
*/
|
|
142
|
-
async initialize() {
|
|
143
|
-
if (this.initialized) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
try {
|
|
147
|
-
// Ensure parent directory of database file exists (skip for in-memory)
|
|
148
|
-
if (!this.inMemory) {
|
|
149
|
-
await fs.mkdir(dirname(this.dbPath), { recursive: true });
|
|
150
|
-
}
|
|
151
|
-
// Open/create database (':memory:' for in-memory mode)
|
|
152
|
-
this.db = new Database(this.dbPath);
|
|
153
|
-
// Enable WAL mode for better concurrent performance
|
|
154
|
-
this.db.pragma('journal_mode = WAL');
|
|
155
|
-
// Run migrations to ensure schema is up-to-date
|
|
156
|
-
runMigrations(this.db, this.logger);
|
|
157
|
-
this.initialized = true;
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
throw BlobError.initializationError(`Failed to initialize SQLite storage: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* List all blob keys, optionally filtered by prefix
|
|
165
|
-
*/
|
|
166
|
-
async list(prefix) {
|
|
167
|
-
this.ensureInitialized();
|
|
168
|
-
try {
|
|
169
|
-
let stmt;
|
|
170
|
-
let rows;
|
|
171
|
-
if (prefix) {
|
|
172
|
-
stmt = this.db.prepare('SELECT key FROM blobs WHERE key LIKE ? ORDER BY key');
|
|
173
|
-
rows = stmt.all(`${prefix}%`);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
stmt = this.db.prepare('SELECT key FROM blobs ORDER BY key');
|
|
177
|
-
rows = stmt.all();
|
|
178
|
-
}
|
|
179
|
-
return rows.map((row) => row.key);
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
throw BlobError.retrievalError(`Failed to list blobs: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Retrieve a blob by its key
|
|
187
|
-
*/
|
|
188
|
-
async retrieve(key) {
|
|
189
|
-
this.ensureInitialized();
|
|
190
|
-
this.validateKey(key);
|
|
191
|
-
try {
|
|
192
|
-
const stmt = this.db.prepare('SELECT * FROM blobs WHERE key = ?');
|
|
193
|
-
const row = stmt.get(key);
|
|
194
|
-
if (!row) {
|
|
195
|
-
return undefined;
|
|
196
|
-
}
|
|
197
|
-
return {
|
|
198
|
-
content: row.content,
|
|
199
|
-
key: row.key,
|
|
200
|
-
metadata: this.rowToMetadata(row),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
catch (error) {
|
|
204
|
-
throw BlobError.retrievalError(`Failed to retrieve blob ${key}: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Store a blob with optional metadata
|
|
209
|
-
*/
|
|
210
|
-
async store(key, content, metadata) {
|
|
211
|
-
this.ensureInitialized();
|
|
212
|
-
this.validateKey(key);
|
|
213
|
-
// Convert content to Buffer
|
|
214
|
-
const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content);
|
|
215
|
-
// Check individual blob size
|
|
216
|
-
if (buffer.length > this.maxBlobSize) {
|
|
217
|
-
throw BlobError.tooLarge(buffer.length, this.maxBlobSize);
|
|
218
|
-
}
|
|
219
|
-
// Check total storage size
|
|
220
|
-
const stats = await this.getStats();
|
|
221
|
-
const existingBlob = await this.retrieve(key);
|
|
222
|
-
const existingSize = existingBlob?.metadata.size ?? 0;
|
|
223
|
-
const newTotalSize = stats.totalSize - existingSize + buffer.length;
|
|
224
|
-
if (newTotalSize > this.maxTotalSize) {
|
|
225
|
-
throw BlobError.totalSizeExceeded(stats.totalSize - existingSize, buffer.length, this.maxTotalSize);
|
|
226
|
-
}
|
|
227
|
-
const now = Date.now();
|
|
228
|
-
const fullMetadata = {
|
|
229
|
-
createdAt: existingBlob?.metadata.createdAt ?? now,
|
|
230
|
-
size: buffer.length,
|
|
231
|
-
updatedAt: now,
|
|
232
|
-
...metadata,
|
|
233
|
-
};
|
|
234
|
-
try {
|
|
235
|
-
const stmt = this.db.prepare(`
|
|
236
|
-
INSERT INTO blobs (key, content, content_type, original_name, size, tags, created_at, updated_at)
|
|
237
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
238
|
-
ON CONFLICT(key) DO UPDATE SET
|
|
239
|
-
content = excluded.content,
|
|
240
|
-
content_type = excluded.content_type,
|
|
241
|
-
original_name = excluded.original_name,
|
|
242
|
-
size = excluded.size,
|
|
243
|
-
tags = excluded.tags,
|
|
244
|
-
updated_at = excluded.updated_at
|
|
245
|
-
`);
|
|
246
|
-
stmt.run(key, buffer, fullMetadata.contentType ?? null, fullMetadata.originalName ?? null, buffer.length, fullMetadata.tags ? JSON.stringify(fullMetadata.tags) : null, fullMetadata.createdAt, fullMetadata.updatedAt);
|
|
247
|
-
return {
|
|
248
|
-
content: buffer,
|
|
249
|
-
key,
|
|
250
|
-
metadata: fullMetadata,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
catch (error) {
|
|
254
|
-
throw BlobError.storageError(`Failed to store blob ${key}: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Ensure storage has been initialized
|
|
259
|
-
*/
|
|
260
|
-
ensureInitialized() {
|
|
261
|
-
if (!this.initialized || !this.db) {
|
|
262
|
-
throw BlobError.notInitialized();
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Convert database row to BlobMetadata
|
|
267
|
-
*/
|
|
268
|
-
rowToMetadata(row) {
|
|
269
|
-
const metadata = {
|
|
270
|
-
createdAt: row.created_at,
|
|
271
|
-
size: row.size,
|
|
272
|
-
updatedAt: row.updated_at,
|
|
273
|
-
};
|
|
274
|
-
if (row.content_type) {
|
|
275
|
-
metadata.contentType = row.content_type;
|
|
276
|
-
}
|
|
277
|
-
if (row.original_name) {
|
|
278
|
-
metadata.originalName = row.original_name;
|
|
279
|
-
}
|
|
280
|
-
if (row.tags) {
|
|
281
|
-
try {
|
|
282
|
-
metadata.tags = JSON.parse(row.tags);
|
|
283
|
-
}
|
|
284
|
-
catch {
|
|
285
|
-
// Ignore invalid JSON
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return metadata;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Validate blob key
|
|
292
|
-
* Keys must be alphanumeric with hyphens and underscores only
|
|
293
|
-
*/
|
|
294
|
-
validateKey(key) {
|
|
295
|
-
if (!key || typeof key !== 'string') {
|
|
296
|
-
throw BlobError.invalidKey(String(key), 'Key must be a non-empty string');
|
|
297
|
-
}
|
|
298
|
-
if (key.length === 0) {
|
|
299
|
-
throw BlobError.invalidKey(key, 'Key cannot be empty');
|
|
300
|
-
}
|
|
301
|
-
// Allow alphanumeric, hyphens, and underscores only
|
|
302
|
-
const validKeyRegex = /^[a-zA-Z0-9_-]+$/;
|
|
303
|
-
if (!validKeyRegex.test(key)) {
|
|
304
|
-
throw BlobError.invalidKey(key, 'Key must contain only alphanumeric characters, hyphens, and underscores');
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google Vertex AI Provider Module
|
|
3
|
-
*
|
|
4
|
-
* Access Gemini models via Google Cloud Vertex AI using @ai-sdk/google-vertex.
|
|
5
|
-
* Uses service account authentication (Application Default Credentials).
|
|
6
|
-
*
|
|
7
|
-
* Required env vars:
|
|
8
|
-
* - GOOGLE_CLOUD_PROJECT (or GCP_PROJECT, GCLOUD_PROJECT)
|
|
9
|
-
* - GOOGLE_APPLICATION_CREDENTIALS (path to service account JSON)
|
|
10
|
-
*
|
|
11
|
-
* Optional env vars:
|
|
12
|
-
* - GOOGLE_CLOUD_LOCATION (defaults to us-central1)
|
|
13
|
-
*/
|
|
14
|
-
import type { ProviderModule } from './types.js';
|
|
15
|
-
export declare const googleVertexProvider: ProviderModule;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google Vertex AI Provider Module
|
|
3
|
-
*
|
|
4
|
-
* Access Gemini models via Google Cloud Vertex AI using @ai-sdk/google-vertex.
|
|
5
|
-
* Uses service account authentication (Application Default Credentials).
|
|
6
|
-
*
|
|
7
|
-
* Required env vars:
|
|
8
|
-
* - GOOGLE_CLOUD_PROJECT (or GCP_PROJECT, GCLOUD_PROJECT)
|
|
9
|
-
* - GOOGLE_APPLICATION_CREDENTIALS (path to service account JSON)
|
|
10
|
-
*
|
|
11
|
-
* Optional env vars:
|
|
12
|
-
* - GOOGLE_CLOUD_LOCATION (defaults to us-central1)
|
|
13
|
-
*/
|
|
14
|
-
import { createVertex } from '@ai-sdk/google-vertex';
|
|
15
|
-
import { AiSdkContentGenerator } from '../generators/ai-sdk-content-generator.js';
|
|
16
|
-
export const googleVertexProvider = {
|
|
17
|
-
apiKeyUrl: 'https://console.cloud.google.com/iam-admin/serviceaccounts',
|
|
18
|
-
authType: 'service-account',
|
|
19
|
-
category: 'popular',
|
|
20
|
-
createGenerator(config) {
|
|
21
|
-
const provider = createVertex({
|
|
22
|
-
location: config.location ?? 'us-central1',
|
|
23
|
-
project: config.project,
|
|
24
|
-
});
|
|
25
|
-
return new AiSdkContentGenerator({
|
|
26
|
-
model: provider(config.model),
|
|
27
|
-
});
|
|
28
|
-
},
|
|
29
|
-
defaultModel: 'gemini-2.5-flash',
|
|
30
|
-
description: 'Gemini models via Google Cloud Vertex AI',
|
|
31
|
-
envVars: ['GOOGLE_APPLICATION_CREDENTIALS'],
|
|
32
|
-
id: 'google-vertex',
|
|
33
|
-
name: 'Google Vertex AI',
|
|
34
|
-
priority: 5,
|
|
35
|
-
providerType: 'gemini',
|
|
36
|
-
};
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import type { SessionMetadata } from '../../core/domain/storage/history-types.js';
|
|
2
|
-
import type { IBlobStorage } from '../../core/interfaces/i-blob-storage.js';
|
|
3
|
-
import type { IHistoryStorage } from '../../core/interfaces/i-history-storage.js';
|
|
4
|
-
import type { InternalMessage } from '../../core/interfaces/message-types.js';
|
|
5
|
-
/**
|
|
6
|
-
* Blob-based implementation of history storage.
|
|
7
|
-
*
|
|
8
|
-
* Stores conversation history as JSON blobs in the file system.
|
|
9
|
-
* Each session gets its own blob file at `.brv/blobs/session-{sessionId}.blob`.
|
|
10
|
-
*
|
|
11
|
-
* Follows the same pattern as MemoryManager for consistency.
|
|
12
|
-
*/
|
|
13
|
-
export declare class BlobHistoryStorage implements IHistoryStorage {
|
|
14
|
-
private readonly blobStorage;
|
|
15
|
-
private static readonly SESSION_KEY_PREFIX;
|
|
16
|
-
/**
|
|
17
|
-
* Creates a new blob history storage instance.
|
|
18
|
-
*
|
|
19
|
-
* @param blobStorage - The blob storage backend to use
|
|
20
|
-
*/
|
|
21
|
-
constructor(blobStorage: IBlobStorage);
|
|
22
|
-
/**
|
|
23
|
-
* Append a single message to the session history.
|
|
24
|
-
* For blob storage, this loads existing history, appends, and re-saves.
|
|
25
|
-
*/
|
|
26
|
-
appendMessage(sessionId: string, message: InternalMessage): Promise<void>;
|
|
27
|
-
/**
|
|
28
|
-
* Delete all history for a specific session.
|
|
29
|
-
*
|
|
30
|
-
* @param sessionId - Unique session identifier
|
|
31
|
-
*/
|
|
32
|
-
deleteHistory(sessionId: string): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* Check if history exists for a specific session.
|
|
35
|
-
*
|
|
36
|
-
* @param sessionId - Unique session identifier
|
|
37
|
-
* @returns True if history exists
|
|
38
|
-
*/
|
|
39
|
-
exists(sessionId: string): Promise<boolean>;
|
|
40
|
-
/**
|
|
41
|
-
* Get metadata for a specific session without loading full history.
|
|
42
|
-
*
|
|
43
|
-
* @param sessionId - Unique session identifier
|
|
44
|
-
* @returns Session metadata or undefined if not found
|
|
45
|
-
*/
|
|
46
|
-
getSessionMetadata(sessionId: string): Promise<SessionMetadata | undefined>;
|
|
47
|
-
/**
|
|
48
|
-
* List all session IDs that have persisted history.
|
|
49
|
-
*
|
|
50
|
-
* @returns Array of session IDs
|
|
51
|
-
*/
|
|
52
|
-
listSessions(): Promise<string[]>;
|
|
53
|
-
/**
|
|
54
|
-
* Load conversation history for a specific session.
|
|
55
|
-
*
|
|
56
|
-
* @param sessionId - Unique session identifier
|
|
57
|
-
* @returns Array of messages, or undefined if session not found
|
|
58
|
-
*/
|
|
59
|
-
loadHistory(sessionId: string): Promise<InternalMessage[] | undefined>;
|
|
60
|
-
/**
|
|
61
|
-
* Save conversation history for a specific session.
|
|
62
|
-
*
|
|
63
|
-
* @param sessionId - Unique session identifier
|
|
64
|
-
* @param messages - Array of messages to persist
|
|
65
|
-
*/
|
|
66
|
-
saveHistory(sessionId: string, messages: InternalMessage[]): Promise<void>;
|
|
67
|
-
/**
|
|
68
|
-
* Extract session ID from storage key.
|
|
69
|
-
*
|
|
70
|
-
* @param key - Storage key (e.g., "session-abc123")
|
|
71
|
-
* @returns Session ID (e.g., "abc123") or undefined if invalid key
|
|
72
|
-
*/
|
|
73
|
-
private extractSessionId;
|
|
74
|
-
/**
|
|
75
|
-
* Get storage key for a session.
|
|
76
|
-
*
|
|
77
|
-
* @param sessionId - Unique session identifier
|
|
78
|
-
* @returns Storage key (e.g., "session-abc123")
|
|
79
|
-
*/
|
|
80
|
-
private getSessionKey;
|
|
81
|
-
}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Blob-based implementation of history storage.
|
|
3
|
-
*
|
|
4
|
-
* Stores conversation history as JSON blobs in the file system.
|
|
5
|
-
* Each session gets its own blob file at `.brv/blobs/session-{sessionId}.blob`.
|
|
6
|
-
*
|
|
7
|
-
* Follows the same pattern as MemoryManager for consistency.
|
|
8
|
-
*/
|
|
9
|
-
export class BlobHistoryStorage {
|
|
10
|
-
blobStorage;
|
|
11
|
-
static SESSION_KEY_PREFIX = 'session-';
|
|
12
|
-
/**
|
|
13
|
-
* Creates a new blob history storage instance.
|
|
14
|
-
*
|
|
15
|
-
* @param blobStorage - The blob storage backend to use
|
|
16
|
-
*/
|
|
17
|
-
constructor(blobStorage) {
|
|
18
|
-
this.blobStorage = blobStorage;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Append a single message to the session history.
|
|
22
|
-
* For blob storage, this loads existing history, appends, and re-saves.
|
|
23
|
-
*/
|
|
24
|
-
async appendMessage(sessionId, message) {
|
|
25
|
-
try {
|
|
26
|
-
const existing = await this.loadHistory(sessionId);
|
|
27
|
-
const messages = existing ?? [];
|
|
28
|
-
messages.push(message);
|
|
29
|
-
await this.saveHistory(sessionId, messages);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
console.error(`[BlobHistoryStorage] Failed to append message for session ${sessionId}:`, error);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Delete all history for a specific session.
|
|
37
|
-
*
|
|
38
|
-
* @param sessionId - Unique session identifier
|
|
39
|
-
*/
|
|
40
|
-
async deleteHistory(sessionId) {
|
|
41
|
-
const key = this.getSessionKey(sessionId);
|
|
42
|
-
try {
|
|
43
|
-
await this.blobStorage.delete(key);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
// Log error but don't throw - graceful degradation
|
|
47
|
-
console.error(`[BlobHistoryStorage] Failed to delete history for session ${sessionId}:`, error);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Check if history exists for a specific session.
|
|
52
|
-
*
|
|
53
|
-
* @param sessionId - Unique session identifier
|
|
54
|
-
* @returns True if history exists
|
|
55
|
-
*/
|
|
56
|
-
async exists(sessionId) {
|
|
57
|
-
const key = this.getSessionKey(sessionId);
|
|
58
|
-
try {
|
|
59
|
-
return await this.blobStorage.exists(key);
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
console.error(`[BlobHistoryStorage] Error checking existence for session ${sessionId}:`, error);
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Get metadata for a specific session without loading full history.
|
|
68
|
-
*
|
|
69
|
-
* @param sessionId - Unique session identifier
|
|
70
|
-
* @returns Session metadata or undefined if not found
|
|
71
|
-
*/
|
|
72
|
-
async getSessionMetadata(sessionId) {
|
|
73
|
-
const key = this.getSessionKey(sessionId);
|
|
74
|
-
try {
|
|
75
|
-
const blob = await this.blobStorage.retrieve(key);
|
|
76
|
-
if (!blob) {
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
// Parse JSON content to extract metadata
|
|
80
|
-
const historyData = JSON.parse(blob.content.toString('utf8'));
|
|
81
|
-
return {
|
|
82
|
-
createdAt: historyData.createdAt,
|
|
83
|
-
lastActivity: historyData.updatedAt,
|
|
84
|
-
messageCount: historyData.messageCount,
|
|
85
|
-
sessionId: historyData.sessionId,
|
|
86
|
-
title: historyData.metadata?.title,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
console.error(`[BlobHistoryStorage] Failed to get metadata for session ${sessionId}:`, error);
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* List all session IDs that have persisted history.
|
|
96
|
-
*
|
|
97
|
-
* @returns Array of session IDs
|
|
98
|
-
*/
|
|
99
|
-
async listSessions() {
|
|
100
|
-
try {
|
|
101
|
-
const keys = await this.blobStorage.list(BlobHistoryStorage.SESSION_KEY_PREFIX);
|
|
102
|
-
// Extract session IDs from keys (remove prefix)
|
|
103
|
-
return keys.map(key => this.extractSessionId(key)).filter((id) => id !== undefined);
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
console.error('[BlobHistoryStorage] Failed to list sessions:', error);
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Load conversation history for a specific session.
|
|
112
|
-
*
|
|
113
|
-
* @param sessionId - Unique session identifier
|
|
114
|
-
* @returns Array of messages, or undefined if session not found
|
|
115
|
-
*/
|
|
116
|
-
async loadHistory(sessionId) {
|
|
117
|
-
const key = this.getSessionKey(sessionId);
|
|
118
|
-
try {
|
|
119
|
-
const blob = await this.blobStorage.retrieve(key);
|
|
120
|
-
if (!blob) {
|
|
121
|
-
return undefined;
|
|
122
|
-
}
|
|
123
|
-
// Parse JSON content
|
|
124
|
-
const historyData = JSON.parse(blob.content.toString('utf8'));
|
|
125
|
-
// Removed verbose console.log for cleaner interactive UX
|
|
126
|
-
// console.log(`[BlobHistoryStorage] Loaded ${historyData.messages.length} messages for session ${sessionId}`)
|
|
127
|
-
return historyData.messages;
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
console.error(`[BlobHistoryStorage] Failed to load history for session ${sessionId}:`, error);
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Save conversation history for a specific session.
|
|
136
|
-
*
|
|
137
|
-
* @param sessionId - Unique session identifier
|
|
138
|
-
* @param messages - Array of messages to persist
|
|
139
|
-
*/
|
|
140
|
-
async saveHistory(sessionId, messages) {
|
|
141
|
-
const key = this.getSessionKey(sessionId);
|
|
142
|
-
// Check if session already exists to preserve createdAt timestamp
|
|
143
|
-
const existingMetadata = await this.getSessionMetadata(sessionId);
|
|
144
|
-
// Build history data structure
|
|
145
|
-
const now = Date.now();
|
|
146
|
-
const historyData = {
|
|
147
|
-
createdAt: existingMetadata?.createdAt ?? now, // Preserve original creation time
|
|
148
|
-
messageCount: messages.length,
|
|
149
|
-
messages,
|
|
150
|
-
sessionId,
|
|
151
|
-
updatedAt: now,
|
|
152
|
-
};
|
|
153
|
-
try {
|
|
154
|
-
// Serialize to JSON with pretty-printing for inspectability
|
|
155
|
-
const content = JSON.stringify(historyData, null, 2);
|
|
156
|
-
// Store in blob storage
|
|
157
|
-
await this.blobStorage.store(key, content, {
|
|
158
|
-
contentType: 'application/json',
|
|
159
|
-
tags: {
|
|
160
|
-
sessionId,
|
|
161
|
-
type: 'chat-history',
|
|
162
|
-
},
|
|
163
|
-
});
|
|
164
|
-
// Removed verbose console.log for cleaner interactive UX
|
|
165
|
-
// console.log(`[BlobHistoryStorage] Saved ${messages.length} messages for session ${sessionId}`)
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
// Log error but don't throw - graceful degradation
|
|
169
|
-
console.error(`[BlobHistoryStorage] Failed to save history for session ${sessionId}:`, error);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Extract session ID from storage key.
|
|
174
|
-
*
|
|
175
|
-
* @param key - Storage key (e.g., "session-abc123")
|
|
176
|
-
* @returns Session ID (e.g., "abc123") or undefined if invalid key
|
|
177
|
-
*/
|
|
178
|
-
extractSessionId(key) {
|
|
179
|
-
if (!key.startsWith(BlobHistoryStorage.SESSION_KEY_PREFIX)) {
|
|
180
|
-
return undefined;
|
|
181
|
-
}
|
|
182
|
-
return key.slice(BlobHistoryStorage.SESSION_KEY_PREFIX.length);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Get storage key for a session.
|
|
186
|
-
*
|
|
187
|
-
* @param sessionId - Unique session identifier
|
|
188
|
-
* @returns Storage key (e.g., "session-abc123")
|
|
189
|
-
*/
|
|
190
|
-
getSessionKey(sessionId) {
|
|
191
|
-
return `${BlobHistoryStorage.SESSION_KEY_PREFIX}${sessionId}`;
|
|
192
|
-
}
|
|
193
|
-
}
|