Skip to content

feat(ai): capture model calls with Rudimint - #855

Merged
urjitc merged 2 commits into
mainfrom
feat/rudimint-capture
Oct 12, 2026
Merged

urjitc merged 2 commits into
mainfrom
feat/rudimint-capture

Conversation

@urjitc

@urjitc urjitc commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

ThinkEx's model calls aren't recorded anywhere we can evaluate or train on: PostHog keeps metadata, and content only with analytics consent. This routes every model call through Rudimint, which forwards it to Vercel AI Gateway unchanged and keeps a copy of the request and response.

How it works

flowchart LR
    TX[ThinkEx Worker] -->|same AI SDK request + x-rudimint-* headers| R[api.rudimint.com/vercel]
    R -->|forwarded unchanged| V[Vercel AI Gateway]
    V --> P[OpenAI / Anthropic / Google]
    P --> V --> R -->|streamed back| TX
    R -.->|copy after the response| S[(Rudimint)]
Loading
  • One place. Every call already builds its model in getWorkspaceAiLanguageModelForGatewayModel (src/features/workspaces/ai/gateway.ts). When RUDIMINT_KEY is set, createGateway gets Rudimint's base URL and headers; without it, calls go to Vercel exactly as before. Vercel's key, BYOK routing, fallbacks and streaming are untouched.
  • Tags. Each call says what it is:
Call task session user metadata
Chat turn chat thread id user id workspace, turn trace id, model
Compaction chat-compaction thread id user id same
Thread title chat-title thread id user id same
Image to markdown image-to-markdown — — workspace, item

Evals and the probe script stay untagged.

Rollout

  • Add RUDIMINT_KEY (a key from the ThinkEx tenant in Rudimint) to Infisical for each environment. It's optional on purpose: merging before the key exists changes nothing.
  • Content is captured for every user, regardless of the analytics cookie choice. ThinkEx's privacy policy should list Rudimint as a processor alongside Vercel and PostHog.

Validation

  • Typecheck, lint and the AI tests (51) pass.
  • Not yet exercised against the live Rudimint gateway; the first calls after the key is set will show up in Rudimint's admin under the ThinkEx tenant.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

View guided diff

Summary by CodeRabbit

  • Improvements
    • AI chat replies, title generation, conversation compaction, and image-to-markdown processing can include task and workspace context in request tracking when configured.
    • Chat requests can also be associated with a shared session and user for easier monitoring.
  • Documentation
    • The privacy policy now explains that AI requests and responses pass through Rudimint, which retains copies for model evaluation and improvement.

When RUDIMINT_KEY is set, every Vercel AI Gateway call goes through
Rudimint's gateway, which forwards it unchanged and keeps a copy for
evaluation and training. Calls are tagged with their task, the thread as the
session, the user, and the workspace, turn and model as metadata. Without the
key, calls go straight to Vercel as before.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-12T05:36:06.064539Z 7ee8393 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c14ef7d0-1ded-4ec3-8bea-5c273b16ba4d

📥 Commits

Reviewing files that changed from the base of the PR and between 7ee8393 and 70b8589.


📒 Files selected for processing (4)
  • src/features/workspaces/ai/chat/chat-endpoint.ts
  • src/routes/privacy.tsx
  • worker-configuration.d.ts
  • wrangler.jsonc

 _____________________________________________
< Code Wars Episode I: The Phantom Reference. >
 ---------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
📝 Walkthrough
📝 Walkthrough

Walkthrough

AI model creation now accepts optional Rudimint capture data. Chat, thread-title, and image-to-markdown generation provide task-specific capture data, which the gateway uses when a Rudimint key is available.

Changes

AI generation capture

Layer / File(s) Summary
Gateway capture configuration
src/features/workspaces/ai/gateway.ts
Gateway model creation accepts optional capture data. When a Rudimint key is available, it applies the Rudimint URL and key header, along with supplied capture headers. Thread-title generation forwards optional capture data.
Generation call-site capture
src/features/workspaces/ai/chat/chat-endpoint.ts, src/features/workspaces/extraction/providers/gemini-image-markdown.ts
Chat compaction, thread-title, and chat reply generation supply task, thread session, user, workspace, turn trace ID, and resolved model ID capture data. Image-to-markdown generation supplies its task and workspace/item metadata.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Feature



Merge Risk: ⚪ Minimal · up to 7ee83

No confirmed issue blocks merging. The meaning of the captured model metadata remains unclear.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: capturing AI model calls with Rudimint.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.



  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR




🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 70b8589.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔇 Additional comments (1)
src/features/workspaces/ai/chat/chat-endpoint.ts-201-201 (1)

201-201: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

⚠️ Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.

Record the compaction model in compaction capture metadata.

When a turn selects a model other than "gemini", capture("chat-compaction") still records the selected chat modelId. The compaction call at Line 237 uses AI_CHAT_COMPACTION_MODEL_ID instead. Pass the compaction model ID to the capture callback so Rudimint records the model used for that call.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1e791028-2d91-4c64-8ff2-5e0603ae724a
📥 Commits

Reviewing files that changed from the base of the PR and between 29cdda4 and 7ee8393.

📒 Files selected for processing (3)
  • src/features/workspaces/ai/chat/chat-endpoint.ts
  • src/features/workspaces/ai/gateway.ts
  • src/features/workspaces/extraction/providers/gemini-image-markdown.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ee83938fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/workspaces/ai/gateway.ts
Comment thread src/features/workspaces/ai/gateway.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

const key = (env as { RUDIMINT_KEY?: string }).RUDIMINT_KEY ?? process.env.RUDIMINT_KEY;

P1 Badge Declare RUDIMINT_KEY in Wrangler

When the key is supplied through the documented Infisical or local-dev paths, it still cannot reach this lookup: docs/ENVIRONMENT.md:25-29 states that wrangler.jsonc's secrets.required lists are the source of truth and undeclared variables are silently ignored, but RUDIMINT_KEY is absent from the root, staging, and production lists. Consequently getRudimintGatewaySettings returns {} and every model call continues directly to Vercel, making the feature a no-op after the documented rollout; declare the secret in every environment and regenerate the Worker types.

AGENTS.md reference: AGENTS.md:L7-L9


// Rudimint forwards each call to Vercel AI Gateway unchanged and keeps a copy for
// evaluation and training. Without RUDIMINT_KEY, calls go to Vercel directly.

P1 Badge Disclose unconditional Rudimint capture before shipping

Once RUDIMINT_KEY is enabled, this sends every model request and response to a new processor that keeps a copy for evaluation and training, regardless of analytics consent. That contradicts the shipped policy in src/routes/privacy.tsx:22, which says prompts, responses, tool inputs, and tool outputs enter AI diagnostics only after explicit consent, while its provider list at line 38 also omits Rudimint. Update the user-facing policy in this commit, or preserve the promised consent gate, before enabling capture.

AGENTS.md reference: AGENTS.md:L10-L12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cubic-dev-ai cubic-dev-ai 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.

5 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/workspaces/ai/chat/chat-endpoint.ts">

<violation number="1" location="src/features/workspaces/ai/chat/chat-endpoint.ts:197">
P2: Rudimint captures and retains full request/response content for every chat turn, compaction summary, and title generation, even when the user opted out of analytics content capture. The existing telemetry on the lines above this one gates content behind `analyticsConsent` (`includeContent: analyticsConsent` in `captureAiChatGeneration`), but this new path has no equivalent gate, so opt-out users' conversation content is copied to a third party whenever `RUDIMINT_KEY` is configured. Gate `capture` on `analyticsConsent` (or add an explicit consent/PII-handling step before rollout) rather than relying only on the planned privacy-policy update.</violation>

<violation number="2" location="src/features/workspaces/ai/chat/chat-endpoint.ts:201">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

Rudimint receives the session's `modelId` for compaction and title calls, even though those calls use `AI_CHAT_COMPACTION_MODEL_ID` and `AI_THREAD_TITLE_GATEWAY_MODEL`. Pass the actual gateway model into each capture so the recorded model matches the call.</violation>

<violation number="3" location="src/features/workspaces/ai/chat/chat-endpoint.ts:237">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

The new Rudimint capture plumbing is untested: no regression test verifies that chat, compaction, or title calls propagate the task/session/user/metadata headers when `RUDIMINT_KEY` is set. Add a focused gateway/model test that asserts those settings without calling the live Rudimint service.</violation>
</file>

<file name="src/features/workspaces/extraction/providers/gemini-image-markdown.ts">

<violation number="1" location="src/features/workspaces/extraction/providers/gemini-image-markdown.ts:42">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

The new Rudimint capture for image extraction has no regression test: no test asserts that `task` and the workspace/item metadata reach the configured gateway headers. Add a gateway/provider test covering the `RUDIMINT_KEY` path and these values.</violation>
</file>

<file name="src/features/workspaces/ai/gateway.ts">

<violation number="1" location="src/features/workspaces/ai/gateway.ts:159">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

The new Rudimint routing and capture headers have no regression test. Add tests through the exported model factory for enabled routing and the unchanged Vercel fallback when `RUDIMINT_KEY` is absent.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread src/features/workspaces/ai/chat/chat-endpoint.ts
Comment thread src/features/workspaces/ai/chat/chat-endpoint.ts Outdated
Comment thread src/features/workspaces/ai/gateway.ts
Comment thread src/features/workspaces/ai/chat/chat-endpoint.ts
@greptile-apps

greptile-apps Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium impact] Adds optional telemetry capture to AI model calls.

No blocking issue was established; the remaining concerns are non-blocking local capture configuration and regression coverage gaps.

Fix All in CursorFindings

  1. P2 Local capture stays disabled ▶
  2. P2 Capture routing has no tests ▶

T-Rex evidence

Commands for the before and after capture runs

  • The executed shell script runs both revisions and records each command, working directory, exit code, and observed output, making the comparison reproducible.

Local environment-loading test source

  • The executed runner starts actual Cloudflare/Vite Workers with file-only, shell-only, and allow-list-control configurations, isolating whether the capture key reaches the gateway.

Temporary request handler and gateway interception source

  • The executed handler invokes the real gateway model and records outbound requests while returning simulated responses, proving routing without paid calls.

Before-change responses and gateway destinations

  • The parent gateway was executed in three local environment scenarios with captured source and HTTP responses, establishing direct-Vercel behavior before capture was introduced.

After-change responses with missing and allow-listed capture keys

  • The PR-head gateway was executed in the same three scenarios and only selected Rudimint after the temporary allow-list change, confirming the local configuration defect.

Baseline tests and offline gateway requests

  • Ran the existing AI tests and four intercepted model requests against the pre-change gateway source; all 51 tests passed and every request used the direct Vercel destination.

Head tests and offline capture-routing requests

  • Ran the same tests and requests against head; existing tests never entered the capture switch although the separate probe exercised keyed routing and optional headers.

Before-and-after validation runner

  • Executed this runner for baseline and head to capture commands, exit codes, source, test cases, instrumentation counts, and intercepted responses; the evidence is reproducible.

Gateway entry instrumentation used with existing tests

  • Loaded the selected revision of gateway.ts in memory and instrumented factory and switch entry while retaining the existing test projects; production source remained unchanged.

Offline routing and capture-header probe

  • Invoked the actual gateway model factory and SDK generation path for four scenarios while replacing fetch with captured HTTP 200 OK fixtures; no upstream calls occurred.

Evidence from the check

  • The executed shell script runs both revisions and records each command, working directory, exit code, and observed output, making the comparison reproducible.

Evidence from the check

  • The executed runner starts actual Cloudflare/Vite Workers with file-only, shell-only, and allow-list-control configurations, isolating whether the capture key reaches the gateway.

Evidence from the check

  • The executed handler invokes the real gateway model and records outbound requests while returning simulated responses, proving routing without paid calls.

Command output from the check

  • The parent gateway was executed in three local environment scenarios with captured source and HTTP responses, establishing direct-Vercel behavior before capture was introduced.

Command output from the check

  • The PR-head gateway was executed in the same three scenarios and only selected Rudimint after the temporary allow-list change, confirming the local configuration defect.

Command output from the check

  • Ran the existing AI tests and four intercepted model requests against the pre-change gateway source; all 51 tests passed and every request used the direct Vercel destination.

Command output from the check

  • Ran the same tests and requests against head; existing tests never entered the capture switch although the separate probe exercised keyed routing and optional headers.

Evidence from the check

  • Executed this runner for baseline and head to capture commands, exit codes, source, test cases, instrumentation counts, and intercepted responses; the evidence is reproducible.

Evidence from the check

  • Loaded the selected revision of gateway.ts in memory and instrumented factory and switch entry while retaining the existing test projects; production source remained unchanged.

Evidence from the check

  • Invoked the actual gateway model factory and SDK generation path for four scenarios while replacing fetch with captured HTTP 200 OK fixtures; no upstream calls occurred.

View artifacts

Summary

Routes model calls through Rudimint when RUDIMINT_KEY is available.

  • ThinkEx model calls can now be captured through Rudimint.

Acknowledged intent from urjitc: compaction and title calls share the turn's model metadata. The PR description explicitly says they use the same metadata.

Acknowledged intent from urjitc: Rudimint forwards calls to Vercel with the existing key. No unauthorized disclosure was established.

Acknowledged intent from urjitc: content is captured for every user regardless of the analytics cookie choice, as explicitly stated in the rollout description.

No blocking issue was established. These two non-blocking follow-ups do not prevent merging.

Reviews (1) · Last reviewed commit: "feat(ai): capture model calls with Rudim..." · Reviewed by Greptile

Comment thread src/features/workspaces/ai/gateway.ts
Comment thread src/features/workspaces/ai/gateway.ts
- Declare RUDIMINT_KEY in every secrets.required list so the Worker and
  local dev actually receive it.
- Drop modelId from capture metadata; Rudimint records the model each call
  actually used, which differs for compaction and titles.
- Name Rudimint in the privacy policy's providers and AI sections.

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/routes/privacy.tsx">

<violation number="1" location="src/routes/privacy.tsx:42">
P2: This claims every AI request and response passes through Rudimint, but recording transcription calls Cloudflare Workers AI directly. Limit the disclosure to Vercel AI Gateway requests and note that Rudimint is used when configured.</violation>
</file>

<file name="src/features/workspaces/ai/chat/chat-endpoint.ts">

<violation number="1" location="src/features/workspaces/ai/chat/chat-endpoint.ts:201">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

The PR description still claims chat, compaction, and title Rudimint metadata includes `model`, but `capture` now sends only `workspaceId` and `traceId` in `x-rudimint-metadata`. Update the table to say model attribution is recorded from the request separately; do not re-add `modelId` to this session metadata.</violation>
</file>

Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.

View guided diff | Re-trigger cubic

Comment thread src/features/workspaces/ai/chat/chat-endpoint.ts
Comment thread src/routes/privacy.tsx
@urjitc
urjitc merged commit 036dad7 into main Oct 12, 2026
8 of 9 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Dev Board Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant