@mastra/server 1.64.0-alpha.5 → 1.64.0-alpha.7

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 (28) hide show
  1. package/README.md +27 -33
  2. package/dist/{a2a-CMi5AZNR.js → a2a-DdCHhKh5.js} +7 -7
  3. package/dist/{a2a-CMi5AZNR.js.map → a2a-DdCHhKh5.js.map} +1 -1
  4. package/dist/{api-schema-manifest-C0fowe3V.js → api-schema-manifest-Ckuac2Uz.js} +2 -2
  5. package/dist/{api-schema-manifest-C0fowe3V.js.map → api-schema-manifest-Ckuac2Uz.js.map} +1 -1
  6. package/dist/{dist-JaHKn7NU.js → dist-BwPO-2NT.js} +1667 -1378
  7. package/dist/dist-BwPO-2NT.js.map +1 -0
  8. package/dist/{dist-BuyLBfu3.cjs → dist-mj70vroq.cjs} +1667 -1377
  9. package/dist/dist-mj70vroq.cjs.map +1 -0
  10. package/dist/docs/SKILL.md +1 -1
  11. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  12. package/dist/{routes-D9HqtkO2.js → routes-DCdH7ljX.js} +2 -2
  13. package/dist/{routes-D9HqtkO2.js.map → routes-DCdH7ljX.js.map} +1 -1
  14. package/dist/server/browser-stream/index.cjs +4 -2
  15. package/dist/server/browser-stream/index.cjs.map +1 -1
  16. package/dist/server/browser-stream/index.js +4 -2
  17. package/dist/server/browser-stream/index.js.map +1 -1
  18. package/dist/server/browser-stream/viewer-registry.d.ts +2 -0
  19. package/dist/server/browser-stream/viewer-registry.d.ts.map +1 -1
  20. package/dist/server/handlers/a2a.js +1 -1
  21. package/dist/server/handlers/agent-builder.cjs +1 -1
  22. package/dist/server/handlers/agent-builder.js +1 -1
  23. package/dist/server/handlers/system.js +1 -1
  24. package/dist/server/handlers.js +1 -1
  25. package/dist/server/server-adapter/index.js +1 -1
  26. package/package.json +6 -6
  27. package/dist/dist-BuyLBfu3.cjs.map +0 -1
  28. package/dist/dist-JaHKn7NU.js.map +0 -1
@@ -3,7 +3,7 @@ name: mastra-server
3
3
  description: Documentation for @mastra/server. Use when working with @mastra/server APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/server"
6
- version: "1.64.0-alpha.5"
6
+ version: "1.64.0-alpha.7"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.64.0-alpha.5",
2
+ "version": "1.64.0-alpha.7",
3
3
  "package": "@mastra/server",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -3,7 +3,7 @@ import { CANCEL_WORKFLOW_RUN_ROUTE, CREATE_WORKFLOW_RUN_ROUTE, DELETE_WORKFLOW_R
3
3
  import { CANCEL_AGENT_BUILDER_ACTION_RUN_ROUTE, CREATE_AGENT_BUILDER_ACTION_RUN_ROUTE, GET_AGENT_BUILDER_ACTION_BY_ID_ROUTE, GET_AGENT_BUILDER_ACTION_RUN_BY_ID_ROUTE, LIST_AGENT_BUILDER_ACTIONS_ROUTE, LIST_AGENT_BUILDER_ACTION_RUNS_ROUTE, OBSERVE_STREAM_AGENT_BUILDER_ACTION_ROUTE, OBSERVE_STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE, RESUME_AGENT_BUILDER_ACTION_ROUTE, RESUME_ASYNC_AGENT_BUILDER_ACTION_ROUTE, RESUME_NO_WAIT_AGENT_BUILDER_ACTION_ROUTE, RESUME_STREAM_AGENT_BUILDER_ACTION_ROUTE, START_AGENT_BUILDER_ACTION_RUN_ROUTE, START_ASYNC_AGENT_BUILDER_ACTION_ROUTE, STREAM_AGENT_BUILDER_ACTION_ROUTE, STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE } from "./server/handlers/agent-builder.js";
4
4
  import { ABORT_AGENT_THREAD_ROUTE, APPROVE_NETWORK_TOOL_CALL_ROUTE, APPROVE_TOOL_CALL_GENERATE_ROUTE, APPROVE_TOOL_CALL_ROUTE, CLONE_AGENT_ROUTE, DECLINE_NETWORK_TOOL_CALL_ROUTE, DECLINE_TOOL_CALL_GENERATE_ROUTE, DECLINE_TOOL_CALL_ROUTE, ENHANCE_INSTRUCTIONS_ROUTE, GENERATE_AGENT_ROUTE, GENERATE_AGENT_VNEXT_ROUTE, GENERATE_LEGACY_ROUTE, GET_AGENT_BY_ID_ROUTE, GET_AGENT_SKILL_ROUTE, GET_PROVIDERS_ROUTE, LIST_AGENTS_ROUTE, LIST_SUSPENDED_RUNS_ROUTE, OBSERVE_AGENT_STREAM_ROUTE, QUEUE_AGENT_MESSAGE_ROUTE, RECOVER_ROUTE, REORDER_AGENT_MODEL_LIST_ROUTE, RESET_AGENT_MODEL_ROUTE, RESUME_STREAM_ROUTE, RESUME_STREAM_UNTIL_IDLE_ROUTE, SEND_AGENT_MESSAGE_ROUTE, SEND_AGENT_SIGNAL_ROUTE, SEND_TOOL_APPROVAL_ROUTE, STREAM_GENERATE_LEGACY_ROUTE, STREAM_GENERATE_ROUTE, STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE, STREAM_NETWORK_ROUTE, STREAM_UI_MESSAGE_DEPRECATED_ROUTE, STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE, STREAM_UNTIL_IDLE_GENERATE_ROUTE, STREAM_VNEXT_DEPRECATED_ROUTE, SUBSCRIBE_AGENT_THREAD_ROUTE, UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE, UPDATE_AGENT_MODEL_ROUTE } from "./server/handlers/agents.js";
5
5
  import { READ_AGENT_PLAN_ROUTE } from "./server/handlers/plans.js";
6
- import { n as GET_AGENT_CARD_ROUTE, t as AGENT_EXECUTION_ROUTE } from "./a2a-CMi5AZNR.js";
6
+ import { n as GET_AGENT_CARD_ROUTE, t as AGENT_EXECUTION_ROUTE } from "./a2a-DdCHhKh5.js";
7
7
  import { AUTH_ROUTES } from "./server/handlers/auth.js";
8
8
  import { CREATE_CONVERSATION_ROUTE, DELETE_CONVERSATION_ROUTE, GET_CONVERSATION_ITEMS_ROUTE, GET_CONVERSATION_ROUTE } from "./server/handlers/conversations.js";
9
9
  import { LIST_LOGS_BY_RUN_ID_ROUTE, LIST_LOGS_ROUTE, LIST_LOG_TRANSPORTS_ROUTE } from "./server/handlers/logs.js";
@@ -615,4 +615,4 @@ const SERVER_ROUTES = [
615
615
  //#endregion
616
616
  export { SERVER_ROUTES as t };
617
617
 
618
- //# sourceMappingURL=routes-D9HqtkO2.js.map
618
+ //# sourceMappingURL=routes-DCdH7ljX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes-D9HqtkO2.js","names":[],"sources":["../src/server/server-adapter/routes/a2a.ts","../src/server/server-adapter/routes/agent-builder.ts","../src/server/server-adapter/routes/agent-controller.ts","../src/server/server-adapter/routes/agents.ts","../src/server/server-adapter/routes/background-tasks.ts","../src/server/server-adapter/routes/channels.ts","../src/server/server-adapter/routes/conversations.ts","../src/server/server-adapter/routes/datasets.ts","../src/server/server-adapter/routes/dynamic-workflows.ts","../src/server/server-adapter/routes/editor-builder.ts","../src/server/server-adapter/routes/legacy.ts","../src/server/server-adapter/routes/logs.ts","../src/server/server-adapter/routes/mcp.ts","../src/server/server-adapter/routes/memory.ts","../src/server/server-adapter/routes/observability.ts","../src/server/server-adapter/routes/processor-providers.ts","../src/server/server-adapter/routes/processors.ts","../src/server/server-adapter/routes/responses.ts","../src/server/server-adapter/routes/schedules.ts","../src/server/server-adapter/routes/scorers.ts","../src/server/server-adapter/routes/stored-agents.ts","../src/server/server-adapter/routes/stored-mcp-clients.ts","../src/server/server-adapter/routes/stored-prompt-blocks.ts","../src/server/server-adapter/routes/stored-scorers.ts","../src/server/server-adapter/routes/stored-skills.ts","../src/server/server-adapter/routes/stored-workspaces.ts","../src/server/server-adapter/routes/system.ts","../src/server/server-adapter/routes/tool-providers.ts","../src/server/server-adapter/routes/tools.ts","../src/server/server-adapter/routes/vectors.ts","../src/server/server-adapter/routes/workflows.ts","../src/server/server-adapter/routes/workspace.ts","../src/server/server-adapter/routes/index.ts"],"sourcesContent":["import { GET_AGENT_CARD_ROUTE, AGENT_EXECUTION_ROUTE } from '../../handlers/a2a';\n\nexport const A2A_ROUTES = [GET_AGENT_CARD_ROUTE, AGENT_EXECUTION_ROUTE] as const;\n","import {\n LIST_AGENT_BUILDER_ACTIONS_ROUTE,\n GET_AGENT_BUILDER_ACTION_BY_ID_ROUTE,\n LIST_AGENT_BUILDER_ACTION_RUNS_ROUTE,\n GET_AGENT_BUILDER_ACTION_RUN_BY_ID_ROUTE,\n CREATE_AGENT_BUILDER_ACTION_RUN_ROUTE,\n STREAM_AGENT_BUILDER_ACTION_ROUTE,\n STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n START_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n START_AGENT_BUILDER_ACTION_RUN_ROUTE,\n OBSERVE_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n OBSERVE_STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_NO_WAIT_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n CANCEL_AGENT_BUILDER_ACTION_RUN_ROUTE,\n} from '../../handlers/agent-builder';\n\nexport const AGENT_BUILDER_ROUTES = [\n LIST_AGENT_BUILDER_ACTIONS_ROUTE,\n GET_AGENT_BUILDER_ACTION_BY_ID_ROUTE,\n LIST_AGENT_BUILDER_ACTION_RUNS_ROUTE,\n GET_AGENT_BUILDER_ACTION_RUN_BY_ID_ROUTE,\n CREATE_AGENT_BUILDER_ACTION_RUN_ROUTE,\n STREAM_AGENT_BUILDER_ACTION_ROUTE,\n STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n START_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n START_AGENT_BUILDER_ACTION_RUN_ROUTE,\n OBSERVE_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n OBSERVE_STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_NO_WAIT_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n CANCEL_AGENT_BUILDER_ACTION_RUN_ROUTE,\n] as const;\n","import {\n LIST_AGENT_CONTROLLERS_ROUTE,\n CREATE_AGENT_CONTROLLER_SESSION_ROUTE,\n GET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n STREAM_AGENT_CONTROLLER_SESSION_ROUTE,\n SEND_AGENT_CONTROLLER_MESSAGE_ROUTE,\n STEER_AGENT_CONTROLLER_SESSION_ROUTE,\n ABORT_AGENT_CONTROLLER_SESSION_ROUTE,\n AGENT_CONTROLLER_TOOL_APPROVAL_ROUTE,\n AGENT_CONTROLLER_TOOL_SUSPENSION_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODE_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODEL_ROUTE,\n SWITCH_AGENT_CONTROLLER_THREAD_ROUTE,\n LIST_AGENT_CONTROLLER_MODES_ROUTE,\n LIST_AGENT_CONTROLLER_ACTIVE_RUNS_ROUTE,\n LIST_AGENT_CONTROLLER_THREADS_ROUTE,\n SEND_AGENT_CONTROLLER_NOTIFICATION_ROUTE,\n CREATE_AGENT_CONTROLLER_THREAD_ROUTE,\n DELETE_AGENT_CONTROLLER_THREAD_ROUTE,\n RENAME_AGENT_CONTROLLER_THREAD_ROUTE,\n CLONE_AGENT_CONTROLLER_THREAD_ROUTE,\n LIST_AGENT_CONTROLLER_THREAD_MESSAGES_ROUTE,\n FOLLOW_UP_AGENT_CONTROLLER_SESSION_ROUTE,\n LIST_AGENT_CONTROLLER_MODELS_ROUTE,\n GET_AGENT_CONTROLLER_WORKSPACE_STATUS_ROUTE,\n GET_AGENT_CONTROLLER_OM_RECORD_ROUTE,\n SET_AGENT_CONTROLLER_RESOURCE_ID_ROUTE,\n GET_AGENT_CONTROLLER_RESOURCE_IDS_ROUTE,\n GET_AGENT_CONTROLLER_GOAL_ROUTE,\n SET_AGENT_CONTROLLER_GOAL_ROUTE,\n UPDATE_AGENT_CONTROLLER_GOAL_ROUTE,\n CLEAR_AGENT_CONTROLLER_GOAL_ROUTE,\n GET_AGENT_CONTROLLER_PERMISSIONS_ROUTE,\n SET_AGENT_CONTROLLER_CATEGORY_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_TOOL_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n} from '../../handlers/agent-controller';\nimport type { ServerRoute } from '.';\n\n/**\n * Canonical `AgentController` session API, served under `/agent-controller/...`.\n */\nexport const AGENT_CONTROLLER_ROUTES: readonly ServerRoute[] = [\n LIST_AGENT_CONTROLLERS_ROUTE,\n LIST_AGENT_CONTROLLER_MODES_ROUTE,\n LIST_AGENT_CONTROLLER_MODELS_ROUTE,\n LIST_AGENT_CONTROLLER_ACTIVE_RUNS_ROUTE,\n CREATE_AGENT_CONTROLLER_SESSION_ROUTE,\n GET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n LIST_AGENT_CONTROLLER_THREADS_ROUTE,\n CREATE_AGENT_CONTROLLER_THREAD_ROUTE,\n DELETE_AGENT_CONTROLLER_THREAD_ROUTE,\n RENAME_AGENT_CONTROLLER_THREAD_ROUTE,\n CLONE_AGENT_CONTROLLER_THREAD_ROUTE,\n LIST_AGENT_CONTROLLER_THREAD_MESSAGES_ROUTE,\n STREAM_AGENT_CONTROLLER_SESSION_ROUTE,\n SEND_AGENT_CONTROLLER_MESSAGE_ROUTE,\n STEER_AGENT_CONTROLLER_SESSION_ROUTE,\n FOLLOW_UP_AGENT_CONTROLLER_SESSION_ROUTE,\n ABORT_AGENT_CONTROLLER_SESSION_ROUTE,\n AGENT_CONTROLLER_TOOL_APPROVAL_ROUTE,\n AGENT_CONTROLLER_TOOL_SUSPENSION_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODE_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODEL_ROUTE,\n SWITCH_AGENT_CONTROLLER_THREAD_ROUTE,\n SEND_AGENT_CONTROLLER_NOTIFICATION_ROUTE,\n GET_AGENT_CONTROLLER_WORKSPACE_STATUS_ROUTE,\n GET_AGENT_CONTROLLER_OM_RECORD_ROUTE,\n SET_AGENT_CONTROLLER_RESOURCE_ID_ROUTE,\n GET_AGENT_CONTROLLER_RESOURCE_IDS_ROUTE,\n GET_AGENT_CONTROLLER_GOAL_ROUTE,\n SET_AGENT_CONTROLLER_GOAL_ROUTE,\n UPDATE_AGENT_CONTROLLER_GOAL_ROUTE,\n CLEAR_AGENT_CONTROLLER_GOAL_ROUTE,\n GET_AGENT_CONTROLLER_PERMISSIONS_ROUTE,\n SET_AGENT_CONTROLLER_CATEGORY_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_TOOL_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n];\n","import {\n // Agent route objects\n LIST_AGENTS_ROUTE,\n GET_AGENT_BY_ID_ROUTE,\n CLONE_AGENT_ROUTE,\n GENERATE_AGENT_ROUTE,\n GENERATE_AGENT_VNEXT_ROUTE,\n STREAM_GENERATE_ROUTE,\n STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE,\n OBSERVE_AGENT_STREAM_ROUTE,\n SEND_AGENT_MESSAGE_ROUTE,\n QUEUE_AGENT_MESSAGE_ROUTE,\n SEND_AGENT_SIGNAL_ROUTE,\n ABORT_AGENT_THREAD_ROUTE,\n SUBSCRIBE_AGENT_THREAD_ROUTE,\n GET_PROVIDERS_ROUTE,\n APPROVE_TOOL_CALL_ROUTE,\n SEND_TOOL_APPROVAL_ROUTE,\n LIST_SUSPENDED_RUNS_ROUTE,\n DECLINE_TOOL_CALL_ROUTE,\n RESUME_STREAM_ROUTE,\n RECOVER_ROUTE,\n APPROVE_TOOL_CALL_GENERATE_ROUTE,\n DECLINE_TOOL_CALL_GENERATE_ROUTE,\n STREAM_NETWORK_ROUTE,\n UPDATE_AGENT_MODEL_ROUTE,\n RESET_AGENT_MODEL_ROUTE,\n REORDER_AGENT_MODEL_LIST_ROUTE,\n UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE,\n ENHANCE_INSTRUCTIONS_ROUTE,\n STREAM_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_DEPRECATED_ROUTE,\n APPROVE_NETWORK_TOOL_CALL_ROUTE,\n DECLINE_NETWORK_TOOL_CALL_ROUTE,\n GET_AGENT_SKILL_ROUTE,\n STREAM_UNTIL_IDLE_GENERATE_ROUTE,\n RESUME_STREAM_UNTIL_IDLE_ROUTE,\n} from '../../handlers/agents';\nimport { READ_AGENT_PLAN_ROUTE } from '../../handlers/plans';\nimport { GET_AGENT_TOOL_ROUTE, EXECUTE_AGENT_TOOL_ROUTE } from '../../handlers/tools';\nimport {\n GET_SPEAKERS_ROUTE,\n GET_SPEAKERS_DEPRECATED_ROUTE,\n GENERATE_SPEECH_ROUTE,\n GENERATE_SPEECH_DEPRECATED_ROUTE,\n TRANSCRIBE_SPEECH_ROUTE,\n TRANSCRIBE_SPEECH_DEPRECATED_ROUTE,\n GET_LISTENER_ROUTE,\n} from '../../handlers/voice';\nimport type { ServerRoute } from '.';\n\nexport const AGENTS_ROUTES: readonly ServerRoute[] = [\n // ============================================================================\n // Agent Core Routes\n // ============================================================================\n LIST_AGENTS_ROUTE,\n GET_PROVIDERS_ROUTE,\n GET_AGENT_BY_ID_ROUTE,\n CLONE_AGENT_ROUTE,\n\n // ============================================================================\n // Voice Routes\n // ============================================================================\n GET_SPEAKERS_ROUTE,\n GET_SPEAKERS_DEPRECATED_ROUTE,\n\n // ============================================================================\n // Agent Execution Routes\n // ============================================================================\n GENERATE_AGENT_ROUTE,\n GENERATE_AGENT_VNEXT_ROUTE,\n STREAM_GENERATE_ROUTE,\n STREAM_UNTIL_IDLE_GENERATE_ROUTE,\n STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE,\n\n // ============================================================================\n // Resumable Stream Routes\n // ============================================================================\n OBSERVE_AGENT_STREAM_ROUTE,\n SEND_AGENT_MESSAGE_ROUTE,\n QUEUE_AGENT_MESSAGE_ROUTE,\n SEND_AGENT_SIGNAL_ROUTE,\n ABORT_AGENT_THREAD_ROUTE,\n SUBSCRIBE_AGENT_THREAD_ROUTE,\n\n // ============================================================================\n // Tool Routes\n // ============================================================================\n EXECUTE_AGENT_TOOL_ROUTE,\n APPROVE_TOOL_CALL_ROUTE,\n SEND_TOOL_APPROVAL_ROUTE,\n LIST_SUSPENDED_RUNS_ROUTE,\n DECLINE_TOOL_CALL_ROUTE,\n RESUME_STREAM_ROUTE,\n RECOVER_ROUTE,\n APPROVE_TOOL_CALL_GENERATE_ROUTE,\n DECLINE_TOOL_CALL_GENERATE_ROUTE,\n APPROVE_NETWORK_TOOL_CALL_ROUTE,\n DECLINE_NETWORK_TOOL_CALL_ROUTE,\n RESUME_STREAM_UNTIL_IDLE_ROUTE,\n\n // ============================================================================\n // Network Routes\n // ============================================================================\n STREAM_NETWORK_ROUTE,\n\n // ============================================================================\n // Model Management Routes\n // ============================================================================\n UPDATE_AGENT_MODEL_ROUTE,\n RESET_AGENT_MODEL_ROUTE,\n REORDER_AGENT_MODEL_LIST_ROUTE,\n UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE,\n\n // ============================================================================\n // Instruction Enhancement Routes\n // ============================================================================\n ENHANCE_INSTRUCTIONS_ROUTE,\n\n // ============================================================================\n // Agent Tool Routes\n // ============================================================================\n GET_AGENT_TOOL_ROUTE,\n READ_AGENT_PLAN_ROUTE,\n\n // ============================================================================\n // Agent Skill Routes\n // ============================================================================\n GET_AGENT_SKILL_ROUTE,\n\n // ============================================================================\n // Voice/Speech Routes\n // ============================================================================\n GENERATE_SPEECH_ROUTE,\n GENERATE_SPEECH_DEPRECATED_ROUTE,\n TRANSCRIBE_SPEECH_ROUTE,\n TRANSCRIBE_SPEECH_DEPRECATED_ROUTE,\n GET_LISTENER_ROUTE,\n\n // ============================================================================\n // Deprecated Routes\n // ============================================================================\n STREAM_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_DEPRECATED_ROUTE,\n];\n\n/**\n * Type-level tuple preserving each agent route's specific schema types.\n * Used by ServerRoutes to build the type-level route map.\n */\nexport type AgentRoutes = readonly [\n typeof LIST_AGENTS_ROUTE,\n typeof GET_PROVIDERS_ROUTE,\n typeof GET_AGENT_BY_ID_ROUTE,\n typeof CLONE_AGENT_ROUTE,\n typeof GET_SPEAKERS_ROUTE,\n typeof GET_SPEAKERS_DEPRECATED_ROUTE,\n typeof GENERATE_AGENT_ROUTE,\n typeof GENERATE_AGENT_VNEXT_ROUTE,\n typeof STREAM_GENERATE_ROUTE,\n typeof STREAM_UNTIL_IDLE_GENERATE_ROUTE,\n typeof STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE,\n typeof SEND_AGENT_MESSAGE_ROUTE,\n typeof QUEUE_AGENT_MESSAGE_ROUTE,\n typeof SEND_AGENT_SIGNAL_ROUTE,\n typeof ABORT_AGENT_THREAD_ROUTE,\n typeof SUBSCRIBE_AGENT_THREAD_ROUTE,\n typeof EXECUTE_AGENT_TOOL_ROUTE,\n typeof APPROVE_TOOL_CALL_ROUTE,\n typeof SEND_TOOL_APPROVAL_ROUTE,\n typeof LIST_SUSPENDED_RUNS_ROUTE,\n typeof DECLINE_TOOL_CALL_ROUTE,\n typeof RESUME_STREAM_ROUTE,\n typeof RECOVER_ROUTE,\n typeof RESUME_STREAM_UNTIL_IDLE_ROUTE,\n typeof APPROVE_TOOL_CALL_GENERATE_ROUTE,\n typeof DECLINE_TOOL_CALL_GENERATE_ROUTE,\n typeof APPROVE_NETWORK_TOOL_CALL_ROUTE,\n typeof DECLINE_NETWORK_TOOL_CALL_ROUTE,\n typeof STREAM_NETWORK_ROUTE,\n typeof UPDATE_AGENT_MODEL_ROUTE,\n typeof RESET_AGENT_MODEL_ROUTE,\n typeof REORDER_AGENT_MODEL_LIST_ROUTE,\n typeof UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE,\n typeof ENHANCE_INSTRUCTIONS_ROUTE,\n typeof GET_AGENT_TOOL_ROUTE,\n typeof READ_AGENT_PLAN_ROUTE,\n typeof GET_AGENT_SKILL_ROUTE,\n typeof GENERATE_SPEECH_ROUTE,\n typeof GENERATE_SPEECH_DEPRECATED_ROUTE,\n typeof TRANSCRIBE_SPEECH_ROUTE,\n typeof TRANSCRIBE_SPEECH_DEPRECATED_ROUTE,\n typeof GET_LISTENER_ROUTE,\n typeof STREAM_VNEXT_DEPRECATED_ROUTE,\n typeof STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE,\n typeof STREAM_UI_MESSAGE_DEPRECATED_ROUTE,\n];\n","import {\n BACKGROUND_TASK_STREAM_ROUTE,\n GET_BACKGROUND_TASK_ROUTE,\n LIST_BACKGROUND_TASKS_ROUTE,\n} from '../../handlers/background-tasks';\nimport type { ServerRoute } from '.';\n\nexport const BACKGROUND_TASK_ROUTES: ServerRoute<any, any, any>[] = [\n BACKGROUND_TASK_STREAM_ROUTE,\n LIST_BACKGROUND_TASKS_ROUTE,\n GET_BACKGROUND_TASK_ROUTE,\n];\n","import {\n LIST_CHANNEL_PLATFORMS_ROUTE,\n LIST_CHANNEL_INSTALLATIONS_ROUTE,\n CONNECT_CHANNEL_ROUTE,\n DISCONNECT_CHANNEL_ROUTE,\n} from '../../handlers/channels';\n\nexport const CHANNELS_ROUTES = [\n LIST_CHANNEL_PLATFORMS_ROUTE,\n LIST_CHANNEL_INSTALLATIONS_ROUTE,\n CONNECT_CHANNEL_ROUTE,\n DISCONNECT_CHANNEL_ROUTE,\n] as const;\n","import {\n CREATE_CONVERSATION_ROUTE,\n DELETE_CONVERSATION_ROUTE,\n GET_CONVERSATION_ITEMS_ROUTE,\n GET_CONVERSATION_ROUTE,\n} from '../../handlers/conversations';\n\nexport const CONVERSATIONS_ROUTES = [\n CREATE_CONVERSATION_ROUTE,\n GET_CONVERSATION_ROUTE,\n GET_CONVERSATION_ITEMS_ROUTE,\n DELETE_CONVERSATION_ROUTE,\n] as const;\n","import {\n LIST_DATASETS_ROUTE,\n CREATE_DATASET_ROUTE,\n GET_DATASET_ROUTE,\n UPDATE_DATASET_ROUTE,\n DELETE_DATASET_ROUTE,\n LIST_ITEMS_ROUTE,\n ADD_ITEM_ROUTE,\n GET_ITEM_ROUTE,\n UPDATE_ITEM_ROUTE,\n DELETE_ITEM_ROUTE,\n LIST_ALL_EXPERIMENTS_ROUTE,\n EXPERIMENT_REVIEW_SUMMARY_ROUTE,\n LIST_EXPERIMENTS_ROUTE,\n TRIGGER_EXPERIMENT_ROUTE,\n RUN_EXPERIMENT_ITEM_ROUTE,\n SUBMIT_EXPERIMENT_RESULT_ROUTE,\n FINALIZE_EXPERIMENT_ROUTE,\n GET_EXPERIMENT_ROUTE,\n LIST_EXPERIMENT_RESULTS_ROUTE,\n UPDATE_EXPERIMENT_RESULT_ROUTE,\n COMPARE_EXPERIMENTS_ROUTE,\n LIST_DATASET_VERSIONS_ROUTE,\n LIST_ITEM_VERSIONS_ROUTE,\n GET_ITEM_VERSION_ROUTE,\n BATCH_INSERT_ITEMS_ROUTE,\n BATCH_DELETE_ITEMS_ROUTE,\n GENERATE_ITEMS_ROUTE,\n CLUSTER_FAILURES_ROUTE,\n} from '../../handlers/datasets';\n\nexport const DATASETS_ROUTES = [\n // Dataset CRUD\n LIST_DATASETS_ROUTE,\n CREATE_DATASET_ROUTE,\n GET_DATASET_ROUTE,\n UPDATE_DATASET_ROUTE,\n DELETE_DATASET_ROUTE,\n // Item list and add\n LIST_ITEMS_ROUTE,\n ADD_ITEM_ROUTE,\n // Batch operations - MUST come before item-specific routes to avoid /items/batch matching /items/:itemId\n BATCH_INSERT_ITEMS_ROUTE,\n BATCH_DELETE_ITEMS_ROUTE,\n // Item-specific CRUD (uses :itemId param)\n GET_ITEM_ROUTE,\n UPDATE_ITEM_ROUTE,\n DELETE_ITEM_ROUTE,\n // Version operations\n LIST_DATASET_VERSIONS_ROUTE,\n LIST_ITEM_VERSIONS_ROUTE,\n GET_ITEM_VERSION_ROUTE,\n // All experiments (cross-dataset) - MUST come before dataset-scoped experiments\n LIST_ALL_EXPERIMENTS_ROUTE,\n // Experiment review summary (cross-dataset) - MUST come before dataset-scoped experiments\n EXPERIMENT_REVIEW_SUMMARY_ROUTE,\n // Experiment operations (dataset-scoped)\n LIST_EXPERIMENTS_ROUTE,\n TRIGGER_EXPERIMENT_ROUTE,\n // Caller-driven experiments (run one item, submit results, finalize)\n RUN_EXPERIMENT_ITEM_ROUTE,\n SUBMIT_EXPERIMENT_RESULT_ROUTE,\n FINALIZE_EXPERIMENT_ROUTE,\n GET_EXPERIMENT_ROUTE,\n LIST_EXPERIMENT_RESULTS_ROUTE,\n UPDATE_EXPERIMENT_RESULT_ROUTE,\n // Analytics\n COMPARE_EXPERIMENTS_ROUTE,\n // AI generation\n GENERATE_ITEMS_ROUTE,\n // Failure analysis\n CLUSTER_FAILURES_ROUTE,\n] as const;\n","import {\n DELETE_DYNAMIC_WORKFLOW_ROUTE,\n GET_DYNAMIC_WORKFLOW_ROUTE,\n LIST_DYNAMIC_WORKFLOWS_ROUTE,\n UPSERT_DYNAMIC_WORKFLOW_ROUTE,\n} from '../../handlers/dynamic-workflows';\nimport type { ServerRoute } from '.';\n\n/**\n * Routes for dynamic workflow definitions: list / get / upsert / delete.\n * Upsert is the path the chat-driven workflow-builder agent (and Studio's\n * future \"Save\" button) uses to persist + live-register a workflow without\n * a server restart.\n */\nexport const DYNAMIC_WORKFLOWS_ROUTES: readonly ServerRoute[] = [\n LIST_DYNAMIC_WORKFLOWS_ROUTE,\n UPSERT_DYNAMIC_WORKFLOW_ROUTE,\n GET_DYNAMIC_WORKFLOW_ROUTE, // After UPSERT (POST) since both are on the same /stored/workflows base\n DELETE_DYNAMIC_WORKFLOW_ROUTE,\n];\n\nexport type DynamicWorkflowRoutes = readonly [\n typeof LIST_DYNAMIC_WORKFLOWS_ROUTE,\n typeof UPSERT_DYNAMIC_WORKFLOW_ROUTE,\n typeof GET_DYNAMIC_WORKFLOW_ROUTE,\n typeof DELETE_DYNAMIC_WORKFLOW_ROUTE,\n];\n","import {\n BUILDER_REGISTRY_INSTALL_ROUTE,\n BUILDER_REGISTRY_POPULAR_ROUTE,\n BUILDER_REGISTRY_PREVIEW_ROUTE,\n BUILDER_REGISTRY_SEARCH_ROUTE,\n LIST_BUILDER_REGISTRIES_ROUTE,\n} from '../../handlers/builder-registry';\nimport {\n GET_EDITOR_BUILDER_AVAILABLE_MODELS_ROUTE,\n GET_EDITOR_BUILDER_SETTINGS_ROUTE,\n GET_INFRASTRUCTURE_STATUS_ROUTE,\n} from '../../handlers/editor-builder';\n\n/**\n * Editor Builder Routes\n *\n * Routes for agent builder settings, infrastructure status, and external\n * skill registries.\n */\nexport const EDITOR_BUILDER_ROUTES = [\n GET_EDITOR_BUILDER_SETTINGS_ROUTE,\n GET_EDITOR_BUILDER_AVAILABLE_MODELS_ROUTE,\n GET_INFRASTRUCTURE_STATUS_ROUTE,\n LIST_BUILDER_REGISTRIES_ROUTE,\n BUILDER_REGISTRY_SEARCH_ROUTE,\n BUILDER_REGISTRY_POPULAR_ROUTE,\n BUILDER_REGISTRY_PREVIEW_ROUTE,\n BUILDER_REGISTRY_INSTALL_ROUTE,\n] as const;\n","/**\n * Legacy routes that are deprecated but still exist in deployer for backward compatibility.\n * These routes should not be used in new code and will be removed in a future version.\n */\n\nimport { GENERATE_LEGACY_ROUTE, STREAM_GENERATE_LEGACY_ROUTE } from '../../handlers/agents';\nimport { STREAM_LEGACY_WORKFLOW_ROUTE, OBSERVE_STREAM_LEGACY_WORKFLOW_ROUTE } from '../../handlers/workflows';\n\nexport const LEGACY_ROUTES = [\n // ============================================================================\n // Legacy Agent Routes\n // ============================================================================\n GENERATE_LEGACY_ROUTE,\n STREAM_GENERATE_LEGACY_ROUTE,\n\n // ============================================================================\n // Legacy Workflow Routes\n // ============================================================================\n STREAM_LEGACY_WORKFLOW_ROUTE,\n OBSERVE_STREAM_LEGACY_WORKFLOW_ROUTE,\n] as const;\n","import { LIST_LOG_TRANSPORTS_ROUTE, LIST_LOGS_ROUTE, LIST_LOGS_BY_RUN_ID_ROUTE } from '../../handlers/logs';\n\nexport const LOGS_ROUTES = [LIST_LOG_TRANSPORTS_ROUTE, LIST_LOGS_ROUTE, LIST_LOGS_BY_RUN_ID_ROUTE] as const;\n","import {\n LIST_MCP_SERVERS_ROUTE,\n GET_MCP_SERVER_DETAIL_ROUTE,\n LIST_MCP_SERVER_TOOLS_ROUTE,\n GET_MCP_SERVER_TOOL_DETAIL_ROUTE,\n EXECUTE_MCP_SERVER_TOOL_ROUTE,\n LIST_MCP_SERVER_RESOURCES_ROUTE,\n READ_MCP_SERVER_RESOURCE_ROUTE,\n MCP_HTTP_TRANSPORT_ROUTE,\n MCP_SSE_TRANSPORT_ROUTE,\n MCP_SSE_MESSAGES_ROUTE,\n} from '../../handlers/mcp';\n\n/**\n * MCP Routes\n *\n * Registry routes provide access to the MCP server registry and tools.\n * Transport routes handle the MCP protocol communication (HTTP and SSE).\n */\nexport const MCP_ROUTES = [\n // ============================================================================\n // MCP Server Registry Routes\n // ============================================================================\n LIST_MCP_SERVERS_ROUTE,\n GET_MCP_SERVER_DETAIL_ROUTE,\n\n // ============================================================================\n // MCP Server Tool Routes\n // ============================================================================\n LIST_MCP_SERVER_TOOLS_ROUTE,\n GET_MCP_SERVER_TOOL_DETAIL_ROUTE,\n EXECUTE_MCP_SERVER_TOOL_ROUTE,\n\n // ============================================================================\n // MCP Server Resource Routes\n // ============================================================================\n LIST_MCP_SERVER_RESOURCES_ROUTE,\n READ_MCP_SERVER_RESOURCE_ROUTE,\n\n // ============================================================================\n // MCP Transport Routes (handled by adapters)\n // ============================================================================\n MCP_HTTP_TRANSPORT_ROUTE,\n MCP_SSE_TRANSPORT_ROUTE,\n MCP_SSE_MESSAGES_ROUTE,\n] as const;\n","import {\n GET_MEMORY_STATUS_ROUTE,\n GET_MEMORY_CONFIG_ROUTE,\n GET_OBSERVATIONAL_MEMORY_ROUTE,\n AWAIT_BUFFER_STATUS_ROUTE,\n LIST_THREADS_ROUTE,\n GET_THREAD_BY_ID_ROUTE,\n LIST_MESSAGES_ROUTE,\n GET_WORKING_MEMORY_ROUTE,\n SAVE_MESSAGES_ROUTE,\n CREATE_THREAD_ROUTE,\n UPDATE_THREAD_ROUTE,\n DELETE_THREAD_ROUTE,\n CLONE_THREAD_ROUTE,\n UPDATE_WORKING_MEMORY_ROUTE,\n DELETE_MESSAGES_ROUTE,\n SEARCH_MEMORY_ROUTE,\n GET_MEMORY_STATUS_NETWORK_ROUTE,\n LIST_THREADS_NETWORK_ROUTE,\n GET_THREAD_BY_ID_NETWORK_ROUTE,\n LIST_MESSAGES_NETWORK_ROUTE,\n SAVE_MESSAGES_NETWORK_ROUTE,\n CREATE_THREAD_NETWORK_ROUTE,\n UPDATE_THREAD_NETWORK_ROUTE,\n DELETE_THREAD_NETWORK_ROUTE,\n DELETE_MESSAGES_NETWORK_ROUTE,\n} from '../../handlers/memory';\n\nexport const MEMORY_ROUTES = [\n GET_MEMORY_STATUS_ROUTE,\n GET_MEMORY_CONFIG_ROUTE,\n GET_OBSERVATIONAL_MEMORY_ROUTE,\n AWAIT_BUFFER_STATUS_ROUTE,\n LIST_THREADS_ROUTE,\n GET_THREAD_BY_ID_ROUTE,\n LIST_MESSAGES_ROUTE,\n GET_WORKING_MEMORY_ROUTE,\n SAVE_MESSAGES_ROUTE,\n CREATE_THREAD_ROUTE,\n UPDATE_THREAD_ROUTE,\n DELETE_THREAD_ROUTE,\n CLONE_THREAD_ROUTE,\n UPDATE_WORKING_MEMORY_ROUTE,\n DELETE_MESSAGES_ROUTE,\n SEARCH_MEMORY_ROUTE,\n GET_MEMORY_STATUS_NETWORK_ROUTE,\n LIST_THREADS_NETWORK_ROUTE,\n GET_THREAD_BY_ID_NETWORK_ROUTE,\n LIST_MESSAGES_NETWORK_ROUTE,\n SAVE_MESSAGES_NETWORK_ROUTE,\n CREATE_THREAD_NETWORK_ROUTE,\n UPDATE_THREAD_NETWORK_ROUTE,\n DELETE_THREAD_NETWORK_ROUTE,\n DELETE_MESSAGES_NETWORK_ROUTE,\n] as const;\n","import {\n LIST_TRACES_ROUTE,\n LIST_TRACES_LIGHT_ROUTE,\n LIST_BRANCHES_ROUTE,\n GET_BRANCH_ROUTE,\n GET_TRACE_ROUTE,\n GET_TRACE_LIGHT_ROUTE,\n GET_SPAN_ROUTE,\n GET_TRACE_TRAJECTORY_ROUTE,\n SCORE_TRACES_ROUTE,\n LIST_SCORES_BY_SPAN_ROUTE,\n} from '../../handlers/observability';\nimport {\n LIST_METRICS,\n LIST_LOGS,\n LIST_SCORES,\n CREATE_SCORE,\n GET_SCORE,\n GET_SCORE_AGGREGATE,\n GET_SCORE_BREAKDOWN,\n GET_SCORE_TIME_SERIES,\n GET_SCORE_PERCENTILES,\n LIST_FEEDBACK,\n CREATE_FEEDBACK,\n GET_FEEDBACK_AGGREGATE,\n GET_FEEDBACK_BREAKDOWN,\n GET_FEEDBACK_TIME_SERIES,\n GET_FEEDBACK_PERCENTILES,\n GET_METRIC_AGGREGATE,\n GET_METRIC_BREAKDOWN,\n GET_METRIC_TIME_SERIES,\n GET_METRIC_PERCENTILES,\n GET_METRIC_NAMES,\n GET_METRIC_LABEL_KEYS,\n GET_METRIC_LABEL_VALUES,\n GET_ENTITY_TYPES,\n GET_ENTITY_NAMES,\n GET_SERVICE_NAMES,\n GET_ENVIRONMENTS,\n GET_TAGS,\n} from '../../handlers/observability-new-endpoints';\n\nexport const OBSERVABILITY_ROUTES = [\n // Legacy\n LIST_TRACES_ROUTE,\n LIST_TRACES_LIGHT_ROUTE,\n LIST_BRANCHES_ROUTE,\n GET_BRANCH_ROUTE,\n GET_TRACE_ROUTE,\n GET_TRACE_LIGHT_ROUTE,\n GET_SPAN_ROUTE,\n GET_TRACE_TRAJECTORY_ROUTE,\n SCORE_TRACES_ROUTE,\n LIST_SCORES_BY_SPAN_ROUTE,\n // New observability routes\n LIST_METRICS,\n LIST_LOGS,\n LIST_SCORES,\n CREATE_SCORE,\n GET_SCORE,\n GET_SCORE_AGGREGATE,\n GET_SCORE_BREAKDOWN,\n GET_SCORE_TIME_SERIES,\n GET_SCORE_PERCENTILES,\n LIST_FEEDBACK,\n CREATE_FEEDBACK,\n GET_FEEDBACK_AGGREGATE,\n GET_FEEDBACK_BREAKDOWN,\n GET_FEEDBACK_TIME_SERIES,\n GET_FEEDBACK_PERCENTILES,\n GET_METRIC_AGGREGATE,\n GET_METRIC_BREAKDOWN,\n GET_METRIC_TIME_SERIES,\n GET_METRIC_PERCENTILES,\n GET_METRIC_NAMES,\n GET_METRIC_LABEL_KEYS,\n GET_METRIC_LABEL_VALUES,\n GET_ENTITY_TYPES,\n GET_ENTITY_NAMES,\n GET_SERVICE_NAMES,\n GET_ENVIRONMENTS,\n GET_TAGS,\n] as const;\n","import { LIST_PROCESSOR_PROVIDERS_ROUTE, GET_PROCESSOR_PROVIDER_ROUTE } from '../../handlers/processor-providers';\n\nexport const PROCESSOR_PROVIDER_ROUTES = [LIST_PROCESSOR_PROVIDERS_ROUTE, GET_PROCESSOR_PROVIDER_ROUTE] as const;\n","import { LIST_PROCESSORS_ROUTE, GET_PROCESSOR_BY_ID_ROUTE, EXECUTE_PROCESSOR_ROUTE } from '../../handlers/processors';\n\nexport const PROCESSORS_ROUTES = [LIST_PROCESSORS_ROUTE, GET_PROCESSOR_BY_ID_ROUTE, EXECUTE_PROCESSOR_ROUTE] as const;\n","import { CREATE_RESPONSE_ROUTE, DELETE_RESPONSE_ROUTE, GET_RESPONSE_ROUTE } from '../../handlers/responses';\n\nexport const RESPONSES_ROUTES = [CREATE_RESPONSE_ROUTE, GET_RESPONSE_ROUTE, DELETE_RESPONSE_ROUTE] as const;\n","import {\n CREATE_SCHEDULE_ROUTE,\n DELETE_SCHEDULE_ROUTE,\n GET_SCHEDULE_ROUTE,\n LIST_SCHEDULES_ROUTE,\n LIST_SCHEDULE_TRIGGERS_ROUTE,\n PAUSE_SCHEDULE_ROUTE,\n RESUME_SCHEDULE_ROUTE,\n RUN_SCHEDULE_ROUTE,\n UPDATE_SCHEDULE_ROUTE,\n} from '../../handlers/schedules';\nimport type { ServerRoute } from '.';\n\nexport const SCHEDULES_ROUTES: ServerRoute<any, any, any>[] = [\n LIST_SCHEDULES_ROUTE,\n GET_SCHEDULE_ROUTE,\n CREATE_SCHEDULE_ROUTE,\n UPDATE_SCHEDULE_ROUTE,\n DELETE_SCHEDULE_ROUTE,\n LIST_SCHEDULE_TRIGGERS_ROUTE,\n PAUSE_SCHEDULE_ROUTE,\n RESUME_SCHEDULE_ROUTE,\n RUN_SCHEDULE_ROUTE,\n];\n","import {\n LIST_SCORERS_ROUTE,\n GET_SCORER_ROUTE,\n LIST_SCORES_BY_RUN_ID_ROUTE,\n LIST_SCORES_BY_SCORER_ID_ROUTE,\n LIST_SCORES_BY_ENTITY_ID_ROUTE,\n SAVE_SCORE_ROUTE,\n} from '../../handlers/scores';\n\nexport const SCORES_ROUTES = [\n LIST_SCORERS_ROUTE,\n GET_SCORER_ROUTE,\n LIST_SCORES_BY_RUN_ID_ROUTE,\n LIST_SCORES_BY_SCORER_ID_ROUTE,\n LIST_SCORES_BY_ENTITY_ID_ROUTE,\n SAVE_SCORE_ROUTE,\n] as const;\n","import {\n LIST_AGENT_VERSIONS_ROUTE,\n CREATE_AGENT_VERSION_ROUTE,\n GET_AGENT_VERSION_ROUTE,\n ACTIVATE_AGENT_VERSION_ROUTE,\n RESTORE_AGENT_VERSION_ROUTE,\n DELETE_AGENT_VERSION_ROUTE,\n COMPARE_AGENT_VERSIONS_ROUTE,\n} from '../../handlers/agent-versions';\nimport { FAVORITE_STORED_AGENT_ROUTE, UNFAVORITE_STORED_AGENT_ROUTE } from '../../handlers/stored-agent-favorites';\nimport {\n LIST_STORED_AGENTS_ROUTE,\n GET_STORED_AGENT_ROUTE,\n GET_STORED_AGENT_DEPENDENTS_ROUTE,\n CREATE_STORED_AGENT_ROUTE,\n UPDATE_STORED_AGENT_ROUTE,\n DELETE_STORED_AGENT_ROUTE,\n PREVIEW_INSTRUCTIONS_ROUTE,\n EXPORT_STORED_AGENT_ROUTE,\n OPEN_STORED_AGENT_CHANGE_REQUEST_ROUTE,\n} from '../../handlers/stored-agents';\nimport type { ServerRoute } from '.';\n\n/**\n * Routes for stored agents CRUD operations and version management.\n * These routes provide API access to agent configurations stored in the database,\n * enabling dynamic creation and management of agents via Mastra Studio.\n */\nexport const STORED_AGENTS_ROUTES: readonly ServerRoute[] = [\n // ============================================================================\n // Stored Agents CRUD Routes\n // IMPORTANT: Routes with literal paths (e.g., /preview-instructions) must come\n // BEFORE routes with path parameters (e.g., /:storedAgentId) to ensure correct matching.\n // ============================================================================\n LIST_STORED_AGENTS_ROUTE,\n PREVIEW_INSTRUCTIONS_ROUTE, // Must be before GET_STORED_AGENT_ROUTE\n GET_STORED_AGENT_DEPENDENTS_ROUTE, // Must be before GET_STORED_AGENT_ROUTE (longer literal)\n EXPORT_STORED_AGENT_ROUTE, // Must be before GET_STORED_AGENT_ROUTE\n OPEN_STORED_AGENT_CHANGE_REQUEST_ROUTE, // Must be before GET_STORED_AGENT_ROUTE\n GET_STORED_AGENT_ROUTE,\n CREATE_STORED_AGENT_ROUTE,\n UPDATE_STORED_AGENT_ROUTE,\n DELETE_STORED_AGENT_ROUTE,\n\n // ============================================================================\n // Agent Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n // ============================================================================\n LIST_AGENT_VERSIONS_ROUTE,\n CREATE_AGENT_VERSION_ROUTE,\n COMPARE_AGENT_VERSIONS_ROUTE, // Must be before GET_AGENT_VERSION_ROUTE\n GET_AGENT_VERSION_ROUTE,\n ACTIVATE_AGENT_VERSION_ROUTE,\n RESTORE_AGENT_VERSION_ROUTE,\n DELETE_AGENT_VERSION_ROUTE,\n\n // ============================================================================\n // Favorites (EE)\n // ============================================================================\n FAVORITE_STORED_AGENT_ROUTE,\n UNFAVORITE_STORED_AGENT_ROUTE,\n];\n\n/**\n * Type-level tuple preserving each stored agent route's specific schema types.\n * Used by ServerRoutes to build the type-level route map.\n */\nexport type StoredAgentRoutes = readonly [\n typeof LIST_STORED_AGENTS_ROUTE,\n typeof PREVIEW_INSTRUCTIONS_ROUTE,\n typeof GET_STORED_AGENT_DEPENDENTS_ROUTE,\n typeof EXPORT_STORED_AGENT_ROUTE,\n typeof OPEN_STORED_AGENT_CHANGE_REQUEST_ROUTE,\n typeof GET_STORED_AGENT_ROUTE,\n typeof CREATE_STORED_AGENT_ROUTE,\n typeof UPDATE_STORED_AGENT_ROUTE,\n typeof DELETE_STORED_AGENT_ROUTE,\n typeof LIST_AGENT_VERSIONS_ROUTE,\n typeof CREATE_AGENT_VERSION_ROUTE,\n typeof COMPARE_AGENT_VERSIONS_ROUTE,\n typeof GET_AGENT_VERSION_ROUTE,\n typeof ACTIVATE_AGENT_VERSION_ROUTE,\n typeof RESTORE_AGENT_VERSION_ROUTE,\n typeof DELETE_AGENT_VERSION_ROUTE,\n typeof FAVORITE_STORED_AGENT_ROUTE,\n typeof UNFAVORITE_STORED_AGENT_ROUTE,\n];\n","import {\n LIST_MCP_CLIENT_VERSIONS_ROUTE,\n CREATE_MCP_CLIENT_VERSION_ROUTE,\n GET_MCP_CLIENT_VERSION_ROUTE,\n ACTIVATE_MCP_CLIENT_VERSION_ROUTE,\n RESTORE_MCP_CLIENT_VERSION_ROUTE,\n DELETE_MCP_CLIENT_VERSION_ROUTE,\n COMPARE_MCP_CLIENT_VERSIONS_ROUTE,\n} from '../../handlers/mcp-client-versions';\nimport {\n LIST_STORED_MCP_CLIENTS_ROUTE,\n GET_STORED_MCP_CLIENT_ROUTE,\n CREATE_STORED_MCP_CLIENT_ROUTE,\n UPDATE_STORED_MCP_CLIENT_ROUTE,\n DELETE_STORED_MCP_CLIENT_ROUTE,\n} from '../../handlers/stored-mcp-clients';\n\nexport const STORED_MCP_CLIENTS_ROUTES = [\n // Stored MCP Clients CRUD Routes\n LIST_STORED_MCP_CLIENTS_ROUTE,\n GET_STORED_MCP_CLIENT_ROUTE,\n CREATE_STORED_MCP_CLIENT_ROUTE,\n UPDATE_STORED_MCP_CLIENT_ROUTE,\n DELETE_STORED_MCP_CLIENT_ROUTE,\n\n // MCP Client Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n LIST_MCP_CLIENT_VERSIONS_ROUTE,\n CREATE_MCP_CLIENT_VERSION_ROUTE,\n COMPARE_MCP_CLIENT_VERSIONS_ROUTE,\n GET_MCP_CLIENT_VERSION_ROUTE,\n ACTIVATE_MCP_CLIENT_VERSION_ROUTE,\n RESTORE_MCP_CLIENT_VERSION_ROUTE,\n DELETE_MCP_CLIENT_VERSION_ROUTE,\n] as const;\n","import {\n LIST_PROMPT_BLOCK_VERSIONS_ROUTE,\n CREATE_PROMPT_BLOCK_VERSION_ROUTE,\n GET_PROMPT_BLOCK_VERSION_ROUTE,\n ACTIVATE_PROMPT_BLOCK_VERSION_ROUTE,\n RESTORE_PROMPT_BLOCK_VERSION_ROUTE,\n DELETE_PROMPT_BLOCK_VERSION_ROUTE,\n COMPARE_PROMPT_BLOCK_VERSIONS_ROUTE,\n} from '../../handlers/prompt-block-versions';\nimport {\n LIST_STORED_PROMPT_BLOCKS_ROUTE,\n GET_STORED_PROMPT_BLOCK_ROUTE,\n CREATE_STORED_PROMPT_BLOCK_ROUTE,\n UPDATE_STORED_PROMPT_BLOCK_ROUTE,\n DELETE_STORED_PROMPT_BLOCK_ROUTE,\n} from '../../handlers/stored-prompt-blocks';\n\nexport const STORED_PROMPT_BLOCKS_ROUTES = [\n // Stored Prompt Blocks CRUD Routes\n LIST_STORED_PROMPT_BLOCKS_ROUTE,\n GET_STORED_PROMPT_BLOCK_ROUTE,\n CREATE_STORED_PROMPT_BLOCK_ROUTE,\n UPDATE_STORED_PROMPT_BLOCK_ROUTE,\n DELETE_STORED_PROMPT_BLOCK_ROUTE,\n\n // Prompt Block Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n LIST_PROMPT_BLOCK_VERSIONS_ROUTE,\n CREATE_PROMPT_BLOCK_VERSION_ROUTE,\n COMPARE_PROMPT_BLOCK_VERSIONS_ROUTE,\n GET_PROMPT_BLOCK_VERSION_ROUTE,\n ACTIVATE_PROMPT_BLOCK_VERSION_ROUTE,\n RESTORE_PROMPT_BLOCK_VERSION_ROUTE,\n DELETE_PROMPT_BLOCK_VERSION_ROUTE,\n] as const;\n","import {\n LIST_SCORER_VERSIONS_ROUTE,\n CREATE_SCORER_VERSION_ROUTE,\n GET_SCORER_VERSION_ROUTE,\n ACTIVATE_SCORER_VERSION_ROUTE,\n RESTORE_SCORER_VERSION_ROUTE,\n DELETE_SCORER_VERSION_ROUTE,\n COMPARE_SCORER_VERSIONS_ROUTE,\n} from '../../handlers/scorer-versions';\nimport {\n LIST_STORED_SCORERS_ROUTE,\n GET_STORED_SCORER_ROUTE,\n CREATE_STORED_SCORER_ROUTE,\n UPDATE_STORED_SCORER_ROUTE,\n DELETE_STORED_SCORER_ROUTE,\n} from '../../handlers/stored-scorers';\n\nexport const STORED_SCORERS_ROUTES = [\n // Stored Scorers CRUD Routes\n LIST_STORED_SCORERS_ROUTE,\n GET_STORED_SCORER_ROUTE,\n CREATE_STORED_SCORER_ROUTE,\n UPDATE_STORED_SCORER_ROUTE,\n DELETE_STORED_SCORER_ROUTE,\n\n // Scorer Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n LIST_SCORER_VERSIONS_ROUTE,\n CREATE_SCORER_VERSION_ROUTE,\n COMPARE_SCORER_VERSIONS_ROUTE,\n GET_SCORER_VERSION_ROUTE,\n ACTIVATE_SCORER_VERSION_ROUTE,\n RESTORE_SCORER_VERSION_ROUTE,\n DELETE_SCORER_VERSION_ROUTE,\n] as const;\n","import { FAVORITE_STORED_SKILL_ROUTE, UNFAVORITE_STORED_SKILL_ROUTE } from '../../handlers/stored-skill-favorites';\nimport {\n LIST_STORED_SKILLS_ROUTE,\n GET_STORED_SKILL_ROUTE,\n CREATE_STORED_SKILL_ROUTE,\n UPDATE_STORED_SKILL_ROUTE,\n DELETE_STORED_SKILL_ROUTE,\n PUBLISH_STORED_SKILL_ROUTE,\n} from '../../handlers/stored-skills';\n\nexport const STORED_SKILLS_ROUTES = [\n // Stored Skills CRUD Routes\n LIST_STORED_SKILLS_ROUTE,\n GET_STORED_SKILL_ROUTE,\n CREATE_STORED_SKILL_ROUTE,\n UPDATE_STORED_SKILL_ROUTE,\n DELETE_STORED_SKILL_ROUTE,\n // Publish\n PUBLISH_STORED_SKILL_ROUTE,\n // Favorites (EE)\n FAVORITE_STORED_SKILL_ROUTE,\n UNFAVORITE_STORED_SKILL_ROUTE,\n] as const;\n","import {\n LIST_STORED_WORKSPACES_ROUTE,\n GET_STORED_WORKSPACE_ROUTE,\n CREATE_STORED_WORKSPACE_ROUTE,\n UPDATE_STORED_WORKSPACE_ROUTE,\n DELETE_STORED_WORKSPACE_ROUTE,\n} from '../../handlers/stored-workspaces';\n\nexport const STORED_WORKSPACES_ROUTES = [\n // Stored Workspaces CRUD Routes\n LIST_STORED_WORKSPACES_ROUTE,\n GET_STORED_WORKSPACE_ROUTE,\n CREATE_STORED_WORKSPACE_ROUTE,\n UPDATE_STORED_WORKSPACE_ROUTE,\n DELETE_STORED_WORKSPACE_ROUTE,\n] as const;\n","import { GET_API_SCHEMA_ROUTE, GET_SYSTEM_PACKAGES_ROUTE } from '../../handlers/system';\n\n/**\n * System Routes\n *\n * Routes for system information and diagnostics.\n */\nexport const SYSTEM_ROUTES = [GET_SYSTEM_PACKAGES_ROUTE, GET_API_SCHEMA_ROUTE] as const;\n","import {\n AUTHORIZE_TOOL_PROVIDER_ROUTE,\n DISCONNECT_TOOL_PROVIDER_CONNECTION_ROUTE,\n GET_TOOL_PROVIDER_AUTH_STATUS_ROUTE,\n GET_TOOL_PROVIDER_CONNECTION_USAGE_ROUTE,\n GET_TOOL_PROVIDER_HEALTH_ROUTE,\n GET_TOOL_PROVIDER_TOOL_SCHEMA_ROUTE,\n LIST_TOOL_PROVIDERS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTIONS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTION_FIELDS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLKITS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLS_ROUTE,\n TOOL_PROVIDER_CONNECTION_STATUS_ROUTE,\n UPDATE_TOOL_PROVIDER_CONNECTION_ROUTE,\n} from '../../handlers/tool-providers';\n\nexport const TOOL_PROVIDER_ROUTES = [\n LIST_TOOL_PROVIDERS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLKITS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLS_ROUTE,\n GET_TOOL_PROVIDER_TOOL_SCHEMA_ROUTE,\n AUTHORIZE_TOOL_PROVIDER_ROUTE,\n GET_TOOL_PROVIDER_AUTH_STATUS_ROUTE,\n TOOL_PROVIDER_CONNECTION_STATUS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTIONS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTION_FIELDS_ROUTE,\n DISCONNECT_TOOL_PROVIDER_CONNECTION_ROUTE,\n UPDATE_TOOL_PROVIDER_CONNECTION_ROUTE,\n GET_TOOL_PROVIDER_CONNECTION_USAGE_ROUTE,\n GET_TOOL_PROVIDER_HEALTH_ROUTE,\n] as const;\n","import { LIST_TOOLS_ROUTE, GET_TOOL_BY_ID_ROUTE, EXECUTE_TOOL_ROUTE } from '../../handlers/tools';\n\nexport const TOOLS_ROUTES = [LIST_TOOLS_ROUTE, GET_TOOL_BY_ID_ROUTE, EXECUTE_TOOL_ROUTE] as const;\n","import {\n UPSERT_VECTORS_ROUTE,\n CREATE_INDEX_ROUTE,\n QUERY_VECTORS_ROUTE,\n LIST_INDEXES_ROUTE,\n DESCRIBE_INDEX_ROUTE,\n DELETE_INDEX_ROUTE,\n LIST_VECTORS_ROUTE,\n LIST_EMBEDDERS_ROUTE,\n} from '../../handlers/vector';\n\nexport const VECTORS_ROUTES = [\n UPSERT_VECTORS_ROUTE,\n CREATE_INDEX_ROUTE,\n QUERY_VECTORS_ROUTE,\n LIST_INDEXES_ROUTE,\n DESCRIBE_INDEX_ROUTE,\n DELETE_INDEX_ROUTE,\n LIST_VECTORS_ROUTE,\n LIST_EMBEDDERS_ROUTE,\n] as const;\n","import {\n LIST_WORKFLOWS_ROUTE,\n LIST_WORKFLOW_RUN_COUNTS_ROUTE,\n GET_WORKFLOW_BY_ID_ROUTE,\n LIST_WORKFLOW_RUNS_ROUTE,\n GET_WORKFLOW_RUN_BY_ID_ROUTE,\n CREATE_WORKFLOW_RUN_ROUTE,\n STREAM_WORKFLOW_ROUTE,\n RESUME_STREAM_WORKFLOW_ROUTE,\n START_ASYNC_WORKFLOW_ROUTE,\n START_WORKFLOW_RUN_ROUTE,\n OBSERVE_STREAM_WORKFLOW_ROUTE,\n RESUME_ASYNC_WORKFLOW_ROUTE,\n RESUME_NO_WAIT_WORKFLOW_ROUTE,\n RESUME_WORKFLOW_ROUTE,\n CANCEL_WORKFLOW_RUN_ROUTE,\n TIME_TRAVEL_WORKFLOW_ROUTE,\n TIME_TRAVEL_STREAM_WORKFLOW_ROUTE,\n RESTART_WORKFLOW_ROUTE,\n RESTART_ASYNC_WORKFLOW_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ASYNC_ROUTE,\n TIME_TRAVEL_ASYNC_WORKFLOW_ROUTE,\n DELETE_WORKFLOW_RUN_BY_ID_ROUTE,\n EXECUTE_WORKFLOW_STEP_ROUTE,\n RECEIVE_WORKFLOW_EVENT_ROUTE,\n} from '../../handlers/workflows';\n\nexport const WORKFLOWS_ROUTES = [\n LIST_WORKFLOWS_ROUTE,\n // Static path must register before the parameterized /workflows/:workflowId\n // route below, or the router would capture \"run-counts\" as a workflowId.\n LIST_WORKFLOW_RUN_COUNTS_ROUTE,\n GET_WORKFLOW_BY_ID_ROUTE,\n LIST_WORKFLOW_RUNS_ROUTE,\n GET_WORKFLOW_RUN_BY_ID_ROUTE,\n DELETE_WORKFLOW_RUN_BY_ID_ROUTE,\n CREATE_WORKFLOW_RUN_ROUTE,\n STREAM_WORKFLOW_ROUTE,\n RESUME_STREAM_WORKFLOW_ROUTE,\n START_ASYNC_WORKFLOW_ROUTE,\n START_WORKFLOW_RUN_ROUTE,\n OBSERVE_STREAM_WORKFLOW_ROUTE,\n RESUME_ASYNC_WORKFLOW_ROUTE,\n RESUME_NO_WAIT_WORKFLOW_ROUTE,\n RESUME_WORKFLOW_ROUTE,\n CANCEL_WORKFLOW_RUN_ROUTE,\n TIME_TRAVEL_WORKFLOW_ROUTE,\n TIME_TRAVEL_ASYNC_WORKFLOW_ROUTE,\n TIME_TRAVEL_STREAM_WORKFLOW_ROUTE,\n RESTART_WORKFLOW_ROUTE,\n RESTART_ASYNC_WORKFLOW_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ASYNC_ROUTE,\n EXECUTE_WORKFLOW_STEP_ROUTE,\n RECEIVE_WORKFLOW_EVENT_ROUTE,\n] as const;\n","/**\n * Workspace Routes\n *\n * All routes for workspace operations under /api/workspaces/*\n */\n\nimport {\n LIST_WORKSPACES_ROUTE,\n GET_WORKSPACE_ROUTE,\n WORKSPACE_FS_ROUTES,\n WORKSPACE_SEARCH_ROUTES,\n WORKSPACE_SKILLS_ROUTES,\n WORKSPACE_SKILLS_SH_ROUTES,\n} from '../../handlers/workspace';\n\nexport const WORKSPACE_ROUTES = [\n // List all workspaces route (at /api/workspaces)\n LIST_WORKSPACES_ROUTE,\n\n // Get workspace route (at /api/workspaces/:workspaceId)\n GET_WORKSPACE_ROUTE,\n\n // Filesystem routes (at /api/workspaces/:workspaceId/fs/*)\n ...WORKSPACE_FS_ROUTES,\n\n // Search routes (at /api/workspaces/:workspaceId/search, /api/workspaces/:workspaceId/index)\n ...WORKSPACE_SEARCH_ROUTES,\n\n // Skills routes (search must come before parameterized routes)\n ...WORKSPACE_SKILLS_ROUTES,\n\n // skills.sh proxy routes (at /api/workspaces/:workspaceId/skills-sh/*)\n ...WORKSPACE_SKILLS_SH_ROUTES,\n] as const;\n","import type { Mastra } from '@mastra/core';\nimport type { ToolsInput } from '@mastra/core/agent';\nimport type { FGARouteConfig, MastraFGAPermissionInput } from '@mastra/core/auth/ee';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute, ValidationErrorHook } from '@mastra/core/server';\nimport type * as z from 'zod/v4';\nimport type { InMemoryTaskStore } from '../../a2a/store';\nimport type { OpenAPIRoute } from '../openapi-utils';\nimport { A2A_ROUTES } from './a2a';\nimport { AGENT_BUILDER_ROUTES } from './agent-builder';\nimport { AGENT_CONTROLLER_ROUTES } from './agent-controller';\nimport { AGENTS_ROUTES } from './agents';\nimport type { AgentRoutes } from './agents';\nimport { AUTH_ROUTES } from './auth';\nimport { BACKGROUND_TASK_ROUTES } from './background-tasks';\nimport { CHANNELS_ROUTES } from './channels';\nimport { CONVERSATIONS_ROUTES } from './conversations';\nimport { DATASETS_ROUTES } from './datasets';\nimport { DYNAMIC_WORKFLOWS_ROUTES } from './dynamic-workflows';\nimport { EDITOR_BUILDER_ROUTES } from './editor-builder';\nimport { LEGACY_ROUTES } from './legacy';\nimport { LOGS_ROUTES } from './logs';\nimport { MCP_ROUTES } from './mcp';\nimport { MEMORY_ROUTES } from './memory';\nimport { OBSERVABILITY_ROUTES } from './observability';\nimport { PROCESSOR_PROVIDER_ROUTES } from './processor-providers';\nimport { PROCESSORS_ROUTES } from './processors';\nimport { RESPONSES_ROUTES } from './responses';\nimport { SCHEDULES_ROUTES } from './schedules';\nimport { SCORES_ROUTES } from './scorers';\nimport { STORED_AGENTS_ROUTES } from './stored-agents';\nimport type { StoredAgentRoutes } from './stored-agents';\nimport { STORED_MCP_CLIENTS_ROUTES } from './stored-mcp-clients';\nimport { STORED_PROMPT_BLOCKS_ROUTES } from './stored-prompt-blocks';\nimport { STORED_SCORERS_ROUTES } from './stored-scorers';\nimport { STORED_SKILLS_ROUTES } from './stored-skills';\nimport { STORED_WORKSPACES_ROUTES } from './stored-workspaces';\nimport type { MastraStreamReturn } from './stream-types';\nimport { SYSTEM_ROUTES } from './system';\nimport { TOOL_PROVIDER_ROUTES } from './tool-providers';\nimport { TOOLS_ROUTES } from './tools';\nimport { VECTORS_ROUTES } from './vectors';\nimport { WORKFLOWS_ROUTES } from './workflows';\nimport { WORKSPACE_ROUTES } from './workspace';\n\n/**\n * Server context fields that are available to route handlers.\n * These are injected by the server adapters (Express, Hono, etc.)\n * Fields other than `mastra` are optional to allow direct handler testing.\n */\nexport type ServerContext = {\n mastra: Mastra;\n requestContext: RequestContext;\n registeredTools?: ToolsInput;\n taskStore?: InMemoryTaskStore;\n abortSignal: AbortSignal;\n /** The route prefix configured for the server (e.g., '/api') */\n routePrefix?: string;\n /** The web-standard Request object for accessing headers, cookies, etc. */\n request?: Request;\n};\n\n/**\n * Utility type to infer parameters from Zod schemas.\n * Merges path params, query params, and body params into a single type.\n */\nexport type InferParams<\n TPathSchema extends z.ZodTypeAny | undefined,\n TQuerySchema extends z.ZodTypeAny | undefined,\n TBodySchema extends z.ZodTypeAny | undefined,\n> = (TPathSchema extends z.ZodTypeAny ? z.infer<TPathSchema> : {}) &\n (TQuerySchema extends z.ZodTypeAny ? z.infer<TQuerySchema> : {}) &\n (TBodySchema extends z.ZodTypeAny ? z.infer<TBodySchema> : {});\n\n/**\n * All supported response types for server routes.\n * - 'json': Standard JSON response\n * - 'stream': Streaming response (SSE or raw stream)\n * - 'datastream-response': Pre-built Response object for data streams\n * - 'mcp-http': MCP Streamable HTTP transport (handled by adapter)\n * - 'mcp-sse': MCP SSE transport (handled by adapter)\n */\nexport type ResponseType = 'stream' | 'json' | 'datastream-response' | 'mcp-http' | 'mcp-sse';\n\nexport type ServerRouteHandler<\n TParams = Record<string, unknown>,\n TResponse = unknown,\n TResponseType extends ResponseType = 'json',\n> = (\n params: TParams & ServerContext,\n) => Promise<\n TResponseType extends 'stream'\n ? MastraStreamReturn\n : TResponseType extends 'datastream-response'\n ? Response\n : TResponse\n>;\n\n/**\n * Phantom type for preserving Zod schema types on routes.\n * Not present at runtime — used only for type-level inference via RouteMap.\n */\nexport interface RouteSchemas<\n TPathSchema = unknown,\n TQuerySchema = unknown,\n TBodySchema = unknown,\n TResponseSchema = unknown,\n> {\n readonly pathParams: TPathSchema;\n readonly queryParams: TQuerySchema;\n readonly body: TBodySchema;\n readonly response: TResponseSchema;\n}\n\nexport type ServerRoute<\n TParams = Record<string, unknown>,\n TResponse = unknown,\n TResponseType extends ResponseType = ResponseType,\n TSchemas extends RouteSchemas = RouteSchemas,\n TMethod extends string = string,\n TPath extends string = string,\n> = Omit<ApiRoute, 'handler' | 'createHandler' | 'method' | 'path' | 'openapi'> & {\n method: TMethod;\n path: TPath;\n responseType: TResponseType;\n streamFormat?: 'sse' | 'stream'; // Only used when responseType is 'stream', defaults to 'stream'\n sseFlushOnConnect?: boolean;\n // Method signature is bivariant in params, allowing heterogeneous route arrays\n // while still preserving specific param types on individual routes.\n handler(params: TParams & ServerContext): ReturnType<ServerRouteHandler<TParams, TResponse, TResponseType>>;\n pathParamSchema?: z.ZodSchema;\n queryParamSchema?: z.ZodSchema;\n bodySchema?: z.ZodSchema;\n responseSchema?: z.ZodSchema;\n openapi?: OpenAPIRoute; // Auto-generated OpenAPI spec for this route\n maxBodySize?: number; // Optional route-specific body size limit in bytes\n deprecated?: boolean; // Flag for deprecated routes (used for route parity, skipped in tests)\n /**\n * Permission required to access this route (EE feature).\n * If set, the user must have this permission to access the route.\n * Uses the format: `resource:action` or `resource:action:resourceId`\n *\n * When an array is provided, the user needs ANY ONE of the listed permissions\n * (logical OR). This is useful for routes that serve multiple resource types,\n * e.g. a streaming endpoint used by both runtime and stored agents.\n *\n * @example\n * requiresPermission: MastraFGAPermissions.AGENTS_READ\n * requiresPermission: MastraFGAPermissions.WORKFLOWS_EXECUTE\n */\n requiresPermission?: MastraFGAPermissionInput | MastraFGAPermissionInput[];\n /**\n * FGA authorization config for this route (EE feature).\n * If set, the user must have the specified permission on the resource.\n *\n * @example\n * fga: { resourceType: 'agent', resourceIdParam: 'agentId', permission: MastraFGAPermissions.AGENTS_EXECUTE }\n */\n fga?: FGARouteConfig;\n onValidationError?: ValidationErrorHook;\n /** @internal Phantom type — not present at runtime. Used for type-level schema inference. */\n readonly __schemas?: TSchemas;\n};\n\nexport const SERVER_ROUTES: readonly ServerRoute[] = [\n ...AGENTS_ROUTES,\n ...AUTH_ROUTES,\n ...WORKFLOWS_ROUTES,\n ...TOOLS_ROUTES,\n ...PROCESSORS_ROUTES,\n ...RESPONSES_ROUTES,\n ...CONVERSATIONS_ROUTES,\n ...MEMORY_ROUTES,\n ...SCORES_ROUTES,\n ...OBSERVABILITY_ROUTES,\n ...LOGS_ROUTES,\n ...VECTORS_ROUTES,\n ...A2A_ROUTES,\n ...WORKSPACE_ROUTES,\n ...LEGACY_ROUTES,\n ...MCP_ROUTES,\n ...STORED_AGENTS_ROUTES,\n ...DYNAMIC_WORKFLOWS_ROUTES,\n ...STORED_MCP_CLIENTS_ROUTES,\n ...STORED_PROMPT_BLOCKS_ROUTES,\n ...STORED_SCORERS_ROUTES,\n ...STORED_WORKSPACES_ROUTES,\n ...STORED_SKILLS_ROUTES,\n ...TOOL_PROVIDER_ROUTES,\n ...PROCESSOR_PROVIDER_ROUTES,\n ...SYSTEM_ROUTES,\n ...DATASETS_ROUTES,\n ...BACKGROUND_TASK_ROUTES,\n ...EDITOR_BUILDER_ROUTES,\n ...AGENT_BUILDER_ROUTES,\n ...SCHEDULES_ROUTES,\n ...CHANNELS_ROUTES,\n ...AGENT_CONTROLLER_ROUTES,\n];\n\n/**\n * Union type of all individual route arrays.\n * Built from the per-domain `as const` tuples to preserve each route's specific schema types.\n */\nexport type ServerRoutes = readonly [\n ...AgentRoutes,\n ...typeof AUTH_ROUTES,\n ...typeof WORKFLOWS_ROUTES,\n ...typeof TOOLS_ROUTES,\n ...typeof PROCESSORS_ROUTES,\n ...typeof RESPONSES_ROUTES,\n ...typeof CONVERSATIONS_ROUTES,\n ...typeof MEMORY_ROUTES,\n ...typeof SCORES_ROUTES,\n ...typeof OBSERVABILITY_ROUTES,\n ...typeof LOGS_ROUTES,\n ...typeof VECTORS_ROUTES,\n ...typeof A2A_ROUTES,\n ...typeof AGENT_BUILDER_ROUTES,\n ...typeof WORKSPACE_ROUTES,\n ...typeof LEGACY_ROUTES,\n ...typeof MCP_ROUTES,\n ...StoredAgentRoutes,\n ...typeof STORED_MCP_CLIENTS_ROUTES,\n ...typeof STORED_PROMPT_BLOCKS_ROUTES,\n ...typeof STORED_SCORERS_ROUTES,\n ...typeof STORED_WORKSPACES_ROUTES,\n ...typeof STORED_SKILLS_ROUTES,\n ...typeof TOOL_PROVIDER_ROUTES,\n ...typeof PROCESSOR_PROVIDER_ROUTES,\n ...typeof SYSTEM_ROUTES,\n ...typeof DATASETS_ROUTES,\n ...typeof EDITOR_BUILDER_ROUTES,\n ...typeof CHANNELS_ROUTES,\n];\n\n// Export route builder and OpenAPI utilities\nexport { createRoute, createPublicRoute, pickParams, jsonQueryParam, wrapSchemaForQueryParams } from './route-builder';\nexport { generateOpenAPIDocument } from '../openapi-utils';\n\n// Export permission utilities\nexport { derivePermission, extractResource, deriveAction, getEffectivePermission } from './permissions';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,MAAa,aAAa,CAAC,sBAAsB,qBAAqB;;;ACiBtE,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;ACMA,MAAa,0BAAkD;CAC7D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AC1BA,MAAa,gBAAwC;CAInD;CACA;CACA;CACA;CAKA;CACA;CAKA;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAKA;CAKA;CACA;CACA;CACA;CAKA;CAKA;CACA;CAKA;CAKA;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;AACF;;;AC3IA,MAAa,yBAAuD;CAClE;CACA;CACA;AACF;;;ACJA,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;AACF;;;ACLA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;AACF;;;ACmBA,MAAa,kBAAkB;CAE7B;CACA;CACA;CACA;CACA;CAEA;CACA;CAEA;CACA;CAEA;CACA;CACA;CAEA;CACA;CACA;CAEA;CAEA;CAEA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CAEA;CAEA;CAEA;AACF;;;;;;;;;AC1DA,MAAa,2BAAmD;CAC9D;CACA;CACA;CACA;AACF;;;;;;;;;ACAA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;ACpBA,MAAa,gBAAgB;CAI3B;CACA;CAKA;CACA;AACF;;;AClBA,MAAa,cAAc;CAAC;CAA2B;CAAiB;AAAyB;;;;;;;;;ACiBjG,MAAa,aAAa;CAIxB;CACA;CAKA;CACA;CACA;CAKA;CACA;CAKA;CACA;CACA;AACF;;;ACjBA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACZA,MAAa,uBAAuB;CAElC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AChFA,MAAa,4BAA4B,CAAC,gCAAgC,4BAA4B;;;ACAtG,MAAa,oBAAoB;CAAC;CAAuB;CAA2B;AAAuB;;;ACA3G,MAAa,mBAAmB;CAAC;CAAuB;CAAoB;AAAqB;;;ACWjG,MAAa,mBAAiD;CAC5D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACdA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;ACYA,MAAa,uBAA+C;CAM1D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAOA;CACA;CACA;CACA;CACA;CACA;CACA;CAKA;CACA;AACF;;;AC7CA,MAAa,4BAA4B;CAEvC;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AClBA,MAAa,8BAA8B;CAEzC;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AClBA,MAAa,wBAAwB;CAEnC;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACzBA,MAAa,uBAAuB;CAElC;CACA;CACA;CACA;CACA;CAEA;CAEA;CACA;AACF;;;ACdA,MAAa,2BAA2B;CAEtC;CACA;CACA;CACA;CACA;AACF;;;;;;;;ACRA,MAAa,gBAAgB,CAAC,2BAA2B,oBAAoB;;;ACS7E,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AC5BA,MAAa,eAAe;CAAC;CAAkB;CAAsB;AAAkB;;;ACSvF,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACQA,MAAa,mBAAmB;CAC9B;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;ACzCA,MAAa,mBAAmB;CAE9B;CAGA;CAGA,GAAG;CAGH,GAAG;CAGH,GAAG;CAGH,GAAG;AACL;;;ACmIA,MAAa,gBAAwC;CACnD,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL"}
1
+ {"version":3,"file":"routes-DCdH7ljX.js","names":[],"sources":["../src/server/server-adapter/routes/a2a.ts","../src/server/server-adapter/routes/agent-builder.ts","../src/server/server-adapter/routes/agent-controller.ts","../src/server/server-adapter/routes/agents.ts","../src/server/server-adapter/routes/background-tasks.ts","../src/server/server-adapter/routes/channels.ts","../src/server/server-adapter/routes/conversations.ts","../src/server/server-adapter/routes/datasets.ts","../src/server/server-adapter/routes/dynamic-workflows.ts","../src/server/server-adapter/routes/editor-builder.ts","../src/server/server-adapter/routes/legacy.ts","../src/server/server-adapter/routes/logs.ts","../src/server/server-adapter/routes/mcp.ts","../src/server/server-adapter/routes/memory.ts","../src/server/server-adapter/routes/observability.ts","../src/server/server-adapter/routes/processor-providers.ts","../src/server/server-adapter/routes/processors.ts","../src/server/server-adapter/routes/responses.ts","../src/server/server-adapter/routes/schedules.ts","../src/server/server-adapter/routes/scorers.ts","../src/server/server-adapter/routes/stored-agents.ts","../src/server/server-adapter/routes/stored-mcp-clients.ts","../src/server/server-adapter/routes/stored-prompt-blocks.ts","../src/server/server-adapter/routes/stored-scorers.ts","../src/server/server-adapter/routes/stored-skills.ts","../src/server/server-adapter/routes/stored-workspaces.ts","../src/server/server-adapter/routes/system.ts","../src/server/server-adapter/routes/tool-providers.ts","../src/server/server-adapter/routes/tools.ts","../src/server/server-adapter/routes/vectors.ts","../src/server/server-adapter/routes/workflows.ts","../src/server/server-adapter/routes/workspace.ts","../src/server/server-adapter/routes/index.ts"],"sourcesContent":["import { GET_AGENT_CARD_ROUTE, AGENT_EXECUTION_ROUTE } from '../../handlers/a2a';\n\nexport const A2A_ROUTES = [GET_AGENT_CARD_ROUTE, AGENT_EXECUTION_ROUTE] as const;\n","import {\n LIST_AGENT_BUILDER_ACTIONS_ROUTE,\n GET_AGENT_BUILDER_ACTION_BY_ID_ROUTE,\n LIST_AGENT_BUILDER_ACTION_RUNS_ROUTE,\n GET_AGENT_BUILDER_ACTION_RUN_BY_ID_ROUTE,\n CREATE_AGENT_BUILDER_ACTION_RUN_ROUTE,\n STREAM_AGENT_BUILDER_ACTION_ROUTE,\n STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n START_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n START_AGENT_BUILDER_ACTION_RUN_ROUTE,\n OBSERVE_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n OBSERVE_STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_NO_WAIT_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n CANCEL_AGENT_BUILDER_ACTION_RUN_ROUTE,\n} from '../../handlers/agent-builder';\n\nexport const AGENT_BUILDER_ROUTES = [\n LIST_AGENT_BUILDER_ACTIONS_ROUTE,\n GET_AGENT_BUILDER_ACTION_BY_ID_ROUTE,\n LIST_AGENT_BUILDER_ACTION_RUNS_ROUTE,\n GET_AGENT_BUILDER_ACTION_RUN_BY_ID_ROUTE,\n CREATE_AGENT_BUILDER_ACTION_RUN_ROUTE,\n STREAM_AGENT_BUILDER_ACTION_ROUTE,\n STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n START_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n START_AGENT_BUILDER_ACTION_RUN_ROUTE,\n OBSERVE_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n OBSERVE_STREAM_LEGACY_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_ASYNC_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_NO_WAIT_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_AGENT_BUILDER_ACTION_ROUTE,\n RESUME_STREAM_AGENT_BUILDER_ACTION_ROUTE,\n CANCEL_AGENT_BUILDER_ACTION_RUN_ROUTE,\n] as const;\n","import {\n LIST_AGENT_CONTROLLERS_ROUTE,\n CREATE_AGENT_CONTROLLER_SESSION_ROUTE,\n GET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n STREAM_AGENT_CONTROLLER_SESSION_ROUTE,\n SEND_AGENT_CONTROLLER_MESSAGE_ROUTE,\n STEER_AGENT_CONTROLLER_SESSION_ROUTE,\n ABORT_AGENT_CONTROLLER_SESSION_ROUTE,\n AGENT_CONTROLLER_TOOL_APPROVAL_ROUTE,\n AGENT_CONTROLLER_TOOL_SUSPENSION_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODE_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODEL_ROUTE,\n SWITCH_AGENT_CONTROLLER_THREAD_ROUTE,\n LIST_AGENT_CONTROLLER_MODES_ROUTE,\n LIST_AGENT_CONTROLLER_ACTIVE_RUNS_ROUTE,\n LIST_AGENT_CONTROLLER_THREADS_ROUTE,\n SEND_AGENT_CONTROLLER_NOTIFICATION_ROUTE,\n CREATE_AGENT_CONTROLLER_THREAD_ROUTE,\n DELETE_AGENT_CONTROLLER_THREAD_ROUTE,\n RENAME_AGENT_CONTROLLER_THREAD_ROUTE,\n CLONE_AGENT_CONTROLLER_THREAD_ROUTE,\n LIST_AGENT_CONTROLLER_THREAD_MESSAGES_ROUTE,\n FOLLOW_UP_AGENT_CONTROLLER_SESSION_ROUTE,\n LIST_AGENT_CONTROLLER_MODELS_ROUTE,\n GET_AGENT_CONTROLLER_WORKSPACE_STATUS_ROUTE,\n GET_AGENT_CONTROLLER_OM_RECORD_ROUTE,\n SET_AGENT_CONTROLLER_RESOURCE_ID_ROUTE,\n GET_AGENT_CONTROLLER_RESOURCE_IDS_ROUTE,\n GET_AGENT_CONTROLLER_GOAL_ROUTE,\n SET_AGENT_CONTROLLER_GOAL_ROUTE,\n UPDATE_AGENT_CONTROLLER_GOAL_ROUTE,\n CLEAR_AGENT_CONTROLLER_GOAL_ROUTE,\n GET_AGENT_CONTROLLER_PERMISSIONS_ROUTE,\n SET_AGENT_CONTROLLER_CATEGORY_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_TOOL_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n} from '../../handlers/agent-controller';\nimport type { ServerRoute } from '.';\n\n/**\n * Canonical `AgentController` session API, served under `/agent-controller/...`.\n */\nexport const AGENT_CONTROLLER_ROUTES: readonly ServerRoute[] = [\n LIST_AGENT_CONTROLLERS_ROUTE,\n LIST_AGENT_CONTROLLER_MODES_ROUTE,\n LIST_AGENT_CONTROLLER_MODELS_ROUTE,\n LIST_AGENT_CONTROLLER_ACTIVE_RUNS_ROUTE,\n CREATE_AGENT_CONTROLLER_SESSION_ROUTE,\n GET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n LIST_AGENT_CONTROLLER_THREADS_ROUTE,\n CREATE_AGENT_CONTROLLER_THREAD_ROUTE,\n DELETE_AGENT_CONTROLLER_THREAD_ROUTE,\n RENAME_AGENT_CONTROLLER_THREAD_ROUTE,\n CLONE_AGENT_CONTROLLER_THREAD_ROUTE,\n LIST_AGENT_CONTROLLER_THREAD_MESSAGES_ROUTE,\n STREAM_AGENT_CONTROLLER_SESSION_ROUTE,\n SEND_AGENT_CONTROLLER_MESSAGE_ROUTE,\n STEER_AGENT_CONTROLLER_SESSION_ROUTE,\n FOLLOW_UP_AGENT_CONTROLLER_SESSION_ROUTE,\n ABORT_AGENT_CONTROLLER_SESSION_ROUTE,\n AGENT_CONTROLLER_TOOL_APPROVAL_ROUTE,\n AGENT_CONTROLLER_TOOL_SUSPENSION_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODE_ROUTE,\n SWITCH_AGENT_CONTROLLER_MODEL_ROUTE,\n SWITCH_AGENT_CONTROLLER_THREAD_ROUTE,\n SEND_AGENT_CONTROLLER_NOTIFICATION_ROUTE,\n GET_AGENT_CONTROLLER_WORKSPACE_STATUS_ROUTE,\n GET_AGENT_CONTROLLER_OM_RECORD_ROUTE,\n SET_AGENT_CONTROLLER_RESOURCE_ID_ROUTE,\n GET_AGENT_CONTROLLER_RESOURCE_IDS_ROUTE,\n GET_AGENT_CONTROLLER_GOAL_ROUTE,\n SET_AGENT_CONTROLLER_GOAL_ROUTE,\n UPDATE_AGENT_CONTROLLER_GOAL_ROUTE,\n CLEAR_AGENT_CONTROLLER_GOAL_ROUTE,\n GET_AGENT_CONTROLLER_PERMISSIONS_ROUTE,\n SET_AGENT_CONTROLLER_CATEGORY_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_TOOL_PERMISSION_ROUTE,\n SET_AGENT_CONTROLLER_SESSION_STATE_ROUTE,\n];\n","import {\n // Agent route objects\n LIST_AGENTS_ROUTE,\n GET_AGENT_BY_ID_ROUTE,\n CLONE_AGENT_ROUTE,\n GENERATE_AGENT_ROUTE,\n GENERATE_AGENT_VNEXT_ROUTE,\n STREAM_GENERATE_ROUTE,\n STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE,\n OBSERVE_AGENT_STREAM_ROUTE,\n SEND_AGENT_MESSAGE_ROUTE,\n QUEUE_AGENT_MESSAGE_ROUTE,\n SEND_AGENT_SIGNAL_ROUTE,\n ABORT_AGENT_THREAD_ROUTE,\n SUBSCRIBE_AGENT_THREAD_ROUTE,\n GET_PROVIDERS_ROUTE,\n APPROVE_TOOL_CALL_ROUTE,\n SEND_TOOL_APPROVAL_ROUTE,\n LIST_SUSPENDED_RUNS_ROUTE,\n DECLINE_TOOL_CALL_ROUTE,\n RESUME_STREAM_ROUTE,\n RECOVER_ROUTE,\n APPROVE_TOOL_CALL_GENERATE_ROUTE,\n DECLINE_TOOL_CALL_GENERATE_ROUTE,\n STREAM_NETWORK_ROUTE,\n UPDATE_AGENT_MODEL_ROUTE,\n RESET_AGENT_MODEL_ROUTE,\n REORDER_AGENT_MODEL_LIST_ROUTE,\n UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE,\n ENHANCE_INSTRUCTIONS_ROUTE,\n STREAM_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_DEPRECATED_ROUTE,\n APPROVE_NETWORK_TOOL_CALL_ROUTE,\n DECLINE_NETWORK_TOOL_CALL_ROUTE,\n GET_AGENT_SKILL_ROUTE,\n STREAM_UNTIL_IDLE_GENERATE_ROUTE,\n RESUME_STREAM_UNTIL_IDLE_ROUTE,\n} from '../../handlers/agents';\nimport { READ_AGENT_PLAN_ROUTE } from '../../handlers/plans';\nimport { GET_AGENT_TOOL_ROUTE, EXECUTE_AGENT_TOOL_ROUTE } from '../../handlers/tools';\nimport {\n GET_SPEAKERS_ROUTE,\n GET_SPEAKERS_DEPRECATED_ROUTE,\n GENERATE_SPEECH_ROUTE,\n GENERATE_SPEECH_DEPRECATED_ROUTE,\n TRANSCRIBE_SPEECH_ROUTE,\n TRANSCRIBE_SPEECH_DEPRECATED_ROUTE,\n GET_LISTENER_ROUTE,\n} from '../../handlers/voice';\nimport type { ServerRoute } from '.';\n\nexport const AGENTS_ROUTES: readonly ServerRoute[] = [\n // ============================================================================\n // Agent Core Routes\n // ============================================================================\n LIST_AGENTS_ROUTE,\n GET_PROVIDERS_ROUTE,\n GET_AGENT_BY_ID_ROUTE,\n CLONE_AGENT_ROUTE,\n\n // ============================================================================\n // Voice Routes\n // ============================================================================\n GET_SPEAKERS_ROUTE,\n GET_SPEAKERS_DEPRECATED_ROUTE,\n\n // ============================================================================\n // Agent Execution Routes\n // ============================================================================\n GENERATE_AGENT_ROUTE,\n GENERATE_AGENT_VNEXT_ROUTE,\n STREAM_GENERATE_ROUTE,\n STREAM_UNTIL_IDLE_GENERATE_ROUTE,\n STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE,\n\n // ============================================================================\n // Resumable Stream Routes\n // ============================================================================\n OBSERVE_AGENT_STREAM_ROUTE,\n SEND_AGENT_MESSAGE_ROUTE,\n QUEUE_AGENT_MESSAGE_ROUTE,\n SEND_AGENT_SIGNAL_ROUTE,\n ABORT_AGENT_THREAD_ROUTE,\n SUBSCRIBE_AGENT_THREAD_ROUTE,\n\n // ============================================================================\n // Tool Routes\n // ============================================================================\n EXECUTE_AGENT_TOOL_ROUTE,\n APPROVE_TOOL_CALL_ROUTE,\n SEND_TOOL_APPROVAL_ROUTE,\n LIST_SUSPENDED_RUNS_ROUTE,\n DECLINE_TOOL_CALL_ROUTE,\n RESUME_STREAM_ROUTE,\n RECOVER_ROUTE,\n APPROVE_TOOL_CALL_GENERATE_ROUTE,\n DECLINE_TOOL_CALL_GENERATE_ROUTE,\n APPROVE_NETWORK_TOOL_CALL_ROUTE,\n DECLINE_NETWORK_TOOL_CALL_ROUTE,\n RESUME_STREAM_UNTIL_IDLE_ROUTE,\n\n // ============================================================================\n // Network Routes\n // ============================================================================\n STREAM_NETWORK_ROUTE,\n\n // ============================================================================\n // Model Management Routes\n // ============================================================================\n UPDATE_AGENT_MODEL_ROUTE,\n RESET_AGENT_MODEL_ROUTE,\n REORDER_AGENT_MODEL_LIST_ROUTE,\n UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE,\n\n // ============================================================================\n // Instruction Enhancement Routes\n // ============================================================================\n ENHANCE_INSTRUCTIONS_ROUTE,\n\n // ============================================================================\n // Agent Tool Routes\n // ============================================================================\n GET_AGENT_TOOL_ROUTE,\n READ_AGENT_PLAN_ROUTE,\n\n // ============================================================================\n // Agent Skill Routes\n // ============================================================================\n GET_AGENT_SKILL_ROUTE,\n\n // ============================================================================\n // Voice/Speech Routes\n // ============================================================================\n GENERATE_SPEECH_ROUTE,\n GENERATE_SPEECH_DEPRECATED_ROUTE,\n TRANSCRIBE_SPEECH_ROUTE,\n TRANSCRIBE_SPEECH_DEPRECATED_ROUTE,\n GET_LISTENER_ROUTE,\n\n // ============================================================================\n // Deprecated Routes\n // ============================================================================\n STREAM_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE,\n STREAM_UI_MESSAGE_DEPRECATED_ROUTE,\n];\n\n/**\n * Type-level tuple preserving each agent route's specific schema types.\n * Used by ServerRoutes to build the type-level route map.\n */\nexport type AgentRoutes = readonly [\n typeof LIST_AGENTS_ROUTE,\n typeof GET_PROVIDERS_ROUTE,\n typeof GET_AGENT_BY_ID_ROUTE,\n typeof CLONE_AGENT_ROUTE,\n typeof GET_SPEAKERS_ROUTE,\n typeof GET_SPEAKERS_DEPRECATED_ROUTE,\n typeof GENERATE_AGENT_ROUTE,\n typeof GENERATE_AGENT_VNEXT_ROUTE,\n typeof STREAM_GENERATE_ROUTE,\n typeof STREAM_UNTIL_IDLE_GENERATE_ROUTE,\n typeof STREAM_GENERATE_VNEXT_DEPRECATED_ROUTE,\n typeof SEND_AGENT_MESSAGE_ROUTE,\n typeof QUEUE_AGENT_MESSAGE_ROUTE,\n typeof SEND_AGENT_SIGNAL_ROUTE,\n typeof ABORT_AGENT_THREAD_ROUTE,\n typeof SUBSCRIBE_AGENT_THREAD_ROUTE,\n typeof EXECUTE_AGENT_TOOL_ROUTE,\n typeof APPROVE_TOOL_CALL_ROUTE,\n typeof SEND_TOOL_APPROVAL_ROUTE,\n typeof LIST_SUSPENDED_RUNS_ROUTE,\n typeof DECLINE_TOOL_CALL_ROUTE,\n typeof RESUME_STREAM_ROUTE,\n typeof RECOVER_ROUTE,\n typeof RESUME_STREAM_UNTIL_IDLE_ROUTE,\n typeof APPROVE_TOOL_CALL_GENERATE_ROUTE,\n typeof DECLINE_TOOL_CALL_GENERATE_ROUTE,\n typeof APPROVE_NETWORK_TOOL_CALL_ROUTE,\n typeof DECLINE_NETWORK_TOOL_CALL_ROUTE,\n typeof STREAM_NETWORK_ROUTE,\n typeof UPDATE_AGENT_MODEL_ROUTE,\n typeof RESET_AGENT_MODEL_ROUTE,\n typeof REORDER_AGENT_MODEL_LIST_ROUTE,\n typeof UPDATE_AGENT_MODEL_IN_MODEL_LIST_ROUTE,\n typeof ENHANCE_INSTRUCTIONS_ROUTE,\n typeof GET_AGENT_TOOL_ROUTE,\n typeof READ_AGENT_PLAN_ROUTE,\n typeof GET_AGENT_SKILL_ROUTE,\n typeof GENERATE_SPEECH_ROUTE,\n typeof GENERATE_SPEECH_DEPRECATED_ROUTE,\n typeof TRANSCRIBE_SPEECH_ROUTE,\n typeof TRANSCRIBE_SPEECH_DEPRECATED_ROUTE,\n typeof GET_LISTENER_ROUTE,\n typeof STREAM_VNEXT_DEPRECATED_ROUTE,\n typeof STREAM_UI_MESSAGE_VNEXT_DEPRECATED_ROUTE,\n typeof STREAM_UI_MESSAGE_DEPRECATED_ROUTE,\n];\n","import {\n BACKGROUND_TASK_STREAM_ROUTE,\n GET_BACKGROUND_TASK_ROUTE,\n LIST_BACKGROUND_TASKS_ROUTE,\n} from '../../handlers/background-tasks';\nimport type { ServerRoute } from '.';\n\nexport const BACKGROUND_TASK_ROUTES: ServerRoute<any, any, any>[] = [\n BACKGROUND_TASK_STREAM_ROUTE,\n LIST_BACKGROUND_TASKS_ROUTE,\n GET_BACKGROUND_TASK_ROUTE,\n];\n","import {\n LIST_CHANNEL_PLATFORMS_ROUTE,\n LIST_CHANNEL_INSTALLATIONS_ROUTE,\n CONNECT_CHANNEL_ROUTE,\n DISCONNECT_CHANNEL_ROUTE,\n} from '../../handlers/channels';\n\nexport const CHANNELS_ROUTES = [\n LIST_CHANNEL_PLATFORMS_ROUTE,\n LIST_CHANNEL_INSTALLATIONS_ROUTE,\n CONNECT_CHANNEL_ROUTE,\n DISCONNECT_CHANNEL_ROUTE,\n] as const;\n","import {\n CREATE_CONVERSATION_ROUTE,\n DELETE_CONVERSATION_ROUTE,\n GET_CONVERSATION_ITEMS_ROUTE,\n GET_CONVERSATION_ROUTE,\n} from '../../handlers/conversations';\n\nexport const CONVERSATIONS_ROUTES = [\n CREATE_CONVERSATION_ROUTE,\n GET_CONVERSATION_ROUTE,\n GET_CONVERSATION_ITEMS_ROUTE,\n DELETE_CONVERSATION_ROUTE,\n] as const;\n","import {\n LIST_DATASETS_ROUTE,\n CREATE_DATASET_ROUTE,\n GET_DATASET_ROUTE,\n UPDATE_DATASET_ROUTE,\n DELETE_DATASET_ROUTE,\n LIST_ITEMS_ROUTE,\n ADD_ITEM_ROUTE,\n GET_ITEM_ROUTE,\n UPDATE_ITEM_ROUTE,\n DELETE_ITEM_ROUTE,\n LIST_ALL_EXPERIMENTS_ROUTE,\n EXPERIMENT_REVIEW_SUMMARY_ROUTE,\n LIST_EXPERIMENTS_ROUTE,\n TRIGGER_EXPERIMENT_ROUTE,\n RUN_EXPERIMENT_ITEM_ROUTE,\n SUBMIT_EXPERIMENT_RESULT_ROUTE,\n FINALIZE_EXPERIMENT_ROUTE,\n GET_EXPERIMENT_ROUTE,\n LIST_EXPERIMENT_RESULTS_ROUTE,\n UPDATE_EXPERIMENT_RESULT_ROUTE,\n COMPARE_EXPERIMENTS_ROUTE,\n LIST_DATASET_VERSIONS_ROUTE,\n LIST_ITEM_VERSIONS_ROUTE,\n GET_ITEM_VERSION_ROUTE,\n BATCH_INSERT_ITEMS_ROUTE,\n BATCH_DELETE_ITEMS_ROUTE,\n GENERATE_ITEMS_ROUTE,\n CLUSTER_FAILURES_ROUTE,\n} from '../../handlers/datasets';\n\nexport const DATASETS_ROUTES = [\n // Dataset CRUD\n LIST_DATASETS_ROUTE,\n CREATE_DATASET_ROUTE,\n GET_DATASET_ROUTE,\n UPDATE_DATASET_ROUTE,\n DELETE_DATASET_ROUTE,\n // Item list and add\n LIST_ITEMS_ROUTE,\n ADD_ITEM_ROUTE,\n // Batch operations - MUST come before item-specific routes to avoid /items/batch matching /items/:itemId\n BATCH_INSERT_ITEMS_ROUTE,\n BATCH_DELETE_ITEMS_ROUTE,\n // Item-specific CRUD (uses :itemId param)\n GET_ITEM_ROUTE,\n UPDATE_ITEM_ROUTE,\n DELETE_ITEM_ROUTE,\n // Version operations\n LIST_DATASET_VERSIONS_ROUTE,\n LIST_ITEM_VERSIONS_ROUTE,\n GET_ITEM_VERSION_ROUTE,\n // All experiments (cross-dataset) - MUST come before dataset-scoped experiments\n LIST_ALL_EXPERIMENTS_ROUTE,\n // Experiment review summary (cross-dataset) - MUST come before dataset-scoped experiments\n EXPERIMENT_REVIEW_SUMMARY_ROUTE,\n // Experiment operations (dataset-scoped)\n LIST_EXPERIMENTS_ROUTE,\n TRIGGER_EXPERIMENT_ROUTE,\n // Caller-driven experiments (run one item, submit results, finalize)\n RUN_EXPERIMENT_ITEM_ROUTE,\n SUBMIT_EXPERIMENT_RESULT_ROUTE,\n FINALIZE_EXPERIMENT_ROUTE,\n GET_EXPERIMENT_ROUTE,\n LIST_EXPERIMENT_RESULTS_ROUTE,\n UPDATE_EXPERIMENT_RESULT_ROUTE,\n // Analytics\n COMPARE_EXPERIMENTS_ROUTE,\n // AI generation\n GENERATE_ITEMS_ROUTE,\n // Failure analysis\n CLUSTER_FAILURES_ROUTE,\n] as const;\n","import {\n DELETE_DYNAMIC_WORKFLOW_ROUTE,\n GET_DYNAMIC_WORKFLOW_ROUTE,\n LIST_DYNAMIC_WORKFLOWS_ROUTE,\n UPSERT_DYNAMIC_WORKFLOW_ROUTE,\n} from '../../handlers/dynamic-workflows';\nimport type { ServerRoute } from '.';\n\n/**\n * Routes for dynamic workflow definitions: list / get / upsert / delete.\n * Upsert is the path the chat-driven workflow-builder agent (and Studio's\n * future \"Save\" button) uses to persist + live-register a workflow without\n * a server restart.\n */\nexport const DYNAMIC_WORKFLOWS_ROUTES: readonly ServerRoute[] = [\n LIST_DYNAMIC_WORKFLOWS_ROUTE,\n UPSERT_DYNAMIC_WORKFLOW_ROUTE,\n GET_DYNAMIC_WORKFLOW_ROUTE, // After UPSERT (POST) since both are on the same /stored/workflows base\n DELETE_DYNAMIC_WORKFLOW_ROUTE,\n];\n\nexport type DynamicWorkflowRoutes = readonly [\n typeof LIST_DYNAMIC_WORKFLOWS_ROUTE,\n typeof UPSERT_DYNAMIC_WORKFLOW_ROUTE,\n typeof GET_DYNAMIC_WORKFLOW_ROUTE,\n typeof DELETE_DYNAMIC_WORKFLOW_ROUTE,\n];\n","import {\n BUILDER_REGISTRY_INSTALL_ROUTE,\n BUILDER_REGISTRY_POPULAR_ROUTE,\n BUILDER_REGISTRY_PREVIEW_ROUTE,\n BUILDER_REGISTRY_SEARCH_ROUTE,\n LIST_BUILDER_REGISTRIES_ROUTE,\n} from '../../handlers/builder-registry';\nimport {\n GET_EDITOR_BUILDER_AVAILABLE_MODELS_ROUTE,\n GET_EDITOR_BUILDER_SETTINGS_ROUTE,\n GET_INFRASTRUCTURE_STATUS_ROUTE,\n} from '../../handlers/editor-builder';\n\n/**\n * Editor Builder Routes\n *\n * Routes for agent builder settings, infrastructure status, and external\n * skill registries.\n */\nexport const EDITOR_BUILDER_ROUTES = [\n GET_EDITOR_BUILDER_SETTINGS_ROUTE,\n GET_EDITOR_BUILDER_AVAILABLE_MODELS_ROUTE,\n GET_INFRASTRUCTURE_STATUS_ROUTE,\n LIST_BUILDER_REGISTRIES_ROUTE,\n BUILDER_REGISTRY_SEARCH_ROUTE,\n BUILDER_REGISTRY_POPULAR_ROUTE,\n BUILDER_REGISTRY_PREVIEW_ROUTE,\n BUILDER_REGISTRY_INSTALL_ROUTE,\n] as const;\n","/**\n * Legacy routes that are deprecated but still exist in deployer for backward compatibility.\n * These routes should not be used in new code and will be removed in a future version.\n */\n\nimport { GENERATE_LEGACY_ROUTE, STREAM_GENERATE_LEGACY_ROUTE } from '../../handlers/agents';\nimport { STREAM_LEGACY_WORKFLOW_ROUTE, OBSERVE_STREAM_LEGACY_WORKFLOW_ROUTE } from '../../handlers/workflows';\n\nexport const LEGACY_ROUTES = [\n // ============================================================================\n // Legacy Agent Routes\n // ============================================================================\n GENERATE_LEGACY_ROUTE,\n STREAM_GENERATE_LEGACY_ROUTE,\n\n // ============================================================================\n // Legacy Workflow Routes\n // ============================================================================\n STREAM_LEGACY_WORKFLOW_ROUTE,\n OBSERVE_STREAM_LEGACY_WORKFLOW_ROUTE,\n] as const;\n","import { LIST_LOG_TRANSPORTS_ROUTE, LIST_LOGS_ROUTE, LIST_LOGS_BY_RUN_ID_ROUTE } from '../../handlers/logs';\n\nexport const LOGS_ROUTES = [LIST_LOG_TRANSPORTS_ROUTE, LIST_LOGS_ROUTE, LIST_LOGS_BY_RUN_ID_ROUTE] as const;\n","import {\n LIST_MCP_SERVERS_ROUTE,\n GET_MCP_SERVER_DETAIL_ROUTE,\n LIST_MCP_SERVER_TOOLS_ROUTE,\n GET_MCP_SERVER_TOOL_DETAIL_ROUTE,\n EXECUTE_MCP_SERVER_TOOL_ROUTE,\n LIST_MCP_SERVER_RESOURCES_ROUTE,\n READ_MCP_SERVER_RESOURCE_ROUTE,\n MCP_HTTP_TRANSPORT_ROUTE,\n MCP_SSE_TRANSPORT_ROUTE,\n MCP_SSE_MESSAGES_ROUTE,\n} from '../../handlers/mcp';\n\n/**\n * MCP Routes\n *\n * Registry routes provide access to the MCP server registry and tools.\n * Transport routes handle the MCP protocol communication (HTTP and SSE).\n */\nexport const MCP_ROUTES = [\n // ============================================================================\n // MCP Server Registry Routes\n // ============================================================================\n LIST_MCP_SERVERS_ROUTE,\n GET_MCP_SERVER_DETAIL_ROUTE,\n\n // ============================================================================\n // MCP Server Tool Routes\n // ============================================================================\n LIST_MCP_SERVER_TOOLS_ROUTE,\n GET_MCP_SERVER_TOOL_DETAIL_ROUTE,\n EXECUTE_MCP_SERVER_TOOL_ROUTE,\n\n // ============================================================================\n // MCP Server Resource Routes\n // ============================================================================\n LIST_MCP_SERVER_RESOURCES_ROUTE,\n READ_MCP_SERVER_RESOURCE_ROUTE,\n\n // ============================================================================\n // MCP Transport Routes (handled by adapters)\n // ============================================================================\n MCP_HTTP_TRANSPORT_ROUTE,\n MCP_SSE_TRANSPORT_ROUTE,\n MCP_SSE_MESSAGES_ROUTE,\n] as const;\n","import {\n GET_MEMORY_STATUS_ROUTE,\n GET_MEMORY_CONFIG_ROUTE,\n GET_OBSERVATIONAL_MEMORY_ROUTE,\n AWAIT_BUFFER_STATUS_ROUTE,\n LIST_THREADS_ROUTE,\n GET_THREAD_BY_ID_ROUTE,\n LIST_MESSAGES_ROUTE,\n GET_WORKING_MEMORY_ROUTE,\n SAVE_MESSAGES_ROUTE,\n CREATE_THREAD_ROUTE,\n UPDATE_THREAD_ROUTE,\n DELETE_THREAD_ROUTE,\n CLONE_THREAD_ROUTE,\n UPDATE_WORKING_MEMORY_ROUTE,\n DELETE_MESSAGES_ROUTE,\n SEARCH_MEMORY_ROUTE,\n GET_MEMORY_STATUS_NETWORK_ROUTE,\n LIST_THREADS_NETWORK_ROUTE,\n GET_THREAD_BY_ID_NETWORK_ROUTE,\n LIST_MESSAGES_NETWORK_ROUTE,\n SAVE_MESSAGES_NETWORK_ROUTE,\n CREATE_THREAD_NETWORK_ROUTE,\n UPDATE_THREAD_NETWORK_ROUTE,\n DELETE_THREAD_NETWORK_ROUTE,\n DELETE_MESSAGES_NETWORK_ROUTE,\n} from '../../handlers/memory';\n\nexport const MEMORY_ROUTES = [\n GET_MEMORY_STATUS_ROUTE,\n GET_MEMORY_CONFIG_ROUTE,\n GET_OBSERVATIONAL_MEMORY_ROUTE,\n AWAIT_BUFFER_STATUS_ROUTE,\n LIST_THREADS_ROUTE,\n GET_THREAD_BY_ID_ROUTE,\n LIST_MESSAGES_ROUTE,\n GET_WORKING_MEMORY_ROUTE,\n SAVE_MESSAGES_ROUTE,\n CREATE_THREAD_ROUTE,\n UPDATE_THREAD_ROUTE,\n DELETE_THREAD_ROUTE,\n CLONE_THREAD_ROUTE,\n UPDATE_WORKING_MEMORY_ROUTE,\n DELETE_MESSAGES_ROUTE,\n SEARCH_MEMORY_ROUTE,\n GET_MEMORY_STATUS_NETWORK_ROUTE,\n LIST_THREADS_NETWORK_ROUTE,\n GET_THREAD_BY_ID_NETWORK_ROUTE,\n LIST_MESSAGES_NETWORK_ROUTE,\n SAVE_MESSAGES_NETWORK_ROUTE,\n CREATE_THREAD_NETWORK_ROUTE,\n UPDATE_THREAD_NETWORK_ROUTE,\n DELETE_THREAD_NETWORK_ROUTE,\n DELETE_MESSAGES_NETWORK_ROUTE,\n] as const;\n","import {\n LIST_TRACES_ROUTE,\n LIST_TRACES_LIGHT_ROUTE,\n LIST_BRANCHES_ROUTE,\n GET_BRANCH_ROUTE,\n GET_TRACE_ROUTE,\n GET_TRACE_LIGHT_ROUTE,\n GET_SPAN_ROUTE,\n GET_TRACE_TRAJECTORY_ROUTE,\n SCORE_TRACES_ROUTE,\n LIST_SCORES_BY_SPAN_ROUTE,\n} from '../../handlers/observability';\nimport {\n LIST_METRICS,\n LIST_LOGS,\n LIST_SCORES,\n CREATE_SCORE,\n GET_SCORE,\n GET_SCORE_AGGREGATE,\n GET_SCORE_BREAKDOWN,\n GET_SCORE_TIME_SERIES,\n GET_SCORE_PERCENTILES,\n LIST_FEEDBACK,\n CREATE_FEEDBACK,\n GET_FEEDBACK_AGGREGATE,\n GET_FEEDBACK_BREAKDOWN,\n GET_FEEDBACK_TIME_SERIES,\n GET_FEEDBACK_PERCENTILES,\n GET_METRIC_AGGREGATE,\n GET_METRIC_BREAKDOWN,\n GET_METRIC_TIME_SERIES,\n GET_METRIC_PERCENTILES,\n GET_METRIC_NAMES,\n GET_METRIC_LABEL_KEYS,\n GET_METRIC_LABEL_VALUES,\n GET_ENTITY_TYPES,\n GET_ENTITY_NAMES,\n GET_SERVICE_NAMES,\n GET_ENVIRONMENTS,\n GET_TAGS,\n} from '../../handlers/observability-new-endpoints';\n\nexport const OBSERVABILITY_ROUTES = [\n // Legacy\n LIST_TRACES_ROUTE,\n LIST_TRACES_LIGHT_ROUTE,\n LIST_BRANCHES_ROUTE,\n GET_BRANCH_ROUTE,\n GET_TRACE_ROUTE,\n GET_TRACE_LIGHT_ROUTE,\n GET_SPAN_ROUTE,\n GET_TRACE_TRAJECTORY_ROUTE,\n SCORE_TRACES_ROUTE,\n LIST_SCORES_BY_SPAN_ROUTE,\n // New observability routes\n LIST_METRICS,\n LIST_LOGS,\n LIST_SCORES,\n CREATE_SCORE,\n GET_SCORE,\n GET_SCORE_AGGREGATE,\n GET_SCORE_BREAKDOWN,\n GET_SCORE_TIME_SERIES,\n GET_SCORE_PERCENTILES,\n LIST_FEEDBACK,\n CREATE_FEEDBACK,\n GET_FEEDBACK_AGGREGATE,\n GET_FEEDBACK_BREAKDOWN,\n GET_FEEDBACK_TIME_SERIES,\n GET_FEEDBACK_PERCENTILES,\n GET_METRIC_AGGREGATE,\n GET_METRIC_BREAKDOWN,\n GET_METRIC_TIME_SERIES,\n GET_METRIC_PERCENTILES,\n GET_METRIC_NAMES,\n GET_METRIC_LABEL_KEYS,\n GET_METRIC_LABEL_VALUES,\n GET_ENTITY_TYPES,\n GET_ENTITY_NAMES,\n GET_SERVICE_NAMES,\n GET_ENVIRONMENTS,\n GET_TAGS,\n] as const;\n","import { LIST_PROCESSOR_PROVIDERS_ROUTE, GET_PROCESSOR_PROVIDER_ROUTE } from '../../handlers/processor-providers';\n\nexport const PROCESSOR_PROVIDER_ROUTES = [LIST_PROCESSOR_PROVIDERS_ROUTE, GET_PROCESSOR_PROVIDER_ROUTE] as const;\n","import { LIST_PROCESSORS_ROUTE, GET_PROCESSOR_BY_ID_ROUTE, EXECUTE_PROCESSOR_ROUTE } from '../../handlers/processors';\n\nexport const PROCESSORS_ROUTES = [LIST_PROCESSORS_ROUTE, GET_PROCESSOR_BY_ID_ROUTE, EXECUTE_PROCESSOR_ROUTE] as const;\n","import { CREATE_RESPONSE_ROUTE, DELETE_RESPONSE_ROUTE, GET_RESPONSE_ROUTE } from '../../handlers/responses';\n\nexport const RESPONSES_ROUTES = [CREATE_RESPONSE_ROUTE, GET_RESPONSE_ROUTE, DELETE_RESPONSE_ROUTE] as const;\n","import {\n CREATE_SCHEDULE_ROUTE,\n DELETE_SCHEDULE_ROUTE,\n GET_SCHEDULE_ROUTE,\n LIST_SCHEDULES_ROUTE,\n LIST_SCHEDULE_TRIGGERS_ROUTE,\n PAUSE_SCHEDULE_ROUTE,\n RESUME_SCHEDULE_ROUTE,\n RUN_SCHEDULE_ROUTE,\n UPDATE_SCHEDULE_ROUTE,\n} from '../../handlers/schedules';\nimport type { ServerRoute } from '.';\n\nexport const SCHEDULES_ROUTES: ServerRoute<any, any, any>[] = [\n LIST_SCHEDULES_ROUTE,\n GET_SCHEDULE_ROUTE,\n CREATE_SCHEDULE_ROUTE,\n UPDATE_SCHEDULE_ROUTE,\n DELETE_SCHEDULE_ROUTE,\n LIST_SCHEDULE_TRIGGERS_ROUTE,\n PAUSE_SCHEDULE_ROUTE,\n RESUME_SCHEDULE_ROUTE,\n RUN_SCHEDULE_ROUTE,\n];\n","import {\n LIST_SCORERS_ROUTE,\n GET_SCORER_ROUTE,\n LIST_SCORES_BY_RUN_ID_ROUTE,\n LIST_SCORES_BY_SCORER_ID_ROUTE,\n LIST_SCORES_BY_ENTITY_ID_ROUTE,\n SAVE_SCORE_ROUTE,\n} from '../../handlers/scores';\n\nexport const SCORES_ROUTES = [\n LIST_SCORERS_ROUTE,\n GET_SCORER_ROUTE,\n LIST_SCORES_BY_RUN_ID_ROUTE,\n LIST_SCORES_BY_SCORER_ID_ROUTE,\n LIST_SCORES_BY_ENTITY_ID_ROUTE,\n SAVE_SCORE_ROUTE,\n] as const;\n","import {\n LIST_AGENT_VERSIONS_ROUTE,\n CREATE_AGENT_VERSION_ROUTE,\n GET_AGENT_VERSION_ROUTE,\n ACTIVATE_AGENT_VERSION_ROUTE,\n RESTORE_AGENT_VERSION_ROUTE,\n DELETE_AGENT_VERSION_ROUTE,\n COMPARE_AGENT_VERSIONS_ROUTE,\n} from '../../handlers/agent-versions';\nimport { FAVORITE_STORED_AGENT_ROUTE, UNFAVORITE_STORED_AGENT_ROUTE } from '../../handlers/stored-agent-favorites';\nimport {\n LIST_STORED_AGENTS_ROUTE,\n GET_STORED_AGENT_ROUTE,\n GET_STORED_AGENT_DEPENDENTS_ROUTE,\n CREATE_STORED_AGENT_ROUTE,\n UPDATE_STORED_AGENT_ROUTE,\n DELETE_STORED_AGENT_ROUTE,\n PREVIEW_INSTRUCTIONS_ROUTE,\n EXPORT_STORED_AGENT_ROUTE,\n OPEN_STORED_AGENT_CHANGE_REQUEST_ROUTE,\n} from '../../handlers/stored-agents';\nimport type { ServerRoute } from '.';\n\n/**\n * Routes for stored agents CRUD operations and version management.\n * These routes provide API access to agent configurations stored in the database,\n * enabling dynamic creation and management of agents via Mastra Studio.\n */\nexport const STORED_AGENTS_ROUTES: readonly ServerRoute[] = [\n // ============================================================================\n // Stored Agents CRUD Routes\n // IMPORTANT: Routes with literal paths (e.g., /preview-instructions) must come\n // BEFORE routes with path parameters (e.g., /:storedAgentId) to ensure correct matching.\n // ============================================================================\n LIST_STORED_AGENTS_ROUTE,\n PREVIEW_INSTRUCTIONS_ROUTE, // Must be before GET_STORED_AGENT_ROUTE\n GET_STORED_AGENT_DEPENDENTS_ROUTE, // Must be before GET_STORED_AGENT_ROUTE (longer literal)\n EXPORT_STORED_AGENT_ROUTE, // Must be before GET_STORED_AGENT_ROUTE\n OPEN_STORED_AGENT_CHANGE_REQUEST_ROUTE, // Must be before GET_STORED_AGENT_ROUTE\n GET_STORED_AGENT_ROUTE,\n CREATE_STORED_AGENT_ROUTE,\n UPDATE_STORED_AGENT_ROUTE,\n DELETE_STORED_AGENT_ROUTE,\n\n // ============================================================================\n // Agent Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n // ============================================================================\n LIST_AGENT_VERSIONS_ROUTE,\n CREATE_AGENT_VERSION_ROUTE,\n COMPARE_AGENT_VERSIONS_ROUTE, // Must be before GET_AGENT_VERSION_ROUTE\n GET_AGENT_VERSION_ROUTE,\n ACTIVATE_AGENT_VERSION_ROUTE,\n RESTORE_AGENT_VERSION_ROUTE,\n DELETE_AGENT_VERSION_ROUTE,\n\n // ============================================================================\n // Favorites (EE)\n // ============================================================================\n FAVORITE_STORED_AGENT_ROUTE,\n UNFAVORITE_STORED_AGENT_ROUTE,\n];\n\n/**\n * Type-level tuple preserving each stored agent route's specific schema types.\n * Used by ServerRoutes to build the type-level route map.\n */\nexport type StoredAgentRoutes = readonly [\n typeof LIST_STORED_AGENTS_ROUTE,\n typeof PREVIEW_INSTRUCTIONS_ROUTE,\n typeof GET_STORED_AGENT_DEPENDENTS_ROUTE,\n typeof EXPORT_STORED_AGENT_ROUTE,\n typeof OPEN_STORED_AGENT_CHANGE_REQUEST_ROUTE,\n typeof GET_STORED_AGENT_ROUTE,\n typeof CREATE_STORED_AGENT_ROUTE,\n typeof UPDATE_STORED_AGENT_ROUTE,\n typeof DELETE_STORED_AGENT_ROUTE,\n typeof LIST_AGENT_VERSIONS_ROUTE,\n typeof CREATE_AGENT_VERSION_ROUTE,\n typeof COMPARE_AGENT_VERSIONS_ROUTE,\n typeof GET_AGENT_VERSION_ROUTE,\n typeof ACTIVATE_AGENT_VERSION_ROUTE,\n typeof RESTORE_AGENT_VERSION_ROUTE,\n typeof DELETE_AGENT_VERSION_ROUTE,\n typeof FAVORITE_STORED_AGENT_ROUTE,\n typeof UNFAVORITE_STORED_AGENT_ROUTE,\n];\n","import {\n LIST_MCP_CLIENT_VERSIONS_ROUTE,\n CREATE_MCP_CLIENT_VERSION_ROUTE,\n GET_MCP_CLIENT_VERSION_ROUTE,\n ACTIVATE_MCP_CLIENT_VERSION_ROUTE,\n RESTORE_MCP_CLIENT_VERSION_ROUTE,\n DELETE_MCP_CLIENT_VERSION_ROUTE,\n COMPARE_MCP_CLIENT_VERSIONS_ROUTE,\n} from '../../handlers/mcp-client-versions';\nimport {\n LIST_STORED_MCP_CLIENTS_ROUTE,\n GET_STORED_MCP_CLIENT_ROUTE,\n CREATE_STORED_MCP_CLIENT_ROUTE,\n UPDATE_STORED_MCP_CLIENT_ROUTE,\n DELETE_STORED_MCP_CLIENT_ROUTE,\n} from '../../handlers/stored-mcp-clients';\n\nexport const STORED_MCP_CLIENTS_ROUTES = [\n // Stored MCP Clients CRUD Routes\n LIST_STORED_MCP_CLIENTS_ROUTE,\n GET_STORED_MCP_CLIENT_ROUTE,\n CREATE_STORED_MCP_CLIENT_ROUTE,\n UPDATE_STORED_MCP_CLIENT_ROUTE,\n DELETE_STORED_MCP_CLIENT_ROUTE,\n\n // MCP Client Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n LIST_MCP_CLIENT_VERSIONS_ROUTE,\n CREATE_MCP_CLIENT_VERSION_ROUTE,\n COMPARE_MCP_CLIENT_VERSIONS_ROUTE,\n GET_MCP_CLIENT_VERSION_ROUTE,\n ACTIVATE_MCP_CLIENT_VERSION_ROUTE,\n RESTORE_MCP_CLIENT_VERSION_ROUTE,\n DELETE_MCP_CLIENT_VERSION_ROUTE,\n] as const;\n","import {\n LIST_PROMPT_BLOCK_VERSIONS_ROUTE,\n CREATE_PROMPT_BLOCK_VERSION_ROUTE,\n GET_PROMPT_BLOCK_VERSION_ROUTE,\n ACTIVATE_PROMPT_BLOCK_VERSION_ROUTE,\n RESTORE_PROMPT_BLOCK_VERSION_ROUTE,\n DELETE_PROMPT_BLOCK_VERSION_ROUTE,\n COMPARE_PROMPT_BLOCK_VERSIONS_ROUTE,\n} from '../../handlers/prompt-block-versions';\nimport {\n LIST_STORED_PROMPT_BLOCKS_ROUTE,\n GET_STORED_PROMPT_BLOCK_ROUTE,\n CREATE_STORED_PROMPT_BLOCK_ROUTE,\n UPDATE_STORED_PROMPT_BLOCK_ROUTE,\n DELETE_STORED_PROMPT_BLOCK_ROUTE,\n} from '../../handlers/stored-prompt-blocks';\n\nexport const STORED_PROMPT_BLOCKS_ROUTES = [\n // Stored Prompt Blocks CRUD Routes\n LIST_STORED_PROMPT_BLOCKS_ROUTE,\n GET_STORED_PROMPT_BLOCK_ROUTE,\n CREATE_STORED_PROMPT_BLOCK_ROUTE,\n UPDATE_STORED_PROMPT_BLOCK_ROUTE,\n DELETE_STORED_PROMPT_BLOCK_ROUTE,\n\n // Prompt Block Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n LIST_PROMPT_BLOCK_VERSIONS_ROUTE,\n CREATE_PROMPT_BLOCK_VERSION_ROUTE,\n COMPARE_PROMPT_BLOCK_VERSIONS_ROUTE,\n GET_PROMPT_BLOCK_VERSION_ROUTE,\n ACTIVATE_PROMPT_BLOCK_VERSION_ROUTE,\n RESTORE_PROMPT_BLOCK_VERSION_ROUTE,\n DELETE_PROMPT_BLOCK_VERSION_ROUTE,\n] as const;\n","import {\n LIST_SCORER_VERSIONS_ROUTE,\n CREATE_SCORER_VERSION_ROUTE,\n GET_SCORER_VERSION_ROUTE,\n ACTIVATE_SCORER_VERSION_ROUTE,\n RESTORE_SCORER_VERSION_ROUTE,\n DELETE_SCORER_VERSION_ROUTE,\n COMPARE_SCORER_VERSIONS_ROUTE,\n} from '../../handlers/scorer-versions';\nimport {\n LIST_STORED_SCORERS_ROUTE,\n GET_STORED_SCORER_ROUTE,\n CREATE_STORED_SCORER_ROUTE,\n UPDATE_STORED_SCORER_ROUTE,\n DELETE_STORED_SCORER_ROUTE,\n} from '../../handlers/stored-scorers';\n\nexport const STORED_SCORERS_ROUTES = [\n // Stored Scorers CRUD Routes\n LIST_STORED_SCORERS_ROUTE,\n GET_STORED_SCORER_ROUTE,\n CREATE_STORED_SCORER_ROUTE,\n UPDATE_STORED_SCORER_ROUTE,\n DELETE_STORED_SCORER_ROUTE,\n\n // Scorer Versions Routes\n // IMPORTANT: Routes with literal paths (e.g., /compare) must come BEFORE\n // routes with path parameters (e.g., /:versionId) to ensure correct matching.\n LIST_SCORER_VERSIONS_ROUTE,\n CREATE_SCORER_VERSION_ROUTE,\n COMPARE_SCORER_VERSIONS_ROUTE,\n GET_SCORER_VERSION_ROUTE,\n ACTIVATE_SCORER_VERSION_ROUTE,\n RESTORE_SCORER_VERSION_ROUTE,\n DELETE_SCORER_VERSION_ROUTE,\n] as const;\n","import { FAVORITE_STORED_SKILL_ROUTE, UNFAVORITE_STORED_SKILL_ROUTE } from '../../handlers/stored-skill-favorites';\nimport {\n LIST_STORED_SKILLS_ROUTE,\n GET_STORED_SKILL_ROUTE,\n CREATE_STORED_SKILL_ROUTE,\n UPDATE_STORED_SKILL_ROUTE,\n DELETE_STORED_SKILL_ROUTE,\n PUBLISH_STORED_SKILL_ROUTE,\n} from '../../handlers/stored-skills';\n\nexport const STORED_SKILLS_ROUTES = [\n // Stored Skills CRUD Routes\n LIST_STORED_SKILLS_ROUTE,\n GET_STORED_SKILL_ROUTE,\n CREATE_STORED_SKILL_ROUTE,\n UPDATE_STORED_SKILL_ROUTE,\n DELETE_STORED_SKILL_ROUTE,\n // Publish\n PUBLISH_STORED_SKILL_ROUTE,\n // Favorites (EE)\n FAVORITE_STORED_SKILL_ROUTE,\n UNFAVORITE_STORED_SKILL_ROUTE,\n] as const;\n","import {\n LIST_STORED_WORKSPACES_ROUTE,\n GET_STORED_WORKSPACE_ROUTE,\n CREATE_STORED_WORKSPACE_ROUTE,\n UPDATE_STORED_WORKSPACE_ROUTE,\n DELETE_STORED_WORKSPACE_ROUTE,\n} from '../../handlers/stored-workspaces';\n\nexport const STORED_WORKSPACES_ROUTES = [\n // Stored Workspaces CRUD Routes\n LIST_STORED_WORKSPACES_ROUTE,\n GET_STORED_WORKSPACE_ROUTE,\n CREATE_STORED_WORKSPACE_ROUTE,\n UPDATE_STORED_WORKSPACE_ROUTE,\n DELETE_STORED_WORKSPACE_ROUTE,\n] as const;\n","import { GET_API_SCHEMA_ROUTE, GET_SYSTEM_PACKAGES_ROUTE } from '../../handlers/system';\n\n/**\n * System Routes\n *\n * Routes for system information and diagnostics.\n */\nexport const SYSTEM_ROUTES = [GET_SYSTEM_PACKAGES_ROUTE, GET_API_SCHEMA_ROUTE] as const;\n","import {\n AUTHORIZE_TOOL_PROVIDER_ROUTE,\n DISCONNECT_TOOL_PROVIDER_CONNECTION_ROUTE,\n GET_TOOL_PROVIDER_AUTH_STATUS_ROUTE,\n GET_TOOL_PROVIDER_CONNECTION_USAGE_ROUTE,\n GET_TOOL_PROVIDER_HEALTH_ROUTE,\n GET_TOOL_PROVIDER_TOOL_SCHEMA_ROUTE,\n LIST_TOOL_PROVIDERS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTIONS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTION_FIELDS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLKITS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLS_ROUTE,\n TOOL_PROVIDER_CONNECTION_STATUS_ROUTE,\n UPDATE_TOOL_PROVIDER_CONNECTION_ROUTE,\n} from '../../handlers/tool-providers';\n\nexport const TOOL_PROVIDER_ROUTES = [\n LIST_TOOL_PROVIDERS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLKITS_ROUTE,\n LIST_TOOL_PROVIDER_TOOLS_ROUTE,\n GET_TOOL_PROVIDER_TOOL_SCHEMA_ROUTE,\n AUTHORIZE_TOOL_PROVIDER_ROUTE,\n GET_TOOL_PROVIDER_AUTH_STATUS_ROUTE,\n TOOL_PROVIDER_CONNECTION_STATUS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTIONS_ROUTE,\n LIST_TOOL_PROVIDER_CONNECTION_FIELDS_ROUTE,\n DISCONNECT_TOOL_PROVIDER_CONNECTION_ROUTE,\n UPDATE_TOOL_PROVIDER_CONNECTION_ROUTE,\n GET_TOOL_PROVIDER_CONNECTION_USAGE_ROUTE,\n GET_TOOL_PROVIDER_HEALTH_ROUTE,\n] as const;\n","import { LIST_TOOLS_ROUTE, GET_TOOL_BY_ID_ROUTE, EXECUTE_TOOL_ROUTE } from '../../handlers/tools';\n\nexport const TOOLS_ROUTES = [LIST_TOOLS_ROUTE, GET_TOOL_BY_ID_ROUTE, EXECUTE_TOOL_ROUTE] as const;\n","import {\n UPSERT_VECTORS_ROUTE,\n CREATE_INDEX_ROUTE,\n QUERY_VECTORS_ROUTE,\n LIST_INDEXES_ROUTE,\n DESCRIBE_INDEX_ROUTE,\n DELETE_INDEX_ROUTE,\n LIST_VECTORS_ROUTE,\n LIST_EMBEDDERS_ROUTE,\n} from '../../handlers/vector';\n\nexport const VECTORS_ROUTES = [\n UPSERT_VECTORS_ROUTE,\n CREATE_INDEX_ROUTE,\n QUERY_VECTORS_ROUTE,\n LIST_INDEXES_ROUTE,\n DESCRIBE_INDEX_ROUTE,\n DELETE_INDEX_ROUTE,\n LIST_VECTORS_ROUTE,\n LIST_EMBEDDERS_ROUTE,\n] as const;\n","import {\n LIST_WORKFLOWS_ROUTE,\n LIST_WORKFLOW_RUN_COUNTS_ROUTE,\n GET_WORKFLOW_BY_ID_ROUTE,\n LIST_WORKFLOW_RUNS_ROUTE,\n GET_WORKFLOW_RUN_BY_ID_ROUTE,\n CREATE_WORKFLOW_RUN_ROUTE,\n STREAM_WORKFLOW_ROUTE,\n RESUME_STREAM_WORKFLOW_ROUTE,\n START_ASYNC_WORKFLOW_ROUTE,\n START_WORKFLOW_RUN_ROUTE,\n OBSERVE_STREAM_WORKFLOW_ROUTE,\n RESUME_ASYNC_WORKFLOW_ROUTE,\n RESUME_NO_WAIT_WORKFLOW_ROUTE,\n RESUME_WORKFLOW_ROUTE,\n CANCEL_WORKFLOW_RUN_ROUTE,\n TIME_TRAVEL_WORKFLOW_ROUTE,\n TIME_TRAVEL_STREAM_WORKFLOW_ROUTE,\n RESTART_WORKFLOW_ROUTE,\n RESTART_ASYNC_WORKFLOW_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ASYNC_ROUTE,\n TIME_TRAVEL_ASYNC_WORKFLOW_ROUTE,\n DELETE_WORKFLOW_RUN_BY_ID_ROUTE,\n EXECUTE_WORKFLOW_STEP_ROUTE,\n RECEIVE_WORKFLOW_EVENT_ROUTE,\n} from '../../handlers/workflows';\n\nexport const WORKFLOWS_ROUTES = [\n LIST_WORKFLOWS_ROUTE,\n // Static path must register before the parameterized /workflows/:workflowId\n // route below, or the router would capture \"run-counts\" as a workflowId.\n LIST_WORKFLOW_RUN_COUNTS_ROUTE,\n GET_WORKFLOW_BY_ID_ROUTE,\n LIST_WORKFLOW_RUNS_ROUTE,\n GET_WORKFLOW_RUN_BY_ID_ROUTE,\n DELETE_WORKFLOW_RUN_BY_ID_ROUTE,\n CREATE_WORKFLOW_RUN_ROUTE,\n STREAM_WORKFLOW_ROUTE,\n RESUME_STREAM_WORKFLOW_ROUTE,\n START_ASYNC_WORKFLOW_ROUTE,\n START_WORKFLOW_RUN_ROUTE,\n OBSERVE_STREAM_WORKFLOW_ROUTE,\n RESUME_ASYNC_WORKFLOW_ROUTE,\n RESUME_NO_WAIT_WORKFLOW_ROUTE,\n RESUME_WORKFLOW_ROUTE,\n CANCEL_WORKFLOW_RUN_ROUTE,\n TIME_TRAVEL_WORKFLOW_ROUTE,\n TIME_TRAVEL_ASYNC_WORKFLOW_ROUTE,\n TIME_TRAVEL_STREAM_WORKFLOW_ROUTE,\n RESTART_WORKFLOW_ROUTE,\n RESTART_ASYNC_WORKFLOW_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ROUTE,\n RESTART_ALL_ACTIVE_WORKFLOW_RUNS_ASYNC_ROUTE,\n EXECUTE_WORKFLOW_STEP_ROUTE,\n RECEIVE_WORKFLOW_EVENT_ROUTE,\n] as const;\n","/**\n * Workspace Routes\n *\n * All routes for workspace operations under /api/workspaces/*\n */\n\nimport {\n LIST_WORKSPACES_ROUTE,\n GET_WORKSPACE_ROUTE,\n WORKSPACE_FS_ROUTES,\n WORKSPACE_SEARCH_ROUTES,\n WORKSPACE_SKILLS_ROUTES,\n WORKSPACE_SKILLS_SH_ROUTES,\n} from '../../handlers/workspace';\n\nexport const WORKSPACE_ROUTES = [\n // List all workspaces route (at /api/workspaces)\n LIST_WORKSPACES_ROUTE,\n\n // Get workspace route (at /api/workspaces/:workspaceId)\n GET_WORKSPACE_ROUTE,\n\n // Filesystem routes (at /api/workspaces/:workspaceId/fs/*)\n ...WORKSPACE_FS_ROUTES,\n\n // Search routes (at /api/workspaces/:workspaceId/search, /api/workspaces/:workspaceId/index)\n ...WORKSPACE_SEARCH_ROUTES,\n\n // Skills routes (search must come before parameterized routes)\n ...WORKSPACE_SKILLS_ROUTES,\n\n // skills.sh proxy routes (at /api/workspaces/:workspaceId/skills-sh/*)\n ...WORKSPACE_SKILLS_SH_ROUTES,\n] as const;\n","import type { Mastra } from '@mastra/core';\nimport type { ToolsInput } from '@mastra/core/agent';\nimport type { FGARouteConfig, MastraFGAPermissionInput } from '@mastra/core/auth/ee';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute, ValidationErrorHook } from '@mastra/core/server';\nimport type * as z from 'zod/v4';\nimport type { InMemoryTaskStore } from '../../a2a/store';\nimport type { OpenAPIRoute } from '../openapi-utils';\nimport { A2A_ROUTES } from './a2a';\nimport { AGENT_BUILDER_ROUTES } from './agent-builder';\nimport { AGENT_CONTROLLER_ROUTES } from './agent-controller';\nimport { AGENTS_ROUTES } from './agents';\nimport type { AgentRoutes } from './agents';\nimport { AUTH_ROUTES } from './auth';\nimport { BACKGROUND_TASK_ROUTES } from './background-tasks';\nimport { CHANNELS_ROUTES } from './channels';\nimport { CONVERSATIONS_ROUTES } from './conversations';\nimport { DATASETS_ROUTES } from './datasets';\nimport { DYNAMIC_WORKFLOWS_ROUTES } from './dynamic-workflows';\nimport { EDITOR_BUILDER_ROUTES } from './editor-builder';\nimport { LEGACY_ROUTES } from './legacy';\nimport { LOGS_ROUTES } from './logs';\nimport { MCP_ROUTES } from './mcp';\nimport { MEMORY_ROUTES } from './memory';\nimport { OBSERVABILITY_ROUTES } from './observability';\nimport { PROCESSOR_PROVIDER_ROUTES } from './processor-providers';\nimport { PROCESSORS_ROUTES } from './processors';\nimport { RESPONSES_ROUTES } from './responses';\nimport { SCHEDULES_ROUTES } from './schedules';\nimport { SCORES_ROUTES } from './scorers';\nimport { STORED_AGENTS_ROUTES } from './stored-agents';\nimport type { StoredAgentRoutes } from './stored-agents';\nimport { STORED_MCP_CLIENTS_ROUTES } from './stored-mcp-clients';\nimport { STORED_PROMPT_BLOCKS_ROUTES } from './stored-prompt-blocks';\nimport { STORED_SCORERS_ROUTES } from './stored-scorers';\nimport { STORED_SKILLS_ROUTES } from './stored-skills';\nimport { STORED_WORKSPACES_ROUTES } from './stored-workspaces';\nimport type { MastraStreamReturn } from './stream-types';\nimport { SYSTEM_ROUTES } from './system';\nimport { TOOL_PROVIDER_ROUTES } from './tool-providers';\nimport { TOOLS_ROUTES } from './tools';\nimport { VECTORS_ROUTES } from './vectors';\nimport { WORKFLOWS_ROUTES } from './workflows';\nimport { WORKSPACE_ROUTES } from './workspace';\n\n/**\n * Server context fields that are available to route handlers.\n * These are injected by the server adapters (Express, Hono, etc.)\n * Fields other than `mastra` are optional to allow direct handler testing.\n */\nexport type ServerContext = {\n mastra: Mastra;\n requestContext: RequestContext;\n registeredTools?: ToolsInput;\n taskStore?: InMemoryTaskStore;\n abortSignal: AbortSignal;\n /** The route prefix configured for the server (e.g., '/api') */\n routePrefix?: string;\n /** The web-standard Request object for accessing headers, cookies, etc. */\n request?: Request;\n};\n\n/**\n * Utility type to infer parameters from Zod schemas.\n * Merges path params, query params, and body params into a single type.\n */\nexport type InferParams<\n TPathSchema extends z.ZodTypeAny | undefined,\n TQuerySchema extends z.ZodTypeAny | undefined,\n TBodySchema extends z.ZodTypeAny | undefined,\n> = (TPathSchema extends z.ZodTypeAny ? z.infer<TPathSchema> : {}) &\n (TQuerySchema extends z.ZodTypeAny ? z.infer<TQuerySchema> : {}) &\n (TBodySchema extends z.ZodTypeAny ? z.infer<TBodySchema> : {});\n\n/**\n * All supported response types for server routes.\n * - 'json': Standard JSON response\n * - 'stream': Streaming response (SSE or raw stream)\n * - 'datastream-response': Pre-built Response object for data streams\n * - 'mcp-http': MCP Streamable HTTP transport (handled by adapter)\n * - 'mcp-sse': MCP SSE transport (handled by adapter)\n */\nexport type ResponseType = 'stream' | 'json' | 'datastream-response' | 'mcp-http' | 'mcp-sse';\n\nexport type ServerRouteHandler<\n TParams = Record<string, unknown>,\n TResponse = unknown,\n TResponseType extends ResponseType = 'json',\n> = (\n params: TParams & ServerContext,\n) => Promise<\n TResponseType extends 'stream'\n ? MastraStreamReturn\n : TResponseType extends 'datastream-response'\n ? Response\n : TResponse\n>;\n\n/**\n * Phantom type for preserving Zod schema types on routes.\n * Not present at runtime — used only for type-level inference via RouteMap.\n */\nexport interface RouteSchemas<\n TPathSchema = unknown,\n TQuerySchema = unknown,\n TBodySchema = unknown,\n TResponseSchema = unknown,\n> {\n readonly pathParams: TPathSchema;\n readonly queryParams: TQuerySchema;\n readonly body: TBodySchema;\n readonly response: TResponseSchema;\n}\n\nexport type ServerRoute<\n TParams = Record<string, unknown>,\n TResponse = unknown,\n TResponseType extends ResponseType = ResponseType,\n TSchemas extends RouteSchemas = RouteSchemas,\n TMethod extends string = string,\n TPath extends string = string,\n> = Omit<ApiRoute, 'handler' | 'createHandler' | 'method' | 'path' | 'openapi'> & {\n method: TMethod;\n path: TPath;\n responseType: TResponseType;\n streamFormat?: 'sse' | 'stream'; // Only used when responseType is 'stream', defaults to 'stream'\n sseFlushOnConnect?: boolean;\n // Method signature is bivariant in params, allowing heterogeneous route arrays\n // while still preserving specific param types on individual routes.\n handler(params: TParams & ServerContext): ReturnType<ServerRouteHandler<TParams, TResponse, TResponseType>>;\n pathParamSchema?: z.ZodSchema;\n queryParamSchema?: z.ZodSchema;\n bodySchema?: z.ZodSchema;\n responseSchema?: z.ZodSchema;\n openapi?: OpenAPIRoute; // Auto-generated OpenAPI spec for this route\n maxBodySize?: number; // Optional route-specific body size limit in bytes\n deprecated?: boolean; // Flag for deprecated routes (used for route parity, skipped in tests)\n /**\n * Permission required to access this route (EE feature).\n * If set, the user must have this permission to access the route.\n * Uses the format: `resource:action` or `resource:action:resourceId`\n *\n * When an array is provided, the user needs ANY ONE of the listed permissions\n * (logical OR). This is useful for routes that serve multiple resource types,\n * e.g. a streaming endpoint used by both runtime and stored agents.\n *\n * @example\n * requiresPermission: MastraFGAPermissions.AGENTS_READ\n * requiresPermission: MastraFGAPermissions.WORKFLOWS_EXECUTE\n */\n requiresPermission?: MastraFGAPermissionInput | MastraFGAPermissionInput[];\n /**\n * FGA authorization config for this route (EE feature).\n * If set, the user must have the specified permission on the resource.\n *\n * @example\n * fga: { resourceType: 'agent', resourceIdParam: 'agentId', permission: MastraFGAPermissions.AGENTS_EXECUTE }\n */\n fga?: FGARouteConfig;\n onValidationError?: ValidationErrorHook;\n /** @internal Phantom type — not present at runtime. Used for type-level schema inference. */\n readonly __schemas?: TSchemas;\n};\n\nexport const SERVER_ROUTES: readonly ServerRoute[] = [\n ...AGENTS_ROUTES,\n ...AUTH_ROUTES,\n ...WORKFLOWS_ROUTES,\n ...TOOLS_ROUTES,\n ...PROCESSORS_ROUTES,\n ...RESPONSES_ROUTES,\n ...CONVERSATIONS_ROUTES,\n ...MEMORY_ROUTES,\n ...SCORES_ROUTES,\n ...OBSERVABILITY_ROUTES,\n ...LOGS_ROUTES,\n ...VECTORS_ROUTES,\n ...A2A_ROUTES,\n ...WORKSPACE_ROUTES,\n ...LEGACY_ROUTES,\n ...MCP_ROUTES,\n ...STORED_AGENTS_ROUTES,\n ...DYNAMIC_WORKFLOWS_ROUTES,\n ...STORED_MCP_CLIENTS_ROUTES,\n ...STORED_PROMPT_BLOCKS_ROUTES,\n ...STORED_SCORERS_ROUTES,\n ...STORED_WORKSPACES_ROUTES,\n ...STORED_SKILLS_ROUTES,\n ...TOOL_PROVIDER_ROUTES,\n ...PROCESSOR_PROVIDER_ROUTES,\n ...SYSTEM_ROUTES,\n ...DATASETS_ROUTES,\n ...BACKGROUND_TASK_ROUTES,\n ...EDITOR_BUILDER_ROUTES,\n ...AGENT_BUILDER_ROUTES,\n ...SCHEDULES_ROUTES,\n ...CHANNELS_ROUTES,\n ...AGENT_CONTROLLER_ROUTES,\n];\n\n/**\n * Union type of all individual route arrays.\n * Built from the per-domain `as const` tuples to preserve each route's specific schema types.\n */\nexport type ServerRoutes = readonly [\n ...AgentRoutes,\n ...typeof AUTH_ROUTES,\n ...typeof WORKFLOWS_ROUTES,\n ...typeof TOOLS_ROUTES,\n ...typeof PROCESSORS_ROUTES,\n ...typeof RESPONSES_ROUTES,\n ...typeof CONVERSATIONS_ROUTES,\n ...typeof MEMORY_ROUTES,\n ...typeof SCORES_ROUTES,\n ...typeof OBSERVABILITY_ROUTES,\n ...typeof LOGS_ROUTES,\n ...typeof VECTORS_ROUTES,\n ...typeof A2A_ROUTES,\n ...typeof AGENT_BUILDER_ROUTES,\n ...typeof WORKSPACE_ROUTES,\n ...typeof LEGACY_ROUTES,\n ...typeof MCP_ROUTES,\n ...StoredAgentRoutes,\n ...typeof STORED_MCP_CLIENTS_ROUTES,\n ...typeof STORED_PROMPT_BLOCKS_ROUTES,\n ...typeof STORED_SCORERS_ROUTES,\n ...typeof STORED_WORKSPACES_ROUTES,\n ...typeof STORED_SKILLS_ROUTES,\n ...typeof TOOL_PROVIDER_ROUTES,\n ...typeof PROCESSOR_PROVIDER_ROUTES,\n ...typeof SYSTEM_ROUTES,\n ...typeof DATASETS_ROUTES,\n ...typeof EDITOR_BUILDER_ROUTES,\n ...typeof CHANNELS_ROUTES,\n];\n\n// Export route builder and OpenAPI utilities\nexport { createRoute, createPublicRoute, pickParams, jsonQueryParam, wrapSchemaForQueryParams } from './route-builder';\nexport { generateOpenAPIDocument } from '../openapi-utils';\n\n// Export permission utilities\nexport { derivePermission, extractResource, deriveAction, getEffectivePermission } from './permissions';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,MAAa,aAAa,CAAC,sBAAsB,qBAAqB;;;ACiBtE,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;ACMA,MAAa,0BAAkD;CAC7D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AC1BA,MAAa,gBAAwC;CAInD;CACA;CACA;CACA;CAKA;CACA;CAKA;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAKA;CAKA;CACA;CACA;CACA;CAKA;CAKA;CACA;CAKA;CAKA;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;AACF;;;AC3IA,MAAa,yBAAuD;CAClE;CACA;CACA;AACF;;;ACJA,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;AACF;;;ACLA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;AACF;;;ACmBA,MAAa,kBAAkB;CAE7B;CACA;CACA;CACA;CACA;CAEA;CACA;CAEA;CACA;CAEA;CACA;CACA;CAEA;CACA;CACA;CAEA;CAEA;CAEA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CAEA;CAEA;CAEA;AACF;;;;;;;;;AC1DA,MAAa,2BAAmD;CAC9D;CACA;CACA;CACA;AACF;;;;;;;;;ACAA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;ACpBA,MAAa,gBAAgB;CAI3B;CACA;CAKA;CACA;AACF;;;AClBA,MAAa,cAAc;CAAC;CAA2B;CAAiB;AAAyB;;;;;;;;;ACiBjG,MAAa,aAAa;CAIxB;CACA;CAKA;CACA;CACA;CAKA;CACA;CAKA;CACA;CACA;AACF;;;ACjBA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACZA,MAAa,uBAAuB;CAElC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AChFA,MAAa,4BAA4B,CAAC,gCAAgC,4BAA4B;;;ACAtG,MAAa,oBAAoB;CAAC;CAAuB;CAA2B;AAAuB;;;ACA3G,MAAa,mBAAmB;CAAC;CAAuB;CAAoB;AAAqB;;;ACWjG,MAAa,mBAAiD;CAC5D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACdA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;ACYA,MAAa,uBAA+C;CAM1D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAOA;CACA;CACA;CACA;CACA;CACA;CACA;CAKA;CACA;AACF;;;AC7CA,MAAa,4BAA4B;CAEvC;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AClBA,MAAa,8BAA8B;CAEzC;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AClBA,MAAa,wBAAwB;CAEnC;CACA;CACA;CACA;CACA;CAKA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACzBA,MAAa,uBAAuB;CAElC;CACA;CACA;CACA;CACA;CAEA;CAEA;CACA;AACF;;;ACdA,MAAa,2BAA2B;CAEtC;CACA;CACA;CACA;CACA;AACF;;;;;;;;ACRA,MAAa,gBAAgB,CAAC,2BAA2B,oBAAoB;;;ACS7E,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;AC5BA,MAAa,eAAe;CAAC;CAAkB;CAAsB;AAAkB;;;ACSvF,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACQA,MAAa,mBAAmB;CAC9B;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;ACzCA,MAAa,mBAAmB;CAE9B;CAGA;CAGA,GAAG;CAGH,GAAG;CAGH,GAAG;CAGH,GAAG;AACL;;;ACmIA,MAAa,gBAAwC;CACnD,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL"}
@@ -58,7 +58,7 @@ var ViewerRegistry = class {
58
58
  }
59
59
  const wasEmpty = viewerSet.size === 0;
60
60
  viewerSet.add(ws);
61
- if (wasEmpty) await this.startScreencast(viewerKey, getToolset, agentId ?? viewerKey, threadId);
61
+ if (wasEmpty || !this.browserReadyCleanups.has(viewerKey)) await this.startScreencast(viewerKey, getToolset, agentId ?? viewerKey, threadId);
62
62
  else this.sendCurrentState(viewerKey, ws);
63
63
  }
64
64
  /**
@@ -179,6 +179,8 @@ var ViewerRegistry = class {
179
179
  /**
180
180
  * Start screencast for a viewer. Only starts if browser is already running.
181
181
  * If browser not running, registers a callback to start when browser becomes ready.
182
+ * If no toolset can be resolved, nothing is registered; `addViewer` retries the
183
+ * lookup the next time a viewer connects for this key.
182
184
  *
183
185
  * @param viewerKey - The viewer key (for registry keying)
184
186
  * @param getToolset - Function to retrieve the BrowserToolset
@@ -189,7 +191,7 @@ var ViewerRegistry = class {
189
191
  const toolset = await getToolset(agentId);
190
192
  if (!this.viewers.has(viewerKey)) return;
191
193
  if (!toolset) {
192
- console.info(`[ViewerRegistry] No toolset for ${viewerKey}, waiting...`);
194
+ console.info(`[ViewerRegistry] No browser toolset for ${viewerKey}; will retry on next viewer connect`);
193
195
  return;
194
196
  }
195
197
  if (!this.browserReadyCleanups.has(viewerKey)) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/server/browser-stream/viewer-registry.ts","../../../src/server/browser-stream/input-handler.ts"],"sourcesContent":["import type { MastraBrowser } from '@mastra/core/browser';\nimport type {\n StatusMessage,\n BrowserStreamConfig,\n ViewportMessage,\n BrowserStreamWebSocket,\n ViewerRegistryLike,\n} from './types.js';\n\n/** Minimal screencast stream interface matching BrowserToolsetLike.startScreencast return type */\ninterface ScreencastStreamLike {\n on(event: 'frame', handler: (frame: { data: string; viewport: { width: number; height: number } }) => void): void;\n on(event: 'stop', handler: (reason: string) => void): void;\n on(event: 'error', handler: (error: Error) => void): void;\n on(event: 'url', handler: (url: string) => void): void;\n stop(): Promise<void>;\n}\n\n/**\n * ViewerRegistry manages WebSocket connections per agent and controls screencast lifecycle.\n *\n * Key responsibilities:\n * - Track connected viewers per agentId\n * - Start screencast when browser becomes active (not on viewer connect)\n * - Stop screencast when last viewer disconnects\n * - Broadcast frames to all viewers for an agent\n *\n * The browser is NOT launched when viewers connect - it only starts streaming\n * when the browser is already running from agent tool usage.\n *\n * @example\n * ```typescript\n * const registry = new ViewerRegistry();\n *\n * // When a viewer connects\n * registry.addViewer('agent-123', ws, getToolset);\n *\n * // When a viewer disconnects\n * registry.removeViewer('agent-123', ws);\n * ```\n */\nexport class ViewerRegistry implements ViewerRegistryLike {\n /** Map of agentId to set of connected WebSocket contexts */\n private viewers = new Map<string, Set<BrowserStreamWebSocket>>();\n\n /** Map of agentId to active screencast stream */\n private screencasts = new Map<string, ScreencastStreamLike>();\n\n /** Set of viewerKeys currently starting a screencast (to prevent race conditions) */\n private startingScreencasts = new Set<string>();\n\n /** Map of agentId to cleanup function for onBrowserReady callback */\n private browserReadyCleanups = new Map<string, () => void>();\n\n /** Map of agentId to cleanup function for onBrowserClosed callback */\n private browserClosedCleanups = new Map<string, () => void>();\n\n /** Map of agentId to last known URL (for dedup) */\n private lastUrls = new Map<string, string>();\n\n /** Map of agentId to last known viewport dimensions (for change detection) */\n private lastViewports = new Map<string, { width: number; height: number }>();\n\n /** Map of viewerKey to last broadcast status (for replay to new viewers) */\n private lastStatuses = new Map<string, string>();\n\n /**\n * Add a viewer for an agent. Starts screencast if this is the first viewer.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param ws - The WebSocket context for this viewer\n * @param getToolset - Function to retrieve the BrowserToolset for this agent\n * @param agentId - The actual agent ID for toolset lookup (optional, defaults to viewerKey)\n * @param threadId - The thread ID for thread-scoped screencasts (optional)\n */\n async addViewer(\n viewerKey: string,\n ws: BrowserStreamWebSocket,\n getToolset: BrowserStreamConfig['getToolset'],\n agentId?: string,\n threadId?: string,\n ): Promise<void> {\n // Get or create the viewer set for this viewer key\n let viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n viewerSet = new Set();\n this.viewers.set(viewerKey, viewerSet);\n }\n\n const wasEmpty = viewerSet.size === 0;\n viewerSet.add(ws);\n\n // Start screencast if this is the first viewer\n // Use agentId for toolset lookup, viewerKey for registry keying\n if (wasEmpty) {\n await this.startScreencast(viewerKey, getToolset, agentId ?? viewerKey, threadId);\n } else {\n // Send current state to new viewer (screencast already running)\n this.sendCurrentState(viewerKey, ws);\n }\n }\n\n /**\n * Send current state (URL, viewport) to a newly connected viewer.\n */\n private sendCurrentState(viewerKey: string, ws: BrowserStreamWebSocket): void {\n try {\n // Send last known URL\n const lastUrl = this.lastUrls.get(viewerKey);\n if (lastUrl) {\n ws.send(JSON.stringify({ url: lastUrl }));\n }\n\n // Send last known viewport\n const lastViewport = this.lastViewports.get(viewerKey);\n if (lastViewport) {\n ws.send(JSON.stringify({ viewport: lastViewport }));\n }\n\n // Send actual current status (not always 'streaming')\n const lastStatus = this.lastStatuses.get(viewerKey);\n if (lastStatus) {\n ws.send(JSON.stringify({ status: lastStatus }));\n }\n } catch (error) {\n console.warn('[ViewerRegistry] Error sending current state to new viewer:', error);\n }\n }\n\n /**\n * Remove a viewer. Stops screencast if this was the last viewer.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param ws - The WebSocket context to remove\n */\n async removeViewer(viewerKey: string, ws: BrowserStreamWebSocket): Promise<void> {\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n return;\n }\n\n viewerSet.delete(ws);\n\n // Clean up if no more viewers\n if (viewerSet.size === 0) {\n this.viewers.delete(viewerKey);\n this.lastUrls.delete(viewerKey);\n this.lastViewports.delete(viewerKey);\n\n // Clean up browser callbacks if pending\n const readyCleanup = this.browserReadyCleanups.get(viewerKey);\n if (readyCleanup) {\n readyCleanup();\n this.browserReadyCleanups.delete(viewerKey);\n }\n const closedCleanup = this.browserClosedCleanups.get(viewerKey);\n if (closedCleanup) {\n closedCleanup();\n this.browserClosedCleanups.delete(viewerKey);\n }\n\n await this.stopScreencast(viewerKey);\n }\n }\n\n /**\n * Broadcast a binary frame to all viewers.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param data - The binary frame data (base64 encoded)\n */\n broadcastFrame(viewerKey: string, data: string): void {\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n return;\n }\n\n // Send as binary (base64 string)\n for (const ws of viewerSet) {\n try {\n ws.send(data);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting frame:', error);\n }\n }\n }\n\n /**\n * Broadcast a status message to all viewers.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param status - The status message to send\n */\n broadcastStatus(viewerKey: string, status: StatusMessage): void {\n // Track last status for replay to new viewers\n if (status.status) {\n this.lastStatuses.set(viewerKey, status.status);\n }\n\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n return;\n }\n\n const message = JSON.stringify(status);\n for (const ws of viewerSet) {\n try {\n ws.send(message);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting status:', error);\n }\n }\n }\n\n /**\n * Broadcast a URL update to all viewers (only if changed).\n */\n private broadcastUrlIfChanged(viewerKey: string, url: string | null): void {\n if (!url) return;\n if (this.lastUrls.get(viewerKey) === url) return;\n\n this.lastUrls.set(viewerKey, url);\n\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) return;\n\n const message = JSON.stringify({ url });\n for (const ws of viewerSet) {\n try {\n ws.send(message);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting URL:', error);\n }\n }\n }\n\n /**\n * Broadcast viewport metadata to all viewers.\n * Only sends if dimensions have changed from last broadcast.\n * Called on stream start and on each frame to detect dimension changes.\n */\n private broadcastViewportIfChanged(viewerKey: string, viewport: { width: number; height: number }): void {\n const last = this.lastViewports.get(viewerKey);\n if (last && last.width === viewport.width && last.height === viewport.height) {\n return;\n }\n\n this.lastViewports.set(viewerKey, { width: viewport.width, height: viewport.height });\n\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) return;\n\n const message: ViewportMessage = { viewport: { width: viewport.width, height: viewport.height } };\n const json = JSON.stringify(message);\n for (const ws of viewerSet) {\n try {\n ws.send(json);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting viewport:', error);\n }\n }\n }\n\n /**\n * Start screencast for a viewer. Only starts if browser is already running.\n * If browser not running, registers a callback to start when browser becomes ready.\n *\n * @param viewerKey - The viewer key (for registry keying)\n * @param getToolset - Function to retrieve the BrowserToolset\n * @param agentId - The actual agent ID for toolset lookup\n * @param threadId - The thread ID for thread-scoped page selection (optional)\n */\n private async startScreencast(\n viewerKey: string,\n getToolset: BrowserStreamConfig['getToolset'],\n agentId: string,\n threadId?: string,\n ): Promise<void> {\n const toolset = await getToolset(agentId);\n // Viewer may have disconnected while awaiting async toolset lookup.\n // Bail out so we don't register callbacks or start a screencast for a stale viewer.\n if (!this.viewers.has(viewerKey)) {\n return;\n }\n if (!toolset) {\n // No browser available for this agent - just keep connection open.\n // The screencast will start when the agent hydrates and the browser launches\n // (via the generation flow calling getAgentFromSystem → createAgentFromStoredConfig).\n console.info(`[ViewerRegistry] No toolset for ${viewerKey}, waiting...`);\n return;\n }\n\n // Register callback for browser restarts (external close + re-launch)\n // This ensures screencast reconnects after browser is externally closed\n // Pass threadId so callback only fires when that specific thread's browser is ready\n if (!this.browserReadyCleanups.has(viewerKey)) {\n const cleanup = toolset.onBrowserReady(() => {\n // Only start if we still have viewers\n if (!this.viewers.has(viewerKey)) {\n return;\n }\n\n // Stop any existing (likely dead) screencast before starting new one\n const existingStream = this.screencasts.get(viewerKey);\n if (existingStream) {\n console.info(`[ViewerRegistry] Stopping old screencast for ${viewerKey} before reconnecting...`);\n this.screencasts.delete(viewerKey);\n // Stop async, don't wait - the old CDP session is probably dead anyway\n existingStream.stop().catch(() => {});\n }\n\n console.info(`[ViewerRegistry] Browser ready for ${viewerKey}, starting screencast...`);\n this.doStartScreencast(viewerKey, toolset, threadId).catch(error => {\n console.error(`[ViewerRegistry] Failed to start screencast on browser ready for ${viewerKey}:`, error);\n });\n }, threadId);\n this.browserReadyCleanups.set(viewerKey, cleanup);\n }\n\n // Register callback for browser closed (external close detection)\n // This ensures UI shows \"browser closed\" overlay immediately\n // Pass threadId so callback only fires when that specific thread's browser closes\n if (!this.browserClosedCleanups.has(viewerKey)) {\n const cleanup = toolset.onBrowserClosed(() => {\n console.info(`[ViewerRegistry] Browser closed for ${viewerKey}, notifying viewers...`);\n // Clean up screencast reference (CDP session is dead)\n this.screencasts.delete(viewerKey);\n // Broadcast browser_closed status to UI\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n }, threadId);\n this.browserClosedCleanups.set(viewerKey, cleanup);\n }\n\n // Check if browser is already running for this viewer's thread.\n // Pass threadId so thread-scoped viewers don't fall back to the globally \"current\" thread.\n if (toolset.isBrowserRunning(threadId)) {\n // Browser is running, start screencast immediately\n await this.doStartScreencast(viewerKey, toolset, threadId);\n } else {\n // Browser not running - callback will fire when it becomes ready\n console.info(`[ViewerRegistry] Browser not running for ${viewerKey}, waiting for browser to start...`);\n }\n }\n\n /**\n * Internal method to actually start the screencast stream.\n *\n * @param viewerKey - The viewer key (for registry keying and logging)\n * @param toolset - The browser toolset\n * @param threadId - The thread ID for thread-scoped page selection (optional)\n */\n private async doStartScreencast(viewerKey: string, toolset: MastraBrowser, threadId?: string): Promise<void> {\n // Skip if already streaming or currently starting (prevents race conditions)\n if (this.screencasts.has(viewerKey) || this.startingScreencasts.has(viewerKey)) {\n return;\n }\n\n // Mark as starting to prevent concurrent starts\n this.startingScreencasts.add(viewerKey);\n\n try {\n this.broadcastStatus(viewerKey, { status: 'browser_starting' });\n\n // Use startScreencastIfBrowserActive to avoid launching browser\n // Pass threadId for thread-scoped page selection\n const stream = await toolset.startScreencastIfBrowserActive(threadId ? { threadId } : undefined);\n if (!stream) {\n console.warn(`[ViewerRegistry] No browser session for ${viewerKey}`);\n // Tell the UI this thread has no browser session yet\n // Using 'browser_closed' to indicate no active browser for this thread\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n return;\n }\n\n this.screencasts.set(viewerKey, stream);\n\n // Capture reference to guard against stale callbacks from superseded streams\n const currentStream = stream;\n\n // Wire up frame events + viewport tracking\n stream.on('frame', frame => {\n // Ignore frames from superseded streams\n if (this.screencasts.get(viewerKey) !== currentStream) return;\n this.broadcastFrame(viewerKey, frame.data);\n this.broadcastViewportIfChanged(viewerKey, frame.viewport);\n });\n\n // Wire up URL change events (emitted by browser providers on navigation)\n stream.on('url', (url: string) => {\n // Ignore URL updates from superseded streams\n if (this.screencasts.get(viewerKey) !== currentStream) return;\n this.broadcastUrlIfChanged(viewerKey, url);\n });\n\n // Wire up stop events\n stream.on('stop', reason => {\n // Ignore stop events from superseded streams (e.g., old stream stopping after reconnect)\n if (this.screencasts.get(viewerKey) !== currentStream) {\n console.info(`[ViewerRegistry] Ignoring stop from superseded stream for ${viewerKey}`);\n return;\n }\n console.info(`[ViewerRegistry] Screencast stopped for ${viewerKey}: ${reason}`);\n this.screencasts.delete(viewerKey);\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n });\n\n // Wire up error events - treat errors as browser closed since screencast can't continue\n stream.on('error', error => {\n // Ignore errors from superseded streams\n if (this.screencasts.get(viewerKey) !== currentStream) return;\n console.error(`[ViewerRegistry] Screencast error for ${viewerKey}:`, error);\n this.screencasts.delete(viewerKey);\n // Explicitly stop the stream to clean up CDP resources\n currentStream.stop().catch(stopError => {\n console.warn(`[ViewerRegistry] Error stopping errored screencast for ${viewerKey}:`, stopError);\n });\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n });\n\n this.broadcastStatus(viewerKey, { status: 'streaming' });\n\n // Send initial URL - pass threadId to get URL from correct browser session\n const initialUrl = await toolset.getCurrentUrl(threadId);\n this.broadcastUrlIfChanged(viewerKey, initialUrl);\n } catch (error) {\n console.error(`[ViewerRegistry] Failed to start screencast for ${viewerKey}:`, error);\n // Connection stays open - user can see error status\n } finally {\n // Clear starting flag\n this.startingScreencasts.delete(viewerKey);\n }\n }\n\n /**\n * Stop screencast for an agent. Called when last viewer disconnects.\n */\n private async stopScreencast(agentId: string): Promise<void> {\n const stream = this.screencasts.get(agentId);\n if (!stream) {\n return;\n }\n\n try {\n await stream.stop();\n } catch (error) {\n console.warn(`[ViewerRegistry] Error stopping screencast for ${agentId}:`, error);\n } finally {\n this.screencasts.delete(agentId);\n }\n }\n\n /**\n * Get the number of viewers for an agent.\n *\n * @param agentId - The agent ID\n * @returns The number of connected viewers\n */\n getViewerCount(agentId: string): number {\n return this.viewers.get(agentId)?.size ?? 0;\n }\n\n /**\n * Check if an agent has an active screencast.\n *\n * @param agentId - The agent ID\n * @returns True if screencast is active\n */\n hasActiveScreencast(agentId: string): boolean {\n return this.screencasts.has(agentId);\n }\n\n /**\n * Close the browser session for an agent.\n * Stops screencast and broadcasts browser_closed status.\n * Call this before calling toolset.close() to ensure UI is notified.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n */\n async closeBrowserSession(viewerKey: string): Promise<void> {\n // NOTE: Do NOT clean up the onBrowserReady callback here.\n // Viewers are still connected (WebSocket stays open), so we need\n // the callback to fire when the browser relaunches from a subsequent\n // tool call. Callback cleanup only happens in removeViewer() when\n // the last viewer disconnects.\n\n // Clear URL, viewport, and status tracking so next session sends fresh data\n this.lastUrls.delete(viewerKey);\n this.lastViewports.delete(viewerKey);\n this.lastStatuses.delete(viewerKey);\n\n // Stop screencast if active\n const stream = this.screencasts.get(viewerKey);\n if (stream) {\n try {\n await stream.stop();\n // Note: stream.stop() emits 'stop' event which triggers broadcastStatus\n } catch (error) {\n console.warn(`[ViewerRegistry] Error stopping screencast for ${viewerKey}:`, error);\n // Still broadcast browser_closed even if stop fails\n this.screencasts.delete(viewerKey);\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n }\n } else {\n // No active screencast, but still broadcast browser_closed\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n }\n }\n}\n","import type { MastraBrowser } from '@mastra/core/browser';\nimport type { BrowserStreamConfig, ClientInputMessage, MouseInputMessage, KeyboardInputMessage } from './types.js';\n\n// Valid CDP mouse event types\nconst VALID_MOUSE_EVENTS = new Set(['mousePressed', 'mouseReleased', 'mouseMoved', 'mouseWheel']);\n\n// Valid CDP keyboard event types\nconst VALID_KEYBOARD_EVENTS = new Set(['keyDown', 'keyUp', 'char']);\n\n// Input dispatch queue per agent+thread to serialize input events\nconst inputQueues = new Map<string, Promise<void>>();\n\n/**\n * Serialize input dispatch to maintain event ordering.\n * Input events must be processed in order to avoid race conditions.\n */\nfunction enqueueInput(key: string, fn: () => Promise<void>): void {\n const current = inputQueues.get(key) ?? Promise.resolve();\n const next = current.then(fn).catch(() => {\n // Errors are handled inside fn, just ensure chain continues\n });\n inputQueues.set(key, next);\n}\n\n/**\n * Map of key names to Windows virtual key codes.\n * Required for non-printable keys (Enter, Tab, Arrow keys, etc.)\n * See: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes\n */\nconst VIRTUAL_KEY_CODES: Record<string, number> = {\n // Control keys\n Backspace: 8,\n Tab: 9,\n Enter: 13,\n Shift: 16,\n Control: 17,\n Alt: 18,\n Pause: 19,\n CapsLock: 20,\n Escape: 27,\n Space: 32,\n ' ': 32,\n PageUp: 33,\n PageDown: 34,\n End: 35,\n Home: 36,\n // Arrow keys\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n // Editing keys\n Insert: 45,\n Delete: 46,\n // Function keys\n F1: 112,\n F2: 113,\n F3: 114,\n F4: 115,\n F5: 116,\n F6: 117,\n F7: 118,\n F8: 119,\n F9: 120,\n F10: 121,\n F11: 122,\n F12: 123,\n};\n\n/**\n * Get the Windows virtual key code for a key.\n * For printable characters, uses the character code.\n * For special keys, looks up in the mapping.\n */\nfunction getVirtualKeyCode(key: string | undefined): number | undefined {\n if (!key) return undefined;\n\n // Check special keys first\n if (VIRTUAL_KEY_CODES[key] !== undefined) {\n return VIRTUAL_KEY_CODES[key];\n }\n\n // For single printable characters, use the uppercase char code\n if (key.length === 1) {\n return key.toUpperCase().charCodeAt(0);\n }\n\n return undefined;\n}\n\n/**\n * Handle an incoming WebSocket message by parsing, validating,\n * and routing to the appropriate toolset injection method.\n *\n * Fire-and-forget: no acknowledgment sent back to client.\n * Silently ignores malformed or unrecognized messages.\n *\n * @param data - Raw string data from WebSocket message\n * @param getToolset - Function to retrieve MastraBrowser for an agent\n * @param agentId - The agent ID this WebSocket connection is for\n * @param threadId - The thread ID for thread-scoped operations (optional)\n */\nexport async function handleInputMessage(\n data: string,\n getToolset: BrowserStreamConfig['getToolset'],\n agentId: string,\n threadId?: string,\n): Promise<void> {\n let message: unknown;\n try {\n message = JSON.parse(data);\n } catch {\n return;\n }\n\n if (!isValidInputMessage(message)) {\n return;\n }\n\n const toolset = await getToolset(agentId);\n if (!toolset) {\n return;\n }\n\n // Serialize input dispatch per agent+thread to maintain event ordering\n const queueKey = `${agentId}:${threadId ?? 'default'}`;\n\n switch (message.type) {\n case 'mouse':\n enqueueInput(queueKey, async () => {\n try {\n await injectMouse(toolset, message, threadId);\n } catch (err) {\n if (isDisconnectionError(err)) {\n notifyBrowserClosed(toolset, threadId);\n } else if (!isExpectedInjectionError(err)) {\n console.warn('[InputHandler] Mouse injection error:', err);\n }\n }\n });\n break;\n case 'keyboard':\n enqueueInput(queueKey, async () => {\n try {\n await injectKeyboard(toolset, message, threadId);\n } catch (err) {\n if (isDisconnectionError(err)) {\n notifyBrowserClosed(toolset, threadId);\n } else if (!isExpectedInjectionError(err)) {\n console.warn('[InputHandler] Keyboard injection error:', err);\n }\n }\n });\n break;\n }\n}\n\n// --- Error handling ---\n\n/**\n * Check if an error indicates browser disconnection (target closed).\n * These errors mean the browser was externally closed.\n */\nfunction isDisconnectionError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n // Note: 'no cdp session' is handled by isExpectedInjectionError (startup race)\n // and should not trigger browser closed state\n return (\n msg.includes('target closed') ||\n msg.includes('browser has been closed') ||\n msg.includes('page has been closed') ||\n msg.includes('session closed') ||\n msg.includes('browser has disconnected')\n );\n}\n\n/**\n * Check if an injection error is expected (browser not ready yet).\n * These are silently ignored to avoid log spam.\n */\nfunction isExpectedInjectionError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes('no cdp session') ||\n msg.includes('browser not launched') ||\n msg.includes('not connected to browser') ||\n msg.includes('no active target') ||\n (msg.includes('target') && msg.includes('not attached'))\n );\n}\n\n/**\n * Notify the browser that it was closed externally.\n * This triggers the onBrowserClosed callbacks to update the UI.\n * If threadId is provided and the browser supports thread-specific closing,\n * only that thread's session is closed.\n */\nfunction notifyBrowserClosed(toolset: MastraBrowser, threadId?: string): void {\n const browser = toolset as unknown as {\n closeThreadSession?: (threadId: string) => Promise<void>;\n handleBrowserDisconnected?: () => void;\n };\n\n // For thread-scoped browsers, close only the specific thread's session\n if (threadId && typeof browser.closeThreadSession === 'function') {\n void browser.closeThreadSession(threadId).catch(() => {\n // Fall back to global disconnect if thread-specific close fails\n browser.handleBrowserDisconnected?.();\n });\n return;\n }\n\n // Fall back to global disconnect handling\n browser.handleBrowserDisconnected?.();\n}\n\n// --- Input injection ---\n\n/**\n * Inject a mouse event into the browser.\n */\nasync function injectMouse(toolset: MastraBrowser, msg: MouseInputMessage, threadId?: string): Promise<void> {\n await toolset.injectMouseEvent(\n {\n type: msg.eventType,\n x: msg.x,\n y: msg.y,\n button: msg.button,\n clickCount: msg.clickCount,\n deltaX: msg.deltaX,\n deltaY: msg.deltaY,\n modifiers: msg.modifiers,\n },\n threadId,\n );\n}\n\n/**\n * Inject a keyboard event into the browser.\n */\nasync function injectKeyboard(toolset: MastraBrowser, msg: KeyboardInputMessage, threadId?: string): Promise<void> {\n const windowsVirtualKeyCode = getVirtualKeyCode(msg.key);\n\n await toolset.injectKeyboardEvent(\n {\n type: msg.eventType,\n key: msg.key,\n code: msg.code,\n text: msg.text,\n modifiers: msg.modifiers,\n windowsVirtualKeyCode,\n },\n threadId,\n );\n}\n\n// --- Validation ---\n\n/**\n * Type guard to validate incoming messages.\n * Validates structure and rejects invalid event types at the boundary.\n */\nfunction isValidInputMessage(msg: unknown): msg is ClientInputMessage {\n if (typeof msg !== 'object' || msg === null) {\n return false;\n }\n\n const typed = msg as Record<string, unknown>;\n\n if (typed.type === 'mouse') {\n // Validate mouse message structure\n if (typeof typed.eventType !== 'string' || !VALID_MOUSE_EVENTS.has(typed.eventType)) {\n return false;\n }\n if (typeof typed.x !== 'number' || typeof typed.y !== 'number') {\n return false;\n }\n // Optional fields validation\n if (typed.button !== undefined && typeof typed.button !== 'string') {\n return false;\n }\n if (typed.deltaX !== undefined && typeof typed.deltaX !== 'number') {\n return false;\n }\n if (typed.deltaY !== undefined && typeof typed.deltaY !== 'number') {\n return false;\n }\n return true;\n }\n\n if (typed.type === 'keyboard') {\n // Validate keyboard message structure\n if (typeof typed.eventType !== 'string' || !VALID_KEYBOARD_EVENTS.has(typed.eventType)) {\n return false;\n }\n // At least one of key, code, or text should be present for meaningful input\n const hasKey = typeof typed.key === 'string';\n const hasCode = typeof typed.code === 'string';\n const hasText = typeof typed.text === 'string';\n if (!hasKey && !hasCode && !hasText) {\n return false;\n }\n // Optional modifiers validation\n if (typed.modifiers !== undefined && typeof typed.modifiers !== 'number') {\n return false;\n }\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/server/browser-stream/viewer-registry.ts","../../../src/server/browser-stream/input-handler.ts"],"sourcesContent":["import type { MastraBrowser } from '@mastra/core/browser';\nimport type {\n StatusMessage,\n BrowserStreamConfig,\n ViewportMessage,\n BrowserStreamWebSocket,\n ViewerRegistryLike,\n} from './types.js';\n\n/** Minimal screencast stream interface matching BrowserToolsetLike.startScreencast return type */\ninterface ScreencastStreamLike {\n on(event: 'frame', handler: (frame: { data: string; viewport: { width: number; height: number } }) => void): void;\n on(event: 'stop', handler: (reason: string) => void): void;\n on(event: 'error', handler: (error: Error) => void): void;\n on(event: 'url', handler: (url: string) => void): void;\n stop(): Promise<void>;\n}\n\n/**\n * ViewerRegistry manages WebSocket connections per agent and controls screencast lifecycle.\n *\n * Key responsibilities:\n * - Track connected viewers per agentId\n * - Start screencast when browser becomes active (not on viewer connect)\n * - Stop screencast when last viewer disconnects\n * - Broadcast frames to all viewers for an agent\n *\n * The browser is NOT launched when viewers connect - it only starts streaming\n * when the browser is already running from agent tool usage.\n *\n * @example\n * ```typescript\n * const registry = new ViewerRegistry();\n *\n * // When a viewer connects\n * registry.addViewer('agent-123', ws, getToolset);\n *\n * // When a viewer disconnects\n * registry.removeViewer('agent-123', ws);\n * ```\n */\nexport class ViewerRegistry implements ViewerRegistryLike {\n /** Map of agentId to set of connected WebSocket contexts */\n private viewers = new Map<string, Set<BrowserStreamWebSocket>>();\n\n /** Map of agentId to active screencast stream */\n private screencasts = new Map<string, ScreencastStreamLike>();\n\n /** Set of viewerKeys currently starting a screencast (to prevent race conditions) */\n private startingScreencasts = new Set<string>();\n\n /** Map of agentId to cleanup function for onBrowserReady callback */\n private browserReadyCleanups = new Map<string, () => void>();\n\n /** Map of agentId to cleanup function for onBrowserClosed callback */\n private browserClosedCleanups = new Map<string, () => void>();\n\n /** Map of agentId to last known URL (for dedup) */\n private lastUrls = new Map<string, string>();\n\n /** Map of agentId to last known viewport dimensions (for change detection) */\n private lastViewports = new Map<string, { width: number; height: number }>();\n\n /** Map of viewerKey to last broadcast status (for replay to new viewers) */\n private lastStatuses = new Map<string, string>();\n\n /**\n * Add a viewer for an agent. Starts screencast if this is the first viewer.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param ws - The WebSocket context for this viewer\n * @param getToolset - Function to retrieve the BrowserToolset for this agent\n * @param agentId - The actual agent ID for toolset lookup (optional, defaults to viewerKey)\n * @param threadId - The thread ID for thread-scoped screencasts (optional)\n */\n async addViewer(\n viewerKey: string,\n ws: BrowserStreamWebSocket,\n getToolset: BrowserStreamConfig['getToolset'],\n agentId?: string,\n threadId?: string,\n ): Promise<void> {\n // Get or create the viewer set for this viewer key\n let viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n viewerSet = new Set();\n this.viewers.set(viewerKey, viewerSet);\n }\n\n const wasEmpty = viewerSet.size === 0;\n viewerSet.add(ws);\n\n // Start screencast if this is the first viewer, or if an earlier viewer failed to\n // resolve a toolset (no callbacks registered yet) so the lookup gets retried.\n // Use agentId for toolset lookup, viewerKey for registry keying\n if (wasEmpty || !this.browserReadyCleanups.has(viewerKey)) {\n await this.startScreencast(viewerKey, getToolset, agentId ?? viewerKey, threadId);\n } else {\n // Send current state to new viewer (screencast already running)\n this.sendCurrentState(viewerKey, ws);\n }\n }\n\n /**\n * Send current state (URL, viewport) to a newly connected viewer.\n */\n private sendCurrentState(viewerKey: string, ws: BrowserStreamWebSocket): void {\n try {\n // Send last known URL\n const lastUrl = this.lastUrls.get(viewerKey);\n if (lastUrl) {\n ws.send(JSON.stringify({ url: lastUrl }));\n }\n\n // Send last known viewport\n const lastViewport = this.lastViewports.get(viewerKey);\n if (lastViewport) {\n ws.send(JSON.stringify({ viewport: lastViewport }));\n }\n\n // Send actual current status (not always 'streaming')\n const lastStatus = this.lastStatuses.get(viewerKey);\n if (lastStatus) {\n ws.send(JSON.stringify({ status: lastStatus }));\n }\n } catch (error) {\n console.warn('[ViewerRegistry] Error sending current state to new viewer:', error);\n }\n }\n\n /**\n * Remove a viewer. Stops screencast if this was the last viewer.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param ws - The WebSocket context to remove\n */\n async removeViewer(viewerKey: string, ws: BrowserStreamWebSocket): Promise<void> {\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n return;\n }\n\n viewerSet.delete(ws);\n\n // Clean up if no more viewers\n if (viewerSet.size === 0) {\n this.viewers.delete(viewerKey);\n this.lastUrls.delete(viewerKey);\n this.lastViewports.delete(viewerKey);\n\n // Clean up browser callbacks if pending\n const readyCleanup = this.browserReadyCleanups.get(viewerKey);\n if (readyCleanup) {\n readyCleanup();\n this.browserReadyCleanups.delete(viewerKey);\n }\n const closedCleanup = this.browserClosedCleanups.get(viewerKey);\n if (closedCleanup) {\n closedCleanup();\n this.browserClosedCleanups.delete(viewerKey);\n }\n\n await this.stopScreencast(viewerKey);\n }\n }\n\n /**\n * Broadcast a binary frame to all viewers.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param data - The binary frame data (base64 encoded)\n */\n broadcastFrame(viewerKey: string, data: string): void {\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n return;\n }\n\n // Send as binary (base64 string)\n for (const ws of viewerSet) {\n try {\n ws.send(data);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting frame:', error);\n }\n }\n }\n\n /**\n * Broadcast a status message to all viewers.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n * @param status - The status message to send\n */\n broadcastStatus(viewerKey: string, status: StatusMessage): void {\n // Track last status for replay to new viewers\n if (status.status) {\n this.lastStatuses.set(viewerKey, status.status);\n }\n\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) {\n return;\n }\n\n const message = JSON.stringify(status);\n for (const ws of viewerSet) {\n try {\n ws.send(message);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting status:', error);\n }\n }\n }\n\n /**\n * Broadcast a URL update to all viewers (only if changed).\n */\n private broadcastUrlIfChanged(viewerKey: string, url: string | null): void {\n if (!url) return;\n if (this.lastUrls.get(viewerKey) === url) return;\n\n this.lastUrls.set(viewerKey, url);\n\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) return;\n\n const message = JSON.stringify({ url });\n for (const ws of viewerSet) {\n try {\n ws.send(message);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting URL:', error);\n }\n }\n }\n\n /**\n * Broadcast viewport metadata to all viewers.\n * Only sends if dimensions have changed from last broadcast.\n * Called on stream start and on each frame to detect dimension changes.\n */\n private broadcastViewportIfChanged(viewerKey: string, viewport: { width: number; height: number }): void {\n const last = this.lastViewports.get(viewerKey);\n if (last && last.width === viewport.width && last.height === viewport.height) {\n return;\n }\n\n this.lastViewports.set(viewerKey, { width: viewport.width, height: viewport.height });\n\n const viewerSet = this.viewers.get(viewerKey);\n if (!viewerSet) return;\n\n const message: ViewportMessage = { viewport: { width: viewport.width, height: viewport.height } };\n const json = JSON.stringify(message);\n for (const ws of viewerSet) {\n try {\n ws.send(json);\n } catch (error) {\n console.warn('[ViewerRegistry] Error broadcasting viewport:', error);\n }\n }\n }\n\n /**\n * Start screencast for a viewer. Only starts if browser is already running.\n * If browser not running, registers a callback to start when browser becomes ready.\n * If no toolset can be resolved, nothing is registered; `addViewer` retries the\n * lookup the next time a viewer connects for this key.\n *\n * @param viewerKey - The viewer key (for registry keying)\n * @param getToolset - Function to retrieve the BrowserToolset\n * @param agentId - The actual agent ID for toolset lookup\n * @param threadId - The thread ID for thread-scoped page selection (optional)\n */\n private async startScreencast(\n viewerKey: string,\n getToolset: BrowserStreamConfig['getToolset'],\n agentId: string,\n threadId?: string,\n ): Promise<void> {\n const toolset = await getToolset(agentId);\n // Viewer may have disconnected while awaiting async toolset lookup.\n // Bail out so we don't register callbacks or start a screencast for a stale viewer.\n if (!this.viewers.has(viewerKey)) {\n return;\n }\n if (!toolset) {\n // No browser configured for this agent (neither agent.browser nor workspace.browser).\n // Keep the connection open; the lookup is retried when the next viewer connects.\n console.info(`[ViewerRegistry] No browser toolset for ${viewerKey}; will retry on next viewer connect`);\n return;\n }\n\n // Register callback for browser restarts (external close + re-launch)\n // This ensures screencast reconnects after browser is externally closed\n // Pass threadId so callback only fires when that specific thread's browser is ready\n if (!this.browserReadyCleanups.has(viewerKey)) {\n const cleanup = toolset.onBrowserReady(() => {\n // Only start if we still have viewers\n if (!this.viewers.has(viewerKey)) {\n return;\n }\n\n // Stop any existing (likely dead) screencast before starting new one\n const existingStream = this.screencasts.get(viewerKey);\n if (existingStream) {\n console.info(`[ViewerRegistry] Stopping old screencast for ${viewerKey} before reconnecting...`);\n this.screencasts.delete(viewerKey);\n // Stop async, don't wait - the old CDP session is probably dead anyway\n existingStream.stop().catch(() => {});\n }\n\n console.info(`[ViewerRegistry] Browser ready for ${viewerKey}, starting screencast...`);\n this.doStartScreencast(viewerKey, toolset, threadId).catch(error => {\n console.error(`[ViewerRegistry] Failed to start screencast on browser ready for ${viewerKey}:`, error);\n });\n }, threadId);\n this.browserReadyCleanups.set(viewerKey, cleanup);\n }\n\n // Register callback for browser closed (external close detection)\n // This ensures UI shows \"browser closed\" overlay immediately\n // Pass threadId so callback only fires when that specific thread's browser closes\n if (!this.browserClosedCleanups.has(viewerKey)) {\n const cleanup = toolset.onBrowserClosed(() => {\n console.info(`[ViewerRegistry] Browser closed for ${viewerKey}, notifying viewers...`);\n // Clean up screencast reference (CDP session is dead)\n this.screencasts.delete(viewerKey);\n // Broadcast browser_closed status to UI\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n }, threadId);\n this.browserClosedCleanups.set(viewerKey, cleanup);\n }\n\n // Check if browser is already running for this viewer's thread.\n // Pass threadId so thread-scoped viewers don't fall back to the globally \"current\" thread.\n if (toolset.isBrowserRunning(threadId)) {\n // Browser is running, start screencast immediately\n await this.doStartScreencast(viewerKey, toolset, threadId);\n } else {\n // Browser not running - callback will fire when it becomes ready\n console.info(`[ViewerRegistry] Browser not running for ${viewerKey}, waiting for browser to start...`);\n }\n }\n\n /**\n * Internal method to actually start the screencast stream.\n *\n * @param viewerKey - The viewer key (for registry keying and logging)\n * @param toolset - The browser toolset\n * @param threadId - The thread ID for thread-scoped page selection (optional)\n */\n private async doStartScreencast(viewerKey: string, toolset: MastraBrowser, threadId?: string): Promise<void> {\n // Skip if already streaming or currently starting (prevents race conditions)\n if (this.screencasts.has(viewerKey) || this.startingScreencasts.has(viewerKey)) {\n return;\n }\n\n // Mark as starting to prevent concurrent starts\n this.startingScreencasts.add(viewerKey);\n\n try {\n this.broadcastStatus(viewerKey, { status: 'browser_starting' });\n\n // Use startScreencastIfBrowserActive to avoid launching browser\n // Pass threadId for thread-scoped page selection\n const stream = await toolset.startScreencastIfBrowserActive(threadId ? { threadId } : undefined);\n if (!stream) {\n console.warn(`[ViewerRegistry] No browser session for ${viewerKey}`);\n // Tell the UI this thread has no browser session yet\n // Using 'browser_closed' to indicate no active browser for this thread\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n return;\n }\n\n this.screencasts.set(viewerKey, stream);\n\n // Capture reference to guard against stale callbacks from superseded streams\n const currentStream = stream;\n\n // Wire up frame events + viewport tracking\n stream.on('frame', frame => {\n // Ignore frames from superseded streams\n if (this.screencasts.get(viewerKey) !== currentStream) return;\n this.broadcastFrame(viewerKey, frame.data);\n this.broadcastViewportIfChanged(viewerKey, frame.viewport);\n });\n\n // Wire up URL change events (emitted by browser providers on navigation)\n stream.on('url', (url: string) => {\n // Ignore URL updates from superseded streams\n if (this.screencasts.get(viewerKey) !== currentStream) return;\n this.broadcastUrlIfChanged(viewerKey, url);\n });\n\n // Wire up stop events\n stream.on('stop', reason => {\n // Ignore stop events from superseded streams (e.g., old stream stopping after reconnect)\n if (this.screencasts.get(viewerKey) !== currentStream) {\n console.info(`[ViewerRegistry] Ignoring stop from superseded stream for ${viewerKey}`);\n return;\n }\n console.info(`[ViewerRegistry] Screencast stopped for ${viewerKey}: ${reason}`);\n this.screencasts.delete(viewerKey);\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n });\n\n // Wire up error events - treat errors as browser closed since screencast can't continue\n stream.on('error', error => {\n // Ignore errors from superseded streams\n if (this.screencasts.get(viewerKey) !== currentStream) return;\n console.error(`[ViewerRegistry] Screencast error for ${viewerKey}:`, error);\n this.screencasts.delete(viewerKey);\n // Explicitly stop the stream to clean up CDP resources\n currentStream.stop().catch(stopError => {\n console.warn(`[ViewerRegistry] Error stopping errored screencast for ${viewerKey}:`, stopError);\n });\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n });\n\n this.broadcastStatus(viewerKey, { status: 'streaming' });\n\n // Send initial URL - pass threadId to get URL from correct browser session\n const initialUrl = await toolset.getCurrentUrl(threadId);\n this.broadcastUrlIfChanged(viewerKey, initialUrl);\n } catch (error) {\n console.error(`[ViewerRegistry] Failed to start screencast for ${viewerKey}:`, error);\n // Connection stays open - user can see error status\n } finally {\n // Clear starting flag\n this.startingScreencasts.delete(viewerKey);\n }\n }\n\n /**\n * Stop screencast for an agent. Called when last viewer disconnects.\n */\n private async stopScreencast(agentId: string): Promise<void> {\n const stream = this.screencasts.get(agentId);\n if (!stream) {\n return;\n }\n\n try {\n await stream.stop();\n } catch (error) {\n console.warn(`[ViewerRegistry] Error stopping screencast for ${agentId}:`, error);\n } finally {\n this.screencasts.delete(agentId);\n }\n }\n\n /**\n * Get the number of viewers for an agent.\n *\n * @param agentId - The agent ID\n * @returns The number of connected viewers\n */\n getViewerCount(agentId: string): number {\n return this.viewers.get(agentId)?.size ?? 0;\n }\n\n /**\n * Check if an agent has an active screencast.\n *\n * @param agentId - The agent ID\n * @returns True if screencast is active\n */\n hasActiveScreencast(agentId: string): boolean {\n return this.screencasts.has(agentId);\n }\n\n /**\n * Close the browser session for an agent.\n * Stops screencast and broadcasts browser_closed status.\n * Call this before calling toolset.close() to ensure UI is notified.\n *\n * @param viewerKey - The viewer key (agentId or agentId:threadId for thread-scoped)\n */\n async closeBrowserSession(viewerKey: string): Promise<void> {\n // NOTE: Do NOT clean up the onBrowserReady callback here.\n // Viewers are still connected (WebSocket stays open), so we need\n // the callback to fire when the browser relaunches from a subsequent\n // tool call. Callback cleanup only happens in removeViewer() when\n // the last viewer disconnects.\n\n // Clear URL, viewport, and status tracking so next session sends fresh data\n this.lastUrls.delete(viewerKey);\n this.lastViewports.delete(viewerKey);\n this.lastStatuses.delete(viewerKey);\n\n // Stop screencast if active\n const stream = this.screencasts.get(viewerKey);\n if (stream) {\n try {\n await stream.stop();\n // Note: stream.stop() emits 'stop' event which triggers broadcastStatus\n } catch (error) {\n console.warn(`[ViewerRegistry] Error stopping screencast for ${viewerKey}:`, error);\n // Still broadcast browser_closed even if stop fails\n this.screencasts.delete(viewerKey);\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n }\n } else {\n // No active screencast, but still broadcast browser_closed\n this.broadcastStatus(viewerKey, { status: 'browser_closed' });\n }\n }\n}\n","import type { MastraBrowser } from '@mastra/core/browser';\nimport type { BrowserStreamConfig, ClientInputMessage, MouseInputMessage, KeyboardInputMessage } from './types.js';\n\n// Valid CDP mouse event types\nconst VALID_MOUSE_EVENTS = new Set(['mousePressed', 'mouseReleased', 'mouseMoved', 'mouseWheel']);\n\n// Valid CDP keyboard event types\nconst VALID_KEYBOARD_EVENTS = new Set(['keyDown', 'keyUp', 'char']);\n\n// Input dispatch queue per agent+thread to serialize input events\nconst inputQueues = new Map<string, Promise<void>>();\n\n/**\n * Serialize input dispatch to maintain event ordering.\n * Input events must be processed in order to avoid race conditions.\n */\nfunction enqueueInput(key: string, fn: () => Promise<void>): void {\n const current = inputQueues.get(key) ?? Promise.resolve();\n const next = current.then(fn).catch(() => {\n // Errors are handled inside fn, just ensure chain continues\n });\n inputQueues.set(key, next);\n}\n\n/**\n * Map of key names to Windows virtual key codes.\n * Required for non-printable keys (Enter, Tab, Arrow keys, etc.)\n * See: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes\n */\nconst VIRTUAL_KEY_CODES: Record<string, number> = {\n // Control keys\n Backspace: 8,\n Tab: 9,\n Enter: 13,\n Shift: 16,\n Control: 17,\n Alt: 18,\n Pause: 19,\n CapsLock: 20,\n Escape: 27,\n Space: 32,\n ' ': 32,\n PageUp: 33,\n PageDown: 34,\n End: 35,\n Home: 36,\n // Arrow keys\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n // Editing keys\n Insert: 45,\n Delete: 46,\n // Function keys\n F1: 112,\n F2: 113,\n F3: 114,\n F4: 115,\n F5: 116,\n F6: 117,\n F7: 118,\n F8: 119,\n F9: 120,\n F10: 121,\n F11: 122,\n F12: 123,\n};\n\n/**\n * Get the Windows virtual key code for a key.\n * For printable characters, uses the character code.\n * For special keys, looks up in the mapping.\n */\nfunction getVirtualKeyCode(key: string | undefined): number | undefined {\n if (!key) return undefined;\n\n // Check special keys first\n if (VIRTUAL_KEY_CODES[key] !== undefined) {\n return VIRTUAL_KEY_CODES[key];\n }\n\n // For single printable characters, use the uppercase char code\n if (key.length === 1) {\n return key.toUpperCase().charCodeAt(0);\n }\n\n return undefined;\n}\n\n/**\n * Handle an incoming WebSocket message by parsing, validating,\n * and routing to the appropriate toolset injection method.\n *\n * Fire-and-forget: no acknowledgment sent back to client.\n * Silently ignores malformed or unrecognized messages.\n *\n * @param data - Raw string data from WebSocket message\n * @param getToolset - Function to retrieve MastraBrowser for an agent\n * @param agentId - The agent ID this WebSocket connection is for\n * @param threadId - The thread ID for thread-scoped operations (optional)\n */\nexport async function handleInputMessage(\n data: string,\n getToolset: BrowserStreamConfig['getToolset'],\n agentId: string,\n threadId?: string,\n): Promise<void> {\n let message: unknown;\n try {\n message = JSON.parse(data);\n } catch {\n return;\n }\n\n if (!isValidInputMessage(message)) {\n return;\n }\n\n const toolset = await getToolset(agentId);\n if (!toolset) {\n return;\n }\n\n // Serialize input dispatch per agent+thread to maintain event ordering\n const queueKey = `${agentId}:${threadId ?? 'default'}`;\n\n switch (message.type) {\n case 'mouse':\n enqueueInput(queueKey, async () => {\n try {\n await injectMouse(toolset, message, threadId);\n } catch (err) {\n if (isDisconnectionError(err)) {\n notifyBrowserClosed(toolset, threadId);\n } else if (!isExpectedInjectionError(err)) {\n console.warn('[InputHandler] Mouse injection error:', err);\n }\n }\n });\n break;\n case 'keyboard':\n enqueueInput(queueKey, async () => {\n try {\n await injectKeyboard(toolset, message, threadId);\n } catch (err) {\n if (isDisconnectionError(err)) {\n notifyBrowserClosed(toolset, threadId);\n } else if (!isExpectedInjectionError(err)) {\n console.warn('[InputHandler] Keyboard injection error:', err);\n }\n }\n });\n break;\n }\n}\n\n// --- Error handling ---\n\n/**\n * Check if an error indicates browser disconnection (target closed).\n * These errors mean the browser was externally closed.\n */\nfunction isDisconnectionError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n // Note: 'no cdp session' is handled by isExpectedInjectionError (startup race)\n // and should not trigger browser closed state\n return (\n msg.includes('target closed') ||\n msg.includes('browser has been closed') ||\n msg.includes('page has been closed') ||\n msg.includes('session closed') ||\n msg.includes('browser has disconnected')\n );\n}\n\n/**\n * Check if an injection error is expected (browser not ready yet).\n * These are silently ignored to avoid log spam.\n */\nfunction isExpectedInjectionError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes('no cdp session') ||\n msg.includes('browser not launched') ||\n msg.includes('not connected to browser') ||\n msg.includes('no active target') ||\n (msg.includes('target') && msg.includes('not attached'))\n );\n}\n\n/**\n * Notify the browser that it was closed externally.\n * This triggers the onBrowserClosed callbacks to update the UI.\n * If threadId is provided and the browser supports thread-specific closing,\n * only that thread's session is closed.\n */\nfunction notifyBrowserClosed(toolset: MastraBrowser, threadId?: string): void {\n const browser = toolset as unknown as {\n closeThreadSession?: (threadId: string) => Promise<void>;\n handleBrowserDisconnected?: () => void;\n };\n\n // For thread-scoped browsers, close only the specific thread's session\n if (threadId && typeof browser.closeThreadSession === 'function') {\n void browser.closeThreadSession(threadId).catch(() => {\n // Fall back to global disconnect if thread-specific close fails\n browser.handleBrowserDisconnected?.();\n });\n return;\n }\n\n // Fall back to global disconnect handling\n browser.handleBrowserDisconnected?.();\n}\n\n// --- Input injection ---\n\n/**\n * Inject a mouse event into the browser.\n */\nasync function injectMouse(toolset: MastraBrowser, msg: MouseInputMessage, threadId?: string): Promise<void> {\n await toolset.injectMouseEvent(\n {\n type: msg.eventType,\n x: msg.x,\n y: msg.y,\n button: msg.button,\n clickCount: msg.clickCount,\n deltaX: msg.deltaX,\n deltaY: msg.deltaY,\n modifiers: msg.modifiers,\n },\n threadId,\n );\n}\n\n/**\n * Inject a keyboard event into the browser.\n */\nasync function injectKeyboard(toolset: MastraBrowser, msg: KeyboardInputMessage, threadId?: string): Promise<void> {\n const windowsVirtualKeyCode = getVirtualKeyCode(msg.key);\n\n await toolset.injectKeyboardEvent(\n {\n type: msg.eventType,\n key: msg.key,\n code: msg.code,\n text: msg.text,\n modifiers: msg.modifiers,\n windowsVirtualKeyCode,\n },\n threadId,\n );\n}\n\n// --- Validation ---\n\n/**\n * Type guard to validate incoming messages.\n * Validates structure and rejects invalid event types at the boundary.\n */\nfunction isValidInputMessage(msg: unknown): msg is ClientInputMessage {\n if (typeof msg !== 'object' || msg === null) {\n return false;\n }\n\n const typed = msg as Record<string, unknown>;\n\n if (typed.type === 'mouse') {\n // Validate mouse message structure\n if (typeof typed.eventType !== 'string' || !VALID_MOUSE_EVENTS.has(typed.eventType)) {\n return false;\n }\n if (typeof typed.x !== 'number' || typeof typed.y !== 'number') {\n return false;\n }\n // Optional fields validation\n if (typed.button !== undefined && typeof typed.button !== 'string') {\n return false;\n }\n if (typed.deltaX !== undefined && typeof typed.deltaX !== 'number') {\n return false;\n }\n if (typed.deltaY !== undefined && typeof typed.deltaY !== 'number') {\n return false;\n }\n return true;\n }\n\n if (typed.type === 'keyboard') {\n // Validate keyboard message structure\n if (typeof typed.eventType !== 'string' || !VALID_KEYBOARD_EVENTS.has(typed.eventType)) {\n return false;\n }\n // At least one of key, code, or text should be present for meaningful input\n const hasKey = typeof typed.key === 'string';\n const hasCode = typeof typed.code === 'string';\n const hasText = typeof typed.text === 'string';\n if (!hasKey && !hasCode && !hasText) {\n return false;\n }\n // Optional modifiers validation\n if (typed.modifiers !== undefined && typeof typed.modifiers !== 'number') {\n return false;\n }\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
@@ -56,7 +56,7 @@ var ViewerRegistry = class {
56
56
  }
57
57
  const wasEmpty = viewerSet.size === 0;
58
58
  viewerSet.add(ws);
59
- if (wasEmpty) await this.startScreencast(viewerKey, getToolset, agentId ?? viewerKey, threadId);
59
+ if (wasEmpty || !this.browserReadyCleanups.has(viewerKey)) await this.startScreencast(viewerKey, getToolset, agentId ?? viewerKey, threadId);
60
60
  else this.sendCurrentState(viewerKey, ws);
61
61
  }
62
62
  /**
@@ -177,6 +177,8 @@ var ViewerRegistry = class {
177
177
  /**
178
178
  * Start screencast for a viewer. Only starts if browser is already running.
179
179
  * If browser not running, registers a callback to start when browser becomes ready.
180
+ * If no toolset can be resolved, nothing is registered; `addViewer` retries the
181
+ * lookup the next time a viewer connects for this key.
180
182
  *
181
183
  * @param viewerKey - The viewer key (for registry keying)
182
184
  * @param getToolset - Function to retrieve the BrowserToolset
@@ -187,7 +189,7 @@ var ViewerRegistry = class {
187
189
  const toolset = await getToolset(agentId);
188
190
  if (!this.viewers.has(viewerKey)) return;
189
191
  if (!toolset) {
190
- console.info(`[ViewerRegistry] No toolset for ${viewerKey}, waiting...`);
192
+ console.info(`[ViewerRegistry] No browser toolset for ${viewerKey}; will retry on next viewer connect`);
191
193
  return;
192
194
  }
193
195
  if (!this.browserReadyCleanups.has(viewerKey)) {