diff --git a/packages/core/src/schema.sql b/packages/core/src/schema.sql index 3514cc8..f7a9f0a 100644 --- a/packages/core/src/schema.sql +++ b/packages/core/src/schema.sql @@ -56,8 +56,10 @@ CREATE INDEX IF NOT EXISTS idx_messages_ts ON messages(session_id, timestamp); CREATE INDEX IF NOT EXISTS idx_sessions_source ON sessions(source); CREATE INDEX IF NOT EXISTS idx_messages_source ON messages(source); CREATE INDEX IF NOT EXISTS idx_tc_session_name ON tool_calls(session_id, name); +CREATE INDEX IF NOT EXISTS idx_tc_message ON tool_calls(message_uuid); CREATE INDEX IF NOT EXISTS idx_tc_file ON tool_calls(file_path); CREATE INDEX IF NOT EXISTS idx_tr_session ON tool_results(session_id); +CREATE INDEX IF NOT EXISTS idx_tr_message ON tool_results(message_uuid); CREATE INDEX IF NOT EXISTS idx_sa_session ON subagents(session_id); CREATE INDEX IF NOT EXISTS idx_wf_session ON workflows(session_id); CREATE INDEX IF NOT EXISTS idx_wa_run ON workflow_agents(run_id); diff --git a/tests/db-schema.test.mjs b/tests/db-schema.test.mjs index befea30..f2c4fb5 100644 --- a/tests/db-schema.test.mjs +++ b/tests/db-schema.test.mjs @@ -67,6 +67,59 @@ test('tool results schema indexes live session patch lookups', async () => { } }); +test('tool payload schema indexes subagent joins and guardian retractions', async () => { + const db = new DatabaseSync(':memory:'); + try { + db.exec(await readExecutableSchema()); + const toolCallJoinPlan = db.prepare(` + EXPLAIN QUERY PLAN + SELECT tc.* FROM tool_calls tc + JOIN messages m ON m.uuid = tc.message_uuid + WHERE m.agent_id = ? + `).all('agent-1'); + const toolResultJoinPlan = db.prepare(` + EXPLAIN QUERY PLAN + SELECT tr.* FROM tool_results tr + JOIN messages m ON m.uuid = tr.message_uuid + WHERE m.agent_id = ? + `).all('agent-1'); + const toolCallRetractionPlan = db.prepare(` + EXPLAIN QUERY PLAN + SELECT rowid FROM tool_calls + WHERE session_id = ? OR message_uuid IN ( + SELECT uuid FROM messages WHERE session_id = ? OR agent_id = ? + ) + `).all('session-1', 'session-1', 'session-1'); + const toolResultRetractionPlan = db.prepare(` + EXPLAIN QUERY PLAN + SELECT rowid FROM tool_results + WHERE session_id = ? OR message_uuid IN ( + SELECT uuid FROM messages WHERE session_id = ? OR agent_id = ? + ) + `).all('session-1', 'session-1', 'session-1'); + + const details = plans => plans.map(row => String(row.detail)); + assert.ok( + details(toolCallJoinPlan).some(detail => /USING INDEX idx_tc_message/.test(detail)), + `expected indexed tool call join, got: ${details(toolCallJoinPlan).join('; ')}`, + ); + assert.ok( + details(toolResultJoinPlan).some(detail => /USING INDEX idx_tr_message/.test(detail)), + `expected indexed tool result join, got: ${details(toolResultJoinPlan).join('; ')}`, + ); + assert.ok( + details(toolCallRetractionPlan).some(detail => /USING INDEX idx_tc_message/.test(detail)), + `expected indexed tool call retraction, got: ${details(toolCallRetractionPlan).join('; ')}`, + ); + assert.ok( + details(toolResultRetractionPlan).some(detail => /USING INDEX idx_tr_message/.test(detail)), + `expected indexed tool result retraction, got: ${details(toolResultRetractionPlan).join('; ')}`, + ); + } finally { + db.close(); + } +}); + test('schema reference stays focused on raw SQL structure', async () => { const ref = await readSchemaReference();