pi-hypercharm-provider 1.3.37 → 1.3.39
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/bun.lock +16 -13
- package/deprecated-models.json +66 -1
- package/models.json +0 -62
- package/package.json +7 -4
- package/scripts/test-pi-compat.mjs +4 -4
- package/tests/provider.integration.test.ts +21 -8
package/bun.lock
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"": {
|
|
6
6
|
"name": "pi-hypercharm-provider",
|
|
7
7
|
"devDependencies": {
|
|
8
|
-
"@earendil-works/pi-ai": "1.
|
|
9
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
10
|
-
"@earendil-works/pi-tui": "1.
|
|
8
|
+
"@earendil-works/pi-ai": "1.1.0",
|
|
9
|
+
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
10
|
+
"@earendil-works/pi-tui": "1.1.0",
|
|
11
11
|
"@types/node": "^24.10.1",
|
|
12
12
|
"jiti": "2.7.0",
|
|
13
13
|
"typescript": "6.0.3",
|
|
@@ -19,8 +19,11 @@
|
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
|
+
"overrides": {
|
|
23
|
+
"brace-expansion": "5.0.12",
|
|
24
|
+
},
|
|
22
25
|
"packages": {
|
|
23
|
-
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.
|
|
26
|
+
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.129.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-MH7LB20kNpGLUpPTe2OG5XvL/KhX8HUO9XyBaFjgFk6TLS4Xjt0VPIuMKywe7POKKPslX+QxSlVok9e+8kG5Nw=="],
|
|
24
27
|
|
|
25
28
|
"@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1127.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/credential-provider-node": "^3.972.82", "@aws-sdk/eventstream-handler-node": "^3.972.34", "@aws-sdk/middleware-eventstream": "^3.972.29", "@aws-sdk/middleware-websocket": "^3.972.52", "@aws-sdk/token-providers": "3.1127.0", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA=="],
|
|
26
29
|
|
|
@@ -62,21 +65,21 @@
|
|
|
62
65
|
|
|
63
66
|
"@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
|
|
64
67
|
|
|
65
|
-
"@earendil-works/chord": ["@earendil-works/chord@1.
|
|
68
|
+
"@earendil-works/chord": ["@earendil-works/chord@1.1.0", "", { "dependencies": { "esbuild": "0.28.2" } }, "sha512-gsHzKfyQ3t0ZIQ3cLBjJ5Vqy1TYnFyruHIV3g3BwmulCDYe5BW4yT9vaJk9QzN6YANILIO75uzuq+Gdxtzz1og=="],
|
|
66
69
|
|
|
67
|
-
"@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@1.
|
|
70
|
+
"@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@1.1.0", "", { "dependencies": { "@earendil-works/pi-ai": "^1.1.0", "typebox": "1.3.27" } }, "sha512-aX1KZomNCPmwYnXa3OivF3VYLJ+WPUkIJlEIZTgwdOZdY/+oToWTQ334WYpQeOz9POpiYFNMJLPwIhXQ4e48kg=="],
|
|
68
71
|
|
|
69
|
-
"@earendil-works/pi-ai": ["@earendil-works/pi-ai@1.
|
|
72
|
+
"@earendil-works/pi-ai": ["@earendil-works/pi-ai@1.1.0", "", { "dependencies": { "@anthropic-ai/sdk": "0.129.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "^1.1.0", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-1T7LAkc/5Bvc0v6w4vAGVdCrli0o/E0pEmYKTnixu95vSFArBjvbhS/G4ZwI0RUePgf0Imcu0VyqlM4EcXxqfw=="],
|
|
70
73
|
|
|
71
|
-
"@earendil-works/pi-codemode": ["@earendil-works/pi-codemode@1.
|
|
74
|
+
"@earendil-works/pi-codemode": ["@earendil-works/pi-codemode@1.1.0", "", { "dependencies": { "quickjs-wasi": "3.6.2" } }, "sha512-8Asc2AzhoNaXS1snmRFa96OhcWIlFM5k1Kuiz6p2DvIYgi5QHQccRAmDVY9oO92TzWrizpvQpconZGQ7JhlI7Q=="],
|
|
72
75
|
|
|
73
|
-
"@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@1.
|
|
76
|
+
"@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@1.1.0", "", { "dependencies": { "@earendil-works/chord": "^1.1.0", "@earendil-works/pi-agent-core": "^1.1.0", "@earendil-works/pi-ai": "^1.1.0", "@earendil-works/pi-codemode": "^1.1.0", "@earendil-works/pi-mcp": "^1.1.0", "@earendil-works/pi-tui": "^1.1.0", "@silvia-odwyer/photon-node": "0.3.4", "brace-expansion": "5.0.12", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "minimatch": "10.2.6", "proper-lockfile": "4.1.2", "quickjs-wasi": "3.6.2", "semver": "7.8.5", "typebox": "1.3.27", "undici": "8.10.2", "yaml": "2.9.0" }, "bin": { "pi": "dist/bundle/cli.js" } }, "sha512-SeEi/4hdcHNgA9UWlefZl7ZZpm3dzi2OoxNjDHsBJ9o298LNOtbL4DGKgitlEj6uCTccvtw6f2hlCkTPVJ2RXg=="],
|
|
74
77
|
|
|
75
|
-
"@earendil-works/pi-mcp": ["@earendil-works/pi-mcp@1.
|
|
78
|
+
"@earendil-works/pi-mcp": ["@earendil-works/pi-mcp@1.1.0", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-xGKwvu3SvVTeoIx8Z7UGoJprB4VK20wKORMhufcWGx61fIauhu3J+UqfB5eeoF1oE/geYBA598K6nh1SdABQkg=="],
|
|
76
79
|
|
|
77
|
-
"@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@1.
|
|
80
|
+
"@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@1.1.0", "", {}, "sha512-8gAK05/2pPozZZz6hCLOi8x2vsqzvsmO9gG92kbvuvTPm0qMHaFlaXX98ndXsrOi5pmzha7vNLguuG4+0Rgxjw=="],
|
|
78
81
|
|
|
79
|
-
"@earendil-works/pi-tui": ["@earendil-works/pi-tui@1.
|
|
82
|
+
"@earendil-works/pi-tui": ["@earendil-works/pi-tui@1.1.0", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.11" } }, "sha512-v7wkS0y2ErZvZkSfemqd9RrBZJ5x6p8Ujsv7NdJj01IXJyFM0kNL6rMdcKcvTe7EVTd6ugvDB9VPZSoaBF9QxQ=="],
|
|
80
83
|
|
|
81
84
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
|
|
82
85
|
|
|
@@ -180,7 +183,7 @@
|
|
|
180
183
|
|
|
181
184
|
"bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
|
|
182
185
|
|
|
183
|
-
"brace-expansion": ["brace-expansion@5.0.
|
|
186
|
+
"brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="],
|
|
184
187
|
|
|
185
188
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
|
186
189
|
|
package/deprecated-models.json
CHANGED
|
@@ -1 +1,66 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"deepseek-v4-flash": {
|
|
3
|
+
"id": "deepseek-v4-flash",
|
|
4
|
+
"name": "DeepSeek V4 Flash",
|
|
5
|
+
"reasoning": true,
|
|
6
|
+
"thinkingLevelMap": {
|
|
7
|
+
"off": null,
|
|
8
|
+
"minimal": null,
|
|
9
|
+
"low": null,
|
|
10
|
+
"medium": null,
|
|
11
|
+
"high": "high",
|
|
12
|
+
"xhigh": "xhigh",
|
|
13
|
+
"max": null
|
|
14
|
+
},
|
|
15
|
+
"input": [
|
|
16
|
+
"text"
|
|
17
|
+
],
|
|
18
|
+
"cost": {
|
|
19
|
+
"input": 0.2,
|
|
20
|
+
"output": 0.4,
|
|
21
|
+
"cacheRead": 0.04,
|
|
22
|
+
"cacheWrite": 0
|
|
23
|
+
},
|
|
24
|
+
"contextWindow": 1000000,
|
|
25
|
+
"maxTokens": 384000,
|
|
26
|
+
"compat": {
|
|
27
|
+
"supportsStore": false,
|
|
28
|
+
"supportsReasoningEffort": true,
|
|
29
|
+
"thinkingFormat": "deepseek",
|
|
30
|
+
"maxTokensField": "max_tokens"
|
|
31
|
+
},
|
|
32
|
+
"deprecatedAt": "2026-10-10T00:00:09.617Z"
|
|
33
|
+
},
|
|
34
|
+
"deepseek-v4-pro": {
|
|
35
|
+
"id": "deepseek-v4-pro",
|
|
36
|
+
"name": "DeepSeek V4 Pro",
|
|
37
|
+
"reasoning": true,
|
|
38
|
+
"thinkingLevelMap": {
|
|
39
|
+
"off": null,
|
|
40
|
+
"minimal": null,
|
|
41
|
+
"low": null,
|
|
42
|
+
"medium": null,
|
|
43
|
+
"high": "high",
|
|
44
|
+
"xhigh": "xhigh",
|
|
45
|
+
"max": null
|
|
46
|
+
},
|
|
47
|
+
"input": [
|
|
48
|
+
"text"
|
|
49
|
+
],
|
|
50
|
+
"cost": {
|
|
51
|
+
"input": 2.4,
|
|
52
|
+
"output": 4.8,
|
|
53
|
+
"cacheRead": 0.2,
|
|
54
|
+
"cacheWrite": 0
|
|
55
|
+
},
|
|
56
|
+
"contextWindow": 1000000,
|
|
57
|
+
"maxTokens": 384000,
|
|
58
|
+
"compat": {
|
|
59
|
+
"supportsStore": false,
|
|
60
|
+
"supportsReasoningEffort": true,
|
|
61
|
+
"thinkingFormat": "deepseek",
|
|
62
|
+
"maxTokensField": "max_tokens"
|
|
63
|
+
},
|
|
64
|
+
"deprecatedAt": "2026-10-10T00:00:09.617Z"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/models.json
CHANGED
|
@@ -1,35 +1,4 @@
|
|
|
1
1
|
[
|
|
2
|
-
{
|
|
3
|
-
"id": "deepseek-v4-flash",
|
|
4
|
-
"name": "DeepSeek V4 Flash",
|
|
5
|
-
"reasoning": true,
|
|
6
|
-
"thinkingLevelMap": {
|
|
7
|
-
"off": null,
|
|
8
|
-
"minimal": null,
|
|
9
|
-
"low": null,
|
|
10
|
-
"medium": null,
|
|
11
|
-
"high": "high",
|
|
12
|
-
"xhigh": "xhigh",
|
|
13
|
-
"max": null
|
|
14
|
-
},
|
|
15
|
-
"input": [
|
|
16
|
-
"text"
|
|
17
|
-
],
|
|
18
|
-
"cost": {
|
|
19
|
-
"input": 0.2,
|
|
20
|
-
"output": 0.4,
|
|
21
|
-
"cacheRead": 0.04,
|
|
22
|
-
"cacheWrite": 0
|
|
23
|
-
},
|
|
24
|
-
"contextWindow": 1000000,
|
|
25
|
-
"maxTokens": 384000,
|
|
26
|
-
"compat": {
|
|
27
|
-
"supportsStore": false,
|
|
28
|
-
"supportsReasoningEffort": true,
|
|
29
|
-
"thinkingFormat": "deepseek",
|
|
30
|
-
"maxTokensField": "max_tokens"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
2
|
{
|
|
34
3
|
"id": "deepseek-v4-flash-0731",
|
|
35
4
|
"name": "DeepSeek V4 Flash 0731",
|
|
@@ -61,37 +30,6 @@
|
|
|
61
30
|
"maxTokensField": "max_tokens"
|
|
62
31
|
}
|
|
63
32
|
},
|
|
64
|
-
{
|
|
65
|
-
"id": "deepseek-v4-pro",
|
|
66
|
-
"name": "DeepSeek V4 Pro",
|
|
67
|
-
"reasoning": true,
|
|
68
|
-
"thinkingLevelMap": {
|
|
69
|
-
"off": null,
|
|
70
|
-
"minimal": null,
|
|
71
|
-
"low": null,
|
|
72
|
-
"medium": null,
|
|
73
|
-
"high": "high",
|
|
74
|
-
"xhigh": "xhigh",
|
|
75
|
-
"max": null
|
|
76
|
-
},
|
|
77
|
-
"input": [
|
|
78
|
-
"text"
|
|
79
|
-
],
|
|
80
|
-
"cost": {
|
|
81
|
-
"input": 2.4,
|
|
82
|
-
"output": 4.8,
|
|
83
|
-
"cacheRead": 0.2,
|
|
84
|
-
"cacheWrite": 0
|
|
85
|
-
},
|
|
86
|
-
"contextWindow": 1000000,
|
|
87
|
-
"maxTokens": 384000,
|
|
88
|
-
"compat": {
|
|
89
|
-
"supportsStore": false,
|
|
90
|
-
"supportsReasoningEffort": true,
|
|
91
|
-
"thinkingFormat": "deepseek",
|
|
92
|
-
"maxTokensField": "max_tokens"
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
33
|
{
|
|
96
34
|
"id": "deepseek-v4-pro-0813",
|
|
97
35
|
"name": "DeepSeek V4 Pro 0813",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-hypercharm-provider",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.39",
|
|
4
4
|
"description": "HyperCharm provider extension for pi - Access DeepSeek, GLM, Kimi, Qwen, MiniMax, Gemma, and GPT-OSS models through the Charm Hyper API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -26,10 +26,13 @@
|
|
|
26
26
|
"@earendil-works/pi-ai": "*",
|
|
27
27
|
"@earendil-works/pi-coding-agent": "*"
|
|
28
28
|
},
|
|
29
|
+
"overrides": {
|
|
30
|
+
"brace-expansion": "5.0.12"
|
|
31
|
+
},
|
|
29
32
|
"devDependencies": {
|
|
30
|
-
"@earendil-works/pi-ai": "1.
|
|
31
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
32
|
-
"@earendil-works/pi-tui": "1.
|
|
33
|
+
"@earendil-works/pi-ai": "1.1.0",
|
|
34
|
+
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
35
|
+
"@earendil-works/pi-tui": "1.1.0",
|
|
33
36
|
"@types/node": "^24.10.1",
|
|
34
37
|
"jiti": "2.7.0",
|
|
35
38
|
"typescript": "6.0.3"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Offline Pi 1.0 manifest, lifecycle, catalog and real transport regression.
|
|
1
|
+
// Offline Pi 1.1.0 manifest, lifecycle, catalog and real transport regression.
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
@@ -18,13 +18,13 @@ try {
|
|
|
18
18
|
const hostEntry = process.env.PI1_HOST_ENTRY === 'bundle' ? 'dist/bundle/index.js' : 'dist/index.js';
|
|
19
19
|
const sdk = await import(host ? pathToFileURL(join(host, hostEntry)).href : '@earendil-works/pi-coding-agent');
|
|
20
20
|
const { createAgentSession, DefaultResourceLoader, ModelRuntime, SessionManager, SettingsManager, VERSION } = sdk;
|
|
21
|
-
assert.equal(VERSION, '1.
|
|
22
|
-
assert.equal((await import('@earendil-works/pi-coding-agent')).VERSION, '1.
|
|
21
|
+
assert.equal(VERSION, '1.1.0', 'executing host version');
|
|
22
|
+
assert.equal((await import('@earendil-works/pi-coding-agent')).VERSION, '1.1.0', 'development host version');
|
|
23
23
|
const manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
24
24
|
for (const name of ['@earendil-works/pi-ai', '@earendil-works/pi-agent-core', '@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', 'typebox']) {
|
|
25
25
|
assert.equal(manifest.dependencies?.[name], undefined, `${name}: do not bundle host packages`);
|
|
26
26
|
if (manifest.peerDependencies?.[name] !== undefined) assert.equal(manifest.peerDependencies[name], '*');
|
|
27
|
-
if (name !== 'typebox' && manifest.devDependencies?.[name]) assert.equal(manifest.devDependencies[name], '1.
|
|
27
|
+
if (name !== 'typebox' && manifest.devDependencies?.[name]) assert.equal(manifest.devDependencies[name], '1.1.0');
|
|
28
28
|
}
|
|
29
29
|
const settingsManager = SettingsManager.inMemory({ packages: [root], compaction: { enabled: false }, retry: { enabled: false } });
|
|
30
30
|
const resourceLoader = new DefaultResourceLoader({ cwd: home, agentDir: home, settingsManager,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* official provider's identifier surface (tests/fixtures/official-surface.ts).
|
|
10
10
|
*/
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
|
-
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
12
|
+
import { copyFileSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { tmpdir } from "node:os";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { after, test } from "node:test";
|
|
@@ -22,7 +22,6 @@ delete process.env.HYPERCHARM_API_KEY;
|
|
|
22
22
|
|
|
23
23
|
const extensionPath = fileURLToPath(new URL("../index.ts", import.meta.url));
|
|
24
24
|
const officialSurfacePath = fileURLToPath(new URL("./fixtures/official-surface.ts", import.meta.url));
|
|
25
|
-
const deprecatedModelsPath = fileURLToPath(new URL("../deprecated-models.json", import.meta.url));
|
|
26
25
|
const embeddedModelsPath = fileURLToPath(new URL("../models.json", import.meta.url));
|
|
27
26
|
|
|
28
27
|
const EMBEDDED_AUTHORITY_NOTE = "tests must run against the embedded catalog";
|
|
@@ -199,9 +198,22 @@ test("loads offline: embedded catalog, deprecated grace, namespaced registration
|
|
|
199
198
|
const stderr = captureStderr();
|
|
200
199
|
let harness;
|
|
201
200
|
try {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
// The generated graveyard may be empty. Exercise the actual extension
|
|
202
|
+
// against deterministic data in an isolated copy, never edit generated files.
|
|
203
|
+
const fixtureDir = mkdtempSync(path.join(agentDir, "grace-fixture-"));
|
|
204
|
+
const sourceDir = path.dirname(extensionPath);
|
|
205
|
+
for (const file of readdirSync(sourceDir)) {
|
|
206
|
+
if (/\.(ts|json)$/.test(file)) copyFileSync(path.join(sourceDir, file), path.join(fixtureDir, file));
|
|
207
|
+
}
|
|
208
|
+
const graceNow = Date.UTC(2026, 0, 15);
|
|
209
|
+
const base = JSON.parse(readFileSync(embeddedModelsPath, "utf8"))[0];
|
|
210
|
+
const deprecated = {
|
|
211
|
+
fresh: { ...base, id: "fixture-grace-fresh", deprecatedAt: new Date(graceNow - DEPRECATED_TTL_MS).toISOString() },
|
|
212
|
+
stale: { ...base, id: "fixture-grace-stale", deprecatedAt: new Date(graceNow - DEPRECATED_TTL_MS - 1).toISOString() },
|
|
213
|
+
invalid: { ...base, id: "fixture-grace-invalid", deprecatedAt: "invalid" },
|
|
214
|
+
};
|
|
215
|
+
writeFileSync(path.join(fixtureDir, "deprecated-models.json"), JSON.stringify(deprecated));
|
|
216
|
+
harness = await load({ catalogNow: graceNow, extensionPaths: [path.join(fixtureDir, "index.ts")] });
|
|
205
217
|
|
|
206
218
|
const embedded = harness.runtime.getModel("hypercharm", "deepseek-v4-flash");
|
|
207
219
|
assert.ok(embedded, "embedded catalog must register without any network");
|
|
@@ -211,8 +223,7 @@ test("loads offline: embedded catalog, deprecated grace, namespaced registration
|
|
|
211
223
|
assert.equal(EMBEDDED_AUTHORITY_NOTE, "tests must run against the embedded catalog");
|
|
212
224
|
|
|
213
225
|
// Deprecated grace: entries inside the 14-day TTL are still served,
|
|
214
|
-
// entries past it are evicted
|
|
215
|
-
const deprecated = JSON.parse(readFileSync(deprecatedModelsPath, "utf8"));
|
|
226
|
+
// entries past it are evicted, including the exact TTL + 1ms boundary.
|
|
216
227
|
const embeddedIds = new Set(
|
|
217
228
|
(Array.isArray(JSON.parse(readFileSync(embeddedModelsPath, "utf8")))
|
|
218
229
|
? JSON.parse(readFileSync(embeddedModelsPath, "utf8"))
|
|
@@ -222,7 +233,9 @@ test("loads offline: embedded catalog, deprecated grace, namespaced registration
|
|
|
222
233
|
const deprecatedOnly = Object.values(deprecated).filter((entry) => !embeddedIds.has(entry.id));
|
|
223
234
|
const fresh = deprecatedOnly.filter((entry) => graceNow - Date.parse(entry.deprecatedAt) <= DEPRECATED_TTL_MS);
|
|
224
235
|
const stale = deprecatedOnly.filter((entry) => graceNow - Date.parse(entry.deprecatedAt) > DEPRECATED_TTL_MS);
|
|
225
|
-
assert.
|
|
236
|
+
assert.equal(fresh.length, 1, "exact TTL boundary is still served");
|
|
237
|
+
assert.equal(stale.length, 1, "TTL + 1ms is expired");
|
|
238
|
+
assert.equal(harness.runtime.getModel("hypercharm", deprecated.invalid.id), undefined, "invalid deprecation timestamps are evicted");
|
|
226
239
|
for (const entry of fresh) {
|
|
227
240
|
assert.ok(harness.runtime.getModel("hypercharm", entry.id), entry.id + " must be served during its grace period");
|
|
228
241
|
}
|