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 ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 1.0.26
4
+
5
+ - Test against Pi 0.99.0 and declare host-provided modules as wildcard peers.
6
+ - Replace no-op checks with scoped TypeScript checks and an offline real-Pi loader, provider-registration, and session-lifecycle smoke test.
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.24",
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": "echo 'nothing to 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.87.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
+ }