grix-connector 4.12.3 → 4.14.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 (58) hide show
  1. package/dist/adapter/acp/acp-adapter.js +13 -13
  2. package/dist/adapter/acp/grok-liveness.js +3 -0
  3. package/dist/adapter/agy/agy-adapter.js +12 -12
  4. package/dist/adapter/agy/stream-parser.js +2 -0
  5. package/dist/adapter/claude/claude-adapter.js +22 -21
  6. package/dist/adapter/claude/claude-bridge-server.js +1 -1
  7. package/dist/adapter/claude/claude-tools.js +1 -1
  8. package/dist/adapter/claude/claude-worker-client.js +1 -1
  9. package/dist/adapter/claude/mcp-http-launcher.js +2 -2
  10. package/dist/adapter/claude/model-list.js +1 -1
  11. package/dist/adapter/claude/result-timeout.js +1 -1
  12. package/dist/adapter/claude/session-recovery.js +1 -0
  13. package/dist/adapter/codex/codex-bridge.js +12 -10
  14. package/dist/adapter/codex/wait-loop.js +1 -0
  15. package/dist/adapter/cursor/cursor-adapter.js +1 -1
  16. package/dist/adapter/cursor/fetch-usage.js +1 -1
  17. package/dist/adapter/cursor/index.js +1 -1
  18. package/dist/adapter/pi/pi-adapter.js +4 -4
  19. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.14.0.tgz +0 -0
  20. package/dist/assets/dsh-bridge/manifest.json +5 -5
  21. package/dist/audit/adapters/codex/codex-audit-adapter.js +1 -1
  22. package/dist/bridge/adapter-pool.js +1 -1
  23. package/dist/bridge/bridge.js +2 -2
  24. package/dist/bridge/event-queue.js +1 -1
  25. package/dist/bridge/event-stop.js +1 -1
  26. package/dist/bridge/provider-quota.js +1 -1
  27. package/dist/bridge/rate-limits.js +1 -1
  28. package/dist/bridge/send-controller.js +3 -3
  29. package/dist/bridge/session-control-router.js +3 -3
  30. package/dist/bridge/tool-card-utils.js +1 -1
  31. package/dist/bridge/toolbar-meta.js +1 -1
  32. package/dist/bridge/toolbar-selection.js +1 -1
  33. package/dist/core/access/allowlist-store.js +1 -1
  34. package/dist/core/aibot/client.js +2 -2
  35. package/dist/core/config/claude-direct-env.js +1 -1
  36. package/dist/core/file-ops/list-files.js +1 -1
  37. package/dist/core/persistence/session-binding-store.js +2 -2
  38. package/dist/core/protocol/protocol-send.js +1 -0
  39. package/dist/core/provider-quota/grix-relay.js +1 -0
  40. package/dist/core/provider-quota/index.js +1 -1
  41. package/dist/core/proxy/index.js +1 -1
  42. package/dist/core/util/quoted-message-stream.js +3 -3
  43. package/dist/default-skills/grix-agent-dispatch/SKILL.md +37 -7
  44. package/dist/default-skills/grix-agent-dispatch/scripts/callback-dedupe.mjs +12 -0
  45. package/dist/grix.js +6 -6
  46. package/dist/log.js +2 -2
  47. package/dist/manager.js +1 -1
  48. package/dist/mcp/stream-http/config.js +1 -1
  49. package/dist/mcp/stream-http/connection-binding.js +1 -1
  50. package/dist/mcp/stream-http/tool-executor.js +1 -1
  51. package/dist/mcp/stream-http/tool-registry.js +1 -1
  52. package/dist/mcp/stream-http/tool-schemas.js +1 -1
  53. package/openclaw-plugin/audit-recorder-worker.js +37 -0
  54. package/openclaw-plugin/index.js +9 -3
  55. package/openclaw-plugin/skills/grix-agent-dispatch/SKILL.md +37 -7
  56. package/openclaw-plugin/skills/grix-agent-dispatch/scripts/callback-dedupe.mjs +12 -0
  57. package/package.json +1 -1
  58. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.12.3.tgz +0 -0
@@ -1 +1 @@
1
- import{log as c}from"../core/log/index.js";const k=10*1e3,w=["discardEventTrackingState","pushQueueSnapshotForSession","sendCanceledPendingEventResult","sendEventResultWithCleanup","killAndResumeStopSlot","waitForEventDone"],A=["name","config","stopped","aibotHandle","pool","pendingEvents","deferredMgr","revokeHandler","sendCtrl"];async function T(e,n){const{event_id:t,session_id:s}=n;if(c.info(e.name,`handleEventCancel start event_id=${t} session_id=${s}`),e.pendingEvents.markCanceled(t),e.pool.cancelEvent(t,s)){if(!(e.pool.getSlot(s)?.adapter?.getActiveEventIds().includes(t)??!1)){await e.pendingEvents.remove(t),e.sendEventResultWithCleanup(t,"canceled","canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}await e.waitForEventDone(t,s,15e3),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"}),e.pushQueueSnapshotForSession(s);return}const d=e.deferredMgr.removeEvent(t);if(d){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(d,"canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}const l=await e.pendingEvents.cancel(t,s);if(l){e.sendCanceledPendingEventResult(l.event,"canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!1,reason:"event not found or not cancelable"})}function D(e,n,t,s){return new Promise(o=>{const d=e.pool.getSlot(t);if(!d?.adapter){o();return}const l=setTimeout(()=>{d.adapter.removeListener("eventDone",r),o()},s),r=u=>{u===n&&(clearTimeout(l),d.adapter.removeListener("eventDone",r),o())};d.adapter.on("eventDone",r)})}function H(e,n){const t=n.event_id?.trim()??"",s=n.scope?.trim()??"";c.info(e.name,`[stop-trace] handleAibotStop begin session=${n.session_id} event=${t||"-"} scope=${s||"event"} stop_id=${n.stop_id||"-"} adapterType=${e.config.adapterType??"acp"}`);const o=e.pool.getSlot(n.session_id),d=o?.adapter?.getStatus().busy??!1;let l=!1,r=[];if(o?.adapter)try{r=[...new Set(o.adapter.getActiveEventIds().map(a=>a.trim()).filter(Boolean))]}catch(a){l=!0,c.warn(e.name,`[stop-trace] handleAibotStop active event probe failed session=${n.session_id}: ${a}`)}const u=s==="session";let i=u?"":t;const p=a=>({stop_id:n.stop_id,...a?{event_id:a}:{},...n.terminal_commit_token?{terminal_commit_token:n.terminal_commit_token}:{},session_id:n.session_id,...s?{scope:s}:{}}),v=a=>{!a||!n.terminal_commit_token?.trim()||e.sendEventResultWithCleanup(a,"canceled","stopped by owner","event_stopped")};if(u)if(!l&&r.length===1)[i]=r;else if(!l&&r.length===0&&!d){e.aibotHandle.sendEventStopAck({...p(""),accepted:!0,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(""),status:"already_finished",updated_at:Date.now()}),c.info(e.name,`[stop-trace] handleAibotStop session idle -> stopResult(already_finished) session=${n.session_id} stop_id=${n.stop_id||"-"}`);return}else{const a=l?"session_stop_target_unavailable":r.length>1?"session_stop_target_ambiguous":"session_stop_target_unresolved",f=l?"failed to inspect active events for session stop":r.length>1?"multiple active events prevent a safe session stop":"adapter is busy but no active event can be identified";e.aibotHandle.sendEventStopAck({...p(""),accepted:!1,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(""),status:"failed",code:a,msg:f,updated_at:Date.now()}),c.warn(e.name,`[stop-trace] handleAibotStop session target unsafe -> stopResult(failed) session=${n.session_id} activeIds=[${r.join(",")}] busy=${d} code=${a}`);return}i&&e.pendingEvents.markCanceled(i);const $=i?e.pool.cancelStartupEvent(i,n.session_id):void 0;if(i&&e.sendCtrl.hasTerminalResult(i)){e.pool.cleanupEvent(i,n.session_id),e.aibotHandle.sendEventStopAck({...p(i),accepted:!0,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(i),status:"already_finished",updated_at:Date.now()}),e.pushQueueSnapshotForSession(n.session_id);return}if(e.aibotHandle.sendEventStopAck({...p(i),accepted:!0,updated_at:Date.now()}),$){n.terminal_commit_token?.trim()?v(i):(e.discardEventTrackingState(i),e.pendingEvents.remove(i).catch(a=>{c.warn(e.name,`Failed to remove stopped startup event from pending store event=${i}: ${a instanceof Error?a.message:String(a)}`)})),e.pushQueueSnapshotForSession(n.session_id),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()});return}if(e.pool.removeQueuedEvent(n.session_id,i)){c.info(e.name,`[stop-trace] handleAibotStop removed queued(not-running) event -> stopResult(stopped) session=${n.session_id} event=${i} stop_id=${n.stop_id||"-"}`),n.terminal_commit_token?.trim()?v(i):e.discardEventTrackingState(i),e.pushQueueSnapshotForSession(n.session_id),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()});return}const R=(e.config.adapterType??"acp")==="acp",S=r.length>0?r.includes(i):d,_=(R||(e.config.adapterType??"acp")==="codex"||(e.config.adapterType??"acp")==="claude")&&S;if(c.info(e.name,`[stop-trace] handleAibotStop decision session=${n.session_id} event=${i} scope=${s||"event"} slotExists=${!!o?.adapter} busy=${d} activeIds=[${r.join(",")}] stoppingActiveEvent=${S} killOnStop=${_}`),S&&e.sendCtrl.markEventStopped(i),o?.adapter&&d){const a=_?e.pool.drainQueuedForSession(n.session_id):[];let f=!1,m=null;const g=E=>{f||(f=!0,m&&(clearTimeout(m),m=null),o.adapter.removeListener("eventDone",b),c.info(e.name,`[stop-trace] handleAibotStop ${E} -> stopResult(stopped) session=${n.session_id} event=${i} stop_id=${n.stop_id||"-"} killOnStop=${_}`),v(i),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()}),_&&e.killAndResumeStopSlot(n.session_id,a))},b=E=>{E===i&&g("eventDone")};o.adapter.on("eventDone",b),m=setTimeout(()=>g("timeout"),k),e.pool.deliverStopEvent(i,n.session_id)}else c.info(e.name,`[stop-trace] handleAibotStop slot-not-busy -> immediate stopResult(stopped) session=${n.session_id} event=${i} slotExists=${!!o?.adapter}`),e.pool.deliverStopEvent(i,n.session_id),v(i),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()});(e.config.adapterType??"acp")==="pi"&&e.aibotHandle.sendText({event_id:i,session_id:n.session_id,content:"/stop",msg_type:0})}async function F(e,n,t){if(!e.stopped){c.info(e.name,`[stop-trace] killAndResumeStopSlot begin session=${n} siblings=${t.length} -> removeSlot (kill process group)`);try{await e.pool.removeSlot(n),c.info(e.name,`[stop-trace] killAndResumeStopSlot removeSlot done session=${n} (process killed) -> redeliver ${t.length} sibling(s)`)}catch(s){c.warn(e.name,`[acp-stop] removeSlot failed session=${n}: ${s instanceof Error?s.message:String(s)}`)}if(!e.stopped)for(const s of t){if(e.stopped)break;try{await e.pool.deliverInboundEvent(s)}catch(o){c.error(e.name,`[acp-stop] sibling redeliver failed event=${s.event_id} session=${n}: ${o instanceof Error?o.message:String(o)}`),e.sendEventResultWithCleanup(s.event_id,"failed",o instanceof Error?o.message:String(o))}}}}async function x(e,n){if(!n.event_id||!e.revokeHandler.checkAndTrack(n.event_id))return;const t=n.event_id,s=n.session_id;if(e.pendingEvents.markCanceled(t),s&&e.pool.cancelEvent(t,s)){(e.pool.getSlot(s)?.adapter?.getActiveEventIds().includes(t)??!1)||(await e.pendingEvents.remove(t),e.sendEventResultWithCleanup(t,"canceled","revoked"));return}const o=e.deferredMgr.removeEvent(t);if(o){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(o,"revoked");return}const d=e.pool.cancelStartupEvent(t,s||void 0);if(d){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(d,"revoked");return}const l=await e.pendingEvents.cancel(t,s||void 0);if(l){e.sendCanceledPendingEventResult(l.event,"revoked");return}e.pool.deliverStopEvent(t,s||void 0)}export{A as EVENT_STOP_HOST_FIELDS,w as EVENT_STOP_HOST_METHODS,x as handleAibotRevoke,H as handleAibotStop,T as handleEventCancel,F as killAndResumeStopSlot,D as waitForEventDone};
1
+ import{log as c}from"../core/log/index.js";const k=10*1e3,w=["discardEventTrackingState","pushQueueSnapshotForSession","sendCanceledPendingEventResult","sendEventResultWithCleanup","killAndResumeStopSlot","waitForEventDone"],A=["name","config","stopped","aibotHandle","pool","pendingEvents","deferredMgr","revokeHandler","sendCtrl"];async function T(e,n){const{event_id:t,session_id:s}=n;if(c.info(e.name,`handleEventCancel start event_id=${t} session_id=${s}`),e.pendingEvents.markCanceled(t),e.pool.cancelEvent(t,s)){if(!(e.pool.getSlot(s)?.adapter?.getActiveEventIds().includes(t)??!1)){await e.pendingEvents.remove(t),e.sendEventResultWithCleanup(t,"canceled","canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}await e.waitForEventDone(t,s,15e3),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"}),e.pushQueueSnapshotForSession(s);return}const d=e.deferredMgr.removeEvent(t);if(d){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(d,"canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}const l=await e.pendingEvents.cancel(t,s);if(l){e.sendCanceledPendingEventResult(l.event,"canceled"),e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!0,final_state:"canceled"});return}e.aibotHandle.sendEventCancelResult({event_id:t,accepted:!1,reason:"event not found or not cancelable"})}function D(e,n,t,s){return new Promise(o=>{const d=e.pool.getSlot(t);if(!d?.adapter){o();return}const l=setTimeout(()=>{d.adapter.removeListener("eventDone",r),o()},s),r=u=>{u===n&&(clearTimeout(l),d.adapter.removeListener("eventDone",r),o())};d.adapter.on("eventDone",r)})}function H(e,n){const t=n.event_id?.trim()??"",s=n.scope?.trim()??"";c.info(e.name,`[stop-trace] handleAibotStop begin session=${n.session_id} event=${t||"-"} scope=${s||"event"} stop_id=${n.stop_id||"-"} adapterType=${e.config.adapterType??"acp"}`);const o=e.pool.getSlot(n.session_id),d=o?.adapter?.getStatus().busy??!1;let l=!1,r=[];if(o?.adapter)try{r=[...new Set(o.adapter.getActiveEventIds().map(a=>a.trim()).filter(Boolean))]}catch(a){l=!0,c.warn(e.name,`[stop-trace] handleAibotStop active event probe failed session=${n.session_id}: ${a}`)}const u=s==="session";let i=u?"":t;const p=a=>({stop_id:n.stop_id,...a?{event_id:a}:{},...n.terminal_commit_token?{terminal_commit_token:n.terminal_commit_token}:{},session_id:n.session_id,...s?{scope:s}:{}}),v=a=>{!a||!n.terminal_commit_token?.trim()||e.sendEventResultWithCleanup(a,"canceled","stopped by owner","event_stopped")};if(u)if(!l&&r.length===1)[i]=r;else if(!l&&r.length===0&&!d){e.aibotHandle.sendEventStopAck({...p(""),accepted:!0,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(""),status:"already_finished",updated_at:Date.now()}),c.info(e.name,`[stop-trace] handleAibotStop session idle -> stopResult(already_finished) session=${n.session_id} stop_id=${n.stop_id||"-"}`);return}else{const a=l?"session_stop_target_unavailable":r.length>1?"session_stop_target_ambiguous":"session_stop_target_unresolved",f=l?"failed to inspect active events for session stop":r.length>1?"multiple active events prevent a safe session stop":"adapter is busy but no active event can be identified";e.aibotHandle.sendEventStopAck({...p(""),accepted:!1,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(""),status:"failed",code:a,msg:f,updated_at:Date.now()}),c.warn(e.name,`[stop-trace] handleAibotStop session target unsafe -> stopResult(failed) session=${n.session_id} activeIds=[${r.join(",")}] busy=${d} code=${a}`);return}i&&e.pendingEvents.markCanceled(i);const $=i?e.pool.cancelStartupEvent(i,n.session_id):void 0;if(i&&e.sendCtrl.hasTerminalResult(i)){e.pool.cleanupEvent(i,n.session_id),e.aibotHandle.sendEventStopAck({...p(i),accepted:!0,updated_at:Date.now()}),e.aibotHandle.sendEventStopResult({...p(i),status:"already_finished",updated_at:Date.now()}),e.pushQueueSnapshotForSession(n.session_id);return}if(e.aibotHandle.sendEventStopAck({...p(i),accepted:!0,updated_at:Date.now()}),$){n.terminal_commit_token?.trim()?v(i):(e.discardEventTrackingState(i),e.pendingEvents.remove(i).catch(a=>{c.warn(e.name,`Failed to remove stopped startup event from pending store event=${i}: ${a instanceof Error?a.message:String(a)}`)})),e.pushQueueSnapshotForSession(n.session_id),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()});return}if(e.pool.removeQueuedEvent(n.session_id,i)){c.info(e.name,`[stop-trace] handleAibotStop removed queued(not-running) event -> stopResult(stopped) session=${n.session_id} event=${i} stop_id=${n.stop_id||"-"}`),n.terminal_commit_token?.trim()?v(i):e.discardEventTrackingState(i),e.pushQueueSnapshotForSession(n.session_id),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()});return}const R=(e.config.adapterType??"acp")==="acp",S=r.length>0?r.includes(i)||!!o?.eventQueue.snapshot(n.session_id).running.includes(i):d,_=(R||(e.config.adapterType??"acp")==="codex"||(e.config.adapterType??"acp")==="claude")&&S;if(c.info(e.name,`[stop-trace] handleAibotStop decision session=${n.session_id} event=${i} scope=${s||"event"} slotExists=${!!o?.adapter} busy=${d} activeIds=[${r.join(",")}] stoppingActiveEvent=${S} killOnStop=${_}`),S&&e.sendCtrl.markEventStopped(i),o?.adapter&&d){const a=_?e.pool.drainQueuedForSession(n.session_id):[];let f=!1,m=null;const E=g=>{f||(f=!0,m&&(clearTimeout(m),m=null),o.adapter.removeListener("eventDone",b),c.info(e.name,`[stop-trace] handleAibotStop ${g} -> stopResult(stopped) session=${n.session_id} event=${i} stop_id=${n.stop_id||"-"} killOnStop=${_}`),v(i),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()}),_&&e.killAndResumeStopSlot(n.session_id,a))},b=g=>{g===i&&E("eventDone")};o.adapter.on("eventDone",b),m=setTimeout(()=>E("timeout"),k),e.pool.deliverStopEvent(i,n.session_id)}else c.info(e.name,`[stop-trace] handleAibotStop slot-not-busy -> immediate stopResult(stopped) session=${n.session_id} event=${i} slotExists=${!!o?.adapter}`),e.pool.deliverStopEvent(i,n.session_id),v(i),e.aibotHandle.sendEventStopResult({...p(i),status:"stopped",updated_at:Date.now()});(e.config.adapterType??"acp")==="pi"&&e.aibotHandle.sendText({event_id:i,session_id:n.session_id,content:"/stop",msg_type:0})}async function F(e,n,t){if(!e.stopped){c.info(e.name,`[stop-trace] killAndResumeStopSlot begin session=${n} siblings=${t.length} -> removeSlot (kill process group)`);try{await e.pool.removeSlot(n),c.info(e.name,`[stop-trace] killAndResumeStopSlot removeSlot done session=${n} (process killed) -> redeliver ${t.length} sibling(s)`)}catch(s){c.warn(e.name,`[acp-stop] removeSlot failed session=${n}: ${s instanceof Error?s.message:String(s)}`)}if(!e.stopped)for(const s of t){if(e.stopped)break;try{await e.pool.deliverInboundEvent(s)}catch(o){c.error(e.name,`[acp-stop] sibling redeliver failed event=${s.event_id} session=${n}: ${o instanceof Error?o.message:String(o)}`),e.sendEventResultWithCleanup(s.event_id,"failed",o instanceof Error?o.message:String(o))}}}}async function x(e,n){if(!n.event_id||!e.revokeHandler.checkAndTrack(n.event_id))return;const t=n.event_id,s=n.session_id;if(e.pendingEvents.markCanceled(t),s&&e.pool.cancelEvent(t,s)){(e.pool.getSlot(s)?.adapter?.getActiveEventIds().includes(t)??!1)||(await e.pendingEvents.remove(t),e.sendEventResultWithCleanup(t,"canceled","revoked"));return}const o=e.deferredMgr.removeEvent(t);if(o){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(o,"revoked");return}const d=e.pool.cancelStartupEvent(t,s||void 0);if(d){await e.pendingEvents.remove(t),e.sendCanceledPendingEventResult(d,"revoked");return}const l=await e.pendingEvents.cancel(t,s||void 0);if(l){e.sendCanceledPendingEventResult(l.event,"revoked");return}e.pool.deliverStopEvent(t,s||void 0)}export{A as EVENT_STOP_HOST_FIELDS,w as EVENT_STOP_HOST_METHODS,x as handleAibotRevoke,H as handleAibotStop,T as handleEventCancel,F as killAndResumeStopSlot,D as waitForEventDone};
@@ -1 +1 @@
1
- import{sharedProviderQuotaService as Q,detectProviderFromModel as m,normalizeProviderId as y,readPiProviderSettings as b,readOpenCodeProviderSettings as A,isOpenaiCodexProviderName as T,queryOpenaiCodexQuota as S,openaiCodexQuotaCacheKey as $,resolveKimiProviderSettings as q,providerQuotaToRateLimits as K,providerQuotaToCodexRateLimits as R}from"../core/provider-quota/index.js";import{queryKiroQuota as E}from"../core/provider-quota/kiro.js";import{DshJsonRpcAdapter as H,resolveDshHome as x,readDshCredentials as D}from"../adapter/deepseek-harness/index.js";import{readSettingsEnv as M}from"../adapter/claude/model-list.js";import{readCodexProviderSettings as O}from"../adapter/codex/codex-trust.js";import{agentIdOf as U}from"../adapter/shared/native-provider-config.js";import{log as u}from"../core/log/index.js";const w=30*1e3,C=10*1e3,V=["isRateLimitsCacheFresh","providerQuotaToRateLimits","resolveProviderQuotaSource","maybeQueryProviderQuota","stopProviderQuotaTimer","refreshAndPushProviderQuota","pushProviderQuotaToBindings","enrichProviderQuotaMeta","refreshProviderQuotaForSession","doRefreshQuotaAfterModelSwitch"],W=["name","config","stopped","aibotHandle","pool","bindingStore","sessionBindings","sessionProviderHints","sessionProviderQuotas","sessionProviderMeta","cachedAcpContextWindow","cachedProviderQuota","cachedProviderQuotaKey","cachedProviderQuotaSampledAtMs","providerQuotaTimer","lastModelSwitchQuotaRefresh"];async function z(e,o){if(o?.disabled||o?.providerId==="openai_codex")return null;let a=e.config.providerBaseUrl??e.config.agent.provider?.baseUrl,t=e.config.providerApiKey??e.config.agent.provider?.apiKey;if((e.config.adapterType??"acp")==="deepseek-harness"){if(t??=e.config.agent.env?.DEEPSEEK_API_KEY,a??=e.config.agent.env?.DEEPSEEK_BASE_URL,!t){const r=x(typeof e.config.adapterOptions?.dshHome=="string"?e.config.adapterOptions.dshHome:void 0,e.config.agent.env);try{const i=await D(r),d=typeof i.DEEPSEEK_API_KEY=="string"?i.DEEPSEEK_API_KEY.trim():"";d&&(t=d,a??=typeof i.DEEPSEEK_BASE_URL=="string"&&i.DEEPSEEK_BASE_URL.trim()?i.DEEPSEEK_BASE_URL.trim():"https://api.deepseek.com",u.debug(e.name,"[provider-quota] deepseek-harness: resolved official DeepSeek API key from DSH credential store ($DSH_HOME)"))}catch(i){u.warn(e.name,`[provider-quota] deepseek-harness: could not read DSH credential store: ${i instanceof Error?i.message:String(i)}`)}}a??=t?"https://api.deepseek.com":void 0}if((!a||!t)&&(e.config.adapterType??"acp")==="claude"){const r=M();a||(a=(r.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(r.ANTHROPIC_API_KEY??"").trim()||(r.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!a||!t)&&(e.config.adapterType??"acp")==="codex"){const r=O();!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!a||!t)&&(e.config.adapterType??"acp")==="acp"&&e.config.aibot.clientType==="kimi"){const r=await q();!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!a||!t)&&(e.config.adapterType??"acp")==="pi"){const r=b(o,e.config.agent.env?.PI_CODING_AGENT_DIR);!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!a||!t)&&(e.config.adapterType??"acp")==="opencode"){const r=A(o,void 0,U(e.config.agent.command||"opencode")||"opencode");!a&&r.baseUrl&&(a=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if(!a||!t)return null;const n=y(o?.providerId)??m(o?.model)?.id??y(e.config.agent.provider?.providerId)??m(e.config.agent.provider?.model)?.id;return{baseUrl:a,...e.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:e.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...n?{providerId:n}:{}}}async function Y(e,o=!1,a){if(e.config.aibot.clientType==="kiro"){if(!o&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota)return e.cachedProviderQuota;try{const r=await E();return e.cachedProviderQuota=r,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="kiro",u.info(e.name,`[provider-quota] kiro queried: success=${r.success}`+(r.balance?` balance=${r.balance.remaining} ${r.balance.unit}`:"")+(r.planName?` plan=${r.planName}`:"")+(r.error?` error=${r.error}`:"")),r}catch(r){return u.warn(e.name,`[provider-quota] kiro query failed: ${r instanceof Error?r.message:String(r)}`),null}}if(a?.providerId==="openai_codex")try{const r=await S(e.config.agent.env?.PI_CODING_AGENT_DIR);return r.quota.success?r.quota:null}catch(r){return u.warn(e.name,`[provider-quota] openai_codex query failed: ${r instanceof Error?r.message:String(r)}`),null}const t=await e.resolveProviderQuotaSource(a);if(!t)return null;const n=Q.cacheKey(t);if(!o&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota&&e.cachedProviderQuotaKey===n)return e.cachedProviderQuota;try{const r=await Q.query(t,{fresh:o}),i=r.quota;return e.cachedProviderQuota=i,e.cachedProviderQuotaSampledAtMs=r.sampledAt,e.cachedProviderQuotaKey=r.cacheKey,u.info(e.name,`[provider-quota] queried: provider=${i.provider} success=${i.success}`+(i.tiers.length>0?` tiers=${i.tiers.map(d=>`${d.name}=${d.usedPercent}%`).join(",")}`:"")+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.error?` error=${i.error}`:"")),i}catch(r){return u.warn(e.name,`[provider-quota] query failed: ${r instanceof Error?r.message:String(r)}`),null}}function j(e){e.stopped||e.providerQuotaTimer||(e.providerQuotaTimer=setInterval(()=>{if(e.stopped){e.stopProviderQuotaTimer();return}e.refreshAndPushProviderQuota().catch(()=>{})},w),u.info(e.name,`[provider-quota-timer] started (interval=${w}ms)`))}function J(e){e.providerQuotaTimer&&(clearInterval(e.providerQuotaTimer),e.providerQuotaTimer=null,u.info(e.name,"[provider-quota-timer] stopped"))}async function X(e,o=!1){try{let a;if(e.config.aibot.clientType==="kiro")a=await E(),e.cachedProviderQuota=a,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="kiro";else{const t=[...e.sessionBindings.entries()].filter(([n,r])=>!!r&&e.sessionProviderHints.has(n));if(t.length>0&&await Promise.all(t.map(([n,r])=>e.refreshProviderQuotaForSession(n,r,o))),t.length===e.sessionBindings.size&&t.length>0)return;a=await e.maybeQueryProviderQuota(o)}a?.success&&e.pushProviderQuotaToBindings(a,e.sessionProviderHints.size>0)}catch{}}function Z(e,o,a=!1){const t=e.providerQuotaToRateLimits(o);for(const[n,r]of e.sessionBindings.entries()){if(!r||a&&e.sessionProviderHints.has(n))continue;if((e.config.adapterType??"acp")==="deepseek-harness"){const s=e.pool.getSlot(n)?.adapter;if(s instanceof H){s.updateProviderQuotaSnapshot(o);continue}}const i={provider_quota:o};t&&(i.rate_limits=t);const d=e.cachedAcpContextWindow;d&&("usedPercentage"in d?i.context_window={usedPercentage:d.usedPercentage,remainingPercentage:100-d.usedPercentage}:i.context_window=d),e.aibotHandle.sendUpdateBindingCard({session_id:n,worker_status:"ready",cwd:r,meta:i})}}function ee(e,o,a="standard",t=e.cachedProviderQuota,n=e.cachedProviderQuotaSampledAtMs){const r={...o??{}};if(!t?.success||(r.provider_quota||(r.provider_quota=t),r.rate_limits))return r;if(a==="codex"){const d=R(t,n??Date.now());return d&&(r.rate_limits=d.rateLimits,r.rate_limit_primary_percent=d.primaryPercent,r.rate_limit_secondary_percent=d.secondaryPercent,r.rate_limit_primary_window_min=d.primaryWindowMin,r.rate_limit_secondary_window_min=d.secondaryWindowMin),r}const i=K(t,n??Date.now());return i&&(r.rate_limits=i),r}function re(e,o,a,t){let n=e.cachedProviderQuota,r=e.cachedProviderQuotaSampledAtMs,i=!1;if(a){const s=typeof o?.model_provider=="string"?o.model_provider:void 0,p=typeof o?.model_id=="string"?o.model_id:void 0,v=y(s)??m(s)?.id??m(p)?.id??(T(s)?"openai_codex":null);if(v||p){const c=s?.trim().toLowerCase()??"",l=c==="grix"||c.startsWith("grix-"),P={...v?{providerId:v}:{},...p?{model:p}:{},...!!s&&!l&&!v?{disabled:!0}:{}},g=e.sessionProviderHints.get(a),_=g?.providerId!==P.providerId||g?.model!==P.model||g?.disabled!==P.disabled;e.sessionProviderHints.set(a,P),e.sessionProviderMeta.set(a,{...o??{}}),_&&e.sessionProviderQuotas.delete(a),(_||!e.sessionProviderQuotas.has(a))&&t&&e.refreshProviderQuotaForSession(a,t,!1)}const f=e.sessionProviderQuotas.get(a);i=e.sessionProviderHints.has(a),i&&(n=null,r=null),f&&(n=f.quota,r=f.sampledAt)}const d=e.enrichProviderQuotaMeta(o,"standard",n,r);return i&&(d.provider_quota||(d.provider_quota=null),d.rate_limits||(d.rate_limits=null)),Object.keys(d).length>0?{meta:d}:{}}async function ie(e,o,a,t){const n=e.sessionProviderHints.get(o);if(!n)return;if(n.disabled){u.debug(e.name,`[provider-quota] session skip: session=${o} reason=hint_disabled providerId=${n.providerId??""} model=${n.model??""}`);return}const r=`${n.providerId??""}|${n.model??""}|false`;try{let i,d,s;if(n.providerId==="openai_codex"){const c=e.sessionProviderQuotas.get(o);if(!t&&c&&c.quota.success&&c.cacheKey.startsWith("openai_codex|")&&e.isRateLimitsCacheFresh(c.sampledAt))i=c.quota,d=c.sampledAt,s=c.cacheKey;else{const l=await S(e.config.agent.env?.PI_CODING_AGENT_DIR);i=l.quota,d=Date.now(),s=$(l.accountKey)}}else{const c=await e.resolveProviderQuotaSource(n);if(!c){u.debug(e.name,`[provider-quota] session skip: session=${o} reason=no_source providerId=${n.providerId??""} model=${n.model??""}`);return}const l=await Q.query(c,{fresh:t});i=l.quota,d=l.sampledAt,s=l.cacheKey}const p=e.sessionProviderHints.get(o);if(`${p?.providerId??""}|${p?.model??""}|${p?.disabled===!0}`!==r)return;if(u.info(e.name,`[provider-quota] queried: provider=${i.provider} success=${i.success}`+(i.tiers.length>0?` tiers=${i.tiers.map(c=>`${c.name}=${c.usedPercent}%`).join(",")}`:"")+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.error?` error=${i.error}`:"")+` session=${o}`),!i.success){const c=e.sessionProviderQuotas.get(o);(!c?.quota.success||c.cacheKey!==s)&&e.sessionProviderQuotas.delete(o);return}e.sessionProviderQuotas.set(o,{quota:i,sampledAt:d,cacheKey:s});const f=e.enrichProviderQuotaMeta(e.sessionProviderMeta.get(o),"standard",i,d);e.aibotHandle.sendUpdateBindingCard({session_id:o,worker_status:"ready",cwd:a,meta:f})}catch(i){u.warn(e.name,`[provider-quota] session query failed: session=${o} ${i instanceof Error?i.message:String(i)}`)}}function oe(e,o,a,t){const n=a.trim();if(!o||!n)return;const r=t?.trim()||void 0,i=`${o}|${r??""}|${n}`,d=Date.now();e.lastModelSwitchQuotaRefresh&&e.lastModelSwitchQuotaRefresh.key===i&&d-e.lastModelSwitchQuotaRefresh.at<C||(e.lastModelSwitchQuotaRefresh={key:i,at:d},e.doRefreshQuotaAfterModelSwitch(o,n,r).catch(s=>{u.warn(e.name,`[provider-quota] model-switch refresh failed: session=${o} model=${n} ${s instanceof Error?s.message:String(s)}`)}))}async function ae(e,o,a,t){const n=e.sessionProviderHints.get(o);if(n||t){const i=t??m(a)?.id??n?.providerId,d={...i?{providerId:i}:{},model:a,...n?.disabled?{disabled:!0}:{}},s=n?.providerId!==d.providerId||n?.model!==d.model||n?.disabled!==d.disabled;e.sessionProviderHints.set(o,d),s&&e.sessionProviderQuotas.delete(o);const p=e.sessionBindings.get(o)??e.bindingStore.get(o)?.cwd??"";(s||!e.sessionProviderQuotas.has(o))&&p&&await e.refreshProviderQuotaForSession(o,p,!0);return}const r=await e.maybeQueryProviderQuota(!0,{model:a});r?.success&&e.pushProviderQuotaToBindings(r,e.sessionProviderHints.size>0)}export{W as PROVIDER_QUOTA_HOST_FIELDS,V as PROVIDER_QUOTA_HOST_METHODS,ae as doRefreshQuotaAfterModelSwitch,ee as enrichProviderQuotaMeta,Y as maybeQueryProviderQuota,re as providerQuotaMetaPayload,Z as pushProviderQuotaToBindings,X as refreshAndPushProviderQuota,ie as refreshProviderQuotaForSession,oe as refreshQuotaAfterModelSwitch,z as resolveProviderQuotaSource,j as startProviderQuotaTimer,J as stopProviderQuotaTimer};
1
+ import{sharedProviderQuotaService as y,detectProviderFromModel as m,normalizeProviderId as Q,readPiProviderSettings as b,readOpenCodeProviderSettings as $,isOpenaiCodexProviderName as A,queryOpenaiCodexQuota as S,openaiCodexQuotaCacheKey as q,resolveKimiProviderSettings as K,providerQuotaToRateLimits as T,providerQuotaToCodexRateLimits as x}from"../core/provider-quota/index.js";import{queryKiroQuota as E}from"../core/provider-quota/kiro.js";import{queryGrixRelayWalletBalance as R}from"../core/provider-quota/grix-relay.js";import{DshJsonRpcAdapter as H,resolveDshHome as M,readDshCredentials as D}from"../adapter/deepseek-harness/index.js";import{readSettingsEnv as C}from"../adapter/claude/model-list.js";import{readCodexProviderSettings as U}from"../adapter/codex/codex-trust.js";import{agentIdOf as O}from"../adapter/shared/native-provider-config.js";import{log as u}from"../core/log/index.js";const w=30*1e3,k=10*1e3,z=["isRateLimitsCacheFresh","isGrixRelayActive","providerQuotaToRateLimits","resolveProviderQuotaSource","maybeQueryProviderQuota","stopProviderQuotaTimer","refreshAndPushProviderQuota","pushProviderQuotaToBindings","enrichProviderQuotaMeta","refreshProviderQuotaForSession","doRefreshQuotaAfterModelSwitch"],Y=["name","config","stopped","aibotHandle","pool","bindingStore","sessionBindings","sessionProviderHints","sessionProviderQuotas","sessionProviderMeta","cachedAcpContextWindow","cachedProviderQuota","cachedProviderQuotaKey","cachedProviderQuotaSampledAtMs","providerQuotaTimer","lastModelSwitchQuotaRefresh"];async function j(e,a){if(a?.disabled||a?.providerId==="openai_codex")return null;let o=e.config.providerBaseUrl??e.config.agent.provider?.baseUrl,t=e.config.providerApiKey??e.config.agent.provider?.apiKey;if((e.config.adapterType??"acp")==="deepseek-harness"){if(t??=e.config.agent.env?.DEEPSEEK_API_KEY,o??=e.config.agent.env?.DEEPSEEK_BASE_URL,!t){const r=M(typeof e.config.adapterOptions?.dshHome=="string"?e.config.adapterOptions.dshHome:void 0,e.config.agent.env);try{const i=await D(r),d=typeof i.DEEPSEEK_API_KEY=="string"?i.DEEPSEEK_API_KEY.trim():"";d&&(t=d,o??=typeof i.DEEPSEEK_BASE_URL=="string"&&i.DEEPSEEK_BASE_URL.trim()?i.DEEPSEEK_BASE_URL.trim():"https://api.deepseek.com",u.debug(e.name,"[provider-quota] deepseek-harness: resolved official DeepSeek API key from DSH credential store ($DSH_HOME)"))}catch(i){u.warn(e.name,`[provider-quota] deepseek-harness: could not read DSH credential store: ${i instanceof Error?i.message:String(i)}`)}}o??=t?"https://api.deepseek.com":void 0}if((!o||!t)&&(e.config.adapterType??"acp")==="claude"){const r=C();o||(o=(r.ANTHROPIC_BASE_URL??"").trim()||void 0),t||(t=(r.ANTHROPIC_API_KEY??"").trim()||(r.ANTHROPIC_AUTH_TOKEN??"").trim()||void 0)}if((!o||!t)&&(e.config.adapterType??"acp")==="codex"){const r=U();!o&&r.baseUrl&&(o=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!o||!t)&&(e.config.adapterType??"acp")==="acp"&&e.config.aibot.clientType==="kimi"){const r=await K();!o&&r.baseUrl&&(o=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!o||!t)&&(e.config.adapterType??"acp")==="pi"){const r=b(a,e.config.agent.env?.PI_CODING_AGENT_DIR);!o&&r.baseUrl&&(o=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if((!o||!t)&&(e.config.adapterType??"acp")==="opencode"){const r=$(a,void 0,O(e.config.agent.command||"opencode")||"opencode");!o&&r.baseUrl&&(o=r.baseUrl),!t&&r.apiKey&&(t=r.apiKey)}if(!o||!t)return null;const n=Q(a?.providerId)??m(a?.model)?.id??Q(e.config.agent.provider?.providerId)??m(e.config.agent.provider?.model)?.id;return{baseUrl:o,...e.config.agent.provider?.quotaBaseUrl?{quotaBaseUrl:e.config.agent.provider.quotaBaseUrl}:{},apiKey:t,...n?{providerId:n}:{}}}async function J(e,a=!1,o){if(e.config.aibot.clientType==="kiro"){if(!a&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota)return e.cachedProviderQuota;try{const r=await E();return e.cachedProviderQuota=r,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="kiro",u.info(e.name,`[provider-quota] kiro queried: success=${r.success}`+(r.balance?` balance=${r.balance.remaining} ${r.balance.unit}`:"")+(r.planName?` plan=${r.planName}`:"")+(r.error?` error=${r.error}`:"")),r}catch(r){return u.warn(e.name,`[provider-quota] kiro query failed: ${r instanceof Error?r.message:String(r)}`),null}}if((e.config.adapterType??"acp")==="claude"&&e.isGrixRelayActive()){if(!a&&e.cachedProviderQuotaKey==="grix-relay"&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota)return e.cachedProviderQuota;try{const r=await R({wsUrl:e.config.aibot.url,apiKey:e.config.aibot.apiKey});return r.success&&(e.cachedProviderQuota=r,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="grix-relay"),u.info(e.name,`[provider-quota] grix-relay queried: success=${r.success}`+(r.balance?` balance=${r.balance.remaining} ${r.balance.unit}`:"")+(r.error?` error=${r.error}`:"")),r.success?r:null}catch(r){return u.warn(e.name,`[provider-quota] grix-relay query failed: ${r instanceof Error?r.message:String(r)}`),null}}if(o?.providerId==="openai_codex")try{const r=await S(e.config.agent.env?.PI_CODING_AGENT_DIR);return r.quota.success?r.quota:null}catch(r){return u.warn(e.name,`[provider-quota] openai_codex query failed: ${r instanceof Error?r.message:String(r)}`),null}const t=await e.resolveProviderQuotaSource(o);if(!t)return null;const n=y.cacheKey(t);if(!a&&e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&e.cachedProviderQuota&&e.cachedProviderQuotaKey===n)return e.cachedProviderQuota;try{const r=await y.query(t,{fresh:a}),i=r.quota;return e.cachedProviderQuota=i,e.cachedProviderQuotaSampledAtMs=r.sampledAt,e.cachedProviderQuotaKey=r.cacheKey,u.info(e.name,`[provider-quota] queried: provider=${i.provider} success=${i.success}`+(i.tiers.length>0?` tiers=${i.tiers.map(d=>`${d.name}=${d.usedPercent}%`).join(",")}`:"")+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.error?` error=${i.error}`:"")),i}catch(r){return u.warn(e.name,`[provider-quota] query failed: ${r instanceof Error?r.message:String(r)}`),null}}function X(e){e.stopped||e.providerQuotaTimer||(e.providerQuotaTimer=setInterval(()=>{if(e.stopped){e.stopProviderQuotaTimer();return}e.refreshAndPushProviderQuota().catch(()=>{})},w),u.info(e.name,`[provider-quota-timer] started (interval=${w}ms)`))}function Z(e){e.providerQuotaTimer&&(clearInterval(e.providerQuotaTimer),e.providerQuotaTimer=null,u.info(e.name,"[provider-quota-timer] stopped"))}async function ee(e,a=!1){try{let o;if(e.config.aibot.clientType==="kiro")o=await E(),e.cachedProviderQuota=o,e.cachedProviderQuotaSampledAtMs=Date.now(),e.cachedProviderQuotaKey="kiro";else{const t=[...e.sessionBindings.entries()].filter(([n,r])=>!!r&&e.sessionProviderHints.has(n));if(t.length>0&&await Promise.all(t.map(([n,r])=>e.refreshProviderQuotaForSession(n,r,a))),t.length===e.sessionBindings.size&&t.length>0)return;o=await e.maybeQueryProviderQuota(a)}o?.success&&e.pushProviderQuotaToBindings(o,e.sessionProviderHints.size>0)}catch{}}function re(e,a,o=!1){const t=(e.config.adapterType??"acp")==="claude"&&a.provider==="grix",n=e.providerQuotaToRateLimits(a);for(const[r,i]of e.sessionBindings.entries()){if(!i||o&&e.sessionProviderHints.has(r))continue;if((e.config.adapterType??"acp")==="deepseek-harness"){const l=e.pool.getSlot(r)?.adapter;if(l instanceof H){l.updateProviderQuotaSnapshot(a);continue}}const d={provider_quota:a};t?d.rate_limits=null:n&&(d.rate_limits=n);const c=e.cachedAcpContextWindow;c&&("usedPercentage"in c?d.context_window={usedPercentage:c.usedPercentage,remainingPercentage:100-c.usedPercentage}:d.context_window=c),e.aibotHandle.sendUpdateBindingCard({session_id:r,worker_status:"ready",cwd:i,meta:d})}}function ie(e,a,o="standard",t=e.cachedProviderQuota,n=e.cachedProviderQuotaSampledAtMs){const r={...a??{}};if(!t?.success||(r.provider_quota||(r.provider_quota=t),r.rate_limits))return r;if(o==="codex"){const d=x(t,n??Date.now());return d&&(r.rate_limits=d.rateLimits,r.rate_limit_primary_percent=d.primaryPercent,r.rate_limit_secondary_percent=d.secondaryPercent,r.rate_limit_primary_window_min=d.primaryWindowMin,r.rate_limit_secondary_window_min=d.secondaryWindowMin),r}const i=T(t,n??Date.now());return i&&(r.rate_limits=i),r}function ae(e,a,o,t){let n=e.cachedProviderQuota,r=e.cachedProviderQuotaSampledAtMs,i=!1;if(o){const c=typeof a?.model_provider=="string"?a.model_provider:void 0,l=typeof a?.model_id=="string"?a.model_id:void 0,v=Q(c)??m(c)?.id??m(l)?.id??(A(c)?"openai_codex":null);if(v||l){const s=c?.trim().toLowerCase()??"",p=s==="grix"||s.startsWith("grix-"),P={...v?{providerId:v}:{},...l?{model:l}:{},...!!c&&!p&&!v?{disabled:!0}:{}},g=e.sessionProviderHints.get(o),_=g?.providerId!==P.providerId||g?.model!==P.model||g?.disabled!==P.disabled;e.sessionProviderHints.set(o,P),e.sessionProviderMeta.set(o,{...a??{}}),_&&e.sessionProviderQuotas.delete(o),(_||!e.sessionProviderQuotas.has(o))&&t&&e.refreshProviderQuotaForSession(o,t,!1)}const f=e.sessionProviderQuotas.get(o);i=e.sessionProviderHints.has(o),i&&(n=null,r=null),f&&(n=f.quota,r=f.sampledAt)}const d=e.enrichProviderQuotaMeta(a,"standard",n,r);return i&&(d.provider_quota||(d.provider_quota=null),d.rate_limits||(d.rate_limits=null)),Object.keys(d).length>0?{meta:d}:{}}async function oe(e,a,o,t){const n=e.sessionProviderHints.get(a);if(!n)return;if(n.disabled){u.debug(e.name,`[provider-quota] session skip: session=${a} reason=hint_disabled providerId=${n.providerId??""} model=${n.model??""}`);return}const r=`${n.providerId??""}|${n.model??""}|false`;try{let i,d,c;if(n.providerId==="openai_codex"){const s=e.sessionProviderQuotas.get(a);if(!t&&s&&s.quota.success&&s.cacheKey.startsWith("openai_codex|")&&e.isRateLimitsCacheFresh(s.sampledAt))i=s.quota,d=s.sampledAt,c=s.cacheKey;else{const p=await S(e.config.agent.env?.PI_CODING_AGENT_DIR);i=p.quota,d=Date.now(),c=q(p.accountKey)}}else{const s=await e.resolveProviderQuotaSource(n);if(!s){u.debug(e.name,`[provider-quota] session skip: session=${a} reason=no_source providerId=${n.providerId??""} model=${n.model??""}`);return}const p=await y.query(s,{fresh:t});i=p.quota,d=p.sampledAt,c=p.cacheKey}const l=e.sessionProviderHints.get(a);if(`${l?.providerId??""}|${l?.model??""}|${l?.disabled===!0}`!==r)return;if(u.info(e.name,`[provider-quota] queried: provider=${i.provider} success=${i.success}`+(i.tiers.length>0?` tiers=${i.tiers.map(s=>`${s.name}=${s.usedPercent}%`).join(",")}`:"")+(i.balance?` balance=${i.balance.remaining} ${i.balance.unit}`:"")+(i.error?` error=${i.error}`:"")+` session=${a}`),!i.success){const s=e.sessionProviderQuotas.get(a);(!s?.quota.success||s.cacheKey!==c)&&e.sessionProviderQuotas.delete(a);return}e.sessionProviderQuotas.set(a,{quota:i,sampledAt:d,cacheKey:c});const f=e.enrichProviderQuotaMeta(e.sessionProviderMeta.get(a),"standard",i,d);e.aibotHandle.sendUpdateBindingCard({session_id:a,worker_status:"ready",cwd:o,meta:f})}catch(i){u.warn(e.name,`[provider-quota] session query failed: session=${a} ${i instanceof Error?i.message:String(i)}`)}}function te(e,a,o,t){const n=o.trim();if(!a||!n)return;const r=t?.trim()||void 0,i=`${a}|${r??""}|${n}`,d=Date.now();e.lastModelSwitchQuotaRefresh&&e.lastModelSwitchQuotaRefresh.key===i&&d-e.lastModelSwitchQuotaRefresh.at<k||(e.lastModelSwitchQuotaRefresh={key:i,at:d},e.doRefreshQuotaAfterModelSwitch(a,n,r).catch(c=>{u.warn(e.name,`[provider-quota] model-switch refresh failed: session=${a} model=${n} ${c instanceof Error?c.message:String(c)}`)}))}async function ne(e,a,o,t){const n=e.sessionProviderHints.get(a);if(n||t){const i=t??m(o)?.id??n?.providerId,d={...i?{providerId:i}:{},model:o,...n?.disabled?{disabled:!0}:{}},c=n?.providerId!==d.providerId||n?.model!==d.model||n?.disabled!==d.disabled;e.sessionProviderHints.set(a,d),c&&e.sessionProviderQuotas.delete(a);const l=e.sessionBindings.get(a)??e.bindingStore.get(a)?.cwd??"";(c||!e.sessionProviderQuotas.has(a))&&l&&await e.refreshProviderQuotaForSession(a,l,!0);return}const r=await e.maybeQueryProviderQuota(!0,{model:o});r?.success&&e.pushProviderQuotaToBindings(r,e.sessionProviderHints.size>0)}export{Y as PROVIDER_QUOTA_HOST_FIELDS,z as PROVIDER_QUOTA_HOST_METHODS,ne as doRefreshQuotaAfterModelSwitch,ie as enrichProviderQuotaMeta,J as maybeQueryProviderQuota,ae as providerQuotaMetaPayload,re as pushProviderQuotaToBindings,ee as refreshAndPushProviderQuota,oe as refreshProviderQuotaForSession,te as refreshQuotaAfterModelSwitch,j as resolveProviderQuotaSource,X as startProviderQuotaTimer,Z as stopProviderQuotaTimer};
@@ -1 +1 @@
1
- import{queryKiroQuota as g}from"../core/provider-quota/kiro.js";import{ClaudeAdapter as f}from"../adapter/claude/index.js";import{CursorAdapter as v,fetchCursorAccountUsage as L}from"../adapter/cursor/index.js";import{getCachedAgyQuotaInfo as A,refreshAgyQuotaInfo as b}from"../adapter/agy/quota.js";import{log as s}from"../core/log/index.js";const x=["isRateLimitsCacheFresh","getFreshClaudeRateLimitState","getFreshCodexGlobalRateLimitCache","maybeQueryProviderQuota","refreshProviderQuotaForSession","buildAgyToolbarMeta","buildAgyQuotaMeta","sendAgyBindingCard","resolveRateLimitWakeSessionId","wakeRateLimitSlot"],y=["name","config","aibotHandle","pool","bindingStore","sessionBindings","sessionProviderHints","sessionProviderQuotas","cachedAcpContextWindow","cachedClaudeRateLimitState","cachedCodexUsageSampledAtMs","cachedProviderQuota","cachedProviderQuotaSampledAtMs","cachedRateLimitsSampledAtMs"];async function R(e,c,n){const r=e.config.adapterType??"acp";if(e.config.aibot.clientType==="kiro"){const i=e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs),a=e.cachedAcpContextWindow;if(i&&e.cachedProviderQuota){e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"acp",available:!0,cached:!0,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:a,tokenUsage:null,providerQuota:e.cachedProviderQuota}});return}try{const t=await g();e.cachedProviderQuota=t,e.cachedProviderQuotaSampledAtMs=Date.now(),s.info(e.name,`[rate-limits] kiro quota queried: success=${t.success}`+(t.balance?` balance=${t.balance.remaining} ${t.balance.unit}`:"")+(t.error?` error=${t.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"acp",available:!0,cached:!1,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:a,tokenUsage:null,providerQuota:t}})}catch(t){s.warn(e.name,`[rate-limits] kiro quota query failed: ${t instanceof Error?t.message:String(t)}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"acp",available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:a,tokenUsage:null}})}return}switch(r){case"codex":{const i=e.maybeQueryProviderQuota(),a=e.getFreshCodexGlobalRateLimitCache();if(a.hasData&&!e.isRateLimitsCacheFresh(e.cachedRateLimitsSampledAtMs)&&!e.isRateLimitsCacheFresh(e.cachedCodexUsageSampledAtMs)){const l=e.pool.getAllSlots().find(p=>p.state==="ready"&&p.adapter);if(l&&(s.info(e.name,`[rate-limits] codex cache stale, refreshing from slot: session=${l.sessionId}`),(await l.adapter.handleLocalAction?.(c))?.handled))return}if(a.hasData){a.rateLimits?s.info(e.name,`[rate-limits] codex cached: primary=${a.rateLimits.primary.usedPercent.toFixed(1)}% resetsAt=${a.rateLimits.primary.resetsAt} secondary=${a.rateLimits.secondary.usedPercent.toFixed(1)}% resetsAt=${a.rateLimits.secondary.resetsAt}`):s.info(e.name,`[rate-limits] codex cached context/token only: hasContext=${!!a.contextWindow} hasToken=${!!a.tokenUsage}`);const l=await i;e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"codex",available:a.hasData||!!l,cached:!0,sampledAt:a.sampledAt,rateLimits:a.rateLimits,contextWindow:a.contextWindow,tokenUsage:a.tokenUsage,providerQuota:l}});return}const o=e.pool.getAllSlots().find(l=>l.state==="ready"&&l.adapter);if(o&&(s.info(e.name,`[rate-limits] codex reuse existing slot: session=${o.sessionId}`),(await o.adapter.handleLocalAction?.(c))?.handled))return;const u=e.resolveRateLimitWakeSessionId(n,r);if(u){const l=await e.wakeRateLimitSlot(u,r);if(l?.adapter&&(await l.adapter.handleLocalAction?.(c))?.handled)return}const d=await i,m=!!d;s.info(e.name,`[rate-limits] codex no native data, providerQuota=${d?d.provider:"none"} available=${m}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"codex",available:m,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:d}});return}case"claude":{const i=e.maybeQueryProviderQuota(),a=e.getFreshClaudeRateLimitState();if(a){const m=a.rateLimits,l=await i;s.info(e.name,`[rate-limits] claude global cached: sampledAt=${a.sampledAt} hasRateLimits=${!!m}`+(l?` providerQuota=${l.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"claude",available:!0,cached:!0,sampledAt:a.sampledAt,rateLimits:a.rateLimits??null,contextWindow:a.contextWindow,tokenUsage:null,providerQuota:l}});return}let t=e.pool.getAllSlots().find(m=>m.state==="ready"&&m.adapter instanceof f)??null;if(!t){const m=e.resolveRateLimitWakeSessionId(n,r);m&&(t=await e.wakeRateLimitSlot(m,r))}s.info(e.name,`[rate-limits] handleGetRateLimits: session_id=${n} adapterType=claude hasSlot=${!!t} hasAdapter=${!!t?.adapter}`);const o=t?.adapter,u=o instanceof f?o.getSessionState():null,d=await i;if(u){(u.rateLimits?.fiveHour||u.rateLimits?.sevenDay||u.contextWindow?.usedPercentage!=null)&&(e.cachedClaudeRateLimitState=u);const m=e.getFreshClaudeRateLimitState(),l=m?.rateLimits&&!u.rateLimits?{...u,rateLimits:m.rateLimits}:u,p=l.rateLimits;s.info(e.name,`[rate-limits] claude global state: sampledAt=${l.sampledAt} hasRateLimits=${!!p}`+(p?` fiveHour=${p.fiveHour?.usedPercentage??"n/a"}% resetsAt=${p.fiveHour?.resetsAt??"n/a"} sevenDay=${p.sevenDay?.usedPercentage??"n/a"}% resetsAt=${p.sevenDay?.resetsAt??"n/a"}`:"")+(m?.rateLimits&&!u.rateLimits?" source=live+cached-fallback":" source=live")+(d?` providerQuota=${d.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"claude",available:!0,cached:!1,sampledAt:l.sampledAt,rateLimits:l.rateLimits??null,contextWindow:l.contextWindow,tokenUsage:null,providerQuota:d}})}else s.info(e.name,`[rate-limits] claude no global state: hasAdapter=${!!o} adapterType=${o?.constructor?.name??"n/a"}`+(d?` providerQuota=${d.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"claude",available:!!d,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:d}});return}case"cursor":{const a=(n?e.pool.getSlot(n):null)?.adapter;if(a instanceof v){await a.refreshAccountRateLimits({force:!0});const o=a.getRateLimitsSnapshot(n);s.info(e.name,`[rate-limits] cursor: available=${o.available} monthly=${o.rateLimits?.fiveHour?.usedPercentage??"n/a"}% api=${o.rateLimits?.sevenDay?.usedPercentage??"n/a"}%`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:o});return}const t=await L();s.info(e.name,`[rate-limits] cursor(no-slot): available=${t.available} monthly=${t.rateLimits?.fiveHour?.usedPercentage??"n/a"}% api=${t.rateLimits?.sevenDay?.usedPercentage??"n/a"}%`+(t.error?` error=${t.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"cursor",available:t.available,cached:!1,sampledAt:Number.isFinite(Date.parse(t.sampledAt))?Date.parse(t.sampledAt):Date.now(),rateLimits:t.rateLimits,contextWindow:null,tokenUsage:null,...t.displayMessage?{displayMessage:t.displayMessage}:{},...t.error?{error:t.error}:{}}});return}case"agy":{const i=await b(e.config.agent.command,!0).catch(()=>A(e.config.agent.command)),a=n?e.buildAgyToolbarMeta(n,i):{...e.buildAgyQuotaMeta(i)},t=n?e.bindingStore.get(n):void 0;t?.cwd&&e.sendAgyBindingCard(n,t.cwd,a),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:"agy",available:!!i.rateLimits,cached:!1,sampledAt:i.sampledAt??null,rateLimits:i.rateLimits?{primary:i.rateLimits.primary,secondary:i.rateLimits.secondary,sampledAt:i.sampledAt??Date.now()}:null,extraLimits:i.rateLimits?.extras??[],contextWindow:null,tokenUsage:null,...i.plan!==void 0?{plan:i.plan}:{},...i.quota_exhausted!==void 0?{quota_exhausted:i.quota_exhausted}:{},...i.quota_reset_at!==void 0?{quota_reset_at:i.quota_reset_at}:{},...i.available_credits!==void 0?{available_credits:i.available_credits}:{}}});return}default:{const i=e.sessionProviderHints.get(n),a=e.sessionBindings.get(n)||e.bindingStore.get(n)?.cwd;if(i&&a&&!i.disabled){await e.refreshProviderQuotaForSession(n,a,!0);const u=e.sessionProviderQuotas.get(n),d=u?.quota??null;if(!d){s.info(e.name,`[rate-limits] no session provider quota available for adapterType=${r} session=${n}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null}});return}s.info(e.name,`[rate-limits] session provider quota queried: provider=${d.provider} success=${d.success}`+(d.tiers.length>0?` tiers=${d.tiers.map(m=>`${m.name}=${m.usedPercent}%`).join(",")}`:"")+(d.error?` error=${d.error}`:"")+` session=${n}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!0,cached:!1,sampledAt:u?.sampledAt??null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null,providerQuota:d}});return}const t=e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&!!e.cachedProviderQuota,o=await e.maybeQueryProviderQuota();if(!o){s.info(e.name,`[rate-limits] no provider quota available for adapterType=${r}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null}});return}s.info(e.name,`[rate-limits] provider quota ${t?"cached":"queried"}: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(u=>`${u.name}=${u.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:{adapterType:r,available:!0,cached:t,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null,providerQuota:o}});return}}}function Q(e,c,n){const r=String(c??"").trim(),i=e.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0});return i?r&&r===i?r:n==="codex"||n==="claude"?(r&&r!==i&&s.info(e.name,`[rate-limits] ${n} remap wake session: requested=${r} use_recent=${i}`),i):r&&r!==i?(s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=not_recent_session recent=${i}`),null):r||null:(s.info(e.name,`[rate-limits] skip wake slot: adapterType=${n} reason=no_recent_binding`),null)}async function P(e,c,n){const r=String(c??"").trim();if(!r)return null;if(!e.bindingStore.get(r)?.cwd)return s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=binding_cwd_missing`),null;try{const a=await e.pool.getOrCreateSlot(r);if(!a)return s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=slot_unavailable`),null;if(a.startPromise){const t=n==="claude"?6e4:2e4;await Promise.race([a.startPromise,new Promise((o,u)=>setTimeout(()=>u(new Error(`wake rate-limits slot timeout (${t}ms)`)),t))])}return s.info(e.name,`[rate-limits] wake slot success: session=${r} adapterType=${n}`),e.pool.getSlot(r)??a}catch(a){return s.warn(e.name,`[rate-limits] wake slot failed: session=${r} adapterType=${n} err=${a instanceof Error?a.message:String(a)}`),null}}export{y as RATE_LIMITS_HOST_FIELDS,x as RATE_LIMITS_HOST_METHODS,R as handleGetRateLimits,Q as resolveRateLimitWakeSessionId,P as wakeRateLimitSlot};
1
+ import{queryKiroQuota as g}from"../core/provider-quota/kiro.js";import{ClaudeAdapter as f}from"../adapter/claude/index.js";import{CursorAdapter as v,fetchCursorAccountUsage as L}from"../adapter/cursor/index.js";import{getCachedAgyQuotaInfo as A,refreshAgyQuotaInfo as b}from"../adapter/agy/quota.js";import{log as s}from"../core/log/index.js";const x=["isRateLimitsCacheFresh","isGrixRelayActive","getFreshClaudeRateLimitState","getFreshCodexGlobalRateLimitCache","maybeQueryProviderQuota","refreshProviderQuotaForSession","buildAgyToolbarMeta","buildAgyQuotaMeta","sendAgyBindingCard","resolveRateLimitWakeSessionId","wakeRateLimitSlot"],y=["name","config","aibotHandle","pool","bindingStore","sessionBindings","sessionProviderHints","sessionProviderQuotas","cachedAcpContextWindow","cachedClaudeRateLimitState","cachedCodexUsageSampledAtMs","cachedProviderQuota","cachedProviderQuotaSampledAtMs","cachedRateLimitsSampledAtMs"];async function R(e,l,n){const r=e.config.adapterType??"acp";if(e.config.aibot.clientType==="kiro"){const i=e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs),t=e.cachedAcpContextWindow;if(i&&e.cachedProviderQuota){e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"acp",available:!0,cached:!0,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:t,tokenUsage:null,providerQuota:e.cachedProviderQuota}});return}try{const a=await g();e.cachedProviderQuota=a,e.cachedProviderQuotaSampledAtMs=Date.now(),s.info(e.name,`[rate-limits] kiro quota queried: success=${a.success}`+(a.balance?` balance=${a.balance.remaining} ${a.balance.unit}`:"")+(a.error?` error=${a.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"acp",available:!0,cached:!1,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:t,tokenUsage:null,providerQuota:a}})}catch(a){s.warn(e.name,`[rate-limits] kiro quota query failed: ${a instanceof Error?a.message:String(a)}`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"acp",available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:t,tokenUsage:null}})}return}switch(r){case"codex":{const i=e.maybeQueryProviderQuota(),t=e.getFreshCodexGlobalRateLimitCache();if(t.hasData&&!e.isRateLimitsCacheFresh(e.cachedRateLimitsSampledAtMs)&&!e.isRateLimitsCacheFresh(e.cachedCodexUsageSampledAtMs)){const c=e.pool.getAllSlots().find(p=>p.state==="ready"&&p.adapter);if(c&&(s.info(e.name,`[rate-limits] codex cache stale, refreshing from slot: session=${c.sessionId}`),(await c.adapter.handleLocalAction?.(l))?.handled))return}if(t.hasData){t.rateLimits?s.info(e.name,`[rate-limits] codex cached: primary=${t.rateLimits.primary.usedPercent.toFixed(1)}% resetsAt=${t.rateLimits.primary.resetsAt} secondary=${t.rateLimits.secondary.usedPercent.toFixed(1)}% resetsAt=${t.rateLimits.secondary.resetsAt}`):s.info(e.name,`[rate-limits] codex cached context/token only: hasContext=${!!t.contextWindow} hasToken=${!!t.tokenUsage}`);const c=await i;e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"codex",available:t.hasData||!!c,cached:!0,sampledAt:t.sampledAt,rateLimits:t.rateLimits,contextWindow:t.contextWindow,tokenUsage:t.tokenUsage,providerQuota:c}});return}const o=e.pool.getAllSlots().find(c=>c.state==="ready"&&c.adapter);if(o&&(s.info(e.name,`[rate-limits] codex reuse existing slot: session=${o.sessionId}`),(await o.adapter.handleLocalAction?.(l))?.handled))return;const m=e.resolveRateLimitWakeSessionId(n,r);if(m){const c=await e.wakeRateLimitSlot(m,r);if(c?.adapter&&(await c.adapter.handleLocalAction?.(l))?.handled)return}const u=await i,d=!!u;s.info(e.name,`[rate-limits] codex no native data, providerQuota=${u?u.provider:"none"} available=${d}`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"codex",available:d,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:u}});return}case"claude":{if(e.isGrixRelayActive()){const d=await e.maybeQueryProviderQuota(!0);s.info(e.name,`[rate-limits] claude grix-relay: providerQuota=${d?d.provider:"none"}`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"claude",available:!!d,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:d}});return}const i=e.maybeQueryProviderQuota(),t=e.getFreshClaudeRateLimitState();if(t){const d=t.rateLimits,c=await i;s.info(e.name,`[rate-limits] claude global cached: sampledAt=${t.sampledAt} hasRateLimits=${!!d}`+(c?` providerQuota=${c.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"claude",available:!0,cached:!0,sampledAt:t.sampledAt,rateLimits:t.rateLimits??null,contextWindow:t.contextWindow,tokenUsage:null,providerQuota:c}});return}let a=e.pool.getAllSlots().find(d=>d.state==="ready"&&d.adapter instanceof f)??null;if(!a){const d=e.resolveRateLimitWakeSessionId(n,r);d&&(a=await e.wakeRateLimitSlot(d,r))}s.info(e.name,`[rate-limits] handleGetRateLimits: session_id=${n} adapterType=claude hasSlot=${!!a} hasAdapter=${!!a?.adapter}`);const o=a?.adapter,m=o instanceof f?o.getSessionState():null,u=await i;if(m){(m.rateLimits?.fiveHour||m.rateLimits?.sevenDay||m.contextWindow?.usedPercentage!=null)&&(e.cachedClaudeRateLimitState=m);const d=e.getFreshClaudeRateLimitState(),c=d?.rateLimits&&!m.rateLimits?{...m,rateLimits:d.rateLimits}:m,p=c.rateLimits;s.info(e.name,`[rate-limits] claude global state: sampledAt=${c.sampledAt} hasRateLimits=${!!p}`+(p?` fiveHour=${p.fiveHour?.usedPercentage??"n/a"}% resetsAt=${p.fiveHour?.resetsAt??"n/a"} sevenDay=${p.sevenDay?.usedPercentage??"n/a"}% resetsAt=${p.sevenDay?.resetsAt??"n/a"}`:"")+(d?.rateLimits&&!m.rateLimits?" source=live+cached-fallback":" source=live")+(u?` providerQuota=${u.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"claude",available:!0,cached:!1,sampledAt:c.sampledAt,rateLimits:c.rateLimits??null,contextWindow:c.contextWindow,tokenUsage:null,providerQuota:u}})}else s.info(e.name,`[rate-limits] claude no global state: hasAdapter=${!!o} adapterType=${o?.constructor?.name??"n/a"}`+(u?` providerQuota=${u.provider}`:"")),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"claude",available:!!u,cached:!1,sampledAt:null,rateLimits:null,contextWindow:null,tokenUsage:null,providerQuota:u}});return}case"cursor":{const t=(n?e.pool.getSlot(n):null)?.adapter;if(t instanceof v){await t.refreshAccountRateLimits({force:!0});const o=t.getRateLimitsSnapshot(n);s.info(e.name,`[rate-limits] cursor: available=${o.available} period=${o.usagePeriod??o.rateLimits?.usagePeriod??"n/a"} total=${o.rateLimits?.fiveHour?.usedPercentage??"n/a"}% api=${o.rateLimits?.sevenDay?.usedPercentage??"n/a"}%`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:o});return}const a=await L();s.info(e.name,`[rate-limits] cursor(no-slot): available=${a.available} period=${a.usagePeriod??a.rateLimits?.usagePeriod??"n/a"} total=${a.rateLimits?.fiveHour?.usedPercentage??"n/a"}% api=${a.rateLimits?.sevenDay?.usedPercentage??"n/a"}%`+(a.error?` error=${a.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"cursor",available:a.available,cached:!1,sampledAt:Number.isFinite(Date.parse(a.sampledAt))?Date.parse(a.sampledAt):Date.now(),rateLimits:a.rateLimits,...a.usagePeriod||a.rateLimits?.usagePeriod?{usagePeriod:a.usagePeriod??a.rateLimits?.usagePeriod}:{},contextWindow:null,tokenUsage:null,...a.displayMessage?{displayMessage:a.displayMessage}:{},...a.error?{error:a.error}:{}}});return}case"agy":{const i=await b(e.config.agent.command,!0).catch(()=>A(e.config.agent.command)),t=n?e.buildAgyToolbarMeta(n,i):{...e.buildAgyQuotaMeta(i)},a=n?e.bindingStore.get(n):void 0;a?.cwd&&e.sendAgyBindingCard(n,a.cwd,t),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:"agy",available:!!i.rateLimits,cached:!1,sampledAt:i.sampledAt??null,rateLimits:i.rateLimits?{primary:i.rateLimits.primary,secondary:i.rateLimits.secondary,sampledAt:i.sampledAt??Date.now()}:null,extraLimits:i.rateLimits?.extras??[],contextWindow:null,tokenUsage:null,...i.plan!==void 0?{plan:i.plan}:{},...i.quota_exhausted!==void 0?{quota_exhausted:i.quota_exhausted}:{},...i.quota_reset_at!==void 0?{quota_reset_at:i.quota_reset_at}:{},...i.available_credits!==void 0?{available_credits:i.available_credits}:{}}});return}default:{const i=e.sessionProviderHints.get(n),t=e.sessionBindings.get(n)||e.bindingStore.get(n)?.cwd;if(i&&t&&!i.disabled){await e.refreshProviderQuotaForSession(n,t,!0);const m=e.sessionProviderQuotas.get(n),u=m?.quota??null;if(!u){s.info(e.name,`[rate-limits] no session provider quota available for adapterType=${r} session=${n}`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:r,available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null}});return}s.info(e.name,`[rate-limits] session provider quota queried: provider=${u.provider} success=${u.success}`+(u.tiers.length>0?` tiers=${u.tiers.map(d=>`${d.name}=${d.usedPercent}%`).join(",")}`:"")+(u.error?` error=${u.error}`:"")+` session=${n}`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:r,available:!0,cached:!1,sampledAt:m?.sampledAt??null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null,providerQuota:u}});return}const a=e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)&&!!e.cachedProviderQuota,o=await e.maybeQueryProviderQuota();if(!o){s.info(e.name,`[rate-limits] no provider quota available for adapterType=${r}`),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:r,available:!1,cached:!1,sampledAt:null,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null}});return}s.info(e.name,`[rate-limits] provider quota ${a?"cached":"queried"}: provider=${o.provider} success=${o.success}`+(o.tiers.length>0?` tiers=${o.tiers.map(m=>`${m.name}=${m.usedPercent}%`).join(",")}`:"")+(o.balance?` balance=${o.balance.remaining} ${o.balance.unit}`:"")+(o.error?` error=${o.error}`:"")),e.aibotHandle.sendLocalActionResult({action_id:l.action_id,status:"ok",result:{adapterType:r,available:!0,cached:a,sampledAt:e.cachedProviderQuotaSampledAtMs,rateLimits:null,contextWindow:e.cachedAcpContextWindow??null,tokenUsage:null,providerQuota:o}});return}}}function P(e,l,n){const r=String(l??"").trim(),i=e.bindingStore.getMostRecentlyUpdatedSessionId({requireCwd:!0});return i?r&&r===i?r:n==="codex"||n==="claude"?(r&&r!==i&&s.info(e.name,`[rate-limits] ${n} remap wake session: requested=${r} use_recent=${i}`),i):r&&r!==i?(s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=not_recent_session recent=${i}`),null):r||null:(s.info(e.name,`[rate-limits] skip wake slot: adapterType=${n} reason=no_recent_binding`),null)}async function Q(e,l,n){const r=String(l??"").trim();if(!r)return null;if(!e.bindingStore.get(r)?.cwd)return s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=binding_cwd_missing`),null;try{const t=await e.pool.getOrCreateSlot(r);if(!t)return s.info(e.name,`[rate-limits] skip wake slot: session=${r} adapterType=${n} reason=slot_unavailable`),null;if(t.startPromise){const a=n==="claude"?6e4:2e4;await Promise.race([t.startPromise,new Promise((o,m)=>setTimeout(()=>m(new Error(`wake rate-limits slot timeout (${a}ms)`)),a))])}return s.info(e.name,`[rate-limits] wake slot success: session=${r} adapterType=${n}`),e.pool.getSlot(r)??t}catch(t){return s.warn(e.name,`[rate-limits] wake slot failed: session=${r} adapterType=${n} err=${t instanceof Error?t.message:String(t)}`),null}}export{y as RATE_LIMITS_HOST_FIELDS,x as RATE_LIMITS_HOST_METHODS,R as handleGetRateLimits,P as resolveRateLimitWakeSessionId,Q as wakeRateLimitSlot};
@@ -1,3 +1,3 @@
1
- import{isRequestTimeoutError as E}from"../core/aibot/errors.js";import{log as h}from"../core/log/index.js";import{splitTextForAibotProtocol as _,AIBOT_PROTOCOL_MAX_RUNES as k}from"../core/protocol/protocol-text.js";import{isThinkingEventDropped as C,isToolEventDropped as y,normalizeRuntimeConfigSnapshot as S}from"./runtime-config.js";const v={claude:!1,acp:!1,codex:!0,codewhale:!0,pi:!0,openhuman:!1,cursor:!1,opencode:!0,agy:!0,"deepseek-harness":!1};class g{handle;connectorRuntimeConfig;eventRuntimeConfigs=new Map;eventQuotedMessageIds=new Map;defaultQuoteTrigger=!1;thinkingSeqMap=new Map;thinkingSessionMap=new Map;toolCardSeq=0;bufferedEventTexts=new Map;singleMessageDeliveries=new Map;chunkSeqMap=new Map;openStreams=new Map;rejectedEvents=new Set;terminalEvents=new Set;terminalResultEvents=new Set;static MAX_TERMINAL_EVENTS=1e3;stoppedEvents=new Set;streamCoalesce=new Map;streamCoalesceMs=T();static STREAM_COALESCE_MAX_RUNES=2048;recentToolCards=new Map;static TOOL_CARD_DEDUP_MS=100;constructor(e){this.connectorRuntimeConfig={...e}}bind(e){this.handle=e}markEventRejected(e){if(!e)return;this.rejectedEvents.add(e);const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])if(s.startsWith(t)){const i=this.streamCoalesce.get(s);i.timer&&clearTimeout(i.timer),this.streamCoalesce.delete(s)}h.info("send-ctrl",`event marked as stream-rejected, future chunks will be dropped event=${e}`)}markEventTerminal(e){if(!(!e||this.terminalEvents.has(e))&&(this.terminalEvents.add(e),this.terminalEvents.size>g.MAX_TERMINAL_EVENTS)){const t=this.terminalEvents.values().next().value;t!==void 0&&this.terminalEvents.delete(t)}}isEventClosed(e){return!!e&&(this.rejectedEvents.has(e)||this.terminalEvents.has(e))}hasTerminalResult(e){return!!e&&(this.terminalResultEvents.has(e)||this.terminalEvents.has(e))}rememberTerminalResult(e){if(e&&(this.terminalResultEvents.add(e),this.terminalResultEvents.size>g.MAX_TERMINAL_EVENTS)){const t=this.terminalResultEvents.values().next().value;t!==void 0&&this.terminalResultEvents.delete(t)}}markEventStopped(e){e&&(this.stoppedEvents.add(e),h.info("send-ctrl",`[stop-trace] event marked stopped; subsequent outbound will be flagged event=${e}`))}flagOutboundAfterStop(e,t,s,i,o,a){!e||!this.stoppedEvents.has(e)||h.warn("send-ctrl",`[stop-trace] OUTBOUND AFTER STOP ${s} event=${e} session=${t} seq=${i} is_finish=${o} len=${a}`)}getGlobalRuntimeConfig(){return this.connectorRuntimeConfig}setStreamCoalesceMs(e){this.streamCoalesceMs=Number.isFinite(e)&&e>0?Math.floor(e):0}captureEventRuntimeConfig(e){this.terminalEvents.delete(e.event_id),this.terminalResultEvents.delete(e.event_id);const t=S(e.connector_runtime_config);if(t||!this.eventRuntimeConfigs.has(e.event_id)){const s=t??this.connectorRuntimeConfig;this.eventRuntimeConfigs.set(e.event_id,{responseDelivery:s.responseDelivery,toolEvents:s.toolEvents,thinkingEvents:s.thinkingEvents}),h.info("send-ctrl",`[runtime-config] event=${e.event_id} response_delivery=${s.responseDelivery} tool_events=${s.toolEvents} thinking_events=${s.thinkingEvents} source=${t?"event":"global"}`)}e.msg_id&&!this.eventQuotedMessageIds.has(e.event_id)&&this.eventQuotedMessageIds.set(e.event_id,e.msg_id)}discardEventState(e){e&&(this.rememberTerminalResult(e),this.markEventTerminal(e),this.clearEventTrackingState(e))}clearEventTrackingState(e){this.eventRuntimeConfigs.delete(e),this.eventQuotedMessageIds.delete(e),this.rejectedEvents.delete(e),this.singleMessageDeliveries.delete(e),this.thinkingSeqMap.delete(e),this.thinkingSessionMap.delete(e),this.bufferedEventTexts.delete(e);for(const t of[...this.streamCoalesce.keys()])if(t.startsWith(`${e}:`)){const s=this.streamCoalesce.get(t);s.timer&&clearTimeout(s.timer),this.streamCoalesce.delete(t)}this.stoppedEvents.delete(e)&&h.info("send-ctrl",`[stop-trace] event tracking cleared stop flag event=${e}`);for(const t of[...this.openStreams.keys()])t.startsWith(`${e}:`)&&this.openStreams.delete(t);for(const t of this.chunkSeqMap.keys())t.startsWith(`${e}:`)&&this.chunkSeqMap.delete(t);for(const t of this.recentToolCards.keys())t.startsWith(`${e}:`)&&this.recentToolCards.delete(t)}setDefaultQuoteTrigger(e){this.defaultQuoteTrigger=e}getDefaultQuotedMessageId(e){if(!(!this.defaultQuoteTrigger||!e))return this.eventQuotedMessageIds.get(e)}resolveEventRuntimeConfig(e){if(e){const t=this.eventRuntimeConfigs.get(e);if(t)return t}return this.connectorRuntimeConfig}shouldDropToolDisplayEvent(e){return y(this.resolveEventRuntimeConfig(e))}shouldDropThinkingDisplayEvent(e){return C(this.resolveEventRuntimeConfig(e))}shouldDropCodexDisplayEvent(e,t){return this.shouldDropToolDisplayEvent(e)?t==="item/completed":!1}shouldDropAcpRawDisplayEvent(e,t){return!!(this.shouldDropToolDisplayEvent(e)&&(t==="tool_use"||t==="tool_result")||this.shouldDropThinkingDisplayEvent(e)&&t==="thinking")}sendReply(e,t,s,i,o,a){if(!a?.skipToolFilter&&this.shouldDropToolDisplayEvent(e)&&$(s,o)||this.isEventClosed(e))return;if(this.flagOutboundAfterStop(e,t,"reply",0,!1,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="stream"&&!o){const n=_(s),l=e?`reply_stream_${e}`:`reply_stream_${Date.now()}`;if(n.length===0){this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s||" ",quoted_message_id:i||void 0});return}for(let u=0;u<n.length;u++){const c=u===n.length-1;this.sendStreamChunk(e,t,n[u],u+1,c,l,i)}return}this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s,quoted_message_id:i||void 0,...o?{extra:o}:{}})}sendStreamChunk(e,t,s,i,o,a,r){if(this.isEventClosed(e))return;if(r=r??this.getDefaultQuotedMessageId(e),this.flagOutboundAfterStop(e,t,"stream_chunk",i,o,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){this.bufferStreamChunk(e,t,s,r,a);return}if(this.streamCoalesceMs<=0){this.emitStreamChunkParts(e,t,s,i,o,a,r);return}this.coalesceStreamChunk(e,t,s,o,a,r)}async sendFinalStreamChunkReliable(e,t,s,i,o=!1,a=!1){if(this.isEventClosed(e))throw new Error(`required agent output was already rejected or the event is terminal: event=${e}`);a||this.finalizeThinking(e,t);const r=this.resolveEventRuntimeConfig(e);if(!o&&r.responseDelivery==="single_message"&&e){if(this.flushCoalesceForEvent(e),await this.ensureSingleMessageDelivery(e,i),this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`);return}const n=`${e}:${s??"default"}`;this.flushCoalesce(n,!1),this.streamCoalesce.delete(n);const l=(this.chunkSeqMap.get(n)??0)+1;this.chunkSeqMap.set(n,l),this.openStreams.delete(n);const u=this.getDefaultQuotedMessageId(e),c={event_id:e,session_id:t,delta_content:"",chunk_seq:l,is_finish:!0,...s?{client_msg_id:s}:{},...u?{quoted_message_id:u}:{}};this.flagOutboundAfterStop(e,t,"stream_chunk_final",l,!0,0);const p=async()=>{const f=await this.handle.sendStreamChunkRequest(c,i);if(f.cmd!=="send_ack"){const d=f.payload;throw new Error(`final chunk rejected: cmd=${f.cmd} code=${d?.code??""} msg=${d?.msg??""}`)}};try{await p()}catch(f){if(E(f))h.warn("send-ctrl",`final chunk ACK timed out, retry request with same chunk_seq=${l} event=${e}`),await p();else throw h.warn("send-ctrl",`final chunk send failed (no resend) event=${e}: ${f}`),f}if(this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`)}async deliverAuxiliaryLargeText(e,t,s,i){if(!s||this.isEventClosed(e))return!1;if(this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){const r=this.getDefaultQuotedMessageId(e),n=_(s);for(let l=0;l<n.length;l++)this.flagOutboundAfterStop(e,t,"aux_detail_msg",l+1,!1,n[l].length),this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:n[l],...l===0&&r?{quoted_message_id:r}:{},client_msg_id:n.length>1?`${i}_p${l+1}`:i});return!0}const a=_(s);for(const r of a)this.sendStreamChunk(e,t,r,0,!1,i);return await this.sendFinalStreamChunkReliable(e,t,i,void 0,!1,!0),!0}coalesceStreamChunk(e,t,s,i,o,a){if(!s&&!i)return;const r=`${e}:${o??"default"}`;let n=this.streamCoalesce.get(r);if(n||(n={eventId:e,sessionId:t,clientMsgId:o,quotedMessageId:a,text:"",flushedOnce:!1},this.streamCoalesce.set(r,n)),s&&(n.text+=s),n.sessionId=t,o!==void 0&&(n.clientMsgId=o),!n.quotedMessageId&&a&&(n.quotedMessageId=a),i){this.flushCoalesce(r,!0);return}if(!n.flushedOnce||n.text.length>=g.STREAM_COALESCE_MAX_RUNES){this.flushCoalesce(r,!1);return}n.timer||(n.timer=setTimeout(()=>this.flushCoalesce(r,!1),this.streamCoalesceMs))}flushCoalesce(e,t){const s=this.streamCoalesce.get(e);if(!s)return;s.timer&&(clearTimeout(s.timer),s.timer=void 0);const i=s.text;s.text="",s.flushedOnce=!0,t&&this.streamCoalesce.delete(e),!(!i&&!t)&&this.emitStreamChunkParts(s.eventId,s.sessionId,i,0,t,s.clientMsgId,s.quotedMessageId)}flushCoalesceForEvent(e){const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])s.startsWith(t)&&(this.flushCoalesce(s,!1),this.streamCoalesce.delete(s))}emitStreamChunkParts(e,t,s,i,o,a,r){const n=s||(o?`
2
- `:"");if(!n&&!o)return;const l=_(n,k);l.length===0&&l.push(n||`
3
- `);const u=`${e}:${a??"default"}`;for(let c=0;c<l.length;c++){const p=c===l.length-1,f=this.chunkSeqMap.get(u)??0,d=c===0&&i>f?i:f+1;this.chunkSeqMap.set(u,d),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:l[c],chunk_seq:d,is_finish:p&&o,...a?{client_msg_id:a}:{},...r?{quoted_message_id:r}:{}})}e&&(o?this.openStreams.delete(u):this.openStreams.set(u,{eventId:e,sessionId:t,clientMsgId:a,quotedMessageId:r}))}finalizeOpenStreams(e){if(!e||this.isEventClosed(e))return;this.finalizeThinking(e,""),this.flushCoalesceForEvent(e);const t=`${e}:`;for(const[s,i]of[...this.openStreams]){if(!s.startsWith(t))continue;this.openStreams.delete(s);const o=(this.chunkSeqMap.get(s)??0)+1;this.chunkSeqMap.set(s,o),this.handle.sendStreamChunk({event_id:i.eventId,session_id:i.sessionId,delta_content:"",chunk_seq:o,is_finish:!0,...i.clientMsgId?{client_msg_id:i.clientMsgId}:{},...i.quotedMessageId?{quoted_message_id:i.quotedMessageId}:{}}),h.info("send-ctrl",`appended missing stream fence before terminal event=${i.eventId} client_msg_id=${i.clientMsgId??"default"} chunk_seq=${o}`)}}sendEventResult(e,t,s,i,o=!1){if(!e||this.hasTerminalResult(e))return;this.rememberTerminalResult(e),this.finalizeThinking(e,""),this.flushCoalesceForEvent(e);const a=this.ensureSingleMessageDelivery(e),r=(n,l=s,u=i)=>{n==="responded"&&this.rejectedEvents.has(e)&&(n="failed",u=u||"agent_output_rejected",l=l||"required agent output was rejected by the server"),this.markEventTerminal(e),this.handle.sendEventResult({event_id:e,status:n,...l?{msg:l}:{},...u?{code:u}:{},...o&&n===t?{error_surfaced:!0}:{},updated_at:Date.now()}),this.clearEventTrackingState(e)};if(!a){r(t);return}a.then(()=>r(t),n=>{const l=`final output delivery failed: ${n instanceof Error?n.message:String(n)}`;r(t==="responded"?"failed":t,t==="responded"?l:s,t==="responded"?"agent_output_delivery_failed":i)})}sendThinking(e,t,s){if(this.shouldDropThinkingDisplayEvent(e)||this.isEventClosed(e))return;this.flagOutboundAfterStop(e,t,"thinking",this.thinkingSeqMap.get(e)??0,!1,(s||"").length);const i=(this.thinkingSeqMap.get(e)??0)+1;this.thinkingSeqMap.set(e,i),this.thinkingSessionMap.set(e,t),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:s,chunk_seq:i,is_finish:!1,client_msg_id:`${e}_thinking`,is_thinking:!0})}sendToolExecutionCard(e,t,s,i){if(this.shouldDropToolDisplayEvent(e)){h.info("send-ctrl",`[tool-card] DROP event=${e} session=${t} summary=${s.summaryText}`);return}const a=Date.now(),r=`${e}:${s.summaryText}:${s.detailText??""}`,n=this.recentToolCards.get(r);if(n!==void 0&&a-n<g.TOOL_CARD_DEDUP_MS){h.info("send-ctrl",`[tool-card] DEDUP event=${e} session=${t} summary=${s.summaryText}`);return}this.recentToolCards.set(r,a);const l={summary_text:s.summaryText};s.detailText&&(l.detail_text=s.detailText),h.info("send-ctrl",`[tool-card] SEND event=${e} session=${t} summary=${s.summaryText}`),this.handle.sendMsg({event_id:e,session_id:t,client_msg_id:i??`tool_${++this.toolCardSeq}_${Date.now()}`,msg_type:1,content:"",extra:{channel_data:{grix:{toolExecution:l}},agent_api_origin:!0}})}finalizeThinking(e,t){const s=this.thinkingSeqMap.get(e);s!==void 0&&(this.thinkingSeqMap.delete(e),t=t||this.thinkingSessionMap.get(e)||"",this.thinkingSessionMap.delete(e),t&&(this.isEventClosed(e)||this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:"",chunk_seq:s+1,is_finish:!0,client_msg_id:`${e}_thinking`,is_thinking:!0})))}bufferOnly(e,t,s,i,o){o=o??this.getDefaultQuotedMessageId(e),this.bufferStreamChunk(e,t,s,o)}bufferStreamChunk(e,t,s,i,o){const a=typeof o=="string"&&o.startsWith("reply_"),r=this.bufferedEventTexts.get(e);if(!r){this.bufferedEventTexts.set(e,{sessionId:t,text:s??"",quotedMessageId:i||void 0,replyReceived:a});return}a?r.replyReceived?s&&(r.text+=s):(r.text=s??"",r.replyReceived=!0):!r.replyReceived&&s&&(r.text+=s),!r.quotedMessageId&&i&&(r.quotedMessageId=i)}ensureSingleMessageDelivery(e,t){const s=this.singleMessageDeliveries.get(e);if(s)return s;const i=this.bufferedEventTexts.get(e);if(!i||(this.bufferedEventTexts.delete(e),!i.text))return;const o=(async()=>{const a={event_id:e,session_id:i.sessionId,content:i.text,client_msg_id:`agent_single_${e}`,...i.quotedMessageId?{quoted_message_id:i.quotedMessageId}:{}},r=async()=>{const n=t===void 0?await this.handle.sendText(a):await this.handle.sendText(a,t);if(n.cmd!=="send_ack"){const l=n.payload;throw new Error(`single-message output rejected: cmd=${n.cmd} code=${l?.code??""} msg=${l?.msg??""}`)}};try{await r()}catch(n){if(!E(n))throw n;h.warn("send-ctrl",`single-message ACK timed out, retry request with stable client_msg_id=${a.client_msg_id} event=${e}`),await r()}})();return this.singleMessageDeliveries.set(e,o),o}}function T(){const m=process.env.GRIX_STREAM_COALESCE_MS;if(m===void 0||m==="")return 500;const e=Number(m);return Number.isFinite(e)&&e>=0?Math.floor(e):500}function $(m,e){return e&&typeof e=="object"&&e.channel_data?.grix?.toolExecution?!0:/^\[tool\]/.test(m)||/^\[tool result\]/.test(m)}export{v as DEFAULT_QUOTE_TRIGGER_BY_ADAPTER,g as SendController};
1
+ import{isRequestTimeoutError as C}from"../core/aibot/errors.js";import{log as f}from"../core/log/index.js";import{splitTextForAibotProtocol as E,AIBOT_PROTOCOL_MAX_RUNES as y}from"../core/protocol/protocol-text.js";import{isThinkingEventDropped as S,isToolEventDropped as T,normalizeRuntimeConfigSnapshot as $}from"./runtime-config.js";const b={claude:!1,acp:!1,codex:!0,codewhale:!0,pi:!0,openhuman:!1,cursor:!1,opencode:!0,agy:!0,"deepseek-harness":!1};class m{handle;connectorRuntimeConfig;eventRuntimeConfigs=new Map;eventQuotedMessageIds=new Map;defaultQuoteTrigger=!1;thinkingSeqMap=new Map;thinkingSessionMap=new Map;toolCardSeq=0;bufferedEventTexts=new Map;singleMessageDeliveries=new Map;chunkSeqMap=new Map;openStreams=new Map;rejectedEvents=new Set;terminalEvents=new Set;terminalResultEvents=new Set;static MAX_TERMINAL_EVENTS=1e3;stoppedEvents=new Set;streamCoalesce=new Map;streamCoalesceMs=R();static STREAM_COALESCE_MAX_RUNES=2048;recentToolCards=new Map;static TOOL_CARD_DEDUP_MS=100;constructor(e){this.connectorRuntimeConfig={...e}}bind(e){this.handle=e}markEventRejected(e){if(!e)return;this.rejectedEvents.add(e),this.rejectedEvents.size>m.MAX_TERMINAL_EVENTS&&this.rejectedEvents.delete(this.rejectedEvents.values().next().value);const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])if(s.startsWith(t)){const i=this.streamCoalesce.get(s);i.timer&&clearTimeout(i.timer),this.streamCoalesce.delete(s)}f.info("send-ctrl",`event marked as stream-rejected, future chunks will be dropped event=${e}`)}markEventTerminal(e){if(!(!e||this.terminalEvents.has(e))&&(this.terminalEvents.add(e),this.terminalEvents.size>m.MAX_TERMINAL_EVENTS)){const t=this.terminalEvents.values().next().value;t!==void 0&&this.terminalEvents.delete(t)}}isEventClosed(e){return!!e&&(this.rejectedEvents.has(e)||this.terminalEvents.has(e))}hasTerminalResult(e){return!!e&&(this.terminalResultEvents.has(e)||this.terminalEvents.has(e))}rememberTerminalResult(e){if(e&&(this.terminalResultEvents.add(e),this.terminalResultEvents.size>m.MAX_TERMINAL_EVENTS)){const t=this.terminalResultEvents.values().next().value;t!==void 0&&this.terminalResultEvents.delete(t)}}markEventStopped(e){e&&(this.stoppedEvents.add(e),f.info("send-ctrl",`[stop-trace] event marked stopped; subsequent outbound will be flagged event=${e}`))}flagOutboundAfterStop(e,t,s,i,r,a){!e||!this.stoppedEvents.has(e)||f.warn("send-ctrl",`[stop-trace] OUTBOUND AFTER STOP ${s} event=${e} session=${t} seq=${i} is_finish=${r} len=${a}`)}getGlobalRuntimeConfig(){return this.connectorRuntimeConfig}setStreamCoalesceMs(e){this.streamCoalesceMs=Number.isFinite(e)&&e>0?Math.floor(e):0}captureEventRuntimeConfig(e){this.terminalEvents.delete(e.event_id),this.terminalResultEvents.delete(e.event_id);const t=$(e.connector_runtime_config);if(t||!this.eventRuntimeConfigs.has(e.event_id)){const s=t??this.connectorRuntimeConfig;this.eventRuntimeConfigs.set(e.event_id,{responseDelivery:s.responseDelivery,toolEvents:s.toolEvents,thinkingEvents:s.thinkingEvents}),f.info("send-ctrl",`[runtime-config] event=${e.event_id} response_delivery=${s.responseDelivery} tool_events=${s.toolEvents} thinking_events=${s.thinkingEvents} source=${t?"event":"global"}`)}e.msg_id&&!this.eventQuotedMessageIds.has(e.event_id)&&this.eventQuotedMessageIds.set(e.event_id,e.msg_id)}discardEventState(e){e&&(this.rememberTerminalResult(e),this.markEventTerminal(e),this.clearEventTrackingState(e))}clearEventTrackingState(e){this.eventRuntimeConfigs.delete(e),this.eventQuotedMessageIds.delete(e),this.singleMessageDeliveries.delete(e),this.thinkingSeqMap.delete(e),this.thinkingSessionMap.delete(e),this.bufferedEventTexts.delete(e);for(const t of[...this.streamCoalesce.keys()])if(t.startsWith(`${e}:`)){const s=this.streamCoalesce.get(t);s.timer&&clearTimeout(s.timer),this.streamCoalesce.delete(t)}this.stoppedEvents.delete(e)&&f.info("send-ctrl",`[stop-trace] event tracking cleared stop flag event=${e}`);for(const t of[...this.openStreams.keys()])t.startsWith(`${e}:`)&&this.openStreams.delete(t);for(const t of this.chunkSeqMap.keys())t.startsWith(`${e}:`)&&this.chunkSeqMap.delete(t);for(const t of this.recentToolCards.keys())t.startsWith(`${e}:`)&&this.recentToolCards.delete(t)}setDefaultQuoteTrigger(e){this.defaultQuoteTrigger=e}applyExplicitFinalQuote(e,t,s){const i=typeof s=="string"?s.trim():"";if(!i)return;const r=this.bufferedEventTexts.get(e);r&&!r.quotedMessageId&&(r.quotedMessageId=i);const a=this.streamCoalesce.get(`${e}:${t??"default"}`);return a&&!a.quotedMessageId&&(a.quotedMessageId=i),i}getDefaultQuotedMessageId(e){if(!(!this.defaultQuoteTrigger||!e))return this.eventQuotedMessageIds.get(e)}resolveEventRuntimeConfig(e){if(e){const t=this.eventRuntimeConfigs.get(e);if(t)return t}return this.connectorRuntimeConfig}shouldDropToolDisplayEvent(e){return T(this.resolveEventRuntimeConfig(e))}shouldDropThinkingDisplayEvent(e){return S(this.resolveEventRuntimeConfig(e))}shouldDropCodexDisplayEvent(e,t){return this.shouldDropToolDisplayEvent(e)?t==="item/completed":!1}shouldDropAcpRawDisplayEvent(e,t){return!!(this.shouldDropToolDisplayEvent(e)&&(t==="tool_use"||t==="tool_result")||this.shouldDropThinkingDisplayEvent(e)&&t==="thinking")}sendReply(e,t,s,i,r,a){if(!a?.skipToolFilter&&this.shouldDropToolDisplayEvent(e)&&M(s,r)||this.isEventClosed(e))return;if(this.flagOutboundAfterStop(e,t,"reply",0,!1,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="stream"&&!r){const n=E(s),l=e?`reply_stream_${e}`:`reply_stream_${Date.now()}`;if(n.length===0){this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s||" ",quoted_message_id:i||void 0});return}for(let u=0;u<n.length;u++){const h=u===n.length-1;this.sendStreamChunk(e,t,n[u],u+1,h,l,i)}return}this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:s,quoted_message_id:i||void 0,...r?{extra:r}:{}})}sendStreamChunk(e,t,s,i,r,a,o){if(this.isEventClosed(e))return;if(o=o??this.getDefaultQuotedMessageId(e),this.flagOutboundAfterStop(e,t,"stream_chunk",i,r,(s||"").length),this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){this.bufferStreamChunk(e,t,s,o,a);return}if(this.streamCoalesceMs<=0){this.emitStreamChunkParts(e,t,s,i,r,a,o);return}this.coalesceStreamChunk(e,t,s,r,a,o)}async sendFinalStreamChunkReliable(e,t,s,i,r=!1,a=!1,o){if(this.isEventClosed(e))throw new Error(`required agent output was already rejected or the event is terminal: event=${e}`);a||this.finalizeThinking(e,t);const n=this.applyExplicitFinalQuote(e,s,o),l=this.resolveEventRuntimeConfig(e);if(!r&&l.responseDelivery==="single_message"&&e){if(this.flushCoalesceForEvent(e),await this.ensureSingleMessageDelivery(e,i),this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`);return}const u=`${e}:${s??"default"}`;this.flushCoalesce(u,!1),this.streamCoalesce.delete(u);const h=(this.chunkSeqMap.get(u)??0)+1;this.chunkSeqMap.set(u,h),this.openStreams.delete(u);const _=n||this.getDefaultQuotedMessageId(e),g={event_id:e,session_id:t,delta_content:"",chunk_seq:h,is_finish:!0,...s?{client_msg_id:s}:{},..._?{quoted_message_id:_}:{}};this.flagOutboundAfterStop(e,t,"stream_chunk_final",h,!0,0);const p=async()=>{const c=await this.handle.sendStreamChunkRequest(g,i);if(c.cmd!=="send_ack"){const k=c.payload;throw new Error(`final chunk rejected: cmd=${c.cmd} code=${k?.code??""} msg=${k?.msg??""}`)}};try{await p()}catch(c){if(C(c))f.warn("send-ctrl",`final chunk ACK timed out, retry request with same chunk_seq=${h} event=${e}`),await p();else throw f.warn("send-ctrl",`final chunk send failed (no resend) event=${e}: ${c}`),c}if(this.isEventClosed(e))throw new Error(`required agent output was rejected before terminal: event=${e}`)}async deliverAuxiliaryLargeText(e,t,s,i){if(!s||this.isEventClosed(e))return!1;if(this.resolveEventRuntimeConfig(e).responseDelivery==="single_message"&&e){const o=this.getDefaultQuotedMessageId(e),n=E(s);for(let l=0;l<n.length;l++)this.flagOutboundAfterStop(e,t,"aux_detail_msg",l+1,!1,n[l].length),this.handle.sendMsg({event_id:e,session_id:t,msg_type:1,content:n[l],...l===0&&o?{quoted_message_id:o}:{},client_msg_id:n.length>1?`${i}_p${l+1}`:i});return!0}const a=E(s);for(const o of a)this.sendStreamChunk(e,t,o,0,!1,i);return await this.sendFinalStreamChunkReliable(e,t,i,void 0,!1,!0),!0}coalesceStreamChunk(e,t,s,i,r,a){if(!s&&!i)return;const o=`${e}:${r??"default"}`;let n=this.streamCoalesce.get(o);if(n||(n={eventId:e,sessionId:t,clientMsgId:r,quotedMessageId:a,text:"",flushedOnce:!1},this.streamCoalesce.set(o,n)),s&&(n.text+=s),n.sessionId=t,r!==void 0&&(n.clientMsgId=r),!n.quotedMessageId&&a&&(n.quotedMessageId=a),i){this.flushCoalesce(o,!0);return}if(!n.flushedOnce||n.text.length>=m.STREAM_COALESCE_MAX_RUNES){this.flushCoalesce(o,!1);return}n.timer||(n.timer=setTimeout(()=>this.flushCoalesce(o,!1),this.streamCoalesceMs))}flushCoalesce(e,t){const s=this.streamCoalesce.get(e);if(!s)return;s.timer&&(clearTimeout(s.timer),s.timer=void 0);const i=s.text;s.text="",s.flushedOnce=!0,t&&this.streamCoalesce.delete(e),!(!i&&!t)&&this.emitStreamChunkParts(s.eventId,s.sessionId,i,0,t,s.clientMsgId,s.quotedMessageId)}flushCoalesceForEvent(e){const t=`${e}:`;for(const s of[...this.streamCoalesce.keys()])s.startsWith(t)&&(this.flushCoalesce(s,!1),this.streamCoalesce.delete(s))}emitStreamChunkParts(e,t,s,i,r,a,o){const n=s||(r?`
2
+ `:"");if(!n&&!r)return;const l=E(n,y);l.length===0&&l.push(n||`
3
+ `);const u=`${e}:${a??"default"}`;for(let h=0;h<l.length;h++){const _=h===l.length-1,g=this.chunkSeqMap.get(u)??0,p=h===0&&i>g?i:g+1;this.chunkSeqMap.set(u,p),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:l[h],chunk_seq:p,is_finish:_&&r,...a?{client_msg_id:a}:{},...o?{quoted_message_id:o}:{}})}e&&(r?this.openStreams.delete(u):this.openStreams.set(u,{eventId:e,sessionId:t,clientMsgId:a,quotedMessageId:o}))}finalizeOpenStreams(e){if(!e||this.isEventClosed(e))return;this.finalizeThinking(e,""),this.flushCoalesceForEvent(e);const t=`${e}:`;for(const[s,i]of[...this.openStreams]){if(!s.startsWith(t))continue;this.openStreams.delete(s);const r=(this.chunkSeqMap.get(s)??0)+1;this.chunkSeqMap.set(s,r),this.handle.sendStreamChunk({event_id:i.eventId,session_id:i.sessionId,delta_content:"",chunk_seq:r,is_finish:!0,...i.clientMsgId?{client_msg_id:i.clientMsgId}:{},...i.quotedMessageId?{quoted_message_id:i.quotedMessageId}:{}}),f.info("send-ctrl",`appended missing stream fence before terminal event=${i.eventId} client_msg_id=${i.clientMsgId??"default"} chunk_seq=${r}`)}}sendEventResult(e,t,s,i,r=!1){if(!e||this.hasTerminalResult(e))return;this.rememberTerminalResult(e),this.finalizeThinking(e,""),this.flushCoalesceForEvent(e);const a=this.ensureSingleMessageDelivery(e),o=(n,l=s,u=i)=>{n==="responded"&&this.rejectedEvents.has(e)&&(n="failed",u=u||"agent_output_rejected",l=l||"required agent output was rejected by the server"),this.markEventTerminal(e),this.handle.sendEventResult({event_id:e,status:n,...l?{msg:l}:{},...u?{code:u}:{},...r&&n===t?{error_surfaced:!0}:{},updated_at:Date.now()}),this.clearEventTrackingState(e)};if(!a){o(t);return}a.then(()=>o(t),n=>{const l=`final output delivery failed: ${n instanceof Error?n.message:String(n)}`;o(t==="responded"?"failed":t,t==="responded"?l:s,t==="responded"?"agent_output_delivery_failed":i)})}sendThinking(e,t,s){if(this.shouldDropThinkingDisplayEvent(e)||this.isEventClosed(e))return;this.flagOutboundAfterStop(e,t,"thinking",this.thinkingSeqMap.get(e)??0,!1,(s||"").length);const i=(this.thinkingSeqMap.get(e)??0)+1;this.thinkingSeqMap.set(e,i),this.thinkingSessionMap.set(e,t),this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:s,chunk_seq:i,is_finish:!1,client_msg_id:`${e}_thinking`,is_thinking:!0})}sendToolExecutionCard(e,t,s,i){if(this.shouldDropToolDisplayEvent(e)){f.info("send-ctrl",`[tool-card] DROP event=${e} session=${t} summary=${s.summaryText}`);return}const a=Date.now(),o=`${e}:${s.summaryText}:${s.detailText??""}`,n=this.recentToolCards.get(o);if(n!==void 0&&a-n<m.TOOL_CARD_DEDUP_MS){f.info("send-ctrl",`[tool-card] DEDUP event=${e} session=${t} summary=${s.summaryText}`);return}this.recentToolCards.set(o,a);const l={summary_text:s.summaryText};s.detailText&&(l.detail_text=s.detailText),f.info("send-ctrl",`[tool-card] SEND event=${e} session=${t} summary=${s.summaryText}`),this.handle.sendMsg({event_id:e,session_id:t,client_msg_id:i??`tool_${++this.toolCardSeq}_${Date.now()}`,msg_type:1,content:"",extra:{channel_data:{grix:{toolExecution:l}},agent_api_origin:!0}})}finalizeThinking(e,t){const s=this.thinkingSeqMap.get(e);s!==void 0&&(this.thinkingSeqMap.delete(e),t=t||this.thinkingSessionMap.get(e)||"",this.thinkingSessionMap.delete(e),t&&(this.isEventClosed(e)||this.handle.sendStreamChunk({event_id:e,session_id:t,delta_content:"",chunk_seq:s+1,is_finish:!0,client_msg_id:`${e}_thinking`,is_thinking:!0})))}bufferOnly(e,t,s,i,r){r=r??this.getDefaultQuotedMessageId(e),this.bufferStreamChunk(e,t,s,r)}bufferStreamChunk(e,t,s,i,r){const a=typeof r=="string"&&r.startsWith("reply_"),o=this.bufferedEventTexts.get(e);if(!o){this.bufferedEventTexts.set(e,{sessionId:t,text:s??"",quotedMessageId:i||void 0,replyReceived:a});return}a?o.replyReceived?s&&(o.text+=s):(o.text=s??"",o.replyReceived=!0):!o.replyReceived&&s&&(o.text+=s),!o.quotedMessageId&&i&&(o.quotedMessageId=i)}ensureSingleMessageDelivery(e,t){const s=this.singleMessageDeliveries.get(e);if(s)return s;const i=this.bufferedEventTexts.get(e);if(!i||(this.bufferedEventTexts.delete(e),!i.text))return;const r=(async()=>{const a={event_id:e,session_id:i.sessionId,content:i.text,client_msg_id:`agent_single_${e}`,...i.quotedMessageId?{quoted_message_id:i.quotedMessageId}:{}},o=async()=>{const n=t===void 0?await this.handle.sendText(a):await this.handle.sendText(a,t);if(n.cmd!=="send_ack"){const l=n.payload;throw new Error(`single-message output rejected: cmd=${n.cmd} code=${l?.code??""} msg=${l?.msg??""}`)}};try{await o()}catch(n){if(!C(n))throw n;f.warn("send-ctrl",`single-message ACK timed out, retry request with stable client_msg_id=${a.client_msg_id} event=${e}`),await o()}})();return this.singleMessageDeliveries.set(e,r),r}}function R(){const d=process.env.GRIX_STREAM_COALESCE_MS;if(d===void 0||d==="")return 500;const e=Number(d);return Number.isFinite(e)&&e>=0?Math.floor(e):500}function M(d,e){return e&&typeof e=="object"&&e.channel_data?.grix?.toolExecution?!0:/^\[tool\]/.test(d)||/^\[tool result\]/.test(d)}export{b as DEFAULT_QUOTE_TRIGGER_BY_ADAPTER,m as SendController};
@@ -1,3 +1,3 @@
1
- import{LOCAL_ACTION_ERROR_CODES as C,LOCAL_ACTION_TYPES as w,SESSION_CONTROL_ERROR_CODES as u,SESSION_CONTROL_VERBS as l,SESSION_MODE_IDS as b}from"../adapter/claude/protocol-contract.js";import{fetchAvailableModels as I,getCachedModels as v}from"../adapter/claude/model-list.js";import{normalizeClaudeEffort as M,CLAUDE_EFFORT_LEVELS as _}from"../core/config/claude-direct-env.js";import{log as p}from"../core/log/index.js";const R=["buildClaudeToolbarMeta","buildOpenedBindingResult","currentClaudeModeId","deferredCallbacks","ensureImportedAgentSession","ensureSlotStarted","failSessionOpen","getClaudeWorkerStatus","normalizeClaudeModeId","refreshClaudeWorkerStatusCard","refreshQuotaAfterModelSwitch","resolveClaudeSessionEffort","resolveCwdForBinding","setResolvedAgentSessionId"],A=["name","config","aibotHandle","pool","bindingStore","globalConfigStore","sessionBindings","claudeWorkerStatus","deferredMgr"];async function x(e,c,g){const d=g.session_id,r=(i,s,t)=>{e.aibotHandle.sendEventResult({event_id:g.event_id,status:i,...s?{msg:s}:{},...t?{code:t}:{},updated_at:Date.now()})};e.aibotHandle.sendEventAck({event_id:g.event_id,session_id:d,received_at:Date.now()});try{switch(c.verb){case l.open:{await I().catch(()=>{});const i=c.args.trim();if(!i){r("failed","Usage: /grix open <working-directory>",u.cwdRequired);return}let s="";try{s=await e.resolveCwdForBinding(i)}catch(n){r("failed",n instanceof Error?n.message:String(n),u.invalidCwd);return}const t=e.bindingStore.get(d);if(t?.cwd){const n=await e.resolveCwdForBinding(t.cwd);if(n!==s){r("failed","session binding cannot be changed to another working directory",u.rebindForbidden);return}e.bindingStore.ensureModeId(d,b.fullAuto),e.sessionBindings.set(d,n),await e.ensureSlotStarted(d),await e.deferredMgr.release(d,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(d,n),r("responded",`Working directory already bound: ${n}`);return}e.bindingStore.set(d,s,{modeId:b.fullAuto}),e.sessionBindings.set(d,s),await e.ensureSlotStarted(d),await e.deferredMgr.release(d,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(d,s),r("responded",`Session bound to ${s}`);return}case l.where:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}r("responded",`Working directory: ${i.cwd}`);return}case l.status:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}const s=e.currentClaudeModeId(d),t=e.getClaudeWorkerStatus(d);r("responded",`Status: worker=${t} mode=${s} cwd=${i.cwd}`);return}case l.stop:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}await e.pool.removeSlot(d),e.claudeWorkerStatus.set(d,"stopped"),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"stopped",cwd:i.cwd}),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"stopped",cwd:i.cwd,meta:e.buildClaudeToolbarMeta(d)}),r("responded",`Session worker stopped for ${i.cwd}`);return}case l.restart:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,i.cwd),r("responded",`Session worker restarted for ${i.cwd}`);return}case l.setMode:{const i=c.args.trim();if(!i){r("failed","Usage: /grix set_mode <mode-id>",C.modeInvalid);return}const s=e.normalizeClaudeModeId(i);if(s!==i.toLowerCase()){r("failed","set mode_id is invalid",C.modeInvalid);return}const t=e.bindingStore.get(d);if(!t?.cwd){r("failed","session binding was not found",u.bindingMissing);return}if(e.currentClaudeModeId(d)===s){r("responded",`Mode unchanged: ${s}`);return}if(e.getClaudeWorkerStatus(d)==="busy"){r("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F",u.workerBusy);return}e.bindingStore.setModeId(d,s),e.globalConfigStore?.set(e.name,{modeId:s}),await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,t.cwd),r("responded",`Mode set to ${s}`);return}case l.setModel:{const i=c.args.trim();if(!i){r("failed","Usage: /grix set_model <model-id>");return}const s=e.bindingStore.get(d);if(!s?.cwd){r("failed","session binding was not found",u.bindingMissing);return}if((s.modelId??"")===i){r("responded",`Model unchanged: ${i}`);return}if(e.getClaudeWorkerStatus(d)==="busy"){r("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B",u.workerBusy);return}e.bindingStore.setModelId(d,i),e.globalConfigStore?.set(e.name,{modelId:i}),await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,s.cwd),e.refreshQuotaAfterModelSwitch(d,i),r("responded",`Model set to ${i}`);return}case l.listOptions:{const i=v(),s=e.bindingStore.get(d),t=i.map(a=>a.id).join(", "),n=`${b.fullAuto}, ${b.approval}`,o=e.resolveClaudeSessionEffort(d)??"auto";r("responded",`Modes (current: ${e.currentClaudeModeId(d)}): ${n}
2
- Models (current: ${s?.modelId??"default"}): ${t}
3
- Effort (current: ${o}): ${_.join(", ")}`);return}case l.exec:{const[i,...s]=c.args.trim().split(/\s+/);if(!i){r("failed","Usage: /grix exec <command> [args]",u.verbInvalid);return}const n=e.pool.getSlot(d)?.adapter;if(!n?.execCommand){r("failed","Agent does not support command execution",u.verbInvalid);return}const o=n.getSupportedCommands?.()??[];if(!o.some(a=>a.name===i)){r("failed",`Unknown command: ${i}. Supported: ${o.map(a=>a.name).join(", ")}`,u.verbInvalid);return}try{const a=await n.execCommand(i,s.join(" "),d);r(a.status==="ok"?"responded":"failed",a.message??`${i} ${a.status}`,a.status==="ok"?void 0:u.runtimeError)}catch(a){r("failed",`exec error: ${a instanceof Error?a.message:a}`,u.runtimeError)}return}default:r("failed",`Unsupported command for Claude: /grix ${c.verb}`,u.verbInvalid)}}catch(i){if(c.verb===l.open){const{code:s,msg:t}=e.failSessionOpen(i,{sessionId:d,eventId:g.event_id,quotedMessageId:g.msg_id,cwd:e.bindingStore.get(d)?.cwd||c.args.trim()});r("failed",t,s)}else r("failed",i instanceof Error?i.message:String(i),u.runtimeError)}}async function W(e,c){const g=String(c.action_type??"").trim();if(g!==w.sessionControl&&g!==w.setMode&&g!=="set_mode"&&g!==w.setModel&&g!=="set_model"&&g!==w.setReasoningEffort&&g!=="set_effort")return!1;const d=c.params??{},r=String(d.session_id??"").trim(),i=g===w.setMode?l.setMode:g===w.setModel?l.setModel:g===w.setReasoningEffort||g==="set_effort"?w.setReasoningEffort:String(d.verb??"").trim().toLowerCase();if(p.info(e.name,`handleSessionControlLocalAction verb=${i} action_id=${c.action_id} session_id=${r}`),!r)return e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"failed",error_code:C.localActionRouteMissing,error_msg:"local action session_id is required"}),!0;const s=n=>{e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:n},r)},t=(n,o)=>{p.warn(e.name,`session_control local_action failed action_id=${c.action_id} session_id=${r} verb=${i} code=${n} msg=${o}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"failed",error_code:n,error_msg:o})};try{switch(i){case l.open:{await I().catch(()=>{});const n=String(d.cwd??"").trim(),o=String(d.agent_session_id??"").trim();if(!n)return t(u.cwdRequired,"session control cwd is required"),!0;p.info(e.name,`handleSessionControlLocalAction open cwd=${n} session_id=${r}`);const a=await e.resolveCwdForBinding(n);e.ensureImportedAgentSession(o,a);const f=e.bindingStore.get(r);if(f?.cwd){const S=await e.resolveCwdForBinding(f.cwd);return S!==a?(t(u.rebindForbidden,"session binding cannot be changed to another working directory"),!0):(e.bindingStore.ensureModeId(r,b.fullAuto),e.setResolvedAgentSessionId(r,o),e.sessionBindings.set(r,S),await e.ensureSlotStarted(r),await e.deferredMgr.release(r,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(r,S),s({outcome:"opened",binding:{...e.buildOpenedBindingResult(r,S),mode_id:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId)}}),!0)}return e.bindingStore.set(r,a,{modeId:b.fullAuto}),e.setResolvedAgentSessionId(r,o),e.sessionBindings.set(r,a),await e.ensureSlotStarted(r),await e.deferredMgr.release(r,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(r,a),s({outcome:"opened",binding:{...e.buildOpenedBindingResult(r,a),mode_id:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId)}}),!0}case l.status:case l.where:{const n=e.bindingStore.get(r);return n?.cwd?(s({outcome:i,binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r),worker_status:e.getClaudeWorkerStatus(r)}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case l.stop:{const n=e.bindingStore.get(r);return n?.cwd?(await e.pool.removeSlot(r),s({outcome:"stopped",binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r),worker_status:"stopped"}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case l.restart:{const n=e.bindingStore.get(r);return n?.cwd?(await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,n.cwd),s({outcome:"restarted",binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r)}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case w.setReasoningEffort:{const n=[d.effort,d.reasoning_effort,d.reasoning_eff,d.value].map(S=>String(S??"").trim()).find(Boolean)??"",o=M(n);if(!n||!o)return t(C.effortInvalid,`effort is invalid; expected one of ${_.join(", ")}`),!0;const a=e.bindingStore.get(r);if(!a?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if(e.bindingStore.getEffort(r)!==o){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362 effort"),!0;e.bindingStore.setEffort(r,o),await e.pool.removeSlot(r),await e.ensureSlotStarted(r)}return e.globalConfigStore?.set(e.name,{effort:o}),e.refreshClaudeWorkerStatusCard(r,a.cwd),s({outcome:"effort_set",effort:o,reasoning_effort:o,available_efforts:[..._],binding:{cwd:a.cwd,effort:o}}),!0}case l.setMode:{const n=String(d.mode_id??d.modeId??"").trim();if(!n)return t(C.modeInvalid,"set mode_id is invalid"),!0;const o=e.normalizeClaudeModeId(n);if(o!==n.toLowerCase())return t(C.modeInvalid,"set mode_id is invalid"),!0;const a=e.bindingStore.get(r);if(!a?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if(e.currentClaudeModeId(r)!==o){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F"),!0;e.bindingStore.setModeId(r,o),e.globalConfigStore?.set(e.name,{modeId:o}),await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,a.cwd)}return s({outcome:"mode_set",mode_id:o,binding:{cwd:a.cwd,mode_id:o}}),!0}case l.setModel:{const n=String(d.model_id??d.modelId??"").trim();if(!n)return t("set_model_invalid","model_id is required"),!0;const o=e.bindingStore.get(r);if(!o?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if((o.modelId??"")!==n){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B"),!0;e.bindingStore.setModelId(r,n),e.globalConfigStore?.set(e.name,{modelId:n}),await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,o.cwd),e.refreshQuotaAfterModelSwitch(r,n)}return s({outcome:"model_set",model_id:n,binding:{cwd:o.cwd,model_id:n}}),!0}case l.listOptions:{const n=v(),o=e.pool.getSlot(r),a=e.resolveClaudeSessionEffort(r)??"auto";return s({modes:[b.fullAuto,b.approval],currentModeId:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId),models:n.map(f=>({modelId:f.id,name:f.displayName})),currentModelId:e.bindingStore.get(r)?.modelId??"",available_models:n.map(f=>({id:f.id,displayName:f.displayName})),available_efforts:[..._],effort:a,reasoning_effort:a,agent_commands:o?.adapter?.getSupportedCommands?.()??[]}),!0}case l.exec:{const[n,...o]=String(d.args??"").trim().split(/\s+/);if(!n)return t(u.verbInvalid,"Usage: exec <command> [args]"),!0;await e.ensureSlotStarted(r);const f=e.pool.getSlot(r)?.adapter;if(!f?.execCommand)return t(u.verbInvalid,"Agent does not support command execution"),!0;const S=f.getSupportedCommands?.()??[];if(!S.some(m=>m.name===n))return t(u.verbInvalid,`Unknown command: ${n}. Supported: ${S.map(m=>m.name).join(", ")}`),!0;try{const m=await f.execCommand(n,o.join(" "),r);m.status==="ok"?s({outcome:"exec",command:n,message:m.message,data:m.data}):t(u.runtimeError,m.message??`${n} failed`)}catch(m){t(u.runtimeError,`exec error: ${m instanceof Error?m.message:m}`)}return!0}default:return t(u.verbInvalid,`session control verb ${i} is not supported`),!0}}catch(n){if(i===l.open){const{code:o,msg:a}=e.failSessionOpen(n,{sessionId:r,eventId:c.action_id,cwd:e.bindingStore.get(r)?.cwd||String(d.cwd??"").trim()});p.error(e.name,`handleSessionControlLocalAction error verb=${i} session_id=${r}: ${a}`),t(o,a)}else{const o=n instanceof Error?n.message:String(n);p.error(e.name,`handleSessionControlLocalAction error verb=${i} session_id=${r}: ${o}`),t(u.runtimeError,o)}return!0}}export{A as SESSION_CONTROL_ROUTER_HOST_FIELDS,R as SESSION_CONTROL_ROUTER_HOST_METHODS,x as routeSessionControlCommand,W as routeSessionControlLocalAction};
1
+ import{LOCAL_ACTION_ERROR_CODES as C,LOCAL_ACTION_TYPES as w,SESSION_CONTROL_ERROR_CODES as u,SESSION_CONTROL_VERBS as l,SESSION_MODE_IDS as b}from"../adapter/claude/protocol-contract.js";import{fetchAvailableModels as I,getCachedModels as v,toClaudeCliModelId as M}from"../adapter/claude/model-list.js";import{normalizeClaudeEffort as k,CLAUDE_EFFORT_LEVELS as _}from"../core/config/claude-direct-env.js";import{log as p}from"../core/log/index.js";const A=["buildClaudeToolbarMeta","buildOpenedBindingResult","currentClaudeModeId","deferredCallbacks","ensureImportedAgentSession","ensureSlotStarted","failSessionOpen","getClaudeWorkerStatus","normalizeClaudeModeId","refreshClaudeWorkerStatusCard","refreshQuotaAfterModelSwitch","resolveClaudeSessionEffort","resolveCwdForBinding","setResolvedAgentSessionId"],x=["name","config","aibotHandle","pool","bindingStore","globalConfigStore","sessionBindings","claudeWorkerStatus","deferredMgr"];async function W(e,c,g){const d=g.session_id,r=(i,a,t)=>{e.aibotHandle.sendEventResult({event_id:g.event_id,status:i,...a?{msg:a}:{},...t?{code:t}:{},updated_at:Date.now()})};e.aibotHandle.sendEventAck({event_id:g.event_id,session_id:d,received_at:Date.now()});try{switch(c.verb){case l.open:{await I().catch(()=>{});const i=c.args.trim();if(!i){r("failed","Usage: /grix open <working-directory>",u.cwdRequired);return}let a="";try{a=await e.resolveCwdForBinding(i)}catch(n){r("failed",n instanceof Error?n.message:String(n),u.invalidCwd);return}const t=e.bindingStore.get(d);if(t?.cwd){const n=await e.resolveCwdForBinding(t.cwd);if(n!==a){r("failed","session binding cannot be changed to another working directory",u.rebindForbidden);return}e.bindingStore.ensureModeId(d,b.fullAuto),e.sessionBindings.set(d,n),await e.ensureSlotStarted(d),await e.deferredMgr.release(d,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(d,n),r("responded",`Working directory already bound: ${n}`);return}e.bindingStore.set(d,a,{modeId:b.fullAuto}),e.sessionBindings.set(d,a),await e.ensureSlotStarted(d),await e.deferredMgr.release(d,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(d,a),r("responded",`Session bound to ${a}`);return}case l.where:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}r("responded",`Working directory: ${i.cwd}`);return}case l.status:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}const a=e.currentClaudeModeId(d),t=e.getClaudeWorkerStatus(d);r("responded",`Status: worker=${t} mode=${a} cwd=${i.cwd}`);return}case l.stop:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}await e.pool.removeSlot(d),e.claudeWorkerStatus.set(d,"stopped"),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"stopped",cwd:i.cwd}),e.aibotHandle.sendUpdateBindingCard({session_id:d,worker_status:"stopped",cwd:i.cwd,meta:e.buildClaudeToolbarMeta(d)}),r("responded",`Session worker stopped for ${i.cwd}`);return}case l.restart:{const i=e.bindingStore.get(d);if(!i?.cwd){r("failed","session binding was not found",u.bindingMissing);return}await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,i.cwd),r("responded",`Session worker restarted for ${i.cwd}`);return}case l.setMode:{const i=c.args.trim();if(!i){r("failed","Usage: /grix set_mode <mode-id>",C.modeInvalid);return}const a=e.normalizeClaudeModeId(i);if(a!==i.toLowerCase()){r("failed","set mode_id is invalid",C.modeInvalid);return}const t=e.bindingStore.get(d);if(!t?.cwd){r("failed","session binding was not found",u.bindingMissing);return}if(e.currentClaudeModeId(d)===a){r("responded",`Mode unchanged: ${a}`);return}if(e.getClaudeWorkerStatus(d)==="busy"){r("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F",u.workerBusy);return}e.bindingStore.setModeId(d,a),e.globalConfigStore?.set(e.name,{modeId:a}),await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,t.cwd),r("responded",`Mode set to ${a}`);return}case l.setModel:{const i=c.args.trim();if(!i){r("failed","Usage: /grix set_model <model-id>");return}const a=e.bindingStore.get(d);if(!a?.cwd){r("failed","session binding was not found",u.bindingMissing);return}if((a.modelId??"")===i){r("responded",`Model unchanged: ${i}`);return}if(e.getClaudeWorkerStatus(d)==="busy"){r("failed","\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148 /grix stop \u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B",u.workerBusy);return}e.bindingStore.setModelId(d,i),e.globalConfigStore?.set(e.name,{modelId:i}),await e.pool.removeSlot(d),await e.ensureSlotStarted(d),e.refreshClaudeWorkerStatusCard(d,a.cwd),e.refreshQuotaAfterModelSwitch(d,M(i)),r("responded",`Model set to ${i}`);return}case l.listOptions:{const i=v(),a=e.bindingStore.get(d),t=i.map(s=>s.id).join(", "),n=`${b.fullAuto}, ${b.approval}`,o=e.resolveClaudeSessionEffort(d)??"auto";r("responded",`Modes (current: ${e.currentClaudeModeId(d)}): ${n}
2
+ Models (current: ${a?.modelId??"default"}): ${t}
3
+ Effort (current: ${o}): ${_.join(", ")}`);return}case l.exec:{const[i,...a]=c.args.trim().split(/\s+/);if(!i){r("failed","Usage: /grix exec <command> [args]",u.verbInvalid);return}const n=e.pool.getSlot(d)?.adapter;if(!n?.execCommand){r("failed","Agent does not support command execution",u.verbInvalid);return}const o=n.getSupportedCommands?.()??[];if(!o.some(s=>s.name===i)){r("failed",`Unknown command: ${i}. Supported: ${o.map(s=>s.name).join(", ")}`,u.verbInvalid);return}try{const s=await n.execCommand(i,a.join(" "),d);r(s.status==="ok"?"responded":"failed",s.message??`${i} ${s.status}`,s.status==="ok"?void 0:u.runtimeError)}catch(s){r("failed",`exec error: ${s instanceof Error?s.message:s}`,u.runtimeError)}return}default:r("failed",`Unsupported command for Claude: /grix ${c.verb}`,u.verbInvalid)}}catch(i){if(c.verb===l.open){const{code:a,msg:t}=e.failSessionOpen(i,{sessionId:d,eventId:g.event_id,quotedMessageId:g.msg_id,cwd:e.bindingStore.get(d)?.cwd||c.args.trim()});r("failed",t,a)}else r("failed",i instanceof Error?i.message:String(i),u.runtimeError)}}async function L(e,c){const g=String(c.action_type??"").trim();if(g!==w.sessionControl&&g!==w.setMode&&g!=="set_mode"&&g!==w.setModel&&g!=="set_model"&&g!==w.setReasoningEffort&&g!=="set_effort")return!1;const d=c.params??{},r=String(d.session_id??"").trim(),i=g===w.setMode?l.setMode:g===w.setModel?l.setModel:g===w.setReasoningEffort||g==="set_effort"?w.setReasoningEffort:String(d.verb??"").trim().toLowerCase();if(p.info(e.name,`handleSessionControlLocalAction verb=${i} action_id=${c.action_id} session_id=${r}`),!r)return e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"failed",error_code:C.localActionRouteMissing,error_msg:"local action session_id is required"}),!0;const a=n=>{e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"ok",result:n},r)},t=(n,o)=>{p.warn(e.name,`session_control local_action failed action_id=${c.action_id} session_id=${r} verb=${i} code=${n} msg=${o}`),e.aibotHandle.sendLocalActionResult({action_id:c.action_id,status:"failed",error_code:n,error_msg:o})};try{switch(i){case l.open:{await I().catch(()=>{});const n=String(d.cwd??"").trim(),o=String(d.agent_session_id??"").trim();if(!n)return t(u.cwdRequired,"session control cwd is required"),!0;p.info(e.name,`handleSessionControlLocalAction open cwd=${n} session_id=${r}`);const s=await e.resolveCwdForBinding(n);e.ensureImportedAgentSession(o,s);const f=e.bindingStore.get(r);if(f?.cwd){const S=await e.resolveCwdForBinding(f.cwd);return S!==s?(t(u.rebindForbidden,"session binding cannot be changed to another working directory"),!0):(e.bindingStore.ensureModeId(r,b.fullAuto),e.setResolvedAgentSessionId(r,o),e.sessionBindings.set(r,S),await e.ensureSlotStarted(r),await e.deferredMgr.release(r,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(r,S),a({outcome:"opened",binding:{...e.buildOpenedBindingResult(r,S),mode_id:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId)}}),!0)}return e.bindingStore.set(r,s,{modeId:b.fullAuto}),e.setResolvedAgentSessionId(r,o),e.sessionBindings.set(r,s),await e.ensureSlotStarted(r),await e.deferredMgr.release(r,e.deferredCallbacks()),e.refreshClaudeWorkerStatusCard(r,s),a({outcome:"opened",binding:{...e.buildOpenedBindingResult(r,s),mode_id:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId)}}),!0}case l.status:case l.where:{const n=e.bindingStore.get(r);return n?.cwd?(a({outcome:i,binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r),worker_status:e.getClaudeWorkerStatus(r)}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case l.stop:{const n=e.bindingStore.get(r);return n?.cwd?(await e.pool.removeSlot(r),a({outcome:"stopped",binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r),worker_status:"stopped"}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case l.restart:{const n=e.bindingStore.get(r);return n?.cwd?(await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,n.cwd),a({outcome:"restarted",binding:{cwd:n.cwd,mode_id:e.currentClaudeModeId(r)}}),!0):(t(u.bindingMissing,"session binding was not found"),!0)}case w.setReasoningEffort:{const n=[d.effort,d.reasoning_effort,d.reasoning_eff,d.value].map(S=>String(S??"").trim()).find(Boolean)??"",o=k(n);if(!n||!o)return t(C.effortInvalid,`effort is invalid; expected one of ${_.join(", ")}`),!0;const s=e.bindingStore.get(r);if(!s?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if(e.bindingStore.getEffort(r)!==o){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362 effort"),!0;e.bindingStore.setEffort(r,o),await e.pool.removeSlot(r),await e.ensureSlotStarted(r)}return e.globalConfigStore?.set(e.name,{effort:o}),e.refreshClaudeWorkerStatusCard(r,s.cwd),a({outcome:"effort_set",effort:o,reasoning_effort:o,available_efforts:[..._],binding:{cwd:s.cwd,effort:o}}),!0}case l.setMode:{const n=String(d.mode_id??d.modeId??"").trim();if(!n)return t(C.modeInvalid,"set mode_id is invalid"),!0;const o=e.normalizeClaudeModeId(n);if(o!==n.toLowerCase())return t(C.modeInvalid,"set mode_id is invalid"),!0;const s=e.bindingStore.get(r);if(!s?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if(e.currentClaudeModeId(r)!==o){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u5F0F"),!0;e.bindingStore.setModeId(r,o),e.globalConfigStore?.set(e.name,{modeId:o}),await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,s.cwd)}return a({outcome:"mode_set",mode_id:o,binding:{cwd:s.cwd,mode_id:o}}),!0}case l.setModel:{const n=String(d.model_id??d.modelId??"").trim();if(!n)return t("set_model_invalid","model_id is required"),!0;const o=e.bindingStore.get(r);if(!o?.cwd)return t(u.bindingMissing,"session binding was not found"),!0;if((o.modelId??"")!==n){if(e.getClaudeWorkerStatus(r)==="busy")return t(u.workerBusy,"\u5F53\u524D\u6709\u6D88\u606F\u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u6216\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u5207\u6362\u6A21\u578B"),!0;e.bindingStore.setModelId(r,n),e.globalConfigStore?.set(e.name,{modelId:n}),await e.pool.removeSlot(r),await e.ensureSlotStarted(r),e.refreshClaudeWorkerStatusCard(r,o.cwd),e.refreshQuotaAfterModelSwitch(r,M(n))}return a({outcome:"model_set",model_id:n,binding:{cwd:o.cwd,model_id:n}}),!0}case l.listOptions:{const n=v(),o=e.pool.getSlot(r),s=e.resolveClaudeSessionEffort(r)??"auto";return a({modes:[b.fullAuto,b.approval],currentModeId:e.normalizeClaudeModeId(e.bindingStore.get(r)?.modeId),models:n.map(f=>({modelId:f.id,name:f.displayName})),currentModelId:e.bindingStore.get(r)?.modelId??"",available_models:n.map(f=>({id:f.id,displayName:f.displayName})),available_efforts:[..._],effort:s,reasoning_effort:s,agent_commands:o?.adapter?.getSupportedCommands?.()??[]}),!0}case l.exec:{const[n,...o]=String(d.args??"").trim().split(/\s+/);if(!n)return t(u.verbInvalid,"Usage: exec <command> [args]"),!0;await e.ensureSlotStarted(r);const f=e.pool.getSlot(r)?.adapter;if(!f?.execCommand)return t(u.verbInvalid,"Agent does not support command execution"),!0;const S=f.getSupportedCommands?.()??[];if(!S.some(m=>m.name===n))return t(u.verbInvalid,`Unknown command: ${n}. Supported: ${S.map(m=>m.name).join(", ")}`),!0;try{const m=await f.execCommand(n,o.join(" "),r);m.status==="ok"?a({outcome:"exec",command:n,message:m.message,data:m.data}):t(u.runtimeError,m.message??`${n} failed`)}catch(m){t(u.runtimeError,`exec error: ${m instanceof Error?m.message:m}`)}return!0}default:return t(u.verbInvalid,`session control verb ${i} is not supported`),!0}}catch(n){if(i===l.open){const{code:o,msg:s}=e.failSessionOpen(n,{sessionId:r,eventId:c.action_id,cwd:e.bindingStore.get(r)?.cwd||String(d.cwd??"").trim()});p.error(e.name,`handleSessionControlLocalAction error verb=${i} session_id=${r}: ${s}`),t(o,s)}else{const o=n instanceof Error?n.message:String(n);p.error(e.name,`handleSessionControlLocalAction error verb=${i} session_id=${r}: ${o}`),t(u.runtimeError,o)}return!0}}export{x as SESSION_CONTROL_ROUTER_HOST_FIELDS,A as SESSION_CONTROL_ROUTER_HOST_METHODS,W as routeSessionControlCommand,L as routeSessionControlLocalAction};
@@ -1 +1 @@
1
- const _=500,y=140;function i(t){return typeof t=="string"?t.trim().replace(/\s+/g," "):t==null?"":typeof t=="number"||typeof t=="boolean"?String(t):""}function n(t,o){const r=i(t);return r.length<=o?r:o<=3?r.slice(0,o):`${r.slice(0,o-3)}...`}function T(t){const o=i(t);if(!o)return"";try{const r=JSON.parse(o),e=s(r);if(e)return e}catch{}return o}function u(t){const o=i(t);if(!o)return"";try{return s(JSON.parse(o))}catch{return""}}function s(t){if(!t||typeof t!="object"||Array.isArray(t))return"";const o=t;for(const r of["command","file_path","path","pattern","query","description","url","text"]){const e=i(o[r]);if(e)return e}return""}function d(t,o){const r=i(t)||"tool",e=T(o);return{summaryText:e?`${r}: ${n(e,140)}`:r,...e?{detailText:n(e,500)}:{}}}function p(t,o){const r=i(o);if(r==="(failed)")return{summaryText:"(failed)"};if(r.startsWith("(failed) ")){const f=r.slice(9),l=u(f);return{summaryText:l?`${n(l,140)} (failed)`:"(failed)",...l?{detailText:n(l,500)}:{}}}const e=u(r);if(e)return{summaryText:n(e,140),detailText:n(e,500)};const c=n(r,500);return{summaryText:t||"result",...c?{detailText:c}:{}}}function a(t){if(typeof t=="string")return t;if(t==null)return"";try{return JSON.stringify(t)}catch{return String(t)}}function m(t){const o=String(t.type??""),r=t.payload&&typeof t.payload=="object"?t.payload:{};return o==="tool_call"||o==="tool_use"?d(String(r.tool_name??r.toolName??"tool"),a(r.tool_input??r.input)):o==="tool_result"?p(String(r.tool_name??r.toolName??"result"),a(r.result??r.content??r.output)):null}function I(t,o,r){const e=new URLSearchParams;return e.set("d",JSON.stringify(r)),`[${t}](grix://card/${o}?${e.toString()})`}export{m as buildDshOnlineToolCard,I as buildLocalGrixCardLink,p as buildToolResultCard,d as buildToolUseCard,n as compactToolCardText,i as normalizeToolCardText,a as stringifyToolField};
1
+ const _=500,y=140;function i(t){return typeof t=="string"?t.trim().replace(/\s+/g," "):t==null?"":typeof t=="number"||typeof t=="boolean"?String(t):""}function e(t,o){const r=i(t);return r.length<=o?r:o<=3?r.slice(0,o):`${r.slice(0,o-3)}...`}function T(t){const o=i(t);if(!o)return"";try{const r=JSON.parse(o),n=a(r);if(n)return n}catch{}return o}function u(t){const o=i(t);if(!o)return"";try{return a(JSON.parse(o))}catch{return""}}function a(t){if(!t||typeof t!="object"||Array.isArray(t))return"";const o=t;for(const r of["command","CommandLine","file_path","AbsolutePath","path","pattern","query","description","toolSummary","toolAction","url","text"]){const n=i(o[r]);if(n)return n}return""}function d(t,o){const r=i(t)||"tool",n=T(o);return{summaryText:n?`${r}: ${e(n,140)}`:r,...n?{detailText:e(n,500)}:{}}}function p(t,o){const r=i(o);if(r==="(failed)")return{summaryText:"(failed)"};if(r.startsWith("(failed) ")){const f=r.slice(9),l=u(f);return{summaryText:l?`${e(l,140)} (failed)`:"(failed)",...l?{detailText:e(l,500)}:{}}}const n=u(r);if(n)return{summaryText:e(n,140),detailText:e(n,500)};const c=e(r,500);return{summaryText:t||"result",...c?{detailText:c}:{}}}function s(t){if(typeof t=="string")return t;if(t==null)return"";try{return JSON.stringify(t)}catch{return String(t)}}function m(t){const o=String(t.type??""),r=t.payload&&typeof t.payload=="object"?t.payload:{};return o==="tool_call"||o==="tool_use"?d(String(r.tool_name??r.toolName??"tool"),s(r.tool_input??r.input)):o==="tool_result"?p(String(r.tool_name??r.toolName??"result"),s(r.result??r.content??r.output)):null}function L(t,o,r){const n=new URLSearchParams;return n.set("d",JSON.stringify(r)),`[${t}](grix://card/${o}?${n.toString()})`}export{m as buildDshOnlineToolCard,L as buildLocalGrixCardLink,p as buildToolResultCard,d as buildToolUseCard,e as compactToolCardText,i as normalizeToolCardText,s as stringifyToolField};
@@ -1 +1 @@
1
- import{ClaudeAdapter as C}from"../adapter/claude/index.js";import{getCachedModels as A}from"../adapter/claude/model-list.js";import{SESSION_CONTROL_ERROR_CODES as L,SESSION_MODE_IDS as g}from"../adapter/claude/protocol-contract.js";import{CursorAdapter as x,CURSOR_MODE_OPTIONS as I}from"../adapter/cursor/index.js";import{getCachedAgyModels as p,resolveAgyToolbarModelId as b}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as v,refreshAgyQuotaInfo as S}from"../adapter/agy/quota.js";import{normalizeClaudeEffort as R,CLAUDE_EFFORT_LEVELS as T}from"../core/config/claude-direct-env.js";import{resolveToolbarSelection as m}from"./toolbar-selection.js";import{log as M}from"../core/log/index.js";const F=["isRateLimitsCacheFresh","getFreshClaudeRateLimitState","maybeQueryProviderQuota","providerQuotaToRateLimits","normalizeClaudeModeId","resolveSessionModelId","resolveCursorSessionModeId","resolveClaudeSessionEffort","resolveClaudeSessionModeId","currentClaudeModeId","buildAgyToolbarMeta","buildAgyQuotaMeta","sendAgyBindingCard"],z=["name","config","aibotHandle","pool","bindingStore","globalConfigStore","providerResolver","cachedClaudeRateLimitState","cachedProviderQuota","cachedProviderQuotaSampledAtMs"];function k(e,i){return String(i??"").trim().toLowerCase()===g.approval?g.approval:g.fullAuto}function U(e,i,o,d){const t=Array.isArray(d?.options)?d.options:[];if(t.length===0)return;const l=e.bindingStore.get(i)?.cwd??"",s={};if(o==="model"){s.available_models=t.map(n=>({id:n.id,displayName:n.label}));const c=t.find(n=>n.current);c&&(s.model_id=c.id)}else if(o==="mode"){s.available_modes=t.map(n=>({id:n.id,displayName:n.label}));const c=t.find(n=>n.current);c&&(s.mode_id=c.id)}else s[`${o}_options`]=t;e.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:l,meta:s})}function y(e){return e.config.adapterType??"acp"}function $(e,i){return m(e,y(e),i,"model")}function J(e,i){return m(e,y(e),i,"mode")}function V(e,i){return m(e,"cursor",i,"mode")}function W(e,i){return m(e,"claude",i,"effort")}function j(e,i){return m(e,"claude",i,"mode")}function G(e,i){return e.normalizeClaudeModeId(e.resolveClaudeSessionModeId(i))}function K(e,i){const o=e.pool.getSlot(i);if(o?.adapter instanceof x)return o.adapter.getToolbarMeta(i);const d=e.bindingStore.getModelId(i)??"auto",t=e.resolveCursorSessionModeId(i)??"full_auto";return{model_id:d,mode_id:t,currentModelId:d,currentModeId:t,available_models:[],available_modes:I.map(a=>({...a}))}}function X(e,i,o){if(!e.bindingStore.get(i))return;const t=p(e.config.agent.command),a=t.length>0?t[0].id:"";let l=b(e.resolveSessionModelId(i)||"",t)||a;t.length>0&&!t.some(c=>c.id===l)&&(l=a);const s=o??v(e.config.agent.command);return{model_id:l,currentModelId:l,available_models:t.map(c=>({id:c.id,displayName:c.displayName})),...e.buildAgyQuotaMeta(s)}}function Y(e,i){const o={rate_limits:null,extra_limits:null};return i.rateLimits&&(o.rate_limits={primary:i.rateLimits.primary,secondary:i.rateLimits.secondary,sampledAt:i.sampledAt??Date.now()},i.rateLimits.extras&&i.rateLimits.extras.length>0&&(o.extra_limits=i.rateLimits.extras)),{...o,...i.plan!==void 0&&{plan:i.plan},...i.quota_exhausted!==void 0&&{quota_exhausted:i.quota_exhausted},...i.quota_reset_at!==void 0&&{quota_reset_at:i.quota_reset_at},...i.available_credits!==void 0&&{available_credits:i.available_credits}}}function Z(e,i,o,d){const t=d??e.buildAgyToolbarMeta(i);return e.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:o,...t?{meta:t}:{}}),t}async function q(e,i,o=!1){const d=await S(e.config.agent.command,o),t=e.bindingStore.get(i);return t?.cwd&&e.sendAgyBindingCard(i,t.cwd,e.buildAgyToolbarMeta(i,d)),d}async function h(e,i,o){const d=i.params??{},t=p(e.config.agent.command),a=b(String(d.model_id??d.modelId??""),t);if(!o){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for set_model"});return}if(!a){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"set_model_invalid",error_msg:"model_id is required"});return}const l=e.bindingStore.get(o);if(!l?.cwd){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:L.bindingMissing,error_msg:"session binding was not found"});return}l.modelId!==a&&(e.bindingStore.setModelId(o,a),e.globalConfigStore?.set(e.name,{modelId:a}));const s=await S(e.config.agent.command,!0).catch(()=>v(e.config.agent.command));e.sendAgyBindingCard(o,l.cwd,e.buildAgyToolbarMeta(o,s)),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{outcome:"model_set",model_id:a,binding:{cwd:l.cwd,model_id:a}}})}function ee(e,i){if(!e.bindingStore.get(i))return;const d=A(),t=d.length>0?d[0].id:"";let a=e.resolveSessionModelId(i)||t;d.length>0&&!d.some(r=>r.id===a)&&(a=t);const l=e.currentClaudeModeId(i);let s;try{const r=e.providerResolver?e.providerResolver():e.config.agent.provider;s=R(r?.effort)}catch{}const c=e.resolveClaudeSessionEffort(i)??s??"auto",n={model_id:a,mode_id:l,currentModelId:a,currentModeId:l,available_efforts:[...T],effort:c,reasoning_effort:c,available_models:d.map(r=>({id:r.id,displayName:r.displayName}))},_=e.pool.getSlot(i),u=_?.adapter instanceof C?_.adapter.getSessionState():null;(u?.rateLimits?.fiveHour||u?.rateLimits?.sevenDay)&&(e.cachedClaudeRateLimitState=u);const f=u??e.getFreshClaudeRateLimitState();if(f){const r=f.rateLimits;r&&(r.fiveHour||r.sevenDay)&&(n.rate_limits={...r.fiveHour?{fiveHour:r.fiveHour}:{},...r.sevenDay?{sevenDay:r.sevenDay}:{},sampledAt:f.sampledAt||Date.now()})}if(u){const r=u.contextWindow;r.usedPercentage!=null&&(n.context_window={usedPercentage:r.usedPercentage,remainingPercentage:r.remainingPercentage})}if(!n.rate_limits&&e.cachedProviderQuota?.success){e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)||e.maybeQueryProviderQuota().catch(()=>{});const r=e.providerQuotaToRateLimits(e.cachedProviderQuota);r&&(n.rate_limits=r),M.info(e.name,`[toolbar-meta] provider quota fallback: hasCached=${!!e.cachedProviderQuota} fromProvider=${JSON.stringify(r)}`)}return n.rate_limits&&M.info(e.name,`[toolbar-meta] rate_limits included: ${JSON.stringify(n.rate_limits)}`),n}export{z as TOOLBAR_META_HOST_FIELDS,F as TOOLBAR_META_HOST_METHODS,Y as buildAgyQuotaMeta,X as buildAgyToolbarMeta,ee as buildClaudeToolbarMeta,K as buildCursorToolbarMeta,G as currentClaudeModeId,h as handleAgySetModel,U as handleExecCommandOptions,k as normalizeClaudeModeId,q as refreshAndPushAgyQuota,W as resolveClaudeSessionEffort,j as resolveClaudeSessionModeId,V as resolveCursorSessionModeId,J as resolveSessionModeId,$ as resolveSessionModelId,Z as sendAgyBindingCard};
1
+ import{ClaudeAdapter as A}from"../adapter/claude/index.js";import{getCachedModels as x}from"../adapter/claude/model-list.js";import{SESSION_CONTROL_ERROR_CODES as L,SESSION_MODE_IDS as _}from"../adapter/claude/protocol-contract.js";import{CursorAdapter as R,CURSOR_MODE_OPTIONS as I}from"../adapter/cursor/index.js";import{getCachedAgyModels as v,resolveAgyToolbarModelId as b}from"../adapter/agy/model-list.js";import{getCachedAgyQuotaInfo as S,refreshAgyQuotaInfo as M}from"../adapter/agy/quota.js";import{normalizeClaudeEffort as Q,CLAUDE_EFFORT_LEVELS as T}from"../core/config/claude-direct-env.js";import{resolveToolbarSelection as m}from"./toolbar-selection.js";import{log as y}from"../core/log/index.js";const z=["isRateLimitsCacheFresh","isGrixRelayActive","getFreshClaudeRateLimitState","maybeQueryProviderQuota","providerQuotaToRateLimits","normalizeClaudeModeId","resolveSessionModelId","resolveCursorSessionModeId","resolveClaudeSessionEffort","resolveClaudeSessionModeId","currentClaudeModeId","buildAgyToolbarMeta","buildAgyQuotaMeta","sendAgyBindingCard"],k=["name","config","aibotHandle","pool","bindingStore","globalConfigStore","providerResolver","cachedClaudeRateLimitState","cachedProviderQuota","cachedProviderQuotaSampledAtMs"];function U(e,i){return String(i??"").trim().toLowerCase()===_.approval?_.approval:_.fullAuto}function $(e,i,o,a){const r=Array.isArray(a?.options)?a.options:[];if(r.length===0)return;const l=e.bindingStore.get(i)?.cwd??"",c={};if(o==="model"){c.available_models=r.map(d=>({id:d.id,displayName:d.label}));const s=r.find(d=>d.current);s&&(c.model_id=s.id)}else if(o==="mode"){c.available_modes=r.map(d=>({id:d.id,displayName:d.label}));const s=r.find(d=>d.current);s&&(c.mode_id=s.id)}else c[`${o}_options`]=r;e.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:l,meta:c})}function C(e){return e.config.adapterType??"acp"}function G(e,i){return m(e,C(e),i,"model")}function J(e,i){return m(e,C(e),i,"mode")}function q(e,i){return m(e,"cursor",i,"mode")}function V(e,i){return m(e,"claude",i,"effort")}function W(e,i){return m(e,"claude",i,"mode")}function j(e,i){return e.normalizeClaudeModeId(e.resolveClaudeSessionModeId(i))}function K(e,i){const o=e.pool.getSlot(i);if(o?.adapter instanceof R)return o.adapter.getToolbarMeta(i);const a=e.bindingStore.getModelId(i)??"auto",r=e.resolveCursorSessionModeId(i)??"full_auto";return{model_id:a,mode_id:r,currentModelId:a,currentModeId:r,available_models:[],available_modes:I.map(n=>({...n}))}}function X(e,i,o){if(!e.bindingStore.get(i))return;const r=v(e.config.agent.command),n=r.length>0?r[0].id:"";let l=b(e.resolveSessionModelId(i)||"",r)||n;r.length>0&&!r.some(s=>s.id===l)&&(l=n);const c=o??S(e.config.agent.command);return{model_id:l,currentModelId:l,available_models:r.map(s=>({id:s.id,displayName:s.displayName})),...e.buildAgyQuotaMeta(c)}}function Y(e,i){const o={rate_limits:null,extra_limits:null};return i.rateLimits&&(o.rate_limits={primary:i.rateLimits.primary,secondary:i.rateLimits.secondary,sampledAt:i.sampledAt??Date.now()},i.rateLimits.extras&&i.rateLimits.extras.length>0&&(o.extra_limits=i.rateLimits.extras)),{...o,...i.plan!==void 0&&{plan:i.plan},...i.quota_exhausted!==void 0&&{quota_exhausted:i.quota_exhausted},...i.quota_reset_at!==void 0&&{quota_reset_at:i.quota_reset_at},...i.available_credits!==void 0&&{available_credits:i.available_credits}}}function Z(e,i,o,a){const r=a??e.buildAgyToolbarMeta(i);return e.aibotHandle.sendUpdateBindingCard({session_id:i,worker_status:"ready",cwd:o,...r?{meta:r}:{}}),r}async function h(e,i,o=!1){const a=await M(e.config.agent.command,o),r=e.bindingStore.get(i);return r?.cwd&&e.sendAgyBindingCard(i,r.cwd,e.buildAgyToolbarMeta(i,a)),a}async function ee(e,i,o){const a=i.params??{},r=v(e.config.agent.command),n=b(String(a.model_id??a.modelId??""),r);if(!o){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"session_id_required",error_msg:"session_id is required for set_model"});return}if(!n){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:"set_model_invalid",error_msg:"model_id is required"});return}const l=e.bindingStore.get(o);if(!l?.cwd){e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"failed",error_code:L.bindingMissing,error_msg:"session binding was not found"});return}l.modelId!==n&&(e.bindingStore.setModelId(o,n),e.globalConfigStore?.set(e.name,{modelId:n}));const c=await M(e.config.agent.command,!0).catch(()=>S(e.config.agent.command));e.sendAgyBindingCard(o,l.cwd,e.buildAgyToolbarMeta(o,c)),e.aibotHandle.sendLocalActionResult({action_id:i.action_id,status:"ok",result:{outcome:"model_set",model_id:n,binding:{cwd:l.cwd,model_id:n}}})}function ie(e,i){if(!e.bindingStore.get(i))return;const a=x(),r=a.length>0?a[0].id:"";let n=e.resolveSessionModelId(i)||r;a.length>0&&!a.some(t=>t.id===n)&&(n=r);const l=e.currentClaudeModeId(i);let c;try{const t=e.providerResolver?e.providerResolver():e.config.agent.provider;c=Q(t?.effort)}catch{}const s=e.resolveClaudeSessionEffort(i)??c??"auto",d={model_id:n,mode_id:l,currentModelId:n,currentModeId:l,available_efforts:[...T],effort:s,reasoning_effort:s,available_models:a.map(t=>({id:t.id,displayName:t.displayName}))},p=e.pool.getSlot(i),u=p?.adapter instanceof A?p.adapter.getSessionState():null;(u?.rateLimits?.fiveHour||u?.rateLimits?.sevenDay)&&(e.cachedClaudeRateLimitState=u);const f=e.isGrixRelayActive(),g=f?null:u??e.getFreshClaudeRateLimitState();if(g){const t=g.rateLimits;t&&(t.fiveHour||t.sevenDay)&&(d.rate_limits={...t.fiveHour?{fiveHour:t.fiveHour}:{},...t.sevenDay?{sevenDay:t.sevenDay}:{},sampledAt:g.sampledAt||Date.now()})}if(f){d.rate_limits=null;const t=e.cachedProviderQuota?.success&&e.cachedProviderQuota.provider==="grix"?e.cachedProviderQuota:null;d.provider_quota=t,(!t||!e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs))&&e.maybeQueryProviderQuota().catch(()=>{})}else d.provider_quota=null;if(u){const t=u.contextWindow;t.usedPercentage!=null&&(d.context_window={usedPercentage:t.usedPercentage,remainingPercentage:t.remainingPercentage})}if(!f&&!d.rate_limits&&e.cachedProviderQuota?.success&&e.cachedProviderQuota.provider!=="grix"){e.isRateLimitsCacheFresh(e.cachedProviderQuotaSampledAtMs)||e.maybeQueryProviderQuota().catch(()=>{});const t=e.providerQuotaToRateLimits(e.cachedProviderQuota);t&&(d.rate_limits=t),y.info(e.name,`[toolbar-meta] provider quota fallback: hasCached=${!!e.cachedProviderQuota} fromProvider=${JSON.stringify(t)}`)}return d.rate_limits&&y.info(e.name,`[toolbar-meta] rate_limits included: ${JSON.stringify(d.rate_limits)}`),d}export{k as TOOLBAR_META_HOST_FIELDS,z as TOOLBAR_META_HOST_METHODS,Y as buildAgyQuotaMeta,X as buildAgyToolbarMeta,ie as buildClaudeToolbarMeta,K as buildCursorToolbarMeta,j as currentClaudeModeId,ee as handleAgySetModel,$ as handleExecCommandOptions,U as normalizeClaudeModeId,h as refreshAndPushAgyQuota,V as resolveClaudeSessionEffort,W as resolveClaudeSessionModeId,q as resolveCursorSessionModeId,J as resolveSessionModeId,G as resolveSessionModelId,Z as sendAgyBindingCard};
@@ -1 +1 @@
1
- import{SESSION_MODE_IDS as i}from"../adapter/claude/protocol-contract.js";import{normalizeClaudeEffort as g}from"../core/config/claude-direct-env.js";const s={read:(e,o)=>e.getModelId(o),write:(e,o,d)=>e.setModelId(o,d)},c={read:(e,o)=>e.getModeId(o),write:(e,o,d)=>e.setModeId(o,d)},m={model:{globalKey:"modelId"},mode:{globalKey:"acpInitialMode"}},y={claude:{model:{session:s,globalKey:"modelId"},mode:{session:c,globalKey:"modeId",newSessionOnly:!0,normalize:e=>e.trim().toLowerCase()===i.approval?i.approval:i.fullAuto},effort:{session:{read:(e,o)=>e.getEffort(o),write:(e,o,d)=>e.setEffort(o,d)},globalKey:"effort",newSessionOnly:!0,normalize:e=>g(e)}},cursor:{model:{session:s,globalKey:"modelId"},mode:{session:{read:(e,o)=>e.getCursorModeId(o),write:(e,o,d)=>e.setCursorModeId(o,d)},globalKey:"cursorModeId"}},agy:{model:{session:s,globalKey:"modelId"}},opencode:{model:{session:s,globalKey:"modelId"},mode:{session:c,globalKey:"modeId"}},codewhale:{model:{session:s,globalKey:"modelId"},mode:{globalKey:"acpInitialMode"}},"deepseek-harness":{},acp:{model:{session:{read:(e,o)=>e.getAcpModelId(o),write:(e,o,d)=>e.setAcpModelId(o,d)},globalKey:"modelId"},mode:{session:{read:(e,o)=>e.getAcpModeId(o),write:(e,o,d)=>e.setAcpModeId(o,d)},globalKey:"acpInitialMode"}},codex:{model:{session:{read:(e,o)=>e.getCodexModelId(o),write:(e,o,d)=>e.setCodexModelId(o,d),ownedByAdapter:!0},globalKey:"codexModelId",newSessionOnly:!0},mode:{session:{read:(e,o)=>e.getCodexModeId(o),write:(e,o,d)=>e.setCodexModeId(o,d),ownedByAdapter:!0},globalKey:"codexModeId",newSessionOnly:!0},reasoningEffort:{session:{read:(e,o)=>e.getCodexReasoningEffort(o),write:(e,o,d)=>e.setCodexReasoningEffort(o,d),ownedByAdapter:!0},globalKey:"codexReasoningEffort"},serviceTier:{session:{read:(e,o)=>e.getCodexServiceTier(o),write:(e,o,d)=>e.setCodexServiceTier(o,d),ownedByAdapter:!0},globalKey:"codexServiceTier",newSessionOnly:!0,defaultClearsGlobal:!0},sandboxMode:{session:{read:(e,o)=>e.getCodexSandboxMode(o),write:(e,o,d)=>e.setCodexSandboxMode(o,d),ownedByAdapter:!0},globalKey:"codexSandboxMode",defaultClearsGlobal:!0}}};function I(e,o){if(!o)return!1;switch(e){case"claude":return!!o.claudeSessionId;case"codex":return!!o.codexThreadId;case"codewhale":return!!o.codewhaleThreadId;case"agy":return!!o.agyConversationId;case"pi":return!!o.piSessionPath;default:return!!o.acpSessionId}}function u(e,o){return(y[e]??m)[o]}function w(e,o,d,a){const l=u(o,a);if(!l)return;const t=l.session?.read(e.bindingStore,d);if(t)return t;if(!l.globalKey||l.newSessionOnly&&I(o,e.bindingStore.get(d)))return;const r=String(e.globalConfigStore?.get(e.name)?.[l.globalKey]??"").trim();if(!r)return;const n=l.normalize?l.normalize(r):r;if(n)return l.session?.write(e.bindingStore,d,n),n}function S(e,o,d,a,l,t){const r=u(o,a),n=l.trim();if(!r||!n)return!1;if(r.session&&!r.session.ownedByAdapter&&r.session.write(e.bindingStore,d,n),r.globalKey){const f=r.defaultClearsGlobal&&n.toLowerCase()==="default";e.globalConfigStore?.set(e.name,{[r.globalKey]:f?void 0:n,...t??{}})}return!!(r.session||r.globalKey)}export{y as TOOLBAR_FIELD_SPECS,u as getToolbarFieldSpec,I as hasNativeSession,S as persistToolbarSelection,w as resolveToolbarSelection};
1
+ import{SESSION_MODE_IDS as i}from"../adapter/claude/protocol-contract.js";import{normalizeClaudeEffort as g}from"../core/config/claude-direct-env.js";const s={read:(e,o)=>e.getModelId(o),write:(e,o,d)=>e.setModelId(o,d)},c={read:(e,o)=>e.getModeId(o),write:(e,o,d)=>e.setModeId(o,d)},m={model:{globalKey:"modelId"},mode:{globalKey:"acpInitialMode"}},y={claude:{model:{session:s,globalKey:"modelId"},mode:{session:c,globalKey:"modeId",newSessionOnly:!0,normalize:e=>e.trim().toLowerCase()===i.approval?i.approval:i.fullAuto},effort:{session:{read:(e,o)=>e.getEffort(o),write:(e,o,d)=>e.setEffort(o,d)},globalKey:"effort",newSessionOnly:!0,normalize:e=>g(e)}},cursor:{model:{session:s,globalKey:"modelId"},mode:{session:{read:(e,o)=>e.getCursorModeId(o),write:(e,o,d)=>e.setCursorModeId(o,d)},globalKey:"cursorModeId"}},agy:{model:{session:s,globalKey:"modelId"}},opencode:{model:{session:s,globalKey:"modelId"},mode:{session:c,globalKey:"modeId"}},codewhale:{model:{session:s,globalKey:"modelId"},mode:{globalKey:"acpInitialMode"}},pi:{},"deepseek-harness":{},acp:{model:{session:{read:(e,o)=>e.getAcpModelId(o),write:(e,o,d)=>e.setAcpModelId(o,d)},globalKey:"modelId"},mode:{session:{read:(e,o)=>e.getAcpModeId(o),write:(e,o,d)=>e.setAcpModeId(o,d)},globalKey:"acpInitialMode"}},codex:{model:{session:{read:(e,o)=>e.getCodexModelId(o),write:(e,o,d)=>e.setCodexModelId(o,d),ownedByAdapter:!0},globalKey:"codexModelId",newSessionOnly:!0},mode:{session:{read:(e,o)=>e.getCodexModeId(o),write:(e,o,d)=>e.setCodexModeId(o,d),ownedByAdapter:!0},globalKey:"codexModeId",newSessionOnly:!0},reasoningEffort:{session:{read:(e,o)=>e.getCodexReasoningEffort(o),write:(e,o,d)=>e.setCodexReasoningEffort(o,d),ownedByAdapter:!0},globalKey:"codexReasoningEffort"},serviceTier:{session:{read:(e,o)=>e.getCodexServiceTier(o),write:(e,o,d)=>e.setCodexServiceTier(o,d),ownedByAdapter:!0},globalKey:"codexServiceTier",newSessionOnly:!0,defaultClearsGlobal:!0},sandboxMode:{session:{read:(e,o)=>e.getCodexSandboxMode(o),write:(e,o,d)=>e.setCodexSandboxMode(o,d),ownedByAdapter:!0},globalKey:"codexSandboxMode",defaultClearsGlobal:!0}}};function I(e,o){if(!o)return!1;switch(e){case"claude":return!!o.claudeSessionId;case"codex":return!!o.codexThreadId;case"codewhale":return!!o.codewhaleThreadId;case"agy":return!!o.agyConversationId;case"pi":return!!o.piSessionPath;default:return!!o.acpSessionId}}function u(e,o){return(y[e]??m)[o]}function w(e,o,d,a){const l=u(o,a);if(!l)return;const t=l.session?.read(e.bindingStore,d);if(t)return t;if(!l.globalKey||l.newSessionOnly&&I(o,e.bindingStore.get(d)))return;const r=String(e.globalConfigStore?.get(e.name)?.[l.globalKey]??"").trim();if(!r)return;const n=l.normalize?l.normalize(r):r;if(n)return l.session?.write(e.bindingStore,d,n),n}function S(e,o,d,a,l,t){const r=u(o,a),n=l.trim();if(!r||!n)return!1;if(r.session&&!r.session.ownedByAdapter&&r.session.write(e.bindingStore,d,n),r.globalKey){const f=r.defaultClearsGlobal&&n.toLowerCase()==="default";e.globalConfigStore?.set(e.name,{[r.globalKey]:f?void 0:n,...t??{}})}return!!(r.session||r.globalKey)}export{y as TOOLBAR_FIELD_SPECS,u as getToolbarFieldSpec,I as hasNativeSession,S as persistToolbarSelection,w as resolveToolbarSelection};
@@ -1 +1 @@
1
- import{readJSONFile as o,writeJSONFileAtomic as e}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(i=>typeof i=="string"&&i.trim().length>0):[]}async function s(t,r){await e(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};
1
+ import{readJSONFile as o,writeJSONFileAtomic as i}from"../util/json-file.js";function n(t){const r=o(t);return r&&typeof r=="object"&&"owners"in r&&Array.isArray(r.owners)?r.owners.filter(e=>typeof e=="string"&&e.trim().length>0):[]}async function s(t,r){await i(t,{owners:r})}export{n as readAllowlist,s as writeAllowlist};