Skip to content

feat: add decision-model-backed tool discovery - #522

Open
danieljvdm wants to merge 4 commits into
dan/add-jev-tool-call-supportfrom
dan/decision-tool-discovery
Open

danieljvdm wants to merge 4 commits into
dan/add-jev-tool-call-supportfrom
dan/decision-tool-discovery

Conversation

@danieljvdm

@danieljvdm danieljvdm commented Sep 17, 2026

Copy link
Copy Markdown
Owner

When an agent's initial shortlist misses a capability, discover_tools can now rank the eligible catalogue semantically through the same provider-neutral DecisionModel used by initial selection. This PR is stacked on #520.

const discovery = ToolDiscovery.fromDecisionModel({
  minimumRelevance: 0.5,
  maxResults: 8,
});

// Register discovery.tool with the business tools. DecisionLive can be JEV
// or another DecisionModel implementation.
const handlers = discovery.handlers.pipe(Layer.provide(DecisionLive));
sequenceDiagram
    participant Agent
    participant Discovery as discover_tools
    participant Model as DecisionModel
    participant Runtime
    Agent->>Discovery: Capability query, optional namespace
    Discovery->>Model: Bounded query + eligible metadata
    Model-->>Discovery: Independent relevance probabilities
    Discovery-->>Runtime: Bounded tool documentation + native names
    Runtime-->>Agent: Activate selected schemas next turn
Loading

ToolSelector and semantic discovery share relevance ranking and stable tie-breaking. Discovery projects only its query and optional namespace, excludes itself, and retains the existing authority checks, schema/documentation budgets, pins, and next-turn replacement semantics. Empty catalogues skip evaluation; no matches return an empty selection. Provider errors and declared observer failures remain typed, and the host owns deadlines and separately billed decision usage. Keyword search remains available through ToolDiscovery.make; semantic search does not silently fall back to it.

The opt-in benchmark now compares the fixed/JEV initial-selector × keyword/JEV discovery matrix with full-catalogue controls and experimental stable-catalogue OpenAI transport. The latter keeps all 50 business definitions plus discovery in a fixed order and changes native allowed_tools; runtime exposure checks still enforce the active subset. Separate variants append persistent availability messages, preserving earlier messages when the callable subset changes. This transport remains benchmark-only; it is not a new framework API.

Measured 560 agent attempts: seven synthetic tasks × ten configurations × four repetitions × two context sizes. The tasks include paraphrases, two deliberate initial omissions, and a four-record dependent chain. All shortlist configurations start with eight business tools plus discovery. The reference context adds about 3,342 tokens of identical synthetic archive material; business handlers remain local, read-only fixtures with uniform schemas. All attempts, including policy-limit failures, contribute to costs and latency.

The model is gpt-6-astra, low reasoning, default service tier, store=false, 2,048 maximum output tokens, no retries. Agent arms share unsalted prefixes and run serially in rotated order. “Warm” means repetitions 2–4 after every task/configuration has run once; it does not mean an isolated cache namespace. Short-context availability variants were added after observing raw-stable failures and ran later than the controls; their latency comparisons are exploratory.

Reference context: all configurations, costs, latency and warm-up sensitivity
Configuration Pass Mean (P90), s $ / attempt Cached input Warm $ / attempt (pass)
All 50 28/28 5.25 (8.98) $0.0202 98.5% $0.0177 (21/21)
Fixed 8 + keyword discovery 28/28 7.83 (13.35) $0.0421 89.5% $0.0264 (21/21)
JEV 8 + keyword discovery 27/28 7.99 (13.46) $0.0395 89.1% $0.0307 (20/21)
Fixed 8 + JEV discovery 28/28 7.63 (12.76) $0.0328 92.9% $0.0209 (21/21)
JEV 8 + JEV discovery 28/28 7.53 (14.96) $0.0332 90.5% $0.0203 (21/21)
All 50 + discovery 28/28 5.43 (9.43) $0.0206 98.5% $0.0181 (21/21)
Stable definitions; fixed 8 + JEV 6/28 14.21 (25.16) $0.0465 99.4% $0.0463 (3/21)
Stable definitions; JEV 8 + JEV 16/28 10.44 (25.25) $0.0344 99.5% $0.0345 (12/21)
Stable + availability message; fixed 8 + JEV 28/28 7.96 (15.35) $0.0303 98.7% $0.0296 (21/21)
Stable + availability message; JEV 8 + JEV 28/28 6.86 (15.35) $0.0266 98.8% $0.0259 (21/21)
Short context: all configurations, costs, latency and warm-up sensitivity
Configuration Pass Mean (P90), s $ / attempt Cached input Warm $ / attempt (pass)
All 50 28/28 5.03 (9.77) $0.0098 98.2% $0.0087 (21/21)
Fixed 8 + keyword discovery 27/28 7.55 (12.32) $0.0341 13.2% $0.0344 (20/21)
JEV 8 + keyword discovery 24/28 6.92 (13.26) $0.0286 23.2% $0.0271 (18/21)
Fixed 8 + JEV discovery 28/28 6.96 (13.61) $0.0294 9.7% $0.0289 (21/21)
JEV 8 + JEV discovery 28/28 6.14 (12.99) $0.0261 12.1% $0.0261 (21/21)
All 50 + discovery 28/28 5.05 (8.54) $0.0102 98.3% $0.0090 (21/21)
Stable definitions; fixed 8 + JEV 5/28 12.98 (24.69) $0.0245 98.9% $0.0241 (4/21)
Stable definitions; JEV 8 + JEV 16/28 9.37 (22.42) $0.0179 99.3% $0.0177 (12/21)
Stable + availability message; fixed 8 + JEV 28/28 7.48 (15.14) $0.0172 97.2% $0.0165 (21/21)
Stable + availability message; JEV 8 + JEV 28/28 6.63 (14.87) $0.0158 96.5% $0.0153 (21/21)

For reference-context JEV selection/discovery, stable definitions plus availability messages change all-attempt cost from $0.0332 to $0.0266, but warmed cost changes from $0.0203 to $0.0259. Repeated physical subsets can reuse earlier prefixes: the all-attempt result is not a steady-state savings claim. Raw allowed_tools configurations also frequently looped instead of discovering a missing capability; explicit availability messages changed that behavior. A representative rare-tool attempt called the customer-profile tool six times, while the availability variant discovered and executed the required retention-exception lookup.

A separate cache probe isolates transport from agent behavior: 48 independently salted trials / 192 OpenAI requests, all passing. Each trial starts with zero cached-read tokens, then makes four identical shipping requests. A/A/A/A holds eight physical definitions fixed; A/B/C/A changes the callable eight while keeping the required shipping tool present. Costs below include the cold request and cache writes. No handlers or JEV calls run in the probe.

Definition strategy Short: $ / four requests Reference: $ / four requests
Fixed eight, A/A/A/A $0.01900 $0.06479
Changing eight, A/B/C/A $0.01898 $0.14719
Stable 50 with allowed eight, A/B/C/A $0.03821 $0.08998

The experiment made 2,381 OpenAI calls and 461 JEV calls. Returned usage accounts for an estimated $18.1426, including $0.0853 JEV; no usage or cache-write counters are missing. Estimates use OpenAI standard pricing and JEV input pricing, including cache writes, reads and all failed attempts. Four repetitions per synthetic task do not establish production reliability or tail latency. Fresh conversations with heterogeneous tools, remote business-handler latency, native deferred loading and per-turn reranking remain unmeasured.

Measured clean source revisions: 0f3b0e47170575be0db82a725e380e9619d04e29, e1876a95426b0896f6d9db6e426eaf8c30abaed1 (Darwin arm64, Bun 1.4.2). Every paid request has a start/completion checkpoint and captured synthetic request/usage data. The controlled probes substantiate cache preservation; the agent tables measure the additional behavioral and billing tradeoffs.

@danieljvdm
danieljvdm added this pull request to stack #523 September 17, 2026 03:01
@danieljvdm danieljvdm changed the title feat: add decision-model tool discovery and comparison benchmark feat: add decision-model-backed tool discovery Sep 17, 2026
@danieljvdm
danieljvdm marked this pull request as ready for review September 17, 2026 03:02
@github-actions

github-actions Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Bundle size

Fixture Part Base gzip PR gzip Change PR minified
agent-root initial 100.94 kB 100.94 kB 0.00 kB / 0.00% 318.01 kB
agent-module initial 100.76 kB 100.76 kB 0.00 kB / 0.00% 317.52 kB
runtime-root initial 191.90 kB 191.90 kB 0.00 kB / 0.00% 635.72 kB
runtime-module initial 191.34 kB 191.34 kB 0.00 kB / 0.00% 633.92 kB
in-memory-root initial 100.97 kB 100.97 kB 0.00 kB / 0.00% 324.25 kB
in-memory-module initial 100.93 kB 100.93 kB 0.00 kB / 0.00% 324.07 kB
lazy-root initial 192.66 kB 192.66 kB +0.00 kB / +0.00% 637.75 kB
lazy-root deferred 0.08 kB 0.08 kB 0.00 kB / 0.00% 0.07 kB
lazy-root total 192.74 kB 192.74 kB +0.00 kB / +0.00% 637.83 kB
lazy-module initial 144.12 kB 144.12 kB -0.00 kB / -0.00% 458.57 kB
lazy-module deferred 49.17 kB 49.17 kB 0.00 kB / 0.00% 176.08 kB
lazy-module total 193.29 kB 193.29 kB -0.00 kB / -0.00% 634.65 kB

Minified ESM for es2022, browser target, including Effect and other dependencies. Gzip is measured per chunk. Initial includes statically imported shared chunks; deferred is the remaining output. New exports have no prior baseline.

Chunks, module analysis, and exact bytes for 31001efdb6b6.

@effect-agent effect-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect Agent review

Tip

No actionable findings.

Scope Files New findings
Full diff 14 reviewed · 1 ignored ✅ None

Summary

No concrete defects found in the supplied change.

6 model calls · 123,057 input (1,374 uncached · 91,407 cached · 30,276 cache write; 74.3% cache reads) / 738 output tokens · ≈ $1.04 at GPT-6 Astra rates · $20.591580 spending ceiling · inspected at b2c24c4 · 4 automatic reviews remain

@effect-agent effect-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect Agent review

Tip

No actionable findings.

Scope Files New findings
Incremental 8 reviewed ✅ None

Summary

No concrete defects found in the supplied change. Earlier findings remain open unless explicitly verified as addressed; an incremental review does not establish that merging is safe.

6 model calls · 81,889 input (1,374 uncached · 61,812 cached · 18,703 cache write; 75.5% cache reads) / 473 output tokens · ≈ $0.6660 at GPT-6 Astra rates · $20.333980 spending ceiling · inspected at 0f3b0e4 · 3 automatic reviews remain

@effect-agent effect-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect Agent review

Tip

No actionable findings.

Scope Files New findings
Incremental 6 reviewed ✅ None

Summary

No concrete defects found in the supplied change. Earlier findings remain open unless explicitly verified as addressed; an incremental review does not establish that merging is safe.

5 model calls · 56,736 input (1,145 uncached · 41,757 cached · 13,834 cache write; 73.6% cache reads) / 344 output tokens · ≈ $0.4867 at GPT-6 Astra rates · $20.179660 spending ceiling · inspected at e1876a9 · 2 automatic reviews remain

@effect-agent effect-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect Agent review

Tip

No actionable findings.

Scope Files New findings
Incremental 0 reviewed ✅ None

Summary

No pull-request files changed since the last completed review.

No model call · $0.000000 spending ceiling · inspected at 5041735 · 1 automatic review remains

@danieljvdm
danieljvdm force-pushed the dan/decision-tool-discovery branch from 5041735 to 31001ef Compare September 17, 2026 06:23

@effect-agent effect-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect Agent review

Tip

No actionable findings.

Scope Files New findings
Full diff 17 reviewed · 1 ignored ✅ None

Note

Automatic reviews are paused for this pull request.
Further pushes will not start another review. Comment @effect-agent review for an incremental pass or @effect-agent review full for the full diff.

Summary

No concrete defects found in the supplied change.

11 model calls · 313,425 input (2,519 uncached · 273,082 cached · 37,824 cache write; 87.1% cache reads) / 777 output tokens · ≈ $1.62 at GPT-6 Astra rates · $20.887870 spending ceiling · inspected at 31001ef

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant