@earendil-works/pi-coding-agent
Version:
Coding agent CLI with read, bash, edit, write tools and session management
5 lines (4 loc) • 11.4 kB
JavaScript
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
import{buildCopilotDynamicHeaders,hasCopilotVisionInput}from"./chunk-PGXDEOVV.js";import{convertResponsesMessages,convertResponsesTools,getResponsesToolSupport,processResponsesStream}from"./chunk-QN4TOIZN.js";import{clampOpenAIPromptCacheKey}from"./chunk-PRRNXB7S.js";import{OpenAI}from"./chunk-CF5GWZHW.js";import"./chunk-PJACZCIR.js";import{buildBaseOptions,createGrammarToolInputProperties,resolveSamplingParams}from"./chunk-ZGYS4UTC.js";import"./chunk-L2ZPNLYD.js";import{retryProviderRequest}from"./chunk-PMRZO46Y.js";import{formatProviderError,normalizeProviderError}from"./chunk-RKNK4Y6L.js";import{headersToRecord}from"./chunk-UTB4DTYQ.js";import"./chunk-FFMDRXC4.js";import{getProviderEnvValue}from"./chunk-7DDKXS2Q.js";import{clampThinkingLevel,getDeclaredTools,resolveTranscript,resolveTranscriptTools}from"./chunk-AUUCDC7R.js";import{AssistantMessageEventStream}from"./chunk-LPXNMA2W.js";import{getIdentityHeaders}from"./chunk-BAC3QPNW.js";import"./chunk-JXWJOIH4.js";var OPENAI_TOOL_CALL_PROVIDERS=new Set(["openai","openai-codex","opencode"]),OPENAI_RESPONSES_MIN_OUTPUT_TOKENS=16,CHATGPT_USAGE_URL="https://chatgpt.com/settings/usage",CHATGPT_WORKSPACE_LIMIT_HINT="You've reached your ChatGPT workspace's usage limit. Ask your workspace admin to increase it at admin.openai.com \u2192 Workspace \u2192 Usage limits.",CONFIGURATION_UPDATE_REQUEST_EFFORT="medium";function isChatGPTSignIn(model,apiKey){return model.provider==="openai"&&model.baseUrl==="https://api.openai.com/v1"&&apiKey!==void 0&&!apiKey.startsWith("sk-")}function hasHeader(headers,name){if(!headers)return!1;let expected=name.toLowerCase();for(let[key,value]of Object.entries(headers))if(key.toLowerCase()===expected&&value!==null&&value.trim().length>0)return!0;return!1}function getClientApiKey(provider,apiKey,headers){if(apiKey)return apiKey;if(hasHeader(headers,"authorization")||hasHeader(headers,"cf-aig-authorization"))return"unused";throw new Error(`No API key for provider: ${provider}`)}function detectSessionAffinityFormat(model){return model.provider==="openrouter"||model.baseUrl.includes("openrouter.ai")?"openrouter":"openai"}function resolveCacheRetention(cacheRetention,env){return cacheRetention||(getProviderEnvValue("PI_CACHE_RETENTION",env)==="long"?"long":"short")}function getCompat(model){return{supportsDeveloperRole:model.compat?.supportsDeveloperRole??!0,supportsMidConvoSystemMessages:model.compat?.supportsMidConvoSystemMessages??!1,sessionAffinityFormat:model.compat?.sessionAffinityFormat??detectSessionAffinityFormat(model),promptCacheKeyMode:model.compat?.promptCacheKeyMode??"auto",supportsLongCacheRetention:model.compat?.supportsLongCacheRetention??!0,supportsStrictMode:model.compat?.supportsStrictMode??!1,supportsOpenAIGrammarTools:model.compat?.supportsOpenAIGrammarTools??!1,supportsAdditionalTools:model.compat?.supportsAdditionalTools??!1,supportsToolSearch:model.compat?.supportsToolSearch??!1,supportsExplicitPromptCacheMode:model.compat?.supportsExplicitPromptCacheMode??!1,supportsMaxOutputTokens:model.compat?.supportsMaxOutputTokens??!0,supportsMidConvoEffort:model.compat?.supportsMidConvoEffort??!1}}function getConfigurationUpdateEffort(model,options,compat){if(!(!compat.supportsMidConvoEffort||!options?.reasoningEffort||isChatGPTSignIn(model,options.apiKey)))return model.thinkingLevelMap?.[options.reasoningEffort]??options.reasoningEffort}function getPromptCacheRetention(compat,cacheRetention){return cacheRetention==="long"&&compat.supportsLongCacheRetention&&!compat.supportsExplicitPromptCacheMode?"24h":void 0}function getPromptCacheOptions(compat,cacheRetention){if(compat.supportsExplicitPromptCacheMode){if(cacheRetention==="none")return{mode:"explicit"};if(cacheRetention==="long"&&compat.supportsLongCacheRetention)return{ttl:"30m"}}}var stream=(model,context,options)=>{let stream2=new AssistantMessageEventStream,normalizedContext=resolveTranscript(context,getCompat(model).supportsMidConvoSystemMessages);return(async()=>{let compat=getCompat(model),configurationUpdateEffort=getConfigurationUpdateEffort(model,options,compat),output={role:"assistant",content:[],api:model.api,provider:model.provider,model:model.id,...configurationUpdateEffort===void 0?{}:{providerThinkingLevel:configurationUpdateEffort},usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};try{let apiKey=getClientApiKey(model.provider,options?.apiKey,options?.headers),cacheSessionId=resolveCacheRetention(options?.cacheRetention,options?.env)==="none"?void 0:options?.sessionId,grammarToolInputProperties=createGrammarToolInputProperties(getDeclaredTools(normalizedContext.messages),compat.supportsOpenAIGrammarTools),client=createClient(model,normalizedContext,apiKey,options?.headers,options?.identity,options?.fetch,cacheSessionId),params=buildParams(model,normalizedContext,options,compat,grammarToolInputProperties,configurationUpdateEffort),nextParams=await options?.onPayload?.(params,model);nextParams!==void 0&&(params=nextParams);let requestOptions={...options?.signal?{signal:options.signal}:{},...options?.timeoutMs!==void 0?{timeout:options.timeoutMs}:{},maxRetries:0},{data:openaiStream,response}=await retryProviderRequest(()=>client.responses.create(params,requestOptions).withResponse(),{maxRetries:options?.maxRetries,maxRetryDelayMs:options?.maxRetryDelayMs,signal:options?.signal});if(await options?.onResponse?.({status:response.status,headers:headersToRecord(response.headers)},model),stream2.push({type:"start",partial:output}),await processResponsesStream(openaiStream,output,stream2,model,{onProviderStreamEvent:options?.onProviderStreamEvent,serviceTier:options?.serviceTier,grammarToolInputProperties,applyServiceTierPricing:(usage,serviceTier)=>applyServiceTierPricing(usage,serviceTier,model)}),options?.signal?.aborted)throw new Error("Request was aborted");if(output.stopReason==="pending")throw new Error("OpenAI Responses stream ended without a stop reason");if(output.stopReason==="aborted"||output.stopReason==="error")throw new Error(output.errorMessage||"An unknown error occurred");stream2.push({type:"done",reason:output.stopReason,message:output}),stream2.end()}catch(error){output.stopReason=options?.signal?.aborted?"aborted":"error";let errorMessage=formatProviderError(normalizeProviderError(error),`${model.provider==="openai"?"OpenAI":model.provider} API error`);errorMessage.includes("subscription_sharing_usage_limit_exceeded")?output.errorMessage=`${errorMessage}
Check your ChatGPT usage: ${CHATGPT_USAGE_URL}`:errorMessage.includes("subscription_sharing_workplace_individual_usage_limit_exceeded")?output.errorMessage=`${errorMessage}
${CHATGPT_WORKSPACE_LIMIT_HINT}`:output.errorMessage=errorMessage,stream2.push({type:"error",reason:output.stopReason,error:output}),stream2.end()}})(),stream2},streamSimple=(model,context,options)=>{getClientApiKey(model.provider,options?.apiKey,options?.headers);let base={...buildBaseOptions(model,context,options,options?.apiKey),toolChoice:options?.toolChoice},clampedReasoning=options?.reasoning?clampThinkingLevel(model,options.reasoning):void 0;return stream(model,context,{...base,reasoningEffort:clampedReasoning==="off"?void 0:clampedReasoning})};function createClient(model,context,apiKey,optionsHeaders,identity,fetch,sessionId){let compat=getCompat(model),headers={...getIdentityHeaders(model,identity),...model.headers};if(model.provider==="github-copilot"){let hasImages=hasCopilotVisionInput(context.messages),copilotHeaders=buildCopilotDynamicHeaders({messages:context.messages,hasImages});Object.assign(headers,copilotHeaders)}return sessionId&&(compat.sessionAffinityFormat==="openrouter"?headers["x-session-id"]=sessionId:(compat.sessionAffinityFormat==="openai"&&(headers["session-id"]=sessionId),headers["x-client-request-id"]=sessionId)),optionsHeaders&&Object.assign(headers,optionsHeaders),new OpenAI({apiKey,baseURL:model.baseUrl,dangerouslyAllowBrowser:!0,fetch,defaultHeaders:headers})}function buildParams(model,context,options,compat,grammarToolInputProperties,configurationUpdateEffort){let transcriptTools=resolveTranscriptTools(context.messages,getResponsesToolSupport(compat)),messages=convertResponsesMessages(model,context,OPENAI_TOOL_CALL_PROVIDERS,{grammarToolInputProperties,supportsMidConvoSystemMessages:compat.supportsMidConvoSystemMessages,supportsAdditionalTools:compat.supportsAdditionalTools,supportsToolSearch:compat.supportsToolSearch,toolOptions:{supportsStrictMode:compat.supportsStrictMode,supportsOpenAIGrammarTools:compat.supportsOpenAIGrammarTools},configurationUpdateEffort}),cacheRetention=resolveCacheRetention(options?.cacheRetention,options?.env),sendPromptCacheKey=cacheRetention!=="none"&&compat.promptCacheKeyMode!=="disabled",omitUnsupportedFields=isChatGPTSignIn(model,options?.apiKey),params={model:model.id,input:messages,stream:!0,prompt_cache_key:sendPromptCacheKey?clampOpenAIPromptCacheKey(options?.sessionId):void 0,prompt_cache_retention:omitUnsupportedFields?void 0:getPromptCacheRetention(compat,cacheRetention),prompt_cache_options:omitUnsupportedFields?void 0:getPromptCacheOptions(compat,cacheRetention),store:!1};options?.maxTokens&&compat.supportsMaxOutputTokens&&!omitUnsupportedFields&&(params.max_output_tokens=Math.max(options.maxTokens,OPENAI_RESPONSES_MIN_OUTPUT_TOKENS)),options?.temperature!==void 0&&!omitUnsupportedFields&&(params.temperature=options?.temperature),options?.serviceTier!==void 0&&(params.service_tier=options.serviceTier),transcriptTools.requestTools.length>0&&(params.tools=convertResponsesTools(transcriptTools.requestTools,{supportsStrictMode:compat.supportsStrictMode,supportsOpenAIGrammarTools:compat.supportsOpenAIGrammarTools})),options?.toolChoice!==void 0&&(params.tool_choice=options.toolChoice);let reasoningEffort=options?.reasoningEffort??(options?.reasoningSummary?"medium":void 0);if(model.reasoning){if(reasoningEffort){let requestedEffort=options?.reasoningEffort?model.thinkingLevelMap?.[options.reasoningEffort]??options.reasoningEffort:reasoningEffort,effort=configurationUpdateEffort===void 0?requestedEffort:CONFIGURATION_UPDATE_REQUEST_EFFORT;params.reasoning={effort,summary:options?.reasoningSummary||"auto"},params.include=["reasoning.encrypted_content"]}else model.provider!=="github-copilot"&&model.thinkingLevelMap?.off!==null&&(params.reasoning={effort:model.thinkingLevelMap?.off??"none"});model.provider==="xai"&&(params.include=["reasoning.encrypted_content"])}let samplingParams=resolveSamplingParams(model,reasoningEffort??"off",options?.samplingParams);return samplingParams&&Object.assign(params,samplingParams),params}function getServiceTierCostMultiplier(model,serviceTier){switch(serviceTier){case"flex":return .5;case"priority":case"fast":return model.id==="gpt-5.5"?2.5:2;default:return 1}}function applyServiceTierPricing(usage,serviceTier,model){let multiplier=getServiceTierCostMultiplier(model,serviceTier);multiplier!==1&&(usage.cost.input*=multiplier,usage.cost.output*=multiplier,usage.cost.cacheRead*=multiplier,usage.cost.cacheWrite*=multiplier,usage.cost.total=usage.cost.input+usage.cost.output+usage.cost.cacheRead+usage.cost.cacheWrite)}export{stream,streamSimple};