perchai-cli 2.4.46 → 2.4.48

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.
Files changed (2) hide show
  1. package/dist/perch.mjs +770 -132
  2. package/package.json +1 -1
package/dist/perch.mjs CHANGED
@@ -75566,6 +75566,7 @@ var init_payroll = __esm({
75566
75566
  // lib/perchBusinessTools/index.ts
75567
75567
  var init_perchBusinessTools = __esm({
75568
75568
  "lib/perchBusinessTools/index.ts"() {
75569
+ "use strict";
75569
75570
  init_generateAPAuditPacket();
75570
75571
  init_inventoryFolder();
75571
75572
  init_loadBusinessTables();
@@ -75917,6 +75918,7 @@ function isTurnAbortedError(error) {
75917
75918
  var TURN_STOPPED_BY_USER_MESSAGE;
75918
75919
  var init_turnAbort = __esm({
75919
75920
  "features/perchTerminal/runtime/turnAbort.ts"() {
75921
+ "use strict";
75920
75922
  TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
75921
75923
  }
75922
75924
  });
@@ -76222,6 +76224,7 @@ function getToolDisplayName(toolName) {
76222
76224
  var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
76223
76225
  var init_catalog = __esm({
76224
76226
  "features/perchTerminal/runtime/toolSystem/catalog.ts"() {
76227
+ "use strict";
76225
76228
  init_toolNames();
76226
76229
  NON_MODULE_TOOL_OWNERS = {
76227
76230
  [TOOL_NAMES.listSources]: "lane",
@@ -84008,7 +84011,7 @@ function sanitizeModelBackendPreset(value) {
84008
84011
  if (value === "wandb_gemma") return "wandb_qwen";
84009
84012
  if (value === "wandb_glm") return "wandb_glm51";
84010
84013
  if (value === "bedrock_mistral_large_3") return "bedrock_qwen3_coder";
84011
- if (value === "router" || value === "gcp" || value === "modal" || value === "huggingface" || value === "fireworks_deepseek" || value === "wandb_qwen" || value === "wandb_minimax" || value === "wandb_kimi" || value === "wandb_glm51" || value === "wandb_nemotron_ultra" || value === "bedrock_glm5" || value === "bedrock_qwen3_coder" || value === "bedrock_gpt_oss_120b" || value === "bedrock_nemotron_super" || value === "bedrock_minimax_m2" || value === "bedrock_deepseek_v32" || value === "bedrock_qwen3_vl" || value === "codex_gpt55" || value === "codex_gpt54" || value === "codex_gpt54_mini" || value === "claude_haiku45" || value === "claude_sonnet46" || value === "claude_opus48") {
84014
+ if (value === "router" || value === "gcp" || value === "modal" || value === "huggingface" || value === "fireworks_deepseek" || value === "wandb_qwen" || value === "wandb_minimax" || value === "wandb_kimi" || value === "wandb_glm51" || value === "wandb_nemotron_ultra" || value === "wandb_deepseek_flash" || value === "wandb_deepseek_pro" || value === "bedrock_kimi_k25" || value === "bedrock_glm5" || value === "bedrock_qwen3_coder" || value === "bedrock_gpt_oss_120b" || value === "bedrock_nemotron_super" || value === "bedrock_minimax_m2" || value === "bedrock_deepseek_v32" || value === "bedrock_qwen3_vl" || value === "codex_gpt55" || value === "codex_gpt54" || value === "codex_gpt54_mini" || value === "claude_haiku45" || value === "claude_sonnet46" || value === "claude_opus48") {
84012
84015
  return value;
84013
84016
  }
84014
84017
  return null;
@@ -84120,7 +84123,7 @@ function resolveApiModelId(option, env4 = runtimeEnv()) {
84120
84123
  }
84121
84124
  return option.modelId;
84122
84125
  }
84123
- var DEFAULT_NIM_MODEL_ID, DEFAULT_FOUNDER_MODEL_OPTION_ID, ALL_MODEL_LANES, WORKER_LANES, REASONING_LANES, DEFAULT_GITHUB_GPT_41_ID, DEFAULT_GITHUB_GPT_41_MINI_ID, DEFAULT_GITHUB_GPT_4O_ID, DEFAULT_CODE_WORKER_MODEL_ID, GCP_SELF_HOSTED_OPTION_ID, DEFAULT_GCP_INFERENCE_MODEL, MODAL_SELF_HOSTED_OPTION_ID, MODAL_MIMO_OPTION_ID, DEFAULT_MODAL_INFERENCE_MODEL, HUGGINGFACE_KIMI_K25_OPTION_ID, WANDB_QWEN_36_35B_A3B_OPTION_ID, WANDB_MINIMAX_M25_OPTION_ID, WANDB_KIMI_K26_OPTION_ID, WANDB_GLM_51_OPTION_ID, WANDB_NEMOTRON_ULTRA_OPTION_ID, BEDROCK_GLM5_OPTION_ID, BEDROCK_QWEN3_CODER_480B_OPTION_ID, BEDROCK_GPT_OSS_120B_OPTION_ID, BEDROCK_NEMOTRON_SUPER_120B_OPTION_ID, BEDROCK_MINIMAX_M2_OPTION_ID, BEDROCK_DEEPSEEK_V32_OPTION_ID, BEDROCK_QWEN3_VL_235B_OPTION_ID, CODEX_GPT_55_OPTION_ID, CODEX_GPT_54_OPTION_ID, CODEX_GPT_54_MINI_OPTION_ID, CLAUDE_CODE_HAIKU_45_OPTION_ID, CLAUDE_CODE_SONNET_46_OPTION_ID, CLAUDE_CODE_OPUS_48_OPTION_ID, FIREWORKS_DEEPSEEK_V4_FLASH_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_PRIMARY_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_FALLBACK_OPTION_IDS, AUTO_ROUTER_EXCLUDED_BACKEND_OPTION_IDS, AI_GATEWAY_AUTO_ROUTER_OPTION_IDS, MODAL_MODELS, GCP_MODELS, HUGGINGFACE_MODELS, WANDB_MODELS, BEDROCK_MANTLE_MODELS, CODEX_OAUTH_MODELS, CLAUDE_CODE_OAUTH_MODELS, AI_GATEWAY_MODELS, OPENROUTER_MODELS, DEFAULT_OPERATOR_VISION_MODEL_ID, GITHUB_MODELS_VALIDATED_WORKERS, OPENAI_VALIDATED_WORKERS, RAW_FOUNDER_MODEL_OPTIONS, FOUNDER_MODEL_OPTIONS, DEFAULT_FOUNDER_MODEL_SELECTION;
84126
+ var DEFAULT_NIM_MODEL_ID, DEFAULT_FOUNDER_MODEL_OPTION_ID, ALL_MODEL_LANES, WORKER_LANES, REASONING_LANES, DEFAULT_GITHUB_GPT_41_ID, DEFAULT_GITHUB_GPT_41_MINI_ID, DEFAULT_GITHUB_GPT_4O_ID, DEFAULT_CODE_WORKER_MODEL_ID, GCP_SELF_HOSTED_OPTION_ID, DEFAULT_GCP_INFERENCE_MODEL, MODAL_SELF_HOSTED_OPTION_ID, MODAL_MIMO_OPTION_ID, DEFAULT_MODAL_INFERENCE_MODEL, HUGGINGFACE_KIMI_K25_OPTION_ID, WANDB_QWEN_36_35B_A3B_OPTION_ID, WANDB_MINIMAX_M25_OPTION_ID, WANDB_KIMI_K26_OPTION_ID, WANDB_GLM_51_OPTION_ID, WANDB_NEMOTRON_ULTRA_OPTION_ID, WANDB_DEEPSEEK_V4_FLASH_OPTION_ID, WANDB_DEEPSEEK_V4_PRO_OPTION_ID, BEDROCK_KIMI_K25_OPTION_ID, BEDROCK_GLM5_OPTION_ID, BEDROCK_QWEN3_CODER_480B_OPTION_ID, BEDROCK_GPT_OSS_120B_OPTION_ID, BEDROCK_NEMOTRON_SUPER_120B_OPTION_ID, BEDROCK_MINIMAX_M2_OPTION_ID, BEDROCK_DEEPSEEK_V32_OPTION_ID, BEDROCK_QWEN3_VL_235B_OPTION_ID, CODEX_GPT_55_OPTION_ID, CODEX_GPT_54_OPTION_ID, CODEX_GPT_54_MINI_OPTION_ID, CLAUDE_CODE_HAIKU_45_OPTION_ID, CLAUDE_CODE_SONNET_46_OPTION_ID, CLAUDE_CODE_OPUS_48_OPTION_ID, FIREWORKS_DEEPSEEK_V4_FLASH_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_PRIMARY_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_FALLBACK_OPTION_IDS, AUTO_ROUTER_EXCLUDED_BACKEND_OPTION_IDS, AI_GATEWAY_AUTO_ROUTER_OPTION_IDS, MODAL_MODELS, GCP_MODELS, HUGGINGFACE_MODELS, WANDB_MODELS, BEDROCK_MANTLE_MODELS, CODEX_OAUTH_MODELS, CLAUDE_CODE_OAUTH_MODELS, AI_GATEWAY_MODELS, OPENROUTER_MODELS, DEFAULT_OPERATOR_VISION_MODEL_ID, GITHUB_MODELS_VALIDATED_WORKERS, OPENAI_VALIDATED_WORKERS, RAW_FOUNDER_MODEL_OPTIONS, FOUNDER_MODEL_OPTIONS, DEFAULT_FOUNDER_MODEL_SELECTION;
84124
84127
  var init_modelRegistry = __esm({
84125
84128
  "features/perchTerminal/runtime/modelRegistry.ts"() {
84126
84129
  "use strict";
@@ -84166,6 +84169,18 @@ var init_modelRegistry = __esm({
84166
84169
  WANDB_KIMI_K26_OPTION_ID = "wandb-kimi-k2-6";
84167
84170
  WANDB_GLM_51_OPTION_ID = "wandb-zai-org-glm-5-1";
84168
84171
  WANDB_NEMOTRON_ULTRA_OPTION_ID = "wandb-nvidia-nvidia-nemotron-3-ultra-550b-a55b";
84172
+ WANDB_DEEPSEEK_V4_FLASH_OPTION_ID = makeModelOptionId(
84173
+ "wandb",
84174
+ "deepseek-ai/DeepSeek-V4-Flash"
84175
+ );
84176
+ WANDB_DEEPSEEK_V4_PRO_OPTION_ID = makeModelOptionId(
84177
+ "wandb",
84178
+ "deepseek-ai/DeepSeek-V4-Pro"
84179
+ );
84180
+ BEDROCK_KIMI_K25_OPTION_ID = makeModelOptionId(
84181
+ "bedrock_mantle",
84182
+ "moonshotai.kimi-k2.5"
84183
+ );
84169
84184
  BEDROCK_GLM5_OPTION_ID = makeModelOptionId("bedrock_mantle", "zai.glm-5");
84170
84185
  BEDROCK_QWEN3_CODER_480B_OPTION_ID = makeModelOptionId(
84171
84186
  "bedrock_mantle",
@@ -84230,6 +84245,9 @@ var init_modelRegistry = __esm({
84230
84245
  WANDB_KIMI_K26_OPTION_ID,
84231
84246
  WANDB_GLM_51_OPTION_ID,
84232
84247
  WANDB_NEMOTRON_ULTRA_OPTION_ID,
84248
+ WANDB_DEEPSEEK_V4_FLASH_OPTION_ID,
84249
+ WANDB_DEEPSEEK_V4_PRO_OPTION_ID,
84250
+ BEDROCK_KIMI_K25_OPTION_ID,
84233
84251
  BEDROCK_GLM5_OPTION_ID,
84234
84252
  BEDROCK_QWEN3_CODER_480B_OPTION_ID,
84235
84253
  BEDROCK_GPT_OSS_120B_OPTION_ID,
@@ -84456,9 +84474,79 @@ var init_modelRegistry = __esm({
84456
84474
  availabilityNote: "W&B Inference hosted Nemotron 3 Ultra. Text/tools use W&B; browser/image tasks use the NIM vision observer chain when selected."
84457
84475
  }),
84458
84476
  id: WANDB_NEMOTRON_ULTRA_OPTION_ID
84477
+ },
84478
+ {
84479
+ ...makeManualModelOption({
84480
+ providerId: "wandb",
84481
+ modelId: "deepseek-ai/DeepSeek-V4-Flash",
84482
+ label: "W&B \xB7 DeepSeek V4 Flash",
84483
+ providerLabel: "Weights & Biases",
84484
+ vendor: "DeepSeek",
84485
+ family: "V4 Flash",
84486
+ groupLabel: "Hosted / W&B Inference",
84487
+ contextWindow: 104e4,
84488
+ lanes: ALL_MODEL_LANES,
84489
+ reasoningSupport: "false",
84490
+ envKey: "WANDB_API_KEY",
84491
+ adapterStatus: "wired",
84492
+ modality: "chat",
84493
+ capabilities: ["code", "agentic_coding"],
84494
+ costTier: "standard",
84495
+ userFacing: true,
84496
+ manualOnly: true,
84497
+ availabilityNote: "W&B Inference hosted DeepSeek V4 Flash. Text/tools use WANDB_API_KEY; browser/image tasks use the NIM vision observer chain when the W&B DeepSeek Flash backend card is selected."
84498
+ }),
84499
+ id: WANDB_DEEPSEEK_V4_FLASH_OPTION_ID
84500
+ },
84501
+ {
84502
+ ...makeManualModelOption({
84503
+ providerId: "wandb",
84504
+ modelId: "deepseek-ai/DeepSeek-V4-Pro",
84505
+ label: "W&B \xB7 DeepSeek V4 Pro",
84506
+ providerLabel: "Weights & Biases",
84507
+ vendor: "DeepSeek",
84508
+ family: "V4 Pro",
84509
+ groupLabel: "Hosted / W&B Inference",
84510
+ contextWindow: 104e4,
84511
+ lanes: ALL_MODEL_LANES,
84512
+ reasoningSupport: "false",
84513
+ envKey: "WANDB_API_KEY",
84514
+ adapterStatus: "wired",
84515
+ modality: "chat",
84516
+ capabilities: ["code", "agentic_coding"],
84517
+ costTier: "premium",
84518
+ userFacing: true,
84519
+ manualOnly: true,
84520
+ availabilityNote: "W&B Inference hosted DeepSeek V4 Pro. Text/tools use WANDB_API_KEY; browser/image tasks use the NIM vision observer chain when the W&B DeepSeek Pro backend card is selected."
84521
+ }),
84522
+ id: WANDB_DEEPSEEK_V4_PRO_OPTION_ID
84459
84523
  }
84460
84524
  ];
84461
84525
  BEDROCK_MANTLE_MODELS = [
84526
+ {
84527
+ ...makeManualModelOption({
84528
+ providerId: "bedrock_mantle",
84529
+ modelId: "moonshotai.kimi-k2.5",
84530
+ label: "Bedrock Mantle \xB7 Kimi K2.5 Vision",
84531
+ providerLabel: "Bedrock Mantle",
84532
+ vendor: "Moonshot AI",
84533
+ family: "Kimi K2.5",
84534
+ groupLabel: "Hosted / Bedrock Mantle",
84535
+ contextWindow: 256e3,
84536
+ maxOutputTokens: 16e3,
84537
+ lanes: [...ALL_MODEL_LANES, "vision"],
84538
+ reasoningSupport: "false",
84539
+ envKey: "BEDROCK_MANTLE_API_KEY",
84540
+ adapterStatus: "wired",
84541
+ modality: "vision",
84542
+ capabilities: ["vision", "multimodal", "code", "agentic_coding"],
84543
+ costTier: "premium",
84544
+ userFacing: true,
84545
+ manualOnly: true,
84546
+ availabilityNote: "Bedrock Mantle Kimi K2.5 multimodal. Native vision on moonshotai.kimi-k2.5; uses BEDROCK_MANTLE_API_KEY and BEDROCK_MANTLE_BASE_URL if set."
84547
+ }),
84548
+ id: BEDROCK_KIMI_K25_OPTION_ID
84549
+ },
84462
84550
  {
84463
84551
  ...makeManualModelOption({
84464
84552
  providerId: "bedrock_mantle",
@@ -86736,7 +86824,6 @@ function truncateHistoryLine(value, max2) {
86736
86824
  }
86737
86825
  var init_operatorTruth = __esm({
86738
86826
  "features/perchTerminal/runtime/operatorTruth.ts"() {
86739
- "use strict";
86740
86827
  }
86741
86828
  });
86742
86829
 
@@ -116243,6 +116330,33 @@ var init_inferenceCost = __esm({
116243
116330
  outputUsdPer1k: 275e-5,
116244
116331
  cachedInputUsdPer1k: 15e-5
116245
116332
  },
116333
+ [WANDB_DEEPSEEK_V4_FLASH_OPTION_ID]: {
116334
+ modelOptionId: WANDB_DEEPSEEK_V4_FLASH_OPTION_ID,
116335
+ providerId: "wandb",
116336
+ modelId: "deepseek-ai/DeepSeek-V4-Flash",
116337
+ label: "W&B DeepSeek V4 Flash",
116338
+ inputUsdPer1k: 14e-5,
116339
+ outputUsdPer1k: 28e-5,
116340
+ cachedInputUsdPer1k: 7e-5
116341
+ },
116342
+ [WANDB_DEEPSEEK_V4_PRO_OPTION_ID]: {
116343
+ modelOptionId: WANDB_DEEPSEEK_V4_PRO_OPTION_ID,
116344
+ providerId: "wandb",
116345
+ modelId: "deepseek-ai/DeepSeek-V4-Pro",
116346
+ label: "W&B DeepSeek V4 Pro",
116347
+ inputUsdPer1k: 174e-5,
116348
+ outputUsdPer1k: 348e-5,
116349
+ cachedInputUsdPer1k: 14e-5
116350
+ },
116351
+ [BEDROCK_KIMI_K25_OPTION_ID]: {
116352
+ modelOptionId: BEDROCK_KIMI_K25_OPTION_ID,
116353
+ providerId: "bedrock_mantle",
116354
+ modelId: "moonshotai.kimi-k2.5",
116355
+ label: "Bedrock Mantle \xB7 Kimi K2.5 Vision",
116356
+ inputUsdPer1k: 6e-4,
116357
+ outputUsdPer1k: 3e-3,
116358
+ cachedInputUsdPer1k: 6e-4
116359
+ },
116246
116360
  [BEDROCK_GLM5_OPTION_ID]: {
116247
116361
  modelOptionId: BEDROCK_GLM5_OPTION_ID,
116248
116362
  providerId: "bedrock_mantle",
@@ -118544,8 +118658,15 @@ function buildBody(option, opts, model, stream, includeResponseFormat = true) {
118544
118658
  body.tool_choice = opts.toolChoice ?? "auto";
118545
118659
  }
118546
118660
  if (includeResponseFormat && opts.responseFormat) body.response_format = opts.responseFormat;
118547
- if (option.providerId === "wandb" && option.modelId.startsWith("Qwen/")) {
118548
- body.chat_template_kwargs = { enable_thinking: false };
118661
+ const reasoning = opts.reasoning;
118662
+ if (option.providerId === "wandb") {
118663
+ if (reasoning && typeof reasoning.enableThinking === "boolean") {
118664
+ body.chat_template_kwargs = { enable_thinking: reasoning.enableThinking };
118665
+ } else if (option.modelId.startsWith("Qwen/")) {
118666
+ body.chat_template_kwargs = { enable_thinking: false };
118667
+ }
118668
+ } else if (reasoning?.reasoningEffort && (option.providerId === "bedrock_mantle" || option.providerId === "cerebras")) {
118669
+ body.reasoning_effort = reasoning.reasoningEffort;
118549
118670
  }
118550
118671
  if (stream) {
118551
118672
  body.stream = true;
@@ -118992,7 +119113,98 @@ var init_autoRouter = __esm({
118992
119113
  }
118993
119114
  });
118994
119115
 
119116
+ // lib/auth/browserSession.ts
119117
+ async function syncBrowserAuthSession() {
119118
+ if (typeof window === "undefined") return null;
119119
+ const response = await fetch("/api/auth/session", SESSION_FETCH_OPTIONS);
119120
+ if (!response.ok) return null;
119121
+ const body = await response.json();
119122
+ return body.session ?? null;
119123
+ }
119124
+ var SESSION_FETCH_OPTIONS;
119125
+ var init_browserSession = __esm({
119126
+ "lib/auth/browserSession.ts"() {
119127
+ SESSION_FETCH_OPTIONS = {
119128
+ credentials: "same-origin",
119129
+ cache: "no-store"
119130
+ };
119131
+ }
119132
+ });
119133
+
119134
+ // features/perchTerminal/runtime/roost.ts
119135
+ function normalizeRoostTier(value) {
119136
+ if (value === "max") return "pro_max";
119137
+ return isRoostTier(value) ? value : null;
119138
+ }
119139
+ function normalizeRoostModelChoice(value) {
119140
+ if (value === "internal") return "internal";
119141
+ return normalizeRoostTier(value);
119142
+ }
119143
+ function isRoostTier(value) {
119144
+ return value === "standard" || value === "standard_max" || value === "pro" || value === "pro_max";
119145
+ }
119146
+ var ROOST_TIER_LABELS;
119147
+ var init_roost = __esm({
119148
+ "features/perchTerminal/runtime/roost.ts"() {
119149
+ "use strict";
119150
+ init_modelRegistry();
119151
+ ROOST_TIER_LABELS = {
119152
+ standard: "Standard",
119153
+ standard_max: "Standard Max",
119154
+ pro: "Pro",
119155
+ pro_max: "Pro Max"
119156
+ };
119157
+ }
119158
+ });
119159
+
119160
+ // features/perchTerminal/runtime/roostUserSelectionClient.ts
119161
+ function coerceSelection(raw) {
119162
+ const choice = normalizeRoostModelChoice(raw?.choice);
119163
+ return {
119164
+ choice: choice ?? DEFAULT_ROOST_USER_SELECTION.choice,
119165
+ reasoningEnabled: typeof raw?.reasoningEnabled === "boolean" ? raw.reasoningEnabled : DEFAULT_ROOST_USER_SELECTION.reasoningEnabled
119166
+ };
119167
+ }
119168
+ function peekStoredRoostUserSelection() {
119169
+ if (typeof window === "undefined") return null;
119170
+ try {
119171
+ const raw = window.localStorage.getItem(ROOST_USER_SELECTION_STORAGE_KEY);
119172
+ if (!raw) return null;
119173
+ return coerceSelection(JSON.parse(raw));
119174
+ } catch {
119175
+ return null;
119176
+ }
119177
+ }
119178
+ function setRoostUserSelectionForNode(selection) {
119179
+ nodeSelectionOverride = selection ? coerceSelection(selection) : null;
119180
+ }
119181
+ function getEffectiveRoostUserSelection() {
119182
+ if (typeof window !== "undefined") return peekStoredRoostUserSelection();
119183
+ return nodeSelectionOverride;
119184
+ }
119185
+ var ROOST_USER_SELECTION_STORAGE_KEY, DEFAULT_ROOST_USER_SELECTION, nodeSelectionOverride;
119186
+ var init_roostUserSelectionClient = __esm({
119187
+ "features/perchTerminal/runtime/roostUserSelectionClient.ts"() {
119188
+ "use strict";
119189
+ init_roost();
119190
+ ROOST_USER_SELECTION_STORAGE_KEY = "perch.roostUserSelection.v1";
119191
+ DEFAULT_ROOST_USER_SELECTION = {
119192
+ choice: "standard",
119193
+ reasoningEnabled: true
119194
+ };
119195
+ nodeSelectionOverride = null;
119196
+ }
119197
+ });
119198
+
118995
119199
  // features/perchTerminal/runtime/modelRouter.ts
119200
+ function roostUserSelectionBodyFields() {
119201
+ const selection = getEffectiveRoostUserSelection();
119202
+ if (!selection) return {};
119203
+ return {
119204
+ roostModelChoice: selection.choice,
119205
+ roostReasoning: selection.reasoningEnabled
119206
+ };
119207
+ }
118996
119208
  async function callModelRouter(_config, request, opts) {
118997
119209
  const explicitProxyUrl = resolveModelCallProxyUrl(opts?.cliServerAppUrl ?? null);
118998
119210
  if (typeof window !== "undefined") {
@@ -119019,7 +119231,8 @@ async function callModelRouter(_config, request, opts) {
119019
119231
  responseFormat: request.responseFormat,
119020
119232
  preferredModelId: opts?.preferredModelId ?? null,
119021
119233
  avoidModelIds: opts?.avoidModelIds,
119022
- attribution: opts?.attribution ?? null
119234
+ attribution: opts?.attribution ?? null,
119235
+ reasoning: opts?.reasoning ?? null
119023
119236
  };
119024
119237
  try {
119025
119238
  if (request.onChunk || request.onReasoningChunk || request.onStreamEvent) {
@@ -119145,7 +119358,8 @@ async function callModelRouterViaServer(request, opts, endpoint = "/api/perch-te
119145
119358
  raceMode: opts?.raceMode,
119146
119359
  preferredModelId: opts?.preferredModelId ?? null,
119147
119360
  avoidModelIds: opts?.avoidModelIds ?? [],
119148
- attribution: opts?.attribution ?? null
119361
+ attribution: opts?.attribution ?? null,
119362
+ ...roostUserSelectionBodyFields()
119149
119363
  });
119150
119364
  const response = await fetchModelProxyWithRetry(endpoint, {
119151
119365
  method: "POST",
@@ -119277,9 +119491,18 @@ async function callModelRouterViaServer(request, opts, endpoint = "/api/perch-te
119277
119491
  async function fetchModelProxyWithRetry(endpoint, init, options) {
119278
119492
  const maxAttempts = Math.max(1, options?.maxAttempts ?? MODEL_PROXY_MAX_ATTEMPTS);
119279
119493
  let lastError = null;
119494
+ let authSynced = false;
119280
119495
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
119281
119496
  try {
119282
119497
  const response = await fetch(endpoint, init);
119498
+ if (response.status === 401 && !authSynced && typeof globalThis.window !== "undefined") {
119499
+ authSynced = true;
119500
+ await syncBrowserAuthSession();
119501
+ options?.onRetry?.(attempt, "HTTP 401 (session sync)");
119502
+ await response.body?.cancel().catch(() => void 0);
119503
+ await waitForModelProxyRetry(attempt, init.signal);
119504
+ continue;
119505
+ }
119283
119506
  if (!isRetriableModelProxyStatus(response.status) || attempt === maxAttempts - 1) {
119284
119507
  return response;
119285
119508
  }
@@ -119413,6 +119636,8 @@ var init_modelRouter = __esm({
119413
119636
  init_modelRegistry();
119414
119637
  init_contextMeter();
119415
119638
  init_inferenceUsageRecorder();
119639
+ init_browserSession();
119640
+ init_roostUserSelectionClient();
119416
119641
  init_providerModelStep();
119417
119642
  init_toolCallNormalizer();
119418
119643
  MODEL_CALL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
@@ -119432,7 +119657,7 @@ var init_accountHelpers = __esm({
119432
119657
 
119433
119658
  // features/perchTerminal/runtime/fireworksDeepSeekPreset.ts
119434
119659
  function usesNimVisionObserverPreset(selection) {
119435
- return selection?.modelBackendPreset === "fireworks_deepseek" || selection?.modelBackendPreset === "wandb_minimax" || selection?.modelBackendPreset === "wandb_glm51" || selection?.modelBackendPreset === "wandb_nemotron_ultra" || selection?.modelBackendPreset === "bedrock_glm5" || selection?.modelBackendPreset === "bedrock_qwen3_coder" || selection?.modelBackendPreset === "bedrock_gpt_oss_120b" || selection?.modelBackendPreset === "bedrock_nemotron_super" || selection?.modelBackendPreset === "bedrock_minimax_m2" || selection?.modelBackendPreset === "bedrock_deepseek_v32";
119660
+ return selection?.modelBackendPreset === "fireworks_deepseek" || selection?.modelBackendPreset === "wandb_minimax" || selection?.modelBackendPreset === "wandb_glm51" || selection?.modelBackendPreset === "wandb_nemotron_ultra" || selection?.modelBackendPreset === "wandb_deepseek_flash" || selection?.modelBackendPreset === "wandb_deepseek_pro" || selection?.modelBackendPreset === "bedrock_glm5" || selection?.modelBackendPreset === "bedrock_qwen3_coder" || selection?.modelBackendPreset === "bedrock_gpt_oss_120b" || selection?.modelBackendPreset === "bedrock_nemotron_super" || selection?.modelBackendPreset === "bedrock_minimax_m2" || selection?.modelBackendPreset === "bedrock_deepseek_v32";
119436
119661
  }
119437
119662
  function resolveVisionOptionChain(selection) {
119438
119663
  const chain2 = [];
@@ -138907,6 +139132,7 @@ function offSandboxEvent(runId, handler) {
138907
139132
  var LOCAL_WORKSPACE_ACCESS_UNAVAILABLE;
138908
139133
  var init_bridge = __esm({
138909
139134
  "features/perchTerminal/desktop/bridge.ts"() {
139135
+ "use strict";
138910
139136
  LOCAL_WORKSPACE_ACCESS_UNAVAILABLE = "Local workspace access is unavailable. Open Perch Desktop or update the app.";
138911
139137
  }
138912
139138
  });
@@ -223449,6 +223675,12 @@ var init_usageCommand = __esm({
223449
223675
  }
223450
223676
  });
223451
223677
 
223678
+ // lib/perch-ai/entitlements.ts
223679
+ var init_entitlements = __esm({
223680
+ "lib/perch-ai/entitlements.ts"() {
223681
+ }
223682
+ });
223683
+
223452
223684
  // lib/perch-ai/access.ts
223453
223685
  function hasPrivilegedPerchAiRole(memberships) {
223454
223686
  return memberships.some(
@@ -223466,6 +223698,296 @@ function canShowPerchDevTools(membershipRole) {
223466
223698
  }
223467
223699
  var init_access = __esm({
223468
223700
  "lib/perch-ai/access.ts"() {
223701
+ init_entitlements();
223702
+ }
223703
+ });
223704
+
223705
+ // lib/perch-ai/perchTokens.ts
223706
+ function usdToPerchTokens(usd) {
223707
+ if (typeof usd !== "number" || !Number.isFinite(usd) || usd <= 0) return 0;
223708
+ return Math.ceil(usd / PERCH_TOKEN_USD);
223709
+ }
223710
+ function nullableUsdToPerchTokens(usd) {
223711
+ const tokens = usdToPerchTokens(usd);
223712
+ return tokens > 0 ? tokens : null;
223713
+ }
223714
+ function usdLimitToPerchTokens(usd) {
223715
+ if (!Number.isFinite(usd) || usd <= 0) return 0;
223716
+ return Math.round(usd / PERCH_TOKEN_USD);
223717
+ }
223718
+ var PERCH_TOKEN_USD, DEFAULT_PILOT_DAILY_LIMIT_USD, DEFAULT_PILOT_MONTHLY_LIMIT_USD;
223719
+ var init_perchTokens = __esm({
223720
+ "lib/perch-ai/perchTokens.ts"() {
223721
+ PERCH_TOKEN_USD = 1e-3;
223722
+ DEFAULT_PILOT_DAILY_LIMIT_USD = 5;
223723
+ DEFAULT_PILOT_MONTHLY_LIMIT_USD = DEFAULT_PILOT_DAILY_LIMIT_USD * 30;
223724
+ }
223725
+ });
223726
+
223727
+ // features/perchTerminal/persistence/usagePersistence.ts
223728
+ function startOfLocalDay() {
223729
+ const date = /* @__PURE__ */ new Date();
223730
+ date.setHours(0, 0, 0, 0);
223731
+ return date.toISOString();
223732
+ }
223733
+ function startOfRollingWeek() {
223734
+ const date = /* @__PURE__ */ new Date();
223735
+ date.setDate(date.getDate() - 7);
223736
+ return date.toISOString();
223737
+ }
223738
+ function startOfLocalMonth() {
223739
+ const date = /* @__PURE__ */ new Date();
223740
+ date.setDate(1);
223741
+ date.setHours(0, 0, 0, 0);
223742
+ return date.toISOString();
223743
+ }
223744
+ function sumPt(rows, since) {
223745
+ const total = rows.filter((row) => Date.parse(row.created_at) >= Date.parse(since)).reduce((sum, row) => sum + row.total_pt, 0);
223746
+ return total > 0 ? total : null;
223747
+ }
223748
+ function filterInferenceRows(rows, since) {
223749
+ return rows.filter((row) => Date.parse(row.created_at) >= Date.parse(since));
223750
+ }
223751
+ function sumInferenceCost(rows, since) {
223752
+ const total = filterInferenceRows(rows, since).reduce(
223753
+ (sum, row) => sum + Number(row.estimated_cost_usd ?? 0),
223754
+ 0
223755
+ );
223756
+ return total > 0 ? total : null;
223757
+ }
223758
+ function sumInferenceTokens(rows, since) {
223759
+ const total = filterInferenceRows(rows, since).reduce(
223760
+ (sum, row) => sum + Number(row.total_tokens ?? 0),
223761
+ 0
223762
+ );
223763
+ return total > 0 ? total : null;
223764
+ }
223765
+ function countInferenceCalls(rows, since) {
223766
+ const total = filterInferenceRows(rows, since).length;
223767
+ return total > 0 ? total : null;
223768
+ }
223769
+ function createUsagePersistence(supabase) {
223770
+ return {
223771
+ async listRateCards() {
223772
+ const { data, error } = await supabase.from("perch_ai_token_rate_cards").select("*").order("created_at", { ascending: false });
223773
+ if (error) throw error;
223774
+ return data ?? [];
223775
+ },
223776
+ async listUsageRawEvents({
223777
+ userId,
223778
+ workspaceId,
223779
+ limit = 50
223780
+ }) {
223781
+ const { data, error } = await supabase.from("perch_ai_usage_raw_events").select("*").eq("user_id", userId).eq("workspace_id", workspaceId).order("created_at", { ascending: false }).limit(limit);
223782
+ if (error) throw error;
223783
+ return data ?? [];
223784
+ },
223785
+ async listTokenCalculations({
223786
+ userId,
223787
+ workspaceId,
223788
+ since,
223789
+ limit = 250
223790
+ }) {
223791
+ let query = supabase.from("perch_ai_token_calculations").select("*").eq("user_id", userId).eq("workspace_id", workspaceId).order("created_at", { ascending: false }).limit(limit);
223792
+ if (since) query = query.gte("created_at", since);
223793
+ const { data, error } = await query;
223794
+ if (error) throw error;
223795
+ return data ?? [];
223796
+ },
223797
+ async listInferenceUsageRows({
223798
+ userId,
223799
+ workspaceId,
223800
+ since,
223801
+ limit = 250
223802
+ }) {
223803
+ let query = supabase.from("perch_ai_inference_usage").select("*").eq("user_id", userId).eq("workspace_id", workspaceId).order("created_at", { ascending: false }).limit(limit);
223804
+ if (since) query = query.gte("created_at", since);
223805
+ const { data, error } = await query;
223806
+ if (error) throw error;
223807
+ return data ?? [];
223808
+ },
223809
+ async getUsageMeter({
223810
+ userId,
223811
+ workspaceId
223812
+ }) {
223813
+ const localDay = startOfLocalDay();
223814
+ const rollingWeek = startOfRollingWeek();
223815
+ const localMonth = startOfLocalMonth();
223816
+ const [rows, inferenceRows] = await Promise.all([
223817
+ this.listTokenCalculations({
223818
+ userId,
223819
+ workspaceId,
223820
+ since: localMonth,
223821
+ limit: 5e3
223822
+ }),
223823
+ this.listInferenceUsageRows({
223824
+ userId,
223825
+ workspaceId,
223826
+ since: localMonth,
223827
+ limit: 5e3
223828
+ })
223829
+ ]);
223830
+ const dailyUsd = sumInferenceCost(inferenceRows, localDay);
223831
+ const weeklyUsd = sumInferenceCost(inferenceRows, rollingWeek);
223832
+ const monthlyUsd = sumInferenceCost(inferenceRows, localMonth);
223833
+ return {
223834
+ dailyPt: nullableUsdToPerchTokens(dailyUsd) ?? sumPt(rows, localDay),
223835
+ weeklyPt: nullableUsdToPerchTokens(weeklyUsd) ?? sumPt(rows, rollingWeek),
223836
+ rows,
223837
+ dailyUsd,
223838
+ weeklyUsd,
223839
+ monthlyUsd,
223840
+ dailyTokens: sumInferenceTokens(inferenceRows, localDay),
223841
+ weeklyTokens: sumInferenceTokens(inferenceRows, rollingWeek),
223842
+ monthlyTokens: sumInferenceTokens(inferenceRows, localMonth),
223843
+ dailyCalls: countInferenceCalls(inferenceRows, localDay),
223844
+ weeklyCalls: countInferenceCalls(inferenceRows, rollingWeek),
223845
+ monthlyCalls: countInferenceCalls(inferenceRows, localMonth),
223846
+ inferenceRows
223847
+ };
223848
+ }
223849
+ };
223850
+ }
223851
+ var init_usagePersistence = __esm({
223852
+ "features/perchTerminal/persistence/usagePersistence.ts"() {
223853
+ init_perchTokens();
223854
+ }
223855
+ });
223856
+
223857
+ // features/perchTerminal/runtime/usage/usageAllowance.ts
223858
+ function readEntitlementNumber(value) {
223859
+ if (typeof value === "number" && Number.isFinite(value)) return value;
223860
+ if (typeof value === "string") {
223861
+ const parsed = Number(value);
223862
+ return Number.isFinite(parsed) ? parsed : null;
223863
+ }
223864
+ if (value && typeof value === "object") {
223865
+ const record = value;
223866
+ return readEntitlementNumber(record.usd) ?? readEntitlementNumber(record.amount) ?? readEntitlementNumber(record.value) ?? readEntitlementNumber(record.limit);
223867
+ }
223868
+ return null;
223869
+ }
223870
+ function readLimitUsd(entitlements, keys2, fallback) {
223871
+ for (const key of keys2) {
223872
+ const match = entitlements.find((entitlement) => entitlement.key === key);
223873
+ const value = match ? readEntitlementNumber(match.value_json) : null;
223874
+ if (value != null && value > 0) return value;
223875
+ }
223876
+ return fallback;
223877
+ }
223878
+ function isUnlimitedUsageSession(session) {
223879
+ if (!session) return false;
223880
+ return session.membershipRole === "admin" || session.membershipRole === "internal" || session.planCode === "internal";
223881
+ }
223882
+ function buildUsageAllowanceSnapshot(session, meter) {
223883
+ const unlimited = isUnlimitedUsageSession(session);
223884
+ const entitlements = session.entitlements ?? [];
223885
+ const dailyLimitUsd = readLimitUsd(
223886
+ entitlements,
223887
+ ["usage_daily_usd", "daily_usage_usd", "pilot_daily_usd", "user_daily_cap_usd"],
223888
+ DEFAULT_PILOT_DAILY_LIMIT_USD
223889
+ );
223890
+ const monthlyLimitUsd = readLimitUsd(
223891
+ entitlements,
223892
+ ["usage_monthly_usd", "monthly_usage_usd", "pilot_monthly_usd", "user_monthly_cap_usd"],
223893
+ DEFAULT_PILOT_MONTHLY_LIMIT_USD
223894
+ );
223895
+ return {
223896
+ unlimited,
223897
+ planLabel: session.planName ?? session.planCode ?? "Pilot",
223898
+ dailyUsedPt: meter?.dailyPt ?? usdToPerchTokens(meter?.dailyUsd),
223899
+ weeklyUsedPt: meter?.weeklyPt ?? usdToPerchTokens(meter?.weeklyUsd),
223900
+ monthlyUsedPt: usdToPerchTokens(meter?.monthlyUsd),
223901
+ dailyLimitPt: usdLimitToPerchTokens(dailyLimitUsd),
223902
+ monthlyLimitPt: usdLimitToPerchTokens(monthlyLimitUsd),
223903
+ dailyCalls: meter?.dailyCalls ?? null,
223904
+ weeklyCalls: meter?.weeklyCalls ?? null,
223905
+ monthlyCalls: meter?.monthlyCalls ?? null,
223906
+ dailyTokens: meter?.dailyTokens ?? null,
223907
+ weeklyTokens: meter?.weeklyTokens ?? null,
223908
+ monthlyTokens: meter?.monthlyTokens ?? null
223909
+ };
223910
+ }
223911
+ function formatInteger(value) {
223912
+ return Math.max(0, Math.round(value ?? 0)).toLocaleString("en-US");
223913
+ }
223914
+ function formatPt(value) {
223915
+ return `${formatInteger(value)} PT`;
223916
+ }
223917
+ function percentUsed(used, limit) {
223918
+ if (limit <= 0) return 0;
223919
+ return Math.max(0, Math.min(used / limit * 100, 100));
223920
+ }
223921
+ function renderTextBar(percent2, width = 24) {
223922
+ const clamped = Math.max(0, Math.min(100, percent2));
223923
+ const filled = Math.round(clamped / 100 * width);
223924
+ return `${"\u2588".repeat(filled)}${"\u2591".repeat(Math.max(0, width - filled))}`;
223925
+ }
223926
+ function formatAllowanceLine(label, usedPt, limitPt, unlimited) {
223927
+ const bar = renderTextBar(unlimited ? 100 : percentUsed(usedPt, limitPt));
223928
+ const amount = unlimited ? `${formatPt(usedPt)} / Unlimited` : `${formatPt(usedPt)} / ${formatPt(limitPt)} \xB7 ${Math.round(percentUsed(usedPt, limitPt))}%`;
223929
+ return `- ${label.padEnd(10)} ${bar} ${amount}`;
223930
+ }
223931
+ function formatUsageAllowanceText(allowance) {
223932
+ const allowanceLabel = allowance.unlimited ? `${allowance.planLabel} \xB7 unlimited allowance` : `${allowance.planLabel} \xB7 ${formatPt(allowance.dailyLimitPt)} daily allowance`;
223933
+ const lines = [
223934
+ "Perch Tokens",
223935
+ `- Plan: ${allowanceLabel}`,
223936
+ formatAllowanceLine("Today", allowance.dailyUsedPt, allowance.dailyLimitPt, allowance.unlimited),
223937
+ formatAllowanceLine("Month", allowance.monthlyUsedPt, allowance.monthlyLimitPt, allowance.unlimited),
223938
+ `- Activity ${formatInteger(allowance.monthlyCalls)} chats this month \xB7 ${formatPt(allowance.weeklyUsedPt)} in 7 days \xB7 ${formatInteger(allowance.weeklyTokens)} model tokens`
223939
+ ];
223940
+ return lines.join("\n");
223941
+ }
223942
+ async function fetchUsageAllowanceFromServer(input) {
223943
+ const appUrl = input.cliServerAppUrl?.trim();
223944
+ const token = input.cliServerAccessToken?.trim();
223945
+ if (!appUrl || !token || typeof fetch !== "function") return null;
223946
+ const controller = new AbortController();
223947
+ const timeout = setTimeout(() => controller.abort(), 5e3);
223948
+ try {
223949
+ const response = await fetch(`${appUrl.replace(/\/+$/, "")}/api/perchai/account`, {
223950
+ method: "GET",
223951
+ headers: {
223952
+ Accept: "application/json",
223953
+ Authorization: `Bearer ${token}`
223954
+ },
223955
+ signal: controller.signal
223956
+ });
223957
+ if (!response.ok) return null;
223958
+ const payload = await response.json();
223959
+ if (!payload.ok || !payload.session) return null;
223960
+ return buildUsageAllowanceSnapshot(payload.session, payload.usageMeter ?? null);
223961
+ } catch {
223962
+ return null;
223963
+ } finally {
223964
+ clearTimeout(timeout);
223965
+ }
223966
+ }
223967
+ async function resolveUsageAllowance(input) {
223968
+ if (input.supabase && input.userId && input.workspaceId) {
223969
+ try {
223970
+ const meter = await createUsagePersistence(input.supabase).getUsageMeter({
223971
+ userId: input.userId,
223972
+ workspaceId: input.workspaceId
223973
+ });
223974
+ return buildUsageAllowanceSnapshot(input.sessionContext, meter);
223975
+ } catch {
223976
+ return null;
223977
+ }
223978
+ }
223979
+ const viaServer = await fetchUsageAllowanceFromServer(input);
223980
+ if (viaServer) return viaServer;
223981
+ if (input.userId && input.workspaceId) {
223982
+ return buildUsageAllowanceSnapshot(input.sessionContext, null);
223983
+ }
223984
+ return null;
223985
+ }
223986
+ var init_usageAllowance = __esm({
223987
+ "features/perchTerminal/runtime/usage/usageAllowance.ts"() {
223988
+ "use strict";
223989
+ init_usagePersistence();
223990
+ init_perchTokens();
223469
223991
  }
223470
223992
  });
223471
223993
 
@@ -223515,10 +224037,14 @@ function summarizeInferenceUsageRows(rows, options = {}) {
223515
224037
  return summary;
223516
224038
  }
223517
224039
  function formatUsageSummaryText(summary) {
224040
+ const sections = [];
224041
+ if (summary.allowance) {
224042
+ sections.push(formatUsageAllowanceText(summary.allowance));
224043
+ }
223518
224044
  const lines = [
223519
224045
  "Usage this session",
223520
- `- Calls: ${formatInteger(summary.calls)}`,
223521
- `- Tokens: ${formatInteger(summary.totalTokens)} total (${formatInteger(summary.promptTokens)} input \xB7 ${formatInteger(summary.completionTokens)} output${summary.cachedTokens ? ` \xB7 ${formatInteger(summary.cachedTokens)} cached` : ""})`,
224046
+ `- Calls: ${formatInteger2(summary.calls)}`,
224047
+ `- Tokens: ${formatInteger2(summary.totalTokens)} total (${formatInteger2(summary.promptTokens)} input \xB7 ${formatInteger2(summary.completionTokens)} output${summary.cachedTokens ? ` \xB7 ${formatInteger2(summary.cachedTokens)} cached` : ""})`,
223522
224048
  `- Estimated cost: ${formatUsd(summary.estimatedCostUsd)}`
223523
224049
  ];
223524
224050
  if (summary.calls === 0) {
@@ -223528,11 +224054,12 @@ function formatUsageSummaryText(summary) {
223528
224054
  lines.push("", "Internal detail:");
223529
224055
  for (const row of summary.modelBreakdown.slice(0, 8)) {
223530
224056
  lines.push(
223531
- `- ${row.label}: ${formatInteger(row.totalTokens)} tokens \xB7 ${formatUsd(row.estimatedCostUsd)} \xB7 ${formatInteger(row.calls)} calls`
224057
+ `- ${row.label}: ${formatInteger2(row.totalTokens)} tokens \xB7 ${formatUsd(row.estimatedCostUsd)} \xB7 ${formatInteger2(row.calls)} calls`
223532
224058
  );
223533
224059
  }
223534
224060
  }
223535
- return lines.join("\n");
224061
+ sections.push(lines.join("\n"));
224062
+ return sections.join("\n\n");
223536
224063
  }
223537
224064
  function buildModelBreakdown(rows) {
223538
224065
  const byModel = /* @__PURE__ */ new Map();
@@ -223568,7 +224095,7 @@ function readNumber(value) {
223568
224095
  }
223569
224096
  return 0;
223570
224097
  }
223571
- function formatInteger(value) {
224098
+ function formatInteger2(value) {
223572
224099
  return Math.max(0, Math.round(value)).toLocaleString("en-US");
223573
224100
  }
223574
224101
  function formatUsd(value) {
@@ -223578,6 +224105,7 @@ function formatUsd(value) {
223578
224105
  var init_usageSummary = __esm({
223579
224106
  "features/perchTerminal/runtime/usage/usageSummary.ts"() {
223580
224107
  "use strict";
224108
+ init_usageAllowance();
223581
224109
  }
223582
224110
  });
223583
224111
 
@@ -223610,7 +224138,11 @@ async function runUsageTurn(input, deps) {
223610
224138
  recentMessages: input.recentMessages
223611
224139
  });
223612
224140
  const showModelDetails = canShowPerchDevTools(input.sessionContext.membershipRole);
223613
- const summary = await resolveUsageSummary(input, runIds, showModelDetails);
224141
+ const [summary, allowance] = await Promise.all([
224142
+ resolveUsageSummary(input, runIds, showModelDetails),
224143
+ resolveUsageAllowance(input)
224144
+ ]);
224145
+ summary.allowance = allowance;
223614
224146
  const assistantText = formatUsageSummaryText(summary);
223615
224147
  let assistantMessageId = null;
223616
224148
  if (input.workspaceId) {
@@ -223695,6 +224227,7 @@ var init_runUsageTurn = __esm({
223695
224227
  "features/perchTerminal/runtime/usage/runUsageTurn.ts"() {
223696
224228
  "use strict";
223697
224229
  init_access();
224230
+ init_usageAllowance();
223698
224231
  init_usageSummary();
223699
224232
  }
223700
224233
  });
@@ -225085,10 +225618,7 @@ async function runLiveAgentsLoop(input) {
225085
225618
  const { turn, deps, runId, onEvent } = input;
225086
225619
  try {
225087
225620
  const loopLane = "chat";
225088
- const selectedChatModel = resolveModelForLane(
225089
- turn.founderModelSelection,
225090
- loopLane
225091
- );
225621
+ const selectedChatModel = turn.activeContextModel ?? resolveModelForLane(turn.founderModelSelection, loopLane);
225092
225622
  const context = input.assembledContext;
225093
225623
  if (!context) {
225094
225624
  return {
@@ -230380,6 +230910,7 @@ async function runOperatorTurn(input, deps) {
230380
230910
  });
230381
230911
  try {
230382
230912
  const memoryRetriever = buildTurnMemoryRetriever(input);
230913
+ const inputContextModel = input.activeContextModel ?? null;
230383
230914
  const memoryContext = await buildMemoryContext({
230384
230915
  query: input.trimmedInput,
230385
230916
  userId: input.userId ?? (memoryRetriever && input.cliServerAccessToken?.trim() ? "cli_authenticated_user" : null),
@@ -230387,7 +230918,8 @@ async function runOperatorTurn(input, deps) {
230387
230918
  threadId: input.threadId,
230388
230919
  permanentMemories: input.permanentMemories,
230389
230920
  userMemories: input.userMemories,
230390
- retriever: memoryRetriever
230921
+ retriever: memoryRetriever,
230922
+ contextLimitTokens: inputContextModel ? getEffectiveContextWindow(inputContextModel) : void 0
230391
230923
  });
230392
230924
  const earlySession = input.threadId ? await loadThreadSession(input.threadId, { supabase: input.supabase ?? null }) : null;
230393
230925
  const {
@@ -230403,10 +230935,7 @@ async function runOperatorTurn(input, deps) {
230403
230935
  memoryContext,
230404
230936
  isSystemNotification
230405
230937
  });
230406
- const chatSelectedModelOption = resolveModelForLane(
230407
- enrichedInput.founderModelSelection,
230408
- "chat"
230409
- );
230938
+ const chatSelectedModelOption = enrichedInput.activeContextModel ?? resolveModelForLane(enrichedInput.founderModelSelection, "chat");
230410
230939
  const sources = await prepareTurnSources({ enrichedInput, deps });
230411
230940
  const toolDefinitions = prepareTurnToolDefinitions({
230412
230941
  enrichedInput,
@@ -230545,6 +231074,7 @@ var init_runOperatorTurn = __esm({
230545
231074
  init_liveAgentsLoop();
230546
231075
  init_turnAbort();
230547
231076
  init_modelRegistry();
231077
+ init_contextThresholds();
230548
231078
  init_threadSession();
230549
231079
  init_turnMemoryRetriever();
230550
231080
  init_turnBootstrap();
@@ -233519,111 +234049,6 @@ var init_cliAuthSession = __esm({
233519
234049
  }
233520
234050
  });
233521
234051
 
233522
- // features/perchTerminal/runtime/cliHost/modelConnection.ts
233523
- async function connectCliModelProxy(input = {}) {
233524
- const storedSession = input.storedSession === void 0 ? await readStoredCliAuthSession() : input.storedSession;
233525
- const usableStoredSession = isStoredCliAuthSessionUsable(storedSession) ? storedSession : null;
233526
- const appUrl = resolveCliAppUrl(input.appUrl, usableStoredSession?.appUrl ?? null);
233527
- if (!appUrl) return noCliModelConnection();
233528
- if (!usableStoredSession?.accessToken) return noCliModelConnection(appUrl);
233529
- const fetchImpl = input.fetchImpl ?? globalThis.fetch;
233530
- if (typeof fetchImpl !== "function") return noCliModelConnection(appUrl);
233531
- const selection = await fetchPublicModelDefaultSelection(
233532
- appUrl,
233533
- fetchImpl,
233534
- usableStoredSession?.accessToken ?? null
233535
- );
233536
- if (!selection) return noCliModelConnection(appUrl);
233537
- const priorProxy = process.env[MODEL_PROXY_ENV];
233538
- const priorToken = process.env[MODEL_PROXY_TOKEN_ENV];
233539
- process.env[MODEL_PROXY_ENV] = appUrl;
233540
- if (usableStoredSession?.accessToken) {
233541
- process.env[MODEL_PROXY_TOKEN_ENV] = usableStoredSession.accessToken;
233542
- }
233543
- return {
233544
- appUrl,
233545
- authenticated: !!usableStoredSession?.accessToken,
233546
- userId: usableStoredSession?.userId ?? null,
233547
- email: usableStoredSession?.email ?? null,
233548
- founderModelSelection: selection,
233549
- restore: () => {
233550
- if (priorProxy === void 0) {
233551
- delete process.env[MODEL_PROXY_ENV];
233552
- } else {
233553
- process.env[MODEL_PROXY_ENV] = priorProxy;
233554
- }
233555
- if (priorToken === void 0) {
233556
- delete process.env[MODEL_PROXY_TOKEN_ENV];
233557
- } else {
233558
- process.env[MODEL_PROXY_TOKEN_ENV] = priorToken;
233559
- }
233560
- }
233561
- };
233562
- }
233563
- function resolveCliAppUrl(explicit, stored) {
233564
- const raw = explicit?.trim() || process.env[CLI_APP_URL_ENV]?.trim() || process.env[FALLBACK_APP_URL_ENV]?.trim() || stored?.trim() || DEFAULT_CLI_APP_URL;
233565
- if (!raw) return null;
233566
- const withProtocol = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
233567
- try {
233568
- const url = new URL(withProtocol);
233569
- url.pathname = url.pathname.replace(/\/+$/, "");
233570
- url.search = "";
233571
- url.hash = "";
233572
- return url.toString().replace(/\/+$/, "");
233573
- } catch {
233574
- return null;
233575
- }
233576
- }
233577
- async function fetchPublicModelDefaultSelection(appUrl, fetchImpl, accessToken) {
233578
- const url = `${appUrl}/api/perch-terminal/public-model-default`;
233579
- const controller = new AbortController();
233580
- const timeout = setTimeout(() => controller.abort(), 3500);
233581
- try {
233582
- const response = await fetchImpl(url, {
233583
- method: "GET",
233584
- headers: {
233585
- Accept: "application/json",
233586
- ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
233587
- },
233588
- signal: controller.signal
233589
- });
233590
- if (!response.ok) return null;
233591
- const body = await response.json();
233592
- if (!body || typeof body !== "object") return null;
233593
- const record = body;
233594
- if (record.ok !== true) return null;
233595
- return parsePublicModelDefaultPayload({ selection: record.selection }).selection;
233596
- } catch {
233597
- return null;
233598
- } finally {
233599
- clearTimeout(timeout);
233600
- }
233601
- }
233602
- function noCliModelConnection(appUrl = null) {
233603
- return {
233604
- appUrl,
233605
- authenticated: false,
233606
- userId: null,
233607
- email: null,
233608
- founderModelSelection: null,
233609
- restore: () => {
233610
- }
233611
- };
233612
- }
233613
- var MODEL_PROXY_ENV, MODEL_PROXY_TOKEN_ENV, CLI_APP_URL_ENV, FALLBACK_APP_URL_ENV, DEFAULT_CLI_APP_URL;
233614
- var init_modelConnection = __esm({
233615
- "features/perchTerminal/runtime/cliHost/modelConnection.ts"() {
233616
- "use strict";
233617
- init_publicModelDefault();
233618
- init_cliAuthSession();
233619
- MODEL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
233620
- MODEL_PROXY_TOKEN_ENV = "PERCH_MODEL_CALL_PROXY_TOKEN";
233621
- CLI_APP_URL_ENV = "PERCH_CLI_APP_URL";
233622
- FALLBACK_APP_URL_ENV = "PERCH_APP_URL";
233623
- DEFAULT_CLI_APP_URL = "https://app.perchai.app";
233624
- }
233625
- });
233626
-
233627
234052
  // features/perchTerminal/runtime/cliHost/cliStandaloneOAuth.ts
233628
234053
  import { execFile as execFile2 } from "node:child_process";
233629
234054
  import http from "node:http";
@@ -233672,7 +234097,8 @@ async function runCliStandaloneOAuthLogin(input) {
233672
234097
  provider,
233673
234098
  options: {
233674
234099
  redirectTo: callback.redirectTo,
233675
- skipBrowserRedirect: true
234100
+ skipBrowserRedirect: true,
234101
+ data: { signup_source: "cli" }
233676
234102
  }
233677
234103
  });
233678
234104
  if (error || !data.url) {
@@ -233831,6 +234257,166 @@ var init_cliStandaloneOAuth = __esm({
233831
234257
  }
233832
234258
  });
233833
234259
 
234260
+ // features/perchTerminal/runtime/cliHost/cliAuthRefresh.ts
234261
+ async function ensureFreshCliAuthSession(input) {
234262
+ const session = input.session;
234263
+ if (!session?.accessToken?.trim()) return null;
234264
+ const nowSeconds = Math.floor(Date.now() / 1e3);
234265
+ const stillUsable = !session.expiresAt || session.expiresAt > nowSeconds + 90;
234266
+ if (stillUsable) return session;
234267
+ if (!session.refreshToken?.trim()) return null;
234268
+ const fetchImpl = input.fetchImpl ?? globalThis.fetch;
234269
+ if (typeof fetchImpl !== "function") return null;
234270
+ const appUrl = session.appUrl?.trim();
234271
+ if (!appUrl) return null;
234272
+ const config = await fetchCliAuthConfig(appUrl, fetchImpl).catch(() => ({ ok: false }));
234273
+ if (!config.ok || !config.supabaseUrl || !config.supabaseAnonKey) return null;
234274
+ const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey, {
234275
+ auth: {
234276
+ autoRefreshToken: false,
234277
+ detectSessionInUrl: false,
234278
+ persistSession: false
234279
+ }
234280
+ });
234281
+ try {
234282
+ const { data, error } = await supabase.auth.refreshSession({
234283
+ refresh_token: session.refreshToken
234284
+ });
234285
+ if (error || !data.session) return null;
234286
+ const refreshed = {
234287
+ version: 1,
234288
+ appUrl: session.appUrl,
234289
+ accessToken: data.session.access_token,
234290
+ refreshToken: data.session.refresh_token ?? session.refreshToken,
234291
+ expiresAt: data.session.expires_at ?? null,
234292
+ userId: data.session.user?.id ?? session.userId ?? null,
234293
+ email: data.session.user?.email ?? session.email ?? null,
234294
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
234295
+ };
234296
+ await writeStoredCliAuthSession(refreshed);
234297
+ return refreshed;
234298
+ } catch {
234299
+ return null;
234300
+ }
234301
+ }
234302
+ var init_cliAuthRefresh = __esm({
234303
+ "features/perchTerminal/runtime/cliHost/cliAuthRefresh.ts"() {
234304
+ "use strict";
234305
+ init_dist4();
234306
+ init_cliStandaloneOAuth();
234307
+ init_cliAuthSession();
234308
+ }
234309
+ });
234310
+
234311
+ // features/perchTerminal/runtime/cliHost/modelConnection.ts
234312
+ async function connectCliModelProxy(input = {}) {
234313
+ const storedSession = input.storedSession === void 0 ? await readStoredCliAuthSession() : input.storedSession;
234314
+ const usableStoredSession = await ensureFreshCliAuthSession({
234315
+ session: storedSession,
234316
+ fetchImpl: input.fetchImpl
234317
+ });
234318
+ const appUrl = resolveCliAppUrl(input.appUrl, usableStoredSession?.appUrl ?? null);
234319
+ if (!appUrl) return noCliModelConnection();
234320
+ if (!usableStoredSession?.accessToken) return noCliModelConnection(appUrl);
234321
+ const fetchImpl = input.fetchImpl ?? globalThis.fetch;
234322
+ if (typeof fetchImpl !== "function") return noCliModelConnection(appUrl);
234323
+ const selection = await fetchPublicModelDefaultSelection(
234324
+ appUrl,
234325
+ fetchImpl,
234326
+ usableStoredSession?.accessToken ?? null
234327
+ );
234328
+ if (!selection) return noCliModelConnection(appUrl);
234329
+ const priorProxy = process.env[MODEL_PROXY_ENV];
234330
+ const priorToken = process.env[MODEL_PROXY_TOKEN_ENV];
234331
+ process.env[MODEL_PROXY_ENV] = appUrl;
234332
+ if (usableStoredSession?.accessToken) {
234333
+ process.env[MODEL_PROXY_TOKEN_ENV] = usableStoredSession.accessToken;
234334
+ }
234335
+ return {
234336
+ appUrl,
234337
+ authenticated: !!usableStoredSession?.accessToken,
234338
+ userId: usableStoredSession?.userId ?? null,
234339
+ email: usableStoredSession?.email ?? null,
234340
+ founderModelSelection: selection,
234341
+ restore: () => {
234342
+ if (priorProxy === void 0) {
234343
+ delete process.env[MODEL_PROXY_ENV];
234344
+ } else {
234345
+ process.env[MODEL_PROXY_ENV] = priorProxy;
234346
+ }
234347
+ if (priorToken === void 0) {
234348
+ delete process.env[MODEL_PROXY_TOKEN_ENV];
234349
+ } else {
234350
+ process.env[MODEL_PROXY_TOKEN_ENV] = priorToken;
234351
+ }
234352
+ }
234353
+ };
234354
+ }
234355
+ function resolveCliAppUrl(explicit, stored) {
234356
+ const raw = explicit?.trim() || process.env[CLI_APP_URL_ENV]?.trim() || process.env[FALLBACK_APP_URL_ENV]?.trim() || stored?.trim() || DEFAULT_CLI_APP_URL;
234357
+ if (!raw) return null;
234358
+ const withProtocol = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
234359
+ try {
234360
+ const url = new URL(withProtocol);
234361
+ url.pathname = url.pathname.replace(/\/+$/, "");
234362
+ url.search = "";
234363
+ url.hash = "";
234364
+ return url.toString().replace(/\/+$/, "");
234365
+ } catch {
234366
+ return null;
234367
+ }
234368
+ }
234369
+ async function fetchPublicModelDefaultSelection(appUrl, fetchImpl, accessToken) {
234370
+ const url = `${appUrl}/api/perch-terminal/public-model-default`;
234371
+ const controller = new AbortController();
234372
+ const timeout = setTimeout(() => controller.abort(), 3500);
234373
+ try {
234374
+ const response = await fetchImpl(url, {
234375
+ method: "GET",
234376
+ headers: {
234377
+ Accept: "application/json",
234378
+ ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
234379
+ },
234380
+ signal: controller.signal
234381
+ });
234382
+ if (!response.ok) return null;
234383
+ const body = await response.json();
234384
+ if (!body || typeof body !== "object") return null;
234385
+ const record = body;
234386
+ if (record.ok !== true) return null;
234387
+ return parsePublicModelDefaultPayload({ selection: record.selection }).selection;
234388
+ } catch {
234389
+ return null;
234390
+ } finally {
234391
+ clearTimeout(timeout);
234392
+ }
234393
+ }
234394
+ function noCliModelConnection(appUrl = null) {
234395
+ return {
234396
+ appUrl,
234397
+ authenticated: false,
234398
+ userId: null,
234399
+ email: null,
234400
+ founderModelSelection: null,
234401
+ restore: () => {
234402
+ }
234403
+ };
234404
+ }
234405
+ var MODEL_PROXY_ENV, MODEL_PROXY_TOKEN_ENV, CLI_APP_URL_ENV, FALLBACK_APP_URL_ENV, DEFAULT_CLI_APP_URL;
234406
+ var init_modelConnection = __esm({
234407
+ "features/perchTerminal/runtime/cliHost/modelConnection.ts"() {
234408
+ "use strict";
234409
+ init_publicModelDefault();
234410
+ init_cliAuthSession();
234411
+ init_cliAuthRefresh();
234412
+ MODEL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
234413
+ MODEL_PROXY_TOKEN_ENV = "PERCH_MODEL_CALL_PROXY_TOKEN";
234414
+ CLI_APP_URL_ENV = "PERCH_CLI_APP_URL";
234415
+ FALLBACK_APP_URL_ENV = "PERCH_APP_URL";
234416
+ DEFAULT_CLI_APP_URL = "https://app.perchai.app";
234417
+ }
234418
+ });
234419
+
233834
234420
  // lib/perchTerminal/statusLabels.ts
233835
234421
  function sectionLabel(sectionKey) {
233836
234422
  if (STATUS_LABELS[sectionKey]) return STATUS_LABELS[sectionKey];
@@ -290330,6 +290916,27 @@ async function runInteractiveSlashCommand(input) {
290330
290916
  input.state.personaId = parsed.value;
290331
290917
  writeModeLine(input.writer, "persona", input.state.personaId);
290332
290918
  return "continue";
290919
+ case "model": {
290920
+ const labelFor = (choice) => choice === "internal" ? "Internal" : ROOST_TIER_LABELS[choice];
290921
+ if (!parsed.value) {
290922
+ writeModeLine(input.writer, "model", labelFor(input.state.roostChoice));
290923
+ return "continue";
290924
+ }
290925
+ input.state.roostChoice = parsed.value;
290926
+ setRoostUserSelectionForNode({ choice: parsed.value, reasoningEnabled: input.state.roostReasoningEnabled });
290927
+ writeModeLine(input.writer, "model", labelFor(parsed.value));
290928
+ return "continue";
290929
+ }
290930
+ case "thinking": {
290931
+ if (parsed.value === void 0) {
290932
+ writeModeLine(input.writer, "thinking", input.state.roostReasoningEnabled ? "on" : "off");
290933
+ return "continue";
290934
+ }
290935
+ input.state.roostReasoningEnabled = parsed.value;
290936
+ setRoostUserSelectionForNode({ choice: input.state.roostChoice, reasoningEnabled: parsed.value });
290937
+ writeModeLine(input.writer, "thinking", input.state.roostReasoningEnabled ? "on" : "off");
290938
+ return "continue";
290939
+ }
290333
290940
  case "appUrl":
290334
290941
  if (!parsed.value) {
290335
290942
  writeModeLine(input.writer, "app-url", input.state.appUrl ?? "(none)");
@@ -290423,6 +291030,22 @@ function parseInteractiveSlashCommand(input) {
290423
291030
  if (!value) return { ok: true, kind: "persona" };
290424
291031
  if (!isPersonaId(value)) return { ok: false, error: `Unknown persona: ${value}` };
290425
291032
  return { ok: true, kind: "persona", value };
291033
+ case "model":
291034
+ if (!value) return { ok: true, kind: "model" };
291035
+ {
291036
+ const normalized = value.toLowerCase().replace(/[\s-]+/g, "_");
291037
+ const choice = normalizeRoostModelChoice(
291038
+ normalized === "standardmax" ? "standard_max" : normalized === "promax" ? "pro_max" : normalized
291039
+ );
291040
+ if (!choice) {
291041
+ return { ok: false, error: `Unknown model: ${value}. Try standard, standard max, pro, pro max, or internal.` };
291042
+ }
291043
+ return { ok: true, kind: "model", value: choice };
291044
+ }
291045
+ case "thinking":
291046
+ if (!value) return { ok: true, kind: "thinking" };
291047
+ if (value !== "on" && value !== "off") return { ok: false, error: "/thinking expects on or off." };
291048
+ return { ok: true, kind: "thinking", value: value === "on" };
290426
291049
  case "app-url":
290427
291050
  case "app":
290428
291051
  return { ok: true, kind: "appUrl", ...value ? { value } : {} };
@@ -290463,6 +291086,8 @@ function renderInteractiveStatus(state, connection, session, workspaceId) {
290463
291086
  ["permission", state.permissionMode],
290464
291087
  ["mode", state.chatMode],
290465
291088
  ["persona", state.personaId],
291089
+ ["model", state.roostChoice === "internal" ? "Internal" : ROOST_TIER_LABELS[state.roostChoice]],
291090
+ ["thinking", state.roostReasoningEnabled ? "on" : "off"],
290466
291091
  ["thread", state.threadId],
290467
291092
  ["context", renderCliContextMeter(state.contextSnapshot, activeContextModel)],
290468
291093
  ["saved", state.persistedThreadUpdatedAt ? new Date(state.persistedThreadUpdatedAt).toLocaleString() : "(new thread)"],
@@ -290602,11 +291227,13 @@ function renderInkSpeakerLabel(label) {
290602
291227
  return `${label}\u203A`;
290603
291228
  }
290604
291229
  function createInteractiveCliState(options) {
290605
- return {
291230
+ const state = {
290606
291231
  cwd: resolveExistingDirectory(options.cwd ?? process.cwd()),
290607
291232
  chatMode: options.chatMode ?? "agents",
290608
291233
  personaId: options.personaId ?? "saffron",
290609
291234
  permissionMode: options.permissionMode ?? "default",
291235
+ roostChoice: "internal",
291236
+ roostReasoningEnabled: true,
290610
291237
  threadId: options.threadId?.trim() || "cli-default",
290611
291238
  threadScopeKey: null,
290612
291239
  desktopConnected: options.desktopConnected ?? false,
@@ -290617,6 +291244,11 @@ function createInteractiveCliState(options) {
290617
291244
  contextSnapshot: null,
290618
291245
  persistedThreadUpdatedAt: null
290619
291246
  };
291247
+ setRoostUserSelectionForNode({
291248
+ choice: state.roostChoice,
291249
+ reasoningEnabled: state.roostReasoningEnabled
291250
+ });
291251
+ return state;
290620
291252
  }
290621
291253
  async function hydrateInteractiveCliState(state) {
290622
291254
  const persisted = await hydrateCliThreadState(state.threadId, state.threadScopeKey);
@@ -291675,6 +292307,8 @@ var init_perch_cli = __esm({
291675
292307
  init_perchCore();
291676
292308
  init_cliHost();
291677
292309
  init_modelConnection();
292310
+ init_roost();
292311
+ init_roostUserSelectionClient();
291678
292312
  init_cliAuthSession();
291679
292313
  init_cliStandaloneOAuth();
291680
292314
  init_contextMeterDisplay();
@@ -291750,7 +292384,9 @@ Commands:
291750
292384
  /help Show this list.
291751
292385
  /status Show cwd, auth, mode, persona, permission, and thread.
291752
292386
  /skills [name] List Perch core skills, or show one skill body.
291753
- /usage Show tokens and estimated cost for this session.
292387
+ /usage Show Perch Token allowance and session usage.
292388
+ /model [standard|standard max|pro|pro max|internal] Show or set your model.
292389
+ /thinking [on|off] Show or toggle Thinking for the selected model.
291754
292390
  /cwd [dir] Show or change the working directory.
291755
292391
  /permission [mode] Show or set default, auto_review, take_the_wheel, or plan.
291756
292392
  /permissions [mode] Alias for /permission.
@@ -291812,8 +292448,10 @@ Commands:
291812
292448
  ];
291813
292449
  PERCH_SPLASH_COMMANDS = [
291814
292450
  ["/status", "show auth, route, tools, and thread"],
291815
- ["/usage", "show session tokens and estimated cost"],
292451
+ ["/usage", "show Perch Token allowance and session usage"],
291816
292452
  ["/skills", "show reusable operator skills"],
292453
+ ["/model", "choose Standard, Standard Max, Pro, or Pro Max"],
292454
+ ["/thinking", "toggle model thinking"],
291817
292455
  ["/persona", "swap saffron or quill"],
291818
292456
  ["/permission", "change autonomy for the next turns"],
291819
292457
  ["/login", "connect your Perch account"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perchai-cli",
3
- "version": "2.4.46",
3
+ "version": "2.4.48",
4
4
  "description": "Perch AI command-line interface",
5
5
  "bin": {
6
6
  "perch": "bin/perch"