@agent-native/core 0.155.0 → 0.157.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +19 -4
  3. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +7 -2
  4. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
  5. package/corpus/templates/assets/app/global.css +4 -0
  6. package/corpus/templates/assets/app/i18n-data.ts +21 -1
  7. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +18 -15
  8. package/corpus/templates/brain/app/routes/sources.tsx +1 -2
  9. package/corpus/templates/calendar/app/hooks/use-bookings.ts +12 -2
  10. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +64 -2
  11. package/corpus/templates/calendar/server/handlers/bookings.ts +219 -93
  12. package/corpus/templates/calendar/server/plugins/auth.ts +0 -2
  13. package/corpus/templates/clips/actions/create-folder.ts +7 -1
  14. package/corpus/templates/clips/actions/create-meeting.ts +6 -2
  15. package/corpus/templates/clips/actions/create-recording.ts +5 -3
  16. package/corpus/templates/clips/actions/finalize-recording.ts +97 -65
  17. package/corpus/templates/clips/actions/import-loom-recording.ts +5 -3
  18. package/corpus/templates/clips/actions/request-recording-access.ts +272 -0
  19. package/corpus/templates/clips/actions/stitch-recordings.ts +5 -3
  20. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +38 -63
  21. package/corpus/templates/clips/app/components/player/share-dialog.tsx +177 -134
  22. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -21
  23. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +13 -30
  24. package/corpus/templates/clips/app/i18n/en-US.ts +10 -0
  25. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -5
  26. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +24 -17
  27. package/corpus/templates/clips/app/routes/share.$shareId.tsx +151 -20
  28. package/corpus/templates/clips/changelog/2026-08-14-long-resumable-uploads-now-abort-cleanly-and-show-errors.md +6 -0
  29. package/corpus/templates/clips/changelog/2026-08-14-standardized-share-popovers.md +6 -0
  30. package/corpus/templates/clips/chrome-extension/public/manifest.json +11 -3
  31. package/corpus/templates/clips/chrome-extension/src/github-preview-content.ts +37 -8
  32. package/corpus/templates/clips/chrome-extension/src/github-preview.ts +3 -3
  33. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -25
  34. package/corpus/templates/clips/desktop/src/app.tsx +24 -0
  35. package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +42 -13
  36. package/corpus/templates/clips/desktop/src/lib/recorder.ts +11 -18
  37. package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +1 -0
  38. package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
  39. package/corpus/templates/clips/desktop/src/styles.css +24 -9
  40. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -0
  41. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +8 -0
  42. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +154 -176
  43. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +115 -31
  44. package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +7 -0
  45. package/corpus/templates/clips/server/db/index.ts +1 -0
  46. package/corpus/templates/clips/server/db/schema.ts +1 -0
  47. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +6 -1
  48. package/corpus/templates/clips/server/lib/emails.ts +23 -0
  49. package/corpus/templates/clips/server/lib/public-agent-context.ts +55 -0
  50. package/corpus/templates/clips/server/lib/recordings.ts +2 -1
  51. package/corpus/templates/clips/server/lib/resumable-upload-cleanup.ts +49 -0
  52. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +34 -7
  53. package/corpus/templates/clips/server/lib/upload-interruption.ts +15 -1
  54. package/corpus/templates/clips/server/lib/upload-lease.ts +94 -9
  55. package/corpus/templates/clips/server/routes/api/agent-context.json.get.ts +82 -7
  56. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +1 -0
  57. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +71 -12
  58. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +4 -3
  59. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +19 -0
  60. package/corpus/templates/clips/server/routes/api/uploads/reap.post.ts +8 -1
  61. package/corpus/templates/clips/shared/recording-link.ts +4 -0
  62. package/corpus/templates/clips/shared/share-loader-response.ts +2 -1
  63. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +7 -16
  64. package/corpus/templates/factory/AGENTS.md +5 -1
  65. package/corpus/templates/factory/README.md +6 -2
  66. package/corpus/templates/factory/actions/view-screen.ts +15 -0
  67. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +58 -189
  68. package/corpus/templates/factory/app/components/layout/Header.tsx +1 -0
  69. package/corpus/templates/factory/app/components/layout/Layout.tsx +1 -1
  70. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +7 -0
  71. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +3 -0
  72. package/corpus/templates/factory/app/i18n/en-US.ts +3 -1
  73. package/corpus/templates/factory/app/routes/agents.tsx +9 -0
  74. package/corpus/templates/mail/server/plugins/auth.ts +0 -2
  75. package/corpus/templates/plan/app/components/plan/LocalCodebasePicker.tsx +50 -14
  76. package/corpus/templates/plan/app/pages/PlansPage.tsx +9 -19
  77. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
  78. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
  79. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
  80. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
  81. package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +7 -1
  82. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
  83. package/corpus/templates/slides/app/context/DeckContext.tsx +108 -19
  84. package/corpus/templates/slides/app/global.css +7 -40
  85. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  86. package/corpus/templates/slides/app/lib/editor-shortcuts.ts +46 -0
  87. package/corpus/templates/slides/app/pages/DeckEditor.tsx +143 -45
  88. package/dist/agent/index.d.ts +1 -1
  89. package/dist/agent/production-agent.d.ts +30 -0
  90. package/dist/agent/production-agent.js +100 -8
  91. package/dist/agent/types.d.ts +9 -0
  92. package/dist/client/AgentPanel.d.ts +13 -1
  93. package/dist/client/AgentPanel.js +22 -17
  94. package/dist/client/AssistantChat.d.ts +15 -1
  95. package/dist/client/AssistantChat.js +135 -48
  96. package/dist/client/HighlightedCodeBlock.js +12 -2
  97. package/dist/client/MultiTabAssistantChat.js +44 -27
  98. package/dist/client/agent-chat/index.d.ts +1 -0
  99. package/dist/client/agent-chat/index.js +1 -0
  100. package/dist/client/chat/markdown-renderer.js +20 -5
  101. package/dist/client/chat/message-components.d.ts +2 -2
  102. package/dist/client/chat/message-components.js +69 -35
  103. package/dist/client/chat/run-recovery.d.ts +4 -1
  104. package/dist/client/chat/run-recovery.js +62 -30
  105. package/dist/client/chat/tool-call-display.d.ts +12 -3
  106. package/dist/client/chat/tool-call-display.js +79 -40
  107. package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
  108. package/dist/client/chat/widgets/DataChartWidget.js +8 -2
  109. package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
  110. package/dist/client/chat/widgets/DataTableWidget.js +23 -9
  111. package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
  112. package/dist/client/chat-first/apps-rail.js +1 -1
  113. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  114. package/dist/client/components/ui/message-scroller.js +7 -3
  115. package/dist/client/composer/runtime-adapters.js +3 -2
  116. package/dist/client/context-xray/ContextMeter.js +5 -1
  117. package/dist/client/context-xray/ContextXRayPanel.js +5 -5
  118. package/dist/client/error-format.d.ts +4 -0
  119. package/dist/client/error-format.js +93 -5
  120. package/dist/client/i18n.js +83 -17
  121. package/dist/client/observability/ThumbsFeedback.js +10 -8
  122. package/dist/client/settings/AccountSettingsCard.js +48 -19
  123. package/dist/client/sharing/ShareButton.d.ts +1 -2
  124. package/dist/client/sharing/ShareButton.js +151 -81
  125. package/dist/client/sharing/ShareDialog.js +5 -4
  126. package/dist/client/use-chat-threads.js +10 -14
  127. package/dist/coding-tools/run-code.js +2 -1
  128. package/dist/coding-tools/sandbox/background.d.ts +1 -0
  129. package/dist/coding-tools/sandbox/background.js +8 -1
  130. package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
  131. package/dist/coding-tools/sandbox/executions-store.js +41 -3
  132. package/dist/collab/routes.d.ts +1 -1
  133. package/dist/collab/struct-routes.d.ts +1 -1
  134. package/dist/index.d.ts +1 -1
  135. package/dist/localization/core-messages/ar-SA.d.ts +3 -0
  136. package/dist/localization/core-messages/ar-SA.js +541 -0
  137. package/dist/localization/core-messages/de-DE.d.ts +3 -0
  138. package/dist/localization/core-messages/de-DE.js +513 -0
  139. package/dist/localization/core-messages/en-US.d.ts +513 -0
  140. package/dist/localization/core-messages/en-US.js +513 -0
  141. package/dist/localization/core-messages/es-ES.d.ts +3 -0
  142. package/dist/localization/core-messages/es-ES.js +520 -0
  143. package/dist/localization/core-messages/fr-FR.d.ts +3 -0
  144. package/dist/localization/core-messages/fr-FR.js +520 -0
  145. package/dist/localization/core-messages/hi-IN.d.ts +3 -0
  146. package/dist/localization/core-messages/hi-IN.js +513 -0
  147. package/dist/localization/core-messages/ja-JP.d.ts +3 -0
  148. package/dist/localization/core-messages/ja-JP.js +506 -0
  149. package/dist/localization/core-messages/ko-KR.d.ts +3 -0
  150. package/dist/localization/core-messages/ko-KR.js +506 -0
  151. package/dist/localization/core-messages/pt-BR.d.ts +3 -0
  152. package/dist/localization/core-messages/pt-BR.js +520 -0
  153. package/dist/localization/core-messages/zh-CN.d.ts +3 -0
  154. package/dist/localization/core-messages/zh-CN.js +506 -0
  155. package/dist/localization/core-messages/zh-TW.d.ts +3 -0
  156. package/dist/localization/core-messages/zh-TW.js +506 -0
  157. package/dist/localization/core-messages.d.ts +524 -0
  158. package/dist/localization/core-messages.js +124 -0
  159. package/dist/localization/default-messages.d.ts +3 -0
  160. package/dist/localization/default-messages.js +3 -0
  161. package/dist/notifications/routes.d.ts +1 -1
  162. package/dist/observability/routes.d.ts +5 -5
  163. package/dist/progress/routes.d.ts +1 -1
  164. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  165. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  166. package/dist/resources/handlers.d.ts +1 -1
  167. package/dist/secrets/routes.d.ts +9 -9
  168. package/dist/server/agent-chat/plugin-options.d.ts +7 -2
  169. package/dist/server/agent-chat-plugin.d.ts +10 -0
  170. package/dist/server/agent-chat-plugin.js +144 -41
  171. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  172. package/dist/server/agent-run-context.d.ts +7 -1
  173. package/dist/server/agent-run-context.js +9 -2
  174. package/dist/server/agent-teams-run-queue.d.ts +3 -0
  175. package/dist/server/agent-teams.js +38 -9
  176. package/dist/server/auth-marketing.d.ts +1 -0
  177. package/dist/server/auth-marketing.js +0 -2
  178. package/dist/server/auth.d.ts +1 -0
  179. package/dist/server/auth.js +18 -0
  180. package/dist/server/index.d.ts +1 -1
  181. package/dist/server/onboarding-html.d.ts +1 -0
  182. package/dist/server/onboarding-html.js +2 -88
  183. package/dist/server/realtime-token.d.ts +1 -1
  184. package/dist/server/request-context.d.ts +7 -0
  185. package/dist/server/request-context.js +15 -0
  186. package/dist/shared/markdown-block-split.d.ts +16 -0
  187. package/dist/shared/markdown-block-split.js +81 -5
  188. package/dist/styles/agent-native.css +13 -0
  189. package/dist/voice/voice-cleanup-prompt.js +1 -0
  190. package/docs/content/agent-surfaces.mdx +30 -0
  191. package/package.json +2 -2
  192. package/corpus/templates/clips/shared/mic-audio-cleanup.ts +0 -350
@@ -255,6 +255,29 @@ export interface ActionEntry {
255
255
  /** @deprecated Use `ActionEntry` instead */
256
256
  export type ScriptEntry = ActionEntry;
257
257
  export type AgentExecutionMode = "act" | "plan";
258
+ export interface AgentActionSurface {
259
+ allowedActionNames: readonly string[];
260
+ }
261
+ export interface AgentActionSurfaceDetails {
262
+ event: any;
263
+ ownerEmail: string | null;
264
+ orgId: string | null;
265
+ threadId?: string;
266
+ mode: AgentExecutionMode;
267
+ internalContinuation: boolean;
268
+ availableActionNames: readonly string[];
269
+ }
270
+ /** Read a persisted allowlist while preserving legacy absence and failing
271
+ * closed when the field is present but malformed. */
272
+ export declare function readPersistedAllowedActionNames(value: unknown): string[] | undefined;
273
+ export interface PersistedActionSurface {
274
+ orgId: string | null;
275
+ allowedActionNames: string[];
276
+ }
277
+ /** Read a nested persisted action surface. An absent envelope is legacy;
278
+ * a present but invalid envelope is an explicit org-less, empty surface. */
279
+ export declare function readPersistedActionSurface(value: unknown, propertyName: string): PersistedActionSurface | undefined;
280
+ export declare function filterActionsByAllowedNames(actions: Record<string, ActionEntry>, allowedActionNames: readonly string[]): Record<string, ActionEntry>;
258
281
  export declare const PLAN_MODE_SYSTEM_PROMPT = "## Plan Mode Active\n\nYou are in Plan mode. This turn is for research, clarification, and a proposed approach only.\n\nHard rules:\n- Use only read-only tools. Do not edit files, write resources, run mutating bash commands, mutate SQL rows, navigate the UI, send notifications, create jobs, create tools, send messages or tasks to external agents, or change external systems.\n- If a needed detail is unclear, ask a concise clarifying question before proposing a plan.\n- When ready, present a concrete plan with the files/tools you expect to touch, the intended changes, validation steps, and notable risks.\n- Do not treat approval as implicit while Plan mode is still active. Tell the user to switch to Act mode with the mode selector or /act before implementation.";
259
282
  export declare function isPlanModeToolCallAllowed(name: string, input: unknown, entry: ActionEntry): boolean;
260
283
  export declare function createPlanModeActionRegistry(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
@@ -314,6 +337,13 @@ export interface ProductionAgentOptions {
314
337
  displayMessage?: string;
315
338
  attachments?: AgentChatAttachment[];
316
339
  }>;
340
+ /**
341
+ * Resolve the exact action registry exposed to one interactive agent-chat
342
+ * request. Returned names are a hard allowlist: omitted actions are absent
343
+ * from both the provider schemas and the searchable registry. When set, all
344
+ * allowed actions are loaded directly on the first model request.
345
+ */
346
+ resolveActionSurface?: (details: AgentActionSurfaceDetails) => AgentActionSurface | Promise<AgentActionSurface>;
317
347
  /** Optional per-app agent run chunk budget in milliseconds. Defaults to
318
348
  * AGENT_RUN_SOFT_TIMEOUT_MS when set, otherwise no framework-imposed
319
349
  * timeout. When reached, the client receives an internal auto-continuation
@@ -16,7 +16,7 @@ import { completeRun as completeProgressRun, startRun as startProgressRun, updat
16
16
  import { isRuntimeVisibleScope, parseSkillFrontmatter, } from "../server/agent-chat/skill-frontmatter.js";
17
17
  import { canUseDeployCredentialFallbackForRequest, getProviderCredentialAuthFailure, readDeployCredentialEnv, } from "../server/credential-provider.js";
18
18
  import { readBody } from "../server/h3-helpers.js";
19
- import { getRequestRunContext, ensureRequestRunContext, getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
19
+ import { assertRequestActionSurfaceIsolation, getRequestRunContext, ensureRequestRunContext, getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
20
20
  import { fireInternalDispatch } from "../server/self-dispatch.js";
21
21
  import { isReasoningEffort, normalizeReasoningEffortForRequest, stepDownReasoningEffort, } from "../shared/reasoning-effort.js";
22
22
  import { actionPreparationContinuationNote } from "./action-continuation-guidance.js";
@@ -391,6 +391,55 @@ export async function resolveOwnerEngineApiKey(input) {
391
391
  export async function getOwnerAnthropicApiKey(ownerEmail) {
392
392
  return getOwnerApiKey("anthropic", ownerEmail);
393
393
  }
394
+ function hasOwn(value, propertyName) {
395
+ return (typeof value === "object" &&
396
+ value !== null &&
397
+ Object.prototype.hasOwnProperty.call(value, propertyName));
398
+ }
399
+ /** Read a persisted allowlist while preserving legacy absence and failing
400
+ * closed when the field is present but malformed. */
401
+ export function readPersistedAllowedActionNames(value) {
402
+ if (!hasOwn(value, "allowedActionNames"))
403
+ return undefined;
404
+ const names = value.allowedActionNames;
405
+ if (!Array.isArray(names) ||
406
+ !names.every((name) => typeof name === "string")) {
407
+ return [];
408
+ }
409
+ return [...new Set(names)];
410
+ }
411
+ /** Read a nested persisted action surface. An absent envelope is legacy;
412
+ * a present but invalid envelope is an explicit org-less, empty surface. */
413
+ export function readPersistedActionSurface(value, propertyName) {
414
+ if (!hasOwn(value, propertyName))
415
+ return undefined;
416
+ const surface = value[propertyName];
417
+ const allowedActionNames = readPersistedAllowedActionNames(surface) ?? [];
418
+ if (!hasOwn(surface, "orgId")) {
419
+ return { orgId: null, allowedActionNames: [] };
420
+ }
421
+ const orgId = surface.orgId;
422
+ if (orgId !== null &&
423
+ (typeof orgId !== "string" || orgId.trim().length === 0)) {
424
+ return { orgId: null, allowedActionNames: [] };
425
+ }
426
+ return { orgId, allowedActionNames };
427
+ }
428
+ export function filterActionsByAllowedNames(actions, allowedActionNames) {
429
+ const allowedNames = [...new Set(allowedActionNames)];
430
+ const unknownNames = allowedNames.filter((name) => !Object.prototype.hasOwnProperty.call(actions, name));
431
+ if (unknownNames.length > 0) {
432
+ throw new Error(`resolveActionSurface returned unknown action name(s): ${unknownNames.join(", ")}`);
433
+ }
434
+ const filtered = Object.fromEntries(allowedNames.map((name) => [name, actions[name]]));
435
+ // `attachToolSearch` closes over the registry it was originally attached to.
436
+ // Rebind it to this request's filtered registry so explicitly allowing
437
+ // `tool-search` cannot disclose actions that the resolver omitted.
438
+ if (filtered[TOOL_SEARCH_ACTION_NAME]) {
439
+ filtered[TOOL_SEARCH_ACTION_NAME] = createToolSearchEntry(() => filtered);
440
+ }
441
+ return filtered;
442
+ }
394
443
  export const PLAN_MODE_SYSTEM_PROMPT = `## Plan Mode Active
395
444
 
396
445
  You are in Plan mode. This turn is for research, clarification, and a proposed approach only.
@@ -6031,6 +6080,9 @@ export function resolveAgentRequestReasoningEffort({ model, requestEffort, confi
6031
6080
  return normalizeReasoningEffortForRequest(model, isReasoningEffort(requestEffort) ? requestEffort : configuredEffort);
6032
6081
  }
6033
6082
  export function createProductionAgentHandler(options) {
6083
+ if (options.resolveActionSurface) {
6084
+ assertRequestActionSurfaceIsolation();
6085
+ }
6034
6086
  // Undefined = let each engine pick its own defaultModel at request time.
6035
6087
  const configuredModel = options.model;
6036
6088
  // Resolve actions — prefer `actions`, fall back to deprecated `scripts`
@@ -6040,7 +6092,7 @@ export function createProductionAgentHandler(options) {
6040
6092
  // the settings UI) show up to the LLM without a process restart. MCP tools
6041
6093
  // are also scope-filtered per request — a user-scope server added by Alice
6042
6094
  // must not appear in Bob's tool list in a shared-process deployment.
6043
- const getEngineTools = (actions = resolvedActions) => {
6095
+ const getRequestActions = (actions = resolvedActions) => {
6044
6096
  const filtered = {};
6045
6097
  for (const [name, entry] of Object.entries(actions)) {
6046
6098
  if (name.startsWith("mcp__") && !isMcpToolAllowedForRequest(name)) {
@@ -6048,8 +6100,9 @@ export function createProductionAgentHandler(options) {
6048
6100
  }
6049
6101
  filtered[name] = entry;
6050
6102
  }
6051
- return actionsToEngineTools(filtered);
6103
+ return filtered;
6052
6104
  };
6105
+ const getEngineTools = (actions) => actionsToEngineTools(getRequestActions(actions));
6053
6106
  return defineEventHandler(async (event) => {
6054
6107
  // Diagnostic-only setup-timing instrumentation. Captures wall-clock offsets
6055
6108
  // from handler entry through the work done BEFORE startRun so a slow pre-run
@@ -6089,12 +6142,20 @@ export function createProductionAgentHandler(options) {
6089
6142
  // (the route HMAC-verifies the dispatch before invoking us). When set, we
6090
6143
  // run the loop inline with the background soft-timeout, reusing the
6091
6144
  // pre-claimed runId/turnId — we must NOT re-claim the slot or re-dispatch.
6092
- const backgroundRunMarker = body[AGENT_CHAT_BACKGROUND_RUN_FIELD] &&
6145
+ const backgroundRunMarker = preInjectedBody &&
6146
+ body[AGENT_CHAT_BACKGROUND_RUN_FIELD] &&
6093
6147
  typeof body[AGENT_CHAT_BACKGROUND_RUN_FIELD] === "object" &&
6094
6148
  typeof body[AGENT_CHAT_BACKGROUND_RUN_FIELD].runId === "string"
6095
6149
  ? body[AGENT_CHAT_BACKGROUND_RUN_FIELD]
6096
6150
  : null;
6097
6151
  const isBackgroundWorker = backgroundRunMarker !== null;
6152
+ // Both fields are internal durable-dispatch artifacts, never client input.
6153
+ // A body marker alone is not proof of worker identity: only the verified
6154
+ // `_process-run` route can install `preInjectedBody` on the event context.
6155
+ if (!isBackgroundWorker) {
6156
+ delete body[AGENT_CHAT_BACKGROUND_RUN_FIELD];
6157
+ delete body.__resolvedActionSurface;
6158
+ }
6098
6159
  // DIAGNOSTIC-ONLY: progressive per-stage hang localizer for the bg worker.
6099
6160
  // The worker's runId is available EARLY on the marker (the general `runId`
6100
6161
  // var resolves much later), so capture it now and emit the LAST setup stage
@@ -6197,6 +6258,35 @@ export function createProductionAgentHandler(options) {
6197
6258
  requestAttachments = preparedRequest.attachments;
6198
6259
  }
6199
6260
  }
6261
+ const availableRequestActions = getRequestActions();
6262
+ let surfacedRequestActions = availableRequestActions;
6263
+ if (options.resolveActionSurface) {
6264
+ const persistedSurface = isBackgroundWorker
6265
+ ? readPersistedActionSurface(body, "__resolvedActionSurface")
6266
+ : undefined;
6267
+ const surface = persistedSurface !== undefined
6268
+ ? persistedSurface
6269
+ : await options.resolveActionSurface({
6270
+ event,
6271
+ ownerEmail,
6272
+ orgId: getRequestOrgId() ?? null,
6273
+ threadId,
6274
+ mode: requestMode,
6275
+ internalContinuation: Boolean(internalContinuation),
6276
+ availableActionNames: Object.keys(availableRequestActions),
6277
+ });
6278
+ surfacedRequestActions = filterActionsByAllowedNames(availableRequestActions, surface.allowedActionNames);
6279
+ const allowedNames = Object.keys(surfacedRequestActions);
6280
+ const runCtx = ensureRequestRunContext();
6281
+ if (runCtx)
6282
+ runCtx.allowedActionNames = allowedNames;
6283
+ if (!isBackgroundWorker) {
6284
+ body.__resolvedActionSurface = {
6285
+ orgId: getRequestOrgId() ?? null,
6286
+ allowedActionNames: allowedNames,
6287
+ };
6288
+ }
6289
+ }
6200
6290
  // DIAGNOSTIC-ONLY: owner/request context prep (resolveAgentOwnerEmail +
6201
6291
  // prepareRequest) finished. A worker stuck before this points at the
6202
6292
  // owner/request-context awaits.
@@ -6428,7 +6518,7 @@ export function createProductionAgentHandler(options) {
6428
6518
  const screenContextThunk = () => (async () => {
6429
6519
  const screenStart = Date.now();
6430
6520
  try {
6431
- const viewScreenAction = resolvedActions["view-screen"];
6521
+ const viewScreenAction = surfacedRequestActions["view-screen"];
6432
6522
  if (viewScreenAction) {
6433
6523
  const result = await viewScreenAction.run({}, {
6434
6524
  userEmail: getRequestUserEmail(),
@@ -6667,10 +6757,12 @@ export function createProductionAgentHandler(options) {
6667
6757
  }
6668
6758
  const screenContext = timeBlock + screenBlock + urlBlock + selectionBlock;
6669
6759
  const requestActions = requestMode === "plan"
6670
- ? createPlanModeActionRegistry(resolvedActions)
6671
- : resolvedActions;
6760
+ ? createPlanModeActionRegistry(surfacedRequestActions)
6761
+ : surfacedRequestActions;
6672
6762
  const availableRequestTools = getEngineTools(requestActions);
6673
- const initialRequestTools = filterInitialEngineTools(availableRequestTools, options.initialToolNames);
6763
+ const initialRequestTools = options.resolveActionSurface
6764
+ ? availableRequestTools
6765
+ : filterInitialEngineTools(availableRequestTools, options.initialToolNames);
6674
6766
  const requestTools = requestMode === "plan"
6675
6767
  ? preloadPlanModeEngineTools({
6676
6768
  request: requestMessage,
@@ -186,6 +186,15 @@ export interface AgentChatRequest {
186
186
  */
187
187
  payloadRef?: boolean;
188
188
  };
189
+ /**
190
+ * Server-resolved action authorization carried across authenticated durable
191
+ * background dispatches. Normal client requests must not trust this field;
192
+ * the foreground handler deletes and replaces it before persistence.
193
+ */
194
+ __resolvedActionSurface?: {
195
+ orgId: string | null;
196
+ allowedActionNames: string[];
197
+ };
189
198
  /**
190
199
  * Stable identity for the logical assistant turn this request belongs to.
191
200
  * The client sends the SAME turnId for the initial POST and every
@@ -201,6 +201,18 @@ export interface AgentSidebarProps {
201
201
  chatViewTransitionHandoff?: boolean;
202
202
  /** Namespace for persisted chat state. Use the same key as AgentChatHome. */
203
203
  storageKey?: string;
204
+ /** Namespace for the persisted open/closed preference. Defaults to storageKey. */
205
+ openStorageKey?: string;
206
+ /** API base URL used by the chat surface. */
207
+ apiUrl?: string;
208
+ /** Runtime surface identity used for server-side chat capabilities. */
209
+ agentChatSurface?: AgentChatSurfaceKind;
210
+ /** Show the chat thread tab row. Default: true. */
211
+ showTabBar?: MultiTabAssistantChatProps["showTabBar"];
212
+ /** Keep inline app-opening results inside the current app chat. */
213
+ suppressInlineOpenApp?: AssistantChatProps["suppressInlineOpenApp"];
214
+ /** Placeholder shown in the chat composer. */
215
+ composerPlaceholder?: AssistantChatProps["composerPlaceholder"];
204
216
  /** Open the sidebar when a chat run is active or reconnects. */
205
217
  openOnChatRunning?: boolean;
206
218
  /** Called when the user selects the full-view action from the chat sidebar. */
@@ -222,7 +234,7 @@ export interface AgentSidebarProps {
222
234
  * Wraps app content with a toggleable agent sidebar.
223
235
  * Use AgentToggleButton in your header to open/close it.
224
236
  */
225
- export declare function AgentSidebar({ children, emptyStateText, suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position, defaultOpen, animateMobile, animateDesktop, chatViewTransition, chatViewTransitionHandoff, storageKey, openOnChatRunning, onFullscreenRequest, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding, }: AgentSidebarProps): React.JSX.Element;
237
+ export declare function AgentSidebar({ children, emptyStateText, suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position, defaultOpen, animateMobile, animateDesktop, chatViewTransition, chatViewTransitionHandoff, storageKey, openStorageKey, apiUrl, agentChatSurface, showTabBar, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning, onFullscreenRequest, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding, }: AgentSidebarProps): React.JSX.Element;
226
238
  /**
227
239
  * Focus the agent chat composer input.
228
240
  * Opens the sidebar if closed, then focuses the text input.
@@ -200,6 +200,7 @@ function IconTooltip({ content, children, }) {
200
200
  return (_jsx(DesignSystemTooltip, { trigger: children, content: normalizeTooltipText(content), placement: "bottom", delayMs: 250, className: "z-[300] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md" }));
201
201
  }
202
202
  function ChatLoadingSkeleton({ renderHeader, centerComposerWhenEmpty = false, composerSlot, composerAreaClassName, composerLayoutVariant = "default", }) {
203
+ const t = useT();
203
204
  // Provide empty no-op implementations so renderHeader can render the real
204
205
  // tab/mode buttons without needing actual chat state.
205
206
  const noop = useCallback(() => { }, []);
@@ -219,7 +220,7 @@ function ChatLoadingSkeleton({ renderHeader, centerComposerWhenEmpty = false, co
219
220
  toggleHistory: noop,
220
221
  };
221
222
  if (centerComposerWhenEmpty) {
222
- return (_jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [renderHeader ? renderHeader(stubProps) : null, _jsxs("div", { "data-agent-empty-state": "centered", className: "relative flex flex-1 flex-col h-full min-h-0 text-foreground", children: [_jsx("div", { className: "agent-chat-scroll flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: _jsx("div", { className: "agent-empty-state sr-only", "aria-busy": "true", children: "Loading chat..." }) }), composerSlot, _jsx("div", { className: "agent-composer-stack", children: _jsx("div", { className: cn("agent-composer-area shrink-0 px-3 py-2", composerLayoutVariant !== "default" &&
223
+ return (_jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [renderHeader ? renderHeader(stubProps) : null, _jsxs("div", { "data-agent-empty-state": "centered", className: "relative flex flex-1 flex-col h-full min-h-0 text-foreground", children: [_jsx("div", { className: "agent-chat-scroll flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: _jsx("div", { className: "agent-empty-state sr-only", "aria-busy": "true", children: t("agentChat.empty.loadingChat") }) }), composerSlot, _jsx("div", { className: "agent-composer-stack", children: _jsx("div", { className: cn("agent-composer-area shrink-0 px-3 py-2", composerLayoutVariant !== "default" &&
223
224
  `agent-composer-area--${composerLayoutVariant}`, composerAreaClassName), children: _jsxs("div", { className: cn("agent-composer-root flex flex-col rounded-lg border border-input bg-muted/45 transition-colors", composerLayoutVariant !== "default" &&
224
225
  `agent-composer-root--${composerLayoutVariant}`), children: [_jsx("div", { className: "px-3 pt-3", children: _jsx("div", { className: "h-5 w-3/5 rounded bg-muted animate-pulse motion-reduce:animate-none" }) }), _jsxs("div", { className: "mt-auto flex items-center gap-2 px-3 py-2", children: [_jsx("div", { className: "h-5 w-5 rounded bg-muted animate-pulse motion-reduce:animate-none" }), _jsx("div", { className: "ml-auto h-4 w-28 rounded bg-muted animate-pulse motion-reduce:animate-none" }), _jsx("div", { className: "h-7 w-7 rounded-md bg-muted animate-pulse motion-reduce:animate-none" })] })] }) }) })] })] }));
225
226
  }
@@ -721,7 +722,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
721
722
  (activeTabMessageCount <= 0 && activeTab.status === "idle")) {
722
723
  return null;
723
724
  }
724
- return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7", defaultOpen: onCollapse && shareFromMenuOpen, onOpenChange: onCollapse ? setShareFromMenuOpen : undefined }));
725
+ return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || t("agentPanel.chat"), shareUrl: getChatThreadShareUrl(activeTab.id), triggerClassName: "h-7 px-2", defaultOpen: onCollapse && shareFromMenuOpen, onOpenChange: onCollapse ? setShareFromMenuOpen : undefined }));
725
726
  })(), feedbackEnabled ? (_jsx(FeedbackButton, { variant: "icon", side: "bottom", align: "end", chatSessionId: activeChatSessionId, chatStorageKey: storageKey, open: feedbackOpen, onOpenChange: setFeedbackOpen, trigger: _jsx("button", { type: "button", tabIndex: -1, "aria-hidden": "true", className: "pointer-events-none absolute end-0 top-full h-px w-px opacity-0" }) })) : null, mode === "chat" && (_jsx(IconTooltip, { content: t("agentPanel.newChat"), children: _jsx("button", { onClick: addTab, "aria-label": t("agentPanel.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), !onCollapse && mode === "cli" && canUseCodeTools && (_jsx(IconTooltip, { content: t("agentPanel.newTerminal"), children: _jsx("button", { onClick: addCliTab, "aria-label": t("agentPanel.newTerminal"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), _jsxs(DropdownMenu, { open: headerMenuOpen, onOpenChange: setHeaderMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", (headerMenuOpen || mode === "settings") &&
726
727
  "bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", onCloseAutoFocus: (event) => {
727
728
  // A sibling overlay owns focus next; restoring it to the menu
@@ -785,7 +786,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
785
786
  ? tabs.find((tab) => tab.id === activeTabId)
786
787
  : undefined;
787
788
  const canShareActiveTab = activeTab && (activeTabMessageCount > 0 || activeTab.status !== "idle");
788
- return (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", "data-agent-page-chat-fade": "", className: "pointer-events-none absolute inset-x-0 top-0 z-50 h-16 bg-gradient-to-b from-background via-background/90 to-transparent opacity-0 transition-opacity duration-150" }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 top-3 z-[60] flex justify-end px-3 sm:top-4 sm:px-4", children: _jsxs("div", { className: "pointer-events-auto flex items-center gap-1", children: [canShareActiveTab ? (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-8 w-8 border border-border bg-background/95 shadow-sm backdrop-blur hover:bg-accent" })) : null, _jsxs("button", { type: "button", "data-agent-page-new-chat": "", "aria-label": t("agentPanel.newChat"), onClick: () => {
789
+ return (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", "data-agent-page-chat-fade": "", className: "pointer-events-none absolute inset-x-0 top-0 z-50 h-16 bg-gradient-to-b from-background via-background/90 to-transparent opacity-0 transition-opacity duration-150" }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 top-3 z-[60] flex justify-end px-3 sm:top-4 sm:px-4", children: _jsxs("div", { className: "pointer-events-auto flex items-center gap-1", children: [canShareActiveTab ? (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || t("agentPanel.chat"), shareUrl: getChatThreadShareUrl(activeTab.id), triggerClassName: "h-8 px-2 border border-border bg-background/95 shadow-sm backdrop-blur hover:bg-accent" })) : null, _jsxs("button", { type: "button", "data-agent-page-new-chat": "", "aria-label": t("agentPanel.newChat"), onClick: () => {
789
790
  addTab();
790
791
  }, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background/95 px-2.5 text-xs font-medium text-foreground shadow-sm backdrop-blur transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconPlus, { size: 14 }), _jsx("span", { children: t("agentPanel.newChat") })] })] }) })] }));
791
792
  }, [getChatThreadShareUrl, t]);
@@ -829,7 +830,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
829
830
  activeTab?.parentThreadId === tab.id);
830
831
  return (_jsxs("div", { role: "button", tabIndex: 0, ref: isActive ? activeTabRefCb : undefined, onClick: () => setActiveTabId(tab.id), onKeyDown: activateOnKeyDown(() => setActiveTabId(tab.id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer max-w-[150px]", isActive
831
832
  ? "bg-accent text-foreground"
832
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
833
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
833
834
  e.stopPropagation();
834
835
  closeTab(tab.id);
835
836
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -872,7 +873,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
872
873
  activeTab?.parentThreadId === tab.id);
873
874
  return (_jsxs("div", { role: "button", tabIndex: 0, ref: isActive ? activeTabRefCb : undefined, onClick: () => setActiveTabId(tab.id), onKeyDown: activateOnKeyDown(() => setActiveTabId(tab.id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer max-w-[150px]", isActive
874
875
  ? "bg-accent text-foreground"
875
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
876
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
876
877
  e.stopPropagation();
877
878
  closeTab(tab.id);
878
879
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -890,7 +891,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
890
891
  ? activeTabRefCb
891
892
  : undefined, onClick: () => setActiveCliTab(id), onKeyDown: activateOnKeyDown(() => setActiveCliTab(id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer", id === activeCliTab
892
893
  ? "bg-accent text-foreground"
893
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsxs("span", { children: ["Terminal ", i + 1] }), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
894
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsxs("span", { children: ["Terminal ", i + 1] }), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
894
895
  e.stopPropagation();
895
896
  closeCliTab(id);
896
897
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -908,7 +909,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
908
909
  ? activeTabRefCb
909
910
  : undefined, onClick: () => setActiveTabId(tab.id), onKeyDown: activateOnKeyDown(() => setActiveTabId(tab.id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium cursor-pointer max-w-[140px]", tab.id === activeTabId
910
911
  ? "bg-accent text-foreground"
911
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.subAgentName || tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1 w-1 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
912
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.subAgentName || tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1 w-1 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
912
913
  e.stopPropagation();
913
914
  closeTab(tab.id);
914
915
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -937,6 +938,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
937
938
  activeTabRefCb,
938
939
  activateOnKeyDown,
939
940
  closeCliTab,
941
+ t,
940
942
  ]);
941
943
  return (_jsxs("div", { className: cn("agent-panel-root flex flex-1 flex-col min-h-0 h-full text-[13px] leading-[1.2] antialiased", className), style: {
942
944
  ...AGENT_PANEL_ROOT_STYLE,
@@ -972,7 +974,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
972
974
  ? mode === "cli" &&
973
975
  cliTabs.map((id) => (_jsx("div", { className: "min-h-0 relative flex-1", style: {
974
976
  display: id === activeCliTab ? undefined : "none",
975
- }, children: _jsx(Suspense, { fallback: _jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground text-sm", children: "Loading terminal..." }), children: _jsx(AgentTerminal, { command: selectedCli, hideInFrame: false, className: "h-full", style: { background: "transparent" } }) }) }, id)))
977
+ }, children: _jsx(Suspense, { fallback: _jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground text-sm", children: t("agentPanel.loadingTerminal") }), children: _jsx(AgentTerminal, { command: selectedCli, hideInFrame: false, className: "h-full", style: { background: "transparent" } }) }) }, id)))
976
978
  : mode === "cli" && (_jsx("div", { className: "flex flex-1 flex-col items-center justify-center min-h-0 px-6 gap-3", children: _jsx(CodeAccessUnavailablePanel, { title: codeAccessEnabled
977
979
  ? t("agentPanel.cliRequiresDevMode")
978
980
  : codeUnavailableTitle, description: codeAccessEnabled
@@ -1405,14 +1407,16 @@ export function AgentChatSurface({ mode = "panel", className, defaultMode = "cha
1405
1407
  * Wraps app content with a toggleable agent sidebar.
1406
1408
  * Use AgentToggleButton in your header to open/close it.
1407
1409
  */
1408
- export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openOnChatRunning = false, onFullscreenRequest, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
1410
+ export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, apiUrl, agentChatSurface, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
1411
+ const sidebarOpenStorageKey = openStorageKey ?? storageKey;
1409
1412
  const onboardingPreviewMode = useOnboardingPreviewMode();
1410
1413
  const firstRunOnboardingGateOwnsSurface = useFirstRunOnboardingGateOwnsSurface();
1411
1414
  const showFirstRunOnboarding = !firstRunOnboardingGateOwnsSurface &&
1412
1415
  !suppressFirstRunOnboarding &&
1413
1416
  (SHOW_FIRST_RUN_ONBOARDING || onboardingPreviewMode);
1414
1417
  const initialWidth = defaultSidebarWidth ?? sidebarWidth ?? 380;
1415
- const [open, setOpen] = useState(() => openOnChatRunning || getInitialAgentSidebarOpen(defaultOpen, storageKey));
1418
+ const [open, setOpen] = useState(() => openOnChatRunning ||
1419
+ getInitialAgentSidebarOpen(defaultOpen, sidebarOpenStorageKey));
1416
1420
  const [presentationMode, setPresentationMode] = useState(false);
1417
1421
  const [width, setWidth] = useState(initialWidth);
1418
1422
  const [isWideDrawer, setIsWideDrawer] = useState(() => {
@@ -1469,15 +1473,15 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1469
1473
  const setOpenPersisted = useCallback((next) => {
1470
1474
  setOpen((prev) => {
1471
1475
  const value = typeof next === "function" ? next(prev) : next;
1472
- setAgentSidebarOpenPreference(value, storageKey);
1476
+ setAgentSidebarOpenPreference(value, sidebarOpenStorageKey);
1473
1477
  return value;
1474
1478
  });
1475
- }, [storageKey]);
1479
+ }, [sidebarOpenStorageKey]);
1476
1480
  const applyUrlOpenOverride = useCallback(() => {
1477
- const override = consumeAgentSidebarUrlOpenOverride(storageKey);
1481
+ const override = consumeAgentSidebarUrlOpenOverride(sidebarOpenStorageKey);
1478
1482
  if (override !== null)
1479
1483
  setOpenPersisted(override);
1480
- }, [setOpenPersisted, storageKey]);
1484
+ }, [setOpenPersisted, sidebarOpenStorageKey]);
1481
1485
  useEffect(() => {
1482
1486
  applyUrlOpenOverride();
1483
1487
  return subscribeAgentSidebarUrlChanges(applyUrlOpenOverride);
@@ -1922,11 +1926,11 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1922
1926
  ? "desktop"
1923
1927
  : undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": position, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
1924
1928
  ? getAgentChatViewTransitionStyle(panelStyle)
1925
- : panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, threadFooterSlot: threadFooterSlot, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
1929
+ : panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, showTabBar: showTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
1926
1930
  const drawerPlaceholder = wideDrawerEnabled && !presentationMode && panelOpen ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-drawer-placeholder shrink-0", "data-agent-sidebar-placeholder": "true", style: { width: drawerPlaceholderWidth + 1 } })) : null;
1927
1931
  return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": position, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
1928
1932
  !presentationMode &&
1929
- (mobileAnimationEnabled ? shouldRenderPanel : open) && (_jsx("div", { className: cn("agent-sidebar-backdrop fixed inset-0 bg-foreground/40", mobileAnimationEnabled && !panelOpen && "pointer-events-none"), "data-agent-sidebar-animation": mobileAnimationEnabled ? "mobile" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", style: { zIndex: SIDEBAR_OVERLAY_Z_INDEX - 1 }, onClick: () => setOpenPersisted(false) })), shouldMountPanel ? _jsx(URLSync, { browserTabId: browserTabId }) : null, isLeft && !presentationMode ? sidebar : null, isLeft && !presentationMode ? drawerPlaceholder : null, _jsx("div", { className: "agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0", "data-agent-sidebar-main-position": position, "data-agent-sidebar-main-state": !isMobile && !presentationMode && panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? drawerPlaceholder : null, !isLeft && !presentationMode ? sidebar : null] })] }) }));
1933
+ (mobileAnimationEnabled ? shouldRenderPanel : open) && (_jsx("div", { className: cn("agent-sidebar-backdrop fixed inset-0 bg-foreground/40", mobileAnimationEnabled && !panelOpen && "pointer-events-none"), "data-agent-sidebar-animation": mobileAnimationEnabled ? "mobile" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", style: { zIndex: SIDEBAR_OVERLAY_Z_INDEX - 1 }, onClick: () => setOpenPersisted(false) })), shouldMountPanel ? _jsx(URLSync, { browserTabId: browserTabId }) : null, isResizing ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-resize-overlay" })) : null, isLeft && !presentationMode ? sidebar : null, isLeft && !presentationMode ? drawerPlaceholder : null, _jsx("div", { className: "agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0", "data-agent-sidebar-main-position": position, "data-agent-sidebar-main-state": !isMobile && !presentationMode && panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? drawerPlaceholder : null, !isLeft && !presentationMode ? sidebar : null] })] }) }));
1930
1934
  }
1931
1935
  /**
1932
1936
  * Focus the agent chat composer input.
@@ -1957,6 +1961,7 @@ export function focusAgentChat() {
1957
1961
  * Dispatches a custom event that AgentSidebar listens for.
1958
1962
  */
1959
1963
  export function AgentToggleButton({ className }) {
1964
+ const t = useT();
1960
1965
  const [open, setOpen] = useState(false);
1961
1966
  useEffect(() => {
1962
1967
  const handler = (event) => {
@@ -1972,5 +1977,5 @@ export function AgentToggleButton({ className }) {
1972
1977
  // own close button.
1973
1978
  if (open)
1974
1979
  return null;
1975
- return (_jsx(DesignSystemTooltip, { trigger: _jsx("button", { type: "button", "aria-label": "Toggle agent", onClick: () => window.dispatchEvent(new Event("agent-panel:toggle")), className: cn("inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", className), children: _jsx(IconMessageDots, { size: 20, "aria-hidden": true }) }), content: "Toggle agent", delayMs: 200 }));
1980
+ return (_jsx(DesignSystemTooltip, { trigger: _jsx("button", { type: "button", "aria-label": t("agentPanel.toggleAgent"), onClick: () => window.dispatchEvent(new Event("agent-panel:toggle")), className: cn("inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", className), children: _jsx(IconMessageDots, { size: 20, "aria-hidden": true }) }), content: t("agentPanel.toggleAgent"), delayMs: 200 }));
1976
1981
  }
@@ -132,11 +132,22 @@ export declare function resolveAssistantChatRunningState({ forceStopped, isRunti
132
132
  isRunning: boolean;
133
133
  showRunningInUI: boolean;
134
134
  };
135
- export declare function resolveAssistantChatRunningStatusLabel({ runningActivityLabel, isAutoResuming, isReconnecting, hasReconnectContent, }: {
135
+ export declare function resolveAssistantChatRunningStatusLabel({ runningActivityLabel, isAutoResuming, isReconnecting, hasReconnectContent, labels, }: {
136
136
  runningActivityLabel: string | null | undefined;
137
137
  isAutoResuming: boolean;
138
138
  isReconnecting: boolean;
139
139
  hasReconnectContent: boolean;
140
+ labels?: {
141
+ thinking: string;
142
+ resuming: string;
143
+ stillWorking: string;
144
+ working?: string;
145
+ contactingModel?: string;
146
+ starting?: (activity: string) => string;
147
+ preparing?: (activity: string) => string;
148
+ writing?: (activity: string) => string;
149
+ stillGenerating?: (activity: string) => string;
150
+ };
140
151
  }): string;
141
152
  export declare function resolveAssistantChatComposerPlaceholder(composerPlaceholder: string | null | undefined): string;
142
153
  export declare function shouldShowGlobalRunningStatus({ showRunningInUI, runningActivityLabel, runningActivityTool, latestMessage, reconnectContent, }: {
@@ -311,6 +322,8 @@ export interface AssistantChatProps {
311
322
  composerToolbarSlot?: React.ReactNode;
312
323
  /** Optional action rendered beside the voice/send controls. */
313
324
  composerExtraActionButton?: React.ReactNode;
325
+ /** Show the framework model picker in the shared composer. Defaults to true. */
326
+ showModelSelector?: boolean;
314
327
  /** Disable the composer for capability-gated surfaces while still showing history. */
315
328
  composerDisabled?: boolean;
316
329
  /** Placeholder to show while the composer is disabled by the host surface. */
@@ -410,6 +423,7 @@ export interface AssistantChatProps {
410
423
  onAlwaysAllow?: (approvalKey: string) => void;
411
424
  };
412
425
  }
426
+ export declare function shouldShowAssistantChatModelSelector(showModelSelector: boolean | undefined): boolean;
413
427
  export declare const CHAT_STORAGE_PREFIX = "agent-chat:";
414
428
  /** Remove persisted chat for a given tabId (or "default"). */
415
429
  export declare function clearChatStorage(tabId?: string): void;