@oh-my-pi/pi-ai 17.2.2 → 17.2.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [17.2.3] - 2026-08-01
6
+
7
+ ### Added
8
+
9
+ - Added the ai& (`aiand`) provider registry entry with API-key paste login validated against `https://api.aiand.com/v1/models`.
10
+
11
+ ### Fixed
12
+
13
+ - Fixed Anthropic OAuth (Claude Pro/Max subscription) requests hard-429ing (`Usage credits are required for long context requests`) on every beta-gated 1M model — e.g. `claude-sonnet-4-6`, which the default `task`/`smol`/`scout` subagent roles resolve to — regardless of prompt size, breaking all subagents. The 17.2.1 cowork request profile reintroduced the `context-1m-2025-08-07` beta for any model with a 1M catalog window, but subscription credentials have no long-context credit balance so Anthropic rejects the request outright. The beta is no longer advertised on OAuth requests; subscription accounts transparently get the standard 200k window. ([#7238](https://github.com/can1357/oh-my-pi/issues/7238))
14
+ - Fixed OpenAI Codex Responses ignoring disabled cache retention when deriving `prompt_cache_key`, while preserving transport session identity ([#7219](https://github.com/can1357/oh-my-pi/issues/7219)).
15
+
5
16
  ## [17.2.2] - 2026-07-31
6
17
 
7
18
  ### Added
@@ -0,0 +1,7 @@
1
+ import type { OAuthLoginCallbacks } from "./oauth/types.js";
2
+ export declare const loginAiand: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
3
+ export declare const aiandProvider: {
4
+ readonly id: "aiand";
5
+ readonly name: "ai&";
6
+ readonly login: (cb: OAuthLoginCallbacks) => Promise<string>;
7
+ };
@@ -7,6 +7,10 @@ import type { ProviderDefinition } from "./types.js";
7
7
  * list for the loginable providers; non-login model providers are appended.
8
8
  */
9
9
  declare const ALL: ({
10
+ readonly id: "aiand";
11
+ readonly name: "ai&";
12
+ readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
13
+ } | {
10
14
  readonly id: "aimlapi";
11
15
  readonly name: "AIML API";
12
16
  } | {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "17.2.2",
4
+ "version": "17.2.3",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -38,9 +38,9 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@bufbuild/protobuf": "^2.12.1",
41
- "@oh-my-pi/pi-catalog": "17.2.2",
42
- "@oh-my-pi/pi-utils": "17.2.2",
43
- "@oh-my-pi/pi-wire": "17.2.2",
41
+ "@oh-my-pi/pi-catalog": "17.2.3",
42
+ "@oh-my-pi/pi-utils": "17.2.3",
43
+ "@oh-my-pi/pi-wire": "17.2.3",
44
44
  "arktype": "2.2.3",
45
45
  "zod": "^4"
46
46
  },
@@ -157,7 +157,6 @@ function mergeAnthropicBetaHeader(callerHeaders: Record<string, string>, beta: s
157
157
  const midConversationSystemBeta = "mid-conversation-system-2026-04-07";
158
158
  const contextManagementBeta = "context-management-2025-06-27";
159
159
  const structuredOutputsBeta = "structured-outputs-2025-12-15";
160
- const context1mBeta = "context-1m-2025-08-07";
161
160
  const thinkingTokenCountBeta = "thinking-token-count-2026-05-13";
162
161
  const fallbackCreditBeta = "fallback-credit-2026-06-01";
163
162
  const coworkUtilityBetaDefaults = [
@@ -187,15 +186,18 @@ const serverSideFallbackBeta = "server-side-fallback-2026-06-01";
187
186
  function buildCoworkBetas(
188
187
  agentRequest: boolean,
189
188
  thinkingRequest: boolean,
190
- longContext: boolean,
191
189
  disableStrictTools = false,
192
190
  ): readonly string[] {
191
+ // `context-1m-2025-08-07` is intentionally never advertised. OAuth
192
+ // subscription credentials have no long-context credit balance, so Anthropic
193
+ // hard-429s ("Usage credits are required for long context requests") on any
194
+ // beta-gated 1M model regardless of prompt size (#7238). Natively-1M models
195
+ // (e.g. claude-sonnet-5) serve their full window without the beta anyway.
193
196
  if (!agentRequest && !disableStrictTools) return coworkUtilityBetaDefaults;
194
197
  const betas: string[] = [];
195
198
  for (const beta of agentRequest ? coworkAgentBetaDefaults : coworkUtilityBetaDefaults) {
196
199
  if (disableStrictTools && beta === structuredOutputsBeta) continue;
197
200
  betas.push(beta);
198
- if (agentRequest && longContext && beta === "claude-code-20250219") betas.push(context1mBeta);
199
201
  }
200
202
  if (!agentRequest) return betas;
201
203
  if (thinkingRequest) betas.push(effortBeta);
@@ -245,7 +247,7 @@ export function buildAnthropicHeaders(options: AnthropicHeaderOptions): Record<s
245
247
  // Cowork's beta profile is part of the OAuth fingerprint; API-key requests
246
248
  // default to extras only, matching the streaming path.
247
249
  const betaHeader = buildBetaHeader(
248
- options.coworkBetas ?? (oauthToken ? buildCoworkBetas(true, true, false) : []),
250
+ options.coworkBetas ?? (oauthToken ? buildCoworkBetas(true, true) : []),
249
251
  extraBetas,
250
252
  );
251
253
  const acceptHeader = oauthToken ? "application/json" : stream ? "text/event-stream" : "application/json";
@@ -2949,14 +2951,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
2949
2951
  isCloudflareAiGateway: model.provider === "cloudflare-ai-gateway",
2950
2952
  allowAnthropicHeaderOverrides: model.compat.allowAnthropicHeaderOverrides,
2951
2953
  claudeCodeSessionId,
2952
- coworkBetas: oauthToken
2953
- ? buildCoworkBetas(
2954
- hasTools || thinkingEnabled,
2955
- thinkingEnabled,
2956
- (model.contextWindow ?? 0) >= 1_000_000,
2957
- disableStrictTools,
2958
- )
2959
- : [],
2954
+ coworkBetas: oauthToken ? buildCoworkBetas(hasTools || thinkingEnabled, thinkingEnabled, disableStrictTools) : [],
2960
2955
  });
2961
2956
 
2962
2957
  if (model.provider === "cloudflare-ai-gateway") {
@@ -111,6 +111,7 @@ import {
111
111
  finalizePendingResponsesToolCalls,
112
112
  finalizeReasoningThinking,
113
113
  finalizeToolCallArgumentsDone,
114
+ getOpenAIPromptCacheKey,
114
115
  hasExecutableIncompleteResponsesToolCalls,
115
116
  isOpenAIResponsesProgressEvent,
116
117
  mapOpenAIResponsesStopReason,
@@ -1373,7 +1374,7 @@ async function buildCodexRequestContext(
1373
1374
  const accountId = getCodexAccountId(apiKey);
1374
1375
  const baseUrl = model.baseUrl || CODEX_BASE_URL;
1375
1376
  const url = resolveCodexResponsesUrl(baseUrl);
1376
- const promptCacheKey = normalizeOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
1377
+ const promptCacheKey = getOpenAIPromptCacheKey(options);
1377
1378
  const transportSessionId = normalizeOpenAIPromptCacheKey(options?.sessionId);
1378
1379
  const codexClientVersion = CODEX_CLIENT_VERSION;
1379
1380
  const transformedBody = await buildTransformedCodexRequestBody(model, context, options, promptCacheKey);
@@ -1463,7 +1464,7 @@ export async function buildTransformedCodexRequestBody(
1463
1464
  model: Model<"openai-codex-responses">,
1464
1465
  context: Context,
1465
1466
  options: OpenAICodexResponsesOptions | undefined,
1466
- promptCacheKey = normalizeOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId),
1467
+ promptCacheKey = getOpenAIPromptCacheKey(options),
1467
1468
  ): Promise<RequestBody> {
1468
1469
  const params: RequestBody = {
1469
1470
  model: model.requestModelId ?? model.id,
@@ -0,0 +1,22 @@
1
+ import { createApiKeyLogin } from "./api-key-login";
2
+ import type { OAuthLoginCallbacks } from "./oauth/types";
3
+ import type { ProviderDefinition } from "./types";
4
+
5
+ export const loginAiand = createApiKeyLogin({
6
+ providerLabel: "ai&",
7
+ authUrl: "https://console.aiand.com/api-keys",
8
+ instructions: "Copy your API key from the ai& console",
9
+ promptMessage: "Paste your ai& API key",
10
+ placeholder: "sk-...",
11
+ validation: {
12
+ kind: "models-endpoint",
13
+ provider: "ai&",
14
+ modelsUrl: "https://api.aiand.com/v1/models",
15
+ },
16
+ });
17
+
18
+ export const aiandProvider = {
19
+ id: "aiand",
20
+ name: "ai&",
21
+ login: (cb: OAuthLoginCallbacks) => loginAiand(cb),
22
+ } as const satisfies ProviderDefinition;
@@ -1,4 +1,5 @@
1
1
  import type { KnownProvider } from "@oh-my-pi/pi-catalog";
2
+ import { aiandProvider } from "./aiand";
2
3
  import { aimlApiProvider } from "./aimlapi";
3
4
  import { alibabaCodingPlanProvider } from "./alibaba-coding-plan";
4
5
  import { alibabaTokenPlanProvider } from "./alibaba-token-plan";
@@ -101,6 +102,7 @@ const ALL = [
101
102
  gitLabDuoWorkflowProvider,
102
103
  alibabaCodingPlanProvider,
103
104
  alibabaTokenPlanProvider,
105
+ aiandProvider,
104
106
  aimlApiProvider,
105
107
  zhipuCodingPlanProvider,
106
108
  umansProvider,