feat: agent-to-agent communication, dynamic agent creation, self-modification tools
Agent-to-agent: host routes messages with channel_type='agent' to target agent's inbound.db, enriches with sender info, wakes target container. Bidirectional routing works via inherited routing context. Dynamic agents: create_agent MCP tool + system action handler creates agent groups, folders, and optional CLAUDE.md on the fly. Self-modification: install_packages (apt/npm, requires admin approval), add_mcp_server (no approval), request_rebuild (builds per-agent-group Docker image with approved packages). Approval flow reuses interactive card infrastructure with pending_approvals table. Also includes fixes from prior session: attachment download, reply context extraction, message editing (platform message ID tracking), delivery retry limits, and card update on button click. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -90,8 +90,10 @@ export function initTestSessionDb(): { inbound: Database.Database; outbound: Dat
|
||||
content TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE delivered (
|
||||
message_out_id TEXT PRIMARY KEY,
|
||||
delivered_at TEXT NOT NULL
|
||||
message_out_id TEXT PRIMARY KEY,
|
||||
platform_message_id TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'delivered',
|
||||
delivered_at TEXT NOT NULL
|
||||
);
|
||||
`);
|
||||
|
||||
|
||||
@@ -70,16 +70,37 @@ export function writeMessageOut(msg: WriteMessageOut): number {
|
||||
/**
|
||||
* Look up a message's platform ID by seq number.
|
||||
* Searches both inbound and outbound DBs since seq spans both.
|
||||
*
|
||||
* For inbound messages, the Chat SDK message ID is already the platform message ID
|
||||
* (e.g., "6037840640:42" for Telegram).
|
||||
*
|
||||
* For outbound messages, the internal ID (msg-xxx) won't work for edits/reactions.
|
||||
* Instead, look up the platform_message_id from the delivered table (host writes this
|
||||
* after successful delivery).
|
||||
*/
|
||||
export function getMessageIdBySeq(seq: number): string | null {
|
||||
const inRow = getInboundDb().prepare('SELECT id FROM messages_in WHERE seq = ?').get(seq) as
|
||||
const inbound = getInboundDb();
|
||||
|
||||
// Inbound messages: ID is already the platform message ID
|
||||
const inRow = inbound.prepare('SELECT id FROM messages_in WHERE seq = ?').get(seq) as
|
||||
| { id: string }
|
||||
| undefined;
|
||||
if (inRow) return inRow.id;
|
||||
|
||||
// Outbound messages: look up platform message ID from delivered table
|
||||
const outRow = getOutboundDb().prepare('SELECT id FROM messages_out WHERE seq = ?').get(seq) as
|
||||
| { id: string }
|
||||
| undefined;
|
||||
return outRow?.id ?? null;
|
||||
if (!outRow) return null;
|
||||
|
||||
// Check if host has stored the platform message ID after delivery
|
||||
const deliveredRow = inbound
|
||||
.prepare('SELECT platform_message_id FROM delivered WHERE message_out_id = ?')
|
||||
.get(outRow.id) as { platform_message_id: string | null } | undefined;
|
||||
if (deliveredRow?.platform_message_id) return deliveredRow.platform_message_id;
|
||||
|
||||
// Fallback to internal ID (edits/reactions on undelivered messages won't work)
|
||||
return outRow.id;
|
||||
}
|
||||
|
||||
/** Get undelivered messages (for host polling — reads from outbound.db). */
|
||||
|
||||
Reference in New Issue
Block a user