@vtstech/pi-api 1.0.3 → 1.0.4-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.
Files changed (3) hide show
  1. package/README.md +46 -0
  2. package/api.js +71 -91
  3. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # @vtstech/pi-api
2
+
3
+ API Mode Switcher extension for the [Pi Coding Agent](https://github.com/badlogic/pi-mono).
4
+
5
+ Runtime switching of API modes, base URLs, thinking settings, and compat flags in `models.json`. Supports all 10 Pi API modes.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pi install "npm:@vtstech/pi-api"
11
+ ```
12
+
13
+ ## Commands
14
+
15
+ ```
16
+ /api Show current provider config (mode, URL, compat flags)
17
+ /api mode <mode> Switch API mode (partial match supported)
18
+ /api url <url> Switch base URL
19
+ /api think on|off|auto Toggle thinking for all models in provider
20
+ /api compat <key> View compat flags
21
+ /api compat <key> <val> Set compat flag
22
+ /api modes List all 10 supported API modes
23
+ /api providers List all configured providers
24
+ /api reload Hint to run /reload
25
+ ```
26
+
27
+ ## Supported API Modes
28
+
29
+ `anthropic-messages` · `openai-completions` · `openai-responses` · `azure-openai-responses` · `openai-codex-responses` · `mistral-conversations` · `google-generative-ai` · `google-gemini-cli` · `google-vertex` · `bedrock-converse-stream`
30
+
31
+ ## Features
32
+
33
+ - Partial mode matching — `/api mode openai-r` matches `openai-responses`
34
+ - Auto-detect local provider — targets the first `localhost`/`ollama` provider by default
35
+ - Batch thinking toggle — set `reasoning: true/false` across all models at once
36
+ - Compat flag management — get/set `supportsDeveloperRole`, `thinkingFormat`, `maxTokensField`, etc.
37
+ - Tab-completion for sub-commands
38
+
39
+ ## Links
40
+
41
+ - [Full Documentation](https://github.com/VTSTech/pi-coding-agent#api-mode-switcher-apits)
42
+ - [Changelog](https://github.com/VTSTech/pi-coding-agent/blob/main/CHANGELOG.md)
43
+
44
+ ## License
45
+
46
+ MIT — [VTSTech](https://www.vts-tech.org)
package/api.js CHANGED
@@ -1,29 +1,6 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
-
19
1
  // .build-npm/api/api.temp.ts
20
- var api_temp_exports = {};
21
- __export(api_temp_exports, {
22
- default: () => api_temp_default
23
- });
24
- module.exports = __toCommonJS(api_temp_exports);
25
- var import_format = require("@vtstech/pi-shared/format");
26
- var import_ollama = require("@vtstech/pi-shared/ollama");
2
+ import { section, ok, info, warn } from "@vtstech/pi-shared/format";
3
+ import { readModelsJson, writeModelsJson, getOllamaBaseUrl } from "@vtstech/pi-shared/ollama";
27
4
  var API_MODES = {
28
5
  "anthropic-messages": "Anthropic Claude API and compatibles",
29
6
  "openai-completions": "OpenAI Chat Completions API and compatibles",
@@ -87,7 +64,7 @@ function api_temp_default(pi) {
87
64
  const parts = args.trim().split(/\s+/);
88
65
  const sub = parts[0]?.toLowerCase() || "";
89
66
  const rest = parts.slice(1).join(" ");
90
- const config = (0, import_ollama.readModelsJson)();
67
+ const config = readModelsJson();
91
68
  const provider = resolveProvider(config);
92
69
  if (!provider) {
93
70
  ctx.ui.notify("No providers found in models.json", "error");
@@ -122,22 +99,22 @@ function api_temp_default(pi) {
122
99
  const modelCount = p.models?.length || 0;
123
100
  const firstModel = p.models?.[0]?.id || "none";
124
101
  const lines = [branding];
125
- lines.push((0, import_format.section)("CURRENT PROVIDER CONFIG"));
126
- lines.push((0, import_format.info)(`Provider: ${provider.name}`));
127
- lines.push((0, import_format.info)(`API mode: ${p.api || "(not set)"}`));
128
- lines.push((0, import_format.info)(`Base URL: ${p.baseUrl || "(not set)"}`));
129
- lines.push((0, import_format.info)(`API key: ${p.apiKey ? "\u2022\u2022\u2022\u2022" + String(p.apiKey).slice(-4) : "(not set)"}`));
130
- lines.push((0, import_format.info)(`Models: ${modelCount} (first: ${firstModel})`));
102
+ lines.push(section("CURRENT PROVIDER CONFIG"));
103
+ lines.push(info(`Provider: ${provider.name}`));
104
+ lines.push(info(`API mode: ${p.api || "(not set)"}`));
105
+ lines.push(info(`Base URL: ${p.baseUrl || "(not set)"}`));
106
+ lines.push(info(`API key: ${p.apiKey ? "\u2022\u2022\u2022\u2022" + String(p.apiKey).slice(-4) : "(not set)"}`));
107
+ lines.push(info(`Models: ${modelCount} (first: ${firstModel})`));
131
108
  if (Object.keys(compat).length > 0) {
132
- lines.push((0, import_format.section)("COMPAT FLAGS"));
109
+ lines.push(section("COMPAT FLAGS"));
133
110
  for (const [key, value] of Object.entries(compat)) {
134
- lines.push((0, import_format.info)(` ${key}: ${JSON.stringify(value)}`));
111
+ lines.push(info(` ${key}: ${JSON.stringify(value)}`));
135
112
  }
136
113
  }
137
- const ollamaBase = (0, import_ollama.getOllamaBaseUrl)();
138
- lines.push((0, import_format.section)("RESOLVED"));
139
- lines.push((0, import_format.info)(`Ollama base: ${ollamaBase}`));
140
- lines.push((0, import_format.info)(`(strip /v1 \u2192 ${ollamaBase})`));
114
+ const ollamaBase = getOllamaBaseUrl();
115
+ lines.push(section("RESOLVED"));
116
+ lines.push(info(`Ollama base: ${ollamaBase}`));
117
+ lines.push(info(`(strip /v1 \u2192 ${ollamaBase})`));
141
118
  pi.sendMessage({
142
119
  customType: "api-config",
143
120
  content: lines.join("\n"),
@@ -158,7 +135,7 @@ function api_temp_default(pi) {
158
135
  ctx.ui.notify(`Unknown API mode: "${mode}". Use /api modes to list available modes.`, "error");
159
136
  return;
160
137
  }
161
- const config = (0, import_ollama.readModelsJson)();
138
+ const config = readModelsJson();
162
139
  const provider = config.providers[providerName];
163
140
  if (!provider) {
164
141
  ctx.ui.notify(`Provider "${providerName}" not found in models.json`, "error");
@@ -166,14 +143,14 @@ function api_temp_default(pi) {
166
143
  }
167
144
  const oldMode = provider.api || "(not set)";
168
145
  provider.api = matched;
169
- (0, import_ollama.writeModelsJson)(config);
146
+ writeModelsJson(config);
170
147
  const lines = [branding];
171
- lines.push((0, import_format.section)("API MODE CHANGED"));
172
- lines.push((0, import_format.ok)(`Provider: ${providerName}`));
173
- lines.push((0, import_format.info)(`Old mode: ${oldMode}`));
174
- lines.push((0, import_format.ok)(`New mode: ${matched}`));
175
- lines.push((0, import_format.info)(`Description: ${API_MODES[matched]}`));
176
- lines.push((0, import_format.warn)("Run /api reload or /reload to apply changes in Pi"));
148
+ lines.push(section("API MODE CHANGED"));
149
+ lines.push(ok(`Provider: ${providerName}`));
150
+ lines.push(info(`Old mode: ${oldMode}`));
151
+ lines.push(ok(`New mode: ${matched}`));
152
+ lines.push(info(`Description: ${API_MODES[matched]}`));
153
+ lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
177
154
  pi.sendMessage({
178
155
  customType: "api-mode-changed",
179
156
  content: lines.join("\n"),
@@ -190,7 +167,7 @@ function api_temp_default(pi) {
190
167
  if (!normalizedUrl.startsWith("http")) {
191
168
  normalizedUrl = "http://" + normalizedUrl;
192
169
  }
193
- const config = (0, import_ollama.readModelsJson)();
170
+ const config = readModelsJson();
194
171
  const provider = config.providers[providerName];
195
172
  if (!provider) {
196
173
  ctx.ui.notify(`Provider "${providerName}" not found in models.json`, "error");
@@ -198,13 +175,13 @@ function api_temp_default(pi) {
198
175
  }
199
176
  const oldUrl = provider.baseUrl || "(not set)";
200
177
  provider.baseUrl = normalizedUrl;
201
- (0, import_ollama.writeModelsJson)(config);
178
+ writeModelsJson(config);
202
179
  const lines = [branding];
203
- lines.push((0, import_format.section)("BASE URL CHANGED"));
204
- lines.push((0, import_format.ok)(`Provider: ${providerName}`));
205
- lines.push((0, import_format.info)(`Old URL: ${oldUrl}`));
206
- lines.push((0, import_format.ok)(`New URL: ${normalizedUrl}`));
207
- lines.push((0, import_format.warn)("Run /api reload or /reload to apply changes in Pi"));
180
+ lines.push(section("BASE URL CHANGED"));
181
+ lines.push(ok(`Provider: ${providerName}`));
182
+ lines.push(info(`Old URL: ${oldUrl}`));
183
+ lines.push(ok(`New URL: ${normalizedUrl}`));
184
+ lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
208
185
  pi.sendMessage({
209
186
  customType: "api-url-changed",
210
187
  content: lines.join("\n"),
@@ -217,7 +194,7 @@ function api_temp_default(pi) {
217
194
  ctx.ui.notify("Usage: /api think <on|off|auto>", "error");
218
195
  return;
219
196
  }
220
- const config = (0, import_ollama.readModelsJson)();
197
+ const config = readModelsJson();
221
198
  const provider = config.providers[providerName];
222
199
  if (!provider) {
223
200
  ctx.ui.notify(`Provider "${providerName}" not found in models.json`, "error");
@@ -249,16 +226,16 @@ function api_temp_default(pi) {
249
226
  ctx.ui.notify("Invalid value. Use: on, off, or auto", "error");
250
227
  return;
251
228
  }
252
- (0, import_ollama.writeModelsJson)(config);
229
+ writeModelsJson(config);
253
230
  const lines = [branding];
254
- lines.push((0, import_format.section)("THINKING MODE"));
255
- lines.push((0, import_format.info)(`Provider: ${providerName}`));
256
- lines.push((0, import_format.info)(`Mode: ${valLower}`));
257
- lines.push((0, import_format.info)(`Affected ${models.length} model(s):`));
231
+ lines.push(section("THINKING MODE"));
232
+ lines.push(info(`Provider: ${providerName}`));
233
+ lines.push(info(`Mode: ${valLower}`));
234
+ lines.push(info(`Affected ${models.length} model(s):`));
258
235
  for (const model of models) {
259
- lines.push((0, import_format.info)(` ${(model.id || "?").padEnd(40)} reasoning: ${model.reasoning ? "true" : "false"}`));
236
+ lines.push(info(` ${(model.id || "?").padEnd(40)} reasoning: ${model.reasoning ? "true" : "false"}`));
260
237
  }
261
- lines.push((0, import_format.warn)("Run /api reload or /reload to apply changes in Pi"));
238
+ lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
262
239
  pi.sendMessage({
263
240
  customType: "api-think-changed",
264
241
  content: lines.join("\n"),
@@ -271,7 +248,7 @@ function api_temp_default(pi) {
271
248
  const key = parts[0];
272
249
  const value = parts.slice(1).join(" ");
273
250
  if (!key) {
274
- const config2 = (0, import_ollama.readModelsJson)();
251
+ const config2 = readModelsJson();
275
252
  const provider2 = config2.providers[providerName];
276
253
  if (!provider2) {
277
254
  ctx.ui.notify(`Provider "${providerName}" not found`, "error");
@@ -279,20 +256,20 @@ function api_temp_default(pi) {
279
256
  }
280
257
  const compat = provider2.compat || {};
281
258
  const lines2 = [branding];
282
- lines2.push((0, import_format.section)("COMPAT FLAGS"));
259
+ lines2.push(section("COMPAT FLAGS"));
283
260
  if (Object.keys(compat).length === 0) {
284
- lines2.push((0, import_format.info)("No compat flags set"));
261
+ lines2.push(info("No compat flags set"));
285
262
  } else {
286
263
  for (const [k, v] of Object.entries(compat)) {
287
264
  const flag = COMPAT_FLAGS[k];
288
- lines2.push((0, import_format.info)(` ${k}: ${JSON.stringify(v)}${flag ? ` \u2014 ${flag.description}` : ""}`));
265
+ lines2.push(info(` ${k}: ${JSON.stringify(v)}${flag ? ` \u2014 ${flag.description}` : ""}`));
289
266
  }
290
267
  }
291
- lines2.push((0, import_format.section)("AVAILABLE FLAGS"));
268
+ lines2.push(section("AVAILABLE FLAGS"));
292
269
  for (const [k, flag] of Object.entries(COMPAT_FLAGS)) {
293
- lines2.push((0, import_format.info)(` ${k} = <${flag.values.join(" | ")}> \u2014 ${flag.description}`));
270
+ lines2.push(info(` ${k} = <${flag.values.join(" | ")}> \u2014 ${flag.description}`));
294
271
  }
295
- lines2.push((0, import_format.info)("Usage: /api compat <key> <value>"));
272
+ lines2.push(info("Usage: /api compat <key> <value>"));
296
273
  pi.sendMessage({
297
274
  customType: "api-compat-flags",
298
275
  content: lines2.join("\n"),
@@ -301,7 +278,7 @@ function api_temp_default(pi) {
301
278
  return;
302
279
  }
303
280
  if (!value) {
304
- const config2 = (0, import_ollama.readModelsJson)();
281
+ const config2 = readModelsJson();
305
282
  const provider2 = config2.providers[providerName];
306
283
  if (!provider2) {
307
284
  ctx.ui.notify(`Provider "${providerName}" not found`, "error");
@@ -311,7 +288,7 @@ function api_temp_default(pi) {
311
288
  ctx.ui.notify(`${key} = ${current !== void 0 ? JSON.stringify(current) : "(not set)"}`, "info");
312
289
  return;
313
290
  }
314
- const config = (0, import_ollama.readModelsJson)();
291
+ const config = readModelsJson();
315
292
  const provider = config.providers[providerName];
316
293
  if (!provider) {
317
294
  ctx.ui.notify(`Provider "${providerName}" not found`, "error");
@@ -330,14 +307,14 @@ function api_temp_default(pi) {
330
307
  }
331
308
  const oldValue = provider.compat[key];
332
309
  provider.compat[key] = parsedValue;
333
- (0, import_ollama.writeModelsJson)(config);
310
+ writeModelsJson(config);
334
311
  const lines = [branding];
335
- lines.push((0, import_format.section)("COMPAT FLAG SET"));
336
- lines.push((0, import_format.ok)(`Provider: ${providerName}`));
337
- lines.push((0, import_format.info)(`Key: ${key}`));
338
- lines.push((0, import_format.info)(`Old value: ${oldValue !== void 0 ? JSON.stringify(oldValue) : "(not set)"}`));
339
- lines.push((0, import_format.ok)(`New value: ${JSON.stringify(parsedValue)}`));
340
- lines.push((0, import_format.warn)("Run /api reload or /reload to apply changes in Pi"));
312
+ lines.push(section("COMPAT FLAG SET"));
313
+ lines.push(ok(`Provider: ${providerName}`));
314
+ lines.push(info(`Key: ${key}`));
315
+ lines.push(info(`Old value: ${oldValue !== void 0 ? JSON.stringify(oldValue) : "(not set)"}`));
316
+ lines.push(ok(`New value: ${JSON.stringify(parsedValue)}`));
317
+ lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
341
318
  pi.sendMessage({
342
319
  customType: "api-compat-set",
343
320
  content: lines.join("\n"),
@@ -347,11 +324,11 @@ function api_temp_default(pi) {
347
324
  }
348
325
  function reloadConfig(ctx) {
349
326
  const lines = [branding];
350
- lines.push((0, import_format.section)("RELOAD"));
351
- lines.push((0, import_format.ok)("models.json has been modified"));
352
- lines.push((0, import_format.info)("To apply changes, run Pi's built-in command:"));
353
- lines.push((0, import_format.info)(" /reload"));
354
- lines.push((0, import_format.warn)("This will reload all provider configurations from models.json"));
327
+ lines.push(section("RELOAD"));
328
+ lines.push(ok("models.json has been modified"));
329
+ lines.push(info("To apply changes, run Pi's built-in command:"));
330
+ lines.push(info(" /reload"));
331
+ lines.push(warn("This will reload all provider configurations from models.json"));
355
332
  pi.sendMessage({
356
333
  customType: "api-reload",
357
334
  content: lines.join("\n"),
@@ -361,17 +338,17 @@ function api_temp_default(pi) {
361
338
  }
362
339
  function listModes() {
363
340
  const lines = [branding];
364
- lines.push((0, import_format.section)("SUPPORTED API MODES"));
365
- const config = (0, import_ollama.readModelsJson)();
341
+ lines.push(section("SUPPORTED API MODES"));
342
+ const config = readModelsJson();
366
343
  const provider = resolveProvider(config);
367
344
  const currentMode = provider?.config?.api || "(not set)";
368
345
  for (const [mode, description] of Object.entries(API_MODES)) {
369
346
  const isActive = mode === currentMode;
370
- const marker = isActive ? (0, import_format.ok)(" \u25C0 current") : "";
371
- lines.push((0, import_format.info)(` ${mode.padEnd(30)} ${description}${marker}`));
347
+ const marker = isActive ? ok(" \u25C0 current") : "";
348
+ lines.push(info(` ${mode.padEnd(30)} ${description}${marker}`));
372
349
  }
373
- lines.push((0, import_format.info)(""));
374
- lines.push((0, import_format.info)("Usage: /api mode <mode>"));
350
+ lines.push(info(""));
351
+ lines.push(info("Usage: /api mode <mode>"));
375
352
  pi.sendMessage({
376
353
  customType: "api-modes",
377
354
  content: lines.join("\n"),
@@ -380,14 +357,14 @@ function api_temp_default(pi) {
380
357
  }
381
358
  function listProviders(config) {
382
359
  const lines = [branding];
383
- lines.push((0, import_format.section)("PROVIDERS"));
360
+ lines.push(section("PROVIDERS"));
384
361
  for (const [name, provider] of Object.entries(config.providers)) {
385
362
  const modelCount = provider.models?.length || 0;
386
363
  const url = provider.baseUrl || "(no URL)";
387
364
  const api = provider.api || "(no mode)";
388
365
  const isLocal = url.includes("localhost") || url.includes("127.0.0.1") || name === "ollama";
389
- lines.push((0, import_format.info)(` ${name}${isLocal ? " (local)" : ""}`));
390
- lines.push((0, import_format.info)(` API: ${api} | URL: ${url} | Models: ${modelCount}`));
366
+ lines.push(info(` ${name}${isLocal ? " (local)" : ""}`));
367
+ lines.push(info(` API: ${api} | URL: ${url} | Models: ${modelCount}`));
391
368
  }
392
369
  pi.sendMessage({
393
370
  customType: "api-providers",
@@ -409,3 +386,6 @@ function api_temp_default(pi) {
409
386
  }
410
387
  });
411
388
  }
389
+ export {
390
+ api_temp_default as default
391
+ };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@vtstech/pi-api",
3
- "version": "1.0.3",
3
+ "version": "1.0.4-1",
4
4
  "description": "API Mode Switcher extension for Pi Coding Agent",
5
5
  "main": "api.js",
6
6
  "keywords": ["pi-package", "pi-extensions"],
7
7
  "license": "MIT",
8
8
  "access": "public",
9
+ "type": "module",
9
10
  "author": "VTSTech",
10
11
  "homepage": "https://www.vts-tech.org",
11
12
  "repository": {
@@ -13,7 +14,7 @@
13
14
  "url": "https://github.com/VTSTech/pi-coding-agent"
14
15
  },
15
16
  "dependencies": {
16
- "@vtstech/pi-shared": "1.0.3"
17
+ "@vtstech/pi-shared": "1.0.4-1"
17
18
  },
18
19
  "peerDependencies": {
19
20
  "@mariozechner/pi-coding-agent": ">=0.66"