pi-tensorix-provider 1.0.7 → 1.0.8
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/README.md +1 -1
- package/deprecated-models.json +17 -0
- package/models.json +16 -16
- package/package.json +8 -9
- package/scripts/update-models.js +116 -3
package/README.md
CHANGED
|
@@ -29,7 +29,6 @@ _32 models — DeepSeek, Kimi, GLM, Qwen, MiniMax, Llama — all **free** for [p
|
|
|
29
29
|
| Chatterbox Turbo | 131K | ❌ | ❌ | **Free** | **Free** |
|
|
30
30
|
| Deepseek R1 0528 | 131K | ❌ | ✅ | **Free** | **Free** |
|
|
31
31
|
| Deepseek V3.2 | 164K | ❌ | ✅ | **Free** | **Free** |
|
|
32
|
-
| Deepseek V4 Flash | 1.0M | ❌ | ✅ | **Free** | **Free** |
|
|
33
32
|
| Deepseek V4 Flash 0731 | 131K | ❌ | ✅ | **Free** | **Free** |
|
|
34
33
|
| Deepseek V4 Pro | 1.0M | ❌ | ✅ | **Free** | **Free** |
|
|
35
34
|
| Glm 5 | 203K | ❌ | ✅ | **Free** | **Free** |
|
|
@@ -46,6 +45,7 @@ _32 models — DeepSeek, Kimi, GLM, Qwen, MiniMax, Llama — all **free** for [p
|
|
|
46
45
|
| Qwen3 235b A22b 2507 | 262K | ❌ | ✅ | **Free** | **Free** |
|
|
47
46
|
| Qwen3.5 122b A10b | 262K | ❌ | ✅ | **Free** | **Free** |
|
|
48
47
|
| Qwen3.5 9b | 262K | ❌ | ✅ | **Free** | **Free** |
|
|
48
|
+
| Qwen3.8 2.4t A95b | 131K | ❌ | ❌ | **Free** | **Free** |
|
|
49
49
|
|
|
50
50
|
## Installation
|
|
51
51
|
|
package/deprecated-models.json
CHANGED
|
@@ -83,5 +83,22 @@
|
|
|
83
83
|
"contextWindow": 131072,
|
|
84
84
|
"maxTokens": 131072,
|
|
85
85
|
"deprecatedAt": "2026-08-01T02:00:23.121Z"
|
|
86
|
+
},
|
|
87
|
+
"deepseek/deepseek-v4-flash": {
|
|
88
|
+
"id": "deepseek/deepseek-v4-flash",
|
|
89
|
+
"name": "Deepseek V4 Flash",
|
|
90
|
+
"reasoning": false,
|
|
91
|
+
"input": [
|
|
92
|
+
"text"
|
|
93
|
+
],
|
|
94
|
+
"cost": {
|
|
95
|
+
"input": 0,
|
|
96
|
+
"output": 0,
|
|
97
|
+
"cacheRead": 0,
|
|
98
|
+
"cacheWrite": 0
|
|
99
|
+
},
|
|
100
|
+
"contextWindow": 131072,
|
|
101
|
+
"maxTokens": 131072,
|
|
102
|
+
"deprecatedAt": "2026-08-09T02:00:20.006Z"
|
|
86
103
|
}
|
|
87
104
|
}
|
package/models.json
CHANGED
|
@@ -47,22 +47,6 @@
|
|
|
47
47
|
"contextWindow": 131072,
|
|
48
48
|
"maxTokens": 131072
|
|
49
49
|
},
|
|
50
|
-
{
|
|
51
|
-
"id": "deepseek/deepseek-v4-flash",
|
|
52
|
-
"name": "Deepseek V4 Flash",
|
|
53
|
-
"reasoning": false,
|
|
54
|
-
"input": [
|
|
55
|
-
"text"
|
|
56
|
-
],
|
|
57
|
-
"cost": {
|
|
58
|
-
"input": 0,
|
|
59
|
-
"output": 0,
|
|
60
|
-
"cacheRead": 0,
|
|
61
|
-
"cacheWrite": 0
|
|
62
|
-
},
|
|
63
|
-
"contextWindow": 131072,
|
|
64
|
-
"maxTokens": 131072
|
|
65
|
-
},
|
|
66
50
|
{
|
|
67
51
|
"id": "deepseek/deepseek-v4-flash-0731",
|
|
68
52
|
"name": "Deepseek V4 Flash 0731",
|
|
@@ -239,6 +223,22 @@
|
|
|
239
223
|
"contextWindow": 131072,
|
|
240
224
|
"maxTokens": 131072
|
|
241
225
|
},
|
|
226
|
+
{
|
|
227
|
+
"id": "qwen/qwen3.8-2.4t-a95b",
|
|
228
|
+
"name": "Qwen3.8 2.4t A95b",
|
|
229
|
+
"reasoning": false,
|
|
230
|
+
"input": [
|
|
231
|
+
"text"
|
|
232
|
+
],
|
|
233
|
+
"cost": {
|
|
234
|
+
"input": 0,
|
|
235
|
+
"output": 0,
|
|
236
|
+
"cacheRead": 0,
|
|
237
|
+
"cacheWrite": 0
|
|
238
|
+
},
|
|
239
|
+
"contextWindow": 131072,
|
|
240
|
+
"maxTokens": 131072
|
|
241
|
+
},
|
|
242
242
|
{
|
|
243
243
|
"id": "z-ai/glm-5",
|
|
244
244
|
"name": "Glm 5",
|
package/package.json
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-tensorix-provider",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"packageManager": "pnpm@11.18.0",
|
|
3
|
+
"version": "1.0.8",
|
|
5
4
|
"description": "Tensorix provider extension for pi - Access DeepSeek, GLM, Kimi, Qwen, MiniMax, Llama, and more through the Tensorix API",
|
|
6
5
|
"type": "module",
|
|
7
6
|
"main": "index.ts",
|
|
8
|
-
"scripts": {
|
|
9
|
-
"clean": "echo 'nothing to clean'",
|
|
10
|
-
"build": "echo 'nothing to build'",
|
|
11
|
-
"check": "echo 'nothing to check'",
|
|
12
|
-
"update-models": "node scripts/update-models.js"
|
|
13
|
-
},
|
|
14
7
|
"keywords": [
|
|
15
8
|
"pi",
|
|
16
9
|
"extension",
|
|
@@ -31,5 +24,11 @@
|
|
|
31
24
|
"extensions": [
|
|
32
25
|
"./index.ts"
|
|
33
26
|
]
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"clean": "echo 'nothing to clean'",
|
|
30
|
+
"build": "echo 'nothing to build'",
|
|
31
|
+
"check": "echo 'nothing to check'",
|
|
32
|
+
"update-models": "node scripts/update-models.js"
|
|
34
33
|
}
|
|
35
|
-
}
|
|
34
|
+
}
|
package/scripts/update-models.js
CHANGED
|
@@ -12,14 +12,120 @@
|
|
|
12
12
|
* reasoning capability and adds compatibility overrides at runtime.
|
|
13
13
|
*
|
|
14
14
|
* Merge order for README: models.json → apply patch.json → merge custom-models.json
|
|
15
|
+
*
|
|
16
|
+
* API key: the stored `tensorix` credential in ~/.pi/agent/auth.json wins, then
|
|
17
|
+
* the TENSORIX_API_KEY environment variable. The script refuses to run without one.
|
|
15
18
|
*/
|
|
16
19
|
|
|
17
20
|
import fs from 'fs';
|
|
21
|
+
import os from 'os';
|
|
22
|
+
import { execSync } from 'child_process';
|
|
18
23
|
import path from 'path';
|
|
19
24
|
import { fileURLToPath } from 'url';
|
|
20
25
|
|
|
21
26
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
22
27
|
|
|
28
|
+
// pi's agent directory: PI_CODING_AGENT_DIR (with ~ expansion) or ~/.pi/agent.
|
|
29
|
+
function piAgentDir() {
|
|
30
|
+
const envDir = process.env.PI_CODING_AGENT_DIR;
|
|
31
|
+
if (envDir) {
|
|
32
|
+
return envDir.startsWith('~/') || envDir === '~'
|
|
33
|
+
? path.join(os.homedir(), envDir.slice(1))
|
|
34
|
+
: envDir;
|
|
35
|
+
}
|
|
36
|
+
return path.join(os.homedir(), '.pi', 'agent');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const AUTH_JSON_PATH = path.join(piAgentDir(), 'auth.json');
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a configured value using pi's semantics (resolve-config-value.ts in
|
|
43
|
+
* pi-mono): "!command" runs via the shell (10s timeout) and uses trimmed
|
|
44
|
+
* stdout; "$VAR" / "${VAR}" interpolate environment variables ("$$" escapes a
|
|
45
|
+
* literal "$", "$!" a literal "!"); anything else is a literal. Returns
|
|
46
|
+
* undefined when a referenced env var is unset or a command fails.
|
|
47
|
+
*/
|
|
48
|
+
function resolveConfigValue(config, env) {
|
|
49
|
+
if (typeof config !== 'string' || config.length === 0) return undefined;
|
|
50
|
+
if (config.startsWith('!')) {
|
|
51
|
+
try {
|
|
52
|
+
const out = execSync(config.slice(1), {
|
|
53
|
+
encoding: 'utf8',
|
|
54
|
+
timeout: 10000,
|
|
55
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
56
|
+
});
|
|
57
|
+
return out.trim() || undefined;
|
|
58
|
+
} catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
63
|
+
let resolved = '';
|
|
64
|
+
let index = 0;
|
|
65
|
+
while (index < config.length) {
|
|
66
|
+
const dollar = config.indexOf('$', index);
|
|
67
|
+
if (dollar < 0) {
|
|
68
|
+
resolved += config.slice(index);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
resolved += config.slice(index, dollar);
|
|
72
|
+
const next = config[dollar + 1];
|
|
73
|
+
let name;
|
|
74
|
+
if (next === '$' || next === '!') {
|
|
75
|
+
resolved += next;
|
|
76
|
+
index = dollar + 2;
|
|
77
|
+
continue;
|
|
78
|
+
} else if (next === '{') {
|
|
79
|
+
const end = config.indexOf('}', dollar + 2);
|
|
80
|
+
if (end < 0) {
|
|
81
|
+
resolved += '$';
|
|
82
|
+
index = dollar + 1;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const inner = config.slice(dollar + 2, end);
|
|
86
|
+
if (!ENV_NAME_RE.test(inner)) {
|
|
87
|
+
resolved += config.slice(dollar, end + 1);
|
|
88
|
+
index = end + 1;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
name = inner;
|
|
92
|
+
index = end + 1;
|
|
93
|
+
} else {
|
|
94
|
+
const match = config.slice(dollar + 1).match(/^[A-Za-z_][A-Za-z0-9_]*/);
|
|
95
|
+
if (!match) {
|
|
96
|
+
resolved += '$';
|
|
97
|
+
index = dollar + 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
name = match[0];
|
|
101
|
+
index = dollar + 1 + name.length;
|
|
102
|
+
}
|
|
103
|
+
const value = (env && env[name]) || process.env[name] || undefined;
|
|
104
|
+
if (value === undefined) return undefined;
|
|
105
|
+
resolved += value;
|
|
106
|
+
}
|
|
107
|
+
return resolved;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The API key, resolved the way pi itself resolves it for this provider: the
|
|
112
|
+
* stored `tensorix` credential in ~/.pi/agent/auth.json wins, then
|
|
113
|
+
* the TENSORIX_API_KEY environment variable.
|
|
114
|
+
*/
|
|
115
|
+
function resolveApiKey() {
|
|
116
|
+
try {
|
|
117
|
+
const auth = JSON.parse(fs.readFileSync(AUTH_JSON_PATH, 'utf8'));
|
|
118
|
+
const credential = auth?.tensorix;
|
|
119
|
+
if (credential && credential.type === 'api_key' && typeof credential.key === 'string') {
|
|
120
|
+
const key = resolveConfigValue(credential.key, credential.env);
|
|
121
|
+
if (key) return key;
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
// Missing or unparseable auth.json: fall through to the env var.
|
|
125
|
+
}
|
|
126
|
+
return process.env.TENSORIX_API_KEY || undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
23
129
|
const MODELS_API_URL = 'https://api.tensorix.ai/v1/models';
|
|
24
130
|
const MODELS_JSON_PATH = path.join(__dirname, '..', 'models.json');
|
|
25
131
|
const PATCH_JSON_PATH = path.join(__dirname, '..', 'patch.json');
|
|
@@ -263,9 +369,16 @@ async function main() {
|
|
|
263
369
|
console.log(`Fetching models from ${MODELS_API_URL}...`);
|
|
264
370
|
|
|
265
371
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
372
|
+
// Without a key the API answers 200 with only the PUBLIC model list, so an
|
|
373
|
+
// unauthenticated run does not fail: it silently rewrites models.json (and
|
|
374
|
+
// the README table) with every gated model missing. Refuse to run rather
|
|
375
|
+
// than corrupt the generated files.
|
|
376
|
+
const apiKey = resolveApiKey();
|
|
377
|
+
if (!apiKey) {
|
|
378
|
+
console.error('❌ No API key found: no `tensorix` credential resolved from ' + AUTH_JSON_PATH + ' and TENSORIX_API_KEY is not set.');
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
const headers = { Authorization: `Bearer ${apiKey}` };
|
|
269
382
|
|
|
270
383
|
const response = await fetch(MODELS_API_URL, { headers });
|
|
271
384
|
if (!response.ok) {
|