shortcutxl 0.3.75 → 0.3.76

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 (92) hide show
  1. package/BINARY-INVENTORY.json +9 -9
  2. package/CHANGELOG.md +4 -0
  3. package/dist/ai/models.d.ts +1 -1
  4. package/dist/ai/models.js +2 -2
  5. package/dist/ai/providers/anthropic.js +4 -4
  6. package/dist/ai/providers/google-shared.d.ts +2 -0
  7. package/dist/ai/providers/google-shared.js +6 -0
  8. package/dist/ai/providers/google-vertex.js +3 -9
  9. package/dist/ai/providers/google.js +3 -9
  10. package/dist/ai/providers/provider-error-normalization.js +47 -20
  11. package/dist/app/agent-session.js +2 -0
  12. package/dist/app/providers/model-resolver.js +4 -4
  13. package/dist/app/session/run-agent-observability.d.ts +2 -0
  14. package/dist/app/session/run-agent-observability.js +1 -0
  15. package/dist/app/session/session-models.js +2 -2
  16. package/dist/app/subagents/defaults.d.ts +1 -1
  17. package/dist/app/subagents/defaults.js +1 -4
  18. package/dist/app/tools/cron.js +3 -2
  19. package/dist/app/tools/llm-analysis.js +9 -4
  20. package/dist/app/tools/refresh-context.js +1 -1
  21. package/dist/app/tools/take-screenshot.js +2 -1
  22. package/dist/app/tools/task/task.js +1 -1
  23. package/dist/cli/list-models.js +2 -1
  24. package/dist/cli.js +1542 -1385
  25. package/dist/contracts/agent-failure.d.ts +4 -0
  26. package/dist/contracts/agent-failure.js +2 -0
  27. package/dist/contracts/model-call.d.ts +4 -1
  28. package/dist/contracts/model-stream.d.ts +29 -1
  29. package/dist/contracts/model-stream.js +86 -0
  30. package/dist/core/agent-loop.js +2 -5
  31. package/dist/core/error-classification.js +35 -30
  32. package/dist/core/prompts/agent-guidelines.d.ts +1 -1
  33. package/dist/core/prompts/agent-guidelines.js +1 -1
  34. package/dist/core/run-failure.js +38 -6
  35. package/dist/core/session/session-error-recovery.js +8 -3
  36. package/dist/embedded-agent/anthropic-messages-transport.js +60 -140
  37. package/dist/embedded-agent/google-vertex-transport.js +14 -81
  38. package/dist/embedded-agent/host-tools/execute-code/raw-sdk-patterns.json +1 -3
  39. package/dist/embedded-agent/host-tools/sandbox-llm/contract.d.ts +2 -0
  40. package/dist/embedded-agent/host-tools/sandbox-llm/contract.js +10 -3
  41. package/dist/embedded-agent/host-tools/sandbox-llm/index.d.ts +1 -1
  42. package/dist/embedded-agent/host-tools/sandbox-llm/index.js +1 -1
  43. package/dist/embedded-agent/host-tools/take-screenshot/contract.d.ts +2 -0
  44. package/dist/embedded-agent/host-tools/take-screenshot/contract.js +5 -2
  45. package/dist/embedded-agent/host-tools/take-screenshot/index.d.ts +1 -1
  46. package/dist/embedded-agent/host-tools/take-screenshot/index.js +1 -1
  47. package/dist/embedded-agent/host-tools/task/contract.d.ts +3 -6
  48. package/dist/embedded-agent/host-tools/task/contract.js +5 -8
  49. package/dist/embedded-agent/model-registry.d.ts +1 -0
  50. package/dist/embedded-agent/model-registry.js +1 -0
  51. package/dist/embedded-agent/openai-completions-transport.js +4 -70
  52. package/dist/embedded-agent/openai-responses-transport.js +4 -70
  53. package/dist/embedded-agent/provider-fast-mode.js +6 -1
  54. package/dist/embedded-agent/stream.js +7 -6
  55. package/dist/embedded-agent/transport-errors.d.ts +25 -0
  56. package/dist/embedded-agent/transport-errors.js +107 -0
  57. package/dist/embedded-agent/worker-bridge/host-client.js +17 -2
  58. package/dist/main.js +8 -4
  59. package/dist/model-ids.d.ts +4 -0
  60. package/dist/model-ids.js +7 -1
  61. package/dist/rpc/rpc-types.d.ts +1 -2
  62. package/dist/shell/theme/theme-schema.json +1 -1
  63. package/dist/shell/tools/presentation/registry.js +2 -1
  64. package/dist/shell/tools/presentation/renderers/task.d.ts +2 -2
  65. package/dist/shell/tools/presentation/renderers/task.js +2 -2
  66. package/dist/shortcut-model-catalog.js +27 -0
  67. package/native-app/package.json +1 -1
  68. package/package.json +3 -3
  69. package/user-docs/dist/shortcutxl-docs.pdf +0 -0
  70. package/xll/ShortcutXL.xll +0 -0
  71. package/xll/python/Lib/site-packages/certifi/__init__.py +1 -1
  72. package/xll/python/Lib/site-packages/certifi/cacert.pem +125 -29
  73. package/xll/python/Lib/site-packages/certifi/tests/__init__.py +0 -0
  74. package/xll/python/Lib/site-packages/certifi/tests/test_certify.py +18 -0
  75. package/xll/python/Lib/site-packages/{certifi-2026.6.17.dist-info → certifi-2026.7.22.dist-info}/METADATA +1 -1
  76. package/xll/python/Lib/site-packages/certifi-2026.7.22.dist-info/RECORD +18 -0
  77. package/xll/python/Lib/site-packages/{certifi-2026.6.17.dist-info → certifi-2026.7.22.dist-info}/WHEEL +1 -1
  78. package/xll/python/Lib/site-packages/httpx-0.28.1.dist-info/RECORD +1 -1
  79. package/xll/python/Lib/site-packages/idna-3.18.dist-info/RECORD +1 -1
  80. package/xll/python/Lib/site-packages/pip-26.1.2.dist-info/RECORD +3 -3
  81. package/xll/python/Lib/site-packages/pywin32-311.dist-info/RECORD +2 -2
  82. package/xll/python/Scripts/httpx.exe +0 -0
  83. package/xll/python/Scripts/idna.exe +0 -0
  84. package/xll/python/Scripts/pip.exe +0 -0
  85. package/xll/python/Scripts/pip3.13.exe +0 -0
  86. package/xll/python/Scripts/pip3.exe +0 -0
  87. package/xll/python/Scripts/pywin32_postinstall.exe +0 -0
  88. package/xll/python/Scripts/pywin32_testall.exe +0 -0
  89. package/xll/python/Lib/site-packages/certifi-2026.6.17.dist-info/RECORD +0 -14
  90. /package/xll/python/Lib/site-packages/{certifi-2026.6.17.dist-info → certifi-2026.7.22.dist-info}/INSTALLER +0 -0
  91. /package/xll/python/Lib/site-packages/{certifi-2026.6.17.dist-info → certifi-2026.7.22.dist-info}/licenses/LICENSE +0 -0
  92. /package/xll/python/Lib/site-packages/{certifi-2026.6.17.dist-info → certifi-2026.7.22.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-07-19T05:57:28.143Z",
3
+ "generatedAt": "2026-07-27T04:35:44.825Z",
4
4
  "package": "shortcutxl",
5
5
  "binaryExtensions": [
6
6
  ".dll",
@@ -11,7 +11,7 @@
11
11
  "files": [
12
12
  {
13
13
  "path": "xll/ShortcutXL.xll",
14
- "sha256": "696c2e28259854eb1a0406f0f432f94c838d32ea5518a3a1f82514e6d97af016",
14
+ "sha256": "f0d06082d5296e5737b9e4416a62942d22afd1780c27c84304bb5b11b0ba1c8a",
15
15
  "source": "ShortcutXL native XLL build",
16
16
  "version": "package",
17
17
  "builtBy": "shortcut",
@@ -523,7 +523,7 @@
523
523
  },
524
524
  {
525
525
  "path": "xll/python/Scripts/httpx.exe",
526
- "sha256": "54ace5c8b5d0aedc90fc7b9c68d593719ec35f0f67066fb3f4006442e720d4e7",
526
+ "sha256": "27001c85dbe85fa448ba575c9b41295349f72b8bcfe2e0805748bebe8ccc9888",
527
527
  "source": "httpx console launcher installed into embedded Python",
528
528
  "version": "see packaged httpx distribution",
529
529
  "builtBy": "third-party",
@@ -531,7 +531,7 @@
531
531
  },
532
532
  {
533
533
  "path": "xll/python/Scripts/idna.exe",
534
- "sha256": "66ec7c50882b73888e3505d063057f15951a36627c4c9a58b5e9742f9777ab95",
534
+ "sha256": "9f01a7efccc9917f3ed7e7a41b950b8734be8c844db5a6b78014188ddb2255da",
535
535
  "source": "Python package console launcher installed into embedded Python",
536
536
  "version": "see owning Python package metadata in site-packages",
537
537
  "builtBy": "third-party",
@@ -539,7 +539,7 @@
539
539
  },
540
540
  {
541
541
  "path": "xll/python/Scripts/pip.exe",
542
- "sha256": "d6daf847f1bf812774d489fde310516baee00a6c141d211aed1932429d8233e4",
542
+ "sha256": "8296d812e172cc359b23905d4a424185e80a9ab470770c8a247fb033b0c12554",
543
543
  "source": "pip console launcher installed into embedded Python",
544
544
  "version": "see packaged pip distribution",
545
545
  "builtBy": "third-party",
@@ -547,7 +547,7 @@
547
547
  },
548
548
  {
549
549
  "path": "xll/python/Scripts/pip3.13.exe",
550
- "sha256": "d6daf847f1bf812774d489fde310516baee00a6c141d211aed1932429d8233e4",
550
+ "sha256": "8296d812e172cc359b23905d4a424185e80a9ab470770c8a247fb033b0c12554",
551
551
  "source": "pip console launcher installed into embedded Python",
552
552
  "version": "see packaged pip distribution",
553
553
  "builtBy": "third-party",
@@ -555,7 +555,7 @@
555
555
  },
556
556
  {
557
557
  "path": "xll/python/Scripts/pip3.exe",
558
- "sha256": "d6daf847f1bf812774d489fde310516baee00a6c141d211aed1932429d8233e4",
558
+ "sha256": "8296d812e172cc359b23905d4a424185e80a9ab470770c8a247fb033b0c12554",
559
559
  "source": "pip console launcher installed into embedded Python",
560
560
  "version": "see packaged pip distribution",
561
561
  "builtBy": "third-party",
@@ -563,7 +563,7 @@
563
563
  },
564
564
  {
565
565
  "path": "xll/python/Scripts/pywin32_postinstall.exe",
566
- "sha256": "94a2b7c198cbda23c1bff4a8780422e2f1e73fd03c1347fc39fa99625938e345",
566
+ "sha256": "72dfdcd5711cf7093921eb0da7c196f308b5a75471a124039401eed472b87547",
567
567
  "source": "Python package console launcher installed into embedded Python",
568
568
  "version": "see owning Python package metadata in site-packages",
569
569
  "builtBy": "third-party",
@@ -571,7 +571,7 @@
571
571
  },
572
572
  {
573
573
  "path": "xll/python/Scripts/pywin32_testall.exe",
574
- "sha256": "f61ee14e2798955301beadbb45503e63e33dad398ed3f216b9bb98270a8bbe54",
574
+ "sha256": "8201c25e4d02041af95225057a08873831cb343767d1660cab9bc0891da1114b",
575
575
  "source": "Python package console launcher installed into embedded Python",
576
576
  "version": "see owning Python package metadata in site-packages",
577
577
  "builtBy": "third-party",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.76]
4
+
5
+ - **Claude Opus 5** - Claude Opus 5 is now available as ShortcutXL's high-accuracy Opus option.
6
+
3
7
  ## [0.3.75]
4
8
 
5
9
  - **Native desktop app** - Run `shortcut app` for a multi-session desktop experience with tools, approvals, subagents, attachments, skills, themes, and account controls.
@@ -12,7 +12,7 @@ export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usag
12
12
  *
13
13
  * Supported today:
14
14
  * - Shortcut's current and legacy OpenAI reasoning models
15
- * - Anthropic Messages API Opus 4.8 models (xhigh maps to adaptive effort "max")
15
+ * - Anthropic Messages API Opus models (xhigh maps to adaptive effort "max")
16
16
  */
17
17
  export declare function supportsXhigh<TApi extends Api>(model: Model<TApi>): boolean;
18
18
  /**
package/dist/ai/models.js CHANGED
@@ -37,7 +37,7 @@ export function calculateCost(model, usage) {
37
37
  *
38
38
  * Supported today:
39
39
  * - Shortcut's current and legacy OpenAI reasoning models
40
- * - Anthropic Messages API Opus 4.8 models (xhigh maps to adaptive effort "max")
40
+ * - Anthropic Messages API Opus models (xhigh maps to adaptive effort "max")
41
41
  */
42
42
  export function supportsXhigh(model) {
43
43
  const modelId = model.id.startsWith('openai/') ? model.id.slice('openai/'.length) : model.id;
@@ -45,7 +45,7 @@ export function supportsXhigh(model) {
45
45
  return true;
46
46
  }
47
47
  if (model.api === 'anthropic-messages') {
48
- return model.id.includes('opus-4-8') || model.id.includes('opus-4.8');
48
+ return model.id.toLowerCase().includes('opus');
49
49
  }
50
50
  return false;
51
51
  }
@@ -379,7 +379,7 @@ export const streamAnthropic = (model, context, options) => {
379
379
  * tolerated. These are the only Claude Opus/Sonnet/Fable models still served;
380
380
  * older budget-based models have been retired.
381
381
  */
382
- const ADAPTIVE_THINKING_MODELS = ['opus-4-8', 'sonnet-5', 'fable-5'];
382
+ const ADAPTIVE_THINKING_MODELS = ['opus-5', 'opus-4-8', 'sonnet-5', 'fable-5'];
383
383
  /** Check if a model uses adaptive thinking. */
384
384
  function supportsAdaptiveThinking(modelId) {
385
385
  const normalized = modelId.toLowerCase();
@@ -419,8 +419,8 @@ export const streamSimpleAnthropic = (model, context, options) => {
419
419
  thinkingEnabled: false
420
420
  });
421
421
  }
422
- // For Opus 4.6 and Sonnet 4.6: use adaptive thinking with effort level
423
- // For older models: use budget-based thinking
422
+ // Current served Claude models use adaptive thinking with an effort level.
423
+ // Older models use budget-based thinking.
424
424
  if (supportsAdaptiveThinking(model.id)) {
425
425
  const effort = mapThinkingLevelToEffort(options.reasoning, model.id);
426
426
  return streamAnthropic(model, context, {
@@ -488,7 +488,7 @@ function buildParams(model, context, options) {
488
488
  if (context.tools) {
489
489
  params.tools = convertTools(context.tools);
490
490
  }
491
- // Configure thinking mode: adaptive (Opus 4.6 and Sonnet 4.6) or budget-based (older models)
491
+ // Configure adaptive thinking for current models or budget-based thinking for older models.
492
492
  if (options?.thinkingEnabled && model.reasoning) {
493
493
  if (supportsAdaptiveThinking(model.id)) {
494
494
  // Adaptive thinking: Claude decides when and how much to think
@@ -38,6 +38,8 @@ export declare function retainThoughtSignature(existing: string | undefined, inc
38
38
  * Models via Google APIs that require explicit tool call IDs in function calls/responses.
39
39
  */
40
40
  export declare function requiresToolCallId(modelId: string): boolean;
41
+ export declare function isGemini3FlashModelId(modelId: string): boolean;
42
+ export declare function isGemini3ProModelId(modelId: string): boolean;
41
43
  /**
42
44
  * Convert internal messages to Gemini Content[] format.
43
45
  */
@@ -57,6 +57,12 @@ function resolveThoughtSignature(isSameProviderAndModel, signature) {
57
57
  export function requiresToolCallId(modelId) {
58
58
  return modelId.startsWith('claude-') || modelId.startsWith('gpt-oss-');
59
59
  }
60
+ export function isGemini3FlashModelId(modelId) {
61
+ return /^gemini-3(?:\.\d+)?-flash(?:-|$)/.test(modelId);
62
+ }
63
+ export function isGemini3ProModelId(modelId) {
64
+ return /^gemini-3(?:\.\d+)?-pro(?:-|$)/.test(modelId);
65
+ }
60
66
  /**
61
67
  * Convert internal messages to Gemini Content[] format.
62
68
  */
@@ -2,7 +2,7 @@ import { GoogleGenAI, ThinkingLevel } from '@google/genai';
2
2
  import { calculateCost } from '../models.js';
3
3
  import { AssistantMessageEventStream } from '../utils/event-stream.js';
4
4
  import { sanitizeSurrogates } from '../utils/sanitize-unicode.js';
5
- import { convertMessages, convertTools, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature } from './google-shared.js';
5
+ import { convertMessages, convertTools, isGemini3FlashModelId, isGemini3ProModelId, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature } from './google-shared.js';
6
6
  import { buildBaseOptions, clampReasoning } from './simple-options.js';
7
7
  const API_VERSION = 'v1';
8
8
  const THINKING_LEVEL_MAP = {
@@ -235,7 +235,7 @@ export const streamSimpleGoogleVertex = (model, context, options) => {
235
235
  }
236
236
  const effort = clampReasoning(options.reasoning);
237
237
  const geminiModel = model;
238
- if (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {
238
+ if (isGemini3ProModelId(geminiModel.id) || isGemini3FlashModelId(geminiModel.id)) {
239
239
  return streamGoogleVertex(model, context, {
240
240
  ...base,
241
241
  thinking: {
@@ -327,14 +327,8 @@ function buildParams(model, context, options = {}) {
327
327
  };
328
328
  return params;
329
329
  }
330
- function isGemini3ProModel(model) {
331
- return model.id.includes('3-pro');
332
- }
333
- function isGemini3FlashModel(model) {
334
- return model.id.includes('3-flash');
335
- }
336
330
  function getGemini3ThinkingLevel(effort, model) {
337
- if (isGemini3ProModel(model)) {
331
+ if (isGemini3ProModelId(model.id)) {
338
332
  switch (effort) {
339
333
  case 'minimal':
340
334
  case 'low':
@@ -3,7 +3,7 @@ import { getEnvApiKey } from '../env-api-keys.js';
3
3
  import { calculateCost } from '../models.js';
4
4
  import { AssistantMessageEventStream } from '../utils/event-stream.js';
5
5
  import { sanitizeSurrogates } from '../utils/sanitize-unicode.js';
6
- import { convertMessages, convertTools, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature } from './google-shared.js';
6
+ import { convertMessages, convertTools, isGemini3FlashModelId, isGemini3ProModelId, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature } from './google-shared.js';
7
7
  import { buildBaseOptions, clampReasoning } from './simple-options.js';
8
8
  // Counter for generating unique tool call IDs
9
9
  let toolCallCounter = 0;
@@ -232,7 +232,7 @@ export const streamSimpleGoogle = (model, context, options) => {
232
232
  }
233
233
  const effort = clampReasoning(options.reasoning);
234
234
  const googleModel = model;
235
- if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel)) {
235
+ if (isGemini3ProModelId(googleModel.id) || isGemini3FlashModelId(googleModel.id)) {
236
236
  return streamGoogle(model, context, {
237
237
  ...base,
238
238
  thinking: {
@@ -311,14 +311,8 @@ function buildParams(model, context, options = {}) {
311
311
  };
312
312
  return params;
313
313
  }
314
- function isGemini3ProModel(model) {
315
- return model.id.includes('3-pro');
316
- }
317
- function isGemini3FlashModel(model) {
318
- return model.id.includes('3-flash');
319
- }
320
314
  function getGemini3ThinkingLevel(effort, model) {
321
- if (isGemini3ProModel(model)) {
315
+ if (isGemini3ProModelId(model.id)) {
322
316
  switch (effort) {
323
317
  case 'minimal':
324
318
  case 'low':
@@ -1,4 +1,6 @@
1
- import { applyModelAccessDeniedErrorDetails, isShortcutXLModelStreamErrorDetails, LLMErrorMetadataHeaders, parseStreamErrorPayload, safeModelStreamErrorMessage } from '../../contracts/model-stream.js';
1
+ import { APIConnectionError as AnthropicAPIConnectionError } from '@anthropic-ai/sdk';
2
+ import { APIConnectionError as OpenAIAPIConnectionError } from 'openai';
3
+ import { applyModelAccessDeniedErrorDetails, LLMErrorMetadataHeaders, modelStreamErrorDetailsFromThrown, networkErrorDetails, parseStreamErrorPayload, providerErrorDetailsFromRawType, safeModelStreamErrorMessage, ShortcutXLModelStreamFetchStage } from '../../contracts/model-stream.js';
2
4
  import { isContextOverflowErrorMessage } from '../utils/overflow.js';
3
5
  function getErrorMessage(error) {
4
6
  return error instanceof Error ? error.message : (JSON.stringify(error) ?? String(error));
@@ -22,32 +24,57 @@ function apiV2PayloadFromHeaders(headers) {
22
24
  };
23
25
  return Object.values(payload).some((value) => value !== undefined) ? payload : undefined;
24
26
  }
25
- function normalizeApiV2ErrorDetails(error, rawMessage) {
26
- const payload = apiV2PayloadFromHeaders(error.headers);
27
- if (!payload)
28
- return undefined;
27
+ /**
28
+ * Classify an SDK-thrown error from what the provider itself reported.
29
+ * Anthropic's `APIError` carries the error type as `.type` (in-stream error
30
+ * events) or `.error.error.type`; OpenAI's as `.error.type` / `.code`. SDK
31
+ * connection failures (fetch rejected before an HTTP response) classify as
32
+ * network errors.
33
+ */
34
+ function sdkErrorDetails(error) {
35
+ if (error instanceof AnthropicAPIConnectionError || error instanceof OpenAIAPIConnectionError) {
36
+ return networkErrorDetails(ShortcutXLModelStreamFetchStage.BeforeResponse);
37
+ }
38
+ const candidates = [
39
+ error.type,
40
+ error.error?.error?.type,
41
+ error.error?.type,
42
+ error.code,
43
+ error.error?.code
44
+ ];
45
+ for (const raw of candidates) {
46
+ if (typeof raw !== 'string')
47
+ continue;
48
+ const details = providerErrorDetailsFromRawType(raw);
49
+ if (details)
50
+ return details;
51
+ }
52
+ return undefined;
53
+ }
54
+ /**
55
+ * Build normalized details for an SDK-thrown error by merging what the
56
+ * provider reported on the error itself with the api-v2 gateway's metadata
57
+ * headers. Header values win: the gateway sets `X-LLM-Provider-Error-Type`
58
+ * deliberately on HTTP failures, and a real HTTP `status` beats the synthetic
59
+ * one the raw-type mapping supplies.
60
+ */
61
+ function normalizedSdkErrorDetails(error, rawMessage) {
29
62
  const status = typeof error.status === 'number' ? error.status : undefined;
30
- const details = parseStreamErrorPayload(payload, status) ?? (status ? { status } : undefined);
31
- if (!details)
63
+ const classified = sdkErrorDetails(error);
64
+ const headerDetails = parseStreamErrorPayload(apiV2PayloadFromHeaders(error.headers), status);
65
+ if (!classified && !headerDetails)
32
66
  return undefined;
33
- const accessAwareDetails = applyModelAccessDeniedErrorDetails(details, rawMessage);
67
+ const merged = { ...classified, ...headerDetails };
68
+ const accessAware = applyModelAccessDeniedErrorDetails(merged, rawMessage);
34
69
  if (isContextOverflowErrorMessage(rawMessage)) {
35
- return { ...accessAwareDetails, code: 'context_overflow' };
70
+ return { ...accessAware, code: 'context_overflow' };
36
71
  }
37
- return accessAwareDetails;
38
- }
39
- function streamDetailsFromError(error) {
40
- const detailsError = error;
41
- if (isShortcutXLModelStreamErrorDetails(detailsError.details))
42
- return detailsError.details;
43
- if (isShortcutXLModelStreamErrorDetails(detailsError.errorDetails))
44
- return detailsError.errorDetails;
45
- return undefined;
72
+ return accessAware;
46
73
  }
47
74
  export function applyNormalizedProviderError(output, error) {
48
75
  const rawMessage = getErrorMessage(error);
49
- const details = streamDetailsFromError(error) ??
50
- normalizeApiV2ErrorDetails(error, rawMessage);
76
+ const details = modelStreamErrorDetailsFromThrown(error) ??
77
+ normalizedSdkErrorDetails(error, rawMessage);
51
78
  if (!details) {
52
79
  output.errorMessage = rawMessage;
53
80
  return { usedStructuredDetails: false };
@@ -371,6 +371,7 @@ export class AgentSession {
371
371
  charCount: deliveredContent.charCount,
372
372
  imageCount: deliveredContent.imageCount,
373
373
  conversationId,
374
+ modelName: this.agent.state.model?.id,
374
375
  userMessageId
375
376
  })),
376
377
  conversationId,
@@ -979,6 +980,7 @@ export class AgentSession {
979
980
  imageCount: currentImages?.length ?? 0,
980
981
  conversationId: this.sessionManager.getSessionId(),
981
982
  workbookDetails,
983
+ modelName: this.agent.state.model?.id,
982
984
  userMessageId
983
985
  });
984
986
  this._pendingImmediateRunAgentMetadata = promptMetadata;
@@ -37,13 +37,13 @@ export function resolveExactModelRef(availableModels, requested) {
37
37
  /** Default model IDs for each provider with a preferred initial model. */
38
38
  export const defaultModelPerProvider = {
39
39
  [SHORTCUT_PROVIDER_ID]: SHORTCUT_OPENAI_MODEL_ID,
40
- anthropic: SHORTCUT_MODEL_ID.ClaudeOpus48,
40
+ anthropic: SHORTCUT_MODEL_ID.ClaudeOpus5,
41
41
  openai: SHORTCUT_OPENAI_MODEL_ID,
42
42
  'azure-openai-responses': SHORTCUT_OPENAI_MODEL_ID,
43
43
  google: 'gemini-2.5-pro',
44
44
  'google-vertex': 'gemini-3-pro-preview',
45
45
  openrouter: `openai/${SHORTCUT_OPENAI_MODEL_ID}`,
46
- 'vercel-ai-gateway': 'anthropic/claude-opus-4-8',
46
+ 'vercel-ai-gateway': 'anthropic/claude-opus-5',
47
47
  xai: 'grok-4-fast-non-reasoning',
48
48
  groq: 'openai/gpt-oss-120b',
49
49
  cerebras: 'zai-glm-4.6',
@@ -51,7 +51,7 @@ export const defaultModelPerProvider = {
51
51
  minimax: 'MiniMax-M2.1',
52
52
  'minimax-cn': 'MiniMax-M2.1',
53
53
  huggingface: 'moonshotai/Kimi-K2.5',
54
- opencode: SHORTCUT_MODEL_ID.ClaudeOpus48,
54
+ opencode: SHORTCUT_MODEL_ID.ClaudeOpus5,
55
55
  'kimi-coding': 'kimi-k2-thinking'
56
56
  };
57
57
  function getDefaultModelCandidatesForProvider(provider) {
@@ -59,7 +59,7 @@ function getDefaultModelCandidatesForProvider(provider) {
59
59
  return [
60
60
  SHORTCUT_OPENAI_MODEL_ID,
61
61
  SHORTCUT_MODEL_ID.ClaudeFable5,
62
- SHORTCUT_MODEL_ID.ClaudeOpus48
62
+ SHORTCUT_MODEL_ID.ClaudeOpus5
63
63
  ];
64
64
  }
65
65
  return [defaultModelPerProvider[provider]].filter((modelId) => !!modelId);
@@ -8,6 +8,7 @@ export type RunAgentMetadata = {
8
8
  has_workbook_context: boolean;
9
9
  workbook_count: number;
10
10
  workbook_scope_mode: string | undefined;
11
+ modelName?: string;
11
12
  user_message_id?: string;
12
13
  turnId?: string;
13
14
  };
@@ -31,6 +32,7 @@ export declare function buildRunAgentMetadata(options: {
31
32
  workbooks?: string[];
32
33
  scopeMode?: string;
33
34
  };
35
+ modelName?: string;
34
36
  userMessageId?: string;
35
37
  }): RunAgentMetadata;
36
38
  export declare function emitRunAgent(observability: RunAgentObservability | undefined, metadata: RunAgentMetadata): void;
@@ -33,6 +33,7 @@ export function buildRunAgentMetadata(options) {
33
33
  has_workbook_context: Boolean(options.workbookDetails),
34
34
  workbook_count: options.workbookDetails?.workbooks?.length ?? 0,
35
35
  workbook_scope_mode: options.workbookDetails?.scopeMode,
36
+ ...(options.modelName ? { modelName: options.modelName } : {}),
36
37
  ...(options.userMessageId
37
38
  ? { user_message_id: options.userMessageId, turnId: options.userMessageId }
38
39
  : {})
@@ -25,12 +25,12 @@ export const THINKING_LEVELS_WITH_XHIGH = [
25
25
  const INTERACTIVE_MODELS_PER_PROVIDER = {
26
26
  shortcut: new Set([
27
27
  SHORTCUT_MODEL_ID.ClaudeFable5,
28
- SHORTCUT_MODEL_ID.ClaudeOpus48,
28
+ SHORTCUT_MODEL_ID.ClaudeOpus5,
29
29
  SHORTCUT_OPENAI_MODEL_ID,
30
30
  SHORTCUT_MODEL_ID.Glm52Fireworks,
31
31
  SHORTCUT_MODEL_ID.Hosted
32
32
  ]),
33
- anthropic: new Set([SHORTCUT_MODEL_ID.ClaudeOpus48]),
33
+ anthropic: new Set([SHORTCUT_MODEL_ID.ClaudeOpus5]),
34
34
  openai: new Set([SHORTCUT_OPENAI_MODEL_ID])
35
35
  };
36
36
  // ============================================================================
@@ -1,4 +1,4 @@
1
1
  export declare const DEFAULT_SUBAGENT_MODEL: "shortcut/gpt-5.6-sol";
2
2
  export declare const DEFAULT_SUBAGENT_TIMEOUT_SECONDS: number;
3
- export declare const TASK_MODEL_CHOICES: readonly ["shortcut/gpt-5.6-sol", "shortcut/claude-opus-4-8"];
3
+ export declare const TASK_MODEL_CHOICES: readonly ["shortcut/gpt-5.6-sol", "shortcut/claude-opus-5"];
4
4
  //# sourceMappingURL=defaults.d.ts.map
@@ -1,8 +1,5 @@
1
1
  import { SHORTCUT_MODEL_REF, SHORTCUT_OPENAI_MODEL_REF } from '../../model-ids.js';
2
2
  export const DEFAULT_SUBAGENT_MODEL = SHORTCUT_OPENAI_MODEL_REF;
3
3
  export const DEFAULT_SUBAGENT_TIMEOUT_SECONDS = 30 * 60;
4
- export const TASK_MODEL_CHOICES = [
5
- DEFAULT_SUBAGENT_MODEL,
6
- SHORTCUT_MODEL_REF.ClaudeOpus48
7
- ];
4
+ export const TASK_MODEL_CHOICES = [DEFAULT_SUBAGENT_MODEL, SHORTCUT_MODEL_REF.ClaudeOpus5];
8
5
  //# sourceMappingURL=defaults.js.map
@@ -32,12 +32,13 @@ const ScheduleSchema = Type.Union([
32
32
  }))
33
33
  })
34
34
  ]);
35
+ const MODEL_OVERRIDE_DESCRIPTION = `Model override, for example "${SHORTCUT_MODEL_REF.ClaudeOpus5}" for Opus.`;
35
36
  const JobInputSchema = Type.Object({
36
37
  name: Type.String({ description: 'Short name for the job' }),
37
38
  schedule: ScheduleSchema,
38
39
  payload: Type.Object({
39
40
  message: Type.String({ description: 'The prompt/instruction for the agent to execute' }),
40
- model: Type.Optional(Type.String({ description: `Model override, e.g. "${SHORTCUT_MODEL_REF.ClaudeOpus48}"` }))
41
+ model: Type.Optional(Type.String({ description: MODEL_OVERRIDE_DESCRIPTION }))
41
42
  }),
42
43
  enabled: Type.Optional(Type.Boolean({ description: 'Whether the job is enabled (default: true)' })),
43
44
  description: Type.Optional(Type.String({ description: 'Longer description of what the job does' }))
@@ -49,7 +50,7 @@ const PatchSchema = Type.Object({
49
50
  schedule: Type.Optional(ScheduleSchema),
50
51
  payload: Type.Optional(Type.Object({
51
52
  message: Type.Optional(Type.String()),
52
- model: Type.Optional(Type.String())
53
+ model: Type.Optional(Type.String({ description: MODEL_OVERRIDE_DESCRIPTION }))
53
54
  }))
54
55
  });
55
56
  const schema = Type.Object({
@@ -8,6 +8,7 @@ import { Type } from '@sinclair/typebox';
8
8
  import { mkdir, readdir, readFile, stat, unlink, writeFile } from 'fs/promises';
9
9
  import { basename, extname, join } from 'path';
10
10
  import { getAgentTempDir } from '../../config.js';
11
+ import { SHORTCUT_MODEL_ID } from '../../model-ids.js';
11
12
  import { LLM_ANALYSIS } from '../../tool-names.js';
12
13
  import { mapShortcutLlmProxyError } from '../providers/shortcut-llm-proxy-client.js';
13
14
  const TOOL_NAME = LLM_ANALYSIS;
@@ -53,10 +54,12 @@ const TEXT_EXTENSIONS = new Set([
53
54
  '.bas'
54
55
  ]);
55
56
  const MODELS = {
56
- 'gemini-3-flash-preview': 'gemini-3-flash-preview',
57
+ [SHORTCUT_MODEL_ID.Gemini3Flash]: SHORTCUT_MODEL_ID.Gemini3Flash,
58
+ [SHORTCUT_MODEL_ID.Gemini35FlashLite]: SHORTCUT_MODEL_ID.Gemini35FlashLite,
59
+ [SHORTCUT_MODEL_ID.Gemini36Flash]: SHORTCUT_MODEL_ID.Gemini36Flash,
57
60
  'claude-haiku-4-5-20251001': 'claude-haiku-4-5-20251001'
58
61
  };
59
- const DEFAULT_MODEL = 'gemini-3-flash-preview';
62
+ const DEFAULT_MODEL = SHORTCUT_MODEL_ID.Gemini3Flash;
60
63
  const SYSTEM_PROMPT = `You are a document extraction assistant.
61
64
 
62
65
  Extraction rules:
@@ -76,7 +79,9 @@ Supported text types: ${[...TEXT_EXTENSIONS].join(', ')}
76
79
  Also supports: .pdf
77
80
 
78
81
  MODEL SELECTION:
79
- - "gemini-3-flash-preview" (default): Best for careful extraction, tables, and especially images
82
+ - "${SHORTCUT_MODEL_ID.Gemini3Flash}" (default): Current production model for careful extraction, tables, and images
83
+ - "${SHORTCUT_MODEL_ID.Gemini35FlashLite}": Fast, cost-efficient document parsing and structured extraction
84
+ - "${SHORTCUT_MODEL_ID.Gemini36Flash}": Complex visual and multimodal reasoning
80
85
  - "claude-haiku-4-5-20251001": Quick scanning, structure discovery
81
86
 
82
87
  FOR EXTRACTION TASKS:
@@ -97,7 +102,7 @@ const schema = Type.Object({
97
102
  description: 'The question/instruction for the LLM about the file content.'
98
103
  }),
99
104
  model: Type.Optional(Type.String({
100
- description: `Model to use: '${DEFAULT_MODEL}' (default, best for images/tables) or 'claude-haiku-4-5-20251001' (fallback/verifier)`
105
+ description: `Model to use: '${DEFAULT_MODEL}' (default), '${SHORTCUT_MODEL_ID.Gemini35FlashLite}' (fast, cost-efficient extraction), '${SHORTCUT_MODEL_ID.Gemini36Flash}' (complex visual reasoning), or 'claude-haiku-4-5-20251001' (fallback/verifier)`
101
106
  })),
102
107
  output_filename: Type.Optional(Type.String({
103
108
  description: "Optional output filename (e.g., 'analysis.md'). Auto-generated if omitted."
@@ -20,7 +20,7 @@ const schema = Type.Object({
20
20
  description: 'Progress folder for autonomous continuation. When autonomous mode is active, pass this explicitly so the runtime can inject it into the next-session prompt.'
21
21
  })),
22
22
  model: Type.Optional(Type.String({
23
- description: `Optional model override for the next session. Accepts the same model patterns as CLI model selection, e.g. "${SHORTCUT_MODEL_REF.ClaudeOpus48}" or "opus".`
23
+ description: `Optional model override for the next session. Set model to "${SHORTCUT_MODEL_REF.ClaudeOpus5}" to use Opus.`
24
24
  })),
25
25
  thinkingLevel: Type.Optional(thinkingLevelSchema)
26
26
  });
@@ -17,10 +17,11 @@
17
17
  */
18
18
  import { Type } from '@sinclair/typebox';
19
19
  import { TAKE_SCREENSHOT_SYSTEM_PROMPT, TAKE_SCREENSHOT_TOOL_DESCRIPTION } from '../../core/prompts/take-screenshot.js';
20
+ import { SHORTCUT_MODEL_ID } from '../../model-ids.js';
20
21
  import { TAKE_SCREENSHOT } from '../../tool-names.js';
21
22
  import { mapShortcutLlmProxyError } from '../providers/shortcut-llm-proxy-client.js';
22
23
  const TOOL_NAME = TAKE_SCREENSHOT;
23
- const DEFAULT_VISION_MODEL = 'gemini-3-flash-preview';
24
+ const DEFAULT_VISION_MODEL = SHORTCUT_MODEL_ID.Gemini3Flash;
24
25
  const SCREENSHOT_LLM_MAX_TOKENS = 16384;
25
26
  const SCREENSHOT_LLM_TIMEOUT_MS = 120_000;
26
27
  // ---------------------------------------------------------------------------
@@ -153,7 +153,7 @@ function buildSchema(excludeSubagents) {
153
153
  description: 'Full sandbox path to a .txt file containing the complete subagent prompt. Prefer this for long prompts, repeated/batched tasks, or many parallel agents using similar guidance; generate the files programmatically, then launch the tasks concurrently with these paths.'
154
154
  })),
155
155
  model: Type.Optional(StringEnum(TASK_MODEL_CHOICES, {
156
- description: `${SHORTCUT_OPENAI_MODEL_REF} (default) is fastest; ${SHORTCUT_MODEL_REF.ClaudeOpus48} is as accurate, better at formatting, slower, and useful for an independent opinion.`
156
+ description: `${SHORTCUT_OPENAI_MODEL_REF} is the default and fastest option. Set model to "${SHORTCUT_MODEL_REF.ClaudeOpus5}" for the Opus option with higher accuracy and stronger formatting when extra latency is acceptable.`
157
157
  })),
158
158
  run_in_background: Type.Optional(Type.Boolean({
159
159
  description: RUN_IN_BACKGROUND_DESCRIPTION
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * List available models with optional fuzzy search
3
3
  */
4
+ import { filterInteractiveSelectableModels } from '../app/session/session-models.js';
4
5
  import { fuzzyFilter } from '../tui/index.js';
5
6
  /**
6
7
  * Format a number as human-readable (e.g., 200000 -> "200K", 1000000 -> "1M")
@@ -20,7 +21,7 @@ function formatTokenCount(count) {
20
21
  * List available models, optionally filtered by search pattern
21
22
  */
22
23
  export async function listModels(modelRegistry, searchPattern) {
23
- const models = modelRegistry.getAvailable();
24
+ const models = filterInteractiveSelectableModels(modelRegistry.getAvailable());
24
25
  if (models.length === 0) {
25
26
  console.log('No models available. Set API keys in environment variables.');
26
27
  return;