-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[OPIK-7852] [BE] Persist cipx call attribution: trigger, trigger_detail, turn_key, parent_tool_use_id #7937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
2a99970
ade7d8a
79b112a
b0941b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| --liquibase formatted sql | ||
| --changeset aadereiko:000118_add_trigger_to_cipx_spends | ||
| --comment: Persist the per-call trigger, its detail (subagent NAME), the turn key and the parent tool_use id on cipx_spends | ||
| -- | ||
| -- cipx already ships all four on metadata.cipx.call; none of them reached a typed column, so the | ||
| -- spend tables cannot tell a subagent's spend from the main agent's, let alone name the agent or | ||
| -- reconstruct the parent/child tree the AI Spend UI wants. | ||
| -- | ||
| -- trigger what caused this call: user_turn | tool_continuation | subagent | automated | ||
| -- | unknown. Closed enum -> LowCardinality. | ||
| -- trigger_detail trigger-dependent qualifier. For trigger='subagent' this is the agent NAME | ||
| -- (the parent's `Agent` tool_use input.subagent_type: "code-reviewer", | ||
| -- "Explore", ...); for trigger='tool_continuation' it is the tool name. Empty | ||
| -- when the proxy could not resolve it -- deliberately NOT defaulted, so an | ||
| -- empty string means "unknown", never "general-purpose". | ||
| -- turn_key groups a user prompt's root call with every continuation that followed it | ||
| -- (SHA256 hex of the prompt text). The grain a per-turn read aggregates on. | ||
| -- parent_tool_use_id the `Agent` tool_use that spawned this call -- the identity of one agent | ||
| -- INVOCATION, stable across every call that agent makes. This is the edge of | ||
| -- the agent tree: child rows point at the parent's tool_use id. | ||
| -- | ||
| -- Additive columns with defaults; every pre-existing row reads '' (unknown), which is honest -- | ||
| -- those rows were written before the proxy carried the fields. | ||
| ALTER TABLE ${ANALYTICS_DB_DATABASE_NAME}.cipx_spends ON CLUSTER '{cluster}' | ||
| ADD COLUMN IF NOT EXISTS `trigger` LowCardinality(String) DEFAULT '', | ||
| ADD COLUMN IF NOT EXISTS trigger_detail LowCardinality(String) DEFAULT '', | ||
| ADD COLUMN IF NOT EXISTS turn_key String DEFAULT '', | ||
| ADD COLUMN IF NOT EXISTS parent_tool_use_id String DEFAULT ''; | ||
|
|
||
| --rollback ALTER TABLE ${ANALYTICS_DB_DATABASE_NAME}.cipx_spends ON CLUSTER '{cluster}' DROP COLUMN IF EXISTS `trigger`, DROP COLUMN IF EXISTS trigger_detail, DROP COLUMN IF EXISTS turn_key, DROP COLUMN IF EXISTS parent_tool_use_id; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Migration violates required final blank lineThe migration ends immediately after the Want Baz to fix this for you? Activate Fixer You can also update your AI coding guidelines based on this comment by Other fix methodsPrompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commit 79b112a addressed this comment by adding a trailing blank line after the rollback statement. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Malformed attribution silently persisted
metadata.cipx.callaccepts any object, then parses its fourcallfields withasText("")without validation, so malformed values become the empty unknown sentinel or unsupported text and are indistinguishable from genuine unresolved attribution or unusable in downstream spend queries. Should we validate field shapes andtriggeragainst migration 000118’s closed set (user_turn,tool_continuation,subagent,automated,unknown), or normalize malformed values tounknownwhile preserving the row insert and covering each JSON node kind?Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Declining — validating
triggeragainst a closed set would work against what the sibling test in this PR exists to protect.cipx ships to laptops on its own cadence, independently of this service's deploys, so a newer proxy talking to an older backend is the normal state, not an edge case.
triggeris a closed enum as of today; the moment cipx adds a value (a fork trigger is already on the roadmap — OPIK_8026), validating against migration 000118's list would reject or mangle a legitimate value. That is exactly the failureunknownFieldsDoNotRejectTheRowguards against, and dropping the row would lose the spend entirely — spend totals being the one thing that is already correct today.On the normalization half:
asText("")already does it. A null, numeric, object or array node yields"", which is the documented unknown sentinel (see theSpanRow.fromcomment and the 000118 changeset). So malformed input already lands on "unknown" without rejecting the row.You're right that this makes malformed values indistinguishable from genuinely unresolved attribution. That's deliberate and stated:
""means unknown, and a guessed agent name would book real spend against an agent that never ran. Distinguishing "the proxy could not resolve this" from "the proxy sent something we could not parse" would need a separate signal on the wire, not a decision made at parse time here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification—forward compatibility and the intentional unknown sentinel make sense here. I’ll save this context to memory once the PR is merged.