@x-otto/provider 0.1.0-alpha.25 → 0.1.0-alpha.27
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 +11 -0
- package/dist/index.js +5 -5
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -624,6 +624,16 @@ interface PKCEOAuthTemplateParams {
|
|
|
624
624
|
* 对齐 Anthropic 的 54545 白名单端口机制与 Codex 的 [1455,1457] 多端口。
|
|
625
625
|
*/
|
|
626
626
|
loopbackPorts?: number[];
|
|
627
|
+
/**
|
|
628
|
+
* loopback 回调**路径**(厂商在授权服务器白名单里注册的 exact 值)。
|
|
629
|
+
* 缺省 `/auth/callback`(官方 Codex CLI 注册值);Anthropic 注册的是 `/callback`,
|
|
630
|
+
* 由 `plugin-anthropic` manifest 显式声明。
|
|
631
|
+
*
|
|
632
|
+
* 此前本模板把 Anthropic 的 `/callback` 硬编码进骨架,导致所有 PKCE 插件(含
|
|
633
|
+
* codex)都被迫使用它——codex 的注册值是 `/auth/callback`,授权服务器会以
|
|
634
|
+
* "Redirect URI is not supported by client" 拒绝,登录必失败。
|
|
635
|
+
*/
|
|
636
|
+
callbackPath?: string;
|
|
627
637
|
/**
|
|
628
638
|
* loopback 是否假定始终可用、不提供手动粘贴兜底。
|
|
629
639
|
* `false`(缺省,对齐 Anthropic)= 端口被占时降级手动粘贴框;
|
|
@@ -671,6 +681,7 @@ interface DeviceFlowOAuthTemplateParams {
|
|
|
671
681
|
*
|
|
672
682
|
* 行为与终态参数由 `PKCEOAuthTemplateParams` 完全控制:
|
|
673
683
|
* - loopback 端口按列表顺序回退(`assumesLoopbackAlways:true` 时不提供手动粘贴兜底)
|
|
684
|
+
* - loopback 回调路径由 `callbackPath` 声明(缺省 `/auth/callback`,不再硬编码厂商路径)
|
|
674
685
|
* - authorize URL 上拼装额外 query 参数(`extraAuthParams`)
|
|
675
686
|
* - token 端点请求体编码由 `tokenExchangeEncoding` 决定(`json` vs `form`)
|
|
676
687
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{normalizeImageData as e}from"@x-otto/interchange";import{
|
|
1
|
+
import{normalizeImageData as e}from"@x-otto/interchange";import{DEFAULT_LOOPBACK_CALLBACK_PATH as t,OAuthError as n,ProviderError as r,createLogger as i,createPkcePair as a,createPkcePair as o,generateChallenge as s,generateState as c,generateVerifier as l,headerGet as u,startLoopbackServer as d,startLoopbackServer as f,stream as p}from"@x-otto/shared";import{createWriteStream as m,mkdirSync as h}from"node:fs";import{readFile as g}from"node:fs/promises";import{join as _}from"node:path";const v={debug:()=>{},info:()=>{},warn:()=>{},error:()=>{}};async function y(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 b=i(`@x-otto/provider:tool-roundtrip`);function x(e){let t=[],n=[],r=()=>{for(let e of n)b.warn({toolCallId:e.id,toolName:e.name},`Synthesizing placeholder for unanswered tool_call`),t.push(S(e));n=[]};for(let i of e){if(i.role===`tool_result`){let e=n.findIndex(e=>e.id===i.toolCallId);if(e===-1){b.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 S(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 C(e){return`[System notification] ${e}`}function ee(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 w(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`)||b.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`||b.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 T(e){return e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,`�`)}function te(e){return!e||typeof e!=`object`||Array.isArray(e)?{}:typeof e.toJSONSchema==`function`?e.toJSONSchema():e}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 ne(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 re(e){let t=e.systemPromptSegments;if(!t||t.length===0)return e.systemPrompt?[{role:`system`,content:T(e.systemPrompt)}]:[];let n=t.filter(e=>(e.cache??`stable`)===`stable`).map(e=>e.text).filter(e=>e.length>0).join(`
|
|
2
2
|
|
|
3
3
|
`),r=t.filter(e=>e.cache===`volatile`).map(e=>e.text).filter(e=>e.length>0).join(`
|
|
4
4
|
|
|
5
|
-
`),i=[];return n&&i.push({role:`system`,content:
|
|
5
|
+
`),i=[];return n&&i.push({role:`system`,content:T(n)}),r&&i.push({role:`system`,content:T(r)}),i}function k(t){let n=[],r=O(t.model,t.thinkingLevel);n.push(...re(t));for(let i of x(t.messages))if(i.role===`user`)typeof i.content==`string`?n.push({role:`user`,content:T(i.content)}):n.push({role:`user`,content:i.content.map(t=>{if(t.type===`text`)return{type:`text`,text:T(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)}})),a=i.content.filter(e=>e.type===`text`).filter(e=>e.text.trim().length>0).map(e=>T(e.text)).join(``),o=i.content.filter(e=>e.type===`thinking`).map(e=>T(e.text)).join(``).trim();if(!a&&e.length===0&&!o)continue;let s=t.model.reasoningContentRequired===!0;n.push({role:`assistant`,content:a||null,...e.length>0?{tool_calls:e}:{},...o?{reasoning_content:o}:e.length>0&&r||s?{reasoning_content:null}:{}})}else i.role===`tool_result`?n.push({role:`tool`,tool_call_id:i.toolCallId,content:T(i.content.map(e=>e.type===`text`?e.text:``).join(``))}):i.role===`system_notification`&&n.push({role:`user`,content:T(C(i.content))});return n}function ie(e){switch(e){case`low`:case`medium`:case`high`:return`high`;case`xhigh`:case`max`:return`max`;default:return`high`}}function ae(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}};t.temperature!==void 0&&!e.reasoning&&(r.temperature=t.temperature);let i=!!(t.tools&&t.tools.length>0);return e.reasoningToolsExclusive===!0&&i?r.reasoning_effort=`none`:O(e,t.thinkingLevel)&&t.thinkingLevel!==void 0&&(r.reasoning_effort=ie(D(t.thinkingLevel,e.thinkingLevels))),i?r.tools=t.tools.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:te(e.parameters)}})):ne(t.messages)&&(r.tools=[]),r}const A=i(`@x-otto/provider:openai-usage`);function oe(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 se(e){if(!e)return null;let t=oe(e);if(A.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}`)}),A.trace(`OpenAI Codex response headers (%d):
|
|
6
6
|
%s`,t.length,t.sort().join(`
|
|
7
|
-
`))}return t?{status:`unknown`,standardLimits:t}:null}const se=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 se.debug({toolName:t,argumentsJson:e.slice(0,500),length:e.length},`Failed to parse tool arguments JSON`),{args:{},parseFailed:!0}}}function ce(e,t){return M(e,t).args}function le(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 ue=/<invoke name="([^"]+)">((?:(?!<invoke name=")[\s\S])*?)<\/invoke>\s*$/,F=/<parameter name="([^"]+)">([\s\S]*?)<\/parameter>/g;function de(e,t){return I(e,t)!==null}function I(e,t){let n=e.trimEnd(),r=ue.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 fe(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:r===`max_tokens`?t:t.map(e=>{if(e.type!==`tool_call`||!(`argumentsParseFailed`in e))return e;let{argumentsParseFailed:t,...n}=e;return n}),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 pe=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 pe.warn(`Unknown chat-completions finish_reason: ${e}`),`end_turn`}}async function*me(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,_=!1,v,y=f({url:t,body:i,headers:r,signal:o,timeout:s,idleTimeout:c,onResponse:e=>{v=e,l?.(e)}});try{for await(let e of y){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&&(_=!0,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()};_||(d.stopReason=`incomplete`),yield{type:`done`,reason:d.stopReason,message:P(p(!0),u??new Set),providerUsage:A(v)}}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 he=new Set([`authorization`,`x-api-key`]),ge=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/,_e=/[\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(!ge.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(_e,``).trim();s&&i.set(e.toLowerCase(),{name:e,value:s})}return i}function ve(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 ye(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(ve(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)&&he.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 be(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 xe(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 Se=[/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?!!Se.some(e=>e.test(t)):!1}const Ce=[/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],we=new Set([`PROVIDER_INCOMPLETE_STREAM`,`PROVIDER_STREAM_ERROR`]),Te=[/rate_limit_error/i,/overloaded_error/i,/throttling/i,/flow[\s_-]?control/i,/流量控制/,/限流/,/请求过于频繁/];function Ee(e){return q(e,e=>{let t=e.headers;return t===void 0?void 0:t})}function De(e){let t=Ee(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 Z(e){return q(e,e=>typeof e.code==`string`?e.code:void 0)}function Oe(e){return q(e,e=>{let t=e.abortKind;if(t===`idle`||t===`wallclock`||t===`external`)return t})}const ke=[/many-image requests/i,/image dimensions exceed/i,/image exceeds \d+\s*(?:mb|bytes)/i];function Ae(e){if(e==null||J(e)!==void 0||Oe(e)!==void 0)return!1;let t=Y(e);if(t&&Te.some(e=>e.test(t)))return!1;let n=Z(e);return n&&we.has(n)?!0:!!t&&Ce.some(e=>e.test(t))}function je(e){if(e==null)return!1;let t=Z(e);return t===`PROVIDER_AUTH_MISSING`||t===`PROVIDER_AUTH_REFRESH_FAILED`?!0:J(e)===401}function Me(e){let t=Z(e);return t===`PROVIDER_AUTH_MISSING`?`credential-missing`:t===`PROVIDER_AUTH_REFRESH_FAILED`?`refresh-failed`:`server-rejected`}function Ne(e){if(e==null)return`fatal`;let t=J(e);if(t===400){let t=Y(e);if(ke.some(e=>e.test(t)))return`image-constraint`}if(X(e))return`context-overflow`;if(De(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&&Te.some(e=>e.test(n)))return`retryable`;if(t!==void 0&&t>=400&&t<500)return`fatal`;let r=Z(e);return r&&we.has(r)||n&&Ce.some(e=>e.test(n))?`retryable`:`fatal`}function Pe(e){return q(e,e=>Fe(e.headers))}function Fe(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 Ie(e){return g(e,`recordings`)}async function*Le(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)+`
|
|
7
|
+
`))}return t?{status:`unknown`,standardLimits:t}:null}const ce=i(`@x-otto/provider:stream-state`);function le(){return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0}}function j(e,t){try{return{args:JSON.parse(e),parseFailed:!1}}catch{return ce.debug({toolName:t,argumentsJson:e.slice(0,500),length:e.length},`Failed to parse tool arguments JSON`),{args:{},parseFailed:!0}}}function ue(e,t){return j(e,t).args}function de(e){return new Set(e?.map(e=>e.name)??[])}function M(e,t,n){let{args:r,parseFailed:i}=j(n,t);return{type:`tool_call`,id:e,name:t,arguments:r,...i?{argumentsParseFailed:!0}:{}}}function N(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=F(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(M(`recovered_${n}`,i.name,i.argumentsJson)),{...e,content:a}}const fe=/<invoke name="([^"]+)">((?:(?!<invoke name=")[\s\S])*?)<\/invoke>\s*$/,P=/<parameter name="([^"]+)">([\s\S]*?)<\/parameter>/g;function pe(e,t){return F(e,t)!==null}function F(e,t){let n=e.trimEnd(),r=fe.exec(n);if(!r)return null;let i=r[1];if(!t.has(i))return null;let a={},o=r[2],s;for(P.lastIndex=0;(s=P.exec(o))!==null;)a[s[1]]=s[2];return{name:i,argumentsJson:JSON.stringify(a),matchStart:r.index}}function I(){return{...le(),textContent:``,thinkingText:``,toolCalls:new Map,stopReason:`end_turn`}}function L(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(M(t.id,t.name,t.argumentsJson));return n}function me(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(M(e.id,e.name,e.argumentsJson));return n}function R(e,t,n,r){return{role:`assistant`,content:r===`max_tokens`?t:t.map(e=>{if(e.type!==`tool_call`||!(`argumentsParseFailed`in e))return e;let{argumentsParseFailed:t,...n}=e;return n}),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 he=i(`@x-otto/provider:chat-completions-stream`);function z(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 he.warn(`Unknown chat-completions finish_reason: ${e}`),`end_turn`}}async function*ge(e){let{url:t,headers:n,body:i,identity:a,signal:o,timeout:s,idleTimeout:c,onResponse:l,registeredToolNames:u}=e,d=I(),f=(e=!1)=>R(a,L(d,e),d,d.stopReason),m=!1,h=!1,g=!1,_=!1,v,y=p({url:t,body:i,headers:n,signal:o,timeout:s,idleTimeout:c,onResponse:e=>{v=e,l?.(e)}});try{for await(let e of y){if(e.data===`[DONE]`)break;let t;try{t=JSON.parse(e.data)}catch{continue}if(t.error){let e=t.error,n=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 r(`Chat Completions stream error: ${n}`,{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 n=t.choices?.[0];if(!n)continue;let i=n.delta;if(m||(m=!0,yield{type:`start`,partial:f()}),n.finish_reason&&(_=!0,d.stopReason=z(n.finish_reason)),!i)continue;if(i.content){let e=i.content;h||(h=!0,yield{type:`text_start`,index:0,partial:f()}),d.textContent+=e,yield{type:`text_delta`,index:0,delta:e,partial:f()}}let a=i.reasoning_content??i.reasoning??i.reasoning_text??null;if(a&&(g||(g=!0,yield{type:`thinking_start`,index:0,partial:f()}),d.thinkingText+=a,yield{type:`thinking_delta`,index:0,delta:a,partial:f()}),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:f()});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:f()}}}}g&&(yield{type:`thinking_end`,index:0,content:d.thinkingText,partial:f()}),h&&(yield{type:`text_end`,index:0,content:d.textContent,partial:f()});for(let[e,t]of d.toolCalls)yield{type:`tool_call_end`,index:e,toolCall:M(t.id,t.name,t.argumentsJson),partial:f()};_||(d.stopReason=`incomplete`),yield{type:`done`,reason:d.stopReason,message:N(f(!0),u??new Set),providerUsage:se(v)}}catch(e){yield{type:`error`,error:e instanceof Error?e:new r(`Unknown Chat Completions stream error`,{code:`PROVIDER_STREAM_ERROR`})}}}function B(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 _e=new Set([`authorization`,`x-api-key`]),ve=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/,ye=/[\u0000-\u001f\u007f]/g;function V(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(!ve.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(ye,``).trim();s&&i.set(e.toLowerCase(),{name:e,value:s})}return i}function be(e){if(!e?.headers.length)return;let t={};for(let n of e.headers){if(n.source.kind!==`jwt-claim`)continue;let r=B(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 xe(e){let{logger:t,diagnosticLabel:n,allowAuthHeaderOverride:r}=e,i=[{label:`protocolDefaults`,entries:V(e.protocolDefaults,`protocolDefaults`,t,n)},{label:`staticHeaders`,entries:V(e.staticHeaders,`staticHeaders`,t,n)},{label:`tokenDerived`,entries:V(be(e.tokenDerived),`tokenDerived`,t,n)},{label:`customized`,entries:V(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)&&_e.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 V(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 H=i(`@x-otto/provider:oauth:templates`);function U(e,t){return new Promise((r,i)=>{if(t?.aborted){i(new n(`Login cancelled`,{code:`OAUTH_CANCELLED`}));return}let a=setTimeout(r,e);t?.addEventListener(`abort`,()=>{clearTimeout(a),i(new n(`Login cancelled`,{code:`OAUTH_CANCELLED`}))},{once:!0})})}function W(e){if(e?.aborted)throw new n(`Login cancelled`,{code:`OAUTH_CANCELLED`})}function G(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 Se(e){let{id:r,name:i,clientId:a,authorizeUrl:s,tokenUrl:c,redirectUri:l,scope:u,loopbackPorts:d,callbackPath:p=t,assumesLoopbackAlways:m=!1,extraAuthParams:h,tokenExchangeEncoding:g=`form`,subscriptionScoped:_=!1,oauthBeta:v}=e,y=!m&&Array.isArray(d)&&d.length>0;async function b(e){return G(await e.onManualCode())}async function x(e){let t=await e.waitForCallback();return{code:t.code,returnedState:t.state}}async function S(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(G):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 C(e,t){if(!t){if(m)throw new n(`${i}: loopback required but all ports are unavailable. Configured ports: ${(d??[]).join(`, `)||`none`}.`,{code:`OAUTH_LOOPBACK_FAILED`});return b(e)}return m?x(t):S(e,t)}function ee(e,t,n){let r=new URL(s);if(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),h)for(let[e,t]of Object.entries(h))r.searchParams.set(e,t);return r.toString().replace(/\+/g,`%20`)}async function w(e,t){let r=g===`json`,a={Accept:`application/json`},o;r?(a[`Content-Type`]=`application/json`,o=JSON.stringify(e)):(a[`Content-Type`]=`application/x-www-form-urlencoded`,o=new URLSearchParams(e).toString());let s;try{s=await fetch(c,{method:`POST`,headers:a,body:o})}catch(e){let t=e.cause;throw new n(`${i} token endpoint unreachable (${t?.code??t?.message??e.message}) — ${c}`,{code:`OAUTH_TOKEN_NETWORK`,cause:e})}let l;try{l=await s.json()}catch(e){throw new n(`${i} token endpoint returned non-JSON response (HTTP ${s.status})`,{code:`OAUTH_TOKEN_FAILED`,cause:e})}if(!l.access_token)throw new n(`${i} token exchange failed: ${l.error_description||l.error||`HTTP ${s.status}`}`,{code:`OAUTH_TOKEN_FAILED`,status:s.status,errorType:l.error});return{access:l.access_token,refresh:l.refresh_token??t??``,expires:Date.now()+(l.expires_in??0)*1e3}}return{id:r,name:i,usesCallbackServer:!1,oauthBeta:v,subscriptionScoped:_,async login(e){if(!y&&!m&&!e.onManualCode)throw new n(`${i} OAuth requires an onManualCode callback to paste the code.`,{code:`OAUTH_MANUAL_CODE_REQUIRED`});W(e.signal);let{verifier:t,challenge:r}=o(),s=t,c;if(Array.isArray(d)&&d.length>0)try{c=await f({ports:d,callbackPath:p,expectedState:s,signal:e.signal})}catch(e){if(H.info(`${i}: loopback ports [${d.join(`,`)}] unavailable; `+(m?``:`falling back to manual paste.`)+` (${e.message})`),m)throw new n(`${i}: loopback required but all ports [${d.join(`,`)}] are unavailable.`,{code:`OAUTH_LOOPBACK_FAILED`})}let u=c?`http://localhost:${c.port}${p}`:l;try{let o=ee(u,r,s);e.onAuth({url:o,instructions:c?`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:l,returnedState:d}=await C(e,c);if(W(e.signal),!l)throw new n(`Empty authorization code.`,{code:`OAUTH_AUTHORIZE_FAILED`});if(d!==void 0&&d!==s)throw new n(`OAuth state mismatch (possible CSRF).`,{code:`OAUTH_STATE_MISMATCH`});d===void 0&&H.warn(`Authorization code returned without state; skipping CSRF state check.`);let f=await w({grant_type:`authorization_code`,code:l,state:d??s,client_id:a,redirect_uri:u,code_verifier:t});return H.info(`${i} OAuth login completed`),f}finally{await c?.close()}},async refreshToken(e){return w({grant_type:`refresh_token`,refresh_token:e.refresh,client_id:a},e.refresh)},getAccessKey(e){return e.access}}}function Ce(e){let{id:t,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,t,r){let i=await e.text();if(!e.ok)throw new n(`${r} failed: HTTP ${e.status}${i?`: ${i.slice(0,200)}`:``}`,{code:t,status:e.status});try{return JSON.parse(i)}catch{throw new n(`${r} returned a non-JSON response.`,{code:t})}}function p(e,t){return e.replace(/\{domain\}/g,t)}async function m(e,t,a,s,c){let l=Date.now()+s*1e3;for(;Date.now()<l;){if(c?.aborted)throw new n(`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:t,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 U(Math.max(1e3,Math.min(Math.floor(a*1e3),l-Date.now())),c);continue}if(u.error===`slow_down`){a+=5,await U(Math.max(1e3,Math.min(Math.floor(a*1e3),l-Date.now())),c);continue}throw new n(`Authorize failed: ${u.error}${u.error_description?`: ${u.error_description}`:``}`,{code:`OAUTH_AUTHORIZE_FAILED`})}if(u.access_token)return u.access_token}throw new n(`Timed out while waiting for ${r} device authorization.`,{code:`OAUTH_AUTHORIZE_TIMEOUT`})}async function h(e,t){if(!s)throw new n(`${r} device-flow OAuth requires refreshUrlTemplate to be declared.`,{code:`OAUTH_REFRESH_URL_MISSING`});let i=p(s,t),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 n(`${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:t,name:r,async login(e){let t=`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 n(`Login cancelled`,{code:`OAUTH_CANCELLED`});let a=i.trim()||`github.com`;t=a.startsWith(`http://`)||a.startsWith(`https://`)?new URL(a).hostname:a}let o=p(a,t),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 n(`${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(t,s.device_code,s.interval,s.expires_in,e.signal),{access:g,expires:_}=await h(u,t),v={access:g,refresh:u,expires:_};return l&&t!==`github.com`&&(v.domain=t),await e.onProgress?.(`...`),H.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 K(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 q(e){return K(e,e=>{if(typeof e.status==`number`)return e.status;if(typeof e.statusCode==`number`)return e.statusCode})}function J(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 we=[/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 Y(e){if(e==null)return!1;if(q(e)===413)return!0;let t=J(e);return t?!!we.some(e=>e.test(t)):!1}const X=[/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],Te=new Set([`PROVIDER_INCOMPLETE_STREAM`,`PROVIDER_STREAM_ERROR`]),Ee=[/rate_limit_error/i,/overloaded_error/i,/throttling/i,/flow[\s_-]?control/i,/流量控制/,/限流/,/请求过于频繁/];function De(e){return K(e,e=>{let t=e.headers;return t===void 0?void 0:t})}function Oe(e){let t=De(e);if(!t)return null;let n=u(t,`anthropic-ratelimit-unified-status`);if(n!==`rejected`&&n!==`allowed_warning`)return null;let r=u(t,`anthropic-ratelimit-unified-representative-claim`),i=u(t,`anthropic-ratelimit-unified-reset`);return{status:n,type:r,resetsAt:i?Number(i):void 0}}function Z(e){return K(e,e=>typeof e.code==`string`?e.code:void 0)}function ke(e){return K(e,e=>{let t=e.abortKind;if(t===`idle`||t===`wallclock`||t===`external`)return t})}const Ae=[/many-image requests/i,/image dimensions exceed/i,/image exceeds \d+\s*(?:mb|bytes)/i];function je(e){if(e==null||q(e)!==void 0||ke(e)!==void 0)return!1;let t=J(e);if(t&&Ee.some(e=>e.test(t)))return!1;let n=Z(e);return n&&Te.has(n)?!0:!!t&&X.some(e=>e.test(t))}function Me(e){if(e==null)return!1;let t=Z(e);return t===`PROVIDER_AUTH_MISSING`||t===`PROVIDER_AUTH_REFRESH_FAILED`?!0:q(e)===401}function Ne(e){let t=Z(e);return t===`PROVIDER_AUTH_MISSING`?`credential-missing`:t===`PROVIDER_AUTH_REFRESH_FAILED`?`refresh-failed`:`server-rejected`}function Pe(e){if(e==null)return`fatal`;let t=q(e);if(t===400){let t=J(e);if(Ae.some(e=>e.test(t)))return`image-constraint`}if(Y(e))return`context-overflow`;if(Oe(e)?.status===`rejected`)return`fatal`;if(t===429||t!==void 0&&t>=500&&t<=599)return`retryable`;let n=J(e);if(t===void 0&&n&&Ee.some(e=>e.test(n)))return`retryable`;if(t!==void 0&&t>=400&&t<500)return`fatal`;let r=Z(e);return r&&Te.has(r)||n&&X.some(e=>e.test(n))?`retryable`:`fatal`}function Fe(e){return K(e,e=>Ie(e.headers))}function Ie(e){let t=u(e,`retry-after-ms`);if(t!==void 0){let e=Number(t);if(Number.isFinite(e)&&e>=0)return e}let n=u(e,`retry-after`);if(n!==void 0){let e=Number(n);if(Number.isFinite(e)&&e>=0)return e*1e3}}function Le(e){return _(e,`recordings`)}async function*Re(e,t,n){h(_(n,`..`),{recursive:!0,mode:448});let r=m(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)+`
|
|
8
8
|
`);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)+`
|
|
9
|
-
`),yield t}}finally{await new Promise(e=>r.end(()=>e()))}}async function
|
|
10
|
-
`).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*ze(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
|
|
9
|
+
`),yield t}}finally{await new Promise(e=>r.end(()=>e()))}}async function Q(e){let t=(await g(e,`utf-8`)).split(`
|
|
10
|
+
`).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*ze(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 Be(e){return{id:`replay/${e.header.modelId}`,name:`Replay of ${e.header.modelId}`,api:$,provider:`replay`,contextWindow:e.header.contextWindow}}var Ve=class{id=$;displayName=`Replay Provider (RFC-200)`;recording;constructor(e,t={}){this.filePath=e,this.options=t}async preload(){return this.recording??=await Q(this.filePath),this.recording}async*converse(e,t,n,r){yield*ze(await this.preload(),this.options,n.signal??r)}};function He(e,t={}){return()=>new Ve(e,t)}export{Ce as DeviceFlowOAuthTemplate,Se as PKCEOAuthTemplate,$ as REPLAY_API,Ve as ReplayProviderStream,R as assembleAssistantMessage,w as assertSystemNotificationPlacement,me as blocksContent,ae as buildChatCompletionsBody,k as buildChatCompletionsMessages,Be as buildReplayModel,xe as buildRequestHeaders,D as clampThinkingLevel,Ne as classifyAuthErrorType,Pe as classifyStreamError,a as createPkcePair,He as createReplayProviderFactory,C as degradedSystemNotificationText,ke as extractAbortKind,Oe as extractAnthropicRateLimit,B as extractJwtClaim,Fe as extractRetryAfterMs,se as extractStandardRateLimitHeaders,L as flatContent,s as generateChallenge,c as generateState,l as generateVerifier,pe as hasTrailingInvokeXml,I as initFlatStreamState,le as initStreamUsage,Me as isAuthError,Y as isContextOverflowError,je as isNetworkDisconnectError,Q as loadRecording,z as mapChatFinishReason,ee as mergeConsecutiveSystemNotifications,v as noopWireProtocolLogger,ue as parseToolArguments,j as parseToolArgumentsWithStatus,Re as recordStream,Le as recordingsDir,N as recoverLiteralInvokeToolCalls,de as registeredToolNames,ze as replayStream,y as resolveProviderBaseUrl,T as sanitizeSurrogates,x as sanitizeToolRoundtrips,d as startLoopbackServer,ge as streamChatCompletions,te as toJsonSchema,M 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.27",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist"
|
|
6
6
|
],
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"tag": "alpha"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@x-otto/
|
|
23
|
-
"@x-otto/
|
|
22
|
+
"@x-otto/interchange": "0.1.0-alpha.27",
|
|
23
|
+
"@x-otto/shared": "0.1.0-alpha.27"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsdown && rm -f dist/*.map && sed -i '' '\\|//# sourceMappingURL=|d' dist/*.js 2>/dev/null; true",
|