@north-light/cli 0.3.523 → 0.3.525
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.
- package/dist/api/command-manifest/result.d.ts +4 -2
- package/dist/api/command-manifest/result.js +1 -1
- package/dist/api/command-manifest/schema.js +1 -1
- package/dist/api/plugin-manifest-schema.d.ts +3 -0
- package/dist/builtin-memory/crouter-plugin/bundles-and-memory.md +2 -2
- package/dist/builtin-memory/crouter-plugin/commands.md +2 -2
- package/dist/builtin-memory/crouter-plugin/deploying.md +2 -2
- package/dist/builtin-memory/crouter-plugin/output.md +3 -1
- package/dist/clients/attach/chrome/roster.d.ts +1 -1
- package/dist/clients/attach/chrome/roster.js +4 -4
- package/dist/clients/attach/render/chat-view.d.ts +9 -0
- package/dist/clients/attach/render/chat-view.js +3 -3
- package/dist/clients/attach/render/page-block.d.ts +2 -0
- package/dist/clients/attach/render/page-block.js +1 -1
- package/dist/clients/attach/session/connection.d.ts +1 -1
- package/dist/clients/attach/session/context.d.ts +1 -1
- package/dist/clients/attach/session/profile-files.d.ts +3 -3
- package/dist/clients/attach/session/profile-files.js +1 -1
- package/dist/clients/attach/viewer.js +633 -756
- package/dist/commands/pkg/browse/command-view.js +1 -1
- package/dist/core/canvas/db.d.ts +28 -2
- package/dist/core/canvas/db.js +2 -2
- package/dist/core/canvas/nav-model.js +1 -1
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/conversation-store/client.d.ts +2 -2
- package/dist/core/conversation-store/index.d.ts +30 -2
- package/dist/core/conversation-store/index.js +1 -1
- package/dist/core/conversation-store/patch.js +1 -1
- package/dist/core/graph/watches.d.ts +2 -0
- package/dist/core/graph/watches.js +9 -9
- package/dist/core/help.js +7 -7
- package/dist/core/llm/run.js +2 -2
- package/dist/core/runtime/broker/fault-retry.d.ts +9 -3
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/rebind.d.ts +4 -0
- package/dist/core/runtime/broker/rebind.js +1 -1
- package/dist/core/runtime/broker/run-turn-queue.d.ts +2 -0
- package/dist/core/runtime/broker/run-turn-queue.js +1 -1
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +3 -3
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/close.d.ts +2 -2
- package/dist/core/runtime/close.js +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/runs/observer.js +2 -2
- package/docs/plugin/bundles-and-memory.md +2 -2
- package/docs/plugin/commands.md +2 -2
- package/docs/plugin/deploying.md +2 -2
- package/docs/plugin/output.md +3 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -61,14 +61,12 @@ export declare class FaultRetry {
|
|
|
61
61
|
private providerFallbackInFlight;
|
|
62
62
|
private notFoundFallbackInFlight;
|
|
63
63
|
private stagedCapacityFailure;
|
|
64
|
-
private
|
|
64
|
+
private agentStarts;
|
|
65
65
|
constructor(deps: FaultRetryDeps);
|
|
66
66
|
clearTimer(): void;
|
|
67
67
|
reset(): void;
|
|
68
68
|
/** No recovery turn will follow the settled turn: a run node writes its held-back turn end now. */
|
|
69
69
|
abandonTurnEnd(): void;
|
|
70
|
-
/** A failed daemon-backed persona gate is local evidence, not a provider fault. */
|
|
71
|
-
notePersonaGateFailure(): void;
|
|
72
70
|
private state;
|
|
73
71
|
private recordFault;
|
|
74
72
|
private clearFault;
|
|
@@ -77,7 +75,15 @@ export declare class FaultRetry {
|
|
|
77
75
|
onEvent(event: BrokerToClient): void;
|
|
78
76
|
isActiveAutoFault(fault: RecoveryFaultDTO | null): fault is RecoveryFaultDTO;
|
|
79
77
|
isActiveAutoFault(fault: Fault | null): fault is Fault;
|
|
78
|
+
/** Record the settled turn's outcome with the daemon. The staged outcome is
|
|
79
|
+
* taken once; the daemon writes are then retried until the daemon answers,
|
|
80
|
+
* because a turn that ended on a daemon-call failure (the machine just woke)
|
|
81
|
+
* must still leave its fault behind — an unrecorded fault lets the
|
|
82
|
+
* unattended check release the node. Retrying stops when a rebind replaces
|
|
83
|
+
* this generation, since the replacement owns recovery from then on, and when
|
|
84
|
+
* another turn starts, since a stale fault would re-drive from the old anchor. */
|
|
80
85
|
publishSettledProviderFault(generation: SubscriptionGeneration): Promise<void>;
|
|
86
|
+
private recordStagedOutcome;
|
|
81
87
|
/** Startup re-drive reads the durable episode surviving from the process this
|
|
82
88
|
* replaces. Revive deliberately clears the ordinary fault marker before this
|
|
83
89
|
* boundary, so the episode is the recovery authority. A `pending` episode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var y=(r,e)=>ie(r,"name",{value:e,configurable:!0});import{envModelIntent as G,envNodeCwd as $,envProfileId as L}from"../../../shared/env.js";import{isContextOverflow as D}from"@earendil-works/pi-ai";import{classify as N}from"../../fault-classifier.js";import{isModelNotFoundError as ne,isProviderUnconfiguredError as re}from"../fault.js";import{brokerRecovery as se,mutateBrokerFault as U,mutateBrokerProviderRetry as b}from"./daemon-ops.js";import{extractCoolingDeadline as oe}from"../managed-provider-cooling.js";import{extractProviderFailureDetails as ae}from"../../provider-failure.js";import{expandModelCandidates as B,modelRequestFromConfig as Y,probeRouteAvailability as de}from"../../model-routes.js";import{operationIdContext as W}from"../../events/operation-id.js";import{emitEvent as F}from"../../events/emit.js";import{CONNECTION_FAULT_RECOVERY_BODY as le,PROVIDER_FAULT_RECOVERY_BODY as ue,RUN_CONNECTION_FAULT_RETRY_BODY as ce,formatCard as q,formatModelFallbackRecovery as pe}from"../../../shared/generated-context.js";import{markFatalOnExhaust as V,nextFaultRetry as j,policyFor as J}from"../fault-recovery.js";import{parseModelSpec as X}from"../model-selection.js";import{endedByAbort as z}from"../session-cycles.js";import{resolveProviderCandidates as fe}from"../../subscription-state.js";import{announceMessageOrigin as H}from"../stamp/channel.js";import{LLM_REFUSAL_DIAGNOSTIC as he,refusalRetryAt as me}from"./model-adapter.js";import{isSafetyRefusal as K}from"../../llm/refusal.js";const ge=2147483647,Q=3e4;function ye(r,e,t){const i=Date.parse(r);return!Number.isFinite(i)||t+e-i>Q}y(ye,"runTurnRetryExpired");function ve(r,e){return r!=="connection"?ue:e?ce:le}y(ve,"retryCardBody");function w(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,since:r.since,operation_id:r.operation_id,...r.anchor_entry_id===void 0?{}:{anchorEntryId:r.anchor_entry_id},...r.provider_error===void 0?{}:{providerError:r.provider_error}}}y(w,"policyFault");function S(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,...r.operation_id===void 0?{}:{operation_id:r.operation_id},...r.since===void 0?{}:{since:r.since},...r.anchorEntryId===void 0?{}:{anchor_entry_id:r.anchorEntryId},...r.providerError===void 0?{}:{provider_error:r.providerError}}}y(S,"faultInput");function Z(r,e){const t=y(i=>`${i.providerId}/${i.modelId}`===e.modelSpec,"onLiveModel");return(r.find(i=>t(i)&&i.thinkingLevel===e.thinkingLevel)??r.find(t))?.rank}y(Z,"liveRouteRank");function ee(r){const e=N("pi\u2192provider",r),t=r.diagnostics?.some(i=>i.type===he)??!1;return{classified:e,disposition:t?"fatal":e.disposition}}y(ee,"settledProviderFault");function Ue(r,e){if(r.stopReason!=="error"||z(r)||K(r)||D(r,e))return!1;const{classified:t,disposition:i}=ee(r);return i==="auto"&&(t.kind==="connection"||t.kind==="rate-limit"||t.kind==="overloaded")}y(Ue,"willDaemonRetry");const Fe=/does not support assistant message prefill|conversation must end with a user message/i;function ke(r,e){return e&&Fe.test(r)}y(ke,"isPrefillRejectionDuringEpisode");class Be{static{y(this,"FaultRetry")}deps;timer=null;failedRetryRoutes=new Set;notFoundModels=new Set;providerFallbackInFlight=null;notFoundFallbackInFlight=null;stagedCapacityFailure=null;personaGateFailed=!1;constructor(e){this.deps=e}clearTimer(){this.timer!==null&&(clearTimeout(this.timer),this.timer=null)}reset(){this.clearTimer(),this.deps.turnEnds?.abandon(),this.providerFallbackInFlight=null,this.notFoundFallbackInFlight=null,this.stagedCapacityFailure=null,this.personaGateFailed=!1}abandonTurnEnd(){this.deps.turnEnds?.abandon()}notePersonaGateFailure(){this.personaGateFailed=!0}state(){return se(this.deps.nodeId)}async recordFault(e){return(await U(this.deps.nodeId,{op:"record",input:e})).fault}async clearFault(e,t=!1){await U(this.deps.nodeId,{op:"clear",...e===void 0?{}:{link:e},...t?{preserve_episode:!0}:{}})}sessionId(e){const t=e.sessionManager.getSessionId?.();return typeof t=="string"&&t!==""?t:null}async clearEpisode(e){const t=this.sessionId(e);t!==null&&await b(this.deps.nodeId,{op:"clear",session_id:t})}onEvent(e){this.maybeSwitchProviderForRetry(e),this.maybeFallbackOnUnusableModel(e)}isActiveAutoFault(e){return e===null||e.retry.disposition!=="auto"||e.retry.by!=="daemon"?!1:e.kind==="connection"||e.kind==="rate-limit"||e.kind==="overloaded"}async publishSettledProviderFault(e){const t=e.stagedProviderAgentEnd,i=e.stagedWatchdogAbort,n=e.stagedRefreshAbort,o=e.stagedOverflowFailure,a=this.stagedCapacityFailure?.generation===e?this.stagedCapacityFailure:null,c=this.personaGateFailed;this.stagedCapacityFailure=null,this.personaGateFailed=!1,e.stagedProviderAgentEnd=null,e.stagedWatchdogAbort=!1,e.stagedRefreshAbort=!1,e.stagedOverflowFailure=null;const s=e.session,l=await this.state(),p=l.fault,h=l.episode,f=this.sessionId(s),m=this.isActiveAutoFault(p)&&p.link==="pi\u2192provider"?p:h?.state==="admitted"&&h.session_id===f&&this.isActiveAutoFault(h.fault)?h.fault:null,d=m===null?null:{since:m.since,anchorEntryId:m.anchor_entry_id,attempt:m.retry.attempt},u=[...Array.isArray(t?.messages)?t.messages:[]].reverse().find(R=>typeof R=="object"&&R!==null&&R.role==="assistant");if(c){await this.clearEpisode(s);return}if(a!==null||o!==null){await this.clearFault("pi\u2192provider"),await this.clearEpisode(s),await this.recordFault({link:"pi\u2192provider",op:"context overflow recovery",kind:"context-overflow",retry:{disposition:"fatal"},message:a?.errorMessage??o.errorMessage,anchor_entry_id:s.sessionManager.getLeafId?.()??void 0});return}if(i&&u?.stopReason==="aborted"){await this.recordPendingProviderFault(s,{link:"pi\u2192provider",op:"generation turn",kind:"connection",retry:{disposition:"auto",by:"daemon",...d?.attempt!==void 0?{attempt:d.attempt}:{}},message:typeof u.errorMessage=="string"?u.errorMessage:"engine error (no errorMessage recorded)",...d!==null?{since:d.since}:{},anchor_entry_id:d?.anchorEntryId??s.sessionManager.getLeafId?.()??void 0});return}if(u?.stopReason!=="error"){u!==void 0&&await this.clearEpisode(s);return}if(n){await this.clearEpisode(s);return}if(K(u)){await this.clearEpisode(s);return}const k=typeof u.errorMessage=="string"?u.errorMessage:"engine error (no errorMessage recorded)";if(z({stopReason:"error",errorMessage:k})){await this.clearEpisode(s);return}const v=D(u,s.model?.contextWindow),I=ee(u),A=d!==null&&I.disposition!=="auto"&&ke(k,!0),te=A?{kind:"connection",disposition:"auto"}:I.classified,E=A?"auto":I.disposition,M=oe(u),x=me(u),C=ae(u),T=typeof u.provider=="string"&&u.provider!==""?u.provider:s.model?.provider,O=typeof u.model=="string"&&u.model!==""?u.model:s.model?.id,P=C===void 0||T===void 0||O===void 0?void 0:{provider:T,model:O,...C};v&&(await this.clearFault("pi\u2192provider"),await this.clearEpisode(s));const _={link:"pi\u2192provider",op:"generation turn",kind:v?"context-overflow":te.kind,retry:v?{disposition:"fatal"}:E==="auto"?{disposition:"auto",by:"daemon",...M!==void 0?{nextAt:new Date(M).toISOString()}:{},...d?.attempt!==void 0?{attempt:d.attempt}:{}}:{disposition:E,...x!==void 0?{nextAt:new Date(x).toISOString()}:{}},message:k,...!v&&E==="auto"&&d!==null?{since:d.since}:{},anchor_entry_id:!v&&E==="auto"&&d?.anchorEntryId!==void 0?d.anchorEntryId:s.sessionManager.getLeafId?.()??void 0,...P===void 0?{}:{provider_error:P}};_.retry.disposition==="auto"?await this.recordPendingProviderFault(s,_):(await this.clearEpisode(s),await this.clearFault("pi\u2192provider"),await this.recordFault(_))}async recoverOnStartup(){const e=this.deps.installedGeneration();if(e===void 0)return"none";const t=(await this.state()).episode,i=this.sessionId(e.session);if(this.deps.cfg.newCycle===!0)return t!==null&&i!==null&&t.session_id===i&&await b(this.deps.nodeId,{op:"invalidate",session_id:i}),"none";if(t===null||i===null||t.session_id!==i)return"none";if(t.state==="admitted")if(t.fault.anchor_entry_id!==void 0&&!this.hasProgressPastAnchor(e.session,t.fault.anchor_entry_id)){if(!(await b(this.deps.nodeId,{op:"reopen",session_id:i})).applied)return"none"}else return await this.clearEpisode(e.session),"none";else if(t.state!=="pending")return"none";return await this.recordFault(S(w(t.fault))),await this.schedule(),"retry-armed"}hasProgressPastAnchor(e,t){const i=e.sessionManager.getBranch(),n=i.findIndex(a=>a.id===t);return(n===-1?i:i.slice(n+1)).some(a=>{if(a.type!=="message")return!1;const{message:c}=a;return c.role==="toolResult"?!0:c.role==="assistant"&&Array.isArray(c.content)&&c.content.length>0})}async schedule(){const e=this.deps.installedGeneration(),t=this.deps.currentSession();if(t.isStreaming||this.timer!==null)return;if(e===void 0){this.abandonTurnEnd();return}const i=await this.state(),n=i.fault;if(!this.isActiveAutoFault(n)||this.sessionId(t)!==null&&!this.pendingEpisodeMatches(t,n,i)){this.clearTimer(),this.abandonTurnEnd();return}const o=Date.now(),a=this.faultRetryDelayMs(n,o);if(a!==null&&this.deps.turnEnds?.holding()===!0&&ye(n.since,a,o)){await this.endRunTurnOnFault(t,n,a);return}a!==null?this.clearAndArmFaultRetry(a,e):this.abandonTurnEnd()}async endRunTurnOnFault(e,t,i){this.clearTimer(),this.abandonTurnEnd(),F({level:"info",event:"broker.runtime.diagnostic",fields:{message:`run turn completed on provider fault: ${t.kind} retry in ${i}ms is past the ${Q}ms turn window (since ${t.since}, attempt ${t.retry.attempt??0})`}}),await this.clearEpisode(e),await this.clearFault("pi\u2192provider")}async rearmIfStranded(){if(this.timer!==null||this.deps.installedGeneration()===void 0)return;const e=this.deps.currentSession();if(e.isStreaming)return;const t=await this.state();!this.isActiveAutoFault(t.fault)||!this.pendingEpisodeMatches(e,t.fault,t)||await this.schedule()}maybeSwitchProviderForRetry(e){if(e.type!=="auto_retry_start")return;const t=N("pi\u2192provider",e.errorMessage??"").kind;if(t!=="rate-limit"&&t!=="connection"||this.providerFallbackInFlight!==null||this.deps.cfg.modelExact===!0)return;const i=this.deps.installedGeneration();if(i===void 0)return;const n=this.deps.currentSession(),o=this.deps.currentServices(),a=this.deps.formatModelSpec(n.model,n.thinkingLevel);if(a===null)return;const c=Y(this.deps.cfg.model,G(),!1);if(c===void 0)return;const s=B(c,$()??this.deps.cfg.cwd,L()),l=X(a),p=Z(s,l),h=p===void 0?{route:void 0,capacityExhausted:!1}:this.nextEligibleFallbackRoute(s.slice(p+1),this.deps.registryOf(o),n.getContextUsage()?.tokens,d=>!this.failedRetryRoutes.has(d.routeId));if(h.route===void 0){h.capacityExhausted&&(this.stageCapacityFailure(i,n),queueMicrotask(()=>{this.deps.installedGeneration()===i&&this.deps.currentSession()===n&&n.abortRetry()}));return}const f=h.route,m=(async()=>{const d=this.deps.registryOf(o).find(f.providerId,f.modelId);if(!d||(await n.setModel(d),this.deps.installedGeneration()!==i||this.deps.currentSession()!==n))return;const g=`${f.providerId}/${f.modelId}`===l.modelSpec?l.thinkingLevel:f.thinkingLevel;n.setThinkingLevel(g??"off"),this.failedRetryRoutes.add(f.routeId),await this.deps.broadcastModelChanged(!1)})().catch(d=>{F({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`provider route fallback failed: ${d instanceof Error?d.message:String(d)}`}})}).finally(()=>{this.deps.installedGeneration()===i&&(this.providerFallbackInFlight=null)});this.providerFallbackInFlight=m}maybeFallbackOnUnusableModel(e){if(e.type!=="message_end"||e.message.role!=="assistant"||e.message.stopReason!=="error")return;const t=re(e.message.errorMessage??"");if(!t&&!ne(e.message.errorMessage??"")||this.deps.cfg.modelExact===!0||this.notFoundFallbackInFlight!==null)return;const i=this.deps.installedGeneration();if(i===void 0)return;const n=this.deps.currentSession(),o=this.deps.currentServices(),a=this.deps.formatModelSpec(n.model,n.thinkingLevel);if(a===null)return;const c=X(a);this.notFoundModels.add(c.modelSpec);const s=Y(this.deps.cfg.model,G(),!1),l=s?B(s,$()??this.deps.cfg.cwd,L()):[],p=Z(l,c),h=p===void 0?{route:void 0,capacityExhausted:!1}:this.nextEligibleFallbackRoute(l.slice(p+1),this.deps.registryOf(o),n.getContextUsage()?.tokens,g=>!this.notFoundModels.has(`${g.providerId}/${g.modelId}`));if(h.route===void 0){h.capacityExhausted&&this.stageCapacityFailure(i,n);return}const f=h.route,m=`${f.providerId}/${f.modelId}${f.thinkingLevel?`:${f.thinkingLevel}`:""}`,d=(async()=>{const g=this.deps.registryOf(o).find(f.providerId,f.modelId);if(g===void 0){F({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`${t?"unconfigured-provider":"not_found"} fallback skipped: ${m} is not registered`}});return}if(await n.setModel(g),this.deps.installedGeneration()!==i||this.deps.currentSession()!==n)return;n.setThinkingLevel(f.thinkingLevel??"off"),await this.deps.broadcastModelChanged();const u=this.deps.formatModelSpec(n.model,n.thinkingLevel)??m;if(F({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`${t?"unconfigured-provider":"not_found"} fallback: ${a} unavailable \u2192 ${u}; re-driving turn`}}),await n.agent.waitForIdle(),this.deps.installedGeneration()!==i||this.deps.currentSession()!==n)return;t&&await this.clearFault("pi\u2192provider");const k=q("recovery",{},pe(a,u,t?"credential":"not-found"));H(k,{type:"runtime",kind:"recovery"}),await this.deps.turnAdmission.admit(v=>W.fresh(()=>n.prompt(k,{preflightResult:v})))})().catch(g=>{F({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`${t?"unconfigured-provider":"not_found"} fallback failed: ${g instanceof Error?g.message:String(g)}`}})}).finally(()=>{this.deps.installedGeneration()===i&&(this.notFoundFallbackInFlight=null)});this.notFoundFallbackInFlight=d}nextEligibleFallbackRoute(e,t,i,n){let o=0,a=0;for(const c of e){if(!n(c)||fe([{...c,...de(c,t),automaticFallback:!0}]).candidates.length===0)continue;const s=t.find(c.providerId,c.modelId);if(s!==void 0){if(o++,this.targetCannotFitContext(s.contextWindow,i)){a++;continue}return{route:c,capacityExhausted:!1}}}return{route:void 0,capacityExhausted:o>0&&o===a}}targetCannotFitContext(e,t){return Number.isFinite(e)&&Number.isFinite(t)&&e<t}stageCapacityFailure(e,t){const i=t.getContextUsage()?.tokens;this.stagedCapacityFailure={generation:e,errorMessage:Number.isFinite(i)?`All available fallback models have context windows smaller than the current conversation (${i} tokens).`:"All available fallback models have context windows smaller than the current conversation."}}async recordPendingProviderFault(e,t){const i=this.sessionId(e);if(i===null){await this.recordFault(t);return}await b(this.deps.nodeId,{op:"record-pending",session_id:i,input:t})}pendingEpisodeMatches(e,t,i){const n=this.sessionId(e),o=i.episode;return n!==null&&o!==null&&o.state==="pending"&&o.session_id===n&&o.fault.fault_id===t.fault_id}faultRetryDelayMs(e,t){if(e.retry.nextAt!==void 0){const i=Date.parse(e.retry.nextAt)-t;return Number.isFinite(i)?Math.max(0,i):null}return j(w(e),t)?.delayMs??null}clearAndArmFaultRetry(e,t){if(this.deps.installedGeneration()!==t)return;this.clearTimer();const i=Math.min(Math.max(0,e),ge),n=Math.max(0,e-i);this.timer=setTimeout(()=>{if(this.timer=null,this.deps.installedGeneration()===t){if(n>0){this.clearAndArmFaultRetry(n,t);return}this.runFaultRetry().catch(o=>{this.abandonTurnEnd(),F({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry fire failed: ${o instanceof Error?o.message:String(o)}`}})})}},i),typeof this.timer.unref=="function"&&this.timer.unref()}async runFaultRetry(){await this.attemptFaultRetry()===void 0&&this.abandonTurnEnd()}async attemptFaultRetry(){const e=this.deps.installedGeneration();if(e===void 0)return;const t=e.session;if(t.isStreaming)return;const i=(await this.state()).fault;if(!this.isActiveAutoFault(i))return;let n=i;if(i.kind==="connection"&&this.deps.turnEnds===void 0){const l=await this.deps.retryProbe();if(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t||t.isStreaming)return;const p=(await this.state()).fault;if(!this.isActiveAutoFault(p)||p.since!==i.since)return;if(!l)return this.clearAndArmFaultRetry(J(p.kind).baseDelayMs,e),"rearmed";n=p}const o=this.deps.turnEnds!==void 0,a=n.retry.attempt??0,c=J(n.kind);if(a>=c.max){await this.recordFault(S(V(w(n)))),await this.clearEpisode(t);return}const s=j(w(n),Date.now());if(s===null){await this.recordFault(S(V(w(n)))),await this.clearEpisode(t);return}if(n.anchor_entry_id!==void 0)try{if((t.sessionManager.getLeafId?.()??null)!==n.anchor_entry_id){const l=await t.navigateTree(n.anchor_entry_id);if(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t)return;l.cancelled||this.deps.reWelcomeAll()}}catch(l){F({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`fault retry rewind skipped: ${l instanceof Error?l.message:String(l)}`}})}if(!(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t))return this.deps.turnAdmission.admit(async l=>{const p=(await this.state()).fault;if(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t||t.isStreaming||!this.isActiveAutoFault(p)||p.since!==n.since){l();return}const h=this.sessionId(t);if(h===null){l();return}if(!(await b(this.deps.nodeId,{op:"admit",session_id:h,fault_id:p.fault_id,retry:s.fault.retry})).applied){l();return}const m=q("recovery",o?{attempt:s.attempt}:{attempt:s.attempt,max:s.max},ve(n.kind,o));H(m,{type:"runtime",kind:"recovery"}),this.deps.turnEnds?.beginRecovery();try{await W.fresh(()=>t.prompt(m,{preflightResult:l}))}finally{this.deps.turnEnds?.recoveryReturned()}return"prompted"})}}export{Be as FaultRetry,Q as RUN_TURN_RETRY_WINDOW_MS,ke as isPrefillRejectionDuringEpisode,ve as retryCardBody,ye as runTurnRetryExpired,ee as settledProviderFault,Ue as willDaemonRetry};
|
|
1
|
+
var ae=Object.defineProperty;var h=(r,e)=>ae(r,"name",{value:e,configurable:!0});import{envModelIntent as N,envNodeCwd as G,envProfileId as U}from"../../../shared/env.js";import{isContextOverflow as Y}from"@earendil-works/pi-ai";import{classify as B}from"../../fault-classifier.js";import{isDaemonTransportApiError as de}from"../../../api/errors.js";import{isModelNotFoundError as le,isProviderUnconfiguredError as ce}from"../fault.js";import{brokerRecovery as ue,mutateBrokerFault as W,mutateBrokerProviderRetry as _}from"./daemon-ops.js";import{extractCoolingDeadline as pe}from"../managed-provider-cooling.js";import{extractProviderFailureDetails as fe}from"../../provider-failure.js";import{expandModelCandidates as q,modelRequestFromConfig as V,probeRouteAvailability as he}from"../../model-routes.js";import{operationIdContext as j}from"../../events/operation-id.js";import{emitEvent as w}from"../../events/emit.js";import{CONNECTION_FAULT_RECOVERY_BODY as me,PROVIDER_FAULT_RECOVERY_BODY as ge,RUN_CONNECTION_FAULT_RETRY_BODY as ye,formatCard as X,formatModelFallbackRecovery as ve}from"../../../shared/generated-context.js";import{markFatalOnExhaust as J,nextFaultRetry as z,policyFor as H}from"../fault-recovery.js";import{parseModelSpec as K}from"../model-selection.js";import{endedByAbort as Q}from"../session-cycles.js";import{resolveProviderCandidates as Fe}from"../../subscription-state.js";import{announceMessageOrigin as Z}from"../stamp/channel.js";import{LLM_REFUSAL_DIAGNOSTIC as we,refusalRetryAt as ke}from"./model-adapter.js";import{isSafetyRefusal as ee}from"../../llm/refusal.js";const be=2147483647,te=3e4;function _e(r,e,t){const n=Date.parse(r);return!Number.isFinite(n)||t+e-n>te}h(_e,"runTurnRetryExpired");class ne extends Error{static{h(this,"StaleOutcome")}}const Ee=1e3,Ie=3e4;function Re(r,e){return r!=="connection"?ge:e?ye:me}h(Re,"retryCardBody");function E(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,since:r.since,operation_id:r.operation_id,...r.anchor_entry_id===void 0?{}:{anchorEntryId:r.anchor_entry_id},...r.provider_error===void 0?{}:{providerError:r.provider_error}}}h(E,"policyFault");function x(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,...r.operation_id===void 0?{}:{operation_id:r.operation_id},...r.since===void 0?{}:{since:r.since},...r.anchorEntryId===void 0?{}:{anchor_entry_id:r.anchorEntryId},...r.providerError===void 0?{}:{provider_error:r.providerError}}}h(x,"faultInput");function ie(r,e){const t=h(n=>`${n.providerId}/${n.modelId}`===e.modelSpec,"onLiveModel");return(r.find(n=>t(n)&&n.thinkingLevel===e.thinkingLevel)??r.find(t))?.rank}h(ie,"liveRouteRank");function re(r){const e=B("pi\u2192provider",r),t=r.diagnostics?.some(n=>n.type===we)??!1;return{classified:e,disposition:t?"fatal":e.disposition}}h(re,"settledProviderFault");function He(r,e){if(r.stopReason!=="error"||Q(r)||ee(r)||Y(r,e))return!1;const{classified:t,disposition:n}=re(r);return n==="auto"&&(t.kind==="connection"||t.kind==="rate-limit"||t.kind==="overloaded")}h(He,"willDaemonRetry");const Se=/does not support assistant message prefill|conversation must end with a user message/i;function Ae(r,e){return e&&Se.test(r)}h(Ae,"isPrefillRejectionDuringEpisode");class Ke{static{h(this,"FaultRetry")}deps;timer=null;failedRetryRoutes=new Set;notFoundModels=new Set;providerFallbackInFlight=null;notFoundFallbackInFlight=null;stagedCapacityFailure=null;agentStarts=0;constructor(e){this.deps=e}clearTimer(){this.timer!==null&&(clearTimeout(this.timer),this.timer=null)}reset(){this.clearTimer(),this.deps.turnEnds?.abandon(),this.providerFallbackInFlight=null,this.notFoundFallbackInFlight=null,this.stagedCapacityFailure=null}abandonTurnEnd(){this.deps.turnEnds?.abandon()}state(){return ue(this.deps.nodeId)}async recordFault(e){return(await W(this.deps.nodeId,{op:"record",input:e})).fault}async clearFault(e,t=!1){await W(this.deps.nodeId,{op:"clear",...e===void 0?{}:{link:e},...t?{preserve_episode:!0}:{}})}sessionId(e){const t=e.sessionManager.getSessionId?.();return typeof t=="string"&&t!==""?t:null}async clearEpisode(e){const t=this.sessionId(e);t!==null&&await _(this.deps.nodeId,{op:"clear",session_id:t})}onEvent(e){e.type==="agent_start"&&this.agentStarts++,this.maybeSwitchProviderForRetry(e),this.maybeFallbackOnUnusableModel(e)}isActiveAutoFault(e){return e===null||e.retry.disposition!=="auto"||e.retry.by!=="daemon"?!1:e.kind==="connection"||e.kind==="rate-limit"||e.kind==="overloaded"}async publishSettledProviderFault(e){const t={agentEnd:e.stagedProviderAgentEnd,watchdogAbort:e.stagedWatchdogAbort,refreshAbort:e.stagedRefreshAbort,overflowFailure:e.stagedOverflowFailure,capacityFailure:this.stagedCapacityFailure?.generation===e?this.stagedCapacityFailure:null};this.stagedCapacityFailure=null,e.stagedProviderAgentEnd=null,e.stagedWatchdogAbort=!1,e.stagedRefreshAbort=!1,e.stagedOverflowFailure=null;const n=this.agentStarts,i=h(()=>{if(this.deps.installedGeneration()!==e||this.agentStarts!==n)throw new ne},"assertCurrent");let a=Ee;try{for(;;){try{await this.recordStagedOutcome(e,t,i);return}catch(o){if(!de(o))throw o;w({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`settled turn fault write waiting for the daemon: ${o.message}`}})}await new Promise(o=>setTimeout(o,a)),a=Math.min(a*2,Ie),i()}}catch(o){if(!(o instanceof ne))throw o}}async recordStagedOutcome(e,t,n){const{agentEnd:i,watchdogAbort:a,refreshAbort:o,overflowFailure:d,capacityFailure:p}=t,s=e.session,l=h(async F=>{n(),await this.clearEpisode(F)},"clearEpisode"),y=h(async F=>{n(),await this.recordFault(F)},"recordFault"),u=h(async(F,oe)=>{n(),await this.recordPendingProviderFault(F,oe)},"recordPendingProviderFault"),v=await this.state(),m=v.fault,f=v.episode,I=this.sessionId(s),k=this.isActiveAutoFault(m)&&m.link==="pi\u2192provider"?m:f?.state==="admitted"&&f.session_id===I&&this.isActiveAutoFault(f.fault)?f.fault:null,g=k===null?null:{since:k.since,anchorEntryId:k.anchor_entry_id,attempt:k.retry.attempt},c=[...Array.isArray(i?.messages)?i.messages:[]].reverse().find(F=>typeof F=="object"&&F!==null&&F.role==="assistant");if(p!==null||d!==null){await l(s),await y({link:"pi\u2192provider",op:"context overflow recovery",kind:"context-overflow",retry:{disposition:"fatal"},message:p?.errorMessage??d.errorMessage,anchor_entry_id:s.sessionManager.getLeafId?.()??void 0});return}if(a&&c?.stopReason==="aborted"){await u(s,{link:"pi\u2192provider",op:"generation turn",kind:"connection",retry:{disposition:"auto",by:"daemon",...g?.attempt!==void 0?{attempt:g.attempt}:{}},message:typeof c.errorMessage=="string"?c.errorMessage:"engine error (no errorMessage recorded)",...g!==null?{since:g.since}:{},anchor_entry_id:g?.anchorEntryId??s.sessionManager.getLeafId?.()??void 0});return}if(c?.stopReason!=="error"){c!==void 0&&await l(s);return}if(o){await l(s);return}if(ee(c)){await l(s);return}const S=typeof c.errorMessage=="string"?c.errorMessage:"engine error (no errorMessage recorded)";if(Q({stopReason:"error",errorMessage:S})){await l(s);return}const b=Y(c,s.model?.contextWindow),A=re(c),T=g!==null&&A.disposition!=="auto"&&Ae(S,!0),se=T?{kind:"connection",disposition:"auto"}:A.classified,R=T?"auto":A.disposition,C=pe(c),O=ke(c),P=fe(c),$=typeof c.provider=="string"&&c.provider!==""?c.provider:s.model?.provider,L=typeof c.model=="string"&&c.model!==""?c.model:s.model?.id,D=P===void 0||$===void 0||L===void 0?void 0:{provider:$,model:L,...P};b&&await l(s);const M={link:"pi\u2192provider",op:"generation turn",kind:b?"context-overflow":se.kind,retry:b?{disposition:"fatal"}:R==="auto"?{disposition:"auto",by:"daemon",...C!==void 0?{nextAt:new Date(C).toISOString()}:{},...g?.attempt!==void 0?{attempt:g.attempt}:{}}:{disposition:R,...O!==void 0?{nextAt:new Date(O).toISOString()}:{}},message:S,...!b&&R==="auto"&&g!==null?{since:g.since}:{},anchor_entry_id:!b&&R==="auto"&&g?.anchorEntryId!==void 0?g.anchorEntryId:s.sessionManager.getLeafId?.()??void 0,...D===void 0?{}:{provider_error:D}};M.retry.disposition==="auto"?await u(s,M):(await l(s),await y(M))}async recoverOnStartup(){const e=this.deps.installedGeneration();if(e===void 0)return"none";const t=(await this.state()).episode,n=this.sessionId(e.session);if(this.deps.cfg.newCycle===!0)return t!==null&&n!==null&&t.session_id===n&&await _(this.deps.nodeId,{op:"invalidate",session_id:n}),"none";if(t===null||n===null||t.session_id!==n)return"none";if(t.state==="admitted")if(t.fault.anchor_entry_id!==void 0&&!this.hasProgressPastAnchor(e.session,t.fault.anchor_entry_id)){if(!(await _(this.deps.nodeId,{op:"reopen",session_id:n})).applied)return"none"}else return await this.clearEpisode(e.session),"none";else if(t.state!=="pending")return"none";return await this.recordFault(x(E(t.fault))),await this.schedule(),"retry-armed"}hasProgressPastAnchor(e,t){const n=e.sessionManager.getBranch(),i=n.findIndex(o=>o.id===t);return(i===-1?n:n.slice(i+1)).some(o=>{if(o.type!=="message")return!1;const{message:d}=o;return d.role==="toolResult"?!0:d.role==="assistant"&&Array.isArray(d.content)&&d.content.length>0})}async schedule(){const e=this.deps.installedGeneration(),t=this.deps.currentSession();if(t.isStreaming||this.timer!==null)return;if(e===void 0){this.abandonTurnEnd();return}const n=await this.state(),i=n.fault;if(!this.isActiveAutoFault(i)||this.sessionId(t)!==null&&!this.pendingEpisodeMatches(t,i,n)){this.clearTimer(),this.abandonTurnEnd();return}const a=Date.now(),o=this.faultRetryDelayMs(i,a);if(o!==null&&this.deps.turnEnds?.holding()===!0&&_e(i.since,o,a)){await this.endRunTurnOnFault(t,i,o);return}o!==null?this.clearAndArmFaultRetry(o,e):this.abandonTurnEnd()}async endRunTurnOnFault(e,t,n){this.clearTimer(),this.abandonTurnEnd(),w({level:"info",event:"broker.runtime.diagnostic",fields:{message:`run turn completed on provider fault: ${t.kind} retry in ${n}ms is past the ${te}ms turn window (since ${t.since}, attempt ${t.retry.attempt??0})`}}),await this.clearEpisode(e),await this.clearFault("pi\u2192provider")}async rearmIfStranded(){if(this.timer!==null||this.deps.installedGeneration()===void 0)return;const e=this.deps.currentSession();if(e.isStreaming)return;const t=await this.state();!this.isActiveAutoFault(t.fault)||!this.pendingEpisodeMatches(e,t.fault,t)||await this.schedule()}maybeSwitchProviderForRetry(e){if(e.type!=="auto_retry_start")return;const t=B("pi\u2192provider",e.errorMessage??"").kind;if(t!=="rate-limit"&&t!=="connection"||this.providerFallbackInFlight!==null||this.deps.cfg.modelExact===!0)return;const n=this.deps.installedGeneration();if(n===void 0)return;const i=this.deps.currentSession(),a=this.deps.currentServices(),o=this.deps.formatModelSpec(i.model,i.thinkingLevel);if(o===null)return;const d=V(this.deps.cfg.model,N(),!1);if(d===void 0)return;const p=q(d,G()??this.deps.cfg.cwd,U()),s=K(o),l=ie(p,s),y=l===void 0?{route:void 0,capacityExhausted:!1}:this.nextEligibleFallbackRoute(p.slice(l+1),this.deps.registryOf(a),i.getContextUsage()?.tokens,m=>!this.failedRetryRoutes.has(m.routeId));if(y.route===void 0){y.capacityExhausted&&(this.stageCapacityFailure(n,i),queueMicrotask(()=>{this.deps.installedGeneration()===n&&this.deps.currentSession()===i&&i.abortRetry()}));return}const u=y.route,v=(async()=>{const m=this.deps.registryOf(a).find(u.providerId,u.modelId);if(!m||(await i.setModel(m),this.deps.installedGeneration()!==n||this.deps.currentSession()!==i))return;const f=`${u.providerId}/${u.modelId}`===s.modelSpec?s.thinkingLevel:u.thinkingLevel;i.setThinkingLevel(f??"off"),this.failedRetryRoutes.add(u.routeId),await this.deps.broadcastModelChanged(!1)})().catch(m=>{w({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`provider route fallback failed: ${m instanceof Error?m.message:String(m)}`}})}).finally(()=>{this.deps.installedGeneration()===n&&(this.providerFallbackInFlight=null)});this.providerFallbackInFlight=v}maybeFallbackOnUnusableModel(e){if(e.type!=="message_end"||e.message.role!=="assistant"||e.message.stopReason!=="error")return;const t=ce(e.message.errorMessage??"");if(!t&&!le(e.message.errorMessage??"")||this.deps.cfg.modelExact===!0||this.notFoundFallbackInFlight!==null)return;const n=this.deps.installedGeneration();if(n===void 0)return;const i=this.deps.currentSession(),a=this.deps.currentServices(),o=this.deps.formatModelSpec(i.model,i.thinkingLevel);if(o===null)return;const d=K(o);this.notFoundModels.add(d.modelSpec);const p=V(this.deps.cfg.model,N(),!1),s=p?q(p,G()??this.deps.cfg.cwd,U()):[],l=ie(s,d),y=l===void 0?{route:void 0,capacityExhausted:!1}:this.nextEligibleFallbackRoute(s.slice(l+1),this.deps.registryOf(a),i.getContextUsage()?.tokens,f=>!this.notFoundModels.has(`${f.providerId}/${f.modelId}`));if(y.route===void 0){y.capacityExhausted&&this.stageCapacityFailure(n,i);return}const u=y.route,v=`${u.providerId}/${u.modelId}${u.thinkingLevel?`:${u.thinkingLevel}`:""}`,m=(async()=>{const f=this.deps.registryOf(a).find(u.providerId,u.modelId);if(f===void 0){w({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`${t?"unconfigured-provider":"not_found"} fallback skipped: ${v} is not registered`}});return}if(await i.setModel(f),this.deps.installedGeneration()!==n||this.deps.currentSession()!==i)return;i.setThinkingLevel(u.thinkingLevel??"off"),await this.deps.broadcastModelChanged();const I=this.deps.formatModelSpec(i.model,i.thinkingLevel)??v;if(w({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`${t?"unconfigured-provider":"not_found"} fallback: ${o} unavailable \u2192 ${I}; re-driving turn`}}),await i.agent.waitForIdle(),this.deps.installedGeneration()!==n||this.deps.currentSession()!==i)return;t&&await this.clearFault("pi\u2192provider");const k=X("recovery",{},ve(o,I,t?"credential":"not-found"));Z(k,{type:"runtime",kind:"recovery"}),await this.deps.turnAdmission.admit(g=>j.fresh(()=>i.prompt(k,{preflightResult:g})))})().catch(f=>{w({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`${t?"unconfigured-provider":"not_found"} fallback failed: ${f instanceof Error?f.message:String(f)}`}})}).finally(()=>{this.deps.installedGeneration()===n&&(this.notFoundFallbackInFlight=null)});this.notFoundFallbackInFlight=m}nextEligibleFallbackRoute(e,t,n,i){let a=0,o=0;for(const d of e){if(!i(d)||Fe([{...d,...he(d,t),automaticFallback:!0}]).candidates.length===0)continue;const p=t.find(d.providerId,d.modelId);if(p!==void 0){if(a++,this.targetCannotFitContext(p.contextWindow,n)){o++;continue}return{route:d,capacityExhausted:!1}}}return{route:void 0,capacityExhausted:a>0&&a===o}}targetCannotFitContext(e,t){return Number.isFinite(e)&&Number.isFinite(t)&&e<t}stageCapacityFailure(e,t){const n=t.getContextUsage()?.tokens;this.stagedCapacityFailure={generation:e,errorMessage:Number.isFinite(n)?`All available fallback models have context windows smaller than the current conversation (${n} tokens).`:"All available fallback models have context windows smaller than the current conversation."}}async recordPendingProviderFault(e,t){const n=this.sessionId(e);if(n===null){await this.recordFault(t);return}await _(this.deps.nodeId,{op:"record-pending",session_id:n,input:t})}pendingEpisodeMatches(e,t,n){const i=this.sessionId(e),a=n.episode;return i!==null&&a!==null&&a.state==="pending"&&a.session_id===i&&a.fault.fault_id===t.fault_id}faultRetryDelayMs(e,t){if(e.retry.nextAt!==void 0){const n=Date.parse(e.retry.nextAt)-t;return Number.isFinite(n)?Math.max(0,n):null}return z(E(e),t)?.delayMs??null}clearAndArmFaultRetry(e,t){if(this.deps.installedGeneration()!==t)return;this.clearTimer();const n=Math.min(Math.max(0,e),be),i=Math.max(0,e-n);this.timer=setTimeout(()=>{if(this.timer=null,this.deps.installedGeneration()===t){if(i>0){this.clearAndArmFaultRetry(i,t);return}this.runFaultRetry().catch(a=>{this.abandonTurnEnd(),w({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry fire failed: ${a instanceof Error?a.message:String(a)}`}})})}},n),typeof this.timer.unref=="function"&&this.timer.unref()}async runFaultRetry(){await this.attemptFaultRetry()===void 0&&this.abandonTurnEnd()}async attemptFaultRetry(){const e=this.deps.installedGeneration();if(e===void 0)return;const t=e.session;if(t.isStreaming)return;const n=(await this.state()).fault;if(!this.isActiveAutoFault(n))return;let i=n;if(n.kind==="connection"&&this.deps.turnEnds===void 0){const s=await this.deps.retryProbe();if(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t||t.isStreaming)return;const l=(await this.state()).fault;if(!this.isActiveAutoFault(l)||l.since!==n.since)return;if(!s)return this.clearAndArmFaultRetry(H(l.kind).baseDelayMs,e),"rearmed";i=l}const a=this.deps.turnEnds!==void 0,o=i.retry.attempt??0,d=H(i.kind);if(o>=d.max){await this.recordFault(x(J(E(i)))),await this.clearEpisode(t);return}const p=z(E(i),Date.now());if(p===null){await this.recordFault(x(J(E(i)))),await this.clearEpisode(t);return}if(i.anchor_entry_id!==void 0)try{if((t.sessionManager.getLeafId?.()??null)!==i.anchor_entry_id){const s=await t.navigateTree(i.anchor_entry_id);if(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t)return;s.cancelled||this.deps.reWelcomeAll()}}catch(s){w({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`fault retry rewind skipped: ${s instanceof Error?s.message:String(s)}`}})}if(!(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t))return this.deps.turnAdmission.admit(async s=>{const l=(await this.state()).fault;if(this.deps.installedGeneration()!==e||this.deps.currentSession()!==t||t.isStreaming||!this.isActiveAutoFault(l)||l.since!==i.since){s();return}const y=this.sessionId(t);if(y===null){s();return}if(!(await _(this.deps.nodeId,{op:"admit",session_id:y,fault_id:l.fault_id,retry:p.fault.retry})).applied){s();return}const v=X("recovery",a?{attempt:p.attempt}:{attempt:p.attempt,max:p.max},Re(i.kind,a));Z(v,{type:"runtime",kind:"recovery"}),this.deps.turnEnds?.beginRecovery();try{await j.fresh(()=>t.prompt(v,{preflightResult:s}))}finally{this.deps.turnEnds?.recoveryReturned()}return"prompted"})}}export{Ke as FaultRetry,te as RUN_TURN_RETRY_WINDOW_MS,Ae as isPrefillRejectionDuringEpisode,Re as retryCardBody,_e as runTurnRetryExpired,re as settledProviderFault,He as willDaemonRetry};
|
|
@@ -59,6 +59,8 @@ export declare class RebindDriver {
|
|
|
59
59
|
private latestRebindRequest;
|
|
60
60
|
private replacementTail;
|
|
61
61
|
private admittedReplacements;
|
|
62
|
+
private rebindsInFlight;
|
|
63
|
+
private rebinding;
|
|
62
64
|
private agentRunActiveValue;
|
|
63
65
|
private shutdownRequested;
|
|
64
66
|
constructor(deps: RebindDriverDeps);
|
|
@@ -67,6 +69,8 @@ export declare class RebindDriver {
|
|
|
67
69
|
installedGeneration(): SubscriptionGeneration | undefined;
|
|
68
70
|
isAgentRunActive(): boolean;
|
|
69
71
|
isReplacing(): boolean;
|
|
72
|
+
/** Resolves when the rebinds requested so far have finished binding extensions (every session_start hook), failed, or been superseded; undefined when none is in flight. */
|
|
73
|
+
pendingRebind(): Promise<void> | undefined;
|
|
70
74
|
requestShutdown(): void;
|
|
71
75
|
setRebindSession(): void;
|
|
72
76
|
enqueueRebind(candidateSession: BrokerSession, candidateServices: AgentSessionServices): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var l=(
|
|
1
|
+
var k=Object.defineProperty;var l=(a,e)=>k(a,"name",{value:e,configurable:!0});import{mkdirSync as v,writeFileSync as _}from"node:fs";import{join as I}from"node:path";import{nodeRunJobDir as A}from"../../canvas/paths.js";import{emitEvent as u}from"../../events/emit.js";import{operationIdContext as c}from"../../events/operation-id.js";import{installPersonaTransitionGate as E}from"../broker-persona-guidance.js";import{installRetryCardElision as T}from"./retry-card-elision.js";import{abortSessionFromExtension as w}from"./extension-abort.js";import{brokerRecovery as S,mutateBrokerFault as x,mutateBrokerProviderRetry as P}from"./daemon-ops.js";const f=2,m=3e4,b=Symbol("replacement-deadline-exceeded"),V="(interrupted)",g=Symbol.for("crtr.trailing-thinking-guard");function C(a){for(let e=a.length-1;e>=0;e--){const t=a[e];if(t!==void 0){if(t.type==="text"){if(t.text.trim().length===0)continue;return t}if(t.type==="thinking"){const d=t.thinkingSignature,r=typeof d=="string"&&d.trim().length>0;if(t.redacted!==!0&&t.thinking.trim().length===0&&!r)continue;return t}return t}}}l(C,"lastSerializedBlock");function y(a){return a.map(e=>e.role!=="assistant"||e.stopReason==="error"||e.stopReason==="aborted"||C(e.content)?.type!=="thinking"?e:{...e,content:[...e.content,{type:"text",text:V}]})}l(y,"guardTrailingThinking");function N(a){const e=a.convertToLlm;if(e[g]===!0)return;const t=l(d=>{const r=e(d);return r instanceof Promise?r.then(y):y(r)},"wrapped");t[g]=!0,a.convertToLlm=t}l(N,"installTrailingThinkingGuard");class ${static{l(this,"RebindDriver")}deps;sessionValue;servicesValue;unsubscribe;installed;nextSubscriptionGeneration=0;rebindTail=Promise.resolve();latestRebindRequest=0;replacementTail=Promise.resolve();admittedReplacements=0;rebindsInFlight=0;rebinding;agentRunActiveValue=!1;shutdownRequested=!1;constructor(e){this.deps=e,this.sessionValue=e.session,this.servicesValue=e.services}session(){return this.sessionValue}services(){return this.servicesValue}installedGeneration(){return this.installed}isAgentRunActive(){return this.agentRunActiveValue}isReplacing(){return this.admittedReplacements>0}pendingRebind(){return this.rebinding?.done}requestShutdown(){if(!this.agentRunActiveValue){this.deps.disposeAndExit("shutdown-hook");return}this.shutdownRequested=!0}setRebindSession(){this.deps.runtime?.setRebindSession(e=>this.enqueueRebind(e,this.deps.runtime.services))}enqueueRebind(e,t){const d=++this.latestRebindRequest;if(this.rebindsInFlight++===0){let n;this.rebinding={done:new Promise(o=>{n=o}),resolve:n}}const r=this.rebindTail.then(async()=>{if(d!==this.latestRebindRequest)return;if(this.installed!==void 0){typeof this.sessionValue.sessionFile=="string"&&this.sessionValue.sessionFile!==""&&await P(this.deps.nodeId,{op:"invalidate",session_id:this.sessionValue.sessionManager.getSessionId()});const i=(await S(this.deps.nodeId)).fault;i?.link==="pi\u2192provider"&&i.retry.disposition==="auto"&&i.retry.by==="daemon"&&await x(this.deps.nodeId,{op:"clear",link:"pi\u2192provider",preserve_episode:!0})}this.installed?.executingTools.clear(),this.removeInstalledSubscription(),this.deps.setActiveSession(e),this.deps.projection().reset(),this.deps.faultRetry().reset(),this.agentRunActiveValue=!1,this.deps.onSessionRebind(),this.deps.toolGroups.resetForSession(),this.sessionValue=e,this.servicesValue=t;const n=e.agent;n&&(E(this.deps.nodeId,{agent:n,sessionManager:e.sessionManager}),T(n),n.steeringMode="all",n.followUpMode="all",N(n));const o={id:++this.nextSubscriptionGeneration,session:e,fallback:{blocked:!1},stagedProviderAgentEnd:null,stagedWatchdogAbort:!1,stagedRefreshAbort:!1,stagedOverflowFailure:null,executingTools:new Set};if(this.unsubscribe=this.sessionValue.subscribe(i=>{if(!this.deps.projection().isCurrent(o))return;if(c.current()!==void 0){this.executeSubscriptionCallback(o,i);return}const s=o.fallback;if(i.type==="turn_start"&&s.storedId!==void 0){s.storedId=void 0,s.blocked=!0,c.fresh(()=>{u({level:"warn",event:"broker.turn.fallback_overlap",fields:{generation:o.id,engine_event:i.type}}),this.executeSubscriptionCallback(o,i)});return}if(i.type==="turn_start"&&!s.blocked){c.fresh(R=>{s.storedId=R,this.executeSubscriptionCallback(o,i)});return}const h=s.storedId;if(h!==void 0&&!s.blocked){c.run(h,()=>{this.executeSubscriptionCallback(o,i),i.type==="agent_settled"&&s.storedId===h&&(s.storedId=void 0)});return}this.executeSubscriptionCallback(o,i)}),this.installed=o,await e.bindExtensions({uiContext:this.deps.uiContext(),mode:"rpc",abortHandler:l(()=>w(e,()=>{const i=this.installed;i?.session===e&&(i.stagedRefreshAbort=!0)}),"abortHandler"),shutdownHandler:l(()=>this.requestShutdown(),"shutdownHandler")}),d===this.latestRebindRequest){if(this.deps.cfg.editorName!==void 0&&this.deps.cfg.editorName!=="")try{e.setSessionName(this.deps.cfg.editorName)}catch{}try{this.deps.turnReplies.seed(this.deps.transcriptMessages(e))}catch(i){u({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply seed failed: ${String(i)}`}})}this.deps.projection().rearmIfStreaming(o),this.captureSystemPrompt(e)}}).finally(()=>{--this.rebindsInFlight>0||(this.rebinding?.resolve(),this.rebinding=void 0)});return this.rebindTail=r.catch(()=>{}),r}runReplacement(e,t,d){const r=this.deps.runtime;if(r===void 0){this.deps.registry.sendFrame(e,{type:"error",code:"engine_error",message:"session replacement unsupported at this engine pin"});return}if(this.admittedReplacements>=f){c.fresh(()=>u({level:"warn",event:"broker.session_replacement.rejected",outcome:"skipped",fields:{op:t,reason:"capacity",admitted:f,cap:f}})),this.ackTo(e,t,!1,`session replacement busy (${f} active or queued)`);return}this.admittedReplacements++;const n=this.replacementTail.then(async()=>{try{await c.fresh(async()=>{const o=process.hrtime.bigint();let i;try{const p=new Promise(h=>{i=setTimeout(()=>h(b),m)}),s=await Promise.race([d(r),p]);if(s===b){u({level:"error",event:"broker.session_replacement.timed_out",outcome:"failed",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{op:t,deadline_ms:m,mutation_outcome:"indeterminate"}}),this.ackTo(e,t,!1,"session replacement timed out; broker restarting because session state is indeterminate"),this.deps.disposeAndExit("session-replacement-timeout",1);return}s.cancelled||this.deps.reWelcomeAll(),this.ackTo(e,t,!s.cancelled,s.cancelled?s.detail??"cancelled by extension":void 0)}catch(p){u({level:"error",event:"broker.session_replacement.failed",outcome:"failed",error:p,fields:{op:t,mutation_outcome:"indeterminate"}}),this.ackTo(e,t,!1,"session replacement failed; broker restarting because session state is indeterminate"),this.deps.disposeAndExit("session-replacement-failed",1)}finally{clearTimeout(i)}})}finally{this.admittedReplacements--,this.admittedReplacements===0&&this.deps.onReplacementIdle?.()}});this.replacementTail=n.catch(()=>{})}removeInstalledSubscription(){this.unsubscribe?.(),this.unsubscribe=void 0,this.installed=void 0}captureSystemPrompt(e){try{const t=A(this.deps.nodeId);v(t,{recursive:!0}),_(I(t,"system-prompt.md"),e.systemPrompt,"utf8")}catch{}}executeSubscriptionCallback(e,t){try{t.type==="agent_start"&&(this.agentRunActiveValue=!0),t.type==="agent_end"&&(e.stagedProviderAgentEnd=t,e.stagedOverflowFailure=null),t.type==="compaction_end"&&t.reason==="overflow"&&t.willRetry===!1&&typeof t.errorMessage=="string"&&(e.stagedOverflowFailure={errorMessage:t.errorMessage}),t.type==="agent_settled"&&(this.agentRunActiveValue=!1,this.publishAndScheduleProviderRecovery(e)),this.deps.toolGroups.observeToolGroupEvent(t),this.deps.turnReplies.observe(t),this.deps.projection().relayEvent(t,e)}catch(d){u({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`event relay threw: ${String(d)}`}})}}async publishAndScheduleProviderRecovery(e){try{if(await this.deps.faultRetry().publishSettledProviderFault(e),this.shutdownRequested){this.deps.disposeAndExit("shutdown-after-settle");return}await this.deps.faultRetry().schedule()}catch(t){this.deps.faultRetry().abandonTurnEnd(),u({level:"error",event:"broker.daemon.operation.failed",node_id:this.deps.nodeId,error:t,fields:{operation:"provider_fault_settlement"}}),this.shutdownRequested&&this.deps.disposeAndExit("shutdown-after-settle")}}ackTo(e,t,d=!0,r,n){this.deps.registry.sendFrame(e,{type:"ack",for:t,ok:d,...r!==void 0?{detail:r}:{},...n!==void 0?{id:n}:{}})}}export{$ as RebindDriver};
|
|
@@ -37,6 +37,8 @@ export type RunTurnQueueDeps = {
|
|
|
37
37
|
runNode: boolean;
|
|
38
38
|
session: () => BrokerSession;
|
|
39
39
|
isReplacing: () => boolean;
|
|
40
|
+
/** Set while a rebind is still binding extensions: no turn may start before every session_start hook has finished. */
|
|
41
|
+
pendingRebind: () => Promise<void> | undefined;
|
|
40
42
|
isAgentRunActive: () => boolean;
|
|
41
43
|
/** Frame/kickoff prompt dispatches still igniting. Zero before the frame
|
|
42
44
|
* dispatcher exists. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var R=Object.defineProperty;var i=(n,e)=>R(n,"name",{value:e,configurable:!0});function A(n){const{runNode:e,session:c,turnAdmission:p}=n,o=[];let f=!1,r=!1;const v=i(()=>n.isReplacing()||n.isAgentRunActive()||c().isStreaming,"engineBusy"),d=i(()=>r||f||v(),"mustQueue"),a=i(()=>{if(d())return;const t=o.shift();t&&g(t.text,t.messageIds)},"drain"),g=i((t,s=[])=>{const l=n.pendingRebind();if(l!==void 0){l.then(()=>g(t,s));return}if(e&&d()){o.push({text:t,messageIds:s});return}e&&(f=!0),p.admit(async h=>{const u=c();if(e&&u.isStreaming)return o.unshift({text:t,messageIds:s}),h(),Promise.resolve();const m=e?await n.prependDeferred(u):[];return e&&s.length+m.length>0&&u.sessionManager.appendCustomEntry("crtr-turn-input",{message_ids:[...m,...s]}),u.prompt(t,{preflightResult:h,...!e&&u.isStreaming?{streamingBehavior:"steer"}:{}})}).catch(n.onError).finally(()=>{e&&(f=!1,a())})},"start");return{start:g,drain:a,busy:i(()=>n.pendingRebind()!==void 0||r||f||n.pendingDispatches()>0||n.isAgentRunActive()||c().isStreaming,"busy"),holdForKickoff:i(()=>{e&&(r=!0)},"holdForKickoff"),releaseKickoff:i(()=>{r&&(r=!1,a())},"releaseKickoff"),queued:i(()=>o,"queued")}}i(A,"createRunTurnQueue");export{A as createRunTurnQueue};
|
|
@@ -23,5 +23,5 @@ interface PersonaTransitionSession {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
/** Gate each provider request on durable delivery of the current persona delta. */
|
|
26
|
-
export declare function installPersonaTransitionGate(nodeId: string, session: PersonaTransitionSession
|
|
26
|
+
export declare function installPersonaTransitionGate(nodeId: string, session: PersonaTransitionSession): void;
|
|
27
27
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)}a(
|
|
1
|
+
var k=Object.defineProperty;var a=(o,e)=>k(o,"name",{value:e,configurable:!0});import{emitEvent as g}from"../events/emit.js";import{brokerDelivery as b,brokerExtensionState as f,commitBrokerPersonaAck as p}from"./broker/daemon-ops.js";import{buildSubPersonaMenu as m}from"../substrate/delivery/sub-persona-menu.js";import{orchestratorContextNote as v}from"./bearings-render.js";import{formatCard as x}from"../../shared/generated-context.js";function T(o){return[`You are now a ${o.kind.toUpperCase()} ORCHESTRATOR. Your scarce resource is your own context window.`,"Your job is to manage context and delegate \u2014 not to do the goal yourself.","","Your roadmap is your document `roadmap`; it loads at every new session of yours. Author it now with `crtr doc edit roadmap`: state the goal and exit criteria, and set the preview to the goal\u2019s first line, using the approach below.","",v(),"","What promotion changes is how long your documents matter: you now persist across refresh cycles, so the documents you own (`crtr doc write`) carry what this goal needs between your refreshes, and a lesson that should outlive this node gets another owner (`--owner user|repo|profile`).","","Then delegate each unit with `crtr node new --kind <kind>`. When your context fills, run `crtr node yield` to refresh against this roadmap."].join(`
|
|
2
|
+
`)}a(T,"orchestrationGuidance");function C(){return"You are HANDS-ON again \u2014 base mode. Do the work yourself in THIS window and finish it here; stop delegating by default. You no longer drive a roadmap, so `crtr node yield` is not your exit. Spawn a child only for a cleanly separable unit, never as your first move."}a(C,"baseModeGuidance");function P(o,e){if(o.kind===e.kind)return"";const r=m(o.kind),n=m(e.kind);return r===n?"":n===""?`The ${e.kind} kind has no specialist sub-personas available.`:n}a(P,"subPersonaGuidance");function S(o,e,r,n){const t=[];return e.mode!==r.mode&&t.push(r.mode==="orchestrator"?T(o.node):C()),t.push(P(e,r)),t.push(n),t.filter(i=>i!=="").join(`
|
|
3
3
|
|
|
4
|
-
`)}a(
|
|
4
|
+
`)}a(S,"transitionGuidance");function u(o){const e=o.node,r={kind:e.kind,mode:e.mode,lifecycle:e.lifecycle},n=e.persona_ack,t=n===void 0?r:{kind:n.kind??e.kind,mode:n.mode,lifecycle:n.lifecycle};return t.kind===r.kind&&t.mode===r.mode&&t.lifecycle===r.lifecycle?null:{from:t,to:r}}a(u,"personaDriftFromBrokerState");async function M(o){const e=u(o);if(e===null)return!1;if(!(await p(o.node.node_id,e)).applied)throw new Error(`persona baseline acknowledgment was rejected for ${o.node.node_id}`);return!0}a(M,"acknowledgePersonaBaseline");async function D(o,e){const r=o.node.node_id;let n=o,t=u(n);if(t===null)return!1;let i=t.from;for(;;){const s={kind:n.node.kind,mode:n.node.mode,lifecycle:n.node.lifecycle};if(i.kind!==s.kind||i.mode!==s.mode||i.lifecycle!==s.lifecycle){const l=await b(r,{activity:"persona"}),c=S(n,i,s,l.content);c!==""&&await e(x("persona-transition",{},c)),i=s}if(t=u(n),t===null||(await p(r,t)).applied)return!0;n=await f(r)}}a(D,"deliverPendingPersonaTransition");function B(o,e){const{agent:r}=e,n=r.transformContext;r.transformContext=async(t,i)=>{const s=n===void 0?t:await n(t,i);try{const d=await f(o);return await D(d,l=>{const c={nodeId:o},h={role:"custom",customType:"crtr-persona-transition",content:l,display:!0,details:c,timestamp:Date.now()};e.sessionManager.appendCustomMessageEntry("crtr-persona-transition",l,!0,c);const w=r.state.messages;for(const y of new Set([w,t,s]))y.push(h)}),s}catch(d){throw g({event:"broker.daemon.operation.failed",level:"error",node_id:o,error:d,fields:{operation:"persona_transition"}}),d}}}a(B,"installPersonaTransitionGate");export{M as acknowledgePersonaBaseline,D as deliverPendingPersonaTransition,B as installPersonaTransitionGate,u as personaDriftFromBrokerState};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var Pe=Object.defineProperty;var n=(t,o)=>Pe(t,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Oe,envModelIntent as Ie,envNodeCwd as De,envNodeId as Ne,envProfileId as Fe,envScopes as Le,isSandboxedNode as $e,scopeAllowed as Be}from"../../shared/env.js";import{createServer as Ue}from"node:net";import{existsSync as ye,readFileSync as Ge,unlinkSync as be}from"node:fs";import{join as Te}from"node:path";import{randomUUID as x}from"node:crypto";import{mark as Ke}from"../timing.js";import{SUBMIT_RESULT_TOOL as je}from"./structured-output.js";import{installSessionManagerStorePatch as We}from"../conversation-store/index.js";import{getAgentDir as Y,ModelRegistry as qe,ModelRuntime as Ve}from"@earendil-works/pi-coding-agent";import{nodeRunDir as Xe,viewSocketPath as He}from"../canvas/paths.js";import{bindBrokerEventSource as Ye}from"../events/source.js";import{emitEvent as T,flushBrokerLog as ze}from"../events/emit.js";import{operationIdContext as Je}from"../events/operation-id.js";import{findMissingPackagePaths as Qe}from"./package-health.js";import{installBrokerConfigSnapshot as Ze}from"../config.js";import{FRONT_DOOR_ENV as en}from"./front-door.js";import{CANVAS_EXTENSIONS as re,piInvocationToSdkConfig as nn}from"./launch.js";import{assertEngineVersion as tn,loadBrokerEngine as rn}from"./broker-sdk.js";import{initCrtrTheme as on}from"./crtr-theme.js";import{resolveBundledPiPackageDir as sn}from"./pi-cli.js";import{captureSessionChatCapabilities as an}from"./command-surface.js";import{InMemoryCredentialStore as dn}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as ln}from"./broker/model-adapter.js";import{mutateBrokerFault as z,recordBrokerTurn as ke}from"./broker/daemon-ops.js";import{modelRequestFromConfig as cn,expandModelCandidates as mn,parseModelSpec as un,unregisteredConcreteModel as fn}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as pn}from"./stream-watchdog.js";import{probeOnline as gn}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as vn,cycleAwareMessages as hn,endedByAbort as Sn}from"./session-cycles.js";import{turnErrorOf as _n}from"../llm/refusal.js";import{projectTranscript as wn}from"./session-visibility.js";import{currentTurnVisibility as yn}from"./turn-visibility.js";import{isUnknownModel as oe}from"./model-selection.js";import{BrokerClientRegistry as bn}from"./broker/client-registry.js";import{ToolGroupTracker as Tn}from"./broker/tool-groups.js";import{TurnReplyTracker as kn}from"./broker/turn-replies.js";import{onNodeNamed as En}from"./broker/node-named.js";import{FaultRetry as Rn,willDaemonRetry as Mn}from"./broker/fault-retry.js";import{RunTurnEnds as xn}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Cn}from"./broker/turn-admission.js";import{BROKER_IDLE_TURN_START as An,BROKER_RUN_TURN_BUSY as Pn}from"./broker/held-deferred-inbox.js";import{prependRunDeferredMail as On,settleRunDeferredMail as In}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Dn}from"./broker/run-turn-queue.js";import{EventProjection as Nn}from"./broker/event-projection.js";import{createFrameDispatchContext as Fn,handleFrame as Ln}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as $n,installAdvertisedCommandInvocationContract as Bn}from"./advertised-command-invocation.js";import{RebindDriver as Un}from"./broker/rebind.js";import{beginRuntimeTeardown as Gn}from"./broker/extension-abort.js";import{receiveNodeToken as Kn}from"./broker/node-token.js";import{serveCliRelay as jn}from"./broker/cli-relay.js";import{decodeKickoffOrigin as Wn,KICKOFF_ORIGIN_ENV as qn}from"./stamp/protocol.js";import{announceMessageOrigin as Vn}from"./stamp/channel.js";import{brokerExtensionState as Xn,commitBrokerModel as Hn}from"./broker/daemon-ops.js";import{composerNames as Yn}from"./broker/frame-memory-refs.js";import{FrameOverflowError as zn,normalizeSnapshotTail as Jn}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as ur,REVIEW_BOUNDARY_NAVIGATION_CODE as fr}from"./broker/frame-replies.js";function se(t){return new qe(t.modelRuntime)}n(se,"registryOf");function B(t,o){if(t==null||oe(t))return null;const i=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${t.provider}/${t.id}${i}`}n(B,"formatModelSpec");function Qn(t,o){const i=B(t,void 0);return i===null?null:`${i}:${o===void 0||o===""?"off":o}`}n(Qn,"formatExactModelSpec");const Zn=12e4;let J=null;import{brokerSignalClient as Q}from"./broker/signal-stream.js";function et(){Q().stop();const t=J;if(J=null,t!==null)try{t.dispose()}catch{}}n(et,"disposeActiveSession");function nt(t,o){const i=Be(o,"crtr:act")?void 0:["bash"],m=t!==void 0&&t.length>0?[...new Set([...t,je])]:t===void 0?void 0:[...t];return{...m!==void 0?{tools:m}:{},...i!==void 0?{excludeTools:i}:{}}}n(nt,"brokerToolOptions");async function lr(t,o=process.hrtime.bigint(),i=new Date().toISOString()){Ye(t);const m=await Kn(),s=await jn(t,m);process.env.CRTR_API_SOCKET=s.path,Je.fresh(()=>{T({level:"info",event:"broker.startup.cli_entry",ts:i,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),T({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let l=null;const d=n((e,r=null)=>{a.has(e)||(a.add(e),Ke(e,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),T({level:"info",event:e,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:l,model:r}}))},"emitStartupMilestone");process.env[en]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,We(t);const p=await rn();tn(p.VERSION),l=p.VERSION;const _=Xe(t),E=Te(_,"broker-launch.json"),w=JSON.parse(Ge(E,"utf8"));if($e()){if(!w.configSnapshot)throw new Error("broker launch is missing its config snapshot");Ze(w.configSnapshot)}const u=nn(w);u.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await Yn(t);let b,C;const V=n(e=>{b!==void 0?b(e):C??=e},"onSignal");process.on("SIGTERM",()=>V("SIGTERM")),process.on("SIGINT",()=>V("SIGINT"));let{session:U,services:A,resuming:ae,runtime:G}=await st(p,u);d("broker.startup.session_built");const R=(await Xn(t)).node.review_binding?.review_id,k=Oe();J=U;const D=gn;try{process.env.PI_PACKAGE_DIR=sn(),on(A.settingsManager.getTheme(),Y(),!1)}catch(e){T({level:"error",event:"broker.theme.initialization_failed",error:e})}try{for(const e of Qe(Y()))T({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:e.source,resolved_path:e.resolved}})}catch{}const K=He(t),g=new bn(t),X=new Map,O=new Tn(t,e=>g.broadcast(e)),j=new kn(t,e=>g.broadcast(e));En(e=>g.broadcast({type:"node_named",...e}));let N=!1,de=!1,H,le,f,W;const Z=new xn;let F,ce=n(()=>{},"notifyTurnAccepted"),me=n(()=>{},"resetFrameState");const ee=Cn();let ue=n(()=>0,"pendingPromptDispatches"),fe;const L=Dn({runNode:k,session:n(()=>f.session(),"session"),isReplacing:n(()=>f.isReplacing(),"isReplacing"),isAgentRunActive:n(()=>f.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:n(()=>ue(),"pendingDispatches"),turnAdmission:ee,prependDeferred:n(e=>On(t,e),"prependDeferred"),onError:n(e=>T({level:"error",event:"broker.inbox.idle_prompt_failed",error:e}),"onError")}),pe=L.drain;u.firstPrompt!==void 0&&u.firstPrompt!==""&&L.holdForKickoff(),globalThis[An]=L.start,globalThis[Pn]=L.busy,f=new Un({nodeId:t,cfg:u,session:U,services:A,runtime:G,registry:g,toolGroups:O,turnReplies:j,transcriptMessages:n(e=>ie(e,R)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:n(()=>le,"uiContext"),faultRetry:n(()=>W,"faultRetry"),projection:n(()=>F,"projection"),setActiveSession:n(e=>{if(J=e,fe?.(),k){let r="stop",c,v=!1;fe=e.subscribe(h=>{if(h.type==="agent_start"&&(r="stop",c=void 0,v=!1,Z.started()),h.type==="agent_end"){const S=[...h.messages??[]].reverse().find($=>$.role==="assistant");S&&(r=S.stopReason,c=Sn(S)?void 0:_n(S),v=S.role==="assistant"&&Mn(S,e.model?.contextWindow))}h.type==="agent_settled"&&(Z.settled(e.sessionManager,{stop_reason:r,...c?{error:c}:{}},v),In(t,e).catch(S=>{T({level:"error",event:"broker.run_deferred_mail.settle_failed",error:S})}),queueMicrotask(()=>{f.session()===e&&pe()}))})}},"setActiveSession"),disposeAndExit:n((e,r)=>q(e,r),"disposeAndExit"),onSessionRebind:n(()=>{me()},"onSessionRebind"),onReplacementIdle:n(()=>{k&&pe()},"onReplacementIdle"),reWelcomeAll:n(()=>ne(),"reWelcomeAll")});const ge=n(async(e,r=!1)=>{const c=f.session(),v=B(c.model,c.thinkingLevel);if(v===null)return null;const h=await Hn(t,{spec:v,...e!==void 0?{intent:e}:{},userSelected:r});return r&&(u.model=h.modelOverride,e!==void 0?(process.env.CRTR_MODEL_INTENT=`${e.family}/${e.strength}`,delete process.env.CRTR_MODEL_EXACT,u.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",u.modelExact=!0)),h.modelOverride},"persistModelChoice"),ve=n(async(e=!0,r,c=!1)=>{const v=f.session(),h=B(v.model,v.thinkingLevel),S=e?await ge(r,c):h;g.broadcast({type:"model_changed",model:oe(v.model)?void 0:v.model,spec:S})},"broadcastModelChanged");W=new Rn({nodeId:t,cfg:u,retryProbe:D,currentSession:n(()=>f.session(),"currentSession"),currentServices:n(()=>f.services(),"currentServices"),installedGeneration:n(()=>f.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:B,broadcastModelChanged:ve,turnAdmission:ee,reWelcomeAll:n(()=>ne(),"reWelcomeAll"),...k?{turnEnds:Z}:{}});const he=n(()=>{W.rearmIfStranded().catch(e=>{T({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${e instanceof Error?e.message:String(e)}`}})})},"rearmStrandedRetry");Q().subscribe("resync",he),Q().subscribe("fault-retry",he),F=new Nn({registry:g,faultRetry:W,installedGeneration:n(()=>f.installedGeneration(),"installedGeneration"),currentSession:n(()=>f.session(),"currentSession"),notifyTurnAccepted:n(()=>ce(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:B});const Re=n(e=>{const r=f.session(),c=ie(r,R),v=Jn(e.snapshotTail),h=c===void 0||v===void 0?c:c.slice(-v),S=h?.map(({message:I})=>I)??r.sessionManager.buildSessionContext().messages,$=O.summaries(),we=h!==void 0&&v!==void 0?tt(S):void 0,Ae=we===void 0?$:Object.fromEntries(Object.entries($).filter(([I])=>we.has(I)));return{messages:S,...h===void 0?{}:{messageIds:h.map(({id:I})=>I)},messageVisibility:h?.map(({visibility:I})=>I)??S.map(()=>"visible"),turnVisibility:yn(),stats:r.getSessionStats(),state:{model:oe(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{...g.displaySnapshot()},toolGroupSummaries:Ae,turnReplies:j.snapshot(),workingActivity:F.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),Se=n(e=>{const r=e.role==="controller"?X.values().next().value:void 0;g.sendFrame(e,{type:"welcome",snapshot:Re(e),role:e.role,pending_dialog:r!==void 0?r.request:null,agentDir:Y()},!0)},"sendWelcome"),Me=n(e=>{const r=[...X.values()];for(let c=1;c<r.length;c++)g.sendFrame(e,r[c].request)},"replayExtraPendingDialogsTo"),ne=n(()=>{try{const e=f.session();j.seed(ie(e,R)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages)}catch(e){T({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply reseed failed: ${String(e)}`}})}g.forEachHelloed(Se)},"reWelcomeAll"),_e=n(async e=>{if(!N){N=!0,Q().stop(),O.persistPendingSummary(),F.dispose(),et();try{H?.close()}catch{}s.close(),g.dispose();try{ye(K)&&be(K)}catch{}g.clearAttachState(),await ze(),process.exit(e)}},"completeExit"),q=n((e,r=0)=>{if(N)return;const c=e==="shutdown-hook"||e==="shutdown-after-settle";if(c&&O.finishOpenToolGroup(!0),c&&(O.hasSummaryTasks()||j.hasTasks())){if(de)return;de=!0,Promise.allSettled([O.waitForSummaryTasks(),j.waitForTasks()]).finally(()=>_e(r));return}_e(r)},"disposeAndExit");le=it({writable:n(()=>g.writableClients(),"writable"),forward:n((e,r)=>g.sendFrame(e,r),"forward"),pending:X,broadcast:n(e=>g.broadcastUi(e),"broadcast"),onKnownStreamWait:n(e=>F.knownStreamWait(e),"onKnownStreamWait")}),f.setRebindSession(),await f.enqueueRebind(U,A),d("broker.startup.extensions_bound");const M=Fn({nodeId:t,registry:g,toolGroups:O,projection:F,rebind:f,boundaryReviewId:R,pendingDialogs:X,sendWelcome:Se,replayExtraPendingDialogsTo:Me,reWelcomeAll:ne,disposeAndExit:q,persistModelChoice:ge,broadcastModelChanged:ve,registryOf:se,formatModelSpec:B,formatExactModelSpec:Qn,turnAdmission:ee,memoryInventory:y,runNode:k,onKickoffAdmitted:L.releaseKickoff});ce=M.notifyTurnAccepted,me=M.resetForSession,ue=M.pendingPromptDispatches;const xe=2500;let te=!1;const Ce=n(async e=>{if(N||te)return;if(te=!0,f.isAgentRunActive()||f.session().isStreaming||M.pendingPromptDispatches()>0){const c=Date.now()+xe;for(;M.pendingPromptDispatches()>0&&!f.session().isStreaming&&Date.now()<c;)await new Promise(v=>setTimeout(v,25));if(f.session().isStreaming){const v=c-Date.now();if(v>0){let h;try{Gn(),await Promise.race([f.session().abort().then(()=>!0,()=>!1),new Promise($=>{h=setTimeout(()=>$(!1),v)})])&&await ke(t,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(M.pendingPromptDispatches()>0||f.isAgentRunActive())&&await ke(t,{event:"interrupted"})}q(e)},"abortAndExit");if(b=n(e=>{Ce(e)},"signalTeardown"),C!==void 0){b(C);return}try{ye(K)&&be(K)}catch{}H=Ue(e=>{const r=g.create(e);e.on("data",v=>{let h;try{h=r.decoder.push(v)}catch(S){S instanceof zn?(g.sendFrame(r,{type:"error",code:"frame_overflow",message:S.message}),g.dropClient(r,`frame overflow: ${S.message}`)):g.dropClient(r,`decoder error: ${String(S)}`);return}for(const S of h)try{Ln(M,r,S)}catch{}});const c=n(()=>{g.removeClient(r)},"drop");e.on("close",c),e.on("error",()=>{})}),H.on("error",e=>{N||(T({level:"error",event:"broker.socket.failed",error:e}),q("socket-error",1))}),H.listen(K,async()=>{Promise.all([z(t,{op:"clear",link:"viewer\u2194broker"}),z(t,{op:"clear",link:"relay\u2194broker"})]).catch(r=>T({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let e;try{e=await W.recoverOnStartup()}catch(r){T({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"recovery_startup"}}),q("recovery-startup-failed",1);return}if(!(N||te))if(e!=="retry-armed"&&u.firstPrompt!==void 0&&u.firstPrompt!==""){const r=Wn(process.env[qn]);r!==null&&Vn(u.firstPrompt,r);const c=process.env.CRTR_KICKOFF_MESSAGE_IDS;M.kickoff(u.firstPrompt,c?JSON.parse(c):[])}else L.releaseKickoff()}),g.persistAttachState()}n(lr,"runBroker");function tt(t){const o=new Set;for(const i of t)if(!(i.role!=="assistant"||!Array.isArray(i.content)))for(const m of i.content)m!==null&&typeof m=="object"&&m.type==="toolCall"&&typeof m.id=="string"&&o.add(m.id);return o}n(tt,"toolCallIds");function ie(t,o){const i=t.sessionManager,m=hn(i);return m!==void 0&&$n(m.map(({message:s})=>s)),m===void 0?void 0:wn(m,{boundaryReviewId:o,sessionEntries:i.getEntries?.()})}n(ie,"snapshotMessages");function Ee(){const t=Ne();if(t===void 0||t==="")throw new Error("broker launch is missing CRTR_NODE_ID");return t}n(Ee,"currentBrokerNodeId");async function rt(t,o){const i=cn(o.model,Ie(),o.modelExact===!0);if(i===void 0)return;const m=se(t),s={cwd:De()??o.cwd,profileId:Fe()},a=fn(i,m,s);if(a!==void 0)throw await z(Ee(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const l=mn(i,s.cwd,s.profileId),d=un(i.spec);for(const p of l){const _=m.find(p.providerId,p.modelId);if(_===void 0)continue;const w=d?.providerId===p.providerId&&d.modelId===p.modelId?d.thinkingLevel??(p.thinkingLevel===void 0?void 0:"off"):p.thinkingLevel;return{model:_,thinkingLevel:w}}if(o.modelExact===!0){const p=l.map(_=>`'${_.providerId}/${_.modelId}' unregistered`).join("; ");throw await z(Ee(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${p})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}T({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:l.map(p=>({provider:p.providerId,model:p.modelId,reason:"unregistered"})).slice(0,16)}})}n(rt,"resolveLaunchModel");function ot(t){let o=!0;return{runtime:new Proxy(t,{get(m,s,a){return o&&s==="getAvailableSnapshot"?()=>[]:o&&s==="getAvailable"?async()=>[]:o&&s==="getModel"?()=>{}:Reflect.get(m,s,a)}}),reveal:n(()=>{o=!1},"reveal")}}n(ot,"modelLessRegistry");async function st(t,o){const i=Y(),m=n(async w=>{const u=await Ve.create({credentials:new dn,modelsPath:Te(w.agentDir,"models.json")});ln(u);const y=await t.createAgentSessionServices({cwd:w.cwd,agentDir:w.agentDir,modelRuntime:u,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:n(P=>({...P,extensions:P.extensions.filter(R=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(R.path))}),"extensionsOverride")}}),b=y.resourceLoader.getExtensions();if(o.extensionPaths.some(P=>re.includes(P))){const P=new Set(b.extensions.map(k=>k.path)),R=re.filter(k=>!P.has(k));if(R.length>0){const k=b.errors.filter(D=>re.includes(D.path)).map(D=>`${D.path}: ${D.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${R.join(", ")}${k===""?"":` (${k})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const C=await rt(y,o),V=C?.model,U=C?.thinkingLevel,A=C===void 0?ot(y.modelRuntime):void 0,ae=A!==void 0?{...y,modelRuntime:A.runtime}:y,G=await t.createAgentSessionFromServices({services:ae,sessionManager:w.sessionManager,model:V,thinkingLevel:U,...nt(o.tools,Le()),sessionStartEvent:w.sessionStartEvent});return Bn(G.session),an(G.session),A?.reveal(),{...G,services:y}},"buildForManager"),s=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(s===void 0||s==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const l=!a&&s!==void 0&&s!=="",d=l&&o.newCycle===!0,p=l&&!d;let _;if(a)_=t.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(p||d){if(_=t.SessionManager.open(s),d){const w=_.getLeafId();_.resetLeaf(),_.appendCustomEntry(vn,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:w})}}else _=t.SessionManager.create(o.cwd);if(t.createAgentSessionRuntime!==void 0){const w=n(async y=>{const b=await m({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...b,diagnostics:b.services.diagnostics??[]}},"factory"),u=await t.createAgentSessionRuntime(w,{cwd:o.cwd,agentDir:i,sessionManager:_});return{session:u.session,services:u.services,resuming:p,runtime:u}}const E=await m({cwd:o.cwd,agentDir:i,sessionManager:_});return{session:E.session,services:E.services,resuming:p,runtime:void 0}}n(st,"buildBrokerSession");function it(t){const o=n((s,a,l,d)=>{if(d?.signal?.aborted)return Promise.resolve(s);const p=t.writable();return p.length===0?Promise.resolve(s):new Promise(_=>{let E;const w=n(()=>{E!==void 0&&clearTimeout(E),d?.signal?.removeEventListener("abort",u),t.pending.delete(a.id)},"cleanup"),u=n(()=>{w(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),_(s)},"onAbort");d?.signal?.addEventListener("abort",u,{once:!0});const y=d?.timeout!==void 0?d.timeout:Zn;E=setTimeout(()=>{w(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),_(s)},y),typeof E.unref=="function"&&E.unref(),t.pending.set(a.id,{request:a,resolve:n(b=>{w(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),_(l(b))},"resolve")});for(const b of p)t.forward(b,a)})},"dialogPromise"),i=n(()=>{},"noop");return{[pn]:t.onKnownStreamWait??(s=>()=>{}),get theme(){const s=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(s==null)throw new Error("Theme not initialized. Call initTheme() first.");return s},select:n((s,a,l)=>o(void 0,{type:"extension_ui_request",id:x(),method:"select",title:s,options:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"select"),confirm:n((s,a,l)=>o(!1,{type:"extension_ui_request",id:x(),method:"confirm",title:s,message:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,l),"confirm"),input:n((s,a,l)=>o(void 0,{type:"extension_ui_request",id:x(),method:"input",title:s,placeholder:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"input"),editor:n((s,a)=>o(void 0,{type:"extension_ui_request",id:x(),method:"editor",title:s,prefill:a},l=>"cancelled"in l&&l.cancelled?void 0:"value"in l?l.value:void 0),"editor"),setStatus:n((s,a)=>t.broadcast({type:"extension_ui_request",id:x(),method:"setStatus",statusKey:s,statusText:a}),"setStatus"),setWidget:n((s,a,l)=>{typeof a!="function"&&t.broadcast({type:"extension_ui_request",id:x(),method:"setWidget",widgetKey:s,widgetLines:a,widgetPlacement:l?.placement})},"setWidget"),setTitle:n(s=>t.broadcast({type:"extension_ui_request",id:x(),method:"setTitle",title:s}),"setTitle"),notify:n((s,a)=>{const l=a==="warn"?"warning":a;t.broadcast({type:"extension_ui_request",id:x(),method:"notify",message:s,notifyType:l})},"notify"),onTerminalInput:n(()=>i,"onTerminalInput"),setWorkingMessage:i,setWorkingVisible:i,setWorkingIndicator:i,setHiddenThinkingLabel:i,setFooter:i,setHeader:i,custom:n(()=>Promise.resolve(void 0),"custom"),pasteToEditor:i,setEditorText:i,getEditorText:n(()=>"","getEditorText"),addAutocompleteProvider:i,setEditorComponent:i,getEditorComponent:n(()=>{},"getEditorComponent"),getAllThemes:n(()=>[],"getAllThemes"),getTheme:n(()=>{},"getTheme"),setTheme:i,getToolsExpanded:n(()=>!1,"getToolsExpanded"),setToolsExpanded:i}}n(it,"makeBrokerUiContext");export{fr as REVIEW_BOUNDARY_NAVIGATION_CODE,ur as ReviewBoundaryNavigationError,nt as brokerToolOptions,st as buildBrokerSession,et as disposeActiveSession,it as makeBrokerUiContext,lr as runBroker,ie as snapshotMessages};
|
|
1
|
+
var Pe=Object.defineProperty;var n=(t,o)=>Pe(t,"name",{value:o,configurable:!0});import{envInboxBetweenTurns as Oe,envModelIntent as Ie,envNodeCwd as De,envNodeId as Ne,envProfileId as Fe,envScopes as Le,isSandboxedNode as $e,scopeAllowed as Be}from"../../shared/env.js";import{createServer as Ue}from"node:net";import{existsSync as ye,readFileSync as Ge,unlinkSync as be}from"node:fs";import{join as Te}from"node:path";import{randomUUID as x}from"node:crypto";import{mark as Ke}from"../timing.js";import{SUBMIT_RESULT_TOOL as je}from"./structured-output.js";import{installSessionManagerStorePatch as We}from"../conversation-store/index.js";import{getAgentDir as Y,ModelRegistry as qe,ModelRuntime as Ve}from"@earendil-works/pi-coding-agent";import{nodeRunDir as Xe,viewSocketPath as He}from"../canvas/paths.js";import{bindBrokerEventSource as Ye}from"../events/source.js";import{emitEvent as T,flushBrokerLog as ze}from"../events/emit.js";import{operationIdContext as Je}from"../events/operation-id.js";import{findMissingPackagePaths as Qe}from"./package-health.js";import{installBrokerConfigSnapshot as Ze}from"../config.js";import{FRONT_DOOR_ENV as en}from"./front-door.js";import{CANVAS_EXTENSIONS as re,piInvocationToSdkConfig as nn}from"./launch.js";import{assertEngineVersion as tn,loadBrokerEngine as rn}from"./broker-sdk.js";import{initCrtrTheme as on}from"./crtr-theme.js";import{resolveBundledPiPackageDir as sn}from"./pi-cli.js";import{captureSessionChatCapabilities as an}from"./command-surface.js";import{InMemoryCredentialStore as dn}from"@earendil-works/pi-ai";import{configureBrokerModelRuntime as ln}from"./broker/model-adapter.js";import{mutateBrokerFault as z,recordBrokerTurn as Re}from"./broker/daemon-ops.js";import{modelRequestFromConfig as cn,expandModelCandidates as mn,parseModelSpec as un,unregisteredConcreteModel as fn}from"../model-routes.js";import{KNOWN_STREAM_WAIT_UI as pn}from"./stream-watchdog.js";import{probeOnline as gn}from"./connectivity.js";import{CRTR_CYCLE_CUSTOM_TYPE as vn,cycleAwareMessages as hn,endedByAbort as Sn}from"./session-cycles.js";import{turnErrorOf as _n}from"../llm/refusal.js";import{projectTranscript as wn}from"./session-visibility.js";import{currentTurnVisibility as yn}from"./turn-visibility.js";import{isUnknownModel as oe}from"./model-selection.js";import{BrokerClientRegistry as bn}from"./broker/client-registry.js";import{ToolGroupTracker as Tn}from"./broker/tool-groups.js";import{TurnReplyTracker as Rn}from"./broker/turn-replies.js";import{onNodeNamed as kn}from"./broker/node-named.js";import{FaultRetry as En,willDaemonRetry as Mn}from"./broker/fault-retry.js";import{RunTurnEnds as xn}from"./broker/run-turn-end.js";import{createTurnAdmissionGate as Cn}from"./broker/turn-admission.js";import{BROKER_IDLE_TURN_START as An,BROKER_RUN_TURN_BUSY as Pn}from"./broker/held-deferred-inbox.js";import{prependRunDeferredMail as On,settleRunDeferredMail as In}from"./broker/run-deferred-mail.js";import{createRunTurnQueue as Dn}from"./broker/run-turn-queue.js";import{EventProjection as Nn}from"./broker/event-projection.js";import{createFrameDispatchContext as Fn,handleFrame as Ln}from"./broker/frame-dispatch.js";import{hydratePersistedAdvertisedCommandMessages as $n,installAdvertisedCommandInvocationContract as Bn}from"./advertised-command-invocation.js";import{RebindDriver as Un}from"./broker/rebind.js";import{beginRuntimeTeardown as Gn}from"./broker/extension-abort.js";import{receiveNodeToken as Kn}from"./broker/node-token.js";import{serveCliRelay as jn}from"./broker/cli-relay.js";import{decodeKickoffOrigin as Wn,KICKOFF_ORIGIN_ENV as qn}from"./stamp/protocol.js";import{announceMessageOrigin as Vn}from"./stamp/channel.js";import{brokerExtensionState as Xn,commitBrokerModel as Hn}from"./broker/daemon-ops.js";import{composerNames as Yn}from"./broker/frame-memory-refs.js";import{FrameOverflowError as zn,normalizeSnapshotTail as Jn}from"./broker-protocol.js";import{ReviewBoundaryNavigationError as ur,REVIEW_BOUNDARY_NAVIGATION_CODE as fr}from"./broker/frame-replies.js";function se(t){return new qe(t.modelRuntime)}n(se,"registryOf");function B(t,o){if(t==null||oe(t))return null;const i=o!==void 0&&o!==""&&o!=="off"?`:${o}`:"";return`${t.provider}/${t.id}${i}`}n(B,"formatModelSpec");function Qn(t,o){const i=B(t,void 0);return i===null?null:`${i}:${o===void 0||o===""?"off":o}`}n(Qn,"formatExactModelSpec");const Zn=12e4;let J=null;import{brokerSignalClient as Q}from"./broker/signal-stream.js";function et(){Q().stop();const t=J;if(J=null,t!==null)try{t.dispose()}catch{}}n(et,"disposeActiveSession");function nt(t,o){const i=Be(o,"crtr:act")?void 0:["bash"],m=t!==void 0&&t.length>0?[...new Set([...t,je])]:t===void 0?void 0:[...t];return{...m!==void 0?{tools:m}:{},...i!==void 0?{excludeTools:i}:{}}}n(nt,"brokerToolOptions");async function lr(t,o=process.hrtime.bigint(),i=new Date().toISOString()){Ye(t);const m=await Kn(),s=await jn(t,m);process.env.CRTR_API_SOCKET=s.path,Je.fresh(()=>{T({level:"info",event:"broker.startup.cli_entry",ts:i,duration_ms:0,fields:{runtime_version:process.version,engine_version:null,model:null}}),T({level:"info",event:"broker.startup.module_loaded",duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:null,model:null}})});const a=new Set;let l=null;const d=n((e,r=null)=>{a.has(e)||(a.add(e),Ke(e,{duration_ms:Number(process.hrtime.bigint()-o)/1e6}),T({level:"info",event:e,duration_ms:Number(process.hrtime.bigint()-o)/1e6,fields:{runtime_version:process.version,engine_version:l,model:r}}))},"emitStartupMilestone");process.env[en]="1",process.env.CRTR_BROKER_PID=String(process.pid),delete process.env.TMUX_PANE,delete process.env.TMUX,We(t);const p=await rn();tn(p.VERSION),l=p.VERSION;const _=Xe(t),k=Te(_,"broker-launch.json"),w=JSON.parse(Ge(k,"utf8"));if($e()){if(!w.configSnapshot)throw new Error("broker launch is missing its config snapshot");Ze(w.configSnapshot)}const f=nn(w);f.modelExact===!0?process.env.CRTR_MODEL_EXACT="1":delete process.env.CRTR_MODEL_EXACT;const y=await Yn(t);let b,C;const V=n(e=>{b!==void 0?b(e):C??=e},"onSignal");process.on("SIGTERM",()=>V("SIGTERM")),process.on("SIGINT",()=>V("SIGINT"));let{session:U,services:A,resuming:ae,runtime:G}=await st(p,f);d("broker.startup.session_built");const E=(await Xn(t)).node.review_binding?.review_id,R=Oe();J=U;const D=gn;try{process.env.PI_PACKAGE_DIR=sn(),on(A.settingsManager.getTheme(),Y(),!1)}catch(e){T({level:"error",event:"broker.theme.initialization_failed",error:e})}try{for(const e of Qe(Y()))T({level:"warn",event:"broker.startup.warning",fields:{stage:"package_health",source:e.source,resolved_path:e.resolved}})}catch{}const K=He(t),g=new bn(t),X=new Map,O=new Tn(t,e=>g.broadcast(e)),j=new Rn(t,e=>g.broadcast(e));kn(e=>g.broadcast({type:"node_named",...e}));let N=!1,de=!1,H,le,u,W;const Z=new xn;let F,ce=n(()=>{},"notifyTurnAccepted"),me=n(()=>{},"resetFrameState");const ee=Cn();let ue=n(()=>0,"pendingPromptDispatches"),fe;const L=Dn({runNode:R,session:n(()=>u.session(),"session"),isReplacing:n(()=>u.isReplacing(),"isReplacing"),pendingRebind:n(()=>u.pendingRebind(),"pendingRebind"),isAgentRunActive:n(()=>u.isAgentRunActive(),"isAgentRunActive"),pendingDispatches:n(()=>ue(),"pendingDispatches"),turnAdmission:ee,prependDeferred:n(e=>On(t,e),"prependDeferred"),onError:n(e=>T({level:"error",event:"broker.inbox.idle_prompt_failed",error:e}),"onError")}),pe=L.drain;f.firstPrompt!==void 0&&f.firstPrompt!==""&&L.holdForKickoff(),globalThis[An]=L.start,globalThis[Pn]=L.busy,u=new Un({nodeId:t,cfg:f,session:U,services:A,runtime:G,registry:g,toolGroups:O,turnReplies:j,transcriptMessages:n(e=>ie(e,E)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages,"transcriptMessages"),uiContext:n(()=>le,"uiContext"),faultRetry:n(()=>W,"faultRetry"),projection:n(()=>F,"projection"),setActiveSession:n(e=>{if(J=e,fe?.(),R){let r="stop",c,v=!1;fe=e.subscribe(h=>{if(h.type==="agent_start"&&(r="stop",c=void 0,v=!1,Z.started()),h.type==="agent_end"){const S=[...h.messages??[]].reverse().find($=>$.role==="assistant");S&&(r=S.stopReason,c=Sn(S)?void 0:_n(S),v=S.role==="assistant"&&Mn(S,e.model?.contextWindow))}h.type==="agent_settled"&&(Z.settled(e.sessionManager,{stop_reason:r,...c?{error:c}:{}},v),In(t,e).catch(S=>{T({level:"error",event:"broker.run_deferred_mail.settle_failed",error:S})}),queueMicrotask(()=>{u.session()===e&&pe()}))})}},"setActiveSession"),disposeAndExit:n((e,r)=>q(e,r),"disposeAndExit"),onSessionRebind:n(()=>{me()},"onSessionRebind"),onReplacementIdle:n(()=>{R&&pe()},"onReplacementIdle"),reWelcomeAll:n(()=>ne(),"reWelcomeAll")});const ge=n(async(e,r=!1)=>{const c=u.session(),v=B(c.model,c.thinkingLevel);if(v===null)return null;const h=await Hn(t,{spec:v,...e!==void 0?{intent:e}:{},userSelected:r});return r&&(f.model=h.modelOverride,e!==void 0?(process.env.CRTR_MODEL_INTENT=`${e.family}/${e.strength}`,delete process.env.CRTR_MODEL_EXACT,f.modelExact=void 0):(delete process.env.CRTR_MODEL_INTENT,process.env.CRTR_MODEL_EXACT="1",f.modelExact=!0)),h.modelOverride},"persistModelChoice"),ve=n(async(e=!0,r,c=!1)=>{const v=u.session(),h=B(v.model,v.thinkingLevel),S=e?await ge(r,c):h;g.broadcast({type:"model_changed",model:oe(v.model)?void 0:v.model,spec:S})},"broadcastModelChanged");W=new En({nodeId:t,cfg:f,retryProbe:D,currentSession:n(()=>u.session(),"currentSession"),currentServices:n(()=>u.services(),"currentServices"),installedGeneration:n(()=>u.installedGeneration(),"installedGeneration"),registryOf:se,formatModelSpec:B,broadcastModelChanged:ve,turnAdmission:ee,reWelcomeAll:n(()=>ne(),"reWelcomeAll"),...R?{turnEnds:Z}:{}});const he=n(()=>{W.rearmIfStranded().catch(e=>{T({level:"warn",event:"broker.runtime.diagnostic",fields:{message:`fault retry re-arm failed: ${e instanceof Error?e.message:String(e)}`}})})},"rearmStrandedRetry");Q().subscribe("resync",he),Q().subscribe("fault-retry",he),F=new Nn({registry:g,faultRetry:W,installedGeneration:n(()=>u.installedGeneration(),"installedGeneration"),currentSession:n(()=>u.session(),"currentSession"),notifyTurnAccepted:n(()=>ce(),"notifyTurnAccepted"),emitStartupMilestone:d,formatModelSpec:B});const Ee=n(e=>{const r=u.session(),c=ie(r,E),v=Jn(e.snapshotTail),h=c===void 0||v===void 0?c:c.slice(-v),S=h?.map(({message:I})=>I)??r.sessionManager.buildSessionContext().messages,$=O.summaries(),we=h!==void 0&&v!==void 0?tt(S):void 0,Ae=we===void 0?$:Object.fromEntries(Object.entries($).filter(([I])=>we.has(I)));return{messages:S,...h===void 0?{}:{messageIds:h.map(({id:I})=>I)},messageVisibility:h?.map(({visibility:I})=>I)??S.map(()=>"visible"),turnVisibility:yn(),stats:r.getSessionStats(),state:{model:oe(r.model)?void 0:r.model,thinkingLevel:r.thinkingLevel,isStreaming:r.isStreaming,isCompacting:r.isCompacting,steeringMode:r.steeringMode,followUpMode:r.followUpMode,sessionFile:r.sessionFile,sessionId:r.sessionId,sessionName:r.sessionName,autoCompactionEnabled:r.autoCompactionEnabled,messageCount:r.messages.length,pendingMessageCount:r.pendingMessageCount},display:{...g.displaySnapshot()},toolGroupSummaries:Ae,turnReplies:j.snapshot(),workingActivity:F.currentWorkingActivity(),queued:{steering:[...r.getSteeringMessages()],followUp:[...r.getFollowUpMessages()]}}},"buildSnapshot"),Se=n(e=>{const r=e.role==="controller"?X.values().next().value:void 0;g.sendFrame(e,{type:"welcome",snapshot:Ee(e),role:e.role,pending_dialog:r!==void 0?r.request:null,agentDir:Y()},!0)},"sendWelcome"),Me=n(e=>{const r=[...X.values()];for(let c=1;c<r.length;c++)g.sendFrame(e,r[c].request)},"replayExtraPendingDialogsTo"),ne=n(()=>{try{const e=u.session();j.seed(ie(e,E)?.map(({message:r})=>r)??e.sessionManager.buildSessionContext().messages)}catch(e){T({level:"debug",event:"broker.runtime.diagnostic",fields:{message:`turn reply reseed failed: ${String(e)}`}})}g.forEachHelloed(Se)},"reWelcomeAll"),_e=n(async e=>{if(!N){N=!0,Q().stop(),O.persistPendingSummary(),F.dispose(),et();try{H?.close()}catch{}s.close(),g.dispose();try{ye(K)&&be(K)}catch{}g.clearAttachState(),await ze(),process.exit(e)}},"completeExit"),q=n((e,r=0)=>{if(N)return;const c=e==="shutdown-hook"||e==="shutdown-after-settle";if(c&&O.finishOpenToolGroup(!0),c&&(O.hasSummaryTasks()||j.hasTasks())){if(de)return;de=!0,Promise.allSettled([O.waitForSummaryTasks(),j.waitForTasks()]).finally(()=>_e(r));return}_e(r)},"disposeAndExit");le=it({writable:n(()=>g.writableClients(),"writable"),forward:n((e,r)=>g.sendFrame(e,r),"forward"),pending:X,broadcast:n(e=>g.broadcastUi(e),"broadcast"),onKnownStreamWait:n(e=>F.knownStreamWait(e),"onKnownStreamWait")}),u.setRebindSession(),await u.enqueueRebind(U,A),d("broker.startup.extensions_bound");const M=Fn({nodeId:t,registry:g,toolGroups:O,projection:F,rebind:u,boundaryReviewId:E,pendingDialogs:X,sendWelcome:Se,replayExtraPendingDialogsTo:Me,reWelcomeAll:ne,disposeAndExit:q,persistModelChoice:ge,broadcastModelChanged:ve,registryOf:se,formatModelSpec:B,formatExactModelSpec:Qn,turnAdmission:ee,memoryInventory:y,runNode:R,onKickoffAdmitted:L.releaseKickoff});ce=M.notifyTurnAccepted,me=M.resetForSession,ue=M.pendingPromptDispatches;const xe=2500;let te=!1;const Ce=n(async e=>{if(N||te)return;if(te=!0,u.isAgentRunActive()||u.session().isStreaming||M.pendingPromptDispatches()>0){const c=Date.now()+xe;for(;M.pendingPromptDispatches()>0&&!u.session().isStreaming&&Date.now()<c;)await new Promise(v=>setTimeout(v,25));if(u.session().isStreaming){const v=c-Date.now();if(v>0){let h;try{Gn(),await Promise.race([u.session().abort().then(()=>!0,()=>!1),new Promise($=>{h=setTimeout(()=>$(!1),v)})])&&await Re(t,{event:"closed",end_reason:"teardown-aborted"})}finally{h!==void 0&&clearTimeout(h)}}}else(M.pendingPromptDispatches()>0||u.isAgentRunActive())&&await Re(t,{event:"interrupted"})}q(e)},"abortAndExit");if(b=n(e=>{Ce(e)},"signalTeardown"),C!==void 0){b(C);return}try{ye(K)&&be(K)}catch{}H=Ue(e=>{const r=g.create(e);e.on("data",v=>{let h;try{h=r.decoder.push(v)}catch(S){S instanceof zn?(g.sendFrame(r,{type:"error",code:"frame_overflow",message:S.message}),g.dropClient(r,`frame overflow: ${S.message}`)):g.dropClient(r,`decoder error: ${String(S)}`);return}for(const S of h)try{Ln(M,r,S)}catch{}});const c=n(()=>{g.removeClient(r)},"drop");e.on("close",c),e.on("error",()=>{})}),H.on("error",e=>{N||(T({level:"error",event:"broker.socket.failed",error:e}),q("socket-error",1))}),H.listen(K,async()=>{Promise.all([z(t,{op:"clear",link:"viewer\u2194broker"}),z(t,{op:"clear",link:"relay\u2194broker"})]).catch(r=>T({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"broker_socket_bound_fault_clear"}}));let e;try{e=await W.recoverOnStartup()}catch(r){T({level:"error",event:"broker.daemon.operation.failed",node_id:t,error:r,fields:{operation:"recovery_startup"}}),q("recovery-startup-failed",1);return}if(!(N||te))if(e!=="retry-armed"&&f.firstPrompt!==void 0&&f.firstPrompt!==""){const r=Wn(process.env[qn]);r!==null&&Vn(f.firstPrompt,r);const c=process.env.CRTR_KICKOFF_MESSAGE_IDS;M.kickoff(f.firstPrompt,c?JSON.parse(c):[])}else L.releaseKickoff()}),g.persistAttachState()}n(lr,"runBroker");function tt(t){const o=new Set;for(const i of t)if(!(i.role!=="assistant"||!Array.isArray(i.content)))for(const m of i.content)m!==null&&typeof m=="object"&&m.type==="toolCall"&&typeof m.id=="string"&&o.add(m.id);return o}n(tt,"toolCallIds");function ie(t,o){const i=t.sessionManager,m=hn(i);return m!==void 0&&$n(m.map(({message:s})=>s)),m===void 0?void 0:wn(m,{boundaryReviewId:o,sessionEntries:i.getEntries?.()})}n(ie,"snapshotMessages");function ke(){const t=Ne();if(t===void 0||t==="")throw new Error("broker launch is missing CRTR_NODE_ID");return t}n(ke,"currentBrokerNodeId");async function rt(t,o){const i=cn(o.model,Ie(),o.modelExact===!0);if(i===void 0)return;const m=se(t),s={cwd:De()??o.cwd,profileId:Fe()},a=fn(i,m,s);if(a!==void 0)throw await z(ke(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`model '${a.request.spec}' is not registered in the serving model registry`}}),new Error(`[broker] FATAL: model '${a.request.spec}' is not registered in the serving model registry`);const l=mn(i,s.cwd,s.profileId),d=un(i.spec);for(const p of l){const _=m.find(p.providerId,p.modelId);if(_===void 0)continue;const w=d?.providerId===p.providerId&&d.modelId===p.modelId?d.thinkingLevel??(p.thinkingLevel===void 0?void 0:"off"):p.thinkingLevel;return{model:_,thinkingLevel:w}}if(o.modelExact===!0){const p=l.map(_=>`'${_.providerId}/${_.modelId}' unregistered`).join("; ");throw await z(ke(),{op:"record",input:{link:"crtr\u2192pi",op:"model resolution at launch",kind:"model-not-found",retry:{disposition:"fatal"},message:`exact-consult model '${o.model}' is unavailable \u2014 refusing to substitute (${p})`}}),new Error(`[broker] FATAL: exact-consult model '${o.model}' is unavailable`)}T({level:"warn",event:"broker.model.none_viable",fields:{rejected_candidates:l.map(p=>({provider:p.providerId,model:p.modelId,reason:"unregistered"})).slice(0,16)}})}n(rt,"resolveLaunchModel");function ot(t){let o=!0;return{runtime:new Proxy(t,{get(m,s,a){return o&&s==="getAvailableSnapshot"?()=>[]:o&&s==="getAvailable"?async()=>[]:o&&s==="getModel"?()=>{}:Reflect.get(m,s,a)}}),reveal:n(()=>{o=!1},"reveal")}}n(ot,"modelLessRegistry");async function st(t,o){const i=Y(),m=n(async w=>{const f=await Ve.create({credentials:new dn,modelsPath:Te(w.agentDir,"models.json")});ln(f);const y=await t.createAgentSessionServices({cwd:w.cwd,agentDir:w.agentDir,modelRuntime:f,resourceLoaderOptions:{additionalExtensionPaths:o.extensionPaths,appendSystemPrompt:o.appendSystemPromptPath!==void 0?[o.appendSystemPromptPath]:void 0,noContextFiles:!0,extensionsOverride:n(P=>({...P,extensions:P.extensions.filter(E=>!/[/\\]provider-rotation\.(?:ts|js)$/.test(E.path))}),"extensionsOverride")}}),b=y.resourceLoader.getExtensions();if(o.extensionPaths.some(P=>re.includes(P))){const P=new Set(b.extensions.map(R=>R.path)),E=re.filter(R=>!P.has(R));if(E.length>0){const R=b.errors.filter(D=>re.includes(D.path)).map(D=>`${D.path}: ${D.error}`).join("; ");throw new Error(`[broker] FATAL: mandatory canvas extensions failed to load: ${E.join(", ")}${R===""?"":` (${R})`}`)}}y.settingsManager.getRetryEnabled=()=>!1;const C=await rt(y,o),V=C?.model,U=C?.thinkingLevel,A=C===void 0?ot(y.modelRuntime):void 0,ae=A!==void 0?{...y,modelRuntime:A.runtime}:y,G=await t.createAgentSessionFromServices({services:ae,sessionManager:w.sessionManager,model:V,thinkingLevel:U,...nt(o.tools,Le()),sessionStartEvent:w.sessionStartEvent});return Bn(G.session),an(G.session),A?.reveal(),{...G,services:y}},"buildForManager"),s=o.resumeSessionPath,a=o.forkFrom!==void 0&&o.forkFrom!=="";if(!a&&(s===void 0||s==="")&&o.resumeSessionId!==void 0&&o.resumeSessionId!=="")throw new Error(`[broker] resume requires a session .jsonl PATH; got only a bare id '${o.resumeSessionId}' (pi_session_file was never captured for this node)`);const l=!a&&s!==void 0&&s!=="",d=l&&o.newCycle===!0,p=l&&!d;let _;if(a)_=t.SessionManager.forkFrom(o.forkFrom,o.cwd);else if(p||d){if(_=t.SessionManager.open(s),d){const w=_.getLeafId();_.resetLeaf(),_.appendCustomEntry(vn,{cycle:Number(process.env.CRTR_CYCLES),fromLeaf:w})}}else _=t.SessionManager.create(o.cwd);if(t.createAgentSessionRuntime!==void 0){const w=n(async y=>{const b=await m({cwd:y.cwd,agentDir:y.agentDir,sessionManager:y.sessionManager,sessionStartEvent:y.sessionStartEvent});return{...b,diagnostics:b.services.diagnostics??[]}},"factory"),f=await t.createAgentSessionRuntime(w,{cwd:o.cwd,agentDir:i,sessionManager:_});return{session:f.session,services:f.services,resuming:p,runtime:f}}const k=await m({cwd:o.cwd,agentDir:i,sessionManager:_});return{session:k.session,services:k.services,resuming:p,runtime:void 0}}n(st,"buildBrokerSession");function it(t){const o=n((s,a,l,d)=>{if(d?.signal?.aborted)return Promise.resolve(s);const p=t.writable();return p.length===0?Promise.resolve(s):new Promise(_=>{let k;const w=n(()=>{k!==void 0&&clearTimeout(k),d?.signal?.removeEventListener("abort",f),t.pending.delete(a.id)},"cleanup"),f=n(()=>{w(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),_(s)},"onAbort");d?.signal?.addEventListener("abort",f,{once:!0});const y=d?.timeout!==void 0?d.timeout:Zn;k=setTimeout(()=>{w(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),_(s)},y),typeof k.unref=="function"&&k.unref(),t.pending.set(a.id,{request:a,resolve:n(b=>{w(),t.broadcast({type:"extension_ui_dismiss",id:a.id}),_(l(b))},"resolve")});for(const b of p)t.forward(b,a)})},"dialogPromise"),i=n(()=>{},"noop");return{[pn]:t.onKnownStreamWait??(s=>()=>{}),get theme(){const s=globalThis[Symbol.for("@earendil-works/pi-coding-agent:theme")];if(s==null)throw new Error("Theme not initialized. Call initTheme() first.");return s},select:n((s,a,l)=>o(void 0,{type:"extension_ui_request",id:x(),method:"select",title:s,options:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"select"),confirm:n((s,a,l)=>o(!1,{type:"extension_ui_request",id:x(),method:"confirm",title:s,message:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?!1:"confirmed"in d?d.confirmed:!1,l),"confirm"),input:n((s,a,l)=>o(void 0,{type:"extension_ui_request",id:x(),method:"input",title:s,placeholder:a,timeout:l?.timeout},d=>"cancelled"in d&&d.cancelled?void 0:"value"in d?d.value:void 0,l),"input"),editor:n((s,a)=>o(void 0,{type:"extension_ui_request",id:x(),method:"editor",title:s,prefill:a},l=>"cancelled"in l&&l.cancelled?void 0:"value"in l?l.value:void 0),"editor"),setStatus:n((s,a)=>t.broadcast({type:"extension_ui_request",id:x(),method:"setStatus",statusKey:s,statusText:a}),"setStatus"),setWidget:n((s,a,l)=>{typeof a!="function"&&t.broadcast({type:"extension_ui_request",id:x(),method:"setWidget",widgetKey:s,widgetLines:a,widgetPlacement:l?.placement})},"setWidget"),setTitle:n(s=>t.broadcast({type:"extension_ui_request",id:x(),method:"setTitle",title:s}),"setTitle"),notify:n((s,a)=>{const l=a==="warn"?"warning":a;t.broadcast({type:"extension_ui_request",id:x(),method:"notify",message:s,notifyType:l})},"notify"),onTerminalInput:n(()=>i,"onTerminalInput"),setWorkingMessage:i,setWorkingVisible:i,setWorkingIndicator:i,setHiddenThinkingLabel:i,setFooter:i,setHeader:i,custom:n(()=>Promise.resolve(void 0),"custom"),pasteToEditor:i,setEditorText:i,getEditorText:n(()=>"","getEditorText"),addAutocompleteProvider:i,setEditorComponent:i,getEditorComponent:n(()=>{},"getEditorComponent"),getAllThemes:n(()=>[],"getAllThemes"),getTheme:n(()=>{},"getTheme"),setTheme:i,getToolsExpanded:n(()=>!1,"getToolsExpanded"),setToolsExpanded:i}}n(it,"makeBrokerUiContext");export{fr as REVIEW_BOUNDARY_NAVIGATION_CODE,ur as ReviewBoundaryNavigationError,nt as brokerToolOptions,st as buildBrokerSession,et as disposeActiveSession,it as makeBrokerUiContext,lr as runBroker,ie as snapshotMessages};
|
|
@@ -4,8 +4,8 @@ export type NoticeEvent = 'notice.crash' | 'notice.deadline' | 'notice.close';
|
|
|
4
4
|
/** Publish a lifecycle notice on `nodeId` to its watchers, inside the caller's write when one
|
|
5
5
|
* is open. The message body carries today's sentence (as `body`, which the inbox card shows)
|
|
6
6
|
* and data; `publish` picks the recipients, their tier and wake from each watch. A node whose
|
|
7
|
-
* object is already gone publishes nothing. */
|
|
8
|
-
export declare function publishNotice(nodeId: string, event: NoticeEvent, label: string, data: Record<string, unknown>, tier?: InboxTier, actor?: ObjectRow | null): void;
|
|
7
|
+
* object is already gone publishes nothing. `onlyWatchers` narrows the recipients to those watchers. */
|
|
8
|
+
export declare function publishNotice(nodeId: string, event: NoticeEvent, label: string, data: Record<string, unknown>, tier?: InboxTier, actor?: ObjectRow | null, onlyWatchers?: readonly string[]): void;
|
|
9
9
|
export interface CloseNodeResult {
|
|
10
10
|
/** The focused node that was closed — the cascade root. */
|
|
11
11
|
root: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var a=(r,o)=>k(r,"name",{value:o,configurable:!0});import{getNode as h,subscriptionsOf as u,subscribersOf as E}from"../canvas/index.js";import{transition as w}from"./lifecycle.js";import{stopNodeSandboxes as $}from"../spaces/stop.js";import{tearDownNode as D,reapIfEmpty as N}from"./placement.js";import{crtrHome as L,jobDir as O}from"../canvas/paths.js";import{contextDir as x,nodeAgentDir as S}from"../canvas/node-agent-paths.js";import{readLiveSession as j}from"../canvas/sessions.js";import{discoverLifecycleHookRegistry as H}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as A}from"../command-hooks/transport/exec-lifecycle.js";import{emitEvent as p}from"../events/emit.js";import{enqueueNodeMail as B}from"../feed/messages.js";import{withCanvasWrite as v}from"../canvas/db.js";import{recordActedOn as C}from"../graph/edges.js";import{publish as R}from"../graph/events.js";import{getById as y,nodeObject as T,ownerForGrantee as Y}from"../graph/objects.js";const q={deferred:3,normal:5,urgent:7,critical:7};function P(r,o,l,s,d="normal",
|
|
1
|
+
var k=Object.defineProperty;var a=(r,o)=>k(r,"name",{value:o,configurable:!0});import{getNode as h,subscriptionsOf as u,subscribersOf as E}from"../canvas/index.js";import{transition as w}from"./lifecycle.js";import{stopNodeSandboxes as $}from"../spaces/stop.js";import{tearDownNode as D,reapIfEmpty as N}from"./placement.js";import{crtrHome as L,jobDir as O}from"../canvas/paths.js";import{contextDir as x,nodeAgentDir as S}from"../canvas/node-agent-paths.js";import{readLiveSession as j}from"../canvas/sessions.js";import{discoverLifecycleHookRegistry as H}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as A}from"../command-hooks/transport/exec-lifecycle.js";import{emitEvent as p}from"../events/emit.js";import{enqueueNodeMail as B}from"../feed/messages.js";import{withCanvasWrite as v}from"../canvas/db.js";import{recordActedOn as C}from"../graph/edges.js";import{publish as R}from"../graph/events.js";import{getById as y,nodeObject as T,ownerForGrantee as Y}from"../graph/objects.js";const q={deferred:3,normal:5,urgent:7,critical:7};function P(r,o,l,s,d="normal",i=null,c){v(e=>{const n=y(e,r);n===null||n.type!=="node"||R(e,{event:o,object:n,actor:i,level:q[d],attrs:{},messageBody:{...s,body:l},...c===void 0?{}:{onlyWatchers:c}})})}a(P,"publishNotice");function z(r){const o=new Set([r]);let l=!0;for(;l;){l=!1;for(const s of[...o])for(const d of u(s)){const i=d.node_id;o.has(i)||E(i).every(c=>o.has(c.node_id))&&(o.add(i),l=!0)}}return o}a(z,"closingSet");function F(r,o){const l=[],s=new Set([r]),d=[r];for(;d.length>0;){const i=d.shift();l.push(i);for(const c of u(i))o.has(c.node_id)&&!s.has(c.node_id)&&(s.add(c.node_id),d.push(c.node_id))}for(const i of o)s.has(i)||l.push(i);return l.reverse()}a(F,"killOrder");function G(r,o){const l=r?"You were CLOSED by the user from the canvas":"You were CANCELED \u2014 an ancestor of yours was closed from the canvas";if(o.length===0)return`${l}. Your pi session is preserved; this resume reopened it.`;const s=o.slice(0,4).map(i=>{const c=h(i);return c!==null?`${c.name} (${i})`:i}),d=o.length>s.length?` +${o.length-s.length} more`:"";return`${l}. ${o.length} child node(s) you subscribe to were canceled with you and are no longer running: ${s.join(", ")}${d}. Resuming will NOT restore them \u2014 re-spawn if you still need that work.`}a(G,"cancellationLabel");function se(r,o={}){if(h(r)===null)throw new Error(`closeNode: unknown node ${r}`);const l=o.rootEvent??"cancel",s=z(r),d=F(r,s),i=[];for(const e of s)for(const n of u(e))!s.has(n.node_id)&&!i.includes(n.node_id)&&i.push(n.node_id);const c=[];for(const e of d)try{const n=h(e);if(n===null)continue;const _=u(e).map(t=>t.node_id).filter(t=>s.has(t));let m;try{const t=H(n.cwd,n.profile_id).plans.get("node:close")??[];if(t.length>0){const f={node:{id:e,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,cwd:n.cwd,nodeDir:S(e),contextDir:x(e),jobDir:O(e)},runtime:{isBirth:!1,canvasHome:L(),profile:n.profile_id??null}};m=a(()=>A(t,f),"afterTeardown")}}catch(t){p({level:"error",event:"node.close_hook.discovery_failed",node_id:e,error:t})}const b=$(e,o.stopReason??"node_closed",{...e===r?{excludePid:o.callerPid}:{},...m?{after:m}:{}});try{o.registerDetached?.(b.then(()=>{}))}catch(t){p({level:"error",event:"node.close_hook.detached_registration_failed",node_id:e,error:t})}if(v(t=>{const f=y(t,e);if(f===null||f.type!=="node")return;const g=o.closer!==void 0?T(t,o.closer):Y(t,"user:local");C(t,g,f),P(e,"notice.close",`Child closed \u2014 ${n.name} (${e}) was closed from the canvas and is no longer running.`,{reason:"child-closed",child:e},"normal",g)}),o.preserveEmpty||n.run_id!==null&&n.pi_pid!==null&&j(e)?.sessionId!=null||!N(e,void 0,!1)){const t=n.final_report!==null&&n.final_report!==void 0;e===r&&l==="finish"||t?(n.status==="active"||n.status==="idle")&&w(e,"finish"):w(e,"cancel",{reason:"closed"}),D(e),B(e,{kind:"message",label:G(e===r,_),bodyJson:{reason:"user-close",cascade_root:r,canceled_children:_},urgency:"normal",wake:1})}c.push(e)}catch(n){p({level:"error",event:"node.close.failed",node_id:e,error:n})}return{root:r,closed:c,spared:i}}a(se,"closeNode");export{se as closeNode,z as closingSet,P as publishNotice};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)){const i=a.trim();if(i==="")continue;const n=i.split(/\s+/);if(n.length<3)continue;const o=Number(n[0]),r=Number(n[1]),l=Number(n[2]);if(!Number.isFinite(o)||!Number.isFinite(r)||!Number.isFinite(l))continue;e.set(o,l);const
|
|
3
|
-
`).map(async
|
|
4
|
-
`)[0]??"").slice(0,200),r=t.providerError,l=r===void 0?"":` Provider: ${r.provider}/${r.model}.`+(r.status===void 0?"":` HTTP status: ${r.status}.`)+(r.errno===void 0?"":` Errno: ${r.errno}.`)+(r.code===void 0?"":` Code: ${r.code}.`)+(r.body===void 0?"":` Body: ${r.body.slice(0,200)}.`)+(r.ratelimit===void 0?"":` Rate limit: ${r.ratelimit.scope??"account"}${r.ratelimit.claim===void 0?"":` (${r.ratelimit.claim})`}${r.ratelimit.model===void 0?"":` on ${r.ratelimit.model}`}.`),
|
|
1
|
+
var Y=Object.defineProperty;var m=(s,e)=>Y(s,"name",{value:e,configurable:!0});import{existsSync as H}from"node:fs";import{LAUNCHER_SOCKET as K}from"../../launcher/spec.js";import{launcherRequest as V}from"../../launcher/client.js";import{execFile as z}from"node:child_process";import{promisify as j}from"node:util";import{getNode as $,isWarmSpare as J,subscribersOf as Q}from"../../core/canvas/index.js";import{isSafeNodeId as c}from"../../core/canvas/paths.js";import{contextDir as X}from"../../core/canvas/node-agent-paths.js";import{fullName as I}from"../../core/canvas/labels.js";import{recordedPidLiveness as D}from"../../core/canvas/pid.js";import{transition as Z}from"../../core/runtime/lifecycle.js";import{readFault as O,readLiveTurn as E,recordFault as ee}from"../../core/canvas/recovery.js";import{errorClassFromFault as te}from"../../core/fault-classifier.js";import{nextFaultRetry as ne}from"../../core/runtime/fault-recovery.js";import{publishNotice as C}from"../../core/runtime/close.js";import{openDb as R}from"../../core/canvas/db.js";import{getById as re}from"../../core/graph/objects.js";import{watcherIdsOf as ie}from"../../core/graph/watches.js";import{headlessBrokerHost as b}from"../../core/runtime/host.js";import{emitEvent as p}from"../../core/events/emit.js";import{operationIdContext as L}from"../../core/events/operation-id.js";import{hasUnseenWakeMail as ae,resetStaleExecutionMail as se}from"../../core/canvas/deliveries.js";import{activeBackgroundBashJobs as oe}from"../../core/bash-jobs.js";import{focusOf as le}from"../../core/runtime/placement.js";import{hasAttachedBrokerViewers as de}from"../api/viewer-presence.js";import{deliverLive as ce}from"../../core/runtime/interactive-deliver.js";import{BrokerUnreachableError as ue}from"../../core/runtime/broker-request.js";import{formatCard as fe,PARK_SUMMARY_PROMPT as pe}from"../../shared/generated-context.js";import{brokerThresholdsForDaemon as me}from"../../core/runtime/fleet.js";import{readConfig as he}from"../../core/config.js";import{beginPendingPark as _e,consumePendingPark as S,pendingParkIds as ge,pendingParkStartedAt as ke}from"../park-pending.js";import{shouldParkAfterSummary as ve}from"../park-activity.js";import{applyParkEvent as N,parkEvent as ye}from"./live-obligation.js";import{memoryDeniedRecently as be}from"../../core/runtime/memory-admission.js";import{envNoDaemonAutostart as we,envTestUnattendedParkMs as Se,parkSummaryGraceMs as Ne,envUnattendedParkMs as Pe}from"../../shared/env.js";const A=j(z);function $e(s){return E(s)?.busy===!0}m($e,"liveBusy");function gt(s){const e=E(s)?.progressAt;if(e==null)return null;const t=Date.parse(e);return Number.isNaN(t)?null:t}m(gt,"liveTurnProgressMs");function G(s,e){return e===null?null:`${s}:${e}`}m(G,"incarnationOf");function F(s){const e=E(s.node_id),t=e?.busy===!0&&e.progressAt!==null?Date.parse(e.progressAt):Number.NaN,a=s.launched_at===null||s.launched_at===void 0?Number.NaN:Date.parse(s.launched_at);return!Number.isFinite(t)||!Number.isFinite(a)||t<a?null:t}m(F,"busySinceForIncarnation");const W=3*6e4,B=2e4,x=20*6e4,Ae=2,Me=5*6e4;function Te(s,e){return s===null||s.parent!=null?!1:s.lifecycle==="terminal"?!0:e==="cap_exhausted"&&s.run_id===s.node_id}m(Te,"settlesOnFatalProviderFault");function Ee(){const s=Pe();if(s!==void 0)return s;const e=he("user").lifecycle.unattendedParkMs;return we()?Se()??e:e}m(Ee,"unattendedParkMsForDaemon");function U(){return Ne()}m(U,"parkSummaryGraceMsForDaemon");function Fe(s,e,t,a){return s!==!0||e!=="refresh"||t?"leave":a===null||a<W?"pending":"kill"}m(Fe,"yieldStallVerdict");function xe(s){return!s.busy||s.quietForMs===null||s.quietForMs<x?"leave":s.cpuPercent===null||s.hasDescendants!==!1&&s.cpuPercent>Ae?"pending":"wedged"}m(xe,"wedgeVerdict");function q(s){const e=new Map,t=new Map;for(const a of s.split(`
|
|
2
|
+
`)){const i=a.trim();if(i==="")continue;const n=i.split(/\s+/);if(n.length<3)continue;const o=Number(n[0]),r=Number(n[1]),l=Number(n[2]);if(!Number.isFinite(o)||!Number.isFinite(r)||!Number.isFinite(l))continue;e.set(o,l);const u=t.get(r);u===void 0?t.set(r,[o]):u.push(o)}return{byPid:e,childrenOf:t}}m(q,"parsePsTree");function Ie(s,e){const{byPid:t,childrenOf:a}=q(s);if(!t.has(e))return null;let i=0;const n=[e],o=new Set;for(;n.length>0;){const r=n.pop();if(o.has(r))continue;o.add(r),i+=t.get(r)??0;const l=a.get(r);l!==void 0&&n.push(...l)}return i}m(Ie,"sumTreeCpu");function De(s,e){const{byPid:t,childrenOf:a}=q(s);return t.has(e)?(a.get(e)??[]).length>0:null}m(De,"treeHasDescendants");class kt{static{m(this,"BrokerSupervisionReconciler")}yieldStalls=new Map;wedgeNotifiedAt=new Map;fatalFaultNotifiedAt=new Map;unattendedSince=new Map;sampleTree;signal;lastOverCapWarnAt=Number.NEGATIVE_INFINITY;constructor(e={}){this.sampleTree=e.readTreeSample??(t=>this.readTreeSample(t)),this.signal=e.signal??((t,a)=>{if(process.platform==="linux"&&H(K)){if(a!=="SIGTERM"&&a!=="SIGKILL")throw new Error(`unsupported launcher signal ${a}`);return V({operation:"stop",pid:t,signal:a}).then(()=>{})}process.kill(t,a)})}async runFleetPreamble(e){return me()}warnIfSaturated(e){if(e.fleet.size()<e.thresholds.warning||!e.lifecycle.acceptsDetachedWork())return;const t=L.fresh(()=>this.warnOverCapInTmux(e.fleet.size(),e.thresholds,e.frozen));e.lifecycle.registerDetached(t)}async run(e,t){const a=Ee();for(const i of t.rows){const n=i.node_id,o=t.fleet.get(n);if(o===void 0||i.status!=="active"&&i.status!=="idle"){this.unattendedSince.delete(n);continue}await L.fresh(async()=>{try{await this.handleYieldStall(i,o,t.fleet,e),await this.handleWedgeDetection(i,o,t.fleet,e),this.handleFatalFault(n),this.handleUnattendedParking(n,$(n),o.pid,e,t,a)}catch(r){this.unattendedSince.delete(n),p({level:"error",event:"broker.supervision.failed",...c(n)?{node_id:n}:{fields:{affected_node_id:n}},error:r})}})}for(const i of this.unattendedSince.keys())t.fleet.has(i)||this.unattendedSince.delete(i);for(const i of ge())t.fleet.has(i)||S(i);se(e)}parkResetCondition(e,t,a,i){if(t.pi_session_id==null||t.pi_pid!==a||t.status==="done"||t.status==="canceled"||t.status==="dead"||t.intent!==null||oe(X(e)).length>0||le(e)!==null||de(e))return!0;const n=O(e);return n!==null&&n.retry.disposition==="auto"&&n.retry.by==="daemon"&&(n.kind==="connection"||n.kind==="rate-limit"||n.kind==="overloaded")&&(n.retry.nextAt!==void 0||ne(n,i)!==null)?!0:ae(e)}handleUnattendedParking(e,t,a,i,n,o){if(J(e)){this.unattendedSince.delete(e),S(e);return}if(t===null){this.unattendedSince.delete(e),S(e);return}const r=this.parkResetCondition(e,t,a,i),l=ke(e);if(l!==void 0){if(i-l<U())return;const _=S(e);if(_===void 0||(this.unattendedSince.delete(e),!ve(e,t,_)))return;p({level:"warn",event:"broker.park.summary_expired",...c(e)?{node_id:e}:{},fields:{...c(e)?{}:{affected_node_id:e},grace_ms:U()}}),N(e,"park"),b.teardown(e);return}if(r||$e(e)){this.unattendedSince.delete(e);return}const u=this.unattendedSince.get(e);if(u===void 0){this.unattendedSince.set(e,i);return}const d=ye(e,t.lifecycle),h=d!=="cancel"&&be(t.grantee??"app:terminal",i)?0:o;if(!(i-u<h)){if(this.unattendedSince.delete(e),d==="release"){N(e,d),b.teardown(e);return}if(d==="cancel"){N(e,d),b.teardown(e);return}if(t.grantee!==void 0&&t.grantee!=="app:terminal"){N(e,"park"),b.teardown(e);return}n.lifecycle.acceptsDetachedWork()&&(_e(e,i),n.lifecycle.registerDetached(this.requestParkSummary(e)))}}async requestParkSummary(e){try{const t=await ce(e,fe("park",{},pe),{origin:{type:"runtime",kind:"park"}});p({level:"info",event:"broker.park.summary_requested",...c(e)?{node_id:e}:{},fields:{...c(e)?{}:{affected_node_id:e},route:t}})}catch(t){if(S(e)===void 0)return;if(t instanceof ue){N(e,"park"),b.teardown(e);return}p({level:"error",event:"broker.park.summary_failed",...c(e)?{node_id:e}:{fields:{affected_node_id:e}},error:t})}}async warnOverCapInTmux(e,t,a){const i=Date.now();if(i-this.lastOverCapWarnAt<Me)return;this.lastOverCapWarnAt=i;const{warning:n,automaticReviveCap:o}=t,r=a.stalled+a.waitingOnMail;p({level:"warn",event:"broker.capacity.warning",fields:{live_count:e,warning_threshold:n,hard_cap:o,frozen_stalled:a.stalled,frozen_waiting_on_mail:a.waitingOnMail}});const l=r===0?"":` \u2014 ${r} frozen (${a.stalled} stalled, ${a.waitingOnMail} waiting on mail)`,u=`\u26A0 crtrd: ${e} live brokers (warning ${n}; hard cap ${o})${l} \u2014 possible broker leak. ps -ax | grep broker-cli.js`;try{const d=await A("tmux",["list-clients","-F","#{client_name}"],{encoding:"utf8",timeout:2e3});if(typeof d.stdout!="string")return;await Promise.allSettled(d.stdout.split(`
|
|
3
|
+
`).map(async h=>{if(h!=="")try{await A("tmux",["display-message","-C","-d","10000","-c",h,u],{encoding:"utf8",timeout:2e3})}catch{try{await A("tmux",["display-message","-c",h,u],{encoding:"utf8",timeout:2e3})}catch(_){p({level:"error",event:"broker.capacity.tmux_display_failed",error:_,fields:{client:h}})}}}))}catch(d){p({level:"error",event:"broker.capacity.tmux_list_clients_failed",error:d})}}async handleYieldStall(e,t,a,i){const n=e.node_id,o=G(t.pid,e.pi_pid_identity);if(e.intent!=="refresh"||F(e)!==null||o===null){o!==null&&this.yieldStalls.delete(o);return}let r=this.yieldStalls.get(o);if(r===void 0){r={since:i},this.yieldStalls.set(o,r);return}if(Fe(!0,e.intent,!1,i-r.since)!=="kill")return;const l=$(n);if(!(a.get(n)!==t||l?.pi_pid!==t.pid||l.pi_pid_identity!==e.pi_pid_identity||D(t.pid,e.pi_pid_identity)!=="alive"))if(r.termedAt===void 0){if(!await this.signalYieldStall(n,t.pid,"SIGTERM"))return;r.termedAt=i,p({level:"warn",event:"broker.yield_stall.sigterm",...c(n)?{node_id:n}:{},fields:{...c(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:i-r.since,grace_ms:W}})}else i-r.termedAt>=B&&await this.signalYieldStall(n,t.pid,"SIGKILL")&&p({level:"warn",event:"broker.yield_stall.sigkill",...c(n)?{node_id:n}:{},fields:{...c(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:i-r.termedAt,grace_ms:B,stall_elapsed_ms:i-r.since}})}async signalYieldStall(e,t,a){try{return await this.signal(t,a),!0}catch(i){return p({level:"error",event:"broker.yield_stall.signal_failed",...c(e)?{node_id:e}:{},error:i,fields:{...c(e)?{}:{affected_node_id:e},pid:t,signal:a}}),!1}}async readTreeSample(e){try{const{stdout:t}=await A("ps",["-ax","-o","pid=,ppid=,pcpu="],{encoding:"utf8",timeout:2e3});if(typeof t!="string")return null;const a=Ie(t,e),i=De(t,e);return a===null||i===null?null:{cpuPercent:a,hasDescendants:i}}catch{return null}}async handleWedgeDetection(e,t,a,i){const n=e.node_id,o=G(t.pid,e.pi_pid_identity),r=F(e);if(r===null||o===null){o!==null&&this.wedgeNotifiedAt.delete(o);return}const l=i-r,u=l>=x?await this.sampleTree(t.pid):null,d=$(n),h=d===null?null:F(d);if(a.get(n)!==t||d===null||d.pi_pid!==t.pid||d.pi_pid_identity!==e.pi_pid_identity||h!==r)return;const _=u?.cpuPercent??null,P=u?.hasDescendants??null;if(xe({busy:!0,quietForMs:l,cpuPercent:_,hasDescendants:P})!=="wedged"||this.wedgeNotifiedAt.get(o)===r)return;this.wedgeNotifiedAt.set(o,r);const g=I(d),k=Math.round((l??x)/6e4),w=P??!0,f=!w&&D(t.pid,e.pi_pid_identity)!=="alive"?"pid_identity_unproven":null;let v=!1,M=!1,y;if(w)y=`Child wedged \u2014 ${g} (${n}) is alive and mid-turn but has shown NO engine progress for ${k}+ minutes and its process is near-idle. It will NOT recover on its own \u2014 read \`crtr canvas read wedged-child-on-runaway-bash\` and kill the runaway SUBPROCESS (not this node) so its turn can resume with no lost context.`;else if(f!==null)y=`Child wedged \u2014 ${g} (${n}) is alive and mid-turn but has shown NO engine progress for ${k}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon did not SIGTERM the broker because its PID identity cannot be confirmed alive.`;else{v=!0;try{await this.signal(t.pid,"SIGTERM"),M=!0,y=`Child wedged \u2014 ${g} (${n}) is alive and mid-turn but has shown NO engine progress for ${k}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon sent SIGTERM to the broker and will resume a cleanly aborted session with a continuation, or start a recovery cycle if the abort cannot settle.`}catch(T){p({level:"error",event:"broker.wedge.signal_failed",...c(n)?{node_id:n}:{},error:T,fields:{...c(n)?{}:{affected_node_id:n},pid:t.pid,signal:"SIGTERM"}}),y=`Child wedged \u2014 ${g} (${n}) is alive and mid-turn but has shown NO engine progress for ${k}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon attempted SIGTERM to the broker, but the signal call failed.`}}p({level:"error",event:"broker.wedge.detected",...c(n)?{node_id:n}:{},fields:{...c(n)?{}:{affected_node_id:n},pid:t.pid,quiet_ms:l,cpu_percent:_,has_descendants:w,kick_attempted:v,kicked:M,...f===null?{}:{kick_suppression_reason:f}}});try{ee(n,{link:"daemon\u2192node",op:"engine wedge",kind:"wedged",retry:{disposition:"manual"},message:y})}catch(T){p({level:"error",event:"broker.wedge.fault_record_failed",...c(n)?{node_id:n}:{fields:{affected_node_id:n}},error:T})}C(n,"notice.crash",y,{reason:"child-wedged",child:n,quiet_ms:l,cpu_percent:_,kick_attempted:v,kicked:M,...f===null?{}:{kick_suppression_reason:f}})}handleFatalFault(e){const t=O(e);if(t===null){this.fatalFaultNotifiedAt.delete(e);return}if(t.retry.disposition!=="fatal"||t.link!=="pi\u2192provider"||this.fatalFaultNotifiedAt.get(e)===t.since)return;const a=$(e),i=a!==null?I(a):e,n=t.kind==="auth",o=(t.message.split(`
|
|
4
|
+
`)[0]??"").slice(0,200),r=t.providerError,l=r===void 0?"":` Provider: ${r.provider}/${r.model}.`+(r.status===void 0?"":` HTTP status: ${r.status}.`)+(r.errno===void 0?"":` Errno: ${r.errno}.`)+(r.code===void 0?"":` Code: ${r.code}.`)+(r.body===void 0?"":` Body: ${r.body.slice(0,200)}.`)+(r.ratelimit===void 0?"":` Rate limit: ${r.ratelimit.scope??"account"}${r.ratelimit.claim===void 0?"":` (${r.ratelimit.claim})`}${r.ratelimit.model===void 0?"":` on ${r.ratelimit.model}`}.`),u=t.kind==="context-overflow",d=Te(a,typeof r?.code=="string"?r.code:void 0),h=u||d,_=u?`exceeded its model context window and is now dead. Shrink the task or loaded context, or choose a larger-context model before spawning it again. Error: ${o}`:`got a non-retryable ${t.kind} error and will NOT recover on its own; `+(d?"its terminal run has failed. ":"it stays alive, and waking it clears the fault as soon as one turn completes \u2014 a wake that hits the same cause fails again. "+(n?"Its provider credential is dead \u2014 re-authenticate (`/login`, or re-auth crtr); it recovers on its next wake once the auth reloads. ":""))+`Error: ${o}.${l}`,P=u?"failed":"hit a fatal provider fault",g=new Set(Q(e).map(f=>f.node_id)),k=ie(R(),re(R(),e)),w=[{relation:"Child",recipients:k.filter(f=>g.has(f))},{relation:"Watched node",recipients:k.filter(f=>!g.has(f))}];this.fatalFaultNotifiedAt.set(e,t.since),p({level:"error",event:"fault.fatal.fanout",...c(e)?{node_id:e}:{},fields:{...c(e)?{}:{affected_node_id:e},kind:t.kind,link:t.link,terminal_overflow:u,terminal_provider_fault:d}});for(const{relation:f,recipients:v}of w)v.length!==0&&C(e,"notice.crash",`${f} ${P} \u2014 ${i} (${e}) ${_}`,{reason:u?"child-context-overflow":"child-fault-fatal",child:e,kind:t.kind,message:o,...r===void 0?{}:{provider_error:r}},"normal",null,v);h&&(Z(e,"crash",{reason:u?"context_overflow":r?.code==="cap_exhausted"?"cap_exhausted":"provider_fatal",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t.message,fault_kind:t.kind,error_class:te(t).class}}}),b.teardown(e).then(f=>{f.confirmed||p({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:f.error??new Error("Broker teardown not confirmed")})},f=>p({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:f})))}}export{kt as BrokerSupervisionReconciler,Ae as WEDGE_CPU_MAX_PERCENT,x as WEDGE_QUIET_MS,W as YIELD_STALL_GRACE_MS,U as parkSummaryGraceMsForDaemon,Te as settlesOnFatalProviderFault,Ie as sumTreeCpu,De as treeHasDescendants,Ee as unattendedParkMsForDaemon,xe as wedgeVerdict,Fe as yieldStallVerdict};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var D=Object.defineProperty;var r=(n,t)=>D(n,"name",{value:t,configurable:!0});import{prepared as d}from"../../core/sqlite-statements.js";import{randomUUID as O}from"node:crypto";import{openDb as l}from"../../core/canvas/db.js";import{getNode as
|
|
1
|
+
var D=Object.defineProperty;var r=(n,t)=>D(n,"name",{value:t,configurable:!0});import{prepared as d}from"../../core/sqlite-statements.js";import{randomUUID as O}from"node:crypto";import{openDb as l}from"../../core/canvas/db.js";import{getNode as f}from"../../core/canvas/canvas.js";import{BrokerClient as T,SocketTransport as I}from"../../core/broker-client/client.js";import{emitRunEvent as c,emitRunSettlement as m}from"../../core/runs/events.js";import{cancelOpenQuestions as R}from"../../core/runs/questions.js";import{emitEvent as p}from"../../core/events/emit.js";import{toRunOutcomeDTO as v}from"../api/map.js";import{readOutputResult as N}from"../../core/runtime/structured-output.js";const A=JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),h=new Map,y=250;class b{static{r(this,"RunObserver")}nodeId;runId;client;timer;status;piPid=null;outcomeRevision;openAssistant=!1;assistantStartSequence=0;block=null;thinking="";output="";pendingThinking="";pendingOutput="";flushTimer;closed=!1;constructor(t,e){this.nodeId=t,this.runId=e;const i=l(),s=d(i,"SELECT body_json FROM run_events WHERE node_id = ? AND type = ? ORDER BY sequence_number DESC LIMIT 1").get(t,t===e?"node.settled":"child.settled");s&&(this.outcomeRevision=JSON.parse(s.body_json).outcome.revision);const o=d(i,"SELECT body_json FROM run_events WHERE node_id = ? AND type = 'node.status.changed' ORDER BY sequence_number DESC LIMIT 1").get(t);o&&(this.status=JSON.parse(o.body_json).status),this.timer=setInterval(()=>this.pollOrClose(),250),this.timer.unref(),h.set(t,this),this.poll()}pollOrClose(){try{this.poll()}catch(t){this.close(),p({level:"error",event:"daemon.runs.observer_failed",node_id:this.nodeId,error:t})}}poll(){const t=f(this.nodeId);if(!t||t.run_id!==this.runId||!g(this.runId)){this.close();return}this.piPid=t.pi_pid??null;const e=t.pi_pid===null?"dormant":t.status;this.status!==e&&c(this.runId,this.nodeId,"node.status.changed",{status:e,reason:t.intent??null}),this.status=e;const i=v(t);if(i&&i.revision!==this.outcomeRevision&&Date.now()-Date.parse(i.settled_at)<720*60*6e4){if(this.nodeId===this.runId){const s=d(l(),"SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(this.runId,this.runId);for(const o of s)E(o.node_id,this.runId),h.get(o.node_id)?.poll()}if(this.outcomeRevision=i.revision,this.nodeId===this.runId){const s=i.kind==="result"?N(this.nodeId,t.grantee):void 0;m(this.runId,this.nodeId,"node.settled",{outcome:i,usage:JSON.parse(t.usage_json??A),...s===void 0?{}:{result:s}})}else m(this.runId,this.nodeId,"child.settled",{child_node_id:this.nodeId,outcome:i});if(t.grantee&&t.grantee!=="app:terminal"){const s=this.nodeId===this.runId?{run_id:this.runId}:{node_id:this.nodeId};R(s,this.nodeId===this.runId?"the run settled":"the asking node was closed").catch(o=>p({level:"error",event:"daemon.runs.question_cancel_failed",node_id:this.nodeId,error:o}))}}t.pi_pid===null?this.close():this.connect()}get assistantMessageStartSequence(){return this.openAssistant&&this.client&&this.piPid!==null?this.assistantStartSequence:null}get openBlock(){return this.assistantMessageStartSequence===null?null:this.block}connect(){if(this.client||this.closed)return;const t=new T(this.nodeId,{transport:new I(this.nodeId,{recordsViewerFaults:!1})});this.client=t,t.on("connect",()=>t.send({type:"hello",role:"observer",client_id:O(),attends:!1})),t.on("frame",e=>{if(e.type==="message_start"&&e.message.role==="assistant"&&(this.discardDeltas(),this.openAssistant=!0,this.block=null,this.thinking="",this.output="",this.assistantStartSequence=d(l(),"SELECT event_cursor FROM nodes WHERE node_id = ?").get(this.runId).event_cursor),e.type==="message_update"&&e.message.role==="assistant"&&this.openAssistant){const i=e.message.content;if(!Array.isArray(i))return;const s=i.at(-1);s&&typeof s=="object"&&"type"in s&&(s.type==="toolCall"?this.block={kind:"tool_call",name:"name"in s&&typeof s.name=="string"?s.name:""}:(s.type==="text"||s.type==="thinking")&&(this.block={kind:s.type}));const o=i.filter(u=>u?.type==="thinking").map(u=>u.thinking).join(""),a=i.filter(u=>u?.type==="text").map(u=>u.text).join(""),S=o.startsWith(this.thinking)?o.slice(this.thinking.length):o,k=a.startsWith(this.output)?a.slice(this.output.length):a;this.thinking=o,this.output=a,this.pendingThinking+=S,this.pendingOutput+=k,(this.pendingThinking||this.pendingOutput)&&!this.flushTimer&&(this.flushTimer=setTimeout(()=>this.flushDeltas(),y),this.flushTimer.unref())}e.type==="message_end"&&e.message.role==="assistant"&&(this.flushDeltas(),this.openAssistant=!1,this.block=null)}),t.on("error",()=>{}),t.on("close",()=>{this.client===t&&(this.client=void 0,this.discardDeltas(),this.openAssistant=!1,this.block=null)}),t.connect()}flushDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0;const t=this.pendingThinking,e=this.pendingOutput;if(this.pendingThinking="",this.pendingOutput="",!this.openAssistant||!t&&!e)return;if(d(l(),"SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND sequence_number >= ? AND type IN ('node.output_text.done', 'node.thinking.done', 'usage') LIMIT 1").get(this.runId,this.nodeId,this.assistantStartSequence)){this.openAssistant=!1;return}t&&c(this.runId,this.nodeId,"node.thinking.delta",{delta:t}),e&&c(this.runId,this.nodeId,"node.output_text.delta",{delta:e})}discardDeltas(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=void 0,this.pendingThinking="",this.pendingOutput=""}close(){this.closed=!0,this.discardDeltas(),clearInterval(this.timer),h.delete(this.nodeId);const t=this.client;this.client=void 0,t?.close()}}function J(n){return h.get(n)?.assistantMessageStartSequence??null}r(J,"openAssistantMessageStartSequence");function P(n){return h.get(n)?.openBlock??null}r(P,"openAssistantBlock");function g(n){return d(l(),"SELECT 1 FROM nodes WHERE node_id = ? AND run_id = ? AND event_cursor IS NOT NULL").get(n,n)!==void 0}r(g,"runRootExists");function E(n,t){if(!h.has(n)&&g(t)){if(n!==t){const e=f(n);!d(l(),"SELECT 1 FROM run_events WHERE run_id = ? AND node_id = ? AND type = 'child.started' LIMIT 1").get(t,n)&&e&&Date.now()-Date.parse(e.created)<720*60*6e4&&c(t,n,"child.started",{child_node_id:n,kind:e.kind})}new b(n,t)}}r(E,"ensureRunObserver");function Y(){const n=new Date(Date.now()-2592e6).toISOString(),t=d(l(),`SELECT n.node_id, n.run_id FROM node_rows n WHERE n.run_id IS NOT NULL AND (n.pi_pid IS NOT NULL OR (n.outcome_at IS NOT NULL AND n.outcome_at > ?
|
|
2
2
|
AND n.outcome_reason != 'parked' AND NOT EXISTS (
|
|
3
3
|
SELECT 1 FROM run_events e WHERE e.run_id = n.run_id AND e.node_id = n.node_id AND e.type = CASE WHEN n.node_id = n.run_id THEN 'node.settled' ELSE 'child.settled' END
|
|
4
|
-
AND json_extract(e.body_json, '$.outcome.revision') = COALESCE(n.outcome_revision, 1))))`).all(n);for(const e of t)try{E(e.node_id,e.run_id),
|
|
4
|
+
AND json_extract(e.body_json, '$.outcome.revision') = COALESCE(n.outcome_revision, 1))))`).all(n);for(const e of t)try{E(e.node_id,e.run_id),_.delete(e.node_id)}catch(i){L(e.node_id,i)}}r(Y,"pollRunObservers");const _=new Map;function L(n,t){const e=t instanceof Error?t.message:String(t);_.get(n)!==e&&(_.set(n,e),p({level:"error",event:"daemon.runs.observer_failed",node_id:n,error:t}))}r(L,"reportObserverFailure");export{E as ensureRunObserver,P as openAssistantBlock,J as openAssistantMessageStartSequence,Y as pollRunObservers};
|