feat: store tool call IDs to determine interception lineage#22246
feat: store tool call IDs to determine interception lineage#22246dannykopping merged 18 commits intomainfrom
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
7aec92f to
6d4111f
Compare
93873fb to
668fb26
Compare
67f72a7 to
b9689c6
Compare
There was a problem hiding this comment.
Generally ok, few nits / small improvements.
Would be nice to have proper end to end test. May wait for sessions to be finished.
e9a962c to
740c8c6
Compare
740c8c6 to
3c73db0
Compare
|
@pawbana I had another PR stacked on top of this to handle the threads, but after a while I just collapsed those changes into here since it replaced some of the original implementations (like SQL queries). I also added an integration test: |
a45d054 to
94aabd6
Compare
Track provider-supplied tool call IDs with each tool use response. Add `CorrelatingToolCallID` to the `Interceptor` interface for interception lineage tracking. Each interceptor scans backward through request messages to find the most recent tool call result, identifying the parent interception that triggered the current one. Adapted from the [aibridge `prompt_provenance_poc`](main...prompt_provenance_poc) branch. Downstream: [coder/coder#22246](coder/coder#22246). Closes #165
Adds database columns (provider_tool_call_id on aibridge_tool_usages, parent_id on aibridge_interceptions) and the plumbing to populate them. When an interception ends with a correlating tool call ID, the server looks up which interception issued that tool call and sets parent_id. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add test cases for parent interception correlation in TestRecordInterceptionEnded (ok_with_parent_correlation and ok_no_parent_found) and ToolCallId assertion in TestRecordToolUsage. Update aibridge dependency to include extracted scan methods and tests. Fix dbauthz authorization for GetAIBridgeInterceptionByToolCallID to use proper RBAC check instead of comment-only justification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Danny Kopping <danny@coder.com>
The hand-written ListAuthorizedAIBridgeInterceptions in modelqueries.go was missing the new thread_parent_id column in its Scan call, causing "expected 14 destination arguments in Scan, not 13" errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same fix as downstack but for the additional thread_root_id column. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
94aabd6 to
958a7e5
Compare
| // tool call IDs correctly propagates thread_parent_id and thread_root_id. | ||
| // | ||
| // The chain is: A → B → C | ||
| // - A is the root (no parent, no root) |
There was a problem hiding this comment.
nit: Is there a reason for A having no root?
With rootID := A.ID (self reference) there would be distinction between old entires with no root set and new first/root entries?
There was a problem hiding this comment.
I think you're suggesting that we should always set the root ID to discriminate new entries from previous ones (before this change)?
Only interceptions with prompts can classify as thread roots, though.
A thread is a prompt (root) plus an optional agentic loop that follows (children all pointing to their own parent and the original root).
Does that answer your question?
There was a problem hiding this comment.
always set the root ID to discriminate new entries from previous ones (before this change)?
Yes, it was more of a open question, I don't have strong opinion on NULL vs set to self since I don't have clear idea why this distinction would be needed.
I've asked since we could add it for "free" in case it would be helpful (and I missed some use case).
Signed-off-by: Danny Kopping <danny@coder.com>

Adds database columns and server-side logic to track interception lineage via tool call IDs. When an interception ends, the server resolves the correlating tool call ID to find the parent interception and links them via
parent_id.New
provider_tool_call_idcolumn onaibridge_tool_usagesandparent_idcolumn onaibridge_interceptions, with indexes for lookup.findParentInterceptionIDqueries by tool call ID and filters out the current interception to find the parent.Adapted from the coder/coder
dk/prompt_provenance_pocbranch.Depends on coder/aibridge#188.
Closes coder/internal#1334