@oh-my-pi/pi-catalog 18.9.0 → 18.9.2

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/types/compat/auth-ids.d.ts +2 -2
  3. package/dist/types/compat/judgment-questions.d.ts +7 -0
  4. package/dist/types/compat/provider-ids.d.ts +1 -1
  5. package/dist/types/compat/types.d.ts +2 -0
  6. package/dist/types/provider-models/openai-compat.d.ts +1 -1
  7. package/dist/types/provider-models/special.d.ts +2 -0
  8. package/dist/types/types.d.ts +11 -1
  9. package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -10
  10. package/dist/types/wire/cloudflare.d.ts +10 -0
  11. package/package.json +4 -4
  12. package/src/compat/auth-ids.ts +2 -0
  13. package/src/compat/axes.ts +6 -1
  14. package/src/compat/judgment-questions.ts +12 -0
  15. package/src/compat/provider-ids.ts +1 -0
  16. package/src/compat/resolve.ts +3 -0
  17. package/src/compat/rules/README.md +3 -1
  18. package/src/compat/rules/auth/_order.kdl +1 -1
  19. package/src/compat/rules/auth/cloudflare-workers-ai.kdl +9 -0
  20. package/src/compat/rules/classes/qwen.kdl +2 -1
  21. package/src/compat/rules/providers/cloudflare-workers-ai.kdl +34 -0
  22. package/src/compat/rules/providers/groq.kdl +21 -0
  23. package/src/compat/rules/providers/judgment-questions.kdl +53 -0
  24. package/src/compat/rules/providers/openai.kdl +15 -0
  25. package/src/compat/rules.json +1 -1
  26. package/src/compat/types.ts +2 -0
  27. package/src/models.json +1 -1
  28. package/src/provider-models/descriptors.ts +2 -0
  29. package/src/provider-models/openai-compat.ts +26 -2
  30. package/src/provider-models/special.ts +9 -0
  31. package/src/types.ts +14 -0
  32. package/src/wire/cloudflare-ai-gateway.ts +0 -36
  33. package/src/wire/cloudflare.ts +40 -0
@@ -79,6 +79,7 @@ import {
79
79
  zhipuCodingPlanModelManagerOptions,
80
80
  } from "./openai-compat";
81
81
  import {
82
+ cloudflareWorkersAiModelManagerOptions,
82
83
  cursorModelManagerOptions,
83
84
  devinModelManagerOptions,
84
85
  factoryDroidModelManagerOptions,
@@ -105,6 +106,7 @@ const MODEL_MANAGER_FACTORIES: Readonly<Partial<Record<KnownProvider, ModelManag
105
106
  cerebras: config => cerebrasModelManagerOptions(config),
106
107
  "charm-hyper": config => charmHyperModelManagerOptions(config),
107
108
  "cloudflare-ai-gateway": config => cloudflareAiGatewayModelManagerOptions(config),
109
+ "cloudflare-workers-ai": () => cloudflareWorkersAiModelManagerOptions(),
108
110
  commandcode: config => commandCodeModelManagerOptions(config),
109
111
  coralbricks: config => coralbricksModelManagerOptions(config),
110
112
  cursor: config => cursorModelManagerOptions(config),
@@ -1071,8 +1071,8 @@ export interface OpenAIModelManagerConfig {
1071
1071
  fetch?: FetchImpl;
1072
1072
  }
1073
1073
 
1074
- export function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): ModelManagerOptions<"openai-responses"> {
1075
- return createOpenAICompatibleModelManagerOptions({
1074
+ export function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): ModelManagerOptions<Api> {
1075
+ const options = createOpenAICompatibleModelManagerOptions({
1076
1076
  api: "openai-responses",
1077
1077
  providerId: "openai",
1078
1078
  defaultBaseUrl: OPENAI_API_BASE_URL,
@@ -1081,6 +1081,30 @@ export function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): Mo
1081
1081
  filterModel: (_entry, model, references) => isLikelyOpenAIResponsesModelId(model.id, references),
1082
1082
  mapModel: mapWithBundledReference,
1083
1083
  });
1084
+ const fetchDiscovered = options.fetchDynamicModels;
1085
+ if (!fetchDiscovered) return options;
1086
+ return {
1087
+ ...options,
1088
+ fetchDynamicModels: async () => appendUnbundledSeedModels("openai", await fetchDiscovered()),
1089
+ };
1090
+ }
1091
+
1092
+ /**
1093
+ * Append the authored seed rows that neither discovery nor the bundled catalog
1094
+ * carries yet: a seed added since the last models.json regeneration (the
1095
+ * Decisions judge row) reaches runtime through a successful discovery. Seeds
1096
+ * already bundled keep resolving through the bundled slice, and the static
1097
+ * catalog (and with it the cache fingerprint) stays the bundled one.
1098
+ */
1099
+ function appendUnbundledSeedModels(
1100
+ providerId: GeneratedProvider,
1101
+ discovered: readonly ModelSpec<Api>[] | null,
1102
+ ): readonly ModelSpec<Api>[] | null {
1103
+ if (!discovered) return null;
1104
+ const known = new Set(getBundledModels(providerId).map(model => model.id));
1105
+ for (const model of discovered) known.add(model.id);
1106
+ const seeds = seedModels(providerId).filter(seed => !known.has(seed.id));
1107
+ return seeds.length === 0 ? discovered : [...discovered, ...seeds.map(seed => ({ ...seed }))];
1084
1108
  }
1085
1109
 
1086
1110
  /**
@@ -405,6 +405,15 @@ export function webModelManagerOptions(): ModelManagerOptions<"web-search"> {
405
405
  };
406
406
  }
407
407
 
408
+ /** Cloudflare Workers AI judges: the authored Clef rows; the account id resolves per request. */
409
+ export function cloudflareWorkersAiModelManagerOptions(): ModelManagerOptions<"workers-ai-systemone"> {
410
+ return {
411
+ providerId: "cloudflare-workers-ai",
412
+ cacheProviderId: resolveModelCacheProviderId("cloudflare-workers-ai"),
413
+ staticModels: seedModels<"workers-ai-systemone">("cloudflare-workers-ai"),
414
+ };
415
+ }
416
+
408
417
  /** Credentials and endpoint overrides for the TypeSafe catalog manager. */
409
418
  export interface TypeSafeModelManagerConfig {
410
419
  apiKey?: string;
package/src/types.ts CHANGED
@@ -51,6 +51,8 @@ export const RUNNER_APIS = [
51
51
  "web-search",
52
52
  "typesafe",
53
53
  "openrouter-decisions",
54
+ "openai-decisions",
55
+ "workers-ai-systemone",
54
56
  "openai-images",
55
57
  "openrouter-images",
56
58
  "xai-tts",
@@ -65,6 +67,8 @@ export const RUNNER_API_KINDS: Record<Exclude<(typeof RUNNER_APIS)[number], "loc
65
67
  "web-search": "search",
66
68
  typesafe: "judge",
67
69
  "openrouter-decisions": "judge",
70
+ "openai-decisions": "judge",
71
+ "workers-ai-systemone": "judge",
68
72
  "openai-images": "image",
69
73
  "openrouter-images": "image",
70
74
  "xai-tts": "tts",
@@ -829,6 +833,14 @@ export interface BedrockCompat {
829
833
  * choices to `auto` when this is false. Default: true.
830
834
  */
831
835
  supportsForcedToolChoice?: boolean;
836
+ /**
837
+ * Whether the endpoint accepts thinking-binding controls (`thinking.block_binding`,
838
+ * the `thinking-binding-controls-2026-08-01` beta and the `/input_transformations`
839
+ * response path) on prefix-bound models. Only consulted when
840
+ * `thinking.prefixBinding` is set; `false` omits the controls while keeping the
841
+ * local prefix-binding safeguards. Default: true.
842
+ */
843
+ supportsThinkingBindingControls?: boolean;
832
844
  }
833
845
 
834
846
  /** Fully-resolved Bedrock Converse prompt-cache capabilities, materialized once by `buildModel`. */
@@ -844,6 +856,8 @@ export interface ResolvedBedrockCompat {
844
856
  /** See {@link BedrockCompat.supportsSamplingParams}. */
845
857
  supportsSamplingParams?: boolean;
846
858
  supportsForcedToolChoice: boolean;
859
+ /** See {@link BedrockCompat.supportsThinkingBindingControls}. */
860
+ supportsThinkingBindingControls: boolean;
847
861
  /**
848
862
  * Stream-watchdog idle-timeout fallback in ms for hosts with no keepalive
849
863
  * events; 0 disables the idle watchdog. Undefined defers to
@@ -1,5 +1,3 @@
1
- import { isRecord } from "../utils";
2
-
3
1
  /** Provider-native AI Gateway prefix before the upstream route segment. */
4
2
  export const CLOUDFLARE_AI_GATEWAY_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>";
5
3
  /** Anthropic Messages passthrough endpoint. */
@@ -8,37 +6,3 @@ export const CLOUDFLARE_AI_GATEWAY_ANTHROPIC_BASE_URL = `${CLOUDFLARE_AI_GATEWAY
8
6
  export const CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL = `${CLOUDFLARE_AI_GATEWAY_BASE_URL}/openai`;
9
7
  /** OpenAI-compatible Workers AI endpoint. */
10
8
  export const CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL = `${CLOUDFLARE_AI_GATEWAY_BASE_URL}/compat`;
11
-
12
- /** Opaque API-key credential payload persisted by Cloudflare AI Gateway login. */
13
- export interface CloudflareAiGatewayCredential {
14
- token: string;
15
- accountId?: string;
16
- gatewayId?: string;
17
- }
18
-
19
- /** Parse both structured login credentials and legacy plain gateway tokens. */
20
- export function parseCloudflareAiGatewayCredential(value: string): CloudflareAiGatewayCredential | null {
21
- const trimmed = value.trim();
22
- if (!trimmed) return null;
23
- if (!trimmed.startsWith("{")) return { token: trimmed };
24
- try {
25
- const parsed: unknown = JSON.parse(trimmed);
26
- if (!isRecord(parsed)) return null;
27
- if (typeof parsed.token !== "string" || !parsed.token.trim()) return null;
28
- if (parsed.accountId !== undefined && typeof parsed.accountId !== "string") return null;
29
- if (parsed.gatewayId !== undefined && typeof parsed.gatewayId !== "string") return null;
30
- const credential: CloudflareAiGatewayCredential = { token: parsed.token.trim() };
31
- const accountId = parsed.accountId?.trim();
32
- const gatewayId = parsed.gatewayId?.trim();
33
- if (accountId) credential.accountId = accountId;
34
- if (gatewayId) credential.gatewayId = gatewayId;
35
- return credential;
36
- } catch {
37
- return null;
38
- }
39
- }
40
-
41
- /** Serialize the gateway token with the routing identifiers collected during login. */
42
- export function serializeCloudflareAiGatewayCredential(token: string, accountId: string, gatewayId: string): string {
43
- return JSON.stringify({ token: token.trim(), accountId: accountId.trim(), gatewayId: gatewayId.trim() });
44
- }
@@ -0,0 +1,40 @@
1
+ import { isRecord } from "../utils";
2
+
3
+ /** Cloudflare credential persisted by the AI Gateway and Workers AI logins: a bearer token plus the routing ids collected at login. */
4
+ export interface CloudflareCredential {
5
+ token: string;
6
+ accountId?: string;
7
+ gatewayId?: string;
8
+ }
9
+
10
+ /** Parses a structured login credential or a legacy plain token; null when empty or malformed. */
11
+ export function parseCloudflareCredential(value: string): CloudflareCredential | null {
12
+ const trimmed = value.trim();
13
+ if (!trimmed) return null;
14
+ if (!trimmed.startsWith("{")) return { token: trimmed };
15
+ try {
16
+ const parsed: unknown = JSON.parse(trimmed);
17
+ if (!isRecord(parsed)) return null;
18
+ if (typeof parsed.token !== "string" || !parsed.token.trim()) return null;
19
+ if (parsed.accountId !== undefined && typeof parsed.accountId !== "string") return null;
20
+ if (parsed.gatewayId !== undefined && typeof parsed.gatewayId !== "string") return null;
21
+ const credential: CloudflareCredential = { token: parsed.token.trim() };
22
+ const accountId = parsed.accountId?.trim();
23
+ const gatewayId = parsed.gatewayId?.trim();
24
+ if (accountId) credential.accountId = accountId;
25
+ if (gatewayId) credential.gatewayId = gatewayId;
26
+ return credential;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+
32
+ /** Serializes a login credential, trimming fields and omitting empty optional ids. */
33
+ export function serializeCloudflareCredential(credential: CloudflareCredential): string {
34
+ const serialized: CloudflareCredential = { token: credential.token.trim() };
35
+ const accountId = credential.accountId?.trim();
36
+ const gatewayId = credential.gatewayId?.trim();
37
+ if (accountId) serialized.accountId = accountId;
38
+ if (gatewayId) serialized.gatewayId = gatewayId;
39
+ return JSON.stringify(serialized);
40
+ }