verybot 0.1.8
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 +167 -0
- package/dist/aliases/store.d.ts +21 -0
- package/dist/aliases/store.js +148 -0
- package/dist/aliases/types.d.ts +6 -0
- package/dist/aliases/types.js +1 -0
- package/dist/brain/agent-registry.d.ts +96 -0
- package/dist/brain/agent-registry.js +141 -0
- package/dist/brain/agent.d.ts +167 -0
- package/dist/brain/agent.js +932 -0
- package/dist/brain/channel-store.d.ts +27 -0
- package/dist/brain/channel-store.js +78 -0
- package/dist/brain/compaction.d.ts +37 -0
- package/dist/brain/compaction.js +214 -0
- package/dist/brain/context.d.ts +43 -0
- package/dist/brain/context.js +139 -0
- package/dist/brain/delegation-store.d.ts +33 -0
- package/dist/brain/delegation-store.js +106 -0
- package/dist/brain/loop.d.ts +24 -0
- package/dist/brain/loop.js +318 -0
- package/dist/brain/mcp-adapter.d.ts +43 -0
- package/dist/brain/mcp-adapter.js +244 -0
- package/dist/brain/memory-extractor.d.ts +26 -0
- package/dist/brain/memory-extractor.js +82 -0
- package/dist/brain/providers.d.ts +14 -0
- package/dist/brain/providers.js +85 -0
- package/dist/brain/queue.d.ts +18 -0
- package/dist/brain/queue.js +111 -0
- package/dist/brain/run-tools.d.ts +50 -0
- package/dist/brain/run-tools.js +136 -0
- package/dist/brain/session-key.d.ts +23 -0
- package/dist/brain/session-key.js +41 -0
- package/dist/brain/session-state.d.ts +36 -0
- package/dist/brain/session-state.js +51 -0
- package/dist/brain/session-store.d.ts +50 -0
- package/dist/brain/session-store.js +207 -0
- package/dist/brain/session.d.ts +32 -0
- package/dist/brain/session.js +75 -0
- package/dist/brain/task-subscriber.d.ts +56 -0
- package/dist/brain/task-subscriber.js +317 -0
- package/dist/brain/user-content.d.ts +16 -0
- package/dist/brain/user-content.js +32 -0
- package/dist/brain/utils.d.ts +4 -0
- package/dist/brain/utils.js +26 -0
- package/dist/brain/worker-coordinator.d.ts +25 -0
- package/dist/brain/worker-coordinator.js +83 -0
- package/dist/channels/commands.d.ts +50 -0
- package/dist/channels/commands.js +132 -0
- package/dist/channels/discord/channel.d.ts +29 -0
- package/dist/channels/discord/channel.js +159 -0
- package/dist/channels/discord/markdown.d.ts +19 -0
- package/dist/channels/discord/markdown.js +62 -0
- package/dist/channels/manager.d.ts +29 -0
- package/dist/channels/manager.js +100 -0
- package/dist/channels/slack/channel.d.ts +37 -0
- package/dist/channels/slack/channel.js +227 -0
- package/dist/channels/slack/markdown.d.ts +19 -0
- package/dist/channels/slack/markdown.js +62 -0
- package/dist/channels/specs.d.ts +32 -0
- package/dist/channels/specs.js +99 -0
- package/dist/channels/telegram/channel.d.ts +29 -0
- package/dist/channels/telegram/channel.js +182 -0
- package/dist/channels/telegram/markdown.d.ts +17 -0
- package/dist/channels/telegram/markdown.js +66 -0
- package/dist/channels/types.d.ts +26 -0
- package/dist/channels/types.js +1 -0
- package/dist/channels/whatsapp/channel.d.ts +34 -0
- package/dist/channels/whatsapp/channel.js +276 -0
- package/dist/channels/whatsapp/markdown.d.ts +20 -0
- package/dist/channels/whatsapp/markdown.js +51 -0
- package/dist/cli/claude-login.d.ts +5 -0
- package/dist/cli/claude-login.js +47 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.js +78 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.js +96 -0
- package/dist/computer/browser/actions.d.ts +31 -0
- package/dist/computer/browser/actions.js +148 -0
- package/dist/computer/browser/context-manager.d.ts +28 -0
- package/dist/computer/browser/context-manager.js +78 -0
- package/dist/computer/browser/manager.d.ts +91 -0
- package/dist/computer/browser/manager.js +344 -0
- package/dist/computer/browser/profile-badge.d.ts +13 -0
- package/dist/computer/browser/profile-badge.js +67 -0
- package/dist/computer/browser/screenshot.d.ts +5 -0
- package/dist/computer/browser/screenshot.js +21 -0
- package/dist/computer/browser/snapshot.d.ts +30 -0
- package/dist/computer/browser/snapshot.js +242 -0
- package/dist/computer/browser/tools.d.ts +5 -0
- package/dist/computer/browser/tools.js +167 -0
- package/dist/computer/browser/types.d.ts +26 -0
- package/dist/computer/browser/types.js +1 -0
- package/dist/computer/desktop/adapter.d.ts +25 -0
- package/dist/computer/desktop/adapter.js +11 -0
- package/dist/computer/desktop/macos.d.ts +24 -0
- package/dist/computer/desktop/macos.js +223 -0
- package/dist/computer/desktop/tools.d.ts +25 -0
- package/dist/computer/desktop/tools.js +114 -0
- package/dist/config/agent-config.d.ts +55 -0
- package/dist/config/agent-config.js +16 -0
- package/dist/config/model-catalog.d.ts +22 -0
- package/dist/config/model-catalog.js +112 -0
- package/dist/config/model-spec.d.ts +8 -0
- package/dist/config/model-spec.js +66 -0
- package/dist/config/store.d.ts +25 -0
- package/dist/config/store.js +143 -0
- package/dist/config.d.ts +110 -0
- package/dist/config.js +259 -0
- package/dist/control-ui/assets/index-Cbl7G5Sc.css +1 -0
- package/dist/control-ui/assets/index-Cu1P4C62.js +266 -0
- package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
- package/dist/control-ui/index.html +14 -0
- package/dist/control-ui/vite.svg +1 -0
- package/dist/events.d.ts +2 -0
- package/dist/events.js +11 -0
- package/dist/gateway/broadcast.d.ts +5 -0
- package/dist/gateway/broadcast.js +33 -0
- package/dist/gateway/methods/aliases.d.ts +17 -0
- package/dist/gateway/methods/aliases.js +22 -0
- package/dist/gateway/methods/chat.d.ts +33 -0
- package/dist/gateway/methods/chat.js +37 -0
- package/dist/gateway/methods/config.d.ts +14 -0
- package/dist/gateway/methods/config.js +24 -0
- package/dist/gateway/methods/models.d.ts +10 -0
- package/dist/gateway/methods/models.js +14 -0
- package/dist/gateway/methods/playbooks.d.ts +45 -0
- package/dist/gateway/methods/playbooks.js +488 -0
- package/dist/gateway/methods/prompt-templates.d.ts +27 -0
- package/dist/gateway/methods/prompt-templates.js +106 -0
- package/dist/gateway/methods/scheduler.d.ts +62 -0
- package/dist/gateway/methods/scheduler.js +129 -0
- package/dist/gateway/methods/sessions.d.ts +44 -0
- package/dist/gateway/methods/sessions.js +111 -0
- package/dist/gateway/methods/system.d.ts +12 -0
- package/dist/gateway/methods/system.js +39 -0
- package/dist/gateway/methods/tasks.d.ts +40 -0
- package/dist/gateway/methods/tasks.js +151 -0
- package/dist/gateway/methods/teams.d.ts +69 -0
- package/dist/gateway/methods/teams.js +376 -0
- package/dist/gateway/methods/tools.d.ts +6 -0
- package/dist/gateway/methods/tools.js +7 -0
- package/dist/gateway/methods/whatsapp.d.ts +19 -0
- package/dist/gateway/methods/whatsapp.js +35 -0
- package/dist/gateway/rpc.d.ts +38 -0
- package/dist/gateway/rpc.js +79 -0
- package/dist/gateway/server.d.ts +9 -0
- package/dist/gateway/server.js +137 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +254 -0
- package/dist/integrations/github.d.ts +7 -0
- package/dist/integrations/github.js +133 -0
- package/dist/integrations/mcp.d.ts +7 -0
- package/dist/integrations/mcp.js +106 -0
- package/dist/integrations/registry.d.ts +47 -0
- package/dist/integrations/registry.js +332 -0
- package/dist/integrations/scanner.d.ts +10 -0
- package/dist/integrations/scanner.js +122 -0
- package/dist/integrations/twitter.d.ts +10 -0
- package/dist/integrations/twitter.js +120 -0
- package/dist/integrations/types.d.ts +72 -0
- package/dist/integrations/types.js +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +104 -0
- package/dist/markdown/chunk.d.ts +9 -0
- package/dist/markdown/chunk.js +52 -0
- package/dist/markdown/ir.d.ts +37 -0
- package/dist/markdown/ir.js +529 -0
- package/dist/markdown/render.d.ts +22 -0
- package/dist/markdown/render.js +148 -0
- package/dist/markdown/table-render.d.ts +43 -0
- package/dist/markdown/table-render.js +219 -0
- package/dist/markdown/tables.d.ts +17 -0
- package/dist/markdown/tables.js +27 -0
- package/dist/memory/embedding.d.ts +16 -0
- package/dist/memory/embedding.js +66 -0
- package/dist/memory/explicit.d.ts +16 -0
- package/dist/memory/explicit.js +29 -0
- package/dist/memory/extractor.d.ts +13 -0
- package/dist/memory/extractor.js +82 -0
- package/dist/memory/search.d.ts +15 -0
- package/dist/memory/search.js +57 -0
- package/dist/memory/session-learning.d.ts +23 -0
- package/dist/memory/session-learning.js +55 -0
- package/dist/memory/store.d.ts +36 -0
- package/dist/memory/store.js +334 -0
- package/dist/memory/types.d.ts +9 -0
- package/dist/memory/types.js +2 -0
- package/dist/paths.d.ts +28 -0
- package/dist/paths.js +48 -0
- package/dist/prompt-templates/builtins/index.d.ts +4 -0
- package/dist/prompt-templates/builtins/index.js +5 -0
- package/dist/prompt-templates/builtins/planner.d.ts +4 -0
- package/dist/prompt-templates/builtins/planner.js +77 -0
- package/dist/prompt-templates/store.d.ts +45 -0
- package/dist/prompt-templates/store.js +224 -0
- package/dist/prompt-templates/types.d.ts +10 -0
- package/dist/prompt-templates/types.js +1 -0
- package/dist/scheduler/connected-channels.d.ts +24 -0
- package/dist/scheduler/connected-channels.js +57 -0
- package/dist/scheduler/scheduler.d.ts +22 -0
- package/dist/scheduler/scheduler.js +132 -0
- package/dist/scheduler/store.d.ts +27 -0
- package/dist/scheduler/store.js +205 -0
- package/dist/scheduler/types.d.ts +29 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/security/command-validator.d.ts +22 -0
- package/dist/security/command-validator.js +160 -0
- package/dist/security/docker-sandbox.d.ts +48 -0
- package/dist/security/docker-sandbox.js +218 -0
- package/dist/security/env-filter.d.ts +8 -0
- package/dist/security/env-filter.js +41 -0
- package/dist/skills/loader.d.ts +33 -0
- package/dist/skills/loader.js +132 -0
- package/dist/skills/prompt.d.ts +6 -0
- package/dist/skills/prompt.js +17 -0
- package/dist/skills/read-tool.d.ts +7 -0
- package/dist/skills/read-tool.js +24 -0
- package/dist/skills/scanner.d.ts +6 -0
- package/dist/skills/scanner.js +73 -0
- package/dist/skills/types.d.ts +15 -0
- package/dist/skills/types.js +1 -0
- package/dist/tasks/inline-attachment-content.d.ts +9 -0
- package/dist/tasks/inline-attachment-content.js +64 -0
- package/dist/tasks/store.d.ts +112 -0
- package/dist/tasks/store.js +519 -0
- package/dist/tasks/types.d.ts +129 -0
- package/dist/tasks/types.js +80 -0
- package/dist/teams/status-config.d.ts +8 -0
- package/dist/teams/status-config.js +40 -0
- package/dist/teams/store.d.ts +111 -0
- package/dist/teams/store.js +671 -0
- package/dist/teams/types.d.ts +30 -0
- package/dist/teams/types.js +1 -0
- package/dist/tools/bash.d.ts +18 -0
- package/dist/tools/bash.js +64 -0
- package/dist/tools/channel-history.d.ts +10 -0
- package/dist/tools/channel-history.js +43 -0
- package/dist/tools/delegate.d.ts +20 -0
- package/dist/tools/delegate.js +299 -0
- package/dist/tools/fs.d.ts +4 -0
- package/dist/tools/fs.js +335 -0
- package/dist/tools/integration-toggle.d.ts +14 -0
- package/dist/tools/integration-toggle.js +47 -0
- package/dist/tools/memory.d.ts +13 -0
- package/dist/tools/memory.js +59 -0
- package/dist/tools/prompt-templates.d.ts +7 -0
- package/dist/tools/prompt-templates.js +133 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +9 -0
- package/dist/tools/schedule.d.ts +8 -0
- package/dist/tools/schedule.js +219 -0
- package/dist/tools/speak.d.ts +10 -0
- package/dist/tools/speak.js +56 -0
- package/dist/tools/tasks.d.ts +67 -0
- package/dist/tools/tasks.js +288 -0
- package/dist/tools/teams.d.ts +22 -0
- package/dist/tools/teams.js +470 -0
- package/dist/tools/web-fetch.d.ts +3 -0
- package/dist/tools/web-fetch.js +22 -0
- package/dist/tts/edge.d.ts +10 -0
- package/dist/tts/edge.js +60 -0
- package/dist/tts/speak.d.ts +12 -0
- package/dist/tts/speak.js +81 -0
- package/dist/tts/transcribe.d.ts +5 -0
- package/dist/tts/transcribe.js +40 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +22 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +13 -0
- package/package.json +102 -0
- package/verybot.js +2 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { MemoryEntry } from "./types.js";
|
|
2
|
+
export declare class MemoryStore {
|
|
3
|
+
private db;
|
|
4
|
+
private vectorEnabled;
|
|
5
|
+
private vecTableCreated;
|
|
6
|
+
private constructor();
|
|
7
|
+
/** Async factory — loads sqlite-vec extension if available. */
|
|
8
|
+
static create(dbPath: string): Promise<MemoryStore>;
|
|
9
|
+
get hasVectorSearch(): boolean;
|
|
10
|
+
private createSchema;
|
|
11
|
+
/** Add team_id column if it doesn't exist yet (idempotent). */
|
|
12
|
+
private migrateTeamId;
|
|
13
|
+
private loadVecExtension;
|
|
14
|
+
private ensureVecTable;
|
|
15
|
+
/** Ensure rowid is bound as SQLite INTEGER (BigInt) for sqlite-vec tables. */
|
|
16
|
+
private toSqliteIntegerRowid;
|
|
17
|
+
/** Save a memory entry. Returns false if duplicate or near-duplicate fact exists. */
|
|
18
|
+
save(entry: MemoryEntry): boolean;
|
|
19
|
+
/** Full-text search using FTS5/BM25. Optionally scoped to a source and/or team. */
|
|
20
|
+
searchByText(query: string, limit?: number, source?: string, teamId?: string): MemoryEntry[];
|
|
21
|
+
/** Vector similarity search using sqlite-vec. Optionally scoped to a source and/or team. */
|
|
22
|
+
searchByVector(embedding: number[], limit?: number, source?: string, teamId?: string): MemoryEntry[];
|
|
23
|
+
/** Delete a single memory by its ID. Optionally verify team ownership. Returns true if found and deleted. */
|
|
24
|
+
deleteById(id: string, teamId?: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Paginated list of memories for a specific team (or global if teamId is null).
|
|
27
|
+
* Intended for CRUD management (listing/deleting).
|
|
28
|
+
*/
|
|
29
|
+
listByTeam(teamId: string | null, limit?: number, offset?: number): {
|
|
30
|
+
entries: MemoryEntry[];
|
|
31
|
+
total: number;
|
|
32
|
+
};
|
|
33
|
+
/** Delete all memories from a given session source. Returns count deleted. */
|
|
34
|
+
deleteBySource(source: string): number;
|
|
35
|
+
close(): void;
|
|
36
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { mkdirSync } from "fs";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
import Database from "better-sqlite3";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
const DEFAULT_LIMIT = 10;
|
|
6
|
+
export class MemoryStore {
|
|
7
|
+
db;
|
|
8
|
+
vectorEnabled = false;
|
|
9
|
+
vecTableCreated = false;
|
|
10
|
+
constructor(db) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
}
|
|
13
|
+
/** Async factory — loads sqlite-vec extension if available. */
|
|
14
|
+
static async create(dbPath) {
|
|
15
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
16
|
+
const db = new Database(dbPath);
|
|
17
|
+
db.pragma("journal_mode = WAL");
|
|
18
|
+
const store = new MemoryStore(db);
|
|
19
|
+
store.createSchema();
|
|
20
|
+
await store.loadVecExtension();
|
|
21
|
+
return store;
|
|
22
|
+
}
|
|
23
|
+
get hasVectorSearch() {
|
|
24
|
+
return this.vectorEnabled;
|
|
25
|
+
}
|
|
26
|
+
// --- Schema ---
|
|
27
|
+
createSchema() {
|
|
28
|
+
this.db.exec(`
|
|
29
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
30
|
+
id TEXT PRIMARY KEY,
|
|
31
|
+
fact TEXT NOT NULL,
|
|
32
|
+
source TEXT NOT NULL,
|
|
33
|
+
timestamp INTEGER NOT NULL,
|
|
34
|
+
embedding BLOB
|
|
35
|
+
);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_memories_source ON memories(source);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp DESC);
|
|
38
|
+
`);
|
|
39
|
+
// FTS5 external content table (synced manually in save/delete, no triggers)
|
|
40
|
+
// Porter tokenizer enables stemming: "like" matches "likes", "running" matches "run"
|
|
41
|
+
this.db.exec(`
|
|
42
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
43
|
+
fact,
|
|
44
|
+
content='memories',
|
|
45
|
+
content_rowid='rowid',
|
|
46
|
+
tokenize='porter unicode61'
|
|
47
|
+
);
|
|
48
|
+
`);
|
|
49
|
+
// Idempotent migration: add team_id column for team-scoped memories
|
|
50
|
+
this.migrateTeamId();
|
|
51
|
+
}
|
|
52
|
+
/** Add team_id column if it doesn't exist yet (idempotent). */
|
|
53
|
+
migrateTeamId() {
|
|
54
|
+
const columns = this.db.pragma("table_info(memories)");
|
|
55
|
+
const hasTeamId = columns.some((c) => c.name === "team_id");
|
|
56
|
+
if (!hasTeamId) {
|
|
57
|
+
this.db.exec("ALTER TABLE memories ADD COLUMN team_id TEXT");
|
|
58
|
+
logger.info("Migrated memories table: added team_id column");
|
|
59
|
+
}
|
|
60
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_memories_team_id ON memories(team_id)");
|
|
61
|
+
}
|
|
62
|
+
async loadVecExtension() {
|
|
63
|
+
try {
|
|
64
|
+
const sqliteVec = await import("sqlite-vec");
|
|
65
|
+
// Handle both ESM default export and CJS module patterns
|
|
66
|
+
const loader = sqliteVec.default?.load ?? sqliteVec.load;
|
|
67
|
+
loader(this.db);
|
|
68
|
+
this.vectorEnabled = true;
|
|
69
|
+
// Check if vec table already exists from a previous run
|
|
70
|
+
const vecExists = this.db
|
|
71
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memories_vec'")
|
|
72
|
+
.get();
|
|
73
|
+
if (vecExists)
|
|
74
|
+
this.vecTableCreated = true;
|
|
75
|
+
logger.info(`sqlite-vec extension loaded (vec table: ${this.vecTableCreated ? "exists" : "pending"})`);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
logger.info("sqlite-vec not available — vector search disabled");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
ensureVecTable(dims) {
|
|
82
|
+
if (this.vecTableCreated || !this.vectorEnabled)
|
|
83
|
+
return;
|
|
84
|
+
this.db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(embedding float[${dims}])`);
|
|
85
|
+
this.vecTableCreated = true;
|
|
86
|
+
logger.info(`Vector table created (${dims} dimensions)`);
|
|
87
|
+
}
|
|
88
|
+
/** Ensure rowid is bound as SQLite INTEGER (BigInt) for sqlite-vec tables. */
|
|
89
|
+
toSqliteIntegerRowid(value) {
|
|
90
|
+
return typeof value === "bigint" ? value : BigInt(value);
|
|
91
|
+
}
|
|
92
|
+
// --- CRUD ---
|
|
93
|
+
/** Save a memory entry. Returns false if duplicate or near-duplicate fact exists. */
|
|
94
|
+
save(entry) {
|
|
95
|
+
// Normalize: trim whitespace and trailing punctuation
|
|
96
|
+
entry = { ...entry, fact: normalizeFact(entry.fact) };
|
|
97
|
+
// Skip exact duplicate (scoped to same team)
|
|
98
|
+
const teamFilter = entry.teamId
|
|
99
|
+
? "AND team_id = ?"
|
|
100
|
+
: "AND team_id IS NULL";
|
|
101
|
+
const exactParams = entry.teamId
|
|
102
|
+
? [entry.fact, entry.teamId]
|
|
103
|
+
: [entry.fact];
|
|
104
|
+
const exact = this.db
|
|
105
|
+
.prepare(`SELECT id FROM memories WHERE fact = ? ${teamFilter}`)
|
|
106
|
+
.get(...exactParams);
|
|
107
|
+
if (exact)
|
|
108
|
+
return false;
|
|
109
|
+
// Skip near-duplicate via FTS5 (e.g. "lives in US" vs "lives in United States")
|
|
110
|
+
// Scope dedup to same team
|
|
111
|
+
const ftsQuery = buildFtsQuery(entry.fact);
|
|
112
|
+
if (ftsQuery) {
|
|
113
|
+
const dedupTeamFilter = entry.teamId
|
|
114
|
+
? "AND m.team_id = ?"
|
|
115
|
+
: "AND m.team_id IS NULL";
|
|
116
|
+
const dedupParams = entry.teamId
|
|
117
|
+
? [ftsQuery, entry.source, entry.teamId]
|
|
118
|
+
: [ftsQuery, entry.source];
|
|
119
|
+
const similar = this.db
|
|
120
|
+
.prepare(`SELECT m.fact FROM memories_fts f
|
|
121
|
+
JOIN memories m ON m.rowid = f.rowid
|
|
122
|
+
WHERE memories_fts MATCH ? AND m.source = ? ${dedupTeamFilter}
|
|
123
|
+
LIMIT 3`)
|
|
124
|
+
.all(...dedupParams);
|
|
125
|
+
for (const row of similar) {
|
|
126
|
+
if (isSimilarFact(row.fact, entry.fact))
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const embeddingBlob = entry.embedding
|
|
131
|
+
? Buffer.from(new Float32Array(entry.embedding).buffer)
|
|
132
|
+
: null;
|
|
133
|
+
const info = this.db
|
|
134
|
+
.prepare(`INSERT INTO memories (id, fact, source, timestamp, embedding, team_id)
|
|
135
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
136
|
+
.run(entry.id, entry.fact, entry.source, entry.timestamp, embeddingBlob, entry.teamId ?? null);
|
|
137
|
+
// Keep as BigInt — better-sqlite3 binds BigInt as INTEGER, but Number as REAL.
|
|
138
|
+
// sqlite-vec rejects REAL primary keys on virtual tables.
|
|
139
|
+
const rowid = this.toSqliteIntegerRowid(info.lastInsertRowid);
|
|
140
|
+
// Sync FTS5 index
|
|
141
|
+
this.db
|
|
142
|
+
.prepare("INSERT INTO memories_fts(rowid, fact) VALUES (?, ?)")
|
|
143
|
+
.run(rowid, entry.fact);
|
|
144
|
+
// Insert into vector table if we have an embedding
|
|
145
|
+
if (this.vectorEnabled && entry.embedding) {
|
|
146
|
+
this.ensureVecTable(entry.embedding.length);
|
|
147
|
+
this.db
|
|
148
|
+
.prepare("INSERT INTO memories_vec (rowid, embedding) VALUES (?, ?)")
|
|
149
|
+
.run(rowid, embeddingBlob);
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
/** Full-text search using FTS5/BM25. Optionally scoped to a source and/or team. */
|
|
154
|
+
searchByText(query, limit = DEFAULT_LIMIT, source, teamId) {
|
|
155
|
+
const ftsQuery = buildFtsQuery(query);
|
|
156
|
+
if (!ftsQuery)
|
|
157
|
+
return [];
|
|
158
|
+
const conditions = ["memories_fts MATCH ?"];
|
|
159
|
+
const params = [ftsQuery];
|
|
160
|
+
if (source) {
|
|
161
|
+
conditions.push("m.source = ?");
|
|
162
|
+
params.push(source);
|
|
163
|
+
}
|
|
164
|
+
// Team filter: return only team-specific memories
|
|
165
|
+
if (teamId) {
|
|
166
|
+
conditions.push("m.team_id = ?");
|
|
167
|
+
params.push(teamId);
|
|
168
|
+
}
|
|
169
|
+
params.push(limit);
|
|
170
|
+
const rows = this.db
|
|
171
|
+
.prepare(`SELECT m.id, m.fact, m.source, m.timestamp, m.team_id, rank
|
|
172
|
+
FROM memories_fts f
|
|
173
|
+
JOIN memories m ON m.rowid = f.rowid
|
|
174
|
+
WHERE ${conditions.join(" AND ")}
|
|
175
|
+
ORDER BY rank
|
|
176
|
+
LIMIT ?`)
|
|
177
|
+
.all(...params);
|
|
178
|
+
return rows.map((r) => ({
|
|
179
|
+
id: r.id, fact: r.fact, source: r.source, timestamp: r.timestamp,
|
|
180
|
+
...(r.team_id ? { teamId: r.team_id } : {}),
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
/** Vector similarity search using sqlite-vec. Optionally scoped to a source and/or team. */
|
|
184
|
+
searchByVector(embedding, limit = DEFAULT_LIMIT, source, teamId) {
|
|
185
|
+
if (!this.vectorEnabled || !this.vecTableCreated)
|
|
186
|
+
return [];
|
|
187
|
+
const buf = Buffer.from(new Float32Array(embedding).buffer);
|
|
188
|
+
// Fetch more than needed so we can filter by source/team and still fill the limit
|
|
189
|
+
const needsPostFilter = !!source || !!teamId;
|
|
190
|
+
const fetchLimit = needsPostFilter ? limit * 3 : limit;
|
|
191
|
+
const vecRows = this.db
|
|
192
|
+
.prepare("SELECT rowid, distance FROM memories_vec WHERE embedding MATCH ? ORDER BY distance LIMIT ?")
|
|
193
|
+
.all(buf, fetchLimit);
|
|
194
|
+
if (vecRows.length === 0)
|
|
195
|
+
return [];
|
|
196
|
+
const rowids = vecRows.map((r) => r.rowid);
|
|
197
|
+
const placeholders = rowids.map(() => "?").join(",");
|
|
198
|
+
const conditions = [`rowid IN (${placeholders})`];
|
|
199
|
+
const params = [...rowids];
|
|
200
|
+
if (source) {
|
|
201
|
+
conditions.push("source = ?");
|
|
202
|
+
params.push(source);
|
|
203
|
+
}
|
|
204
|
+
if (teamId) {
|
|
205
|
+
conditions.push("team_id = ?");
|
|
206
|
+
params.push(teamId);
|
|
207
|
+
}
|
|
208
|
+
params.push(limit);
|
|
209
|
+
const memRows = this.db
|
|
210
|
+
.prepare(`SELECT id, fact, source, timestamp, team_id FROM memories
|
|
211
|
+
WHERE ${conditions.join(" AND ")}
|
|
212
|
+
LIMIT ?`)
|
|
213
|
+
.all(...params);
|
|
214
|
+
return memRows.map((r) => ({
|
|
215
|
+
id: r.id, fact: r.fact, source: r.source, timestamp: r.timestamp,
|
|
216
|
+
...(r.team_id ? { teamId: r.team_id } : {}),
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
/** Delete a single memory by its ID. Optionally verify team ownership. Returns true if found and deleted. */
|
|
220
|
+
deleteById(id, teamId) {
|
|
221
|
+
// Verify ownership when teamId is provided
|
|
222
|
+
const query = teamId
|
|
223
|
+
? "SELECT rowid, fact FROM memories WHERE id = ? AND team_id = ?"
|
|
224
|
+
: "SELECT rowid, fact FROM memories WHERE id = ?";
|
|
225
|
+
const params = teamId ? [id, teamId] : [id];
|
|
226
|
+
const row = this.db
|
|
227
|
+
.prepare(query)
|
|
228
|
+
.get(...params);
|
|
229
|
+
if (!row)
|
|
230
|
+
return false;
|
|
231
|
+
const doDelete = this.db.transaction(() => {
|
|
232
|
+
// Remove from FTS5 index
|
|
233
|
+
this.db
|
|
234
|
+
.prepare("INSERT INTO memories_fts(memories_fts, rowid, fact) VALUES('delete', ?, ?)")
|
|
235
|
+
.run(this.toSqliteIntegerRowid(row.rowid), row.fact);
|
|
236
|
+
// Remove from vector table
|
|
237
|
+
if (this.vectorEnabled && this.vecTableCreated) {
|
|
238
|
+
this.db
|
|
239
|
+
.prepare("DELETE FROM memories_vec WHERE rowid = ?")
|
|
240
|
+
.run(this.toSqliteIntegerRowid(row.rowid));
|
|
241
|
+
}
|
|
242
|
+
// Remove from main table
|
|
243
|
+
this.db.prepare("DELETE FROM memories WHERE id = ?").run(id);
|
|
244
|
+
});
|
|
245
|
+
doDelete();
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Paginated list of memories for a specific team (or global if teamId is null).
|
|
250
|
+
* Intended for CRUD management (listing/deleting).
|
|
251
|
+
*/
|
|
252
|
+
listByTeam(teamId, limit = DEFAULT_LIMIT, offset = 0) {
|
|
253
|
+
const filter = teamId ? "WHERE team_id = ?" : "WHERE team_id IS NULL";
|
|
254
|
+
const params = teamId ? [teamId] : [];
|
|
255
|
+
const countRow = this.db
|
|
256
|
+
.prepare(`SELECT COUNT(*) AS cnt FROM memories ${filter}`)
|
|
257
|
+
.get(...params);
|
|
258
|
+
const rows = this.db
|
|
259
|
+
.prepare(`SELECT id, fact, source, timestamp, team_id FROM memories
|
|
260
|
+
${filter}
|
|
261
|
+
ORDER BY timestamp DESC
|
|
262
|
+
LIMIT ? OFFSET ?`)
|
|
263
|
+
.all(...params, limit, offset);
|
|
264
|
+
return {
|
|
265
|
+
total: countRow.cnt,
|
|
266
|
+
entries: rows.map((r) => ({
|
|
267
|
+
id: r.id, fact: r.fact, source: r.source, timestamp: r.timestamp,
|
|
268
|
+
...(r.team_id ? { teamId: r.team_id } : {}),
|
|
269
|
+
})),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/** Delete all memories from a given session source. Returns count deleted. */
|
|
273
|
+
deleteBySource(source) {
|
|
274
|
+
const rows = this.db
|
|
275
|
+
.prepare("SELECT rowid, fact FROM memories WHERE source = ?")
|
|
276
|
+
.all(source);
|
|
277
|
+
if (rows.length === 0)
|
|
278
|
+
return 0;
|
|
279
|
+
const rowids = rows.map((r) => this.toSqliteIntegerRowid(r.rowid));
|
|
280
|
+
const placeholders = rowids.map(() => "?").join(",");
|
|
281
|
+
// Remove from FTS5 index
|
|
282
|
+
for (const row of rows) {
|
|
283
|
+
this.db
|
|
284
|
+
.prepare("INSERT INTO memories_fts(memories_fts, rowid, fact) VALUES('delete', ?, ?)")
|
|
285
|
+
.run(this.toSqliteIntegerRowid(row.rowid), row.fact);
|
|
286
|
+
}
|
|
287
|
+
// Remove from vector table
|
|
288
|
+
if (this.vectorEnabled && this.vecTableCreated) {
|
|
289
|
+
this.db
|
|
290
|
+
.prepare(`DELETE FROM memories_vec WHERE rowid IN (${placeholders})`)
|
|
291
|
+
.run(...rowids);
|
|
292
|
+
}
|
|
293
|
+
// Remove from main table
|
|
294
|
+
const info = this.db
|
|
295
|
+
.prepare(`DELETE FROM memories WHERE rowid IN (${placeholders})`)
|
|
296
|
+
.run(...rowids);
|
|
297
|
+
return info.changes;
|
|
298
|
+
}
|
|
299
|
+
close() {
|
|
300
|
+
this.db.close();
|
|
301
|
+
logger.info("Memory store closed");
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/** Build an FTS5 query from raw text. Returns null if no usable tokens. */
|
|
305
|
+
function buildFtsQuery(raw) {
|
|
306
|
+
const tokens = raw
|
|
307
|
+
.match(/[A-Za-z0-9_]+/g)
|
|
308
|
+
?.map((t) => t.trim())
|
|
309
|
+
.filter(Boolean) ?? [];
|
|
310
|
+
if (tokens.length === 0)
|
|
311
|
+
return null;
|
|
312
|
+
// Use OR for broader matching (AND would be too strict for memory recall)
|
|
313
|
+
return tokens.map((t) => `"${t.replaceAll('"', "")}"`).join(" OR ");
|
|
314
|
+
}
|
|
315
|
+
/** Trim whitespace and trailing punctuation from a fact. */
|
|
316
|
+
function normalizeFact(fact) {
|
|
317
|
+
return fact.trim().replace(/[.\s]+$/, "");
|
|
318
|
+
}
|
|
319
|
+
/** Check if two facts are near-duplicates by comparing their word overlap. */
|
|
320
|
+
function isSimilarFact(a, b) {
|
|
321
|
+
const wordsA = new Set(a.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
322
|
+
const wordsB = new Set(b.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
323
|
+
if (wordsA.size === 0 || wordsB.size === 0)
|
|
324
|
+
return false;
|
|
325
|
+
let overlap = 0;
|
|
326
|
+
for (const w of wordsA) {
|
|
327
|
+
if (wordsB.has(w))
|
|
328
|
+
overlap++;
|
|
329
|
+
}
|
|
330
|
+
// If 80%+ of words overlap in both directions, it's a near-duplicate
|
|
331
|
+
const ratioA = overlap / wordsA.size;
|
|
332
|
+
const ratioB = overlap / wordsB.size;
|
|
333
|
+
return ratioA >= 0.8 && ratioB >= 0.8;
|
|
334
|
+
}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Root data directory: ~/.verybot */
|
|
2
|
+
export declare const BASE_DIR: string;
|
|
3
|
+
/** Conversation history (JSONL files): ~/.verybot/sessions/ */
|
|
4
|
+
export declare const SESSIONS_DIR: string;
|
|
5
|
+
/** Long-term memory + schedules (SQLite): ~/.verybot/memory.db */
|
|
6
|
+
export declare const MEMORY_DB_PATH: string;
|
|
7
|
+
/** Global command aliases file: ~/.verybot/command-aliases.json */
|
|
8
|
+
export declare const COMMAND_ALIASES_PATH: string;
|
|
9
|
+
/** Chromium user data: ~/.verybot/browser/ */
|
|
10
|
+
export declare const BROWSER_PROFILE_DIR: string;
|
|
11
|
+
/** Named browser profiles: ~/.verybot/browser-profiles/ */
|
|
12
|
+
export declare const BROWSER_PROFILES_DIR: string;
|
|
13
|
+
/** User skill definitions: ~/.verybot/skills/ */
|
|
14
|
+
export declare const SKILLS_DIR: string;
|
|
15
|
+
/** User integration definitions: ~/.verybot/integrations/ */
|
|
16
|
+
export declare const INTEGRATIONS_DIR: string;
|
|
17
|
+
/** Playbook root: ~/.verybot/playbook */
|
|
18
|
+
export declare const PLAYBOOK_DIR: string;
|
|
19
|
+
/** Playbook folders: ~/.verybot/playbook/playbooks */
|
|
20
|
+
export declare const PLAYBOOKS_DIR: string;
|
|
21
|
+
/** Docker sandbox workspace: ~/.verybot/workspace/ */
|
|
22
|
+
export declare const SANDBOX_WORKSPACE: string;
|
|
23
|
+
/** WhatsApp Baileys auth state: ~/.verybot/whatsapp-auth/ */
|
|
24
|
+
export declare const WHATSAPP_AUTH_DIR: string;
|
|
25
|
+
/** Task image attachments: ~/.verybot/attachments/ */
|
|
26
|
+
export declare const ATTACHMENTS_DIR: string;
|
|
27
|
+
/** Ensure all data directories exist. Call once at startup. */
|
|
28
|
+
export declare function ensureDirs(): void;
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { mkdirSync } from "fs";
|
|
4
|
+
/** Root data directory: ~/.verybot */
|
|
5
|
+
export const BASE_DIR = join(homedir(), ".verybot");
|
|
6
|
+
/** Conversation history (JSONL files): ~/.verybot/sessions/ */
|
|
7
|
+
export const SESSIONS_DIR = join(BASE_DIR, "sessions");
|
|
8
|
+
/** Long-term memory + schedules (SQLite): ~/.verybot/memory.db */
|
|
9
|
+
export const MEMORY_DB_PATH = join(BASE_DIR, "memory.db");
|
|
10
|
+
/** Global command aliases file: ~/.verybot/command-aliases.json */
|
|
11
|
+
export const COMMAND_ALIASES_PATH = join(BASE_DIR, "command-aliases.json");
|
|
12
|
+
/** Chromium user data: ~/.verybot/browser/ */
|
|
13
|
+
export const BROWSER_PROFILE_DIR = join(BASE_DIR, "browser");
|
|
14
|
+
/** Named browser profiles: ~/.verybot/browser-profiles/ */
|
|
15
|
+
export const BROWSER_PROFILES_DIR = join(BASE_DIR, "browser-profiles");
|
|
16
|
+
/** User skill definitions: ~/.verybot/skills/ */
|
|
17
|
+
export const SKILLS_DIR = join(BASE_DIR, "skills");
|
|
18
|
+
/** User integration definitions: ~/.verybot/integrations/ */
|
|
19
|
+
export const INTEGRATIONS_DIR = join(BASE_DIR, "integrations");
|
|
20
|
+
/** Playbook root: ~/.verybot/playbook */
|
|
21
|
+
export const PLAYBOOK_DIR = join(BASE_DIR, "playbook");
|
|
22
|
+
/** Playbook folders: ~/.verybot/playbook/playbooks */
|
|
23
|
+
export const PLAYBOOKS_DIR = join(PLAYBOOK_DIR, "playbooks");
|
|
24
|
+
/** Docker sandbox workspace: ~/.verybot/workspace/ */
|
|
25
|
+
export const SANDBOX_WORKSPACE = join(BASE_DIR, "workspace");
|
|
26
|
+
/** WhatsApp Baileys auth state: ~/.verybot/whatsapp-auth/ */
|
|
27
|
+
export const WHATSAPP_AUTH_DIR = join(BASE_DIR, "whatsapp-auth");
|
|
28
|
+
/** Task image attachments: ~/.verybot/attachments/ */
|
|
29
|
+
export const ATTACHMENTS_DIR = join(BASE_DIR, "attachments");
|
|
30
|
+
/** All directories that should exist at startup. */
|
|
31
|
+
const REQUIRED_DIRS = [
|
|
32
|
+
BASE_DIR,
|
|
33
|
+
SESSIONS_DIR,
|
|
34
|
+
BROWSER_PROFILE_DIR,
|
|
35
|
+
BROWSER_PROFILES_DIR,
|
|
36
|
+
SKILLS_DIR,
|
|
37
|
+
INTEGRATIONS_DIR,
|
|
38
|
+
PLAYBOOK_DIR,
|
|
39
|
+
PLAYBOOKS_DIR,
|
|
40
|
+
WHATSAPP_AUTH_DIR,
|
|
41
|
+
ATTACHMENTS_DIR,
|
|
42
|
+
];
|
|
43
|
+
/** Ensure all data directories exist. Call once at startup. */
|
|
44
|
+
export function ensureDirs() {
|
|
45
|
+
for (const dir of REQUIRED_DIRS) {
|
|
46
|
+
mkdirSync(dir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PromptTemplate } from "../types.js";
|
|
2
|
+
/** Stable ID — never change (used as DB primary key for built-in seeding). */
|
|
3
|
+
export declare const PLANNER_TEMPLATE_ID = "builtin-planner";
|
|
4
|
+
export declare const PLANNER: Omit<PromptTemplate, "createdAt" | "updatedAt">;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Stable ID — never change (used as DB primary key for built-in seeding). */
|
|
2
|
+
export const PLANNER_TEMPLATE_ID = "builtin-planner";
|
|
3
|
+
export const PLANNER = {
|
|
4
|
+
id: PLANNER_TEMPLATE_ID,
|
|
5
|
+
name: "Planner",
|
|
6
|
+
description: "Interactive planning worker that clarifies requirements via task comments.",
|
|
7
|
+
role: "worker",
|
|
8
|
+
builtin: true,
|
|
9
|
+
content: `You are an interactive Planning agent. Your job is to refine vague or incomplete tasks by talking to the user, asking questions, gathering requirements, and recording everything as task comments.
|
|
10
|
+
|
|
11
|
+
## Tools (whitelist — use nothing else)
|
|
12
|
+
|
|
13
|
+
\`task_get\` · \`task_comment_list\` · \`task_comment_add\` · \`task_update\` (needsHumanReview only)
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
- Never change task status, title, or description. Only set \`needsHumanReview: true\` during finalization.
|
|
18
|
+
- Only work on tasks in "plan" status. If the task is in any other status, stop immediately.
|
|
19
|
+
- Anti-loop: after posting a comment, stop and return. Do not call \`task_get\` again. Do not post follow-up comments in the same invocation. One round of questions per invocation.
|
|
20
|
+
- Check \`updated_by\`: if the last update was by you (the Planner), stop and wait for external input.
|
|
21
|
+
- Be conversational and concise. Ask at most 3-5 questions per round.
|
|
22
|
+
- Always record questions and answers as task comments. This is the source of truth.
|
|
23
|
+
- Never write code, run builds, or make file changes. You are a planner, not a coder.
|
|
24
|
+
|
|
25
|
+
## Lifecycle
|
|
26
|
+
|
|
27
|
+
You are invoked once per round. Each invocation follows this flow:
|
|
28
|
+
|
|
29
|
+
1. Read the task and all comments: call \`task_get\` and \`task_comment_list\`.
|
|
30
|
+
2. If the last comment is yours, stop (waiting for user or external input).
|
|
31
|
+
3. If this is a fresh task (no comments), identify gaps (acceptance criteria, scope, constraints, priority, dependencies) and post your first round of questions as a task comment.
|
|
32
|
+
4. If the user answered, post a Q&A summary comment, then either ask the next round of questions or finalize.
|
|
33
|
+
5. If all gaps are filled, post the "Agreed Plan" comment and set \`needsHumanReview: true\`.
|
|
34
|
+
6. Return. Do not loop.
|
|
35
|
+
|
|
36
|
+
## Asking Questions
|
|
37
|
+
|
|
38
|
+
Write questions as a task comment. Use Quick Question Blocks so the UI renders clickable choices:
|
|
39
|
+
|
|
40
|
+
\`\`\`question
|
|
41
|
+
title: Decision title
|
|
42
|
+
options:
|
|
43
|
+
- Option A
|
|
44
|
+
- Option B
|
|
45
|
+
- Option C
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
Add \`type: multi\` only for multi-select. No JSON. Write brief context (1-3 lines) before each block.
|
|
49
|
+
|
|
50
|
+
## Recording Answers
|
|
51
|
+
|
|
52
|
+
After receiving answers, add a summary comment:
|
|
53
|
+
|
|
54
|
+
\`\`\`
|
|
55
|
+
## Planning Notes
|
|
56
|
+
**Q:** <question>
|
|
57
|
+
**A:** <answer>
|
|
58
|
+
...
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
## Finalizing
|
|
62
|
+
|
|
63
|
+
Once you have enough clarity, add a final comment:
|
|
64
|
+
|
|
65
|
+
\`\`\`
|
|
66
|
+
## Agreed Plan
|
|
67
|
+
- **Goal:** ...
|
|
68
|
+
- **Scope:** ...
|
|
69
|
+
- **Acceptance Criteria:**
|
|
70
|
+
- [ ] ...
|
|
71
|
+
- [ ] ...
|
|
72
|
+
- **Out of Scope:** ...
|
|
73
|
+
- **Notes:** ...
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
Then call \`task_update\` to set \`needsHumanReview: true\`. This signals planning is complete and ready for human review.`,
|
|
77
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { PromptTemplate } from "./types.js";
|
|
2
|
+
/** Max allowed length for template names. */
|
|
3
|
+
export declare const MAX_TEMPLATE_NAME_LENGTH = 128;
|
|
4
|
+
/** Max allowed length for template content. */
|
|
5
|
+
export declare const MAX_TEMPLATE_CONTENT_LENGTH = 50000;
|
|
6
|
+
export interface CreatePromptTemplateInput {
|
|
7
|
+
id?: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
role: "orchestrator" | "worker";
|
|
11
|
+
content: string;
|
|
12
|
+
}
|
|
13
|
+
export interface UpdatePromptTemplateInput {
|
|
14
|
+
name?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
role?: "orchestrator" | "worker";
|
|
17
|
+
content?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ForkPromptTemplateInput {
|
|
20
|
+
name?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* SQLite-backed persistence for prompt templates.
|
|
25
|
+
* Shares the same DB file as TeamStore, TaskStore, etc.
|
|
26
|
+
*/
|
|
27
|
+
export declare class PromptTemplateStore {
|
|
28
|
+
private db;
|
|
29
|
+
private constructor();
|
|
30
|
+
static create(dbPath: string): Promise<PromptTemplateStore>;
|
|
31
|
+
private createSchema;
|
|
32
|
+
createPromptTemplate(input: CreatePromptTemplateInput): PromptTemplate;
|
|
33
|
+
forkPromptTemplate(sourceId: string, input?: ForkPromptTemplateInput): PromptTemplate | null;
|
|
34
|
+
updatePromptTemplate(id: string, input: UpdatePromptTemplateInput): PromptTemplate | null;
|
|
35
|
+
deletePromptTemplate(id: string): boolean;
|
|
36
|
+
getPromptTemplateById(id: string): PromptTemplate | null;
|
|
37
|
+
listPromptTemplates(): PromptTemplate[];
|
|
38
|
+
private listPromptTemplateNames;
|
|
39
|
+
/**
|
|
40
|
+
* Upsert built-in templates by id on boot.
|
|
41
|
+
* Only updates name/description/role/content for existing builtins.
|
|
42
|
+
*/
|
|
43
|
+
seedBuiltins(templates: Omit<PromptTemplate, "createdAt" | "updatedAt">[]): void;
|
|
44
|
+
close(): void;
|
|
45
|
+
}
|