Skip to content

feat(providers): prompt caching capability + usage-based cache pricing#5922

Merged
icecrasher321 merged 9 commits into
stagingfrom
fix/openai-live-tool-stream
Jul 24, 2026
Merged

feat(providers): prompt caching capability + usage-based cache pricing#5922
icecrasher321 merged 9 commits into
stagingfrom
fix/openai-live-tool-stream

Conversation

@icecrasher321

@icecrasher321 icecrasher321 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three things, in dependency order:

  • Streaming tool calls and thinking from agent blocks (original scope) — live tool-call chips and thinking for OpenAI, Anthropic, Azure Anthropic, Google, Vertex, DeepSeek, Groq, and Bedrock. Deployed chat is a pure consumer of the stream, gated behind independent includeThinking / includeToolCalls toggles.
  • One pricing function. priceModelUsage in cost-policy.ts is now the only place cache-aware arithmetic happens. Provider adapters normalize their wire shape into ModelUsage; the pricing function never branches on provider.
  • Prompt caching as a capability. Opt-in advanced switch for Anthropic (cache_control breakpoints), always-on prompt_cache_key for OpenAI, billing correctness only for Gemini.

Type of Change

  • New feature
  • Bug fix

Testing

bun run lint, bun run type-check, bun run check:api-validation:strict, bun run check:migrations origin/staging, and the full suite (1111 files / 14478 tests) all pass locally.

New coverage: cross-provider pricing parity (Anthropic's exclusive vs OpenAI's inclusive token shapes must price identically), per-bucket write multipliers, cache_write_tokens parsing and clamping, multi-turn cache accumulation for OpenAI and Gemini, Anthropic breakpoint placement on both the streaming and non-streaming paths, structured-output + caching together, stable/distinct prompt_cache_key, and the two tool-cost invariants.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 24, 2026 9:13pm

Request Review

Keep staging's SSO migration at 0268 and regenerate include_tool_calls as 0269.
@icecrasher321
icecrasher321 marked this pull request as ready for review July 24, 2026 16:48
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

bugbot run

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches public chat streaming, deployment policy migration, and provider billing/caching paths where regressions could leak tool data or mis-price usage; changes are well-tested but span auth-adjacent SSE and cost accounting.

Overview
Deployed chat gains a separate Include tool calls toggle (includeToolCalls in DB/API/UI), with null values grandfathered from includeThinking and PATCH logic so turning thinking off also clears tools when the column was never set.

Agent-events protocol is split: X-Sim-Stream-Protocol only signals client capability (live chunk + chunk_reset); thinking and tools each need their own deployment flag plus the header. shouldEmitAgentStreamEvents is true if either policy is on; protocol response headers echo whenever the client negotiated v1, not when thinking alone is enabled.

Public chat SSE redacts tool arguments/results in final and selected-output chunk paths (sanitizeOutputForEnvelope); authenticated workflow streams keep full tool payloads. Tool frame validation rejects unknown statuses.

Agent block adds an advanced Prompt caching switch for supported Anthropic models; the executor forwards promptCaching and blockId. Anthropic core applies cache_control on system/tools (streaming and non-streaming), aggregates cache read/write tokens into cost, and treats Claude thinking as summary streamed (display: 'summarized' where applicable). Live streaming tool loops no longer depend on a separate streamToolCalls flag.

Billing consistency: evaluator/router/Pi paths use proxied or centralized billable cost instead of recomputing from tokens. Provider streaming responses omit unsettled content from X-Execution-Data. Firecrawl parse preserves creditsUsed on the document output.

Docs and add-model guidance are updated for prompt caching, OpenAI live tools, Anthropic summary thinking, and the new protocol/toggle behavior.

Reviewed by Cursor Bugbot for commit ca00374. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds live agent-event streaming and cache-aware provider pricing.

  • Streams OpenAI and other provider tool-call and thinking events through the agent-events protocol.
  • Separates public-chat thinking and tool-call policies while preserving legacy deployment behavior.
  • Normalizes cache usage across providers and centralizes usage-based pricing.
  • Adds Anthropic prompt-caching controls, OpenAI cache keys, database fields, documentation, and tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failures remain.

Important Files Changed

Filename Overview
apps/sim/providers/openai/streaming-tool-loop.ts Implements a live OpenAI Responses tool loop with start events emitted before execution and end events emitted after completion.
apps/sim/lib/workflows/streaming/agent-stream-protocol.ts Defines the versioned thinking, tool-lifecycle, answer, and reset frames consumed by streaming clients.
apps/sim/providers/cost-policy.ts Centralizes cache-aware model-usage pricing across normalized provider usage shapes.
apps/sim/app/api/chat/[identifier]/route.ts Negotiates agent-event framing and independently applies thinking and tool-call deployment policies.
packages/db/schema.ts Adds persisted provider and chat capability fields with compatibility behavior for existing deployments.
apps/docs/content/docs/en/workflows/blocks/agent.mdx Documents prompt caching and regenerated provider streaming capabilities.

Sequence Diagram

sequenceDiagram
  participant Client
  participant Chat as Chat API
  participant Agent as Agent Executor
  participant OpenAI
  participant Tool
  Client->>Chat: Request with agent-events-v1
  Chat->>Agent: Execute with event policies
  Agent->>OpenAI: Start Responses stream
  OpenAI-->>Agent: response.output_item.added(function_call)
  Agent-->>Client: tool start
  Agent->>Tool: Execute tool call
  Tool-->>Agent: Tool result
  Agent-->>Client: tool end
  Agent->>OpenAI: Continue with tool result
  OpenAI-->>Agent: Final answer deltas
  Agent-->>Client: Answer chunks
Loading

Reviews (5): Last reviewed commit: "refactor(providers): drop unreachable bi..." | Re-trigger Greptile

Comment thread apps/docs/content/docs/en/workflows/blocks/agent.mdx
Comment thread apps/sim/providers/anthropic/core.ts
Replace the arbitrary cached-rate heuristic with a single cache-aware pricing
function, and add prompt caching as an opt-in capability for Anthropic.

Pricing: priceModelUsage in cost-policy.ts is now the only place cache
arithmetic happens. Provider adapters normalize their wire shape into
ModelUsage (input always excludes cache buckets); the pricing function never
branches on provider. This removes five divergent behaviors, including the
!!request.context heuristic that gave Router and Evaluator an unearned 10x
input discount, and the overwrite that silently billed Anthropic cache reads
and writes at zero. Also parses OpenAI cache_write_tokens, previously ignored.

Caching: Anthropic gets a capability-gated advanced switch that places
cache_control on the last tool and last system block; system is now always a
TextBlockParam array. OpenAI gets a stable per-block prompt_cache_key with no
UI, since its caching is automatic.
…ol-stream

# Conflicts:
#	apps/docs/content/docs/en/workflows/blocks/agent.mdx
@icecrasher321 icecrasher321 changed the title feat(providers): validation pass + bugfixes feat(providers): prompt caching capability + usage-based cache pricing Jul 24, 2026
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/providers/openai/streaming-tool-loop.ts Outdated
Comment thread apps/sim/providers/gemini/core.ts
…e pricing

Cache-aware pricing only reached trace segments. The billable block cost still
called calculateCost on the cache-inclusive prompt total, so OpenAI cache hits
and Gemini implicit-cache hits were charged at the full input rate and GPT-5.6+
cache writes went unbilled.

Both providers now accumulate cache buckets and price through priceModelUsage,
matching the Anthropic token convention where input excludes cache reads and
writes. Cached counts are clamped to the prompt total so an over-reporting
payload cannot bill more input than the request contained.
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/workflows/streaming/streaming.ts
Redaction only ran on the empty-selection branch, but a deployment almost
always selects outputs, so it was dead in the case it exists for. Selecting
toolCalls streamed the raw arguments and results to a public chat client in a
chunk frame, and providerTiming carried thinking content the same way.

Both paths now extract from the sanitized block output rather than the raw log:
the streamed selected output, which is the reachable vector, and the final
envelope. Sanitizing the source rather than per selected path means a newly
selectable field cannot reopen the hole.
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit fbca58a. Configure here.

@blacksmith-sh

This comment has been minimized.

Every provider pricing helper took a policy parameter no caller passed. Worse
than dead: passing one would have double-applied the margin the central layer
already applies. Removed, so providers can only price at list.

Also removed guards that cannot fire. The central fallback normalized cache
buckets no provider can reach it with (all three that report cache usage price
themselves) and did so at a 1x write multiplier no vendor charges.
priceModelUsage re-validated token counts the adapter had already clamped, and
applyModelCostPolicy defaulted a required total field.

Validation now happens once, in the adapter that parses the vendor payload and
is the only layer that knows cache buckets are a subset of the prompt total.
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ca00374. Configure here.

@icecrasher321
icecrasher321 merged commit 17d7779 into staging Jul 24, 2026
41 of 44 checks passed
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