Class: Insika::ToolUsageReport
- Inherits:
-
Object
- Object
- Insika::ToolUsageReport
- Defined in:
- lib/insika/tool_usage_report.rb
Overview
The tool AUDIT the per-session trace cannot answer: tool_traces records
every call, but one session at a time, and nothing aggregates — so "which
tools does this agent carry and never use?" had no surface at all. This
report is that surface. Read-only by design: it names the candidates, the
OPERATOR removes (a tool the report flags may still be the one a rare but
critical flow needs).
Attribution rides the task record: a session does not stamp its agent, but every task carries the agent in its command payload — tasks → sessions → tool_traces is the same read the Studio does. Three findings per agent:
never_called — in `tools_allow`, zero calls in any stored trace. Dead
weight: it costs schema tokens on every request and buys
nothing (the pilot's `search_orders` is the known example).
error_rate — called inside the window with > 30% conventional errors
(the trace's own `ok` flag). Either the tool is broken or
the model cannot hold its contract; both are operator work.
stale — called at some point, but not once inside the window.
Bounded and honest: it reads only what the stores kept (the trace caps at 200 entries/session), so a count here is "at least", never an exact total.
Defined Under Namespace
Constant Summary collapse
- WINDOW_DAYS =
14- ERROR_RATE_THRESHOLD =
0.30
Instance Method Summary collapse
-
#generate(days: WINDOW_DAYS, agent: nil) ⇒ Object
-> Report.
-
#initialize(task_store:, tool_trace_store:, profile_source:, now: nil) ⇒ ToolUsageReport
constructor
A new instance of ToolUsageReport.
Constructor Details
#initialize(task_store:, tool_trace_store:, profile_source:, now: nil) ⇒ ToolUsageReport
Returns a new instance of ToolUsageReport.
55 56 57 58 59 60 |
# File 'lib/insika/tool_usage_report.rb', line 55 def initialize(task_store:, tool_trace_store:, profile_source:, now: nil) @task_store = task_store @tool_trace_store = tool_trace_store @profile_source = profile_source @now = now end |
Instance Method Details
#generate(days: WINDOW_DAYS, agent: nil) ⇒ Object
-> Report. agent: narrows to one agent (must still be a stored profile).
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/insika/tool_usage_report.rb', line 63 def generate(days: WINDOW_DAYS, agent: nil) now = @now || Time.now.utc cutoff = now - (days * 24 * 60 * 60) profiles = @profile_source.all_raw profiles = profiles.select { |r| r["id"].to_s == agent.to_s } if agent sessions = sessions_by_agent rows = profiles.flat_map do |record| id = record["id"].to_s stats = tool_stats(sessions[id] || [], cutoff) never_called_rows(id, record, stats) + error_rate_rows(id, stats, days) + stale_rows(id, stats) end Report.new(generated_at: now.iso8601, days: days, agents: profiles.map { |r| r["id"].to_s }.sort, rows: rows.sort_by { |r| [r.agent, r.kind, r.tool] }.freeze) end |