agentix-cli 0.138.1 → 0.139.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/{App-F42CYCKX.js → App-VINKWTYN.js} +2 -2
  2. package/dist/{ChatApp-RPMQBKHV.js → ChatApp-RGHQCRBX.js} +2 -2
  3. package/dist/{absorb-eval-HRPEHJSO.js → absorb-eval-AERHBOQA.js} +2 -2
  4. package/dist/{agent-BLRZVUG4.js → agent-PRHZGF6J.js} +2 -2
  5. package/dist/{board-dashboard-42C7GGD7.js → board-dashboard-GBEBQUFJ.js} +4 -4
  6. package/dist/{chunk-7V73QTQ7.js → chunk-2BEZU5OF.js} +2 -2
  7. package/dist/chunk-3W2BHUGM.js +11 -0
  8. package/dist/chunk-3W2BHUGM.js.map +1 -0
  9. package/dist/{chunk-VVX4RXMV.js → chunk-7KAQHNLT.js} +2 -2
  10. package/dist/{chunk-6AUWEL6V.js → chunk-ANDEMOYE.js} +2 -2
  11. package/dist/{chunk-TFH6S7IT.js → chunk-AXHP6TMT.js} +2 -2
  12. package/dist/{chunk-375MXG3H.js → chunk-B65EC44C.js} +2 -2
  13. package/dist/{chunk-AGQYUOZY.js → chunk-EJIY45FZ.js} +2 -2
  14. package/dist/{chunk-J5FNCTG2.js → chunk-FUJ4KEWS.js} +198 -198
  15. package/dist/chunk-FUJ4KEWS.js.map +1 -0
  16. package/dist/{chunk-AP4DADXG.js → chunk-HGU5B7IY.js} +2 -2
  17. package/dist/{chunk-SK47VJMQ.js → chunk-HXLB2XCT.js} +3 -3
  18. package/dist/{chunk-XBARUCG5.js → chunk-IMUTN7PT.js} +2 -2
  19. package/dist/{chunk-LA6P3TUK.js → chunk-J7U3BASX.js} +2 -2
  20. package/dist/{chunk-ADYTED3R.js → chunk-JBYLG3CQ.js} +2 -2
  21. package/dist/{chunk-QGSUENRK.js → chunk-JJZVFDG6.js} +2 -2
  22. package/dist/{chunk-DBJUGKX2.js → chunk-JS2LEURJ.js} +2 -2
  23. package/dist/{chunk-BKSWOMAM.js → chunk-KO6BU3B3.js} +2 -2
  24. package/dist/{chunk-MTDVAO5C.js → chunk-LMZCB7TT.js} +2 -2
  25. package/dist/{chunk-HJCFLGVT.js → chunk-MGM33GOW.js} +6 -6
  26. package/dist/{chunk-HJCFLGVT.js.map → chunk-MGM33GOW.js.map} +1 -1
  27. package/dist/{chunk-AOV5RMFH.js → chunk-MUC7MMTT.js} +2 -2
  28. package/dist/{chunk-JIJDBCV7.js → chunk-NMYPZR4W.js} +2 -2
  29. package/dist/{chunk-EGPCEQJN.js → chunk-NQGLKWDO.js} +2 -2
  30. package/dist/{chunk-Y7IHOQC7.js → chunk-O6WW7ATO.js} +2 -2
  31. package/dist/{chunk-UPQTTOVQ.js → chunk-QN2OTBVC.js} +2 -2
  32. package/dist/{chunk-6XMISPQD.js → chunk-RIYQNADV.js} +5 -5
  33. package/dist/{chunk-XVYIPVSC.js → chunk-STIZFWDJ.js} +2 -2
  34. package/dist/{chunk-HQH44RGL.js → chunk-XQVL2RYG.js} +2 -2
  35. package/dist/{chunk-6VP2KMUM.js → chunk-Z5IHT6RK.js} +2 -2
  36. package/dist/cli.js +1 -1
  37. package/dist/{client-EB55Y6EJ.js → client-2KZWK6YT.js} +2 -2
  38. package/dist/{config-7DRUA5R3.js → config-THFRJMZD.js} +2 -2
  39. package/dist/{config-mutate-GGA7VXXH.js → config-mutate-HXWAXWHC.js} +2 -2
  40. package/dist/config-mutator-JZOAWRBH.js +2 -0
  41. package/dist/{contributions-TZ26MTML.js → contributions-OSIKL25B.js} +2 -2
  42. package/dist/{doctor-GTRZ7GWF.js → doctor-TOSA3RWP.js} +2 -2
  43. package/dist/{follow-up-tool-PNB7KMCY.js → follow-up-tool-M2KCLRQQ.js} +2 -2
  44. package/dist/{hub-QWJR4E6V.js → hub-XGWCWKMT.js} +2 -2
  45. package/dist/index.d.ts +46 -0
  46. package/dist/index.js +1 -1
  47. package/dist/{program-5RLTC6CR.js → program-X6EKIO24.js} +188 -188
  48. package/dist/program-X6EKIO24.js.map +1 -0
  49. package/dist/{promote-HAPXWGYH.js → promote-YVWRKIAU.js} +2 -2
  50. package/dist/{query-ICLOVLZ3.js → query-X4AFOKZ7.js} +2 -2
  51. package/dist/{query-settings-7AXUOHDL.js → query-settings-HV2RFQK7.js} +2 -2
  52. package/dist/{registry-RH5NFDL7.js → registry-B276QJ75.js} +2 -2
  53. package/dist/{request-planner-TDCLF2CH.js → request-planner-MY6VKTVC.js} +2 -2
  54. package/dist/{review-candidates-QCBXLWG6.js → review-candidates-BRTBB5XV.js} +2 -2
  55. package/dist/{routing-YUP3HHL5.js → routing-CSVLOGNS.js} +2 -2
  56. package/dist/schedule-tool-GUKYTQTY.js +2 -0
  57. package/dist/{scheduler-7NK2FH5V.js → scheduler-OUAVAU4O.js} +2 -2
  58. package/dist/{seat-PTPPQOTP.js → seat-H2QR3CRX.js} +2 -2
  59. package/dist/{select-2XSTWMBR.js → select-EEL5AZ2I.js} +2 -2
  60. package/dist/{set-enabled-SS5Q3OX7.js → set-enabled-IBGEH6U6.js} +2 -2
  61. package/dist/{tool-QCMSXEDB.js → tool-DFPOFXGA.js} +2 -2
  62. package/dist/{tool-RK4LDFFH.js → tool-GJ75MWV5.js} +2 -2
  63. package/dist/{wiki-Q2E44YAE.js → wiki-ISKHNG3P.js} +2 -2
  64. package/dist/wiki-enrich-7SBCPK2E.js +2 -0
  65. package/package.json +1 -1
  66. package/dist/chunk-J5FNCTG2.js.map +0 -1
  67. package/dist/chunk-LLNPKE7H.js +0 -11
  68. package/dist/chunk-LLNPKE7H.js.map +0 -1
  69. package/dist/config-mutator-POFVILXH.js +0 -2
  70. package/dist/program-5RLTC6CR.js.map +0 -1
  71. package/dist/schedule-tool-3C22NBMN.js +0 -2
  72. package/dist/wiki-enrich-6ULCDOTX.js +0 -2
  73. /package/dist/{App-F42CYCKX.js.map → App-VINKWTYN.js.map} +0 -0
  74. /package/dist/{ChatApp-RPMQBKHV.js.map → ChatApp-RGHQCRBX.js.map} +0 -0
  75. /package/dist/{absorb-eval-HRPEHJSO.js.map → absorb-eval-AERHBOQA.js.map} +0 -0
  76. /package/dist/{agent-BLRZVUG4.js.map → agent-PRHZGF6J.js.map} +0 -0
  77. /package/dist/{board-dashboard-42C7GGD7.js.map → board-dashboard-GBEBQUFJ.js.map} +0 -0
  78. /package/dist/{chunk-7V73QTQ7.js.map → chunk-2BEZU5OF.js.map} +0 -0
  79. /package/dist/{chunk-VVX4RXMV.js.map → chunk-7KAQHNLT.js.map} +0 -0
  80. /package/dist/{chunk-6AUWEL6V.js.map → chunk-ANDEMOYE.js.map} +0 -0
  81. /package/dist/{chunk-TFH6S7IT.js.map → chunk-AXHP6TMT.js.map} +0 -0
  82. /package/dist/{chunk-375MXG3H.js.map → chunk-B65EC44C.js.map} +0 -0
  83. /package/dist/{chunk-AGQYUOZY.js.map → chunk-EJIY45FZ.js.map} +0 -0
  84. /package/dist/{chunk-AP4DADXG.js.map → chunk-HGU5B7IY.js.map} +0 -0
  85. /package/dist/{chunk-SK47VJMQ.js.map → chunk-HXLB2XCT.js.map} +0 -0
  86. /package/dist/{chunk-XBARUCG5.js.map → chunk-IMUTN7PT.js.map} +0 -0
  87. /package/dist/{chunk-LA6P3TUK.js.map → chunk-J7U3BASX.js.map} +0 -0
  88. /package/dist/{chunk-ADYTED3R.js.map → chunk-JBYLG3CQ.js.map} +0 -0
  89. /package/dist/{chunk-QGSUENRK.js.map → chunk-JJZVFDG6.js.map} +0 -0
  90. /package/dist/{chunk-DBJUGKX2.js.map → chunk-JS2LEURJ.js.map} +0 -0
  91. /package/dist/{chunk-BKSWOMAM.js.map → chunk-KO6BU3B3.js.map} +0 -0
  92. /package/dist/{chunk-MTDVAO5C.js.map → chunk-LMZCB7TT.js.map} +0 -0
  93. /package/dist/{chunk-AOV5RMFH.js.map → chunk-MUC7MMTT.js.map} +0 -0
  94. /package/dist/{chunk-JIJDBCV7.js.map → chunk-NMYPZR4W.js.map} +0 -0
  95. /package/dist/{chunk-EGPCEQJN.js.map → chunk-NQGLKWDO.js.map} +0 -0
  96. /package/dist/{chunk-Y7IHOQC7.js.map → chunk-O6WW7ATO.js.map} +0 -0
  97. /package/dist/{chunk-UPQTTOVQ.js.map → chunk-QN2OTBVC.js.map} +0 -0
  98. /package/dist/{chunk-6XMISPQD.js.map → chunk-RIYQNADV.js.map} +0 -0
  99. /package/dist/{chunk-XVYIPVSC.js.map → chunk-STIZFWDJ.js.map} +0 -0
  100. /package/dist/{chunk-HQH44RGL.js.map → chunk-XQVL2RYG.js.map} +0 -0
  101. /package/dist/{chunk-6VP2KMUM.js.map → chunk-Z5IHT6RK.js.map} +0 -0
  102. /package/dist/{client-EB55Y6EJ.js.map → client-2KZWK6YT.js.map} +0 -0
  103. /package/dist/{config-7DRUA5R3.js.map → config-THFRJMZD.js.map} +0 -0
  104. /package/dist/{config-mutate-GGA7VXXH.js.map → config-mutate-HXWAXWHC.js.map} +0 -0
  105. /package/dist/{config-mutator-POFVILXH.js.map → config-mutator-JZOAWRBH.js.map} +0 -0
  106. /package/dist/{contributions-TZ26MTML.js.map → contributions-OSIKL25B.js.map} +0 -0
  107. /package/dist/{doctor-GTRZ7GWF.js.map → doctor-TOSA3RWP.js.map} +0 -0
  108. /package/dist/{follow-up-tool-PNB7KMCY.js.map → follow-up-tool-M2KCLRQQ.js.map} +0 -0
  109. /package/dist/{hub-QWJR4E6V.js.map → hub-XGWCWKMT.js.map} +0 -0
  110. /package/dist/{promote-HAPXWGYH.js.map → promote-YVWRKIAU.js.map} +0 -0
  111. /package/dist/{query-ICLOVLZ3.js.map → query-X4AFOKZ7.js.map} +0 -0
  112. /package/dist/{query-settings-7AXUOHDL.js.map → query-settings-HV2RFQK7.js.map} +0 -0
  113. /package/dist/{registry-RH5NFDL7.js.map → registry-B276QJ75.js.map} +0 -0
  114. /package/dist/{request-planner-TDCLF2CH.js.map → request-planner-MY6VKTVC.js.map} +0 -0
  115. /package/dist/{review-candidates-QCBXLWG6.js.map → review-candidates-BRTBB5XV.js.map} +0 -0
  116. /package/dist/{routing-YUP3HHL5.js.map → routing-CSVLOGNS.js.map} +0 -0
  117. /package/dist/{schedule-tool-3C22NBMN.js.map → schedule-tool-GUKYTQTY.js.map} +0 -0
  118. /package/dist/{scheduler-7NK2FH5V.js.map → scheduler-OUAVAU4O.js.map} +0 -0
  119. /package/dist/{seat-PTPPQOTP.js.map → seat-H2QR3CRX.js.map} +0 -0
  120. /package/dist/{select-2XSTWMBR.js.map → select-EEL5AZ2I.js.map} +0 -0
  121. /package/dist/{set-enabled-SS5Q3OX7.js.map → set-enabled-IBGEH6U6.js.map} +0 -0
  122. /package/dist/{tool-QCMSXEDB.js.map → tool-DFPOFXGA.js.map} +0 -0
  123. /package/dist/{tool-RK4LDFFH.js.map → tool-GJ75MWV5.js.map} +0 -0
  124. /package/dist/{wiki-Q2E44YAE.js.map → wiki-ISKHNG3P.js.map} +0 -0
  125. /package/dist/{wiki-enrich-6ULCDOTX.js.map → wiki-enrich-7SBCPK2E.js.map} +0 -0
@@ -1,11 +0,0 @@
1
- import{a as h,b as m}from"./chunk-SHEUCITK.js";import{randomUUID as C}from"crypto";var w=["ringing","answered","later"],p=`id, agent_id AS agentId, kind, reason, urgency, status, created_at AS createdAt,
2
- ringing_since AS ringingSince, answered_at AS answeredAt, ended_at AS endedAt,
3
- ring_again_at AS ringAgainAt, note, summary, channel, chat_id AS chatId`,f=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS calls (
4
- id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, reason TEXT NOT NULL,
5
- urgency TEXT NOT NULL, status TEXT NOT NULL, created_at INTEGER NOT NULL,
6
- ringing_since INTEGER, answered_at INTEGER, ended_at INTEGER,
7
- ring_again_at INTEGER, note TEXT, summary TEXT);
8
- CREATE INDEX IF NOT EXISTS calls_recent ON calls(created_at DESC);`);let s=new Set(e.prepare("PRAGMA table_info(calls)").all().map(n=>n.name));s.has("kind")||e.exec("ALTER TABLE calls ADD COLUMN kind TEXT NOT NULL DEFAULT 'voice'"),s.has("channel")||e.exec("ALTER TABLE calls ADD COLUMN channel TEXT"),s.has("chat_id")||e.exec("ALTER TABLE calls ADD COLUMN chat_id TEXT")}insert(e){this.db.prepare(`INSERT INTO calls (id, agent_id, kind, reason, urgency, status, created_at, ringing_since,
9
- answered_at, ended_at, ring_again_at, note, summary, channel, chat_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(e.id,e.agentId,e.kind,e.reason,e.urgency,e.status,e.createdAt,e.ringingSince,e.answeredAt,e.endedAt,e.ringAgainAt,e.note,e.summary,e.channel,e.chatId)}get(e){return this.db.prepare(`SELECT ${p} FROM calls WHERE id=?`).get(e)}update(e,s){let n={reason:"reason",urgency:"urgency",status:"status",ringingSince:"ringing_since",answeredAt:"answered_at",endedAt:"ended_at",ringAgainAt:"ring_again_at",note:"note",summary:"summary"},t=Object.keys(s).filter(i=>i in n);if(t.length){let i=t.map(r=>`${n[r]}=?`).join(", ");this.db.prepare(`UPDATE calls SET ${i} WHERE id=?`).run(...t.map(r=>s[r]??null),e)}return this.get(e)}transition(e,s,n){let t=Array.isArray(s)?s:[s],i={status:"status",ringingSince:"ringing_since",answeredAt:"answered_at",endedAt:"ended_at",ringAgainAt:"ring_again_at",note:"note",summary:"summary"},r=Object.keys(n).filter(o=>o in i),l=r.map(o=>`${i[o]}=?`).join(", "),g=t.map(()=>"?").join(",");return this.db.prepare(`UPDATE calls SET ${l} WHERE id=? AND status IN (${g})`).run(...r.map(o=>n[o]??null),e,...t).changes?this.get(e):void 0}list(e={}){let s=Math.min(Math.max(e.limit??50,1),200),n=[],t=[];e.status?.length&&(n.push(`status IN (${e.status.map(()=>"?").join(",")})`),t.push(...e.status)),e.kind&&(n.push("kind=?"),t.push(e.kind));let i=n.length?`WHERE ${n.join(" AND ")}`:"";return this.db.prepare(`SELECT ${p} FROM calls ${i} ORDER BY created_at DESC, rowid DESC LIMIT ?`).all(...t,s)}countSince(e,s){return this.db.prepare("SELECT COUNT(*) AS n FROM calls WHERE agent_id=? AND created_at>?").get(e,s).n}};var A=200,S=1e4,k=10*6e4,_=10,y=240;function v(a=process.env){return a.AGENTX_TASK_ID?{"X-AgentX-Task":a.AGENTX_TASK_ID}:a.AGENTX_CHANNEL&&a.AGENTX_CHAT_ID?{"X-AgentX-Channel":a.AGENTX_CHANNEL,"X-AgentX-Chat":a.AGENTX_CHAT_ID}:{}}function I(a){return`[Call answered] The owner just picked up the voice call you asked for. You called because: "${a.reason}". Speak first: greet them in a few words and say why you called, then let them answer.`}var x="[Call ended] The owner hung up. In two or three plain sentences, summarise what was said and decided on this call, for your records. Reply with the summary only.",T=class{constructor(e){this.deps=e}widgetSeenAt=0;waiting=new Map;now(){return this.deps.now?.()??Date.now()}name(e){return this.deps.agentName(e)??e}async request(e,s={}){let n=String(e.agentId??"").trim(),t=String(e.reason??"").replace(/\s+/g," ").trim(),i=e.urgency==="urgent"?"urgent":"normal",r=e.kind==="camera"?"camera":"voice";if(e.kind!==void 0&&e.kind!=="voice"&&e.kind!=="camera")return{ok:!1,status:400,error:"kind must be voice or camera"};if(!n||!t)return{ok:!1,status:400,error:"Required: agentId and reason"};if(t.length>A)return{ok:!1,status:413,error:`reason is over ${A} characters; keep it to one line`};if(this.deps.agentName(n)===null)return{ok:!1,status:404,error:`Unknown agent: ${n}`};if(!this.deps.isRunningTurn(n,s))return{ok:!1,status:403,error:`No running turn of ${n} placed this call. An agent calls from inside its own run.`};let l=this.deps.config();if(!l.allow.includes("*")&&!l.allow.includes(n))return{ok:!1,status:403,error:`${n} ${r==="camera"?"may not ask to see through the owner's camera":"may not call the owner"}. Add it to calls.allow in agentx.json (or: agentx call allow ${n}).`};if(await this.sweep(),this.deps.store.list({status:w,limit:200}).some(u=>u.agentId===n))return{ok:!1,status:409,error:`${n} already has a call in progress`};let g=this.now();if(this.deps.store.countSince(n,g-36e5)>=l.maxPerHour)return{ok:!1,status:429,error:`${n} has placed ${l.maxPerHour} calls in the last hour (calls.maxPerHour)`};let d=r==="camera"?this.deps.turnSession?.(n,s)??s:{},o={id:`call-${C().slice(0,8)}`,agentId:n,kind:r,reason:t,urgency:i,status:"ringing",createdAt:g,ringingSince:g,answeredAt:null,endedAt:null,ringAgainAt:null,note:null,summary:null,channel:d.channel&&d.chatId?d.channel:null,chatId:d.channel&&d.chatId?d.chatId:null};this.deps.store.insert(o),this.deps.log?.(`[calls] ${n} asks ${r==="camera"?"to see":"for a call"} (${i}): ${t}`);let E=await this.ring(o);return{ok:!0,call:this.deps.store.get(o.id),rang:E}}async ring(e){let s=(this.deps.focus??h)();return s.active&&e.urgency!=="urgent"?(this.deps.store.transition(e.id,"ringing",{status:"missed",ringingSince:null,note:m(s)})&&await this.notice(e,this.missedTitle(e)),!1):e.kind==="camera"?(await this.notice(e,`${this.name(e.agentId)} wants to see through your camera`,`Open the phone app and tap Show within ${this.deps.config().ringSeconds} s.`),"notify"):this.widgetAlive()?"widget":(await this.notice(e,`${this.name(e.agentId)} is calling`,`Open AgentX Voice to answer within ${this.deps.config().ringSeconds} s.`),"notify")}async notice(e,s,n){try{await this.deps.alert({title:s,message:n?`${e.reason}
10
- ${n}`:e.reason,urgent:e.urgency==="urgent",from:e.agentId})}catch(t){this.deps.log?.(`[calls] notice for ${e.id} failed: ${t?.message??t}`)}}missedTitle(e){return e.kind==="camera"?`${this.name(e.agentId)} asked to see through your camera`:`Missed call from ${this.name(e.agentId)}`}widgetAlive(){return this.now()-this.widgetSeenAt<S}async ringing(e={}){return this.widgetSeenAt=this.now(),await this.hold(e),await this.sweep(),this.deps.store.list({status:["ringing"],kind:"voice",limit:20}).reverse()}async hold(e){let s=this.now(),n=this.deps.store.list({status:["ringing"],kind:"voice",limit:20});for(let t of this.waiting.keys())n.some(i=>i.id===t)||this.waiting.delete(t);for(let t of n){if(t.id===e.showing){this.waiting.delete(t.id)&&this.deps.store.transition(t.id,"ringing",{ringingSince:s});continue}if(!e.busy)continue;let i=this.waiting.get(t.id);i!==void 0&&s-i>=k||!this.deps.store.transition(t.id,"ringing",{ringingSince:s})||i!==void 0||(this.waiting.set(t.id,s),this.deps.log?.(`[calls] ${t.id} from ${t.agentId} waits: the widget is busy`),await this.notice(t,`${this.name(t.agentId)} is calling`,"AgentX Voice is busy. The call rings when it is free."))}}async asking(){return await this.sweep(),this.deps.store.list({status:["ringing"],kind:"camera",limit:20}).reverse()}async sweep(){let e=this.now(),s=this.deps.config().ringSeconds*1e3,n=this.deps.config().maxCallMinutes*6e4;for(let t of this.deps.store.list({status:["ringing","later","answered"],limit:200}))if(t.status==="ringing"&&t.ringingSince!==null&&e-t.ringingSince>=s){if(!this.deps.store.transition(t.id,"ringing",{status:"missed",ringingSince:null,note:this.waiting.has(t.id)?"widget busy":"not answered"}))continue;this.deps.log?.(`[calls] ${t.id} from ${t.agentId} missed`),await this.notice(t,this.missedTitle(t))}else if(t.status==="answered"&&t.answeredAt!==null&&e-t.answeredAt>=n){if(!this.deps.store.transition(t.id,"answered",{status:"ended",endedAt:e,note:"no hang-up"}))continue;this.deps.log?.(`[calls] ${t.id} from ${t.agentId} ended: no hang-up in ${this.deps.config().maxCallMinutes} min`)}else if(t.status==="later"&&t.ringAgainAt!==null&&e>=t.ringAgainAt){let i=this.deps.store.transition(t.id,"later",{status:"ringing",ringingSince:e,ringAgainAt:null});i&&await this.ring(i)}}answer(e){let s=this.deps.store.get(e);if(!s)return c(e);let n=this.deps.store.transition(e,"ringing",{status:"answered",answeredAt:this.now(),ringingSince:null});return n?(this.deps.log?.(`[calls] ${e} answered (${s.agentId})`),n.kind==="camera"?{ok:!0,call:n}:{ok:!0,call:n,opener:I(n)}):{ok:!1,status:409,error:`call is ${this.deps.store.get(e)?.status}, not ringing`}}decline(e){if(!this.deps.store.get(e))return c(e);let n=this.deps.store.transition(e,["ringing","later"],{status:"declined",endedAt:this.now(),ringingSince:null,ringAgainAt:null});return n?{ok:!0,call:n}:{ok:!1,status:409,error:`call is ${this.deps.store.get(e)?.status}`}}later(e,s){if(!this.deps.store.get(e))return c(e);let t=s===void 0?_:Number(s);if(!Number.isInteger(t)||t<1||t>y)return{ok:!1,status:400,error:`minutes must be a whole number from 1 to ${y}`};let i=this.deps.store.transition(e,"ringing",{status:"later",ringingSince:null,ringAgainAt:this.now()+t*6e4});return i?{ok:!0,call:i}:{ok:!1,status:409,error:`call is ${this.deps.store.get(e)?.status}, not ringing`}}hangup(e){let s=this.deps.store.get(e);if(!s)return c(e);let n=this.deps.store.transition(e,"answered",{status:"ended",endedAt:this.now()});if(!n)return{ok:!1,status:409,error:`call is ${s.status}, not answered`};this.deps.log?.(`[calls] ${e} ended (${s.agentId})`);let t=this.deps.summarize;if(n.kind==="camera"||!this.deps.config().summary||!t)return{ok:!0,call:n};let i=(async()=>{try{let r=(await t(n))?.trim();if(!r)return;let l=this.deps.store.update(e,{summary:r});this.deps.file?.(l,r)}catch(r){this.deps.log?.(`[calls] summary for ${e} failed: ${r?.message??r}`)}})();return{ok:!0,call:n,summarized:i}}endCamera(e,s){let n=this.deps.store.get(e);if(!n||n.kind!=="camera")return!1;let t=this.deps.store.transition(e,"answered",{status:"ended",endedAt:this.now(),note:s??null});return t&&this.deps.log?.(`[calls] ${e} ended (${n.agentId}): ${s??"share over"}`),!!t}get(e){return this.deps.store.get(e)}list(e={}){return this.deps.store.list(e)}},c=a=>({ok:!1,status:404,error:`No such call: ${a}`});export{f as a,v as b,x as c,T as d};
11
- //# sourceMappingURL=chunk-LLNPKE7H.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/calls/service.ts","../src/calls/store.ts"],"sourcesContent":["// --- An agent rings the owner (#321) ---\n//\n// An agent that needs the owner directly asks for a call. It rings on the\n// desktop widget (AgentX Voice), which polls `ringing()`. Answering starts\n// the widget's hands-free conversation with that agent, which opens with\n// its reason. When the widget is not running, `notify` stands in. While\n// the widget is busy (a turn, the microphone, another call) the call waits\n// for it: its ring time does not run, and the owner is told once (#408).\n//\n// Checked before anything rings, in this order:\n// 0. the caller is that agent: a turn of it is running now, named by its\n// task id or by its channel and chat (see CallerProof),\n// 1. the owner allows this agent (calls.allow; empty allows nobody),\n// 2. the agent has no other call in progress,\n// 3. it is under calls.maxPerHour,\n// 4. Focus: a non-urgent call does not ring. It becomes a missed call,\n// and its notice goes through notify, which holds it until Focus\n// ends. Urgent calls ring through, as `notify --urgent` does.\n//\n// A camera ask (#325 phase 3, kind \"camera\") goes through the same checks\n// and the same table. It never rings the widget: the notice goes to the\n// phone through notify, and the phone app polls `asking()` to show a\n// Show / Decline bar. Answering it is the owner tapping Show; the camera\n// opens only then, and the share ends the ask (see camera-api.ts).\n\nimport { randomUUID } from \"crypto\"\nimport { focusLabel, readFocus, type FocusState } from \"@/notify/focus\"\nimport type { CallsConfig } from \"@/daemon/config\"\nimport { LIVE, type Call, type CallKind, type CallStore, type CallUrgency } from \"./store\"\n\nexport const REASON_MAX = 200\n/** The widget polls every 2 s; missing this long means it is not running. */\nexport const WIDGET_FRESH_MS = 10_000\n/** The longest a call waits for a busy widget before its ring time runs. */\nexport const BUSY_WAIT_MAX_MS = 10 * 60_000\nexport const LATER_DEFAULT_MINUTES = 10\nexport const LATER_MAX_MINUTES = 240\n\nexport type CallResult =\n | { ok: true; call: Call }\n | { ok: false; status: number; error: string }\n\n/** What the request says about the turn placing it: the run's\n * AGENTX_TASK_ID, or, for a warm process that has none, its\n * AGENTX_CHANNEL and AGENTX_CHAT_ID. Loopback is not an identity. */\nexport interface CallerProof {\n taskId?: string\n channel?: string\n chatId?: string\n}\n\n/** The proof headers for a call placed from inside an agent's run. */\nexport function callerHeaders(env: NodeJS.ProcessEnv = process.env): Record<string, string> {\n if (env.AGENTX_TASK_ID) return { \"X-AgentX-Task\": env.AGENTX_TASK_ID }\n if (env.AGENTX_CHANNEL && env.AGENTX_CHAT_ID) {\n return { \"X-AgentX-Channel\": env.AGENTX_CHANNEL, \"X-AgentX-Chat\": env.AGENTX_CHAT_ID }\n }\n return {}\n}\n\n/** What the widget says with its poll. A widget from before #408 says nothing. */\nexport interface WidgetState {\n /** It cannot ring a new call now. */\n busy?: boolean\n /** The call ringing on it. */\n showing?: string\n}\n\nexport interface CallDeps {\n store: CallStore\n config: () => CallsConfig\n /** The agent's display name, or null when there is no such agent here. */\n agentName: (agentId: string) => string | null\n /** True when `proof` names a running turn of `agentId`. */\n isRunningTurn: (agentId: string, proof: CallerProof) => boolean\n /** The channel and chat of that running turn, when it has one, so a\n * camera ask is answered where it was asked. Unset: only a proof that\n * names them itself is kept. */\n turnSession?: (agentId: string, proof: CallerProof) => { channel?: string; chatId?: string } | null\n /** Tell the owner through notify. `urgent` passes Focus, like notify --urgent. */\n alert: (notice: { title: string; message: string; urgent: boolean; from: string }) => Promise<void>\n /** Ask the agent, in its voice session, to summarise the call. */\n summarize?: (call: Call) => Promise<string | null>\n /** File a finished summary where the dashboard shows it. */\n file?: (call: Call, summary: string) => void\n focus?: () => FocusState\n now?: () => number\n log?: (m: string) => void\n}\n\n/** What the widget sends through /ask when the owner answers, so the\n * agent speaks first and says why it called. */\nexport function openerPrompt(call: Pick<Call, \"reason\">): string {\n return \"[Call answered] The owner just picked up the voice call you asked for. \" +\n `You called because: \"${call.reason}\". Speak first: greet them in a few words ` +\n \"and say why you called, then let them answer.\"\n}\n\nexport const SUMMARY_PROMPT =\n \"[Call ended] The owner hung up. In two or three plain sentences, summarise what \" +\n \"was said and decided on this call, for your records. Reply with the summary only.\"\n\nexport class CallService {\n private widgetSeenAt = 0\n /** Calls waiting for a busy widget, and since when. */\n private waiting = new Map<string, number>()\n\n constructor(private deps: CallDeps) {}\n\n private now(): number { return this.deps.now?.() ?? Date.now() }\n private name(agentId: string): string { return this.deps.agentName(agentId) ?? agentId }\n\n /** An agent asks for a call, or to see (kind \"camera\"). 201 ringing,\n * 202 held as missed (Focus). */\n async request(input: { agentId?: unknown; reason?: unknown; urgency?: unknown; kind?: unknown }, proof: CallerProof = {}): Promise<CallResult & { rang?: \"widget\" | \"notify\" | false }> {\n const agentId = String(input.agentId ?? \"\").trim()\n const reason = String(input.reason ?? \"\").replace(/\\s+/g, \" \").trim()\n const urgency: CallUrgency = input.urgency === \"urgent\" ? \"urgent\" : \"normal\"\n const kind: CallKind = input.kind === \"camera\" ? \"camera\" : \"voice\"\n if (input.kind !== undefined && input.kind !== \"voice\" && input.kind !== \"camera\") return { ok: false, status: 400, error: \"kind must be voice or camera\" }\n if (!agentId || !reason) return { ok: false, status: 400, error: \"Required: agentId and reason\" }\n if (reason.length > REASON_MAX) return { ok: false, status: 413, error: `reason is over ${REASON_MAX} characters; keep it to one line` }\n if (this.deps.agentName(agentId) === null) return { ok: false, status: 404, error: `Unknown agent: ${agentId}` }\n if (!this.deps.isRunningTurn(agentId, proof)) {\n return { ok: false, status: 403, error: `No running turn of ${agentId} placed this call. An agent calls from inside its own run.` }\n }\n\n const cfg = this.deps.config()\n if (!cfg.allow.includes(\"*\") && !cfg.allow.includes(agentId)) {\n const verb = kind === \"camera\" ? \"may not ask to see through the owner's camera\" : \"may not call the owner\"\n return { ok: false, status: 403, error: `${agentId} ${verb}. Add it to calls.allow in agentx.json (or: agentx call allow ${agentId}).` }\n }\n await this.sweep()\n if (this.deps.store.list({ status: LIVE, limit: 200 }).some((c) => c.agentId === agentId)) {\n return { ok: false, status: 409, error: `${agentId} already has a call in progress` }\n }\n const now = this.now()\n if (this.deps.store.countSince(agentId, now - 3_600_000) >= cfg.maxPerHour) {\n return { ok: false, status: 429, error: `${agentId} has placed ${cfg.maxPerHour} calls in the last hour (calls.maxPerHour)` }\n }\n\n // Where the ask came from, for kind \"camera\": the turn's own chat, or\n // the one the proof names. A task run has neither.\n const session: { channel?: string; chatId?: string } = kind === \"camera\" ? (this.deps.turnSession?.(agentId, proof) ?? proof) : {}\n const call: Call = {\n id: `call-${randomUUID().slice(0, 8)}`, agentId, kind, reason, urgency, status: \"ringing\", createdAt: now,\n ringingSince: now, answeredAt: null, endedAt: null, ringAgainAt: null, note: null, summary: null,\n channel: session.channel && session.chatId ? session.channel : null,\n chatId: session.channel && session.chatId ? session.chatId : null,\n }\n this.deps.store.insert(call)\n this.deps.log?.(`[calls] ${agentId} asks ${kind === \"camera\" ? \"to see\" : \"for a call\"} (${urgency}): ${reason}`)\n const rang = await this.ring(call)\n const saved = this.deps.store.get(call.id)!\n return { ok: true, call: saved, rang }\n }\n\n /** Ring now, or hold as missed in Focus. Returns how it rang. */\n private async ring(call: Call): Promise<\"widget\" | \"notify\" | false> {\n const focus = (this.deps.focus ?? readFocus)()\n if (focus.active && call.urgency !== \"urgent\") {\n if (!this.deps.store.transition(call.id, \"ringing\", { status: \"missed\", ringingSince: null, note: focusLabel(focus) })) return false\n await this.notice(call, this.missedTitle(call))\n return false\n }\n // A camera ask is answered on the phone, never on the widget.\n if (call.kind === \"camera\") {\n await this.notice(call, `${this.name(call.agentId)} wants to see through your camera`,\n `Open the phone app and tap Show within ${this.deps.config().ringSeconds} s.`)\n return \"notify\"\n }\n if (this.widgetAlive()) return \"widget\"\n await this.notice(call, `${this.name(call.agentId)} is calling`,\n `Open AgentX Voice to answer within ${this.deps.config().ringSeconds} s.`)\n return \"notify\"\n }\n\n private async notice(call: Call, title: string, extra?: string): Promise<void> {\n try {\n await this.deps.alert({\n title, message: extra ? `${call.reason}\\n${extra}` : call.reason,\n urgent: call.urgency === \"urgent\", from: call.agentId,\n })\n } catch (e: any) {\n this.deps.log?.(`[calls] notice for ${call.id} failed: ${e?.message ?? e}`)\n }\n }\n\n private missedTitle(call: Call): string {\n return call.kind === \"camera\" ? `${this.name(call.agentId)} asked to see through your camera` : `Missed call from ${this.name(call.agentId)}`\n }\n\n /** True when the widget polled recently. */\n widgetAlive(): boolean {\n return this.now() - this.widgetSeenAt < WIDGET_FRESH_MS\n }\n\n /** The widget's poll: voice calls ringing now, oldest first. Marks it alive. */\n async ringing(widget: WidgetState = {}): Promise<Call[]> {\n this.widgetSeenAt = this.now()\n await this.hold(widget)\n await this.sweep()\n return this.deps.store.list({ status: [\"ringing\"], kind: \"voice\", limit: 20 }).reverse()\n }\n\n /** A busy widget cannot ring: the ring time of each call it is not\n * showing starts over at every poll, for BUSY_WAIT_MAX_MS at most, and\n * the owner is told once that the call waits. It starts over once more\n * when the widget first shows a call that waited. */\n private async hold(widget: WidgetState): Promise<void> {\n const now = this.now()\n const live = this.deps.store.list({ status: [\"ringing\"], kind: \"voice\", limit: 20 })\n for (const id of this.waiting.keys()) if (!live.some((c) => c.id === id)) this.waiting.delete(id)\n for (const call of live) {\n if (call.id === widget.showing) {\n if (this.waiting.delete(call.id)) this.deps.store.transition(call.id, \"ringing\", { ringingSince: now })\n continue\n }\n if (!widget.busy) continue\n const since = this.waiting.get(call.id)\n if (since !== undefined && now - since >= BUSY_WAIT_MAX_MS) continue\n if (!this.deps.store.transition(call.id, \"ringing\", { ringingSince: now }) || since !== undefined) continue\n this.waiting.set(call.id, now)\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} waits: the widget is busy`)\n await this.notice(call, `${this.name(call.agentId)} is calling`, \"AgentX Voice is busy. The call rings when it is free.\")\n }\n }\n\n /** The phone app's poll: camera asks waiting for the owner, oldest first.\n * Does not count as the widget being up. */\n async asking(): Promise<Call[]> {\n await this.sweep()\n return this.deps.store.list({ status: [\"ringing\"], kind: \"camera\", limit: 20 }).reverse()\n }\n\n /** Unanswered calls become missed; \"later\" calls that came due ring\n * again; answered calls nobody hung up end after calls.maxCallMinutes. */\n async sweep(): Promise<void> {\n const now = this.now()\n const ringFor = this.deps.config().ringSeconds * 1000\n const talkFor = this.deps.config().maxCallMinutes * 60_000\n for (const call of this.deps.store.list({ status: [\"ringing\", \"later\", \"answered\"], limit: 200 })) {\n // The list was read before any await below: each move re-checks the\n // status in the store, so a call answered meanwhile is left alone.\n if (call.status === \"ringing\" && call.ringingSince !== null && now - call.ringingSince >= ringFor) {\n if (!this.deps.store.transition(call.id, \"ringing\", { status: \"missed\", ringingSince: null, note: this.waiting.has(call.id) ? \"widget busy\" : \"not answered\" })) continue\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} missed`)\n await this.notice(call, this.missedTitle(call))\n } else if (call.status === \"answered\" && call.answeredAt !== null && now - call.answeredAt >= talkFor) {\n if (!this.deps.store.transition(call.id, \"answered\", { status: \"ended\", endedAt: now, note: \"no hang-up\" })) continue\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} ended: no hang-up in ${this.deps.config().maxCallMinutes} min`)\n } else if (call.status === \"later\" && call.ringAgainAt !== null && now >= call.ringAgainAt) {\n const again = this.deps.store.transition(call.id, \"later\", { status: \"ringing\", ringingSince: now, ringAgainAt: null })\n if (again) await this.ring(again)\n }\n }\n }\n\n /** The owner picked up, or tapped Show. Returns the call and, for a\n * voice call, the opener for /ask. */\n answer(id: string): CallResult & { opener?: string } {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const answered = this.deps.store.transition(id, \"ringing\", { status: \"answered\", answeredAt: this.now(), ringingSince: null })\n if (!answered) return { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}, not ringing` }\n this.deps.log?.(`[calls] ${id} answered (${call.agentId})`)\n return answered.kind === \"camera\" ? { ok: true, call: answered } : { ok: true, call: answered, opener: openerPrompt(answered) }\n }\n\n decline(id: string): CallResult {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const declined = this.deps.store.transition(id, [\"ringing\", \"later\"], { status: \"declined\", endedAt: this.now(), ringingSince: null, ringAgainAt: null })\n return declined ? { ok: true, call: declined } : { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}` }\n }\n\n /** \"Call back in N min\": it rings again then. */\n later(id: string, minutes?: unknown): CallResult {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const n = minutes === undefined ? LATER_DEFAULT_MINUTES : Number(minutes)\n if (!Number.isInteger(n) || n < 1 || n > LATER_MAX_MINUTES) {\n return { ok: false, status: 400, error: `minutes must be a whole number from 1 to ${LATER_MAX_MINUTES}` }\n }\n const later = this.deps.store.transition(id, \"ringing\", { status: \"later\", ringingSince: null, ringAgainAt: this.now() + n * 60_000 })\n return later ? { ok: true, call: later } : { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}, not ringing` }\n }\n\n /** End an answered call. The summary is written in the background;\n * `summarized` settles when it is filed (tests wait on it). */\n hangup(id: string): CallResult & { summarized?: Promise<void> } {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const ended = this.deps.store.transition(id, \"answered\", { status: \"ended\", endedAt: this.now() })\n if (!ended) return { ok: false, status: 409, error: `call is ${call.status}, not answered` }\n this.deps.log?.(`[calls] ${id} ended (${call.agentId})`)\n const summarize = this.deps.summarize\n // What the agent saw is already its answer; only a voice call is summarised.\n if (ended.kind === \"camera\" || !this.deps.config().summary || !summarize) return { ok: true, call: ended }\n const summarized = (async () => {\n try {\n const text = (await summarize(ended))?.trim()\n if (!text) return\n const done = this.deps.store.update(id, { summary: text })!\n this.deps.file?.(done, text)\n } catch (e: any) {\n this.deps.log?.(`[calls] summary for ${id} failed: ${e?.message ?? e}`)\n }\n })()\n return { ok: true, call: ended, summarized }\n }\n\n /** A camera ask ends when the share ends; no summary. Only an answered\n * ask ends this way, so a stop before Show leaves it ringing. */\n endCamera(id: string, note?: string): boolean {\n const call = this.deps.store.get(id)\n if (!call || call.kind !== \"camera\") return false\n const ended = this.deps.store.transition(id, \"answered\", { status: \"ended\", endedAt: this.now(), note: note ?? null })\n if (ended) this.deps.log?.(`[calls] ${id} ended (${call.agentId}): ${note ?? \"share over\"}`)\n return !!ended\n }\n\n get(id: string): Call | undefined { return this.deps.store.get(id) }\n\n list(opts: Parameters<CallStore[\"list\"]>[0] = {}): Call[] { return this.deps.store.list(opts) }\n}\n\nconst unknown = (id: string): CallResult => ({ ok: false, status: 404, error: `No such call: ${id}` })\n","// --- Calls an agent placed to the owner, kept in SQLite ---\n//\n// One row per call, so a missed call is still there after a restart and\n// the dashboard can list them. Nothing else reads this table. A camera\n// ask (#325 phase 3: \"show me\") is a call of kind \"camera\": same\n// allowlist, same hourly limit, same lifecycle, answered on the phone\n// instead of the voice widget.\n\nimport type Database from \"better-sqlite3\"\n\nexport type CallStatus = \"ringing\" | \"answered\" | \"ended\" | \"declined\" | \"missed\" | \"later\"\nexport type CallUrgency = \"normal\" | \"urgent\"\n/** \"voice\": a live voice call on the widget. \"camera\": the agent asks to see through the phone camera. */\nexport type CallKind = \"voice\" | \"camera\"\n\nexport interface Call {\n id: string\n agentId: string\n kind: CallKind\n reason: string\n urgency: CallUrgency\n status: CallStatus\n /** The channel and chat the asking turn ran in, so what the agent sees\n * is answered there; null when the turn had none (a task run). */\n channel: string | null\n chatId: string | null\n /** When the agent asked, ms since the epoch. */\n createdAt: number\n /** When it last started ringing: at the request, or when \"later\" came due. */\n ringingSince: number | null\n answeredAt: number | null\n endedAt: number | null\n /** Status \"later\": when it rings again. */\n ringAgainAt: number | null\n /** Why it ended the way it did, in a few words (\"in Focus\", \"not answered\"). */\n note: string | null\n /** The agent's own summary, written after hang-up. */\n summary: string | null\n}\n\n/** Calls still in progress: an agent has at most one of these. */\nexport const LIVE: CallStatus[] = [\"ringing\", \"answered\", \"later\"]\n\nconst COLUMNS = `id, agent_id AS agentId, kind, reason, urgency, status, created_at AS createdAt,\n ringing_since AS ringingSince, answered_at AS answeredAt, ended_at AS endedAt,\n ring_again_at AS ringAgainAt, note, summary, channel, chat_id AS chatId`\n\nexport class CallStore {\n constructor(private db: Database.Database) {\n db.exec(`CREATE TABLE IF NOT EXISTS calls (\n id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, reason TEXT NOT NULL,\n urgency TEXT NOT NULL, status TEXT NOT NULL, created_at INTEGER NOT NULL,\n ringing_since INTEGER, answered_at INTEGER, ended_at INTEGER,\n ring_again_at INTEGER, note TEXT, summary TEXT);\n CREATE INDEX IF NOT EXISTS calls_recent ON calls(created_at DESC);`)\n // Columns added since the table first shipped (#325 phase 3). A row\n // from before is a voice call from a turn whose chat was not kept.\n const have = new Set((db.prepare(\"PRAGMA table_info(calls)\").all() as Array<{ name: string }>).map((c) => c.name))\n if (!have.has(\"kind\")) db.exec(\"ALTER TABLE calls ADD COLUMN kind TEXT NOT NULL DEFAULT 'voice'\")\n if (!have.has(\"channel\")) db.exec(\"ALTER TABLE calls ADD COLUMN channel TEXT\")\n if (!have.has(\"chat_id\")) db.exec(\"ALTER TABLE calls ADD COLUMN chat_id TEXT\")\n }\n\n insert(call: Call): void {\n this.db.prepare(`INSERT INTO calls (id, agent_id, kind, reason, urgency, status, created_at, ringing_since,\n answered_at, ended_at, ring_again_at, note, summary, channel, chat_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(\n call.id, call.agentId, call.kind, call.reason, call.urgency, call.status, call.createdAt,\n call.ringingSince, call.answeredAt, call.endedAt, call.ringAgainAt, call.note, call.summary, call.channel, call.chatId)\n }\n\n get(id: string): Call | undefined {\n return this.db.prepare(`SELECT ${COLUMNS} FROM calls WHERE id=?`).get(id) as Call | undefined\n }\n\n /** Write the changed fields of one call. */\n update(id: string, patch: Partial<Omit<Call, \"id\" | \"agentId\" | \"createdAt\">>): Call | undefined {\n const cols: Record<string, string> = {\n reason: \"reason\", urgency: \"urgency\", status: \"status\", ringingSince: \"ringing_since\",\n answeredAt: \"answered_at\", endedAt: \"ended_at\", ringAgainAt: \"ring_again_at\", note: \"note\", summary: \"summary\",\n }\n const keys = Object.keys(patch).filter((k) => k in cols)\n if (keys.length) {\n const set = keys.map((k) => `${cols[k]}=?`).join(\", \")\n this.db.prepare(`UPDATE calls SET ${set} WHERE id=?`).run(...keys.map((k) => (patch as any)[k] ?? null), id)\n }\n return this.get(id)\n }\n\n /** Change a call only if it is still `from`: the check and the write are\n * one statement, so two sweeps, or a sweep and the owner answering,\n * cannot both move the same call. Undefined when it had moved on. */\n transition(id: string, from: CallStatus | CallStatus[], patch: Partial<Omit<Call, \"id\" | \"agentId\" | \"createdAt\">>): Call | undefined {\n const statuses = Array.isArray(from) ? from : [from]\n const cols: Record<string, string> = {\n status: \"status\", ringingSince: \"ringing_since\", answeredAt: \"answered_at\", endedAt: \"ended_at\",\n ringAgainAt: \"ring_again_at\", note: \"note\", summary: \"summary\",\n }\n const keys = Object.keys(patch).filter((k) => k in cols)\n const set = keys.map((k) => `${cols[k]}=?`).join(\", \")\n const marks = statuses.map(() => \"?\").join(\",\")\n const changed = this.db.prepare(`UPDATE calls SET ${set} WHERE id=? AND status IN (${marks})`)\n .run(...keys.map((k) => (patch as any)[k] ?? null), id, ...statuses).changes\n return changed ? this.get(id) : undefined\n }\n\n /** Newest first; only these statuses, and only this kind, when given. */\n list(opts: { status?: CallStatus[]; kind?: CallKind; limit?: number } = {}): Call[] {\n const limit = Math.min(Math.max(opts.limit ?? 50, 1), 200)\n const where: string[] = []\n const args: unknown[] = []\n if (opts.status?.length) {\n where.push(`status IN (${opts.status.map(() => \"?\").join(\",\")})`)\n args.push(...opts.status)\n }\n if (opts.kind) { where.push(\"kind=?\"); args.push(opts.kind) }\n const filter = where.length ? `WHERE ${where.join(\" AND \")}` : \"\"\n return this.db.prepare(`SELECT ${COLUMNS} FROM calls ${filter} ORDER BY created_at DESC, rowid DESC LIMIT ?`)\n .all(...args, limit) as Call[]\n }\n\n /** Calls this agent placed after `since` (ms), for the hourly limit. */\n countSince(agentId: string, since: number): number {\n return (this.db.prepare(\"SELECT COUNT(*) AS n FROM calls WHERE agent_id=? AND created_at>?\")\n .get(agentId, since) as { n: number }).n\n }\n}\n"],"mappings":"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","names":["randomUUID","LIVE","COLUMNS","CallStore","db","have","c","call","id","patch","cols","keys","k","set","from","statuses","marks","opts","limit","where","args","filter","agentId","since","REASON_MAX","WIDGET_FRESH_MS","BUSY_WAIT_MAX_MS","LATER_DEFAULT_MINUTES","LATER_MAX_MINUTES","callerHeaders","env","openerPrompt","call","SUMMARY_PROMPT","CallService","deps","agentId","input","proof","reason","urgency","kind","cfg","LIVE","c","now","session","randomUUID","rang","focus","readFocus","focusLabel","title","extra","e","widget","live","id","since","ringFor","talkFor","again","unknown","answered","declined","minutes","n","later","ended","summarize","summarized","text","done","note","opts"]}
@@ -1,2 +0,0 @@
1
- import{a,b,c,d,e}from"./chunk-JIJDBCV7.js";import"./chunk-HJCFLGVT.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{b as applyConfigMutation,a as findConfigPath,d as getAtPath,c as setAtPath,e as unsetAtPath};
2
- //# sourceMappingURL=config-mutator-POFVILXH.js.map