@leviyuan/lodestar 0.19.8 → 0.19.10
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/lodestar-agent.js +2 -2
- package/dist/lodestar.js +224 -223
- package/docs/usage.md +15 -6
- package/package.json +1 -1
package/dist/lodestar-agent.js
CHANGED
|
@@ -119,11 +119,11 @@ try {
|
|
|
119
119
|
`:Df(C));return}case"run":await If(I,A);return;case"follow-up":case"followup":await Cf(I,A);return;case"answer":await Ef(I,A);return;case"status":{let C=NC(A[0],"status requires run_id"),g=await LI(I,"GET",`/agents/runs/${encodeURIComponent(C)}`);if(r1(g,A.includes("--json")),g.status==="failed"||g.status==="cancelled")process.exitCode=1;return}case"cancel":{let C=NC(A[0],"cancel requires run_id"),g=await LI(I,"DELETE",`/agents/runs/${encodeURIComponent(C)}`);process.stdout.write(`${JSON.stringify(g)}
|
|
120
120
|
`);return}default:throw Error(i1())}}async function If(A,Q){let B=n1(Q,!0),I=await a1(B),C={identity_ids:B.identityIds,description:B.description,prompt:I,...B.effort?{effort:B.effort}:{},...B.sessionId?{session_id:B.sessionId}:{},...B.workDir?{work_dir:B.workDir}:{},...B.requestId?{request_id:B.requestId}:{},...B.requesterOpenId?{requester_open_id:B.requesterOpenId}:{}},g=await LI(A,"POST","/agents/runs",C);await o1(A,g,B.noWait,B.json)}async function Cf(A,Q){let B=NC(Q.shift(),"follow-up requires run_id"),I=n1(Q,!1),C=await a1(I),g={description:I.description,prompt:C,...I.identityId?{identity_id:I.identityId}:{},...I.effort?{effort:I.effort}:{},...I.workDir?{work_dir:I.workDir}:{},...I.requestId?{request_id:I.requestId}:{},...I.requesterOpenId?{requester_open_id:I.requesterOpenId}:{}},F=await LI(A,"POST",`/agents/runs/${encodeURIComponent(B)}/follow-up`,g);await o1(A,F,I.noWait,I.json)}async function Ef(A,Q){let B=NC(Q.shift(),"answer requires run_id"),I="",C="",g=!1,F={};for(let J=0;J<Q.length;J++){let N=Q[J],G=()=>NC(Q[++J],`${N} requires a value`);switch(N){case"--identity":case"-i":I=G();break;case"--request":C=G();break;case"--answer":{let M=G(),V=M.indexOf("=");if(V<=0)throw Error("--answer must be question-or-id=value");F[M.slice(0,V)]=M.slice(V+1);break}case"--stdin":g=!0;break;default:throw Error(`unknown answer option: ${N}`)}}if(g){let J=(await t1()).trim(),N;try{N=JSON.parse(J)}catch{throw Error("answer stdin must be a JSON object")}if(!N||typeof N!=="object"||Array.isArray(N))throw Error("answer stdin must be a JSON object");for(let[G,M]of Object.entries(N))F[G]=String(M)}if(!C)throw Error("answer requires --request");if(Object.keys(F).length===0)throw Error("answer requires --answer or --stdin");let Y=await LI(A,"POST",`/agents/runs/${encodeURIComponent(B)}/answer`,{request_id:C,answers:F,...I?{identity_id:I}:{}});await s1(A,String(Y.run_id??B))}function n1(A,Q){let B={identityIds:[],identityId:"",sessionId:"",workDir:"",effort:"",description:"",prompt:"",noWait:!1,readStdin:!1,json:!1},I=[];for(let C=0;C<A.length;C++){let g=A[C],F=()=>NC(A[++C],`${g} requires a value`);switch(g){case"--identity":case"-i":if(Q)B.identityIds.push(F());else B.identityId=F();break;case"--effort":B.effort=F();break;case"--request-id":if(B.requestId)throw Error("--request-id may only be specified once");B.requestId=F();break;case"--requester":if(B.requesterOpenId)throw Error("--requester may only be specified once");B.requesterOpenId=F();break;case"--description":B.description=F();break;case"--workdir":if(B.workDir)throw Error("--workdir may only be specified once");F(),B.workDir=A[C];break;case"--session":if(!Q)throw Error("--session is only supported by run; follow-up accepts a run_id");if(B.sessionId)throw Error("--session may only be specified once");B.sessionId=F();break;case"--prompt":F(),B.prompt=A[C];break;case"--stdin":B.readStdin=!0;break;case"--no-wait":B.noWait=!0;break;case"--json":B.json=!0;break;default:if(g.startsWith("-"))throw Error(`unknown option: ${g}`);I.push(g)}}if(B.identityIds=[...new Set(B.identityIds)],B.sessionId&&B.identityIds.length>1)throw Error("--session accepts at most one --identity");if(Q&&!B.sessionId&&B.identityIds.length===0)throw Error("run requires at least one --identity");if(B.description=v1(B.description),!B.prompt&&I.length)B.prompt=I.join(" ");if(!B.prompt)B.readStdin=!0;return B}async function a1(A){let Q=A.readStdin?await t1():"",B=A.prompt||Q;if(!B.trim())throw Error("agent prompt is empty");return B}async function o1(A,Q,B,I){let C=String(Q.run_id??"");if(!C)throw Error("agent API returned no run_id");if(B){if(process.stdout.write(`${JSON.stringify(Q,null,2)}
|
|
121
121
|
`),Q.status==="failed"||Q.status==="cancelled")process.exitCode=1;return}await s1(A,C,I)}async function s1(A,Q,B=!1){let I=!1,C=()=>{if(I)return;I=!0,LI(A,"DELETE",`/agents/runs/${encodeURIComponent(Q)}`).then(()=>process.exit(130),(g)=>{process.stderr.write(`lodestar-agent: cancellation failed: ${e1(g)}
|
|
122
|
-
`),process.exit(1)})};process.once("SIGINT",C),process.once("SIGTERM",C);try{while(!0){let g=await LI(A,"GET",`/agents/runs/${encodeURIComponent(Q)}`);if(g.status==="needs_input"||g.status==="completed"||g.status==="failed"||g.status==="cancelled"){if(r1(g,B),g.status==="failed"||g.status==="cancelled")process.exitCode=1;return}await new Promise((F)=>setTimeout(F,1000))}}finally{process.off("SIGINT",C),process.off("SIGTERM",C)}}function gf(A){let Q,B=[],I=new Set(["--identity","-i","--effort","--description","--workdir","--session","--prompt","--request","--answer","--request-id","--requester"]);for(let C=0;C<A.length;C++){let g=A[C];if(g==="--project"){if(Q!==void 0)throw Error("--project may only be specified once");Q=NC(A[++C],"--project requires a project name")}else if(B.push(g),I.has(g)&&C+1<A.length)B.push(A[++C])}return{...Q!==void 0?{project:Q}:{},argv:B}}function Ff(A){if(A!==void 0){if(process.env.LODESTAR_AGENT_ROLE==="worker")throw Error("Delegated Agents cannot start project calls");return{...l1(),project:A}}if(process.env.DSH_LODESTAR_AGENT_CONTEXT!==void 0){let I=JSON.parse(process.env.DSH_LODESTAR_AGENT_CONTEXT);if(typeof I.baseUrl!=="string"||!I.baseUrl||typeof I.capability!=="string"||!I.capability)throw Error("invalid DSH Lodestar delegation context");return{baseUrl:I.baseUrl.replace(/\/+$/,""),capability:I.capability}}let Q=String(process.env.LODESTAR_AGENT_URL??"").replace(/\/+$/,""),B=String(process.env.LODESTAR_AGENT_CAPABILITY??"");if(!Q||!B)throw Error("lodestar-agent must run inside a Lodestar-managed Agent session (missing capability)");return{baseUrl:Q,capability:B}}async function LI(A,Q,B,I){let C=new URL(`${A.baseUrl}${B}`);if(A.project)C.searchParams.set("project",A.project);let g=await y1(C.toString(),{method:Q,headers:{authorization:`Bearer ${A.capability}`,...I?{"content-type":"application/json"}:{}},...I?{body:JSON.stringify(I)}:{}}),F=await g.text(),Y;try{Y=JSON.parse(F)}catch{throw Error(`agent API ${Q} ${B} returned HTTP ${g.status}: ${F||"(empty)"}`)}if(!g.ok)throw Error(Y?.error??`agent API HTTP ${g.status}`);return Y}function Df(A){let Q=[`catalog ${A.catalog_generation??"MISS"}`];for(let B of A.identities??[])Q.push([B.status==="ready"?"✅":"MISS",B.id,B.display_name,B.model,`default-effort=${B.default_effort}`,B.source_default?"source-default":"",B.reason??""].filter(Boolean).join(" · "));for(let B of A.source_failures??[])Q.push(`MISS · ${B.display} · ${B.reason}`);return`${Q.join(`
|
|
122
|
+
`),process.exit(1)})};process.once("SIGINT",C),process.once("SIGTERM",C);try{while(!0){let g=await LI(A,"GET",`/agents/runs/${encodeURIComponent(Q)}`);if(g.status==="needs_input"||g.status==="completed"||g.status==="failed"||g.status==="cancelled"){if(r1(g,B),g.status==="failed"||g.status==="cancelled")process.exitCode=1;return}await new Promise((F)=>setTimeout(F,1000))}}finally{process.off("SIGINT",C),process.off("SIGTERM",C)}}function gf(A){let Q,B=[],I=new Set(["--identity","-i","--effort","--description","--workdir","--session","--prompt","--request","--answer","--request-id","--requester"]);for(let C=0;C<A.length;C++){let g=A[C];if(g==="--project"){if(Q!==void 0)throw Error("--project may only be specified once");Q=NC(A[++C],"--project requires a project name")}else if(B.push(g),I.has(g)&&C+1<A.length)B.push(A[++C])}return{...Q!==void 0?{project:Q}:{},argv:B}}function Ff(A){if(A!==void 0){if(process.env.LODESTAR_AGENT_ROLE==="worker")throw Error("Delegated Agents cannot start project calls");if(["LODESTAR_AGENT_ROLE","LODESTAR_AGENT_URL","LODESTAR_AGENT_CAPABILITY","LODESTAR_AGENT_SESSION","DSH_LODESTAR_AGENT_CONTEXT"].some((I)=>process.env[I]!==void 0))throw Error("Agent task calls must remain session-bound; --project is only for independent services and applications");return{...l1(),project:A}}if(process.env.DSH_LODESTAR_AGENT_CONTEXT!==void 0){let I=JSON.parse(process.env.DSH_LODESTAR_AGENT_CONTEXT);if(typeof I.baseUrl!=="string"||!I.baseUrl||typeof I.capability!=="string"||!I.capability)throw Error("invalid DSH Lodestar delegation context");return{baseUrl:I.baseUrl.replace(/\/+$/,""),capability:I.capability}}let Q=String(process.env.LODESTAR_AGENT_URL??"").replace(/\/+$/,""),B=String(process.env.LODESTAR_AGENT_CAPABILITY??"");if(!Q||!B)throw Error("lodestar-agent must run inside a Lodestar-managed Agent session (missing capability)");return{baseUrl:Q,capability:B}}async function LI(A,Q,B,I){let C=new URL(`${A.baseUrl}${B}`);if(A.project)C.searchParams.set("project",A.project);let g=await y1(C.toString(),{method:Q,headers:{authorization:`Bearer ${A.capability}`,...I?{"content-type":"application/json"}:{}},...I?{body:JSON.stringify(I)}:{}}),F=await g.text(),Y;try{Y=JSON.parse(F)}catch{throw Error(`agent API ${Q} ${B} returned HTTP ${g.status}: ${F||"(empty)"}`)}if(!g.ok)throw Error(Y?.error??`agent API HTTP ${g.status}`);return Y}function Df(A){let Q=[`catalog ${A.catalog_generation??"MISS"}`];for(let B of A.identities??[])Q.push([B.status==="ready"?"✅":"MISS",B.id,B.display_name,B.model,`default-effort=${B.default_effort}`,B.source_default?"source-default":"",B.reason??""].filter(Boolean).join(" · "));for(let B of A.source_failures??[])Q.push(`MISS · ${B.display} · ${B.reason}`);return`${Q.join(`
|
|
123
123
|
`)}
|
|
124
124
|
`}function r1(A,Q){process.stdout.write(Q?`${JSON.stringify(A,null,2)}
|
|
125
125
|
`:Yf(A))}function Yf(A){let Q=`lodestar-agent${A.binding==="project"?` --project ${kE(String(A.project))}`:""}`,B=[`# Lodestar agent ${A.run_id??"MISS"}`,"",`- Status: ${A.status??"MISS"}`,...A.binding==="project"?[`- Project: ${A.project}`]:[],`- Description: ${A.description??"MISS"}`,`- Work directory: ${A.work_dir??"MISS"}`,...A.parent_run_id?[`- Parent: ${A.parent_run_id} (${A.parent_kind??"delegate"})`]:[]];if(A.error)B.push(`- Error: ${A.error}`);for(let I of A.workers??[]){if(B.push("",`## ${I.identity_name??I.identity_id}`,"",`Status: ${I.status}`),I.session_id)B.push(`Session: ${I.session_id}`);if(I.error)B.push("",`Error: ${I.error}`);if(I.pending_input){B.push("",`Input request: ${I.pending_input.request_id}`);for(let C of I.pending_input.questions??[])if(B.push(`- [${C.id}] ${C.question}`),C.options?.length)B.push(` Options: ${C.options.map((g)=>g.label).join(" / ")}`);B.push("","Answer with:",`${Q} answer ${kE(A.run_id)} --identity ${kE(I.identity_id)} --request ${kE(I.pending_input.request_id)} --stdin`)}if(I.output)B.push("",I.output);if(I.session_id&&I.identity_id&&["completed","failed","cancelled"].includes(A.status))B.push("","Continue with:",`${Q} run --session ${kE(I.session_id)} --identity ${kE(I.identity_id)} --description '<brief next step>' --stdin`)}if(A.presentation_errors?.length)B.push("","Presentation errors:",...A.presentation_errors.map((I)=>`- ${I}`));return`${B.join(`
|
|
126
126
|
`)}
|
|
127
|
-
`}function kE(A){return`'${A.replace(/'/g,"'\\''")}'`}async function t1(){if(process.stdin.isTTY)return"";let A=[];for await(let Q of process.stdin)A.push(Buffer.isBuffer(Q)?Q:Buffer.from(Q));return Buffer.concat(A).toString("utf8")}function NC(A,Q){if(!A?.trim())throw Error(Q);return A.trim()}function i1(){return["Usage:"," lodestar-agent --project <project-or-worktree> <command> [options]"," lodestar-agent identities [--json]"," lodestar-agent run --identity <id> [--identity <id>...] --description <summary> [--workdir <path>] [--effort <level>] [--json] --stdin"," lodestar-agent run --session <session_id> [--identity <id>] --description <summary> [--workdir <path>] [--effort <level>] [--json] --stdin"," lodestar-agent follow-up <run_id> [--identity <id>] --description <summary> [--workdir <path>] [--effort <level>] [--json] --stdin"," lodestar-agent answer <run_id> [--identity <id>] --request <id> (--answer key=value | --stdin)"," lodestar-agent status <run_id> [--json]"," lodestar-agent cancel <run_id>","","Use --prompt <text> instead of --stdin for inline input. --no-wait returns the started run as JSON.","
|
|
127
|
+
`}function kE(A){return`'${A.replace(/'/g,"'\\''")}'`}async function t1(){if(process.stdin.isTTY)return"";let A=[];for await(let Q of process.stdin)A.push(Buffer.isBuffer(Q)?Q:Buffer.from(Q));return Buffer.concat(A).toString("utf8")}function NC(A,Q){if(!A?.trim())throw Error(Q);return A.trim()}function i1(){return["Usage:"," lodestar-agent --project <project-or-worktree> <command> [options]"," lodestar-agent identities [--json]"," lodestar-agent run --identity <id> [--identity <id>...] --description <summary> [--workdir <path>] [--effort <level>] [--json] --stdin"," lodestar-agent run --session <session_id> [--identity <id>] --description <summary> [--workdir <path>] [--effort <level>] [--json] --stdin"," lodestar-agent follow-up <run_id> [--identity <id>] --description <summary> [--workdir <path>] [--effort <level>] [--json] --stdin"," lodestar-agent answer <run_id> [--identity <id>] --request <id> (--answer key=value | --stdin)"," lodestar-agent status <run_id> [--json]"," lodestar-agent cancel <run_id>","","Use --prompt <text> instead of --stdin for inline input. --no-wait returns the started run as JSON.","Agent task calls must use the managed-session context. --project is only for independent services and applications.","Without --project, the existing managed-session context is required; invalid contexts never switch modes.","Project run/follow-up: --request-id <unique-key> deduplicates retries; --requester <open_id> identifies the cloud-file recipient.","--session resumes the unique native conversation id only within its registered project and group.","Unknown ownership and cross-project/group resumes are rejected, even with an explicit identity.","--identity may change the model/source within the original backend; effort and project-local workdir may be overridden.","The new run belongs to the current caller; the previous run keeps its original owner and cancellation scope.","--workdir defaults to the managed-session or explicit-project directory; relative paths are resolved from it.","New conversations and resumes stay within that project root. Resumes otherwise reuse the recorded directory.","session_id is the stable conversation identity; run_id identifies only one invocation, not a second session.","--description is required for every run/follow-up: one short line, at most 60 characters, shown on the collapsed card.","Each turn has a new run_id; workers[].session_id identifies the native conversation."].join(`
|
|
128
128
|
`)}function e1(A){return A instanceof Error?A.message:String(A)}if(process.argv[1]&&d1(process.argv[1])===d1(Qf(import.meta.url)))Bf().catch((A)=>{process.stderr.write(`lodestar-agent: ${e1(A)}
|
|
129
129
|
`),process.exitCode=1});export{n1 as parsePromptArgs,Bf as main,gf as extractProjectOption};
|