@imisbahk/hive 0.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/.rocket/ARCHITECTURE.md +7 -0
- package/.rocket/README.md +31 -0
- package/.rocket/SYMBOLS.md +282 -0
- package/.rocket/config.json +18 -0
- package/001-local-first-storage.md +43 -0
- package/003-memory-architechture.md +71 -0
- package/CONTRIBUTING.md +149 -0
- package/LICENSE.md +21 -0
- package/README.md +146 -0
- package/dist/agent/agent.d.ts +32 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +103 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +12 -0
- package/dist/cli/commands/chat.d.ts.map +1 -0
- package/dist/cli/commands/chat.js +117 -0
- package/dist/cli/commands/chat.js.map +1 -0
- package/dist/cli/commands/config.d.ts +7 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +234 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +186 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/nuke.d.ts +4 -0
- package/dist/cli/commands/nuke.d.ts.map +1 -0
- package/dist/cli/commands/nuke.js +47 -0
- package/dist/cli/commands/nuke.js.map +1 -0
- package/dist/cli/commands/status.d.ts +4 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +114 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/helpers/providerPrompts.d.ts +13 -0
- package/dist/cli/helpers/providerPrompts.d.ts.map +1 -0
- package/dist/cli/helpers/providerPrompts.js +138 -0
- package/dist/cli/helpers/providerPrompts.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +31 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/providers/anthropic.d.ts +10 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +108 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/api-key.d.ts +3 -0
- package/dist/providers/api-key.d.ts.map +1 -0
- package/dist/providers/api-key.js +15 -0
- package/dist/providers/api-key.js.map +1 -0
- package/dist/providers/base.d.ts +41 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +157 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/google.d.ts +6 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +19 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/groq.d.ts +6 -0
- package/dist/providers/groq.d.ts.map +1 -0
- package/dist/providers/groq.js +19 -0
- package/dist/providers/groq.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +58 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/mistral.d.ts +6 -0
- package/dist/providers/mistral.d.ts.map +1 -0
- package/dist/providers/mistral.js +19 -0
- package/dist/providers/mistral.js.map +1 -0
- package/dist/providers/ollama.d.ts +6 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +20 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +22 -0
- package/dist/providers/openai-compatible.d.ts.map +1 -0
- package/dist/providers/openai-compatible.js +36 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/providers/openai.d.ts +6 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +19 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openrouter.d.ts +6 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +19 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/together.d.ts +6 -0
- package/dist/providers/together.d.ts.map +1 -0
- package/dist/providers/together.js +19 -0
- package/dist/providers/together.js.map +1 -0
- package/dist/storage/db.d.ts +48 -0
- package/dist/storage/db.d.ts.map +1 -0
- package/dist/storage/db.js +298 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/schema.d.ts +43 -0
- package/dist/storage/schema.d.ts.map +1 -0
- package/dist/storage/schema.js +69 -0
- package/dist/storage/schema.js.map +1 -0
- package/index.md +16 -0
- package/package.json +48 -0
- package/prompts/Behaviour.md +23 -0
- package/prompts/Code.md +12 -0
- package/prompts/Memory.md +11 -0
- package/prompts/System.md +6 -0
- package/releases/v1/v0.1/RELEASE-NOTES.md +0 -0
- package/src/agent/agent.ts +155 -0
- package/src/agent/index.ts +2 -0
- package/src/cli/commands/chat.ts +169 -0
- package/src/cli/commands/config.ts +282 -0
- package/src/cli/commands/init.ts +242 -0
- package/src/cli/commands/nuke.ts +60 -0
- package/src/cli/commands/status.ts +147 -0
- package/src/cli/helpers/providerPrompts.ts +192 -0
- package/src/cli/index.ts +38 -0
- package/src/providers/anthropic.ts +146 -0
- package/src/providers/api-key.ts +23 -0
- package/src/providers/base.ts +234 -0
- package/src/providers/google.ts +21 -0
- package/src/providers/groq.ts +21 -0
- package/src/providers/index.ts +65 -0
- package/src/providers/mistral.ts +21 -0
- package/src/providers/ollama.ts +22 -0
- package/src/providers/openai-compatible.ts +58 -0
- package/src/providers/openai.ts +21 -0
- package/src/providers/openrouter.ts +21 -0
- package/src/providers/together.ts +21 -0
- package/src/storage/db.ts +476 -0
- package/src/storage/schema.ts +116 -0
- package/tsconfig.json +51 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { mkdirSync } from "node:fs";
|
|
4
|
+
|
|
5
|
+
import Database from "better-sqlite3";
|
|
6
|
+
import { v4 as uuidv4 } from "uuid";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
CURRENT_SCHEMA_VERSION,
|
|
10
|
+
MIGRATIONS,
|
|
11
|
+
type AgentRecord,
|
|
12
|
+
type ConversationRecord,
|
|
13
|
+
type MessageRecord,
|
|
14
|
+
type MessageRole,
|
|
15
|
+
type MetaRecord,
|
|
16
|
+
} from "./schema.js";
|
|
17
|
+
|
|
18
|
+
export type HiveDatabase = Database.Database;
|
|
19
|
+
export type {
|
|
20
|
+
AgentRecord,
|
|
21
|
+
ConversationRecord,
|
|
22
|
+
MessageRecord,
|
|
23
|
+
MessageRole,
|
|
24
|
+
MetaRecord,
|
|
25
|
+
} from "./schema.js";
|
|
26
|
+
|
|
27
|
+
export interface UpsertAgentInput {
|
|
28
|
+
name: string;
|
|
29
|
+
provider: string;
|
|
30
|
+
model: string;
|
|
31
|
+
persona: string;
|
|
32
|
+
dob?: string | null;
|
|
33
|
+
location?: string | null;
|
|
34
|
+
profession?: string | null;
|
|
35
|
+
aboutRaw?: string | null;
|
|
36
|
+
agentName?: string | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CreateConversationInput {
|
|
40
|
+
agentId: string;
|
|
41
|
+
title?: string | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface AppendMessageInput {
|
|
45
|
+
conversationId: string;
|
|
46
|
+
role: MessageRole;
|
|
47
|
+
content: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface UpdatePrimaryAgentProviderModelInput {
|
|
51
|
+
provider: string;
|
|
52
|
+
model: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const HIVE_DIRECTORY_NAME = ".hive";
|
|
56
|
+
export const HIVE_DB_FILENAME = "hive.db";
|
|
57
|
+
|
|
58
|
+
const AGENT_PROFILE_COLUMNS = [
|
|
59
|
+
{ name: "dob", definition: "TEXT" },
|
|
60
|
+
{ name: "location", definition: "TEXT" },
|
|
61
|
+
{ name: "profession", definition: "TEXT" },
|
|
62
|
+
{ name: "about_raw", definition: "TEXT" },
|
|
63
|
+
{ name: "agent_name", definition: "TEXT" },
|
|
64
|
+
] as const;
|
|
65
|
+
|
|
66
|
+
export function getHiveHomeDir(): string {
|
|
67
|
+
return process.env.HIVE_HOME ?? join(homedir(), HIVE_DIRECTORY_NAME);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getHiveDatabasePath(): string {
|
|
71
|
+
return join(getHiveHomeDir(), HIVE_DB_FILENAME);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function openHiveDatabase(databasePath = getHiveDatabasePath()): HiveDatabase {
|
|
75
|
+
mkdirSync(dirname(databasePath), { recursive: true });
|
|
76
|
+
|
|
77
|
+
const db = new Database(databasePath);
|
|
78
|
+
configureDatabase(db);
|
|
79
|
+
runMigrations(db);
|
|
80
|
+
setMetaValue(db, "schema_version", String(CURRENT_SCHEMA_VERSION));
|
|
81
|
+
|
|
82
|
+
return db;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function closeHiveDatabase(db: HiveDatabase): void {
|
|
86
|
+
db.close();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function configureDatabase(db: HiveDatabase): void {
|
|
90
|
+
db.pragma("foreign_keys = ON");
|
|
91
|
+
db.pragma("journal_mode = WAL");
|
|
92
|
+
db.pragma("synchronous = NORMAL");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function ensureMigrationTable(db: HiveDatabase): void {
|
|
96
|
+
db.exec(`
|
|
97
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
98
|
+
version INTEGER PRIMARY KEY,
|
|
99
|
+
name TEXT NOT NULL,
|
|
100
|
+
applied_at TEXT NOT NULL
|
|
101
|
+
);
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function runMigrations(db: HiveDatabase): void {
|
|
106
|
+
ensureMigrationTable(db);
|
|
107
|
+
|
|
108
|
+
const appliedRows = db
|
|
109
|
+
.prepare("SELECT version FROM schema_migrations")
|
|
110
|
+
.all() as Array<{ version: number }>;
|
|
111
|
+
const appliedVersions = new Set(appliedRows.map((row) => row.version));
|
|
112
|
+
|
|
113
|
+
for (const migration of MIGRATIONS) {
|
|
114
|
+
if (appliedVersions.has(migration.version)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const applyMigration = db.transaction(() => {
|
|
119
|
+
if (migration.name === "v2_agents_profile_columns") {
|
|
120
|
+
ensureAgentProfileColumns(db);
|
|
121
|
+
} else {
|
|
122
|
+
db.exec(migration.sql);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
db.prepare(
|
|
126
|
+
`
|
|
127
|
+
INSERT INTO schema_migrations (version, name, applied_at)
|
|
128
|
+
VALUES (?, ?, ?)
|
|
129
|
+
`,
|
|
130
|
+
).run(migration.version, migration.name, nowIso());
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
applyMigration();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function ensureAgentProfileColumns(db: HiveDatabase): void {
|
|
138
|
+
const tableInfo = db.prepare("PRAGMA table_info(agents)").all() as Array<{
|
|
139
|
+
name: string;
|
|
140
|
+
}>;
|
|
141
|
+
const existingColumns = new Set(tableInfo.map((column) => column.name));
|
|
142
|
+
|
|
143
|
+
for (const column of AGENT_PROFILE_COLUMNS) {
|
|
144
|
+
if (existingColumns.has(column.name)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
db.exec(`ALTER TABLE agents ADD COLUMN ${column.name} ${column.definition}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function nowIso(): string {
|
|
153
|
+
return new Date().toISOString();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function getMetaValue(db: HiveDatabase, key: string): string | null {
|
|
157
|
+
const row = db
|
|
158
|
+
.prepare("SELECT key, value, updated_at FROM meta WHERE key = ?")
|
|
159
|
+
.get(key) as MetaRecord | undefined;
|
|
160
|
+
|
|
161
|
+
return row?.value ?? null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function setMetaValue(db: HiveDatabase, key: string, value: string): void {
|
|
165
|
+
db.prepare(
|
|
166
|
+
`
|
|
167
|
+
INSERT INTO meta (key, value, updated_at)
|
|
168
|
+
VALUES (?, ?, ?)
|
|
169
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
170
|
+
value = excluded.value,
|
|
171
|
+
updated_at = excluded.updated_at
|
|
172
|
+
`,
|
|
173
|
+
).run(key, value, nowIso());
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function isHiveInitialized(db: HiveDatabase): boolean {
|
|
177
|
+
const row = db
|
|
178
|
+
.prepare("SELECT COUNT(1) as count FROM agents")
|
|
179
|
+
.get() as { count: number };
|
|
180
|
+
|
|
181
|
+
return row.count > 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function getPrimaryAgent(db: HiveDatabase): AgentRecord | null {
|
|
185
|
+
const row = db
|
|
186
|
+
.prepare(
|
|
187
|
+
`
|
|
188
|
+
SELECT
|
|
189
|
+
id,
|
|
190
|
+
name,
|
|
191
|
+
provider,
|
|
192
|
+
model,
|
|
193
|
+
persona,
|
|
194
|
+
dob,
|
|
195
|
+
location,
|
|
196
|
+
profession,
|
|
197
|
+
about_raw,
|
|
198
|
+
agent_name,
|
|
199
|
+
created_at,
|
|
200
|
+
updated_at
|
|
201
|
+
FROM agents
|
|
202
|
+
ORDER BY datetime(created_at) ASC
|
|
203
|
+
LIMIT 1
|
|
204
|
+
`,
|
|
205
|
+
)
|
|
206
|
+
.get() as AgentRecord | undefined;
|
|
207
|
+
|
|
208
|
+
return row ?? null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function upsertPrimaryAgent(
|
|
212
|
+
db: HiveDatabase,
|
|
213
|
+
input: UpsertAgentInput,
|
|
214
|
+
): AgentRecord {
|
|
215
|
+
const existing = getPrimaryAgent(db);
|
|
216
|
+
const timestamp = nowIso();
|
|
217
|
+
|
|
218
|
+
if (existing) {
|
|
219
|
+
db.prepare(
|
|
220
|
+
`
|
|
221
|
+
UPDATE agents
|
|
222
|
+
SET
|
|
223
|
+
name = ?,
|
|
224
|
+
provider = ?,
|
|
225
|
+
model = ?,
|
|
226
|
+
persona = ?,
|
|
227
|
+
dob = ?,
|
|
228
|
+
location = ?,
|
|
229
|
+
profession = ?,
|
|
230
|
+
about_raw = ?,
|
|
231
|
+
agent_name = ?,
|
|
232
|
+
updated_at = ?
|
|
233
|
+
WHERE id = ?
|
|
234
|
+
`,
|
|
235
|
+
).run(
|
|
236
|
+
input.name,
|
|
237
|
+
input.provider,
|
|
238
|
+
input.model,
|
|
239
|
+
input.persona,
|
|
240
|
+
input.dob ?? null,
|
|
241
|
+
input.location ?? null,
|
|
242
|
+
input.profession ?? null,
|
|
243
|
+
input.aboutRaw ?? null,
|
|
244
|
+
input.agentName ?? null,
|
|
245
|
+
timestamp,
|
|
246
|
+
existing.id,
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
...existing,
|
|
251
|
+
name: input.name,
|
|
252
|
+
provider: input.provider,
|
|
253
|
+
model: input.model,
|
|
254
|
+
persona: input.persona,
|
|
255
|
+
dob: input.dob ?? null,
|
|
256
|
+
location: input.location ?? null,
|
|
257
|
+
profession: input.profession ?? null,
|
|
258
|
+
about_raw: input.aboutRaw ?? null,
|
|
259
|
+
agent_name: input.agentName ?? null,
|
|
260
|
+
updated_at: timestamp,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const id = uuidv4();
|
|
265
|
+
db.prepare(
|
|
266
|
+
`
|
|
267
|
+
INSERT INTO agents (
|
|
268
|
+
id,
|
|
269
|
+
name,
|
|
270
|
+
provider,
|
|
271
|
+
model,
|
|
272
|
+
persona,
|
|
273
|
+
dob,
|
|
274
|
+
location,
|
|
275
|
+
profession,
|
|
276
|
+
about_raw,
|
|
277
|
+
agent_name,
|
|
278
|
+
created_at,
|
|
279
|
+
updated_at
|
|
280
|
+
)
|
|
281
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
282
|
+
`,
|
|
283
|
+
).run(
|
|
284
|
+
id,
|
|
285
|
+
input.name,
|
|
286
|
+
input.provider,
|
|
287
|
+
input.model,
|
|
288
|
+
input.persona,
|
|
289
|
+
input.dob ?? null,
|
|
290
|
+
input.location ?? null,
|
|
291
|
+
input.profession ?? null,
|
|
292
|
+
input.aboutRaw ?? null,
|
|
293
|
+
input.agentName ?? null,
|
|
294
|
+
timestamp,
|
|
295
|
+
timestamp,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
id,
|
|
300
|
+
name: input.name,
|
|
301
|
+
provider: input.provider,
|
|
302
|
+
model: input.model,
|
|
303
|
+
persona: input.persona,
|
|
304
|
+
dob: input.dob ?? null,
|
|
305
|
+
location: input.location ?? null,
|
|
306
|
+
profession: input.profession ?? null,
|
|
307
|
+
about_raw: input.aboutRaw ?? null,
|
|
308
|
+
agent_name: input.agentName ?? null,
|
|
309
|
+
created_at: timestamp,
|
|
310
|
+
updated_at: timestamp,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function updatePrimaryAgentProviderAndModel(
|
|
315
|
+
db: HiveDatabase,
|
|
316
|
+
input: UpdatePrimaryAgentProviderModelInput,
|
|
317
|
+
): AgentRecord {
|
|
318
|
+
const existing = getPrimaryAgent(db);
|
|
319
|
+
if (!existing) {
|
|
320
|
+
throw new Error("Hive is not initialized. Run `hive init` first.");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return updatePrimaryAgentConfiguration(db, existing, input.provider, input.model);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export function updatePrimaryAgentModel(
|
|
327
|
+
db: HiveDatabase,
|
|
328
|
+
model: string,
|
|
329
|
+
): AgentRecord {
|
|
330
|
+
const existing = getPrimaryAgent(db);
|
|
331
|
+
if (!existing) {
|
|
332
|
+
throw new Error("Hive is not initialized. Run `hive init` first.");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return updatePrimaryAgentConfiguration(db, existing, existing.provider, model);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function updatePrimaryAgentConfiguration(
|
|
339
|
+
db: HiveDatabase,
|
|
340
|
+
existing: AgentRecord,
|
|
341
|
+
provider: string,
|
|
342
|
+
model: string,
|
|
343
|
+
): AgentRecord {
|
|
344
|
+
const timestamp = nowIso();
|
|
345
|
+
|
|
346
|
+
db.prepare(
|
|
347
|
+
`
|
|
348
|
+
UPDATE agents
|
|
349
|
+
SET provider = ?, model = ?, updated_at = ?
|
|
350
|
+
WHERE id = ?
|
|
351
|
+
`,
|
|
352
|
+
).run(provider, model, timestamp, existing.id);
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
...existing,
|
|
356
|
+
provider,
|
|
357
|
+
model,
|
|
358
|
+
updated_at: timestamp,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function createConversation(
|
|
363
|
+
db: HiveDatabase,
|
|
364
|
+
input: CreateConversationInput,
|
|
365
|
+
): ConversationRecord {
|
|
366
|
+
const id = uuidv4();
|
|
367
|
+
const timestamp = nowIso();
|
|
368
|
+
|
|
369
|
+
db.prepare(
|
|
370
|
+
`
|
|
371
|
+
INSERT INTO conversations (id, agent_id, title, created_at, updated_at)
|
|
372
|
+
VALUES (?, ?, ?, ?, ?)
|
|
373
|
+
`,
|
|
374
|
+
).run(id, input.agentId, input.title ?? null, timestamp, timestamp);
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
id,
|
|
378
|
+
agent_id: input.agentId,
|
|
379
|
+
title: input.title ?? null,
|
|
380
|
+
created_at: timestamp,
|
|
381
|
+
updated_at: timestamp,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export function getConversationById(
|
|
386
|
+
db: HiveDatabase,
|
|
387
|
+
conversationId: string,
|
|
388
|
+
): ConversationRecord | null {
|
|
389
|
+
const row = db
|
|
390
|
+
.prepare(
|
|
391
|
+
`
|
|
392
|
+
SELECT id, agent_id, title, created_at, updated_at
|
|
393
|
+
FROM conversations
|
|
394
|
+
WHERE id = ?
|
|
395
|
+
`,
|
|
396
|
+
)
|
|
397
|
+
.get(conversationId) as ConversationRecord | undefined;
|
|
398
|
+
|
|
399
|
+
return row ?? null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function getLatestConversationForAgent(
|
|
403
|
+
db: HiveDatabase,
|
|
404
|
+
agentId: string,
|
|
405
|
+
): ConversationRecord | null {
|
|
406
|
+
const row = db
|
|
407
|
+
.prepare(
|
|
408
|
+
`
|
|
409
|
+
SELECT id, agent_id, title, created_at, updated_at
|
|
410
|
+
FROM conversations
|
|
411
|
+
WHERE agent_id = ?
|
|
412
|
+
ORDER BY datetime(updated_at) DESC
|
|
413
|
+
LIMIT 1
|
|
414
|
+
`,
|
|
415
|
+
)
|
|
416
|
+
.get(agentId) as ConversationRecord | undefined;
|
|
417
|
+
|
|
418
|
+
return row ?? null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function appendMessage(
|
|
422
|
+
db: HiveDatabase,
|
|
423
|
+
input: AppendMessageInput,
|
|
424
|
+
): MessageRecord {
|
|
425
|
+
const id = uuidv4();
|
|
426
|
+
const timestamp = nowIso();
|
|
427
|
+
|
|
428
|
+
const writeMessage = db.transaction(() => {
|
|
429
|
+
db.prepare(
|
|
430
|
+
`
|
|
431
|
+
INSERT INTO messages (id, conversation_id, role, content, created_at)
|
|
432
|
+
VALUES (?, ?, ?, ?, ?)
|
|
433
|
+
`,
|
|
434
|
+
).run(id, input.conversationId, input.role, input.content, timestamp);
|
|
435
|
+
|
|
436
|
+
db.prepare(
|
|
437
|
+
`
|
|
438
|
+
UPDATE conversations
|
|
439
|
+
SET updated_at = ?
|
|
440
|
+
WHERE id = ?
|
|
441
|
+
`,
|
|
442
|
+
).run(timestamp, input.conversationId);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
writeMessage();
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
id,
|
|
449
|
+
conversation_id: input.conversationId,
|
|
450
|
+
role: input.role,
|
|
451
|
+
content: input.content,
|
|
452
|
+
created_at: timestamp,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export function listMessages(
|
|
457
|
+
db: HiveDatabase,
|
|
458
|
+
conversationId: string,
|
|
459
|
+
limit = 100,
|
|
460
|
+
): MessageRecord[] {
|
|
461
|
+
return db
|
|
462
|
+
.prepare(
|
|
463
|
+
`
|
|
464
|
+
SELECT id, conversation_id, role, content, created_at
|
|
465
|
+
FROM (
|
|
466
|
+
SELECT id, conversation_id, role, content, created_at
|
|
467
|
+
FROM messages
|
|
468
|
+
WHERE conversation_id = ?
|
|
469
|
+
ORDER BY datetime(created_at) DESC
|
|
470
|
+
LIMIT ?
|
|
471
|
+
)
|
|
472
|
+
ORDER BY datetime(created_at) ASC
|
|
473
|
+
`,
|
|
474
|
+
)
|
|
475
|
+
.all(conversationId, limit) as MessageRecord[];
|
|
476
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export const MESSAGE_ROLES = ["system", "user", "assistant"] as const;
|
|
2
|
+
|
|
3
|
+
export type MessageRole = (typeof MESSAGE_ROLES)[number];
|
|
4
|
+
|
|
5
|
+
export interface SchemaMigration {
|
|
6
|
+
version: number;
|
|
7
|
+
name: string;
|
|
8
|
+
sql: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const CURRENT_SCHEMA_VERSION = 2;
|
|
12
|
+
|
|
13
|
+
const initialSchemaSql = `
|
|
14
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
15
|
+
version INTEGER PRIMARY KEY,
|
|
16
|
+
name TEXT NOT NULL,
|
|
17
|
+
applied_at TEXT NOT NULL
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
21
|
+
key TEXT PRIMARY KEY,
|
|
22
|
+
value TEXT NOT NULL,
|
|
23
|
+
updated_at TEXT NOT NULL
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
name TEXT NOT NULL,
|
|
29
|
+
provider TEXT NOT NULL,
|
|
30
|
+
model TEXT NOT NULL,
|
|
31
|
+
persona TEXT NOT NULL,
|
|
32
|
+
dob TEXT,
|
|
33
|
+
location TEXT,
|
|
34
|
+
profession TEXT,
|
|
35
|
+
about_raw TEXT,
|
|
36
|
+
agent_name TEXT,
|
|
37
|
+
created_at TEXT NOT NULL,
|
|
38
|
+
updated_at TEXT NOT NULL
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
44
|
+
title TEXT,
|
|
45
|
+
created_at TEXT NOT NULL,
|
|
46
|
+
updated_at TEXT NOT NULL
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
50
|
+
id TEXT PRIMARY KEY,
|
|
51
|
+
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
52
|
+
role TEXT NOT NULL CHECK (role IN ('system', 'user', 'assistant')),
|
|
53
|
+
content TEXT NOT NULL,
|
|
54
|
+
created_at TEXT NOT NULL
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_agent_id ON conversations(agent_id);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
export const MIGRATIONS: readonly SchemaMigration[] = [
|
|
63
|
+
{
|
|
64
|
+
version: 1,
|
|
65
|
+
name: "v1_initial_schema",
|
|
66
|
+
sql: initialSchemaSql,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
version: 2,
|
|
70
|
+
name: "v2_agents_profile_columns",
|
|
71
|
+
sql: `
|
|
72
|
+
ALTER TABLE agents ADD COLUMN dob TEXT;
|
|
73
|
+
ALTER TABLE agents ADD COLUMN location TEXT;
|
|
74
|
+
ALTER TABLE agents ADD COLUMN profession TEXT;
|
|
75
|
+
ALTER TABLE agents ADD COLUMN about_raw TEXT;
|
|
76
|
+
ALTER TABLE agents ADD COLUMN agent_name TEXT;
|
|
77
|
+
`,
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
export interface MetaRecord {
|
|
82
|
+
key: string;
|
|
83
|
+
value: string;
|
|
84
|
+
updated_at: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface AgentRecord {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
provider: string;
|
|
91
|
+
model: string;
|
|
92
|
+
persona: string;
|
|
93
|
+
dob: string | null;
|
|
94
|
+
location: string | null;
|
|
95
|
+
profession: string | null;
|
|
96
|
+
about_raw: string | null;
|
|
97
|
+
agent_name: string | null;
|
|
98
|
+
created_at: string;
|
|
99
|
+
updated_at: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ConversationRecord {
|
|
103
|
+
id: string;
|
|
104
|
+
agent_id: string;
|
|
105
|
+
title: string | null;
|
|
106
|
+
created_at: string;
|
|
107
|
+
updated_at: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface MessageRecord {
|
|
111
|
+
id: string;
|
|
112
|
+
conversation_id: string;
|
|
113
|
+
role: MessageRole;
|
|
114
|
+
content: string;
|
|
115
|
+
created_at: string;
|
|
116
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": [
|
|
7
|
+
"ES2022"
|
|
8
|
+
],
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"declaration": true,
|
|
17
|
+
"declarationMap": true,
|
|
18
|
+
"sourceMap": true,
|
|
19
|
+
"experimentalDecorators": true,
|
|
20
|
+
"emitDecoratorMetadata": true,
|
|
21
|
+
"allowSyntheticDefaultImports": true,
|
|
22
|
+
"paths": {
|
|
23
|
+
"@agent/*": [
|
|
24
|
+
"./src/agent/*"
|
|
25
|
+
],
|
|
26
|
+
"@providers/*": [
|
|
27
|
+
"./src/providers/*"
|
|
28
|
+
],
|
|
29
|
+
"@storage/*": [
|
|
30
|
+
"./src/storage/*"
|
|
31
|
+
],
|
|
32
|
+
"@utils/*": [
|
|
33
|
+
"./src/utils/*"
|
|
34
|
+
],
|
|
35
|
+
"@integrations/*": [
|
|
36
|
+
"./src/integrations/*"
|
|
37
|
+
],
|
|
38
|
+
"@mesh/*": [
|
|
39
|
+
"./src/mesh/*"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"include": [
|
|
44
|
+
"src/**/*"
|
|
45
|
+
],
|
|
46
|
+
"exclude": [
|
|
47
|
+
"node_modules",
|
|
48
|
+
"dist",
|
|
49
|
+
"**/*.test.ts"
|
|
50
|
+
]
|
|
51
|
+
}
|