manifest 5.28.4 → 5.28.5

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.
@@ -498,12 +498,17 @@ let TraceIngestService = class TraceIngestService {
498
498
  select: ['provider', 'auth_type'],
499
499
  });
500
500
  const sub = new Set();
501
+ const apiKey = new Set();
501
502
  for (const r of records) {
502
503
  if (!(0, subscription_support_1.isManifestUsableProvider)(r))
503
504
  continue;
504
505
  if (r.auth_type === 'subscription')
505
506
  sub.add(r.provider);
507
+ else if (r.auth_type === 'api_key')
508
+ apiKey.add(r.provider);
506
509
  }
510
+ for (const p of apiKey)
511
+ sub.delete(p);
507
512
  return sub;
508
513
  }
509
514
  async withTurnWriteTransaction(ctx, fn) {
@@ -78,22 +78,26 @@ function convertTools(tools) {
78
78
  }
79
79
  return out.length > 0 ? out : undefined;
80
80
  }
81
- function toAnthropicRequest(body, _model) {
81
+ function toAnthropicRequest(body, _model, options) {
82
+ const shouldCache = options?.injectCacheControl !== false;
82
83
  const messages = body.messages || [];
83
84
  const systemBlocks = extractSystemBlocks(messages);
84
- if (systemBlocks.length > 0)
85
+ if (systemBlocks.length > 0 && shouldCache) {
85
86
  systemBlocks[systemBlocks.length - 1].cache_control = CACHE;
87
+ }
86
88
  const converted = messages.map(convertMessage).filter(Boolean);
87
89
  const result = {
88
90
  messages: converted,
89
91
  max_tokens: body.max_tokens || 4096,
90
- cache_control: { type: 'ephemeral' },
91
92
  };
93
+ if (shouldCache)
94
+ result.cache_control = { type: 'ephemeral' };
92
95
  if (systemBlocks.length > 0)
93
96
  result.system = systemBlocks;
94
97
  const tools = convertTools(body.tools);
95
98
  if (tools) {
96
- tools[tools.length - 1].cache_control = CACHE;
99
+ if (shouldCache)
100
+ tools[tools.length - 1].cache_control = CACHE;
97
101
  result.tools = tools;
98
102
  }
99
103
  if (body.temperature !== undefined)
@@ -145,11 +145,7 @@ function normalizeDeepSeekMaxTokens(body) {
145
145
  if (!('max_tokens' in body))
146
146
  return;
147
147
  const raw = body.max_tokens;
148
- const parsed = typeof raw === 'number'
149
- ? raw
150
- : typeof raw === 'string'
151
- ? Number(raw)
152
- : Number.NaN;
148
+ const parsed = typeof raw === 'number' ? raw : typeof raw === 'string' ? Number(raw) : Number.NaN;
153
149
  if (!Number.isFinite(parsed) || parsed <= 0) {
154
150
  delete body.max_tokens;
155
151
  return;
@@ -205,7 +201,9 @@ let ProviderClient = ProviderClient_1 = class ProviderClient {
205
201
  else if (isAnthropic) {
206
202
  url = `${endpoint.baseUrl}${endpoint.buildPath(bareModel)}`;
207
203
  headers = endpoint.buildHeaders(apiKey, authType);
208
- requestBody = (0, anthropic_adapter_1.toAnthropicRequest)(body, bareModel);
204
+ requestBody = (0, anthropic_adapter_1.toAnthropicRequest)(body, bareModel, {
205
+ injectCacheControl: authType !== 'subscription',
206
+ });
209
207
  requestBody.model = bareModel;
210
208
  if (stream)
211
209
  requestBody.stream = true;
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.28.4","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.28.4"),Lc=Mt.getMeter("manifest-plugin","5.28.4"),{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.28.5","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.28.5"),Lc=Mt.getMeter("manifest-plugin","5.28.5"),{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: