@north-light/cli 0.3.511 → 0.3.512
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +3 -1
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/health.d.ts +8 -0
- package/dist/api/routes.d.ts +1 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +7 -0
- package/dist/builtin-memory/crouter-sdk/resources.md +1 -1
- package/dist/clients/attach/viewer.js +455 -455
- package/dist/core/human/page-schema.d.ts +1 -1
- package/dist/core/llm/run.js +2 -2
- package/dist/core/runtime/broker/model-adapter.js +2 -2
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/daemon/api/app-listener.js +12 -12
- package/dist/daemon/api/handlers/health.js +3 -3
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/readiness.d.ts +10 -0
- package/dist/daemon/readiness.js +1 -0
- package/docs/sdk/release-notes.md +7 -0
- package/docs/sdk/resources.md +1 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -186,8 +186,8 @@ export declare const chartDataRowsSchema: z.ZodArray<z.ZodRecord<z.ZodString, z.
|
|
|
186
186
|
export declare const chartConfigSchema: z.ZodObject<{
|
|
187
187
|
kind: z.ZodEnum<{
|
|
188
188
|
line: "line";
|
|
189
|
-
bar: "bar";
|
|
190
189
|
area: "area";
|
|
190
|
+
bar: "bar";
|
|
191
191
|
}>;
|
|
192
192
|
x: z.ZodString;
|
|
193
193
|
y: z.ZodArray<z.ZodObject<{
|
package/dist/core/llm/run.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var ge=Object.defineProperty;var u=(e,t)=>ge(e,"name",{value:t,configurable:!0});import{randomUUID as be}from"node:crypto";import{streamSimple as ve}from"@earendil-works/pi-ai/compat";import{expandModelCandidates as re,parseModelSpec as
|
|
1
|
+
var ge=Object.defineProperty;var u=(e,t)=>ge(e,"name",{value:t,configurable:!0});import{randomUUID as be}from"node:crypto";import{streamSimple as ve}from"@earendil-works/pi-ai/compat";import{expandModelCandidates as re,parseModelSpec as ie,probeRouteAvailability as we}from"../model-routes.js";import{readMergedLaunchConfig as se}from"../config.js";import{openModelRegistry as xe}from"../runtime/model-registry.js";import{MAX_RATE_LIMIT_COOLDOWN_MS as ae,coolingUntilFor as de,isManagedProvider as H,markSubscriptionRateLimited as ke,markSubscriptionSuccess as je,readSubscriptionPool as Me,retryAfterMsFromHeaders as K,retryAfterMsFromError as Ae,refreshSubscriptionCredential as qe,subscriptionNeedsSuccessWrite as Re}from"../subscription-state.js";import{classifyRateLimit as $e,describeRateLimitScope as le,rateLimitHeaders as Ie}from"../rate-limit-scope.js";import{RunError as i}from"../runs/operations.js";import{recognizeProviderError as ce}from"../provider-error-recognition.js";import{isSafetyRefusal as Ce}from"./refusal.js";import{assertUnderCap as Oe,recordModelUsage as ue}from"../usage/ledger.js";import{outboundToken as Se}from"../providers/mint.js";import{discardFile as Le}from"../providers/token-cache.js";import{ProviderError as Ee}from"../providers/errors.js";import{appCandidates as Ne}from"./app-rungs.js";function De(e){return typeof e=="string"||e===null||Array.isArray(e)&&e.every(t=>t&&typeof t=="object"&&(t.type==="text"&&typeof t.text=="string"||t.type==="image_url"&&typeof t.image_url?.url=="string"&&/^data:image\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/.test(t.image_url.url)))}u(De,"validContent");function fe(e){return Array.isArray(e)?e.map(t=>{if(t.type==="text")return t;const[,n,r]=/^data:(image\/(?:png|jpeg|gif|webp));base64,(.*)$/.exec(t.image_url.url);return{type:"image",mimeType:n,data:r}}):e??""}u(fe,"imageContent");function at(e){if(!e||typeof e!="object"||Array.isArray(e))throw new i(400,"invalid_request","body must be an object");const t=e;if(!Array.isArray(t.messages)||!t.messages.every(n=>n&&typeof n=="object"&&["system","user","assistant","tool"].includes(n.role)&&De(n.content)))throw new i(400,"invalid_request","messages must be chat messages","messages");if(t.messages.some(n=>["system","assistant"].includes(n.role)&&typeof n.content!="string"&&n.content!==null))throw new i(400,"invalid_request","system and assistant content must be text","messages");if(t.model!==void 0&&typeof t.model!="string")throw new i(400,"invalid_request","model must be a string","model");if(t.model_policy!==void 0&&!["exact","substitute"].includes(t.model_policy))throw new i(400,"invalid_request","invalid model_policy","model_policy");if(t.payer!==void 0&&!["user","app"].includes(t.payer))throw new i(400,"invalid_request","invalid payer","payer");if(t.reasoning_effort!==void 0&&!["minimal","low","medium","high","xhigh","max"].includes(t.reasoning_effort))throw new i(400,"invalid_request","invalid reasoning_effort","reasoning_effort");if(t.stream!==void 0&&typeof t.stream!="boolean")throw new i(400,"invalid_request","stream must be boolean","stream");if(t.tools!==void 0&&(!Array.isArray(t.tools)||!t.tools.every(n=>n?.type==="function"&&typeof n.function?.name=="string"&&n.function.name.length>0&&(n.function.description===void 0||typeof n.function.description=="string")&&(n.function.parameters===void 0||n.function.parameters!==null&&typeof n.function.parameters=="object"&&!Array.isArray(n.function.parameters)&&n.function.parameters.type==="object"))))throw new i(400,"invalid_request","invalid tools","tools");if(t.tool_choice!==void 0&&t.tool_choice!=="auto"&&t.tool_choice!=="none"&&t.tool_choice!=="required"&&(typeof t.tool_choice!="object"||t.tool_choice===null||t.tool_choice.type!=="function"||typeof t.tool_choice.function?.name!="string"))throw new i(400,"invalid_request","invalid tool_choice","tool_choice");if(t.messages.some(n=>n.role==="assistant"&&n.tool_calls!==void 0&&(!Array.isArray(n.tool_calls)||!n.tool_calls.every(r=>r&&typeof r.id=="string"&&typeof r.function?.name=="string"&&typeof r.function.arguments=="string"&&Fe(r.function.arguments)))))throw new i(400,"invalid_request","invalid assistant tool_calls","messages");if(t.stop!==void 0&&!(typeof t.stop=="string"||Array.isArray(t.stop)&&t.stop.every(n=>typeof n=="string")))throw new i(400,"invalid_request","invalid stop","stop");if(t.seed!==void 0&&!Number.isSafeInteger(t.seed))throw new i(400,"invalid_request","invalid seed","seed");for(const[n,r]of[["temperature",t.temperature],["top_p",t.top_p],["max_tokens",t.max_tokens]])if(r!==void 0&&(typeof r!="number"||!Number.isFinite(r)||n==="temperature"&&(r<0||r>2)||n==="top_p"&&(r<0||r>1)||n==="max_tokens"&&(!Number.isSafeInteger(r)||r<1)))throw new i(400,"invalid_request",`invalid ${n}`,n);if(t.response_format!==void 0){const n=t.response_format;if(!n||typeof n!="object"||Array.isArray(n)||!["text","json_object","json_schema"].includes(n.type)||n.type==="json_schema"&&(typeof n.json_schema?.name!="string"||!n.json_schema.name||!n.json_schema.schema||typeof n.json_schema.schema!="object"||Array.isArray(n.json_schema.schema)))throw new i(400,"invalid_request","invalid response_format","response_format")}if(t.metadata!==void 0&&Buffer.byteLength(JSON.stringify(t.metadata)??"")>4096)throw new i(400,"invalid_request","metadata exceeds 4 KB","metadata");return t}u(at,"parseLlmRequest");function Fe(e){try{const t=JSON.parse(e);return t!==null&&typeof t=="object"&&!Array.isArray(t)}catch{return!1}}u(Fe,"isJsonObject");function Te(e){const t=Date.now(),n=e.messages.map(s=>s.role==="system"?{role:"system",content:s.content??"",timestamp:t}:s.role==="tool"?{role:"toolResult",toolCallId:s.tool_call_id??"",toolName:"",content:typeof s.content=="string"||s.content===null?[{type:"text",text:s.content??""}]:fe(s.content),isError:!1,timestamp:t}:s.role==="assistant"?{role:"assistant",content:[...s.content?[{type:"text",text:s.content}]:[],...(s.tool_calls??[]).map(g=>({type:"toolCall",id:g.id,name:g.function.name,arguments:JSON.parse(g.function.arguments)}))],api:"openai-completions",provider:"openai",model:e.model??"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"stop",timestamp:t}:{role:"user",content:fe(s.content),timestamp:t}),r=n.findIndex(s=>s.role!=="system"),w=n.slice(0,r<0?n.length:r).map(s=>s.content),y=w.join(`
|
|
2
2
|
|
|
3
|
-
`),l=e.tools?.map(({function:i})=>({name:i.name,description:i.description??"",parameters:i.parameters??{type:"object",properties:{}}}));return{...y?{systemPrompt:y}:{},messages:n.slice(w.length),...l?{tools:l}:{}}}u(Pe,"contextOf");function me(e,t,n,r){if(!e){const y=ie(n,r),l=Object.values({...y.modelRoutes??{},...y.legacyModelRoutes??{}}),i=l.length?[y.modelLadders.defaultProvider,...y.modelRouting?.familyOrder??[],...l.map(g=>g.family)].find(g=>l.some(F=>F.family===g)):y.modelLadders.defaultProvider??"anthropic";return{kind:"logical",family:i,strength:"strong",spec:`${i}/strong`}}const w=/^([^/]+)\/(ultra|strong|medium|light)$/.exec(e);return w?{kind:"logical",family:w[1],strength:w[2],spec:e}:{kind:t==="exact"?"exact":"concrete",spec:e}}u(me,"requestFor");function Te(e,t){const{input:n,output:r,cacheRead:w,cacheWrite:y}=e.cost;return n===0&&r===0&&w===0&&y===0?null:Number.isFinite(t)&&t>=0?t:null}u(Te,"usdEquivalent");function Ue(e,t){return e.compat?.allowedFallbackModels?.find(r=>r.provider===e.provider&&r.model===t)}u(Ue,"allowedFallback");function it(e){return e?{payer:e.payer??"user",sub:e.sub,grantee:e.grantee,inference_endpoint:e.inference_endpoint??null}:void 0}u(it,"llmCallerOf");function Je(e){return e instanceof Fe?e.code==="server_error"?new s(503,"upstream_model_unavailable",e.message):new s(404,"model_unavailable",e.message):e}u(Je,"mintFailure");async function at(e,t,n,r,w,y){const l=y?.payer==="app"?y:void 0;if(e.payer==="app"&&!l)throw new s(403,"payer_not_app","this grant is not app-paid");if(e.payer==="user"&&l)throw new s(400,"invalid_request","this grant is app-paid; payer cannot be user","payer");if(l&&!l.inference_endpoint)throw new s(404,"model_unavailable",`${l.grantee} is app-paid but its grant carries no inference endpoint`);const i=l?.inference_endpoint??void 0;l||Ce(w);const g=await xe(),F=u(c=>c.routeId!=="concrete"&&c.routeId!=="exact","configured"),Y=u(c=>{const p=g.find(c.providerId,c.modelId);return p!==void 0&&(!e.reasoning_effort||p.reasoning)&&(e.seed===void 0&&e.response_format===void 0||p.api==="openai-completions")&&(e.stop===void 0||["openai-completions","anthropic-messages"].includes(p.api))},"matchesFeatures"),pe=u(()=>{const c=me(e.model,e.model_policy,r?.cwd,r?.profileId),p=re(c.kind==="exact"?{kind:"concrete",spec:c.spec}:c,r?.cwd,r?.profileId).filter(F);let a;if(c.kind==="logical")a=e.model_policy==="exact"?p.filter(m=>m.family===c.family&&m.strength===c.strength).slice(0,1):p;else{const m=se(c.spec),A=p.filter(j=>j.providerId===m?.providerId&&j.modelId===m.modelId&&(e.model_policy!=="exact"||j.thinkingLevel===m.thinkingLevel)&&Y(j));if(e.model_policy==="exact")a=A.slice(0,1);else if(A.length)a=A;else{const j=ie(r?.cwd,r?.profileId),x=[...Object.values(j.modelRoutes??{}).flatMap(v=>Object.entries(v.models)),...[j.modelLadders.anthropic,j.modelLadders.openai].flatMap(v=>Object.entries(v))].find(([,v])=>v===c.spec)?.[0],f=me(void 0,"substitute",r?.cwd,r?.profileId);a=x&&f.kind==="logical"?re({...f,strength:x,spec:c.spec},r?.cwd,r?.profileId).filter(v=>F(v)&&v.strength===x):[]}}return a},"ownerCandidates");let I;if(i?I=Ne(i,e.model,e.model_policy==="exact").flatMap((c,p)=>{const a=se(c.model);return a?[{routeId:"app",credentialSource:"app",family:"app",strength:c.strength,...a,rank:p}]:[]}):I=pe(),I=I.filter(Y),I.length===0)throw e.model_policy==="exact"?new s(400,"substitution_refused","no eligible model route is configured"):new s(404,"model_unavailable","no eligible model route is configured");const ee=`chatcmpl-${be()}`;let R=1/0,b,z;for(const c of I){if(!l&&!we(c,g).authenticated)continue;const p=g.find(c.providerId,c.modelId);if(!p)continue;const a=i?{...p,baseUrl:`${i.base_url}/${p.provider}`}:p,m=c.providerId,A=!l&&H(m)?Me(m).filter(x=>!x.authFailure):[],j=A.filter(x=>de(x,a.id)<=Date.now());if(A.length&&!j.length){const x=Math.min(...A.map(f=>de(f,a.id)));x<R&&(R=x,z=`${a.provider}/${a.id}`);continue}const te=l?[void 0,void 0]:A.length?j:[void 0];for(const[x,f]of te.entries()){const v=Date.now();let oe=f?.access;if(f&&f.expires<=Date.now()&&H(m)){const o=g.getProvider(m)?.auth.oauth;if(!o)throw new s(503,"upstream_model_unavailable",`no OAuth refresh for ${m}`,void 0,{served_model:`${a.provider}/${a.id}`});oe=(await Ae(m,f.label,async(k,ne)=>{const W=await o.refresh({type:"oauth",refresh:k,access:"",expires:0,...ne?{clientId:ne}:{}},t??new AbortController().signal),V=W.clientId;return{refresh:W.refresh,access:W.access,expires:W.expires,...typeof V=="string"&&V?{clientId:V}:{}}})).access}const he=Pe(e);let N;if(l&&i)try{N=await Le({audience:i.base_url,sub:l.sub,grantee:l.grantee,initiating_app:l.grantee,scope:["crtr:llm"]},{signal:t})}catch(o){throw Je(o)}const S=f||l?void 0:await g.getApiKeyAndHeaders(a);if(S&&!S.ok)continue;const h=`${a.provider}/${a.id}`,C=e.model??h;let q=!1,O,M=3e4,$;const B=[],X=[],D=[];let d,E;const P=u((o,_=null)=>({id:ee,object:"chat.completion.chunk",created:Math.floor(v/1e3),model:h,served_model:h,requested_model:C,substituted:C!==h&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(C),choices:[{index:0,delta:o,finish_reason:_}]}),"chunk"),T=u(o=>{B.push(o),n?.(o)},"emit"),_e=ve(a,he,{apiKey:N?.access_token??oe??(S?.ok?S.apiKey:void 0),...S?.ok?{headers:S.headers}:{},signal:t,reasoning:e.reasoning_effort??c.thinkingLevel,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.max_tokens!==void 0?{maxTokens:e.max_tokens}:{},...e.top_p!==void 0?{samplingParams:{top_p:e.top_p}}:{},...e.tool_choice==="none"?{toolChoice:"none"}:{},onPayload:u(o=>{if(!o||typeof o!="object")return;const _=e.tool_choice,k=_==="required"?a.api==="anthropic-messages"?{type:"any"}:"required":typeof _=="object"&&_!==null?a.api==="anthropic-messages"?{type:"tool",name:_.function.name}:_:void 0;return{...o,...k?{tool_choice:k}:{},...e.stop!==void 0?{[a.api==="anthropic-messages"?"stop_sequences":"stop"]:typeof e.stop=="string"?[e.stop]:e.stop}:{},...e.seed!==void 0?{seed:e.seed}:{},...e.response_format!==void 0?{response_format:e.response_format}:{}}},"onPayload"),fetch:u(async(o,_)=>{const k=await fetch(o,_);return O=k.status,k.status===429&&(q=!0,$=k.headers,M=K(k.headers)??15e3),k},"fetch"),onResponse:u(o=>{o.status===429&&(q=!0,$=o.headers,M=K(o.headers)??15e3)},"onResponse")});try{for await(const o of _e)o.type==="text_delta"&&(X.push(o.delta),T(P({content:o.delta}))),o.type==="thinking_delta"&&(D.push(o.delta),T(P({reasoning_content:o.delta}))),o.type==="done"&&(d=o.message),o.type==="error"&&(d=o.error)}catch(o){const _=qe(o);$===void 0&&o&&typeof o=="object"&&"headers"in o&&Object.keys(Re(o.headers)).length&&($=o.headers);const k=ce({status:o&&typeof o=="object"&&"status"in o?o.status:void 0,message:o instanceof Error?o.message:String(o)});if(l)E=o;else{if(!q&&k.kind!=="rate-limit")throw B.length?new s(503,"upstream_model_unavailable",o instanceof Error?o.message:String(o),void 0,{served_model:h}):o;q=!0,M=_??M}}if(l){if(O===401){if(N&&Oe(N.key),x===0)continue;throw new s(404,"model_unavailable",`${i.base_url} refuses this runtime's tokens`,void 0,{served_model:h})}if(q&&K($)===void 0)throw new s(503,"upstream_model_unavailable",`${h} was rate-limited without a retry-after`,void 0,{served_model:h});if(!q&&(E!==void 0||O!==void 0&&O>=500))throw new s(503,"upstream_model_unavailable",E instanceof Error?E.message:d?.errorMessage??"inference endpoint failed",void 0,{served_model:h})}if(!q&&d?.stopReason==="error"&&ce({message:d.errorMessage}).kind==="rate-limit"&&(q=!0,M=15e3),q){const o=Ie($,a.id);if(K($)===void 0&&o.resetAt!==void 0&&(M=Math.max(M,o.resetAt-Date.now())),b={provider:m,model:a.id,...f?{account:f.label}:{},observation:o},console.error(`[llm] 429 from ${h}${f?` account "${f.label}"`:""}: scope=${le(o.scope)} retry_after_ms=${M} headers=${JSON.stringify(o.headers)}`),f&&H(m)&&await ke(m,f.label,M,v,Date.now(),o.scope),Date.now()+Math.min(M,ae)<R&&(R=Date.now()+Math.min(M,ae),z=h),X.length||D.length)throw new s(503,"service_unavailable","vendor rate limit after output began",void 0,{served_model:h});if(l)break;continue}const U=Se(d);if(O===400&&e.tool_choice!==void 0&&e.tool_choice!=="auto"&&e.tool_choice!=="none"&&/\btool[_ ]choice\b/i.test(d?.errorMessage??"")&&/not supported|does not support|unsupported|cannot|must be auto/i.test(d?.errorMessage??""))throw new s(400,"invalid_request",d.errorMessage,"tool_choice",{served_model:h});if(!d||d.stopReason==="error"&&!U||d.stopReason==="aborted")throw new s(503,"upstream_model_unavailable",d?.errorMessage??"model request failed",void 0,{served_model:h});f&&H(m)&&$e(f,a.id)&&await je(m,f.label,v,a.id);const Z=d.content.filter(o=>o.type==="toolCall").map(o=>({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.arguments)}})),G=U?"content_filter":d.stopReason==="toolUse"?"tool_calls":d.stopReason==="length"?"length":"stop",Q=d.responseModel?Ue(a,d.responseModel):void 0,L=Q?`${a.provider}/${Q.model}`:h,J={prompt_tokens:d.usage.input,completion_tokens:d.usage.output,total_tokens:d.usage.totalTokens,cache_read_tokens:d.usage.cacheRead,cache_write_tokens:d.usage.cacheWrite,usd_equivalent:Te(Q??a,d.usage.cost.total),served_model:L};l?ue(l.grantee,"app",L,d.usage,J.usd_equivalent):w&&ue(w.grantee,"user",L,d.usage,J.usd_equivalent);const ye={id:ee,object:"chat.completion",created:Math.floor(v/1e3),model:L,served_model:L,requested_model:C,substituted:C!==L&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(C),choices:[{index:0,message:{role:"assistant",content:X.join("")||null,...D.length?{reasoning_content:D.join("")}:{},...Z.length?{tool_calls:Z}:{},...U?{refusal:d.errorMessage??"Content filtered"}:{}},finish_reason:G}],usage:J,...e.metadata!==void 0?{metadata:e.metadata}:{}};for(const[o,_]of Z.entries())T(P({tool_calls:[{index:o,..._}]}));return T({...P({},G),...U?{choices:[{index:0,delta:{},finish_reason:G,message:{refusal:d.errorMessage??"Content filtered"}}]}:{},usage:J}),{completion:ye,chunks:B}}}throw R!==1/0?new s(429,"all_routes_exhausted","all eligible model routes are rate-limited",void 0,{retry_after_s:Math.max(1,Math.ceil((R-Date.now())/1e3)),served_model:b?`${b.provider}/${b.model}`:z,...b?{rate_limit:{provider:b.provider,model:b.model,...b.account?{account:b.account}:{},scope:le(b.observation.scope),...b.observation.claim?{claim:b.observation.claim}:{},headers:b.observation.headers}}:{}},void 0,!0):e.model_policy==="exact"?new s(400,"substitution_refused","the requested model is unavailable"):new s(404,"model_unavailable","no usable model route is available")}u(at,"runLlm");export{it as llmCallerOf,st as parseLlmRequest,at as runLlm};
|
|
3
|
+
`),l=e.tools?.map(({function:s})=>({name:s.name,description:s.description??"",parameters:s.parameters??{type:"object",properties:{}}}));return{...y?{systemPrompt:y}:{},messages:n.slice(w.length),...l?{tools:l}:{}}}u(Te,"contextOf");function me(e,t,n,r){if(!e){const y=se(n,r),l=Object.values({...y.modelRoutes??{},...y.legacyModelRoutes??{}}),s=l.length?[y.modelLadders.defaultProvider,...y.modelRouting?.familyOrder??[],...l.map(g=>g.family)].find(g=>l.some(E=>E.family===g)):y.modelLadders.defaultProvider??"anthropic";return{kind:"logical",family:s,strength:"strong",spec:`${s}/strong`}}const w=/^([^/]+)\/(ultra|strong|medium|light)$/.exec(e);return w?{kind:"logical",family:w[1],strength:w[2],spec:e}:{kind:t==="exact"?"exact":"concrete",spec:e}}u(me,"requestFor");function Pe(e,t){const{input:n,output:r,cacheRead:w,cacheWrite:y}=e.cost;return n===0&&r===0&&w===0&&y===0?null:Number.isFinite(t)&&t>=0?t:null}u(Pe,"usdEquivalent");function Ue(e,t){return e.compat?.allowedFallbackModels?.find(r=>r.provider===e.provider&&r.model===t)}u(Ue,"allowedFallback");function dt(e){return e?{payer:e.payer??"user",sub:e.sub,grantee:e.grantee,inference_endpoint:e.inference_endpoint??null}:void 0}u(dt,"llmCallerOf");function Je(e){return e instanceof Ee?e.code==="server_error"?new i(503,"upstream_model_unavailable",e.message):new i(404,"model_unavailable",e.message):e}u(Je,"mintFailure");const We=/\bmodel is not supported when using Codex with a ChatGPT account\b/i;function He(e,t,n){if(!(e!=="openai-codex"||t===void 0||!We.test(t)))return new i(404,"model_unavailable",t,void 0,{served_model:n})}u(He,"codexAccountModelRejection");async function lt(e,t,n,r,w,y){const l=y?.payer==="app"?y:void 0;if(e.payer==="app"&&!l)throw new i(403,"payer_not_app","this grant is not app-paid");if(e.payer==="user"&&l)throw new i(400,"invalid_request","this grant is app-paid; payer cannot be user","payer");if(l&&!l.inference_endpoint)throw new i(404,"model_unavailable",`${l.grantee} is app-paid but its grant carries no inference endpoint`);const s=l?.inference_endpoint??void 0;l||Oe(w);const g=await xe(),E=u(c=>c.routeId!=="concrete"&&c.routeId!=="exact","configured"),Y=u(c=>{const h=g.find(c.providerId,c.modelId);return h!==void 0&&(!e.reasoning_effort||h.reasoning)&&(e.seed===void 0&&e.response_format===void 0||h.api==="openai-completions")&&(e.stop===void 0||["openai-completions","anthropic-messages"].includes(h.api))},"matchesFeatures"),pe=u(()=>{const c=me(e.model,e.model_policy,r?.cwd,r?.profileId),h=re(c.kind==="exact"?{kind:"concrete",spec:c.spec}:c,r?.cwd,r?.profileId).filter(E);let a;if(c.kind==="logical")a=e.model_policy==="exact"?h.filter(m=>m.family===c.family&&m.strength===c.strength).slice(0,1):h;else{const m=ie(c.spec),q=h.filter(j=>j.providerId===m?.providerId&&j.modelId===m.modelId&&(e.model_policy!=="exact"||j.thinkingLevel===m.thinkingLevel)&&Y(j));if(e.model_policy==="exact")a=q.slice(0,1);else if(q.length)a=q;else{const j=se(r?.cwd,r?.profileId),x=[...Object.values(j.modelRoutes??{}).flatMap(v=>Object.entries(v.models)),...[j.modelLadders.anthropic,j.modelLadders.openai].flatMap(v=>Object.entries(v))].find(([,v])=>v===c.spec)?.[0],f=me(void 0,"substitute",r?.cwd,r?.profileId);a=x&&f.kind==="logical"?re({...f,strength:x,spec:c.spec},r?.cwd,r?.profileId).filter(v=>E(v)&&v.strength===x):[]}}return a},"ownerCandidates");let $;if(s?$=Ne(s,e.model,e.model_policy==="exact").flatMap((c,h)=>{const a=ie(c.model);return a?[{routeId:"app",credentialSource:"app",family:"app",strength:c.strength,...a,rank:h}]:[]}):$=pe(),$=$.filter(Y),$.length===0)throw e.model_policy==="exact"?new i(400,"substitution_refused","no eligible model route is configured"):new i(404,"model_unavailable","no eligible model route is configured");const ee=`chatcmpl-${be()}`;let I=1/0,b,z;for(const c of $){if(!l&&!we(c,g).authenticated)continue;const h=g.find(c.providerId,c.modelId);if(!h)continue;const a=s?{...h,baseUrl:`${s.base_url}/${h.provider}`}:h,m=c.providerId,q=!l&&H(m)?Me(m).filter(x=>!x.authFailure):[],j=q.filter(x=>de(x,a.id)<=Date.now());if(q.length&&!j.length){const x=Math.min(...q.map(f=>de(f,a.id)));x<I&&(I=x,z=`${a.provider}/${a.id}`);continue}const te=l?[void 0,void 0]:q.length?j:[void 0];for(const[x,f]of te.entries()){const v=Date.now();let oe=f?.access;if(f&&f.expires<=Date.now()&&H(m)){const o=g.getProvider(m)?.auth.oauth;if(!o)throw new i(503,"upstream_model_unavailable",`no OAuth refresh for ${m}`,void 0,{served_model:`${a.provider}/${a.id}`});oe=(await qe(m,f.label,async(k,ne)=>{const W=await o.refresh({type:"oauth",refresh:k,access:"",expires:0,...ne?{clientId:ne}:{}},t??new AbortController().signal),V=W.clientId;return{refresh:W.refresh,access:W.access,expires:W.expires,...typeof V=="string"&&V?{clientId:V}:{}}})).access}const he=Te(e);let N;if(l&&s)try{N=await Se({audience:s.base_url,sub:l.sub,grantee:l.grantee,initiating_app:l.grantee,scope:["crtr:llm"]},{signal:t})}catch(o){throw Je(o)}const C=f||l?void 0:await g.getApiKeyAndHeaders(a);if(C&&!C.ok)continue;const p=`${a.provider}/${a.id}`,O=e.model??p;let A=!1,L,M=3e4,R;const B=[],X=[],D=[];let d,F;const T=u((o,_=null)=>({id:ee,object:"chat.completion.chunk",created:Math.floor(v/1e3),model:p,served_model:p,requested_model:O,substituted:O!==p&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(O),choices:[{index:0,delta:o,finish_reason:_}]}),"chunk"),P=u(o=>{B.push(o),n?.(o)},"emit"),_e=ve(a,he,{apiKey:N?.access_token??oe??(C?.ok?C.apiKey:void 0),...C?.ok?{headers:C.headers}:{},signal:t,reasoning:e.reasoning_effort??c.thinkingLevel,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.max_tokens!==void 0?{maxTokens:e.max_tokens}:{},...e.top_p!==void 0?{samplingParams:{top_p:e.top_p}}:{},...e.tool_choice==="none"?{toolChoice:"none"}:{},onPayload:u(o=>{if(!o||typeof o!="object")return;const _=e.tool_choice,k=_==="required"?a.api==="anthropic-messages"?{type:"any"}:"required":typeof _=="object"&&_!==null?a.api==="anthropic-messages"?{type:"tool",name:_.function.name}:_:void 0;return{...o,...k?{tool_choice:k}:{},...e.stop!==void 0?{[a.api==="anthropic-messages"?"stop_sequences":"stop"]:typeof e.stop=="string"?[e.stop]:e.stop}:{},...e.seed!==void 0?{seed:e.seed}:{},...e.response_format!==void 0?{response_format:e.response_format}:{}}},"onPayload"),fetch:u(async(o,_)=>{const k=await fetch(o,_);return L=k.status,k.status===429&&(A=!0,R=k.headers,M=K(k.headers)??15e3),k},"fetch"),onResponse:u(o=>{o.status===429&&(A=!0,R=o.headers,M=K(o.headers)??15e3)},"onResponse")});try{for await(const o of _e)o.type==="text_delta"&&(X.push(o.delta),P(T({content:o.delta}))),o.type==="thinking_delta"&&(D.push(o.delta),P(T({reasoning_content:o.delta}))),o.type==="done"&&(d=o.message),o.type==="error"&&(d=o.error)}catch(o){const _=Ae(o);R===void 0&&o&&typeof o=="object"&&"headers"in o&&Object.keys(Ie(o.headers)).length&&(R=o.headers);const k=ce({status:o&&typeof o=="object"&&"status"in o?o.status:void 0,message:o instanceof Error?o.message:String(o)});if(l)F=o;else{if(!A&&k.kind!=="rate-limit")throw B.length?new i(503,"upstream_model_unavailable",o instanceof Error?o.message:String(o),void 0,{served_model:p}):o;A=!0,M=_??M}}if(l){if(L===401){if(N&&Le(N.key),x===0)continue;throw new i(404,"model_unavailable",`${s.base_url} refuses this runtime's tokens`,void 0,{served_model:p})}if(A&&K(R)===void 0)throw new i(503,"upstream_model_unavailable",`${p} was rate-limited without a retry-after`,void 0,{served_model:p});if(!A&&(F!==void 0||L!==void 0&&L>=500))throw new i(503,"upstream_model_unavailable",F instanceof Error?F.message:d?.errorMessage??"inference endpoint failed",void 0,{served_model:p})}if(!A&&d?.stopReason==="error"&&ce({message:d.errorMessage}).kind==="rate-limit"&&(A=!0,M=15e3),A){const o=$e(R,a.id);if(K(R)===void 0&&o.resetAt!==void 0&&(M=Math.max(M,o.resetAt-Date.now())),b={provider:m,model:a.id,...f?{account:f.label}:{},observation:o},console.error(`[llm] 429 from ${p}${f?` account "${f.label}"`:""}: scope=${le(o.scope)} retry_after_ms=${M} headers=${JSON.stringify(o.headers)}`),f&&H(m)&&await ke(m,f.label,M,v,Date.now(),o.scope),Date.now()+Math.min(M,ae)<I&&(I=Date.now()+Math.min(M,ae),z=p),X.length||D.length)throw new i(503,"service_unavailable","vendor rate limit after output began",void 0,{served_model:p});if(l)break;continue}const U=Ce(d);if(L===400&&e.tool_choice!==void 0&&e.tool_choice!=="auto"&&e.tool_choice!=="none"&&/\btool[_ ]choice\b/i.test(d?.errorMessage??"")&&/not supported|does not support|unsupported|cannot|must be auto/i.test(d?.errorMessage??""))throw new i(400,"invalid_request",d.errorMessage,"tool_choice",{served_model:p});if(d?.stopReason==="error"){const o=He(a.provider,d.errorMessage,p);if(o)throw o}if(!d||d.stopReason==="error"&&!U||d.stopReason==="aborted")throw new i(503,"upstream_model_unavailable",d?.errorMessage??"model request failed",void 0,{served_model:p});f&&H(m)&&Re(f,a.id)&&await je(m,f.label,v,a.id);const G=d.content.filter(o=>o.type==="toolCall").map(o=>({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.arguments)}})),Z=U?"content_filter":d.stopReason==="toolUse"?"tool_calls":d.stopReason==="length"?"length":"stop",Q=d.responseModel?Ue(a,d.responseModel):void 0,S=Q?`${a.provider}/${Q.model}`:p,J={prompt_tokens:d.usage.input,completion_tokens:d.usage.output,total_tokens:d.usage.totalTokens,cache_read_tokens:d.usage.cacheRead,cache_write_tokens:d.usage.cacheWrite,usd_equivalent:Pe(Q??a,d.usage.cost.total),served_model:S};l?ue(l.grantee,"app",S,d.usage,J.usd_equivalent):w&&ue(w.grantee,"user",S,d.usage,J.usd_equivalent);const ye={id:ee,object:"chat.completion",created:Math.floor(v/1e3),model:S,served_model:S,requested_model:O,substituted:O!==S&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(O),choices:[{index:0,message:{role:"assistant",content:X.join("")||null,...D.length?{reasoning_content:D.join("")}:{},...G.length?{tool_calls:G}:{},...U?{refusal:d.errorMessage??"Content filtered"}:{}},finish_reason:Z}],usage:J,...e.metadata!==void 0?{metadata:e.metadata}:{}};for(const[o,_]of G.entries())P(T({tool_calls:[{index:o,..._}]}));return P({...T({},Z),...U?{choices:[{index:0,delta:{},finish_reason:Z,message:{refusal:d.errorMessage??"Content filtered"}}]}:{},usage:J}),{completion:ye,chunks:B}}}throw I!==1/0?new i(429,"all_routes_exhausted","all eligible model routes are rate-limited",void 0,{retry_after_s:Math.max(1,Math.ceil((I-Date.now())/1e3)),served_model:b?`${b.provider}/${b.model}`:z,...b?{rate_limit:{provider:b.provider,model:b.model,...b.account?{account:b.account}:{},scope:le(b.observation.scope),...b.observation.claim?{claim:b.observation.claim}:{},headers:b.observation.headers}}:{}},void 0,!0):e.model_policy==="exact"?new i(400,"substitution_refused","the requested model is unavailable"):new i(404,"model_unavailable","no usable model route is available")}u(lt,"runLlm");export{dt as llmCallerOf,at as parseLlmRequest,lt as runLlm};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var W=Object.defineProperty;var d=(e,t)=>W(e,"name",{value:t,configurable:!0});import{setTimeout as j}from"node:timers/promises";import{createAssistantMessageEventStream as J,getCurrentSystemPrompt as Y,getCurrentTools as z}from"@earendil-works/pi-ai";import{socketFetch as X}from"../../../api/node-transport.js";import{apiSocketPath as G}from"../../canvas/paths.js";import{currentNodeToken as H}from"./node-token.js";import{envModelExact as
|
|
2
|
-
`))>=0;){const f=g.slice(0,m).trim();g=g.slice(m+1),f
|
|
1
|
+
var W=Object.defineProperty;var d=(e,t)=>W(e,"name",{value:t,configurable:!0});import{setTimeout as j}from"node:timers/promises";import{createAssistantMessageEventStream as J,getCurrentSystemPrompt as Y,getCurrentTools as z}from"@earendil-works/pi-ai";import{socketFetch as X}from"../../../api/node-transport.js";import{apiSocketPath as G}from"../../canvas/paths.js";import{currentNodeToken as H}from"./node-token.js";import{envModelExact as C,envModelIntent as K}from"../../../shared/env.js";import{MODEL_CONTEXT_BODY_MAX_BYTES as E}from"../../llm/body-limits.js";import{modelRequestFromConfig as V}from"../../model-routes.js";import{parseProviderRateLimit as Q,providerFailureDiagnostic as b}from"../../provider-failure.js";import{UPSTREAM_MODEL_UNAVAILABLE as R}from"../../fault-classifier.js";function me(e,t){e.checkAuth=async n=>e.getProvider(n)?{type:"api_key"}:void 0,e.getAvailable=async n=>e.getModels(n),e.getAvailableSnapshot=()=>e.getModels(),e.streamSimple=(n,c,r)=>ne(n,c,r,t)}d(me,"configureBrokerModelRuntime");const Z=300,N="crtr:llm-refusal";class k extends Error{static{d(this,"LlmRefusalError")}retryAt;rateLimit;code;status;constructor(t,n,c,r,o){super(t),this.retryAt=n,this.rateLimit=c,this.code=r,this.status=o}}class S extends Error{static{d(this,"UpstreamModelUnavailableError")}}function D(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`)}d(D,"contextTooLargeError");function A(e){const t=e.details?.rate_limit;if(!t||typeof t!="object")return;const n=Q(t);if(n===void 0)return;const{provider:c,model:r}=t;return typeof c=="string"&&c!==""&&typeof r=="string"&&r!==""?{...n,model:`${c}/${r}`}:n}d(A,"refusalRateLimit");function he(e){for(const t of e.diagnostics??[]){if(t.type!==N)continue;const n=t.details?.retryAt;if(typeof n=="number"&&Number.isFinite(n)&&n>0)return n}}d(he,"refusalRetryAt");class q extends Error{static{d(this,"ContentFilteredError")}}function B(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}`}})}d(B,"wireContent");function ee(e){const t=d(r=>r.role==="assistant"&&(r.stopReason==="error"||r.stopReason==="aborted"),"incomplete"),n=e.some(t)?e.filter(r=>!t(r)):e;let c=n.length;for(;c>0&&n[c-1]?.role==="assistant";)c--;return c===n.length?n:n.slice(0,c)}d(ee,"wireHistory");function te(e,t,n,c){const r=[],o=Y(t.messages),a=z(t.messages);o?r.push({role:"system",content:o}):t.systemPrompt&&r.push({role:"system",content:t.systemPrompt});for(const p of ee(t.messages))p.role==="user"?r.push({role:"user",content:B(p.content)}):p.role==="toolResult"?r.push({role:"tool",content:B(p.content),tool_call_id:p.toolCallId}):p.role==="assistant"&&r.push({role:"assistant",content:p.content.filter(u=>u.type==="text").map(u=>u.text).join("")||null,tool_calls:p.content.filter(u=>u.type==="toolCall").map(u=>({id:u.id,type:"function",function:{name:u.name,arguments:JSON.stringify(u.arguments)}}))});const x=`${e.provider}/${e.id}`,_=c??K();return{model:V(x,_,C())?.kind==="logical"?_:x,model_policy:C()?"exact":"substitute",stream:!0,messages:r,...a.length?{tools:a.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}:{}}}d(te,"requestBody");function L(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)}d(L,"applyServedModel");function F(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}d(F,"refusalRoute");function P(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}d(P,"parseRefusal");function ne(e,t,n={},c){const r=J(),o={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 a=H();if(!a)throw new Error("llm requires a node token");const x=JSON.stringify(te(e,t,n,c)),_=Buffer.byteLength(x);if(_>E)throw D(_,E);let p=0;for(;;){n.signal?.throwIfAborted();const u=await X(G())("http://localhost/v1/llm",{method:"POST",headers:{authorization:`Bearer ${a}`,"content-type":"application/json"},body:x,signal:n.signal});if(!u.ok){const l=P(await u.json());if(u.status===413||l.code==="payload_too_large")throw D(_,E);if(L(o,F(l)),l.retryable!==!0)throw new k(l.message,void 0,A(l),l.code,u.status);const s=l.retry_after_s;if(typeof s!="number"||!Number.isFinite(s)||s<=0)throw l.code===R?new S(l.message):new Error(l.message);const m=Z-p;if(s>m){const f=Date.now()+s*1e3;throw new k(`${l.message} (retry after ${s}s, at ${new Date(f).toISOString()})`,f,A(l))}await j(s*1e3,void 0,{signal:n.signal}),p+=s;continue}if(!u.body)throw new Error("llm returned no stream");r.push({type:"start",partial:o});const U=u.body.getReader(),I=new TextDecoder;let g="",w="stop",M,T=!1,O=!1;const $=d(l=>{const s=JSON.parse(l);if(s.error){const i=P(s);throw L(o,F(i)),i.retryable!==!0?new k(i.message,void 0,A(i),i.code):i.code===R?new S(i.message):new Error(i.message)}if(s.served_model){if(O=!0,s.served_model.indexOf("/")<1)throw new Error("llm returned an invalid served_model");L(o,s.served_model)}const m=s.choices?.[0],f=m?.delta;if(f?.reasoning_content){const i=o.content.findIndex(v=>v.type==="thinking"),h=i<0?{type:"thinking",thinking:""}:o.content[i],y=i<0?o.content.push(h)-1:i;if(i<0&&r.push({type:"thinking_start",contentIndex:y,partial:o}),h.type!=="thinking")throw new Error("invalid thinking block");h.thinking+=f.reasoning_content,r.push({type:"thinking_delta",contentIndex:y,delta:f.reasoning_content,partial:o})}if(f?.content){const i=o.content.findIndex(v=>v.type==="text"),h=i<0?{type:"text",text:""}:o.content[i],y=i<0?o.content.push(h)-1:i;if(i<0&&r.push({type:"text_start",contentIndex:y,partial:o}),h.type!=="text")throw new Error("invalid text block");h.text+=f.content,r.push({type:"text_delta",contentIndex:y,delta:f.content,partial:o})}for(const i of f?.tool_calls??[]){const h={type:"toolCall",id:i.id,name:i.function.name,arguments:JSON.parse(i.function.arguments)},y=o.content.push(h)-1;r.push({type:"toolcall_start",contentIndex:y,partial:o}),r.push({type:"toolcall_end",contentIndex:y,toolCall:h,partial:o})}m?.finish_reason&&(w=m.finish_reason),m?.message?.refusal&&(M=m.message.refusal),s.usage&&(T=!0,o.usage={input:s.usage.prompt_tokens,output:s.usage.completion_tokens,cacheRead:s.usage.cache_read_tokens,cacheWrite:s.usage.cache_write_tokens,totalTokens:s.usage.total_tokens,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:typeof s.usage.usd_equivalent=="number"&&Number.isFinite(s.usage.usd_equivalent)?s.usage.usd_equivalent:0}})},"apply");for(;;){const{value:l,done:s}=await U.read();if(s)break;g+=I.decode(l,{stream:!0});let m;for(;(m=g.indexOf(`
|
|
2
|
+
`))>=0;){const f=g.slice(0,m).trim();g=g.slice(m+1),f&&$(f)}}if(g+=I.decode(),g.trim()&&$(g.trim()),!T||!O)throw new Error("llm stream ended without usage or served_model");for(const[l,s]of o.content.entries())s.type==="text"&&r.push({type:"text_end",contentIndex:l,content:s.text,partial:o}),s.type==="thinking"&&r.push({type:"thinking_end",contentIndex:l,content:s.thinking,partial:o});if(w==="content_filter")throw new q(M??"Content filtered");if(!["stop","tool_calls","length"].includes(w))throw new Error(`llm returned unknown finish reason: ${w}`);o.stopReason=w==="tool_calls"?"toolUse":w==="length"?"length":"stop",r.push({type:"done",reason:o.stopReason,message:o}),r.end();return}})().catch(a=>{o.stopReason=n.signal?.aborted?"aborted":"error",o.errorMessage=a instanceof Error?a.message:String(a),a instanceof k&&(o.diagnostics=[{type:N,timestamp:Date.now(),...a.retryAt!==void 0?{details:{retryAt:a.retryAt}}:{}},...a.rateLimit!==void 0?[b({status:429,ratelimit:a.rateLimit})]:[],...a.rateLimit===void 0&&a.code==="cap_exhausted"?[b({status:a.status??402,code:a.code})]:[]]),a instanceof S&&(o.diagnostics=[b({status:503,code:R})]),a instanceof q&&o.stopReason==="error"&&(o.rawStopReason="content_filter"),r.push({type:"error",reason:o.stopReason,error:o}),r.end()}),r}d(ne,"streamBrokerModel");export{Z as LLM_BROKER_RETRY_WINDOW_S,N as LLM_REFUSAL_DIAGNOSTIC,me as configureBrokerModelRuntime,he as refusalRetryAt,te as requestBody,ne as streamBrokerModel,ee as wireHistory};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var J=Object.defineProperty;var a=(e,t)=>J(e,"name",{value:t,configurable:!0});import{envHomeOverride as K,envRuntimeHomeOverride as X,INBOX_BETWEEN_TURNS_ENV as z,SCOPES_FILE_ENV as V,scopeAllowed as C}from"../../shared/env.js";import{isOwnMemoryScope as Y,validateScopes as Q}from"../scopes.js";import{activeGrant as B,terminalGrant as k}from"../grants/mirror.js";import{appendRunEvent as Z}from"../runs/events.js";import{readConfig as S}from"../config.js";import{InputError as T}from"../io.js";import{ApiError as w}from"../../api/errors.js";import{assertGranteeRunsHere as ee}from"./unsandboxed.js";import{randomBytes as ne}from"node:crypto";import{existsSync as P}from"node:fs";import{resolve as re,relative as te,isAbsolute as H,join as ie,sep as oe}from"node:path";import{appSpace as le}from"../layout.js";import{scopesFilePath as ae}from"../canvas/paths.js";import{createNode as se,assertRunNotDeleting as de,conversationOwner as ue,getNode as c,getRow as ce}from"../canvas/index.js";import{ensureAppSpace as fe}from"../spaces/space.js";import{LAUNCHER_SOCKET as L}from"../../launcher/spec.js";import{resolveInstallId as pe}from"../canvas/install-id.js";import{isAppRun as me}from"../canvas/app-run.js";import{canvasDbPath as _e,contextDir as ge}from"../canvas/paths.js";import{conversationIdFromPath as we}from"../conversation-store/index.js";import{usage as U}from"../errors.js";import{assertProfileAvailableForBirth as he}from"../profiles/deletion-reservation.js";import{loadExactProfileManifest as ve}from"../profiles/manifest.js";import{admitNodeCreate as Re}from"../command-hooks/lifecycle-create.js";import{getById as Ee,nodeObject as I,ownerForGrantee as ye}from"../graph/objects.js";import{recordActedOn as Ce}from"../graph/edges.js";import{recordWatch as Ie,copyWatchesForFork as Ne}from"../graph/watches.js";import{publish as ke}from"../graph/events.js";let O;const j=new Map;function cn(e){O=e}a(cn,"setInstallId");function Se(){if(O!==void 0)return O;const e=_e(),t=j.get(e);if(t!==void 0)return t;const o=pe();return j.set(e,o),o}a(Se,"installId");function Te(){return`${Date.now().toString(36)}-${ne(4).toString("hex")}`}a(Te,"newJobId");function Oe(){return`${Se()}-${Te()}`}a(Oe,"newNodeId");const x=128,xe=/^[a-z0-9-]+$/;class q extends Error{static{a(this,"NodeIdConflictError")}nodeId;constructor(t){super(`node already exists: ${t}`),this.nodeId=t,this.name="NodeIdConflictError"}}function D(e){if(e.length===0||e.length>x)throw U(`invalid --node-id '${e}': must be 1-${x} characters`,{next:`Pass an id-safe string (lowercase letters, digits, hyphens) of at most ${x} characters.`});if(!xe.test(e))throw U(`invalid --node-id '${e}': must contain only lowercase letters, digits, and hyphens (e.g. 'remote42', 'my-node-1')`,{next:"Use only lowercase letters, digits, and hyphens."})}a(D,"validateNodeIdFormat");function fn(e){if(D(e),c(e)!==null)throw new q(e)}a(fn,"preflightNodeId");function De(e){if(D(e),c(e)!==null)throw new q(e);return e}a(De,"validatedExplicitNodeId");function pn(e){let t=e;const o=new Set;for(;;){if(o.has(t))return t;o.add(t);const s=ce(t);if(s===null||s.parent==null)return t;t=s.parent}}a(pn,"rootOfSpine");function mn(){const e=process.env;return{nodeId:e.CRTR_NODE_ID??null,kind:e.CRTR_KIND??null,mode:e.CRTR_MODE??null}}a(mn,"currentNodeContext");function be(e){return me(e)}a(be,"inboxBetweenTurns");function _n(e){const t={CRTR_NODE_ID:e.node_id,CRTR_KIND:e.kind,CRTR_MODE:e.mode,CRTR_LIFECYCLE:e.lifecycle,CRTR_NODE_CWD:e.cwd,CRTR_CONTEXT_DIR:ge(e.node_id,e.grantee),CRTR_CYCLES:(e.cycles??0).toString(),CRTR_PROFILE_ID:e.profile_id??"",PI_CLAUDE_OAUTH_REINJECT_SCOPE:"never"};e.parent&&(t.CRTR_PARENT_NODE_ID=e.parent),e.run_id&&(t.CRTR_RUN_ID=e.run_id),be(e)&&(t[z]="1"),e.scopes!==null&&e.scopes!==void 0&&(t[V]=ae(e.node_id)),t.CRTR_GRANTEE=e.grantee??"app:terminal";const o=K();o!==void 0&&o!==""&&(t.CRTR_HOME=o);const s=X();s!==void 0&&s!==""&&(t.CRTR_RUNTIME_HOME=s);const f=process.env.CRTR_SUBTREE;return f!==void 0&&f!==""&&(t.CRTR_SUBTREE=f),{...t,...e.launch?.env??{}}}a(_n,"nodeEnv");function Ae(e){const t=we(e),o=t===null?null:ue(t);return o===null?null:c(o)}a(Ae,"forkSourceNode");async function gn(e){const t=e.nodeId!==void 0?(D(e.nodeId),e.nodeId):Oe(),o=e.parent??null,s=o===null,f=e.spawnedBy??o,m=e.creator??null,b=e.mode??"base",N=e.lifecycle??(s?"resident":"terminal"),h=e.run===void 0?k():null,n={node_id:t,name:e.name??e.kind,description:e.description,cycles:0,created:new Date().toISOString(),cwd:e.cwd,host_kind:"broker",profile_id:e.profile_id??null,kind:e.kind,mode:b,lifecycle:N,persona_ack:{kind:e.kind,mode:b,lifecycle:N},status:"active",parent:o,spawned_by:f,creator:m,fork_from:e.forkFrom,fork_source_file:e.forkSourceFile,review_binding:e.reviewBinding,model_override:e.modelOverride??null,scopes:e.scopes??null,isolated:e.isolated===!0,grantee:e.run?.grantee??"app:terminal",sub:e.run?.sub??h?.sub??null,grant_id:e.run?.grant_id??h?.id??null,client_id:e.run?.client_id??null,metadata_json:s?e.run?.metadata_json??null:null,run_id:s?t:e.run?.run_id??null,event_cursor:s?e.run?.event_cursor??1:null,usage_json:s?e.run?.usage_json??JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}):null,passive_default:e.passiveDefault??!1,...e.managedWorktree!==void 0?{managed_worktree:e.managedWorktree}:{},intent:null,deadline_at:e.deadlineAt??null,pi_session_id:null,pi_session_file:null,launch:e.launch},E=e.scopes===void 0?void 0:Q(e.scopes),v=o===null?null:c(o);if(o!==null&&v===null)throw new Error(`cannot spawn under unknown parent node: ${o}`);if(v?.run_id&&c(v.run_id)?.deleting_at)throw new Error("run is deleting");const u=m===null?null:c(m);if(m!==null&&u===null)throw new Error(`cannot spawn from unknown creator node: ${m}`);if(u?.run_id&&c(u.run_id)?.deleting_at)throw new Error("run is deleting");const A=e.forkSourceFile==null?null:Ae(e.forkSourceFile),$=e.replaces==null?null:c(e.replaces),_=v??A??$??u??(f===null?null:c(f)),F=[v,u,A,$,f===null?null:c(f)].some(r=>r?.isolated===!0||r?.run_id!=null&&c(r.run_id)?.isolated===!0);if(F&&e.isolated===!1)throw new w(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});if(n.isolated=F||e.isolated===!0,_!==null){const r=u??_;if(u&&_.grantee&&u.grantee&&u.grantee!==_.grantee)throw new w(403,"other_app_run","cannot create under another app's node");const i=u&&u!==_?[_,u]:[_],d=[],g=new Set;for(const l of i){l.scopes!==null&&l.scopes!==void 0&&d.push(l.scopes);const p=l.grantee==="app:terminal"?k():l.grant_id?B(l.grant_id):null;if(p){const R=[...p.resolved];g.add(R),d.push(R)}else if(!(l.grantee==="app:terminal"&&!S("user").runtime?.issuer)){const R=[];g.add(R),d.push(R)}}const y=a(l=>Y(l,r.grantee==="user:local"?"app:terminal":r.grantee??"app:terminal"),"ownMemory"),M=a((l,p)=>y(p)&&g.has(l)||C(l,p),"allowed");if(E!==void 0&&!E.every(l=>d.every(p=>M(p,l))))throw new T({error:"unknown_scope",message:"child scopes must be covered by the creating node, its source and their current grants",received:E,field:"scopes",next:"Request only scopes the creating node currently holds."});if(n.scopes=E??(i.every(l=>l.scopes==null)&&i.every(l=>l.grant_id===r.grant_id&&l.sub===r.sub)?null:i.length===1?_.scopes??null:[...new Set(d.flat().filter(l=>d.every(p=>M(p,l))))]),n.scopes?.includes("crtr:act")&&!C(n.scopes,"crtr:llm"))throw new T({error:"invalid_scope",message:"crtr:act requires crtr:llm",received:n.scopes,field:"scopes",next:"Include crtr:llm or omit crtr:act."});n.grantee=r.grantee==="user:local"?"app:terminal":r.grantee,n.sub=r.sub??(n.grantee==="app:terminal"?h?.sub:null)??null,n.grant_id=r.grant_id??(n.grantee==="app:terminal"?h?.id:null)??null,n.client_id=r.client_id,n.run_id=s?t:r.run_id??null}if(ee(n.grantee),e.run===void 0&&n.grantee==="app:terminal"&&S("user").runtime?.issuer&&h===null)throw new w(403,"scope_missing","terminal grant is not active");if(n.isolated){if(process.platform!=="linux"||!P(L))throw new w(400,"isolated_unavailable","isolated nodes require the Linux root launcher");if(e.managedWorktree!==void 0)throw new w(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const r=ie(le(n.grantee??"app:terminal").nodes,t),i=te(r,re(n.cwd));if(!H(n.cwd)||i===".."||i.startsWith(`..${oe}`)||H(i))throw new w(400,"invalid_request","isolated node cwd must be inside its own folder",{param:"cwd"})}if(n.profile_id){const r=ve(n.profile_id).manifest.grantee??"app:terminal";if(r!==n.grantee){const i=`crtr:memory:rw:${r}:profile:${n.profile_id}`,d=n.grantee==="app:terminal"?k():n.grant_id?B(n.grant_id):null;if(!(n.grantee==="app:terminal"&&!S("user").runtime?.issuer)&&(!d||d.grantee!==n.grantee||!C(d.resolved,i))||!C(n.scopes,i))throw new T({error:"scope_missing",message:`missing scope ${i}`,received:n.profile_id,field:"profile",next:"Select a profile covered by this run and its current grant."})}}if(he(n.profile_id??null),!n.grantee)throw new Error("node creation requires an app");const W=await Re({kind:n.kind,mode:n.mode,cwd:n.cwd,profile:n.profile_id??null,root:s,parentId:o,requestingNodeId:m,lifecycle:N,replaces:e.replaces??null},n.grantee),G=a((r,i)=>{const d=I(r,i.node_id),g=m??o??e.actor??f??null,y=g!==null&&Ee(r,g)?.type==="node"?I(r,g):ye(r,e.run===void 0?"user:local":i.grantee);Ce(r,y,d),o!==null&&e.subscribe!==!1&&Ie(r,I(r,o),d,"spawn"),e.forkSourceNode&&Ne(r,I(r,e.forkSourceNode),d),ke(r,{event:"created",object:d,actor:y,attrs:{name:i.name,kind:i.kind,creator:m??null}})},"recordBirth");try{e.nodeId!==void 0&&De(e.nodeId),await e.beforeCreate?.(),(process.platform!=="linux"||P(L))&&await fe(n.grantee??"app:terminal"),se(n,{outcomeDelivery:e.outcomeDelivery,withinCreate:a((r,i)=>{i.run_id&&i.run_id!==i.node_id&&de(r,i.run_id),s&&e.run===void 0&&Z(r,t,t,"run.started",{scopes:i.scopes??null,payer:"user",usage:JSON.parse(i.usage_json)}),e.withinCreate?.(r,i),G(r,i)},"withinCreate")})}finally{W()}return n}a(gn,"spawnNode");export{q as NodeIdConflictError,mn as currentNodeContext,Ae as forkSourceNode,be as inboxBetweenTurns,Te as newJobId,Oe as newNodeId,_n as nodeEnv,fn as preflightNodeId,pn as rootOfSpine,cn as setInstallId,gn as spawnNode};
|
|
1
|
+
var J=Object.defineProperty;var a=(e,t)=>J(e,"name",{value:t,configurable:!0});import{envHomeOverride as K,envRuntimeHomeOverride as X,INBOX_BETWEEN_TURNS_ENV as z,SCOPES_FILE_ENV as V,scopeAllowed as C}from"../../shared/env.js";import{isOwnMemoryScope as Y,validateScopes as Q}from"../scopes.js";import{activeGrant as B,terminalGrant as k}from"../grants/mirror.js";import{grantSnapshotMissing as Z}from"../../daemon/readiness.js";import{appendRunEvent as ee}from"../runs/events.js";import{readConfig as S}from"../config.js";import{InputError as T}from"../io.js";import{ApiError as w}from"../../api/errors.js";import{assertGranteeRunsHere as ne}from"./unsandboxed.js";import{randomBytes as re}from"node:crypto";import{existsSync as P}from"node:fs";import{resolve as te,relative as ie,isAbsolute as H,join as oe,sep as le}from"node:path";import{appSpace as ae}from"../layout.js";import{scopesFilePath as se}from"../canvas/paths.js";import{createNode as de,assertRunNotDeleting as ue,conversationOwner as ce,getNode as c,getRow as fe}from"../canvas/index.js";import{ensureAppSpace as pe}from"../spaces/space.js";import{LAUNCHER_SOCKET as L}from"../../launcher/spec.js";import{resolveInstallId as me}from"../canvas/install-id.js";import{isAppRun as _e}from"../canvas/app-run.js";import{canvasDbPath as ge,contextDir as we}from"../canvas/paths.js";import{conversationIdFromPath as he}from"../conversation-store/index.js";import{usage as U}from"../errors.js";import{assertProfileAvailableForBirth as ve}from"../profiles/deletion-reservation.js";import{loadExactProfileManifest as Re}from"../profiles/manifest.js";import{admitNodeCreate as Ee}from"../command-hooks/lifecycle-create.js";import{getById as ye,nodeObject as I,ownerForGrantee as Ce}from"../graph/objects.js";import{recordActedOn as Ie}from"../graph/edges.js";import{recordWatch as Ne,copyWatchesForFork as ke}from"../graph/watches.js";import{publish as Se}from"../graph/events.js";let O;const j=new Map;function pn(e){O=e}a(pn,"setInstallId");function Te(){if(O!==void 0)return O;const e=ge(),t=j.get(e);if(t!==void 0)return t;const o=me();return j.set(e,o),o}a(Te,"installId");function Oe(){return`${Date.now().toString(36)}-${re(4).toString("hex")}`}a(Oe,"newJobId");function xe(){return`${Te()}-${Oe()}`}a(xe,"newNodeId");const x=128,De=/^[a-z0-9-]+$/;class q extends Error{static{a(this,"NodeIdConflictError")}nodeId;constructor(t){super(`node already exists: ${t}`),this.nodeId=t,this.name="NodeIdConflictError"}}function D(e){if(e.length===0||e.length>x)throw U(`invalid --node-id '${e}': must be 1-${x} characters`,{next:`Pass an id-safe string (lowercase letters, digits, hyphens) of at most ${x} characters.`});if(!De.test(e))throw U(`invalid --node-id '${e}': must contain only lowercase letters, digits, and hyphens (e.g. 'remote42', 'my-node-1')`,{next:"Use only lowercase letters, digits, and hyphens."})}a(D,"validateNodeIdFormat");function mn(e){if(D(e),c(e)!==null)throw new q(e)}a(mn,"preflightNodeId");function be(e){if(D(e),c(e)!==null)throw new q(e);return e}a(be,"validatedExplicitNodeId");function _n(e){let t=e;const o=new Set;for(;;){if(o.has(t))return t;o.add(t);const s=fe(t);if(s===null||s.parent==null)return t;t=s.parent}}a(_n,"rootOfSpine");function gn(){const e=process.env;return{nodeId:e.CRTR_NODE_ID??null,kind:e.CRTR_KIND??null,mode:e.CRTR_MODE??null}}a(gn,"currentNodeContext");function Ae(e){return _e(e)}a(Ae,"inboxBetweenTurns");function wn(e){const t={CRTR_NODE_ID:e.node_id,CRTR_KIND:e.kind,CRTR_MODE:e.mode,CRTR_LIFECYCLE:e.lifecycle,CRTR_NODE_CWD:e.cwd,CRTR_CONTEXT_DIR:we(e.node_id,e.grantee),CRTR_CYCLES:(e.cycles??0).toString(),CRTR_PROFILE_ID:e.profile_id??"",PI_CLAUDE_OAUTH_REINJECT_SCOPE:"never"};e.parent&&(t.CRTR_PARENT_NODE_ID=e.parent),e.run_id&&(t.CRTR_RUN_ID=e.run_id),Ae(e)&&(t[z]="1"),e.scopes!==null&&e.scopes!==void 0&&(t[V]=se(e.node_id)),t.CRTR_GRANTEE=e.grantee??"app:terminal";const o=K();o!==void 0&&o!==""&&(t.CRTR_HOME=o);const s=X();s!==void 0&&s!==""&&(t.CRTR_RUNTIME_HOME=s);const f=process.env.CRTR_SUBTREE;return f!==void 0&&f!==""&&(t.CRTR_SUBTREE=f),{...t,...e.launch?.env??{}}}a(wn,"nodeEnv");function Me(e){const t=he(e),o=t===null?null:ce(t);return o===null?null:c(o)}a(Me,"forkSourceNode");async function hn(e){const t=e.nodeId!==void 0?(D(e.nodeId),e.nodeId):xe(),o=e.parent??null,s=o===null,f=e.spawnedBy??o,m=e.creator??null,b=e.mode??"base",N=e.lifecycle??(s?"resident":"terminal"),h=e.run===void 0?k():null,n={node_id:t,name:e.name??e.kind,description:e.description,cycles:0,created:new Date().toISOString(),cwd:e.cwd,host_kind:"broker",profile_id:e.profile_id??null,kind:e.kind,mode:b,lifecycle:N,persona_ack:{kind:e.kind,mode:b,lifecycle:N},status:"active",parent:o,spawned_by:f,creator:m,fork_from:e.forkFrom,fork_source_file:e.forkSourceFile,review_binding:e.reviewBinding,model_override:e.modelOverride??null,scopes:e.scopes??null,isolated:e.isolated===!0,grantee:e.run?.grantee??"app:terminal",sub:e.run?.sub??h?.sub??null,grant_id:e.run?.grant_id??h?.id??null,client_id:e.run?.client_id??null,metadata_json:s?e.run?.metadata_json??null:null,run_id:s?t:e.run?.run_id??null,event_cursor:s?e.run?.event_cursor??1:null,usage_json:s?e.run?.usage_json??JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}):null,passive_default:e.passiveDefault??!1,...e.managedWorktree!==void 0?{managed_worktree:e.managedWorktree}:{},intent:null,deadline_at:e.deadlineAt??null,pi_session_id:null,pi_session_file:null,launch:e.launch},E=e.scopes===void 0?void 0:Q(e.scopes),v=o===null?null:c(o);if(o!==null&&v===null)throw new Error(`cannot spawn under unknown parent node: ${o}`);if(v?.run_id&&c(v.run_id)?.deleting_at)throw new Error("run is deleting");const u=m===null?null:c(m);if(m!==null&&u===null)throw new Error(`cannot spawn from unknown creator node: ${m}`);if(u?.run_id&&c(u.run_id)?.deleting_at)throw new Error("run is deleting");const A=e.forkSourceFile==null?null:Me(e.forkSourceFile),M=e.replaces==null?null:c(e.replaces),_=v??A??M??u??(f===null?null:c(f)),$=[v,u,A,M,f===null?null:c(f)].some(r=>r?.isolated===!0||r?.run_id!=null&&c(r.run_id)?.isolated===!0);if($&&e.isolated===!1)throw new w(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});if(n.isolated=$||e.isolated===!0,_!==null){const r=u??_;if(u&&_.grantee&&u.grantee&&u.grantee!==_.grantee)throw new w(403,"other_app_run","cannot create under another app's node");const i=u&&u!==_?[_,u]:[_],d=[],g=new Set;for(const l of i){l.scopes!==null&&l.scopes!==void 0&&d.push(l.scopes);const p=l.grantee==="app:terminal"?k():l.grant_id?B(l.grant_id):null;if(p){const R=[...p.resolved];g.add(R),d.push(R)}else if(!(l.grantee==="app:terminal"&&!S("user").runtime?.issuer)){const R=[];g.add(R),d.push(R)}}const y=a(l=>Y(l,r.grantee==="user:local"?"app:terminal":r.grantee??"app:terminal"),"ownMemory"),F=a((l,p)=>y(p)&&g.has(l)||C(l,p),"allowed");if(E!==void 0&&!E.every(l=>d.every(p=>F(p,l))))throw new T({error:"unknown_scope",message:"child scopes must be covered by the creating node, its source and their current grants",received:E,field:"scopes",next:"Request only scopes the creating node currently holds."});if(n.scopes=E??(i.every(l=>l.scopes==null)&&i.every(l=>l.grant_id===r.grant_id&&l.sub===r.sub)?null:i.length===1?_.scopes??null:[...new Set(d.flat().filter(l=>d.every(p=>F(p,l))))]),n.scopes?.includes("crtr:act")&&!C(n.scopes,"crtr:llm"))throw new T({error:"invalid_scope",message:"crtr:act requires crtr:llm",received:n.scopes,field:"scopes",next:"Include crtr:llm or omit crtr:act."});n.grantee=r.grantee==="user:local"?"app:terminal":r.grantee,n.sub=r.sub??(n.grantee==="app:terminal"?h?.sub:null)??null,n.grant_id=r.grant_id??(n.grantee==="app:terminal"?h?.id:null)??null,n.client_id=r.client_id,n.run_id=s?t:r.run_id??null}if(ne(n.grantee),e.run===void 0&&n.grantee==="app:terminal"&&S("user").runtime?.issuer&&h===null)throw Z()?new w(503,"runtime_starting","the first grant snapshot from the directory has not committed"):new w(403,"scope_missing","terminal grant is not active");if(n.isolated){if(process.platform!=="linux"||!P(L))throw new w(400,"isolated_unavailable","isolated nodes require the Linux root launcher");if(e.managedWorktree!==void 0)throw new w(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const r=oe(ae(n.grantee??"app:terminal").nodes,t),i=ie(r,te(n.cwd));if(!H(n.cwd)||i===".."||i.startsWith(`..${le}`)||H(i))throw new w(400,"invalid_request","isolated node cwd must be inside its own folder",{param:"cwd"})}if(n.profile_id){const r=Re(n.profile_id).manifest.grantee??"app:terminal";if(r!==n.grantee){const i=`crtr:memory:rw:${r}:profile:${n.profile_id}`,d=n.grantee==="app:terminal"?k():n.grant_id?B(n.grant_id):null;if(!(n.grantee==="app:terminal"&&!S("user").runtime?.issuer)&&(!d||d.grantee!==n.grantee||!C(d.resolved,i))||!C(n.scopes,i))throw new T({error:"scope_missing",message:`missing scope ${i}`,received:n.profile_id,field:"profile",next:"Select a profile covered by this run and its current grant."})}}if(ve(n.profile_id??null),!n.grantee)throw new Error("node creation requires an app");const W=await Ee({kind:n.kind,mode:n.mode,cwd:n.cwd,profile:n.profile_id??null,root:s,parentId:o,requestingNodeId:m,lifecycle:N,replaces:e.replaces??null},n.grantee),G=a((r,i)=>{const d=I(r,i.node_id),g=m??o??e.actor??f??null,y=g!==null&&ye(r,g)?.type==="node"?I(r,g):Ce(r,e.run===void 0?"user:local":i.grantee);Ie(r,y,d),o!==null&&e.subscribe!==!1&&Ne(r,I(r,o),d,"spawn"),e.forkSourceNode&&ke(r,I(r,e.forkSourceNode),d),Se(r,{event:"created",object:d,actor:y,attrs:{name:i.name,kind:i.kind,creator:m??null}})},"recordBirth");try{e.nodeId!==void 0&&be(e.nodeId),await e.beforeCreate?.(),(process.platform!=="linux"||P(L))&&await pe(n.grantee??"app:terminal"),de(n,{outcomeDelivery:e.outcomeDelivery,withinCreate:a((r,i)=>{i.run_id&&i.run_id!==i.node_id&&ue(r,i.run_id),s&&e.run===void 0&&ee(r,t,t,"run.started",{scopes:i.scopes??null,payer:"user",usage:JSON.parse(i.usage_json)}),e.withinCreate?.(r,i),G(r,i)},"withinCreate")})}finally{W()}return n}a(hn,"spawnNode");export{q as NodeIdConflictError,gn as currentNodeContext,Me as forkSourceNode,Ae as inboxBetweenTurns,Oe as newJobId,xe as newNodeId,wn as nodeEnv,mn as preflightNodeId,_n as rootOfSpine,pn as setInstallId,hn as spawnNode};
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
var G=Object.defineProperty;var
|
|
1
|
+
var G=Object.defineProperty;var s=(e,r)=>G(e,"name",{value:r,configurable:!0});import{randomUUID as F}from"node:crypto";import{createServer as Y}from"node:http";import{Router as J}from"./router.js";import{toErrorBody as q}from"./map.js";import{objectRoutes as Q}from"./handlers/objects.js";import{customObjectRoutes as W}from"./handlers/custom-objects.js";import{docRoutes as K}from"./handlers/docs.js";import{OPERATIONS as Z}from"./operations.js";import{runtimeReadiness as ee}from"../readiness.js";import{errorCodes as L}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as te,RUNTIME_VERSION_HEADER as ne,minimumRuntimeRefusal as re}from"../../api/runtime-version.js";import{CONTRACT_HEADER as ae,CONTRACT_LEVEL as U,REQUIRED_CONTRACT_HEADER as oe,contractRefusal as ie}from"../../api/contract.js";import{crtrVersion as j}from"../../shared/crtr-version.js";import{AppPrincipalResolver as se}from"./principal.js";import{isDaemonRoute as ue,runtimeOwner as de,servePeer as V}from"../peer/ingress.js";import{applySyncNotice as ce}from"./sync-notice.js";import{ownMachineId as le}from"../../core/peer/directory.js";import{handleRunOperation as fe,integer as me}from"./handlers/runs.js";import{llmCallerOf as pe,parseLlmRequest as he,runLlm as ye}from"../../core/llm/run.js";import{parseUsageMonth as we,usageFor as _e}from"../../core/usage/ledger.js";import{capFields as ge}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as ve,MODEL_CONTEXT_BODY_MAX_BYTES as Re}from"../../core/llm/body-limits.js";import{RunError as l,runIsRunning as Oe}from"../../core/runs/operations.js";import{requireRun as x}from"./router.js";import{deferHead as Ee}from"./deferred-head.js";import{readRunEvents as X,registerGrantStream as be,subscribeRunEvents as Se}from"../../core/runs/events.js";import{activeGrant as $,payerOfGrant as Te}from"../../core/grants/mirror.js";function Ae(e){if(Te(e)==="app")throw new l(401,"grant_revoked","this app-paid grant is no longer active");return null}s(Ae,"appPaidGone");import{releaseGrantWaiters as Ne}from"../../core/grants/watch.js";import{runNotices as Ce}from"../run-notices.js";import{handleVendorSignIn as Pe,isVendorSignInPath as Ie}from"./vendor-signin.js";import{listAppProfiles as ke}from"./handlers/app-profiles.js";import{handleTransferDownload as He,handleTransferOperation as Me,TRANSFER_OPERATIONS as De}from"./handlers/transfer.js";import{handleQuestionOperation as je,QUESTION_OPERATIONS as xe}from"./handlers/questions.js";import{vendorStatus as Be}from"./handlers/vendor-status.js";import{handleMemoryOperation as Je,MEMORY_OPERATIONS as Le}from"./handlers/memory.js";import{abortOnClose as Ue,callerFromApp as Ve,handleProviderOperation as Xe,PROVIDER_OPERATIONS as $e,providerFailure as ze}from"./handlers/providers.js";function Ge(e){return Object.prototype.hasOwnProperty.call(L,e)?L[e]:void 0}s(Ge,"fixedRow");function Fe(e){const r=Ge(e);return r?r.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}s(Fe,"errorType");function Ye(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:r,...o}=e;return o}s(Ye,"appDetails");function D(e,r,o){const f=Ye(e.details);return{error:{code:e.code,message:e.message,...f===void 0?{}:{details:f},type:Fe(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:r,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...ge(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}s(D,"envelope");function qe(e,r,o,f){const u=r instanceof l?r:new l(500,"server_failure","runtime request failed");if(r instanceof l||console.error("[app-listener]",r),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
|
|
2
2
|
data: ${JSON.stringify(D(u,o,f))}
|
|
3
3
|
|
|
4
|
-
`);return}e.writeHead(u.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...u.code==="all_routes_exhausted"?{"Retry-After":String(u.details.retry_after_s)}:{}}),e.end(JSON.stringify(D(u,o,f)))}
|
|
4
|
+
`);return}e.writeHead(u.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...u.code==="all_routes_exhausted"?{"Retry-After":String(u.details.retry_after_s)}:{}}),e.end(JSON.stringify(D(u,o,f)))}s(qe,"fail");function z(e){return Array.isArray(e)?e[0]:e}s(z,"headerValue");function O(e,r,o){e.writeHead(r,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}s(O,"json");async function P(e,r=ve){const o=[];let f=0;for await(const u of e){if(f+=u.length,f>r)throw new l(400,"invalid_request","request body too large");o.push(u)}if(f)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new l(400,"invalid_request","invalid JSON body")}}s(P,"bodyOf");function Qe(e,r){const o=e.headers["last-event-id"]??r.get("after");if(Array.isArray(o))throw new l(400,"invalid_request","invalid cursor","after");return me(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}s(Qe,"cursor");function We(e){return`id: ${e.sequence_number}
|
|
5
5
|
event: ${e.type}
|
|
6
6
|
data: ${JSON.stringify(e)}
|
|
7
7
|
|
|
8
|
-
`}
|
|
8
|
+
`}s(We,"frame");const Ke=6e4;function Ze(e,r,o,f,u,y,E,A={}){x(f,o);let g=X(o,u);if(u>g.latest_sequence)throw new l(400,"invalid_request","cursor is beyond the run","after");if(u<g.latest_sequence&&(g.earliest_sequence===null||u<g.earliest_sequence-1))throw new l(409,"stream_gap","events have expired",void 0,{earliest_sequence:g.earliest_sequence,latest_sequence:g.latest_sequence});if(r.destroyed||e.destroyed)return r.destroy(),Promise.resolve();r.writeHead(200,{"Content-Type":E==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),E==="sse"?r.write(`: connected
|
|
9
9
|
|
|
10
|
-
`):r.flushHeaders();let w=u;const B=
|
|
11
|
-
data: ${JSON.stringify(D(m,
|
|
10
|
+
`):r.flushHeaders();let w=u;const B=Ce().streamOpened(o);let n=!1,t=!1,h=!1,b;const N=new Promise(m=>{b=m}),_=s(()=>{n||(n=!0,B(w),clearInterval(d),clearInterval(R),I(),H(),r.off("close",_),r.off("drain",p),r.end(),b())},"end"),p=s(()=>{h=!1,a()},"onDrain"),v=s(m=>{n||r.write(E==="sse"?`event: error
|
|
11
|
+
data: ${JSON.stringify(D(m,y,o))}
|
|
12
12
|
|
|
13
|
-
`:`${JSON.stringify({type:"error",...D(m,
|
|
14
|
-
`),
|
|
15
|
-
`),w=m.sequence_number}}catch(m){v(m instanceof l?m:new l(500,"server_failure","stream failed"))}finally{t=!1}}},"flush"),k=
|
|
13
|
+
`:`${JSON.stringify({type:"error",...D(m,y,o)})}
|
|
14
|
+
`),_()},"error"),a=s(()=>{if(!(n||t)){t=!0;try{if(!T()){k();return}if(x(f,o),g=X(o,w),g.backlog_count>1e3||g.backlog_bytes>32*1024*1024){v(new l(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:w}));return}for(const m of g.events){if(h)break;h=!r.write(E==="sse"?We(m):`${JSON.stringify(m)}
|
|
15
|
+
`),w=m.sequence_number}}catch(m){v(m instanceof l?m:new l(500,"server_failure","stream failed"))}finally{t=!1}}},"flush"),k=s(()=>v(new l(401,"grant_revoked","grant is not active")),"revoked"),T=s(()=>"class"in f||$(f.grant)!==null,"grantActive"),I=Se(o,a),H="class"in f?()=>{}:be(f.grant,k),d=setInterval(()=>{!n&&!h&&E==="sse"&&r.write(`: keepalive
|
|
16
16
|
|
|
17
|
-
`)},15e3),M=A.idleMs??
|
|
17
|
+
`)},15e3),M=A.idleMs??Ke,i=A.isRunning??Oe;let S=Date.now(),c=w;const R=setInterval(()=>{if(n||E!=="sse")return;const m=Date.now();let C=!0;try{C=i(o)}catch{}if(C||w!==c){S=m,c=w;return}m-S<M||h||(r.write(`event: idle
|
|
18
18
|
data: {}
|
|
19
19
|
|
|
20
|
-
`),
|
|
20
|
+
`),_())},A.idleCheckMs??1e3);return R.unref(),r.on("drain",p),r.on("close",_),a(),N}s(Ze,"streamRunEvents");function xt(e,r,o,f={}){const u=e.listener;if(!e.issuer||!e.audience||!u?.address||!Number.isInteger(u.port)||u.port<1||u.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(u.address))throw new Error("runtime listener must bind a specific address");const y=new se(e.issuer,e.audience,o,e.jwksUrl),E=new J,A=new Map;for(const n of Z.filter(t=>t.stage!==void 0)){const t=s(()=>({status:500}),"handler");E.register({method:n.method,pattern:n.path,handler:t}),A.set(t,n)}const g=new J().registerAll(Q).registerAll(W).registerAll(K),w=Y((n,t)=>{(async()=>{Ee(n,t,f.deferHead);const h=F();t.setHeader("Request-Id",h),t.setHeader(ne,j()),t.setHeader(ae,U);let b;try{const N=z(n.headers[te.toLowerCase()]),_=re(N,j())??ie(z(n.headers[oe.toLowerCase()]),U,{legacyMinimum:N,runtimeVersion:j()});if(_!==null)throw _.status===400?new l(400,_.code,_.message,_.param):new l(426,_.code,_.message,void 0,_.details);const p=new URL(n.url??"/","http://runtime.local");if(Ie(p.pathname)){await Pe(n,t,p,y);return}const v=E.match(n.method??"GET",p.pathname),a=v?A.get(v.handler):void 0,k=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status";let T,I;if(!k&&n.headers.authorization!==void 0)try{T=await y.verifyCall(n.headers.authorization)}catch(i){I=i}const H={issuer:e.issuer,jwks:y.jwks,audience:s(()=>e.audience,"audience"),owner:de,self:le,syncGrants:o,ready:s(()=>y.isReady()&&r(),"ready")};if(T?.chain[0]?.sub.startsWith("runtime:")){await V(n,t,H,T);return}if(T===void 0&&a===void 0&&await ue(n.method??"GET",p.pathname)){await V(n,t,H,{status:401,code:"unauthorized",message:I===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const i=ee({jwksReady:y.isReady(),grantsReady:r});O(t,i.ready?200:503,i);return}if((n.method!=="GET"||p.pathname!=="/v1/health")&&(!y.isReady()||!r()))throw new l(503,"runtime_starting","runtime_starting");if(!v||!a)throw new l(404,"not_found","unknown operation");if(b=v.params.run_id,a.name==="health"){O(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await ce(await y.verifySyncNotice(n.headers.authorization),o,h),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await y.verifyDirectoryRead(n.headers.authorization,"vendor_status"),O(t,200,Be());return}if(T===void 0)throw I??new l(401,"unauthorized","a directory access token is required");const d=await y.resolveVerified(T,a.scope);if(t.setHeader("Request-Id",h),b&&x(d,b,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const i=g.match(a.method,p.pathname);if(!i)throw new l(404,"not_found","unknown operation");const S={method:a.method,path:p.pathname,params:i.params,query:p.searchParams,body:await P(n,i.maxBodyBytes),ceiling:d.resolved,principal:{class:"app",app:d.grantee,scopes:d.resolved},req:n,res:t};let c;try{c=await i.handler(S)}catch(R){const{status:m,body:C}=q(R);throw m>=500&&console.error("[app-listener]",R),new l(m,C.error.code,C.error.message,void 0,C.error.details)}if(t.headersSent)return;if(c.rawBody!==void 0||c.status===204||c.body===void 0){t.writeHead(c.status,c.headers??{}),t.end(c.rawBody);return}t.writeHead(c.status,{"Content-Type":"application/json; charset=utf-8",...c.headers??{}}),t.end(JSON.stringify(c.body));return}if(a.stream==="bytes"){await He(n,t,d,p.searchParams);return}if(a.stream){Ze(n,t,b,d,Qe(n,p.searchParams),h,"sse",f.stream);return}if(a.name==="llm"){const i=he(await P(n,Re)),S=new AbortController,c=s(()=>S.abort(),"abort");t.on("close",c);try{const R=await ye(i,S.signal,i.stream?m=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(m)}
|
|
21
21
|
|
|
22
|
-
`)}:void 0,void 0,{grantee:d.grantee,spend_cap:d.spend_cap},
|
|
22
|
+
`)}:void 0,void 0,{grantee:d.grantee,spend_cap:d.spend_cap},pe($(d.grant)??Ae(d.grant)));i.stream?(t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.end(`data: [DONE]
|
|
23
23
|
|
|
24
|
-
`)):
|
|
24
|
+
`)):O(t,200,R.completion)}finally{t.off("close",c)}return}if(a.name==="usage.get"){O(t,200,_e(d.grantee,d.spend_cap,we(p.searchParams.get("month"))));return}if(a.name==="profile.list"){O(t,200,ke(d));return}if(xe.has(a.name)){const i=await je(a.name,d,v.params.question_id,a.method==="POST"?await P(n):void 0);O(t,i.status,i.body);return}if($e.has(a.name)){const{signal:i,release:S}=Ue(t);try{const c=await Xe(a.name,Ve(d),{params:v.params,body:a.method==="POST"?await P(n):void 0,query:p.searchParams},{requestId:h,signal:i});O(t,c.status,c.body)}catch(c){const R=ze(c,h,!0);t.writeHead(R.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...R.headers}),t.end(JSON.stringify(R.body))}finally{S()}return}if(Le.has(a.name)){const i=Je(a.name,{class:"app",app:d.grantee,scopes:d.resolved},p.searchParams);O(t,i.status,i.body);return}if(De.has(a.name)){const i=await Me(a,d,v.params,p.searchParams,await P(n));O(t,i.status,i.body);return}const M=await fe(a,d,b,p.searchParams,await P(n),n.headers["idempotency-key"]);O(t,M.status,M.body)}catch(N){qe(t,N,h,b)}})()});return{ready:new Promise((n,t)=>{w.once("error",t),w.listen(u.port,u.address,()=>{w.off("error",t),n()})}),close:s(async()=>{y.close(),Ne(),w.closeAllConnections(),await new Promise((n,t)=>w.close(h=>h?t(h):n()))},"close")}}s(xt,"createAppListener");export{Ke as RUN_STREAM_IDLE_MS,xt as createAppListener,Qe as cursor,Ze as streamRunEvents};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=Object.defineProperty;var o=(e,t)=>i(e,"name",{value:t,configurable:!0});import{prepared as r}from"../../../core/sqlite-statements.js";import{openDb as s}from"../../../core/canvas/db.js";import{apiSocketPath as c}from"../../../core/canvas/paths.js";import{currentVersion as d}from"../../../core/self-update.js";import{API_VERSION as p}from"../../../api/index.js";import{DEFAULT_INTERVAL_MS as l}from"../../supervise-cadence.js";import{isPidPresent as _}from"../../../core/canvas/pid.js";import{boundDaemonControl as u}from"../../control.js";import{dueReport as m}from"../../due.js";import{runtimeReadiness as h}from"../../readiness.js";const f=l;function a(){try{return r(s(),"SELECT 1 FROM nodes LIMIT 1").get(),!0}catch{return!1}}o(a,"canvasAccessible");function E(){const e={},t=r(s(),`
|
|
2
2
|
SELECT status, COUNT(*) AS count
|
|
3
3
|
FROM node_rows
|
|
4
4
|
WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
|
|
5
5
|
GROUP BY status
|
|
6
|
-
`).all();for(const
|
|
6
|
+
`).all();for(const n of t)e[n.status]=n.count;return e}o(E,"nodeCounts");function T(){return r(s(),`
|
|
7
7
|
SELECT pi_pid
|
|
8
8
|
FROM node_rows
|
|
9
9
|
WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
|
|
@@ -11,4 +11,4 @@ var c=Object.defineProperty;var o=(e,t)=>c(e,"name",{value:t,configurable:!0});i
|
|
|
11
11
|
AND pi_pid IS NOT NULL
|
|
12
12
|
AND turn_open_at IS NOT NULL
|
|
13
13
|
AND turn_closed_at IS NULL
|
|
14
|
-
`).all().filter(t=>_(t.pi_pid)).length}o(
|
|
14
|
+
`).all().filter(t=>_(t.pi_pid)).length}o(T,"busyNodeCount");function b(){const e=a(),t=u()?.startupBlock()??null,n={ok:e&&t===null,daemon_up:!0,store_accessible:e,brokers_reconciled:t===null,startup_phase:t?.phase??"ready",...t===null?{}:{startup_blocked:t.message}};return{status:n.ok?200:503,body:n}}o(b,"handleHealthz");function N(){const e=h();return{status:e.ready?200:503,body:e}}o(N,"handleReady");function L(e){if(!a())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};return{status:200,body:{daemon_pid:process.pid,tick_interval_ms:f,node_counts:E(),busy_node_count:T(),listeners:{socket_path:c(),tcp:e()},runtime_version:d(),api_version:p,startup_phase:u()?.startupBlock()?.phase??"ready"}}}o(L,"handleStatus");function R(){if(!a())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};return{status:200,body:m()}}o(R,"handleDue");function F(e){return[{method:"GET",pattern:"/healthz",handler:o(t=>b(),"handler")},{method:"GET",pattern:"/v1/ready",handler:o(t=>N(),"handler")},{method:"GET",pattern:"/v1/status",handler:o(t=>L(e),"handler")},{method:"GET",pattern:"/v1/due",handler:o(t=>R(),"handler")}]}o(F,"healthRoutes");export{F as healthRoutes};
|