@pasko70/pibo 1.7.8 → 1.7.9

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.
@@ -1,13 +1,15 @@
1
1
  import { getModels } from "@mariozechner/pi-ai";
2
+ import { getOAuthProvider } from "@mariozechner/pi-ai/oauth";
2
3
  export const OPENAI_PROVIDER_ID = "openai";
3
4
  export const OPENAI_RESPONSES_API = "openai-responses";
4
5
  export const OPENAI_BASE_URL = "https://api.openai.com/v1";
5
6
  export const OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
6
- const GPT_56_CONTEXT_WINDOW = 1_050_000;
7
+ export const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
8
+ export const OPENAI_CODEX_RESPONSES_API = "openai-codex-responses";
9
+ export const OPENAI_CODEX_BASE_URL = "https://chatgpt.com/backend-api";
10
+ const OPENAI_GPT_56_CONTEXT_WINDOW = 1_050_000;
11
+ const OPENAI_CODEX_GPT_56_CONTEXT_WINDOW = 272_000;
7
12
  const GPT_56_MAX_TOKENS = 128_000;
8
- // Register GPT-5.6 on the normal OpenAI API provider only.
9
- // This keeps Pibo on the existing token-plan path (OPENAI_API_KEY) and does not
10
- // route these models through ChatGPT/Codex OAuth (`openai-codex`).
11
13
  export const OPENAI_GPT_56_MODELS = [
12
14
  {
13
15
  id: "gpt-5.6",
@@ -30,62 +32,122 @@ export const OPENAI_GPT_56_MODELS = [
30
32
  cost: { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 1.25 },
31
33
  },
32
34
  ];
35
+ const OPENAI_GPT_56_MODEL_IDS = new Set(OPENAI_GPT_56_MODELS.map((model) => model.id));
33
36
  export function getBuiltInOpenAiModels() {
34
- try {
35
- return getModels(OPENAI_PROVIDER_ID);
36
- }
37
- catch {
38
- return [];
39
- }
37
+ return getBuiltInProviderModels(OPENAI_PROVIDER_ID);
38
+ }
39
+ export function getBuiltInOpenAiCodexModels() {
40
+ return getBuiltInProviderModels(OPENAI_CODEX_PROVIDER_ID);
40
41
  }
41
42
  export function buildOpenAiGpt56Models(baseModels = getBuiltInOpenAiModels()) {
42
- const openAiBaseModels = baseModels
43
- .filter((model) => model.provider === OPENAI_PROVIDER_ID)
44
- .map((model) => ({
45
- ...model,
46
- input: [...model.input],
47
- cost: { ...model.cost },
48
- headers: model.headers ? { ...model.headers } : undefined,
49
- compat: model.compat ? { ...model.compat } : undefined,
50
- }));
51
- const existingIds = new Set(openAiBaseModels.map((model) => model.id));
52
- const additions = OPENAI_GPT_56_MODELS
53
- .filter((model) => !existingIds.has(model.id))
54
- .map(openAiGpt56ModelToRegistryModel);
55
- return [...openAiBaseModels, ...additions];
43
+ return buildProviderGpt56Models({
44
+ providerId: OPENAI_PROVIDER_ID,
45
+ api: OPENAI_RESPONSES_API,
46
+ baseUrl: OPENAI_BASE_URL,
47
+ contextWindow: OPENAI_GPT_56_CONTEXT_WINDOW,
48
+ thinkingLevelMap: { off: null, xhigh: "xhigh" },
49
+ baseModels,
50
+ modelCost: (model) => model.cost,
51
+ });
52
+ }
53
+ export function buildOpenAiCodexGpt56Models(baseModels = getBuiltInOpenAiCodexModels()) {
54
+ return buildProviderGpt56Models({
55
+ providerId: OPENAI_CODEX_PROVIDER_ID,
56
+ api: OPENAI_CODEX_RESPONSES_API,
57
+ baseUrl: OPENAI_CODEX_BASE_URL,
58
+ contextWindow: OPENAI_CODEX_GPT_56_CONTEXT_WINDOW,
59
+ thinkingLevelMap: { xhigh: "xhigh", minimal: "low" },
60
+ baseModels,
61
+ modelCost: (model) => ({ ...model.cost, cacheWrite: 0 }),
62
+ });
56
63
  }
57
64
  export function registerOpenAiGpt56Models(modelRegistry, options = {}) {
58
- const baseModels = options.baseModels ?? getBuiltInOpenAiModels();
59
- const models = buildOpenAiGpt56Models(baseModels);
60
- const baseOpenAiIds = new Set(baseModels.filter((model) => model.provider === OPENAI_PROVIDER_ID).map((model) => model.id));
61
- const added = OPENAI_GPT_56_MODELS.filter((model) => !baseOpenAiIds.has(model.id)).length;
65
+ const baseOpenAiModels = options.baseOpenAiModels ?? getBuiltInOpenAiModels();
66
+ const openAiModels = buildOpenAiGpt56Models(baseOpenAiModels);
67
+ const openAiAdded = countMissingGpt56Models(baseOpenAiModels, OPENAI_PROVIDER_ID);
62
68
  modelRegistry.registerProvider(OPENAI_PROVIDER_ID, {
63
69
  baseUrl: OPENAI_BASE_URL,
64
70
  api: OPENAI_RESPONSES_API,
65
71
  apiKey: OPENAI_API_KEY_ENV,
66
- models,
72
+ models: openAiModels,
73
+ });
74
+ const baseOpenAiCodexModels = options.baseOpenAiCodexModels ?? getBuiltInOpenAiCodexModels();
75
+ const openAiCodexModels = buildOpenAiCodexGpt56Models(baseOpenAiCodexModels);
76
+ const openAiCodexAdded = countMissingGpt56Models(baseOpenAiCodexModels, OPENAI_CODEX_PROVIDER_ID);
77
+ const openAiCodexOAuth = getOpenAiCodexOAuthConfig();
78
+ modelRegistry.registerProvider(OPENAI_CODEX_PROVIDER_ID, {
79
+ name: openAiCodexOAuth.name,
80
+ baseUrl: OPENAI_CODEX_BASE_URL,
81
+ api: OPENAI_CODEX_RESPONSES_API,
82
+ oauth: openAiCodexOAuth,
83
+ models: openAiCodexModels,
67
84
  });
68
- return { registered: true, models: models.length, added };
85
+ return {
86
+ registered: true,
87
+ providers: 2,
88
+ models: openAiModels.length + openAiCodexModels.length,
89
+ added: openAiAdded + openAiCodexAdded,
90
+ };
69
91
  }
70
92
  export function findOpenAiGpt56Model(modelRegistry, model) {
71
- if (model?.provider !== OPENAI_PROVIDER_ID || !model.id)
93
+ if (!model?.provider || !model.id)
94
+ return undefined;
95
+ if (model.provider !== OPENAI_PROVIDER_ID && model.provider !== OPENAI_CODEX_PROVIDER_ID)
72
96
  return undefined;
73
- if (!OPENAI_GPT_56_MODELS.some((candidate) => candidate.id === model.id))
97
+ if (!OPENAI_GPT_56_MODEL_IDS.has(model.id))
74
98
  return undefined;
75
- return modelRegistry.find(OPENAI_PROVIDER_ID, model.id);
99
+ return modelRegistry.find(model.provider, model.id);
76
100
  }
77
- function openAiGpt56ModelToRegistryModel(model) {
101
+ function getBuiltInProviderModels(providerId) {
102
+ try {
103
+ return getModels(providerId);
104
+ }
105
+ catch {
106
+ return [];
107
+ }
108
+ }
109
+ function buildProviderGpt56Models(options) {
110
+ const providerBaseModels = options.baseModels
111
+ .filter((model) => model.provider === options.providerId)
112
+ .map(cloneModel);
113
+ const existingIds = new Set(providerBaseModels.map((model) => model.id));
114
+ const additions = OPENAI_GPT_56_MODELS
115
+ .filter((model) => !existingIds.has(model.id))
116
+ .map((model) => openAiGpt56ModelToRegistryModel(model, options));
117
+ return [...providerBaseModels, ...additions];
118
+ }
119
+ function countMissingGpt56Models(baseModels, providerId) {
120
+ const existingIds = new Set(baseModels.filter((model) => model.provider === providerId).map((model) => model.id));
121
+ return OPENAI_GPT_56_MODELS.filter((model) => !existingIds.has(model.id)).length;
122
+ }
123
+ function cloneModel(model) {
124
+ return {
125
+ ...model,
126
+ input: [...model.input],
127
+ cost: { ...model.cost },
128
+ headers: model.headers ? { ...model.headers } : undefined,
129
+ compat: model.compat ? { ...model.compat } : undefined,
130
+ };
131
+ }
132
+ function openAiGpt56ModelToRegistryModel(model, options) {
78
133
  return {
79
134
  id: model.id,
80
135
  name: model.name,
81
- api: OPENAI_RESPONSES_API,
82
- provider: OPENAI_PROVIDER_ID,
83
- baseUrl: OPENAI_BASE_URL,
136
+ api: options.api,
137
+ provider: options.providerId,
138
+ baseUrl: options.baseUrl,
84
139
  reasoning: true,
85
- thinkingLevelMap: { off: null, xhigh: "xhigh" },
140
+ thinkingLevelMap: options.thinkingLevelMap,
86
141
  input: ["text", "image"],
87
- cost: { ...model.cost },
88
- contextWindow: GPT_56_CONTEXT_WINDOW,
142
+ cost: options.modelCost(model),
143
+ contextWindow: options.contextWindow,
89
144
  maxTokens: GPT_56_MAX_TOKENS,
90
145
  };
91
146
  }
147
+ function getOpenAiCodexOAuthConfig() {
148
+ const provider = getOAuthProvider(OPENAI_CODEX_PROVIDER_ID);
149
+ if (!provider)
150
+ throw new Error("OpenAI Codex OAuth provider is unavailable.");
151
+ const { id: _id, ...oauth } = provider;
152
+ return oauth;
153
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pasko70/pibo",
3
- "version": "1.7.8",
3
+ "version": "1.7.9",
4
4
  "type": "module",
5
5
  "imports": {
6
6
  "vscode": "./src/apps/chat-vscode/extension/src/vscode-shim.js"