heyhank 0.1.0 → 0.2.0

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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -10
  3. package/bin/cli.ts +7 -7
  4. package/bin/ctl.ts +42 -42
  5. package/dist/assets/{AgentsPage-BPhirnCe.js → AgentsPage-B-AAmsMK.js} +3 -3
  6. package/dist/assets/AssistantPage-BV1Mfwdt.js +2 -0
  7. package/dist/assets/BusinessPage-tLpNEz19.js +1 -0
  8. package/dist/assets/{CronManager-DDbz-yiT.js → CronManager-B-K_n3Jg.js} +1 -1
  9. package/dist/assets/HelpPage-Bhf_j6Xr.js +1 -0
  10. package/dist/assets/{IntegrationsPage-CrOitCmJ.js → IntegrationsPage-DAMjs9tM.js} +1 -1
  11. package/dist/assets/JarvisHUD-C_TGXCCn.js +120 -0
  12. package/dist/assets/MediaPage-C48HTTrt.js +1 -0
  13. package/dist/assets/MemoryPage-JkC-qtgp.js +1 -0
  14. package/dist/assets/{PlatformDashboard-Do6F0O2p.js → PlatformDashboard-AUo7tNnE.js} +1 -1
  15. package/dist/assets/{Playground-Fc5cdc5p.js → Playground-AzNMsRBL.js} +1 -1
  16. package/dist/assets/{ProcessPanel-CslEiZkI.js → ProcessPanel-DpE_2sX3.js} +1 -1
  17. package/dist/assets/{PromptsPage-D2EhsdNO.js → PromptsPage-C2RQOs6p.js} +2 -2
  18. package/dist/assets/RunsPage-B9UOyO79.js +1 -0
  19. package/dist/assets/{SandboxManager-a1AVI5q2.js → SandboxManager-jHvYjwfh.js} +1 -1
  20. package/dist/assets/SettingsPage-BBJax6gt.js +51 -0
  21. package/dist/assets/SkillsMarketplace-IjmjfdjD.js +1 -0
  22. package/dist/assets/SocialMediaPage-DoPZHhr2.js +10 -0
  23. package/dist/assets/{TailscalePage-CHiFhZXF.js → TailscalePage-DDEY7ckO.js} +1 -1
  24. package/dist/assets/TelephonyPage-OPNBZYKt.js +9 -0
  25. package/dist/assets/{TerminalPage-Drwyrnfd.js → TerminalPage-BjMbHHW3.js} +1 -1
  26. package/dist/assets/{gemini-live-client-C7rqAW7G.js → gemini-live-client-C70FEtX2.js} +11 -8
  27. package/dist/assets/{index-CEqZnThB.js → index-BgYM4wXw.js} +94 -93
  28. package/dist/assets/index-BkjSoVgn.css +32 -0
  29. package/dist/assets/sw-register-C7NOHtIu.js +1 -0
  30. package/dist/assets/text-chat-client-BSbLJerZ.js +2 -0
  31. package/dist/index.html +2 -2
  32. package/dist/sw.js +1 -1
  33. package/package.json +6 -1
  34. package/server/agent-executor.ts +37 -2
  35. package/server/agent-store.ts +3 -3
  36. package/server/agent-types.ts +11 -0
  37. package/server/assistant-store.ts +232 -6
  38. package/server/auth-manager.ts +9 -0
  39. package/server/cache-headers.ts +1 -1
  40. package/server/calendar-service.ts +10 -0
  41. package/server/ceo/document-store.ts +129 -0
  42. package/server/ceo/finance-store.ts +343 -0
  43. package/server/ceo/kpi-store.ts +208 -0
  44. package/server/ceo/memory-import.ts +277 -0
  45. package/server/ceo/news-store.ts +208 -0
  46. package/server/ceo/template-store.ts +134 -0
  47. package/server/ceo/time-tracking-store.ts +227 -0
  48. package/server/claude-auth-monitor.ts +128 -0
  49. package/server/claude-code-worker.ts +86 -0
  50. package/server/claude-session-discovery.ts +74 -1
  51. package/server/cli-launcher.ts +32 -10
  52. package/server/codex-adapter.ts +2 -2
  53. package/server/codex-ws-proxy.cjs +1 -1
  54. package/server/container-manager.ts +4 -4
  55. package/server/content-intelligence/content-engine.ts +1112 -0
  56. package/server/content-intelligence/platform-knowledge.ts +870 -0
  57. package/server/cron-store.ts +3 -3
  58. package/server/embedding-service.ts +49 -0
  59. package/server/event-bus-types.ts +13 -0
  60. package/server/federation/node-store.ts +5 -4
  61. package/server/fs-utils.ts +28 -1
  62. package/server/hank-notifications-store.ts +91 -0
  63. package/server/hank-tool-executor.ts +1835 -0
  64. package/server/hank-tools.ts +2107 -0
  65. package/server/image-pull-manager.ts +2 -2
  66. package/server/index.ts +25 -2
  67. package/server/llm-providers-streaming.ts +541 -0
  68. package/server/llm-providers.ts +12 -0
  69. package/server/marketplace.ts +249 -0
  70. package/server/mcp-registry.ts +158 -0
  71. package/server/memory-service.ts +296 -0
  72. package/server/obsidian-sync.ts +184 -0
  73. package/server/provider-manager.ts +5 -2
  74. package/server/provider-registry.ts +12 -0
  75. package/server/reminder-scheduler.ts +37 -1
  76. package/server/routes/agent-routes.ts +2 -1
  77. package/server/routes/assistant-routes.ts +198 -5
  78. package/server/routes/ceo-finance-kpi-routes.ts +167 -0
  79. package/server/routes/ceo-news-time-routes.ts +137 -0
  80. package/server/routes/ceo-routes.ts +99 -0
  81. package/server/routes/content-routes.ts +116 -0
  82. package/server/routes/email-routes.ts +147 -0
  83. package/server/routes/env-routes.ts +3 -3
  84. package/server/routes/fs-routes.ts +12 -9
  85. package/server/routes/hank-chat-routes.ts +592 -0
  86. package/server/routes/llm-routes.ts +12 -0
  87. package/server/routes/marketplace-routes.ts +63 -0
  88. package/server/routes/media-routes.ts +1 -1
  89. package/server/routes/memory-routes.ts +127 -0
  90. package/server/routes/platform-routes.ts +14 -675
  91. package/server/routes/sandbox-routes.ts +1 -1
  92. package/server/routes/settings-routes.ts +51 -1
  93. package/server/routes/socialmedia-routes.ts +152 -2
  94. package/server/routes/system-routes.ts +2 -2
  95. package/server/routes/team-routes.ts +71 -0
  96. package/server/routes/telephony-routes.ts +98 -18
  97. package/server/routes.ts +36 -9
  98. package/server/session-creation-service.ts +2 -2
  99. package/server/session-orchestrator.ts +54 -2
  100. package/server/session-types.ts +2 -0
  101. package/server/settings-manager.ts +50 -2
  102. package/server/skill-discovery.ts +68 -0
  103. package/server/socialmedia/adapters/browser-adapter.ts +179 -0
  104. package/server/socialmedia/adapters/postiz-adapter.ts +291 -14
  105. package/server/socialmedia/manager.ts +234 -15
  106. package/server/socialmedia/store.ts +51 -1
  107. package/server/socialmedia/types.ts +35 -2
  108. package/server/socialview/browser-manager.ts +150 -0
  109. package/server/socialview/extractors.ts +1298 -0
  110. package/server/socialview/image-describe.ts +188 -0
  111. package/server/socialview/library.ts +119 -0
  112. package/server/socialview/poster.ts +276 -0
  113. package/server/socialview/routes.ts +371 -0
  114. package/server/socialview/style-analyzer.ts +187 -0
  115. package/server/socialview/style-profiles.ts +67 -0
  116. package/server/socialview/types.ts +166 -0
  117. package/server/socialview/vision.ts +127 -0
  118. package/server/socialview/vnc-manager.ts +110 -0
  119. package/server/style-injector.ts +135 -0
  120. package/server/team-service.ts +239 -0
  121. package/server/team-store.ts +75 -0
  122. package/server/team-types.ts +52 -0
  123. package/server/telephony/audio-bridge.ts +281 -35
  124. package/server/telephony/audio-recorder.ts +132 -0
  125. package/server/telephony/call-manager.ts +803 -104
  126. package/server/telephony/call-types.ts +67 -1
  127. package/server/telephony/esl-client.ts +319 -0
  128. package/server/telephony/freeswitch-sync.ts +155 -0
  129. package/server/telephony/phone-utils.ts +63 -0
  130. package/server/telephony/telephony-store.ts +9 -8
  131. package/server/url-validator.ts +82 -0
  132. package/server/vault-markdown.ts +317 -0
  133. package/server/vault-migration.ts +121 -0
  134. package/server/vault-store.ts +466 -0
  135. package/server/vault-watcher.ts +59 -0
  136. package/server/vector-store.ts +210 -0
  137. package/server/voice-pipeline/gemini-live-adapter.ts +97 -0
  138. package/server/voice-pipeline/greeting-cache.ts +200 -0
  139. package/server/voice-pipeline/manager.ts +249 -0
  140. package/server/voice-pipeline/pipeline.ts +335 -0
  141. package/server/voice-pipeline/providers/index.ts +47 -0
  142. package/server/voice-pipeline/providers/llm-internal.ts +527 -0
  143. package/server/voice-pipeline/providers/stt-google.ts +157 -0
  144. package/server/voice-pipeline/providers/tts-google.ts +126 -0
  145. package/server/voice-pipeline/types.ts +247 -0
  146. package/server/ws-bridge-types.ts +6 -1
  147. package/dist/assets/AssistantPage-DJ-cMQfb.js +0 -1
  148. package/dist/assets/HelpPage-DMfkzERp.js +0 -1
  149. package/dist/assets/MediaPage-CE5rdvkC.js +0 -1
  150. package/dist/assets/RunsPage-C5BZF5Rx.js +0 -1
  151. package/dist/assets/SettingsPage-DirhjQrJ.js +0 -51
  152. package/dist/assets/SocialMediaPage-DBuM28vD.js +0 -1
  153. package/dist/assets/TelephonyPage-x0VV0fOo.js +0 -1
  154. package/dist/assets/index-C8M_PUmX.css +0 -32
  155. package/dist/assets/sw-register-LSSpj6RU.js +0 -1
  156. package/server/socialmedia/adapters/ayrshare-adapter.ts +0 -169
@@ -1 +1 @@
1
- import{r as l,b as i,j as e,u as d,n as N,a as y}from"./index-CEqZnThB.js";function w({embedded:x=!1}){const[t,r]=l.useState(null),[a,h]=l.useState(!0),[c,o]=l.useState(!1),[g,m]=l.useState(!1);l.useEffect(()=>{i.getTailscaleStatus().then(r).catch(()=>r(null)).finally(()=>h(!1))},[]);async function u(){const s=await i.getTailscaleStatus().catch(()=>null);s&&r(s)}async function p(){o(!0);try{const s=await i.startTailscaleFunnel();r(s),s.funnelUrl&&!s.error&&!s.warning&&d.getState().setPublicUrl(s.funnelUrl)}catch(s){await u(),r(n=>n?{...n,error:s instanceof Error?s.message:String(s)}:null)}finally{o(!1)}}async function b(){o(!0);try{const s=await i.stopTailscaleFunnel();r(s);const n=d.getState().publicUrl;(!n||n===(t==null?void 0:t.funnelUrl))&&d.getState().setPublicUrl("")}catch(s){await u(),r(n=>n?{...n,error:s instanceof Error?s.message:String(s)}:null)}finally{o(!1)}}function f(){t!=null&&t.funnelUrl&&navigator.clipboard.writeText(t.funnelUrl).then(()=>{m(!0),setTimeout(()=>m(!1),1800)}).catch(()=>{})}const j=t?t.installed?t.connected?t.funnelActive?"Funnel active":"Ready":"Not connected":"Not installed":"Loading...",v=t?!t.installed||!t.connected?"text-cc-muted":t.funnelActive?"text-cc-success":"text-amber-500":"text-cc-muted";return e.jsx("div",{className:`${x?"h-full":"h-[100dvh]"} bg-cc-bg text-cc-fg font-sans-ui antialiased overflow-y-auto`,children:e.jsxs("div",{className:"max-w-5xl mx-auto px-4 sm:px-8 py-6 sm:py-10 pb-safe",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold text-cc-fg",children:"Tailscale Settings"}),e.jsx("p",{className:"mt-1 text-sm text-cc-muted",children:"Expose HeyHank over HTTPS with Tailscale Funnel."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:()=>{window.location.hash="#/integrations"},className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:"Integrations"}),!x&&e.jsx("button",{onClick:()=>{const s=d.getState().currentSessionId;s?N(s):y()},className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:"Back"})]})]}),e.jsxs("section",{className:"relative overflow-hidden bg-cc-card border border-cc-border rounded-xl p-4 sm:p-6 mb-4",children:[e.jsx("div",{className:"absolute inset-0 pointer-events-none bg-[radial-gradient(circle_at_top_right,rgba(6,182,212,0.1),transparent_45%)]"}),e.jsxs("div",{className:"relative flex items-start justify-between gap-4 flex-wrap",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"inline-flex items-center gap-2 px-2.5 py-1 rounded-full border border-cc-border bg-cc-hover/60 text-xs text-cc-muted",children:[e.jsx("svg",{className:"w-3.5 h-3.5 text-cc-fg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"})}),e.jsx("span",{children:"Tailscale Integration"})]}),e.jsx("h2",{className:"mt-3 text-lg sm:text-xl font-semibold text-cc-fg",children:"HTTPS access in one click"}),e.jsx("p",{className:"mt-1.5 text-sm text-cc-muted max-w-2xl",children:"Tailscale Funnel exposes HeyHank to the internet over HTTPS with automatic TLS certificates. No configuration needed."}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2 text-[11px]",children:[e.jsx("span",{className:"px-2 py-1 rounded-md bg-cc-hover text-cc-muted",children:"Automatic TLS"}),e.jsx("span",{className:"px-2 py-1 rounded-md bg-cc-hover text-cc-muted",children:"Stable *.ts.net domain"}),e.jsx("span",{className:"px-2 py-1 rounded-md bg-cc-hover text-cc-muted",children:"No API keys needed"})]})]}),e.jsxs("div",{className:"shrink-0 rounded-xl border border-cc-border bg-cc-bg px-3 py-2 text-right min-w-[170px]",children:[e.jsx("p",{className:"text-[11px] text-cc-muted uppercase tracking-wide",children:"Status"}),e.jsx("p",{className:`mt-1 text-sm font-medium ${v}`,children:j}),e.jsx("p",{className:"mt-0.5 text-[11px] text-cc-muted truncate",children:(t==null?void 0:t.dnsName)||"No machine name"})]})]})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4 sm:p-5 space-y-4",children:[e.jsxs("h2",{className:"text-sm font-semibold text-cc-fg flex items-center gap-2",children:[e.jsx("svg",{className:"w-4 h-4 text-cc-fg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"})}),e.jsx("span",{children:"Tailscale Funnel"})]}),a&&e.jsx("p",{className:"text-sm text-cc-muted",children:"Checking Tailscale status..."}),!a&&!t&&e.jsx("p",{className:"text-sm text-cc-muted",children:"Could not check Tailscale status."}),!a&&t&&!t.installed&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-cc-muted",children:"Tailscale is not installed on this machine. Install it to enable one-click HTTPS."}),e.jsxs("a",{href:"https://tailscale.com/download",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors",children:["Install Tailscale",e.jsxs("svg",{className:"w-3.5 h-3.5",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"}),e.jsx("polyline",{points:"15 3 21 3 21 9"}),e.jsx("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})]})]}),!a&&t&&t.installed&&!t.connected&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-cc-muted",children:"Tailscale is installed but not connected to a tailnet."}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-hover text-xs text-cc-fg font-mono-code",children:"tailscale up"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"Run this command to connect to your Tailscale network."})]}),!a&&t&&t.installed&&t.connected&&!t.funnelActive&&e.jsxs("div",{className:"space-y-3",children:[e.jsxs("p",{className:"text-sm text-cc-muted",children:["Tailscale is connected as ",e.jsx("span",{className:"font-medium text-cc-fg",children:t.dnsName}),". Enable Funnel to expose HeyHank over HTTPS."]}),t.needsOperatorMode&&!t.error&&e.jsxs("div",{className:"space-y-2 px-3 py-3 rounded-lg bg-amber-500/10 border border-amber-500/20",children:[e.jsx("p",{className:"text-xs text-amber-500 font-medium",children:"Setup needed: Tailscale operator mode"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"On Linux, Tailscale requires operator mode to manage Funnel. Run this command first:"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-hover text-xs text-cc-fg font-mono-code",children:"sudo tailscale set --operator=$USER"})]}),e.jsx("button",{type:"button",onClick:p,disabled:c,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${c?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:c?"Starting...":"Enable HTTPS via Tailscale Funnel"})]}),!a&&t&&t.installed&&t.connected&&t.funnelActive&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-cc-muted",children:"Funnel is active. Your HeyHank is accessible at:"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("a",{href:t.funnelUrl||"#",target:"_blank",rel:"noopener noreferrer",className:"flex-1 px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg border border-cc-border text-cc-primary font-mono-code truncate flex items-center hover:underline",children:t.funnelUrl}),e.jsx("button",{type:"button",onClick:f,className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors cursor-pointer",children:g?"Copied!":"Copy"})]}),e.jsx("p",{className:"text-xs text-cc-muted",children:"This URL has been automatically set as your Public URL in Settings."}),e.jsx("button",{type:"button",onClick:b,disabled:c,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${c?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-error/10 hover:bg-cc-error/20 text-cc-error cursor-pointer"}`,children:c?"Stopping...":"Disable Funnel"})]}),(t==null?void 0:t.error)&&t.needsOperatorMode&&e.jsxs("div",{className:"space-y-3 px-3 py-3 rounded-lg bg-amber-500/10 border border-amber-500/20",children:[e.jsx("p",{className:"text-sm font-medium text-amber-500",children:"Operator mode required"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"On Linux, Tailscale requires operator mode to manage Funnel without sudo. Run this command once in your terminal:"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-hover text-xs text-cc-fg font-mono-code",children:"sudo tailscale set --operator=$USER"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"After running the command, click Retry to enable Funnel."}),e.jsx("button",{type:"button",onClick:p,disabled:c,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${c?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:c?"Retrying...":"Retry"})]}),(t==null?void 0:t.warning)&&e.jsxs("div",{className:"space-y-2 px-3 py-3 rounded-lg bg-amber-500/10 border border-amber-500/20",children:[e.jsx("p",{className:"text-sm font-medium text-amber-500",children:"URL may not be publicly accessible"}),e.jsx("p",{className:"text-xs text-cc-muted",children:t.warning}),e.jsxs("a",{href:"https://login.tailscale.com/admin/acls",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 text-xs text-cc-primary hover:underline",children:["Open Tailscale admin console",e.jsxs("svg",{className:"w-3 h-3",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"}),e.jsx("polyline",{points:"15 3 21 3 21 9"}),e.jsx("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})]})]}),(t==null?void 0:t.error)&&!t.needsOperatorMode&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 border border-cc-error/20 text-xs text-cc-error",children:t.error})]}),e.jsxs("section",{className:"mt-4 grid grid-cols-1 md:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-wide text-cc-muted",children:"1. Install"}),e.jsx("p",{className:"mt-1 text-sm text-cc-fg",children:"Install Tailscale on your machine and sign in."})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-wide text-cc-muted",children:"2. Enable"}),e.jsx("p",{className:"mt-1 text-sm text-cc-fg",children:"One click to get an HTTPS URL with automatic TLS."})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-wide text-cc-muted",children:"3. Done"}),e.jsx("p",{className:"mt-1 text-sm text-cc-fg",children:"Webhooks and remote access just work."})]})]})]})})}export{w as TailscalePage};
1
+ import{r as l,b as i,j as e,u as d,n as N,a as y}from"./index-BgYM4wXw.js";function w({embedded:x=!1}){const[t,r]=l.useState(null),[a,h]=l.useState(!0),[c,o]=l.useState(!1),[g,m]=l.useState(!1);l.useEffect(()=>{i.getTailscaleStatus().then(r).catch(()=>r(null)).finally(()=>h(!1))},[]);async function u(){const s=await i.getTailscaleStatus().catch(()=>null);s&&r(s)}async function p(){o(!0);try{const s=await i.startTailscaleFunnel();r(s),s.funnelUrl&&!s.error&&!s.warning&&d.getState().setPublicUrl(s.funnelUrl)}catch(s){await u(),r(n=>n?{...n,error:s instanceof Error?s.message:String(s)}:null)}finally{o(!1)}}async function b(){o(!0);try{const s=await i.stopTailscaleFunnel();r(s);const n=d.getState().publicUrl;(!n||n===(t==null?void 0:t.funnelUrl))&&d.getState().setPublicUrl("")}catch(s){await u(),r(n=>n?{...n,error:s instanceof Error?s.message:String(s)}:null)}finally{o(!1)}}function f(){t!=null&&t.funnelUrl&&navigator.clipboard.writeText(t.funnelUrl).then(()=>{m(!0),setTimeout(()=>m(!1),1800)}).catch(()=>{})}const j=t?t.installed?t.connected?t.funnelActive?"Funnel active":"Ready":"Not connected":"Not installed":"Loading...",v=t?!t.installed||!t.connected?"text-cc-muted":t.funnelActive?"text-cc-success":"text-amber-500":"text-cc-muted";return e.jsx("div",{className:`${x?"h-full":"h-[100dvh]"} bg-cc-bg text-cc-fg font-sans-ui antialiased overflow-y-auto`,children:e.jsxs("div",{className:"max-w-5xl mx-auto px-4 sm:px-8 py-6 sm:py-10 pb-safe",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold text-cc-fg",children:"Tailscale Settings"}),e.jsx("p",{className:"mt-1 text-sm text-cc-muted",children:"Expose HeyHank over HTTPS with Tailscale Funnel."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:()=>{window.location.hash="#/integrations"},className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:"Integrations"}),!x&&e.jsx("button",{onClick:()=>{const s=d.getState().currentSessionId;s?N(s):y()},className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:"Back"})]})]}),e.jsxs("section",{className:"relative overflow-hidden bg-cc-card border border-cc-border rounded-xl p-4 sm:p-6 mb-4",children:[e.jsx("div",{className:"absolute inset-0 pointer-events-none bg-[radial-gradient(circle_at_top_right,rgba(6,182,212,0.1),transparent_45%)]"}),e.jsxs("div",{className:"relative flex items-start justify-between gap-4 flex-wrap",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"inline-flex items-center gap-2 px-2.5 py-1 rounded-full border border-cc-border bg-cc-hover/60 text-xs text-cc-muted",children:[e.jsx("svg",{className:"w-3.5 h-3.5 text-cc-fg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"})}),e.jsx("span",{children:"Tailscale Integration"})]}),e.jsx("h2",{className:"mt-3 text-lg sm:text-xl font-semibold text-cc-fg",children:"HTTPS access in one click"}),e.jsx("p",{className:"mt-1.5 text-sm text-cc-muted max-w-2xl",children:"Tailscale Funnel exposes HeyHank to the internet over HTTPS with automatic TLS certificates. No configuration needed."}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2 text-[11px]",children:[e.jsx("span",{className:"px-2 py-1 rounded-md bg-cc-hover text-cc-muted",children:"Automatic TLS"}),e.jsx("span",{className:"px-2 py-1 rounded-md bg-cc-hover text-cc-muted",children:"Stable *.ts.net domain"}),e.jsx("span",{className:"px-2 py-1 rounded-md bg-cc-hover text-cc-muted",children:"No API keys needed"})]})]}),e.jsxs("div",{className:"shrink-0 rounded-xl border border-cc-border bg-cc-bg px-3 py-2 text-right min-w-[170px]",children:[e.jsx("p",{className:"text-[11px] text-cc-muted uppercase tracking-wide",children:"Status"}),e.jsx("p",{className:`mt-1 text-sm font-medium ${v}`,children:j}),e.jsx("p",{className:"mt-0.5 text-[11px] text-cc-muted truncate",children:(t==null?void 0:t.dnsName)||"No machine name"})]})]})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4 sm:p-5 space-y-4",children:[e.jsxs("h2",{className:"text-sm font-semibold text-cc-fg flex items-center gap-2",children:[e.jsx("svg",{className:"w-4 h-4 text-cc-fg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"})}),e.jsx("span",{children:"Tailscale Funnel"})]}),a&&e.jsx("p",{className:"text-sm text-cc-muted",children:"Checking Tailscale status..."}),!a&&!t&&e.jsx("p",{className:"text-sm text-cc-muted",children:"Could not check Tailscale status."}),!a&&t&&!t.installed&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-cc-muted",children:"Tailscale is not installed on this machine. Install it to enable one-click HTTPS."}),e.jsxs("a",{href:"https://tailscale.com/download",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors",children:["Install Tailscale",e.jsxs("svg",{className:"w-3.5 h-3.5",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"}),e.jsx("polyline",{points:"15 3 21 3 21 9"}),e.jsx("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})]})]}),!a&&t&&t.installed&&!t.connected&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-cc-muted",children:"Tailscale is installed but not connected to a tailnet."}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-hover text-xs text-cc-fg font-mono-code",children:"tailscale up"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"Run this command to connect to your Tailscale network."})]}),!a&&t&&t.installed&&t.connected&&!t.funnelActive&&e.jsxs("div",{className:"space-y-3",children:[e.jsxs("p",{className:"text-sm text-cc-muted",children:["Tailscale is connected as ",e.jsx("span",{className:"font-medium text-cc-fg",children:t.dnsName}),". Enable Funnel to expose HeyHank over HTTPS."]}),t.needsOperatorMode&&!t.error&&e.jsxs("div",{className:"space-y-2 px-3 py-3 rounded-lg bg-amber-500/10 border border-amber-500/20",children:[e.jsx("p",{className:"text-xs text-amber-500 font-medium",children:"Setup needed: Tailscale operator mode"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"On Linux, Tailscale requires operator mode to manage Funnel. Run this command first:"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-hover text-xs text-cc-fg font-mono-code",children:"sudo tailscale set --operator=$USER"})]}),e.jsx("button",{type:"button",onClick:p,disabled:c,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${c?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:c?"Starting...":"Enable HTTPS via Tailscale Funnel"})]}),!a&&t&&t.installed&&t.connected&&t.funnelActive&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-sm text-cc-muted",children:"Funnel is active. Your HeyHank is accessible at:"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("a",{href:t.funnelUrl||"#",target:"_blank",rel:"noopener noreferrer",className:"flex-1 px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg border border-cc-border text-cc-primary font-mono-code truncate flex items-center hover:underline",children:t.funnelUrl}),e.jsx("button",{type:"button",onClick:f,className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors cursor-pointer",children:g?"Copied!":"Copy"})]}),e.jsx("p",{className:"text-xs text-cc-muted",children:"This URL has been automatically set as your Public URL in Settings."}),e.jsx("button",{type:"button",onClick:b,disabled:c,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${c?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-error/10 hover:bg-cc-error/20 text-cc-error cursor-pointer"}`,children:c?"Stopping...":"Disable Funnel"})]}),(t==null?void 0:t.error)&&t.needsOperatorMode&&e.jsxs("div",{className:"space-y-3 px-3 py-3 rounded-lg bg-amber-500/10 border border-amber-500/20",children:[e.jsx("p",{className:"text-sm font-medium text-amber-500",children:"Operator mode required"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"On Linux, Tailscale requires operator mode to manage Funnel without sudo. Run this command once in your terminal:"}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-hover text-xs text-cc-fg font-mono-code",children:"sudo tailscale set --operator=$USER"}),e.jsx("p",{className:"text-xs text-cc-muted",children:"After running the command, click Retry to enable Funnel."}),e.jsx("button",{type:"button",onClick:p,disabled:c,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${c?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:c?"Retrying...":"Retry"})]}),(t==null?void 0:t.warning)&&e.jsxs("div",{className:"space-y-2 px-3 py-3 rounded-lg bg-amber-500/10 border border-amber-500/20",children:[e.jsx("p",{className:"text-sm font-medium text-amber-500",children:"URL may not be publicly accessible"}),e.jsx("p",{className:"text-xs text-cc-muted",children:t.warning}),e.jsxs("a",{href:"https://login.tailscale.com/admin/acls",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 text-xs text-cc-primary hover:underline",children:["Open Tailscale admin console",e.jsxs("svg",{className:"w-3 h-3",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"}),e.jsx("polyline",{points:"15 3 21 3 21 9"}),e.jsx("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})]})]}),(t==null?void 0:t.error)&&!t.needsOperatorMode&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 border border-cc-error/20 text-xs text-cc-error",children:t.error})]}),e.jsxs("section",{className:"mt-4 grid grid-cols-1 md:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-wide text-cc-muted",children:"1. Install"}),e.jsx("p",{className:"mt-1 text-sm text-cc-fg",children:"Install Tailscale on your machine and sign in."})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-wide text-cc-muted",children:"2. Enable"}),e.jsx("p",{className:"mt-1 text-sm text-cc-fg",children:"One click to get an HTTPS URL with automatic TLS."})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-wide text-cc-muted",children:"3. Done"}),e.jsx("p",{className:"mt-1 text-sm text-cc-fg",children:"Webhooks and remote access just work."})]})]})]})})}export{w as TailscalePage};
@@ -0,0 +1,9 @@
1
+ import{r as l,b as x,j as e}from"./index-BgYM4wXw.js";const X=[{code:"en",label:"English",flag:"🇬🇧"},{code:"de",label:"Deutsch",flag:"🇩🇪"},{code:"fr",label:"Français",flag:"🇫🇷"},{code:"it",label:"Italiano",flag:"🇮🇹"},{code:"es",label:"Español",flag:"🇪🇸"},{code:"pt",label:"Português",flag:"🇵🇹"},{code:"nl",label:"Nederlands",flag:"🇳🇱"},{code:"pl",label:"Polski",flag:"🇵🇱"},{code:"cs",label:"Čeština",flag:"🇨🇿"},{code:"hu",label:"Magyar",flag:"🇭🇺"},{code:"ro",label:"Română",flag:"🇷🇴"},{code:"tr",label:"Türkçe",flag:"🇹🇷"},{code:"ru",label:"Русский",flag:"🇷🇺"},{code:"ja",label:"日本語",flag:"🇯🇵"},{code:"zh",label:"中文",flag:"🇨🇳"},{code:"ko",label:"한국어",flag:"🇰🇷"},{code:"ar",label:"العربية",flag:"🇸🇦"}];function Je({embedded:g}){var xe,pe,ue,he,me,ge,be,ve,fe,je,ye,Ne;const[b,f]=l.useState(""),[N,O]=l.useState(""),[_,ee]=l.useState(!1),[te,n]=l.useState(null),[z,Ce]=l.useState(50),[r,j]=l.useState(null),[P,E]=l.useState(!1),[U,se]=l.useState(!1),[ke,W]=l.useState(!1),[A,re]=l.useState(null),[F,ce]=l.useState(!1),[d,v]=l.useState({name:"peoplefone",provider:"peoplefone",username:"",password:"",server:"sip.peoplefone.at",callerId:"",enabled:!0}),[ae,Se]=l.useState([]),[q,Te]=l.useState([]),[u,J]=l.useState(null),[I,D]=l.useState([]),L=l.useRef(null),w=l.useRef(null),[G,C]=l.useState([]),[$,le]=l.useState(!1),[h,k]=l.useState({name:"",phone:"",notes:"",language:"en"}),[R,Z]=l.useState(null),[m,S]=l.useState({name:"",phone:"",notes:"",language:"en"}),[y,Q]=l.useState(null),[B,V]=l.useState("simple"),[H,M]=l.useState(""),[a,p]=l.useState(null),[ne,oe]=l.useState(!1);l.useEffect(()=>{K();const t=setInterval(K,5e3);return()=>clearInterval(t)},[z]),l.useEffect(()=>{x.getContacts().then(t=>C(t.contacts)).catch(t=>{n(t instanceof Error?t.message:"Failed to load contacts"),setTimeout(()=>n(null),5e3)}),x.getTelephonySettings().then(t=>j(t)).catch(t=>{n(t instanceof Error?t.message:"Failed to load settings"),setTimeout(()=>n(null),5e3)})},[]),l.useEffect(()=>{L.current&&(L.current.scrollTop=L.current.scrollHeight)},[I]);async function K(){try{const[t,s]=await Promise.all([x.getActiveCalls(),x.getCallHistory(z)]);Se(t.calls),Te(s.calls)}catch(t){n(t instanceof Error?t.message:"Failed to load call data"),setTimeout(()=>n(null),5e3)}}async function Pe(){if(!(!b.trim()||!N.trim()||_)){ee(!0),n(null);try{const t=await x.startCall({phone:b.trim(),prompt:N.trim()});t.error?n(t.error):(f(""),O(""),ie(t.id),K())}catch(t){n(t instanceof Error?t.message:"Failed to start call")}finally{ee(!1)}}}function ie(t){w.current&&w.current.close(),D([]);const s=window.location.protocol==="https:"?"wss:":"ws:",c=new WebSocket(`${s}//${window.location.host}/ws/telephony/transcript/${t}`);c.onmessage=o=>{try{const Y=JSON.parse(o.data);Y.type==="transcript"&&Y.entry&&D(ze=>[...ze,Y.entry])}catch{}},c.onclose=()=>{w.current=null},w.current=c}async function Ee(t){if(confirm("End this call?"))try{await x.endCall(t),K()}catch(s){n(s instanceof Error?s.message:"Failed to end call"),setTimeout(()=>n(null),5e3)}}async function Ae(){if(!(!h.name.trim()||!h.phone.trim()))try{const t=await x.addContact(h);C(s=>[...s,t]),k({name:"",phone:"",notes:"",language:"en"}),le(!1)}catch(t){n(t instanceof Error?t.message:"Failed to add contact"),setTimeout(()=>n(null),5e3)}}async function Fe(t){if(confirm("Remove this contact?"))try{await x.deleteContact(t),C(s=>s.filter(c=>c.id!==t))}catch(s){n(s instanceof Error?s.message:"Failed to remove contact"),setTimeout(()=>n(null),5e3)}}async function Ie(){if(R)try{const t=await x.updateContact(R,m);C(s=>s.map(c=>c.id===R?t:c)),Z(null)}catch(t){n(t instanceof Error?t.message:"Failed to save contact"),setTimeout(()=>n(null),5e3)}}function De(t){Q(t.id),t.callFlow&&t.callFlow.nodes.length>0?(V("flow"),p(t.callFlow),M(t.script||"")):(V("simple"),M(t.script||""),p(t.callFlow||null))}async function Le(){if(y){oe(!0);try{const t={};B==="simple"?(t.script=H.trim()||void 0,a&&(t.callFlow=a)):(t.callFlow=a,t.script=H.trim()||void 0);const s=await x.updateContact(y,t);C(c=>c.map(o=>o.id===y?{...o,...s}:o))}catch(t){n(t instanceof Error?t.message:"Failed to save script"),setTimeout(()=>n(null),5e3)}oe(!1),Q(null)}}function Ge(t){if(!a)return;const s=`node_${Date.now()}`,c=a.nodes.length,o={id:s,type:t,label:t==="start"?"Start":t==="end"?"End":`${t.charAt(0).toUpperCase()+t.slice(1)} ${c}`,prompt:"",position:{x:100,y:80+c*100}};p({...a,nodes:[...a.nodes,o]})}function T(t,s){a&&p({...a,nodes:a.nodes.map(c=>c.id===t?{...c,...s}:c)})}function $e(t){a&&confirm("Delete this flow node? Connected edges will also be removed.")&&p({...a,nodes:a.nodes.filter(s=>s.id!==t),edges:a.edges.filter(s=>s.from!==t&&s.to!==t)})}function Re(t,s,c){if(!a)return;const o=`edge_${Date.now()}`;p({...a,edges:[...a.edges,{id:o,from:t,to:s,label:""}]})}function Be(t){a&&confirm("Delete this flow edge?")&&p({...a,edges:a.edges.filter(s=>s.id!==t)})}function Ve(){const t=G.find(s=>s.id===y);p({id:`flow_${Date.now()}`,name:t!=null&&t.name?`${t.name} Script`:"Call Script",nodes:[{id:"start_1",type:"start",label:"Start",position:{x:100,y:50}},{id:"say_1",type:"say",label:"Greeting",prompt:"Greet the person naturally",position:{x:100,y:150}},{id:"ask_1",type:"ask",label:"Main Question",prompt:"",expectedResponses:["yes","no"],position:{x:100,y:250}},{id:"end_1",type:"end",label:"Goodbye",prompt:"Thank them and say goodbye",position:{x:100,y:350}}],edges:[{id:"e1",from:"start_1",to:"say_1",label:"begin"},{id:"e2",from:"say_1",to:"ask_1",label:"then"},{id:"e3",from:"ask_1",to:"end_1",label:"default"}]})}async function He(t){E(!0);try{await x.updateTelephonySettings(t);const s=await x.getTelephonySettings();j(s)}catch(s){n(s instanceof Error?s.message:"Failed to save settings"),setTimeout(()=>n(null),5e3)}E(!1)}function i(t){j(s=>s&&{...s,...t}),se(!0),W(!1)}async function Me(){if(r){E(!0);try{await x.updateTelephonySettings({freeswitch:r.freeswitch,defaultVoice:r.defaultVoice,maxCallDurationSeconds:r.maxCallDurationSeconds,geminiBackend:r.geminiBackend,gcpProjectId:r.gcpProjectId,gcpLocation:r.gcpLocation,gcpServiceAccountKey:r.gcpServiceAccountKey,...r.defaultLanguage&&{defaultLanguage:r.defaultLanguage},...r.inboundEnabled!==void 0&&{inboundEnabled:r.inboundEnabled},...r.defaultInboundPrompt&&{defaultInboundPrompt:r.defaultInboundPrompt},...r.defaultInboundVoice&&{defaultInboundVoice:r.defaultInboundVoice},...r.inboundKnowledgeBase!==void 0&&{inboundKnowledgeBase:r.inboundKnowledgeBase},...r.voicePipeline!==void 0&&{voicePipeline:r.voicePipeline}});const t=await x.getTelephonySettings();j(t),se(!1),W(!0),setTimeout(()=>W(!1),3e3)}catch(t){n(t instanceof Error?t.message:"Failed to save settings"),setTimeout(()=>n(null),5e3)}E(!1)}}async function Ke(){re(null);const t=await x.testFreeSwitchConnection();re(t)}async function Oe(){if(!(!d.username||!d.password||!d.server))try{await fetch("/api/telephony/trunks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});const t=await x.getTelephonySettings();j(t),ce(!1),v({name:"peoplefone",provider:"peoplefone",username:"",password:"",server:"sip.peoplefone.at",callerId:"",enabled:!0})}catch(t){n(t instanceof Error?t.message:"Failed to add trunk"),setTimeout(()=>n(null),5e3)}}async function _e(t){if(confirm("Remove this SIP trunk? Inbound calls via this trunk will stop working."))try{await fetch(`/api/telephony/trunks/${encodeURIComponent(t)}`,{method:"DELETE"});const s=await x.getTelephonySettings();j(s)}catch(s){n(s instanceof Error?s.message:"Failed to remove trunk"),setTimeout(()=>n(null),5e3)}}function de(t){J(t),t.status==="active"||t.status==="dialing"||t.status==="ringing"?ie(t.id):x.getCall(t.id).then(s=>{J({...t,...s}),D(s.transcript||[])}).catch(s=>{n(s instanceof Error?s.message:"Failed to load call details"),setTimeout(()=>n(null),5e3)})}return r===null?e.jsx("div",{className:"h-full flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"w-6 h-6 border-2 border-cc-muted/30 border-t-cc-primary rounded-full animate-spin mx-auto mb-3"}),e.jsx("p",{className:"text-sm text-cc-muted",children:"Loading..."})]})}):e.jsxs("div",{className:"h-full overflow-y-auto bg-cc-bg",children:[te&&e.jsx("div",{className:"fixed top-4 left-1/2 -translate-x-1/2 z-50 px-4 py-2.5 rounded-lg bg-red-600 text-white text-sm shadow-lg max-w-md",role:"alert",children:te}),e.jsxs("div",{className:"max-w-4xl mx-auto px-4 sm:px-8 py-6 sm:py-10 pb-safe",children:[e.jsxs("div",{className:"mb-8",children:[e.jsx("h1",{className:"text-lg font-semibold text-cc-fg",children:"Telephony"}),e.jsx("p",{className:"text-xs text-cc-muted mt-1",children:"Make AI-powered phone calls via FreeSWITCH + Gemini Live."})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4 mb-6",children:[e.jsx("h2",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider mb-3",children:"New Call"}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{children:e.jsx("input",{type:"tel",value:b,onChange:t=>f(t.target.value),placeholder:"+43 664 1234567","aria-label":"Phone number to call",className:"w-full px-3 py-2 text-sm bg-cc-bg border border-cc-border rounded-lg text-cc-fg placeholder:text-cc-muted/60 focus:outline-none focus:border-cc-primary"})}),e.jsx("div",{children:e.jsx("textarea",{value:N,onChange:t=>O(t.target.value),placeholder:"Task for the AI (e.g. 'Reserve a table for 4 at 7pm on Friday')",rows:2,"aria-label":"Call prompt or task for the AI",className:"w-full px-3 py-2 text-sm bg-cc-bg border border-cc-border rounded-lg text-cc-fg placeholder:text-cc-muted/60 focus:outline-none focus:border-cc-primary resize-none"})}),e.jsx("button",{onClick:Pe,disabled:!b.trim()||!N.trim()||_,className:"px-4 py-2 rounded-lg text-xs font-medium bg-green-600 text-white hover:bg-green-500 transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",children:_?e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"w-3 h-3 border-2 border-white/30 border-t-white rounded-full animate-spin"}),"Dialing..."]}):e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(Ue,{className:"w-3.5 h-3.5"}),"Call"]})})]})]}),e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4 mb-6",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("h2",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"Contacts"}),e.jsx("button",{onClick:()=>le(!$),className:"text-xs text-cc-primary hover:text-cc-primary/80 transition-colors cursor-pointer",children:$?"Cancel":"+ Add"})]}),$&&e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 border border-cc-border space-y-2 mb-3",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Name"}),e.jsx("input",{type:"text",value:h.name,onChange:t=>k({...h,name:t.target.value}),placeholder:"e.g. Mama",className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Phone"}),e.jsx("input",{type:"tel",value:h.phone,onChange:t=>k({...h,phone:t.target.value}),placeholder:"+43...",className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]})]}),e.jsxs("div",{className:"grid grid-cols-[1fr_auto] gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Notes (optional)"}),e.jsx("input",{type:"text",value:h.notes,onChange:t=>k({...h,notes:t.target.value}),placeholder:"e.g. Mo-Sa 10-18 Uhr",className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Language"}),e.jsx("select",{value:h.language,onChange:t=>k({...h,language:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg w-28",children:X.map(t=>e.jsxs("option",{value:t.code,children:[t.flag," ",t.label]},t.code))})]})]}),e.jsx("button",{onClick:Ae,disabled:!h.name.trim()||!h.phone.trim(),className:"px-3 py-1.5 text-xs rounded bg-green-600 text-white hover:bg-green-500 transition-colors cursor-pointer disabled:opacity-50",children:"Add Contact"})]}),G.length===0&&!$?e.jsx("p",{className:"text-xs text-cc-muted",children:"No contacts yet. Add contacts so Gemini can call them by name."}):e.jsx("div",{className:"space-y-1.5",children:G.map(t=>{var s;return e.jsx("div",{className:"bg-cc-bg rounded-lg px-3 py-2 border border-cc-border",children:R===t.id?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsx("input",{type:"text",value:m.name,onChange:c=>S({...m,name:c.target.value}),className:"px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"}),e.jsx("input",{type:"tel",value:m.phone,onChange:c=>S({...m,phone:c.target.value}),className:"px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{className:"grid grid-cols-[1fr_auto] gap-2",children:[e.jsx("input",{type:"text",value:m.notes,onChange:c=>S({...m,notes:c.target.value}),placeholder:"Notes",className:"px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"}),e.jsx("select",{value:m.language,onChange:c=>S({...m,language:c.target.value}),className:"px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg w-28",children:X.map(c=>e.jsxs("option",{value:c.code,children:[c.flag," ",c.label]},c.code))})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:Ie,className:"px-2 py-1 text-[11px] rounded bg-green-600 text-white hover:bg-green-500 cursor-pointer",children:"Save"}),e.jsx("button",{onClick:()=>Z(null),className:"px-2 py-1 text-[11px] rounded bg-cc-hover text-cc-muted hover:text-cc-fg cursor-pointer",children:"Cancel"})]})]}):e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("button",{onClick:()=>{f(t.phone),!N.trim()&&t.script&&O(t.script)},className:"min-w-0 flex-1 text-left cursor-pointer hover:opacity-80",title:"Click to use this number",children:[e.jsx("p",{className:"text-xs font-medium text-cc-fg",children:t.name}),e.jsxs("p",{className:"text-[11px] text-cc-muted",children:[t.phone,t.language&&e.jsxs("span",{className:"ml-1",children:[" ",((s=X.find(c=>c.code===t.language))==null?void 0:s.flag)||""]}),t.notes?` — ${t.notes}`:"",(t.script||t.callFlow)&&e.jsx("span",{className:"ml-1.5 text-green-500 text-[9px]",children:"(script)"})]})]}),e.jsxs("div",{className:"flex items-center gap-1 ml-2 shrink-0",children:[e.jsx("button",{onClick:()=>De(t),className:`px-2 py-1.5 text-[11px] rounded transition-colors cursor-pointer ${t.script||t.callFlow?"text-green-500 hover:text-green-400 hover:bg-green-500/10":"text-cc-muted hover:text-cc-fg hover:bg-cc-hover"}`,title:t.script||t.callFlow?"Edit call script":"Add call script",children:t.script||t.callFlow?"Script":"+ Script"}),e.jsx("button",{onClick:()=>{Z(t.id),S({name:t.name,phone:t.phone,notes:t.notes||"",language:t.language||"en"})},className:"px-3 py-2 min-h-[44px] text-[11px] text-cc-muted hover:text-cc-fg hover:bg-cc-hover rounded transition-colors cursor-pointer",children:"Edit"}),e.jsx("button",{onClick:()=>Fe(t.id),"aria-label":`Remove contact ${t.name}`,className:"px-3 py-2 min-h-[44px] text-[11px] text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded transition-colors cursor-pointer",children:"Remove"})]})]})},t.id)})})]}),y&&e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-xl p-4 mb-6",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsxs("div",{children:[e.jsxs("h2",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:["Call Script — ",(xe=G.find(t=>t.id===y))==null?void 0:xe.name]}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Define what Gemini should say and how to handle responses during the call."})]}),e.jsx("div",{className:"flex items-center gap-2",children:e.jsxs("div",{className:"flex bg-cc-bg rounded-lg border border-cc-border overflow-hidden",children:[e.jsx("button",{onClick:()=>V("simple"),className:`px-2.5 py-1 text-[11px] transition-colors cursor-pointer ${B==="simple"?"bg-cc-primary text-white":"text-cc-muted hover:text-cc-fg"}`,children:"Simple"}),e.jsx("button",{onClick:()=>V("flow"),className:`px-2.5 py-1 text-[11px] transition-colors cursor-pointer ${B==="flow"?"bg-cc-primary text-white":"text-cc-muted hover:text-cc-fg"}`,children:"Flow Builder"})]})})]}),B==="simple"?e.jsxs("div",{className:"space-y-2",children:[e.jsx("textarea",{value:H,onChange:t=>M(t.target.value),placeholder:`Example script:
2
+
3
+ 1. Greet and introduce yourself
4
+ 2. Ask if they have a table for 4 on Friday at 7pm
5
+ 3. If yes: confirm and ask for name
6
+ 4. If no: ask about Saturday
7
+ 5. Thank them and say goodbye
8
+
9
+ IMPORTANT: Always be polite and speak German.`,rows:10,className:"w-full px-3 py-2 text-xs bg-cc-bg border border-cc-border rounded-lg text-cc-fg placeholder:text-cc-muted/60 focus:outline-none focus:border-cc-primary font-mono resize-y"}),e.jsx("p",{className:"text-[10px] text-cc-muted",children:"Write a simple call script in plain text or markdown. Gemini will follow this as a guide during the call."})]}):e.jsx("div",{className:"space-y-3",children:!a||a.nodes.length===0?e.jsxs("div",{className:"text-center py-8 space-y-3",children:[e.jsx("p",{className:"text-xs text-cc-muted",children:"No call flow defined yet."}),e.jsx("button",{onClick:Ve,className:"px-3 py-1.5 text-xs rounded bg-cc-primary text-white hover:bg-cc-primary/90 transition-colors cursor-pointer",children:"Create Template Flow"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-[10px] text-cc-muted",children:"Flow Name"}),e.jsx("input",{type:"text",value:a.name,onChange:t=>p({...a,name:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[10px] text-cc-muted",children:"Description"}),e.jsx("input",{type:"text",value:a.description||"",onChange:t=>p({...a,description:t.target.value}),placeholder:"e.g. Restaurant reservation flow",className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h3",{className:"text-[11px] font-medium text-cc-muted uppercase tracking-wider",children:"Nodes"}),e.jsx("div",{className:"flex gap-1",children:["say","ask","condition","action","end"].map(t=>e.jsxs("button",{onClick:()=>Ge(t),className:"px-1.5 py-0.5 text-[10px] rounded bg-cc-hover text-cc-muted hover:text-cc-fg transition-colors cursor-pointer",title:`Add ${t} node`,children:["+ ",t]},t))})]}),a.nodes.map((t,s)=>e.jsxs("div",{className:"bg-cc-bg rounded-lg px-3 py-2 border border-cc-border space-y-1.5",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`text-[10px] font-mono px-1.5 py-0.5 rounded ${t.type==="start"?"bg-green-500/20 text-green-400":t.type==="end"?"bg-red-500/20 text-red-400":t.type==="say"?"bg-blue-500/20 text-blue-400":t.type==="ask"?"bg-yellow-500/20 text-yellow-400":t.type==="condition"?"bg-purple-500/20 text-purple-400":"bg-orange-500/20 text-orange-400"}`,children:t.type}),e.jsx("input",{type:"text",value:t.label,onChange:c=>T(t.id,{label:c.target.value}),className:"px-1.5 py-0.5 text-xs bg-transparent border-b border-cc-border/50 text-cc-fg focus:outline-none focus:border-cc-primary w-40"})]}),t.type!=="start"&&e.jsx("button",{onClick:()=>$e(t.id),"aria-label":`Remove ${t.type} node ${t.label||""}`,className:"px-3 py-2 min-h-[44px] text-[10px] text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded cursor-pointer",children:"remove"})]}),(t.type==="say"||t.type==="ask"||t.type==="end")&&e.jsx("textarea",{value:t.prompt||"",onChange:c=>T(t.id,{prompt:c.target.value}),placeholder:t.type==="say"?"What should the AI say?":t.type==="ask"?"What question to ask?":"Goodbye message",rows:2,className:"w-full px-2 py-1 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg placeholder:text-cc-muted/60 focus:outline-none focus:border-cc-primary resize-none"}),t.type==="ask"&&e.jsxs("div",{children:[e.jsx("label",{className:"text-[10px] text-cc-muted",children:"Expected responses (comma-separated)"}),e.jsx("input",{type:"text",value:(t.expectedResponses||[]).join(", "),onChange:c=>T(t.id,{expectedResponses:c.target.value.split(",").map(o=>o.trim()).filter(Boolean)}),placeholder:"yes, no, maybe",className:"w-full px-2 py-1 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),t.type==="condition"&&e.jsxs("div",{children:[e.jsx("label",{className:"text-[10px] text-cc-muted",children:"Condition / Variable"}),e.jsx("input",{type:"text",value:t.conditionVariable||"",onChange:c=>T(t.id,{conditionVariable:c.target.value}),placeholder:"e.g. callee said yes",className:"w-full px-2 py-1 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),t.type==="action"&&e.jsxs("div",{children:[e.jsx("label",{className:"text-[10px] text-cc-muted",children:"Tool to call"}),e.jsx("input",{type:"text",value:t.actionTool||"",onChange:c=>T(t.id,{actionTool:c.target.value}),placeholder:"e.g. save_note, end_call",className:"w-full px-2 py-1 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg"})]})]},t.id))]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsx("h3",{className:"text-[11px] font-medium text-cc-muted uppercase tracking-wider",children:"Connections"})}),a.edges.map(t=>{const s=a.nodes.find(c=>c.id===t.from);return a.nodes.find(c=>c.id===t.to),e.jsxs("div",{className:"flex items-center gap-2 text-[11px]",children:[e.jsx("span",{className:"text-cc-fg",children:(s==null?void 0:s.label)||t.from}),e.jsx("span",{className:"text-cc-muted",children:"→"}),e.jsx("input",{type:"text",value:t.label||"",onChange:c=>{p({...a,edges:a.edges.map(o=>o.id===t.id?{...o,label:c.target.value}:o)})},placeholder:"condition",className:"w-20 px-1.5 py-0.5 text-[10px] bg-cc-hover border border-cc-border rounded text-cc-fg text-center"}),e.jsx("span",{className:"text-cc-muted",children:"→"}),e.jsx("select",{value:t.to,onChange:c=>{p({...a,edges:a.edges.map(o=>o.id===t.id?{...o,to:c.target.value}:o)})},className:"px-1.5 py-0.5 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg",children:a.nodes.map(c=>e.jsx("option",{value:c.id,children:c.label},c.id))}),e.jsx("button",{onClick:()=>Be(t.id),"aria-label":"Remove flow edge",className:"px-3 py-2 min-h-[44px] min-w-[44px] text-[10px] text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded cursor-pointer",children:"x"})]},t.id)}),a.nodes.length>=2&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("select",{id:"edge-from",className:"px-1.5 py-0.5 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg",children:a.nodes.map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))}),e.jsx("span",{className:"text-[11px] text-cc-muted",children:"→"}),e.jsx("select",{id:"edge-to",className:"px-1.5 py-0.5 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg",children:a.nodes.map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))}),e.jsx("button",{onClick:()=>{var c,o;const t=(c=document.getElementById("edge-from"))==null?void 0:c.value,s=(o=document.getElementById("edge-to"))==null?void 0:o.value;t&&s&&t!==s&&Re(t,s)},className:"px-1.5 py-0.5 text-[10px] rounded bg-cc-hover text-cc-muted hover:text-cc-fg cursor-pointer",children:"+ Connect"})]})]}),e.jsxs("details",{className:"group",children:[e.jsxs("summary",{className:"text-[11px] text-cc-muted cursor-pointer hover:text-cc-fg",children:["Template Variables (",Object.keys(a.variables||{}).length,")"]}),e.jsxs("div",{className:"mt-2 space-y-1",children:[Object.entries(a.variables||{}).map(([t,s])=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[11px] text-cc-muted font-mono",children:`{{${t}}}`}),e.jsx("input",{type:"text",value:s,onChange:c=>p({...a,variables:{...a.variables,[t]:c.target.value}}),className:"flex-1 px-2 py-0.5 text-[11px] bg-cc-hover border border-cc-border rounded text-cc-fg"}),e.jsx("button",{onClick:()=>{const c={...a.variables};delete c[t],p({...a,variables:c})},className:"text-[10px] text-red-400 cursor-pointer",children:"x"})]},t)),e.jsx("button",{onClick:()=>{const t=window.prompt("Variable name:");t&&p({...a,variables:{...a.variables,[t]:""}})},className:"text-[10px] text-cc-primary hover:text-cc-primary/80 cursor-pointer",children:"+ Add Variable"})]})]})]})}),e.jsxs("div",{className:"flex items-center justify-between mt-4 pt-3 border-t border-cc-border",children:[e.jsx("button",{onClick:()=>Q(null),className:"px-3 py-1.5 text-xs rounded bg-cc-hover text-cc-muted hover:text-cc-fg transition-colors cursor-pointer",children:"Cancel"}),e.jsxs("div",{className:"flex items-center gap-2",children:[(H||a&&a.nodes.length>0)&&e.jsx("button",{onClick:()=>{M(""),p(null)},className:"px-3 py-1.5 text-xs rounded text-red-400 hover:text-red-300 transition-colors cursor-pointer",children:"Clear Script"}),e.jsx("button",{onClick:Le,disabled:ne,className:"px-4 py-1.5 text-xs rounded bg-green-600 text-white hover:bg-green-500 transition-colors cursor-pointer disabled:opacity-50",children:ne?"Saving...":"Save Script"})]})]})]}),ae.length>0&&e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider mb-3",children:"Active Calls"}),e.jsx("div",{className:"space-y-2",children:ae.map(t=>e.jsxs("div",{className:"bg-cc-card border border-cc-border rounded-lg px-4 py-3 flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-2 h-2 rounded-full bg-green-500 animate-pulse"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-cc-fg",children:t.phone}),e.jsx("p",{className:"text-[11px] text-cc-muted truncate max-w-[200px]",children:t.prompt})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-[11px] text-cc-muted",children:t.status}),e.jsx("button",{onClick:()=>de(t),className:"text-xs text-cc-primary hover:text-cc-primary/80 transition-colors cursor-pointer",children:"View"}),e.jsx("button",{onClick:()=>Ee(t.id),className:"text-xs text-red-500 hover:text-red-400 transition-colors cursor-pointer",children:"Hang up"})]})]},t.id))})]}),(I.length>0||u)&&e.jsxs("div",{className:"mb-6",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("h2",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:u?`${u.direction==="inbound"?"Inbound":"Outbound"} — ${u.phone}`:"Live Transcript"}),u&&e.jsx("button",{onClick:()=>{var t;J(null),D([]),(t=w.current)==null||t.close()},className:"text-[11px] text-cc-muted hover:text-cc-fg transition-colors cursor-pointer",children:"Close"})]}),(u==null?void 0:u.audioFile)&&e.jsxs("div",{className:"mb-3 bg-cc-card border border-cc-border rounded-xl p-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsxs("svg",{className:"w-3.5 h-3.5 text-cc-muted",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("polygon",{points:"11 5 6 9 2 9 2 15 6 15 11 19 11 5"}),e.jsx("path",{d:"M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"})]}),e.jsx("span",{className:"text-[11px] text-cc-muted font-medium",children:"Recording"}),u.durationSeconds>0&&e.jsxs("span",{className:"text-[10px] text-cc-muted",children:["(",we(u.durationSeconds),")"]})]}),e.jsx("audio",{controls:!0,preload:"metadata",className:"w-full h-8",style:{filter:"invert(0.8) hue-rotate(180deg)"},src:`/api/telephony/calls/${u.id}/audio`}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-1",children:"Stereo: Left = Caller, Right = AI (Hank)"})]}),e.jsxs("div",{ref:L,className:"bg-cc-card border border-cc-border rounded-xl p-3 max-h-[300px] overflow-y-auto space-y-2",children:[I.length===0&&e.jsx("p",{className:"text-xs text-cc-muted text-center py-4",children:"Waiting for conversation..."}),I.map((t,s)=>e.jsx("div",{className:`flex ${t.speaker==="ai"?"justify-end":"justify-start"}`,children:e.jsxs("div",{className:`max-w-[80%] rounded-lg px-3 py-1.5 text-xs ${t.speaker==="ai"?"bg-cc-primary/20 text-cc-fg":t.speaker==="system"?"bg-cc-hover text-cc-muted italic":"bg-cc-card text-cc-fg border border-cc-border"}`,children:[e.jsx("span",{className:"text-[10px] text-cc-muted font-medium",children:t.speaker==="callee"?"Caller":t.speaker==="ai"?"Hank":"System"}),e.jsx("p",{className:"mt-0.5",children:t.text})]})},s))]}),(u==null?void 0:u.summary)&&e.jsxs("div",{className:"mt-2 px-3 py-2 bg-cc-hover rounded-lg",children:[e.jsx("p",{className:"text-[11px] text-cc-muted font-medium mb-1",children:"Summary"}),e.jsx("p",{className:"text-xs text-cc-fg",children:u.summary})]})]}),r&&e.jsxs("details",{className:"bg-cc-card border border-cc-border rounded-xl mb-6 group",children:[e.jsxs("summary",{className:"px-4 py-3 cursor-pointer text-xs font-semibold text-cc-muted uppercase tracking-wider flex items-center justify-between select-none",children:[e.jsx("span",{children:"Settings"}),e.jsx("svg",{className:"w-3.5 h-3.5 text-cc-muted transition-transform group-open:rotate-180",viewBox:"0 0 20 20",fill:"currentColor",children:e.jsx("path",{fillRule:"evenodd",d:"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",clipRule:"evenodd"})})]}),e.jsxs("div",{className:"px-4 pb-4 space-y-4",children:[e.jsxs("button",{type:"button",onClick:()=>He({enabled:!r.enabled}),disabled:P,className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Enable Telephony"}),e.jsx("span",{className:`inline-flex w-9 h-5 rounded-full transition-colors relative shrink-0 ${r.enabled?"bg-green-500":"bg-cc-muted/30"}`,children:e.jsx("span",{className:`absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white shadow transition-transform ${r.enabled?"translate-x-4":"translate-x-0"}`})})]}),r.enabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 space-y-2 border border-cc-border",children:[e.jsx("h3",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"FreeSWITCH ESL"}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"fs-esl-host",className:"text-[11px] text-cc-muted",children:"Host"}),e.jsx("input",{id:"fs-esl-host",type:"text",value:r.freeswitch.eslHost,onChange:t=>i({freeswitch:{...r.freeswitch,eslHost:t.target.value}}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"fs-esl-port",className:"text-[11px] text-cc-muted",children:"Port"}),e.jsx("input",{id:"fs-esl-port",type:"number",value:r.freeswitch.eslPort,onChange:t=>i({freeswitch:{...r.freeswitch,eslPort:parseInt(t.target.value)||8021}}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"fs-esl-password",className:"text-[11px] text-cc-muted",children:"ESL Password"}),e.jsx("input",{id:"fs-esl-password",type:"password",value:r.freeswitch.eslPassword||"",onChange:t=>i({freeswitch:{...r.freeswitch,eslPassword:t.target.value}}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:Ke,className:"px-3 py-1.5 text-xs rounded bg-cc-primary text-white hover:opacity-90 transition-opacity cursor-pointer",children:"Test Connection"}),A&&e.jsx("span",{className:`text-xs ${A.connected?"text-green-500":"text-red-400"}`,children:A.connected?"Connected":A.error||"Failed"})]})]}),e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 space-y-2 border border-cc-border",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h3",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"SIP Trunks"}),e.jsx("button",{onClick:()=>ce(!F),className:"text-xs text-cc-primary hover:text-cc-primary/80 transition-colors cursor-pointer",children:F?"Cancel":"+ Add Trunk"})]}),r.trunks.length===0&&!F&&e.jsx("p",{className:"text-xs text-cc-muted",children:"No SIP trunks configured."}),r.trunks.map(t=>e.jsxs("div",{className:"flex items-center justify-between bg-cc-hover rounded-lg px-3 py-2",children:[e.jsxs("div",{children:[e.jsxs("p",{className:"text-xs font-medium text-cc-fg",children:[t.name," ",e.jsxs("span",{className:"text-cc-muted",children:["(",t.provider,")"]})]}),e.jsx("p",{className:"text-[11px] text-cc-muted",children:t.callerId||"No caller ID"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`w-2 h-2 rounded-full ${t.enabled?"bg-green-500":"bg-cc-muted"}`}),e.jsx("button",{onClick:()=>_e(t.id),"aria-label":`Remove trunk ${t.name}`,className:"px-3 py-2 min-h-[44px] text-[11px] text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded transition-colors cursor-pointer",children:"Remove"})]})]},t.id)),F&&e.jsxs("div",{className:"bg-cc-hover rounded-lg p-3 space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Name"}),e.jsx("input",{type:"text",value:d.name,onChange:t=>v({...d,name:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Provider"}),e.jsxs("select",{value:d.provider,onChange:t=>{const s=t.target.value;v({...d,provider:s,name:s,server:{peoplefone:"sip.peoplefone.at",easybell:"sip.easybell.de",sipgate:"sipconnect.sipgate.de"}[s]||""})},className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg",children:[e.jsx("option",{value:"peoplefone",children:"peoplefone (AT)"}),e.jsx("option",{value:"easybell",children:"easybell (DE)"}),e.jsx("option",{value:"sipgate",children:"sipgate (DE)"}),e.jsx("option",{value:"custom",children:"Custom"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"SIP Server"}),e.jsx("input",{type:"text",value:d.server,onChange:t=>v({...d,server:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"SIP Username"}),e.jsx("input",{type:"text",value:d.username,onChange:t=>v({...d,username:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"SIP Password"}),e.jsx("input",{type:"password",value:d.password,onChange:t=>v({...d,password:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Caller ID (E.164)"}),e.jsx("input",{type:"text",value:d.callerId,onChange:t=>v({...d,callerId:t.target.value}),placeholder:"+43...",className:"w-full px-2 py-1.5 text-xs bg-cc-bg border border-cc-border rounded text-cc-fg"})]}),e.jsx("button",{onClick:Oe,disabled:!d.username||!d.password||!d.server,className:"px-3 py-1.5 text-xs rounded bg-green-600 text-white hover:bg-green-500 transition-colors cursor-pointer disabled:opacity-50",children:"Add Trunk"})]})]}),e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 space-y-2 border border-cc-border",children:[e.jsx("h3",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"Defaults"}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"max-call-duration",className:"text-[11px] text-cc-muted",children:"Max Call Duration (seconds)"}),e.jsx("input",{id:"max-call-duration",type:"number",value:r.maxCallDurationSeconds||600,onChange:t=>i({maxCallDurationSeconds:parseInt(t.target.value)||600}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Safety limit — calls are automatically ended after this duration"})]})]}),e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 space-y-3 border border-cc-border",children:[e.jsx("h3",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"Gemini Live Backend"}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"gemini-backend",className:"text-[11px] text-cc-muted",children:"Backend"}),e.jsxs("select",{id:"gemini-backend",value:r.geminiBackend||"aistudio",onChange:t=>i({geminiBackend:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsx("option",{value:"aistudio",children:"Google AI Studio (default — US routing)"}),e.jsx("option",{value:"vertexai",children:"Vertex AI (EU routing — lower latency)"})]}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:r.geminiBackend==="vertexai"?"Model: gemini-live-2.5-flash-native-audio (Chirp3-HD voices, 30 voices, 24 languages)":"Model: gemini-3.1-flash-live-preview"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"default-voice",className:"text-[11px] text-cc-muted",children:"Default Voice"}),e.jsx("select",{id:"default-voice",value:r.defaultVoice||"Puck",onChange:t=>i({defaultVoice:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:r.geminiBackend==="vertexai"?e.jsxs(e.Fragment,{children:[e.jsxs("optgroup",{label:"Male",children:[e.jsx("option",{value:"Puck",children:"Puck"}),e.jsx("option",{value:"Charon",children:"Charon"}),e.jsx("option",{value:"Fenrir",children:"Fenrir"}),e.jsx("option",{value:"Orus",children:"Orus"}),e.jsx("option",{value:"Achird",children:"Achird"}),e.jsx("option",{value:"Algenib",children:"Algenib"}),e.jsx("option",{value:"Algieba",children:"Algieba"}),e.jsx("option",{value:"Alnilam",children:"Alnilam"}),e.jsx("option",{value:"Enceladus",children:"Enceladus"}),e.jsx("option",{value:"Iapetus",children:"Iapetus"}),e.jsx("option",{value:"Rasalgethi",children:"Rasalgethi"}),e.jsx("option",{value:"Sadachbia",children:"Sadachbia"}),e.jsx("option",{value:"Sadaltager",children:"Sadaltager"}),e.jsx("option",{value:"Schedar",children:"Schedar"}),e.jsx("option",{value:"Umbriel",children:"Umbriel"}),e.jsx("option",{value:"Zubenelgenubi",children:"Zubenelgenubi"})]}),e.jsxs("optgroup",{label:"Female",children:[e.jsx("option",{value:"Kore",children:"Kore"}),e.jsx("option",{value:"Aoede",children:"Aoede"}),e.jsx("option",{value:"Leda",children:"Leda"}),e.jsx("option",{value:"Zephyr",children:"Zephyr"}),e.jsx("option",{value:"Achernar",children:"Achernar"}),e.jsx("option",{value:"Autonoe",children:"Autonoe"}),e.jsx("option",{value:"Callirrhoe",children:"Callirrhoe"}),e.jsx("option",{value:"Despina",children:"Despina"}),e.jsx("option",{value:"Erinome",children:"Erinome"}),e.jsx("option",{value:"Gacrux",children:"Gacrux"}),e.jsx("option",{value:"Laomedeia",children:"Laomedeia"}),e.jsx("option",{value:"Pulcherrima",children:"Pulcherrima"}),e.jsx("option",{value:"Sulafat",children:"Sulafat"}),e.jsx("option",{value:"Vindemiatrix",children:"Vindemiatrix"})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("optgroup",{label:"Male",children:[e.jsx("option",{value:"Kore",children:"Kore"}),e.jsx("option",{value:"Puck",children:"Puck"}),e.jsx("option",{value:"Charon",children:"Charon"}),e.jsx("option",{value:"Fenrir",children:"Fenrir"})]}),e.jsxs("optgroup",{label:"Female",children:[e.jsx("option",{value:"Aoede",children:"Aoede"}),e.jsx("option",{value:"Leda",children:"Leda"})]})]})}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:r.geminiBackend==="vertexai"?"Chirp3-HD voices — note: Kore is female on Vertex AI (unlike AI Studio)":"Standard Gemini Live voices"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"default-language",className:"text-[11px] text-cc-muted",children:"Default Language"}),e.jsxs("select",{id:"default-language",value:r.defaultLanguage||"de",onChange:t=>i({defaultLanguage:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsx("option",{value:"de",children:"Deutsch"}),e.jsx("option",{value:"en",children:"English"}),e.jsx("option",{value:"fr",children:"Français"}),e.jsx("option",{value:"it",children:"Italiano"}),e.jsx("option",{value:"es",children:"Español"}),e.jsx("option",{value:"pt",children:"Português"}),e.jsx("option",{value:"nl",children:"Nederlands"}),e.jsx("option",{value:"pl",children:"Polski"}),e.jsx("option",{value:"cs",children:"Čeština"}),e.jsx("option",{value:"hu",children:"Magyar"}),e.jsx("option",{value:"ro",children:"Română"}),e.jsx("option",{value:"tr",children:"Türkçe"}),e.jsx("option",{value:"ru",children:"Русский"}),e.jsx("option",{value:"ja",children:"日本語"}),e.jsx("option",{value:"zh",children:"中文"}),e.jsx("option",{value:"ko",children:"한국어"}),e.jsx("option",{value:"ar",children:"العربية"})]}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Used for outbound and inbound calls when a contact has no language set."})]}),r.geminiBackend==="vertexai"&&e.jsxs("div",{className:"space-y-3 mt-1 pl-2 border-l-2 border-cc-primary/30",children:[e.jsxs("div",{className:"text-[10px] text-cc-muted space-y-1",children:[e.jsx("p",{children:"Vertex AI routes Gemini Live audio through a Google Cloud region you control (e.g. Netherlands) instead of the default US routing. This can significantly reduce latency for European callers."}),e.jsxs("p",{children:[e.jsx("strong",{children:"Setup required:"})," Create a GCP project, enable the ",e.jsx("em",{children:"Vertex AI API"}),", set up billing, and create a service account with the ",e.jsx("em",{children:"Vertex AI Administrator"})," role. Download the service account key as JSON and place it on this server."]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"gcp-project-id",className:"text-[11px] text-cc-muted",children:"GCP Project ID"}),e.jsx("input",{id:"gcp-project-id",type:"text",value:r.gcpProjectId||"",onChange:t=>i({gcpProjectId:t.target.value}),placeholder:"my-project-id",className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg"}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Find this in the GCP Console dashboard"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"gcp-region",className:"text-[11px] text-cc-muted",children:"Region"}),e.jsxs("select",{id:"gcp-region",value:r.gcpLocation||"europe-west4",onChange:t=>i({gcpLocation:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsx("option",{value:"europe-west4",children:"europe-west4 (Netherlands)"}),e.jsx("option",{value:"europe-west3",children:"europe-west3 (Frankfurt)"}),e.jsx("option",{value:"europe-west1",children:"europe-west1 (Belgium)"}),e.jsx("option",{value:"us-central1",children:"us-central1 (Iowa)"})]}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Choose the region closest to your server"})]})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"gcp-service-key",className:"text-[11px] text-cc-muted",children:"Service Account Key"}),e.jsx("input",{id:"gcp-service-key",type:"text",value:r.gcpServiceAccountKey||"",onChange:t=>i({gcpServiceAccountKey:t.target.value}),placeholder:"/path/to/service-account-key.json",className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg font-mono"}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Absolute path to the JSON key file on this server. Create one in GCP Console → IAM → Service Accounts → Keys."})]})]})]}),e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 space-y-3 border border-cc-border",children:[e.jsx("h3",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"Inbound Call Handling"}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:r.inboundEnabled||!1,onChange:t=>i({inboundEnabled:t.target.checked}),className:"rounded border-cc-border"}),e.jsx("span",{className:"text-xs text-cc-fg",children:"Enable inbound call handling"})]}),e.jsx("p",{className:"text-[10px] text-cc-muted",children:"When enabled, Hank will automatically answer incoming calls and respond using Gemini Live."}),r.inboundEnabled&&e.jsxs("div",{className:"space-y-3 pl-2 border-l-2 border-cc-primary/30",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Default Inbound Prompt"}),e.jsx("textarea",{value:r.defaultInboundPrompt||"You are Hank, a helpful AI assistant answering the phone.",onChange:t=>i({defaultInboundPrompt:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg resize-y",rows:3,placeholder:"System prompt for inbound calls..."}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"This prompt is used when the caller is not a known contact (or the contact has no script)."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Knowledge Base"}),e.jsx("textarea",{value:r.inboundKnowledgeBase||"",onChange:t=>i({inboundKnowledgeBase:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg resize-y font-mono",rows:10,placeholder:"Business info, FAQs, services, pricing — everything Hank should know when answering calls..."}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"This information is injected into every inbound call so Hank can answer questions about your business accurately."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-[11px] text-cc-muted",children:"Inbound Voice"}),e.jsxs("select",{value:r.defaultInboundVoice||r.defaultVoice||"Kore",onChange:t=>i({defaultInboundVoice:t.target.value}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsxs("option",{value:"",children:["Same as outbound (",r.defaultVoice||"Kore",")"]}),e.jsxs("optgroup",{label:"Male",children:[e.jsx("option",{value:"Puck",children:"Puck"}),e.jsx("option",{value:"Charon",children:"Charon"}),e.jsx("option",{value:"Fenrir",children:"Fenrir"})]}),e.jsxs("optgroup",{label:"Female",children:[e.jsx("option",{value:"Kore",children:"Kore"}),e.jsx("option",{value:"Aoede",children:"Aoede"}),e.jsx("option",{value:"Leda",children:"Leda"})]})]})]})]})]}),e.jsxs("div",{className:"bg-cc-bg rounded-lg p-3 space-y-3 border border-cc-border",children:[e.jsx("h3",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider",children:"Voice Engine"}),e.jsxs("p",{className:"text-[10px] text-cc-muted",children:["Alternative zu Gemini Live: Pipeline-basierte Engine mit Google Cloud STT + TTS und konfigurierbarem LLM. Vorteil: ",e.jsx("strong",{children:"vorgerendertes Begrüßungs-Audio"})," spielt sofort beim Abheben (0ms Latenz)."]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:((pe=r.voicePipeline)==null?void 0:pe.enabled)||!1,onChange:t=>i({voicePipeline:{...r.voicePipeline||{},enabled:t.target.checked}}),className:"rounded border-cc-border"}),e.jsx("span",{className:"text-xs text-cc-fg",children:"Pipeline-Engine aktivieren"})]}),((ue=r.voicePipeline)==null?void 0:ue.enabled)&&e.jsxs("div",{className:"space-y-3 pl-2 border-l-2 border-cc-primary/30",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"vp-engine",className:"text-[11px] text-cc-muted",children:"Default Engine"}),e.jsxs("select",{id:"vp-engine",value:((he=r.voicePipeline)==null?void 0:he.engine)||"pipeline",onChange:t=>i({voicePipeline:{...r.voicePipeline||{},engine:t.target.value}}),className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsx("option",{value:"pipeline",children:"Pipeline (Google STT/TTS + LLM)"}),e.jsx("option",{value:"gemini-live",children:"Gemini Live (klassisch)"})]}),e.jsx("p",{className:"text-[10px] text-cc-muted mt-0.5",children:"Welche Engine wird für neue Anrufe verwendet?"})]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:((me=r.voicePipeline)==null?void 0:me.fallbackToGeminiLive)??!0,onChange:t=>i({voicePipeline:{...r.voicePipeline||{},fallbackToGeminiLive:t.target.checked}}),className:"rounded border-cc-border"}),e.jsx("span",{className:"text-xs text-cc-fg",children:"Fallback auf Gemini Live bei Pipeline-Fehler"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"vp-tts-voice",className:"text-[11px] text-cc-muted",children:"TTS Voice (Google Cloud)"}),e.jsxs("select",{id:"vp-tts-voice",value:((be=(ge=r.voicePipeline)==null?void 0:ge.tts)==null?void 0:be.voice)||"de-DE-Chirp-HD-D",onChange:t=>{var s;return i({voicePipeline:{...r.voicePipeline||{},tts:{...((s=r.voicePipeline)==null?void 0:s.tts)||{},voice:t.target.value}}})},className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsxs("optgroup",{label:"Chirp HD (neueste, ~$16/1M chars)",children:[e.jsx("option",{value:"de-DE-Chirp-HD-D",children:"de-DE-Chirp-HD-D (männlich)"}),e.jsx("option",{value:"de-DE-Chirp-HD-O",children:"de-DE-Chirp-HD-O (männlich)"}),e.jsx("option",{value:"de-DE-Chirp-HD-F",children:"de-DE-Chirp-HD-F (weiblich)"})]}),e.jsxs("optgroup",{label:"Studio (Premium, ~$160/1M chars)",children:[e.jsx("option",{value:"de-DE-Studio-B",children:"de-DE-Studio-B (männlich)"}),e.jsx("option",{value:"de-DE-Studio-C",children:"de-DE-Studio-C (weiblich)"})]}),e.jsxs("optgroup",{label:"Neural2 (Standard, ~$16/1M chars)",children:[e.jsx("option",{value:"de-DE-Neural2-G",children:"de-DE-Neural2-G (männlich)"}),e.jsx("option",{value:"de-DE-Neural2-H",children:"de-DE-Neural2-H (männlich)"})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"vp-language",className:"text-[11px] text-cc-muted",children:"STT/TTS Language"}),e.jsxs("select",{id:"vp-language",value:((fe=(ve=r.voicePipeline)==null?void 0:ve.stt)==null?void 0:fe.language)||"de-DE",onChange:t=>{var c;const s=t.target.value;i({voicePipeline:{...r.voicePipeline||{},stt:{...((c=r.voicePipeline)==null?void 0:c.stt)||{},language:s}}})},className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsx("option",{value:"de-DE",children:"Deutsch (DE)"}),e.jsx("option",{value:"de-AT",children:"Deutsch (AT)"}),e.jsx("option",{value:"en-US",children:"English (US)"}),e.jsx("option",{value:"en-GB",children:"English (GB)"})]})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"vp-llm-provider",className:"text-[11px] text-cc-muted",children:"LLM Provider (nur für Telephony)"}),e.jsxs("select",{id:"vp-llm-provider",value:((ye=(je=r.voicePipeline)==null?void 0:je.llm)==null?void 0:ye.provider)||"groq",onChange:t=>{var c;const s=t.target.value;i({voicePipeline:{...r.voicePipeline||{},llm:{...((c=r.voicePipeline)==null?void 0:c.llm)||{},provider:s}}})},className:"w-full px-2 py-1.5 text-xs bg-cc-hover border border-cc-border rounded text-cc-fg",children:[e.jsx("optgroup",{label:"Empfohlen für Voice (niedrigste Latenz)",children:e.jsx("option",{value:"groq",children:"Groq (Llama 3.3 70B, ~50ms TTFT)"})}),e.jsxs("optgroup",{label:"Cloud-Anbieter",children:[e.jsx("option",{value:"anthropic",children:"Anthropic (Claude)"}),e.jsx("option",{value:"openai",children:"OpenAI (GPT)"}),e.jsx("option",{value:"mistral",children:"Mistral AI"}),e.jsx("option",{value:"deepseek",children:"DeepSeek"}),e.jsx("option",{value:"xai",children:"xAI (Grok)"}),e.jsx("option",{value:"qwen",children:"Qwen"}),e.jsx("option",{value:"moonshot",children:"Moonshot (Kimi)"}),e.jsx("option",{value:"venice",children:"Venice AI"})]}),e.jsxs("optgroup",{label:"Gateways",children:[e.jsx("option",{value:"openrouter",children:"OpenRouter"}),e.jsx("option",{value:"together",children:"Together AI"})]})]}),e.jsxs("p",{className:"mt-1 text-[10px] text-cc-muted",children:["Der gewählte Provider muss unter ",e.jsx("em",{children:"Settings → Providers"})," konfiguriert sein (API-Key hinterlegt)."]})]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:((Ne=r.voicePipeline)==null?void 0:Ne.preRenderGreetings)??!0,onChange:t=>i({voicePipeline:{...r.voicePipeline||{},preRenderGreetings:t.target.checked}}),className:"rounded border-cc-border"}),e.jsx("span",{className:"text-xs text-cc-fg",children:"Begrüßungs-Audio pro Kontakt vorrendern (Cache)"})]}),e.jsxs("p",{className:"text-[10px] text-cc-muted",children:["Voraussetzung: Cloud Speech-to-Text + Cloud Text-to-Speech APIs müssen im GCP-Projekt aktiviert sein. Service Account braucht zusätzlich die Rollen ",e.jsx("em",{children:"Cloud Speech Client"})," + ",e.jsx("em",{children:"Service Usage Consumer"}),"."]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 pt-2",children:[e.jsx("button",{type:"button",onClick:Me,disabled:P||!U,className:`px-4 py-2 text-xs font-medium rounded-lg transition-all cursor-pointer ${U?"bg-cc-primary text-white hover:opacity-90 shadow-sm":"bg-cc-hover text-cc-muted"} disabled:opacity-50 disabled:cursor-default`,children:P?"Saving...":"Save Settings"}),ke&&e.jsx("span",{className:"text-xs text-green-500 animate-fade-in",children:"Settings saved"}),U&&!P&&e.jsx("span",{className:"text-[11px] text-amber-400",children:"Unsaved changes"})]})]})]})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-cc-muted uppercase tracking-wider mb-3",children:"History"}),q.length===0?e.jsx("p",{className:"text-xs text-cc-muted",children:"No calls yet."}):e.jsxs("div",{className:"space-y-1.5",children:[q.map(t=>e.jsxs("button",{onClick:()=>de(t),className:"w-full text-left bg-cc-card border border-cc-border rounded-lg px-4 py-2.5 hover:border-cc-primary/40 transition-colors cursor-pointer",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full ${t.status==="ended"?"bg-cc-muted":t.status==="failed"?"bg-red-500":"bg-green-500"}`}),e.jsx("span",{className:"text-[10px] text-cc-muted",children:t.direction==="inbound"?"IN":"OUT"}),e.jsx("span",{className:"text-sm text-cc-fg",children:t.phone})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[t.audioFile&&e.jsxs("svg",{className:"w-3 h-3 text-cc-muted",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("polygon",{points:"11 5 6 9 2 9 2 15 6 15 11 19 11 5"}),e.jsx("path",{d:"M15.54 8.46a5 5 0 0 1 0 7.07"})]}),t.durationSeconds>0&&e.jsx("span",{className:"text-[11px] text-cc-muted",children:we(t.durationSeconds)}),e.jsx("span",{className:"text-[11px] text-cc-muted",children:We(t.startedAt)})]})]}),e.jsx("p",{className:"text-[11px] text-cc-muted truncate mt-0.5",children:t.prompt}),t.summary&&e.jsx("p",{className:"text-[11px] text-cc-fg/70 truncate mt-0.5",children:t.summary})]},t.id)),q.length>=z&&e.jsx("button",{onClick:()=>Ce(t=>t+50),className:"w-full text-center py-2 text-xs text-cc-primary hover:text-cc-primary/80 transition-colors cursor-pointer",children:"Load more"})]})]})]})]})}function Ue({className:g}){return e.jsx("svg",{className:g,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"})})}function we(g){const b=Math.floor(g/60),f=g%60;return b>0?`${b}m ${f}s`:`${f}s`}function We(g){return new Date(g).toLocaleString("de-AT",{day:"2-digit",month:"2-digit",hour:"2-digit",minute:"2-digit"})}export{Je as TelephonyPage};
@@ -1 +1 @@
1
- import{u as a,r as i,j as e,T as c,F as n}from"./index-CEqZnThB.js";function m(){const s=a(r=>r.terminalCwd),[l,t]=i.useState(!1);return e.jsxs("div",{className:"h-full bg-cc-bg overflow-y-auto",children:[e.jsxs("div",{className:"max-w-5xl mx-auto px-4 sm:px-8 py-6 sm:py-10 pb-safe h-full flex flex-col",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-6 shrink-0",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold text-cc-fg",children:"Terminal"}),e.jsx("p",{className:"mt-1 text-sm text-cc-muted",children:"Run shell commands directly in the browser without leaving the dashboard."})]}),e.jsx("button",{type:"button",onClick:()=>t(!0),className:"px-3 py-2 rounded-lg text-sm font-medium bg-cc-primary hover:bg-cc-primary-hover text-white transition-colors cursor-pointer whitespace-nowrap",children:s?"Change Folder":"Choose Folder"})]}),e.jsx("div",{className:"flex-1 min-h-[420px]",children:s?e.jsx(c,{cwd:s,embedded:!0}):e.jsx("div",{className:"h-full bg-cc-card border border-cc-border rounded-xl p-6 sm:p-8 flex items-center justify-center text-center",children:e.jsxs("div",{className:"max-w-md",children:[e.jsx("h2",{className:"text-lg font-semibold text-cc-fg mb-2",children:"No terminal started yet"}),e.jsx("p",{className:"text-sm text-cc-muted",children:"Choose a folder to start a terminal session. You can switch folders anytime."})]})})})]}),l&&e.jsx(n,{initialPath:s||"",onSelect:r=>{a.getState().openTerminal(r),window.location.hash="#/terminal",t(!1)},onClose:()=>t(!1)})]})}export{m as TerminalPage};
1
+ import{u as a,r as i,j as e,T as c,F as n}from"./index-BgYM4wXw.js";function m(){const s=a(r=>r.terminalCwd),[l,t]=i.useState(!1);return e.jsxs("div",{className:"h-full bg-cc-bg overflow-y-auto",children:[e.jsxs("div",{className:"max-w-5xl mx-auto px-4 sm:px-8 py-6 sm:py-10 pb-safe h-full flex flex-col",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-6 shrink-0",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold text-cc-fg",children:"Terminal"}),e.jsx("p",{className:"mt-1 text-sm text-cc-muted",children:"Run shell commands directly in the browser without leaving the dashboard."})]}),e.jsx("button",{type:"button",onClick:()=>t(!0),className:"px-3 py-2 rounded-lg text-sm font-medium bg-cc-primary hover:bg-cc-primary-hover text-white transition-colors cursor-pointer whitespace-nowrap",children:s?"Change Folder":"Choose Folder"})]}),e.jsx("div",{className:"flex-1 min-h-[420px]",children:s?e.jsx(c,{cwd:s,embedded:!0}):e.jsx("div",{className:"h-full bg-cc-card border border-cc-border rounded-xl p-6 sm:p-8 flex items-center justify-center text-center",children:e.jsxs("div",{className:"max-w-md",children:[e.jsx("h2",{className:"text-lg font-semibold text-cc-fg mb-2",children:"No terminal started yet"}),e.jsx("p",{className:"text-sm text-cc-muted",children:"Choose a folder to start a terminal session. You can switch folders anytime."})]})})})]}),l&&e.jsx(n,{initialPath:s||"",onSelect:r=>{a.getState().openTerminal(r),window.location.hash="#/terminal",t(!1)},onClose:()=>t(!1)})]})}export{m as TerminalPage};
@@ -1,4 +1,4 @@
1
- var m=Object.defineProperty;var u=(n,e,i)=>e in n?m(n,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):n[e]=i;var d=(n,e,i)=>u(n,typeof e!="symbol"?e+"":e,i);import{base64ToUint8Array as h}from"./gemini-audio-t-TSU-To.js";const y="wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent",f="models/gemini-3.1-flash-live-preview";function g(n,e,i,t,l,o){const s=n?`You are "${n}", a personal voice assistant on the HeyHank platform.`:"You are a personal voice assistant on the HeyHank platform.",r=l?`
1
+ var m=Object.defineProperty;var u=(n,e,i)=>e in n?m(n,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):n[e]=i;var d=(n,e,i)=>u(n,typeof e!="symbol"?e+"":e,i);import{base64ToUint8Array as h}from"./gemini-audio-t-TSU-To.js";const y="wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent",f="models/gemini-3.1-flash-live-preview";function g(n,e,i,t,l,r){const s=n?`You are "${n}", a personal voice assistant on the HeyHank platform.`:"You are a personal voice assistant on the HeyHank platform.",o=l?`
2
2
  The user's name is ${l}. Address them by name when appropriate.`:"",p=e.length>0?`
3
3
  AGENTS (configured on the platform):
4
4
  The following agents are available. You are the orchestrator — when the user assigns a task,
@@ -9,7 +9,7 @@ ${e.map(a=>`- "${a.name}" (${a.backend}): ${a.description}`).join(`
9
9
  `)}
10
10
 
11
11
  When the user mentions an agent name (even approximately, e.g. "Max 2.0" for "Agent Max 2.0"),
12
- recognize it and start the appropriate session. Only ask if it is truly unclear.`:"";return`${s}${r}
12
+ recognize it and start the appropriate session. Only ask if it is truly unclear.`:"";return`${s}${o}
13
13
  You speak English by default, unless the user speaks another language.
14
14
  Keep your answers short and natural — you are a voice assistant, not a text bot.
15
15
 
@@ -85,16 +85,19 @@ If they want to create an event ("schedule a...", "meeting on..."), use create_e
85
85
  If the user assigns a complex task (create a website, write code, etc.), delegate to the appropriate agent.
86
86
 
87
87
  TELEPHONY (phone calls):
88
- - make_call: Place a real phone call via SIP trunk. The AI on the other end conducts the conversation autonomously.
89
- You can pass a contact NAME instead of a phone number the system will resolve it automatically.
88
+ - make_call: Place a real phone call via SIP trunk. The AI conducts the conversation autonomously.
89
+ IMPORTANT: You can ONLY call saved contacts by name. You cannot call arbitrary phone numbers.
90
90
  Example: "Call Mama" → make_call("Mama", "Say hi and ask how she's doing")
91
- Example: "Call +4312345678" → make_call("+4312345678", "Reserve a table for 4 at 7pm Friday")
91
+ Example: "Call Restaurant Steirereck" → make_call("Restaurant Steirereck", "Reserve a table for 4 at 7pm Friday")
92
+ If the user provides a phone number that's not a saved contact, ask them to save it first in Settings → Telephony → Contacts.
93
+ You can optionally pass listen=true to let the user hear the call live through their speakers.
94
+ Example: "Call Mama and let me listen" → make_call("Mama", "...", listen=true)
92
95
  - list_active_calls: Show current active phone calls
93
96
  - end_active_call: Hang up an active call
94
- After starting a call, inform the user about the status. The call runs autonomously — you don't need to monitor it.${o&&o.length>0?`
97
+ After starting a call, inform the user about the status. The call runs autonomously — you don't need to monitor it.${r&&r.length>0?`
95
98
 
96
99
  PHONE CONTACTS (you may call these by name):
97
- ${o.map(a=>`- "${a.name}": ${a.phone}${a.notes?` (${a.notes})`:""}`).join(`
100
+ ${r.map(a=>`- "${a.name}": ${a.phone}${a.notes?` (${a.notes})`:""}`).join(`
98
101
  `)}`:""}
99
102
 
100
103
  SOCIAL MEDIA:
@@ -163,4 +166,4 @@ ${i.map(a=>`--- ${a.title} ---
163
166
  ${a.content}`).join(`
164
167
 
165
168
  `)}
166
- Use this knowledge to maintain context.`:""}`}const T=[{functionDeclarations:[{name:"run_agent",description:"Run a configured agent by name or ID. This starts the agent with its full configuration (system prompt, model, permissions, working directory). Use this when the user asks to activate/start a specific agent like 'Max 2.0' or 'Coding Agent'. The agent will execute the given task autonomously.",parameters:{type:"OBJECT",properties:{agent:{type:"STRING",description:"Agent name or ID (e.g. 'Agent Max 2.0', 'Coding Agent', 'agent-max-20'). Fuzzy matching is supported."},task:{type:"STRING",description:"The task/instruction to give to the agent."}},required:["agent","task"]}},{name:"create_agent",description:"Create a new agent on the platform. Use this when the user wants a new specialized agent that doesn't exist yet. The agent will be saved and can be started later with run_agent.",parameters:{type:"OBJECT",properties:{name:{type:"STRING",description:"Name for the agent (e.g. 'Website Builder', 'Data Analyst')"},description:{type:"STRING",description:"Short description of what the agent does"},prompt:{type:"STRING",description:"System prompt / instructions for the agent. Be detailed about the agent's role, capabilities, and how it should approach tasks."},model:{type:"STRING",description:"AI model to use. Default: 'claude-sonnet-4-20250514'. Options: 'claude-sonnet-4-20250514', 'claude-opus-4-20250514'"},cwd:{type:"STRING",description:"Working directory for the agent. Default: home directory."},autoStart:{type:"BOOLEAN",description:"If true, immediately start the agent with a task after creation. Default: false."},task:{type:"STRING",description:"Task to give the agent if autoStart is true."}},required:["name","prompt"]}},{name:"list_sessions",description:"List all active coding sessions on the platform. Returns session IDs, status, model, and working directory.",parameters:{type:"OBJECT",properties:{}}},{name:"create_session",description:"Create a new coding session with Claude Code or Codex. Returns the new session ID.",parameters:{type:"OBJECT",properties:{backend:{type:"STRING",description:"The AI backend to use: 'claude' for Claude Code, 'codex' for OpenAI Codex. Default: 'claude'.",enum:["claude","codex"]},cwd:{type:"STRING",description:"Working directory for the session. Default: /opt/agentplatform/web"},message:{type:"STRING",description:"Optional initial message to send to the session after creation."}}}},{name:"send_message",description:"Send a text message/instruction to an existing coding session. The AI in that session will execute it.",parameters:{type:"OBJECT",properties:{session_id:{type:"STRING",description:"The session ID to send the message to. Use list_sessions to find available sessions."},message:{type:"STRING",description:"The message/instruction to send to the session."}},required:["session_id","message"]}},{name:"get_session_status",description:"Get detailed status of a specific session including state, model, and recent activity.",parameters:{type:"OBJECT",properties:{session_id:{type:"STRING",description:"The session ID to check."}},required:["session_id"]}},{name:"monitor_agent_session",description:"Monitor a running agent session. Returns whether the agent needs user input (permission questions), is still working, or has completed. IMPORTANT: After starting an agent with run_agent, use this tool periodically to check progress and immediately inform the user about questions or completion.",parameters:{type:"OBJECT",properties:{session_id:{type:"STRING",description:"The session ID returned by run_agent."}},required:["session_id"]}},{name:"list_todos",description:"List all todos/tasks. Can filter by status, priority or category.",parameters:{type:"OBJECT",properties:{show_completed:{type:"BOOLEAN",description:"If true, also show completed todos. Default: false (only open todos)."},priority:{type:"STRING",description:"Filter by priority.",enum:["high","medium","low"]},category:{type:"STRING",description:"Filter by category (e.g. 'arbeit', 'privat', 'projekt')."}}}},{name:"add_todo",description:"Add a new todo/task to the list.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"The todo text/description."},priority:{type:"STRING",description:"Priority level. Default: 'medium'.",enum:["high","medium","low"]},category:{type:"STRING",description:"Optional category (e.g. 'arbeit', 'privat', 'projekt')."}},required:["text"]}},{name:"complete_todo",description:"Mark a todo as completed.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The todo ID to complete."}},required:["id"]}},{name:"delete_todo",description:"Delete a todo permanently.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The todo ID to delete."}},required:["id"]}},{name:"update_todo",description:"Update an existing todo's text, priority or category.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The todo ID to update."},text:{type:"STRING",description:"New text."},priority:{type:"STRING",enum:["high","medium","low"]},category:{type:"STRING",description:"New category."}},required:["id"]}},{name:"search_notes",description:"Search notes/memory. Returns all notes if no query given. Use this when the user asks 'what do you know about X' or 'did I note something about Y'.",parameters:{type:"OBJECT",properties:{query:{type:"STRING",description:"Search term to filter notes by title, content or tags. Leave empty to list all."}}}},{name:"add_note",description:"Save a note/memory. Use when user says 'remember that...', 'note that...', 'save that...'.",parameters:{type:"OBJECT",properties:{title:{type:"STRING",description:"Short title for the note."},content:{type:"STRING",description:"Detailed content."},tags:{type:"STRING",description:"Comma-separated tags for categorization."}},required:["title"]}},{name:"update_note",description:"Update an existing note.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The note ID."},title:{type:"STRING"},content:{type:"STRING"},tags:{type:"STRING",description:"Comma-separated tags."}},required:["id"]}},{name:"delete_note",description:"Delete a note.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The note ID to delete."}},required:["id"]}},{name:"list_reminders",description:"List all pending reminders.",parameters:{type:"OBJECT",properties:{include_fired:{type:"BOOLEAN",description:"If true, also show already fired reminders."}}}},{name:"add_reminder",description:"Set a reminder for a specific time. Use when user says 'remind me in 2 hours' or 'remind me tomorrow at 9'.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"What to be reminded about."},trigger_at:{type:"STRING",description:"ISO 8601 datetime when the reminder should fire. Calculate from current time if user says 'in 2 hours' etc. Current timezone is Europe/Vienna (CET/CEST)."}},required:["text","trigger_at"]}},{name:"delete_reminder",description:"Delete/cancel a reminder.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The reminder ID to delete."}},required:["id"]}},{name:"list_email_accounts",description:"List all configured email accounts. Shows account name and email address.",parameters:{type:"OBJECT",properties:{}}},{name:"list_emails",description:"List recent emails from a specific account. Use list_email_accounts first to get the account name.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address (e.g. 'Gmail', 'Work', 'user@example.com')."},folder:{type:"STRING",description:"Mail folder. Default: INBOX."},limit:{type:"NUMBER",description:"Number of emails to fetch. Default: 10."},unseen:{type:"BOOLEAN",description:"If true, only show unread emails."}},required:["account"]}},{name:"read_email",description:"Read the full content of a specific email by UID. Use list_emails first to get the UID.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address."},uid:{type:"NUMBER",description:"The email UID from list_emails."},folder:{type:"STRING",description:"Mail folder. Default: INBOX."}},required:["account","uid"]}},{name:"search_emails",description:"Search emails in an account by subject, sender, or body text.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address."},query:{type:"STRING",description:"Search term to find in subject, from, or body."},limit:{type:"NUMBER",description:"Max results. Default: 10."}},required:["account","query"]}},{name:"send_email",description:"Send a new email from one of the configured accounts.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address to send from."},to:{type:"STRING",description:"Recipient email address."},subject:{type:"STRING",description:"Email subject line."},body:{type:"STRING",description:"Email body text."}},required:["account","to","subject","body"]}},{name:"reply_email",description:"Reply to an existing email. Automatically uses Re: subject and correct recipient.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address."},uid:{type:"NUMBER",description:"UID of the email to reply to."},body:{type:"STRING",description:"Reply body text."},folder:{type:"STRING",description:"Mail folder of the original email. Default: INBOX."}},required:["account","uid","body"]}},{name:"email_summary",description:"Get unread email count across all configured accounts. Good for a quick overview.",parameters:{type:"OBJECT",properties:{}}},{name:"list_calendar_accounts",description:"List all configured calendar accounts. Shows account name and provider.",parameters:{type:"OBJECT",properties:{}}},{name:"list_events",description:"List calendar events for a date range. Default: next 7 days. Use list_calendar_accounts first to get the account name.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name (e.g. 'Google', 'iCloud'). Use list_calendar_accounts to find available accounts."},from:{type:"STRING",description:"Start date/time in ISO format (e.g. '2026-04-03'). Default: today."},to:{type:"STRING",description:"End date/time in ISO format (e.g. '2026-04-10'). Default: 7 days from now."}},required:["account"]}},{name:"create_event",description:"Create a new calendar event. Use when the user says 'add to calendar', 'schedule a meeting', etc.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name."},summary:{type:"STRING",description:"Event title/summary."},start:{type:"STRING",description:"Start date/time in ISO format (e.g. '2026-04-05T14:00:00' or '2026-04-05' for all-day)."},end:{type:"STRING",description:"End date/time in ISO format (e.g. '2026-04-05T15:00:00' or '2026-04-06' for all-day)."},description:{type:"STRING",description:"Optional event description/notes."},location:{type:"STRING",description:"Optional event location."},all_day:{type:"BOOLEAN",description:"If true, create an all-day event. Default: false."}},required:["account","summary","start","end"]}},{name:"search_events",description:"Search calendar events by text in title, description or location.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name."},query:{type:"STRING",description:"Search text to find in event title, description or location."},from:{type:"STRING",description:"Start of search range. Default: today."},to:{type:"STRING",description:"End of search range. Default: 30 days from now."}},required:["account","query"]}},{name:"delete_event",description:"Delete a calendar event by its UID. Use list_events or search_events first to find the UID.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name."},uid:{type:"STRING",description:"The event UID to delete (from list_events)."}},required:["account","uid"]}},{name:"calendar_summary",description:"Get an overview of upcoming events across all configured calendar accounts. Shows today's count, this week's count, and next event.",parameters:{type:"OBJECT",properties:{}}},{name:"make_call",description:"Place a real phone call. An AI assistant will conduct the conversation autonomously based on the given task. You can pass either a phone number (E.164) or a contact name — the system resolves contact names to numbers automatically.",parameters:{type:"OBJECT",properties:{phone:{type:"STRING",description:"Phone number in E.164 format (e.g. '+4366412345') OR a contact name (e.g. 'Mama', 'Restaurant Steirereck'). Contact names are resolved automatically."},task:{type:"STRING",description:"The task/instruction for the AI on the call. Be specific about what to say and achieve."},voice:{type:"STRING",description:"Voice for the call AI. Default: same as current voice."}},required:["phone","task"]}},{name:"list_active_calls",description:"List currently active phone calls with their status and duration.",parameters:{type:"OBJECT",properties:{}}},{name:"end_active_call",description:"Hang up an active phone call by its call ID.",parameters:{type:"OBJECT",properties:{call_id:{type:"STRING",description:"The call ID to hang up."}},required:["call_id"]}},{name:"prepare_social_post",description:"Prepare a social media post as a draft for user review. The post will appear in the Social Media page where the user can edit, schedule, and publish it.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"The post text/content."},platforms:{type:"ARRAY",items:{type:"STRING"},description:'Target platforms, e.g. ["twitter", "linkedin"].'},title:{type:"STRING",description:"Optional title/headline for the post."},firstComment:{type:"STRING",description:"Optional text for the first comment (common on Instagram/LinkedIn)."},mediaUrls:{type:"ARRAY",items:{type:"STRING"},description:"Optional image URLs to attach."},videoUrl:{type:"STRING",description:"Optional video URL."},thumbnailUrl:{type:"STRING",description:"Optional thumbnail/preview image URL."},scheduledAt:{type:"STRING",description:"Optional ISO 8601 datetime to schedule the post."}},required:["text","platforms"]}},{name:"create_social_post",description:"Create and publish a social media post on one or more platforms.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"The post text/content."},platforms:{type:"ARRAY",items:{type:"STRING"},description:'Platforms to post to, e.g. ["twitter", "linkedin"].'},scheduledAt:{type:"STRING",description:"Optional ISO 8601 datetime to schedule the post for later."}},required:["text","platforms"]}},{name:"list_social_posts",description:"List recent social media posts. Optionally filter by status.",parameters:{type:"OBJECT",properties:{limit:{type:"INTEGER",description:"Max number of posts to return."},status:{type:"STRING",description:"Filter by status: published, scheduled, failed."}}}},{name:"get_social_analytics",description:"Get analytics/metrics for a social media profile.",parameters:{type:"OBJECT",properties:{profileId:{type:"STRING",description:"Profile/platform identifier."}},required:["profileId"]}},{name:"reply_to_social_comment",description:"Reply to a comment on a social media post.",parameters:{type:"OBJECT",properties:{postId:{type:"STRING",description:"The post ID."},commentId:{type:"STRING",description:"The comment ID to reply to (optional for new comment)."},text:{type:"STRING",description:"Reply text."}},required:["postId","text"]}}]}];class _{constructor(e){d(this,"ws",null);d(this,"handler");d(this,"setupDone",!1);d(this,"resumeHistory",null);this.handler=e}connect(e,i="Kore",t){this.resumeHistory=(t==null?void 0:t.resumeHistory)||null;const l=`${y}?key=${e}`;this.ws=new WebSocket(l);const o=g((t==null?void 0:t.assistantName)||"",(t==null?void 0:t.agents)||[],t==null?void 0:t.recentConversations,t==null?void 0:t.activeSessions,t==null?void 0:t.userName,t==null?void 0:t.contacts);this.ws.onopen=()=>{var s;(s=this.ws)==null||s.send(JSON.stringify({setup:{model:f,generationConfig:{responseModalities:["AUDIO"],speechConfig:{voiceConfig:{prebuiltVoiceConfig:{voiceName:i}}}},systemInstruction:{parts:[{text:o}]},tools:[...T,{googleSearch:{}}],outputAudioTranscription:{},inputAudioTranscription:{}}}))},this.ws.onmessage=async s=>{try{let r;s.data instanceof Blob?r=await s.data.text():r=s.data;const p=JSON.parse(r);this.handleMessage(p)}catch{}},this.ws.onerror=s=>{console.error("[GeminiLive] WebSocket error:",s),this.handler({type:"error",error:"WebSocket connection error"})},this.ws.onclose=s=>{console.log(`[GeminiLive] WebSocket closed: code=${s.code} reason=${s.reason}`),this.handler({type:"closed"}),this.ws=null,this.setupDone=!1}}handleMessage(e){var i,t,l;if("setupComplete"in e){if(this.setupDone=!0,this.resumeHistory&&this.resumeHistory.length>0&&this.ws){const o=this.resumeHistory.map(s=>({role:s.role==="user"?"user":"model",parts:[{text:s.text}]}));this.ws.send(JSON.stringify({clientContent:{turns:o,turnComplete:!0}})),this.resumeHistory=null}this.handler({type:"setupComplete"});return}if("toolCall"in e){const o=e.toolCall;if((i=o.functionCalls)!=null&&i.length){const s=o.functionCalls.map(r=>({id:r.id,name:r.name,args:r.args||{}}));this.handler({type:"toolCall",calls:s})}return}if("serverContent"in e){const o=e.serverContent,s=o.outputTranscription;s!=null&&s.text&&this.handler({type:"text",text:s.text});const r=o.inputTranscription;if((t=r==null?void 0:r.text)!=null&&t.trim()&&this.handler({type:"inputTranscript",text:r.text.trim()}),o.turnComplete){this.handler({type:"turnComplete"});return}if(o.interrupted){this.handler({type:"interrupted"});return}const p=o.modelTurn;if(p!=null&&p.parts)for(const a of p.parts){if((l=a.inlineData)!=null&&l.data){const c=h(a.inlineData.data);this.handler({type:"audio",data:c})}a.text&&this.handler({type:"text",text:a.text})}}}sendToolResponse(e){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({toolResponse:{functionResponses:e.map(i=>({id:i.id,name:i.name,response:i.response}))}}))}sendAudio(e){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({realtimeInput:{audio:{mimeType:"audio/pcm;rate=16000",data:e}}}))}sendImage(e,i="image/jpeg"){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({realtimeInput:{media:{mimeType:i,data:e}}}))}sendText(e){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({clientContent:{turns:[{role:"user",parts:[{text:e}]}],turnComplete:!0}}))}get isReady(){var e;return this.setupDone&&((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}disconnect(){this.ws&&(this.ws.onclose=null,this.ws.close(),this.ws=null),this.setupDone=!1}}export{_ as GeminiLiveClient};
169
+ Use this knowledge to maintain context.`:""}`}const T=[{functionDeclarations:[{name:"run_agent",description:"Run a configured agent by name or ID. This starts the agent with its full configuration (system prompt, model, permissions, working directory). Use this when the user asks to activate/start a specific agent like 'Max 2.0' or 'Coding Agent'. The agent will execute the given task autonomously.",parameters:{type:"OBJECT",properties:{agent:{type:"STRING",description:"Agent name or ID (e.g. 'Agent Max 2.0', 'Coding Agent', 'agent-max-20'). Fuzzy matching is supported."},task:{type:"STRING",description:"The task/instruction to give to the agent."}},required:["agent","task"]}},{name:"create_agent",description:"Create a new agent on the platform. Use this when the user wants a new specialized agent that doesn't exist yet. The agent will be saved and can be started later with run_agent.",parameters:{type:"OBJECT",properties:{name:{type:"STRING",description:"Name for the agent (e.g. 'Website Builder', 'Data Analyst')"},description:{type:"STRING",description:"Short description of what the agent does"},prompt:{type:"STRING",description:"System prompt / instructions for the agent. Be detailed about the agent's role, capabilities, and how it should approach tasks."},model:{type:"STRING",description:"AI model to use. Default: 'claude-sonnet-4-20250514'. Options: 'claude-sonnet-4-20250514', 'claude-opus-4-20250514'"},cwd:{type:"STRING",description:"Working directory for the agent. Default: home directory."},autoStart:{type:"BOOLEAN",description:"If true, immediately start the agent with a task after creation. Default: false."},task:{type:"STRING",description:"Task to give the agent if autoStart is true."}},required:["name","prompt"]}},{name:"list_sessions",description:"List all active coding sessions on the platform. Returns session IDs, status, model, and working directory.",parameters:{type:"OBJECT",properties:{}}},{name:"create_session",description:"Create a new coding session with Claude Code or Codex. Returns the new session ID.",parameters:{type:"OBJECT",properties:{backend:{type:"STRING",description:"The AI backend to use: 'claude' for Claude Code, 'codex' for OpenAI Codex. Default: 'claude'.",enum:["claude","codex"]},cwd:{type:"STRING",description:"Working directory for the session. Default: /opt/agentplatform/web"},message:{type:"STRING",description:"Optional initial message to send to the session after creation."}}}},{name:"send_message",description:"Send a text message/instruction to an existing coding session. The AI in that session will execute it.",parameters:{type:"OBJECT",properties:{session_id:{type:"STRING",description:"The session ID to send the message to. Use list_sessions to find available sessions."},message:{type:"STRING",description:"The message/instruction to send to the session."}},required:["session_id","message"]}},{name:"get_session_status",description:"Get detailed status of a specific session including state, model, and recent activity.",parameters:{type:"OBJECT",properties:{session_id:{type:"STRING",description:"The session ID to check."}},required:["session_id"]}},{name:"monitor_agent_session",description:"Monitor a running agent session. Returns whether the agent needs user input (permission questions), is still working, or has completed. IMPORTANT: After starting an agent with run_agent, use this tool periodically to check progress and immediately inform the user about questions or completion.",parameters:{type:"OBJECT",properties:{session_id:{type:"STRING",description:"The session ID returned by run_agent."}},required:["session_id"]}},{name:"list_todos",description:"List all todos/tasks. Can filter by status, priority or category.",parameters:{type:"OBJECT",properties:{show_completed:{type:"BOOLEAN",description:"If true, also show completed todos. Default: false (only open todos)."},priority:{type:"STRING",description:"Filter by priority.",enum:["high","medium","low"]},category:{type:"STRING",description:"Filter by category (e.g. 'arbeit', 'privat', 'projekt')."}}}},{name:"add_todo",description:"Add a new todo/task to the list.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"The todo text/description."},priority:{type:"STRING",description:"Priority level. Default: 'medium'.",enum:["high","medium","low"]},category:{type:"STRING",description:"Optional category (e.g. 'arbeit', 'privat', 'projekt')."}},required:["text"]}},{name:"complete_todo",description:"Mark a todo as completed.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The todo ID to complete."}},required:["id"]}},{name:"delete_todo",description:"Delete a todo permanently.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The todo ID to delete."}},required:["id"]}},{name:"update_todo",description:"Update an existing todo's text, priority or category.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The todo ID to update."},text:{type:"STRING",description:"New text."},priority:{type:"STRING",enum:["high","medium","low"]},category:{type:"STRING",description:"New category."}},required:["id"]}},{name:"search_notes",description:"Search notes/memory. Returns all notes if no query given. Use this when the user asks 'what do you know about X' or 'did I note something about Y'.",parameters:{type:"OBJECT",properties:{query:{type:"STRING",description:"Search term to filter notes by title, content or tags. Leave empty to list all."}}}},{name:"add_note",description:"Save a note/memory. Use when user says 'remember that...', 'note that...', 'save that...'.",parameters:{type:"OBJECT",properties:{title:{type:"STRING",description:"Short title for the note."},content:{type:"STRING",description:"Detailed content."},tags:{type:"STRING",description:"Comma-separated tags for categorization."}},required:["title"]}},{name:"update_note",description:"Update an existing note.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The note ID."},title:{type:"STRING"},content:{type:"STRING"},tags:{type:"STRING",description:"Comma-separated tags."}},required:["id"]}},{name:"delete_note",description:"Delete a note.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The note ID to delete."}},required:["id"]}},{name:"list_reminders",description:"List all pending reminders.",parameters:{type:"OBJECT",properties:{include_fired:{type:"BOOLEAN",description:"If true, also show already fired reminders."}}}},{name:"add_reminder",description:"Set a reminder for a specific time. Use when user says 'remind me in 2 hours' or 'remind me tomorrow at 9'.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"What to be reminded about."},trigger_at:{type:"STRING",description:"ISO 8601 datetime when the reminder should fire. Calculate from current time if user says 'in 2 hours' etc. Current timezone is Europe/Vienna (CET/CEST)."}},required:["text","trigger_at"]}},{name:"delete_reminder",description:"Delete/cancel a reminder.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The reminder ID to delete."}},required:["id"]}},{name:"list_email_accounts",description:"List all configured email accounts. Shows account name and email address.",parameters:{type:"OBJECT",properties:{}}},{name:"list_emails",description:"List recent emails from a specific account. Use list_email_accounts first to get the account name.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address (e.g. 'Gmail', 'Work', 'user@example.com')."},folder:{type:"STRING",description:"Mail folder. Default: INBOX."},limit:{type:"NUMBER",description:"Number of emails to fetch. Default: 10."},unseen:{type:"BOOLEAN",description:"If true, only show unread emails."}},required:["account"]}},{name:"read_email",description:"Read the full content of a specific email by UID. Use list_emails first to get the UID.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address."},uid:{type:"NUMBER",description:"The email UID from list_emails."},folder:{type:"STRING",description:"Mail folder. Default: INBOX."}},required:["account","uid"]}},{name:"search_emails",description:"Search emails in an account by subject, sender, or body text.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address."},query:{type:"STRING",description:"Search term to find in subject, from, or body."},limit:{type:"NUMBER",description:"Max results. Default: 10."}},required:["account","query"]}},{name:"send_email",description:"Send a new email from one of the configured accounts.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address to send from."},to:{type:"STRING",description:"Recipient email address."},subject:{type:"STRING",description:"Email subject line."},body:{type:"STRING",description:"Email body text."}},required:["account","to","subject","body"]}},{name:"reply_email",description:"Reply to an existing email. Automatically uses Re: subject and correct recipient.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Account name or email address."},uid:{type:"NUMBER",description:"UID of the email to reply to."},body:{type:"STRING",description:"Reply body text."},folder:{type:"STRING",description:"Mail folder of the original email. Default: INBOX."}},required:["account","uid","body"]}},{name:"email_summary",description:"Get unread email count across all configured accounts. Good for a quick overview.",parameters:{type:"OBJECT",properties:{}}},{name:"list_calendar_accounts",description:"List all configured calendar accounts. Shows account name and provider.",parameters:{type:"OBJECT",properties:{}}},{name:"list_events",description:"List calendar events for a date range. Default: next 7 days. Use list_calendar_accounts first to get the account name.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name (e.g. 'Google', 'iCloud'). Use list_calendar_accounts to find available accounts."},from:{type:"STRING",description:"Start date/time in ISO format (e.g. '2026-04-03'). Default: today."},to:{type:"STRING",description:"End date/time in ISO format (e.g. '2026-04-10'). Default: 7 days from now."}},required:["account"]}},{name:"create_event",description:"Create a new calendar event. Use when the user says 'add to calendar', 'schedule a meeting', etc.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name."},summary:{type:"STRING",description:"Event title/summary."},start:{type:"STRING",description:"Start date/time in ISO format (e.g. '2026-04-05T14:00:00' or '2026-04-05' for all-day)."},end:{type:"STRING",description:"End date/time in ISO format (e.g. '2026-04-05T15:00:00' or '2026-04-06' for all-day)."},description:{type:"STRING",description:"Optional event description/notes."},location:{type:"STRING",description:"Optional event location."},all_day:{type:"BOOLEAN",description:"If true, create an all-day event. Default: false."}},required:["account","summary","start","end"]}},{name:"search_events",description:"Search calendar events by text in title, description or location.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name."},query:{type:"STRING",description:"Search text to find in event title, description or location."},from:{type:"STRING",description:"Start of search range. Default: today."},to:{type:"STRING",description:"End of search range. Default: 30 days from now."}},required:["account","query"]}},{name:"delete_event",description:"Delete a calendar event by its UID. Use list_events or search_events first to find the UID.",parameters:{type:"OBJECT",properties:{account:{type:"STRING",description:"Calendar account name."},uid:{type:"STRING",description:"The event UID to delete (from list_events)."}},required:["account","uid"]}},{name:"calendar_summary",description:"Get an overview of upcoming events across all configured calendar accounts. Shows today's count, this week's count, and next event.",parameters:{type:"OBJECT",properties:{}}},{name:"make_call",description:"Place a real phone call to a SAVED CONTACT. An AI assistant will conduct the conversation autonomously. You MUST use a contact name — arbitrary phone numbers are NOT allowed for safety.",parameters:{type:"OBJECT",properties:{phone:{type:"STRING",description:"Contact name (e.g. 'Mama', 'Restaurant Steirereck'). Must be a saved contact in Settings → Telephony → Contacts."},task:{type:"STRING",description:"The task/instruction for the AI on the call. Be specific about what to say and achieve."},voice:{type:"STRING",description:"Voice for the call AI. Default: same as current voice."},listen:{type:"BOOLEAN",description:"If true, stream live call audio to the user's browser so they can listen in real-time."}},required:["phone","task"]}},{name:"list_active_calls",description:"List currently active phone calls with their status and duration.",parameters:{type:"OBJECT",properties:{}}},{name:"end_active_call",description:"Hang up an active phone call by its call ID.",parameters:{type:"OBJECT",properties:{call_id:{type:"STRING",description:"The call ID to hang up."}},required:["call_id"]}},{name:"prepare_social_post",description:"Prepare a social media post as a draft for user review. The post will appear in the Social Media page where the user can edit, schedule, and publish it.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"The post text/content."},platforms:{type:"ARRAY",items:{type:"STRING"},description:'Target platforms, e.g. ["twitter", "linkedin"].'},title:{type:"STRING",description:"Optional title/headline for the post."},firstComment:{type:"STRING",description:"Optional text for the first comment (common on Instagram/LinkedIn)."},mediaUrls:{type:"ARRAY",items:{type:"STRING"},description:"Optional image URLs to attach."},videoUrl:{type:"STRING",description:"Optional video URL."},thumbnailUrl:{type:"STRING",description:"Optional thumbnail/preview image URL."},scheduledAt:{type:"STRING",description:"Optional ISO 8601 datetime to schedule the post."}},required:["text","platforms"]}},{name:"create_social_post",description:"Create and publish a social media post on one or more platforms.",parameters:{type:"OBJECT",properties:{text:{type:"STRING",description:"The post text/content."},platforms:{type:"ARRAY",items:{type:"STRING"},description:'Platforms to post to, e.g. ["twitter", "linkedin"].'},scheduledAt:{type:"STRING",description:"Optional ISO 8601 datetime to schedule the post for later."}},required:["text","platforms"]}},{name:"list_social_posts",description:"List recent social media posts. Optionally filter by status.",parameters:{type:"OBJECT",properties:{limit:{type:"INTEGER",description:"Max number of posts to return."},status:{type:"STRING",description:"Filter by status: published, scheduled, failed."}}}},{name:"get_social_analytics",description:"Get analytics/metrics for a social media profile.",parameters:{type:"OBJECT",properties:{profileId:{type:"STRING",description:"Profile/platform identifier."}},required:["profileId"]}},{name:"reply_to_social_comment",description:"Reply to a comment on a social media post.",parameters:{type:"OBJECT",properties:{postId:{type:"STRING",description:"The post ID."},commentId:{type:"STRING",description:"The comment ID to reply to (optional for new comment)."},text:{type:"STRING",description:"Reply text."}},required:["postId","text"]}},{name:"save_memory",description:"Save a fact about the user to long-term memory. Use when the user says something personal, a preference, or a fact worth remembering.",parameters:{type:"OBJECT",properties:{content:{type:"STRING",description:"The fact to remember (e.g. 'User prefers dark mode', 'User's birthday is March 5')."}},required:["content"]}},{name:"search_memory",description:"Search long-term memory for facts about the user. Use when you need to recall something previously saved.",parameters:{type:"OBJECT",properties:{query:{type:"STRING",description:"Search query (e.g. 'birthday', 'food preferences')."}},required:["query"]}},{name:"list_memories",description:"List all saved memories/facts about the user.",parameters:{type:"OBJECT",properties:{}}},{name:"delete_memory",description:"Delete a specific memory by ID.",parameters:{type:"OBJECT",properties:{id:{type:"STRING",description:"The memory ID to delete."}},required:["id"]}}]}];class _{constructor(e){d(this,"ws",null);d(this,"handler");d(this,"setupDone",!1);d(this,"resumeHistory",null);this.handler=e}connect(e,i="Kore",t){this.resumeHistory=(t==null?void 0:t.resumeHistory)||null;const l=`${y}?key=${e}`;this.ws=new WebSocket(l);const r=g((t==null?void 0:t.assistantName)||"",(t==null?void 0:t.agents)||[],t==null?void 0:t.recentConversations,t==null?void 0:t.activeSessions,t==null?void 0:t.userName,t==null?void 0:t.contacts);this.ws.onopen=()=>{var s;(s=this.ws)==null||s.send(JSON.stringify({setup:{model:f,generationConfig:{responseModalities:["AUDIO"],speechConfig:{voiceConfig:{prebuiltVoiceConfig:{voiceName:i}}}},systemInstruction:{parts:[{text:r}]},tools:[...T,{googleSearch:{}}],outputAudioTranscription:{},inputAudioTranscription:{}}}))},this.ws.onmessage=async s=>{try{let o;s.data instanceof Blob?o=await s.data.text():o=s.data;const p=JSON.parse(o);this.handleMessage(p)}catch{}},this.ws.onerror=s=>{console.error("[GeminiLive] WebSocket error:",s),this.handler({type:"error",error:"WebSocket connection error"})},this.ws.onclose=s=>{console.log(`[GeminiLive] WebSocket closed: code=${s.code} reason=${s.reason}`),this.handler({type:"closed"}),this.ws=null,this.setupDone=!1}}handleMessage(e){var i,t,l;if("setupComplete"in e){if(this.setupDone=!0,this.resumeHistory&&this.resumeHistory.length>0&&this.ws){const r=this.resumeHistory.map(s=>({role:s.role==="user"?"user":"model",parts:[{text:s.text}]}));this.ws.send(JSON.stringify({clientContent:{turns:r,turnComplete:!0}})),this.resumeHistory=null}this.handler({type:"setupComplete"});return}if("toolCall"in e){const r=e.toolCall;if((i=r.functionCalls)!=null&&i.length){const s=r.functionCalls.map(o=>({id:o.id,name:o.name,args:o.args||{}}));this.handler({type:"toolCall",calls:s})}return}if("serverContent"in e){const r=e.serverContent,s=r.outputTranscription;s!=null&&s.text&&this.handler({type:"text",text:s.text});const o=r.inputTranscription;if((t=o==null?void 0:o.text)!=null&&t.trim()&&this.handler({type:"inputTranscript",text:o.text.trim()}),r.turnComplete){this.handler({type:"turnComplete"});return}if(r.interrupted){this.handler({type:"interrupted"});return}const p=r.modelTurn;if(p!=null&&p.parts)for(const a of p.parts){if((l=a.inlineData)!=null&&l.data){const c=h(a.inlineData.data);this.handler({type:"audio",data:c})}a.text&&this.handler({type:"text",text:a.text})}}}sendToolResponse(e){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({toolResponse:{functionResponses:e.map(i=>({id:i.id,name:i.name,response:i.response}))}}))}sendAudio(e){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({realtimeInput:{audio:{mimeType:"audio/pcm;rate=16000",data:e}}}))}sendImage(e,i="image/jpeg"){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({realtimeInput:{media:{mimeType:i,data:e}}}))}sendText(e){!this.ws||this.ws.readyState!==WebSocket.OPEN||!this.setupDone||this.ws.send(JSON.stringify({clientContent:{turns:[{role:"user",parts:[{text:e}]}],turnComplete:!0}}))}get isReady(){var e;return this.setupDone&&((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}disconnect(){this.ws&&(this.ws.onclose=null,this.ws.close(),this.ws=null),this.setupDone=!1}}export{_ as GeminiLiveClient};