@ai-matrx/chat 0.2.4 → 0.2.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 (65) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/agents/addressing/agentAddress.js +1 -1
  3. package/dist/agents/components/context-items/bodies/ProcessedDocumentTitle.js +3 -2
  4. package/dist/agents/components/context-items/bodies/WebpageBody.js +6 -1
  5. package/dist/agents/components/debug/SandboxFileViewer.js +6 -1
  6. package/dist/agents/components/debug/StreamDebugPanel.js +6 -1
  7. package/dist/agents/components/inputs/input-components/MediaVariableInput.js +1 -1
  8. package/dist/agents/components/inputs/input-components/PicklistVariableInput.js +2 -2
  9. package/dist/agents/components/inputs/resources/attached-documents.js +3 -2
  10. package/dist/agents/components/inputs/resources/usePasteImageResource.js +2 -2
  11. package/dist/agents/components/messages-display/TranscriptIntegrityCopyButton.js +6 -2
  12. package/dist/agents/components/observational-memory/components/MemoryStateInspector.d.ts +0 -12
  13. package/dist/agents/components/observational-memory/components/MemoryStateInspector.js +10 -2
  14. package/dist/agents/components/run-controls/AgentExecutionTestModal.js +6 -1
  15. package/dist/agents/components/shared/AgentDuplicateOutcomeDialog.d.ts +26 -2
  16. package/dist/agents/components/shared/AgentDuplicateOutcomeDialog.js +50 -4
  17. package/dist/agents/components/shared/AgentOptionsMenu.js +11 -61
  18. package/dist/agents/components/shared/StreamProfilerOverlay.js +6 -1
  19. package/dist/agents/components/working-document/workingDocumentSurface.d.ts +1 -1
  20. package/dist/agents/hooks/useAgentDuplicateFlow.d.ts +13 -3
  21. package/dist/agents/hooks/useAgentDuplicateFlow.js +81 -24
  22. package/dist/agents/hooks/useWidgetHandle.js +1 -1
  23. package/dist/agents/prompt-preview/PromptPreviewContent.js +6 -1
  24. package/dist/agents/redux/agent-definition/cache-bust-middleware.js +1 -1
  25. package/dist/agents/redux/agent-definition/parse-messages-variables.js +6 -0
  26. package/dist/agents/redux/agent-shortcuts/thunks.js +1 -1
  27. package/dist/agents/redux/execution-system/instance-resources/resource-source.js +1 -2
  28. package/dist/agents/redux/execution-system/thunks/execute-manual-instance.thunk.js +1 -1
  29. package/dist/agents/redux/execution-system/thunks/launch-conversation.thunk.js +1 -1
  30. package/dist/agents/redux/execution-system/thunks/run-headless-agent-json.d.ts +8 -3
  31. package/dist/agents/redux/execution-system/thunks/run-headless-agent-json.js +36 -3
  32. package/dist/agents/redux/execution-system/utils/assert-conversation-id.js +1 -1
  33. package/dist/agents/redux/execution-system/utils/content-prefilter.js +2 -2
  34. package/dist/agents/runtime/realtime/launchRealtimeSession.thunk.js +1 -1
  35. package/dist/agents/surface-catalog-profile.d.ts +2 -2
  36. package/dist/agents/types/agent-definition.types.d.ts +8 -6
  37. package/dist/agents/utils/variable-customcomponent.d.ts +2 -2
  38. package/dist/agents/utils/variable-customcomponent.js +4 -4
  39. package/dist/cx-chat/components/messages/AssistantMessage.js +1 -1
  40. package/dist/cx-chat/components/user-input/ConversationInput.js +1 -1
  41. package/dist/cx-conversation/AssistantMessage.js +1 -1
  42. package/dist/cx-conversation/ConversationInput.js +1 -1
  43. package/dist/host/builder-door.d.ts +13 -2
  44. package/dist/host/db-types.d.ts +150 -2
  45. package/dist/host/defaults/diagnostics.js +1 -1
  46. package/dist/host/ui-slots.d.ts +2 -22
  47. package/dist/host/ui-slots.js +3 -29
  48. package/dist/host/window-openers.d.ts +3 -3
  49. package/dist/host/window-openers.js +4 -4
  50. package/dist/store/create-chat-store.d.ts +2 -0
  51. package/dist/store/create-chat-store.js +15 -3
  52. package/dist/surfaces/runtime/loaded-value-check.js +1 -1
  53. package/dist/surfaces/runtime/surface-writeback.js +1 -1
  54. package/dist/surfaces/utils/route-to-surface.js +1 -1
  55. package/dist/surfaces/utils/surface-display.js +1 -1
  56. package/dist/tool-call-visualization/effects/toolStateEffects.d.ts +1 -1
  57. package/dist/tool-call-visualization/registry/registry.js +3 -7
  58. package/dist/tool-call-visualization/result-fields/shape.js +1 -1
  59. package/dist/ui/file-source.d.ts +3 -17
  60. package/dist/voice-agent/components/VoiceDebugPanel.js +6 -1
  61. package/dist/voice-agent/hooks/useRealtimeAgentConfig.js +1 -1
  62. package/dist/voice-agent/hooks/useXaiVoiceSession.js +2 -2
  63. package/dist/voice-agent/transport/xaiClient.js +1 -1
  64. package/dist/window-panels/windows/agents/AgentMemoryWindow.js +7 -5
  65. package/package.json +3 -3
@@ -20,7 +20,7 @@ export declare function surfaceNameForKind(kind: WorkingDocumentKind): string;
20
20
  export declare function sourceFeatureForKind(kind: WorkingDocumentKind): SourceFeature;
21
21
  /** `UnifiedAgentContextMenu` prop bundle for a document kind. */
22
22
  export declare function workingDocumentContextMenuProps(kind: WorkingDocumentKind): {
23
- sourceFeature: "action_request_continuation" | "action_request_credential" | "action_request_one_time_code" | "action_request_park" | "action_request_resolve" | "admin" | "agent" | "agent-app" | "agent-builder" | "agent-comparison" | "agent-factory" | "agent-generator" | "agent-runner" | "agent-service" | "agent-studio" | "agent_blocks" | "agent_call" | "agent_flow_v1" | "agent_foundry_v1" | "agent_run" | "agent_structure_builder" | "agent_tool" | "agent_usage_sync" | "agents-other" | "ai-results" | "ai_judge" | "analysis-studio" | "auto_ingest" | "auto_ingest_ner" | "background_agent" | "billing" | "browser_handoff_delegate" | "browser_handoff_resolve" | "browser_session_health" | "builtin_agent" | "builtin_categorize" | "canvas" | "chat" | "claude-code" | "clean_pdf_extracted_content" | "client-unmapped" | "cloud_browser.local_login_learning" | "cms" | "code-editor" | "codex" | "coding_session_bridge.backfill" | "coding_session_native" | "coding_session_reply" | "communications.sms" | "conductor" | "content-extractor" | "content_plan_acceptance" | "content_plan_cms_fill" | "content_plan_cms_fill_preview" | "content_plan_deepen" | "content_plan_generate" | "content_processing" | "content_processing.research_landing" | "content_processing.transcript_landing" | "content_processing_upload_hook" | "context-parity" | "context_compare_answer" | "context_follow_listener" | "context_summary" | "conversation" | "conversation_context" | "conversation_crash_recovery" | "conversation_fork" | "conversation_resume" | "coverage" | "crawl_run" | "crm" | "crm.media_list_refresh" | "crm.media_list_research" | "crm.party_kind" | "crm.personalization" | "cursor" | "deep_research_v1" | "deferred_claim_recovery" | "dictionary" | "distillation_coherence" | "doc_verify" | "documents" | "education-analytics" | "education-assessment" | "education-fastfire" | "education-flashcards" | "education-ingest" | "education-media-reconcile" | "education-mindmap" | "education-planner" | "education-tutor" | "education_card_image_generator" | "education_card_image_prompt_writer" | "education_card_image_qc_judge" | "education_card_image_rot" | "education_card_image_web_source" | "education_card_images" | "education_study_pack" | "education_study_pack_v2" | "endpoint_family_sweep" | "external_url_change" | "files" | "fork_and_run" | "google_workspace.approval_replay" | "group_chat_cadence" | "hindsight" | "hindsight/crystallization" | "hindsight/wire_replay" | "hindsight_replay" | "hindsight_replay_worker" | "hindsight_shadow_recompilation" | "hr" | "human_decisions" | "image-studio" | "incident-assurance" | "internal" | "judge" | "kg_clustering_namer" | "legal" | "local_proxy" | "mandate_candidate_review" | "mandates.batch_lane" | "manual" | "marketing" | "masterwork" | "masterwork_audition_elicitation_vanilla" | "masterwork_audition_outcome_vanilla" | "masterwork_audition_unfolding_vanilla" | "masterwork_audition_vanilla" | "masterwork_bench_a2" | "masterwork_bench_extract" | "masterwork_bench_judge" | "masterwork_bench_panel" | "masterwork_build" | "masterwork_recovery" | "media_catalog" | "media_heal" | "meet:after_meeting_workflow" | "mermaid-workbench" | "messages" | "ner" | "news_monitor" | "notes" | "notify_listener" | "outcome_attribution" | "outreach" | "page_extraction" | "page_extraction_retry" | "pdf-cleaner" | "pdf-extractor" | "pdf-widgets" | "personal-staff" | "personal_staff_workspace_listener" | "platform_checks" | "platform_checks_drain" | "podcasts" | "print" | "product_capture_intake" | "product_capture_research" | "projects" | "prompt" | "proof_run:content_plan_family_grounding" | "proof_run:news_self_validating" | "provenance" | "provider_outage" | "rag" | "rag-search" | "rag.page_clean" | "rag_chunk_contextualizer" | "rag_hyde_generator" | "rag_pdf_page_cleaner" | "rag_query_expander" | "reachability" | "realtime" | "realtime_tool" | "registry_ingestion.pass" | "reroute" | "research" | "research_condenser_1" | "research_condenser_2" | "research_refresh_dispatch" | "row_history" | "scanner" | "scheduled" | "schema_coerce" | "scraper" | "scratchpad" | "screen_tool_run" | "seo" | "seo.engine_schedule_dispatcher" | "seo.keyword_place_backfill" | "seo.page_analysis" | "seo.rank_schedule" | "seo_analysis_sweep" | "seo_keyword_research" | "server-door" | "server-run" | "sharing" | "sms-assistant" | "sms-outbound" | "socket_compat" | "source_intelligence" | "staff-inbox-driver" | "suggestion_sweep" | "summarize_content" | "sweep_listener" | "system" | "tasks" | "tool-call-visualization" | "tool-testing" | "transcription" | "udt" | "vision_interview" | "vision_interview_tracker" | "voice-agent" | "vscode" | "web-capture" | "web_crawl_crash_resume" | "web_crawl_schedule_dispatch" | "web_research" | "web_url_announce" | "whole_value_follower" | "workflow_decision_fallback" | "workflow_extract_sweep" | "workflow_node_test" | "workflow_plan_assist" | "workflow_recovery_advisor" | "workflow_recovery_push" | "workflow_recovery_resolve" | "workflow_run" | "workflow_run_assists" | "workflow_worker" | "working-document" | "youtube_research_processing" | "youtube_transcription";
23
+ sourceFeature: "action_request_continuation" | "action_request_credential" | "action_request_one_time_code" | "action_request_park" | "action_request_resolve" | "admin" | "agent" | "agent-app" | "agent-builder" | "agent-comparison" | "agent-factory" | "agent-generator" | "agent-runner" | "agent-service" | "agent-studio" | "agent_blocks" | "agent_call" | "agent_factory.copy_probe" | "agent_factory.tool_probe" | "agent_flow_v1" | "agent_foundry_v1" | "agent_run" | "agent_structure_builder" | "agent_tool" | "agent_usage_sync" | "agents-other" | "ai-results" | "ai_judge" | "analysis-studio" | "auto_ingest" | "auto_ingest_ner" | "background_agent" | "billing" | "browser_handoff_delegate" | "browser_handoff_resolve" | "browser_session_health" | "builtin_agent" | "builtin_categorize" | "canvas" | "chat" | "claude-code" | "clean_pdf_extracted_content" | "client-unmapped" | "cloud_browser.local_login_learning" | "cms" | "code-editor" | "codex" | "coding_session_bridge.backfill" | "coding_session_native" | "coding_session_reply" | "communications.sms" | "conductor" | "content-extractor" | "content_plan_acceptance" | "content_plan_cms_fill" | "content_plan_cms_fill_preview" | "content_plan_deepen" | "content_plan_generate" | "content_processing" | "content_processing.research_landing" | "content_processing.transcript_landing" | "content_processing_upload_hook" | "context-parity" | "context_compare_answer" | "context_follow_listener" | "context_summary" | "conversation" | "conversation_context" | "conversation_crash_recovery" | "conversation_fork" | "conversation_resume" | "coverage" | "crawl_run" | "crm" | "crm.media_list_refresh" | "crm.media_list_research" | "crm.party_kind" | "crm.personalization" | "cursor" | "deep_research_v1" | "deferred_claim_recovery" | "dictionary" | "distillation_coherence" | "doc_verify" | "documents" | "education-analytics" | "education-assessment" | "education-fastfire" | "education-flashcards" | "education-ingest" | "education-media-reconcile" | "education-mindmap" | "education-planner" | "education-tutor" | "education_card_image_generator" | "education_card_image_prompt_writer" | "education_card_image_qc_judge" | "education_card_image_rot" | "education_card_image_web_source" | "education_card_images" | "education_study_pack" | "education_study_pack_v2" | "endpoint_family_sweep" | "external_url_change" | "files" | "fork_and_run" | "google_workspace.approval_replay" | "group_chat_cadence" | "hindsight" | "hindsight/crystallization" | "hindsight/wire_replay" | "hindsight_replay" | "hindsight_replay_worker" | "hindsight_shadow_recompilation" | "hr" | "human_decisions" | "image-studio" | "incident-assurance" | "internal" | "judge" | "kg_clustering_namer" | "legal" | "local_proxy" | "mandate_candidate_review" | "mandates.batch_lane" | "manual" | "marketing" | "masterwork" | "masterwork_audition_elicitation_vanilla" | "masterwork_audition_outcome_vanilla" | "masterwork_audition_unfolding_vanilla" | "masterwork_audition_vanilla" | "masterwork_bench_a2" | "masterwork_bench_extract" | "masterwork_bench_judge" | "masterwork_bench_panel" | "masterwork_build" | "masterwork_recovery" | "media_catalog" | "media_heal" | "meet:after_meeting_workflow" | "mermaid-workbench" | "messages" | "ner" | "news_monitor" | "notes" | "notify_listener" | "outcome_attribution" | "outreach" | "page_extraction" | "page_extraction_retry" | "pdf-cleaner" | "pdf-extractor" | "pdf-widgets" | "personal-staff" | "personal_staff_workspace_listener" | "platform_checks" | "platform_checks_drain" | "podcasts" | "print" | "product_capture_intake" | "product_capture_research" | "projects" | "prompt" | "proof_run:content_plan_family_grounding" | "proof_run:news_self_validating" | "provenance" | "provider_outage" | "rag" | "rag-search" | "rag.page_clean" | "rag_chunk_contextualizer" | "rag_hyde_generator" | "rag_pdf_page_cleaner" | "rag_query_expander" | "reachability" | "realtime" | "realtime_tool" | "registry_ingestion.pass" | "request_snapshot_blob" | "reroute" | "research" | "research_condenser_1" | "research_condenser_2" | "research_refresh_dispatch" | "row_history" | "scanner" | "scheduled" | "schema_coerce" | "scraper" | "scratchpad" | "screen_tool_run" | "seo" | "seo.engine_schedule_dispatcher" | "seo.keyword_place_backfill" | "seo.page_analysis" | "seo.rank_schedule" | "seo_analysis_sweep" | "seo_keyword_research" | "server-door" | "server-run" | "sharing" | "sms-assistant" | "sms-outbound" | "socket_compat" | "source_intelligence" | "staff-inbox-driver" | "suggestion_sweep" | "summarize_content" | "sweep_listener" | "system" | "tasks" | "test.agent_factory.intake" | "tool-call-visualization" | "tool-testing" | "transcription" | "udt" | "vision_interview" | "vision_interview_tracker" | "voice-agent" | "vscode" | "web-capture" | "web_crawl_crash_resume" | "web_crawl_schedule_dispatch" | "web_research" | "web_url_announce" | "whole_value_follower" | "workflow_decision_fallback" | "workflow_extract_sweep" | "workflow_holder_proof" | "workflow_node_test" | "workflow_plan_assist" | "workflow_recovery_advisor" | "workflow_recovery_push" | "workflow_recovery_resolve" | "workflow_run" | "workflow_run_assists" | "workflow_worker" | "working-document" | "youtube_research_processing" | "youtube_transcription";
24
24
  surfaceName: string;
25
25
  isEditable: true;
26
26
  enabledPlacements: ("ai-action" | "content-block" | "quick-action")[];
@@ -1,12 +1,22 @@
1
1
  interface UseAgentDuplicateFlowOptions {
2
2
  basePath?: string;
3
+ /** Sub-route the copy opens on when the source is not the current page. */
4
+ fallbackSuffix?: string;
5
+ }
6
+ export interface StartDuplicateOptions {
7
+ /** Copy this saved version (definition_version id). Omitted = the current agent. */
8
+ versionId?: string;
3
9
  }
4
10
  /**
5
- * Shared duplicate flow for agent surfaces (options menu, read-only builder save,
6
- * floating "create my copy" chip). Returns a trigger + the outcome dialog element.
11
+ * Shared duplicate flow for agent surfaces (options menu, versions tab,
12
+ * read-only builder save, floating "create my copy" chip). Returns triggers +
13
+ * the one dialog element:
14
+ * - `startDuplicate()` copies right away (current agent, or `{ versionId }`).
15
+ * - `openChooser()` first asks which version to copy, defaulting to current.
7
16
  */
8
17
  export declare function useAgentDuplicateFlow(agentId: string, options?: UseAgentDuplicateFlowOptions): {
9
- readonly startDuplicate: () => Promise<void>;
18
+ readonly startDuplicate: (opts?: StartDuplicateOptions) => Promise<void>;
19
+ readonly openChooser: () => Promise<void>;
10
20
  readonly dialog: import("react").JSX.Element;
11
21
  readonly isDuplicating: boolean;
12
22
  /** False in a host that registered no builder door: nothing offers a duplicate (reported once). */
@@ -5,8 +5,10 @@ import { usePathname } from "../../host/navigation.js";
5
5
  import { useAppDispatch, useAppSelector } from "../../store/hooks.js";
6
6
  import { selectAgentById } from "../redux/agent-definition/selectors.js";
7
7
  import { getBuilderDoor, requireBuilderDoor } from "../../host/builder-door.js";
8
+ import { supabase } from "../../host/db.js";
8
9
  import {
9
- AgentDuplicateOutcomeDialog
10
+ AgentDuplicateOutcomeDialog,
11
+ CURRENT_VERSION_CHOICE
10
12
  } from "../components/shared/AgentDuplicateOutcomeDialog.js";
11
13
  import { isAdminSystemAgentsContext } from "../components/shared/agent-route-context.js";
12
14
  import { getUserMessage } from "@ai-matrx/agents/matrx";
@@ -15,56 +17,111 @@ function useAgentDuplicateFlow(agentId, options) {
15
17
  const dispatch = useAppDispatch();
16
18
  const pathname = usePathname();
17
19
  const basePath = options?.basePath ?? "/agents";
20
+ const fallbackSuffix = options?.fallbackSuffix ?? "/build";
18
21
  const agent = useAppSelector((state2) => selectAgentById(state2, agentId));
19
22
  const [open, setOpen] = useState(false);
20
23
  const [state, setState] = useState("loading");
21
24
  const [newAgentId, setNewAgentId] = useState(null);
22
25
  const [errorMessage, setErrorMessage] = useState("");
23
26
  const [asSystem, setAsSystem] = useState(false);
27
+ const [versions, setVersions] = useState([]);
28
+ const [versionsLoading, setVersionsLoading] = useState(false);
29
+ const [versionsError, setVersionsError] = useState(null);
30
+ const [selected, setSelected] = useState(CURRENT_VERSION_CHOICE);
31
+ const newAgent = useAppSelector(
32
+ (s) => newAgentId ? selectAgentById(s, newAgentId) : void 0
33
+ );
24
34
  const isAdminContext = isAdminSystemAgentsContext(basePath);
25
35
  const isBuiltin = agent?.agentType === "builtin";
26
- const newAgentName = agent?.name ? `Copy of ${agent.name}` : "";
27
36
  const newAgentPath = newAgentId ? (() => {
28
37
  const sourceSegment = `${basePath}/${agentId}`;
29
- const suffix = pathname && pathname.startsWith(sourceSegment) ? pathname.slice(sourceSegment.length) : "/build";
30
- return `${basePath}/${newAgentId}${suffix || "/build"}`;
38
+ const here = pathname && pathname.startsWith(sourceSegment) ? pathname.slice(sourceSegment.length) : fallbackSuffix;
39
+ const suffix = /^\/v(\/|$)/.test(here) ? fallbackSuffix : here;
40
+ return `${basePath}/${newAgentId}${suffix || fallbackSuffix}`;
31
41
  })() : null;
32
- const startDuplicate = useCallback(async () => {
33
- const duplicateAsSystem = isAdminContext && isBuiltin;
34
- setAsSystem(duplicateAsSystem);
42
+ const startDuplicate = useCallback(
43
+ async (opts) => {
44
+ const duplicateAsSystem = isAdminContext && isBuiltin;
45
+ setAsSystem(duplicateAsSystem);
46
+ setNewAgentId(null);
47
+ setErrorMessage("");
48
+ setState("loading");
49
+ setOpen(true);
50
+ try {
51
+ const id = await dispatch(
52
+ requireBuilderDoor().duplicateAgent({
53
+ agentId,
54
+ asSystem: duplicateAsSystem,
55
+ versionId: opts?.versionId
56
+ })
57
+ ).unwrap();
58
+ setNewAgentId(id);
59
+ setState("success");
60
+ } catch (err) {
61
+ if (isOrganizationSelectionCancelled(err)) {
62
+ setOpen(false);
63
+ return;
64
+ }
65
+ setErrorMessage(getUserMessage(err));
66
+ setState("error");
67
+ }
68
+ },
69
+ [agentId, dispatch, isAdminContext, isBuiltin]
70
+ );
71
+ const openChooser = useCallback(async () => {
72
+ setSelected(CURRENT_VERSION_CHOICE);
35
73
  setNewAgentId(null);
36
74
  setErrorMessage("");
37
- setState("loading");
75
+ setState("choose");
38
76
  setOpen(true);
39
- try {
40
- const id = await dispatch(
41
- requireBuilderDoor().duplicateAgent({ agentId, asSystem: duplicateAsSystem })
42
- ).unwrap();
43
- setNewAgentId(id);
44
- setState("success");
45
- } catch (err) {
46
- if (isOrganizationSelectionCancelled(err)) {
47
- setOpen(false);
48
- return;
49
- }
50
- setErrorMessage(getUserMessage(err));
51
- setState("error");
77
+ setVersionsLoading(true);
78
+ setVersionsError(null);
79
+ const { data, error } = await supabase.rpc("agx_get_version_history", {
80
+ p_agent_id: agentId,
81
+ p_limit: 500,
82
+ p_offset: 0
83
+ });
84
+ setVersionsLoading(false);
85
+ if (error) {
86
+ setVersions([]);
87
+ setVersionsError(error.message);
88
+ return;
52
89
  }
53
- }, [agentId, dispatch, isAdminContext, isBuiltin]);
90
+ setVersions(
91
+ (data ?? []).map((row) => ({
92
+ versionId: row.version_id,
93
+ versionNumber: row.version_number,
94
+ changedAt: row.changed_at,
95
+ changeNote: row.change_note ?? null
96
+ }))
97
+ );
98
+ }, [agentId]);
54
99
  const dialog = /* @__PURE__ */ jsx(
55
100
  AgentDuplicateOutcomeDialog,
56
101
  {
57
102
  open,
58
103
  onOpenChange: setOpen,
59
104
  state,
60
- newAgentName,
105
+ newAgentName: newAgent?.name ?? "",
61
106
  newAgentPath,
62
107
  errorMessage,
63
- asSystem
108
+ asSystem,
109
+ chooser: {
110
+ currentVersion: agent?.version ?? null,
111
+ versions,
112
+ versionsLoading,
113
+ versionsError,
114
+ selected,
115
+ onSelectedChange: setSelected,
116
+ onConfirm: () => void startDuplicate(
117
+ selected === CURRENT_VERSION_CHOICE ? void 0 : { versionId: selected }
118
+ )
119
+ }
64
120
  }
65
121
  );
66
122
  return {
67
123
  startDuplicate,
124
+ openChooser,
68
125
  dialog,
69
126
  isDuplicating: open && state === "loading",
70
127
  /** False in a host that registered no builder door: nothing offers a duplicate (reported once). */
@@ -38,7 +38,7 @@ function useWidgetHandle(handle) {
38
38
  idRef.current = callbackManager.registerWidgetHandle(
39
39
  makeStableHandle(handleRef)
40
40
  );
41
- if (true) {
41
+ if (process.env.NODE_ENV !== "production") {
42
42
  const methodCount = [
43
43
  ...Object.values(WIDGET_TOOL_NAME_TO_HANDLE_METHOD),
44
44
  ...LIFECYCLE_KEYS
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useClipboard } from "@ai-matrx/kit/clipboard";
4
+ import { toast as copyToast } from "../../host/notify.js";
3
5
  import { useEffect, useState } from "react";
4
6
  import { Loader2, Copy, RefreshCw, AlertTriangle } from "lucide-react";
5
7
  import { Button } from "@ai-matrx/design-system/controls";
@@ -10,6 +12,9 @@ import { ErrorAlchemyMenu } from "../../host/ui-slots.js";
10
12
  function PromptPreviewContent({
11
13
  conversationId
12
14
  }) {
15
+ const { copyText } = useClipboard({
16
+ notify: (message, kind) => kind === "error" ? copyToast.error(message) : copyToast.success(message)
17
+ });
13
18
  const store = useAppStore();
14
19
  const [loading, setLoading] = useState(false);
15
20
  const [error, setError] = useState(null);
@@ -39,7 +44,7 @@ function PromptPreviewContent({
39
44
  }, [conversationId, store, nonce]);
40
45
  const copy = async (label, text) => {
41
46
  try {
42
- await navigator.clipboard.writeText(text);
47
+ await copyText(text);
43
48
  toast.success(`${label} copied`);
44
49
  } catch {
45
50
  toast.error("Couldn't copy");
@@ -43,7 +43,7 @@ async function bustAgentCache(baseUrl, agentId, headers) {
43
43
  keepalive: true
44
44
  });
45
45
  } catch (err) {
46
- if (true) {
46
+ if (process.env.NODE_ENV !== "production") {
47
47
  console.warn(`[agent cache-bust] ${agentId} \u2192`, err);
48
48
  }
49
49
  }
@@ -28,6 +28,7 @@ const VARIABLE_COMPONENT_KNOWN_KEYS = [
28
28
  "min",
29
29
  "max",
30
30
  "step",
31
+ "pick_list",
31
32
  "structured_list",
32
33
  "picklist",
33
34
  "assignment",
@@ -201,6 +202,10 @@ function parseVariableCustomComponent(value, path) {
201
202
  const min = parseOptionalNumber(value.min, `${path}.min`);
202
203
  const max = parseOptionalNumber(value.max, `${path}.max`);
203
204
  const step = parseOptionalNumber(value.step, `${path}.step`);
205
+ const pickList = parseStructuredListBinding(
206
+ value.pick_list,
207
+ `${path}.pick_list`
208
+ );
204
209
  const structuredList = parseStructuredListBinding(
205
210
  value.structured_list,
206
211
  `${path}.structured_list`
@@ -224,6 +229,7 @@ function parseVariableCustomComponent(value, path) {
224
229
  if (min !== void 0) parsed.min = min;
225
230
  if (max !== void 0) parsed.max = max;
226
231
  if (step !== void 0) parsed.step = step;
232
+ if (pickList !== void 0) parsed.pick_list = pickList;
227
233
  if (structuredList !== void 0) parsed.structured_list = structuredList;
228
234
  if (picklist !== void 0) parsed.picklist = picklist;
229
235
  if (assignment !== void 0) parsed.assignment = assignment;
@@ -708,7 +708,7 @@ const fetchUnifiedMenu = createAsyncThunk(
708
708
  const categoryDefs = [];
709
709
  const shortcutDefs = [];
710
710
  const contentBlockDefs = [];
711
- if (true) {
711
+ if (process.env.NODE_ENV !== "production") {
712
712
  const placementSummary = (payload.data ?? []).map((p) => ({
713
713
  placement_type: p.placement_type,
714
714
  categories: (p.categories_flat ?? []).length,
@@ -1,5 +1,4 @@
1
- import { normalize } from "../../../../host/ui-slots.js";
2
- import { toMediaRef } from "../../../../host/ui-slots.js";
1
+ import { normalize, toMediaRef } from "@ai-matrx/media/files/engine";
3
2
  const MEDIA_BLOCK_TYPES = /* @__PURE__ */ new Set([
4
3
  "image",
5
4
  "audio",
@@ -532,7 +532,7 @@ const executeManualInstance = createAsyncThunk(
532
532
  })
533
533
  );
534
534
  }
535
- if (true) {
535
+ if (process.env.NODE_ENV !== "production") {
536
536
  if (/\/ai\/agents\//.test(url) || /\/ai\/conversations\//.test(url)) {
537
537
  throw new Error(
538
538
  `[ManualExec] Forbidden URL "${url}". The manual execution path must NEVER hit /ai/agents/* or /ai/conversations/* (those do server-side definition lookup + caching). Use /ai/manual or a deliberate route override via manualEndpointOverride / apiConfig.`
@@ -61,7 +61,7 @@ function invocationToManagedOptions(invocation) {
61
61
  return managed;
62
62
  }
63
63
  function warnUnsupported(invocation) {
64
- if (false) return;
64
+ if (process.env.NODE_ENV === "production") return;
65
65
  if (invocation.identity.conversationId) {
66
66
  console.warn(
67
67
  "[launchConversation] identity.conversationId is passed through to the execution thunk, but turn-2+ routing currently still goes through executeInstance's existing `selectHasMessages` branch. The explicit conversationId-in-invocation path lands in Phase 3."
@@ -104,9 +104,12 @@ export interface HeadlessAgentJsonOptions {
104
104
  *
105
105
  * A markdown agent asked for "json" fails with "produced no structured
106
106
  * JSON" even though it answered perfectly — which is the whole reason this
107
- * option exists rather than a second primitive.
107
+ * option exists rather than a second primitive. `"media"` — the run's
108
+ * finished media blocks are the product (an image/audio/video model answers
109
+ * with a media block, never text); `data` is the array of unified media
110
+ * blocks (`fileId`, `mimeType`, `width`, `height`, …).
108
111
  */
109
- expect?: "json" | "text";
112
+ expect?: "json" | "text" | "media";
110
113
  /** Let the extractor fuzzy-parse at finalize. Default true. */
111
114
  fuzzyOnFinalize?: boolean;
112
115
  /**
@@ -190,6 +193,8 @@ export interface HeadlessAgentJsonOptions {
190
193
  noJson?: string;
191
194
  /** `expect: "text"` run finished but produced no answer text. */
192
195
  noText?: string;
196
+ /** `expect: "media"` run finished but produced no media. */
197
+ noMedia?: string;
193
198
  /** Ceiling elapsed. */
194
199
  timeout?: string;
195
200
  };
@@ -302,7 +307,7 @@ export interface AdoptedAgentJsonOptions {
302
307
  /** Bounded settle window after a terminal stream state. Default 6s. */
303
308
  settleMs?: number;
304
309
  /** See `expect` on `HeadlessAgentJsonOptions`. Default "json". */
305
- expect?: "json" | "text";
310
+ expect?: "json" | "text" | "media";
306
311
  /**
307
312
  * Keep the conversation/instance alive after the run. Default false — the
308
313
  * instance is destroyed on settle, matching the launched path. A caller
@@ -9,7 +9,8 @@ import {
9
9
  selectFirstExtractedObject,
10
10
  selectJsonExtractionComplete,
11
11
  selectRequestError,
12
- selectRequestStatus
12
+ selectRequestStatus,
13
+ selectRenderBlocksByType
13
14
  } from "../active-requests/active-requests.selectors.js";
14
15
  import {
15
16
  selectLatestAnswerText,
@@ -47,10 +48,22 @@ const DEFAULT_MESSAGES = {
47
48
  streamError: "The agent failed before returning a result.",
48
49
  noJson: "The agent finished but produced no structured JSON.",
49
50
  noText: "The agent finished but produced no text.",
51
+ noMedia: "The agent finished but produced no image, audio or video.",
50
52
  timeout: "The AI response timed out. If you switched browser tabs during this process, the connection may have been suspended \u2014 keep this tab active and try again."
51
53
  };
52
54
  const TERMINAL_STATUSES = /* @__PURE__ */ new Set(["complete", "error", "timeout", "cancelled"]);
53
55
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
56
+ const MEDIA_BLOCK_TYPES = ["image_output", "audio_output", "video_output"];
57
+ function completedMediaOf(getState, requestId) {
58
+ const state = getState();
59
+ const out = [];
60
+ for (const type of MEDIA_BLOCK_TYPES) {
61
+ for (const block of selectRenderBlocksByType(requestId, type)(state) ?? []) {
62
+ if (block.status === "complete" && block.data) out.push(block.data);
63
+ }
64
+ }
65
+ return out;
66
+ }
54
67
  function screamFlattening(verdict, ctx) {
55
68
  console.error(verdict.message);
56
69
  captureError({
@@ -99,7 +112,7 @@ async function deliverResult(seam, result) {
99
112
  }
100
113
  }
101
114
  async function failWarnedOutputMissingKeys(getState, opts, result) {
102
- if (!opts.mandateKey || (opts.expect ?? "json") === "text") return result;
115
+ if (!opts.mandateKey || (opts.expect ?? "json") !== "json") return result;
103
116
  const mandateKey = opts.mandateKey;
104
117
  const data = result.data;
105
118
  const isRecord = typeof data === "object" && data !== null && !Array.isArray(data);
@@ -414,7 +427,7 @@ function reportNoResult(getState, args) {
414
427
  }
415
428
  async function waitForExtraction(dispatch, getState, args) {
416
429
  const { conversationId, requestId, msgs } = args;
417
- const noResultMsg = args.expect === "text" ? msgs.noText : msgs.noJson;
430
+ const noResultMsg = args.expect === "text" ? msgs.noText : args.expect === "media" ? msgs.noMedia : msgs.noJson;
418
431
  const start = Date.now();
419
432
  let terminalAt = null;
420
433
  const viewerId = `runHeadlessAgentJson:${args.surfaceKey}:${requestId}`;
@@ -425,6 +438,23 @@ async function waitForExtraction(dispatch, getState, args) {
425
438
  fullResponse: selectLatestAnswerText(conversationId)(getState())
426
439
  });
427
440
  const settle = (reason, message) => {
441
+ if (args.expect === "media") {
442
+ const b = base();
443
+ const media = completedMediaOf(getState, requestId);
444
+ if (media.length > 0) return { success: true, data: media, ...b };
445
+ if (reason === "aborted") return { success: false, data: null, error: message, ...b };
446
+ if (!args.deferNoJsonCapture || reason === "timeout") {
447
+ reportNoResult(getState, {
448
+ requestId,
449
+ conversationId,
450
+ surfaceKey: args.surfaceKey,
451
+ agentRef: args.agentRef,
452
+ reason,
453
+ message
454
+ });
455
+ }
456
+ return { success: false, data: null, error: message, ...b };
457
+ }
428
458
  if (args.expect === "text") {
429
459
  const b = base();
430
460
  if (b.fullResponse.trim()) {
@@ -511,6 +541,9 @@ async function waitForExtraction(dispatch, getState, args) {
511
541
  return settle("extraction-complete", noResultMsg);
512
542
  }
513
543
  if (status !== void 0 && TERMINAL_STATUSES.has(status)) {
544
+ if (args.expect === "media" && completedMediaOf(getState, requestId).length > 0) {
545
+ return settle("stream-ended", noResultMsg);
546
+ }
514
547
  terminalAt ??= Date.now();
515
548
  if (Date.now() - terminalAt > args.settleMs) {
516
549
  return settle("stream-ended", noResultMsg);
@@ -2,7 +2,7 @@ function assertConversationIdMatches(localConversationId, incomingId, source) {
2
2
  if (!incomingId) return;
3
3
  if (incomingId === localConversationId) return;
4
4
  const message = `[conversation-id drift] server returned a different conversation id via ${source}. local=${localConversationId} incoming=${incomingId}. The server must honor the client-generated conversation id.`;
5
- if (true) {
5
+ if (process.env.NODE_ENV !== "production") {
6
6
  throw new Error(message);
7
7
  }
8
8
  console.error(message);
@@ -1,4 +1,4 @@
1
- import { ourFileUrlMarkers } from "../../../../host/ui-slots.js";
1
+ import { OUR_FILE_URL_MARKERS } from "@ai-matrx/media/files/engine";
2
2
  const Candidate = {
3
3
  NONE: 0,
4
4
  TEXT: 0,
@@ -34,7 +34,7 @@ function isStandaloneAudioLink(trimmed) {
34
34
  return false;
35
35
  }
36
36
  function mightBeOurFile(trimmed) {
37
- const markers = ourFileUrlMarkers();
37
+ const markers = OUR_FILE_URL_MARKERS;
38
38
  for (let mi = 0; mi < markers.length; mi++) {
39
39
  if (trimmed.includes(markers[mi])) return true;
40
40
  }
@@ -2,7 +2,7 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
2
2
  const launchRealtimeSession = createAsyncThunk("agents/runtime/launchRealtimeSession", async (opts) => {
3
3
  const { agentId, surfaceName } = opts;
4
4
  const instanceId = `realtime-${agentId}`;
5
- if (true) {
5
+ if (process.env.NODE_ENV !== "production") {
6
6
  console.debug(
7
7
  "[launchRealtimeSession] resolved",
8
8
  { agentId, surfaceName, instanceId }
@@ -16,8 +16,8 @@
16
16
  * `settings_catalog_profile`.
17
17
  *
18
18
  * Two target definitions over the same fields is a defect, not a coincidence:
19
- * the campaign's own precedent is `matrx-user/lists` / `matrx-user/list-manager`,
20
- * whose shared targets were lifted into `features/user-lists/`. So the CONTRACT
19
+ * the campaign's own precedent is `matrx-user/pick-lists` / `matrx-user/pick-list-manager`,
20
+ * whose shared targets were lifted into `features/data-tables/pick-lists/`. So the CONTRACT
21
21
  * — the accepted keys, the per-field bounds, the replace-vs-patch semantics,
22
22
  * and the model-facing prose that states them — is defined exactly once, here.
23
23
  *
@@ -26,7 +26,7 @@ export type VariableComponentType = (typeof VARIABLE_COMPONENT_TYPES)[number];
26
26
  * Binding of a variable to a Structured List (a Table of choices in the record store). When set, the
27
27
  * variable's options are hydrated at runtime from the list (labels only — the secret `description`
28
28
  * never reaches the client) and the emitted value is a ```matrx reference fence string
29
- * (`kind:"reference"`, `type:"structured_list_item"`), not text. Orthogonal to `type`, so a
29
+ * (`kind:"reference"`, `type:"pick_list_item"`), not text. Orthogonal to `type`, so a
30
30
  * structured-list-bound variable can render as select / radio / buttons / checkbox (a "picklist"
31
31
  * in the dropdown-projection sense).
32
32
  */
@@ -69,16 +69,18 @@ export interface VariableCustomComponent {
69
69
  unit?: string;
70
70
  /**
71
71
  * Structured-list binding. When present, options come from the bound Structured List and the
72
- * variable's value is a ```matrx reference fence string (one `structured_list_item` for
72
+ * variable's value is a ```matrx reference fence string (one `pick_list_item` for
73
73
  * single-select, N items + any "Other" lines for multi). Kept top-level (not stashable) so it
74
74
  * survives component-type switches.
75
75
  */
76
- structured_list?: StructuredListBinding;
76
+ pick_list?: StructuredListBinding;
77
77
  /**
78
- * @deprecated Legacy key — READ-ONLY. Historical agent definitions store the binding under
79
- * `picklist`; readers fall back to it via {@link readStructuredList}. New writes use
80
- * `structured_list` only. Do not emit this key.
78
+ * @deprecated Legacy keys — READ-ONLY. Historical agent definitions store the binding under
79
+ * `structured_list` or `picklist`; readers fall back to them via {@link readStructuredList}.
80
+ * New writes use `pick_list` only. Do not emit these keys.
81
81
  */
82
+ structured_list?: StructuredListBinding;
83
+ /** @deprecated Legacy key — READ-ONLY (see `structured_list`). */
82
84
  picklist?: StructuredListBinding;
83
85
  /** Automatic-assignment strategies explicitly enabled by the agent author. */
84
86
  assignment?: VariableAssignmentConfig;
@@ -21,8 +21,8 @@ export declare function readMax(cc: VariableCustomComponent | undefined): number
21
21
  export declare function readStep(cc: VariableCustomComponent | undefined): number;
22
22
  /**
23
23
  * The structured-list binding, if this variable is bound to a Structured List. Top-level only.
24
- * Reads the canonical `structured_list` key and falls back to the legacy `picklist` key
25
- * (read-only back-compat for historical agent definitions — new writes use `structured_list`).
24
+ * Reads the canonical `pick_list` key and falls back to the legacy `structured_list` and `picklist` keys
25
+ * (read-only back-compat for historical agent definitions — new writes use `pick_list`).
26
26
  */
27
27
  export declare function readStructuredList(cc: VariableCustomComponent | undefined): StructuredListBinding | undefined;
28
28
  export interface BuildCustomComponentInput {
@@ -48,7 +48,7 @@ function readStep(cc) {
48
48
  return cc?.step ?? cc?.stash?.step ?? 1;
49
49
  }
50
50
  function readStructuredList(cc) {
51
- return cc?.structured_list ?? cc?.picklist;
51
+ return cc?.pick_list ?? cc?.structured_list ?? cc?.picklist;
52
52
  }
53
53
  function buildCustomComponent(input) {
54
54
  const { type } = input;
@@ -81,7 +81,7 @@ function buildCustomComponent(input) {
81
81
  cc.stash = stash;
82
82
  }
83
83
  if (input.structuredList?.listId) {
84
- cc.structured_list = input.structuredList;
84
+ cc.pick_list = input.structuredList;
85
85
  }
86
86
  if (input.randomAssignment) {
87
87
  cc.assignment = { random: true };
@@ -89,7 +89,7 @@ function buildCustomComponent(input) {
89
89
  if (input.resourceContext && ((input.resourceContext.promote?.length ?? 0) > 0 || (input.resourceContext.exclude?.length ?? 0) > 0)) {
90
90
  cc.resource_context = input.resourceContext;
91
91
  }
92
- if (type === "textarea" && !cc.stash && !cc.structured_list && !cc.assignment && !cc.resource_context)
92
+ if (type === "textarea" && !cc.stash && !cc.pick_list && !cc.assignment && !cc.resource_context)
93
93
  return void 0;
94
94
  return cc;
95
95
  }
@@ -114,7 +114,7 @@ function normalizeCustomComponent(cc) {
114
114
  const { stash: _drop, ...rest } = next;
115
115
  next = rest;
116
116
  }
117
- if (next.type === "textarea" && !next.stash && !next.structured_list && !next.picklist && !next.assignment && !next.resource_context)
117
+ if (next.type === "textarea" && !next.stash && !next.pick_list && !next.structured_list && !next.picklist && !next.assignment && !next.resource_context)
118
118
  return void 0;
119
119
  return next;
120
120
  }
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { recognizeOurFileUrl } from "@ai-matrx/media/files/engine";
3
4
  import { useState, useEffect, useCallback } from "react";
4
5
  import {
5
6
  Volume2,
@@ -17,7 +18,6 @@ import { selectMessageHasUnsavedChanges } from "../../_legacy-stubs.js";
17
18
  import { editMessage } from "../../_legacy-stubs.js";
18
19
  import { buildContentBlocksForSave } from "../../utils/buildContentBlocksForSave.js";
19
20
  import { useMediaLoadRecovery } from "@ai-matrx/media/core";
20
- import { recognizeOurFileUrl } from "../../../host/ui-slots.js";
21
21
  import { chatConversationsActions } from "../../_legacy-stubs.js";
22
22
  import { RichDocumentActions } from "../../../host/rich-document-slots.js";
23
23
  import { MessageTimestamp } from "../../../agents/components/messages-display/MessageTimestamp.js";
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useFileUpload } from "@ai-matrx/media/files/engine/handler/hooks/useFileUpload";
3
4
  import {
4
5
  useState,
5
6
  useRef,
@@ -44,7 +45,6 @@ import { selectIsDebugMode } from "../../../host/prefs.js";
44
45
  import { openOverlay, CHAT_WINDOWS } from "../../../host/windows.js";
45
46
  import { ResourceChips } from "../../../agents/resources/ResourceChips.js";
46
47
  import { useClipboardPaste } from "../../../host/ui-slots.js";
47
- import { useFileUpload } from "../../../host/ui-slots.js";
48
48
  import { composeUploadFolderPath } from "@ai-matrx/media/files";
49
49
  import { RunControlsMenu } from "../../../agents/components/inputs/smart-input/RunControlsMenu.js";
50
50
  import { PlusAttachMenu } from "../../../agents/components/inputs/smart-input/PlusAttachMenu.js";
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { recognizeOurFileUrl } from "@ai-matrx/media/files/engine";
3
4
  import { useState, useEffect, useCallback } from "react";
4
5
  import {
5
6
  Volume2,
@@ -17,7 +18,6 @@ import { selectMessageHasUnsavedChanges } from "./_legacy-stubs.js";
17
18
  import { editMessage } from "./_legacy-stubs.js";
18
19
  import { buildContentBlocksForSave } from "./utils/buildContentBlocksForSave.js";
19
20
  import { useMediaLoadRecovery } from "@ai-matrx/media/core";
20
- import { recognizeOurFileUrl } from "../host/ui-slots.js";
21
21
  import { chatConversationsActions } from "./_legacy-stubs.js";
22
22
  import { RichDocumentActions } from "../host/rich-document-slots.js";
23
23
  import { MessageTimestamp } from "../agents/components/messages-display/MessageTimestamp.js";
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useFileUpload } from "@ai-matrx/media/files/engine/handler/hooks/useFileUpload";
3
4
  import {
4
5
  useState,
5
6
  useRef,
@@ -54,7 +55,6 @@ import { selectActiveChatAgent } from "./_legacy-stubs.js";
54
55
  import { selectIsDebugMode } from "../host/prefs.js";
55
56
  import { ResourceChips } from "../agents/resources/ResourceChips.js";
56
57
  import { ResourcePickerMenu } from "../host/ui-slots.js";
57
- import { useFileUpload } from "../host/ui-slots.js";
58
58
  import { composeUploadFolderPath } from "@ai-matrx/media/files";
59
59
  import { useRecordAndTranscribe } from "../host/ui-slots.js";
60
60
  import { TranscriptionLoader } from "../host/ui-slots.js";