manifest 5.29.3 → 5.30.0

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.
@@ -82,7 +82,7 @@ let AgentsController = class AgentsController {
82
82
  const keyData = await this.apiKeyGenerator.getKeyForAgent(user.id, agentName);
83
83
  const customEndpoint = this.config.get('app.pluginOtlpEndpoint', '');
84
84
  const isLocal = this.config.get('MANIFEST_MODE') === 'local';
85
- const fullKey = isLocal ? (0, local_mode_constants_1.readLocalApiKey)() : undefined;
85
+ const fullKey = isLocal && agentName === local_mode_constants_1.LOCAL_AGENT_NAME ? (0, local_mode_constants_1.readLocalApiKey)() : undefined;
86
86
  return {
87
87
  ...keyData,
88
88
  ...(fullKey ? { apiKey: fullKey } : {}),
@@ -104,8 +104,8 @@ let AgentsController = class AgentsController {
104
104
  return { renamed: true, name: slug, display_name: displayName };
105
105
  }
106
106
  async deleteAgent(user, agentName) {
107
- if (this.config.get('MANIFEST_MODE') === 'local') {
108
- throw new common_1.ForbiddenException('Cannot delete agents in local mode');
107
+ if (this.config.get('MANIFEST_MODE') === 'local' && agentName === local_mode_constants_1.LOCAL_AGENT_NAME) {
108
+ throw new common_1.ForbiddenException('Cannot delete the default local agent');
109
109
  }
110
110
  await this.aggregation.deleteAgent(user.id, agentName);
111
111
  await this.cacheManager.del(this.agentListCacheKey(user.id));
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ To resolve the conflict:`,(0,ri.getConflictResolutionRecipe)(u,r))),c=a):QM.diag
16
16
  openclaw config set plugins.entries.manifest.config.endpoint https://app.manifest.build/otlp`:`Invalid apiKey format. Keys must start with '${Qe}'. Fix it via:
17
17
  openclaw config set manifest.apiKey ${Qe}YOUR_KEY`:`Missing apiKey. Set it via:
18
18
  openclaw config set manifest.apiKey ${Qe}YOUR_KEY
19
- or export MANIFEST_API_KEY=${Qe}YOUR_KEY`}var na=ve(sM()),oa=ve(di()),wI=ve(LI()),BI=ve(VI()),GI=ve(Oo());m();var en=null,tn=null,gc=null,Lc=null;function HI(o,r){let i=new GI.Resource({"service.name":fr.SERVICE_NAME,"service.version":"5.29.3","manifest.plugin":"true"}),c=o.apiKey?{Authorization:`Bearer ${o.apiKey}`}:{},a=new wI.OTLPTraceExporter({url:`${o.endpoint}/v1/traces`,headers:c});en=new na.BasicTracerProvider({resource:i,spanProcessors:[new na.BatchSpanProcessor(a,{scheduledDelayMillis:5e3,maxQueueSize:2048,maxExportBatchSize:512})]}),en.register(),r.debug(`[manifest] Trace exporter -> ${o.endpoint}/v1/traces`);let u=new BI.OTLPMetricExporter({url:`${o.endpoint}/v1/metrics`,headers:c}),t=o.devMode||o.mode==="local"?xc.METRICS_INTERVAL_MS:fr.METRICS_INTERVAL_MS;return tn=new oa.MeterProvider({resource:i,readers:[new oa.PeriodicExportingMetricReader({exporter:u,exportIntervalMillis:t})]}),Mt.setGlobalMeterProvider(tn),r.debug(`[manifest] Metrics exporter -> ${o.endpoint}/v1/metrics (interval=${t}ms)`),gc=Be.getTracer("manifest-plugin","5.29.3"),Lc=Mt.getMeter("manifest-plugin","5.29.3"),{tracer:gc,meter:Lc}}async function kI(o){o.info("[manifest] Shutting down telemetry..."),en&&(await en.shutdown(),en=null),tn&&(await tn.shutdown(),tn=null),gc=null,Lc=null,o.info("[manifest] Telemetry shut down")}m();var g5=5,FI=30*60*1e3,L5=3e3,I5=5*60*1e3,x5=new Set(["system","developer"]),C5=10,rn=new Map,YI=!1;function b5(){if(YI)return;YI=!0;let o=setInterval(()=>{let r=Date.now();for(let[i,c]of rn)r-c.lastUpdated>FI&&rn.delete(i)},I5);typeof o=="object"&&"unref"in o&&o.unref()}async function KI(o,r,i,c){b5();let u=`${o.endpoint.replace(/\/otlp(\/v1)?\/?$/,"")}/api/v1/routing/resolve`;try{if(!r||!Array.isArray(r)||r.length===0)return c.debug("[manifest] Routing resolve: no messages, skipping"),null;let t=r.filter(C=>C&&typeof C=="object"&&"role"in C&&!x5.has(C.role)).slice(-C5).map(C=>({role:C.role,content:C.content}));if(t.length===0)return c.debug("[manifest] Routing resolve: no scorable messages, skipping"),null;let e=rn.get(i),n=e&&Date.now()-e.lastUpdated<FI?e.tiers:void 0,s={messages:t};n&&(s.recentTiers=n);let l={"Content-Type":"application/json"};o.apiKey&&(l.Authorization=`Bearer ${o.apiKey}`);let E=await fetch(u,{method:"POST",headers:l,body:JSON.stringify(s),signal:AbortSignal.timeout(L5)});if(!E.ok)return c.debug(`[manifest] Routing resolve returned ${E.status}`),null;let A=await E.json();if(!A.model)return c.debug(`[manifest] Routing resolve: no model for tier=${A.tier}`),null;let g=rn.get(i);return g?(g.tiers=[A.tier,...g.tiers].slice(0,g5),g.lastUpdated=Date.now()):rn.set(i,{tiers:[A.tier],lastUpdated:Date.now()}),c.debug(`[manifest] Routing resolved: tier=${A.tier} model=${A.model} provider=${A.provider}`),{tier:A.tier,model:A.model,provider:A.provider??"unknown",reason:A.reason??"",auth_type:A.auth_type??"api_key"}}catch(t){let e=t instanceof Error?t.message:String(t);return c.debug(`[manifest] Routing resolve failed (${e})`),null}}function jI(o,r,i){if(typeof o.registerProvider!="function"){i.debug("[manifest] registerProvider not available, skipping provider registration");return}let c=r.endpoint.replace(/\/otlp(\/v1)?\/?$/,"");try{o.registerProvider({id:"manifest",name:"Manifest Router",label:"Manifest Router",api:"openai-completions",baseUrl:c,apiKey:r.apiKey,models:["auto"]}),i.info("[manifest] Registered as OpenAI-compatible provider (proxy mode)")}catch(a){let u=a instanceof Error?a.message:String(a);i.debug(`[manifest] registerProvider failed (${u})`)}}var _r=new Map,qI,WI,zI,JI,U5,XI,$I,QI,ZI;function ex(o){qI=o.createCounter(Oe.LLM_REQUESTS,{description:"Total LLM inference requests"}),WI=o.createCounter(Oe.LLM_TOKENS_INPUT,{description:"Total input tokens sent to LLM"}),zI=o.createCounter(Oe.LLM_TOKENS_OUTPUT,{description:"Total output tokens from LLM"}),JI=o.createCounter(Oe.LLM_TOKENS_CACHE_READ,{description:"Total cache-read tokens"}),U5=o.createHistogram(Oe.LLM_DURATION,{description:"LLM request duration in ms",unit:"ms"}),XI=o.createCounter(Oe.TOOL_CALLS,{description:"Total tool invocations"}),$I=o.createCounter(Oe.TOOL_ERRORS,{description:"Total tool errors"}),QI=o.createHistogram(Oe.TOOL_DURATION,{description:"Tool execution duration in ms",unit:"ms"}),ZI=o.createCounter(Oe.MESSAGES_RECEIVED,{description:"Total messages received from users"})}function ia(o,r,i){typeof o.on=="function"?o.on(r,i):typeof o.registerHook=="function"&&o.registerHook(r,i)}function tx(o,r,i,c){ia(o,"message_received",a=>{let u=a.sessionKey||a.session?.key||`agent:${a.agent||"main"}:main`,t=a.channel||"unknown",e=r.startSpan(un.REQUEST,{kind:Ve.SERVER,attributes:{[b.SESSION_KEY]:u,[b.CHANNEL]:t}});_r.set(u,{root:e}),ZI.add(1,{[b.CHANNEL]:t}),c.debug(`[manifest] Root span started for session=${u}`)}),ia(o,"before_agent_start",a=>{let u=a.sessionKey||a.session?.key||`agent:${a.agent||"main"}:main`,t=a.agent||"main",e=_r.get(u),n=e?.root?Be.setSpan(we.active(),e.root):we.active(),s=r.startSpan(un.AGENT_TURN,{kind:Ve.INTERNAL,attributes:{[b.AGENT_NAME]:t,[b.SESSION_KEY]:u}},n);e?e.turn=s:_r.set(u,{root:s,turn:s}),c.debug(`[manifest] Agent turn started: agent=${t}, session=${u}`)}),ia(o,"tool_result_persist",a=>{let u=a.toolName||a.tool||"unknown",t=a.durationMs||0,e=a.error==null,n=a.sessionKey||"unknown",s=_r.get(n),l=s?.turn?Be.setSpan(we.active(),s.turn):we.active(),E=r.startSpan(`${un.TOOL_PREFIX}${u}`,{kind:Ve.INTERNAL,attributes:{[b.TOOL_NAME]:u,[b.TOOL_SUCCESS]:String(e),[b.SESSION_KEY]:n}},l);e||(E.setStatus({code:rt.ERROR,message:a.error?.message||"Tool execution failed"}),$I.add(1,{[b.TOOL_NAME]:u})),E.end(),XI.add(1,{[b.TOOL_NAME]:u}),QI.record(t,{[b.TOOL_NAME]:u})}),ia(o,"agent_end",async a=>{let u=a.sessionKey||a.session?.key||`agent:${a.agent||"main"}:main`,t=a.messages||[],e=[...t].reverse().find(k=>k.role==="assistant"&&k.usage),n=e?.model||a.model||"unknown",s=e?.provider||a.provider||"unknown",l=e?.usage||a.usage||{},E=l.input||l.inputTokens||l.prompt_tokens||l.promptTokens||0,A=l.output||l.outputTokens||l.completion_tokens||l.completionTokens||0,g=l.prompt_tokens_details||{},C=l.cacheRead||l.cacheReadTokens||l.cache_read_tokens||g.cached_tokens||0,nn=l.cacheWrite||l.cacheWriteTokens||l.cache_creation_tokens||0,Le=n,Tr=s,$e=null,mt=null;if(Le==="auto"){let k=await KI(i,t,u,c);k&&(Le=k.model,Tr=k.provider,$e=k.tier,mt=k.reason||null)}let ht=[...t].reverse().find(k=>k?.role==="user");(ht?typeof ht.content=="string"?ht.content.includes("HEARTBEAT_OK"):Array.isArray(ht.content)?ht.content.some(k=>k.type==="text"&&typeof k.text=="string"&&k.text.includes("HEARTBEAT_OK")):!1:!1)&&(mt="heartbeat",$e="simple");let Ae=_r.get(u);if(Ae?.turn){if(Ae.turn.setAttributes({[b.MODEL]:Le,[b.PROVIDER]:Tr,[b.INPUT_TOKENS]:E,[b.OUTPUT_TOKENS]:A,[b.CACHE_READ_TOKENS]:C,[b.CACHE_WRITE_TOKENS]:nn}),$e&&Ae.turn.setAttribute(b.ROUTING_TIER,$e),mt&&Ae.turn.setAttribute(b.ROUTING_REASON,mt),a.success===!1||a.error!=null){let k=a.error?.message||a.errorMessage||"Agent turn failed";Ae.turn.setStatus({code:rt.ERROR,message:typeof k=="string"?k.slice(0,500):String(k)})}Ae.turn.end()}Ae?.root&&Ae.root!==Ae.turn&&Ae.root.end(),_r.delete(u);let on={[b.MODEL]:Le,[b.PROVIDER]:Tr};qI.add(1,on),WI.add(E,on),zI.add(A,on),C>0&&JI.add(C,on),c.debug(`[manifest] agent_end tokens: in=${E}, out=${A}, cache=${C}`),c.debug(`[manifest] Trace completed for session=${u}`)}),c.debug("[manifest] All hooks registered")}async function Ot(o){let r=o.endpoint.replace(/\/otlp(\/v1)?\/?$/,""),i={endpointReachable:!1,authValid:!1,agentName:null,error:null};try{let c=await fetch(`${r}/api/v1/health`,{signal:AbortSignal.timeout(5e3)});if(!c.ok)return i.error=`Health endpoint returned ${c.status}`,i;i.endpointReachable=!0}catch(c){let a=c instanceof Error?c.message:String(c);return i.error=`Cannot reach endpoint: ${a}`,i}try{let c=o.apiKey?{Authorization:`Bearer ${o.apiKey}`}:{},a=await fetch(`${r}/api/v1/agent/usage?range=24h`,{headers:c,signal:AbortSignal.timeout(5e3)});if(a.status===401||a.status===403)return i.error="API key rejected \u2014 check your mnfst_ key is correct",i;if(!a.ok)return i.error=`Usage endpoint returned ${a.status}`,i;i.authValid=!0;let u=await a.json();u&&typeof u.agentName=="string"&&(i.agentName=u.agentName)}catch(c){let a=c instanceof Error?c.message:String(c);return i.error=`Auth check failed: ${a}`,i}return i}var aa={today:"24h",week:"7d",month:"30d"};async function ua(o,r,i,c){let a=`${o}${r}`;try{let u=i?{Authorization:`Bearer ${i}`}:{},t=await fetch(a,{headers:u});if(!t.ok)return{content:[{type:"text",text:JSON.stringify({error:`API returned ${t.status}`})}]};let e=await t.json();return{content:[{type:"text",text:JSON.stringify(e)}]}}catch(u){let t=u instanceof Error?u.message:String(u);return c.error(`[manifest] API call failed: ${t}`),{content:[{type:"text",text:JSON.stringify({error:t})}]}}}function rx(o){try{let r=JSON.parse(o.content[0].text);return r.error?{error:r.error}:{result:r}}catch{return{result:o.content[0].text}}}function nx(o,r,i){let c=r.endpoint.replace(/\/otlp(\/v1)?\/?$/,"");o.registerTool({name:"manifest_usage",description:"Get token consumption for this agent: total, input, output, cache-read tokens, and action count. Use when the user asks about token usage or consumption.",parameters:{type:"object",properties:{period:{type:"string",enum:["today","week","month"],default:"today",description:"Time period"}}},async handler(a){let u=aa[a.period||"today"]||"24h";return rx(await ua(c,`/api/v1/agent/usage?range=${u}`,r.apiKey,i))},async execute(a,u){let t=aa[u.period||"today"]||"24h";return ua(c,`/api/v1/agent/usage?range=${t}`,r.apiKey,i)}},{optional:!0}),o.registerTool({name:"manifest_costs",description:"Get cost breakdown for this agent in USD, grouped by model. Use when the user asks about costs, spending, or money burned.",parameters:{type:"object",properties:{period:{type:"string",enum:["today","week","month"],default:"week",description:"Time period"}}},async handler(a){let u=aa[a.period||"week"]||"7d";return rx(await ua(c,`/api/v1/agent/costs?range=${u}`,r.apiKey,i))},async execute(a,u){let t=aa[u.period||"week"]||"7d";return ua(c,`/api/v1/agent/costs?range=${t}`,r.apiKey,i)}},{optional:!0}),o.registerTool({name:"manifest_health",description:"Check whether Manifest observability is connected and working. Use when the user asks if monitoring is set up or wants a connectivity test.",parameters:{type:"object",properties:{}},async handler(){let a=await Ot(r);return a.error?{error:a.error}:{result:{endpointReachable:a.endpointReachable,authValid:a.authValid,agentName:a.agentName,status:"ok"}}},async execute(){let a=await Ot(r);return a.error?{content:[{type:"text",text:JSON.stringify({error:a.error})}]}:{content:[{type:"text",text:JSON.stringify({endpointReachable:a.endpointReachable,authValid:a.authValid,agentName:a.agentName,status:"ok"})}]}}},{optional:!0}),i.debug("[manifest] Registered agent tools: manifest_usage, manifest_costs, manifest_health")}function ox(o,r,i){if(typeof o.registerCommand!="function"){i.debug("[manifest] registerCommand not available, skipping /manifest command");return}let c=async()=>{try{let a=await Ot(r),u=[`Mode: ${r.mode}`,`Dev mode: ${r.devMode?"yes":"no"}`,`Endpoint reachable: ${a.endpointReachable?"yes":"no"}`,`Auth valid: ${a.authValid?"yes":"no"}`];return a.agentName&&u.push(`Agent: ${a.agentName}`),a.error&&u.push(`Error: ${a.error}`),u.join(`
19
+ or export MANIFEST_API_KEY=${Qe}YOUR_KEY`}var na=ve(sM()),oa=ve(di()),wI=ve(LI()),BI=ve(VI()),GI=ve(Oo());m();var en=null,tn=null,gc=null,Lc=null;function HI(o,r){let i=new GI.Resource({"service.name":fr.SERVICE_NAME,"service.version":"5.30.0","manifest.plugin":"true"}),c=o.apiKey?{Authorization:`Bearer ${o.apiKey}`}:{},a=new wI.OTLPTraceExporter({url:`${o.endpoint}/v1/traces`,headers:c});en=new na.BasicTracerProvider({resource:i,spanProcessors:[new na.BatchSpanProcessor(a,{scheduledDelayMillis:5e3,maxQueueSize:2048,maxExportBatchSize:512})]}),en.register(),r.debug(`[manifest] Trace exporter -> ${o.endpoint}/v1/traces`);let u=new BI.OTLPMetricExporter({url:`${o.endpoint}/v1/metrics`,headers:c}),t=o.devMode||o.mode==="local"?xc.METRICS_INTERVAL_MS:fr.METRICS_INTERVAL_MS;return tn=new oa.MeterProvider({resource:i,readers:[new oa.PeriodicExportingMetricReader({exporter:u,exportIntervalMillis:t})]}),Mt.setGlobalMeterProvider(tn),r.debug(`[manifest] Metrics exporter -> ${o.endpoint}/v1/metrics (interval=${t}ms)`),gc=Be.getTracer("manifest-plugin","5.30.0"),Lc=Mt.getMeter("manifest-plugin","5.30.0"),{tracer:gc,meter:Lc}}async function kI(o){o.info("[manifest] Shutting down telemetry..."),en&&(await en.shutdown(),en=null),tn&&(await tn.shutdown(),tn=null),gc=null,Lc=null,o.info("[manifest] Telemetry shut down")}m();var g5=5,FI=30*60*1e3,L5=3e3,I5=5*60*1e3,x5=new Set(["system","developer"]),C5=10,rn=new Map,YI=!1;function b5(){if(YI)return;YI=!0;let o=setInterval(()=>{let r=Date.now();for(let[i,c]of rn)r-c.lastUpdated>FI&&rn.delete(i)},I5);typeof o=="object"&&"unref"in o&&o.unref()}async function KI(o,r,i,c){b5();let u=`${o.endpoint.replace(/\/otlp(\/v1)?\/?$/,"")}/api/v1/routing/resolve`;try{if(!r||!Array.isArray(r)||r.length===0)return c.debug("[manifest] Routing resolve: no messages, skipping"),null;let t=r.filter(C=>C&&typeof C=="object"&&"role"in C&&!x5.has(C.role)).slice(-C5).map(C=>({role:C.role,content:C.content}));if(t.length===0)return c.debug("[manifest] Routing resolve: no scorable messages, skipping"),null;let e=rn.get(i),n=e&&Date.now()-e.lastUpdated<FI?e.tiers:void 0,s={messages:t};n&&(s.recentTiers=n);let l={"Content-Type":"application/json"};o.apiKey&&(l.Authorization=`Bearer ${o.apiKey}`);let E=await fetch(u,{method:"POST",headers:l,body:JSON.stringify(s),signal:AbortSignal.timeout(L5)});if(!E.ok)return c.debug(`[manifest] Routing resolve returned ${E.status}`),null;let A=await E.json();if(!A.model)return c.debug(`[manifest] Routing resolve: no model for tier=${A.tier}`),null;let g=rn.get(i);return g?(g.tiers=[A.tier,...g.tiers].slice(0,g5),g.lastUpdated=Date.now()):rn.set(i,{tiers:[A.tier],lastUpdated:Date.now()}),c.debug(`[manifest] Routing resolved: tier=${A.tier} model=${A.model} provider=${A.provider}`),{tier:A.tier,model:A.model,provider:A.provider??"unknown",reason:A.reason??"",auth_type:A.auth_type??"api_key"}}catch(t){let e=t instanceof Error?t.message:String(t);return c.debug(`[manifest] Routing resolve failed (${e})`),null}}function jI(o,r,i){if(typeof o.registerProvider!="function"){i.debug("[manifest] registerProvider not available, skipping provider registration");return}let c=r.endpoint.replace(/\/otlp(\/v1)?\/?$/,"");try{o.registerProvider({id:"manifest",name:"Manifest Router",label:"Manifest Router",api:"openai-completions",baseUrl:c,apiKey:r.apiKey,models:["auto"]}),i.info("[manifest] Registered as OpenAI-compatible provider (proxy mode)")}catch(a){let u=a instanceof Error?a.message:String(a);i.debug(`[manifest] registerProvider failed (${u})`)}}var _r=new Map,qI,WI,zI,JI,U5,XI,$I,QI,ZI;function ex(o){qI=o.createCounter(Oe.LLM_REQUESTS,{description:"Total LLM inference requests"}),WI=o.createCounter(Oe.LLM_TOKENS_INPUT,{description:"Total input tokens sent to LLM"}),zI=o.createCounter(Oe.LLM_TOKENS_OUTPUT,{description:"Total output tokens from LLM"}),JI=o.createCounter(Oe.LLM_TOKENS_CACHE_READ,{description:"Total cache-read tokens"}),U5=o.createHistogram(Oe.LLM_DURATION,{description:"LLM request duration in ms",unit:"ms"}),XI=o.createCounter(Oe.TOOL_CALLS,{description:"Total tool invocations"}),$I=o.createCounter(Oe.TOOL_ERRORS,{description:"Total tool errors"}),QI=o.createHistogram(Oe.TOOL_DURATION,{description:"Tool execution duration in ms",unit:"ms"}),ZI=o.createCounter(Oe.MESSAGES_RECEIVED,{description:"Total messages received from users"})}function ia(o,r,i){typeof o.on=="function"?o.on(r,i):typeof o.registerHook=="function"&&o.registerHook(r,i)}function tx(o,r,i,c){ia(o,"message_received",a=>{let u=a.sessionKey||a.session?.key||`agent:${a.agent||"main"}:main`,t=a.channel||"unknown",e=r.startSpan(un.REQUEST,{kind:Ve.SERVER,attributes:{[b.SESSION_KEY]:u,[b.CHANNEL]:t}});_r.set(u,{root:e}),ZI.add(1,{[b.CHANNEL]:t}),c.debug(`[manifest] Root span started for session=${u}`)}),ia(o,"before_agent_start",a=>{let u=a.sessionKey||a.session?.key||`agent:${a.agent||"main"}:main`,t=a.agent||"main",e=_r.get(u),n=e?.root?Be.setSpan(we.active(),e.root):we.active(),s=r.startSpan(un.AGENT_TURN,{kind:Ve.INTERNAL,attributes:{[b.AGENT_NAME]:t,[b.SESSION_KEY]:u}},n);e?e.turn=s:_r.set(u,{root:s,turn:s}),c.debug(`[manifest] Agent turn started: agent=${t}, session=${u}`)}),ia(o,"tool_result_persist",a=>{let u=a.toolName||a.tool||"unknown",t=a.durationMs||0,e=a.error==null,n=a.sessionKey||"unknown",s=_r.get(n),l=s?.turn?Be.setSpan(we.active(),s.turn):we.active(),E=r.startSpan(`${un.TOOL_PREFIX}${u}`,{kind:Ve.INTERNAL,attributes:{[b.TOOL_NAME]:u,[b.TOOL_SUCCESS]:String(e),[b.SESSION_KEY]:n}},l);e||(E.setStatus({code:rt.ERROR,message:a.error?.message||"Tool execution failed"}),$I.add(1,{[b.TOOL_NAME]:u})),E.end(),XI.add(1,{[b.TOOL_NAME]:u}),QI.record(t,{[b.TOOL_NAME]:u})}),ia(o,"agent_end",async a=>{let u=a.sessionKey||a.session?.key||`agent:${a.agent||"main"}:main`,t=a.messages||[],e=[...t].reverse().find(k=>k.role==="assistant"&&k.usage),n=e?.model||a.model||"unknown",s=e?.provider||a.provider||"unknown",l=e?.usage||a.usage||{},E=l.input||l.inputTokens||l.prompt_tokens||l.promptTokens||0,A=l.output||l.outputTokens||l.completion_tokens||l.completionTokens||0,g=l.prompt_tokens_details||{},C=l.cacheRead||l.cacheReadTokens||l.cache_read_tokens||g.cached_tokens||0,nn=l.cacheWrite||l.cacheWriteTokens||l.cache_creation_tokens||0,Le=n,Tr=s,$e=null,mt=null;if(Le==="auto"){let k=await KI(i,t,u,c);k&&(Le=k.model,Tr=k.provider,$e=k.tier,mt=k.reason||null)}let ht=[...t].reverse().find(k=>k?.role==="user");(ht?typeof ht.content=="string"?ht.content.includes("HEARTBEAT_OK"):Array.isArray(ht.content)?ht.content.some(k=>k.type==="text"&&typeof k.text=="string"&&k.text.includes("HEARTBEAT_OK")):!1:!1)&&(mt="heartbeat",$e="simple");let Ae=_r.get(u);if(Ae?.turn){if(Ae.turn.setAttributes({[b.MODEL]:Le,[b.PROVIDER]:Tr,[b.INPUT_TOKENS]:E,[b.OUTPUT_TOKENS]:A,[b.CACHE_READ_TOKENS]:C,[b.CACHE_WRITE_TOKENS]:nn}),$e&&Ae.turn.setAttribute(b.ROUTING_TIER,$e),mt&&Ae.turn.setAttribute(b.ROUTING_REASON,mt),a.success===!1||a.error!=null){let k=a.error?.message||a.errorMessage||"Agent turn failed";Ae.turn.setStatus({code:rt.ERROR,message:typeof k=="string"?k.slice(0,500):String(k)})}Ae.turn.end()}Ae?.root&&Ae.root!==Ae.turn&&Ae.root.end(),_r.delete(u);let on={[b.MODEL]:Le,[b.PROVIDER]:Tr};qI.add(1,on),WI.add(E,on),zI.add(A,on),C>0&&JI.add(C,on),c.debug(`[manifest] agent_end tokens: in=${E}, out=${A}, cache=${C}`),c.debug(`[manifest] Trace completed for session=${u}`)}),c.debug("[manifest] All hooks registered")}async function Ot(o){let r=o.endpoint.replace(/\/otlp(\/v1)?\/?$/,""),i={endpointReachable:!1,authValid:!1,agentName:null,error:null};try{let c=await fetch(`${r}/api/v1/health`,{signal:AbortSignal.timeout(5e3)});if(!c.ok)return i.error=`Health endpoint returned ${c.status}`,i;i.endpointReachable=!0}catch(c){let a=c instanceof Error?c.message:String(c);return i.error=`Cannot reach endpoint: ${a}`,i}try{let c=o.apiKey?{Authorization:`Bearer ${o.apiKey}`}:{},a=await fetch(`${r}/api/v1/agent/usage?range=24h`,{headers:c,signal:AbortSignal.timeout(5e3)});if(a.status===401||a.status===403)return i.error="API key rejected \u2014 check your mnfst_ key is correct",i;if(!a.ok)return i.error=`Usage endpoint returned ${a.status}`,i;i.authValid=!0;let u=await a.json();u&&typeof u.agentName=="string"&&(i.agentName=u.agentName)}catch(c){let a=c instanceof Error?c.message:String(c);return i.error=`Auth check failed: ${a}`,i}return i}var aa={today:"24h",week:"7d",month:"30d"};async function ua(o,r,i,c){let a=`${o}${r}`;try{let u=i?{Authorization:`Bearer ${i}`}:{},t=await fetch(a,{headers:u});if(!t.ok)return{content:[{type:"text",text:JSON.stringify({error:`API returned ${t.status}`})}]};let e=await t.json();return{content:[{type:"text",text:JSON.stringify(e)}]}}catch(u){let t=u instanceof Error?u.message:String(u);return c.error(`[manifest] API call failed: ${t}`),{content:[{type:"text",text:JSON.stringify({error:t})}]}}}function rx(o){try{let r=JSON.parse(o.content[0].text);return r.error?{error:r.error}:{result:r}}catch{return{result:o.content[0].text}}}function nx(o,r,i){let c=r.endpoint.replace(/\/otlp(\/v1)?\/?$/,"");o.registerTool({name:"manifest_usage",description:"Get token consumption for this agent: total, input, output, cache-read tokens, and action count. Use when the user asks about token usage or consumption.",parameters:{type:"object",properties:{period:{type:"string",enum:["today","week","month"],default:"today",description:"Time period"}}},async handler(a){let u=aa[a.period||"today"]||"24h";return rx(await ua(c,`/api/v1/agent/usage?range=${u}`,r.apiKey,i))},async execute(a,u){let t=aa[u.period||"today"]||"24h";return ua(c,`/api/v1/agent/usage?range=${t}`,r.apiKey,i)}},{optional:!0}),o.registerTool({name:"manifest_costs",description:"Get cost breakdown for this agent in USD, grouped by model. Use when the user asks about costs, spending, or money burned.",parameters:{type:"object",properties:{period:{type:"string",enum:["today","week","month"],default:"week",description:"Time period"}}},async handler(a){let u=aa[a.period||"week"]||"7d";return rx(await ua(c,`/api/v1/agent/costs?range=${u}`,r.apiKey,i))},async execute(a,u){let t=aa[u.period||"week"]||"7d";return ua(c,`/api/v1/agent/costs?range=${t}`,r.apiKey,i)}},{optional:!0}),o.registerTool({name:"manifest_health",description:"Check whether Manifest observability is connected and working. Use when the user asks if monitoring is set up or wants a connectivity test.",parameters:{type:"object",properties:{}},async handler(){let a=await Ot(r);return a.error?{error:a.error}:{result:{endpointReachable:a.endpointReachable,authValid:a.authValid,agentName:a.agentName,status:"ok"}}},async execute(){let a=await Ot(r);return a.error?{content:[{type:"text",text:JSON.stringify({error:a.error})}]}:{content:[{type:"text",text:JSON.stringify({endpointReachable:a.endpointReachable,authValid:a.authValid,agentName:a.agentName,status:"ok"})}]}}},{optional:!0}),i.debug("[manifest] Registered agent tools: manifest_usage, manifest_costs, manifest_health")}function ox(o,r,i){if(typeof o.registerCommand!="function"){i.debug("[manifest] registerCommand not available, skipping /manifest command");return}let c=async()=>{try{let a=await Ot(r),u=[`Mode: ${r.mode}`,`Dev mode: ${r.devMode?"yes":"no"}`,`Endpoint reachable: ${a.endpointReachable?"yes":"no"}`,`Auth valid: ${a.authValid?"yes":"no"}`];return a.agentName&&u.push(`Agent: ${a.agentName}`),a.error&&u.push(`Error: ${a.error}`),u.join(`
20
20
  `)}catch(a){return`Manifest status check failed: ${a instanceof Error?a.message:String(a)}`}};o.registerCommand({name:"manifest",description:"Show Manifest plugin status and connection info",async handler(){return c()},async execute(){let a=await c();return{text:a,content:[{type:"text",text:a}]}}}),i.debug("[manifest] Registered /manifest command")}var Er=require("./local-mode"),sa=require("./subscription");module.exports={id:"manifest",name:"Manifest \u2014 Agent Observability",register(o){let r=o.logger||{info:(...A)=>console.log(...A),debug:()=>{},error:(...A)=>console.error(...A),warn:(...A)=>console.warn(...A)},{config:i,_deprecatedDevMode:c}=Cc(o.pluginConfig);if(c&&r.warn?.(`[manifest] mode: "dev" is deprecated. Use mode: "cloud" with devMode: true instead.
21
21
  openclaw config set plugins.entries.manifest.config.mode cloud
22
22
  openclaw config set plugins.entries.manifest.config.devMode true`),i.mode==="local"){(0,Er.registerLocalMode)(o,i,r);return}let a=bc(i);if(a){!i.devMode&&i.mode==="cloud"&&!i.apiKey?r.info(`[manifest] Cloud mode requires an API key: