@oh-my-pi/pi-ai 13.6.0 → 13.6.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "13.6.0",
4
+ "version": "13.6.1",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Can Boluk",
@@ -41,7 +41,7 @@
41
41
  "@aws-sdk/client-bedrock-runtime": "^3.1000",
42
42
  "@bufbuild/protobuf": "^2.11",
43
43
  "@google/genai": "^1.43",
44
- "@oh-my-pi/pi-utils": "13.6.0",
44
+ "@oh-my-pi/pi-utils": "13.6.1",
45
45
  "@sinclair/typebox": "^0.34",
46
46
  "@smithy/node-http-handler": "^4.4",
47
47
  "ajv": "^8.18",
@@ -7,6 +7,7 @@ import {
7
7
  type OpenAICompatibleModelMapperContext,
8
8
  type OpenAICompatibleModelRecord,
9
9
  } from "../utils/discovery/openai-compatible";
10
+ import { getGitHubCopilotBaseUrl } from "../utils/oauth/github-copilot";
10
11
 
11
12
  const MODELS_DEV_URL = "https://models.dev/api.json";
12
13
  const ANTHROPIC_BASE_URL = "https://api.anthropic.com/v1";
@@ -1286,7 +1287,11 @@ function extractCopilotLimits(entry: OpenAICompatibleModelRecord): {
1286
1287
 
1287
1288
  export function githubCopilotModelManagerOptions(config?: GithubCopilotModelManagerConfig): ModelManagerOptions<Api> {
1288
1289
  const apiKey = config?.apiKey;
1289
- const baseUrl = config?.baseUrl ?? "https://api.individual.githubcopilot.com";
1290
+ const configuredBaseUrl = config?.baseUrl ?? "https://api.individual.githubcopilot.com";
1291
+ const baseUrl =
1292
+ apiKey?.includes("proxy-ep=") && configuredBaseUrl.includes("githubcopilot.com")
1293
+ ? getGitHubCopilotBaseUrl(apiKey)
1294
+ : configuredBaseUrl;
1290
1295
  const references = createBundledReferenceMap<Api>("github-copilot");
1291
1296
  const globalReferences = createGlobalReferenceMap();
1292
1297
  return {
@@ -32,7 +32,11 @@ import { isAnthropicOAuthToken, normalizeToolCallId, resolveCacheRetention } fro
32
32
  import { AssistantMessageEventStream } from "../utils/event-stream";
33
33
  import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-inspector";
34
34
  import { parseStreamingJson } from "../utils/json-parse";
35
- import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers";
35
+ import {
36
+ buildCopilotDynamicHeaders,
37
+ hasCopilotVisionInput,
38
+ resolveGitHubCopilotBaseUrl,
39
+ } from "./github-copilot-headers";
36
40
  import { transformMessages } from "./transform-messages";
37
41
 
38
42
  export type AnthropicHeaderOptions = {
@@ -396,7 +400,10 @@ function normalizeBaseUrl(baseUrl: string | undefined): string | undefined {
396
400
  return trimmed ? trimmed.replace(/\/+$/, "") : undefined;
397
401
  }
398
402
 
399
- function resolveAnthropicBaseUrl(model: Model<"anthropic-messages">): string | undefined {
403
+ function resolveAnthropicBaseUrl(model: Model<"anthropic-messages">, apiKey?: string): string | undefined {
404
+ if (model.provider === "github-copilot") {
405
+ return normalizeBaseUrl(resolveGitHubCopilotBaseUrl(model.baseUrl, apiKey) ?? model.baseUrl);
406
+ }
400
407
  if (model.provider === "anthropic" && isFoundryEnabled()) {
401
408
  const foundryBaseUrl = normalizeBaseUrl($env.FOUNDRY_BASE_URL);
402
409
  if (foundryBaseUrl) {
@@ -583,7 +590,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
583
590
 
584
591
  try {
585
592
  const apiKey = options?.apiKey ?? getEnvApiKey(model.provider) ?? "";
586
- const baseUrl = resolveAnthropicBaseUrl(model) ?? "https://api.anthropic.com";
593
+ const baseUrl = resolveAnthropicBaseUrl(model, apiKey) ?? "https://api.anthropic.com";
587
594
 
588
595
  const { client, isOAuthToken } = createClient(model, {
589
596
  model,
@@ -932,7 +939,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
932
939
  isOAuth,
933
940
  } = args;
934
941
  const oauthToken = isOAuth ?? isAnthropicOAuthToken(apiKey);
935
- const baseUrl = resolveAnthropicBaseUrl(model);
942
+ const baseUrl = resolveAnthropicBaseUrl(model, apiKey);
936
943
  const foundryCustomHeaders = resolveAnthropicCustomHeaders(model);
937
944
  const tlsFetchOptions = buildClaudeCodeTlsFetchOptions(model, baseUrl);
938
945
  if (model.provider === "github-copilot") {
@@ -1,4 +1,5 @@
1
1
  import type { Message } from "../types";
2
+ import { getGitHubCopilotBaseUrl } from "../utils/oauth/github-copilot";
2
3
  /**
3
4
  * Infer whether the current request to Copilot is user-initiated or agent-initiated.
4
5
  * Accepts `unknown[]` because providers may pass pre-converted message shapes.
@@ -10,6 +11,14 @@ export type CopilotDynamicHeaders = {
10
11
  initiator: CopilotInitiator;
11
12
  premiumRequests: CopilotPremiumRequests;
12
13
  };
14
+ export function resolveGitHubCopilotBaseUrl(
15
+ baseUrl: string | undefined,
16
+ apiKey: string | undefined,
17
+ ): string | undefined {
18
+ if (!apiKey?.includes("proxy-ep=")) return baseUrl;
19
+ if (baseUrl && !baseUrl.includes("githubcopilot.com")) return baseUrl;
20
+ return getGitHubCopilotBaseUrl(apiKey);
21
+ }
13
22
  export function inferCopilotInitiator(messages: unknown[]): CopilotInitiator {
14
23
  if (messages.length === 0) return "user";
15
24
 
@@ -33,7 +33,11 @@ import { parseStreamingJson } from "../utils/json-parse";
33
33
  import { getKimiCommonHeaders } from "../utils/oauth/kimi";
34
34
  import { adaptSchemaForStrict, NO_STRICT } from "../utils/schema";
35
35
  import { mapToOpenAICompletionsToolChoice } from "../utils/tool-choice";
36
- import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers";
36
+ import {
37
+ buildCopilotDynamicHeaders,
38
+ hasCopilotVisionInput,
39
+ resolveGitHubCopilotBaseUrl,
40
+ } from "./github-copilot-headers";
37
41
  import { transformMessages } from "./transform-messages";
38
42
 
39
43
  /**
@@ -184,7 +188,12 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
184
188
 
185
189
  try {
186
190
  const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
187
- const { client, copilotPremiumRequests } = await createClient(model, context, apiKey, options?.headers);
191
+ const { client, copilotPremiumRequests, baseUrl } = await createClient(
192
+ model,
193
+ context,
194
+ apiKey,
195
+ options?.headers,
196
+ );
188
197
  const params = buildParams(model, context, options);
189
198
  options?.onPayload?.(params);
190
199
  rawRequestDump = {
@@ -192,7 +201,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
192
201
  api: output.api,
193
202
  model: model.id,
194
203
  method: "POST",
195
- url: `${model.baseUrl ?? "https://api.openai.com/v1"}/chat/completions`,
204
+ url: `${baseUrl ?? "https://api.openai.com/v1"}/chat/completions`,
196
205
  body: params,
197
206
  };
198
207
  const openaiStream = await client.chat.completions.create(params, { signal: options?.signal });
@@ -509,6 +518,8 @@ async function createClient(
509
518
  headers = { ...(await getKimiCommonHeaders()), ...headers };
510
519
  }
511
520
  let copilotPremiumRequests: number | undefined;
521
+
522
+ let baseUrl = model.baseUrl;
512
523
  if (model.provider === "github-copilot") {
513
524
  const hasImages = hasCopilotVisionInput(context.messages);
514
525
  const copilot = buildCopilotDynamicHeaders({
@@ -519,17 +530,18 @@ async function createClient(
519
530
  });
520
531
  Object.assign(headers, copilot.headers);
521
532
  copilotPremiumRequests = copilot.premiumRequests;
533
+ baseUrl = resolveGitHubCopilotBaseUrl(model.baseUrl, apiKey) ?? model.baseUrl;
522
534
  }
523
-
524
535
  return {
525
536
  client: new OpenAI({
526
537
  apiKey,
527
- baseURL: model.baseUrl,
538
+ baseURL: baseUrl,
528
539
  dangerouslyAllowBrowser: true,
529
540
  maxRetries: 5,
530
541
  defaultHeaders: headers,
531
542
  }),
532
543
  copilotPremiumRequests,
544
+ baseUrl,
533
545
  };
534
546
  }
535
547
 
@@ -34,7 +34,11 @@ import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-ins
34
34
  import { parseStreamingJson } from "../utils/json-parse";
35
35
  import { adaptSchemaForStrict, NO_STRICT } from "../utils/schema";
36
36
  import { mapToOpenAIResponsesToolChoice } from "../utils/tool-choice";
37
- import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers";
37
+ import {
38
+ buildCopilotDynamicHeaders,
39
+ hasCopilotVisionInput,
40
+ resolveGitHubCopilotBaseUrl,
41
+ } from "./github-copilot-headers";
38
42
  import { transformMessages } from "./transform-messages";
39
43
 
40
44
  /**
@@ -109,7 +113,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses"> = (
109
113
  try {
110
114
  // Create OpenAI client
111
115
  const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
112
- const { client, copilotPremiumRequests } = createClient(model, context, apiKey, options?.headers);
116
+ const { client, copilotPremiumRequests, baseUrl } = createClient(model, context, apiKey, options?.headers);
113
117
  const params = buildParams(model, context, options);
114
118
  options?.onPayload?.(params);
115
119
  rawRequestDump = {
@@ -117,7 +121,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses"> = (
117
121
  api: output.api,
118
122
  model: model.id,
119
123
  method: "POST",
120
- url: `${model.baseUrl ?? "https://api.openai.com/v1"}/responses`,
124
+ url: `${baseUrl ?? "https://api.openai.com/v1"}/responses`,
121
125
  body: params,
122
126
  };
123
127
  const openaiStream = await client.responses.create(
@@ -391,6 +395,8 @@ function createClient(
391
395
 
392
396
  const headers = { ...(model.headers ?? {}), ...(extraHeaders ?? {}) };
393
397
  let copilotPremiumRequests: number | undefined;
398
+
399
+ let baseUrl = model.baseUrl;
394
400
  if (model.provider === "github-copilot") {
395
401
  const hasImages = hasCopilotVisionInput(context.messages);
396
402
  const copilot = buildCopilotDynamicHeaders({
@@ -401,17 +407,18 @@ function createClient(
401
407
  });
402
408
  Object.assign(headers, copilot.headers);
403
409
  copilotPremiumRequests = copilot.premiumRequests;
410
+ baseUrl = resolveGitHubCopilotBaseUrl(model.baseUrl, apiKey) ?? model.baseUrl;
404
411
  }
405
-
406
412
  return {
407
413
  client: new OpenAI({
408
414
  apiKey,
409
- baseURL: model.baseUrl,
415
+ baseURL: baseUrl,
410
416
  dangerouslyAllowBrowser: true,
411
417
  maxRetries: 5,
412
418
  defaultHeaders: headers,
413
419
  }),
414
420
  copilotPremiumRequests,
421
+ baseUrl,
415
422
  };
416
423
  }
417
424