@pentect/pi 0.0.29 → 0.0.30
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 +5 -0
- package/extensions/pentect.js +61 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,5 +19,10 @@ Set `PENTECT_PI_MODEL` before Pi starts to expose a different model. Set
|
|
|
19
19
|
`PENTECT_PI_API=responses` for the OpenAI Responses API. `OPENAI_BASE_URL` and
|
|
20
20
|
`OPENAI_API_KEY` configure the upstream.
|
|
21
21
|
|
|
22
|
+
For a custom upstream whose model limits differ from the defaults, set
|
|
23
|
+
`PENTECT_PI_CONTEXT_WINDOW`, `PENTECT_PI_MAX_TOKENS`,
|
|
24
|
+
`PENTECT_PI_INPUTS=text`, or `PENTECT_PI_REASONING=true|false`. Invalid values
|
|
25
|
+
stop startup instead of advertising incorrect capabilities to Pi.
|
|
26
|
+
|
|
22
27
|
The JavaScript extension only manages Pi's provider lifecycle. Detection,
|
|
23
28
|
handles, plugins, and network forwarding remain inside the Pentect binary.
|
package/extensions/pentect.js
CHANGED
|
@@ -6,6 +6,8 @@ const require = createRequire(import.meta.url);
|
|
|
6
6
|
const STATE = Symbol.for("@pentect/pi/provider-state");
|
|
7
7
|
const MAX_READY_BYTES = 16 * 1024;
|
|
8
8
|
const START_TIMEOUT_MS = 10_000;
|
|
9
|
+
const DEFAULT_CONTEXT_WINDOW = 128_000;
|
|
10
|
+
const DEFAULT_MAX_TOKENS = 32_768;
|
|
9
11
|
|
|
10
12
|
function sharedState() {
|
|
11
13
|
if (!globalThis[STATE]) {
|
|
@@ -43,7 +45,34 @@ export function parseReady(line) {
|
|
|
43
45
|
return ready;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
function positiveInteger(env, name, fallback) {
|
|
49
|
+
const raw = env[name]?.trim();
|
|
50
|
+
if (!raw) return fallback;
|
|
51
|
+
const value = Number(raw);
|
|
52
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
53
|
+
throw new Error(`${name} must be a positive integer`);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function reasoningSupport(env, api) {
|
|
59
|
+
const value = env.PENTECT_PI_REASONING?.trim().toLowerCase();
|
|
60
|
+
if (!value || value === "auto") return api === "openai-responses";
|
|
61
|
+
if (value === "true") return true;
|
|
62
|
+
if (value === "false") return false;
|
|
63
|
+
throw new Error("PENTECT_PI_REASONING must be auto, true, or false");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function inputSupport(env) {
|
|
67
|
+
const value = env.PENTECT_PI_INPUTS?.trim().toLowerCase();
|
|
68
|
+
if (!value || value === "text,image" || value === "image,text") {
|
|
69
|
+
return ["text", "image"];
|
|
70
|
+
}
|
|
71
|
+
if (value === "text") return ["text"];
|
|
72
|
+
throw new Error("PENTECT_PI_INPUTS must be text or text,image");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function providerDefinition(ready, env = process.env) {
|
|
47
76
|
return {
|
|
48
77
|
name: "Pentect",
|
|
49
78
|
baseUrl: ready.baseUrl,
|
|
@@ -54,11 +83,19 @@ export function providerDefinition(ready) {
|
|
|
54
83
|
{
|
|
55
84
|
id: ready.model,
|
|
56
85
|
name: ready.model,
|
|
57
|
-
reasoning: ready.api
|
|
58
|
-
input:
|
|
86
|
+
reasoning: reasoningSupport(env, ready.api),
|
|
87
|
+
input: inputSupport(env),
|
|
59
88
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
60
|
-
contextWindow:
|
|
61
|
-
|
|
89
|
+
contextWindow: positiveInteger(
|
|
90
|
+
env,
|
|
91
|
+
"PENTECT_PI_CONTEXT_WINDOW",
|
|
92
|
+
DEFAULT_CONTEXT_WINDOW,
|
|
93
|
+
),
|
|
94
|
+
maxTokens: positiveInteger(
|
|
95
|
+
env,
|
|
96
|
+
"PENTECT_PI_MAX_TOKENS",
|
|
97
|
+
DEFAULT_MAX_TOKENS,
|
|
98
|
+
),
|
|
62
99
|
},
|
|
63
100
|
],
|
|
64
101
|
};
|
|
@@ -101,11 +138,22 @@ async function startProvider() {
|
|
|
101
138
|
return { child, ready: parseReady(line) };
|
|
102
139
|
} catch (error) {
|
|
103
140
|
child.kill();
|
|
141
|
+
restoreProviderCredentials(state, process.env);
|
|
104
142
|
const detail = errors.trim();
|
|
105
143
|
throw new Error(detail || error.message, { cause: error });
|
|
106
144
|
}
|
|
107
145
|
}
|
|
108
146
|
|
|
147
|
+
export function restoreProviderCredentials(state, env) {
|
|
148
|
+
if (state.openaiApiKey === undefined) delete env.OPENAI_API_KEY;
|
|
149
|
+
else env.OPENAI_API_KEY = state.openaiApiKey;
|
|
150
|
+
if (state.upstreamAuthorization === undefined) {
|
|
151
|
+
delete env.PENTECT_UPSTREAM_AUTHORIZATION;
|
|
152
|
+
} else {
|
|
153
|
+
env.PENTECT_UPSTREAM_AUTHORIZATION = state.upstreamAuthorization;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
109
157
|
function firstLine(child) {
|
|
110
158
|
return new Promise((resolveLine, reject) => {
|
|
111
159
|
let output = "";
|
|
@@ -149,7 +197,14 @@ function stopProvider(child) {
|
|
|
149
197
|
}
|
|
150
198
|
|
|
151
199
|
export default async function pentect(pi) {
|
|
200
|
+
const state = sharedState();
|
|
152
201
|
const { child, ready } = await startProvider();
|
|
153
|
-
|
|
202
|
+
try {
|
|
203
|
+
pi.registerProvider("pentect", providerDefinition(ready));
|
|
204
|
+
} catch (error) {
|
|
205
|
+
stopProvider(child);
|
|
206
|
+
restoreProviderCredentials(state, process.env);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
154
209
|
pi.on("session_shutdown", () => stopProvider(child));
|
|
155
210
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pentect/pi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.30",
|
|
4
4
|
"description": "Pentect provider extension for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"pentect": "0.0.
|
|
37
|
+
"pentect": "0.0.30"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=20.6.0"
|