@x-otto/provider 0.1.0-alpha.6 → 0.1.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -12
- package/dist/index.js +4 -4
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -141,13 +141,18 @@ interface WireProtocolLogger {
|
|
|
141
141
|
warn: (objOrMsg: string | Record<string, unknown>, ...args: unknown[]) => void;
|
|
142
142
|
error: (objOrMsg: string | Record<string, unknown>, ...args: unknown[]) => void;
|
|
143
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* `WireProtocolLogger` 的 no-op 默认实现(RFC-185 D3)——宿主未注入 logger 时的缺省值。
|
|
146
|
+
* 单一真源:此前 otto-wire-protocols 三协议 + plugin-github-copilot 各复制一份逐字相同的
|
|
147
|
+
* 定义(4 份),默认实现若需演进(如 debug 门控)要改四处。协议/provider 插件经
|
|
148
|
+
* `@x-otto/provider` 复用此单例,不再复制。
|
|
149
|
+
*/
|
|
150
|
+
declare const noopWireProtocolLogger: WireProtocolLogger;
|
|
144
151
|
interface WireProtocolFactoryInput {
|
|
145
|
-
resolveAuth: () => Promise<
|
|
146
|
-
token: string;
|
|
147
|
-
mode: 'api_key' | 'oauth';
|
|
148
|
-
beta?: string;
|
|
149
|
-
} | undefined>;
|
|
152
|
+
resolveAuth: () => Promise<ResolvedAuth | undefined>;
|
|
150
153
|
resolveBaseUrl: () => Promise<string | undefined>;
|
|
154
|
+
/** 声明式 provider 已在 resolver 内完成进程/配置/凭据优先级,协议层不得再抢先读旧 env。 */
|
|
155
|
+
preferResolvedBaseUrl?: boolean;
|
|
151
156
|
headers?: Record<string, string>;
|
|
152
157
|
tokenDerivedHeaders?: TokenDerivedHeader[];
|
|
153
158
|
/** 请求定制点——厂商个性注入唯一通道(如 plugin-anthropic 的 Claude Code 伪装)。 */
|
|
@@ -238,6 +243,12 @@ interface ResolvedAuth {
|
|
|
238
243
|
/** OAuth 模式下需附带的 beta 头(来源于 OAuthProvider.oauthBeta)。 */
|
|
239
244
|
beta?: string;
|
|
240
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* 统一 baseUrl 解析(env > resolver > model.baseUrl)——三协议此前各写一份,
|
|
248
|
+
* 且 openai-completions 根本没有 env 覆盖层(DEEPSEEK_BASE_URL 静默无效)。
|
|
249
|
+
* 优先级一致:env key 优先、resolver 次之、model.baseUrl 兜底。
|
|
250
|
+
*/
|
|
251
|
+
declare function resolveProviderBaseUrl(envKey: string, resolver: (() => Promise<string | undefined>) | undefined, modelBaseUrl: string, preferResolver?: boolean): Promise<string>;
|
|
241
252
|
//#endregion
|
|
242
253
|
//#region src/provider/chat-completions.d.ts
|
|
243
254
|
declare function buildChatCompletionsMessages(context: StreamContext): unknown[];
|
|
@@ -687,12 +698,6 @@ declare function DeviceFlowOAuthTemplate(params: DeviceFlowOAuthTemplateParams):
|
|
|
687
698
|
* Header dump:debug 级别输出全部响应头 key+value,供实证分析。
|
|
688
699
|
*/
|
|
689
700
|
declare function extractStandardRateLimitHeaders(headers: Headers | undefined): ProviderUsageSnapshot | null;
|
|
690
|
-
/**
|
|
691
|
-
* @deprecated 改名为 {@link extractStandardRateLimitHeaders}(终局架构 review
|
|
692
|
-
* 2026-07-21:函数只解析厂商无关的标准 x-ratelimit-* 头族,"OpenAi" 后缀具有误导性)。
|
|
693
|
-
* 保留别名过渡,下个大版本移除。
|
|
694
|
-
*/
|
|
695
|
-
declare const extractProviderUsageFromOpenAiHeaders: typeof extractStandardRateLimitHeaders;
|
|
696
701
|
//#endregion
|
|
697
702
|
//#region src/stream-errors.d.ts
|
|
698
703
|
/**
|
|
@@ -861,5 +866,5 @@ declare class ReplayProviderStream implements ProviderStream {
|
|
|
861
866
|
}
|
|
862
867
|
declare function createReplayProviderFactory(filePath: string, options?: ReplayOptions): () => ProviderStream;
|
|
863
868
|
//#endregion
|
|
864
|
-
export { type Api, type AssistantContent, type AssistantMessage, type AssistantMessageMeta, type AuthErrorType, type AuthMode, type CacheRetention, type ChatCompletionsStreamParams, type ContentPart, DeviceFlowOAuthTemplate, type DeviceFlowOAuthTemplateParams, type FlatStreamState, type FlatToolCallAcc, type ImageContent, type LoopbackCallback, type LoopbackServer, type LoopbackServerOptions, type Message, type Model, type OAuthCredentials, type OAuthInfo, type OAuthLoginOptions, type OAuthPrompt, type OAuthProvider, type OAuthProviderFactory, type OAuthProviderId, type OAuthRefreshTokenOptions, PKCEOAuthTemplate, type PKCEOAuthTemplateParams, type PkcePair, type Provider, type ProviderFactory, type ProviderStream, REPLAY_API, type Recording, type RecordingHeader, type RecordingLine, type ReplayOptions, ReplayProviderStream, type RequestHeaderSources, type ResolvedAuth, type StopReason, type StreamBlock, type StreamContext, type StreamErrorClass, type StreamEvent, type StreamFunction, type StreamOptions, type StreamUsage, type SystemPromptSegment, type TextContent, type ThinkingContent, type TokenDerivedHeader, type ToolCall, type ToolDefinition, type ToolResultMessage, type UserMessage, type WireProtocolFactoryInput, type WireProtocolLogger, type WireProtocolMeta, type WireProtocolRegistration, type WireRequestCustomization, type WireRequestCustomizeInput, type WireSystemTextBlock, assembleAssistantMessage, assertSystemNotificationPlacement, blocksContent, buildChatCompletionsBody, buildChatCompletionsMessages, buildReplayModel, buildRequestHeaders, clampThinkingLevel, classifyAuthErrorType, classifyStreamError, createPkcePair, createReplayProviderFactory, degradedSystemNotificationText, extractAbortKind, extractAnthropicRateLimit, extractJwtClaim,
|
|
869
|
+
export { type Api, type AssistantContent, type AssistantMessage, type AssistantMessageMeta, type AuthErrorType, type AuthMode, type CacheRetention, type ChatCompletionsStreamParams, type ContentPart, DeviceFlowOAuthTemplate, type DeviceFlowOAuthTemplateParams, type FlatStreamState, type FlatToolCallAcc, type ImageContent, type LoopbackCallback, type LoopbackServer, type LoopbackServerOptions, type Message, type Model, type OAuthCredentials, type OAuthInfo, type OAuthLoginOptions, type OAuthPrompt, type OAuthProvider, type OAuthProviderFactory, type OAuthProviderId, type OAuthRefreshTokenOptions, PKCEOAuthTemplate, type PKCEOAuthTemplateParams, type PkcePair, type Provider, type ProviderFactory, type ProviderStream, REPLAY_API, type Recording, type RecordingHeader, type RecordingLine, type ReplayOptions, ReplayProviderStream, type RequestHeaderSources, type ResolvedAuth, type StopReason, type StreamBlock, type StreamContext, type StreamErrorClass, type StreamEvent, type StreamFunction, type StreamOptions, type StreamUsage, type SystemPromptSegment, type TextContent, type ThinkingContent, type TokenDerivedHeader, type ToolCall, type ToolDefinition, type ToolResultMessage, type UserMessage, type WireProtocolFactoryInput, type WireProtocolLogger, type WireProtocolMeta, type WireProtocolRegistration, type WireRequestCustomization, type WireRequestCustomizeInput, type WireSystemTextBlock, assembleAssistantMessage, assertSystemNotificationPlacement, blocksContent, buildChatCompletionsBody, buildChatCompletionsMessages, buildReplayModel, buildRequestHeaders, clampThinkingLevel, classifyAuthErrorType, classifyStreamError, createPkcePair, createReplayProviderFactory, degradedSystemNotificationText, extractAbortKind, extractAnthropicRateLimit, extractJwtClaim, extractRetryAfterMs, extractStandardRateLimitHeaders, flatContent, generateChallenge, generateState, generateVerifier, hasTrailingInvokeXml, initFlatStreamState, initStreamUsage, isAuthError, isContextOverflowError, isNetworkDisconnectError, loadRecording, mapChatFinishReason, mergeConsecutiveSystemNotifications, noopWireProtocolLogger, parseToolArguments, parseToolArgumentsWithStatus, recordStream, recordingsDir, recoverLiteralInvokeToolCalls, registeredToolNames, replayStream, resolveProviderBaseUrl, sanitizeSurrogates, sanitizeToolRoundtrips, startLoopbackServer, streamChatCompletions, toJsonSchema, toolCallFromParsed };
|
|
865
870
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{normalizeImageData as e}from"@x-otto/interchange";import{OAuthError as t,ProviderError as n,createLogger as r,createPkcePair as i,
|
|
1
|
+
import{normalizeImageData as e}from"@x-otto/interchange";import{OAuthError as t,ProviderError as n,createLogger as r,createPkcePair as i,createPkcePair as a,generateChallenge as o,generateState as s,generateVerifier as c,headerGet as l,startLoopbackServer as u,startLoopbackServer as d,stream as f}from"@x-otto/shared";import{createWriteStream as p,mkdirSync as m}from"node:fs";import{readFile as h}from"node:fs/promises";import{join as g}from"node:path";const _={debug:()=>{},info:()=>{},warn:()=>{},error:()=>{}};async function v(e,t,n,r=!1){if(r&&t){let e=await t();if(e)return e}let i=process.env[e];if(i)return i;if(t){let e=await t();if(e)return e}return n}const y=r(`@x-otto/provider:tool-roundtrip`);function b(e){let t=[],n=[],r=()=>{for(let e of n)y.warn({toolCallId:e.id,toolName:e.name},`Synthesizing placeholder for unanswered tool_call`),t.push(x(e));n=[]};for(let i of e){if(i.role===`tool_result`){let e=n.findIndex(e=>e.id===i.toolCallId);if(e===-1){y.warn({toolCallId:i.toolCallId,toolName:i.toolName},`Dropping orphan tool_result with no preceding tool_call`);continue}n.splice(e,1),t.push(i);continue}r(),t.push(i),i.role===`assistant`&&(n=i.content.filter(e=>e.type===`tool_call`))}return r(),t}function x(e){return{role:`tool_result`,toolCallId:e.id,toolName:e.name,content:[{type:`text`,text:`[tool result unavailable]`}],details:void 0,isError:!0,timestamp:0}}function S(e){return`[System notification] ${e}`}function C(e){let t=[];for(let n of e){let e=t.at(-1);if(n.role===`system_notification`&&e?.role===`system_notification`){t[t.length-1]={...e,content:`${e.content}\n${n.content}`,isError:e.isError||n.isError};continue}t.push(n)}return t}function ee(e){for(let t=0;t<e.length;t++){let n=e[t];if(n.role!==`system_notification`)continue;let r=t>0?e[t-1]:void 0;r!==void 0&&(r.role===`tool_result`||r.role===`assistant`)||y.warn({index:t,relatedToolCallId:n.relatedToolCallId,precedingRole:r?.role??`(start of array)`},`system_notification message does not immediately follow a tool_result/assistant turn (Anthropic placement rule violation risk) — sending anyway, provider may reject`);let i=t+1<e.length?e[t+1]:void 0;i===void 0||i.role===`assistant`||y.warn({index:t,relatedToolCallId:n.relatedToolCallId,followingRole:i?.role},`system_notification message is not the last entry and is not immediately followed by an assistant turn (Anthropic placement rule violation risk) — sending anyway, provider may reject`)}}function w(e){return e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,`�`)}function T(e){return e.toJSONSchema?.()??{}}const E=[`low`,`medium`,`high`,`xhigh`,`max`];function D(e,t){if(!t||t.length===0||t.includes(e))return e;let n=E.indexOf(e),r=[...t].sort((e,t)=>E.indexOf(e)-E.indexOf(t)),i;for(let e of r)if(E.indexOf(e)<=n)i=e;else break;return i??r[0]}function O(e,t){return e.reasoning===!0&&!!t}function te(e){for(let t of e)if(t.role===`tool_result`||t.role===`assistant`&&t.content.some(e=>e.type===`tool_call`))return!0;return!1}function k(t){let n=[],r=O(t.model,t.thinkingLevel);t.systemPrompt&&n.push({role:`system`,content:w(t.systemPrompt)});for(let i of b(t.messages))if(i.role===`user`)typeof i.content==`string`?n.push({role:`user`,content:w(i.content)}):n.push({role:`user`,content:i.content.map(t=>{if(t.type===`text`)return{type:`text`,text:w(t.text)};if(t.type===`image`){let{base64:n,mediaType:r,valid:i}=e(t.source,t.mime);return i?{type:`image_url`,image_url:{url:`data:${r||`image/png`};base64,${n}`}}:{type:`text`,text:`[image omitted: corrupted or empty data]`}}return{type:`text`,text:`[unsupported]`}})});else if(i.role===`assistant`){let e=i.content.filter(e=>e.type===`tool_call`).map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.arguments)}})),t=i.content.filter(e=>e.type===`text`).filter(e=>e.text.trim().length>0).map(e=>w(e.text)).join(``),a=i.content.filter(e=>e.type===`thinking`).map(e=>w(e.text)).join(``).trim();if(!t&&e.length===0&&!a)continue;n.push({role:`assistant`,content:t||null,...e.length>0?{tool_calls:e}:{},...a?{reasoning_content:a}:e.length>0&&r?{reasoning_content:null}:{}})}else i.role===`tool_result`?n.push({role:`tool`,tool_call_id:i.toolCallId,content:w(i.content.map(e=>e.type===`text`?e.text:``).join(``))}):i.role===`system_notification`&&n.push({role:`user`,content:w(S(i.content))});return n}function ne(e){switch(e){case`low`:case`medium`:case`high`:return`high`;case`xhigh`:case`max`:return`max`;default:return`high`}}function re(e,t,n={}){let r={model:n.modelName??e.name,messages:k(t),max_tokens:t.maxTokens??e.maxOutputTokens,stream:!0,stream_options:{include_usage:!0}};return t.temperature!==void 0&&!e.reasoning&&(r.temperature=t.temperature),O(e,t.thinkingLevel)&&t.thinkingLevel!==void 0&&(r.reasoning_effort=ne(D(t.thinkingLevel,e.thinkingLevels))),t.tools&&t.tools.length>0?r.tools=t.tools.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:T(e.parameters)}})):te(t.messages)&&(r.tools=[]),r}const ie=r(`@x-otto/provider:openai-usage`);function ae(e){let t=t=>{let n=e.get(t);if(n===null)return;let r=Number(n);return Number.isFinite(r)?r:void 0},n=t=>{let n=e.get(t);if(!n)return;let r=n.match(/^(\d+(?:\.\d+)?)(m|s|ms)$/);if(!r)return;let i=Number(r[1]),a=r[2];if(a===`ms`)return i;if(a===`s`)return i*1e3;if(a===`m`)return i*60*1e3},r={remainingRequests:t(`x-ratelimit-remaining-requests`),remainingTokens:t(`x-ratelimit-remaining-tokens`),limitRequests:t(`x-ratelimit-limit-requests`),limitTokens:t(`x-ratelimit-limit-tokens`),resetRequestsMs:n(`x-ratelimit-reset-requests`),resetTokensMs:n(`x-ratelimit-reset-tokens`)};if(!Object.values(r).every(e=>e===void 0))return r}function A(e){if(!e)return null;let t=ae(e);if(ie.isLevelEnabled(`trace`)){let t=[];e.forEach((e,n)=>{let r=n.startsWith(`x-ratelimit-`)||e.length<40?e:e.slice(0,20)+`…`;t.push(` ${n}: ${r}`)}),ie.trace(`OpenAI Codex response headers (%d):
|
|
2
2
|
%s`,t.length,t.sort().join(`
|
|
3
|
-
`))}return t?{status:`unknown`,standardLimits:t}:null}const ae=E,oe=r(`@x-otto/provider:stream-state`);function D(){return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0}}function O(e,t){try{return{args:JSON.parse(e),parseFailed:!1}}catch{return oe.debug({toolName:t},`Failed to parse tool arguments JSON`),{args:{},parseFailed:!0}}}function se(e,t){return O(e,t).args}function ce(e){return new Set(e?.map(e=>e.name)??[])}function k(e,t,n){let{args:r,parseFailed:i}=O(n,t);return{type:`tool_call`,id:e,name:t,arguments:r,...i?{argumentsParseFailed:!0}:{}}}function A(e,t){if(e.content.some(e=>e.type===`tool_call`))return e;let n=e.content.findLastIndex(e=>e.type===`text`);if(n<0)return e;let r=e.content[n],i=M(r.text,t);if(!i)return e;let a=[...e.content],o=r.text.slice(0,i.matchStart).trimEnd();return o.length>0?a[n]={...r,text:o}:a.splice(n,1),a.push(k(`recovered_${n}`,i.name,i.argumentsJson)),{...e,content:a}}const le=/<invoke name="([^"]+)">((?:(?!<invoke name=")[\s\S])*?)<\/invoke>\s*$/,j=/<parameter name="([^"]+)">([\s\S]*?)<\/parameter>/g;function ue(e,t){return M(e,t)!==null}function M(e,t){let n=e.trimEnd(),r=le.exec(n);if(!r)return null;let i=r[1];if(!t.has(i))return null;let a={},o=r[2],s;for(j.lastIndex=0;(s=j.exec(o))!==null;)a[s[1]]=s[2];return{name:i,argumentsJson:JSON.stringify(a),matchStart:r.index}}function N(){return{...D(),textContent:``,thinkingText:``,toolCalls:new Map,stopReason:`end_turn`}}function P(e,t=!0){let n=[];if(e.thinkingText&&n.push({type:`thinking`,text:e.thinkingText}),e.textContent&&n.push({type:`text`,text:e.textContent}),t)for(let[,t]of e.toolCalls)n.push(k(t.id,t.name,t.argumentsJson));return n}function de(e,t=!0){let n=[],r=[...e.entries()].sort(([e],[t])=>e-t);for(let[,e]of r)e.kind===`thinking`?e.text&&n.push({type:`thinking`,text:e.text,...e.signature===void 0?{}:{signature:e.signature}}):e.kind===`text`?e.text&&n.push({type:`text`,text:e.text}):t&&n.push(k(e.id,e.name,e.argumentsJson));return n}function F(e,t,n,r){return{role:`assistant`,content:t,api:e.api,provider:e.provider,model:e.model,usage:{inputTokens:n.inputTokens,outputTokens:n.outputTokens,cacheReadTokens:n.cacheReadTokens,cacheWriteTokens:n.cacheWriteTokens},stopReason:r}}const fe=r(`@x-otto/provider:chat-completions-stream`);function I(e){switch(e){case`stop`:return`end_turn`;case`length`:return`max_tokens`;case`tool_calls`:return`tool_use`;case`content_filter`:return`refusal`;default:return fe.warn(`Unknown chat-completions finish_reason: ${e}`),`end_turn`}}async function*pe(e){let{url:t,headers:r,body:i,identity:a,signal:o,timeout:s,idleTimeout:c,onResponse:l,registeredToolNames:d}=e,f=N(),p=(e=!1)=>F(a,P(f,e),f,f.stopReason),m=!1,h=!1,g=!1,_,v=u({url:t,body:i,headers:r,signal:o,timeout:s,idleTimeout:c,onResponse:e=>{_=e,l?.(e)}});try{for await(let e of v){if(e.data===`[DONE]`)break;let t;try{t=JSON.parse(e.data)}catch{continue}if(t.error){let e=t.error,r=typeof e.message==`string`?e.message:JSON.stringify(e),i=e.code,a=typeof i==`number`?i:typeof i==`string`&&/^\d+/.test(i)?Number(i.match(/^\d+/)?.[0]):void 0;throw new n(`Chat Completions stream error: ${r}`,{code:`PROVIDER_API_ERROR`,status:a})}if(t.usage){let e=t.usage,n=e.prompt_tokens??0,r=e.completion_tokens??0,i=e.prompt_tokens_details?.cached_tokens??e.prompt_cache_hit_tokens??0;f.inputTokens=n-i,f.cacheReadTokens=i,f.outputTokens=r}let r=t.choices?.[0];if(!r)continue;let i=r.delta;if(m||(m=!0,yield{type:`start`,partial:p()}),r.finish_reason&&(f.stopReason=I(r.finish_reason)),!i)continue;if(i.content){let e=i.content;h||(h=!0,yield{type:`text_start`,index:0,partial:p()}),f.textContent+=e,yield{type:`text_delta`,index:0,delta:e,partial:p()}}let a=i.reasoning_content??i.reasoning??i.reasoning_text??null;if(a&&(g||(g=!0,yield{type:`thinking_start`,index:0,partial:p()}),f.thinkingText+=a,yield{type:`thinking_delta`,index:0,delta:a,partial:p()}),i.tool_calls)for(let e of i.tool_calls){let t=e.index,n=e.function;f.toolCalls.has(t)||(f.toolCalls.set(t,{id:e.id??`call_${t}`,name:n?.name??``,argumentsJson:``}),yield{type:`tool_call_start`,index:t,partial:p()});let r=f.toolCalls.get(t);if(n?.arguments){let e=n.arguments;r.argumentsJson+=e,yield{type:`tool_call_delta`,index:t,delta:e,partial:p()}}}}g&&(yield{type:`thinking_end`,index:0,content:f.thinkingText,partial:p()}),h&&(yield{type:`text_end`,index:0,content:f.textContent,partial:p()});for(let[e,t]of f.toolCalls)yield{type:`tool_call_end`,index:e,toolCall:k(t.id,t.name,t.argumentsJson),partial:p()};yield{type:`done`,reason:f.stopReason,message:A(p(!0),d??new Set),providerUsage:E(_)}}catch(e){yield{type:`error`,error:e instanceof Error?e:new n(`Unknown Chat Completions stream error`,{code:`PROVIDER_STREAM_ERROR`})}}}function L(e,t,n){for(let r of e){if(!r)continue;let e=r.split(`.`)[1];if(e)try{let r=JSON.parse(Buffer.from(e,`base64url`).toString(`utf-8`));if(n){let e=r[n]?.[t]??r[t];if(typeof e==`string`)return e}else{let e=r[t];if(typeof e==`string`)return e}}catch{}}}const me=new Set([`authorization`,`x-api-key`]),he=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/,ge=/[\u0000-\u001f\u007f]/g;function R(e,t,n,r){let i=new Map;if(!e)return i;for(let[a,o]of Object.entries(e)){let e=a.trim();if(!he.test(e)){n?.warn({provider:r,source:t,header:a},`dropped request header with invalid name (RFC 7230 token expected)`);continue}if(typeof o!=`string`)continue;let s=o.replace(ge,``).trim();s&&i.set(e.toLowerCase(),{name:e,value:s})}return i}function _e(e){if(!e?.headers.length)return;let t={};for(let n of e.headers){if(n.source.kind!==`jwt-claim`)continue;let r=L(n.source.tokenSources?.length?n.source.tokenSources.map(t=>t===`access_token`?e.token:void 0):[e.token],n.source.claim,n.source.namespace);r&&(t[n.header]=r)}return Object.keys(t).length>0?t:void 0}function ve(e){let{logger:t,diagnosticLabel:n,allowAuthHeaderOverride:r}=e,i=[{label:`protocolDefaults`,entries:R(e.protocolDefaults,`protocolDefaults`,t,n)},{label:`staticHeaders`,entries:R(e.staticHeaders,`staticHeaders`,t,n)},{label:`tokenDerived`,entries:R(_e(e.tokenDerived),`tokenDerived`,t,n)},{label:`customized`,entries:R(e.customized,`customized`,t,n)}],a=new Set([`staticHeaders`,`tokenDerived`,`customized`]),o=new Map;for(let{label:e,entries:s}of i)for(let[i,c]of s){if(!r&&a.has(e)&&me.has(i)){t?.warn({provider:n,source:e,header:c.name},`dropped attempt to override auth header (declare allowAuthHeaderOverride to permit)`);continue}let s=o.get(i);s&&e===`customized`&&s.value!==c.value&&t?.debug({provider:n,header:c.name},`customizeRequest overrode a previously declared request header`),o.set(i,c)}for(let[i,a]of R(e.auth,`auth`,t,n)){if(r&&o.has(i)){t?.debug({provider:n,header:a.name},`provider-declared auth header kept (allowAuthHeaderOverride); otto-resolved credential not applied`);continue}o.set(i,a)}let s={};for(let{name:e,value:t}of o.values())s[e]=t;return s}const z=r(`@x-otto/provider:oauth:templates`);function B(e,n){return new Promise((r,i)=>{if(n?.aborted){i(new t(`Login cancelled`,{code:`OAUTH_CANCELLED`}));return}let a=setTimeout(r,e);n?.addEventListener(`abort`,()=>{clearTimeout(a),i(new t(`Login cancelled`,{code:`OAUTH_CANCELLED`}))},{once:!0})})}function V(e){if(e?.aborted)throw new t(`Login cancelled`,{code:`OAUTH_CANCELLED`})}function ye(e){let{id:n,name:r,clientId:a,authorizeUrl:o,tokenUrl:s,redirectUri:c,scope:u,loopbackPorts:d,assumesLoopbackAlways:f=!1,extraAuthParams:p,tokenExchangeEncoding:m=`form`,subscriptionScoped:h=!1,oauthBeta:g}=e,_=!f&&Array.isArray(d)&&d.length>0;async function v(e,n){let i=e=>{let t=e.trim(),n=t.indexOf(`#`);return{code:n>=0?t.slice(0,n):t,returnedState:n>=0?t.slice(n+1):void 0}};if(!n){if(f)throw new t(`${r}: loopback required but all ports are unavailable. Configured ports: ${(d??[]).join(`, `)||`none`}.`,{code:`OAUTH_LOOPBACK_FAILED`});return i(await e.onManualCode())}if(f){let e=await n.waitForCallback();return{code:e.code,returnedState:e.state}}let a=new AbortController,o=n.waitForCallback().then(e=>({code:e.code,returnedState:e.state})),s=e.onManualCode?e.onManualCode(a.signal).then(i):new Promise(()=>{});o.catch(()=>{}),s.catch(()=>{});try{return await Promise.race([o,s.then(t=>t.code?t:(e.onProgress?.(`Waiting for browser authorization…`),o))])}finally{a.abort()}}function y(e,t,n){let r=new URL(o);if(r.searchParams.set(`code`,`true`),r.searchParams.set(`client_id`,a),r.searchParams.set(`response_type`,`code`),r.searchParams.set(`redirect_uri`,e),r.searchParams.set(`scope`,u),r.searchParams.set(`code_challenge`,t),r.searchParams.set(`code_challenge_method`,`S256`),r.searchParams.set(`state`,n),p)for(let[e,t]of Object.entries(p))r.searchParams.set(e,t);return r.toString().replace(/\+/g,`%20`)}async function b(e,n){let i=m===`json`,a={Accept:`application/json`},o;i?(a[`Content-Type`]=`application/json`,o=JSON.stringify(e)):(a[`Content-Type`]=`application/x-www-form-urlencoded`,o=new URLSearchParams(e).toString());let c;try{c=await fetch(s,{method:`POST`,headers:a,body:o})}catch(e){let n=e.cause;throw new t(`${r} token endpoint unreachable (${n?.code??n?.message??e.message}) — ${s}`,{code:`OAUTH_TOKEN_NETWORK`,cause:e})}let l;try{l=await c.json()}catch(e){throw new t(`${r} token endpoint returned non-JSON response (HTTP ${c.status})`,{code:`OAUTH_TOKEN_FAILED`,cause:e})}if(!l.access_token)throw new t(`${r} token exchange failed: ${l.error_description||l.error||`HTTP ${c.status}`}`,{code:`OAUTH_TOKEN_FAILED`,status:c.status,errorType:l.error});return{access:l.access_token,refresh:l.refresh_token??n??``,expires:Date.now()+(l.expires_in??0)*1e3}}return{id:n,name:r,usesCallbackServer:!1,oauthBeta:g,subscriptionScoped:h,async login(e){if(!_&&!f&&!e.onManualCode)throw new t(`${r} OAuth requires an onManualCode callback to paste the code.`,{code:`OAUTH_MANUAL_CODE_REQUIRED`});V(e.signal);let{verifier:n,challenge:o}=i(),s=n,u;if(Array.isArray(d)&&d.length>0)try{u=await l({ports:d,callbackPath:`/callback`,expectedState:s,signal:e.signal})}catch(e){if(z.info(`${r}: loopback ports [${d.join(`,`)}] unavailable; `+(f?``:`falling back to manual paste.`)+` (${e.message})`),f)throw new t(`${r}: loopback required but all ports [${d.join(`,`)}] are unavailable.`,{code:`OAUTH_LOOPBACK_FAILED`})}let p=u?`http://localhost:${u.port}/callback`:c;try{let i=y(p,o,s);e.onAuth({url:i,instructions:u?`Open the URL and authorize; login completes automatically. If it does not, paste the code shown (format: code#state).`:`Open the URL, authorize, then paste the code shown (format: code#state).`});let{code:c,returnedState:l}=await v(e,u);if(V(e.signal),!c)throw new t(`Empty authorization code.`,{code:`OAUTH_AUTHORIZE_FAILED`});if(l!==void 0&&l!==s)throw new t(`OAuth state mismatch (possible CSRF).`,{code:`OAUTH_STATE_MISMATCH`});l===void 0&&z.warn(`Authorization code returned without state; skipping CSRF state check.`);let d=await b({grant_type:`authorization_code`,code:c,state:l??s,client_id:a,redirect_uri:p,code_verifier:n});return z.info(`${r} OAuth login completed`),d}finally{await u?.close()}},async refreshToken(e){return b({grant_type:`refresh_token`,refresh_token:e.refresh,client_id:a},e.refresh)},getAccessKey(e){return e.access}}}function be(e){let{id:n,name:r,clientId:i,deviceCodeUrlTemplate:a,tokenUrlTemplate:o,refreshUrlTemplate:s,scope:c,allowCustomDomain:l=!1,userAgent:u}=e,d={Accept:`application/json`};u&&(d[`User-Agent`]=u);async function f(e,n,r){let i=await e.text();if(!e.ok)throw new t(`${r} failed: HTTP ${e.status}${i?`: ${i.slice(0,200)}`:``}`,{code:n,status:e.status});try{return JSON.parse(i)}catch{throw new t(`${r} returned a non-JSON response.`,{code:n})}}function p(e,t){return e.replace(/\{domain\}/g,t)}async function m(e,n,a,s,c){let l=Date.now()+s*1e3;for(;Date.now()<l;){if(c?.aborted)throw new t(`Login cancelled`,{code:`OAUTH_CANCELLED`});let s=p(o,e),u=await f(await fetch(s,{method:`POST`,headers:{...d,"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:i,device_code:n,grant_type:`urn:ietf:params:oauth:grant-type:device_code`})}),`OAUTH_AUTHORIZE_FAILED`,`${r} access token exchange`);if(u.error){if(u.error===`authorization_pending`){await B(Math.max(1e3,Math.min(Math.floor(a*1e3),l-Date.now())),c);continue}if(u.error===`slow_down`){a+=5,await B(Math.max(1e3,Math.min(Math.floor(a*1e3),l-Date.now())),c);continue}throw new t(`Authorize failed: ${u.error}${u.error_description?`: ${u.error_description}`:``}`,{code:`OAUTH_AUTHORIZE_FAILED`})}if(u.access_token)return u.access_token}throw new t(`Timed out while waiting for ${r} device authorization.`,{code:`OAUTH_AUTHORIZE_TIMEOUT`})}async function h(e,n){if(!s)throw new t(`${r} device-flow OAuth requires refreshUrlTemplate to be declared.`,{code:`OAUTH_REFRESH_URL_MISSING`});let i=p(s,n),a=await f(await fetch(i,{headers:{...d,Authorization:`Bearer ${e}`}}),`OAUTH_REFRESH_FAILED`,`${r} token refresh`),o=a.token??a.access_token;if(!o)throw new t(`${r}: invalid token response fields.`,{code:`OAUTH_REFRESH_FAILED`});return{access:o,expires:(a.expires_at??Math.floor(Date.now()/1e3)+3600)*1e3}}return{id:n,name:r,async login(e){let n=`github.com`;if(l){let i=await e.onPrompt({message:`${r} URL/domain (blank for default)`,placeholder:`company.ghe.com`,allowEmpty:!0});if(e.signal?.aborted)throw new t(`Login cancelled`,{code:`OAUTH_CANCELLED`});let a=i.trim()||`github.com`;n=a.startsWith(`http://`)||a.startsWith(`https://`)?new URL(a).hostname:a}let o=p(a,n),s=await f(await fetch(o,{method:`POST`,headers:{...d,"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:i,scope:c})}),`OAUTH_AUTHORIZE_FAILED`,`${r} device authorization`);if(!s.device_code)throw new t(`${r} device authorization returned invalid response fields.`,{code:`OAUTH_AUTHORIZE_FAILED`});await e.onAuth({url:s.verification_uri,code:s.user_code,instructions:`Enter code: ${s.user_code}`});let u=await m(n,s.device_code,s.interval,s.expires_in,e.signal),{access:g,expires:_}=await h(u,n),v={access:g,refresh:u,expires:_};return l&&n!==`github.com`&&(v.domain=n),await e.onProgress?.(`...`),z.info(`${r} OAuth login completed`),v},async refreshToken(e){let t=e.domain??`github.com`,{access:n,expires:r}=await h(e.refresh,t);return{access:n,refresh:e.refresh,expires:r,...t===`github.com`?{}:{domain:t}}},getAccessKey(e){return e.access}}}function H(e){let t=e;for(let e=0;e<3&&t!=null;e++){let e=t;if(typeof e.status==`number`)return e.status;if(typeof e.statusCode==`number`)return e.statusCode;t=e.cause}}function U(e){let t=[],n=e;for(let e=0;e<3&&n!=null;e++){let e=n;typeof e.message==`string`&&t.push(e.message),n=e.cause}return t.join(` ← `).toLowerCase()}const xe=[/prompt is too long/i,/context[\s_-]{0,3}(?:length|window|limit)/i,/context_length_exceeded/i,/maximum[\s_-]{0,3}context/i,/too many (?:input )?tokens/i,/exceeds? the maximum/i,/reduce the length/i,/input is too large/i,/request too large/i];function W(e){if(e==null)return!1;if(H(e)===413)return!0;let t=U(e);return t?!!xe.some(e=>e.test(t)):!1}const G=[/econnreset/i,/econnrefused/i,/etimedout/i,/timed? ?out/i,/enotfound/i,/eai_again/i,/socket hang ?up/i,/network/i,/fetch failed/i,/stream (?:ended|closed|disconnected|interrupted)/i,/premature close/i,/connection (?:closed|reset|error)/i,/overloaded/i,/\bterminated\b/i,/other side closed/i],K=new Set([`PROVIDER_INCOMPLETE_STREAM`,`PROVIDER_STREAM_ERROR`]),q=[/rate_limit_error/i,/overloaded_error/i,/throttling/i,/flow[\s_-]?control/i,/流量控制/,/限流/,/请求过于频繁/];function Se(e){let t=e;for(let e=0;e<3&&t!=null;e++){let e=t;if(e.headers!==void 0)return e.headers;t=e.cause}}function J(e){let t=Se(e);if(!t)return null;let n=c(t,`anthropic-ratelimit-unified-status`);if(n!==`rejected`&&n!==`allowed_warning`)return null;let r=c(t,`anthropic-ratelimit-unified-representative-claim`),i=c(t,`anthropic-ratelimit-unified-reset`);return{status:n,type:r,resetsAt:i?Number(i):void 0}}function Y(e){let t=e;for(let e=0;e<3&&t!=null;e++){let e=t;if(typeof e.code==`string`)return e.code;t=e.cause}}function X(e){let t=e;for(let e=0;e<3&&t!=null;e++){let e=t;if(e.abortKind===`idle`||e.abortKind===`wallclock`||e.abortKind===`external`)return e.abortKind;t=e.cause}}const Ce=[/many-image requests/i,/image dimensions exceed/i,/image exceeds \d+\s*(?:mb|bytes)/i];function we(e){if(e==null||H(e)!==void 0||X(e)!==void 0)return!1;let t=U(e);if(t&&q.some(e=>e.test(t)))return!1;let n=Y(e);return n&&K.has(n)?!0:!!t&&G.some(e=>e.test(t))}function Te(e){if(e==null)return!1;let t=Y(e);return t===`PROVIDER_AUTH_MISSING`||t===`PROVIDER_AUTH_REFRESH_FAILED`?!0:H(e)===401}function Ee(e){let t=Y(e);return t===`PROVIDER_AUTH_MISSING`?`credential-missing`:t===`PROVIDER_AUTH_REFRESH_FAILED`?`refresh-failed`:`server-rejected`}function De(e){if(e==null)return`fatal`;let t=H(e);if(t===400){let t=U(e);if(Ce.some(e=>e.test(t)))return`image-constraint`}if(W(e))return`context-overflow`;if(J(e)?.status===`rejected`)return`fatal`;if(t===429||t!==void 0&&t>=500&&t<=599)return`retryable`;let n=U(e);if(t===void 0&&n&&q.some(e=>e.test(n)))return`retryable`;if(t!==void 0&&t>=400&&t<500)return`fatal`;let r=Y(e);return r&&K.has(r)||n&&G.some(e=>e.test(n))?`retryable`:`fatal`}function Oe(e){let t=e;for(let e=0;e<3&&t!=null;e++){let e=t.headers,n=ke(e);if(n!==void 0)return n;t=t.cause}}function ke(e){let t=c(e,`retry-after-ms`);if(t!==void 0){let e=Number(t);if(Number.isFinite(e)&&e>=0)return e}let n=c(e,`retry-after`);if(n!==void 0){let e=Number(n);if(Number.isFinite(e)&&e>=0)return e*1e3}}function Ae(e){return m(e,`recordings`)}async function*je(e,t,n){f(m(n,`..`),{recursive:!0,mode:448});let r=d(n,{flags:`w`,mode:384}),i={version:1,modelId:t.id,api:String(t.api),recordedAt:new Date().toISOString(),contextWindow:t.contextWindow};r.write(JSON.stringify(i)+`
|
|
3
|
+
`))}return t?{status:`unknown`,standardLimits:t}:null}const oe=r(`@x-otto/provider:stream-state`);function j(){return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0}}function M(e,t){try{return{args:JSON.parse(e),parseFailed:!1}}catch{return oe.debug({toolName:t},`Failed to parse tool arguments JSON`),{args:{},parseFailed:!0}}}function se(e,t){return M(e,t).args}function ce(e){return new Set(e?.map(e=>e.name)??[])}function N(e,t,n){let{args:r,parseFailed:i}=M(n,t);return{type:`tool_call`,id:e,name:t,arguments:r,...i?{argumentsParseFailed:!0}:{}}}function P(e,t){if(e.content.some(e=>e.type===`tool_call`))return e;let n=e.content.findLastIndex(e=>e.type===`text`);if(n<0)return e;let r=e.content[n],i=I(r.text,t);if(!i)return e;let a=[...e.content],o=r.text.slice(0,i.matchStart).trimEnd();return o.length>0?a[n]={...r,text:o}:a.splice(n,1),a.push(N(`recovered_${n}`,i.name,i.argumentsJson)),{...e,content:a}}const le=/<invoke name="([^"]+)">((?:(?!<invoke name=")[\s\S])*?)<\/invoke>\s*$/,F=/<parameter name="([^"]+)">([\s\S]*?)<\/parameter>/g;function ue(e,t){return I(e,t)!==null}function I(e,t){let n=e.trimEnd(),r=le.exec(n);if(!r)return null;let i=r[1];if(!t.has(i))return null;let a={},o=r[2],s;for(F.lastIndex=0;(s=F.exec(o))!==null;)a[s[1]]=s[2];return{name:i,argumentsJson:JSON.stringify(a),matchStart:r.index}}function L(){return{...j(),textContent:``,thinkingText:``,toolCalls:new Map,stopReason:`end_turn`}}function R(e,t=!0){let n=[];if(e.thinkingText&&n.push({type:`thinking`,text:e.thinkingText}),e.textContent&&n.push({type:`text`,text:e.textContent}),t)for(let[,t]of e.toolCalls)n.push(N(t.id,t.name,t.argumentsJson));return n}function de(e,t=!0){let n=[],r=[...e.entries()].sort(([e],[t])=>e-t);for(let[,e]of r)e.kind===`thinking`?e.text&&n.push({type:`thinking`,text:e.text,...e.signature===void 0?{}:{signature:e.signature}}):e.kind===`text`?e.text&&n.push({type:`text`,text:e.text}):t&&n.push(N(e.id,e.name,e.argumentsJson));return n}function z(e,t,n,r){return{role:`assistant`,content:t,api:e.api,provider:e.provider,model:e.model,usage:{inputTokens:n.inputTokens,outputTokens:n.outputTokens,cacheReadTokens:n.cacheReadTokens,cacheWriteTokens:n.cacheWriteTokens},stopReason:r}}const fe=r(`@x-otto/provider:chat-completions-stream`);function B(e){switch(e){case`stop`:return`end_turn`;case`length`:return`max_tokens`;case`tool_calls`:return`tool_use`;case`content_filter`:return`refusal`;default:return fe.warn(`Unknown chat-completions finish_reason: ${e}`),`end_turn`}}async function*pe(e){let{url:t,headers:r,body:i,identity:a,signal:o,timeout:s,idleTimeout:c,onResponse:l,registeredToolNames:u}=e,d=L(),p=(e=!1)=>z(a,R(d,e),d,d.stopReason),m=!1,h=!1,g=!1,_,v=f({url:t,body:i,headers:r,signal:o,timeout:s,idleTimeout:c,onResponse:e=>{_=e,l?.(e)}});try{for await(let e of v){if(e.data===`[DONE]`)break;let t;try{t=JSON.parse(e.data)}catch{continue}if(t.error){let e=t.error,r=typeof e.message==`string`?e.message:JSON.stringify(e),i=e.code,a=typeof i==`number`?i:typeof i==`string`&&/^\d+/.test(i)?Number(i.match(/^\d+/)?.[0]):void 0;throw new n(`Chat Completions stream error: ${r}`,{code:`PROVIDER_API_ERROR`,status:a})}if(t.usage){let e=t.usage,n=e.prompt_tokens??0,r=e.completion_tokens??0,i=e.prompt_tokens_details?.cached_tokens??e.prompt_cache_hit_tokens??0;d.inputTokens=n-i,d.cacheReadTokens=i,d.outputTokens=r}let r=t.choices?.[0];if(!r)continue;let i=r.delta;if(m||(m=!0,yield{type:`start`,partial:p()}),r.finish_reason&&(d.stopReason=B(r.finish_reason)),!i)continue;if(i.content){let e=i.content;h||(h=!0,yield{type:`text_start`,index:0,partial:p()}),d.textContent+=e,yield{type:`text_delta`,index:0,delta:e,partial:p()}}let a=i.reasoning_content??i.reasoning??i.reasoning_text??null;if(a&&(g||(g=!0,yield{type:`thinking_start`,index:0,partial:p()}),d.thinkingText+=a,yield{type:`thinking_delta`,index:0,delta:a,partial:p()}),i.tool_calls)for(let e of i.tool_calls){let t=e.index,n=e.function;d.toolCalls.has(t)||(d.toolCalls.set(t,{id:e.id??`call_${t}`,name:n?.name??``,argumentsJson:``}),yield{type:`tool_call_start`,index:t,partial:p()});let r=d.toolCalls.get(t);if(n?.arguments){let e=n.arguments;r.argumentsJson+=e,yield{type:`tool_call_delta`,index:t,delta:e,partial:p()}}}}g&&(yield{type:`thinking_end`,index:0,content:d.thinkingText,partial:p()}),h&&(yield{type:`text_end`,index:0,content:d.textContent,partial:p()});for(let[e,t]of d.toolCalls)yield{type:`tool_call_end`,index:e,toolCall:N(t.id,t.name,t.argumentsJson),partial:p()};yield{type:`done`,reason:d.stopReason,message:P(p(!0),u??new Set),providerUsage:A(_)}}catch(e){yield{type:`error`,error:e instanceof Error?e:new n(`Unknown Chat Completions stream error`,{code:`PROVIDER_STREAM_ERROR`})}}}function V(e,t,n){for(let r of e){if(!r)continue;let e=r.split(`.`)[1];if(e)try{let r=JSON.parse(Buffer.from(e,`base64url`).toString(`utf-8`));if(n){let e=r[n]?.[t]??r[t];if(typeof e==`string`)return e}else{let e=r[t];if(typeof e==`string`)return e}}catch{}}}const me=new Set([`authorization`,`x-api-key`]),he=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/,ge=/[\u0000-\u001f\u007f]/g;function H(e,t,n,r){let i=new Map;if(!e)return i;for(let[a,o]of Object.entries(e)){let e=a.trim();if(!he.test(e)){n?.warn({provider:r,source:t,header:a},`dropped request header with invalid name (RFC 7230 token expected)`);continue}if(typeof o!=`string`)continue;let s=o.replace(ge,``).trim();s&&i.set(e.toLowerCase(),{name:e,value:s})}return i}function _e(e){if(!e?.headers.length)return;let t={};for(let n of e.headers){if(n.source.kind!==`jwt-claim`)continue;let r=V(n.source.tokenSources?.length?n.source.tokenSources.map(t=>t===`access_token`?e.token:void 0):[e.token],n.source.claim,n.source.namespace);r&&(t[n.header]=r)}return Object.keys(t).length>0?t:void 0}function ve(e){let{logger:t,diagnosticLabel:n,allowAuthHeaderOverride:r}=e,i=[{label:`protocolDefaults`,entries:H(e.protocolDefaults,`protocolDefaults`,t,n)},{label:`staticHeaders`,entries:H(e.staticHeaders,`staticHeaders`,t,n)},{label:`tokenDerived`,entries:H(_e(e.tokenDerived),`tokenDerived`,t,n)},{label:`customized`,entries:H(e.customized,`customized`,t,n)}],a=new Set([`staticHeaders`,`tokenDerived`,`customized`]),o=new Map;for(let{label:e,entries:s}of i)for(let[i,c]of s){if(!r&&a.has(e)&&me.has(i)){t?.warn({provider:n,source:e,header:c.name},`dropped attempt to override auth header (declare allowAuthHeaderOverride to permit)`);continue}let s=o.get(i);s&&e===`customized`&&s.value!==c.value&&t?.debug({provider:n,header:c.name},`customizeRequest overrode a previously declared request header`),o.set(i,c)}for(let[i,a]of H(e.auth,`auth`,t,n)){if(r&&o.has(i)){t?.debug({provider:n,header:a.name},`provider-declared auth header kept (allowAuthHeaderOverride); otto-resolved credential not applied`);continue}o.set(i,a)}let s={};for(let{name:e,value:t}of o.values())s[e]=t;return s}const U=r(`@x-otto/provider:oauth:templates`);function W(e,n){return new Promise((r,i)=>{if(n?.aborted){i(new t(`Login cancelled`,{code:`OAUTH_CANCELLED`}));return}let a=setTimeout(r,e);n?.addEventListener(`abort`,()=>{clearTimeout(a),i(new t(`Login cancelled`,{code:`OAUTH_CANCELLED`}))},{once:!0})})}function G(e){if(e?.aborted)throw new t(`Login cancelled`,{code:`OAUTH_CANCELLED`})}function K(e){let t=e.trim(),n=t.indexOf(`#`);return{code:n>=0?t.slice(0,n):t,returnedState:n>=0?t.slice(n+1):void 0}}function ye(e){let{id:n,name:r,clientId:i,authorizeUrl:o,tokenUrl:s,redirectUri:c,scope:l,loopbackPorts:u,assumesLoopbackAlways:f=!1,extraAuthParams:p,tokenExchangeEncoding:m=`form`,subscriptionScoped:h=!1,oauthBeta:g}=e,_=!f&&Array.isArray(u)&&u.length>0;async function v(e){return K(await e.onManualCode())}async function y(e){let t=await e.waitForCallback();return{code:t.code,returnedState:t.state}}async function b(e,t){let n=new AbortController,r=t.waitForCallback().then(e=>({code:e.code,returnedState:e.state})),i=e.onManualCode?e.onManualCode(n.signal).then(K):new Promise(()=>{});r.catch(()=>{}),i.catch(()=>{});try{return await Promise.race([r,i.then(t=>t.code?t:(e.onProgress?.(`Waiting for browser authorization…`),r))])}finally{n.abort()}}async function x(e,n){if(!n){if(f)throw new t(`${r}: loopback required but all ports are unavailable. Configured ports: ${(u??[]).join(`, `)||`none`}.`,{code:`OAUTH_LOOPBACK_FAILED`});return v(e)}return f?y(n):b(e,n)}function S(e,t,n){let r=new URL(o);if(r.searchParams.set(`code`,`true`),r.searchParams.set(`client_id`,i),r.searchParams.set(`response_type`,`code`),r.searchParams.set(`redirect_uri`,e),r.searchParams.set(`scope`,l),r.searchParams.set(`code_challenge`,t),r.searchParams.set(`code_challenge_method`,`S256`),r.searchParams.set(`state`,n),p)for(let[e,t]of Object.entries(p))r.searchParams.set(e,t);return r.toString().replace(/\+/g,`%20`)}async function C(e,n){let i=m===`json`,a={Accept:`application/json`},o;i?(a[`Content-Type`]=`application/json`,o=JSON.stringify(e)):(a[`Content-Type`]=`application/x-www-form-urlencoded`,o=new URLSearchParams(e).toString());let c;try{c=await fetch(s,{method:`POST`,headers:a,body:o})}catch(e){let n=e.cause;throw new t(`${r} token endpoint unreachable (${n?.code??n?.message??e.message}) — ${s}`,{code:`OAUTH_TOKEN_NETWORK`,cause:e})}let l;try{l=await c.json()}catch(e){throw new t(`${r} token endpoint returned non-JSON response (HTTP ${c.status})`,{code:`OAUTH_TOKEN_FAILED`,cause:e})}if(!l.access_token)throw new t(`${r} token exchange failed: ${l.error_description||l.error||`HTTP ${c.status}`}`,{code:`OAUTH_TOKEN_FAILED`,status:c.status,errorType:l.error});return{access:l.access_token,refresh:l.refresh_token??n??``,expires:Date.now()+(l.expires_in??0)*1e3}}return{id:n,name:r,usesCallbackServer:!1,oauthBeta:g,subscriptionScoped:h,async login(e){if(!_&&!f&&!e.onManualCode)throw new t(`${r} OAuth requires an onManualCode callback to paste the code.`,{code:`OAUTH_MANUAL_CODE_REQUIRED`});G(e.signal);let{verifier:n,challenge:o}=a(),s=n,l;if(Array.isArray(u)&&u.length>0)try{l=await d({ports:u,callbackPath:`/callback`,expectedState:s,signal:e.signal})}catch(e){if(U.info(`${r}: loopback ports [${u.join(`,`)}] unavailable; `+(f?``:`falling back to manual paste.`)+` (${e.message})`),f)throw new t(`${r}: loopback required but all ports [${u.join(`,`)}] are unavailable.`,{code:`OAUTH_LOOPBACK_FAILED`})}let p=l?`http://localhost:${l.port}/callback`:c;try{let a=S(p,o,s);e.onAuth({url:a,instructions:l?`Open the URL and authorize; login completes automatically. If it does not, paste the code shown (format: code#state).`:`Open the URL, authorize, then paste the code shown (format: code#state).`});let{code:c,returnedState:u}=await x(e,l);if(G(e.signal),!c)throw new t(`Empty authorization code.`,{code:`OAUTH_AUTHORIZE_FAILED`});if(u!==void 0&&u!==s)throw new t(`OAuth state mismatch (possible CSRF).`,{code:`OAUTH_STATE_MISMATCH`});u===void 0&&U.warn(`Authorization code returned without state; skipping CSRF state check.`);let d=await C({grant_type:`authorization_code`,code:c,state:u??s,client_id:i,redirect_uri:p,code_verifier:n});return U.info(`${r} OAuth login completed`),d}finally{await l?.close()}},async refreshToken(e){return C({grant_type:`refresh_token`,refresh_token:e.refresh,client_id:i},e.refresh)},getAccessKey(e){return e.access}}}function be(e){let{id:n,name:r,clientId:i,deviceCodeUrlTemplate:a,tokenUrlTemplate:o,refreshUrlTemplate:s,scope:c,allowCustomDomain:l=!1,userAgent:u}=e,d={Accept:`application/json`};u&&(d[`User-Agent`]=u);async function f(e,n,r){let i=await e.text();if(!e.ok)throw new t(`${r} failed: HTTP ${e.status}${i?`: ${i.slice(0,200)}`:``}`,{code:n,status:e.status});try{return JSON.parse(i)}catch{throw new t(`${r} returned a non-JSON response.`,{code:n})}}function p(e,t){return e.replace(/\{domain\}/g,t)}async function m(e,n,a,s,c){let l=Date.now()+s*1e3;for(;Date.now()<l;){if(c?.aborted)throw new t(`Login cancelled`,{code:`OAUTH_CANCELLED`});let s=p(o,e),u=await f(await fetch(s,{method:`POST`,headers:{...d,"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:i,device_code:n,grant_type:`urn:ietf:params:oauth:grant-type:device_code`})}),`OAUTH_AUTHORIZE_FAILED`,`${r} access token exchange`);if(u.error){if(u.error===`authorization_pending`){await W(Math.max(1e3,Math.min(Math.floor(a*1e3),l-Date.now())),c);continue}if(u.error===`slow_down`){a+=5,await W(Math.max(1e3,Math.min(Math.floor(a*1e3),l-Date.now())),c);continue}throw new t(`Authorize failed: ${u.error}${u.error_description?`: ${u.error_description}`:``}`,{code:`OAUTH_AUTHORIZE_FAILED`})}if(u.access_token)return u.access_token}throw new t(`Timed out while waiting for ${r} device authorization.`,{code:`OAUTH_AUTHORIZE_TIMEOUT`})}async function h(e,n){if(!s)throw new t(`${r} device-flow OAuth requires refreshUrlTemplate to be declared.`,{code:`OAUTH_REFRESH_URL_MISSING`});let i=p(s,n),a=await f(await fetch(i,{headers:{...d,Authorization:`Bearer ${e}`}}),`OAUTH_REFRESH_FAILED`,`${r} token refresh`),o=a.token??a.access_token;if(!o)throw new t(`${r}: invalid token response fields.`,{code:`OAUTH_REFRESH_FAILED`});return{access:o,expires:(a.expires_at??Math.floor(Date.now()/1e3)+3600)*1e3}}return{id:n,name:r,async login(e){let n=`github.com`;if(l){let i=await e.onPrompt({message:`${r} URL/domain (blank for default)`,placeholder:`company.ghe.com`,allowEmpty:!0});if(e.signal?.aborted)throw new t(`Login cancelled`,{code:`OAUTH_CANCELLED`});let a=i.trim()||`github.com`;n=a.startsWith(`http://`)||a.startsWith(`https://`)?new URL(a).hostname:a}let o=p(a,n),s=await f(await fetch(o,{method:`POST`,headers:{...d,"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:i,scope:c})}),`OAUTH_AUTHORIZE_FAILED`,`${r} device authorization`);if(!s.device_code)throw new t(`${r} device authorization returned invalid response fields.`,{code:`OAUTH_AUTHORIZE_FAILED`});await e.onAuth({url:s.verification_uri,code:s.user_code,instructions:`Enter code: ${s.user_code}`});let u=await m(n,s.device_code,s.interval,s.expires_in,e.signal),{access:g,expires:_}=await h(u,n),v={access:g,refresh:u,expires:_};return l&&n!==`github.com`&&(v.domain=n),await e.onProgress?.(`...`),U.info(`${r} OAuth login completed`),v},async refreshToken(e){let t=e.domain??`github.com`,{access:n,expires:r}=await h(e.refresh,t);return{access:n,refresh:e.refresh,expires:r,...t===`github.com`?{}:{domain:t}}},getAccessKey(e){return e.access}}}function q(e,t){let n=e;for(let e=0;e<3&&n!=null;e++){let e=t(n);if(e!==void 0)return e;n=n.cause}}function J(e){return q(e,e=>{if(typeof e.status==`number`)return e.status;if(typeof e.statusCode==`number`)return e.statusCode})}function Y(e){let t=[],n=e;for(let e=0;e<3&&n!=null;e++){let e=n.message;typeof e==`string`&&t.push(e),n=n.cause}return t.join(` ← `).toLowerCase()}const xe=[/prompt is too long/i,/context[\s_-]{0,3}(?:length|window|limit)/i,/context_length_exceeded/i,/maximum[\s_-]{0,3}context/i,/too many (?:input )?tokens/i,/exceeds? the maximum/i,/reduce the length/i,/input is too large/i,/request too large/i];function X(e){if(e==null)return!1;if(J(e)===413)return!0;let t=Y(e);return t?!!xe.some(e=>e.test(t)):!1}const Z=[/econnreset/i,/econnrefused/i,/etimedout/i,/timed? ?out/i,/enotfound/i,/eai_again/i,/socket hang ?up/i,/network/i,/fetch failed/i,/stream (?:ended|closed|disconnected|interrupted)/i,/premature close/i,/connection (?:closed|reset|error)/i,/overloaded/i,/\bterminated\b/i,/other side closed/i],Se=new Set([`PROVIDER_INCOMPLETE_STREAM`,`PROVIDER_STREAM_ERROR`]),Ce=[/rate_limit_error/i,/overloaded_error/i,/throttling/i,/flow[\s_-]?control/i,/流量控制/,/限流/,/请求过于频繁/];function we(e){return q(e,e=>{let t=e.headers;return t===void 0?void 0:t})}function Te(e){let t=we(e);if(!t)return null;let n=l(t,`anthropic-ratelimit-unified-status`);if(n!==`rejected`&&n!==`allowed_warning`)return null;let r=l(t,`anthropic-ratelimit-unified-representative-claim`),i=l(t,`anthropic-ratelimit-unified-reset`);return{status:n,type:r,resetsAt:i?Number(i):void 0}}function Q(e){return q(e,e=>typeof e.code==`string`?e.code:void 0)}function Ee(e){return q(e,e=>{let t=e.abortKind;if(t===`idle`||t===`wallclock`||t===`external`)return t})}const De=[/many-image requests/i,/image dimensions exceed/i,/image exceeds \d+\s*(?:mb|bytes)/i];function Oe(e){if(e==null||J(e)!==void 0||Ee(e)!==void 0)return!1;let t=Y(e);if(t&&Ce.some(e=>e.test(t)))return!1;let n=Q(e);return n&&Se.has(n)?!0:!!t&&Z.some(e=>e.test(t))}function ke(e){if(e==null)return!1;let t=Q(e);return t===`PROVIDER_AUTH_MISSING`||t===`PROVIDER_AUTH_REFRESH_FAILED`?!0:J(e)===401}function Ae(e){let t=Q(e);return t===`PROVIDER_AUTH_MISSING`?`credential-missing`:t===`PROVIDER_AUTH_REFRESH_FAILED`?`refresh-failed`:`server-rejected`}function je(e){if(e==null)return`fatal`;let t=J(e);if(t===400){let t=Y(e);if(De.some(e=>e.test(t)))return`image-constraint`}if(X(e))return`context-overflow`;if(Te(e)?.status===`rejected`)return`fatal`;if(t===429||t!==void 0&&t>=500&&t<=599)return`retryable`;let n=Y(e);if(t===void 0&&n&&Ce.some(e=>e.test(n)))return`retryable`;if(t!==void 0&&t>=400&&t<500)return`fatal`;let r=Q(e);return r&&Se.has(r)||n&&Z.some(e=>e.test(n))?`retryable`:`fatal`}function Me(e){return q(e,e=>Ne(e.headers))}function Ne(e){let t=l(e,`retry-after-ms`);if(t!==void 0){let e=Number(t);if(Number.isFinite(e)&&e>=0)return e}let n=l(e,`retry-after`);if(n!==void 0){let e=Number(n);if(Number.isFinite(e)&&e>=0)return e*1e3}}function Pe(e){return g(e,`recordings`)}async function*Fe(e,t,n){m(g(n,`..`),{recursive:!0,mode:448});let r=p(n,{flags:`w`,mode:384}),i={version:1,modelId:t.id,api:String(t.api),recordedAt:new Date().toISOString(),contextWindow:t.contextWindow};r.write(JSON.stringify(i)+`
|
|
4
4
|
`);let a;try{for await(let t of e){let e=Date.now();a===void 0&&(a=e);let n={t:e-a,e:t};r.write(JSON.stringify(n)+`
|
|
5
|
-
`),yield t}}finally{await new Promise(e=>r.end(()=>e()))}}async function
|
|
6
|
-
`).filter(e=>e.trim().length>0),n=t[0];if(n===void 0)throw Error(`录制文件为空: ${e}`);let r=JSON.parse(n);if(r.version!==1)throw Error(`不支持的录制版本 ${r.version}(本实现支持 1)`);let i=t.slice(1).map(e=>JSON.parse(e));if(i.length===0)throw Error(`录制文件无事件: ${e}`);return{header:r,events:i}}async function*
|
|
5
|
+
`),yield t}}finally{await new Promise(e=>r.end(()=>e()))}}async function Ie(e){let t=(await h(e,`utf-8`)).split(`
|
|
6
|
+
`).filter(e=>e.trim().length>0),n=t[0];if(n===void 0)throw Error(`录制文件为空: ${e}`);let r=JSON.parse(n);if(r.version!==1)throw Error(`不支持的录制版本 ${r.version}(本实现支持 1)`);let i=t.slice(1).map(e=>JSON.parse(e));if(i.length===0)throw Error(`录制文件无事件: ${e}`);return{header:r,events:i}}async function*Le(e,t={},n){let r=Date.now();for(let i of e.events){if(n?.aborted)throw Error(`Replay aborted`);if(!t.fast&&i.t>0){let e=i.t-(Date.now()-r);e>0&&await new Promise(t=>setTimeout(t,e))}yield i.e}}const $=`replay`;function Re(e){return{id:`replay/${e.header.modelId}`,name:`Replay of ${e.header.modelId}`,api:$,provider:`replay`,contextWindow:e.header.contextWindow}}var ze=class{id=$;displayName=`Replay Provider (RFC-200)`;recording;constructor(e,t={}){this.filePath=e,this.options=t}async preload(){return this.recording??=await Ie(this.filePath),this.recording}async*converse(e,t,n,r){yield*Le(await this.preload(),this.options,n.signal??r)}};function Be(e,t={}){return()=>new ze(e,t)}export{be as DeviceFlowOAuthTemplate,ye as PKCEOAuthTemplate,$ as REPLAY_API,ze as ReplayProviderStream,z as assembleAssistantMessage,ee as assertSystemNotificationPlacement,de as blocksContent,re as buildChatCompletionsBody,k as buildChatCompletionsMessages,Re as buildReplayModel,ve as buildRequestHeaders,D as clampThinkingLevel,Ae as classifyAuthErrorType,je as classifyStreamError,i as createPkcePair,Be as createReplayProviderFactory,S as degradedSystemNotificationText,Ee as extractAbortKind,Te as extractAnthropicRateLimit,V as extractJwtClaim,Me as extractRetryAfterMs,A as extractStandardRateLimitHeaders,R as flatContent,o as generateChallenge,s as generateState,c as generateVerifier,ue as hasTrailingInvokeXml,L as initFlatStreamState,j as initStreamUsage,ke as isAuthError,X as isContextOverflowError,Oe as isNetworkDisconnectError,Ie as loadRecording,B as mapChatFinishReason,C as mergeConsecutiveSystemNotifications,_ as noopWireProtocolLogger,se as parseToolArguments,M as parseToolArgumentsWithStatus,Fe as recordStream,Pe as recordingsDir,P as recoverLiteralInvokeToolCalls,ce as registeredToolNames,Le as replayStream,v as resolveProviderBaseUrl,w as sanitizeSurrogates,b as sanitizeToolRoundtrips,u as startLoopbackServer,pe as streamChatCompletions,T as toJsonSchema,N as toolCallFromParsed};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x-otto/provider",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist"
|
|
6
6
|
],
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"tag": "alpha"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@x-otto/interchange": "0.1.0-alpha.
|
|
23
|
-
"@x-otto/shared": "0.1.0-alpha.
|
|
22
|
+
"@x-otto/interchange": "0.1.0-alpha.8",
|
|
23
|
+
"@x-otto/shared": "0.1.0-alpha.8"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsdown && rm -f dist/*.map && sed -i '' '\\|//# sourceMappingURL=|d' dist/*.js 2>/dev/null; true",
|