v2 phase 4+5: Discord via Chat SDK, expanded MCP tools, message seq IDs
- Chat SDK bridge + Discord adapter (gateway listener, message routing) - MCP tools refactored into modular structure: core (send_message, send_file, edit_message, add_reaction), scheduling (schedule/list/cancel/pause/resume tasks), interactive (ask_user_question, send_card), agents (send_to_agent) - Message seq IDs: shared integer sequence across messages_in/out so agents see small numeric IDs instead of platform snowflakes - busy_timeout=5000 for session DB (poll loop + MCP server concurrent access) - Always copy agent-runner source to fix stale cache when non-index files change - Seed script for Discord testing, e2e test script Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ export function getSessionDb(): Database.Database {
|
||||
if (!_db) {
|
||||
_db = new Database(process.env.SESSION_DB_PATH || SESSION_DB_PATH);
|
||||
_db.pragma('journal_mode = DELETE');
|
||||
_db.pragma('busy_timeout = 5000');
|
||||
_db.pragma('foreign_keys = ON');
|
||||
}
|
||||
return _db;
|
||||
@@ -20,6 +21,7 @@ export function initTestSessionDb(): Database.Database {
|
||||
_db.exec(`
|
||||
CREATE TABLE messages_in (
|
||||
id TEXT PRIMARY KEY,
|
||||
seq INTEGER UNIQUE,
|
||||
kind TEXT NOT NULL,
|
||||
timestamp TEXT NOT NULL,
|
||||
status TEXT DEFAULT 'pending',
|
||||
@@ -34,6 +36,7 @@ export function initTestSessionDb(): Database.Database {
|
||||
);
|
||||
CREATE TABLE messages_out (
|
||||
id TEXT PRIMARY KEY,
|
||||
seq INTEGER UNIQUE,
|
||||
in_reply_to TEXT,
|
||||
timestamp TEXT NOT NULL,
|
||||
delivered INTEGER DEFAULT 0,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { getSessionDb } from './connection.js';
|
||||
|
||||
export interface MessageInRow {
|
||||
id: string;
|
||||
seq: number | null;
|
||||
kind: string;
|
||||
timestamp: string;
|
||||
status: string;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { getSessionDb } from './connection.js';
|
||||
|
||||
export interface MessageOutRow {
|
||||
id: string;
|
||||
seq: number | null;
|
||||
in_reply_to: string | null;
|
||||
timestamp: string;
|
||||
delivered: number;
|
||||
@@ -26,22 +27,44 @@ export interface WriteMessageOut {
|
||||
content: string;
|
||||
}
|
||||
|
||||
/** Write a new outbound message. */
|
||||
export function writeMessageOut(msg: WriteMessageOut): void {
|
||||
getSessionDb()
|
||||
.prepare(
|
||||
`INSERT INTO messages_out (id, in_reply_to, timestamp, delivered, deliver_after, recurrence, kind, platform_id, channel_type, thread_id, content)
|
||||
VALUES (@id, @in_reply_to, datetime('now'), 0, @deliver_after, @recurrence, @kind, @platform_id, @channel_type, @thread_id, @content)`,
|
||||
)
|
||||
.run({
|
||||
in_reply_to: null,
|
||||
deliver_after: null,
|
||||
recurrence: null,
|
||||
platform_id: null,
|
||||
channel_type: null,
|
||||
thread_id: null,
|
||||
...msg,
|
||||
});
|
||||
/** Write a new outbound message, auto-assigning a seq number. */
|
||||
export function writeMessageOut(msg: WriteMessageOut): number {
|
||||
const db = getSessionDb();
|
||||
const nextSeq = (
|
||||
db
|
||||
.prepare(
|
||||
`SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM (
|
||||
SELECT seq FROM messages_in WHERE seq IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT seq FROM messages_out WHERE seq IS NOT NULL
|
||||
)`,
|
||||
)
|
||||
.get() as { next: number }
|
||||
).next;
|
||||
|
||||
db.prepare(
|
||||
`INSERT INTO messages_out (id, seq, in_reply_to, timestamp, delivered, deliver_after, recurrence, kind, platform_id, channel_type, thread_id, content)
|
||||
VALUES (@id, @seq, @in_reply_to, datetime('now'), 0, @deliver_after, @recurrence, @kind, @platform_id, @channel_type, @thread_id, @content)`,
|
||||
).run({
|
||||
in_reply_to: null,
|
||||
deliver_after: null,
|
||||
recurrence: null,
|
||||
platform_id: null,
|
||||
channel_type: null,
|
||||
thread_id: null,
|
||||
...msg,
|
||||
seq: nextSeq,
|
||||
});
|
||||
|
||||
return nextSeq;
|
||||
}
|
||||
|
||||
/** Look up a message's platform ID by seq number. */
|
||||
export function getMessageIdBySeq(seq: number): string | null {
|
||||
const inRow = getSessionDb().prepare('SELECT id FROM messages_in WHERE seq = ?').get(seq) as { id: string } | undefined;
|
||||
if (inRow) return inRow.id;
|
||||
const outRow = getSessionDb().prepare('SELECT id FROM messages_out WHERE seq = ?').get(seq) as { id: string } | undefined;
|
||||
return outRow?.id ?? null;
|
||||
}
|
||||
|
||||
/** Get undelivered messages (for host polling). */
|
||||
|
||||
Reference in New Issue
Block a user