tokenfactory-pi 0.1.0 → 0.2.1
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/dist/index.d.ts +16 -0
- package/dist/index.js +117 -0
- package/package.json +12 -7
- package/tsconfig.json +18 -0
- package/.idea/inspectionProfiles/profiles_settings.xml +0 -5
- package/index.ts +0 -146
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nebius Token Factory — pi extension
|
|
3
|
+
*
|
|
4
|
+
* Fetches the current model catalog from the Token Factory API on startup
|
|
5
|
+
* and registers all tool-capable text-generation models as a "nebius" provider.
|
|
6
|
+
*
|
|
7
|
+
* Environment:
|
|
8
|
+
* NEBIUS_API_KEY — required, Token Factory API key
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* pi -e /path/to/tokenfactory-pi
|
|
12
|
+
* pi -e /path/to/tokenfactory-pi --provider nebius
|
|
13
|
+
* pi -e /path/to/tokenfactory-pi --provider nebius --model Qwen/Qwen3-32B
|
|
14
|
+
*/
|
|
15
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
16
|
+
export default function (pi: ExtensionAPI): Promise<void>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nebius Token Factory — pi extension
|
|
3
|
+
*
|
|
4
|
+
* Fetches the current model catalog from the Token Factory API on startup
|
|
5
|
+
* and registers all tool-capable text-generation models as a "nebius" provider.
|
|
6
|
+
*
|
|
7
|
+
* Environment:
|
|
8
|
+
* NEBIUS_API_KEY — required, Token Factory API key
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* pi -e /path/to/tokenfactory-pi
|
|
12
|
+
* pi -e /path/to/tokenfactory-pi --provider nebius
|
|
13
|
+
* pi -e /path/to/tokenfactory-pi --provider nebius --model Qwen/Qwen3-32B
|
|
14
|
+
*/
|
|
15
|
+
const PROVIDER_NAME = "nebius";
|
|
16
|
+
const BASE_URL = "https://api.tokenfactory.nebius.com/v1";
|
|
17
|
+
const ENV_VAR = "NEBIUS_API_KEY";
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Helpers
|
|
20
|
+
// ============================================================================
|
|
21
|
+
function isToolCapableTextModel(m) {
|
|
22
|
+
const features = m.supported_features || [];
|
|
23
|
+
const modality = m.architecture?.modality || "";
|
|
24
|
+
return features.includes("tools") && modality.includes("->text");
|
|
25
|
+
}
|
|
26
|
+
function parseInputModalities(modality) {
|
|
27
|
+
const input = ["text"];
|
|
28
|
+
if (modality.includes("image"))
|
|
29
|
+
input.push("image");
|
|
30
|
+
return input;
|
|
31
|
+
}
|
|
32
|
+
function parseCostPerMillion(raw) {
|
|
33
|
+
return parseFloat(raw || "0") * 1_000_000;
|
|
34
|
+
}
|
|
35
|
+
function isReasoningModel(id) {
|
|
36
|
+
return /(-R1|-Thinking|QwQ)/.test(id);
|
|
37
|
+
}
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Extension entry point
|
|
40
|
+
// ============================================================================
|
|
41
|
+
export default async function (pi) {
|
|
42
|
+
const apiKey = process.env[ENV_VAR];
|
|
43
|
+
if (!apiKey) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(`${BASE_URL}/models?verbose=true`, {
|
|
49
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
console.warn(`[${PROVIDER_NAME}] API returned ${res.status}: ${res.statusText}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
response = (await res.json());
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.warn(`[${PROVIDER_NAME}] Failed to fetch models:`, error);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!Array.isArray(response.data)) {
|
|
62
|
+
console.warn(`[${PROVIDER_NAME}] Unexpected API response shape`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const models = [];
|
|
66
|
+
for (const m of response.data) {
|
|
67
|
+
if (!isToolCapableTextModel(m))
|
|
68
|
+
continue;
|
|
69
|
+
const modality = m.architecture?.modality || "";
|
|
70
|
+
models.push({
|
|
71
|
+
id: m.id,
|
|
72
|
+
name: m.name || m.id,
|
|
73
|
+
reasoning: isReasoningModel(m.id),
|
|
74
|
+
input: parseInputModalities(modality),
|
|
75
|
+
cost: {
|
|
76
|
+
input: parseCostPerMillion(m.pricing?.prompt),
|
|
77
|
+
output: parseCostPerMillion(m.pricing?.completion),
|
|
78
|
+
cacheRead: 0,
|
|
79
|
+
cacheWrite: 0,
|
|
80
|
+
},
|
|
81
|
+
contextWindow: m.context_length || 131072,
|
|
82
|
+
maxTokens: Math.min(m.context_length || 32768, 32768),
|
|
83
|
+
compat: {
|
|
84
|
+
supportsDeveloperRole: false,
|
|
85
|
+
maxTokensField: "max_tokens",
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
pi.registerProvider(PROVIDER_NAME, {
|
|
90
|
+
baseUrl: BASE_URL,
|
|
91
|
+
apiKey: ENV_VAR,
|
|
92
|
+
api: "openai-completions",
|
|
93
|
+
models,
|
|
94
|
+
});
|
|
95
|
+
// /nebius-models command to list and select a model
|
|
96
|
+
pi.registerCommand("nebius-models", {
|
|
97
|
+
description: "List available Nebius Token Factory models",
|
|
98
|
+
handler: async (_args, ctx) => {
|
|
99
|
+
if (models.length === 0) {
|
|
100
|
+
ctx.ui.notify("No Nebius models available", "warning");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const items = models
|
|
104
|
+
.sort((a, b) => a.id.localeCompare(b.id))
|
|
105
|
+
.map((m) => {
|
|
106
|
+
const tags = [];
|
|
107
|
+
if (m.reasoning)
|
|
108
|
+
tags.push("reasoning");
|
|
109
|
+
if (m.input.includes("image"))
|
|
110
|
+
tags.push("vision");
|
|
111
|
+
const suffix = tags.length > 0 ? ` (${tags.join(", ")})` : "";
|
|
112
|
+
return `${m.id}${suffix}`;
|
|
113
|
+
});
|
|
114
|
+
await ctx.ui.select(`Nebius Token Factory — ${models.length} models`, items);
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokenfactory-pi",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Nebius Token Factory provider extension for pi coding agent",
|
|
5
|
-
"main": "index.
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"license": "MIT",
|
|
8
9
|
"repository": {
|
|
@@ -20,15 +21,19 @@
|
|
|
20
21
|
],
|
|
21
22
|
"pi": {
|
|
22
23
|
"extensions": [
|
|
23
|
-
"./index.
|
|
24
|
+
"./dist/index.js"
|
|
24
25
|
]
|
|
25
26
|
},
|
|
26
27
|
"peerDependencies": {
|
|
27
28
|
"@mariozechner/pi-coding-agent": "*"
|
|
28
29
|
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.0.0",
|
|
32
|
+
"typescript": "^5.9.3"
|
|
33
|
+
},
|
|
29
34
|
"scripts": {
|
|
30
|
-
"clean": "
|
|
31
|
-
"build": "
|
|
32
|
-
"check": "
|
|
35
|
+
"clean": "rm -rf dist",
|
|
36
|
+
"build": "tsc",
|
|
37
|
+
"check": "tsc --noEmit"
|
|
33
38
|
}
|
|
34
|
-
}
|
|
39
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["*.ts"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
package/index.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nebius Token Factory — pi extension
|
|
3
|
-
*
|
|
4
|
-
* Fetches the current model catalog from the Token Factory API on startup
|
|
5
|
-
* and registers all tool-capable text-generation models as a "nebius" provider.
|
|
6
|
-
*
|
|
7
|
-
* Environment:
|
|
8
|
-
* NEBIUS_API_KEY — required, Token Factory API key
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* pi -e /path/to/tokenfactory-pi
|
|
12
|
-
* pi -e /path/to/tokenfactory-pi --provider nebius
|
|
13
|
-
* pi -e /path/to/tokenfactory-pi --provider nebius --model Qwen/Qwen3-32B
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
17
|
-
|
|
18
|
-
const PROVIDER_NAME = "nebius";
|
|
19
|
-
const BASE_URL = "https://api.tokenfactory.nebius.com/v1";
|
|
20
|
-
const ENV_VAR = "NEBIUS_API_KEY";
|
|
21
|
-
|
|
22
|
-
// ============================================================================
|
|
23
|
-
// Token Factory API types
|
|
24
|
-
// ============================================================================
|
|
25
|
-
|
|
26
|
-
interface TokenFactoryModel {
|
|
27
|
-
id: string;
|
|
28
|
-
name?: string;
|
|
29
|
-
context_length?: number;
|
|
30
|
-
supported_features?: string[];
|
|
31
|
-
architecture?: { modality?: string };
|
|
32
|
-
pricing?: { prompt?: string; completion?: string };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface TokenFactoryResponse {
|
|
36
|
-
data: TokenFactoryModel[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ============================================================================
|
|
40
|
-
// Helpers
|
|
41
|
-
// ============================================================================
|
|
42
|
-
|
|
43
|
-
function isToolCapableTextModel(m: TokenFactoryModel): boolean {
|
|
44
|
-
const features = m.supported_features || [];
|
|
45
|
-
const modality = m.architecture?.modality || "";
|
|
46
|
-
return features.includes("tools") && modality.includes("->text");
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function parseInputModalities(modality: string): ("text" | "image")[] {
|
|
50
|
-
const input: ("text" | "image")[] = ["text"];
|
|
51
|
-
if (modality.includes("image")) input.push("image");
|
|
52
|
-
return input;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function parseCostPerMillion(raw: string | undefined): number {
|
|
56
|
-
return parseFloat(raw || "0") * 1_000_000;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function isReasoningModel(id: string): boolean {
|
|
60
|
-
return /(-R1|-Thinking|QwQ)/.test(id);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ============================================================================
|
|
64
|
-
// Extension entry point
|
|
65
|
-
// ============================================================================
|
|
66
|
-
|
|
67
|
-
export default async function (pi: ExtensionAPI) {
|
|
68
|
-
const apiKey = process.env[ENV_VAR];
|
|
69
|
-
if (!apiKey) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
let response: TokenFactoryResponse;
|
|
74
|
-
try {
|
|
75
|
-
const res = await fetch(`${BASE_URL}/models?verbose=true`, {
|
|
76
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
77
|
-
});
|
|
78
|
-
if (!res.ok) {
|
|
79
|
-
console.warn(`[${PROVIDER_NAME}] API returned ${res.status}: ${res.statusText}`);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
response = (await res.json()) as TokenFactoryResponse;
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.warn(`[${PROVIDER_NAME}] Failed to fetch models:`, error);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (!Array.isArray(response.data)) {
|
|
89
|
-
console.warn(`[${PROVIDER_NAME}] Unexpected API response shape`);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const models = [];
|
|
94
|
-
for (const m of response.data) {
|
|
95
|
-
if (!isToolCapableTextModel(m)) continue;
|
|
96
|
-
|
|
97
|
-
const modality = m.architecture?.modality || "";
|
|
98
|
-
|
|
99
|
-
models.push({
|
|
100
|
-
id: m.id,
|
|
101
|
-
name: m.name || m.id,
|
|
102
|
-
reasoning: isReasoningModel(m.id),
|
|
103
|
-
input: parseInputModalities(modality),
|
|
104
|
-
cost: {
|
|
105
|
-
input: parseCostPerMillion(m.pricing?.prompt),
|
|
106
|
-
output: parseCostPerMillion(m.pricing?.completion),
|
|
107
|
-
cacheRead: 0,
|
|
108
|
-
cacheWrite: 0,
|
|
109
|
-
},
|
|
110
|
-
contextWindow: m.context_length || 131072,
|
|
111
|
-
maxTokens: Math.min(m.context_length || 32768, 32768),
|
|
112
|
-
compat: {
|
|
113
|
-
supportsDeveloperRole: false,
|
|
114
|
-
maxTokensField: "max_tokens" as const,
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
pi.registerProvider(PROVIDER_NAME, {
|
|
120
|
-
baseUrl: BASE_URL,
|
|
121
|
-
apiKey: ENV_VAR,
|
|
122
|
-
api: "openai-completions",
|
|
123
|
-
models,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// /nebius-models command to list and select a model
|
|
127
|
-
pi.registerCommand("nebius-models", {
|
|
128
|
-
description: "List available Nebius Token Factory models",
|
|
129
|
-
handler: async (_args, ctx) => {
|
|
130
|
-
if (models.length === 0) {
|
|
131
|
-
ctx.ui.notify("No Nebius models available", "warning");
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const items = models
|
|
135
|
-
.sort((a, b) => a.id.localeCompare(b.id))
|
|
136
|
-
.map((m) => {
|
|
137
|
-
const tags = [];
|
|
138
|
-
if (m.reasoning) tags.push("reasoning");
|
|
139
|
-
if (m.input.includes("image")) tags.push("vision");
|
|
140
|
-
const suffix = tags.length > 0 ? ` (${tags.join(", ")})` : "";
|
|
141
|
-
return `${m.id}${suffix}`;
|
|
142
|
-
});
|
|
143
|
-
await ctx.ui.select(`Nebius Token Factory — ${models.length} models`, items);
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
}
|