Skip to content

feat(slack): Route passive replies with a decision model - #2238

Merged
dcramer merged 3 commits into
mainfrom
feat/passive-router-decide
Oct 26, 2026
Merged

dcramer merged 3 commits into
mainfrom
feat/passive-router-decide

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

This moves the passive subscribed-thread reply router from a structured LLM completion to the AI SDK decision API, so it can run on a classifier model such as Jev. Passive routing stays behind the passive-routing experimental flag.

AI SDK 7 upgrade

  • ai 6.0.190 → 7.0.153 and @ai-sdk/gateway 3 → 4.0.126. Both are older than the 24h release quarantine, so no exception is needed.
  • Pi does not depend on the AI SDK. It uses the provider SDKs directly. Only chat/pi/client.ts and tools/web/search.ts import ai, and both typecheck as they are.
  • Gateway 4 moved the base URL from /v3/ai to /v4/ai. I updated the MSW turn-router fixture, the eval web fixture, and the recording-rule comment to match.
  • chat@4.29.0 declares peer ai@^6, but the root ai override already pins one version. Junior does not import chat/ai, and pnpm peers check shows no new problems.

Router

  • New completeDecision in chat/pi/client.ts wraps experimental_decide with gateway.decisionModel(...). It emits a gen_ai.decide span, maps refusals to invalid_response, and estimates cost from gateway input rates: Jev $0.042/M, Luna-decisions $0.10/M, from /v1/models. With the cost estimate, passive_reply_routed events keep recording.
  • The router asks one choice question: reply / stay_quiet / unsubscribe. The policy text is the same Guardian-style floor policy, with outputs renamed to routes. The probability of the chosen route replaces the old self-reported confidence for the 0.7 gate.
  • Decision models return no prose, so reasonDetail is now "<route> p=<prob>" instead of a model-written sentence.
  • New AI_DECISION_MODEL / decisionModelId setting. It defaults to typesafe-ai/jev. openai/gpt-6-luna-decisions is the OpenAI Decisions alternative.

Test bookkeeping

  • check-test-architecture now counts completeDecision: fakes as model fakes, so the baseline counts are unchanged.
  • watched-message-behavior.test.ts dropped under 1,000 lines, so I removed its file-length exception.

Checks run

  • pnpm lint passes. This includes oxlint, depcruise, file-length, and test architecture.
  • pnpm --filter @sentry/junior typecheck and pnpm --filter @sentry/junior-evals typecheck pass.
  • Unit and component tests: 304/305 files passed. The one failure came from an edit during the run, and that file passes when rerun.
  • tests/unit/routing, tests/unit/pi, config tests, and junior-evals harness tests pass.
  • Integration: watched-message-behavior passes 21/21 with --testTimeout=30000. Some agent-reply integration tests in this sandbox time out at the default 5s. These include durable-queue, annotation-cards, event-wake-delay, and bot-image-hydration. They fail the same way on a clean origin/main worktree, and timings are similar on both, so this looks like sandbox slowness, not this change.

Not run

  • Live passive evals (evals/conversation/participation.eval.ts). This sandbox has no ROACH_TOKEN or gateway credentials. The new /v4/ai and decision-model requests need fresh recordings from CI. Comparing pass rates with the old Luna path is the main open item.

via David Cramer.

--

View Junior Session [Sentry]

Upgrade to AI SDK 7 and AI Gateway provider 4, which add
experimental_decide and gateway decision models. Pi does not depend on
the AI SDK, so the upgrade only touches Junior's direct callers and the
gateway URL that tests and evals fake (/v3/ai moved to /v4/ai).

The passive subscribed-thread router now asks one choice question
(reply, stay_quiet, unsubscribe) through completeDecision instead of a
structured LLM completion. The choice probability replaces the
self-reported confidence for the existing 0.7 gate. Decision models
return no prose, so reasonDetail now records the route and probability.

AI_DECISION_MODEL / decisionModelId selects the model. It defaults to
typesafe-ai/jev; openai/gpt-6-luna-decisions also works. Route cost uses
gateway input rates so passive_reply_routed events keep recording.

Co-Authored-By: David Cramer <david@sentry.io>
@vercel

vercel Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
junior-docs Ready Ready Preview Oct 26, 2026 9:01pm UTC

Request Review

@sentry-evals

sentry-evals Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentry Evals

junior-behavioral

Run Status Passed Failed Errored Cost Tokens Duration
Head Failed 73 2 0 $1.02 0 385.28s

Base commit 3757bb4 has no eval run to compare against.

junior-guardian

Run Status Passed Failed Errored Cost Tokens Duration
Head Passed 87 0 0 $0.02 0 24.31s

Base commit 3757bb4 has no eval run to compare against.

junior-integration

Run Status Passed Failed Errored Cost Tokens Duration
Head Passed 101 0 0 $0.97 0 307.92s

Base commit 3757bb4 has no eval run to compare against.

junior-router

Run Status Passed Failed Errored Cost Tokens Duration
Head Passed 12 0 0 $0.00 0 3.60s

Base commit 3757bb4 has no eval run to compare against.

@dcramer
dcramer marked this pull request as ready for review October 26, 2026 19:51
@github-actions github-actions Bot added the risk: high PR risk score: high label Oct 26, 2026
Jev routed plain-name messages to a coworker, such as "Alex, ...",
and follow-ups in that human exchange as replies. The passive
participation evals that stayed quiet on the old router now fail.

State the name-address and human-exchange rules in the policy, and give
the reply and stay_quiet criteria discriminating definitions instead of
restating the route name.
The name-address rule used the same names as the passive evals, and the
human-exchange rule listed the eval phrasings. Keep the general rules and
drop the examples so the evals measure the policy, not memorized cases.

Co-Authored-By: David Cramer <david@sentry.io>
@github-actions

Copy link
Copy Markdown
Contributor

2 screenshot changes — 2 changed · 0 added · 0 removed

Review screenshots in Frameshift

Gallery Chart Input Cache · Desktop
Gallery Chart Input Cache · Desktop
Changed
Workspace Create · Mobile
Workspace Create · Mobile
Changed

@dcramer
dcramer merged commit 30601ca into main Oct 26, 2026
52 checks passed
@dcramer
dcramer deleted the feat/passive-router-decide branch October 26, 2026 21:56

This branch was successfully deployed

1 active deployment
Preview – junior-docs — d5953f80 Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant