@north-light/cli 0.3.500 → 0.3.501
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/builtin-memory/crouter-sdk/release-notes.md +1 -1
- package/dist/core/runs/operations.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/docs/sdk/release-notes.md +1 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -9,7 +9,7 @@ when-and-why-to-read: When you need Release notes, this knowledge should be read
|
|
|
9
9
|
|
|
10
10
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
11
11
|
|
|
12
|
-
## 0.3.
|
|
12
|
+
## 0.3.500
|
|
13
13
|
|
|
14
14
|
An app-paid app can serve its model calls from its own service. Additive: no request or response an existing app sends or reads changes.
|
|
15
15
|
|
|
@@ -3,7 +3,7 @@ var Ne=Object.defineProperty;var m=(e,t)=>Ne(e,"name",{value:t,configurable:!0})
|
|
|
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),r=w(O(),"SELECT 1 FROM deliveries WHERE destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||r
|
|
6
|
+
)) LIMIT 1`).get(e.node_id,e.node_id),r=w(O(),"SELECT 1 FROM deliveries WHERE destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id),s=!e.last_settled_at&&e.status!=="done";return t||r||s||st(e)?"running":oe(e.node_id).length?"waiting_on_user":"idle"}m(I,"runStatus");function hn(e){const t=N(e);return t!==null&&I(t)==="running"}m(hn,"runIsRunning");function A(e){X(e.node_id),e=N(e.node_id)??e;const t=I(e),r=t==="settled"?[]:oe(e.node_id),s=Pe(e.node_id)||void 0,i=t==="settled"?rt(e):null,c=i?.kind==="result"?ee(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...i?{outcome:i}:{},...c===void 0?{}:{result:c},...s!==void 0?{last_report:s}:{},pending_question_ids:r,...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(U())),payer:"user",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:at(e.node_id,t)}}m(A,"runObject");const B=864e5,ue=255;function yn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>ue)throw R(`Idempotency-Key must be 1-${ue} characters`);return e}}m(yn,"idempotencyKeyOf");function x(e,t,r,s=G()){const i=w(s,"SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!i||Date.now()-Date.parse(i.created_at)>=B)){if(i.body_hash!==r)throw new S(409,"idempotency_conflict","key used with a different request");return{run_id:i.run_id,response:JSON.parse(i.response_json)}}}m(x,"findIdempotent");function me(e,t,r,s,i,c,d){w(e,"DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,r,new Date(Date.now()-B).toISOString()),w(e,"INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,r,s,i,JSON.stringify(c),d)}m(me,"recordIdempotent");function Rn(e=Date.now()){return L(t=>Number(w(t,"DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-B).toISOString()).changes))}m(Rn,"pruneExpiredIdempotencyKeys");function le(e,t,r,s,i){const c=s.text;let d=0;return{messageId:Ue(t,{kind:"message",label:c.slice(0,120),senderNodeId:"human",senderName:r,bodyJson:i?{body:c}:{body:c,start_turn:!1},urgency:i?"normal":"deferred",wake:i?1:0,withinEnqueue:m((a,_)=>{s.uses.length&&(ie(r,s.uses,a),de(s.uses.map(({upload_id:y,path:E})=>({upload_id:y,path:E,run_id:t})),a)),d=se(a,t,t,"node.message.accepted",{message_id:_,start_turn:i}).sequence_number},"withinEnqueue")}).messageId,sequence:d}}m(le,"acceptRunMessage");class fe extends Error{static{m(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}const gt=1440*60*1e3;function _e(e){const t=typeof e=="string"?Qe(e):null;if(t===null||!Number.isSafeInteger(t))throw R(`deadline '${String(e)}' is not a duration; use one or more <int>[smhd] parts such as 10m or 1h30m`,"deadline");if(t<=0)throw R("deadline must be greater than zero","deadline");if(t>gt)throw R("deadline must be at most 24h","deadline");return t}m(_e,"parseRunDeadlineMs");async function Sn(e,t,r,s=ce){if(t.isolated&&!Ke())throw new S(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");t.deadline!==void 0&&_e(t.deadline);const i=J("sha256").update(JSON.stringify(t)).digest("hex");if(r){const n=x(e.grantee,r,i);if(n){const u=C(n.run_id,e.grantee);return!u.pi_pid&&I(u)==="running"&&(t.output_schema!==void 0&&!u.outcome_at&&nt(u.node_id).state==="absent"&&ee(u.node_id,u.grantee)===void 0&&te(u.node_id,"terminal",t.output_schema),await F(u.node_id,{resume:!0,capacity:"freeze"})),n.response}}await ct(e.grantee);const c=t.profile===void 0?Be(e.grantee):$e(t.profile),d=c.manifest.grantee??"app:terminal";if(d!==e.grantee){const n=`crtr:memory:rw:${d}:profile:${c.profileId}`;if(!e.resolved.some(u=>W(u,n))||t.scopes!==null&&!t.scopes.some(u=>W(u,n)))throw new S(403,"scope_missing",`missing scope ${n}`,"profile",void 0,n)}if(t.model!==void 0){const n=t.model;if(ze(n)){if(n.includes("/")){const u=n.lastIndexOf("/"),h=n.slice(0,u),g=n.slice(u+1);if(["ultra","strong","medium","light"].includes(g)&&Ve({kind:"logical",family:h,strength:g,spec:n},H(e.grantee).files,c.profileId).every(T=>T.family!==h))throw R(`model '${n}' names a model family that is not configured in this daemon`,"model")}}else if(Ze(n)===void 0)throw R(`model '${n}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const o=Ye(),a=Te(H(e.grantee).nodes,o);if(t.isolated&&t.cwd!==void 0){const n=De(a,Me(t.cwd));if(!Y(t.cwd)||n===".."||n.startsWith(`..${Ie}`)||Y(n))throw R("cwd must be inside the isolated root node folder","cwd")}const _=await s(o,e.grantee,t.prompt),y=_.text;let E;try{E=t.message===void 0?void 0:await s(o,e.grantee,t.message)}catch(n){throw _.cleanup(),n}let p;try{await Xe({kind:et(c),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??a:H(e.grantee).files,profile:c.profileId,prompt:y,nodeId:o,isolated:t.isolated??!1,...t.model===void 0?{}:{model:t.model},...t.deadline===void 0?{}:{deadlineAt:new Date(Date.now()+_e(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:o,event_cursor:1,usage_json:JSON.stringify(U())},withinCreate:m((n,u)=>{if(r){const g=x(e.grantee,r,i,n);if(g)throw new fe(g)}const h=_.uses;if(h.length&&(ie(e.grantee,h,n),de(h.map(({upload_id:g,path:T})=>({upload_id:g,path:T,run_id:o})),n)),Ge(o,y),p={run_id:o,node_id:o,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:u.created,metadata:t.metadata,sequence_number:0},se(n,o,o,"run.started",{scopes:t.scopes,payer:"user",usage:U()}),E){const g=le(n,o,e.grantee,E,!1);p.message={run_id:o,message_id:g.messageId,sequence_number:g.sequence}}r&&me(n,e.grantee,r,i,o,p,u.created)},"withinCreate")},t.output_schema===void 0?void 0:n=>{te(n,"terminal",t.output_schema)})}catch(n){if(N(o)||(_.cleanup(),E?.cleanup()),n instanceof fe)return n.winner.response;if(t.model!==void 0&&n instanceof Oe&&n.code==="usage")throw R(n.message,"model");if(n instanceof be&&(n.code==="isolated_run"||n.code==="invalid_request")){const u=n.details&&typeof n.details=="object"&&"param"in n.details&&typeof n.details.param=="string"?n.details.param:void 0;throw new S(n.status,n.code,n.message,u)}throw n}if(!p)throw new Error("run creation did not commit");return p}m(Sn,"startRun");function Nn(e,t){let r;if(t.after)try{const o=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!o||typeof o!="object"||!("activity"in o)||typeof o.activity!="string"||!("id"in o)||typeof o.id!="string")throw new Error("invalid cursor");r={activity:o.activity,id:o.id}}catch{throw R("invalid list cursor","after")}const i=O().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
|
|
7
7
|
WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}
|
|
8
8
|
ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({node_id:o})=>!t.visible||t.visible(o)).filter(({activity:o,node_id:a})=>!r||o<r.activity||o===r.activity&&a<r.id).map(o=>({root:N(o.node_id),activity:o.activity})).filter(({root:o})=>!t.status||I(o)===t.status),c=i.slice(0,t.limit),d=c.at(-1);return{runs:c.map(({root:o})=>A(o)),next:i.length>t.limit&&d?Buffer.from(JSON.stringify({activity:d.activity,id:d.root.node_id})).toString("base64url"):null}}m(Nn,"listRuns");async function vn(e,t,r){const s=C(e,t),i=m(()=>A(C(e,t)),"read");return!r||P.includes(I(s))?i():new Promise((c,d)=>{const o=m(()=>{clearTimeout(y),clearInterval(_),a();try{c(i())}catch(E){d(E)}},"finish"),a=dt(e,()=>{try{P.includes(String(i().status))&&o()}catch(E){clearTimeout(y),clearInterval(_),a(),d(E)}}),_=setInterval(()=>{P.includes(String(i().status))&&o()},250),y=setTimeout(o,r*1e3)})}m(vn,"waitRun");async function bn(e,t,r=ce,s=!0,i){const c=e.status==="canceled"||e.outcome_reason==="closed",d=e.grantee??"app:terminal",o=J("sha256").update(JSON.stringify(["run.message",e.node_id,t,s])).digest("hex"),a=m(async p=>{const n=N(e.node_id),u=w(O(),"SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(p.message_id));return n&&!c&&s&&!n.pi_pid&&u&&await F(e.node_id,{resume:!0,capacity:"freeze"}),p},"replay");if(i){const p=x(d,i,o);if(p)return a(p.response)}if(c)throw new S(409,"run_settled","canceled run cannot receive a message");const _=await r(e.node_id,d,t),y=s&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;let E;try{E=L(p=>{if(i){const h=x(d,i,o,p);if(h)return{replayed:h.response}}y?.(e.node_id);const n=le(p,e.node_id,d,_,s),u={run_id:e.node_id,message_id:n.messageId,sequence_number:n.sequence};return i&&me(p,d,i,o,e.node_id,u,new Date().toISOString()),{result:u}})}catch(p){throw _.cleanup(),p}return"replayed"in E?(_.cleanup(),a(E.replayed)):(s&&!e.pi_pid&&await F(e.node_id,{resume:!0,capacity:"freeze"}),E.result)}m(bn,"messageRun");async function Et(e){const t=m(()=>new S(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let r=0;r<2;r++){const s=N(e);if(!s)throw q();if(!Z(s)){if(s.streaming)throw t();return}const i=z(e)?.executionId;try{await Je(e)==="turn"&&ae({nodes:[e]});return}catch(c){if(!(c instanceof je))throw c;const d=N(e);if(!d)throw q();if(!d.streaming)return;if(r===0&&Z(d)&&z(e)?.executionId!==i)continue;throw t()}}throw t()}m(Et,"interruptNode");async function On(e,t="stop"){const r=t==="stop"?w(O(),"SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:s})=>s):[e.node_id];return await Promise.all(r.map(s=>Et(s))),A(N(e.node_id)??e)}m(On,"interruptRun");async function Dn(e,t={}){const r=w(O(),"SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(d=>d.node_id);ae({run:e.node_id});const s=[];if(I(e)!=="settled")s.push(...ne(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const d of r){if(d===e.node_id)continue;const o=N(d);o&&o.status!=="done"&&o.status!=="canceled"&&o.status!=="dead"&&s.push(...ne(d,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if(await re({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...s])].map(d=>V(d,"run_canceled")))).some(d=>!d.confirmed))throw new S(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const c=N(e.node_id);return A(c??e)}m(Dn,"cancelRun");const pe=200;function Mn(e,t){if(typeof t!="string"||!t.trim())throw R("name is required","name");const r=t.trim();if(r.length>pe)throw R(`name exceeds ${pe} characters`,"name");const s=We(e.node_id,{name:r});return s.window&&He(s.window,Fe(s)),A(s)}m(Mn,"renameRun");async function In(e,t={config:lt,client:mt}){await re({run_id:e.node_id},"the run was deleted");const r=L(a=>(w(a,"UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),w(a,"SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(_=>_.node_id)));if((await Promise.all(r.map(a=>V(a,"run_deleted",{deleting:!0})))).some(a=>!a.confirmed))throw new S(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const i=r.map(a=>{const _=xe(a);if(_.app===null)throw new Error(`run node missing during deletion: ${a}`);return _}),c=w(O(),"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:a}of c)try{Q().delete(a)}catch(_){if(!qe(_))throw _}const d=L(a=>{for(const p of r){const n=Ce(a,p);n!==null&&n.deleted_at===null&&Le(a,n)}const _=_t([e.node_id],a);w(a,"DELETE FROM run_events WHERE run_id = ?").run(e.node_id),w(a,"DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const y=r.map(()=>"?").join(","),E=a.prepare(`SELECT message_id FROM messages WHERE sender_node_id IN (${y}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${y})`).all(...r,...r);a.prepare(`DELETE FROM deliveries WHERE destination_id IN (${y})`).run(...r);for(const{message_id:p}of E)w(a,"DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(p,p);return _});for(const a of i)ke(a);const{notifyRunDeleted:o}=await import("./events.js");return o(e.node_id),{uploads_pending:await wt(d,t)}}m(In,"deleteRun");async function wt(e,t){if(!e.length||!t.config())return e.length;let r;try{r=t.client()}catch{return e.length}const s=new Set,i=e.map(d=>r.deleteUpload(d).then(()=>{ft(d),s.add(d)},()=>{}));let c;return await Promise.race([Promise.all(i),new Promise(d=>{c=setTimeout(d,t.budgetMs??pt),c.unref?.()})]),clearTimeout(c),e.length-s.size}m(wt,"deleteReleasedUploads");function Tn(e,t,r){C(e,t),X(e);const s=O();s.exec("BEGIN");try{const c=w(s,"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).map(n=>({node_id:n.node_id,parent_node_id:n.parent,conversations:w(s,"SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(n.node_id).map(({session_id:u})=>{const{header:h,entries:g}=Q().read(u);if(r==="entries")return{conversation_id:u,header:h,entries:g};const T=Ae.inMemory(h.cwd,void 0,[h,...g]),ge=tt(T)??[],$=new Map(g.map((f,v)=>[f.id,v])),Ee=g.filter(f=>f.type==="custom"&&f.customType==="crtr-system-prompt").map(f=>({id:f.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in f?f.data:void 0,timestamp:f.timestamp}})),j=g.filter(f=>f.type==="custom_message"&&f.customType==="app_message").map(f=>({id:f.id,message:{role:"custom",customType:"app_message",content:"content"in f?f.content:"",timestamp:f.timestamp}})),we=n.node_id===e?g.find(f=>{if(f.type!=="message"||f.message.role!=="user")return!1;const v=K(g,f.message.timestamp);return v?.type==="runtime"&&v.kind==="kickoff"})?.id:void 0,he=[...ge.filter(({id:f})=>!j.some(v=>v.id===f)),...Ee,...j].sort((f,v)=>($.get(f.id)??Number.MAX_SAFE_INTEGER)-($.get(v.id)??Number.MAX_SAFE_INTEGER)).map(({id:f,message:v})=>{const l=v,D=l.usage,k=l.role==="user"?K(g,Number(l.timestamp)):null,ye=k?.type==="human"||f===we,M=l.role==="toolResult"?"tool_result":l.role==="bashExecution"?"bash_execution":l.role==="compactionSummary"?"compaction_summary":l.role==="branchSummary"?"branch_summary":l.role==="custom"&&l.customType==="crtr-system-prompt"?"system":l.role==="user"?ye?"user":"custom":l.role,Re=M==="custom"?l.role==="custom"?l.customType:k?.type==="runtime"?k.kind:"unknown":void 0,Se=M==="system"&&l.customType==="crtr-system-prompt"?[{type:"text",text:l.data?.text??""}]:typeof l.content=="string"?[{type:"text",text:l.content}]:Array.isArray(l.content)?l.content.map(b=>b.type==="toolCall"?{type:"tool_call",tool_call_id:b.id,name:b.name,arguments:b.arguments}:b.type==="image"?{type:"image",mime_type:b.mimeType}:b.type==="thinking"?{type:"thinking",text:b.thinking}:b):[];return{entry_id:f,role:M,...M==="custom"?{custom_type:Re}:{},time:typeof l.timestamp=="string"?l.timestamp:new Date(Number(l.timestamp??Date.now())).toISOString(),content:Se,...M==="assistant"?{model:l.model,provider:l.provider,stop_reason:l.stopReason,...l.errorMessage?{error_message:l.errorMessage}:{},...D?{usage:{input_tokens:D.input??0,output_tokens:D.output??0,cache_read_tokens:D.cacheRead??0,cache_write_tokens:D.cacheWrite??0,cost_usd:D.cost?.total??0}}:{}}:{},...M==="tool_result"?{tool_call_id:l.toolCallId,tool_name:l.toolName,is_error:l.isError}:{}}})??[];return{conversation_id:u,messages:he}})})),o=w(s,"SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,a=new Map(c.map(n=>[n.node_id,ot(n.node_id)])),_=w(s,`SELECT node_id, sequence_number FROM run_events
|
|
9
9
|
WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var E=Object.defineProperty;var d=(i,t)=>E(i,"name",{value:t,configurable:!0});import{clearFrozen as m,getNode as _,getRow as g}from"../../../core/canvas/index.js";import{fullName as y}from"../../../core/canvas/labels.js";import{isSafeNodeId as s}from"../../../core/canvas/paths.js";import{emitEvent as l}from"../../../core/events/emit.js";import{operationIdContext as A}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as S}from"../../../core/canvas/deliveries.js";import{publishNotice as k}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{reviveNode as h}from"../../../core/runtime/revive.js";import{hasPendingWake as v}from"../live-obligation.js";import{readInterruptedTurn as z}from"../../../core/canvas/recovery.js";const f=6,R=10*6e4,L=2e4;function M(i,t){if(t)return 2;const r=i.launched_at;if(r==null)return 1;const e=i.last_settled_at;return e==null?2:Date.parse(e)>Date.parse(r)?1:2}d(M,"thawTier");function C(i,t){if(i.tier!==t.tier)return i.tier-t.tier;const r=i.row.frozen_at,e=t.row.frozen_at;return r==null?e==null?0:1:e==null?-1:Date.parse(r)-Date.parse(e)}d(C,"compareThaw");class B{static{d(this,"FreezeLaneReconciler")}relaunchState=new Map;endEpisode(t){this.relaunchState.delete(t)}async run(t,r){const e=r.candidates.map(a=>({...a,tier:M(a.row,v(a.row.node_id))}));e.sort(C);const n={stalled:0,waitingOnMail:0};for(const a of e)await A.fresh(()=>this.enact(t,a,r.fleet))==="frozen"&&(a.tier===1?n.stalled+=1:n.waitingOnMail+=1);return n}async enact(t,r,e){const n=r.row.node_id;try{return r.enact==="thaw"?await this.enactThaw(r.row):r.enact==="idle-release"?await this.enactIdleRelease(t,r.row):(await e.applyDeadRowPolicy(n),e.has(n)?"launched":g(n)?.frozen_at!=null?"frozen":"skipped")}catch(a){return l({level:"error",event:"node.lifecycle.enact_failed",...s(n)?{node_id:n}:{},error:a,fields:{...s(n)?{}:{affected_node_id:n},enact:r.enact}}),"skipped"}}async enactThaw(t){if(t.lifecycle==="resident"&&_(t.node_id)?.pi_session_id!=null&&!v(t.node_id))return u(t.node_id,"release"),m(t.node_id),"skipped";
|
|
1
|
+
var E=Object.defineProperty;var d=(i,t)=>E(i,"name",{value:t,configurable:!0});import{clearFrozen as m,getNode as _,getRow as g}from"../../../core/canvas/index.js";import{fullName as y}from"../../../core/canvas/labels.js";import{isSafeNodeId as s}from"../../../core/canvas/paths.js";import{emitEvent as l}from"../../../core/events/emit.js";import{operationIdContext as A}from"../../../core/events/operation-id.js";import{acknowledgedNodeMailCount as S}from"../../../core/canvas/deliveries.js";import{publishNotice as k}from"../../../core/runtime/close.js";import{transition as u}from"../../../core/runtime/lifecycle.js";import{reviveNode as h}from"../../../core/runtime/revive.js";import{hasPendingWake as v}from"../live-obligation.js";import{readInterruptedTurn as z}from"../../../core/canvas/recovery.js";const f=6,R=10*6e4,L=2e4;function M(i,t){if(t)return 2;const r=i.launched_at;if(r==null)return 1;const e=i.last_settled_at;return e==null?2:Date.parse(e)>Date.parse(r)?1:2}d(M,"thawTier");function C(i,t){if(i.tier!==t.tier)return i.tier-t.tier;const r=i.row.frozen_at,e=t.row.frozen_at;return r==null?e==null?0:1:e==null?-1:Date.parse(r)-Date.parse(e)}d(C,"compareThaw");class B{static{d(this,"FreezeLaneReconciler")}relaunchState=new Map;endEpisode(t){this.relaunchState.delete(t)}async run(t,r){const e=r.candidates.map(a=>({...a,tier:M(a.row,v(a.row.node_id))}));e.sort(C);const n={stalled:0,waitingOnMail:0};for(const a of e)await A.fresh(()=>this.enact(t,a,r.fleet))==="frozen"&&(a.tier===1?n.stalled+=1:n.waitingOnMail+=1);return n}async enact(t,r,e){const n=r.row.node_id;try{return r.enact==="thaw"?await this.enactThaw(r.row):r.enact==="idle-release"?await this.enactIdleRelease(t,r.row):(await e.applyDeadRowPolicy(n),e.has(n)?"launched":g(n)?.frozen_at!=null?"frozen":"skipped")}catch(a){return l({level:"error",event:"node.lifecycle.enact_failed",...s(n)?{node_id:n}:{},error:a,fields:{...s(n)?{}:{affected_node_id:n},enact:r.enact}}),"skipped"}}async enactThaw(t){const r=z(t.node_id)?.interrupted===!0;if(!r&&t.lifecycle==="resident"&&_(t.node_id)?.pi_session_id!=null&&!v(t.node_id))return u(t.node_id,"release"),m(t.node_id),"skipped";try{return(await h(t.node_id,{resume:!0,capacity:"freeze",recovery:!0,...r?{wakeReason:"runtime-restart-abort"}:{}})).outcome==="frozen"?"frozen":"launched"}catch(e){const n=_(t.node_id);throw n!==null&&(n.status==="active"||n.status==="idle")&&(u(t.node_id,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}),m(t.node_id)),e}}async enactIdleRelease(t,r){const e=r.node_id,n=S(e),a=this.relaunchState.get(e),c=a===void 0||a.acknowledgedCount!==n,o=c?0:a.attempts;if(o>=f)return this.relaunchState.delete(e),l({level:"warn",event:"broker.idle_release.exhausted",...s(e)?{node_id:e}:{},fields:{...s(e)?{}:{affected_node_id:e},attempts:o,max_attempts:f}}),u(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",respawn_failures:o}}}),k(e,"notice.crash",`Child crashed \u2014 ${y(r)} (${e}) failed to relaunch after ${o} attempts while trying to deliver a pending inbox message (no delivery progress across any attempt), and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e}),"skipped";const p=c?void 0:a?.lastAttempt,w=Math.min(L*2**o,R);return p!==void 0&&t-p<w?"skipped":(await h(e,{resume:!0,capacity:"freeze"})).outcome==="frozen"?"frozen":(this.relaunchState.set(e,{acknowledgedCount:n,attempts:o+1,lastAttempt:t}),l({level:"info",event:"broker.revive.idle_release",...s(e)?{node_id:e}:{},attempt:o+1,fields:{...s(e)?{}:{affected_node_id:e},attempts:o+1,max_attempts:f}}),"launched")}}export{B as FreezeLaneReconciler,C as compareThaw,M as thawTier};
|
|
@@ -7,7 +7,7 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
|
|
|
7
7
|
|
|
8
8
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
9
9
|
|
|
10
|
-
## 0.3.
|
|
10
|
+
## 0.3.500
|
|
11
11
|
|
|
12
12
|
An app-paid app can serve its model calls from its own service. Additive: no request or response an existing app sends or reads changes.
|
|
13
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.501",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
"license": "UNLICENSED",
|
|
140
140
|
"dependencies": {
|
|
141
|
-
"@north-light/identity": "0.3.
|
|
141
|
+
"@north-light/identity": "0.3.501",
|
|
142
142
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
143
143
|
"@earendil-works/pi-ai": "1.1.0",
|
|
144
144
|
"@earendil-works/pi-coding-agent": "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.501",
|
|
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.501",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@earendil-works/pi-ai": "1.1.0",
|
|
19
19
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
20
20
|
"@earendil-works/pi-tui": "1.1.0",
|
|
21
|
-
"@north-light/identity": "0.3.
|
|
21
|
+
"@north-light/identity": "0.3.501",
|
|
22
22
|
"cron-parser": "^5.6.0",
|
|
23
23
|
"esbuild": "^0.27.7",
|
|
24
24
|
"jose": "^6.2.12",
|
|
@@ -12116,17 +12116,17 @@
|
|
|
12116
12116
|
},
|
|
12117
12117
|
"packages/crouter-api": {
|
|
12118
12118
|
"name": "@north-light/api",
|
|
12119
|
-
"version": "0.3.
|
|
12119
|
+
"version": "0.3.501",
|
|
12120
12120
|
"license": "UNLICENSED"
|
|
12121
12121
|
},
|
|
12122
12122
|
"packages/crouter-env-docker": {
|
|
12123
12123
|
"name": "@north-light/env-docker",
|
|
12124
|
-
"version": "0.3.
|
|
12124
|
+
"version": "0.3.501",
|
|
12125
12125
|
"license": "UNLICENSED"
|
|
12126
12126
|
},
|
|
12127
12127
|
"packages/crouter-identity": {
|
|
12128
12128
|
"name": "@north-light/identity",
|
|
12129
|
-
"version": "0.3.
|
|
12129
|
+
"version": "0.3.501",
|
|
12130
12130
|
"license": "UNLICENSED",
|
|
12131
12131
|
"dependencies": {
|
|
12132
12132
|
"jose": "^6.2.1"
|
|
@@ -12134,20 +12134,20 @@
|
|
|
12134
12134
|
},
|
|
12135
12135
|
"packages/crouter-plugin": {
|
|
12136
12136
|
"name": "@north-light/plugin",
|
|
12137
|
-
"version": "0.3.
|
|
12137
|
+
"version": "0.3.501",
|
|
12138
12138
|
"license": "UNLICENSED",
|
|
12139
12139
|
"dependencies": {
|
|
12140
|
-
"@north-light/api": "0.3.
|
|
12141
|
-
"@north-light/identity": "0.3.
|
|
12140
|
+
"@north-light/api": "0.3.501",
|
|
12141
|
+
"@north-light/identity": "0.3.501"
|
|
12142
12142
|
}
|
|
12143
12143
|
},
|
|
12144
12144
|
"packages/crouter-sdk": {
|
|
12145
12145
|
"name": "@north-light/sdk",
|
|
12146
|
-
"version": "0.3.
|
|
12146
|
+
"version": "0.3.501",
|
|
12147
12147
|
"license": "UNLICENSED",
|
|
12148
12148
|
"dependencies": {
|
|
12149
|
-
"@north-light/api": "0.3.
|
|
12150
|
-
"@north-light/identity": "0.3.
|
|
12149
|
+
"@north-light/api": "0.3.501",
|
|
12150
|
+
"@north-light/identity": "0.3.501",
|
|
12151
12151
|
"jose": "^6.2.1"
|
|
12152
12152
|
},
|
|
12153
12153
|
"bin": {
|