@vtstech/pi-api 1.2.2 → 1.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.
Files changed (2) hide show
  1. package/api.js +177 -6
  2. package/package.json +10 -6
package/api.js CHANGED
@@ -1,7 +1,178 @@
1
- // .build-npm/api/api.temp.ts
2
- import { section, ok, info, warn } from "@vtstech/pi-shared/format";
3
- import { readModelsJson, readModifyWriteModelsJson, getOllamaBaseUrl, BUILTIN_PROVIDERS, EXTENSION_VERSION, isLocalProvider } from "@vtstech/pi-shared/ollama";
4
- import { SETTINGS_PATH, readSettings, writeSettings } from "@vtstech/pi-shared/config-io";
1
+ // shared/format.ts
2
+ function section(title) {
3
+ return `
4
+ \u2500\u2500 ${title} ${"\u2500".repeat(Math.max(1, 60 - title.length - 4))}`;
5
+ }
6
+ function ok(msg) {
7
+ return ` \u2705 ${msg}`;
8
+ }
9
+ function warn(msg) {
10
+ return ` \u26A0\uFE0F ${msg}`;
11
+ }
12
+ function info(msg) {
13
+ return ` \u2139\uFE0F ${msg}`;
14
+ }
15
+
16
+ // shared/ollama.ts
17
+ import * as fs from "node:fs";
18
+ import * as path from "node:path";
19
+ import os from "node:os";
20
+
21
+ // shared/debug.ts
22
+ var DEBUG_ENABLED = process?.env?.PI_EXTENSIONS_DEBUG === "1";
23
+ function debugLog(module, message, ...args) {
24
+ if (!DEBUG_ENABLED) return;
25
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
26
+ console.debug(`[pi-ext:${module}] ${timestamp} ${message}`, ...args);
27
+ }
28
+
29
+ // shared/ollama.ts
30
+ var EXTENSION_VERSION = "1.2.3";
31
+ var MODELS_JSON_PATH = path.join(os.homedir(), ".pi", "agent", "models.json");
32
+ var _modelsJsonCache = null;
33
+ var _ollamaBaseUrlCache = null;
34
+ var CACHE_TTL_MS = 2e3;
35
+ function getOllamaBaseUrl() {
36
+ const now = Date.now();
37
+ if (_ollamaBaseUrlCache && now - _ollamaBaseUrlCache.ts < CACHE_TTL_MS) return _ollamaBaseUrlCache.data;
38
+ try {
39
+ if (fs.existsSync(MODELS_JSON_PATH)) {
40
+ const raw = fs.readFileSync(MODELS_JSON_PATH, "utf-8");
41
+ const config = JSON.parse(raw);
42
+ const baseUrl = config?.providers?.["ollama"]?.baseUrl;
43
+ if (baseUrl) {
44
+ const result = baseUrl.replace(/\/v1\/?$/, "");
45
+ _ollamaBaseUrlCache = { data: result, ts: now };
46
+ return result;
47
+ }
48
+ }
49
+ } catch (err) {
50
+ debugLog("ollama", "failed to parse models.json for base URL", err);
51
+ }
52
+ if (process.env.OLLAMA_HOST) {
53
+ const result = `http://${process.env.OLLAMA_HOST.replace(/^https?:\/\//, "")}`;
54
+ _ollamaBaseUrlCache = { data: result, ts: now };
55
+ return result;
56
+ }
57
+ const fallback = "http://localhost:11434";
58
+ _ollamaBaseUrlCache = { data: fallback, ts: now };
59
+ return fallback;
60
+ }
61
+ function readModelsJson() {
62
+ const now = Date.now();
63
+ if (_modelsJsonCache && now - _modelsJsonCache.ts < CACHE_TTL_MS) return _modelsJsonCache.data;
64
+ try {
65
+ if (fs.existsSync(MODELS_JSON_PATH)) {
66
+ const raw = fs.readFileSync(MODELS_JSON_PATH, "utf-8");
67
+ const data = JSON.parse(raw);
68
+ _modelsJsonCache = { data, ts: now };
69
+ return data;
70
+ }
71
+ } catch (err) {
72
+ debugLog("ollama", "failed to read/parse models.json", err);
73
+ }
74
+ const empty = { providers: {} };
75
+ _modelsJsonCache = { data: empty, ts: now };
76
+ return empty;
77
+ }
78
+ function writeModelsJson(data) {
79
+ const dir = path.dirname(MODELS_JSON_PATH);
80
+ if (!fs.existsSync(dir)) {
81
+ fs.mkdirSync(dir, { recursive: true });
82
+ }
83
+ const tmpPath = MODELS_JSON_PATH + ".tmp";
84
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
85
+ fs.renameSync(tmpPath, MODELS_JSON_PATH);
86
+ _modelsJsonCache = null;
87
+ _ollamaBaseUrlCache = null;
88
+ }
89
+ var _modelsJsonLock = null;
90
+ async function acquireModelsJsonLock() {
91
+ while (_modelsJsonLock) {
92
+ await _modelsJsonLock;
93
+ }
94
+ let releaseLock;
95
+ _modelsJsonLock = new Promise((resolve) => {
96
+ releaseLock = resolve;
97
+ });
98
+ return {
99
+ release: () => {
100
+ releaseLock();
101
+ _modelsJsonLock = null;
102
+ }
103
+ };
104
+ }
105
+ async function readModifyWriteModelsJson(modifier) {
106
+ const { release } = await acquireModelsJsonLock();
107
+ try {
108
+ const data = readModelsJson();
109
+ const modified = modifier(data);
110
+ if (modified === null) return false;
111
+ writeModelsJson(modified);
112
+ return true;
113
+ } finally {
114
+ release();
115
+ }
116
+ }
117
+ var BUILTIN_PROVIDERS = {
118
+ openrouter: { api: "openai-completions", baseUrl: "https://openrouter.ai/api/v1", envKey: "OPENROUTER_API_KEY" },
119
+ anthropic: { api: "anthropic-messages", baseUrl: "https://api.anthropic.com/v1", envKey: "ANTHROPIC_API_KEY" },
120
+ google: { api: "gemini", baseUrl: "https://generativelanguage.googleapis.com", envKey: "GOOGLE_API_KEY" },
121
+ openai: { api: "openai-completions", baseUrl: "https://api.openai.com/v1", envKey: "OPENAI_API_KEY" },
122
+ groq: { api: "openai-completions", baseUrl: "https://api.groq.com/v1", envKey: "GROQ_API_KEY" },
123
+ deepseek: { api: "openai-completions", baseUrl: "https://api.deepseek.com/v1", envKey: "DEEPSEEK_API_KEY" },
124
+ mistral: { api: "openai-completions", baseUrl: "https://api.mistral.ai/v1", envKey: "MISTRAL_API_KEY" },
125
+ xai: { api: "openai-completions", baseUrl: "https://api.x.ai/v1", envKey: "XAI_API_KEY" },
126
+ together: { api: "openai-completions", baseUrl: "https://api.together.xyz/v1", envKey: "TOGETHER_API_KEY" },
127
+ fireworks: { api: "openai-completions", baseUrl: "https://api.fireworks.ai/inference/v1", envKey: "FIREWORKS_API_KEY" },
128
+ cohere: { api: "cohere-chat", baseUrl: "https://api.cohere.com/v1", envKey: "COHERE_API_KEY" },
129
+ zai: { api: "openai-completions", baseUrl: "https://open.bigmodel.cn/api/paas/v4", envKey: "ZAI_API_KEY" }
130
+ };
131
+ function isLocalProvider(baseUrl, providerName) {
132
+ if (providerName === "ollama") return true;
133
+ const url = baseUrl || "";
134
+ return url.includes("localhost") || url.includes("127.0.0.1") || url.includes("0.0.0.0");
135
+ }
136
+
137
+ // shared/config-io.ts
138
+ import * as fs2 from "fs";
139
+ import * as path2 from "path";
140
+ import os2 from "os";
141
+ var PI_AGENT_DIR = path2.join(os2.homedir(), ".pi", "agent");
142
+ function readJsonConfig(filePath, defaultValue = {}) {
143
+ try {
144
+ if (fs2.existsSync(filePath)) {
145
+ return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
146
+ }
147
+ } catch (err) {
148
+ debugLog("config-io", `failed to read config: ${filePath}`, err);
149
+ }
150
+ return defaultValue;
151
+ }
152
+ function writeJsonConfig(filePath, data) {
153
+ const dir = path2.dirname(filePath);
154
+ if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
155
+ const content = JSON.stringify(data, null, 2) + "\n";
156
+ const tmpPath = filePath + ".tmp";
157
+ try {
158
+ fs2.writeFileSync(tmpPath, content, "utf-8");
159
+ fs2.renameSync(tmpPath, filePath);
160
+ } catch {
161
+ fs2.writeFileSync(filePath, content, "utf-8");
162
+ }
163
+ }
164
+ var SETTINGS_PATH = path2.join(PI_AGENT_DIR, "settings.json");
165
+ var SECURITY_PATH = path2.join(PI_AGENT_DIR, "security.json");
166
+ var REACT_MODE_PATH = path2.join(PI_AGENT_DIR, "react-mode.json");
167
+ var MODEL_TEST_CONFIG_PATH = path2.join(PI_AGENT_DIR, "model-test-config.json");
168
+ function readSettings() {
169
+ return readJsonConfig(SETTINGS_PATH);
170
+ }
171
+ function writeSettings(data) {
172
+ writeJsonConfig(SETTINGS_PATH, data);
173
+ }
174
+
175
+ // extensions/api.ts
5
176
  var API_MODES = {
6
177
  "anthropic-messages": "Anthropic Claude API and compatibles",
7
178
  "openai-completions": "OpenAI Chat Completions API and compatibles",
@@ -64,7 +235,7 @@ function resolveProvider(config, explicit, currentProvider) {
64
235
  if (!provider) return null;
65
236
  return { name: local.name, config: provider };
66
237
  }
67
- function api_temp_default(pi) {
238
+ function api_default(pi) {
68
239
  const branding = [
69
240
  ` \u26A1 Pi API Mode Switcher v${EXTENSION_VERSION}`,
70
241
  ` Written by VTSTech`,
@@ -609,5 +780,5 @@ function api_temp_default(pi) {
609
780
  });
610
781
  }
611
782
  export {
612
- api_temp_default as default
783
+ api_default as default
613
784
  };
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@vtstech/pi-api",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "API Mode Switcher extension for Pi Coding Agent",
5
5
  "main": "api.js",
6
- "keywords": ["pi-package", "pi", "pi-coding-agent", "pi-extensions"],
6
+ "keywords": [
7
+ "pi-package",
8
+ "pi",
9
+ "pi-coding-agent",
10
+ "pi-extensions"
11
+ ],
7
12
  "license": "MIT",
8
13
  "access": "public",
9
14
  "type": "module",
@@ -13,13 +18,12 @@
13
18
  "type": "git",
14
19
  "url": "https://github.com/VTSTech/pi-coding-agent"
15
20
  },
16
- "dependencies": {
17
- "@vtstech/pi-shared": "1.2.2"
18
- },
19
21
  "peerDependencies": {
20
22
  "@mariozechner/pi-coding-agent": ">=0.66"
21
23
  },
22
24
  "pi": {
23
- "extensions": ["./api.js"]
25
+ "extensions": [
26
+ "./api.js"
27
+ ]
24
28
  }
25
29
  }