You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
streamAnthropic hardcodes client creation via internal createClient().
This makes it impossible for extensions to reuse the streaming logic with
Anthropic-compatible clients that need their own auth and URL handling
but share the same Messages API.
Without this, an extension must reimplement streamAnthropic's event loop, buildParams, convertMessages, convertTools, mapStopReason, cache
control, and abort handling (~400 lines). PR #1157 took that approach and
was correctly rejected — the duplication was the problem, not the idea.
Proposed change: add one optional field to AnthropicOptions:
When client is provided, createClient() is skipped and isOAuthToken
is forced to false (disabling Claude Code identity headers and tool name
remapping — correct for non-OAuth credentials). Everything else runs unchanged.
When not provided: zero behavior change.
This keeps core minimal — no new dependencies, no new provider code.
For example, an extension for Google Vertex AI could use Anthropic's @anthropic-ai/vertex-sdk, which extends the base Anthropic class
with the same messages.stream() API but uses Google ADC auth and
rewrites URLs to the Vertex endpoint. The extension would create
the client, inject it via this option, and get full streaming reuse.
The heavy dependencies (@anthropic-ai/vertex-sdk, google-auth-library)
would stay in the extension's package.json, not in core.
Example: how an extension would use this
importAnthropicVertexfrom"@anthropic-ai/vertex-sdk";import{typeAnthropicOptions,typeModel,createAssistantMessageEventStream,streamAnthropic,}from"@mariozechner/pi-ai";// AnthropicVertex extends Anthropic — same messages.stream() API,// but handles Google ADC auth and Vertex URL rewriting internally.constvertexClient=newAnthropicVertex({projectId: process.env.GOOGLE_CLOUD_PROJECT,region: process.env.GOOGLE_CLOUD_LOCATION,});functionstreamVertexAnthropic(model,context,options){conststream=createAssistantMessageEventStream();(async()=>{try{// Inject the Vertex client — streamAnthropic reuses 100% of its// streaming, message conversion, params building, and error handling.constopts: AnthropicOptions={
...base,client: vertexClient,};constinnerStream=streamAnthropic(model,context,opts);forawait(consteventofinnerStream)stream.push(event);stream.end();}catch(error){// ... error handling ...}})();returnstream;}// Register as extension — heavy deps stay in extension package.jsonexportdefaultfunction(pi){pi.registerProvider("anthropic-vertex",{models: VERTEX_MODELS,streamSimple: streamVertexAnthropic,});}
Without the client option, streamVertexAnthropic would need to
reimplement everything streamAnthropic does internally (~400 lines).
With it, the extension is ~30 lines of glue code.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
streamAnthropichardcodes client creation via internalcreateClient().This makes it impossible for extensions to reuse the streaming logic with
Anthropic-compatible clients that need their own auth and URL handling
but share the same Messages API.
Without this, an extension must reimplement
streamAnthropic's event loop,buildParams,convertMessages,convertTools,mapStopReason, cachecontrol, and abort handling (~400 lines). PR #1157 took that approach and
was correctly rejected — the duplication was the problem, not the idea.
Proposed change: add one optional field to
AnthropicOptions:And one conditional in
streamAnthropic:When
clientis provided,createClient()is skipped andisOAuthTokenis forced to
false(disabling Claude Code identity headers and tool nameremapping — correct for non-OAuth credentials). Everything else runs unchanged.
When not provided: zero behavior change.
This keeps core minimal — no new dependencies, no new provider code.
For example, an extension for Google Vertex AI could use Anthropic's
@anthropic-ai/vertex-sdk, which extends the baseAnthropicclasswith the same
messages.stream()API but uses Google ADC auth andrewrites URLs to the Vertex endpoint. The extension would create
the client, inject it via this option, and get full streaming reuse.
The heavy dependencies (
@anthropic-ai/vertex-sdk,google-auth-library)would stay in the extension's
package.json, not in core.Example: how an extension would use this
Without the
clientoption,streamVertexAnthropicwould need toreimplement everything
streamAnthropicdoes internally (~400 lines).With it, the extension is ~30 lines of glue code.
Beta Was this translation helpful? Give feedback.
All reactions