pi-parasail-provider 1.0.24 → 1.0.26
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/CHANGELOG.md +6 -0
- package/README.md +2 -0
- package/models.json +42 -0
- package/package.json +11 -4
- package/scripts/test-pi-compat.mjs +76 -0
- package/tsconfig.json +14 -0
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
|
@@ -82,6 +82,8 @@ Get your API key at [parasail.io](https://parasail.io/).
|
|
|
82
82
|
| Glm 52 | 262K | ✅ | Text | 16K | $1.40 | $4.40 | $0.26 |
|
|
83
83
|
| Glm 53 | 1M | ❌ | Text | 16K | $1.40 | $4.40 | $0.26 |
|
|
84
84
|
| Glm 53 Flash | 1M | ❌ | Text | 16K | $0.15 | $0.50 | $0.03 |
|
|
85
|
+
| Glm 53 Flash Nvfp4 | 1M | ❌ | Text | 16K | — | — | — |
|
|
86
|
+
| Glm 53 Flash Vercel | 1M | ❌ | Text | 16K | — | — | — |
|
|
85
87
|
| Googlegemma 3 4b It | 131K | ❌ | Text | 16K | $0.05 | — | — |
|
|
86
88
|
| Gpt Oss 120b Fast | 131K | ✅ | Text | 16K | $0.15 | $0.60 | — |
|
|
87
89
|
| GPT-OSS 120B | 131K | ✅ | Text | 16K | $0.10 | $0.75 | $0.06 |
|
package/models.json
CHANGED
|
@@ -350,6 +350,48 @@
|
|
|
350
350
|
"supportsStore": false
|
|
351
351
|
}
|
|
352
352
|
},
|
|
353
|
+
{
|
|
354
|
+
"id": "parasail-glm-53-flash-nvfp4",
|
|
355
|
+
"name": "Glm 53 Flash Nvfp4",
|
|
356
|
+
"reasoning": false,
|
|
357
|
+
"input": [
|
|
358
|
+
"text"
|
|
359
|
+
],
|
|
360
|
+
"cost": {
|
|
361
|
+
"input": 0,
|
|
362
|
+
"output": 0,
|
|
363
|
+
"cacheRead": 0,
|
|
364
|
+
"cacheWrite": 0
|
|
365
|
+
},
|
|
366
|
+
"contextWindow": 1048576,
|
|
367
|
+
"maxTokens": 16384,
|
|
368
|
+
"compat": {
|
|
369
|
+
"maxTokensField": "max_completion_tokens",
|
|
370
|
+
"supportsDeveloperRole": false,
|
|
371
|
+
"supportsStore": false
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"id": "parasail-glm-53-flash-vercel",
|
|
376
|
+
"name": "Glm 53 Flash Vercel",
|
|
377
|
+
"reasoning": false,
|
|
378
|
+
"input": [
|
|
379
|
+
"text"
|
|
380
|
+
],
|
|
381
|
+
"cost": {
|
|
382
|
+
"input": 0,
|
|
383
|
+
"output": 0,
|
|
384
|
+
"cacheRead": 0,
|
|
385
|
+
"cacheWrite": 0
|
|
386
|
+
},
|
|
387
|
+
"contextWindow": 1048576,
|
|
388
|
+
"maxTokens": 16384,
|
|
389
|
+
"compat": {
|
|
390
|
+
"maxTokensField": "max_completion_tokens",
|
|
391
|
+
"supportsDeveloperRole": false,
|
|
392
|
+
"supportsStore": false
|
|
393
|
+
}
|
|
394
|
+
},
|
|
353
395
|
{
|
|
354
396
|
"id": "parasail-kimi-k3",
|
|
355
397
|
"name": "Kimi K3",
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-parasail-provider",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
4
4
|
"description": "Parasail provider extension for pi - Access top open-source models (DeepSeek, Qwen, GLM, Kimi, Llama, Gemma, Mistral) through the Parasail API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"clean": "echo 'nothing to clean'",
|
|
9
9
|
"build": "echo 'nothing to build'",
|
|
10
|
-
"check": "
|
|
11
|
-
"update-models": "node scripts/update-models.js"
|
|
10
|
+
"check": "tsc --noEmit && node scripts/test-pi-compat.mjs",
|
|
11
|
+
"update-models": "node scripts/update-models.js",
|
|
12
|
+
"test:pi": "node scripts/test-pi-compat.mjs",
|
|
13
|
+
"typecheck": "tsc --noEmit"
|
|
12
14
|
},
|
|
13
15
|
"keywords": [
|
|
14
16
|
"pi",
|
|
@@ -33,6 +35,11 @@
|
|
|
33
35
|
]
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
38
|
+
"@earendil-works/pi-coding-agent": "0.99.0",
|
|
39
|
+
"typescript": "6.0.3",
|
|
40
|
+
"@types/node": "^25.9.1"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
37
44
|
}
|
|
38
45
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
// Import Pi only after selecting a disposable agent directory. Never read user auth/cache.
|
|
8
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const home = await mkdtemp(join(tmpdir(), 'pi-provider-compat-'));
|
|
10
|
+
const previousHome = process.env.PI_CODING_AGENT_DIR;
|
|
11
|
+
const previousFetch = globalThis.fetch;
|
|
12
|
+
process.env.PI_CODING_AGENT_DIR = home;
|
|
13
|
+
globalThis.fetch = async () => new Response('', { status: 503 });
|
|
14
|
+
let session;
|
|
15
|
+
try {
|
|
16
|
+
const { createAgentSession, DefaultResourceLoader, ModelRuntime, SessionManager, SettingsManager, VERSION } = await import('@earendil-works/pi-coding-agent');
|
|
17
|
+
assert.equal(VERSION, '0.99.0', 'run compatibility checks against the pinned host');
|
|
18
|
+
const manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
19
|
+
const hostPackages = ['@earendil-works/pi-ai', '@earendil-works/pi-agent-core', '@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', 'typebox'];
|
|
20
|
+
for (const name of hostPackages) {
|
|
21
|
+
assert.equal(manifest.dependencies?.[name], undefined, `${name} must not be installed as a runtime dependency`);
|
|
22
|
+
if (manifest.peerDependencies?.[name] !== undefined) assert.equal(manifest.peerDependencies[name], '*');
|
|
23
|
+
}
|
|
24
|
+
const settingsManager = SettingsManager.inMemory({ compaction: { enabled: false }, retry: { enabled: false } });
|
|
25
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
26
|
+
cwd: home, agentDir: home, settingsManager,
|
|
27
|
+
additionalExtensionPaths: [join(root, 'index.ts')],
|
|
28
|
+
noSkills: true, noPromptTemplates: true, noThemes: true, noContextFiles: true,
|
|
29
|
+
});
|
|
30
|
+
await resourceLoader.reload();
|
|
31
|
+
const loaded = resourceLoader.getExtensions();
|
|
32
|
+
assert.deepEqual(loaded.errors, [], 'extension must load in the real Pi loader');
|
|
33
|
+
assert.deepEqual(loaded.warnings ?? [], [], 'extension must not produce host-dependency warnings');
|
|
34
|
+
assert.equal(loaded.extensions.length, 1, 'load only this provider');
|
|
35
|
+
const registrations = [...loaded.runtime.pendingProviderRegistrations];
|
|
36
|
+
assert.ok(registrations.length > 0, 'factory must register a provider before session startup');
|
|
37
|
+
const modelRuntime = await ModelRuntime.create({ authPath: join(home, 'auth.json'), modelsPath: null, modelsStorePath: join(home, 'models-cache'), allowModelNetwork: false });
|
|
38
|
+
({ session } = await createAgentSession({ cwd: home, agentDir: home, resourceLoader, modelRuntime, settingsManager, sessionManager: SessionManager.inMemory(home), noTools: true }));
|
|
39
|
+
const errors = [];
|
|
40
|
+
await session.bindExtensions({ mode: 'print', onError: (error) => errors.push(error) });
|
|
41
|
+
await new Promise((done) => setImmediate(done));
|
|
42
|
+
let modelCount = 0;
|
|
43
|
+
for (const { name, config } of registrations) {
|
|
44
|
+
const models = modelRuntime.getAllModels(name);
|
|
45
|
+
assert.equal(models.length, config.models.length, `${name}: all configured models must survive host registration`);
|
|
46
|
+
assert.ok(models.length > 0, `${name}: nonempty catalog`);
|
|
47
|
+
assert.equal(new Set(models.map((model) => model.id)).size, models.length, `${name}: unique model IDs`);
|
|
48
|
+
for (const model of models) {
|
|
49
|
+
assert.equal(model.provider, name);
|
|
50
|
+
assert.ok(model.api && model.baseUrl && model.id && model.name);
|
|
51
|
+
if (model.type === 'image') assert.ok(model.output.includes('image'));
|
|
52
|
+
else assert.ok(model.contextWindow > 0, `${name}/${model.id}: positive context limit`);
|
|
53
|
+
if (model.type === 'chat') assert.ok(model.maxTokens > 0, `${name}/${model.id}: positive output limit`);
|
|
54
|
+
assert.ok(model.input.includes('text'));
|
|
55
|
+
for (const cost of Object.values(model.cost)) assert.ok(Number.isFinite(cost) && cost >= 0);
|
|
56
|
+
}
|
|
57
|
+
if (name === 'opencode') {
|
|
58
|
+
const { getAllBuiltinModels } = await import('@earendil-works/pi-ai/providers/all');
|
|
59
|
+
for (const native of getAllBuiltinModels(name).filter(model => model.type !== 'chat')) {
|
|
60
|
+
assert.ok(models.some(model => model.id === native.id && model.type === native.type), `${native.id}: preserve native operation`);
|
|
61
|
+
assert.ok(!modelRuntime.getModels(name).some(model => model.id === native.id), `${native.id}: must not become a chat model`);
|
|
62
|
+
}
|
|
63
|
+
assert.equal(typeof modelRuntime.getProvider(name).classify, 'function');
|
|
64
|
+
}
|
|
65
|
+
modelCount += models.length;
|
|
66
|
+
}
|
|
67
|
+
await session.extensionRunner.emit({ type: 'session_shutdown' });
|
|
68
|
+
assert.deepEqual(errors, [], 'startup and shutdown handlers must work with Pi 0.99 contexts');
|
|
69
|
+
console.log(`${manifest.name}: Pi ${VERSION} loader, manifest, session startup, and ${modelCount} models OK`);
|
|
70
|
+
} finally {
|
|
71
|
+
session?.dispose();
|
|
72
|
+
globalThis.fetch = previousFetch;
|
|
73
|
+
if (previousHome === undefined) delete process.env.PI_CODING_AGENT_DIR;
|
|
74
|
+
else process.env.PI_CODING_AGENT_DIR = previousHome;
|
|
75
|
+
await rm(home, { recursive: true, force: true });
|
|
76
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"types": ["node"]
|
|
12
|
+
},
|
|
13
|
+
"files": ["index.ts"]
|
|
14
|
+
}
|