copilot-hub 0.1.19 → 0.1.21
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 +3 -2
- package/apps/agent-engine/dist/config.js +58 -0
- package/apps/agent-engine/dist/index.js +90 -16
- package/apps/control-plane/dist/channels/codex-quota-cache.js +16 -0
- package/apps/control-plane/dist/channels/hub-model-utils.js +244 -24
- package/apps/control-plane/dist/channels/hub-ops-commands.js +631 -279
- package/apps/control-plane/dist/channels/telegram-channel.js +5 -7
- package/apps/control-plane/dist/config.js +58 -0
- package/apps/control-plane/dist/index.js +16 -0
- package/apps/control-plane/dist/test/hub-model-utils.test.js +110 -13
- package/package.json +3 -2
- package/packages/core/dist/agent-supervisor.d.ts +5 -0
- package/packages/core/dist/agent-supervisor.js +11 -0
- package/packages/core/dist/agent-supervisor.js.map +1 -1
- package/packages/core/dist/bot-manager.js +17 -1
- package/packages/core/dist/bot-manager.js.map +1 -1
- package/packages/core/dist/bot-runtime.d.ts +4 -0
- package/packages/core/dist/bot-runtime.js +5 -1
- package/packages/core/dist/bot-runtime.js.map +1 -1
- package/packages/core/dist/codex-app-client.d.ts +13 -2
- package/packages/core/dist/codex-app-client.js +51 -13
- package/packages/core/dist/codex-app-client.js.map +1 -1
- package/packages/core/dist/codex-app-utils.d.ts +6 -0
- package/packages/core/dist/codex-app-utils.js +49 -0
- package/packages/core/dist/codex-app-utils.js.map +1 -1
- package/packages/core/dist/codex-provider.d.ts +3 -1
- package/packages/core/dist/codex-provider.js +3 -1
- package/packages/core/dist/codex-provider.js.map +1 -1
- package/packages/core/dist/kernel-control-plane.d.ts +1 -0
- package/packages/core/dist/kernel-control-plane.js +132 -13
- package/packages/core/dist/kernel-control-plane.js.map +1 -1
- package/packages/core/dist/provider-factory.d.ts +2 -0
- package/packages/core/dist/provider-factory.js +3 -0
- package/packages/core/dist/provider-factory.js.map +1 -1
- package/packages/core/dist/provider-options.js +24 -17
- package/packages/core/dist/provider-options.js.map +1 -1
- package/packages/core/dist/state-store.d.ts +1 -0
- package/packages/core/dist/state-store.js +28 -2
- package/packages/core/dist/state-store.js.map +1 -1
- package/packages/core/dist/telegram-channel.d.ts +1 -0
- package/packages/core/dist/telegram-channel.js +3 -0
- package/packages/core/dist/telegram-channel.js.map +1 -1
- package/scripts/dist/cli.mjs +132 -203
- package/scripts/dist/codex-runtime.mjs +352 -0
- package/scripts/dist/codex-version.mjs +91 -0
- package/scripts/dist/configure.mjs +26 -49
- package/scripts/dist/daemon.mjs +58 -0
- package/scripts/src/cli.mts +166 -233
- package/scripts/src/codex-runtime.mts +499 -0
- package/scripts/src/codex-version.mts +114 -0
- package/scripts/src/configure.mts +30 -65
- package/scripts/src/daemon.mts +69 -0
- package/scripts/test/codex-version.test.mjs +21 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { invalidateCodexQuotaUsageCache } from "./codex-quota-cache.js";
|
|
3
|
+
import { applyBotProviderPolicy, applyProviderPolicyToBots, applyRuntimeProviderPolicy, buildReasoningOptionsForModel, buildSessionModelOptions, fetchCodexModelOptions, formatFastModeLabel, formatModelButtonText, formatModelLabel, formatReasoningLabel, getBotPolicyState, getBotProviderSelection, getRuntimeProviderSelection, parseSetModelAllCommand, parseSetModelCommand, resolveModelSelectionFromAction, resolveReasoningSelectionFromAction, resolveSharedModel, resolveSharedReasoningEffort, resolveSharedServiceTier, } from "./hub-model-utils.js";
|
|
3
4
|
const MENU_TTL_MS = 15 * 60 * 1000;
|
|
4
5
|
const FLOW_TTL_MS = 10 * 60 * 1000;
|
|
5
6
|
const TELEGRAM_VERIFY_TIMEOUT_MS = 10_000;
|
|
@@ -179,14 +180,15 @@ export async function maybeHandleHubOpsCommand({ ctx, runtime, channelId, }) {
|
|
|
179
180
|
.split(/\s+/)
|
|
180
181
|
.filter(Boolean).length;
|
|
181
182
|
if (tokenCount <= 1) {
|
|
182
|
-
await
|
|
183
|
+
await renderGlobalModelMenu(ctx, { editMessage: false, runtime: runtime ?? null });
|
|
183
184
|
return true;
|
|
184
185
|
}
|
|
185
186
|
const parsed = parseSetModelCommand(text, BOT_ID_PATTERN);
|
|
186
187
|
if (!parsed.ok) {
|
|
187
|
-
await
|
|
188
|
+
await renderGlobalModelMenu(ctx, {
|
|
188
189
|
editMessage: false,
|
|
189
|
-
|
|
190
|
+
runtime: runtime ?? null,
|
|
191
|
+
notice: "Choose a model first, then the target.",
|
|
190
192
|
});
|
|
191
193
|
return true;
|
|
192
194
|
}
|
|
@@ -195,15 +197,19 @@ export async function maybeHandleHubOpsCommand({ ctx, runtime, channelId, }) {
|
|
|
195
197
|
await ctx.reply(`Agent '${parsed.botId}' not found.`);
|
|
196
198
|
return true;
|
|
197
199
|
}
|
|
198
|
-
await
|
|
200
|
+
await applyBotProviderPolicy({
|
|
199
201
|
apiPost,
|
|
200
202
|
botId: parsed.botId,
|
|
201
203
|
botState,
|
|
202
|
-
|
|
204
|
+
patch: {
|
|
205
|
+
model: parsed.model,
|
|
206
|
+
reasoningEffort: null,
|
|
207
|
+
},
|
|
203
208
|
});
|
|
204
209
|
const modelLabel = parsed.model ? parsed.model : "auto (workspace default)";
|
|
205
210
|
await ctx.reply([
|
|
206
211
|
`Model updated for '${parsed.botId}': ${modelLabel}`,
|
|
212
|
+
"Reasoning reset to the model default.",
|
|
207
213
|
"Change applies on next message while preserving conversation history.",
|
|
208
214
|
].join("\n"));
|
|
209
215
|
return true;
|
|
@@ -223,9 +229,12 @@ export async function maybeHandleHubOpsCommand({ ctx, runtime, channelId, }) {
|
|
|
223
229
|
return true;
|
|
224
230
|
}
|
|
225
231
|
const bots = await fetchBots();
|
|
226
|
-
const result = await
|
|
232
|
+
const result = await applyGlobalProviderSelection({
|
|
227
233
|
bots,
|
|
228
|
-
|
|
234
|
+
patch: {
|
|
235
|
+
model: parsed.model,
|
|
236
|
+
reasoningEffort: null,
|
|
237
|
+
},
|
|
229
238
|
runtime: runtime ?? null,
|
|
230
239
|
});
|
|
231
240
|
if (result.totalTargets === 0) {
|
|
@@ -233,7 +242,11 @@ export async function maybeHandleHubOpsCommand({ ctx, runtime, channelId, }) {
|
|
|
233
242
|
return true;
|
|
234
243
|
}
|
|
235
244
|
const modelLabel = parsed.model ? parsed.model : "auto (workspace default)";
|
|
236
|
-
const lines = buildGlobalModelUpdateLines({
|
|
245
|
+
const lines = buildGlobalModelUpdateLines({
|
|
246
|
+
modelLabel,
|
|
247
|
+
reasoningLabel: "Default",
|
|
248
|
+
result,
|
|
249
|
+
});
|
|
237
250
|
lines.push("Change applies on next message while preserving conversation history.");
|
|
238
251
|
await ctx.reply(lines.join("\n"));
|
|
239
252
|
return true;
|
|
@@ -272,7 +285,13 @@ export async function maybeHandleHubOpsFollowUp({ ctx, runtime, channelId, }) {
|
|
|
272
285
|
const flowKey = buildFlowKey(runtime?.runtimeId, channelId, chatId);
|
|
273
286
|
const codexFlow = codexSwitchFlows.get(flowKey);
|
|
274
287
|
if (codexFlow) {
|
|
275
|
-
const handled = await handleCodexSwitchFlow({
|
|
288
|
+
const handled = await handleCodexSwitchFlow({
|
|
289
|
+
ctx,
|
|
290
|
+
flowKey,
|
|
291
|
+
flow: codexFlow,
|
|
292
|
+
text,
|
|
293
|
+
runtime: runtime ?? null,
|
|
294
|
+
});
|
|
276
295
|
if (handled) {
|
|
277
296
|
return true;
|
|
278
297
|
}
|
|
@@ -362,7 +381,7 @@ export async function maybeHandleHubOpsFollowUp({ ctx, runtime, channelId, }) {
|
|
|
362
381
|
await ctx.reply("Flow reset. Use /create_agent to start again.");
|
|
363
382
|
return true;
|
|
364
383
|
}
|
|
365
|
-
async function handleCodexSwitchFlow({ ctx, flowKey, flow, text, }) {
|
|
384
|
+
async function handleCodexSwitchFlow({ ctx, flowKey, flow, text, runtime, }) {
|
|
366
385
|
if (flow.step !== "api_key") {
|
|
367
386
|
codexSwitchFlows.delete(flowKey);
|
|
368
387
|
await ctx.reply("Flow reset. Use /codex_switch_key to start again.");
|
|
@@ -379,9 +398,10 @@ async function handleCodexSwitchFlow({ ctx, flowKey, flow, text, }) {
|
|
|
379
398
|
apiKey,
|
|
380
399
|
});
|
|
381
400
|
codexSwitchFlows.delete(flowKey);
|
|
401
|
+
const refreshMessage = await refreshHubProviderAfterCodexLogin(runtime);
|
|
382
402
|
const refreshedBots = readRefreshedBotIds(result);
|
|
383
403
|
const refreshFailures = readRefreshFailures(result);
|
|
384
|
-
const lines = ["Codex account switched successfully."];
|
|
404
|
+
const lines = ["Codex account switched successfully.", refreshMessage];
|
|
385
405
|
if (result?.detail) {
|
|
386
406
|
lines.push(`status: ${String(result.detail)}`);
|
|
387
407
|
}
|
|
@@ -424,24 +444,25 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
424
444
|
await answerCallbackQuerySafe(ctx, "Updated");
|
|
425
445
|
return true;
|
|
426
446
|
}
|
|
427
|
-
if (action.type === "
|
|
428
|
-
await
|
|
447
|
+
if (action.type === "agents_home") {
|
|
448
|
+
await renderAgentsMenu(ctx, {
|
|
429
449
|
sessionId: action.sessionId,
|
|
430
450
|
editMessage: true,
|
|
431
451
|
});
|
|
432
452
|
await answerCallbackQuerySafe(ctx);
|
|
433
453
|
return true;
|
|
434
454
|
}
|
|
435
|
-
if (action.type === "
|
|
436
|
-
await
|
|
455
|
+
if (action.type === "global_model_open") {
|
|
456
|
+
await renderGlobalModelMenu(ctx, {
|
|
437
457
|
sessionId: action.sessionId,
|
|
438
|
-
|
|
458
|
+
editMessage: true,
|
|
459
|
+
runtime: runtime ?? null,
|
|
439
460
|
});
|
|
440
461
|
await answerCallbackQuerySafe(ctx);
|
|
441
462
|
return true;
|
|
442
463
|
}
|
|
443
|
-
if (action.type === "
|
|
444
|
-
await
|
|
464
|
+
if (action.type === "global_fast_open") {
|
|
465
|
+
await renderGlobalFastMenu(ctx, {
|
|
445
466
|
sessionId: action.sessionId,
|
|
446
467
|
editMessage: true,
|
|
447
468
|
runtime: runtime ?? null,
|
|
@@ -449,6 +470,56 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
449
470
|
await answerCallbackQuerySafe(ctx);
|
|
450
471
|
return true;
|
|
451
472
|
}
|
|
473
|
+
if (action.type === "target_choice") {
|
|
474
|
+
const session = getMenuSession(action.sessionId, ctx);
|
|
475
|
+
if (!session || !session.pendingProviderPatch || !session.pendingFlow) {
|
|
476
|
+
await renderBotsMenu(ctx, {
|
|
477
|
+
editMessage: true,
|
|
478
|
+
notice: "Selection expired. Open the menu again.",
|
|
479
|
+
});
|
|
480
|
+
await answerCallbackQuerySafe(ctx, "Selection expired");
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
if (action.profileId === "single") {
|
|
484
|
+
await renderProviderTargetAgentMenu(ctx, {
|
|
485
|
+
sessionId: action.sessionId,
|
|
486
|
+
editMessage: true,
|
|
487
|
+
});
|
|
488
|
+
await answerCallbackQuerySafe(ctx);
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
if (action.profileId === "all" || action.profileId === "all_hub") {
|
|
492
|
+
const bots = await fetchBots();
|
|
493
|
+
const result = await applyGlobalProviderSelection({
|
|
494
|
+
bots,
|
|
495
|
+
patch: session.pendingProviderPatch,
|
|
496
|
+
runtime: action.profileId === "all_hub" ? (runtime ?? null) : null,
|
|
497
|
+
});
|
|
498
|
+
const lines = session.pendingFlow === "speed"
|
|
499
|
+
? buildGlobalFastUpdateLines({
|
|
500
|
+
fastLabel: session.pendingSummary.speedLabel ?? "Standard",
|
|
501
|
+
result,
|
|
502
|
+
})
|
|
503
|
+
: buildGlobalModelUpdateLines({
|
|
504
|
+
modelLabel: session.pendingSummary.modelLabel ?? "auto (workspace default)",
|
|
505
|
+
reasoningLabel: session.pendingSummary.reasoningLabel ?? "Default",
|
|
506
|
+
result,
|
|
507
|
+
});
|
|
508
|
+
lines.push(session.pendingFlow === "speed"
|
|
509
|
+
? "Speed changes apply on next message."
|
|
510
|
+
: "Change applies on next message while preserving conversation history.");
|
|
511
|
+
clearPendingProviderSelection(session);
|
|
512
|
+
menuSessions.set(action.sessionId, session);
|
|
513
|
+
await renderBotsMenu(ctx, {
|
|
514
|
+
editMessage: true,
|
|
515
|
+
notice: lines.join("\n"),
|
|
516
|
+
});
|
|
517
|
+
await answerCallbackQuerySafe(ctx, "Updated");
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
await answerCallbackQuerySafe(ctx, "Invalid target");
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
452
523
|
if (action.type === "back") {
|
|
453
524
|
await renderBotsMenu(ctx, { editMessage: true });
|
|
454
525
|
await answerCallbackQuerySafe(ctx);
|
|
@@ -470,39 +541,103 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
470
541
|
sessionId: action.sessionId,
|
|
471
542
|
editMessage: true,
|
|
472
543
|
runtime: runtime ?? null,
|
|
473
|
-
notice: "Model
|
|
544
|
+
notice: "Model menu expired. Open Model & Reasoning again.",
|
|
474
545
|
});
|
|
475
546
|
await answerCallbackQuerySafe(ctx, "Model menu expired");
|
|
476
547
|
return true;
|
|
477
548
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
549
|
+
if (selection.model) {
|
|
550
|
+
await renderGlobalReasoningMenu(ctx, {
|
|
551
|
+
sessionId: action.sessionId,
|
|
552
|
+
runtime: runtime ?? null,
|
|
553
|
+
modelSelection: selection,
|
|
554
|
+
});
|
|
555
|
+
await answerCallbackQuerySafe(ctx);
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
setPendingProviderSelection(session, {
|
|
559
|
+
patch: {
|
|
560
|
+
model: null,
|
|
561
|
+
reasoningEffort: null,
|
|
562
|
+
},
|
|
563
|
+
flow: "model_reasoning",
|
|
564
|
+
modelLabel: selection.label,
|
|
565
|
+
reasoningLabel: "Default",
|
|
566
|
+
});
|
|
567
|
+
menuSessions.set(action.sessionId, session);
|
|
568
|
+
await renderProviderTargetMenu(ctx, {
|
|
569
|
+
sessionId: action.sessionId,
|
|
570
|
+
editMessage: true,
|
|
482
571
|
runtime: runtime ?? null,
|
|
483
572
|
});
|
|
484
|
-
|
|
573
|
+
await answerCallbackQuerySafe(ctx);
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
if (action.type === "global_reasoning_apply") {
|
|
577
|
+
const modelSelection = resolveModelSelectionFromAction({
|
|
578
|
+
session,
|
|
579
|
+
profileId: action.modelProfileId,
|
|
580
|
+
});
|
|
581
|
+
if (!modelSelection.ok || !modelSelection.model) {
|
|
485
582
|
await renderGlobalModelMenu(ctx, {
|
|
486
583
|
sessionId: action.sessionId,
|
|
487
584
|
editMessage: true,
|
|
488
585
|
runtime: runtime ?? null,
|
|
489
|
-
notice: "
|
|
586
|
+
notice: "Model menu expired. Open Model & Reasoning again.",
|
|
490
587
|
});
|
|
491
|
-
await answerCallbackQuerySafe(ctx, "
|
|
588
|
+
await answerCallbackQuerySafe(ctx, "Model menu expired");
|
|
492
589
|
return true;
|
|
493
590
|
}
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
result,
|
|
591
|
+
const reasoningOptions = buildReasoningOptionsForModel({
|
|
592
|
+
modelSelection,
|
|
497
593
|
});
|
|
498
|
-
|
|
499
|
-
|
|
594
|
+
const reasoningSelection = resolveReasoningSelectionFromAction({
|
|
595
|
+
options: reasoningOptions,
|
|
596
|
+
profileId: action.profileId,
|
|
597
|
+
});
|
|
598
|
+
if (!reasoningSelection.ok) {
|
|
599
|
+
await renderGlobalReasoningMenu(ctx, {
|
|
600
|
+
sessionId: action.sessionId,
|
|
601
|
+
runtime: runtime ?? null,
|
|
602
|
+
modelSelection,
|
|
603
|
+
notice: "Reasoning options expired. Choose the model again.",
|
|
604
|
+
});
|
|
605
|
+
await answerCallbackQuerySafe(ctx, "Reasoning menu expired");
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
setPendingProviderSelection(session, {
|
|
609
|
+
patch: {
|
|
610
|
+
model: modelSelection.model,
|
|
611
|
+
reasoningEffort: reasoningSelection.reasoningEffort,
|
|
612
|
+
},
|
|
613
|
+
flow: "model_reasoning",
|
|
614
|
+
modelLabel: modelSelection.label,
|
|
615
|
+
reasoningLabel: reasoningSelection.label,
|
|
616
|
+
});
|
|
617
|
+
menuSessions.set(action.sessionId, session);
|
|
618
|
+
await renderProviderTargetMenu(ctx, {
|
|
619
|
+
sessionId: action.sessionId,
|
|
620
|
+
editMessage: true,
|
|
621
|
+
runtime: runtime ?? null,
|
|
622
|
+
});
|
|
623
|
+
await answerCallbackQuerySafe(ctx);
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
if (action.type === "global_fast_apply") {
|
|
627
|
+
setPendingProviderSelection(session, {
|
|
628
|
+
patch: {
|
|
629
|
+
serviceTier: action.profileId === "fast" ? "fast" : null,
|
|
630
|
+
},
|
|
631
|
+
flow: "speed",
|
|
632
|
+
speedLabel: action.profileId === "fast" ? "Fast" : "Standard",
|
|
633
|
+
});
|
|
634
|
+
menuSessions.set(action.sessionId, session);
|
|
635
|
+
await renderProviderTargetMenu(ctx, {
|
|
500
636
|
sessionId: action.sessionId,
|
|
501
637
|
editMessage: true,
|
|
502
638
|
runtime: runtime ?? null,
|
|
503
|
-
notice: lines.join("\n"),
|
|
504
639
|
});
|
|
505
|
-
await answerCallbackQuerySafe(ctx
|
|
640
|
+
await answerCallbackQuerySafe(ctx);
|
|
506
641
|
return true;
|
|
507
642
|
}
|
|
508
643
|
const botId = getBotIdFromSession(session, action.index);
|
|
@@ -511,6 +646,43 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
511
646
|
await answerCallbackQuerySafe(ctx, "Agent not found. Refreshed.");
|
|
512
647
|
return true;
|
|
513
648
|
}
|
|
649
|
+
if (action.type === "target_agent_apply") {
|
|
650
|
+
if (!session.pendingProviderPatch || !session.pendingFlow) {
|
|
651
|
+
await renderBotsMenu(ctx, {
|
|
652
|
+
editMessage: true,
|
|
653
|
+
notice: "Selection expired. Open the menu again.",
|
|
654
|
+
});
|
|
655
|
+
await answerCallbackQuerySafe(ctx, "Selection expired");
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
const botState = await fetchBotById(botId);
|
|
659
|
+
if (!botState) {
|
|
660
|
+
await renderAgentsMenu(ctx, {
|
|
661
|
+
sessionId: action.sessionId,
|
|
662
|
+
editMessage: true,
|
|
663
|
+
notice: `Agent '${botId}' not found.`,
|
|
664
|
+
});
|
|
665
|
+
await answerCallbackQuerySafe(ctx, "Agent not found");
|
|
666
|
+
return true;
|
|
667
|
+
}
|
|
668
|
+
await applyBotProviderPolicy({
|
|
669
|
+
apiPost,
|
|
670
|
+
botId,
|
|
671
|
+
botState,
|
|
672
|
+
patch: session.pendingProviderPatch,
|
|
673
|
+
});
|
|
674
|
+
const notice = session.pendingFlow === "speed"
|
|
675
|
+
? `Speed updated for '${botId}': ${session.pendingSummary.speedLabel ?? "Standard"}`
|
|
676
|
+
: `Model updated for '${botId}': ${session.pendingSummary.modelLabel ?? "auto"} / ${session.pendingSummary.reasoningLabel ?? "Default"}`;
|
|
677
|
+
clearPendingProviderSelection(session);
|
|
678
|
+
menuSessions.set(action.sessionId, session);
|
|
679
|
+
await renderBotsMenu(ctx, {
|
|
680
|
+
editMessage: true,
|
|
681
|
+
notice,
|
|
682
|
+
});
|
|
683
|
+
await answerCallbackQuerySafe(ctx, "Updated");
|
|
684
|
+
return true;
|
|
685
|
+
}
|
|
514
686
|
if (action.type === "open") {
|
|
515
687
|
await renderBotActions(ctx, {
|
|
516
688
|
sessionId: action.sessionId,
|
|
@@ -541,78 +713,6 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
541
713
|
await answerCallbackQuerySafe(ctx, "Policy updated");
|
|
542
714
|
return true;
|
|
543
715
|
}
|
|
544
|
-
if (action.type === "model") {
|
|
545
|
-
const botState = await fetchBotById(botId);
|
|
546
|
-
if (!botState) {
|
|
547
|
-
await renderBotsMenu(ctx, { editMessage: true, notice: `Agent '${botId}' not found.` });
|
|
548
|
-
await answerCallbackQuerySafe(ctx, "Agent not found");
|
|
549
|
-
return true;
|
|
550
|
-
}
|
|
551
|
-
const selection = resolveModelSelectionFromAction({
|
|
552
|
-
session,
|
|
553
|
-
profileId: action.profileId,
|
|
554
|
-
});
|
|
555
|
-
if (!selection.ok) {
|
|
556
|
-
await renderBotActions(ctx, {
|
|
557
|
-
sessionId: action.sessionId,
|
|
558
|
-
index: action.index,
|
|
559
|
-
notice: "Model options expired. Open /bots again.",
|
|
560
|
-
});
|
|
561
|
-
await answerCallbackQuerySafe(ctx, "Model menu expired");
|
|
562
|
-
return true;
|
|
563
|
-
}
|
|
564
|
-
await applyBotModelPolicy({
|
|
565
|
-
apiPost,
|
|
566
|
-
botId,
|
|
567
|
-
botState,
|
|
568
|
-
model: selection.model,
|
|
569
|
-
});
|
|
570
|
-
await renderBotActions(ctx, {
|
|
571
|
-
sessionId: action.sessionId,
|
|
572
|
-
index: action.index,
|
|
573
|
-
notice: `Model updated: ${selection.label}`,
|
|
574
|
-
});
|
|
575
|
-
await answerCallbackQuerySafe(ctx, "Model updated");
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
if (action.type === "model_apply") {
|
|
579
|
-
const botState = await fetchBotById(botId);
|
|
580
|
-
if (!botState) {
|
|
581
|
-
await renderSetModelAgentMenu(ctx, {
|
|
582
|
-
sessionId: action.sessionId,
|
|
583
|
-
editMessage: true,
|
|
584
|
-
notice: `Agent '${botId}' not found.`,
|
|
585
|
-
});
|
|
586
|
-
await answerCallbackQuerySafe(ctx, "Agent not found");
|
|
587
|
-
return true;
|
|
588
|
-
}
|
|
589
|
-
const selection = resolveModelSelectionFromAction({
|
|
590
|
-
session,
|
|
591
|
-
profileId: action.profileId,
|
|
592
|
-
});
|
|
593
|
-
if (!selection.ok) {
|
|
594
|
-
await renderBotModelMenu(ctx, {
|
|
595
|
-
sessionId: action.sessionId,
|
|
596
|
-
index: action.index,
|
|
597
|
-
notice: "Model options expired. Open /set_model again.",
|
|
598
|
-
});
|
|
599
|
-
await answerCallbackQuerySafe(ctx, "Model menu expired");
|
|
600
|
-
return true;
|
|
601
|
-
}
|
|
602
|
-
await applyBotModelPolicy({
|
|
603
|
-
apiPost,
|
|
604
|
-
botId,
|
|
605
|
-
botState,
|
|
606
|
-
model: selection.model,
|
|
607
|
-
});
|
|
608
|
-
await renderBotModelMenu(ctx, {
|
|
609
|
-
sessionId: action.sessionId,
|
|
610
|
-
index: action.index,
|
|
611
|
-
notice: `Model updated: ${selection.label}`,
|
|
612
|
-
});
|
|
613
|
-
await answerCallbackQuerySafe(ctx, "Model updated");
|
|
614
|
-
return true;
|
|
615
|
-
}
|
|
616
716
|
if (action.type === "reset_ask") {
|
|
617
717
|
await renderResetConfirm(ctx, {
|
|
618
718
|
sessionId: action.sessionId,
|
|
@@ -643,7 +743,8 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
643
743
|
}
|
|
644
744
|
if (action.type === "delete_confirm") {
|
|
645
745
|
await apiPost(`/api/bots/${encodeURIComponent(botId)}/delete`, { deleteMode: "soft" });
|
|
646
|
-
await
|
|
746
|
+
await renderAgentsMenu(ctx, {
|
|
747
|
+
sessionId: action.sessionId,
|
|
647
748
|
editMessage: true,
|
|
648
749
|
notice: `Agent deleted: ${botId}`,
|
|
649
750
|
});
|
|
@@ -657,7 +758,7 @@ export async function maybeHandleHubOpsCallback({ ctx, runtime, }) {
|
|
|
657
758
|
await answerCallbackQuerySafe(ctx, "Action failed");
|
|
658
759
|
await editMessageOrReply(ctx, `Action failed:\n${sanitizeError(error)}`, {
|
|
659
760
|
reply_markup: {
|
|
660
|
-
inline_keyboard: [[{ text: "Back to
|
|
761
|
+
inline_keyboard: [[{ text: "Back to menu", callback_data: "hub:back" }]],
|
|
661
762
|
},
|
|
662
763
|
});
|
|
663
764
|
return true;
|
|
@@ -668,32 +769,25 @@ function buildHelpText(runtimeName) {
|
|
|
668
769
|
`${String(runtimeName ?? "Copilot Hub")}`,
|
|
669
770
|
"",
|
|
670
771
|
"Commands:",
|
|
671
|
-
"/help",
|
|
672
|
-
"/health",
|
|
673
772
|
"/bots",
|
|
773
|
+
"/health",
|
|
674
774
|
"/create_agent",
|
|
675
775
|
"/codex_status",
|
|
676
776
|
"/codex_login",
|
|
677
777
|
"/codex_switch_key",
|
|
678
778
|
"/set_model",
|
|
679
|
-
"/set_model_all",
|
|
680
779
|
"/cancel",
|
|
681
780
|
"",
|
|
682
|
-
"
|
|
683
|
-
"/
|
|
781
|
+
"/bots: open the main control menu",
|
|
782
|
+
"/set_model: open Model & Reasoning directly",
|
|
783
|
+
"/codex_login: switch account with device code",
|
|
684
784
|
"/codex_switch_key: switch account with API key",
|
|
685
785
|
"",
|
|
686
|
-
"
|
|
687
|
-
"
|
|
688
|
-
"
|
|
689
|
-
"
|
|
690
|
-
"
|
|
691
|
-
"All agent actions start from that agent workspace.",
|
|
692
|
-
"Model changes apply on next message and keep conversation history.",
|
|
693
|
-
"/set_model opens a clickable agent->model flow.",
|
|
694
|
-
"/set_model_all opens a clickable model list for all agents and the hub.",
|
|
695
|
-
"",
|
|
696
|
-
"For development tasks, send a normal message to the assistant.",
|
|
786
|
+
"Use /bots for:",
|
|
787
|
+
"Agents",
|
|
788
|
+
"Model & Reasoning",
|
|
789
|
+
"Speed",
|
|
790
|
+
"Create agent",
|
|
697
791
|
].join("\n");
|
|
698
792
|
}
|
|
699
793
|
function buildFlowKey(runtimeId, channelId, chatId) {
|
|
@@ -734,6 +828,47 @@ async function renderBotsMenu(ctx, { editMessage = false, notice = "" } = {}) {
|
|
|
734
828
|
if (notice) {
|
|
735
829
|
lines.push(notice, "");
|
|
736
830
|
}
|
|
831
|
+
lines.push("Control menu:");
|
|
832
|
+
lines.push(`agents: ${bots.length}`);
|
|
833
|
+
if (bots.length > 0) {
|
|
834
|
+
const runningCount = bots.filter((bot) => bot.running).length;
|
|
835
|
+
lines.push(`running: ${runningCount}/${bots.length}`);
|
|
836
|
+
}
|
|
837
|
+
lines.push("", "Choose a section:");
|
|
838
|
+
const keyboard = buildBotsMenuKeyboard(sessionId, bots);
|
|
839
|
+
if (editMessage) {
|
|
840
|
+
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
841
|
+
reply_markup: {
|
|
842
|
+
inline_keyboard: keyboard,
|
|
843
|
+
},
|
|
844
|
+
});
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
await ctx.reply(lines.join("\n"), {
|
|
848
|
+
reply_markup: {
|
|
849
|
+
inline_keyboard: keyboard,
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
async function renderAgentsMenu(ctx, { sessionId = "", editMessage = false, notice = "", } = {}) {
|
|
854
|
+
const bots = await fetchBots();
|
|
855
|
+
const chatId = getChatId(ctx);
|
|
856
|
+
const activeSessionId = sessionId || createMenuSession(chatId, bots);
|
|
857
|
+
const session = getMenuSession(activeSessionId, ctx);
|
|
858
|
+
if (!session) {
|
|
859
|
+
await renderBotsMenu(ctx, {
|
|
860
|
+
editMessage,
|
|
861
|
+
notice: "Menu expired. Open /bots again.",
|
|
862
|
+
});
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
session.botIds = bots.map((entry) => String(entry?.id ?? "").trim()).filter(Boolean);
|
|
866
|
+
clearPendingProviderSelection(session);
|
|
867
|
+
menuSessions.set(activeSessionId, session);
|
|
868
|
+
const lines = [];
|
|
869
|
+
if (notice) {
|
|
870
|
+
lines.push(notice, "");
|
|
871
|
+
}
|
|
737
872
|
lines.push("Agents:");
|
|
738
873
|
if (bots.length === 0) {
|
|
739
874
|
lines.push("No bots registered.");
|
|
@@ -743,9 +878,9 @@ async function renderBotsMenu(ctx, { editMessage = false, notice = "" } = {}) {
|
|
|
743
878
|
const status = botState.running ? "ON" : "OFF";
|
|
744
879
|
lines.push(`- ${botState.id} (${status})`);
|
|
745
880
|
}
|
|
746
|
-
lines.push("", "
|
|
881
|
+
lines.push("", "Choose an agent:");
|
|
747
882
|
}
|
|
748
|
-
const keyboard =
|
|
883
|
+
const keyboard = buildAgentsMenuKeyboard(activeSessionId, bots);
|
|
749
884
|
if (editMessage) {
|
|
750
885
|
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
751
886
|
reply_markup: {
|
|
@@ -764,41 +899,36 @@ async function renderBotActions(ctx, { sessionId, index, notice = "" }) {
|
|
|
764
899
|
const session = getMenuSession(sessionId, ctx);
|
|
765
900
|
const botId = getBotIdFromSession(session, index);
|
|
766
901
|
if (!botId) {
|
|
767
|
-
await
|
|
902
|
+
await renderAgentsMenu(ctx, {
|
|
903
|
+
sessionId,
|
|
904
|
+
editMessage: true,
|
|
905
|
+
notice: "Agent not found. Refreshed.",
|
|
906
|
+
});
|
|
768
907
|
return;
|
|
769
908
|
}
|
|
770
909
|
const botState = await fetchBotById(botId);
|
|
771
910
|
if (!botState) {
|
|
772
|
-
await
|
|
911
|
+
await renderAgentsMenu(ctx, {
|
|
912
|
+
sessionId,
|
|
913
|
+
editMessage: true,
|
|
914
|
+
notice: `Agent '${botId}' not found.`,
|
|
915
|
+
});
|
|
773
916
|
return;
|
|
774
917
|
}
|
|
775
|
-
const
|
|
776
|
-
? botState.provider.options
|
|
777
|
-
: {};
|
|
778
|
-
const currentModel = String(providerOptions.model ?? "").trim();
|
|
918
|
+
const providerSelection = getBotProviderSelection(botState);
|
|
779
919
|
const botPolicyState = getBotPolicyState(botState);
|
|
780
|
-
const modelCatalog = await fetchCodexModelOptions(apiGet);
|
|
781
|
-
const modelOptions = buildSessionModelOptions({
|
|
782
|
-
catalog: modelCatalog.models,
|
|
783
|
-
currentModel,
|
|
784
|
-
});
|
|
785
920
|
if (session) {
|
|
786
|
-
session
|
|
921
|
+
clearPendingProviderSelection(session);
|
|
787
922
|
menuSessions.set(sessionId, session);
|
|
788
923
|
}
|
|
789
924
|
const lines = [];
|
|
790
925
|
if (notice) {
|
|
791
926
|
lines.push(notice, "");
|
|
792
927
|
}
|
|
793
|
-
lines.push(`Agent: ${botState.id}`, `running: ${botState.running ? "yes" : "no"}`, `telegram: ${botState.telegramRunning ? "yes" : "no"}`, `sandboxMode: ${botPolicyState.sandboxMode}`, `approvalPolicy: ${botPolicyState.approvalPolicy}`, `model: ${formatModelLabel(
|
|
794
|
-
? `Available models: ${modelCatalog.models.length}`
|
|
795
|
-
: "Available models: unavailable (you can still use /set_model).", "", "Choose an action:");
|
|
928
|
+
lines.push(`Agent: ${botState.id}`, `running: ${botState.running ? "yes" : "no"}`, `telegram: ${botState.telegramRunning ? "yes" : "no"}`, `sandboxMode: ${botPolicyState.sandboxMode}`, `approvalPolicy: ${botPolicyState.approvalPolicy}`, `model: ${formatModelLabel(providerSelection.model)}`, `reasoning: ${formatReasoningLabel(providerSelection.reasoningEffort)}`, `speed: ${formatFastModeLabel(providerSelection.serviceTier)}`, "", "Policy quick guide:", "Safe = read-only + approval prompts", "Standard = workspace write + approval prompts", "Semi Auto = workspace write + ask on failures", "Full = no approval prompts", "All actions start from this agent workspace.", "Use the main menu for Model & Reasoning and Speed.", "", "Choose an action:");
|
|
796
929
|
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
797
930
|
reply_markup: {
|
|
798
|
-
inline_keyboard: buildBotActionsKeyboard(sessionId, index,
|
|
799
|
-
modelOptions,
|
|
800
|
-
currentModel,
|
|
801
|
-
}),
|
|
931
|
+
inline_keyboard: buildBotActionsKeyboard(sessionId, index),
|
|
802
932
|
},
|
|
803
933
|
});
|
|
804
934
|
}
|
|
@@ -810,7 +940,7 @@ async function renderResetConfirm(ctx, { sessionId, index, botId }) {
|
|
|
810
940
|
{ text: "Confirm reset", callback_data: `hub:rc:${sessionId}:${index}` },
|
|
811
941
|
{ text: "Cancel", callback_data: `hub:o:${sessionId}:${index}` },
|
|
812
942
|
],
|
|
813
|
-
[{ text: "Back to
|
|
943
|
+
[{ text: "Back to agents", callback_data: `hub:ag:${sessionId}` }],
|
|
814
944
|
],
|
|
815
945
|
},
|
|
816
946
|
});
|
|
@@ -823,12 +953,22 @@ async function renderDeleteConfirm(ctx, { sessionId, index, botId }) {
|
|
|
823
953
|
{ text: "Confirm delete", callback_data: `hub:dc:${sessionId}:${index}` },
|
|
824
954
|
{ text: "Cancel", callback_data: `hub:o:${sessionId}:${index}` },
|
|
825
955
|
],
|
|
826
|
-
[{ text: "Back to
|
|
956
|
+
[{ text: "Back to agents", callback_data: `hub:ag:${sessionId}` }],
|
|
827
957
|
],
|
|
828
958
|
},
|
|
829
959
|
});
|
|
830
960
|
}
|
|
831
961
|
function buildBotsMenuKeyboard(sessionId, bots) {
|
|
962
|
+
const hasBots = bots.length > 0;
|
|
963
|
+
return [
|
|
964
|
+
[{ text: "Agents", callback_data: `hub:ag:${sessionId}` }],
|
|
965
|
+
[{ text: "Model & Reasoning", callback_data: `hub:ga:${sessionId}` }],
|
|
966
|
+
[{ text: "Speed", callback_data: `hub:gf:${sessionId}` }],
|
|
967
|
+
[{ text: "Create agent", callback_data: "hub:create" }],
|
|
968
|
+
...(hasBots ? [[{ text: "Refresh", callback_data: `hub:r:${sessionId}` }]] : []),
|
|
969
|
+
];
|
|
970
|
+
}
|
|
971
|
+
function buildAgentsMenuKeyboard(sessionId, bots) {
|
|
832
972
|
const rows = [];
|
|
833
973
|
for (let index = 0; index < bots.length; index += 1) {
|
|
834
974
|
const botState = bots[index];
|
|
@@ -840,9 +980,8 @@ function buildBotsMenuKeyboard(sessionId, bots) {
|
|
|
840
980
|
{ text: `${botState.id} (${status})`, callback_data: `hub:o:${sessionId}:${index}` },
|
|
841
981
|
]);
|
|
842
982
|
}
|
|
843
|
-
rows.push([{ text: "Refresh", callback_data: `hub:
|
|
844
|
-
rows.push([{ text: "
|
|
845
|
-
rows.push([{ text: "Create agent", callback_data: "hub:create" }]);
|
|
983
|
+
rows.push([{ text: "Refresh", callback_data: `hub:ag:${sessionId}` }]);
|
|
984
|
+
rows.push([{ text: "Back to menu", callback_data: "hub:back" }]);
|
|
846
985
|
return rows;
|
|
847
986
|
}
|
|
848
987
|
async function renderGlobalModelMenu(ctx, { sessionId = "", editMessage = false, runtime = null, notice = "", } = {}) {
|
|
@@ -861,7 +1000,7 @@ async function renderGlobalModelMenu(ctx, { sessionId = "", editMessage = false,
|
|
|
861
1000
|
if (!session) {
|
|
862
1001
|
await renderBotsMenu(ctx, {
|
|
863
1002
|
editMessage,
|
|
864
|
-
notice: "Menu expired. Open
|
|
1003
|
+
notice: "Menu expired. Open Model & Reasoning again.",
|
|
865
1004
|
});
|
|
866
1005
|
return;
|
|
867
1006
|
}
|
|
@@ -872,22 +1011,18 @@ async function renderGlobalModelMenu(ctx, { sessionId = "", editMessage = false,
|
|
|
872
1011
|
catalog: modelCatalog.models,
|
|
873
1012
|
currentModel,
|
|
874
1013
|
});
|
|
1014
|
+
clearPendingProviderSelection(session);
|
|
875
1015
|
session.modelOptions = modelOptions;
|
|
1016
|
+
session.reasoningOptions = [];
|
|
876
1017
|
menuSessions.set(activeSessionId, session);
|
|
877
1018
|
const lines = [];
|
|
878
1019
|
if (notice) {
|
|
879
1020
|
lines.push(notice, "");
|
|
880
1021
|
}
|
|
881
|
-
lines.push(
|
|
1022
|
+
lines.push("Model & Reasoning:");
|
|
882
1023
|
lines.push(`agents: ${bots.length}`);
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}
|
|
886
|
-
lines.push(`current: ${sharedModel.mode === "uniform"
|
|
887
|
-
? formatModelLabel(sharedModel.model)
|
|
888
|
-
: hubIncluded
|
|
889
|
-
? "mixed (agents and hub use different models)"
|
|
890
|
-
: "mixed (agents use different models)"}`);
|
|
1024
|
+
lines.push(`hub available: ${hubIncluded ? "yes" : "no"}`);
|
|
1025
|
+
lines.push(`current model: ${sharedModel.mode === "uniform" ? formatModelLabel(sharedModel.model) : "mixed"}`);
|
|
891
1026
|
lines.push(modelCatalog.available
|
|
892
1027
|
? `available models: ${modelCatalog.models.length}`
|
|
893
1028
|
: "available models: unavailable right now");
|
|
@@ -911,9 +1046,66 @@ async function renderGlobalModelMenu(ctx, { sessionId = "", editMessage = false,
|
|
|
911
1046
|
},
|
|
912
1047
|
});
|
|
913
1048
|
}
|
|
914
|
-
async function
|
|
1049
|
+
async function renderGlobalReasoningMenu(ctx, { sessionId, runtime = null, modelSelection, editMessage = true, notice = "", }) {
|
|
915
1050
|
const bots = await fetchBots();
|
|
916
|
-
|
|
1051
|
+
const hubIncluded = isHubModelControlAvailable(runtime);
|
|
1052
|
+
if (bots.length === 0 && !hubIncluded) {
|
|
1053
|
+
await renderBotsMenu(ctx, {
|
|
1054
|
+
editMessage,
|
|
1055
|
+
notice: notice || "No agents found.",
|
|
1056
|
+
});
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
const session = getMenuSession(sessionId, ctx);
|
|
1060
|
+
if (!session) {
|
|
1061
|
+
await renderBotsMenu(ctx, {
|
|
1062
|
+
editMessage,
|
|
1063
|
+
notice: "Menu expired. Open Model & Reasoning again.",
|
|
1064
|
+
});
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
const sharedReasoning = resolveSharedReasoningForGlobalTargets(bots, runtime);
|
|
1068
|
+
const currentModel = resolveSharedModelForGlobalTargets(bots, runtime);
|
|
1069
|
+
const reasoningOptions = buildReasoningOptionsForModel({
|
|
1070
|
+
modelSelection,
|
|
1071
|
+
currentModel: currentModel.mode === "uniform" && currentModel.model === modelSelection.model
|
|
1072
|
+
? currentModel.model
|
|
1073
|
+
: null,
|
|
1074
|
+
currentReasoningEffort: sharedReasoning.mode === "uniform" ? sharedReasoning.reasoningEffort : null,
|
|
1075
|
+
});
|
|
1076
|
+
session.reasoningOptions = reasoningOptions;
|
|
1077
|
+
menuSessions.set(sessionId, session);
|
|
1078
|
+
const lines = [];
|
|
1079
|
+
if (notice) {
|
|
1080
|
+
lines.push(notice, "");
|
|
1081
|
+
}
|
|
1082
|
+
lines.push("Model & Reasoning:");
|
|
1083
|
+
lines.push(`model: ${modelSelection.label}`);
|
|
1084
|
+
lines.push(`current reasoning: ${sharedReasoning.mode === "uniform"
|
|
1085
|
+
? formatReasoningLabel(sharedReasoning.reasoningEffort)
|
|
1086
|
+
: "mixed"}`);
|
|
1087
|
+
lines.push("", "Choose the reasoning level:");
|
|
1088
|
+
const keyboard = buildGlobalReasoningKeyboard(sessionId, modelSelection.key, {
|
|
1089
|
+
reasoningOptions,
|
|
1090
|
+
});
|
|
1091
|
+
if (editMessage) {
|
|
1092
|
+
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
1093
|
+
reply_markup: {
|
|
1094
|
+
inline_keyboard: keyboard,
|
|
1095
|
+
},
|
|
1096
|
+
});
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
await ctx.reply(lines.join("\n"), {
|
|
1100
|
+
reply_markup: {
|
|
1101
|
+
inline_keyboard: keyboard,
|
|
1102
|
+
},
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
async function renderGlobalFastMenu(ctx, { sessionId = "", editMessage = false, runtime = null, notice = "", } = {}) {
|
|
1106
|
+
const bots = await fetchBots();
|
|
1107
|
+
const hubIncluded = isHubModelControlAvailable(runtime);
|
|
1108
|
+
if (bots.length === 0 && !hubIncluded) {
|
|
917
1109
|
await renderBotsMenu(ctx, {
|
|
918
1110
|
editMessage,
|
|
919
1111
|
notice: notice || "No agents found.",
|
|
@@ -926,18 +1118,29 @@ async function renderSetModelAgentMenu(ctx, { sessionId = "", editMessage = fals
|
|
|
926
1118
|
if (!session) {
|
|
927
1119
|
await renderBotsMenu(ctx, {
|
|
928
1120
|
editMessage,
|
|
929
|
-
notice: "Menu expired. Open /
|
|
1121
|
+
notice: "Menu expired. Open /bots again.",
|
|
930
1122
|
});
|
|
931
1123
|
return;
|
|
932
1124
|
}
|
|
1125
|
+
const sharedServiceTier = resolveSharedServiceTierForGlobalTargets(bots, runtime);
|
|
1126
|
+
clearPendingProviderSelection(session);
|
|
1127
|
+
session.reasoningOptions = [];
|
|
1128
|
+
menuSessions.set(activeSessionId, session);
|
|
933
1129
|
const lines = [];
|
|
934
1130
|
if (notice) {
|
|
935
1131
|
lines.push(notice, "");
|
|
936
1132
|
}
|
|
937
|
-
lines.push("
|
|
1133
|
+
lines.push("Speed:");
|
|
938
1134
|
lines.push(`agents: ${bots.length}`);
|
|
939
|
-
lines.push(""
|
|
940
|
-
|
|
1135
|
+
lines.push(`hub available: ${hubIncluded ? "yes" : "no"}`);
|
|
1136
|
+
lines.push(`current speed: ${sharedServiceTier.mode === "uniform"
|
|
1137
|
+
? formatFastModeLabel(sharedServiceTier.serviceTier)
|
|
1138
|
+
: "mixed"}`);
|
|
1139
|
+
lines.push("", "Choose the speed mode:");
|
|
1140
|
+
const keyboard = buildGlobalFastKeyboard(activeSessionId, {
|
|
1141
|
+
serviceTier: sharedServiceTier.mode === "uniform" ? sharedServiceTier.serviceTier : null,
|
|
1142
|
+
hasMixedSelection: sharedServiceTier.mode === "mixed",
|
|
1143
|
+
});
|
|
941
1144
|
if (editMessage) {
|
|
942
1145
|
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
943
1146
|
reply_markup: {
|
|
@@ -952,52 +1155,80 @@ async function renderSetModelAgentMenu(ctx, { sessionId = "", editMessage = fals
|
|
|
952
1155
|
},
|
|
953
1156
|
});
|
|
954
1157
|
}
|
|
955
|
-
async function
|
|
1158
|
+
async function renderProviderTargetMenu(ctx, { sessionId, runtime = null, editMessage = true, notice = "", }) {
|
|
1159
|
+
const bots = await fetchBots();
|
|
956
1160
|
const session = getMenuSession(sessionId, ctx);
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
editMessage: true,
|
|
962
|
-
notice: "Agent not found. Refreshed.",
|
|
1161
|
+
if (!session || !session.pendingProviderPatch || !session.pendingFlow) {
|
|
1162
|
+
await renderBotsMenu(ctx, {
|
|
1163
|
+
editMessage,
|
|
1164
|
+
notice: "Selection expired. Open the menu again.",
|
|
963
1165
|
});
|
|
964
1166
|
return;
|
|
965
1167
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1168
|
+
session.botIds = bots.map((entry) => String(entry?.id ?? "").trim()).filter(Boolean);
|
|
1169
|
+
menuSessions.set(sessionId, session);
|
|
1170
|
+
const hubIncluded = isHubModelControlAvailable(runtime);
|
|
1171
|
+
const lines = [];
|
|
1172
|
+
if (notice) {
|
|
1173
|
+
lines.push(notice, "");
|
|
1174
|
+
}
|
|
1175
|
+
lines.push(session.pendingFlow === "speed" ? "Speed" : "Model & Reasoning");
|
|
1176
|
+
if (session.pendingSummary.modelLabel) {
|
|
1177
|
+
lines.push(`model: ${session.pendingSummary.modelLabel}`);
|
|
1178
|
+
}
|
|
1179
|
+
if (session.pendingSummary.reasoningLabel) {
|
|
1180
|
+
lines.push(`reasoning: ${session.pendingSummary.reasoningLabel}`);
|
|
1181
|
+
}
|
|
1182
|
+
if (session.pendingSummary.speedLabel) {
|
|
1183
|
+
lines.push(`speed: ${session.pendingSummary.speedLabel}`);
|
|
1184
|
+
}
|
|
1185
|
+
lines.push("", "Choose where to apply it:");
|
|
1186
|
+
const keyboard = buildProviderTargetKeyboard(sessionId, {
|
|
1187
|
+
hubIncluded,
|
|
1188
|
+
backCallbackData: session.pendingFlow === "speed" ? `hub:gf:${sessionId}` : `hub:ga:${sessionId}`,
|
|
1189
|
+
});
|
|
1190
|
+
if (editMessage) {
|
|
1191
|
+
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
1192
|
+
reply_markup: {
|
|
1193
|
+
inline_keyboard: keyboard,
|
|
1194
|
+
},
|
|
972
1195
|
});
|
|
973
1196
|
return;
|
|
974
1197
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
const modelCatalog = await fetchCodexModelOptions(apiGet);
|
|
980
|
-
const modelOptions = buildSessionModelOptions({
|
|
981
|
-
catalog: modelCatalog.models,
|
|
982
|
-
currentModel,
|
|
1198
|
+
await ctx.reply(lines.join("\n"), {
|
|
1199
|
+
reply_markup: {
|
|
1200
|
+
inline_keyboard: keyboard,
|
|
1201
|
+
},
|
|
983
1202
|
});
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1203
|
+
}
|
|
1204
|
+
async function renderProviderTargetAgentMenu(ctx, { sessionId, editMessage = true, notice = "", }) {
|
|
1205
|
+
const bots = await fetchBots();
|
|
1206
|
+
const session = getMenuSession(sessionId, ctx);
|
|
1207
|
+
if (!session || !session.pendingProviderPatch || !session.pendingFlow) {
|
|
1208
|
+
await renderBotsMenu(ctx, {
|
|
1209
|
+
editMessage,
|
|
1210
|
+
notice: "Selection expired. Open the menu again.",
|
|
1211
|
+
});
|
|
1212
|
+
return;
|
|
987
1213
|
}
|
|
1214
|
+
session.botIds = bots.map((entry) => String(entry?.id ?? "").trim()).filter(Boolean);
|
|
1215
|
+
menuSessions.set(sessionId, session);
|
|
988
1216
|
const lines = [];
|
|
989
1217
|
if (notice) {
|
|
990
1218
|
lines.push(notice, "");
|
|
991
1219
|
}
|
|
992
|
-
lines.push(
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1220
|
+
lines.push("Choose one agent:");
|
|
1221
|
+
if (session.pendingSummary.modelLabel) {
|
|
1222
|
+
lines.push(`model: ${session.pendingSummary.modelLabel}`);
|
|
1223
|
+
}
|
|
1224
|
+
if (session.pendingSummary.reasoningLabel) {
|
|
1225
|
+
lines.push(`reasoning: ${session.pendingSummary.reasoningLabel}`);
|
|
1226
|
+
}
|
|
1227
|
+
if (session.pendingSummary.speedLabel) {
|
|
1228
|
+
lines.push(`speed: ${session.pendingSummary.speedLabel}`);
|
|
1229
|
+
}
|
|
1230
|
+
const keyboard = buildProviderTargetAgentKeyboard(sessionId, bots, {
|
|
1231
|
+
backCallbackData: `hub:tt:${sessionId}:single`,
|
|
1001
1232
|
});
|
|
1002
1233
|
if (editMessage) {
|
|
1003
1234
|
await editMessageOrReply(ctx, lines.join("\n"), {
|
|
@@ -1013,8 +1244,26 @@ async function renderBotModelMenu(ctx, { sessionId, index, editMessage = true, n
|
|
|
1013
1244
|
},
|
|
1014
1245
|
});
|
|
1015
1246
|
}
|
|
1016
|
-
function
|
|
1017
|
-
|
|
1247
|
+
function setPendingProviderSelection(session, { patch, flow, modelLabel = null, reasoningLabel = null, speedLabel = null, }) {
|
|
1248
|
+
session.pendingProviderPatch = { ...patch };
|
|
1249
|
+
session.pendingFlow = flow;
|
|
1250
|
+
session.pendingSummary = {
|
|
1251
|
+
modelLabel,
|
|
1252
|
+
reasoningLabel,
|
|
1253
|
+
speedLabel,
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
function clearPendingProviderSelection(session) {
|
|
1257
|
+
session.pendingProviderPatch = null;
|
|
1258
|
+
session.pendingFlow = null;
|
|
1259
|
+
session.pendingSummary = {
|
|
1260
|
+
modelLabel: null,
|
|
1261
|
+
reasoningLabel: null,
|
|
1262
|
+
speedLabel: null,
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function buildBotActionsKeyboard(sessionId, index) {
|
|
1266
|
+
return [
|
|
1018
1267
|
[
|
|
1019
1268
|
{ text: "Safe (read-only)", callback_data: `hub:p:${sessionId}:${index}:safe` },
|
|
1020
1269
|
{ text: "Standard (ask)", callback_data: `hub:p:${sessionId}:${index}:standard` },
|
|
@@ -1023,101 +1272,98 @@ function buildBotActionsKeyboard(sessionId, index, { modelOptions = [], currentM
|
|
|
1023
1272
|
{ text: "Semi (fail ask)", callback_data: `hub:p:${sessionId}:${index}:semi_auto` },
|
|
1024
1273
|
{ text: "Full (no prompts)", callback_data: `hub:p:${sessionId}:${index}:full_auto` },
|
|
1025
1274
|
],
|
|
1275
|
+
[{ text: "Reset Context", callback_data: `hub:ra:${sessionId}:${index}` }],
|
|
1276
|
+
[{ text: "Delete Agent", callback_data: `hub:da:${sessionId}:${index}` }],
|
|
1277
|
+
[{ text: "Back to agents", callback_data: `hub:ag:${sessionId}` }],
|
|
1278
|
+
];
|
|
1279
|
+
}
|
|
1280
|
+
function buildGlobalModelKeyboard(sessionId, { modelOptions = [], currentModel = "", hasMixedSelection = false, } = {}) {
|
|
1281
|
+
const rows = [
|
|
1026
1282
|
[
|
|
1027
1283
|
{
|
|
1028
|
-
text: formatModelButtonText("Auto", currentModel === ""),
|
|
1029
|
-
callback_data: `hub:
|
|
1284
|
+
text: formatModelButtonText("Auto", !hasMixedSelection && currentModel === ""),
|
|
1285
|
+
callback_data: `hub:gm:${sessionId}:auto`,
|
|
1030
1286
|
},
|
|
1031
1287
|
],
|
|
1032
1288
|
];
|
|
1033
1289
|
for (const option of modelOptions) {
|
|
1034
|
-
const isCurrent =
|
|
1035
|
-
|
|
1036
|
-
.toLowerCase() ===
|
|
1037
|
-
String(option.model ?? "")
|
|
1290
|
+
const isCurrent = !hasMixedSelection &&
|
|
1291
|
+
String(currentModel ?? "")
|
|
1038
1292
|
.trim()
|
|
1039
|
-
.toLowerCase()
|
|
1293
|
+
.toLowerCase() ===
|
|
1294
|
+
String(option.model ?? "")
|
|
1295
|
+
.trim()
|
|
1296
|
+
.toLowerCase();
|
|
1040
1297
|
rows.push([
|
|
1041
1298
|
{
|
|
1042
1299
|
text: formatModelButtonText(option.label, isCurrent),
|
|
1043
|
-
callback_data: `hub:
|
|
1300
|
+
callback_data: `hub:gm:${sessionId}:${option.key}`,
|
|
1044
1301
|
},
|
|
1045
1302
|
]);
|
|
1046
1303
|
}
|
|
1047
|
-
rows.push([{ text: "
|
|
1304
|
+
rows.push([{ text: "Back to menu", callback_data: "hub:back" }]);
|
|
1048
1305
|
return rows;
|
|
1049
1306
|
}
|
|
1050
|
-
function
|
|
1307
|
+
function buildGlobalReasoningKeyboard(sessionId, modelProfileId, { reasoningOptions = [] } = {}) {
|
|
1051
1308
|
const rows = [];
|
|
1052
|
-
for (
|
|
1053
|
-
const botState = bots[index];
|
|
1054
|
-
if (!botState) {
|
|
1055
|
-
continue;
|
|
1056
|
-
}
|
|
1057
|
-
const status = botState.running ? "ON" : "OFF";
|
|
1309
|
+
for (const option of reasoningOptions) {
|
|
1058
1310
|
rows.push([
|
|
1059
1311
|
{
|
|
1060
|
-
text:
|
|
1061
|
-
callback_data: `hub:
|
|
1312
|
+
text: formatModelButtonText(option.label, option.selected === true),
|
|
1313
|
+
callback_data: `hub:gr:${sessionId}:${modelProfileId}:${option.key}`,
|
|
1062
1314
|
},
|
|
1063
1315
|
]);
|
|
1064
1316
|
}
|
|
1065
|
-
rows.push([{ text: "
|
|
1066
|
-
rows.push([{ text: "Back to
|
|
1317
|
+
rows.push([{ text: "Back to model", callback_data: `hub:ga:${sessionId}` }]);
|
|
1318
|
+
rows.push([{ text: "Back to menu", callback_data: "hub:back" }]);
|
|
1067
1319
|
return rows;
|
|
1068
1320
|
}
|
|
1069
|
-
function
|
|
1070
|
-
|
|
1321
|
+
function buildGlobalFastKeyboard(sessionId, { serviceTier = null, hasMixedSelection = false, } = {}) {
|
|
1322
|
+
return [
|
|
1071
1323
|
[
|
|
1072
1324
|
{
|
|
1073
|
-
text: formatModelButtonText("
|
|
1074
|
-
callback_data: `hub:
|
|
1325
|
+
text: formatModelButtonText("Standard", !hasMixedSelection && serviceTier !== "fast"),
|
|
1326
|
+
callback_data: `hub:gft:${sessionId}:standard`,
|
|
1075
1327
|
},
|
|
1076
1328
|
],
|
|
1077
|
-
];
|
|
1078
|
-
for (const option of modelOptions) {
|
|
1079
|
-
const isCurrent = String(currentModel ?? "")
|
|
1080
|
-
.trim()
|
|
1081
|
-
.toLowerCase() ===
|
|
1082
|
-
String(option.model ?? "")
|
|
1083
|
-
.trim()
|
|
1084
|
-
.toLowerCase();
|
|
1085
|
-
rows.push([
|
|
1086
|
-
{
|
|
1087
|
-
text: formatModelButtonText(option.label, isCurrent),
|
|
1088
|
-
callback_data: `hub:mm:${sessionId}:${index}:${option.key}`,
|
|
1089
|
-
},
|
|
1090
|
-
]);
|
|
1091
|
-
}
|
|
1092
|
-
rows.push([{ text: "Back to agents", callback_data: `hub:sm:${sessionId}` }]);
|
|
1093
|
-
rows.push([{ text: "Back to bots", callback_data: "hub:back" }]);
|
|
1094
|
-
return rows;
|
|
1095
|
-
}
|
|
1096
|
-
function buildGlobalModelKeyboard(sessionId, { modelOptions = [], currentModel = "", hasMixedSelection = false, } = {}) {
|
|
1097
|
-
const rows = [
|
|
1098
1329
|
[
|
|
1099
1330
|
{
|
|
1100
|
-
text: formatModelButtonText("
|
|
1101
|
-
callback_data: `hub:
|
|
1331
|
+
text: formatModelButtonText("Fast", !hasMixedSelection && serviceTier === "fast"),
|
|
1332
|
+
callback_data: `hub:gft:${sessionId}:fast`,
|
|
1102
1333
|
},
|
|
1103
1334
|
],
|
|
1335
|
+
[{ text: "Back to menu", callback_data: "hub:back" }],
|
|
1104
1336
|
];
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1337
|
+
}
|
|
1338
|
+
function buildProviderTargetKeyboard(sessionId, { hubIncluded, backCallbackData, }) {
|
|
1339
|
+
const rows = [
|
|
1340
|
+
[{ text: "One agent", callback_data: `hub:tt:${sessionId}:single` }],
|
|
1341
|
+
[{ text: "All agents", callback_data: `hub:tt:${sessionId}:all` }],
|
|
1342
|
+
];
|
|
1343
|
+
if (hubIncluded) {
|
|
1344
|
+
rows.push([{ text: "All agents + hub", callback_data: `hub:tt:${sessionId}:all_hub` }]);
|
|
1345
|
+
}
|
|
1346
|
+
rows.push([{ text: "Back", callback_data: backCallbackData }]);
|
|
1347
|
+
rows.push([{ text: "Back to menu", callback_data: "hub:back" }]);
|
|
1348
|
+
return rows;
|
|
1349
|
+
}
|
|
1350
|
+
function buildProviderTargetAgentKeyboard(sessionId, bots, { backCallbackData, }) {
|
|
1351
|
+
const rows = [];
|
|
1352
|
+
for (let index = 0; index < bots.length; index += 1) {
|
|
1353
|
+
const botState = bots[index];
|
|
1354
|
+
if (!botState) {
|
|
1355
|
+
continue;
|
|
1356
|
+
}
|
|
1357
|
+
const status = botState.running ? "ON" : "OFF";
|
|
1113
1358
|
rows.push([
|
|
1114
1359
|
{
|
|
1115
|
-
text:
|
|
1116
|
-
callback_data: `hub:
|
|
1360
|
+
text: `${botState.id} (${status})`,
|
|
1361
|
+
callback_data: `hub:ta:${sessionId}:${index}`,
|
|
1117
1362
|
},
|
|
1118
1363
|
]);
|
|
1119
1364
|
}
|
|
1120
|
-
rows.push([{ text: "Back
|
|
1365
|
+
rows.push([{ text: "Back", callback_data: backCallbackData }]);
|
|
1366
|
+
rows.push([{ text: "Back to menu", callback_data: "hub:back" }]);
|
|
1121
1367
|
return rows;
|
|
1122
1368
|
}
|
|
1123
1369
|
function createMenuSession(chatId, bots) {
|
|
@@ -1137,6 +1383,14 @@ function createMenuSession(chatId, bots) {
|
|
|
1137
1383
|
createdAt: Date.now(),
|
|
1138
1384
|
botIds: bots.map((entry) => String(entry?.id ?? "").trim()).filter(Boolean),
|
|
1139
1385
|
modelOptions: [],
|
|
1386
|
+
reasoningOptions: [],
|
|
1387
|
+
pendingProviderPatch: null,
|
|
1388
|
+
pendingFlow: null,
|
|
1389
|
+
pendingSummary: {
|
|
1390
|
+
modelLabel: null,
|
|
1391
|
+
reasoningLabel: null,
|
|
1392
|
+
speedLabel: null,
|
|
1393
|
+
},
|
|
1140
1394
|
});
|
|
1141
1395
|
return sessionId;
|
|
1142
1396
|
}
|
|
@@ -1200,22 +1454,27 @@ function parseMenuAction(rawData) {
|
|
|
1200
1454
|
sessionId,
|
|
1201
1455
|
};
|
|
1202
1456
|
}
|
|
1203
|
-
if (kind === "
|
|
1457
|
+
if (kind === "gf" && parts.length === 3) {
|
|
1458
|
+
const sessionId = parts[2];
|
|
1459
|
+
if (!sessionId) {
|
|
1460
|
+
return null;
|
|
1461
|
+
}
|
|
1462
|
+
return {
|
|
1463
|
+
type: "global_fast_open",
|
|
1464
|
+
sessionId,
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
if (kind === "ag" && parts.length === 3) {
|
|
1204
1468
|
const sessionId = parts[2];
|
|
1205
1469
|
if (!sessionId) {
|
|
1206
1470
|
return null;
|
|
1207
1471
|
}
|
|
1208
1472
|
return {
|
|
1209
|
-
type: "
|
|
1473
|
+
type: "agents_home",
|
|
1210
1474
|
sessionId,
|
|
1211
1475
|
};
|
|
1212
1476
|
}
|
|
1213
|
-
if ((kind === "o" ||
|
|
1214
|
-
kind === "mo" ||
|
|
1215
|
-
kind === "ra" ||
|
|
1216
|
-
kind === "rc" ||
|
|
1217
|
-
kind === "da" ||
|
|
1218
|
-
kind === "dc") &&
|
|
1477
|
+
if ((kind === "o" || kind === "ra" || kind === "rc" || kind === "da" || kind === "dc") &&
|
|
1219
1478
|
parts.length === 4) {
|
|
1220
1479
|
const sessionId = parts[2];
|
|
1221
1480
|
if (!sessionId) {
|
|
@@ -1227,7 +1486,6 @@ function parseMenuAction(rawData) {
|
|
|
1227
1486
|
}
|
|
1228
1487
|
const mapping = {
|
|
1229
1488
|
o: "open",
|
|
1230
|
-
mo: "model_open",
|
|
1231
1489
|
ra: "reset_ask",
|
|
1232
1490
|
rc: "reset_confirm",
|
|
1233
1491
|
da: "delete_ask",
|
|
@@ -1243,7 +1501,7 @@ function parseMenuAction(rawData) {
|
|
|
1243
1501
|
index,
|
|
1244
1502
|
};
|
|
1245
1503
|
}
|
|
1246
|
-
if (
|
|
1504
|
+
if (kind === "p" && parts.length === 5) {
|
|
1247
1505
|
const index = parseMenuIndex(parts[3]);
|
|
1248
1506
|
const profileId = String(parts[4] ?? "")
|
|
1249
1507
|
.trim()
|
|
@@ -1256,7 +1514,7 @@ function parseMenuAction(rawData) {
|
|
|
1256
1514
|
return null;
|
|
1257
1515
|
}
|
|
1258
1516
|
return {
|
|
1259
|
-
type:
|
|
1517
|
+
type: "policy",
|
|
1260
1518
|
sessionId,
|
|
1261
1519
|
index,
|
|
1262
1520
|
profileId,
|
|
@@ -1276,6 +1534,64 @@ function parseMenuAction(rawData) {
|
|
|
1276
1534
|
profileId,
|
|
1277
1535
|
};
|
|
1278
1536
|
}
|
|
1537
|
+
if (kind === "gft" && parts.length === 4) {
|
|
1538
|
+
const sessionId = parts[2];
|
|
1539
|
+
const profileId = String(parts[3] ?? "")
|
|
1540
|
+
.trim()
|
|
1541
|
+
.toLowerCase();
|
|
1542
|
+
if (!sessionId || !profileId) {
|
|
1543
|
+
return null;
|
|
1544
|
+
}
|
|
1545
|
+
return {
|
|
1546
|
+
type: "global_fast_apply",
|
|
1547
|
+
sessionId,
|
|
1548
|
+
profileId,
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
if (kind === "tt" && parts.length === 4) {
|
|
1552
|
+
const sessionId = parts[2];
|
|
1553
|
+
const profileId = String(parts[3] ?? "")
|
|
1554
|
+
.trim()
|
|
1555
|
+
.toLowerCase();
|
|
1556
|
+
if (!sessionId || !profileId) {
|
|
1557
|
+
return null;
|
|
1558
|
+
}
|
|
1559
|
+
return {
|
|
1560
|
+
type: "target_choice",
|
|
1561
|
+
sessionId,
|
|
1562
|
+
profileId,
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1565
|
+
if (kind === "ta" && parts.length === 4) {
|
|
1566
|
+
const sessionId = parts[2];
|
|
1567
|
+
const index = parseMenuIndex(parts[3]);
|
|
1568
|
+
if (!sessionId || index === null) {
|
|
1569
|
+
return null;
|
|
1570
|
+
}
|
|
1571
|
+
return {
|
|
1572
|
+
type: "target_agent_apply",
|
|
1573
|
+
sessionId,
|
|
1574
|
+
index,
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
if (kind === "gr" && parts.length === 5) {
|
|
1578
|
+
const sessionId = parts[2];
|
|
1579
|
+
const modelProfileId = String(parts[3] ?? "")
|
|
1580
|
+
.trim()
|
|
1581
|
+
.toLowerCase();
|
|
1582
|
+
const profileId = String(parts[4] ?? "")
|
|
1583
|
+
.trim()
|
|
1584
|
+
.toLowerCase();
|
|
1585
|
+
if (!sessionId || !modelProfileId || !profileId) {
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
return {
|
|
1589
|
+
type: "global_reasoning_apply",
|
|
1590
|
+
sessionId,
|
|
1591
|
+
modelProfileId,
|
|
1592
|
+
profileId,
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1279
1595
|
return null;
|
|
1280
1596
|
}
|
|
1281
1597
|
function isHubModelControlAvailable(runtime) {
|
|
@@ -1284,24 +1600,38 @@ function isHubModelControlAvailable(runtime) {
|
|
|
1284
1600
|
function resolveSharedModelForGlobalTargets(bots, runtime) {
|
|
1285
1601
|
const models = bots.map((bot) => bot?.provider?.options?.model);
|
|
1286
1602
|
if (runtime && typeof runtime.getProviderOptions === "function") {
|
|
1287
|
-
models.push(
|
|
1603
|
+
models.push(getRuntimeProviderSelection(runtime).model);
|
|
1288
1604
|
}
|
|
1289
1605
|
return resolveSharedModel(models);
|
|
1290
1606
|
}
|
|
1291
|
-
|
|
1607
|
+
function resolveSharedReasoningForGlobalTargets(bots, runtime) {
|
|
1608
|
+
const values = bots.map((bot) => bot?.provider?.options?.reasoningEffort);
|
|
1609
|
+
if (runtime && typeof runtime.getProviderOptions === "function") {
|
|
1610
|
+
values.push(getRuntimeProviderSelection(runtime).reasoningEffort);
|
|
1611
|
+
}
|
|
1612
|
+
return resolveSharedReasoningEffort(values);
|
|
1613
|
+
}
|
|
1614
|
+
function resolveSharedServiceTierForGlobalTargets(bots, runtime) {
|
|
1615
|
+
const values = bots.map((bot) => bot?.provider?.options?.serviceTier);
|
|
1616
|
+
if (runtime && typeof runtime.getProviderOptions === "function") {
|
|
1617
|
+
values.push(getRuntimeProviderSelection(runtime).serviceTier);
|
|
1618
|
+
}
|
|
1619
|
+
return resolveSharedServiceTier(values);
|
|
1620
|
+
}
|
|
1621
|
+
async function applyGlobalProviderSelection({ bots, patch, runtime, }) {
|
|
1292
1622
|
const hubIncluded = isHubModelControlAvailable(runtime);
|
|
1293
|
-
const botResult = await
|
|
1623
|
+
const botResult = await applyProviderPolicyToBots({
|
|
1294
1624
|
apiPost,
|
|
1295
1625
|
bots,
|
|
1296
|
-
|
|
1626
|
+
patch,
|
|
1297
1627
|
});
|
|
1298
1628
|
let hubError = null;
|
|
1299
1629
|
let hubUpdated = false;
|
|
1300
1630
|
if (hubIncluded) {
|
|
1301
1631
|
try {
|
|
1302
|
-
await
|
|
1632
|
+
await applyRuntimeProviderPolicy({
|
|
1303
1633
|
runtime,
|
|
1304
|
-
|
|
1634
|
+
patch,
|
|
1305
1635
|
});
|
|
1306
1636
|
hubUpdated = true;
|
|
1307
1637
|
}
|
|
@@ -1317,11 +1647,32 @@ async function applyGlobalModelSelection({ bots, model, runtime, }) {
|
|
|
1317
1647
|
hubError,
|
|
1318
1648
|
};
|
|
1319
1649
|
}
|
|
1320
|
-
function buildGlobalModelUpdateLines({ modelLabel, result, }) {
|
|
1650
|
+
function buildGlobalModelUpdateLines({ modelLabel, reasoningLabel, result, }) {
|
|
1651
|
+
const lines = [
|
|
1652
|
+
result.hubIncluded
|
|
1653
|
+
? `Model updated for all agents and hub: ${modelLabel} / ${reasoningLabel}`
|
|
1654
|
+
: `Model updated for all agents: ${modelLabel} / ${reasoningLabel}`,
|
|
1655
|
+
`Updated: ${result.updatedCount}/${result.totalTargets}`,
|
|
1656
|
+
];
|
|
1657
|
+
if (result.botFailures.length > 0 || result.hubError) {
|
|
1658
|
+
lines.push(`Warnings: ${result.botFailures.length + (result.hubError ? 1 : 0)}`);
|
|
1659
|
+
}
|
|
1660
|
+
if (result.botFailures.length > 0) {
|
|
1661
|
+
const failedIds = result.botFailures.map((entry) => entry.botId).filter(Boolean);
|
|
1662
|
+
if (failedIds.length > 0) {
|
|
1663
|
+
lines.push(`Failed agents: ${failedIds.join(", ")}`);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
if (result.hubError) {
|
|
1667
|
+
lines.push(`Hub warning: ${result.hubError}`);
|
|
1668
|
+
}
|
|
1669
|
+
return lines;
|
|
1670
|
+
}
|
|
1671
|
+
function buildGlobalFastUpdateLines({ fastLabel, result, }) {
|
|
1321
1672
|
const lines = [
|
|
1322
1673
|
result.hubIncluded
|
|
1323
|
-
? `
|
|
1324
|
-
: `
|
|
1674
|
+
? `Speed updated for all agents and hub: ${fastLabel}`
|
|
1675
|
+
: `Speed updated for all agents: ${fastLabel}`,
|
|
1325
1676
|
`Updated: ${result.updatedCount}/${result.totalTargets}`,
|
|
1326
1677
|
];
|
|
1327
1678
|
if (result.botFailures.length > 0 || result.hubError) {
|
|
@@ -1644,6 +1995,7 @@ async function watchCodexLoginCompletion({ ctx, runtime, flowKey, watcherToken,
|
|
|
1644
1995
|
await ctx.reply("Codex login is still pending. Run /codex_status. Once succeeded, new turns use the new account quota.");
|
|
1645
1996
|
}
|
|
1646
1997
|
async function refreshHubProviderAfterCodexLogin(runtime) {
|
|
1998
|
+
invalidateCodexQuotaUsageCache();
|
|
1647
1999
|
if (!runtime || typeof runtime.refreshProviderSession !== "function") {
|
|
1648
2000
|
return "Account updated. Hub refresh is not available on this runtime.";
|
|
1649
2001
|
}
|