pi-keyrouter 0.2.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/index.ts +65 -28
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ export default function keyRouterExtension(pi: ExtensionAPI): void {
|
|
|
47
47
|
let config: KeyRouterConfig | undefined;
|
|
48
48
|
const runtimes = new Map<string, ProviderRuntime>();
|
|
49
49
|
let notify: ((text: string, level: "info" | "warning" | "error") => void) | undefined;
|
|
50
|
+
let activationNotified = false;
|
|
50
51
|
|
|
51
52
|
function ensureRuntime(providerName: string, cfg: KeyRouterConfig): ProviderRuntime | undefined {
|
|
52
53
|
let rt = runtimes.get(providerName);
|
|
@@ -61,6 +62,50 @@ export default function keyRouterExtension(pi: ExtensionAPI): void {
|
|
|
61
62
|
return rt;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Activate the router: load config (once), bootstrap all providers.
|
|
67
|
+
* Idempotent — safe to call on every before_agent_start. Only runs
|
|
68
|
+
* the bootstrap the FIRST time for each provider.
|
|
69
|
+
*/
|
|
70
|
+
async function activate(ctx: {
|
|
71
|
+
cwd: string;
|
|
72
|
+
ui: { notify: (t: string, l?: "info" | "warning" | "error") => void };
|
|
73
|
+
modelRegistry: { authStorage: { setRuntimeApiKey: (p: string, k: string) => void } };
|
|
74
|
+
}): Promise<void> {
|
|
75
|
+
// Load config once (reload clears it)
|
|
76
|
+
if (!config) {
|
|
77
|
+
config = loadConfig(ctx.cwd);
|
|
78
|
+
}
|
|
79
|
+
if (config.providers.length === 0) return;
|
|
80
|
+
notify = (text, level) => ctx.ui.notify(text, level);
|
|
81
|
+
|
|
82
|
+
const authStorage = ctx.modelRegistry.authStorage;
|
|
83
|
+
let newlyBootstrapped = 0;
|
|
84
|
+
for (const p of config.providers) {
|
|
85
|
+
const providerName = resolveProviderName(p.name);
|
|
86
|
+
// Skip providers we've already bootstrapped
|
|
87
|
+
if (runtimes.has(providerName)) continue;
|
|
88
|
+
if (bootstrap(providerName)) {
|
|
89
|
+
const rt = runtimes.get(providerName);
|
|
90
|
+
if (rt && rt.currentIndex >= 0) {
|
|
91
|
+
const key = rt.keys[rt.currentIndex];
|
|
92
|
+
if (key) {
|
|
93
|
+
authStorage.setRuntimeApiKey(providerName, key.value);
|
|
94
|
+
newlyBootstrapped++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Only notify on first activation (when we bootstrapped at least one)
|
|
100
|
+
if (newlyBootstrapped > 0 && !activationNotified) {
|
|
101
|
+
activationNotified = true;
|
|
102
|
+
ctx.ui.notify(
|
|
103
|
+
`🔑 keyrouter: active (${config.providers.length} provider(s), ${config.providers.reduce((a, p) => a + p.keys.length, 0)} keys)`,
|
|
104
|
+
"info",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
64
109
|
/** Set the initial key for a provider on first use. */
|
|
65
110
|
function bootstrap(providerName: string): boolean {
|
|
66
111
|
const cfg = config;
|
|
@@ -129,34 +174,14 @@ export default function keyRouterExtension(pi: ExtensionAPI): void {
|
|
|
129
174
|
}
|
|
130
175
|
|
|
131
176
|
pi.on("session_start", async (_event, ctx) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return; // nothing to do
|
|
135
|
-
}
|
|
136
|
-
notify = (text, level) => ctx.ui.notify(text, level);
|
|
177
|
+
await activate(ctx);
|
|
178
|
+
});
|
|
137
179
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (bootstrap(providerName)) {
|
|
144
|
-
const rt = runtimes.get(providerName);
|
|
145
|
-
if (rt && rt.currentIndex >= 0) {
|
|
146
|
-
const key = rt.keys[rt.currentIndex];
|
|
147
|
-
if (key) {
|
|
148
|
-
authStorage.setRuntimeApiKey(providerName, key.value);
|
|
149
|
-
bootstrapped++;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (bootstrapped > 0) {
|
|
155
|
-
ctx.ui.notify(
|
|
156
|
-
`🔑 keyrouter: active (${bootstrapped} provider(s), ${config.providers.reduce((a, p) => a + p.keys.length, 0)} keys)`,
|
|
157
|
-
"info",
|
|
158
|
-
);
|
|
159
|
-
}
|
|
180
|
+
// Lazy bootstrap: also fire on every turn. This handles /reload (which
|
|
181
|
+
// does NOT re-fire session_start) and config changes mid-session.
|
|
182
|
+
// activate() is idempotent — only bootstraps once per provider.
|
|
183
|
+
pi.on("before_agent_start", async (_event, ctx) => {
|
|
184
|
+
await activate(ctx);
|
|
160
185
|
});
|
|
161
186
|
|
|
162
187
|
pi.on("after_provider_response", async (event, ctx) => {
|
|
@@ -196,6 +221,7 @@ export default function keyRouterExtension(pi: ExtensionAPI): void {
|
|
|
196
221
|
runtimes.clear();
|
|
197
222
|
config = undefined;
|
|
198
223
|
notify = undefined;
|
|
224
|
+
activationNotified = false;
|
|
199
225
|
});
|
|
200
226
|
|
|
201
227
|
pi.registerCommand("keyrouter", {
|
|
@@ -203,8 +229,18 @@ export default function keyRouterExtension(pi: ExtensionAPI): void {
|
|
|
203
229
|
handler: async (args, ctx) => {
|
|
204
230
|
const sub = args.trim().split(/\s+/)[0] ?? "status";
|
|
205
231
|
if (sub === "status") {
|
|
232
|
+
// On-demand activation in case session_start/before_agent_start
|
|
233
|
+
// haven't fired yet (e.g. user ran /keyrouter status right after
|
|
234
|
+
// /reload without sending a prompt).
|
|
235
|
+
if (!config || runtimes.size === 0) {
|
|
236
|
+
await activate(ctx);
|
|
237
|
+
}
|
|
206
238
|
if (!config || runtimes.size === 0) {
|
|
207
|
-
ctx.ui.notify(
|
|
239
|
+
ctx.ui.notify(
|
|
240
|
+
"🔑 keyrouter: not active — no providers in ~/.pi/keyrouter.json " +
|
|
241
|
+
"(checked cwd/.soly, cwd/.pi, cwd, ~/.soly, ~/.pi, ~)",
|
|
242
|
+
"warning",
|
|
243
|
+
);
|
|
208
244
|
return;
|
|
209
245
|
}
|
|
210
246
|
const lines: string[] = [`🔑 keyrouter: active`];
|
|
@@ -226,6 +262,7 @@ export default function keyRouterExtension(pi: ExtensionAPI): void {
|
|
|
226
262
|
if (sub === "reload") {
|
|
227
263
|
config = loadConfig(ctx.cwd);
|
|
228
264
|
runtimes.clear();
|
|
265
|
+
activationNotified = false;
|
|
229
266
|
ctx.ui.notify(
|
|
230
267
|
`🔑 keyrouter: reloaded (${config.providers.length} provider(s))`,
|
|
231
268
|
"info",
|
package/package.json
CHANGED