@north-light/cli 0.3.594 → 0.3.595
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/core/runs/initial-input.d.ts +15 -0
- package/dist/core/runs/initial-input.js +1 -0
- package/dist/core/runs/operations.js +5 -5
- package/dist/core/runtime/broker/model-adapter.d.ts +3 -3
- package/dist/core/runtime/broker/model-adapter.js +3 -3
- package/dist/core/runtime/broker/turn-cause.d.ts +4 -0
- package/dist/core/runtime/broker/turn-cause.js +1 -1
- package/dist/core/runtime/headless-pi.d.ts +2 -0
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/naming.d.ts +2 -2
- package/dist/core/runtime/naming.js +9 -9
- package/dist/core/runtime/recap.d.ts +1 -1
- package/dist/core/runtime/recap.js +4 -4
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/pi-extensions/broker-local.d.ts +3 -1
- package/dist/pi-extensions/broker-local.js +1 -1
- package/dist/pi-extensions/canvas-recap.js +7 -7
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** The accepted-message id of an app run's launch prompt. Derived from the run id, so the launch paths can find it
|
|
2
|
+
* again without a second record and a replayed creation can never mint a second one. */
|
|
3
|
+
export declare function initialInputMessageId(runId: string): string;
|
|
4
|
+
/** Gives a run's launch prompt the durable message identity a `run.start` `message` already has, inside the run-creation
|
|
5
|
+
* transaction. The launch prompt reaches the model as the kickoff, so its delivery is written already acknowledged:
|
|
6
|
+
* the inbox never hands it over a second time. Its id is what the first turn's model and tool rows name as their cause. */
|
|
7
|
+
export declare function recordInitialInput(runId: string, grantee: string, prompt: string): Promise<void>;
|
|
8
|
+
/** Puts a run root's launch-prompt message id on its first kickoff's env, where the broker reads the ids of the turn's input.
|
|
9
|
+
* A node that is not a run root, or a run started with a `message` (which joins the first turn through the inbox), has none. */
|
|
10
|
+
export declare function carryInitialInput(inv: {
|
|
11
|
+
env: Record<string, string>;
|
|
12
|
+
}, node: {
|
|
13
|
+
node_id: string;
|
|
14
|
+
run_id?: string | null;
|
|
15
|
+
}): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var d=Object.defineProperty;var n=(e,i)=>d(e,"name",{value:i,configurable:!0});import{createHash as o}from"node:crypto";import{openDb as u}from"../canvas/db.js";import{enqueueNodeMail as c}from"../feed/messages.js";function t(e){return o("sha256").update(`initial-input:${e}`).digest("hex").slice(0,32)}n(t,"initialInputMessageId");async function m(e,i,a){await c(e,{kind:"message",label:a.slice(0,120),senderNodeId:null,senderName:i,bodyJson:{body:a,start_turn:!1},urgency:"deferred",wake:0,messageId:t(e),withinEnqueue:n(async(r,s)=>{await r.prepare("UPDATE deliveries SET state = 'acknowledged', acknowledged_at = ? WHERE message_id = ?").run(Date.now(),s)},"withinEnqueue")})}n(m,"recordInitialInput");async function E(e,i){if(i.run_id!==i.node_id)return;const a=t(i.node_id);await(await u()).prepare("SELECT 1 FROM messages WHERE message_id = ?").get(a)!==void 0&&(e.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify([a]))}n(E,"carryInitialInput");export{E as carryInitialInput,t as initialInputMessageId,m as recordInitialInput};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var Me=Object.defineProperty;var c=(e,t)=>Me(e,"name",{value:t,configurable:!0});import{coveredByAny as
|
|
1
|
+
var Me=Object.defineProperty;var c=(e,t)=>Me(e,"name",{value:t,configurable:!0});import{coveredByAny as Ie}from"../../shared/env.js";import{createHash as Q}from"node:crypto";import{ApiError as Ae}from"../../api/errors.js";import{CrtrError as Te}from"../errors.js";import{isCloudRole as Le}from"../canvas/person.js";import{isAbsolute as V,relative as Ce,resolve as ke,sep as xe,join as We}from"node:path";import{SessionManager as Fe}from"@earendil-works/pi-coding-agent";import{covers as P}from"@north-light/identity";import{openDb as B,withCanvasWrite as F}from"../canvas/db.js";import{deleteNodeWithOwned as qe}from"../graph/deletion.js";import{getById as He}from"../graph/objects.js";import{repairRunConversations as Z}from"../canvas/sessions.js";import{getNode as O,nodeFiles as Ue,removeNodeFiles as $e,updateNode as Pe}from"../canvas/canvas.js";import{fullName as Be}from"../canvas/labels.js";import{renameWindow as je}from"../runtime/placement.js";import{liveExecutionForNode as K}from"../canvas/executions.js";import{conversationStore as ee,isConversationNotFound as Je}from"../conversation-store/index.js";import{PARKED_RESIDENT_SQL as Ye}from"../canvas/canvas.js";import{WAKE_MAIL_SQL as Ge}from"../canvas/deliveries.js";import{readNodeRecap as Xe}from"../canvas/node-recap.js";import{enqueueNodeMail as ze}from"../feed/messages.js";import{recordInitialInput as Qe}from"./initial-input.js";import{newestReportBody as Ve}from"../feed/reports.js";import{ensureAppProfile as te,loadExactProfileManifest as ne}from"../profiles/manifest.js";import{stopNodeSandboxes as se}from"../spaces/stop.js";import{BrokerUnreachableError as Ze}from"../runtime/broker-request.js";import{interruptLive as Ke}from"../runtime/interactive-deliver.js";import{isBrokerLive as ae}from"../runtime/model-swap.js";import{newNodeId as et}from"../runtime/nodes.js";import{reviveNode as j}from"../runtime/revive.js";import{spawnChildPrepared as tt}from"../runtime/spawn.js";import{isPortableModelToken as nt}from"../runtime/launch.js";import{parseDurationMs as st}from"../wake.js";import{expandModelCandidates as at,parseModelSpec as it}from"../model-routes.js";import{payerOfGrant as J}from"../grants/mirror.js";import{isolatedBrokerLauncherAvailable as rt}from"../runtime/host.js";import{blaxelEnvironmentOf as ot}from"../runtime/blaxel-environment.js";import{resolveRunKind as dt,resolveRunModel as ct}from"../runtime/launch-target.js";import{cycleAwareMessages as ut}from"../runtime/session-cycles.js";import{originFor as ie}from"../runtime/stamp/protocol.js";import{readOutputRequest as mt,readOutputResult as re}from"../runtime/output-result.js";import{admitLegacyStructuredOutput as oe}from"../../daemon/structured-requests/sidecar.js";import{runSchemaRepromptPending as lt}from"../runtime/stop-guard.js";import{toRunOutcomeDTO as ft}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as pt}from"../../daemon/runs/observer.js";import{closeNode as de}from"../runtime/close.js";import{parseScope as _t}from"@north-light/identity";import{appendRunEvent as ce,lockRunRoot as wt,subscribeRunEvents as gt}from"./events.js";import{runActivity as Et}from"./activity.js";import{cancelOpenQuestions as ue,openNoticeIds as yt,openQuestionIds as me}from"./questions.js";import{appSpace as Y}from"../layout.js";import{ensureAppSpace as ht}from"../spaces/space.js";import{assertUploadsUsable as le,resolveStorageUrls as Rt}from"../storage/attachments.js";import{storageClient as St,storageConfig as Nt}from"../storage/client.js";import{deleteUploadRow as vt,insertUploadUses as fe,releaseRunUploads as bt,runUsesPath as Ot}from"../storage/tables.js";import{abortProviderCalls as pe}from"../providers/inflight.js";import{filterAsync as _e,mapAsync as x}from"../async-array.js";const we=c((e,t,s,n)=>Rt(t,e,s,n?{taken:n}:{}),"defaultResolver"),Dt=3e3;class R extends Error{static{c(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,s,n,d,f,r,i=t===503){super(n),this.status=t,this.code=s,this.param=d,this.details=f,this.scope=r,this.retryable=i}}const N=c((e,t)=>new R(400,"invalid_request",e,t),"invalid"),G=c(()=>new R(404,"not_found","run not found"),"missing"),X=c(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),I=c(async()=>await B(),"db");async function q(e,t,s=!1){const n=await O(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!s&&n.deleting_at)throw G();return n}c(q,"ownedRun");const ge=["waiting_on_user","idle","settled"];async function C(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=await(await I()).prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
|
|
2
2
|
(n.last_settled_at IS NULL OR EXISTS (
|
|
3
3
|
SELECT 1 FROM run_events e WHERE e.run_id = ? AND e.node_id = n.node_id AND e.type = 'node.turn.started'
|
|
4
4
|
AND e.sequence_number > COALESCE((SELECT MAX(c.sequence_number) FROM run_events c
|
|
5
5
|
WHERE c.run_id = e.run_id AND c.node_id = e.node_id AND c.type = 'node.turn.completed'), 0)
|
|
6
|
-
)) LIMIT 1`).get(e.node_id,e.node_id),s=!e.last_settled_at&&e.status!=="done";return t||s||await
|
|
6
|
+
)) LIMIT 1`).get(e.node_id,e.node_id),s=!e.last_settled_at&&e.status!=="done";return t||s||await lt(e)?"running":(await me(e.node_id)).length?"waiting_on_user":await(await I()).prepare(`SELECT 1 FROM deliveries d JOIN nodes n ON n.node_id = d.destination_id
|
|
7
7
|
WHERE n.run_id = ? AND ${Ge("d","'armed', 'pending', 'handed_off'")}
|
|
8
|
-
AND (n.status IN ('active', 'idle') OR ${Ye("n")}) LIMIT 1`).get(e.node_id)?"running":"idle"}c(C,"runStatus");async function
|
|
8
|
+
AND (n.status IN ('active', 'idle') OR ${Ye("n")}) LIMIT 1`).get(e.node_id)?"running":"idle"}c(C,"runStatus");async function qn(e){const t=await O(e);return t!==null&&await C(t)==="running"}c(qn,"runIsRunning");async function W(e){await Z(e.node_id),e=await O(e.node_id)??e;const t=await C(e),s=t==="settled"?[]:await me(e.node_id),n=await Ve(e.node_id)||void 0,d=t==="settled"?await ft(e):null,f=d?.kind==="result"?await re(e.node_id):void 0,r=Xe(e.node_id);return{run_id:e.node_id,name:e.name,status:t,...d?{outcome:d}:{},...f===void 0?{}:{result:f},...n!==void 0?{last_report:n}:{},...r?{recap:r}:{},pending_question_ids:s,open_notice_ids:t==="settled"?[]:await yt(e.node_id),...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(X())),payer:await J(e.grant_id),scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at,activity:await Et(e.node_id,t)}}c(W,"runObject");const z=864e5,Ee=255;function Hn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>Ee)throw N(`Idempotency-Key must be 1-${Ee} characters`);return e}}c(Hn,"idempotencyKeyOf");function Mt(e){if(Le()){if(!e)throw new R(403,"permission_error","a cloud role serves this call only for a token that names a person");return e}}c(Mt,"cloudPersonScope");function k(e,t){const s=Mt(e);return s===void 0?t:`${s}:${t}`}c(k,"personKey");async function H(e,t,s,n){n&&await n.prepare("SELECT pg_advisory_xact_lock(hashtext(?))").get(`idempotency:${e}:${t}`),n??=await B();const d=await n.prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!d||Date.now()-Date.parse(d.created_at)>=z)){if(d.body_hash!==s)throw new R(409,"idempotency_conflict","key used with a different request");return{run_id:d.run_id,response:JSON.parse(d.response_json)}}}c(H,"findIdempotent");async function ye(e,t,s,n,d,f,r){await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,s,new Date(Date.now()-z).toISOString()),await e.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,s,n,d,JSON.stringify(f),r)}c(ye,"recordIdempotent");async function Un(e=Date.now()){return Number((await(await B()).prepare("DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-z).toISOString())).changes)}c(Un,"pruneExpiredIdempotencyKeys");async function he(e,t,s,n,d,f=!1){const r=n.text;let i=0;return{messageId:(await ze(t,{kind:"message",label:r.slice(0,120),senderNodeId:"human",senderName:s,bodyJson:d?{body:r,...f?{steer:!0}:{}}:{body:r,start_turn:!1},urgency:d?"normal":"deferred",wake:d?1:0,withinEnqueue:c(async(m,h)=>{n.uses.length&&(await le(s,n.uses,m),await fe(n.uses.map(({upload_id:g,path:E,blob_key:o})=>({upload_id:g,path:E,blob_key:o,run_id:t})),m)),i=(await ce(m,t,t,"node.message.accepted",{message_id:h,start_turn:d})).sequence_number},"withinEnqueue")})).messageId,sequence:i}}c(he,"acceptRunMessage");class Re extends Error{static{c(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}const It=1440*60*1e3;function Se(e){const t=typeof e=="string"?st(e):null;if(t===null||!Number.isSafeInteger(t))throw N(`deadline '${String(e)}' is not a duration; use one or more <int>[smhd] parts such as 10m or 1h30m`,"deadline");if(t<=0)throw N("deadline must be greater than zero","deadline");if(t>It)throw N("deadline must be at most 24h","deadline");return t}c(Se,"parseRunDeadlineMs");async function $n(e,t,s,n=we){if(t.isolated&&!rt()&&await ot((t.profile===void 0?await te(e.grantee):ne(t.profile)).profileId)===null)throw new R(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");t.deadline!==void 0&&Se(t.deadline);const{causedBy:d,...f}=t,r=Q("sha256").update(JSON.stringify(f)).digest("hex");if(s){const a=await H(e.grantee,k(e.sub,s),r);if(a){const l=await q(a.run_id,e.grantee);return!l.pi_pid&&await C(l)==="running"&&(t.output_schema!==void 0&&!l.outcome_at&&await mt(l.node_id)===null&&await re(l.node_id)===void 0&&await oe(l.node_id,"terminal",t.output_schema),await j(l.node_id,{resume:!0,capacity:"freeze"})),a.response}}await ht(e.grantee);const i=t.profile===void 0?await te(e.grantee):ne(t.profile),u=i.manifest.grantee??"app:terminal";if(u!==e.grantee){const a=`crtr:memory:rw:${u}:profile:${i.profileId}`;if(!e.resolved.some(l=>P(l,a))||t.scopes!==null&&!t.scopes.some(l=>P(l,a)))throw new R(403,"scope_missing",`missing scope ${a}`,"profile",void 0,a)}if(t.model!==void 0){const a=t.model;if(nt(a)){if(a.includes("/")&&await J(e.grant)!=="app"){const l=a.lastIndexOf("/"),D=a.slice(0,l),v=a.slice(l+1);if(["ultra","strong","medium","light"].includes(v)&&(await at({kind:"logical",family:D,strength:v,spec:a},Y(e.grantee).files,i.profileId)).every(S=>S.family!==D))throw N(`model '${a}' names a model family that is not configured in this daemon`,"model")}}else if(it(a)===void 0)throw N(`model '${a}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const m=await et(),h=We(Y(e.grantee).nodes,m);if(t.isolated&&t.cwd!==void 0){const a=Ce(h,ke(t.cwd));if(!V(t.cwd)||a===".."||a.startsWith(`..${xe}`)||V(a))throw N("cwd must be inside the isolated root node folder","cwd")}const g=await n(m,e.grantee,t.prompt),E=g.text,o=t.message===void 0?void 0:await n(m,e.grantee,t.message,g.uses.map(a=>a.path)),p=await J(e.grant);let y;try{const a=ct(i,t.model);await tt({kind:dt(i),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??h:Y(e.grantee).files,profile:i.profileId,prompt:E,nodeId:m,isolated:t.isolated??!1,...t.causedBy===void 0?{}:{causedBy:t.causedBy},...a===void 0?{}:{model:a},...t.deadline===void 0?{}:{deadlineAt:new Date(Date.now()+Se(t.deadline)).toISOString()},...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:m,event_cursor:1,usage_json:JSON.stringify(X())},withinCreate:c(async(l,D)=>{if(s){const S=await H(e.grantee,k(e.sub,s),r,l);if(S)throw new Re(S)}const v=g.uses;if(v.length&&(await le(e.grantee,v,l),await fe(v.map(({upload_id:S,path:A,blob_key:U})=>({upload_id:S,path:A,blob_key:U,run_id:m})),l)),y={run_id:m,node_id:m,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:p,status:"running",created_at:D.created,metadata:t.metadata,sequence_number:0},await ce(l,m,m,"run.started",{scopes:t.scopes,payer:p,usage:X()}),o){const S=await he(l,m,e.grantee,o,!1);y.message={run_id:m,message_id:S.messageId,sequence_number:S.sequence}}else await Qe(m,e.grantee,E);s&&await ye(l,e.grantee,k(e.sub,s),r,m,y,D.created)},"withinCreate")},t.output_schema===void 0?void 0:async l=>{await oe(l,"terminal",t.output_schema)})}catch(a){if(a instanceof Re)return a.winner.response;if(t.model!==void 0&&a instanceof Te&&a.code==="usage")throw N(a.message,"model");if(a instanceof Ae&&(a.code==="isolated_run"||a.code==="invalid_request")){const l=a.details&&typeof a.details=="object"&&"param"in a.details&&typeof a.details.param=="string"?a.details.param:void 0;throw new R(a.status,a.code,a.message,l)}throw a}if(!y)throw new Error("run creation did not commit");return y}c($n,"startRun");async function Pn(e,t){let s;if(t.after)try{const i=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!i||typeof i!="object"||!("activity"in i)||typeof i.activity!="string"||!("id"in i)||typeof i.id!="string")throw new Error("invalid cursor");s={activity:i.activity,id:i.id}}catch{throw N("invalid list cursor","after")}const n=await(await I()).prepareUncached(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
|
|
9
9
|
WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}${t.sub===void 0?"":" AND sub = ?"}
|
|
10
|
-
ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e],...t.sub===void 0?[]:[t.sub]),d=await _e(await x((await _e(n,async({node_id:i})=>!t.visible||await t.visible(i))).filter(({activity:i,node_id:u})=>!s||i<s.activity||i===s.activity&&u<s.id),async i=>({root:await O(i.node_id),activity:i.activity})),async({root:i})=>!t.status||await C(i)===t.status),f=d.slice(0,t.limit),r=f.at(-1);return{runs:await x(f,async({root:i})=>await W(i)),next:d.length>t.limit&&r?Buffer.from(JSON.stringify({activity:r.activity,id:r.root.node_id})).toString("base64url"):null}}c(
|
|
10
|
+
ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e],...t.sub===void 0?[]:[t.sub]),d=await _e(await x((await _e(n,async({node_id:i})=>!t.visible||await t.visible(i))).filter(({activity:i,node_id:u})=>!s||i<s.activity||i===s.activity&&u<s.id),async i=>({root:await O(i.node_id),activity:i.activity})),async({root:i})=>!t.status||await C(i)===t.status),f=d.slice(0,t.limit),r=f.at(-1);return{runs:await x(f,async({root:i})=>await W(i)),next:d.length>t.limit&&r?Buffer.from(JSON.stringify({activity:r.activity,id:r.root.node_id})).toString("base64url"):null}}c(Pn,"listRuns");async function Bn(e,t,s){const n=await q(e,t),d=c(async()=>await W(await q(e,t)),"read");return!s||ge.includes(await C(n))?await d():new Promise((f,r)=>{let i=c(()=>{},"unsubscribe");const u=c(()=>{clearTimeout(o),clearInterval(E),i()},"settle"),m=c(async()=>{u();try{f(await d())}catch(p){r(p)}},"finish"),h=c(async()=>{ge.includes(String((await d()).status))&&await m()},"check"),g=c(()=>{h().catch(p=>{u(),r(p)})},"run"),E=setInterval(g,250),o=setTimeout(()=>{m()},s*1e3);gt(e,g).then(p=>{i=p},p=>{u(),r(p)})})}c(Bn,"waitRun");const At=5;async function jn(e,t,s=we,n=!0,d,f=!0){const r=e.status==="canceled"||e.outcome_reason==="closed",i=e.grantee??"app:terminal",u=Q("sha256").update(JSON.stringify(["run.message",e.node_id,t,n,...n&&!f?["steer:false"]:[]])).digest("hex"),m=c(async g=>{const E=await O(e.node_id),o=await(await I()).prepare("SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(g.message_id));return E&&!r&&n&&!E.pi_pid&&o&&await j(e.node_id,{resume:!0,capacity:"freeze"}),g},"replay");if(d){const g=await H(i,k(e.sub,d),u);if(g)return m(g.response)}if(r)throw new R(409,"run_settled","canceled run cannot receive a message");const h=n&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;for(let g=1;;g++){const E=await s(e.node_id,i,t),o=await F(async p=>{if(d){const l=await H(i,k(e.sub,d),u,p);if(l)return{replayed:l.response}}if(E.uses.length){await wt(p,e.node_id);for(const l of E.uses)if(await Ot(e.node_id,l.path,p))return"path_taken"}await h?.(e.node_id);const y=await he(p,e.node_id,i,E,n,n&&f),a={run_id:e.node_id,message_id:y.messageId,sequence_number:y.sequence};return d&&await ye(p,i,k(e.sub,d),u,e.node_id,a,new Date().toISOString()),{result:a}});if(o==="path_taken"){if(g>=At)throw new R(503,"service_unavailable","attachments of concurrent messages kept taking each other's file names; retry");continue}return"replayed"in o?m(o.replayed):(n&&!e.pi_pid&&await j(e.node_id,{resume:!0,capacity:"freeze"}),o.result)}}c(jn,"messageRun");async function Tt(e){const t=c(()=>new R(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let s=0;s<2;s++){const n=await O(e);if(!n)throw G();if(!ae(n)){if(n.streaming)throw t();return}const d=(await K(e))?.executionId;try{await Ke(e)==="turn"&&pe({nodes:[e]});return}catch(f){if(!(f instanceof Ze))throw f;const r=await O(e);if(!r)throw G();if(!r.streaming)return;if(s===0&&ae(r)&&(await K(e))?.executionId!==d)continue;throw t()}}throw t()}c(Tt,"interruptNode");async function Jn(e,t="stop"){const s=t==="stop"?(await(await I()).prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id)).map(({node_id:n})=>n):[e.node_id];return await Promise.all(s.map(n=>Tt(n))),await W(await O(e.node_id)??e)}c(Jn,"interruptRun");async function Yn(e,t={}){const s=(await(await I()).prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(r=>r.node_id);pe({run:e.node_id});const n=[];if(await C(e)!=="settled")n.push(...(await de(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"})).closed);else for(const r of s){if(r===e.node_id)continue;const i=await O(r);i&&i.status!=="done"&&i.status!=="canceled"&&i.status!=="dead"&&n.push(...(await de(r,{preserveEmpty:!0,stopReason:"run_canceled"})).closed)}if(await ue({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...n])].map(r=>se(r,"run_canceled")))).some(r=>!r.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const f=await O(e.node_id);return await W(f??e)}c(Yn,"cancelRun");const Ne=200;async function Gn(e,t){if(typeof t!="string"||!t.trim())throw N("name is required","name");const s=t.trim();if(s.length>Ne)throw N(`name exceeds ${Ne} characters`,"name");const n=await Pe(e.node_id,{name:s});return n.window&&je(n.window,Be(n)),await W(n)}c(Gn,"renameRun");async function Xn(e,t={config:Nt,client:St}){await ue({run_id:e.node_id},"the run was deleted");const s=await F(async u=>(await u.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),(await u.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(m=>m.node_id)));if((await Promise.all(s.map(u=>se(u,"run_deleted",{deleting:!0})))).some(u=>!u.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const d=await x(s,async u=>{const m=await Ue(u);if(m.app===null)throw new Error(`run node missing during deletion: ${u}`);return m}),f=await(await I()).prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:u}of f)try{await ee().delete(u)}catch(m){if(!Je(m))throw m}const r=await F(async u=>{for(const E of s){const o=await He(u,E);o!==null&&o.deleted_at===null&&await qe(u,o)}const m=await bt([e.node_id],u);await u.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),await u.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const h=s.map(()=>"?").join(","),g=await u.prepareUncached(`SELECT message_id FROM messages WHERE sender_node_id IN (${h}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${h})`).all(...s,...s);await u.prepareUncached(`DELETE FROM deliveries WHERE destination_id IN (${h})`).run(...s);for(const{message_id:E}of g)await u.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(E,E);return m});for(const u of d)await $e(u);const{notifyRunDeleted:i}=await import("./events.js");return i(e.node_id),{uploads_pending:await Lt(r,t)}}c(Xn,"deleteRun");async function Lt(e,t){if(!e.length||!t.config())return e.length;let s;try{s=t.client()}catch{return e.length}const n=new Set,d=e.map(r=>s.deleteUpload(r).then(async()=>{await vt(r),n.add(r)},()=>{}));let f;return await Promise.race([Promise.all(d),new Promise(r=>{f=setTimeout(r,t.budgetMs??Dt),f.unref?.()})]),clearTimeout(f),e.length-n.size}c(Lt,"deleteReleasedUploads");async function zn(e,t,s){await q(e,t),await Z(e);const n=await F(async o=>{const p=await o.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e),y=new Map;for(const S of p)y.set(S.node_id,(await o.prepare("SELECT session_id FROM sessions WHERE node_id = ? GROUP BY session_id ORDER BY min(created_at)").all(S.node_id)).map(A=>A.session_id));const l=(await o.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e)).event_cursor-1,D=await o.prepare(`SELECT node_id, sequence_number FROM run_events
|
|
11
11
|
WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
|
|
12
12
|
ORDER BY sequence_number`).all(e,l),v=await o.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
|
|
13
13
|
WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.delta', 'node.output_text.delta')
|
|
14
|
-
ORDER BY sequence_number`).all(e,l);return{nodes:p,sessionIds:y,latestSequence:l,completed:D,deltas:v}}),{nodes:d,sessionIds:f,latestSequence:r,completed:i,deltas:u}=n,m=await x(d,async o=>({node_id:o.node_id,parent_node_id:o.parent,conversations:await x(f.get(o.node_id)??[],async p=>{const{header:y,entries:a}=await ee().read(p);if(s==="entries")return{conversation_id:p,header:y,entries:a};const l=Fe.inMemory(y.cwd,void 0,[y,...a]),D=
|
|
14
|
+
ORDER BY sequence_number`).all(e,l);return{nodes:p,sessionIds:y,latestSequence:l,completed:D,deltas:v}}),{nodes:d,sessionIds:f,latestSequence:r,completed:i,deltas:u}=n,m=await x(d,async o=>({node_id:o.node_id,parent_node_id:o.parent,conversations:await x(f.get(o.node_id)??[],async p=>{const{header:y,entries:a}=await ee().read(p);if(s==="entries")return{conversation_id:p,header:y,entries:a};const l=Fe.inMemory(y.cwd,void 0,[y,...a]),D=ut(l)??[],v=new Map(a.map((w,b)=>[w.id,b])),S=a.filter(w=>w.type==="custom"&&w.customType==="crtr-system-prompt").map(w=>({id:w.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in w?w.data:void 0,timestamp:w.timestamp}})),A=a.filter(w=>w.type==="custom_message"&&w.customType==="app_message").map(w=>({id:w.id,message:{role:"custom",customType:"app_message",content:"content"in w?w.content:"",timestamp:w.timestamp}})),U=o.node_id===e?a.find(w=>{if(w.type!=="message"||w.message.role!=="user")return!1;const b=ie(a,w.message.timestamp);return b?.type==="runtime"&&b.kind==="kickoff"})?.id:void 0,ve=[...D.filter(({id:w})=>!A.some(b=>b.id===w)),...S,...A].sort((w,b)=>(v.get(w.id)??Number.MAX_SAFE_INTEGER)-(v.get(b.id)??Number.MAX_SAFE_INTEGER)).map(({id:w,message:b})=>{const _=b,T=_.usage,$=_.role==="user"?ie(a,Number(_.timestamp)):null,be=$?.type==="human"||w===U,L=_.role==="toolResult"?"tool_result":_.role==="bashExecution"?"bash_execution":_.role==="compactionSummary"?"compaction_summary":_.role==="branchSummary"?"branch_summary":_.role==="custom"&&_.customType==="crtr-system-prompt"?"system":_.role==="user"?be?"user":"custom":_.role,Oe=L==="custom"?_.role==="custom"?_.customType:$?.type==="runtime"?$.kind:"unknown":void 0,De=L==="system"&&_.customType==="crtr-system-prompt"?[{type:"text",text:_.data?.text??""}]:typeof _.content=="string"?[{type:"text",text:_.content}]:Array.isArray(_.content)?_.content.map(M=>M.type==="toolCall"?{type:"tool_call",tool_call_id:M.id,name:M.name,arguments:M.arguments}:M.type==="image"?{type:"image",mime_type:M.mimeType}:M.type==="thinking"?{type:"thinking",text:M.thinking}:M):[];return{entry_id:w,role:L,...L==="custom"?{custom_type:Oe}:{},time:typeof _.timestamp=="string"?_.timestamp:new Date(Number(_.timestamp??Date.now())).toISOString(),content:De,...L==="assistant"?{model:_.model,provider:_.provider,stop_reason:_.stopReason,..._.errorMessage?{error_message:_.errorMessage}:{},...T?{usage:{input_tokens:T.input??0,output_tokens:T.output??0,cache_read_tokens:T.cacheRead??0,cache_write_tokens:T.cacheWrite??0,cost_usd:T.cost?.total??0}}:{}}:{},...L==="tool_result"?{tool_call_id:_.toolCallId,tool_name:_.toolName,is_error:_.isError}:{}}})??[];return{conversation_id:p,messages:ve}})})),h=new Map(await Promise.all(m.map(async o=>[o.node_id,await pt(o.node_id)])));for(const o of i){const p=h.get(o.node_id);p!=null&&o.sequence_number>=p&&h.set(o.node_id,null)}const g=new Map;for(const o of u){const p=h.get(o.node_id);if(p==null||o.sequence_number<p)continue;const y=JSON.parse(o.body_json),a=g.get(o.node_id)??{thinking:"",text:""};o.type==="node.thinking.delta"?a.thinking+=y.delta:a.text+=y.delta,g.set(o.node_id,a)}const E=m.map(o=>({...o,in_progress_message:h.get(o.node_id)==null?null:g.get(o.node_id)??{thinking:"",text:""}}));return{run_id:e,latest_sequence:r,nodes:E}}c(zn,"traceRun");function Qn(e,t,s){if(t===void 0){if(!e.some(n=>P(n,"crtr:llm")))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw N("scopes must be a list of scope strings","scopes");for(const n of t){try{_t(n)}catch{throw N(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))throw N(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===s.slice(4))&&!Ie(e,n))throw new R(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}c(Qn,"requestedScopes");export{z as IDEMPOTENCY_WINDOW_MS,It as RUN_DEADLINE_MAX_MS,Dt as RUN_DELETE_STORAGE_BUDGET_MS,Ne as RUN_NAME_MAX,R as RunError,Yn as cancelRun,Mt as cloudPersonScope,Xn as deleteRun,Hn as idempotencyKeyOf,Jn as interruptRun,Pn as listRuns,jn as messageRun,q as ownedRun,Se as parseRunDeadlineMs,Un as pruneExpiredIdempotencyKeys,Gn as renameRun,Qn as requestedScopes,qn as runIsRunning,W as runObject,$n as startRun,zn as traceRun,Bn as waitRun};
|
|
@@ -2,7 +2,7 @@ import { type AssistantMessageEventStream, type Context, type Model, type Models
|
|
|
2
2
|
import type { ModelRuntime } from '@earendil-works/pi-coding-agent';
|
|
3
3
|
/** Pi uses availability and auth for its model controls; only the daemon can
|
|
4
4
|
* decide whether a route has credentials. Keep the broker's metadata selectable. */
|
|
5
|
-
export declare function configureBrokerModelRuntime(runtime: ModelRuntime, intent?: string): void;
|
|
5
|
+
export declare function configureBrokerModelRuntime(runtime: ModelRuntime, intent?: string, causedBy?: string): void;
|
|
6
6
|
export declare const LLM_BROKER_RETRY_WINDOW_S = 300;
|
|
7
7
|
export declare const LLM_REFUSAL_DIAGNOSTIC = "crtr:llm-refusal";
|
|
8
8
|
/** The retry deadline (epoch ms) a final daemon refusal carried on its
|
|
@@ -23,5 +23,5 @@ export declare function requestBody(model: Model<any>, context: Context, options
|
|
|
23
23
|
/** The real response under a deferred-head framing (`daemon/api/deferred-head.ts`): the magic line, keep-alive
|
|
24
24
|
* blank lines, one JSON head line, then the body unchanged. Any other response is returned as it is. */
|
|
25
25
|
export declare function unwrapDeferredHead(response: Response): Promise<Response>;
|
|
26
|
-
/** One pi stream, backed exclusively by the authenticated daemon llm route. `intent` replaces the node's own `CRTR_MODEL_INTENT` for one stream: a background one-shot of an app-paid node asks for `app/light`, not the node's rung. */
|
|
27
|
-
export declare function streamBrokerModel(model: Model<any>, context: Context, options?: ModelsSimpleStreamOptions, intent?: string): AssistantMessageEventStream;
|
|
26
|
+
/** One pi stream, backed exclusively by the authenticated daemon llm route. `intent` replaces the node's own `CRTR_MODEL_INTENT` for one stream: a background one-shot of an app-paid node asks for `app/light`, not the node's rung. `causedBy` is the cause a one-shot helper captured when it was dispatched; the main stream reads the live turn's at call time. */
|
|
27
|
+
export declare function streamBrokerModel(model: Model<any>, context: Context, options?: ModelsSimpleStreamOptions, intent?: string, causedBy?: string): AssistantMessageEventStream;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`!==
|
|
3
|
-
`))>=0;){const
|
|
1
|
+
var Y=Object.defineProperty;var f=(e,t)=>Y(e,"name",{value:t,configurable:!0});import{setTimeout as z}from"node:timers/promises";import{createAssistantMessageEventStream as G,getCurrentSystemPrompt as X,getCurrentTools as K}from"@earendil-works/pi-ai";import{socketFetch as Q}from"../../../api/node-transport.js";import{DEFER_HEAD_REQUEST_HEADER as V,DEFERRED_HEAD_CONTENT_TYPE as Z,DEFERRED_HEAD_MAGIC as ee}from"../../../daemon/api/deferred-head.js";import{apiSocketPath as te}from"../../canvas/paths.js";import{northlightUnreachable as ne}from"../../directory/reach.js";import{currentNodeToken as re}from"./node-token.js";import{brokerApiUrl as A}from"./daemon-ops.js";import{currentCausedBy as oe}from"./turn-cause.js";import{envModelExact as U,envModelIntent as se}from"../../../shared/env.js";import{MODEL_CONTEXT_BODY_MAX_BYTES as S}from"../../llm/body-limits.js";import{modelRequestFromConfig as ie}from"../../model-routes.js";import{parseProviderRateLimit as ae,providerFailureDiagnostic as T}from"../../provider-failure.js";import{UPSTREAM_MODEL_UNAVAILABLE as D}from"../../fault-classifier.js";function Le(e,t,n){e.checkAuth=async a=>e.getProvider(a)?{type:"api_key"}:void 0,e.getAvailable=async a=>e.getModels(a),e.getAvailableSnapshot=()=>e.getModels(),e.streamSimple=(a,s,i)=>me(a,s,i,t,n)}f(Le,"configureBrokerModelRuntime");const ce=300,q="crtr:llm-refusal";class k extends Error{static{f(this,"LlmRefusalError")}retryAt;rateLimit;code;status;constructor(t,n,a,s,i){super(t),this.retryAt=n,this.rateLimit=a,this.code=s,this.status=i}}class R extends Error{static{f(this,"UpstreamModelUnavailableError")}}function B(e,t){const n=e===void 0?"the request body":`the request body (${e} bytes)`;return new Error(`request_too_large: ${n} exceeds the ${t}-byte model request limit; compact the conversation to shrink the context`)}f(B,"contextTooLargeError");function L(e){const t=e.details?.rate_limit;if(!t||typeof t!="object")return;const n=ae(t);if(n===void 0)return;const{provider:a,model:s}=t;return typeof a=="string"&&a!==""&&typeof s=="string"&&s!==""?{...n,model:`${a}/${s}`}:n}f(L,"refusalRateLimit");function Oe(e){for(const t of e.diagnostics??[]){if(t.type!==q)continue;const n=t.details?.retryAt;if(typeof n=="number"&&Number.isFinite(n)&&n>0)return n}}f(Oe,"refusalRetryAt");class F extends Error{static{f(this,"ContentFilteredError")}}function P(e){return typeof e=="string"?e:e.map(t=>t.type==="text"?{type:"text",text:t.text}:{type:"image_url",image_url:{url:`data:${t.mimeType};base64,${t.data}`}})}f(P,"wireContent");function le(e){const t=f(s=>s.role==="assistant"&&(s.stopReason==="error"||s.stopReason==="aborted"),"incomplete"),n=e.some(t)?e.filter(s=>!t(s)):e;let a=n.length;for(;a>0&&n[a-1]?.role==="assistant";)a--;return a===n.length?n:n.slice(0,a)}f(le,"wireHistory");function de(e,t,n,a){const s=[],i=X(t.messages),r=K(t.messages);i?s.push({role:"system",content:i}):t.systemPrompt&&s.push({role:"system",content:t.systemPrompt});for(const p of le(t.messages))p.role==="user"?s.push({role:"user",content:P(p.content)}):p.role==="toolResult"?s.push({role:"tool",content:P(p.content),tool_call_id:p.toolCallId}):p.role==="assistant"&&s.push({role:"assistant",content:p.content.filter(c=>c.type==="text").map(c=>c.text).join("")||null,tool_calls:p.content.filter(c=>c.type==="toolCall").map(c=>({id:c.id,type:"function",function:{name:c.name,arguments:JSON.stringify(c.arguments)}}))});const d=`${e.provider}/${e.id}`,_=a??se();return{model:ie(d,_,U())?.kind==="logical"?_:d,model_policy:U()?"exact":"substitute",stream:!0,messages:s,...r.length?{tools:r.map(p=>({type:"function",function:{name:p.name,description:p.description,parameters:p.parameters}}))}:{},...n.reasoning?{reasoning_effort:n.reasoning}:{},...n.temperature!==void 0?{temperature:n.temperature}:{},...n.maxTokens!==void 0?{max_tokens:n.maxTokens}:{}}}f(de,"requestBody");function O(e,t){if(typeof t!="string")return!1;const n=t.indexOf("/");return n<1||n===t.length-1?!1:(e.provider=t.slice(0,n),e.model=t.slice(n+1),!0)}f(O,"applyServedModel");function H(e){if(e.details?.served_model!==void 0)return e.details.served_model;const t=e.details?.rate_limit;return typeof t?.provider=="string"&&typeof t.model=="string"?`${t.provider}/${t.model}`:void 0}f(H,"refusalRoute");function j(e){if(!e||typeof e!="object"||!("error"in e))throw new Error("llm returned an invalid response");const t=e.error;if(!t||typeof t.message!="string")throw new Error("llm returned an invalid refusal");return t}f(j,"parseRefusal");function W(){const e=A();return e===void 0?"http://localhost/v1/llm":new URL("/v1/llm",e).toString()}f(W,"llmUrl");function ue(){return A()===void 0?Q(te()):globalThis.fetch}f(ue,"llmFetch");async function fe(e){if(!e.headers.get("content-type")?.startsWith(Z))return e;if(!e.body)throw new Error("deferred head response has no body");const t=e.body.getReader();let n=new Uint8Array(0),a=!1;for(;;){const s=n.indexOf(10);if(s<0){const{value:c,done:w}=await t.read();if(w)throw new Error("deferred head response ended before its head");const m=new Uint8Array(n.length+c.length);m.set(n),m.set(c,n.length),n=m;continue}const i=new TextDecoder().decode(n.subarray(0,s)).trim();if(n=n.subarray(s+1),!a){if(`${i}
|
|
2
|
+
`!==ee)throw new Error("deferred head response has no magic line");a=!0;continue}if(i==="")continue;const r=JSON.parse(i),d=new Headers;for(const[c,w]of Object.entries(r.headers))for(const m of Array.isArray(w)?w:[w])d.append(c,m);const _=n,p=new ReadableStream({start(c){_.length>0&&c.enqueue(_)},async pull(c){const{value:w,done:m}=await t.read();m?c.close():c.enqueue(w)},cancel(c){return t.cancel(c)}});return new Response(r.status===204?null:p,{status:r.status,headers:d})}}f(fe,"unwrapDeferredHead");function pe(e){const t=e??oe();return t===void 0?{}:{"crtr-caused-by":t}}f(pe,"causedByHeader");function me(e,t,n={},a,s){const i=G(),r={role:"assistant",content:[],api:e.api,provider:e.provider,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};return(async()=>{const d=re();if(!d)throw new Error("llm requires a node token");const _=JSON.stringify(de(e,t,n,a)),p=Buffer.byteLength(_);if(p>S)throw B(p,S);let c=0;for(;;){n.signal?.throwIfAborted();const w=await ue()(W(),{method:"POST",headers:{authorization:`Bearer ${d}`,"content-type":"application/json",[V]:"1",...pe(s)},body:_,signal:n.signal}).catch(u=>{const o=W();throw A()===void 0||n.signal?.aborted?u:new R(ne(u,o).message)}),m=await fe(w);if(!m.ok){const u=j(await m.json());if(m.status===413||u.code==="payload_too_large")throw B(p,S);if(O(r,H(u)),u.retryable!==!0)throw new k(u.message,void 0,L(u),u.code,m.status);const o=u.retry_after_s;if(typeof o!="number"||!Number.isFinite(o)||o<=0)throw u.code===D?new R(u.message):new Error(u.message);const g=ce-c;if(o>g){const h=Date.now()+o*1e3;throw new k(`${u.message} (retry after ${o}s, at ${new Date(h).toISOString()})`,h,L(u))}await z(o*1e3,void 0,{signal:n.signal}),c+=o;continue}if(!m.body)throw new Error("llm returned no stream");i.push({type:"start",partial:r});const J=m.body.getReader(),I=new TextDecoder;let x="",b="stop",M,$=!1,C=!1;const N=f(u=>{const o=JSON.parse(u);if(o.error){const l=j(o);throw O(r,H(l)),l.retryable!==!0?new k(l.message,void 0,L(l),l.code):l.code===D?new R(l.message):new Error(l.message)}if(o.served_model){if(C=!0,o.served_model.indexOf("/")<1)throw new Error("llm returned an invalid served_model");O(r,o.served_model)}const g=o.choices?.[0],h=g?.delta;if(h?.reasoning_content){const l=r.content.findIndex(v=>v.type==="thinking"),y=l<0?{type:"thinking",thinking:""}:r.content[l],E=l<0?r.content.push(y)-1:l;if(l<0&&i.push({type:"thinking_start",contentIndex:E,partial:r}),y.type!=="thinking")throw new Error("invalid thinking block");y.thinking+=h.reasoning_content,i.push({type:"thinking_delta",contentIndex:E,delta:h.reasoning_content,partial:r})}if(h?.content){const l=r.content.findIndex(v=>v.type==="text"),y=l<0?{type:"text",text:""}:r.content[l],E=l<0?r.content.push(y)-1:l;if(l<0&&i.push({type:"text_start",contentIndex:E,partial:r}),y.type!=="text")throw new Error("invalid text block");y.text+=h.content,i.push({type:"text_delta",contentIndex:E,delta:h.content,partial:r})}for(const l of h?.tool_calls??[]){const y={type:"toolCall",id:l.id,name:l.function.name,arguments:JSON.parse(l.function.arguments)},E=r.content.push(y)-1;i.push({type:"toolcall_start",contentIndex:E,partial:r}),i.push({type:"toolcall_end",contentIndex:E,toolCall:y,partial:r})}g?.finish_reason&&(b=g.finish_reason),g?.message?.refusal&&(M=g.message.refusal),o.usage&&($=!0,r.usage={input:o.usage.prompt_tokens,output:o.usage.completion_tokens,cacheRead:o.usage.cache_read_tokens,cacheWrite:o.usage.cache_write_tokens,totalTokens:o.usage.total_tokens,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:typeof o.usage.usd_equivalent=="number"&&Number.isFinite(o.usage.usd_equivalent)?o.usage.usd_equivalent:0}})},"apply");for(;;){const{value:u,done:o}=await J.read();if(o)break;x+=I.decode(u,{stream:!0});let g;for(;(g=x.indexOf(`
|
|
3
|
+
`))>=0;){const h=x.slice(0,g).trim();x=x.slice(g+1),h&&N(h)}}if(x+=I.decode(),x.trim()&&N(x.trim()),!$||!C)throw new Error("llm stream ended without usage or served_model");for(const[u,o]of r.content.entries())o.type==="text"&&i.push({type:"text_end",contentIndex:u,content:o.text,partial:r}),o.type==="thinking"&&i.push({type:"thinking_end",contentIndex:u,content:o.thinking,partial:r});if(b==="content_filter")throw new F(M??"Content filtered");if(!["stop","tool_calls","length"].includes(b))throw new Error(`llm returned unknown finish reason: ${b}`);r.stopReason=b==="tool_calls"?"toolUse":b==="length"?"length":"stop",i.push({type:"done",reason:r.stopReason,message:r}),i.end();return}})().catch(d=>{r.stopReason=n.signal?.aborted?"aborted":"error",r.errorMessage=d instanceof Error?d.message:String(d),d instanceof k&&(r.diagnostics=[{type:q,timestamp:Date.now(),...d.retryAt!==void 0?{details:{retryAt:d.retryAt}}:{}},...d.rateLimit!==void 0?[T({status:429,ratelimit:d.rateLimit})]:[],...d.rateLimit===void 0&&d.code==="cap_exhausted"?[T({status:d.status??402,code:d.code})]:[]]),d instanceof R&&(r.diagnostics=[T({status:503,code:D})]),d instanceof F&&r.stopReason==="error"&&(r.rawStopReason="content_filter"),i.push({type:"error",reason:r.stopReason,error:r}),i.end()}),i}f(me,"streamBrokerModel");export{ce as LLM_BROKER_RETRY_WINDOW_S,q as LLM_REFUSAL_DIAGNOSTIC,Le as configureBrokerModelRuntime,Oe as refusalRetryAt,de as requestBody,me as streamBrokerModel,fe as unwrapDeferredHead,le as wireHistory};
|
|
@@ -4,4 +4,8 @@ type Branch = ReturnType<BrokerSession['sessionManager']['getBranch']>;
|
|
|
4
4
|
export declare function turnCauseOf(branch: Branch): string | undefined;
|
|
5
5
|
/** `message:<id>` of the turn running now, or undefined. */
|
|
6
6
|
export declare function currentCausedBy(): string | undefined;
|
|
7
|
+
/** The cause a one-shot helper call dispatched now belongs to: the turn whose input entry is staged and whose prompt has not
|
|
8
|
+
* reached the session yet (a helper started by that prompt's own input event runs before its user entry exists), else the
|
|
9
|
+
* running or latest turn's. Read once at dispatch, so a helper that outlives its turn keeps that turn's cause. */
|
|
10
|
+
export declare function currentOrPendingCausedBy(): string | undefined;
|
|
7
11
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var a=Object.defineProperty;var r=(n,e)=>a(n,"name",{value:e,configurable:!0});let u;function g(n){u=n}r(g,"setTurnCauseSource");function d(n){let e=[],s;for(const t of n)if(t.type==="custom"&&t.customType==="crtr-turn-input"){const i=t.data?.message_ids;Array.isArray(i)&&e.push(...i.filter(o=>typeof o=="string"))}else(t.type==="message"&&t.message.role==="user"||t.type==="custom_message")&&(e.length>0?(s=e[0],e=[]):s=void 0);return{cause:s,pending:e}}r(d,"causeAndPending");function f(n){const{cause:e}=d(n);return e===void 0?void 0:`message:${e}`}r(f,"turnCauseOf");function p(){return u===void 0?void 0:f(u().sessionManager.getBranch())}r(p,"currentCausedBy");function y(){if(u===void 0)return;const{cause:n,pending:e}=d(u().sessionManager.getBranch()),s=e[0]??n;return s===void 0?void 0:`message:${s}`}r(y,"currentOrPendingCausedBy");export{p as currentCausedBy,y as currentOrPendingCausedBy,g as setTurnCauseSource,f as turnCauseOf};
|
|
@@ -20,6 +20,8 @@ export interface HeadlessRequest {
|
|
|
20
20
|
seedMessages?: readonly AgentMessage[];
|
|
21
21
|
/** Reuses a provider cache identity without binding or persisting a session. */
|
|
22
22
|
sessionId?: string;
|
|
23
|
+
/** The turn cause the call belongs to (`message:<id>`), captured by the caller with the call's input; null names none. Omit to read the turn at dispatch. */
|
|
24
|
+
causedBy?: string | null;
|
|
23
25
|
/** Omit `noTools` to load Pi's builtin tool suite. */
|
|
24
26
|
toolPolicy?: 'builtin';
|
|
25
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var j=Object.defineProperty;var s=(e,t)=>j(e,"name",{value:t,configurable:!0});import{envModelIntent as
|
|
1
|
+
var j=Object.defineProperty;var s=(e,t)=>j(e,"name",{value:t,configurable:!0});import{envModelIntent as O,envNodeCwd as _,envProfileId as D}from"../../shared/env.js";import{join as E}from"node:path";import{InMemoryCredentialStore as N}from"@earendil-works/pi-ai";import{APP_FAMILY as c,expandModelCandidates as $,modelRequestFromConfig as R}from"../model-routes.js";import{defaultModelLaddersConfig as H}from"../../types.js";import{stripThinkingSuffix as W}from"./model-selection.js";import{configureBrokerModelRuntime as Y}from"./broker/model-adapter.js";import{currentNodeToken as z}from"./broker/node-token.js";import{currentOrPendingCausedBy as G}from"./broker/turn-cause.js";function J(e){for(let t=e.length-1;t>=0;t--){const n=e[t];if(n?.role!=="assistant")continue;if(typeof n.content=="string")return n.content.trim();if(!Array.isArray(n.content))continue;const u=n.content.map(m=>{const i=m;return i.type==="text"&&typeof i.text=="string"?i.text:""}).join("").trim();if(u!=="")return u}return""}s(J,"lastAssistantText");function K(e,t){const n=O();if(!(n===void 0||!n.startsWith(`${c}/`)))return t?{modelRequest:R(e.modelSpec,n,!1),intent:n}:{modelRequest:{kind:"logical",family:c,strength:"light",spec:W(H().anthropic.light)},intent:`${c}/light`}}s(K,"appPaidRequest");async function f(e,t,n,u){const m=e.causedBy===void 0?G():e.causedBy??void 0;let i,p=!1,d=!1,g;const y=s(o=>{i===void 0||p||(p=!0,o&&i.abort().catch(()=>{}),i.dispose())},"disposeSession"),v=new Promise(o=>{g=setTimeout(()=>{d=!0,y(!0),o(t)},e.timeoutMs)}),C=(async()=>{try{const o=await import("@earendil-works/pi-coding-agent");if(z()===void 0||d)return t;const l=_()??process.cwd(),A=D(),x=o.getAgentDir(),M=await o.ModelRuntime.create({credentials:new N,modelsPath:E(x,"models.json")}),h=K(e,n);if(Y(M,h?.intent,m),d)return t;const w=await o.createAgentSessionServices({cwd:l,agentDir:x,modelRuntime:M,settingsManager:o.SettingsManager.inMemory(),resourceLoaderOptions:{noExtensions:!0,noContextFiles:!0,noSkills:!0,noPromptTemplates:!0,noThemes:!0,systemPrompt:e.systemPrompt}});if(d)return t;const S=h?.modelRequest??R(e.modelSpec,e.modelIntent,!1);if(S===void 0)return t;const B=new o.ModelRegistry(w.modelRuntime),P=(await $(S,l,A)).map(a=>B.find(a.providerId,a.modelId)).find(a=>a!==void 0);if(P===void 0)return t;let T;const r=e.tool,F=r===void 0?void 0:o.defineTool({name:r.name,label:r.label,description:r.description,parameters:r.parameters,...r.constrainedSampling===void 0?{}:{constrainedSampling:r.constrainedSampling},async execute(a,L){return T=L,{content:[{type:"text",text:"Recorded."}],details:{recorded:!0},terminate:!0}}}),I=o.SessionManager.inMemory(l,e.sessionId===void 0?void 0:{id:e.sessionId});for(const a of e.seedMessages??[])I.appendMessage(a);return{session:i}=await o.createAgentSessionFromServices({services:w,sessionManager:I,model:P,thinkingLevel:"off",...r===void 0?e.toolPolicy==="builtin"?{}:{noTools:"all"}:{tools:[r.name],customTools:[F]}}),d||(await i.bindExtensions({}),d)?t:(await i.prompt(e.userPrompt),d?t:u(i,T))}catch{return t}finally{y(!1)}})();try{return await Promise.race([C,v])}finally{clearTimeout(g)}}s(f,"runHeadless");function ne(e){return f(e,null,!1,(t,n)=>n)}s(ne,"headlessToolCall");function oe(e){return f(e,"",!1,t=>J(t.messages))}s(oe,"headlessText");function ie(e){return f(e,"failed",!0,()=>"completed")}s(ie,"headlessTurn");export{oe as headlessText,ne as headlessToolCall,ie as headlessTurn};
|
|
@@ -55,11 +55,11 @@ export declare function sanitizeIcon(raw: string): string;
|
|
|
55
55
|
* This module stays canvas-free so CLI leaves can reach it. The canvas-coupled
|
|
56
56
|
* commit path lives in pi-extensions/broker-local.ts, which imports this pure
|
|
57
57
|
* helper and writes through crtrd's guarded generated-name operation. */
|
|
58
|
-
export declare function headlessName(body: string, sourceCap?: number): Promise<SessionName>;
|
|
58
|
+
export declare function headlessName(body: string, sourceCap?: number, causedBy?: string | null | undefined): Promise<SessionName>;
|
|
59
59
|
/** Generate a name from a bounded conversation source rather than a single
|
|
60
60
|
* kickoff message. The caller owns selecting representative conversation text;
|
|
61
61
|
* this cap keeps the one-shot prompt compact. */
|
|
62
|
-
export declare function headlessNameFromConversation(conversation: string): Promise<SessionName>;
|
|
62
|
+
export declare function headlessNameFromConversation(conversation: string, causedBy?: string | null): Promise<SessionName>;
|
|
63
63
|
/** A filesystem-safe slug for the `.todos/<slug>.md` fallback path: lowercase,
|
|
64
64
|
* [a-z0-9] kept, everything else → single hyphen, clamped to 8 words. */
|
|
65
65
|
export declare function titleSlug(title: string): string;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
`),
|
|
1
|
+
var k=Object.defineProperty;var s=(e,t)=>k(e,"name",{value:t,configurable:!0});import{headlessText as x,headlessToolCall as h}from"./headless-pi.js";import{currentOrPendingCausedBy as T}from"./broker/turn-cause.js";import{defaultProvider as m,modelLadders as g,stripThinkingSuffix as f}from"./model-selection.js";const c=2e3,w=45e3,C=["fixing/diagnosis: U+F188 bug, U+F0F1 stethoscope, U+F06D fire, U+F071 warning","building/changing code: U+F0AD wrench, U+F067 plus, U+F121 code, U+F085 cogs, U+F021 refresh","testing/verifying: U+F0C3 flask, U+F00C check, U+F24E balance","writing/docs/research: U+F02D book, U+F15C document, U+F002 magnifier, U+F0EB lightbulb","data/infra: U+F1C0 database, U+F0C2 cloud, U+F120 terminal, U+F013 gear, U+F1B3 packages","ship/perf/scale: U+F135 rocket, U+F0E7 bolt, U+F080 chart, U+F201 trend line","security/access: U+F132 shield, U+F023 lock, U+F084 key","interface/design: U+F1FC paintbrush, U+F03E image, U+F108 display","communication/coordination: U+F1D8 paper plane, U+F0E6 comments, U+F0E8 sitemap, U+F0C1 link"].join(`
|
|
2
|
+
`),E="You label agent sessions. A session is whatever a person opened it for: a coding task, a question, a piece of research, an idea they are turning over, or an ordinary conversation. You are labelling that session, never taking part in it \u2014 do not answer the message, do not do the work it asks for, do not comment on it. Every session gets a label, however short, casual, misspelled, or open-ended its opening message is.\n\nCall the `name_session` tool exactly once with:\n- `title`: how a person would refer to this session in a list of their conversations \u2014 2-8 words, sentence case, written naturally with its punctuation intact (e.g. `What's your favorite color?`, `Payroll export mapping bug`, `Ideas for the launch email`). No quotes, no markdown, no trailing period.\n- `name`: the same subject as a concise 3-8 word kebab-case handle \u2014 lowercase words joined by single hyphens (e.g. `favorite-color-question`, `refactor-auth-token-flow`). No punctuation, quotes, or prose.\n- `icon`: ONE Nerd Font glyph, written as its codepoint in `U+XXXX` form (e.g. `U+F188`). Emit a codepoint, not a name like `nf-fa-bug`, and not an emoji.\n\nChoosing the icon \u2014 work through it in this order:\n1. Name the concrete SUBJECT of the task: the thing being acted on. A font, a trash can, an account, a browser tab, a clock, an invoice, a map, a robot, a specific technology's logo. If a glyph depicts that thing, use it. This is almost always the better icon, because it is what distinguishes this session from every other one.\n2. Only when the task has no depictable subject, fall back to the ACTIVITY (fixing, documenting, testing) using the generic set below.\n\nANY Nerd Font codepoint is allowed and the set is enormous \u2014 the whole Font Awesome range, Devicons and Seti technology logos, Octicons, Codicons, Weather, and the thousands of Material Design nouns above U+F0001. Reach into it. The examples below are the generic tier, NOT a menu: if your pick came from them and the task had a real subject, you picked wrong. Never reuse a generic gear, wrench, or bug for a task that is actually about something.\n\nGeneric fallback set, by kind of work:\n"+C;function N(e,t=c){return`<source>
|
|
3
3
|
${e.slice(0,t)}
|
|
4
4
|
</source>
|
|
5
5
|
|
|
6
|
-
Label the session this text is from: call \`name_session\` once with a title, a name, and an icon depicting it, then stop. Do not answer it.`}s(
|
|
7
|
-
`).map(o=>o.trim()).find(o=>o!=="")??"").toLowerCase().replace(/[^a-z0-9]+/g,"-").split("-").filter(o=>o!=="").slice(0,8).join("-")}s(
|
|
8
|
-
`).map(i=>i.trim()).find(i=>i!=="")??"").replace(/\s+/g," ").replace(/^["'`]+|["'`]+$/g,"").trim();if(n==="")return"";let o=n;if(n.length>
|
|
9
|
-
${e.slice(0,
|
|
6
|
+
Label the session this text is from: call \`name_session\` once with a title, a name, and an icon depicting it, then stop. Do not answer it.`}s(N,"nameUserPrompt");const l=72;function u(e){return((e??"").split(`
|
|
7
|
+
`).map(o=>o.trim()).find(o=>o!=="")??"").toLowerCase().replace(/[^a-z0-9]+/g,"-").split("-").filter(o=>o!=="").slice(0,8).join("-")}s(u,"sanitizeSessionName");function b(e){const n=((e??"").split(`
|
|
8
|
+
`).map(i=>i.trim()).find(i=>i!=="")??"").replace(/\s+/g," ").replace(/^["'`]+|["'`]+$/g,"").trim();if(n==="")return"";let o=n;if(n.length>l){const i=n.slice(0,l),r=i.lastIndexOf(" ");o=`${(r>l/2?i.slice(0,r):i).trimEnd()}\u2026`}return o.charAt(0).toUpperCase()+o.slice(1)}s(b,"sanitizeSessionTitle");function P(e){return b((e??"").replace(/\s+/g," "))}s(P,"titleFromPrompt");function q(e){return u(P(e))||"session"}s(q,"slugFromPrompt");function X(e){const t=e===void 0?void 0:process.env[e];if(t!==void 0&&t.trim()!=="")return t.trim();const n=g();return f(n[m(n)].light)}s(X,"lightModel");function y(){const e=process.env.CRTR_NAME_MODEL;if(e!==void 0&&e.trim()!=="")return{modelSpec:e.trim()};const t=g(),n=m(t);return{modelSpec:f(t[n].light),modelIntent:`${n}/light`}}s(y,"nameModelRequest");const v={type:"object",properties:{title:{type:"string",description:"A 2-8 word sentence-case title a person would recognize this session by in a list, with its punctuation intact, e.g. Payroll export mapping bug. No quotes, markdown, or trailing period."},name:{type:"string",description:"A 3-8 word kebab-case session name: lowercase words joined by single hyphens, e.g. refactor-auth-token-flow. No punctuation, quotes, or prose."},icon:{type:"string",description:"The Nerd Font glyph depicting this session, as a codepoint in U+XXXX form (e.g. U+F188)."}},required:["title","name","icon"],additionalProperties:!1};function S(e){const t=(e??"").trim();if(t==="")return"";const n=/^(?:u\+|0x|\\u\{?|&#x)?([0-9a-f]{4,6})\}?;?$/i.exec(t);if(n!==null){const i=Number.parseInt(n[1],16);if(i>=8192&&i<=1114111)try{return String.fromCodePoint(i)}catch{return""}return""}const o=[...t];return o.length>2?"":o[0].codePointAt(0)>=8192?t:""}s(S,"sanitizeIcon");async function M(e,t=c,n=T()??null){const o={name:"",title:"",icon:""},i={systemPrompt:E,userPrompt:N(e,t),...y(),timeoutMs:w,causedBy:n,tool:{name:"name_session",label:"Name session",description:"Record the title, name, and icon for this session. Call exactly once, then stop.",parameters:v,constrainedSampling:{type:"json_schema",strict:"prefer"}}},r=await h(i)??await h(i);if(r===null||typeof r!="object")return o;const a=r,d=b(typeof a.title=="string"?a.title:""),p=u(typeof a.name=="string"?a.name:"")||u(d),U=S(typeof a.icon=="string"?a.icon:"");return p!==""?{name:p,title:d,icon:U}:o}s(M,"headlessName");function $(e,t){return M(e,3e4,t)}s($,"headlessNameFromConversation");const _='You write GitHub issue titles. Given a free-text note (a todo, idea, or bug report), reply with ONLY a concise issue title: sentence case, 4-10 words, no trailing period, no quotes, no prefix like "Bug:" or "Idea:", no markdown. Capture the gist as an actionable title. Output JUST the title, nothing else.';function A(e){return`<note>
|
|
9
|
+
${e.slice(0,c)}
|
|
10
10
|
</note>
|
|
11
11
|
|
|
12
|
-
Write a concise GitHub issue title for the note above. Output JUST the title, nothing else.`}s(
|
|
13
|
-
`).map(o=>o.trim()).find(o=>o!=="")??"",n=t.length>80?`${t.slice(0,77).trimEnd()}\u2026`:t;return n!==""?n:"untitled"}s(
|
|
14
|
-
`).map(i=>i.trim()).find(i=>i!=="")??"";return o!==""?o.replace(/^["']|["']$/g,"").replace(/\.$/,""):
|
|
12
|
+
Write a concise GitHub issue title for the note above. Output JUST the title, nothing else.`}s(A,"titleUserPrompt");function F(e){const t=(e??"").split(`
|
|
13
|
+
`).map(o=>o.trim()).find(o=>o!=="")??"",n=t.length>80?`${t.slice(0,77).trimEnd()}\u2026`:t;return n!==""?n:"untitled"}s(F,"firstLineTitle");function D(e){return(e??"").toLowerCase().replace(/[^a-z0-9]+/g,"-").split("-").filter(n=>n!=="").slice(0,8).join("-")||"untitled"}s(D,"titleSlug");async function R(e){const t=(e??"").trim();if(t==="")return"untitled";try{const o=(await x({systemPrompt:_,userPrompt:A(t),...y(),timeoutMs:w})).split(`
|
|
14
|
+
`).map(i=>i.trim()).find(i=>i!=="")??"";return o!==""?o.replace(/^["']|["']$/g,"").replace(/\.$/,""):F(t)}catch{return F(t)}}s(R,"generateIssueTitle");export{R as generateIssueTitle,M as headlessName,$ as headlessNameFromConversation,X as lightModel,S as sanitizeIcon,u as sanitizeSessionName,b as sanitizeSessionTitle,q as slugFromPrompt,P as titleFromPrompt,D as titleSlug};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Ask Pi for a concise briefing of `conversation`. Invokes `onRecap` with
|
|
2
2
|
* the parsed string on success, or never on timeout, empty, or garbled output. */
|
|
3
|
-
export declare function generateRecap(conversation: string, onRecap: (briefing: string) => void, liveModel?: string, roadmap?: string): void;
|
|
3
|
+
export declare function generateRecap(conversation: string, onRecap: (briefing: string) => void, liveModel?: string, roadmap?: string, causedBy?: string | null): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var l=Object.defineProperty;var n=(t,e)=>l(t,"name",{value:e,configurable:!0});import{headlessText as c}from"./headless-pi.js";import{envRecapModelOverride as d}from"../../shared/env.js";const m=25e3,u="anthropic/claude-haiku-5-5",p=`You brief a developer returning to a paused coding-agent conversation. They run many agent sessions in parallel and have lost this one's thread: they no longer know what this conversation is about or what they originally asked for. The brief exists to solve exactly that \u2014 pinned above their input box, it must tell them at a glance what this conversation is FOR and where it actually stands. You are given the first and most recent messages of the literal user/agent back-and-forth (tool output omitted), and the agent's roadmap file when one exists.
|
|
2
2
|
|
|
3
3
|
Output EXACTLY two plain-text lines, nothing else:
|
|
4
4
|
Goal: <what was requested \u2014 the original ask / what this conversation is for>
|
|
@@ -14,7 +14,7 @@ Goal: Build the trimmed-v1 command-plugin seam (orchestrating phases).
|
|
|
14
14
|
State: Phase 1 landed; waiting on the core-seam worker's final.
|
|
15
15
|
|
|
16
16
|
Goal: Standing personal assistant \u2014 iMessage wakes, Reddit scans, small tasks.
|
|
17
|
-
State: Idle \u2014 waiting on you: hook pick, map export, Omi timing.`;function
|
|
17
|
+
State: Idle \u2014 waiting on you: hook pick, map export, Omi timing.`;function g(t,e){return`${e!==void 0&&e.trim()!==""?`<roadmap>
|
|
18
18
|
${e.trim()}
|
|
19
19
|
</roadmap>
|
|
20
20
|
|
|
@@ -22,6 +22,6 @@ ${e.trim()}
|
|
|
22
22
|
${t}
|
|
23
23
|
</conversation>
|
|
24
24
|
|
|
25
|
-
Write the two-line Goal:/State: briefing for the conversation above. Output JUST the two lines.`}n(
|
|
25
|
+
Write the two-line Goal:/State: briefing for the conversation above. Output JUST the two lines.`}n(g,"recapUserPrompt");function f(t){const e=d();return e!==void 0?e:t!==void 0&&t.trim()!==""?t.trim():u}n(f,"recapModel");function w(t){return t.split(`
|
|
26
26
|
`).map(e=>e.replace(/\s+/g," ").trim()).filter(e=>e!=="").join(`
|
|
27
|
-
`)}n(
|
|
27
|
+
`)}n(w,"parseRecap");function k(t,e,a,s,o){const i=(t??"").trim();i!==""&&c({systemPrompt:p,userPrompt:g(i,s),modelSpec:f(a),timeoutMs:m,...o===void 0?{}:{causedBy:o}}).then(h=>{const r=w(h);if(r!=="")try{e(r)}catch{}}).catch(()=>{})}n(k,"generateRecap");export{k as generateRecap};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var le=Object.defineProperty;var s=(e,r)=>le(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ce}from"./unsandboxed.js";import{existsSync as U}from"node:fs";import{conversationIdFromPath as _,conversationStore as h,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as ue}from"node:path";import{findNodeBySessionFile as fe,getNode as R,updateNode as N,beginExecution as we,ExecutionAlreadyLive as me,recordExecutionPid as de,abortExecution as F,endLiveExecution as he,unbindSession as G,recordLaunch as pe,setFrozen as ve,clearFrozen as K,fullName as _e}from"../canvas/index.js";import{emitEvent as W}from"../events/emit.js";import{consumeDeadlineOnWake as ye}from"../feed/messages.js";import{isParked as J,transition as A}from"./lifecycle.js";import{publishNotice as ke}from"./close.js";import{InputError as O}from"../io.js";import{buildPiArgv as y}from"./launch.js";import{buildReviveKickoff as ge,drainBearings as be,hasRetainedReports as Re,readGoal as E,readYieldMessage as Ee,RUNTIME_RESTART_CONTINUATION as xe}from"./kickoff.js";import{readRoadmap as j}from"./roadmap.js";import{encodeKickoffOrigin as Se,KICKOFF_ORIGIN_ENV as Ce}from"./stamp/protocol.js";import{headlessBrokerHost as $e,brokerLaunchJson as Ne}from"./host.js";import{isCloudRole as Fe}from"../canvas/person.js";import{asNodePerson as Ae}from"../../daemon/reconcilers/node-lifecycle/node-person.js";import{processRunner as Oe}from"./runner/process.js";import{runnerForEnvironment as V}from"./runner/index.js";import{MachineLaunchUncertainError as Pe,MachineOfflineError as Be}from"./runner/machine/ops.js";import{blaxelEnvironmentOf as X}from"./blaxel-environment.js";import{recordLaunchFailure as De}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as Y,remoteMachineEnvironmentOf as Me,checkBilledWake as Te,EnvironmentImagePending as Le,imageForWake as ze}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Ue,liveExecutionForNode as He,setExecutionLaunchJson as Ge}from"../canvas/executions.js";import{isDrained as Ke}from"../../daemon/drain.js";import{appMemoryFull as We,appMemoryTooSmall as Je,boundFleet as q,brokerCapReached as Q,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as je}from"./memory-admission.js";import{beginBootFaultAttempt as Ve,clearFault as Xe,hasAdmittedTurn as Ye,readFault as qe}from"../canvas/recovery.js";import{clearNodeLedger as Z,forkNodeLedger as Qe,noticeChangedWhileDone as Ze}from"./ledger.js";import{forkSourceNode as Ie,rootOfSpine as er}from"./nodes.js";import{ApiError as rr}from"../../api/errors.js";import{grantSnapshotMissing as ir}from"../../daemon/readiness.js";import{checkStart as tr}from"./start-check.js";import{isReviewCompanionBound as nr}from"../review/companion.js";import{assertProfileActive as ar}from"../profiles/manifest.js";import{isPidAlive as or}from"../canvas/pid.js";import{crtrHome as sr,jobDir as lr}from"../canvas/paths.js";import{contextDir as cr,ensureNodeDirs as ur,nodeAgentDir as fr}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as wr}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as mr}from"../command-hooks/transport/exec-lifecycle.js";async function dr(e,r){const i=e.pi_session_file,t=i?_(i):null;if(t===null)return{};try{const a=await h().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}s(dr,"resumeArgs");async function I(e){const r=_(e);if(r===null)return!1;try{return await h().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}s(I,"conversationExists");async function hr(e){const r=_(e);return r===null?!0:(await h().read(r)).entries.some(i=>i.type==="message")}s(hr,"sessionHasConversation");async function pr(e){const r=_(e);if(r===null)return!0;const i=(await h().header(r)).header.cwd;return typeof i!="string"||U(i)}s(pr,"sessionCwdExists");async function vr(e,r,i,t){const a=r.pi_session_file;if(!a||!await I(a))return{};const u=await fe(a);return u!==null&&u.node_id!==e&&or(u.pi_pid)?{}:t&&!await pr(a)?{}:await dr(r,i)}s(vr,"resumableSessionArgs");async function _r(e){return await j(e)===null&&await Ee(e)===null&&!await Re(e)}s(_r,"isUnstartedBirth");async function ci(e){const r=await E(e);if(r!==null&&r.trim()!=="")return!0;const i=await j(e);return i!==null&&i.trim()!==""}s(ci,"hasFreshGroundState");async function ui(e,r){const i=await ee(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}s(ui,"reviveNode");async function fi(e,r,i){return ee(e,{...r,viewerAttach:!0},i)}s(fi,"decideAttachRevive");async function ee(e,r,i){const t=Fe()?await R(e):null;return t===null?await re(e,r,i):await Ae({node_id:e,sub:t.sub??null,profile_id:t.profile_id??null},()=>re(e,r,i))}s(ee,"decideRevive");async function re(e,r,i){let t=await R(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await R(e)??t,t.run_id&&(await R(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);ar(t.profile_id),ce(t.grantee);const a=q(),u=t.grantee==="app:terminal"&&await ir();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&J(t))&&(await tr(t),await X(t.profile_id??null)!==null&&await Te(t)),await a.has(e))return await A(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&J(t))return{parked:!0};if(u){if(r.capacity==="refuse")throw new rr(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await ie(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const k=await Ke();if(k&&r.capacity==="refuse")throw new Error(`the daemon is drained for an import; ${e} cannot start until it ends`);const p=!k&&await a.reserveSlot(e);let o=null;if(p){try{o=await je(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Je(o);if(!p||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?We(o):Q(P().automaticReviveCap,await a.occupancy());return await ie(e,t,k?{reason:"drain"}:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await kr(e,t,r)}}finally{a.releaseReservation(e)}}s(re,"decideReviveAsCaller");async function ie(e,r,i){r.frozen_at==null&&(await ve(e,new Date().toISOString()),await he(e,{reason:"frozen"}),W({level:"info",event:"broker.frozen",node_id:e,fields:i}))}s(ie,"freezeForWait");async function yr(e,r){const i=await X(r.profile_id??null),t=await Me(r.profile_id??null)!==null;if(!(i!==null||t)&&!U(r.cwd)){const u=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new O({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:u})}return{blaxelEnvironment:i,remoteMachine:t}}s(yr,"assertRecordedCwdExists");async function kr(e,r,i){const{blaxelEnvironment:t,remoteMachine:a}=await yr(e,r),u=t!==null||a;r.host_kind!=="broker"&&(await N(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await nr(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await G(e),r.pi_session_id=null,r.pi_session_file=null);const p=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(p&&(typeof o!="string"||!ue(o)))throw new O({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=p&&typeof o=="string";if(w&&!await I(o))throw new O({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:te}=P();if(t!==null){const l=await ze(t);if(l.state==="pending")throw new Le(t,l.error)}const ne=t!==null?V("blaxel"):a?V("machine"):Oe;let f;try{f=await we(e,{daemonEpoch:q().epoch(),cap:te,...t!==null?{runner:"blaxel",release:Y()}:a?{runner:"machine",release:Y()}:{}})}catch(l){if(l instanceof Ue)throw Q(l.cap,l.live);if(l instanceof me)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw l}try{r.cycles=(r.cycles??0)+1,await N(e,{cycles:r.cycles});const x=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,d=w?{}:await vr(e,r,x,!u),g=d.resumeSessionPath!==void 0,B=g&&d.newCycle===!0,v=g&&!B,D=!g&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await _r(e),S=v&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await Ye(e)&&!await hr(d.resumeSessionPath)?(await E(e))?.trim():void 0,M=S!==void 0&&S!=="",ae=w||D||M,T=r.cycle_pending===!0||B;await N(e,{cycle_pending:T}),r.cycle_pending=T,!w&&!g&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await G(e),r.pi_session_id=null,r.pi_session_file=null);let c,m=null;const C=s(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await E(e),$=_(o);if($===null)throw new Error(`invalid fork source ${o}`);const se=(await h().header(await h().fork($,e))).path;c=y(r,{resumeSessionPath:se,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(m=C()),await Qe(e,(await Ie(o))?.node_id??null)}else if(M)c=y(r,{...d,prompt:S}),m=C();else if(v)c=y(r,{...d,...i.wakeReason==="runtime-restart-abort"?{prompt:xe}:{}}),i.wakeReason==="runtime-restart-abort"&&(m={type:"runtime",kind:"restart-continuation"});else if(D){const n=(await E(e))?.trim();c=y(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(m=C()),await Z(e)}else{const n=await be(r,f);c=y(r,{...d,prompt:await ge(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),m=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await Z(e)}c.env={...c.env,CRTR_SUBTREE:await er(e)},m!==null&&(c.env[Ce]=Se(m)),r.status==="done"&&r.last_settled_at!=null&&await Ze(e,r.last_settled_at),await A(e,r.intent==="refresh"?"refresh-launch":"revive"),(await qe(e))?.op!=="conversation_write_failed"&&await Xe(e,{preserveEpisode:!0});const L=await Ve(e);i.recovery!==!0&&i.viewerAttach!==!0&&await ye(e),await ur(e,r.grantee);const oe=wr(r.cwd,r.profile_id).plans.get("node:start")??[];await mr(oe,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await fr(e),contextDir:await cr(e),jobDir:lr(e)},runtime:{isBirth:ae,canvasHome:sr(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:f};const z=await Ne(e,c,r.cwd);await Ge(f,z);let b;try{const n=await He(e);if(b=await ne.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:v}),!u&&b.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){if(n instanceof Be)throw n;try{await A(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await ke(e,"notice.crash",`Child crashed \u2014 ${_e(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
1
|
+
var ce=Object.defineProperty;var s=(e,r)=>ce(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ue}from"./unsandboxed.js";import{existsSync as U}from"node:fs";import{conversationIdFromPath as _,conversationStore as h,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as fe}from"node:path";import{findNodeBySessionFile as we,getNode as R,updateNode as N,beginExecution as me,ExecutionAlreadyLive as de,recordExecutionPid as he,abortExecution as F,endLiveExecution as pe,unbindSession as G,recordLaunch as ve,setFrozen as _e,clearFrozen as K,fullName as ye}from"../canvas/index.js";import{emitEvent as W}from"../events/emit.js";import{consumeDeadlineOnWake as ke}from"../feed/messages.js";import{isParked as J,transition as A}from"./lifecycle.js";import{publishNotice as ge}from"./close.js";import{InputError as O}from"../io.js";import{buildPiArgv as y}from"./launch.js";import{buildReviveKickoff as be,drainBearings as Re,hasRetainedReports as Ee,readGoal as E,readYieldMessage as xe,RUNTIME_RESTART_CONTINUATION as Se}from"./kickoff.js";import{readRoadmap as j}from"./roadmap.js";import{encodeKickoffOrigin as Ce,KICKOFF_ORIGIN_ENV as $e}from"./stamp/protocol.js";import{carryInitialInput as V}from"../runs/initial-input.js";import{headlessBrokerHost as Ne,brokerLaunchJson as Fe}from"./host.js";import{isCloudRole as Ae}from"../canvas/person.js";import{asNodePerson as Oe}from"../../daemon/reconcilers/node-lifecycle/node-person.js";import{processRunner as Pe}from"./runner/process.js";import{runnerForEnvironment as X}from"./runner/index.js";import{MachineLaunchUncertainError as Be,MachineOfflineError as De}from"./runner/machine/ops.js";import{blaxelEnvironmentOf as Y}from"./blaxel-environment.js";import{recordLaunchFailure as Me}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as q,remoteMachineEnvironmentOf as Te,checkBilledWake as Le,EnvironmentImagePending as ze,imageForWake as Ue}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as He,liveExecutionForNode as Ge,setExecutionLaunchJson as Ke}from"../canvas/executions.js";import{isDrained as We}from"../../daemon/drain.js";import{appMemoryFull as Je,appMemoryTooSmall as je,boundFleet as Q,brokerCapReached as Z,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as Ve}from"./memory-admission.js";import{beginBootFaultAttempt as Xe,clearFault as Ye,hasAdmittedTurn as qe,readFault as Qe}from"../canvas/recovery.js";import{clearNodeLedger as I,forkNodeLedger as Ze,noticeChangedWhileDone as Ie}from"./ledger.js";import{forkSourceNode as er,rootOfSpine as rr}from"./nodes.js";import{ApiError as ir}from"../../api/errors.js";import{grantSnapshotMissing as tr}from"../../daemon/readiness.js";import{checkStart as nr}from"./start-check.js";import{isReviewCompanionBound as ar}from"../review/companion.js";import{assertProfileActive as or}from"../profiles/manifest.js";import{isPidAlive as sr}from"../canvas/pid.js";import{crtrHome as lr,jobDir as cr}from"../canvas/paths.js";import{contextDir as ur,ensureNodeDirs as fr,nodeAgentDir as wr}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as mr}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as dr}from"../command-hooks/transport/exec-lifecycle.js";async function hr(e,r){const i=e.pi_session_file,t=i?_(i):null;if(t===null)return{};try{const a=await h().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}s(hr,"resumeArgs");async function ee(e){const r=_(e);if(r===null)return!1;try{return await h().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}s(ee,"conversationExists");async function pr(e){const r=_(e);return r===null?!0:(await h().read(r)).entries.some(i=>i.type==="message")}s(pr,"sessionHasConversation");async function vr(e){const r=_(e);if(r===null)return!0;const i=(await h().header(r)).header.cwd;return typeof i!="string"||U(i)}s(vr,"sessionCwdExists");async function _r(e,r,i,t){const a=r.pi_session_file;if(!a||!await ee(a))return{};const u=await we(a);return u!==null&&u.node_id!==e&&sr(u.pi_pid)?{}:t&&!await vr(a)?{}:await hr(r,i)}s(_r,"resumableSessionArgs");async function yr(e){return await j(e)===null&&await xe(e)===null&&!await Ee(e)}s(yr,"isUnstartedBirth");async function fi(e){const r=await E(e);if(r!==null&&r.trim()!=="")return!0;const i=await j(e);return i!==null&&i.trim()!==""}s(fi,"hasFreshGroundState");async function wi(e,r){const i=await re(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}s(wi,"reviveNode");async function mi(e,r,i){return re(e,{...r,viewerAttach:!0},i)}s(mi,"decideAttachRevive");async function re(e,r,i){const t=Ae()?await R(e):null;return t===null?await ie(e,r,i):await Oe({node_id:e,sub:t.sub??null,profile_id:t.profile_id??null},()=>ie(e,r,i))}s(re,"decideRevive");async function ie(e,r,i){let t=await R(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await R(e)??t,t.run_id&&(await R(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);or(t.profile_id),ue(t.grantee);const a=Q(),u=t.grantee==="app:terminal"&&await tr();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&J(t))&&(await nr(t),await Y(t.profile_id??null)!==null&&await Le(t)),await a.has(e))return await A(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&J(t))return{parked:!0};if(u){if(r.capacity==="refuse")throw new ir(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await te(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const k=await We();if(k&&r.capacity==="refuse")throw new Error(`the daemon is drained for an import; ${e} cannot start until it ends`);const p=!k&&await a.reserveSlot(e);let o=null;if(p){try{o=await Ve(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw je(o);if(!p||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?Je(o):Z(P().automaticReviveCap,await a.occupancy());return await te(e,t,k?{reason:"drain"}:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await gr(e,t,r)}}finally{a.releaseReservation(e)}}s(ie,"decideReviveAsCaller");async function te(e,r,i){r.frozen_at==null&&(await _e(e,new Date().toISOString()),await pe(e,{reason:"frozen"}),W({level:"info",event:"broker.frozen",node_id:e,fields:i}))}s(te,"freezeForWait");async function kr(e,r){const i=await Y(r.profile_id??null),t=await Te(r.profile_id??null)!==null;if(!(i!==null||t)&&!U(r.cwd)){const u=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new O({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:u})}return{blaxelEnvironment:i,remoteMachine:t}}s(kr,"assertRecordedCwdExists");async function gr(e,r,i){const{blaxelEnvironment:t,remoteMachine:a}=await kr(e,r),u=t!==null||a;r.host_kind!=="broker"&&(await N(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await ar(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await G(e),r.pi_session_id=null,r.pi_session_file=null);const p=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(p&&(typeof o!="string"||!fe(o)))throw new O({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=p&&typeof o=="string";if(w&&!await ee(o))throw new O({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:ne}=P();if(t!==null){const l=await Ue(t);if(l.state==="pending")throw new ze(t,l.error)}const ae=t!==null?X("blaxel"):a?X("machine"):Pe;let f;try{f=await me(e,{daemonEpoch:Q().epoch(),cap:ne,...t!==null?{runner:"blaxel",release:q()}:a?{runner:"machine",release:q()}:{}})}catch(l){if(l instanceof He)throw Z(l.cap,l.live);if(l instanceof de)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw l}try{r.cycles=(r.cycles??0)+1,await N(e,{cycles:r.cycles});const x=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,d=w?{}:await _r(e,r,x,!u),g=d.resumeSessionPath!==void 0,B=g&&d.newCycle===!0,v=g&&!B,D=!g&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await yr(e),S=v&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await qe(e)&&!await pr(d.resumeSessionPath)?(await E(e))?.trim():void 0,M=S!==void 0&&S!=="",oe=w||D||M,T=r.cycle_pending===!0||B;await N(e,{cycle_pending:T}),r.cycle_pending=T,!w&&!g&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await G(e),r.pi_session_id=null,r.pi_session_file=null);let c,m=null;const C=s(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await E(e),$=_(o);if($===null)throw new Error(`invalid fork source ${o}`);const le=(await h().header(await h().fork($,e))).path;c=y(r,{resumeSessionPath:le,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(m=C()),await Ze(e,(await er(o))?.node_id??null)}else if(M)c=y(r,{...d,prompt:S}),m=C(),await V(c,r);else if(v)c=y(r,{...d,...i.wakeReason==="runtime-restart-abort"?{prompt:Se}:{}}),i.wakeReason==="runtime-restart-abort"&&(m={type:"runtime",kind:"restart-continuation"});else if(D){const n=(await E(e))?.trim();c=y(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(m=C(),await V(c,r)),await I(e)}else{const n=await Re(r,f);c=y(r,{...d,prompt:await be(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),m=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await I(e)}c.env={...c.env,CRTR_SUBTREE:await rr(e)},m!==null&&(c.env[$e]=Ce(m)),r.status==="done"&&r.last_settled_at!=null&&await Ie(e,r.last_settled_at),await A(e,r.intent==="refresh"?"refresh-launch":"revive"),(await Qe(e))?.op!=="conversation_write_failed"&&await Ye(e,{preserveEpisode:!0});const L=await Xe(e);i.recovery!==!0&&i.viewerAttach!==!0&&await ke(e),await fr(e,r.grantee);const se=mr(r.cwd,r.profile_id).plans.get("node:start")??[];await dr(se,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await wr(e),contextDir:await ur(e),jobDir:cr(e)},runtime:{isBirth:oe,canvasHome:lr(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:f};const z=await Fe(e,c,r.cwd);await Ke(f,z);let b;try{const n=await Ge(e);if(b=await ae.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:v}),!u&&b.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){if(n instanceof De)throw n;try{await A(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await ge(e,"notice.crash",`Child crashed \u2014 ${ye(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
2
2
|
|
|
3
|
-
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await F(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await
|
|
3
|
+
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await F(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await ve(e,new Date().toISOString()),u)return await K(e),{window:null,session:r.tmux_session??null,resumed:v,faultExplanation:L.explanation,outcome:"launched"};if(await he(f,e,b.pid)==="shutdown")throw await F(f,{reason:"superseded"}),Ne.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await K(e),{window:null,session:r.tmux_session??null,resumed:v,launch:b,faultExplanation:L.explanation,outcome:"launched"}}catch(l){throw l instanceof Be||(await F(f,{reason:"launch_failed"}),await Me(f,l).catch(x=>{W({level:"warn",event:"broker.launch_failure.unrecorded",node_id:e,error:x})})),l}}s(gr,"launchRevive");export{kr as assertRecordedCwdExists,mi as decideAttachRevive,fi as hasFreshGroundState,hr as resumeArgs,wi as reviveNode};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var me=Object.defineProperty;var d=(e,o)=>me(e,"name",{value:o,configurable:!0});import{accessSync as he,constants as pe}from"node:fs";import{isAbsolute as _e,resolve as ke,join as ve}from"node:path";import{appSpace as ge}from"../layout.js";import{ApiError as ne}from"../../api/errors.js";import{spawnNode as ye,forkSourceNode as be,currentNodeContext as xe,rootOfSpine as $e,newNodeId as Se,preflightNodeId as Ce}from"./nodes.js";import{resolveProfileOperand as Ee}from"../profiles/manifest.js";import{selectProfileForCwd as Re,selectProfileForCwdReadOnly as Oe}from"../profiles/select.js";import{buildLaunchSpecAsync as oe,buildPiArgv as Fe}from"./launch.js";import{runsOnBlaxel as Ie,sandboxWorktreeRequest as Pe}from"../../daemon/api/environment-of.js";import{createManagedWorktreeAsync as Be,rollbackManagedWorktreeAsync as De}from"../worktree-mutation-async.js";import{usage as w,brokerLaunchFailed as D}from"../errors.js";import{writeGoal as Ne}from"./kickoff.js";import{appendSituationalContext as Le,formatSituationalProse as Me}from"./situational-context.js";import{ensureRoadmap as Te}from"./roadmap.js";import{buildWakeBearings as Ae}from"./bearings.js";import{encodeKickoffOrigin as We,KICKOFF_ORIGIN_ENV as je}from"./stamp/protocol.js";import{ExecutionCapReached as ze,beginExecution as He,crtrHome as Ke,getNode as u,fullName as re,jobDir as Ge,recordExecutionPid as Ue,abortExecution as j,setFrozen as z}from"../canvas/index.js";import{contextDir as H,nodeAgentDir as K}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ve}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as S}from"../conversation-store/index.js";import{appMemoryTooSmall as Xe,boundFleet as qe,brokerThresholdsForDaemon as te}from"./fleet.js";import{admitBrokerMemory as Ye}from"./memory-admission.js";import{emitEvent as L}from"../events/emit.js";import{blaxelEnvironmentOf as Je}from"./blaxel-environment.js";import{openViewerWindow as Qe,focusOf as Ze,windowOfPane as en}from"./placement.js";import{awaitBrokerViewSocket as nn}from"./view-socket.js";import{readLogSnapshot as on}from"../events/read.js";import{transition as k}from"./lifecycle.js";import{beginBootFaultAttempt as rn}from"../canvas/recovery.js";import{headlessBrokerHost as G}from"./host.js";import{ensureDaemon as tn}from"../../daemon/manage.js";import{readConfig as an}from"../config.js";import{modelRequestFromConfig as dn,unregisteredConcreteModel as sn,unroutableConcreteModel as ln}from"../model-routes.js";import{openModelRegistry as cn}from"./model-registry.js";import{MODEL_SPEC_NEXT as un}from"./model-selection.js";import{forkNodeLedger as fn}from"./ledger.js";import{appRungForGrant as wn}from"../llm/app-rungs.js";import{APP_FAMILY as U}from"../model-routes.js";import{discoverLifecycleHookRegistry as mn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as hn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as pn}from"../async-array.js";import{checkStart as _n}from"./start-check.js";function v(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(v,"launchFailureOutcome");async function kn(e,o,a){try{return await G.launch(e,o,a)}catch(r){try{await k(e,"crash",{reason:"launch_failed",outcome:v(r)})}catch{}const t=r.message;throw D(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(kn,"launchBrokerOrCrash");function vn(e){return on({nodeId:e,component:"broker",pattern:"broker.startup."},!1).items.flatMap(a=>a.kind==="event"&&a.envelope.event.startsWith("broker.startup.")&&a.envelope.event!=="broker.startup.warning"?[a.envelope.event.slice(15)]:[]).at(-1)??null}d(vn,"lastStartupStep");function gn(e,o){const a=vn(e),r=a===null?"it had logged no startup step":`the last startup step it logged was \`${a}\``;if(o.reason==="exited"){const{code:t,signal:s}=o.status;return{text:`exited (code ${t??"null"}, signal ${s??"null"}) before binding its view socket; ${r}`,fields:{reason:"exited",code:t,signal:s,last_startup_step:a}}}return{text:`was still starting after ${Math.round(o.waitedMs/1e3)} s without binding its view socket, so the launcher stopped it; ${r}`,fields:{reason:"timeout",waited_ms:o.waitedMs,last_startup_step:a}}}d(gn,"notReadyDescription");async function yn(e,o){try{await k(e,"crash",{reason:"launch_failed",outcome:v(o)})}catch{}try{G.teardown(e)}catch{}}d(yn,"crashAndTearDown");async function bn(e){const o=(await S().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw w(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw w(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(bn,"resolveSessionUuid");async function ie(e){const o=e.trim();if(o==="")throw w("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=N(_e(o)?o:ke(process.cwd(),o));if(r===null)throw w(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await S().header(r)).path}const a=await u(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw w(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=N(r);if(t===null)throw w(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await S().header(t)).path}return await bn(o)}d(ie,"resolveForkSource");async function xn(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?Ee(e).profileId:o!==null?(await u(o))?.profile_id??null:r.readOnlySelection===!0?Oe(a):Re(a)}d(xn,"resolveProfileId");function ae(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return dn(e.model,o,e.modelExact===!0)}d(ae,"requestFromLaunch");async function de(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await wn(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...l}=e.env??{};return{...e,model:t.model,modelIntent:{family:U,strength:t.strength},modelExact:void 0,env:{...l,CRTR_MODEL_INTENT:`${U}/${t.strength}`}}}d(de,"appPaidLaunch");async function se(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==U)return;const r=await sn(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await cn(),o);if(r!==void 0)throw w(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:un});const t=await ln(e,o);if(t!==void 0)throw w(`model '${t.spec}' is registered but no configured model route offers it, so no turn could be served.`,{received:t.spec,next:"Pick a model from your configured routes (`crtr sys config get modelLadders`), or add this one to a ladder or route."})}d(se,"assertLaunchModelRegistered");function $n(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d($n,"resolveSpawner");async function le(e,o,a){try{tn()}catch{}const r=xe(),t=e.root===!0,s=$n(e.parent,r.nodeId??null,t),l=e.mode??"base",g=e.rootLifecycle??(t?"resident":"terminal"),ce=t&&g==="resident",R=s===null?null:await u(s),V=e.creator===void 0||e.creator===null?null:await u(e.creator);e.nodeId!==void 0&&await Ce(e.nodeId);const y=e.forkFrom!==void 0?await ie(e.forkFrom):void 0,M=y===void 0?null:await be(y),T=await pn([R,V,M],async f=>f?.isolated===!0||f?.run_id!=null&&(await u(f.run_id))?.isolated===!0);if(T&&e.isolated===!1)throw new ne(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const O=T||e.isolated===!0;if(O&&e.worktree===!0)throw new ne(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const C=e.worktree===!0,m=O||C?e.nodeId??await Se():e.nodeId,F=O?e.run!==void 0&&t&&!T?e.cwd:ve(ge(e.run?.grantee??R?.grantee??"app:terminal").nodes,m):e.cwd,h=await xn(e.profile,s,F),X=e.run?.grant_id??R?.grant_id??null,E=e.run??V??R??M,q=await de((await oe(e.kind,l,{lifecycle:g,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:F,profileId:h,app:E?.grantee??"app:terminal"})).launch,X,e.model);await se(ae(q),{cwd:F,profileId:h}),await _n({grantee:E?.grantee??"app:terminal",sub:E?.sub,grant_id:E?.grant_id});const Y=M?.node_id??null;let b,I=F;const A=C&&await Ie(h)?await Pe(h,e.worktreeCwd??e.cwd,m,e.worktreeBase):void 0;try{C&&A===void 0&&(b=await Be(e.worktreeCwd??e.cwd,m,e.worktreeBase),I=b.path);const f=C?await de((await oe(e.kind,l,{lifecycle:g,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:I,profileId:h,app:E?.grantee??"app:terminal"})).launch,X,e.model):q;A!==void 0&&(f.worktree=A),C&&await se(ae(f),{cwd:I,profileId:h});const n=await ye({kind:e.kind,mode:l,lifecycle:g,cwd:I,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:Y,spawnedBy:t?s??void 0:void 0,profile_id:h,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:O,...e.run===void 0?{}:{run:e.run},...e.causedBy===void 0?{}:{causedBy:e.causedBy},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:y,modelOverride:e.model===void 0?void 0:f.model,...b!==void 0?{managedWorktree:b}:{},...m!==void 0?{nodeId:m}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:f});if(a?.(n.node_id),e.forkFrom!==void 0)try{await fn(n.node_id,Y??null)}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}if(await Ne(n.node_id,e.prompt),e.situationalContext!==void 0&&await Le(n.node_id,Me(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}const W=e.prompt!=="",ue=`${W&&e.wakeOrigin!==void 0?`${Ae(e.wakeOrigin)}
|
|
1
|
+
var me=Object.defineProperty;var d=(e,o)=>me(e,"name",{value:o,configurable:!0});import{accessSync as he,constants as pe}from"node:fs";import{isAbsolute as _e,resolve as ke,join as ve}from"node:path";import{appSpace as ge}from"../layout.js";import{ApiError as ne}from"../../api/errors.js";import{spawnNode as ye,forkSourceNode as be,currentNodeContext as xe,rootOfSpine as $e,newNodeId as Se,preflightNodeId as Ce}from"./nodes.js";import{resolveProfileOperand as Ee}from"../profiles/manifest.js";import{selectProfileForCwd as Re,selectProfileForCwdReadOnly as Oe}from"../profiles/select.js";import{buildLaunchSpecAsync as oe,buildPiArgv as Ie}from"./launch.js";import{runsOnBlaxel as Fe,sandboxWorktreeRequest as Pe}from"../../daemon/api/environment-of.js";import{createManagedWorktreeAsync as Be,rollbackManagedWorktreeAsync as De}from"../worktree-mutation-async.js";import{usage as w,brokerLaunchFailed as D}from"../errors.js";import{writeGoal as Ne}from"./kickoff.js";import{appendSituationalContext as Le,formatSituationalProse as Me}from"./situational-context.js";import{ensureRoadmap as Te}from"./roadmap.js";import{buildWakeBearings as Ae}from"./bearings.js";import{encodeKickoffOrigin as We,KICKOFF_ORIGIN_ENV as je}from"./stamp/protocol.js";import{carryInitialInput as ze}from"../runs/initial-input.js";import{ExecutionCapReached as He,beginExecution as Ke,crtrHome as Ge,getNode as u,fullName as re,jobDir as Ue,recordExecutionPid as Ve,abortExecution as j,setFrozen as z}from"../canvas/index.js";import{contextDir as H,nodeAgentDir as K}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Xe}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as S}from"../conversation-store/index.js";import{appMemoryTooSmall as qe,boundFleet as Ye,brokerThresholdsForDaemon as te}from"./fleet.js";import{admitBrokerMemory as Je}from"./memory-admission.js";import{emitEvent as L}from"../events/emit.js";import{blaxelEnvironmentOf as Qe}from"./blaxel-environment.js";import{openViewerWindow as Ze,focusOf as en,windowOfPane as nn}from"./placement.js";import{awaitBrokerViewSocket as on}from"./view-socket.js";import{readLogSnapshot as rn}from"../events/read.js";import{transition as v}from"./lifecycle.js";import{beginBootFaultAttempt as tn}from"../canvas/recovery.js";import{headlessBrokerHost as G}from"./host.js";import{ensureDaemon as an}from"../../daemon/manage.js";import{readConfig as dn}from"../config.js";import{modelRequestFromConfig as sn,unregisteredConcreteModel as ln,unroutableConcreteModel as cn}from"../model-routes.js";import{openModelRegistry as un}from"./model-registry.js";import{MODEL_SPEC_NEXT as fn}from"./model-selection.js";import{forkNodeLedger as wn}from"./ledger.js";import{appRungForGrant as mn}from"../llm/app-rungs.js";import{APP_FAMILY as U}from"../model-routes.js";import{discoverLifecycleHookRegistry as hn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as pn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as _n}from"../async-array.js";import{checkStart as kn}from"./start-check.js";function g(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(g,"launchFailureOutcome");async function vn(e,o,a){try{return await G.launch(e,o,a)}catch(r){try{await v(e,"crash",{reason:"launch_failed",outcome:g(r)})}catch{}const t=r.message;throw D(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(vn,"launchBrokerOrCrash");function gn(e){return rn({nodeId:e,component:"broker",pattern:"broker.startup."},!1).items.flatMap(a=>a.kind==="event"&&a.envelope.event.startsWith("broker.startup.")&&a.envelope.event!=="broker.startup.warning"?[a.envelope.event.slice(15)]:[]).at(-1)??null}d(gn,"lastStartupStep");function yn(e,o){const a=gn(e),r=a===null?"it had logged no startup step":`the last startup step it logged was \`${a}\``;if(o.reason==="exited"){const{code:t,signal:s}=o.status;return{text:`exited (code ${t??"null"}, signal ${s??"null"}) before binding its view socket; ${r}`,fields:{reason:"exited",code:t,signal:s,last_startup_step:a}}}return{text:`was still starting after ${Math.round(o.waitedMs/1e3)} s without binding its view socket, so the launcher stopped it; ${r}`,fields:{reason:"timeout",waited_ms:o.waitedMs,last_startup_step:a}}}d(yn,"notReadyDescription");async function bn(e,o){try{await v(e,"crash",{reason:"launch_failed",outcome:g(o)})}catch{}try{G.teardown(e)}catch{}}d(bn,"crashAndTearDown");async function xn(e){const o=(await S().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw w(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw w(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(xn,"resolveSessionUuid");async function ie(e){const o=e.trim();if(o==="")throw w("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=N(_e(o)?o:ke(process.cwd(),o));if(r===null)throw w(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await S().header(r)).path}const a=await u(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw w(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=N(r);if(t===null)throw w(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await S().header(t)).path}return await xn(o)}d(ie,"resolveForkSource");async function $n(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?Ee(e).profileId:o!==null?(await u(o))?.profile_id??null:r.readOnlySelection===!0?Oe(a):Re(a)}d($n,"resolveProfileId");function ae(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return sn(e.model,o,e.modelExact===!0)}d(ae,"requestFromLaunch");async function de(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await mn(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...l}=e.env??{};return{...e,model:t.model,modelIntent:{family:U,strength:t.strength},modelExact:void 0,env:{...l,CRTR_MODEL_INTENT:`${U}/${t.strength}`}}}d(de,"appPaidLaunch");async function se(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==U)return;const r=await ln(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await un(),o);if(r!==void 0)throw w(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:fn});const t=await cn(e,o);if(t!==void 0)throw w(`model '${t.spec}' is registered but no configured model route offers it, so no turn could be served.`,{received:t.spec,next:"Pick a model from your configured routes (`crtr sys config get modelLadders`), or add this one to a ladder or route."})}d(se,"assertLaunchModelRegistered");function Sn(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d(Sn,"resolveSpawner");async function le(e,o,a){try{an()}catch{}const r=xe(),t=e.root===!0,s=Sn(e.parent,r.nodeId??null,t),l=e.mode??"base",y=e.rootLifecycle??(t?"resident":"terminal"),ce=t&&y==="resident",R=s===null?null:await u(s),V=e.creator===void 0||e.creator===null?null:await u(e.creator);e.nodeId!==void 0&&await Ce(e.nodeId);const b=e.forkFrom!==void 0?await ie(e.forkFrom):void 0,M=b===void 0?null:await be(b),T=await _n([R,V,M],async f=>f?.isolated===!0||f?.run_id!=null&&(await u(f.run_id))?.isolated===!0);if(T&&e.isolated===!1)throw new ne(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const O=T||e.isolated===!0;if(O&&e.worktree===!0)throw new ne(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const C=e.worktree===!0,m=O||C?e.nodeId??await Se():e.nodeId,I=O?e.run!==void 0&&t&&!T?e.cwd:ve(ge(e.run?.grantee??R?.grantee??"app:terminal").nodes,m):e.cwd,h=await $n(e.profile,s,I),X=e.run?.grant_id??R?.grant_id??null,E=e.run??V??R??M,q=await de((await oe(e.kind,l,{lifecycle:y,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:I,profileId:h,app:E?.grantee??"app:terminal"})).launch,X,e.model);await se(ae(q),{cwd:I,profileId:h}),await kn({grantee:E?.grantee??"app:terminal",sub:E?.sub,grant_id:E?.grant_id});const Y=M?.node_id??null;let x,F=I;const A=C&&await Fe(h)?await Pe(h,e.worktreeCwd??e.cwd,m,e.worktreeBase):void 0;try{C&&A===void 0&&(x=await Be(e.worktreeCwd??e.cwd,m,e.worktreeBase),F=x.path);const f=C?await de((await oe(e.kind,l,{lifecycle:y,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:F,profileId:h,app:E?.grantee??"app:terminal"})).launch,X,e.model):q;A!==void 0&&(f.worktree=A),C&&await se(ae(f),{cwd:F,profileId:h});const n=await ye({kind:e.kind,mode:l,lifecycle:y,cwd:F,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:Y,spawnedBy:t?s??void 0:void 0,profile_id:h,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:O,...e.run===void 0?{}:{run:e.run},...e.causedBy===void 0?{}:{causedBy:e.causedBy},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:b,modelOverride:e.model===void 0?void 0:f.model,...x!==void 0?{managedWorktree:x}:{},...m!==void 0?{nodeId:m}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:f});if(a?.(n.node_id),e.forkFrom!==void 0)try{await wn(n.node_id,Y??null)}catch(i){throw await v(n.node_id,"crash",{reason:"launch_failed",outcome:g(i)}),i}if(await Ne(n.node_id,e.prompt),e.situationalContext!==void 0&&await Le(n.node_id,Me(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await v(n.node_id,"crash",{reason:"launch_failed",outcome:g(i)}),i}const W=e.prompt!=="",ue=`${W&&e.wakeOrigin!==void 0?`${Ae(e.wakeOrigin)}
|
|
2
2
|
|
|
3
|
-
`:""}${e.prompt}`;l==="orchestrator"&&await Te(n.node_id,{goal:e.prompt.trim()}),await
|
|
3
|
+
`:""}${e.prompt}`;l==="orchestrator"&&await Te(n.node_id,{goal:e.prompt.trim()}),await Cn(n);let J;if(b!==void 0)try{const i=N(b);if(i===null)throw new Error(`invalid fork source ${b}`);const c=await S().fork(i,n.node_id);J=(await S().header(c)).path}catch(i){throw await v(n.node_id,"crash",{reason:"launch_failed",outcome:g(i)}),i}const p=Ie(n,{prompt:ue,resumeSessionPath:J});if(p.env={...p.env,CRTR_SUBTREE:await $e(n.node_id)},W){const i=e.wakeOrigin!==void 0?{type:"runtime",kind:"wake",wake:e.wakeOrigin}:{type:"runtime",kind:"kickoff",...n.spawned_by!=null&&n.spawned_by!==""?{spawnedBy:n.spawned_by}:{}};p.env[je]=We(i),await ze(p,n)}const _=Ye();if(await Qe(n.profile_id??null)!==null)return await z(n.node_id,new Date().toISOString()),L({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"remote_environment"}}),{node:await u(n.node_id),frozen:!0,window:null,session:null};const Q=await _.reserveSlot(n.node_id),k=Q?await Je(n.node_id):null;if(k?.verdict==="too_small"){_.releaseReservation(n.node_id);const i=qe(k);throw await v(n.node_id,"crash",{reason:"launch_failed",outcome:g(i)}),i}if(!Q||k?.verdict==="denied")return k?.verdict==="denied"&&_.releaseReservation(n.node_id),await z(n.node_id,new Date().toISOString()),L({level:"info",event:"broker.frozen",node_id:n.node_id,fields:k?.verdict==="denied"?{reason:"app_memory",free_bytes:k.free_bytes,needed_bytes:k.needed_bytes}:{reason:"broker_cap",live_count:await _.occupancy(),hard_cap:te().automaticReviveCap}}),{node:await u(n.node_id),frozen:!0,window:null,session:null};const fe=await tn(n.node_id),{automaticReviveCap:we}=te();let $;try{$=await Ke(n.node_id,{daemonEpoch:_.epoch(),cap:we})}catch(i){if(!(i instanceof He))throw i;return _.releaseReservation(n.node_id),await z(n.node_id,new Date().toISOString()),L({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"broker_cap",live_count:i.live,hard_cap:i.cap}}),{node:await u(n.node_id),frozen:!0,window:null,session:null}}p.env={...p.env,CRTR_EXECUTION_ID:$};let P;try{P=await vn(n.node_id,p,{cwd:n.cwd,name:re(n),resuming:!1})}catch(i){throw await j($,{reason:"launch_failed"}),i}finally{_.releaseReservation(n.node_id)}if(P.pid===null){const i=new Error(`broker host returned no pid for ${n.node_id}`);throw await j($,{reason:"launch_failed"}),await v(n.node_id,"crash",{reason:"launch_failed",outcome:g(i)}),D(`failed to launch the broker engine for ${n.node_id} (${n.name}) \u2014 the node was not started.`,`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then verify the pi engine can start in this environment.`)}if(await Ve($,n.node_id,P.pid)==="shutdown")throw await j($,{reason:"superseded"}),G.teardown(n.node_id),D(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(ce&&e.readiness==="await"){const i=await on(n.node_id,P.exited);if(!i.ready){const c=yn(n.node_id,i);L({level:"error",event:"broker.launch.not_ready",node_id:n.node_id,fields:c.fields});const B=await fe.explanation();throw await bn(n.node_id,new Error(B??c.text)),D(B!==null?`the root broker ${n.node_id} could not start \u2014 ${B}`:`the root broker ${n.node_id} ${c.text} \u2014 it was not started.`,B!==null?"Resolve the cause named above, then retry.":`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then retry.`)}}let Z=null,ee=null;if(!t&&s!==null&&dn("user").auto_open_child_viewers)try{const i=await en(s);if(i!==null&&i.pane!==null&&i.pane!==""){const c=await Ze(n.node_id,i.session??"",{name:re(n),cwd:e.cwd,besidePane:i.pane,waitForBroker:!0,initialWhip:W});c!==null&&c.pane!==null&&c.pane!==""&&(ee=c.session,Z=nn(c.pane))}}catch{}return{node:await u(n.node_id),frozen:!1,window:Z,session:ee}}catch(f){throw x!==void 0&&m!==void 0&&await u(m)===null&&await De(x),f}}d(le,"spawnChildPrepared");async function yo(e){return le(e)}d(yo,"spawnChild");async function Cn(e){const o=hn(e.cwd,e.profile_id).plans.get("node:start")??[];await pn(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:await K(e.node_id),contextDir:await H(e.node_id),jobDir:Ue(e.node_id)},runtime:{isBirth:!0,canvasHome:Ge(),profile:e.profile_id??null}})}d(Cn,"invokeBirthLifecycleHooks");const En=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function bo(e,o,a){const r=await u(e);if(r===null)throw w(`unknown node: ${e}`,{received:e,next:"List nodes and pass the id of a node with a captured pi session."});const t=await ie(e),s=await H(e);try{await S().header(N(t)),he(s,pe.R_OK)}catch(l){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${l.message}`)}return le({kind:r.kind,mode:"base",cwd:r.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:r.profile_id,model:r.model_override??void 0,...o===void 0?{}:{scopes:o}},async l=>{const y=await H(l);Xe(await K(e),s,await K(l),y,En)})}d(bo,"forkNode");export{de as appPaidLaunch,se as assertLaunchModelRegistered,bo as forkNode,Cn as invokeBirthLifecycleHooks,ie as resolveForkSource,$n as resolveProfileId,Sn as resolveSpawner,yo as spawnChild,le as spawnChildPrepared};
|
|
@@ -16,4 +16,6 @@ export declare function generateAndCommitRecapName(nodeId: string, conversation:
|
|
|
16
16
|
title: string;
|
|
17
17
|
icon: string;
|
|
18
18
|
kind: string;
|
|
19
|
-
}, isStillAutomatic: () => boolean,
|
|
19
|
+
}, isStillAutomatic: () => boolean,
|
|
20
|
+
/** The turn cause the caller took with `conversation`, before any await; null names none. */
|
|
21
|
+
causedBy: string | null, onNamed?: (editorLabel: string) => void): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var f=Object.defineProperty;var
|
|
1
|
+
var f=Object.defineProperty;var o=(e,t)=>f(e,"name",{value:t,configurable:!0});import{localClient as l}from"../api/node-transport.js";import{brokerExecutionId as s,brokerExtensionState as m,commitBrokerGeneratedName as p}from"../core/runtime/broker/daemon-ops.js";import{publishNodeNamed as b}from"../core/runtime/broker/node-named.js";import{currentOrPendingCausedBy as h}from"../core/runtime/broker/turn-cause.js";import{headlessName as x,headlessNameFromConversation as N,sanitizeSessionName as y,sanitizeSessionTitle as L,slugFromPrompt as k,titleFromPrompt as C}from"../core/runtime/naming.js";async function P(e,t){const n=t.trim();return n===""?!1:(await l({autostart:!1}).captureBrokerGoal(e,{text:n,expected_execution_id:s()})).captured}o(P,"captureGoalIfAbsent");async function S(e){return(await m(e)).roadmap}o(S,"readRoadmap");function u(e,t){return{description:y(t.name)||k(e),title:L(t.title)||C(e),icon:t.icon}}o(u,"generatedLabel");function w(e,t,n){const r=t.trim();if(r==="")return;const c=h()??null;m(e).then(i=>{if((i.node.description??"").trim()==="")return x(r,void 0,c).then(a=>p(e,{kind:"initial",...u(r,a)}))}).then(i=>{!i?.applied||i.editorLabel===void 0||(b({description:i.description??"",title:i.title??"",icon:i.icon??"",editorLabel:i.editorLabel}),n?.(i.editorLabel))}).catch(()=>{})}o(w,"generateAndCommitInitialName");function z(e,t,n,r,c,i){const a=t.trim();a!==""&&N(a,c).then(d=>{if(r())return p(e,{kind:"recap",...u(a,d),expected:n})}).then(d=>{d?.applied&&d.editorLabel!==void 0&&i?.(d.editorLabel)}).catch(()=>{})}o(z,"generateAndCommitRecapName");export{P as captureGoalIfAbsent,w as generateAndCommitInitialName,z as generateAndCommitRecapName,S as readRoadmap};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var
|
|
2
|
-
`).trim():""}
|
|
1
|
+
var U=Object.defineProperty;var c=(t,o)=>U(t,"name",{value:o,configurable:!0});import{envNodeId as V,envRecapIdleMs as q}from"../shared/env.js";import{brokerExtensionState as $}from"../core/runtime/broker/daemon-ops.js";import{generateRecap as F}from"../core/runtime/recap.js";import{currentOrPendingCausedBy as D}from"../core/runtime/broker/turn-cause.js";import{putBrokerRecap as H}from"../core/runtime/broker/daemon-ops.js";import{isReviewBoundary as K}from"../core/runtime/session-visibility.js";import{editorLabelForBrokerNode as Y}from"../core/runtime/broker-extension-render.js";import{generateAndCommitRecapName as z,readRoadmap as J}from"./broker-local.js";function Q(){return q()}c(Q,"idleMs");const X=7e3,b=5,Z=1200,j="crtr-recap";let M;function ee(t){const o=t.content;return typeof o=="string"?o.trim():Array.isArray(o)?o.filter(r=>r!==null&&typeof r=="object"&&r.type==="text"&&typeof r.text=="string").map(r=>(r.text??"").trim()).filter(r=>r!=="").join(`
|
|
2
|
+
`).trim():""}c(ee,"messageText");function te(t,o){let r;try{r=t.getEntries()}catch{return{entries:[],boundaryPresent:o===void 0}}if(o===void 0)return{entries:r,boundaryPresent:!0};const e=r.findIndex(a=>K(a,o));return e===-1?{entries:[],boundaryPresent:!1}:{entries:r.slice(e+1),boundaryPresent:!0}}c(te,"recapEntries");function B(t,o,r,e){const{entries:a,boundaryPresent:u}=te(t,e),l=[],m=c(d=>{const p=d.role;if(p!=="user"&&p!=="assistant")return;let f=ee(d);if(f==="")return;f.length>o&&(f=`${f.slice(0,o)} \u2026[truncated]`);const g=`${p==="user"?"User":"Agent"}: ${f}`;l.at(-1)!==g&&l.push(g)},"append");for(const d of a)d.type!=="message"||d.message===void 0||m(d.message);return u&&r?.role==="assistant"&&m(r),l}c(B,"conversationParts");function ne(t,o,r){const e=B(t,Z,o,r);if(e.length===0)return"";if(e.length<=b*2)return e.join(`
|
|
3
3
|
|
|
4
|
-
`);const
|
|
4
|
+
`);const a=e.length-b*2;return[...e.slice(0,b),`[\u2026 ${a} message${a===1?"":"s"} omitted \u2026]`,...e.slice(e.length-b)].join(`
|
|
5
5
|
|
|
6
|
-
`)}
|
|
6
|
+
`)}c(ne,"buildConversation");function re(t,o,r){const e=B(t,600,o,r);if(e.length===0)return"";const a=48;return e.length<=a?e.join(`
|
|
7
7
|
|
|
8
|
-
`):Array.from({length:
|
|
8
|
+
`):Array.from({length:a},(l,m)=>{const d=Math.round(m*(e.length-1)/(a-1));return e[d]}).join(`
|
|
9
9
|
|
|
10
|
-
`)}
|
|
11
|
-
`).filter(
|
|
10
|
+
`)}c(re,"buildNamingConversation");function ie(t,o=F,r){const e=V();if(e===void 0||e.trim()==="")return;let a,u,l,m;const d=c(i=>{const s=i.model?.provider?.trim(),n=i.model?.id?.trim();s&&n&&(m=`${s}/${n}`)},"captureLiveModel");let p=Date.now(),f=0,g,_=!1,S=!1,E=!1,y=!1,I;const v=c(()=>a!==void 0&&typeof a.setWidget=="function","canPaint"),P=c(i=>{try{a?.notify?.(i,"info")}catch{}},"notify"),k=c(()=>{if(v())try{a.setWidget(j,void 0,{placement:"aboveEditor"})}catch{}},"clearRecap"),T=c(i=>{if(!v()||i==="")return;const s=i.split(`
|
|
11
|
+
`).filter(n=>n.trim()!=="");if(s.length!==0)try{a.setWidget(j,s,{placement:"aboveEditor"})}catch{}},"showRecap"),w=c(()=>{p=Date.now(),f+=1,E=!1,_&&(S=!0)},"onMessage"),L=c(i=>{if(t.getSessionName===void 0||t.setSessionName===void 0)return;if(r!==void 0){const n=t.getSessionName();if(n===void 0)return;r(e,i,()=>t.getSessionName?.()===n,h=>{try{t.setSessionName?.(h)}catch{}});return}const s=D()??null;$(e).then(({node:n})=>{if(n.name.trim()!==""&&n.name!==n.kind)return;const h=Y(n);t.getSessionName?.()===h&&z(e,i,{name:n.name,description:n.description??"",title:n.title??"",icon:n.icon??"",kind:n.kind},()=>t.getSessionName?.()===h,s,x=>{try{t.setSessionName?.(x)}catch{}})}).catch(()=>{})},"refreshAutomaticName"),C=c(i=>{if(!v()||u===void 0||y)return;const s=g,n=l?.review_binding?.review_id??u.getEntries().map(A=>A.details?.reviewId).find(A=>typeof A=="string"),h=ne(u,s,n);if(h===""){E=!0,_=!1,S=!1,k();return}E=!1;const x=i?re(u,s,n):"",R=f;i||(I=R),y=!0,i&&(P("Generating recap\u2026"),L(x));const O=D()??null;J(e).catch(()=>null).then(A=>o(h,G=>{!i&&f!==R||!v()||H(e,G).then(()=>{!i&&f!==R||!v()||(_=!0,S=f!==R,T(G),i&&P("Recap ready"))}).catch(W=>P(`Recap could not be saved: ${String(W)}`)).finally(()=>{y=!1})},m,A??void 0,O)),setTimeout(()=>{y=!1},3e4).unref?.()},"requestRecap");t.registerCommand?.("recap",{description:"Generate a Goal/State recap and refresh the original generated session title",handler:c((i,s)=>{a=s.ui,u=s.sessionManager,d(s),C(!0)},"handler")}),t.on("session_start",(i,s)=>{a=s.ui,u=s.sessionManager,d(s),l=void 0,$(e).then(n=>{l=n.node}).catch(()=>{}),p=Date.now(),f=0,g=void 0,_=!1,S=!1,E=!1,y=!1,I=void 0,k()}),t.on("input",(i,s)=>{w()}),t.on("message_update",(i,s)=>{const n=i?.message;n?.role==="assistant"&&(g=n),w()}),t.on("turn_end",(i,s)=>{g=void 0,d(s),w()}),M!==void 0&&clearInterval(M);const N=setInterval(()=>{try{if(!v()||u===void 0||E||_&&!S||y||I===f||Date.now()-p<Q())return;C(!1)}catch{}},X);typeof N.unref=="function"&&N.unref(),M=N,t.on("session_shutdown",()=>{clearInterval(N),M===N&&(M=void 0)})}c(ie,"registerCanvasRecap");var pe=ie;export{pe as default,ie as registerCanvasRecap};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.595",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
},
|
|
146
146
|
"license": "UNLICENSED",
|
|
147
147
|
"dependencies": {
|
|
148
|
-
"@north-light/identity": "0.3.
|
|
148
|
+
"@north-light/identity": "0.3.595",
|
|
149
149
|
"@earendil-works/chord": "1.1.0",
|
|
150
150
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
151
151
|
"@earendil-works/pi-ai": "1.1.0",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.595",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.595",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@milkdown/preset-gfm": "^7.22.3",
|
|
29
29
|
"@milkdown/prose": "^7.22.3",
|
|
30
30
|
"@milkdown/utils": "^7.22.3",
|
|
31
|
-
"@north-light/identity": "0.3.
|
|
31
|
+
"@north-light/identity": "0.3.595",
|
|
32
32
|
"cron-parser": "^5.6.0",
|
|
33
33
|
"esbuild": "^0.27.7",
|
|
34
34
|
"jose": "^6.2.12",
|
|
@@ -11956,17 +11956,17 @@
|
|
|
11956
11956
|
},
|
|
11957
11957
|
"packages/crouter-api": {
|
|
11958
11958
|
"name": "@north-light/api",
|
|
11959
|
-
"version": "0.3.
|
|
11959
|
+
"version": "0.3.595",
|
|
11960
11960
|
"license": "UNLICENSED"
|
|
11961
11961
|
},
|
|
11962
11962
|
"packages/crouter-env-docker": {
|
|
11963
11963
|
"name": "@north-light/env-docker",
|
|
11964
|
-
"version": "0.3.
|
|
11964
|
+
"version": "0.3.595",
|
|
11965
11965
|
"license": "UNLICENSED"
|
|
11966
11966
|
},
|
|
11967
11967
|
"packages/crouter-identity": {
|
|
11968
11968
|
"name": "@north-light/identity",
|
|
11969
|
-
"version": "0.3.
|
|
11969
|
+
"version": "0.3.595",
|
|
11970
11970
|
"license": "UNLICENSED",
|
|
11971
11971
|
"dependencies": {
|
|
11972
11972
|
"jose": "^6.2.1"
|
|
@@ -11974,21 +11974,21 @@
|
|
|
11974
11974
|
},
|
|
11975
11975
|
"packages/crouter-plugin": {
|
|
11976
11976
|
"name": "@north-light/plugin",
|
|
11977
|
-
"version": "0.3.
|
|
11977
|
+
"version": "0.3.595",
|
|
11978
11978
|
"license": "UNLICENSED",
|
|
11979
11979
|
"dependencies": {
|
|
11980
|
-
"@north-light/api": "0.3.
|
|
11981
|
-
"@north-light/identity": "0.3.
|
|
11980
|
+
"@north-light/api": "0.3.595",
|
|
11981
|
+
"@north-light/identity": "0.3.595"
|
|
11982
11982
|
}
|
|
11983
11983
|
},
|
|
11984
11984
|
"packages/crouter-sdk": {
|
|
11985
11985
|
"name": "@north-light/sdk",
|
|
11986
|
-
"version": "0.3.
|
|
11986
|
+
"version": "0.3.595",
|
|
11987
11987
|
"license": "UNLICENSED",
|
|
11988
11988
|
"dependencies": {
|
|
11989
|
-
"@north-light/api": "0.3.
|
|
11990
|
-
"@north-light/identity": "0.3.
|
|
11991
|
-
"@north-light/plugin": "0.3.
|
|
11989
|
+
"@north-light/api": "0.3.595",
|
|
11990
|
+
"@north-light/identity": "0.3.595",
|
|
11991
|
+
"@north-light/plugin": "0.3.595",
|
|
11992
11992
|
"jose": "^6.2.1"
|
|
11993
11993
|
},
|
|
11994
11994
|
"bin": {
|