MCPcopy
hub / github.com/OpenCoworkAI/open-codesign / buildPiModel

Function buildPiModel

packages/core/src/agent.ts:264–324  ·  view source on GitHub ↗
(
  model: ModelRef,
  wire: WireApi | undefined,
  baseUrl: string | undefined,
  httpHeaders?: Record<string, string> | undefined,
  apiKey?: string,
)

Source from the content-addressed store, hash-verified

262};
263
264function buildPiModel(
265 model: ModelRef,
266 wire: WireApi | undefined,
267 baseUrl: string | undefined,
268 httpHeaders?: Record<string, string> | undefined,
269 apiKey?: string,
270): PiModel {
271 // Fall through to the canonical public endpoint for the 3 first-party
272 // BYOK providers when the caller omitted baseUrl. This is a fact about
273 // those endpoints (api.anthropic.com is anthropic), not a registry lookup for a
274 // model registry — imported / custom providers still require baseUrl and
275 // will throw if absent.
276 const resolvedBaseUrl =
277 baseUrl && baseUrl.trim().length > 0
278 ? baseUrl
279 : (BUILTIN_PUBLIC_BASE_URLS[model.provider] ?? '');
280 if (resolvedBaseUrl.length === 0) {
281 throw new CodesignError(
282 `Provider "${model.provider}" has no baseUrl configured. Add one in Settings or re-import the config.`,
283 ERROR_CODES.PROVIDER_BASE_URL_MISSING,
284 );
285 }
286 // Defensive: canonicalize stored baseUrl before handing to pi-ai. Rescues
287 // legacy configs that persisted pre-normalization (e.g. raw `/v1/chat/completions`
288 // pasted in an older build). No-op for configs saved post-fix.
289 // For openai-codex-responses, canonicalBaseUrl only strips trailing slashes
290 // — pi-ai's codex wire appends `/codex/responses` from the bare base itself.
291 const canonicalBase = wire ? canonicalBaseUrl(resolvedBaseUrl, wire) : resolvedBaseUrl;
292 const effectiveModelId = normalizeGeminiModelId(model.modelId, canonicalBase);
293 const out: PiModel = {
294 id: effectiveModelId,
295 name: effectiveModelId,
296 api: apiForWire(wire),
297 provider: model.provider,
298 baseUrl: canonicalBase,
299 reasoning: inferReasoning(wire, effectiveModelId, canonicalBase),
300 input: supportsImageInput(wire, effectiveModelId) ? ['text', 'image'] : ['text'],
301 cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
302 contextWindow: 200000,
303 maxTokens: 32000,
304 };
305 const compat = openAIChatCompatForBaseUrl(wire, canonicalBase);
306 if (compat !== undefined) out.compat = compat;
307 if (httpHeaders !== undefined) out.headers = httpHeaders;
308
309 // sub2api / claude2api gateways 403 any request without claude-cli
310 // identity headers. pi-ai only emits them for sk-ant-oat OAuth tokens —
311 // so a custom anthropic baseUrl keyed by a plain token hits the edge WAF.
312 // Inject them here too (this path goes through pi-agent-core, which
313 // forwards model.headers to pi-ai). User-supplied headers keep precedence.
314 // Skip when the key already looks OAuth-shaped: pi-ai's OAuth branch
315 // injects the same set, and leaving that the single source keeps us from
316 // silently overriding future pi-ai header updates on the OAuth path.
317 if (
318 shouldForceClaudeCodeIdentity(wire, canonicalBase) &&
319 (apiKey === undefined || !looksLikeClaudeOAuthToken(apiKey))
320 ) {
321 out.headers = { ...claudeCodeIdentityHeaders(), ...(out.headers ?? {}) };

Callers 1

generateViaAgentFunction · 0.85

Calls 9

canonicalBaseUrlFunction · 0.90
normalizeGeminiModelIdFunction · 0.90
inferReasoningFunction · 0.90
apiForWireFunction · 0.85
supportsImageInputFunction · 0.85

Tested by

no test coverage detected