@tbox.cn/app-agent-sdk-server 0.1.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.
- package/LICENSE +21 -0
- package/dist/platform/index.d.ts +1 -0
- package/dist/platform/index.js +1 -0
- package/dist/server/index.d.ts +2282 -0
- package/dist/server/index.js +94 -0
- package/package.json +67 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export*from"@tbox.cn/app-sdk-server";import{Mastra as hd}from"@mastra/core";import{Agent as Td}from"@mastra/core/agent";import{SpanType as ve}from"@mastra/core/observability";import{RequestContext as Sd}from"@mastra/core/request-context";import{Observability as bd}from"@mastra/observability";import{createHash as xi}from"crypto";import{EventType as K}from"@ag-ui/core";var _n=4096,ba=32768;function ts(e,t){return{family:e,open:`<${t}`,close:`</${t}`,body:"drop",openSeal:"gt",closeSeal:"gt"}}function An(e,t){return{family:e,open:`<${t}`,close:`</${t}>`,body:"decision",openSeal:"gt",closeSeal:"self"}}function rs(e,t,r,n){return{family:e,open:t,close:r,body:"drop",openSeal:"self",closeSeal:"self",...n?{normalize:n}:{}}}var ns=e=>e==="|"?"|":e==="▁"?"_":e;function St(e,t){let r=ts(e,t);return e==="think"?{...r,reasoningBody:"passthrough",gate:"leading-zone",source:"builtin"}:{...r,source:"builtin"}}var bt={think:["think","thinking"],"tool-call-text":["tool_call"]},vn=[St("think","think"),St("think","thinking")],On=[St("tool-call-text","tool_call"),{...rs("tool-call-text","<|tool▁calls▁begin|>","<|tool▁calls▁end|>",ns),source:"builtin"}];function It(e,t){let r=t?.track??"content",n=e.find(u=>u.normalize)?.normalize??(u=>u),o=r==="content",s={children:new Map,terminals:[]},i=new Map,l=(u,y,h)=>{let k=s,x="";for(let _ of u){let V=n(_).toLowerCase();x+=V;let ee=k.children.get(V);ee||(ee={children:new Map,terminals:[]},k.children.set(V,ee)),k=ee}k.terminals.push({spec:y,kind:h}),h==="close"&&i.set(y,x)};for(let u of e)l(u.open,u,"open"),l(u.close,u,"close");let a="text",c="",d="",p=s,m=[],g=null,C=null,v=0,P="",F=0,U="",D=0,O=[],H=[],j=0,se=0,ie=!1,W=!0,me=new Set,Oe=[],nt=[],yt=u=>u.length>64?u.slice(0,64):u,ht=u=>u.source??"builtin",$=u=>/\S/.test(u),q=()=>{a="text",p=s,m=[],c="",d="",U="",g=null,C=null,v=0,P="",F=0,D=0,O=[],H=[],j=0,se=0},fe=u=>{c&&(u.push(c),o&&W&&$(c)&&(W=!1)),q()},ae=(u,y,h,k,x)=>{Oe.push({family:u.family,action:y,form:yt(h),chars:k,track:r,source:ht(u),...x?.unclosed?{unclosed:!0}:{},...x?.degraded?{degraded:!0}:{}})},Le=(u,y)=>{if(u.gate==="leading-zone"&&o&&!W){y.push(c),ae(u,"released",c,0),q();return}C=u,F=0,u.body==="decision"?(v=c.length,a="body-decision"):(P=c,c="",d="",U="",a="body-drop"),m=[],p=s},qe=(u,y,h)=>{if(u.reasoningBody==="passthrough"&&r==="reasoning"&&O.length>0){if(!y){let k=i.get(u),x=u.closeSeal==="gt"?k.length+D:k.length,_=Math.max(0,O.length-x);h.push(...O.slice(0,_))}O=[],H=[]}ae(u,"stripped",P,F,{unclosed:y}),q()},Ge=(u,y)=>{u.reasoningBody==="passthrough"&&r==="reasoning"&&O.length>0&&(y.push(...O),O=[],H=[]),me.add(u.family),ae(u,"stripped",P,F,{degraded:!0}),q()},f=(u,y)=>{u.gate==="leading-zone"&&o&&!W?(y.push(c),ae(u,"released",c,0)):u.body==="decision"?y.push(c):ae(u,"stripped",c,0),q()},R=u=>{if(u.terminals.some(y=>!me.has(y.spec.family)))return!0;for(let y of u.children.values())if(R(y))return!0;return!1},w=(u,y)=>{let h=Math.min(u.length,y.length);for(let k=h;k>=1;k--)if(u.slice(-k)===y.slice(0,k))return!0;return!1},M=(u,y)=>{switch(a){case"text":{if(u==="<"&&s.children.has("<")){let h=s.children.get("<");c="<",d="<",p=h,m=[{node:h,heldLen:1}],a="trie"}else y.push(u),o&&W&&$(u)&&(W=!1);break}case"trie":{let h=n(u).toLowerCase(),k=p.children.get(h);if(k){c+=u,d+=h,p=k,m.push({node:k,heldLen:c.length});break}let x=null;for(let _=m.length-1;_>=0;_--){let V=m[_].node.terminals.filter(ee=>!me.has(ee.spec.family));if(V.length>0){x={spec:V[0].spec,kind:V[0].kind,termLen:m[_].heldLen};break}}if(x){let _=c.slice(x.termLen)+u;c=c.slice(0,x.termLen),d=d.slice(0,x.termLen),x.kind==="open"?x.spec.openSeal==="gt"?(g=x.spec,a="wait-gt"):Le(x.spec,y):x.spec.closeSeal==="gt"?(g=x.spec,a="orphan-close-seal"):f(x.spec,y);for(let V of _)M(V,y)}else c+=u,fe(y);break}case"wait-gt":{if(u===">"){c+=u;let h=g;g=null,Le(h,y)}else/\s/.test(u)?c+=u:(c+=u,fe(y));break}case"orphan-close-seal":{if(u===">"){c+=u;let h=g;g=null,f(h,y)}else/\s/.test(u)?c+=u:(c+=u,fe(y));break}case"body-drop":{let h=C;F+=1,j+=1;let k=n(u).toLowerCase();U+=k;let x=h.reasoningBody==="passthrough"&&r==="reasoning";x&&(O.push(u),H.push(k));let _=i.get(h);if(U.length>=_.length&&U.slice(-_.length)===_)F-=_.length,h.closeSeal==="gt"?(D=0,a="wait-gt-close"):qe(h,!1,y);else{let V=w(U,_);if(se=V?se+1:0,j>32768&&(!V||se>_.length+16)){O.pop(),H.pop(),Ge(h,y),M(u,y);break}if(U.length>_.length+64&&(U=U.slice(-(_.length+64))),x&&H.length>0){let ee=0,Se=Math.min(H.length,_.length);for(let X=Se;X>=1;X--)if(H.slice(-X).join("")===_.slice(0,X)){ee=X;break}if(H.length>ee){let X=H.length-ee;y.push(...O.slice(0,X)),O=O.slice(X),H=H.slice(X)}}}break}case"wait-gt-close":{let h=C;if(j+=1,h.reasoningBody==="passthrough"&&r==="reasoning"&&(O.push(u),H.push(n(u).toLowerCase()),D+=1),j>32768+i.get(h).length+64){Ge(h,y),M(u,y);break}u===">"?qe(h,!1,y):/\s/.test(u)?U+=n(u).toLowerCase():(U+=n(u).toLowerCase(),F+=1,D=0,a="body-drop");break}case"body-decision":{let h=C;c+=u,d+=n(u).toLowerCase();let k=i.get(h);if(d.length>=k.length&&d.slice(-k.length)===k){nt.push({family:h.family,body:c.slice(v,c.length-k.length)}),q();break}c.length>4096&&(y.push(c),ae(h,"released",c,c.length-v,{degraded:!0}),me.add(h.family),q());break}case"done":break}};return{push:u=>{if(ie)return"";let y=[];for(let h of u)M(h,y);return a==="trie"&&!R(p)&&fe(y),y.join("")},finish:()=>{if(ie)return{tail:"",closedBodies:[...nt],hits:[...Oe]};ie=!0;let u="";if(a==="trie"){let y=null,h=null,k=x=>{for(let _ of x.terminals)me.has(_.spec.family)||(_.spec.body==="decision"?y=_.spec:h||(h=_.spec));for(let _ of x.children.values())k(_)};for(let x of m)k(x.node);y||c.length<=1?u=c:h&&ae(h,"stripped",c,0,{unclosed:!0})}else if(a==="wait-gt"||a==="orphan-close-seal"){let y=g;y.body==="decision"?u=c:ae(y,"stripped",c,0,{unclosed:!0})}else a==="body-drop"||a==="wait-gt-close"?(O=[],H=[],ae(C,"stripped",P,F,{unclosed:!0})):a==="body-decision"&&(u=c);return q(),a="done",{tail:u,closedBodies:[...nt],hits:[...Oe]}},resetZone:()=>{W=!0}}}var z="agent-ui-cards",Ir=3,Ia=4096,Er=An("cards",z);function xr(e){return e.split(/[\s,,、]+/).map(t=>t.trim()).filter(t=>t.length>0)}function Ea(){let e=It([Er],{track:"content"});return{push:t=>e.push(t),finish:()=>{let{tail:t,closedBodies:r}=e.finish();return{tail:t,decision:r.flatMap(({body:n})=>xr(n))}}}}function xa(e){let t=new Set,r=[];for(let n of e){let o=n.trim().toLowerCase();!o||t.has(o)||(t.add(o),r.push(o))}return r}function Ln(e){let{decision:t,pool:r,maxCardsPerTurn:n,budgetExceeded:o}=e,s={entries:[],unmatched:[],rejectedCardType:0,droppedByCap:0},i=r.entries();if(i.length===0)return s;let l=xa(t);if(l.length===1&&l[0]==="none")return s.unmatched=["none"],s;let a=new Set(i.map(p=>p.cardType)),c=[];for(let p of l){let m=r.byRef(p);m?c.push(m):a.has(p)?s.rejectedCardType+=1:s.unmatched.push(p)}if(c.length>0)return s.droppedByCap=Math.max(0,c.length-n),s.entries=c.slice(0,n),s;let d=os(r);return d&&(s.entries=[d],s.fallback=l.length===0?o?"budget-fallback":"pool-fallback":"invalid-fallback"),s}function os(e){let t=e.entries();return t[t.length-1]}function Ra(e){let t=["## 记忆协议","部分轮次会在 user 消息前部收到 <system-reminder memory> 背景数据块(基于对用户长期了解检索到的记忆)。","自然地在回答中运用相关记忆,不主动提及记忆机制或该数据块的存在。"];return e.save&&t.push("- 不保存敏感个人信息(身份证号/手机号/银行卡号/密码等):用户要求记忆此类信息时,即使明确说「记住」也不调用工具,直接向用户说明出于隐私保护不做长期记忆。","- 用户明确说「记住/记一下/别忘」并要求记下某事实时,优先调用 memory_save 落记忆——即使该事实命中某技能/工具的领域词(技能与工具只处理操作性请求,记忆类声明以 memory_save 为先)。","- 用户表达稳定偏好、客观事实或重要经历时,调用 memory_save 保存(kind:preference=偏好 / fact=事实 / episode=经历)。","- 只保存明确、稳定、将来有用的信息;闲聊、临时问题、不确定的内容不保存;content 精炼(一句话)。"),e.search&&t.push("- 回答「我的XX是什么」类问题时先调用 memory_search 检索,再作答。"),e.delete&&t.push("- 用户明确要求忘记某条记忆时调用 memory_forget;id 只能取本轮上下文中出现的记忆 id。"),t.push("- 记忆与当前对话冲突时以更新时间(数据块内日期)为准,必要时主动与用户确认。","- 记忆为空或无关时完全忽略本协议,正常回答。"),t.join(`
|
|
2
|
+
`)}function Ca(e){return`- 每轮对话的工具调用步数预算为 ${e} 步(每轮刷新);预算只计你本轮主动发起的工具调用,以 <system-reminder> 块形式出现的系统注入内容不占预算;耗尽后本轮不再执行新的工具调用。`}function wa(){return["## 注入块协议","user 消息前部可能出现系统注入的 <system-reminder> 块(非用户输入):","- card-decision 块:每轮注入的出卡决策提醒,卡片协议的轮级重申——按其决策本轮候选,id 规则以卡片协议为准。","- pre-tool 块:系统在用户本次提问前预先执行的工具调用,<input>/<output> 即其入参与出参,结果与你自行调用该工具得到的结果等价(只是提前执行了而已)。结果是执行时点的快照:相同参数在不同时刻可能返回不同结果,重新调用也会得到新的可展示卡片。是否再次调用由你按当前问题判断。预执行按固定维度查询,可能未覆盖用户的全部意图:用户如有该结果未满足的筛选或查询需求,应主动调用对应工具补充。同一事实存在多个来源时,本轮实时执行的工具结果置信度高于检索类背景资料(如 FAQ/知识条目),以其为准作答。","- memory 块:系统基于对用户长期了解检索的背景数据(条目含日期),按记忆协议运用。","- skill 块:持久操作规范,跨轮持续适用。它是你的内部操作手册:其中的流程步骤、工具选择规则不进回复正文——正文只给结果与下一步,不解释你为什么调某个工具,也不复述规程本身。"].join(`
|
|
3
|
+
`)}function Pn(e){return`# 平台规则
|
|
4
|
+
|
|
5
|
+
## 通用行为
|
|
6
|
+
- 违法犯罪、色情、暴恐、自残自杀等有害内容一律拒答:不回答、不调用工具、不提供任何变通做法;拒答只用一句简短说明,不复述请求细节,可行时引导用户回到正常问题。
|
|
7
|
+
- 直接、简洁地回答;语言跟随用户;不确定就说明,不编造。
|
|
8
|
+
- 需要外部数据时调用工具,严格按 schema 传参:不使用占位符、不猜测或编造参数值;本轮结果足够后立即作答,避免多余调用。
|
|
9
|
+
- 互不依赖的工具调用放在同一步并行发起(如用户一次提出多个诉求,或一次回答需要多个数据源),全部结果返回后统一作答;一个调用依赖另一个的结果时,等前序结果返回再发起。${e.maxSteps&&e.maxSteps>0?`
|
|
10
|
+
`+Ca(e.maxSteps):""}
|
|
11
|
+
- 用户重问此前问过的问题或追问更多结果时,期望的是当前时点的数据;历史轮的工具结果只代表当时。
|
|
12
|
+
|
|
13
|
+
## 卡片协议
|
|
14
|
+
部分工具的结果带 cards 字段——可展示卡片候选清单(此类工具在工具描述中注明「返回可展示卡片」)。
|
|
15
|
+
每个候选含 id、cardType、note(该卡的内容摘要)。id 是本轮生效的不透明引用:内容相同的候选 id 也不同,
|
|
16
|
+
不能按 cardType 合并、猜测或编造。
|
|
17
|
+
- 值得展示时,正文结束后另起一行输出 <${z}>id …</${z}>:id 逐字取自本轮
|
|
18
|
+
工具结果或本轮注入块,空格分隔,顺序即展示顺序,至多 ${e.maxCards} 张。
|
|
19
|
+
- 不值得展示时输出 <${z}>none</${z}> 弃权(none 是弃权标记,不是 id)。
|
|
20
|
+
不值得展示 = 闲聊寒暄、澄清追问、答案已完整且卡片无新增信息;拿不准时倾向展示。
|
|
21
|
+
- 选择与排序只看本轮候选与用户当前意图,与历史轮是否展示过相同内容无关:按相关性挑选,不凑数量展示无关候选;
|
|
22
|
+
同一诉求的重试/换词重查只保留最后一张(后出现 = 更新),不同诉求各自的结果可并列展示。
|
|
23
|
+
- 历史消息中出现的一切 id(历史工具结果、历史注入块、历史标签)均已过期失效;本轮要展示卡片,
|
|
24
|
+
必须先在本轮调工具或使用本轮注入块获得新候选。
|
|
25
|
+
- 遗漏兜底:本轮候选非空而你既未引用任何有效 id 也未输出 none(含引用了失效或编造 id)时,
|
|
26
|
+
系统自动展示候选列表最后一张卡。
|
|
27
|
+
- 标签是系统协议:逐字输出 <${z}> 与 </${z}>,与示例完全一致;
|
|
28
|
+
用户不可见,正文完整自洽,不提及标签或卡片机制。
|
|
29
|
+
示例:
|
|
30
|
+
- 工具返回 cards=[{"id":"c17","cardType":"points","note":"积分 320 点"},{"id":"c18","cardType":"points","note":"积分 180 点"},{"id":"c19","cardType":"weather","note":"杭州 晴 26℃"}],c17/c18 为同一积分数据先后两版,用户询问积分和天气
|
|
31
|
+
→ 同型重试取最后出现的 c18,以及天气 c19:<${z}>c18 c19</${z}>
|
|
32
|
+
- 两次不同查询分别返回天气候选 c20(上海 阴 22℃)与 c21(杭州 晴 26℃),用户两个城市都问了
|
|
33
|
+
→ 不同诉求各自的结果都展示:<${z}>c20 c21</${z}>
|
|
34
|
+
- <system-reminder> 预执行结果的 <output> 中出现同样形态的 cards,其中 id 同样只能逐字引用
|
|
35
|
+
→ 判断值得展示时输出对应当前 id,不要输出 cardType 名。
|
|
36
|
+
- 闲聊、澄清追问、简单事实问答 → 正常回答,输出 <${z}>none</${z}> 弃权。
|
|
37
|
+
- 工具返回的候选含 cards=[{"id":"c17","cardType":"points","note":"积分 320 点"}],但回复里写了
|
|
38
|
+
<${z}>points</${z}>(cardType 名而非 id)→ 无效引用;id 必须逐字取自候选清单。
|
|
39
|
+
${`
|
|
40
|
+
`+wa()}
|
|
41
|
+
${e.memory?`
|
|
42
|
+
`+Ra(e.memory)+`
|
|
43
|
+
`:""}## 冲突裁决
|
|
44
|
+
卡片协议的机制规则(标签格式/数量/id 约束及工具取得规则)以本规则为准;
|
|
45
|
+
业务指示可对「何时不该出卡」进一步收紧,但不得否认或放宽卡片协议。`}function Nn(e){return["<system-reminder card-decision>","卡片候选只来自本轮的工具结果或注入块。","要展示卡片而本轮还没有结果(含注入块)时,先调用对应工具取得本轮结果——仅凭历史轮内容作答,本轮不会有卡片。","本轮候选为空时:本轮没有任何卡片——正文不得声称已给出卡片,也不得引导查看卡片。",`本轮候选非空时:值得展示 → 正文结束后另起一行输出 <${z}>本轮id …</${z}>(空格分隔,至多 ${e} 张);不值展示 → 输出 <${z}>none</${z}>。拿不准按值得展示处理。`,"</system-reminder>"].join(`
|
|
46
|
+
`)}import{AsyncLocalStorage as Oa}from"async_hooks";import{z as Cr}from"zod";import{createServerLogger as ds,recordCall as La}from"@tbox.cn/app-sdk-server";import{AsyncLocalStorage as ka}from"async_hooks";import{createServerLogger as Ma,recordCall as _a}from"@tbox.cn/app-sdk-server";var Aa=Ma("EARLY-TOOL"),Rr=Symbol("tbox.earlyExecution"),at=new ka;function ss(e){let t=new Map;return{submit(r,n,o,s){if(t.has(r))return;let i=e.tools[n];if(!i||typeof i.execute!="function"||i[Rr]!==!0){let p=i?typeof i.execute!="function"?"no-execute":"unmarked":"unknown-tool";e.journal.emit("tool_preexec",{toolCallId:r,toolName:n,outcome:"skip",trigger:s,reason:p});return}e.journal.emit("tool_preexec",{toolCallId:r,toolName:n,outcome:"fired",trigger:s});let l=Date.now(),a={requestContext:e.requestContext,toolCallId:r,...e.signal?{abortSignal:e.signal}:{}},d=_a("tool",n,()=>i.execute.call(i,o,a)).then(p=>{if(p===void 0)throw new Error(`工具 ${n} 执行完成但未返回结果(undefined)——请检查工具实现是否缺少 return`);return p});d.then(void 0,()=>{}),t.set(r,{promise:d,toolName:n,startedAt:l,trigger:s})},invalidate(r,n){let o=t.get(r);o&&(t.delete(r),e.journal.emit("tool_preexec",{toolCallId:r,toolName:o.toolName,outcome:"invalidated",trigger:o.trigger,reason:n}))},take(r){let n=t.get(r);if(n)return t.delete(r),e.journal.emit("tool_preexec",{toolCallId:r,toolName:n.toolName,outcome:"hit",trigger:n.trigger,durMs:Date.now()-n.startedAt},n.startedAt),n.promise}}}function va(e){let t=new Map,r=(o,s)=>{let i=t.get(o);if(!(!i||i.firedAt!==void 0)&&i.args.trim()!=="")try{let l=JSON.parse(i.args);if(l===null||typeof l!="object"||Array.isArray(l))return;i.firedAt=i.args,e.submit(o,i.toolName,l,s)}catch{}},n=o=>{for(let s of t.keys())r(s,o)};return new TransformStream({transform(o,s){s.enqueue(o);try{let i=at.getStore();if(!i||i!==e)return;switch(o.type){case"tool-input-start":{n("next-start"),t.set(o.id,{toolName:o.toolName,args:""});break}case"tool-input-end":{r(o.id,"input-end");break}case"tool-input-delta":{let l=t.get(o.id);if(!l)break;l.args+=o.delta,l.firedAt!==void 0&&e.invalidate(o.id,"delta-after-fire");break}case"tool-call":{let l=t.get(o.toolCallId);l?.firedAt!==void 0&&l.firedAt!==o.input&&e.invalidate(o.toolCallId,"final-mismatch");break}default:break}}catch(i){Aa.warn("early-execution 流分析异常(透传不受影响):",i?.message??String(i))}},flush(){let o=at.getStore();!o||o!==e||n("flush")}})}function is(e){let t=Object.create(e);return t.doStream=(async r=>{let n=await e.doStream(r),o=at.getStore(),s=n,i=s?.stream;return!o||!i||typeof i.pipeThrough!="function"?n:{...s,stream:i.pipeThrough(va(o))}}),t}function as(e){if(!(!e||typeof e!="string"))return at.getStore()?.take(e)}var Pa=ds("TOOL"),Ne=ds("TOOLCARDS"),Bt="cards",us="可展示卡片",kr=`命中数据时结果附${us}(cards)。`,$n="操作入口在卡片上。",Na=Cr.object({id:Cr.string(),cardType:Cr.string(),note:Cr.string()}),wr=120,ls=8;function Da(e){try{return JSON.parse(JSON.stringify(e??null))}catch{return}}function $a(e,t,r){e===void 0&&Ne.warn(`note 缺失(${r})——按 note 契约补内容摘要(主体+关键事实,≤${wr} 字符,不复述顶层 facts)`);let n=e??t?.displayName??r;return n.length>wr?(Ne.warn(`note 超长截断(${n.length} → ${wr}): ${r}`),n.slice(0,wr)):n}function Mr(e={}){let t=new Map,r=[],n=0,o=e.allocateRef??(()=>`c${++n}`);return{add(s,i){let l=i[s.cardType];if(!l)return Ne.warn(`跳过未知卡片类型: ${s.cardType}`),null;let a=Da(s.data);if(a==null||typeof a!="object"||Array.isArray(a))return Ne.warn(`跳过 ${s.cardType}: data 非 JSON 对象`),null;let c=l.dataSchema.safeParse(a);if(!c.success)return Ne.warn(`跳过 ${s.cardType}: dataSchema 校验失败(${c.error.message})`),null;let d=c.data,p=o(),m=p.toLowerCase();if(t.has(m))throw new Error(`card ref allocator returned duplicate ref: ${p}`);let g={ref:p,cardType:s.cardType,data:d,note:$a(s.note,l,s.cardType)};return t.set(m,g),r.push(g),{id:g.ref,cardType:g.cardType,note:g.note}},byRef(s){return t.get(s.toLowerCase())},entries(){return r},size(){return r.length}}}function Dn(e,t,r){if(e===null||typeof e!="object"||Array.isArray(e))return e;let n=e;if(!(Bt in n))return e;let o=n[Bt];if(!Array.isArray(o))return Ne.warn("工具出参 cards 非数组,忽略出卡"),e;o.length>ls&&Ne.warn(`单工具出卡 ${o.length} 条(> ${ls}),观测确认是否预期`);let s=[];for(let[i,l]of o.entries()){if(l===null||typeof l!="object"||Array.isArray(l)){Ne.warn(`跳过 cards[${i}]:非对象`);continue}let a=l,{cardType:c,data:d,note:p}=a;if(typeof c!="string"||c.length===0){Ne.warn(`跳过 cards[${i}]:cardType 非法`);continue}if(d===null||typeof d!="object"||Array.isArray(d)){Ne.warn(`跳过 cards[${i}](${c}):data 非对象`);continue}let m=t.add({cardType:c,data:d,...typeof p=="string"?{note:p}:{}},r);m&&s.push(m)}if(s.length===0){let i={};for(let[l,a]of Object.entries(n))l!==Bt&&(i[l]=a);return i}return{...n,[Bt]:s}}var lt=new Oa,cs=Symbol("tbox.toolCardCapture");function Bn(e,t){let r={};for(let[n,o]of Object.entries(e)){let s=o;if(typeof s?.execute!="function"||s[cs]){r[n]=o;continue}let i=o,l=s.execute,a=Object.create(Object.getPrototypeOf(o),Object.getOwnPropertyDescriptors(o)),c=String(o.id??"unknown");a.execute=async function(d,p){let m=p,g=m?.toolCallId??m?.agent?.toolCallId,C=as(g);if(C){let v=await C,P=lt.getStore()?.pool;return P?Dn(v,P,t):v}return La("tool",c,async()=>{let v=await l.call(i,d,p);if(v===void 0)throw new Error(`工具 ${c} 执行完成但未返回结果(undefined)——请检查工具实现是否缺少 return`);let P=lt.getStore()?.pool;return P?Dn(v,P,t):v},{logger:Pa,detail:{args:d}})},a[cs]=!0,r[n]=a}return r}import{createTool as Ka}from"@mastra/core/tools";import{z as Ua}from"zod";var Fn=Symbol("tbox.internalTool");function Ba(e){return e[Fn]=!0,e}function Fa(e){return e[Rr]=!0,e}function Ar(e){let t={},r=!1;for(let[n,o]of Object.entries(e)){if(o[Fn]){r=!0;continue}t[n]=o}return r?t:e}var ps=Symbol("tbox.cardEmissionHint");function ja(e,t){let r=e;if(r[ps])return e;let n=Object.create(Object.getPrototypeOf(e),Object.getOwnPropertyDescriptors(e)),o=t?.actions?kr+$n:kr,s=n;return s.description=r.description?r.description+o:o,s[ps]=!0,n}function _r(e){if(Array.isArray(e))return e.map(_r);if(typeof e!="object"||e===null)return e;let t={};for(let[r,n]of Object.entries(e))n!==null&&(typeof n=="string"&&/^(null|undefined)$/i.test(n.trim())||Object.defineProperty(t,r,{value:_r(n),enumerable:!0,writable:!0,configurable:!0}));return t}function jn(e){return Ua.preprocess(_r,e)}var Un="https://mdn.alipayobjects.com/tcmarket/afts/file/";function Kn(e,t,r=Un){if(!t||t.length===0)return e;let n=[],o=[];for(let a of t)a.type==="image"?n.push({type:"image",image:new URL(`${r}${a.fileId}`),mimeType:a.mimeType}):o.push(a);if(n.length===0)return[{type:"text",text:`${o.map(c=>`[附件: ${c.type}${c.name?` "${c.name}"`:""}, fileId=${c.fileId}]`).join(`
|
|
47
|
+
`)}
|
|
48
|
+
${e}`}];let s=[...n],i=o.map(a=>`[附件: ${a.type}${a.name?` "${a.name}"`:""}, fileId=${a.fileId}]`).join(`
|
|
49
|
+
`),l=i?`${i}
|
|
50
|
+
${e}`:e;return s.push({type:"text",text:l}),s}function vr(e,t){let r=[...e.cardDecision?[e.cardDecision]:[],...e.preToolBlocks??[],...e.memoryBlock?[e.memoryBlock]:[],...e.skillBlock?[e.skillBlock]:[]];if(r.length===0)return typeof t=="string"?t.length>0?t:[]:t;let n=typeof t=="string"?t.length>0?[{type:"text",text:t}]:[]:t;return[...r.map(o=>({type:"text",text:o})),...n]}function Ha(e,t=Un){return!e||e.length===0?[]:e.filter(r=>r.type==="image").map(r=>`${t}${r.fileId}`)}import{SpanType as Xn,TracingEventType as Wa}from"@mastra/core/observability";import{SpanType as Et}from"@mastra/core/observability";function ze(e){return e.replace(/<system-reminder\b[^>]*>[\s\S]*?<\/system-reminder>\s*/g,"")}function ms(e){return/^<system-reminder\b[^>]*>/.test(e)&&/<\/system-reminder>\s*$/.test(e)}var Or={input:2e3,output:2e3,presenterSurface:1e4,attributeValue:2e3},qa=15,Ga=new Set([Et.AGENT_RUN,Et.MODEL_GENERATION,Et.MODEL_STEP,Et.MODEL_INFERENCE]);function Hn(e){if(e instanceof Date)return e.getTime();if(typeof e=="number")return e;if(typeof e=="string"){let t=Date.parse(e);return Number.isFinite(t)?t:NaN}return NaN}function Va(e){return typeof e=="string"?ze(e):Array.isArray(e)?e.filter(t=>!(t&&typeof t=="object"&&t.type==="text"&&typeof t.text=="string"&&ms(t.text))):e}function qn(e){return Array.isArray(e)?e.map(t=>{if(!t||typeof t!="object"||t.role!=="user")return t;let r=t;return{...r,content:Va(r.content)}}):e}function Xa(e,t){if(!Ga.has(e)||t==null)return t;try{if(Array.isArray(t))return qn(t);if(t&&typeof t=="object"&&Array.isArray(t.messages))return{...t,messages:qn(t.messages)};if(typeof t=="string"){let r;try{r=JSON.parse(t)}catch{return t}return Array.isArray(r)?JSON.stringify(qn(r)):t}}catch{}return t}function Ya(e){if(e.type!==Et.MODEL_INFERENCE||!e.attributes)return;let t=e.attributes,r=Hn(e.startTime),n=Hn(e.endTime),o=Hn(t.completionStartTime);if(![r,n,o].every(Number.isFinite))return;let s=Math.round(o-r),i=Math.round(n-o),l={...t,firstTokenMs:s,decodeMs:i},a=t.usage?.outputTokens;return typeof a=="number"&&a>0&&i>0&&(l.tps=Math.round(a/i*1e3)),l}function Gn(e,t){if(e==null)return e;if(typeof e=="string")return e.length<=t?e:e.slice(0,t)+`[truncated: ${e.length-t} more bytes]`;let r;try{r=JSON.stringify(e)}catch{return"[unserializable]"}return r.length<=t?e:r.slice(0,t)+`[truncated: ${r.length-t} more bytes]`}function za(e,t){if(!e)return e;let r=e.split(`
|
|
51
|
+
`);return r.length<=t?e:r.slice(0,t).join(`
|
|
52
|
+
`)+`
|
|
53
|
+
... [truncated ${r.length-t} more frames]`}function Ja(e){if(!e||typeof e!="object")return e;let t={},r=!1;for(let[n,o]of Object.entries(e)){let s=Gn(o,Or.attributeValue);s!==o&&(r=!0),t[n]=s}return r?t:e}function Vn(e){let r=e.type===Et.GENERIC?Or.presenterSurface:Or.output,n=Ya(e);return{...e,input:Gn(Xa(e.type,e.input),Or.input),output:Gn(e.output,r),attributes:Ja(n??e.attributes),errorInfo:e.errorInfo?{...e.errorInfo,stack:za(e.errorInfo.stack,qa)}:void 0}}import{setServerSpanSink as Za}from"@tbox.cn/app-sdk-server";var Qa=100,Lr=class{name="tbox-trace";seq=0;correlationByTraceId=new Map;async exportTracingEvent(t){let r=t.exportedSpan;if(r.isInternal||r.type===Xn.MODEL_CHUNK)return;if(t.type!==Wa.SPAN_ENDED){this.resolveCorrelation(r);return}let n=this.resolveCorrelation(r),o=n.conversationId||"no-conv",s=n.requestId||"no-req",i={type:"span.ended",span:Vn(r),requestId:s,conversationId:o,sessionId:n.sessionId,ts:Date.now(),seq:this.seq++};fs(o,s,i),r.isRootSpan&&r.traceId&&this.correlationByTraceId.delete(r.traceId)}emitCustomSpan(t){let r=t.conversationId||"no-conv",n=t.requestId,o={type:"span.ended",span:Vn({id:t.spanId,traceId:t.traceId,name:t.name,type:t.type,parentSpanId:t.parentSpanId,startTime:t.startTime.toISOString(),endTime:t.endTime.toISOString(),metadata:t.metadata,isEvent:!1,isRootSpan:!1,input:t.input,output:t.output,errorInfo:t.errorInfo}),requestId:n,conversationId:r,sessionId:t.sessionId,ts:Date.now(),seq:this.seq++};fs(r,n,o)}emitErrorSpan(t){let r=new Date,n=t.error;this.emitCustomSpan({spanId:`${t.requestId}_error_${this.seq}`,traceId:t.requestId,type:Xn.GENERIC,name:t.name??"error",startTime:r,endTime:r,metadata:t.metadata,errorInfo:{message:n?.message||String(t.error)||"unknown",type:n?.name,stack:n?.stack},requestId:t.requestId,conversationId:t.conversationId,sessionId:t.sessionId})}async flush(){}async shutdown(){}resolveCorrelation(t){let r=el(t),n=t.traceId;if(r.requestId&&n){if(!this.correlationByTraceId.has(n)){if(this.correlationByTraceId.size>=Qa){let o=this.correlationByTraceId.keys().next().value;o!==void 0&&this.correlationByTraceId.delete(o)}this.correlationByTraceId.set(n,r)}return r}return n&&this.correlationByTraceId.has(n)?this.correlationByTraceId.get(n):r}},Pr=new Lr;Za(e=>Pr.emitCustomSpan({...e,type:Xn.GENERIC}));function el(e){let t=e.requestContext;return t?{requestId:typeof t.requestId=="string"?t.requestId:void 0,conversationId:typeof t.conversationId=="string"?t.conversationId:void 0,sessionId:typeof t.threadKey=="string"?t.threadKey:typeof t.sessionId=="string"?t.sessionId:void 0}:{}}function fs(e,t,r){let n=`[TBOX_TRACE:${e}:${t}] ${JSON.stringify(r)}
|
|
54
|
+
`;process.stdout.write(n)}import{createServerLogger as Te,runLogScope as Ri}from"@tbox.cn/app-sdk-server";import{AsyncLocalStorage as cl}from"async_hooks";import{createHash as dl}from"crypto";import{appendFile as ul,mkdir as pl}from"fs/promises";import{dirname as ml,join as Nr}from"path";import{createServerLogger as fl}from"@tbox.cn/app-sdk-server";import{createHash as tl}from"crypto";import{homedir as rl}from"os";import{join as gs}from"path";import{createServerLogger as nl}from"@tbox.cn/app-sdk-server";var ol=nl("LOCALLOG"),sl=14,il=8*1024*1024,al=64*1024;function Yn(e){let t=e.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,64);return!t||/^_+$/.test(t)?tl("sha256").update(e).digest("hex").slice(0,8):t}function ll(e){let t=e.TBOX_LOCAL_LOG,r=!1;if(t!==void 0&&t!==""){let o=t.toLowerCase();o==="on"||o==="1"||o==="true"?r=!0:o!=="off"&&o!=="0"&&o!=="false"&&ol.warn(`非法 TBOX_LOCAL_LOG="${t}"(on|off),使用默认 off`)}let n=e.TBOX_LOCAL_LOG_DIR||e.XDG_DATA_HOME||gs(rl(),".local","share");return{enabled:r,dataRoot:gs(n,"tbox-app"),appId:Yn(e.TBOX_APP_ID??"default"),retentionDays:sl,maxFileBytes:il,maxFieldBytes:al}}var ys;function Ue(){return ys??=ll(process.env),ys}var gl=fl("LOCALLOG"),yl="journal.jsonl";function hs(e=new Date){let t=(r,n=2)=>String(r).padStart(n,"0");return`${e.getFullYear()}${t(e.getMonth()+1)}${t(e.getDate())}-${t(e.getHours())}${t(e.getMinutes())}${t(e.getSeconds())}-${t(e.getMilliseconds(),3)}`}function Ts(e){return dl("sha256").update(e).digest("hex").slice(0,8)}function hl(e,t){let r=t?Nr("conversations",Yn(t)):Nr("_no-conv",new Date().toISOString().slice(0,10));return Nr(e.dataRoot,e.appId,r)}function Tl(e,t){return Buffer.byteLength(e,"utf-8")<=t?e:`${Buffer.from(e,"utf-8").subarray(0,t).toString("utf-8")}[truncated]`}function Sl(e,t){if(typeof e=="string")return JSON.stringify(Tl(e,t));let r;try{r=JSON.stringify(e)}catch{return'"[unserializable]"'}if(r===void 0)return'"[unserializable]"';let n=Buffer.byteLength(r,"utf-8");return n>t?JSON.stringify(`[oversized:${n}] ${r.slice(0,1024)}`):r}function bl(e,t,r,n){let o=[];for(let[i,l]of Object.entries(r))o.push(`${JSON.stringify(i)}:${Sl(l,n)}`);let s=e?`,"run":${JSON.stringify(e)}`:"";return`{"v":1,"ts":${JSON.stringify(new Date().toISOString())}${s},"type":${JSON.stringify(t)},"data":{${o.join(",")}}}`}function Jn(e){if(!e||typeof e!="object")return{};let t=e,r=typeof t.inputTokens=="number"?t.inputTokens:typeof t.prompt_tokens=="number"?t.prompt_tokens:void 0,n=typeof t.outputTokens=="number"?t.outputTokens:typeof t.completion_tokens=="number"?t.completion_tokens:void 0;return{input:r,output:n}}function Il(e){if(!e||typeof e!="object")return;let t=e;if(typeof t.cache_read_input_tokens=="number")return t.cache_read_input_tokens;let r=t.prompt_tokens_details;if(r&&typeof r=="object"){let n=r.cached_tokens;if(typeof n=="number")return n}}var zn=class{calls=0;_firstCallIndex=Number.POSITIVE_INFINITY;_firstTokenMs;_totalMs=0;_decodeMs=0;_inputTokens=0;_outputTokens=0;_hasUsage=!1;_cachedTokens=0;_uncachedTokens=0;_hasCached=!1;add(t){this.calls+=1;let r=typeof t.callIndex=="number"?t.callIndex:Number.NaN,n=typeof t.ttfbMs=="number"?t.ttfbMs:void 0;Number.isFinite(r)&&r<this._firstCallIndex&&n!==void 0&&(this._firstCallIndex=r,this._firstTokenMs=n);let o=typeof t.durationMs=="number"?t.durationMs:0;this._totalMs+=o,n!==void 0&&o>n&&(this._decodeMs+=o-n);let{input:s,output:i}=Jn(t.usage);s!==void 0&&(this._hasUsage=!0,this._inputTokens+=s),i!==void 0&&(this._hasUsage=!0,this._outputTokens+=i);let l=Il(t.usage);l!==void 0&&s!==void 0&&(this._hasCached=!0,this._cachedTokens+=l,this._uncachedTokens+=Math.max(0,s-l))}toSummary(){if(this.calls!==0)return{calls:this.calls,...this._firstTokenMs!==void 0?{firstTokenMs:this._firstTokenMs}:{},totalMs:this._totalMs,...this._decodeMs>0?{decodeMs:this._decodeMs}:{},...this._hasUsage&&this._decodeMs>0&&this._outputTokens>0?{tps:Math.round(this._outputTokens/this._decodeMs*1e3)}:{},...this._hasUsage?{inputTokens:this._inputTokens,outputTokens:this._outputTokens}:{},...this._hasCached?{cachedTokens:this._cachedTokens,uncachedTokens:this._uncachedTokens}:{}}}},Dr=class{dir;runId;conversationId;_path;_chain=Promise.resolve();_disabled=!1;_callIndex=0;_pending=new Set;_toolStarts=new Map;_llmAgg=new zn;constructor(t,r="",n){this.dir=t,this.runId=r,this.conversationId=n,this._path=Nr(t,yl)}emit(t,r,n){if(!this.dir||this._disabled)return;if(t==="tool_call"&&typeof r.toolCallId=="string")this._toolStarts.set(r.toolCallId,Date.now());else if(t==="tool_result"&&typeof r.toolCallId=="string"){let i=this._toolStarts.get(r.toolCallId);this._toolStarts.delete(r.toolCallId),i!==void 0&&(r={...r,durMs:Date.now()-i},n=n??i)}let o=Date.now();r={startedAt:n??o,endedAt:o,...r};let s;try{s=bl(this.runId,t,r,Ue().maxFieldBytes)}catch{return}this._chain=this._chain.then(()=>this._appendLine(s))}llmCall(t,r){this.dir&&(this._llmAgg.add(t),this.emit("llm_call",t,r))}reserveCallIndex(){return this.dir?++this._callIndex:0}addPendingCall(t){this.dir&&(this._pending.add(t),t.then(()=>this._pending.delete(t),()=>this._pending.delete(t)))}async finish(t,r){if(!this.dir)return;for(;this._pending.size>0;)await Promise.allSettled([...this._pending]);let n=this._llmAgg.toSummary();this.emit("run_end",n?{...t,llm:n}:t,r),await this._chain}async _appendLine(t){if(!this._disabled)try{await pl(ml(this._path),{recursive:!0}),await ul(this._path,`${t}
|
|
55
|
+
`,"utf-8")}catch(r){this._disabled=!0,gl.warn(`journal 写失败,本 run 停写:${r?.message??String(r)}`)}}},Wn=Object.freeze(new Dr("","")),xt=new cl;function Zn(e){let t=Ue();if(!t.enabled)return Wn;let r=hl(t,e.conversationId);return new Dr(r,e.runId,e.conversationId)}import{readdir as El,rm as Ss,rmdir as xl,stat as Rl}from"fs/promises";import{join as Rt}from"path";import{createServerLogger as Cl}from"@tbox.cn/app-sdk-server";var wl=Cl("LOCALLOG"),kl=360*60*1e3,Qn=1e4,bs=!1,Is;function eo(){if(bs||!Ue().enabled)return;bs=!0;let e=()=>{Ml().catch(t=>{wl.warn(`retention 扫描失败:${t?.message??String(t)}`)})};e(),Is=setInterval(e,kl),Is.unref()}async function $r(e){try{return await El(e,{withFileTypes:!0})}catch{return[]}}async function Es(e){try{return(await Rl(e)).mtimeMs}catch{return 0}}async function Ml(){let e=Ue();if(e.retentionDays<=0)return;let t=Date.now()-e.retentionDays*864e5,r={examined:0};for(let n of await $r(e.dataRoot))!n.isDirectory()||r.examined>=Qn||await _l(Rt(e.dataRoot,n.name),t,r)}async function _l(e,t,r){let n=Rt(e,"conversations");for(let s of await $r(n)){if(!s.isDirectory()||r.examined>=Qn)continue;r.examined+=1;let i=Rt(n,s.name),l=await $r(i);if(l.length===0){await xl(i).catch(()=>{});continue}let a=0;for(let c of l)r.examined+=1,a=Math.max(a,await Es(Rt(i,c.name)));a<t&&await Ss(i,{recursive:!0,force:!0}).catch(()=>{})}let o=Rt(e,"_no-conv");for(let s of await $r(o)){if(!s.isDirectory()||r.examined>=Qn)continue;r.examined+=1;let i=Rt(o,s.name);await Es(i)<t&&await Ss(i,{recursive:!0,force:!0}).catch(()=>{})}}import{createTool as Al}from"@mastra/core/tools";import{z as Ft}from"zod";var jt="__a2uiFormSubmit",vl=Al({id:jt,description:"[INTERNAL] 系统自动触发的虚拟工具,禁止主动调用。当看到此工具的 result 时,把它视为用户刚刚提交的卡片表单数据,据此继续对话。",inputSchema:Ft.object({surfaceId:Ft.string(),formId:Ft.string()}),outputSchema:Ft.record(Ft.unknown()),execute:async()=>({})});import{CardEmitter as Id}from"@tbox.cn/app-sdk-server";function to(e,t){let r=t.resolve(e.cardType),n=r?.migrate?r.migrate(e.data,e.schemaVersion??1):e.data,o=r?.dataSchema.safeParse(n);return o?.success?{id:e.id,cardType:e.cardType,data:o.data,status:"ready",messageId:e.messageId,schemaVersion:e.schemaVersion,meta:e.meta,isHistory:!0,...r?.project?.(o.data)??{}}:{id:e.id,cardType:e.cardType,data:{},status:"error",error:"卡片数据已不兼容",messageId:e.messageId,schemaVersion:e.schemaVersion,meta:e.meta,isHistory:!0}}function ro(e){return{id:e.id,cardType:e.cardType,data:e.data,status:e.status,schemaVersion:e.schemaVersion??1,messageId:e.messageId,meta:e.meta}}var xs=new Set(["--","?","ZT","ZZ","a's","able","about","above","according","accordingly","across","actually","after","afterwards","again","against","ain't","all","allow","allows","almost","alone","along","already","also","although","always","am","among","amongst","an","and","another","any","anybody","anyhow","anyone","anything","anyway","anyways","anywhere","apart","appear","appreciate","appropriate","are","aren't","around","as","aside","ask","asking","associated","at","available","away","awfully","be","became","because","become","becomes","becoming","been","before","beforehand","behind","being","believe","below","beside","besides","best","better","between","beyond","both","brief","but","by","c'mon","c's","came","can","can't","cannot","cant","cause","causes","certain","certainly","changes","clearly","co","com","come","comes","concerning","consequently","consider","considering","contain","containing","contains","corresponding","could","couldn't","course","currently","definitely","described","despite","did","didn't","different","do","does","doesn't","doing","don't","done","down","downwards","during","each","edu","eg","eight","either","else","elsewhere","enough","entirely","especially","et","etc","even","ever","every","everybody","everyone","everything","everywhere","ex","exactly","example","except","far","few","fifth","first","five","followed","following","follows","for","former","formerly","forth","four","from","further","furthermore","get","gets","getting","given","gives","go","goes","going","gone","got","gotten","greetings","had","hadn't","happens","hardly","has","hasn't","have","haven't","having","he","he's","hello","help","hence","her","here","here's","hereafter","hereby","herein","hereupon","hers","herself","hi","him","himself","his","hither","hopefully","how","howbeit","however","i'd","i'll","i'm","i've","ie","if","ignored","immediate","in","inasmuch","inc","indeed","indicate","indicated","indicates","inner","insofar","instead","into","inward","is","isn't","it","it'd","it'll","it's","its","itself","just","keep","keeps","kept","know","known","knows","last","lately","later","latter","latterly","least","less","lest","let","let's","like","liked","likely","little","look","looking","looks","ltd","mainly","many","may","maybe","me","mean","meanwhile","merely","might","more","moreover","most","mostly","much","must","my","myself","name","namely","nd","near","nearly","necessary","need","needs","neither","never","nevertheless","new","next","nine","no","nobody","non","none","noone","nor","normally","not","nothing","novel","now","nowhere","obviously","of","off","often","oh","ok","okay","old","on","once","one","ones","only","onto","or","other","others","otherwise","ought","our","ours","ourselves","out","outside","over","overall","own","particular","particularly","per","perhaps","placed","please","plus","possible","presumably","probably","provides","que","quite","qv","rather","rd","re","really","reasonably","regarding","regardless","regards","relatively","respectively","right","said","same","saw","say","saying","says","second","secondly","see","seeing","seem","seemed","seeming","seems","seen","self","selves","sensible","sent","serious","seriously","seven","several","shall","she","should","shouldn't","since","six","so","some","somebody","somehow","someone","something","sometime","sometimes","somewhat","somewhere","soon","sorry","specified","specify","specifying","still","sub","such","sup","sure","t's","take","taken","tell","tends","th","than","thank","thanks","thanx","that","that's","thats","the","their","theirs","them","themselves","then","thence","there","there's","thereafter","thereby","therefore","therein","theres","thereupon","these","they","they'd","they'll","they're","they've","think","third","this","thorough","thoroughly","those","though","three","through","throughout","thru","thus","to","together","too","took","toward","towards","tried","tries","truly","try","trying","twice","two","un","under","unfortunately","unless","unlikely","until","unto","up","upon","us","use","used","useful","uses","using","usually","value","various","very","via","viz","vs","want","wants","was","wasn't","way","we","we'd","we'll","we're","we've","welcome","well","went","were","weren't","what","what's","whatever","when","whence","whenever","where","where's","whereafter","whereas","whereby","wherein","whereupon","wherever","whether","which","while","whither","who","who's","whoever","whole","whom","whose","why","will","willing","wish","with","within","without","won't","wonder","would","wouldn't","yes","yet","you","you'd","you'll","you're","you've","your","yours","yourself","yourselves","zero","zt","zz","“","”","》","一","一下","一些","一切","一则","一天","一定","一方面","一旦","一时","一来","一样","一次","一片","一直","一致","一般","一起","一边","一面","万一","上下","上升","上去","上来","上述","上面","下列","下去","下来","下面","不一","不久","不仅","不会","不但","不光","不单","不变","不只","不可","不同","不够","不如","不得","不怕","不惟","不成","不拘","不敢","不断","不是","不比","不然","不特","不独","不管","不能","不要","不论","不足","不过","不问","与","与其","与否","与此同时","专门","且","两者","严格","严重","个","个人","个别","中小","中间","丰富","临","为","为主","为了","为什么","为什麽","为何","为着","主张","主要","举行","乃","乃至","么","之","之一","之前","之后","之後","之所以","之类","乌乎","乎","乘","也","也好","也是","也罢","了","了解","争取","于","于是","于是乎","云云","互相","产生","人们","人家","什么","什么样","什麽","今后","今天","今年","今後","仍然","从","从事","从而","他","他人","他们","他的","代替","以","以上","以下","以为","以便","以免","以前","以及","以后","以外","以後","以来","以至","以至于","以致","们","任","任何","任凭","任务","企图","伟大","似乎","似的","但","但是","何","何况","何处","何时","作为","你","你们","你的","使得","使用","例如","依","依照","依靠","促进","保持","俺","俺们","倘","倘使","倘或","倘然","倘若","假使","假如","假若","做到","像","允许","充分","先后","先後","先生","全部","全面","兮","共同","关于","其","其一","其中","其二","其他","其余","其它","其实","其次","具体","具体地说","具体说来","具有","再者","再说","冒","冲","决定","况且","准备","几","几乎","几时","凭","凭借","出去","出来","出现","分别","则","别","别的","别说","到","前后","前者","前进","前面","加之","加以","加入","加强","十分","即","即令","即使","即便","即或","即若","却不","原来","又","及","及其","及时","及至","双方","反之","反应","反映","反过来","反过来说","取得","受到","变成","另","另一方面","另外","只是","只有","只要","只限","叫","叫做","召开","叮咚","可","可以","可是","可能","可见","各","各个","各人","各位","各地","各种","各级","各自","合理","同","同一","同时","同样","后来","后面","向","向着","吓","吗","否则","吧","吧哒","吱","呀","呃","呕","呗","呜","呜呼","呢","周围","呵","呸","呼哧","咋","和","咚","咦","咱","咱们","咳","哇","哈","哈哈","哉","哎","哎呀","哎哟","哗","哟","哦","哩","哪","哪个","哪些","哪儿","哪天","哪年","哪怕","哪样","哪边","哪里","哼","哼唷","唉","啊","啐","啥","啦","啪达","喂","喏","喔唷","嗡嗡","嗬","嗯","嗳","嘎","嘎登","嘘","嘛","嘻","嘿","因","因为","因此","因而","固然","在","在下","地","坚决","坚持","基本","处理","复杂","多","多少","多数","多次","大力","大多数","大大","大家","大批","大约","大量","失去","她","她们","她的","好的","好象","如","如上所述","如下","如何","如其","如果","如此","如若","存在","宁","宁可","宁愿","宁肯","它","它们","它们的","它的","安全","完全","完成","实现","实际","宣布","容易","密切","对","对于","对应","将","少数","尔后","尚且","尤其","就","就是","就是说","尽","尽管","属于","岂但","左右","巨大","巩固","己","已经","帮助","常常","并","并不","并不是","并且","并没有","广大","广泛","应当","应用","应该","开外","开始","开展","引起","强烈","强调","归","当","当前","当时","当然","当着","形成","彻底","彼","彼此","往","往往","待","後来","後面","得","得出","得到","心里","必然","必要","必须","怎","怎么","怎么办","怎么样","怎样","怎麽","总之","总是","总的来看","总的来说","总的说来","总结","总而言之","恰恰相反","您","意思","愿意","慢说","成为","我","我们","我的","或","或是","或者","战斗","所","所以","所有","所谓","打","扩大","把","抑或","拿","按","按照","换句话说","换言之","据","掌握","接着","接著","故","故此","整个","方便","方面","旁人","无宁","无法","无论","既","既是","既然","时候","明显","明确","是","是不是","是否","是的","显然","显著","普通","普遍","更加","曾经","替","最后","最大","最好","最後","最近","最高","有","有些","有关","有利","有力","有所","有效","有时","有点","有的","有着","有著","望","朝","朝着","本","本着","来","来着","极了","构成","果然","果真","某","某个","某些","根据","根本","欢迎","正在","正如","正常","此","此外","此时","此间","毋宁","每","每个","每天","每年","每当","比","比如","比方","比较","毫不","没有","沿","沿着","注意","深入","清楚","满足","漫说","焉","然则","然后","然後","然而","照","照着","特别是","特殊","特点","现代","现在","甚么","甚而","甚至","用","由","由于","由此可见","的","的话","目前","直到","直接","相似","相信","相反","相同","相对","相对而言","相应","相当","相等","省得","看出","看到","看来","看看","看见","真是","真正","着","着呢","矣","知道","确定","离","积极","移动","突出","突然","立即","第","等","等等","管","紧接着","纵","纵令","纵使","纵然","练习","组成","经","经常","经过","结合","结果","给","绝对","继续","继而","维持","综上所述","罢了","考虑","者","而","而且","而况","而外","而已","而是","而言","联系","能","能否","能够","腾","自","自个儿","自从","自各儿","自家","自己","自身","至","至于","良好","若","若是","若非","范围","莫若","获得","虽","虽则","虽然","虽说","行为","行动","表明","表示","被","要","要不","要不是","要不然","要么","要是","要求","规定","觉得","认为","认真","认识","让","许多","论","设使","设若","该","说明","说说","诸位","谁","谁知","赶","起","起来","起见","趁","趁着","越是","跟","转动","转变","转贴","较","较之","边","达到","迅速","过","过去","过来","运用","还是","还有","这","这个","这么","这么些","这么样","这么点儿","这些","这会儿","这儿","这就是说","这时","这样","这点","这种","这边","这里","这麽","进入","进步","进而","进行","连","连同","适应","适当","适用","逐步","逐渐","通常","通过","造成","遇到","遭到","避免","那","那个","那么","那么些","那么样","那些","那会儿","那儿","那时","那样","那边","那里","那麽","部分","都","鄙人","采取","里面","重大","重新","重要","鉴于","问题","防止","阿","附近","限制","除","除了","除此之外","除非","随","随着","随著","集中","需要","非但","非常","非徒","靠","顺","顺着","首先","高兴","--"]);var Br=new Set(["推荐","帮我","想要","需要","适合","介绍","有什么","怎么","如何","可以","问题","你好"]),Ol=(()=>{let e=new Set;for(let t of Br){e.add(t);for(let r of t)Nl(r)&&e.add(r)}return e})(),Rs=(()=>{let e=new Set;for(let t of Br)for(let r of t)e.add(r);return e})();function Ll(e){return!e.dict&&e.token.length===2&&(Rs.has(e.token[0])||Rs.has(e.token[1]))}var no={name:3,keywords:2,description:1},Cs=1.2,ws=.75,Pl=new Intl.Segmenter("zh",{granularity:"word"});function Nl(e){return/[\u4e00-\u9fff]/.test(e)}function ks(e){let t=(e??"").trim().toLowerCase().replace(/\s+/g," ");if(!t)return[];let r=[],n=new Set,o=(s,i)=>{!n.has(s)&&!xs.has(s)&&(n.add(s),r.push({token:s,dict:i}))};for(let s of Pl.segment(t))s.isWordLike&&o(s.segment,!0);for(let s of t.match(/[\u4e00-\u9fff]+/g)??[])for(let i=0;i<s.length;i++)o(s[i],!1),i+1<s.length&&o(s.slice(i,i+2),!1);return r}function Dl(e){return ks(e).map(t=>t.token)}function Je(e){let t=e.map(i=>{let l=new Map,a=(c,d)=>{for(let p of c)for(let m of ks(p))Ol.has(m.token)||Ll(m)||l.set(m.token,(l.get(m.token)??0)+d)};return a([i.name],no.name),a(i.keywords,no.keywords),a([i.description],no.description),{id:i.id,tf:l,dl:l.size}}),r=t.length,n=new Map;for(let i of t)for(let l of i.tf.keys())n.set(l,(n.get(l)??0)+1);let o=new Map;for(let[i,l]of n)o.set(i,Math.log(1+(r-l+.5)/(l+.5)));let s=r>0?t.reduce((i,l)=>i+l.dl,0)/r:0;return{entries:t,idf:o,avgdl:s,count:r}}function We(e,t){let r=Dl(t);return e.count===0||r.length===0?[]:e.entries.map(n=>{let o=0,s=[];for(let i of r){let l=n.tf.get(i);l&&(s.push(i),o+=(e.idf.get(i)??0)*(l*(Cs+1)/(l+Cs*(1-ws+ws*(n.dl/e.avgdl)))))}return{id:n.id,score:o,matched:s}}).sort((n,o)=>o.score-n.score||(n.id<o.id?-1:1))}function ct(e){return e.some(t=>t.length>=2)||e.length>=2}var $l=new Set(["exact","prefix"]),Ms=new WeakMap;function Bl(e){let t=Ms.get(e);return t||(t=Je(e.filter(r=>r.keywords.length>0&&!$l.has(r.match??"bm25")).map(r=>({id:r.id,name:r.id,description:"",keywords:r.keywords}))),Ms.set(e,t)),t}function Fr(e,t){if(e.length===0||!t)return;let r=t.trim();for(let s of e)if(s.match==="exact"&&s.keywords.some(i=>i===r))return s;for(let s of e)if(s.match==="prefix"&&s.keywords.some(i=>i&&r.startsWith(i)))return s;let n=Bl(e),o=new Map(e.map(s=>[s.id,s]));for(let s of We(n,t))if(ct(s.matched))return o.get(s.id)}function Fl(e,t){return async(r,n,o)=>{let s=Fr(e,r);if(s)return t.dispatch(s.handlerId,s.action,o,n)}}import jl from"gray-matter";import{readdir as _s,readFile as As}from"fs/promises";import we from"path";import{createRequire as Ul}from"module";import{createSkill as Kl}from"@mastra/core/skills";import{SKILL_NAME_PATTERN as Hl}from"@tbox.cn/app-contracts";import{createServerLogger as ql}from"@tbox.cn/app-sdk-server";import{SKILL_LIMITS as Ze}from"@tbox.cn/app-sdk-server";var Ut=ql("SKILL");function ge(e,t){Ut.warn(`${e}: ${t}`)}async function vs(e){let t=[],r;try{r=await _s(e,{withFileTypes:!0})}catch(n){return n.code==="ENOENT"?(Ut.info(`loadLocalSkills: 目录不存在 ${e}(skills 可选),跳过`),t):(ge("SKILL",`loadLocalSkills: 目录不可读 ${e}(${n.message}),返回空`),t)}for(let n of r){if(!n.isDirectory())continue;let o=we.join(e,n.name);try{let s=await Gl(o);s&&t.push(s)}catch(s){ge("SKILL",`加载 skill 目录失败,跳过 ${o}:${s.message}`)}}return t.length>0?Ut.info(`loaded ${t.length} skills from ${e}: ${t.map(n=>n.name).join(", ")}`):Ut.info(`no skills loaded from ${e}`),t}async function Gl(e){let t=we.join(e,"SKILL.md"),r=await As(t,"utf8").catch(g=>{ge("SKILL",`缺少 ${t}(${g.message}),跳过 ${we.basename(e)}`)});if(r===void 0)return;let n=jl(r),o=n.data??{},s=typeof o.name=="string"?o.name:"";if(!Hl.test(s)){ge("SKILL",`非法 skill 名 "${s||"(空)"}"(须匹配 ^[a-z0-9-]{1,64}$),跳过 ${we.basename(e)}`);return}let i=we.basename(e);s!==i&&ge("SKILL",`skill 名 "${s}" 与目录名 "${i}" 不一致(以 frontmatter name 为准)`);let l=typeof o.description=="string"?o.description:"";l?l.length>Ze.description&&ge("SKILL",`skill "${s}" description 超限(${l.length} > ${Ze.description})`):ge("SKILL",`skill "${s}" 缺少 description(accelerated/progressive 均受影响)`);let a=o.metadata??{},d=(Array.isArray(a.routingTerms)?a.routingTerms:Array.isArray(o.routingTerms)?o.routingTerms:[]).filter(g=>typeof g=="string"&&g.length>0).map(g=>g.trim()).filter(g=>g.length>0);d.length===0&&ge("SKILL",`skill "${s}" 无 routingTerms(仅名称/描述参与路由,召回弱)`);let p=n.content.trim();p?p.length>Ze.instructions&&ge("SKILL",`skill "${s}" 正文超限(${p.length} > ${Ze.instructions})`):ge("SKILL",`skill "${s}" 正文为空`);let m=await Os(we.join(e,"references"));return Object.keys(m).length>Ze.references&&ge("SKILL",`skill "${s}" references 数量超限(${Object.keys(m).length} > ${Ze.references})`),{name:s,description:l,routingTerms:d,instructions:p,references:m}}async function Os(e,t=e){let r={},n;try{n=await _s(e,{withFileTypes:!0})}catch{return r}for(let o of n){let s=we.join(e,o.name);if(o.isDirectory()){let l=await Os(s,t);Object.assign(r,l);continue}if(!o.isFile()||!o.name.endsWith(".md"))continue;let i=we.relative(t,s);if(i.startsWith("..")||we.isAbsolute(i)){ge("SKILL",`穿越防护:跳过 ${i}`);continue}try{let l=await As(s,"utf8");l.length>Ze.referenceSize&&ge("SKILL",`reference ${i} 超限(${l.length} > ${Ze.referenceSize}),仍加载`),r[i.split(we.sep).join("/")]=l}catch(l){ge("SKILL",`读取 reference 失败 ${s}:${l.message}`)}}return r}function oo(e){return Kl({name:e.name,description:e.description,instructions:e.instructions,"user-invocable":!1,metadata:{routingTerms:e.routingTerms},...Object.keys(e.references).length>0?{references:e.references}:{}})}async function Vl(e,t){try{let r=we.dirname(Ul(t).resolve(`${e}/package.json`));return await vs(we.join(r,"skills"))}catch(r){let n=r;return Ut.warn(`loadModuleSkills: 无法解析 "${e}/package.json"(${n.code??n.message??String(r)})——检查模块 exports 是否含 "./package.json" 且包已安装,返回空`),[]}}import{EventType as jr}from"@ag-ui/core";import{buildSkillReminderOpenTagPattern as Xl,buildSkillToolCallPayload as Yl,SKILL_TOOL_CALL_NAME as zl}from"@tbox.cn/app-contracts";import{createServerLogger as Jl}from"@tbox.cn/app-sdk-server";var Wl=Jl("SKILL"),Kt="accelerated";function Zl(e){return e==="accelerated"||e==="progressive"?e:(e!==void 0&&e!==""&&Wl.warn(`非法 TBOX_SKILL_MODE="${e}"(accelerated|progressive),使用默认 ${Kt}`),Kt)}var Ls=new WeakMap;function Ql(e){let t=Ls.get(e);return t||(t=Je(e.map(r=>({id:r.name,name:r.name,description:r.description,keywords:r.routingTerms}))),Ls.set(e,t)),t}function Ps(e,t){if(t.length===0||!e)return[];let r=Ql(t),n=new Map(t.map(o=>[o.name,o]));return We(r,e).map(o=>{let s=n.get(o.id);return s?{skill:s,score:o.score,matched:o.matched}:void 0}).filter(o=>o!==void 0)}function ec(e,t){return Ps(e,t).find(r=>ct(r.matched))?.skill}function tc(){return Xl()}function Ns(e){let t=new Set;for(let r of e){if(r.role!=="user")continue;let n=typeof r.content=="string"?[{type:"text",text:r.content}]:r.content;for(let o of n){if(o.type!=="text"||typeof o.text!="string")continue;let s=tc(),i;for(;(i=s.exec(o.text))!==null;)t.add(i[1])}}return t}function Ur(e){let t=Object.entries(e.references).map(([n,o])=>`## reference: ${n}
|
|
56
|
+
${o}`).join(`
|
|
57
|
+
|
|
58
|
+
`),r=t?`${e.instructions}
|
|
59
|
+
|
|
60
|
+
${t}`:e.instructions;return`<system-reminder skill="${e.name}">
|
|
61
|
+
${r}
|
|
62
|
+
</system-reminder>`}function Kr(e){let{text:t,history:r,skills:n}=e,o=Ns(r),i=Ps(t,n).find(l=>ct(l.matched));return i?o.has(i.skill.name)?{action:"duplicate",skill:i.skill}:{action:"injected",skill:i.skill}:{action:"none"}}function Ds(e,t){return[{type:"text",text:e},...typeof t=="string"?[{type:"text",text:t}]:t]}function $s(e,t){return Ds(Ur(e),t)}var rc=`(本技能完整规则已注入会话历史;以下会话级约束不随注入去重失效,每轮持续有效。)
|
|
63
|
+
历史轮的工具结果不会在本轮出现:用户重问、继续追问或需要新的数据时,必须在本轮重新调用工具获取。`;function Hr(e){return`<system-reminder skill="${e.name}">
|
|
64
|
+
${rc}
|
|
65
|
+
</system-reminder>`}function Bs(e,t){return Ds(Hr(e),t)}function nc(e){let{text:t,userContent:r,history:n,skills:o}=e,s=Kr({text:t,history:n,skills:o});return s.action==="injected"?$s(s.skill,r):s.action==="duplicate"?Bs(s.skill,r):r}function so(e,t,r){let{args:n,result:o}=Yl(e);return[{type:jr.TOOL_CALL_START,toolCallId:t,toolCallName:zl},{type:jr.TOOL_CALL_ARGS,toolCallId:t,delta:n},{type:jr.TOOL_CALL_END,toolCallId:t},{type:jr.TOOL_CALL_RESULT,toolCallId:t,messageId:r,content:o}]}import{EventType as Gr}from"@ag-ui/core";import{noopObserve as oc}from"@mastra/core/tools";import{buildPreToolArgsPayload as sc,buildPreToolResultPayload as ic,PRE_TOOL_CALL_NAME as ac}from"@tbox.cn/app-contracts";import{createServerLogger as lc}from"@tbox.cn/app-sdk-server";var qr=lc("PRETOOL"),Us=20,Ct=2e3,Ks=5,Vr=class extends Error{constructor(){super("pre-tool deadline exceeded"),this.name="PreToolTimeoutError"}};function cc(e){if(e===void 0||e==="")return Ct;let t=Number(e);return!Number.isInteger(t)||t<0?(qr.warn(`非法 TBOX_PRE_TOOL_TIMEOUT_MS="${e}"(非负整数;0 = 禁用),使用默认 ${Ct}`),Ct):t}function io(e){let t=new WeakSet,r=n=>{if(n===void 0)return;if(n===null||typeof n!="object")return n;if(t.has(n))return"[Circular]";if(t.add(n),Array.isArray(n))return n.map(r);let o={};for(let s of Object.keys(n).sort()){let i=r(n[s]);i!==void 0&&(o[s]=i)}return o};return JSON.stringify(r(e))??"null"}function dc(e,t){return{tool:e,...t}}var Fs=new WeakMap;function uc(e){let t=Fs.get(e);if(!t){let r=[];for(let n of e){let o=n?.tool?.id;if(!o||n.routing?.mode!=="keywords")continue;let i=n.routing?.terms;!i||i.length===0||r.push({id:o,name:o,description:"",keywords:i})}t=Je(r),Fs.set(e,t)}return t}function ao(e,t){if(t.length===0||!e)return[];let r=[];for(let i of t){let l=i?.tool?.id;if(!l){qr.warn("跳过无 tool.id 的 pre-tool 声明(须经 definePreTool 构造并引用工具实例)");continue}let a=i.routing?.mode;if(a==="always")r.push({def:i,score:0,always:!0});else if(a==="keywords"){let c=i.routing?.terms;if(!c||c.length===0){qr.warn(`跳过空 terms 的 keywords pre-tool: ${l}`);continue}}else{qr.warn(`跳过非法/旧形态 routing 的 pre-tool: ${l}(须经 definePreTool 构造)`);continue}}let n=new Map;for(let i of t){let l=i?.tool?.id;l&&n.set(l,i)}for(let i of We(uc(t),e)){if(i.score<=0)continue;let l=n.get(i.id);l&&l.routing?.mode!=="always"&&ct(i.matched)&&r.push({def:l,score:i.score,always:!1})}let o=new Map;for(let i of r){let l=o.get(i.def.tool.id);(!l||i.always&&!l.always||i.always===l.always&&i.score>l.score)&&o.set(i.def.tool.id,i)}let s=[...o.values()];return s.sort((i,l)=>(i.always?0:1)-(l.always?0:1)||l.score-i.score||i.def.tool.id.localeCompare(l.def.tool.id)),s.slice(0,Ks).map(i=>i.def)}function Xr(e){let t=[];for(let r of e.slice(-Us)){if(r.role!=="user"&&r.role!=="assistant")continue;let n;typeof r.content=="string"?n=r.content:n=(Array.isArray(r.content)?r.content:[]).filter(s=>s.type==="text").map(s=>s.text).join(`
|
|
66
|
+
`),n&&t.push({role:r.role,content:n})}return t}function js(e){try{return JSON.stringify(e??{}).replace(/</g,"\\u003c")}catch{return"{}"}}function lo(e){return e.map(t=>{let r=js(t.args??{}),n=js(t.result??{});return[`<system-reminder pre-tool="${t.toolName}">`,`<input>${r}</input>`,`<output>${n}</output>`,"</system-reminder>"].join(`
|
|
67
|
+
`)})}function co(e){return[{type:Gr.TOOL_CALL_START,toolCallId:e.toolCallId,toolCallName:ac},{type:Gr.TOOL_CALL_ARGS,toolCallId:e.toolCallId,delta:sc({toolName:e.toolName,...e.description?{description:e.description}:{},...e.toolArgs!==void 0?{toolArgs:e.toolArgs}:{}})}]}function Yr(e){return[{type:Gr.TOOL_CALL_END,toolCallId:e.toolCallId},{type:Gr.TOOL_CALL_RESULT,toolCallId:e.toolCallId,messageId:e.messageId,content:ic({toolName:e.toolName,status:e.status,...e.result!==void 0?{result:e.result}:{},...e.error?{error:e.error}:{}})}]}function Ht(e,t){if(e<=0)return t();let r;return new Promise((n,o)=>{let s=!1;r=setTimeout(()=>{s||(s=!0,o(new Vr))},e),t().then(i=>{s||(s=!0,n(i))},i=>{s||(s=!0,o(i))})}).finally(()=>{clearTimeout(r)})}async function uo(e,t,r){let n=e.execute;if(typeof n!="function")throw new Error(`pre-tool "${e.id}" has no execute function`);let o=await n.call(e,t,{requestContext:r.requestContext,observe:r.observe??oc,abortSignal:r.abortSignal});return JSON.parse(JSON.stringify(o))}var pc="[已展示相关卡片]",mc=String.raw`[||]{1,2}dsml[||]{1,2}`,fc=/<\/?([a-z0-9_-]*cards[a-z0-9_-]*)\b[^>]*>/gi,gc=/<system-reminder\b[^>]*>/gi;function qs(...e){let t=0,r=0,n=[],o=0;for(let s of e){t+=(s.match(new RegExp(mc,"gi"))??[]).length,o+=s.split(pc).length-1,r+=(s.match(gc)??[]).length;for(let i of s.matchAll(fc))(i[1]??"").toLowerCase()!==z&&n.push(i[0])}return{dsmlResidue:t,tagDrift:n,placeholderImitation:o,reminderEcho:r}}var yc=/<\/?(think|thinking|thought)\b[^>]*>/gi,hc=/<\/?tool[_-]?calls?\b[^>]*>/gi,Tc=/[||]{1,2}tool[▁_]?calls?[▁_]?(begin|end)[||]{1,2}/gi,Sc=/<\/?([a-zA-Z0-9_-]+)/,Hs=e=>(e.match(Sc)?.[1]??"").toLowerCase();function Gs(e,t){let r=new Set(t.map(s=>s.toLowerCase())),n=0,o=0;for(let s of e){for(let i of s.matchAll(yc))r.has(Hs(i[0]))||(n+=1);for(let i of s.matchAll(hc))r.has(Hs(i[0]))||(o+=1);for(let i of s.matchAll(Tc)){let l=i[0].replace(/|/g,"|").replace(/▁/g,"_").toLowerCase();l!=="<|tool_calls_begin|>"&&l!=="<|tool_calls_end|>"&&(o+=1)}}return{thinkResidue:n,toolCallResidue:o}}import{readFileSync as bc}from"fs";import{resolve as Ic}from"path";import{expandEnvVars as Ec}from"@tbox.cn/app-sdk-server";import{assertNoInlineSecrets as xc}from"@tbox.cn/app-contracts";import{createServerLogger as Rc}from"@tbox.cn/app-sdk-server";var Cc=Rc("llm-provider-config"),qt=Ic(process.cwd(),"../../config/llm_provider.json"),Vs=new Set;function ye(e,t){Vs.has(e)||(Vs.add(e),Cc.warn(t))}function wc(e){return typeof e=="boolean"||e==="auto"||e!==null&&typeof e=="object"&&!Array.isArray(e)}function kc(e){return e===!0||e===!1||e==="auto"}var Mc=new Set(["think","tool-call-text"]),Xs=/^[a-zA-Z][a-zA-Z0-9_-]{0,31}$/,Ys=16;function _c(e,t){let r={};if(e.off!==void 0)if(Array.isArray(e.off)&&e.off.every(n=>typeof n=="string")){let n=[];for(let o of e.off){if(!Mc.has(o)){ye(`contentTagHygiene.off:${t}`,`contentTagHygiene.off 未知族 "${o}"(仅 think | tool-call-text)——忽略该条`);continue}n.includes(o)||n.push(o)}n.length>0&&(r.off=n)}else ye(`contentTagHygiene.off:${t}`,"contentTagHygiene.off 非法(string[],族名)——忽略");if(e.extraTags!==void 0)if(Array.isArray(e.extraTags)){let n=[],o=new Set([...bt.think,...bt["tool-call-text"]].map(s=>s.toLowerCase()));for(let s of e.extraTags){if(n.length>=Ys){ye(`contentTagHygiene.extraTags:${t}`,`extraTags 超 ${Ys} 上限——截断`);break}let i=s;if(typeof i?.name!="string"||!Xs.test(i.name)){ye(`contentTagHygiene.extraTags:${t}`,`extraTags.name 非法(须匹配 ${Xs.source})——忽略该条`);continue}if(i.family!=="think"&&i.family!=="tool-call-text"){ye(`contentTagHygiene.extraTags:${t}`,"extraTags.family 非法(仅 think | tool-call-text;cards 为协议族不可经 config 注入)——忽略该条");continue}let l=i.name.toLowerCase();if(o.has(l)){ye(`contentTagHygiene.extraTags:${t}`,`extraTags "${i.name}" 与内建/先见条目重名——忽略该条`);continue}o.add(l),n.push({name:i.name,family:i.family})}n.length>0&&(r.extraTags=n)}else ye(`contentTagHygiene.extraTags:${t}`,"contentTagHygiene.extraTags 非法(array)——忽略");return r}function Gt(e){let t;try{t=JSON.parse(Ec(bc(e,"utf-8"),process.env,e))}catch(o){return o.code!=="ENOENT"&&ye(`parse:${e}`,`llm_provider.json 解析失败(${o.message},文件:${e})——忽略文件配置`),{}}try{xc(t)}catch(o){throw new Error(`${e}: ${o.message}`)}let r=t??{},n={};if(typeof r.modelName=="string"&&r.modelName.length>0?n.modelName=r.modelName:"modelName"in r&&ye(`modelName:${e}`,"modelName 非法(须非空 string)——忽略"),wc(r.thinking)?n.thinking=r.thinking:"thinking"in r&&ye(`thinking:${e}`,'thinking 非法(boolean | "auto" | object)——忽略,落默认关闭'),kc(r.parallelToolCalls)?n.parallelToolCalls=r.parallelToolCalls:"parallelToolCalls"in r&&ye(`parallelToolCalls:${e}`,'parallelToolCalls 非法(boolean | "auto")——忽略,落默认 auto(不注入)'),r.contentTagHygiene!==null&&typeof r.contentTagHygiene=="object"&&!Array.isArray(r.contentTagHygiene)){let o=_c(r.contentTagHygiene,e);(o.off!==void 0||o.extraTags!==void 0)&&(n.contentTagHygiene=o)}else"contentTagHygiene"in r&&ye(`contentTagHygiene:${e}`,"contentTagHygiene 非法(object)——忽略,落默认双族全开");return n}function po(e){let t=Gt(e).contentTagHygiene,r=new Set(t?.off??[]),n=[],o=[];r.has("think")||(n.push(...vn),o.push(...bt.think)),r.has("tool-call-text")||(n.push(...On),o.push(...bt["tool-call-text"]));for(let s of t?.extraTags??[])n.push({...St(s.family,s.name),source:"extra"}),o.push(s.name.toLowerCase());return{specs:n,activeNames:o}}function Ac(e){if(e===void 0||e.trim()==="")return;let t=e.trim().toLowerCase();if(t==="true")return!0;if(t==="false")return!1;if(t==="auto")return"auto";ye("env:APP_AI_THINKING",`APP_AI_THINKING 非法值 "${e}"(仅 true|false|auto)——忽略`)}function zs(e){let t=Gt(e).thinking;if(t!==void 0)return t;let r=Ac(process.env.APP_AI_THINKING);return r!==void 0?r:!1}function vc(e){if(e===void 0||e.trim()==="")return;let t=e.trim().toLowerCase();if(t==="true")return!0;if(t==="false")return!1;if(t==="auto")return"auto";ye("env:APP_AI_PARALLEL_TOOL_CALLS",`APP_AI_PARALLEL_TOOL_CALLS 非法值 "${e}"(仅 true|false|auto)——忽略`)}function Js(e){let t=Gt(e).parallelToolCalls;if(t!==void 0)return t;let r=vc(process.env.APP_AI_PARALLEL_TOOL_CALLS);return r!==void 0?r:"auto"}import{AsyncLocalStorage as Oc}from"async_hooks";var Ke=new Oc,Ws=900;function Lc(e){if(!e)return;let t="";for(let r of e)if(/[A-Za-z0-9._-]/.test(r))t+=r;else{let n=r.codePointAt(0);if(n===void 0)continue;t+=`_x${n.toString(16)}`}if(t)return t.length>Ws?t.slice(0,Ws):t}function Zs(e){let t=Lc(e);t&&Ke.enterWith(t)}function zr(e,t){return async(r,n)=>{let o=t(),s=Object.keys(o);if(s.length===0)return e(r,n);if(r instanceof Request)try{let l=new Headers(r.headers);for(let a of s)l.set(a,o[a]);return e(new Request(r,{headers:l}),n)}catch{return e(r,n)}let i=new Headers(n?.headers);for(let l of s)i.set(l,o[l]);return e(r,{...n,headers:i})}}import{randomUUID as Pc}from"crypto";import{createHash as Nc}from"crypto";import{createServerLogger as Dc}from"@tbox.cn/app-sdk-server";var $c=Dc("MEMORY:STORE"),dt={preference:.7,fact:.7,episode:.6},Vt=200,Xt=50,Yt=200;function xe(e){if(!e)return"";let t=Object.keys(e).filter(r=>e[r]!==void 0).sort();return t.length===0?"":t.map(r=>`${Qs(r)}:${Qs(String(e[r]))}`).join("|")}function Qs(e){return e.replace(/\\/g,"\\\\").replace(/\|/g,"\\|").replace(/:/g,"\\:")}function ei(e){if(e==="")return;let t={},r="",n="",o=!1,s=0;for(;s<e.length;){let i=e[s];if(i==="\\"){let l=e[s+1];if(l==="\\"||l==="|"||l===":"){o?n+=l:r+=l,s+=2;continue}return}if(i===":"){if(o)return;o=!0,s++;continue}if(i==="|"){if(!o||r==="")return;t[r]=n,r="",n="",o=!1,s++;continue}o?n+=i:r+=i,s++}if(o){if(r==="")return;t[r]=n}else if(r!=="")return;return Object.keys(t).length>0?t:void 0}function zt(e){return Nc("sha256").update(e.trim().toLowerCase()).digest("hex").slice(0,16)}function Jt(){return`mem_${Pc().replace(/-/g,"").slice(0,8)}`}function mo(e,t){return`${e}\0${t}`}function Jr(e){return{id:e.id,userId:e.userId,kind:e.kind,content:e.content,...e.scope?{scope:{...e.scope}}:{},importance:e.importance,createdAt:e.createdAt}}function wt(e=Date.now){let t=new Map,r=new Map;function n(s,i){return r.get(mo(s,i))??new Set}function o(s){if(s.size<=Vt)return;let i;for(let l of s){let a=t.get(l);a&&(!i||a.importance<i.importance||a.importance===i.importance&&a.createdAt<i.createdAt)&&(i=a)}i&&(s.delete(i.id),t.delete(i.id),$c.debug(`evict ${i.id}(容量淘汰)`))}return{async save(s){let i=s.content.trim(),l=zt(i),a=xe(s.scope),c=mo(s.userId,a),d=r.get(c);d||(d=new Set,r.set(c,d));for(let m of d){let g=t.get(m);if(g&&g.contentHash===l){let C=Math.max(g.importance,dt[s.kind]);return C!==g.importance&&(g.importance=C),Jr(g)}}let p={id:Jt(),userId:s.userId,kind:s.kind,content:i,...s.scope?{scope:{...s.scope}}:{},importance:dt[s.kind],createdAt:e(),contentHash:l,scopeKey:a};return t.set(p.id,p),d.add(p.id),o(d),Jr(p)},async search(s){let i=n(s.userId,xe(s.scope));if(i.size===0||!s.query.trim())return[];let l=[],a=new Map;for(let m of i){let g=t.get(m);g&&(a.set(m,g),l.push({id:m,name:g.content.slice(0,32),description:g.content,keywords:[]}))}let c=Je(l),d=We(c,s.query),p=s.topK??5;return d.filter(m=>m.score>0).slice(0,Math.max(1,p)).map(m=>{let g=a.get(m.id);return Jr(g)})},async list(s){let i=n(s.userId,xe(s.scope)),l=Math.min(Math.max(1,s.limit??Xt),Yt),a=[];for(let c of i){let d=t.get(c);d&&a.push(d)}return a.sort((c,d)=>d.importance-c.importance||d.createdAt-c.createdAt),a.slice(0,l).map(Jr)},async delete(s){let i=t.get(s.id);return!i||i.userId!==s.userId||i.scopeKey!==xe(s.scope)?!1:(t.delete(s.id),r.get(mo(i.userId,i.scopeKey))?.delete(s.id),!0)}}}import{buildMemoryToolCallPayload as Hc,MEMORY_TOOL_CALL_NAME as qc,MEMORY_REMINDER_ATTR as Gc}from"@tbox.cn/app-contracts";import{EventType as en}from"@ag-ui/core";import{createServerLogger as Vc}from"@tbox.cn/app-sdk-server";var fo=6e4,go=1e4,Wr=class extends Map{constructor(r){super();this.max=r}max;touch(r){let n=super.get(r);return n!==void 0&&(super.delete(r),super.set(r,n)),n}setBounded(r,n){for(super.has(r)&&super.delete(r),super.set(r,n);this.size>this.max;){let o=super.keys().next().value;if(o===void 0)break;super.delete(o)}}},ti=new WeakMap;function Zr(e){return ti.get(e)?.last??"miss"}function ri(e,t){let r=t?.listTtlMs??fo,n=t?.maxEntries??go,o={last:"miss"},s=(d,p)=>`${d}\0${xe(p)}`,i=new Wr(n),l=new Wr(n);function a(d,p){let m=s(d,p);i.delete(m),l.delete(m)}let c={save:async d=>{let p=await e.save(d);return a(d.userId,d.scope),p},search:async d=>{let p=s(d.userId,d.scope),m=l.touch(p);if(m!==void 0&&Date.now()-m<r)return o.last="negative",[];let g=await e.search(d);return o.last="miss",g},list:async d=>{let p=s(d.userId,d.scope),m=i.touch(p);if(m&&Date.now()-m.at<r)return o.last=m.records.length===0?"negative":"hit",m.records;let g=await e.list(d);return i.setBounded(p,{records:g,at:Date.now()}),g.length===0&&l.setBounded(p,Date.now()),o.last=g.length===0?"negative":"miss",g},delete:async d=>{let p=await e.delete(d);return p&&a(d.userId,d.scope),p},get capabilities(){return e.capabilities}};return ti.set(c,o),c}function Bc(e){return e.replace(/[0-9]/g,t=>String.fromCharCode(t.charCodeAt(0)-65248)).replace(/[x]/g,"x").replace(/[X]/g,"X").replace(/[\u3000\u00a0]/g," ")}var Fc=/[\dxX]{10,}|[\dxX]+(?:[ \-]{1,3}[\dxX]+)+/g;function jc(e){let t=[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2],r=["1","0","X","9","8","7","6","5","4","3","2"],n=0;for(let o=0;o<17;o++)n+=Number(e[o])*t[o];return r[n%11]}function Uc(e){let t=0,r=!1;for(let n=e.length-1;n>=0;n--){let o=Number(e[n]);r&&(o*=2,o>9&&(o-=9)),t+=o,r=!r}return t%10===0}var Kc=[{type:"id-card",label:"身份证号",test:e=>/^\d{6}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dxX]$/.test(e)&&e[17].toUpperCase()===jc(e.slice(0,17))},{type:"mobile",label:"手机号",test:e=>/^(?:86)?1[3-9]\d{9}$/.test(e)},{type:"bank-card",label:"银行卡号",test:e=>/^\d{16,19}$/.test(e)&&Uc(e)}];function Qr(e){for(let t of Bc(e).matchAll(Fc)){let r=t[0].replace(/[ \-]/g,"");for(let n of Kc)if(n.test(r))return{type:n.type,label:n.label}}}var ni=Vc("MEMORY"),tn=5,Wt=200;function kt(e){return e===void 0?tn:Number.isFinite(e)?Math.max(1,Math.floor(e)):tn}function Zt(e){return e===void 0?Wt:Number.isFinite(e)?Math.max(20,Math.floor(e)):Wt}function Qe(e){return e.capabilities??{save:!0,search:!0,list:!0,delete:!0}}function rn(e){return{store:e.store,...e.resolveScope?{resolveScope:e.resolveScope}:{},topK:kt(e.topK),maxCharsPerRecord:Zt(e.maxCharsPerRecord),caps:Qe(e.store),mode:e.mode??"inmemory"}}async function Qt(e,t){let r=t.store,n=Qe(r),o=kt(t.topK),s=n.search,i=n.list,l=Symbol("skipped");if(!s&&!i)return{records:[],halves:{search:{status:"skipped",durMs:0},list:{status:"skipped",durMs:0}},cache:"miss"};let a={status:"skipped",durMs:0},c={status:"skipped",durMs:0},d=async(U,D,O)=>{if(!U)return l;let H=Date.now();try{let j=await O();return D.status="ok",D.durMs=Date.now()-H,j}catch(j){throw D.status="failed",D.durMs=Date.now()-H,j}},[p,m]=await Promise.allSettled([d(s,a,()=>r.search({userId:e.userId,...e.scope?{scope:e.scope}:{},query:e.query,topK:Math.ceil(o/2)})),d(i,c,()=>r.list({userId:e.userId,...e.scope?{scope:e.scope}:{},limit:o}))]),g=p.status==="fulfilled"&&p.value!==l?p.value:[];p.status==="rejected"&&ni.warn(`search 半失败(降级跳过):${p.reason?.message}`);let C=m.status==="fulfilled"&&m.value!==l?m.value:[];m.status==="rejected"&&ni.warn(`list 半失败(降级跳过):${m.reason?.message}`);let v=s&&p.status==="fulfilled",P=i&&m.status==="fulfilled",F=Zr(r);return v&&!P?{records:yo(g,o),halves:{search:a,list:c},cache:F}:!v&&P?{records:yo(C,o),halves:{search:a,list:c},cache:F}:{records:yo([...g,...C],o),halves:{search:a,list:c},cache:F}}function yo(e,t){let r=new Set,n=[];for(let o of e)if(!r.has(o.id)&&(r.add(o.id),n.push(o),n.length>=t))break;return n}function er(e,t=Wt){if(e.length===0)return"";let r=e.map(n=>{let o=n.content.length>t?`${n.content.slice(0,t)}…`:n.content,s=new Date(n.createdAt),i=String(s.getMonth()+1).padStart(2,"0"),l=String(s.getDate()).padStart(2,"0");return`- (${oi(n.id)}) [${n.kind}] ${oi(o)}(${i}-${l})`});return[`<system-reminder ${Gc}>`,"[背景数据:基于对用户的长期了解检索到的记忆,非本轮用户输入]","",...r,"</system-reminder>"].join(`
|
|
68
|
+
`)}function oi(e){return e.replace(/</g,"\\u003c")}function Mt(e){let t=e.records?.map(o=>{let s=Qr(o.content);return s?{...o,content:`[已脱敏:检测到${s.label}]`}:o}),{args:r,result:n}=Hc({query:e.query,status:e.status,...t?{records:t}:{},...e.reason?{reason:e.reason}:{},...e.error?{error:e.error}:{},...e.durMs!==void 0?{durMs:e.durMs}:{}});return[{type:en.TOOL_CALL_START,toolCallId:e.toolCallId,toolCallName:qc},{type:en.TOOL_CALL_ARGS,toolCallId:e.toolCallId,delta:r},{type:en.TOOL_CALL_END,toolCallId:e.toolCallId},{type:en.TOOL_CALL_RESULT,toolCallId:e.toolCallId,messageId:e.messageId,content:n}]}import{createTool as ho}from"@mastra/core/tools";import{z as ut}from"zod";import{createServerLogger as Xc}from"@tbox.cn/app-sdk-server";var tr=Xc("MEMORY:TOOLS"),Yc=ut.object({kind:ut.enum(["preference","fact","episode"]),content:ut.string()});function nn(e){let t=Zt(e.maxCharsPerRecord);function r(o){let s=o?.requestContext;if(!s||typeof s.get!="function")return{identity:void 0,scope:void 0};let i=s.get("identity"),l=s.get("attributes"),a=e.resolveScope?e.resolveScope(l??{}):void 0;return{identity:i,scope:a}}let n={};return e.caps.save&&(n.memory_save=ho({id:"memory_save",description:"保存一条用户长期记忆(跨会话保留)。kind:preference=稳定偏好(口味/习惯/忌口),fact=客观事实(车牌/职业),episode=事件经历(去过哪/做过什么)。仅保存明确、稳定、将来有用的信息;闲聊、临时问题、不确定的内容不要保存。身份证号、手机号、银行卡号等敏感个人信息一律不保存。",inputSchema:Yc,execute:async(o,s)=>{let{identity:i,scope:l}=r(s);if(!i||i.source==="anonymous")return{saved:!1,error:"匿名会话无长期记忆"};let a=(o.content??"").trim();if(!a)return{saved:!1,error:"content 为空,未保存"};let c=Qr(a);if(c)return tr.warn(`save 拒绝:敏感信息 type=${c.type}`),{saved:!1,error:`已拒绝保存:出于隐私保护,${c.label}等敏感个人信息不做长期记忆;请向用户说明该信息未保存,不要变换该敏感信息的格式重试。`};if(a.length>t)return{saved:!1,error:`content 超长(${a.length} 字符),请精炼至 ${t} 字以内`};try{let d=await e.store.save({userId:i.userId,...l?{scope:l}:{},kind:o.kind,content:a});return tr.info(`save ${d.id} kind=${d.kind}`),{saved:!0,id:d.id}}catch(d){return tr.warn("save 失败:",d?.message),{saved:!1,error:"记忆服务暂不可用,本轮未保存"}}}})),e.caps.search&&(n.memory_search=ho({id:"memory_search",description:"按关键词检索当前用户的长期记忆(偏好/事实/经历)。用于回答「我的XX是什么」类问题,或确认某信息是否已记录。",inputSchema:ut.object({query:ut.string()}),execute:async(o,s)=>{let{identity:i,scope:l}=r(s);if(!i||i.source==="anonymous")return{records:[],error:"匿名会话无长期记忆"};try{return{records:(await e.store.search({userId:i.userId,...l?{scope:l}:{},query:o.query,topK:kt()})).map(c=>({id:c.id,kind:c.kind,content:c.content,createdAt:c.createdAt}))}}catch(a){return tr.warn("search 失败:",a?.message),{records:[],error:"记忆检索暂不可用"}}}})),e.caps.delete&&(n.memory_forget=ho({id:"memory_forget",description:"删除一条长期记忆(用户明确要求「忘记/删掉这条记忆」时使用)。id 只能取本轮上下文中出现的记忆 id(注入块 `(id)` 或 memory_search 结果),不得编造。",inputSchema:ut.object({id:ut.string()}),execute:async(o,s)=>{let{identity:i,scope:l}=r(s);if(!i||i.source==="anonymous")return{deleted:!1,error:"匿名会话无长期记忆"};try{return{deleted:await e.store.delete({userId:i.userId,...l?{scope:l}:{},id:o.id})}}catch(a){return tr.warn("forget 失败:",a?.message),{deleted:!1,error:"记忆删除暂不可用"}}}})),n}import{MEMORY_ERROR_CODES as on}from"@tbox.cn/app-contracts";import{createServerLogger as od}from"@tbox.cn/app-sdk-server";import{createServerLogger as zc}from"@tbox.cn/app-sdk-server";var Jc=zc("KB-TRANSPORT"),So="https://o.tbox.cn",et="__global__",si=[1e3,2e3,4e3,8e3],Wc=200,Zc=[{field:"importance",order:"desc"},{field:"createdAt",order:"desc"}],Qc={retrieve:{retries:1,timeoutMs:1e4},addSegment:{retries:2,timeoutMs:15e3},deleteSegment:{retries:2,timeoutMs:15e3},batchDeleteSegmentByDocument:{retries:2,timeoutMs:15e3},createKnowledgeBaseByDataSet:{retries:5,timeoutMs:6e4},pageQueryKnowledgeBase:{retries:2,timeoutMs:15e3},queryKnowledgeBase:{retries:2,timeoutMs:15e3},queryDocument:{retries:2,timeoutMs:15e3}},To=e=>/not exist|不存在/i.test(String(e.msg??e.errorMsg??"")),he=class extends Error{constructor(r,n){super(n??`${r.code??`HTTP_${r.httpStatus}`}: ${r.msg??""} traceId=${r.traceId??"-"}`);this.detail=r;this.name="KnowledgeOpenapiError"}detail},He=e=>`/openapi/v1/knowledge/${e}`,ed=e=>new Promise(t=>setTimeout(t,e));function ii(e){return e.map(({column:t,value:r})=>({retrievedColumnName:t,relationship:"EQUAL",expressionRelationship:"AND",values:{value:String(r)}}))}function td(e){return e.map(({field:t,order:r})=>({field:t,order:r.toUpperCase()}))}function rd(e){return Math.min(Math.max(1,e),Wc)}function ai(e){if(!e||typeof e!="object")return;let t=e;if(!(typeof t.content!="string"||typeof t.segmentId!="string"||!t.segmentId))return{content:t.content,segmentId:t.segmentId}}async function nd(e){let t=e.policy.retries+1,r=`${e.base.url}${e.path}`;for(let n=1;n<=t;n++){let o,s=!1;try{let i=await e.fetchImpl(r,{method:"POST",headers:e.body!==void 0?{...e.base.headers,"Content-Type":"application/json"}:e.base.headers,body:e.form??(e.body!==void 0?JSON.stringify(e.body):void 0),signal:AbortSignal.timeout(e.policy.timeoutMs)}),l=await i.text(),a;try{a=JSON.parse(l)}catch{throw new he({code:null,msg:`非 JSON 响应(http ${i.status}): ${l.slice(0,120)}`,traceId:null,httpStatus:i.status})}if(a.success===!0)return a.result??a.data??null;let c={code:a.code??a.errorCode??null,msg:a.msg??a.errorMsg??null,traceId:a.traceId??a.trace??null,httpStatus:i.status};if(o=new he(c),e.isTerminal?.(a)||c.code==="PARAM_IS_NULL"||c.code==="PARAM_INVALID")throw o;s=!0}catch(i){if(i instanceof he)throw i;o=new he({code:null,msg:i?.message??String(i),traceId:null,httpStatus:null}),s=!0}if(!s||n===t)throw o;Jc.warn(`[KB-TRANSPORT] ${e.opLabel} 第${n}次失败 code=${o.detail.code} msg=${o.detail.msg} traceId=${o.detail.traceId??"-"}`),await ed(si[Math.min(n-1,si.length-1)])}throw new he({code:null,msg:"unreachable",traceId:null,httpStatus:null})}function rr(e){let t=e.apiKey??process.env.TBOX_API_KEY;if(!t)throw new he({code:"MISSING_CREDENTIAL",msg:"TBOX_API_KEY 未配置",traceId:null,httpStatus:null},"知识库通道缺凭证:TBOX_API_KEY 未配置");let r=(e.baseUrl??So).replace(/\/+$/,""),n=e.fetchImpl??globalThis.fetch,o={Authorization:t};e.cookie&&(o.Cookie=e.cookie);let s={url:r,headers:o},i=(l,a)=>nd({path:a.path,...a.body!==void 0?{body:a.body}:{},...a.form!==void 0?{form:a.form}:{},...a.isTerminal!==void 0?{isTerminal:a.isTerminal}:{},base:s,fetchImpl:n,policy:Qc[l],opLabel:l});return{async retrieveSemantic(l){let a=await i("retrieve",{path:He("retrieve"),body:{datasetId:l.kbId,query:l.query,...l.topK!==void 0?{limit:l.topK}:{},options:[{knowledgeBaseId:l.kbId,legacyPreFilters:ii(l.preFilters)}]}});return Array.isArray(a?.hits)?a.hits.map(ai).filter(c=>c!==void 0):[]},async retrieveSorted(l){let a=await i("retrieve",{path:He("retrieve"),body:{datasetId:l.kbId,query:"",limit:rd(l.limit??50),retrievalStrategy:"FIELD_SORT",options:[{knowledgeBaseId:l.kbId,legacyPreFilters:ii(l.preFilters),fieldSortRules:td(l.sorts??Zc)}]}});return{hits:Array.isArray(a?.hits)?a.hits.map(ai).filter(c=>c!==void 0):[],total:Number(a?.total??0)}},async addSegment(l){let a=await i("addSegment",{path:He("addSegment"),body:{documentId:l.documentId,content:l.rowJson}});if(typeof a!="string"||!a)throw new he({code:"EMPTY_RESULT",msg:`addSegment 无 segmentId: ${JSON.stringify(a).slice(0,120)}`,traceId:null,httpStatus:null});return a},async deleteSegment(l){try{return await i("deleteSegment",{path:He("deleteSegment"),body:{documentSegmentId:l.segmentId},isTerminal:To}),!0}catch(a){if(a instanceof he&&To({msg:a.detail.msg??void 0}))return!1;throw a}},async batchDeleteSegments(l){let a=await i("batchDeleteSegmentByDocument",{path:He("batchDeleteSegmentByDocument"),body:{documentId:l.documentId,documentSegmentIds:l.segmentIds},isTerminal:To});return Number(a??0)},async createKnowledgeBase(l){let a=new FormData;a.append("file",new Blob([l.csv],{type:"text/csv"}),`${l.name}.csv`),a.append("type","STRUCTURED"),a.append("tableSchema",JSON.stringify(l.tableSchema));for(let m of l.indexColumns)a.append("indexColumns",m);let c=await i("createKnowledgeBaseByDataSet",{path:He("createKnowledgeBaseByDataSet"),form:a}),d=c,p=typeof d=="string"?d:d?.response?.documentId??d?.documentId;if(typeof p!="string"||!p)throw new he({code:"EMPTY_RESULT",msg:`createKnowledgeBase 无 documentId: ${JSON.stringify(c).slice(0,120)}`,traceId:null,httpStatus:null});return{documentId:p}},async findKnowledgeBasesByName(l){let a=await i("pageQueryKnowledgeBase",{path:He("pageQueryKnowledgeBase"),body:{fuzzyName:l,pageNum:1,pageSize:20}});return Array.isArray(a?.records)?a.records.map(c=>{let d=c;if(!(typeof d?.id!="string"||typeof d?.name!="string"))return{id:d.id,name:d.name,...typeof d.gmtCreate=="string"?{gmtCreate:d.gmtCreate}:{}}}).filter(c=>c!==void 0):[]},async getKnowledgeBase(l){let c=await i("queryKnowledgeBase",{path:He("queryKnowledgeBase"),body:{id:l,descIndexedDocuments:!0}}),d=c?.data?.knowledgeBase??c?.knowledgeBase??c?.data??{},p=Array.isArray(d?.tableSchema?.columns)?d.tableSchema.columns.map(C=>({name:String(C?.name??""),...C?.dataType!==void 0?{dataType:String(C.dataType)}:{},...C?.indexed===!0?{indexed:!0}:{}})).filter(C=>C.name!==""):[],m=d?.documents??d?.indexedDocuments??d?.documentList,g=Array.isArray(m)?m.map(C=>{let v=C,P=v?.documentId??v?.id;return typeof P=="string"&&P?P:""}).filter(C=>C!=="").map(C=>({id:C})):[];return{type:String(d?.type??""),columns:p,documents:g}},async getDocumentPrimaryKeys(l){let a=await i("queryDocument",{path:He("queryDocument"),body:{documentId:l,pageNum:1,pageSize:5}}),c=a?.documents??a?.data?.documents;if(!Array.isArray(c)||c.length===0)throw new he({code:"EMPTY_RESULT",msg:`queryDocument 无 documents(documentId 不存在或 schema 未回读): ${JSON.stringify(a).slice(0,120)}`,traceId:null,httpStatus:null});let d=c[0];return(Array.isArray(d?.tableSchema?.columns)?d.tableSchema.columns:[]).filter(m=>m?.primaryKey===!0&&typeof m?.name=="string").map(m=>m.name).sort()}}}var bo=od("MEMORY:KB"),nr=class extends Error{constructor(r,n){super(n);this.code=r;this.name="MemoryStoreUnsupportedError"}code},Eo={save:!0,search:!0,list:!0,delete:!0};function sd(e,t,r){return JSON.stringify({id:e.id,userId:e.userId,scopeKey:r,kind:e.kind,content:e.content,contentHash:t,importance:e.importance,createdAt:String(e.createdAt)})}function li(e){if(typeof e=="number")return Number.isFinite(e)?e:void 0;if(typeof e=="string"&&e!==""){let t=Number(e);return Number.isFinite(t)?t:void 0}}function Io(e){try{let t=JSON.parse(e.content);if(typeof t?.id!="string"||typeof t?.userId!="string"||t.kind!=="preference"&&t.kind!=="fact"&&t.kind!=="episode"||typeof t?.content!="string")return;let r=li(t.importance),n=li(t.createdAt);if(r===void 0||n===void 0)return;let o=typeof t.scopeKey=="string"?t.scopeKey:"",s=o===et?void 0:ei(o);return{id:t.id,userId:t.userId,kind:t.kind,content:t.content,...s?{scope:s}:{},importance:r,createdAt:n}}catch{return}}function sn(e){let t=e.capabilities??Eo,{transport:r,knowledgeBaseId:n,documentId:o}=e,s=(a,c)=>new nr(c,`知识库记忆能力未启用(capabilities.${a}=false)`),i=(a,c)=>[{column:"userId",value:a},{column:"scopeKey",value:c}],l=async(a,c)=>{let d=i(a,c),p=[{field:"importance",order:"asc"},{field:"createdAt",order:"asc"}],m=await r.retrieveSorted({kbId:n,preFilters:d,sorts:[...p],limit:1}),g=m.total+1-Vt;if(g<=0)return;let C=g===1&&m.hits.length>0?m.hits:(await r.retrieveSorted({kbId:n,preFilters:d,sorts:[...p],limit:Math.min(g,200)})).hits;C.length!==0&&await r.batchDeleteSegments({documentId:o,segmentIds:C.map(v=>v.segmentId)})};return{capabilities:t,async save(a){if(!t.save)throw s("save",on.KB_SEGMENT_UPSERT_NOT_SUPPORTED);let c=a.content.trim(),d=zt(c),p=xe(a.scope)||et,{hits:m}=await r.retrieveSorted({kbId:n,preFilters:[...i(a.userId,p),{column:"contentHash",value:d}],limit:1}),g=m.length>0?Io(m[0]):void 0,C=g?{...g,importance:Math.max(g.importance,dt[a.kind])}:{id:Jt(),userId:a.userId,kind:a.kind,content:c,...a.scope?{scope:{...a.scope}}:{},importance:dt[a.kind],createdAt:Date.now()};try{await l(a.userId,p)}catch(v){bo.warn(`容量淘汰失败(不阻断 save):${v.message}`)}return await r.addSegment({documentId:o,rowJson:sd(C,d,p)}),C},async search(a){if(!t.search)throw s("search",on.KB_SEARCH_FILTER_NOT_SUPPORTED);if(!a.query.trim())return[];let c=await r.retrieveSemantic({kbId:n,query:a.query,preFilters:i(a.userId,xe(a.scope)||et),topK:a.topK??5}),d=[];for(let p of c){let m=Io(p);if(!m){bo.warn("segment 内容解析失败(跳过该条)");continue}d.push(m)}return d},async list(a){if(!t.list)throw s("list",on.KB_LIST_FIELDSORT_NOT_SUPPORTED);let c=Math.min(Math.max(1,a.limit??Xt),Yt),{hits:d}=await r.retrieveSorted({kbId:n,preFilters:i(a.userId,xe(a.scope)||et),limit:c}),p=[];for(let m of d){let g=Io(m);if(!g){bo.warn("segment 内容解析失败(跳过该条)");continue}p.push(g)}return p},async delete(a){if(!t.delete)throw s("delete",on.KB_SEGMENT_DELETE_NOT_SUPPORTED);let c=xe(a.scope)||et,{hits:d}=await r.retrieveSorted({kbId:n,preFilters:[...i(a.userId,c),{column:"id",value:a.id}],limit:1});return d.length===0?!1:r.deleteSegment({segmentId:d[0].segmentId})}}}var an={name:"agent_memory",description:"tbox agent 长期记忆",columns:[{name:"id",dataType:"STRING",required:!0,order:1},{name:"userId",dataType:"STRING",required:!0,primaryKey:!0,order:2},{name:"scopeKey",dataType:"STRING",primaryKey:!0,order:3},{name:"kind",dataType:"STRING",order:4},{name:"content",dataType:"STRING",indexed:!0,order:5},{name:"contentHash",dataType:"STRING",primaryKey:!0,order:6},{name:"importance",dataType:"NUMBER",order:7},{name:"createdAt",dataType:"STRING",order:8}]},xo=["content"],Ro=`id,userId,scopeKey,kind,content,contentHash,importance,createdAt
|
|
69
|
+
mem_seed000,__system__,__global__,fact,bootstrap-seed,seed,0.0,0
|
|
70
|
+
`,tt=class extends Error{constructor(r,n,o){super(n);this.code=r;this.detail=o;this.name="KnowledgeBootstrapError"}code;detail};async function or(e,t,r){let n=await e.getKnowledgeBase(t),o=[];n.type!=="STRUCTURED"&&o.push(`type=${n.type}(期望 STRUCTURED)`);let s=new Map(n.columns.map(a=>[a.name,a]));for(let a of an.columns){let c=s.get(a.name);c?c.dataType!==a.dataType&&o.push(`列 ${a.name} dataType=${c.dataType}(期望 ${a.dataType})`):o.push(`缺列 ${a.name}`)}let i=n.columns.filter(a=>a.indexed===!0).map(a=>a.name).sort();JSON.stringify(i)!==JSON.stringify(["content"])&&o.push(`indexed=[${i.join(",")}](期望 [content])`);let l=await e.getDocumentPrimaryKeys(r);if(JSON.stringify(l)!==JSON.stringify(["contentHash","scopeKey","userId"])&&o.push(`docPk=[${l.join(",")}](期望 [contentHash,scopeKey,userId])`),o.length>0)throw new tt("SCHEMA_MISMATCH",`知识库 schema 与记忆 schema 不符:${o.join(";")}`,{kbId:t,documentId:r,problems:o})}async function ci(e,t){let r=(await e.findKnowledgeBasesByName(t)).filter(n=>n.name===t);if(r.length!==0)return r.reduce((n,o)=>(o.gmtCreate??"")>(n.gmtCreate??"")?o:n)}async function ln(e){return e.timeoutMs===void 0?or(e.transport,e.kbId,e.documentId):new Promise((t,r)=>{let n=!1,o=setTimeout(()=>{n||(n=!0,r(new tt("VALIDATE_TIMEOUT",`记忆 KB 校验超时(${e.timeoutMs}ms)`)))},e.timeoutMs);o.unref?.(),or(e.transport,e.kbId,e.documentId).then(s=>{n||(n=!0,clearTimeout(o),t(s))},s=>{n||(n=!0,clearTimeout(o),r(s))})})}async function di(e){let{transport:t}=e,r=e.kbName??"agent-memory";if(e.existing)return await or(t,e.existing.kbId,e.existing.documentId),{kbId:e.existing.kbId,documentId:e.existing.documentId,created:!1};let n=await ci(t,r);if(n){let l=(await t.getKnowledgeBase(n.id)).documents[0]?.id;if(!l)throw new tt("DISCOVER_FAILED",`发现 KB "${r}"(kbId=${n.id})但无 document——请确认是否记忆专用 KB 或重建`,{kbId:n.id,kbName:r});return await or(t,n.id,l),{kbId:n.id,documentId:l,created:!1}}let o=await t.createKnowledgeBase({name:r,tableSchema:an,indexColumns:xo,csv:Ro}),s=await ci(t,r);if(!s)throw new tt("DISCOVER_FAILED",`建库后按名发现失败(documentId=${o.documentId})——请在控制台人工确认后配置 existing`,{documentId:o.documentId,kbName:r});return await or(t,s.id,o.documentId),{kbId:s.id,documentId:o.documentId,created:!0}}import{createServerLogger as ad}from"@tbox.cn/app-sdk-server";import{MEMORY_ERROR_CODES as id}from"@tbox.cn/app-contracts";var sr=class extends Error{constructor(r,n){super(r);this.cause=n;this.name="MemoryUnavailableError"}cause;code=id.MEMORY_KB_VALIDATION_FAILED};function cn(e,t){let r=async n=>{let o=await t;if(!o.ok)throw new sr("记忆功能暂不可用(KB 启动校验未通过)——请如实告知用户本轮无法记忆,勿重复调用记忆工具;请检查 TBOX_MEMORY_KB_ID/TBOX_MEMORY_KB_DOC_ID 指向的知识库与凭证配置,修复后重启恢复。",o.error);return n()};return{save:n=>r(()=>e.save(n)),search:n=>r(()=>e.search(n)),list:n=>r(()=>e.list(n)),delete:n=>r(()=>e.delete(n)),get capabilities(){return e.capabilities}}}var rt=ad("MEMORY"),ir=200;function Co(e){let t=e.store;if(t==="off")return{enabled:!1,mode:"off"};if(t===void 0||t===""||t==="inmemory")return{enabled:!0,mode:"inmemory",store:wt()};if(t==="knowledge"){let r=e.apiKey??process.env.TBOX_API_KEY,{kbId:n,kbDocId:o}=e;if(!n||!o||!r){let s=[...n?[]:["TBOX_MEMORY_KB_ID"],...o?[]:["TBOX_MEMORY_KB_DOC_ID"],...r?[]:["TBOX_API_KEY"]].join("/");return rt.warn(`TBOX_MEMORY_STORE=knowledge 但 ${s} 未配置,回退 inmemory`),{enabled:!0,mode:"inmemory",store:wt()}}return e.kbCookie&&rt.warn("TBOX_MEMORY_KB_COOKIE 已配置——该变量通常仅预发联调使用,生产环境不应设置"),{enabled:!0,mode:"knowledge",store:sn({transport:rr({apiKey:r,...e.kbBaseUrl?{baseUrl:e.kbBaseUrl}:{},...e.kbCookie?{cookie:e.kbCookie}:{}}),knowledgeBaseId:n,documentId:o})}}return rt.warn(`非法 TBOX_MEMORY_STORE="${t}"(inmemory|knowledge|off),使用默认 inmemory`),{enabled:!0,mode:"inmemory",store:wt()}}function dn(e){if(e===void 0||e==="")return ir;let t=Number(e);return Number.isFinite(t)&&t>=0?Math.floor(t):(rt.warn(`非法 TBOX_MEMORY_RECALL_TIMEOUT_MS="${e}",使用默认 ${ir}`),ir)}var ar=1e4;function wo(e){return e===void 0||e===""||e==="0"||e==="false"||e==="off"?"off":e==="1"||e==="true"?"degrade":e==="strict"?"strict":(rt.warn(`非法 TBOX_MEMORY_KB_VALIDATE="${e}"(1|strict|off),不校验`),"off")}function ko(e){if(e===void 0||e==="")return ar;let t=Number(e);return Number.isFinite(t)&&t>=1?Math.floor(t):(rt.warn(`非法 TBOX_MEMORY_KB_VALIDATE_TIMEOUT_MS="${e}",使用默认 ${ar}`),ar)}function ui(e){return rr({apiKey:e.apiKey??process.env.TBOX_API_KEY,...e.kbBaseUrl?{baseUrl:e.kbBaseUrl}:{},...e.kbCookie?{cookie:e.kbCookie}:{}})}async function pi(e,t){let r=wo(e.validate),n=Co(e);if(n.mode!=="knowledge"||r==="off")return{...n,validateMode:r};let o=t?.validate??ln,s=ko(e.validateTimeoutMs);if(r==="strict")return await o({transport:ui(e),kbId:e.kbId,documentId:e.kbDocId,timeoutMs:s}),{...n,validateMode:"strict"};let i=Date.now(),l=(async()=>{try{return await o({transport:ui(e),kbId:e.kbId,documentId:e.kbDocId,timeoutMs:s}),{ok:!0}}catch(a){return{ok:!1,error:a}}})();return l.then(a=>{a.ok?rt.info(`KB validate ok (${Date.now()-i}ms)`):rt.error(`KB validate FAILED — 记忆功能降级(调用时报错):${a.error?.message??String(a.error)}。修复指引:检查 TBOX_MEMORY_KB_ID/TBOX_MEMORY_KB_DOC_ID 指向的知识库 schema 与平台凭证;修复后重启恢复。`)}),{...n,store:cn(n.store,l),validateMode:"degrade"}}import{RequestContext as ld}from"@mastra/core/request-context";import{AuthError as cd}from"@tbox.cn/app-sdk-server";var mi="tbox.engine.run",fi=Symbol.for("tbox.engine.runMetadata");function gi(e,t){e.set(mi,Object.freeze({...t,[fi]:!0}))}function Mo(e){let t=e?.requestContext?.get(mi),r=e?.agent?.toolCallId??e?.toolCallId;if(!(!t||t[fi]!==!0||typeof t.runId!="string"||typeof t.threadKey!="string"||typeof r!="string"||!r))return Object.freeze({runId:t.runId,threadKey:t.threadKey,toolCallId:r})}function yi(e){let t=e?.requestContext;if(!t)return;let r=t.get("identity");if(!r)return;let n=t.get("conversationId"),o=t.get("credentials"),s=t.get("attributes");return{identity:r,...typeof n=="string"?{conversationId:n}:{},...o?{credentials:o}:{},...s?{attributes:s}:{}}}function dd(e,t){let r=yi(e);if(!r)throw cd.forbidden(`工具运行上下文缺失${t?`(tool=${t})`:""}:请从 execute 第二参读取(const reqCtx = requireToolRequestContext(execCtx, toolId))`);return r}function ud(e){let t=new ld;return t.set("identity",e.identity),e.conversationId&&t.set("conversationId",e.conversationId),e.credentials&&t.set("credentials",e.credentials),e.attributes&&t.set("attributes",e.attributes),{requestContext:t}}import{isValidationError as hi}from"@mastra/core/tools";import{createServerLogger as pd}from"@tbox.cn/app-sdk-server";var md=256*1024,fd=16*1024,gd=1e3,Ti="本轮处理因运行控制错误结束,请重新提问。",pt="本轮处理已停止,尚未形成可展示的最终答复。请重新提问。",Si=pd("STEP_CONTROL"),yd=e=>(typeof e.content=="string",e.content.length>0),un=e=>JSON.stringify(e);function bi(e){return structuredClone(e).map(t=>{if(!Array.isArray(t.content))return t;let r=t.content.map(n=>{if(!("providerOptions"in n)||!n.providerOptions?.mastra||typeof n.providerOptions.mastra!="object")return n;let o={...n.providerOptions},s={...o.mastra};delete s.createdAt,Object.keys(s).length>0?o.mastra=s:delete o.mastra;let i={...n,...Object.keys(o).length>0?{providerOptions:o}:{}};return Object.keys(o).length===0&&delete i.providerOptions,i});return{...t,content:r}})}function Ii(e){let t=new Set,r=new Map;for(let n of e)if(Array.isArray(n.content)){for(let o of n.content)if(o.type==="tool-call"){if(t.has(o.toolCallId))throw new Error("Duplicate native tool call");t.add(o.toolCallId)}else if(o.type==="tool-result"){if(!t.has(o.toolCallId)||r.has(o.toolCallId))throw new Error("Unpaired native tool result");r.set(o.toolCallId,o.output)}}if(t.size!==r.size)throw new Error("Incomplete native tool pair");return{calls:t,results:r}}async function Ei(e,t){let r,n=Promise.resolve().then(()=>e.onRunEnd(t)).catch(()=>{}),o=new Promise(s=>{r=setTimeout(s,gd),r.unref?.()});try{await Promise.race([n,o])}finally{r&&clearTimeout(r)}}var pn=class e{abortSignal;abortController=new AbortController;controller;input;parentAbortSignal;timer;ledger;prefix;checkpoint;preparedStep=0;completedStep=0;consumedStep=0;status;reasonCode;controlError;quarantine=!1;ended=!1;historyAppended=!1;bufferedBytes=0;activeTools=new Set;observedCalls=new Set;observations=new Map;decisions=new Map;constructor(t,r,n){this.controller=t,this.abortSignal=r.abortSignal,this.input=r,this.parentAbortSignal=n}static async create(t,r){let n=new AbortController,o=AbortSignal.any([r.abortSignal,n.signal]),s={...r,abortSignal:o},i=Promise.resolve().then(()=>t(s)).then(m=>({kind:"controller",controller:m}),()=>({kind:"error"})),l=()=>{},a=new Promise(m=>{if(o.aborted){m({kind:"aborted"});return}let g=()=>m({kind:"aborted"});o.addEventListener("abort",g,{once:!0}),l=()=>o.removeEventListener("abort",g)}),c=await Promise.race([i,a]);if(l(),c.kind==="aborted"){i.then(m=>{if(m.kind==="controller")return Ei(m.controller,{runId:r.runId,threadKey:r.threadKey,requestContext:r.requestContext,abortSignal:o,status:"cancelled",reasonCode:"ENGINE_CANCELLED",quarantine:!1})});return}if(c.kind==="error")throw new Error(Ti);let d=c.controller,p=new e(d,s,r.abortSignal);if(p.abortController.signal.addEventListener("abort",()=>n.abort(),{once:!0}),d.deadlineAt!==void 0)if(!Number.isFinite(d.deadlineAt))p.fail("ENGINE_INVALID_DEADLINE");else{let m=d.deadlineAt-Date.now();m<=0?p.stop("ENGINE_DEADLINE_EXCEEDED",!0):(p.timer=setTimeout(()=>p.stop("ENGINE_DEADLINE_EXCEEDED",!0),m),p.timer.unref?.())}return p}common(){return{runId:this.input.runId,threadKey:this.input.threadKey,requestContext:this.input.requestContext,abortSignal:this.abortSignal}}modelInput(t,r=!1){return{...this.common(),stepNumber:t,availableToolIds:this.input.availableToolIds,maxSteps:this.input.maxSteps,remainingSteps:this.input.maxSteps>0?Math.max(0,this.input.maxSteps-t+(r?0:1)):1/0}}closed(){return this.parentAbortSignal.aborted&&(this.status="cancelled",this.reasonCode="ENGINE_CANCELLED"),!!this.status||this.abortSignal.aborted}stop(t,r=!1){this.status&&!(r&&(this.status==="completed"||this.status==="stopped"))||this.abortSignal.aborted||(this.status="stopped",this.reasonCode=t,r&&this.abortController.abort())}fail(t){this.abortSignal.aborted&&!this.controlError||(this.status="error",this.reasonCode=t,this.controlError=new Error(Ti),this.abortController.abort())}async invoke(t){if(this.closed())return;let r;try{let n=new Promise(s=>{r=()=>s(void 0),this.abortSignal.addEventListener("abort",r,{once:!0})}),o=await Promise.race([t(),n]);return this.closed()?void 0:o}catch{this.fail("ENGINE_CONTROL_ERROR");return}finally{r&&this.abortSignal.removeEventListener("abort",r)}}verifyPrefix(t){if(!this.prefix||un(t.slice(0,this.prefix.length))!==un(this.prefix))throw this.quarantine=!0,this.fail("ENGINE_TRANSCRIPT_INVALID"),new Error("Input transcript prefix changed")}verifyAppendOnly(t){if(this.verifyPrefix(t),this.checkpoint&&un(bi(t.slice(0,this.checkpoint.length)))!==un(this.checkpoint))throw this.quarantine=!0,this.fail("ENGINE_TRANSCRIPT_INVALID"),new Error("Controlled transcript tail changed")}captureCheckpoint(t){this.checkpoint=bi(t)}prepareStep=async t=>{if(this.closed())return{activeTools:[]};try{if(this.ledger&&this.ledger!==t.messageList)throw new Error("Message ledger changed");this.ledger=t.messageList;let r=t.messageList.get.all.aiV5.model();this.prefix?this.verifyAppendOnly(r):(this.prefix=structuredClone(r),this.captureCheckpoint(r));let n=t.stepNumber+1;if(n!==this.preparedStep+1||n!==this.completedStep+1)throw new Error("Unaccounted model step");if(this.input.maxSteps>0&&n>this.input.maxSteps)return this.stop("ENGINE_MAX_STEPS",!0),{activeTools:[]};this.preparedStep=n;let o=await this.invoke(()=>this.controller.beforeModelStep(this.modelInput(n)));if(!o)return{activeTools:[]};let s=new Set(this.input.availableToolIds);if(!Array.isArray(o.activeToolIds)||o.activeToolIds.some(l=>!s.has(l)))return this.fail("ENGINE_TOOL_SCOPE_INVALID"),{activeTools:[]};this.activeTools=new Set(o.summaryOnly?[]:o.activeToolIds);let i;if(o.toolChoice!==void 0)if(o.toolChoice==="required"){if(this.activeTools.size===0)return this.fail("ENGINE_TOOL_SCOPE_INVALID"),{activeTools:[]};i="required"}else if(typeof o.toolChoice=="object"&&o.toolChoice!==null&&Object.keys(o.toolChoice).length===1&&typeof o.toolChoice.toolId=="string"&&o.toolChoice.toolId.length>0&&this.activeTools.has(o.toolChoice.toolId))i={type:"tool",toolName:o.toolChoice.toolId};else return this.fail("ENGINE_TOOL_SCOPE_INVALID"),{activeTools:[]};if(Si.debug("prepare",`step=${n}`,`activeTools=${[...this.activeTools].join(",")||"-"}`,`toolChoice=${i==="required"?"required":i?.toolName??"auto"}`),n>1){let l=new Set(t.messageList.get.response.db().map(a=>a.id));if(!t.messageId||!l.has(t.messageId)||!t.rotateResponseMessageId)throw new Error("Response boundary unavailable");t.messageList.markResponseMessageBoundary(t.messageId),t.rotateResponseMessageId()}if(o.appendHint){if(typeof o.appendHint!="string"||Buffer.byteLength(o.appendHint,"utf8")>fd)return this.fail("ENGINE_HINT_LIMIT"),{activeTools:[]};t.messageList.add({role:"user",content:`<system-reminder type="engine-step-control" run="${this.input.runId}" step="${n}">
|
|
71
|
+
${o.appendHint}
|
|
72
|
+
</system-reminder>`},"input",{merge:!1}),this.verifyAppendOnly(t.messageList.get.all.aiV5.model())}return this.captureCheckpoint(t.messageList.get.all.aiV5.model()),{messageList:t.messageList,activeTools:[...this.activeTools],...i!==void 0?{toolChoice:i}:{}}}catch{return this.quarantine=!0,this.fail("ENGINE_TRANSCRIPT_INVALID"),{activeTools:[]}}};toolInput(t,r,n){let o=Mo(n);if(!o||o.runId!==this.input.runId||o.threadKey!==this.input.threadKey){this.fail("ENGINE_TOOL_CONTEXT_INVALID");return}return{...this.common(),stepNumber:this.preparedStep,toolCallId:o.toolCallId,toolName:t,args:r}}hooks={beforeToolCall:async({toolName:t,input:r,context:n})=>{if(this.closed())return{proceed:!1,output:{text:pt}};let o=this.toolInput(t,r,n);if(!o)return{proceed:!1,output:{text:pt}};if(this.observedCalls.add(o.toolCallId),!this.activeTools.has(t))return{proceed:!1,output:{text:"工具不在本轮可用范围内。"}};let s=await this.invoke(()=>this.controller.beforeToolCall(o));return this.closed()?{proceed:!1,output:{text:pt}}:s},afterToolCall:async({toolName:t,input:r,context:n,output:o,error:s})=>{if(this.closed())return;let i=this.toolInput(t,r,n);if(!i)return;let l=s??(hi(o)?o.message:void 0),a={...i,output:o,...l!==void 0?{error:l}:{}};this.observations.set(i.toolCallId,a),await this.invoke(()=>this.controller.afterToolCall(a))}};onIterationComplete=async t=>{if(this.closed())return{continue:!1};if(t.iteration!==this.preparedStep||t.iteration!==this.completedStep+1||!this.ledger)return this.fail("ENGINE_STEP_INVALID"),{continue:!1};this.completedStep=t.iteration;let r=this.ledger.get.all.aiV5.model(),n;try{this.verifyAppendOnly(r),n=Ii(r.slice(this.prefix.length))}catch{return this.quarantine=!0,this.fail("ENGINE_TRANSCRIPT_INVALID"),{continue:!1}}let o=[...this.ledger.get.response.db()].reverse().find(l=>l.role==="assistant");o&&this.ledger.markResponseMessageBoundary(o.id);let s={...this.modelInput(t.iteration,!0),text:t.text,toolCalls:t.toolCalls.map(l=>({toolCallId:l.id,toolName:l.name,args:l.args})),toolResults:t.toolResults.map(l=>{let a=this.observations.get(l.id),c=n.results.get(l.id),d=a?.error??l.error??(hi(l.result)?l.result.message:void 0)??(c?.type?.startsWith("error")?c.value:void 0);return{toolCallId:l.id,toolName:l.name,output:l.result,...d!==void 0?{error:d}:{}}}),isFinal:t.isFinal,finishReason:t.finishReason},i=await this.invoke(()=>this.controller.afterModelStep(s));if(!i||this.closed())return{continue:!1};switch(Si.debug("complete",`step=${t.iteration}`,`calls=${s.toolCalls.map(l=>l.toolName).join(",")||"-"}`,`isFinal=${s.isFinal}`,`finishReason=${s.finishReason}`,`action=${i.action}`),this.decisions.set(t.iteration,{publish:!1,text:t.text}),i.action){case"continue":return s.remainingSteps<=0?(this.stop("ENGINE_MAX_STEPS"),{continue:!1}):{continue:!0};case"publish-final":return s.toolCalls.length>0?(this.stop("ENGINE_INVALID_FINAL"),{continue:!1}):(this.decisions.set(t.iteration,{publish:!0,text:t.text}),this.status="completed",{continue:!1});case"stop":return this.stop(i.reasonCode??"ENGINE_CONTROL_STOP"),{continue:!1};case"follow-runtime":t.isFinal&&this.stop(i.reasonCode??"ENGINE_NO_FINAL");return;default:return this.fail("ENGINE_DECISION_INVALID"),{continue:!1}}};buffer(t){return this.bufferedBytes+=Buffer.byteLength(t,"utf8"),this.bufferedBytes>md&&this.stop("ENGINE_BUFFER_LIMIT",!0),!this.abortSignal.aborted&&!this.controlError&&this.reasonCode!=="ENGINE_BUFFER_LIMIT"}visibleStep(t,r){let n=this.decisions.get(t);return t!==this.consumedStep+1||!n||n.text!==r?(this.quarantine=!0,this.fail("ENGINE_STEP_STREAM_INVALID"),!1):(this.consumedStep=t,n.publish&&!this.abortSignal.aborted&&!this.controlError)}finishStream(){!this.abortSignal.aborted&&!this.controlError&&this.consumedStep!==this.completedStep&&(this.quarantine=!0,this.fail("ENGINE_STEP_STREAM_INVALID"))}async*iterate(t){let r=t[Symbol.asyncIterator](),n,o=!1,s=new Promise(i=>{n=()=>i(void 0)});this.abortSignal.addEventListener("abort",n,{once:!0});try{for(;!this.abortSignal.aborted;){let i=await Promise.race([r.next(),s]);if(!i||this.abortSignal.aborted)break;if(i.done){o=!0;break}yield i.value}}finally{if(this.abortSignal.removeEventListener("abort",n),!o&&r.return)try{Promise.resolve(r.return()).catch(()=>{})}catch{}}}get hasPublishedFinal(){return this.status==="completed"&&!this.abortSignal.aborted&&!this.controlError}get stopped(){return this.closed()&&!this.hasPublishedFinal}get error(){return this.controlError}appendHistory(t,r){if(!this.historyAppended){this.historyAppended=!0;try{if(!this.ledger||!this.prefix){if(this.preparedStep===0&&!r.text&&!r.reasoning&&this.observedCalls.size===0)return;throw new Error("Message ledger unavailable")}let n=this.ledger.get.all.aiV5.model();this.verifyAppendOnly(n);let o=n.slice(this.prefix.length).filter(yd),s=Ii(o);if([...this.observedCalls].some(c=>!s.calls.has(c)))throw new Error("Missing executed tool call");let i=o.flatMap(c=>c.role==="assistant"&&Array.isArray(c.content)?c.content:c.role==="assistant"&&typeof c.content=="string"?[{type:"text",text:c.content}]:[]),l=i.filter(c=>c.type==="text").map(c=>c.text).join(""),a=i.filter(c=>c.type==="reasoning").map(c=>c.text).join("");if(l!==r.text||a!==r.reasoning)throw new Error("Unaccounted streamed response");t.push(...o)}catch{this.quarantine=!0,this.abortSignal.aborted||this.fail("ENGINE_TRANSCRIPT_INVALID")}}}async end(t,r){this.ended||(this.ended=!0,this.timer&&clearTimeout(this.timer),this.closed(),t&&!this.status&&(this.status="error"),this.status??="stopped",this.quarantine&&r(),await Ei(this.controller,{...this.common(),status:this.status,...this.reasonCode?{reasonCode:this.reasonCode}:{},quarantine:this.quarantine}))}};var lr=Te("CARD"),Ed=Te("MODEL"),xd=Te("MODEL"),mt=Te("PRETOOL"),Ci=Te("SKILL"),_t=Te("MEMORY"),_o=Te("AGENT:SAVE"),wi=Te("AGENT:SUBMIT_SAVE"),Rd=Te("AGENT:CHAT"),Cd=Te("AGENT:SUBMIT_FORM"),ki=Te("MODEL-DIALECT"),wd=Te("TAG-HYGIENE"),Ao=Te("TOOL-DEBUG");function mn(e){return e===void 0?Ir:Number.isInteger(e)&&e>=1?e:(lr.warn(`maxCardsPerTurn 非法(${e}),已 clamp`),Number.isFinite(e)?Math.max(1,Math.floor(e)):Ir)}function kd(e,t){return e==="1"||e==="true"?!0:e==="0"||e==="false"?!1:(e!==void 0&&e!==""&&Ao.warn(`非法 TBOX_TOOL_DEBUG="${e}"(1|0|true|false),使用缺省`),t!=="production")}function Md(e){return e==="1"||e==="true"}var _d=8;function cr(e){return e?.maxSteps!==void 0?e.maxSteps:_d}function ne(e){return`${e}_${Date.now()}_${Math.random().toString(36).slice(2,8)}`}function Mi(e){let t=e||"no-conv";return`${Date.now()}_${t}_${Math.random().toString(36).slice(2,8)}`}function Ad(e){let t=e.replace(/\s+/g," ").trim();return t.length>60?`${t.slice(0,60)}…`:t}function _i(e){let t=new Sd;return t.set("requestId",e.requestId),t.set("threadKey",e.threadKey),e.conversationId&&t.set("conversationId",e.conversationId),e.identity&&t.set("identity",e.identity),e.credentials&&t.set("credentials",e.credentials),e.attributes&&t.set("attributes",e.attributes),t}function Ai(e){if(e.identity)return{identity:e.identity,...e.conversationId?{conversationId:e.conversationId}:{},...e.credentials?{credentials:e.credentials}:{},...e.attributes?{attributes:e.attributes}:{}}}function vd(e){let t=Object.keys(e.tools).sort().join("\0");return{toolsHash:xi("sha256").update(t).digest("hex").slice(0,16),systemPromptHash:xi("sha256").update(e.instructions).digest("hex").slice(0,16)}}function Oi(e,t){return e?[{type:"reasoning",text:e},{type:"text",text:t}]:t}function Od(e){try{let t=e.messageList?.get?.response?.aiV5?.model?.();return Array.isArray(t)?t.filter(r=>{let n=r.content;return typeof n=="string"&&n!==""||Array.isArray(n)&&n.length>0}):[]}catch{return[]}}function Ld(e,t,r,n){let o=Od(e);if(o.length>0){t.push(...o);return}if(r.text||r.reasoning){let s={role:"assistant",content:Oi(r.reasoning,r.text)};t.push(...n?n([s]):[s])}}function vi(e){let t=Date.now(),r=n=>{let o=n.providerOptions&&typeof n.providerOptions=="object"?n.providerOptions:{},s=o.mastra&&typeof o.mastra=="object"?o.mastra:{};return{...n,providerOptions:{...o,mastra:{...s,createdAt:typeof s.createdAt=="number"?s.createdAt:t}}}};return e.map(n=>{if(n.role==="system")return n;let o=typeof n.content=="string"?[r({type:"text",text:n.content})]:n.content.map(s=>r(s));return{...n,content:o}})}function vo(e){let t=e.traceExporter??Pr,r=Te("RUN"),n=e.fileUrlPrefix,o=new Id(e.cardRegistry),s=(f,R)=>{f.push(...e.stepControl?vi(R):R)},i=e.skillMode??Kt,l=e.preToolTimeoutMs??Ct,a=mn(e.maxCardsPerTurn),c=Nn(a),d=e.memory?rn(e.memory):void 0,p=d?e.memory.recallTimeoutMs??dn(process.env.TBOX_MEMORY_RECALL_TIMEOUT_MS):0,m=!!d&&p>0&&(d.caps.search||d.caps.list);d&&_t.info(`enabled topK=${d.topK} maxChars=${d.maxCharsPerRecord} timeoutMs=${p} caps=${["save","search","list","delete"].filter(f=>d.caps[f]).join(",")}`),e.toolDebug&&Ao.info("tool-debug 视图已开启:memory 召回 / silent preTool 伪工具事件将下发前端(不持久化;HELLO_ACK 携带 toolDebug 旗标解锁客户端 dev 视图)");let g=e.earlyToolExecution===!0;g&&Ao.info("early-tool-execution 已开启:白名单工具参数流完即预执行(mastra foreach 命中缓存);多工具轮收益依赖 parallel_tool_calls 注入(config/llm_provider.json parallelToolCalls)");let C={...e.tools};if(d){let f=nn({store:d.store,caps:d.caps,maxCharsPerRecord:d.maxCharsPerRecord,...d.resolveScope?{resolveScope:d.resolveScope}:{}});for(let[R,w]of Object.entries(f)){if(R in C){_t.warn(`记忆工具 "${R}" 与既有工具同名,跳过该记忆工具`);continue}C[R]=w}}let v=Bn(C,e.cardRegistry),P=(e.preTools??[]).map(f=>({...f,tool:v[f.tool.id??""]??f.tool})),F=null,U=null;async function D(){return F||(U||(U=(async()=>{let f=new bd({configs:{default:{serviceName:"tbox-agent-template",exporters:[t]}}}),R=new Td({id:"assistant",name:"assistant",instructions:e.instructions,model:g?is(e.model):e.model,tools:Ar(v),...i==="progressive"&&e.skills&&e.skills.length>0?{skills:e.skills.map(oo)}:{}}),w={mastra:new hd({agents:{assistant:R},observability:f})};return F=w,w})().catch(f=>{throw U=null,f})),U)}let O=new Map,H=new Set,j=new Map,se=new Map,ie=new Map,W=new Map,me=new Map;function Oe(f,R){se.set(f,R)}function nt(f){se.delete(f)}function yt(f){H.add(f),ht(f),O.delete(f),me.delete(f),W.delete(f)}function ht(f,R){let w=j.get(f);w&&(R&&w.runId!==R||(w.controller.abort(),j.delete(f)))}function $(f,R){j.get(f)?.runId===R&&j.delete(f)}async function q(f,R){let w=se.get(f.conversationId);if(!w)return lr.warn(`no active session for ${f.conversationId}`),!1;let M=o.build(f);if(!M)return!1;if(e.cardActionAttacher){let b=me.get(f.conversationId);if(b)try{M=await e.cardActionAttacher(M,b)}catch(A){lr.warn("动作 token 签发失败(跳过):",A.message)}}o.send(M,w);let N=R??(()=>{let b=W.get(f.conversationId);return b?ie.get(b):void 0})();return N&&N.emitted.push(ro(M)),!0}function fe(f){q(f)}async function ae(f){let{state:R,threadKey:w,messageId:M,decision:N,budgetExceeded:b}=f,A=Ln({decision:N,pool:R.pool,maxCardsPerTurn:a,budgetExceeded:b}),u={selected:[],unmatched:A.unmatched,rejectedCardType:A.rejectedCardType,droppedByCap:A.droppedByCap,emitFailed:0,...A.fallback?{fallback:A.fallback}:{}};for(let y of A.entries)try{await q({cardType:y.cardType,data:y.data,conversationId:w,messageId:M},R)?u.selected.push({ref:y.ref,cardType:y.cardType}):u.emitFailed+=1}catch(h){u.emitFailed+=1,lr.warn("决策出卡失败(跳过):",h.message)}return u}async function Le(f,R,w,M,N,b,A,u,y,h,k,x=!0){if(H.has(R))throw new Error("当前会话无法安全继续,请建立新会话后重新提问。");let _=Date.now(),V=xt.getStore()??Wn;Zs(R);let Se=(await D()).mastra.getAgent("assistant");Ed.debug("request",e.modelName,`historyLen=${f.length} lastUser=${(JSON.stringify(f[f.length-1])??"").slice(0,200)}`);let X=_i({requestId:w,conversationId:A,threadKey:R,identity:u?.identity,credentials:u?.credentials,attributes:u?.attributes}),Pe=!!e.stepControl&&x,I=Pe?await pn.create(e.stepControl,{runId:w,requestId:w,threadKey:R,sessionId:R,question:k??"",requestContext:Ai({conversationId:A,identity:u?.identity,credentials:u?.credentials,attributes:u?.attributes}),abortSignal:b??new AbortController().signal,availableToolIds:Object.keys(Ar(v)),maxSteps:cr(e.runBudget),startedAt:_}):void 0;if(Pe&&!I)return"";I&&gi(X,{runId:w,threadKey:R});let be=b,G={text:"",reasoning:""},B=g&&!I?ss({tools:C,requestContext:X,...b?{signal:b}:{},journal:V}):void 0,de=async()=>{let te=I?.abortSignal??be;if(I?.error)throw I.error;if(I?.stopped)return be?.aborted?"":(N({type:K.TEXT_MESSAGE_START,messageId:M,role:"assistant"}),N({type:K.TEXT_MESSAGE_CONTENT,messageId:M,delta:pt}),h&&h.firstVisibleMs===void 0&&(h.firstVisibleMs=Date.now()-h.runStartMs),N({type:K.TEXT_MESSAGE_END,messageId:M}),pt);let ue=cr(e.runBudget),Ve=0,Y=0,pe=await Se.stream(f,{requestContext:X,runId:w,abortSignal:te,...ue>0?{maxSteps:ue}:{},...I?{prepareStep:I.prepareStep,hooks:I.hooks,onIterationComplete:I.onIterationComplete,toolCallConcurrency:1}:{},onStepFinish:()=>{Ve+=1}}),Z="",le="",Ee="",Be=!1,ot=!1,Pt=0,Xe="",Nt="",Dt=po(e.contentTagConfigPath??qt),Tt=[...e.cardTagStripping??!0?[Er]:[],...Dt.specs],Me=It(Tt,{track:"content"}),st=It(Tt,{track:"reasoning"}),it=T=>{T&&(Be||(Be=!0,h&&h.firstVisibleMs===void 0&&(h.firstVisibleMs=Date.now()-h.runStartMs),N({type:K.TEXT_MESSAGE_START,messageId:M,role:"assistant"})),le+=T,N({type:K.TEXT_MESSAGE_CONTENT,messageId:M,delta:T}))},Mn=T=>{T&&(ot||(ot=!0,N({type:K.REASONING_START,messageId:M}),N({type:K.REASONING_MESSAGE_START,messageId:M,role:"reasoning"})),N({type:K.REASONING_MESSAGE_CONTENT,messageId:M,delta:T}))},Re=()=>{ot&&(N({type:K.REASONING_MESSAGE_END,messageId:M}),N({type:K.REASONING_END,messageId:M}),ot=!1)};y&&(I?I.buffer(y):it(y));e:for await(let T of I?I.iterate(pe.fullStream):pe.fullStream){if(te?.aborted)break;switch(T.type){case"step-start":I&&(Pt+=1,Xe="");break;case"step-finish":I&&I.visibleStep(Pt,Xe)&&(Nt=Xe);break;case"text-delta":{if(I&&!I.buffer(T.payload.text))break e;Z+=T.payload.text,I?(G.text=Z,Xe+=T.payload.text):it(Me.push(T.payload.text));break}case"reasoning-delta":{if(I&&!I.buffer(T.payload.text))break e;Ee+=T.payload.text,I?G.reasoning=Ee:Mn(st.push(T.payload.text));break}case"reasoning-end":{I||Re();break}case"tool-call":Y+=1,N({type:K.TOOL_CALL_START,toolCallId:T.payload.toolCallId,toolCallName:T.payload.toolName}),N({type:K.TOOL_CALL_ARGS,toolCallId:T.payload.toolCallId,delta:JSON.stringify(T.payload.args)}),N({type:K.TOOL_CALL_END,toolCallId:T.payload.toolCallId}),V.emit("tool_call",{toolCallId:T.payload.toolCallId,toolName:T.payload.toolName,args:T.payload.args});break;case"tool-result":{Me.resetZone(),N({type:K.TOOL_CALL_RESULT,toolCallId:T.payload.toolCallId,messageId:M,content:JSON.stringify(T.payload.result)}),V.emit("tool_result",{toolCallId:T.payload.toolCallId,result:T.payload.result});break}case"tool-error":{Me.resetZone();let Ce=T.payload.error,je=(typeof Ce?.message=="string"&&Ce.message||typeof Ce?.cause?.message=="string"&&Ce.cause.message||typeof Ce?.details?.errorMessage=="string"&&Ce.details.errorMessage||""||"工具执行失败").slice(0,200);N({type:K.TOOL_CALL_RESULT,toolCallId:T.payload.toolCallId,messageId:M,content:"",isError:!0,errorMessage:je}),V.emit("tool_result",{toolCallId:T.payload.toolCallId,error:je});break}case"error":if(I?.stopped&&!I.error)break e;throw xd.error("stream error",e.modelName,T.payload.error),I?.error??T.payload.error}}if(I){if(I.finishStream(),I.appendHistory(f,G),I.error)throw I.error;if(!I.hasPublishedFinal)return be?.aborted?"":(it(pt),N({type:K.TEXT_MESSAGE_END,messageId:M}),le);y&&it(y),it(Me.push(Nt))}let Q=qs(Z,Ee),E=Gs([Z,Ee],Dt.activeNames);if((Q.dsmlResidue>0||Q.tagDrift.length>0||Q.reminderEcho>0||E.thinkResidue>0||E.toolCallResidue>0)&&ki.warn("方言残留",`dsml=${Q.dsmlResidue}`,`drift=${JSON.stringify(Q.tagDrift.slice(0,5))}`,`reminderEcho=${Q.reminderEcho}`,`thinkResidue=${E.thinkResidue}`,`toolCallResidue=${E.toolCallResidue}`),Q.placeholderImitation>0&&ki.warn("占位符模仿",`count=${Q.placeholderImitation}`,le.slice(0,120)),te?.aborted)return(Z||Ee)&&s(f,[{role:"assistant",content:Oi(Ee,Z)}]),le;let L=st.finish();Re();let Ye=Me.finish();Ye.tail&&it(Ye.tail);let Fe=[...Ye.hits,...L.hits];if(Fe.length>0){for(let T of Fe)V.emit("tag_extracted",{...T});wd.warn("标签异常泄漏(模型退化残缺 token 防护触发;released = 已进入可见面)",...Fe.map(T=>[`${T.family}:${T.action}${T.unclosed?":unclosed":""}${T.degraded?":degraded":""}`,`form=${JSON.stringify(T.form)}`,`chars=${T.chars}`,`track=${T.track}`,`source=${T.source}`].join(" ")))}let _e=Ye.closedBodies.filter(T=>T.family==="cards").flatMap(T=>xr(T.body));Be||N({type:K.TEXT_MESSAGE_START,messageId:M,role:"assistant"}),N({type:K.TEXT_MESSAGE_END,messageId:M});let S=ue>0&&Ve>=ue;if(!le&&!Ee&&S){let T="本轮查询因工具调用步数预算耗尽,未能给出完整回答。请继续提问,我将重新获取所需数据并完成回答。";N({type:K.TEXT_MESSAGE_CONTENT,messageId:M,delta:T}),le=T}else if(!le&&!Ee&&Fe.some(T=>T.family==="tool-call-text"&&T.action==="stripped")){let T="模型尝试调用工具但输出格式异常,调用未能执行。请重试或换一种问法。";N({type:K.TEXT_MESSAGE_CONTENT,messageId:M,delta:T}),le=T}let Ae=ie.get(w),re;if(Ae&&(re=await ae({state:Ae,threadKey:R,messageId:M,decision:_e,budgetExceeded:S})),re&&V.emit("cards_flushed",{selected:re.selected.map(T=>({ref:T.ref,cardType:T.cardType})),emitFailed:re.emitFailed,..._e.length>0?{rawDecision:_e}:{},source:"llm"}),Y===0&&(Ae?.pool.size()??0)===0&&le&&/卡片|卡上|我的(车辆|积分|卡|优惠券|停车|订单)|(帮您|帮你|我再|让我)(查一下|确认下|看下|确认一下)/.test(le)&&lr.warn("promisedNoTool:模型零工具调用且候选池为空,正文提及卡片/数据意图词或查询动作承诺(history 直答,卡片承诺无着落)",le.slice(0,120)),I||Ld(pe,f,{reasoning:Ee,text:Z},e.stepControl?vi:void 0),pe.traceId&&re&&t.emitCustomSpan({spanId:ne("sp_carddecision"),traceId:pe.traceId,type:ve.GENERIC,name:"card-decision",startTime:new Date,endTime:new Date,input:void 0,output:void 0,metadata:{decision:_e.join(" ").slice(0,256),selected:re.selected.map(T=>({ref:T.ref,cardType:T.cardType})),unmatched:re.unmatched.join(" ").slice(0,256),rejectedCardType:re.rejectedCardType,droppedByCap:re.droppedByCap,emitFailed:re.emitFailed,collected:Ae?.pool.size()??0,...Q.dsmlResidue>0||Q.tagDrift.length>0||Q.reminderEcho>0?{dsmlResidue:Q.dsmlResidue,tagDrift:Q.tagDrift.join(" ").slice(0,256),...Q.reminderEcho>0?{reminderEcho:Q.reminderEcho}:{}}:{},...re.fallback?{fallback:re.fallback}:{}},requestId:w,conversationId:A,sessionId:R}),pe.traceId){let T=vd(e);t.emitCustomSpan({spanId:ne("sp_cacheobs"),traceId:pe.traceId,type:ve.GENERIC,name:"run-budget",startTime:new Date,endTime:new Date,input:void 0,output:void 0,metadata:{toolsHash:T.toolsHash,systemPromptHash:T.systemPromptHash,stepCount:Ve,budgetExceeded:S},requestId:w,conversationId:A,sessionId:R})}return le};if(!I)return B?at.run(B,de):de();let Ie;try{return await(B?at.run(B,de):de())}catch(te){throw Ie=te,I?.error??te}finally{if(I&&(I.appendHistory(f,G),await I.end(Ie,()=>yt(R)),!Ie&&I.error))throw I.error}}async function qe(f,R,w,M,N,b,A){let u=Mi(b),y=Date.now(),h={},k={runStartMs:y};Ri.enterWith({requestId:u,...b?{conversationId:b}:{},threadKey:f}),r.info(`start model=${e.modelName} contentLen=${R.length} mediaItems=${M?.length??0}`);let x=Zn({runId:u,...b?{conversationId:b}:{},...e.modelName?{model:e.modelName}:{},entry:"chat"});xt.enterWith(x),eo();let _,V=0;x.emit("run_start",{runId:u,...b?{conversationId:b}:{},...e.modelName?{model:e.modelName}:{},entry:"chat",input:R,mediaItems:M?.length??0,earlyExecution:g}),t.emitCustomSpan({spanId:ne("sp_query"),traceId:u,type:ve.GENERIC,name:`query: ${Ad(R)}`,startTime:new Date,endTime:new Date,input:R,metadata:{mediaItems:M?.length??0},requestId:u,...b?{conversationId:b}:{},sessionId:f});let ee=f,Se=O.get(f)??{history:[],nextCardRef:0,preToolDone:new Set};O.set(f,Se);let X=Se.history,Pe={pool:Mr({allocateRef:()=>`c${++Se.nextCardRef}`}),emitted:[]};ie.set(u,Pe),W.set(f,u),A?.scopeSessionId&&me.set(f,A.scopeSessionId);let I=e.intentRoutes?Fr(e.intentRoutes,R):void 0,be=new AbortController;j.set(f,{runId:u,controller:be}),Oe(f,w);let G=ne("msg");w({type:K.RUN_STARTED,threadId:ee,runId:u});try{let B;if(I&&e.handlerDispatch){let E=Date.now();B=await e.handlerDispatch(I,R,Ai({conversationId:b,identity:A?.identity,credentials:A?.credentials,attributes:A?.attributes}));let L=Date.now()-E;h.intentMs=L,t.emitCustomSpan({spanId:ne("sp_intentroute"),traceId:u,type:ve.GENERIC,name:"intent-route",startTime:new Date(E),endTime:new Date,metadata:{routeId:I.id,handlerId:I.handlerId,durMs:L,continued:!!B?.continueWith?.content.trim()},requestId:u,...b?{conversationId:b}:{},sessionId:f}),r.info(`intent-route ${I.id} durMs=${L} cards=${B?.cards?.length??0} continued=${!!B?.continueWith?.content.trim()} emptyPassthrough=${B!==void 0&&B.cards.length===0&&!B.text?.trim()&&!B.continueWith?.content.trim()}`),x.emit("intent_route",{routeId:I.id,...I.handlerId?{handlerId:I.handlerId}:{},durMs:L,continued:!!B?.continueWith?.content.trim()})}let de=B?.continueWith?.content.trim(),Ie=!!I&&!!e.handlerDispatch&&!!B&&B.cards.length===0&&!B.text?.trim()&&!de,te=!I||!e.handlerDispatch||!!de||Ie,ue=de||R,Ve=Kn(ue,M,n),Y=te&&l>0&&!!e.preTools&&e.preTools.length>0,pe=Y?ao(ue,P):[],Z=d?.resolveScope?.(A?.attributes??{}),le=m&&te&&!!A?.identity&&A.identity.source!=="anonymous",Ee,Be=Date.now(),ot=le?Ht(p,()=>Qt({userId:A.identity.userId,...Z?{scope:Z}:{},query:ue},{store:d.store,topK:d.topK})).then(E=>E,E=>{let L=Date.now()-Be;return _t.warn(`recall degraded: ${E?.message??String(E)}`),{records:[],halves:{search:{status:"failed",durMs:L},list:{status:"failed",durMs:L}},cache:"miss",degraded:!0,error:E?.message??String(E)}}):void 0,Pt=[],Xe=[],Nt=[],Dt=[],Tt=E=>!!e.toolDebug||!E.silent;if(Y&&pe.length>0){mt.info(`candidates=${pe.map(S=>S.tool.id).join(",")}`);let E={text:ue,history:Xr(X),...b?{conversationId:b}:{},...e.preToolContext?{ctx:e.preToolContext}:{},...A?.identity?{identity:A.identity}:{},...A?.credentials?{credentials:A.credentials}:{},...A?.attributes?{attributes:A.attributes}:{}},Ye={requestContext:_i({requestId:u,conversationId:b,threadKey:f,identity:A?.identity,credentials:A?.credentials,attributes:A?.attributes}),abortSignal:be.signal},Fe=Date.now(),_e=await lt.run({pool:Pe.pool},()=>Promise.all(pe.map(async S=>{let Ae=S.tool,re=ne("pretool");if(typeof Ae.execute!="function")return mt.warn(`skip ${S.tool.id}: 工具无 execute`),{kind:"skip",toolId:S.tool.id};let T=!1,Ce;try{return await Ht(l,async()=>{Ce=new Date;let ce=await S.decide(E);if(!ce||typeof ce!="object"||ce.decision!=="skip"&&ce.decision!=="run")return mt.warn(`skip ${S.tool.id}: decide 返回非法形状`),{kind:"skip",toolId:S.tool.id};if(ce.decision==="skip")return{kind:"skip",toolId:S.tool.id,reason:ce.reason};let je=ce.args;if(je===null||typeof je!="object"||Array.isArray(je))return mt.warn(`skip ${S.tool.id}: run args 非法(须 JSON 对象)`),{kind:"skip",toolId:S.tool.id};let $t;try{$t=JSON.parse(JSON.stringify(je))}catch{return mt.warn(`skip ${S.tool.id}: args 非 JSON 可序列化`),{kind:"skip",toolId:S.tool.id}}let br;if(S.dedup&&(br=`${S.tool.id}\0${io($t)}`,Se.preToolDone.has(br)))return{kind:"skip",toolId:S.tool.id,reason:"session-dedup"};if(Tt(S))for(let Sa of co({toolName:S.tool.id,description:Ae.description,toolArgs:$t,toolCallId:re}))w(Sa);T=!0;let Ta=await uo(Ae,$t,Ye);return{kind:"done",def:S,args:$t,result:Ta,toolCallId:re,startedAt:Ce,...br!==void 0?{dedupKey:br}:{}}})}catch(ce){if(mt.warn(`fail ${S.tool.id}:`,ce?.message),t.emitCustomSpan({spanId:ne("sp_pretool"),traceId:u,type:ve.GENERIC,name:`pretool:${S.tool.id}`,startTime:Ce??new Date,endTime:new Date,input:void 0,output:void 0,metadata:{status:"error",started:T},errorInfo:{message:ce?.message||"pre-tool 执行失败",type:ce?.name,stack:ce?.stack},requestId:u,conversationId:b,sessionId:f}),x.emit("pretool",{toolId:S.tool.id,outcome:"error",...Ce?{durMs:Date.now()-Ce.getTime()}:{},error:ce?.message??String(ce)}),T&&Tt(S))for(let je of Yr({toolName:S.tool.id,status:"error",error:ce?.message||"预执行失败",toolCallId:re,messageId:G}))w(je);return{kind:"skip",toolId:S.tool.id}}})));for(let S of _e){if(S.kind==="skip"){S.reason&&(t.emitCustomSpan({spanId:ne("sp_pretool"),traceId:u,type:ve.GENERIC,name:`pretool:${S.toolId}`,startTime:new Date,endTime:new Date,input:void 0,output:void 0,metadata:{status:"skipped",reason:S.reason},requestId:u,conversationId:b,sessionId:f}),x.emit("pretool",{toolId:S.toolId,outcome:"skip",reason:S.reason}));continue}let Ae=new Date,re={toolName:S.def.tool.id,...S.def.tool.description?{description:S.def.tool.description}:{},args:S.args,result:S.result};if(Pt.push(re),S.def.silent||Xe.push(re),Nt.push(S.def.tool.id),Tt(S.def))for(let T of Yr({toolName:S.def.tool.id,status:"done",result:S.result,toolCallId:S.toolCallId,messageId:G}))w(T);t.emitCustomSpan({spanId:ne("sp_pretool"),traceId:u,type:ve.GENERIC,name:`pretool:${S.def.tool.id}`,startTime:S.startedAt,endTime:Ae,input:S.args,output:S.result,metadata:{status:"done"},requestId:u,conversationId:b,sessionId:f}),x.emit("pretool",{toolId:S.def.tool.id,outcome:"ok",args:S.args,result:S.result,durMs:Ae.getTime()-S.startedAt.getTime()}),mt.info(`done ${S.def.tool.id}(预执行成功,注入 LLM 上下文)`),S.dedupKey!==void 0&&Dt.push({key:S.dedupKey,result:S.result,accepts:S.def.dedup?.accepts})}h.preToolMs=Date.now()-Fe}if(be.signal.aborted){w({type:K.RUN_FINISHED,threadId:ee,runId:u,rawEvent:{requestId:u}});return}if(ot){let E=await ot,{records:L,degraded:Ye,error:Fe}={records:E.records,degraded:E.degraded??!1,error:E.error},_e=Date.now()-Be;if(h.recallMs=_e,x.emit("memory_recall",{durMs:_e,hits:E.records.length,...E.records.length>0?{ids:E.records.map(S=>S.id).join(",")}:{},...E.degraded?{degraded:!0,error:E.error}:{},mode:d.mode,halves:E.halves,cache:E.cache},Be),E.records.length>0&&(Ee=er(E.records,d.maxCharsPerRecord),_t.info(`inject hits=${E.records.length} durMs=${_e}`),t.emitCustomSpan({spanId:ne("sp_memory"),traceId:u,type:ve.GENERIC,name:"memory-recall",startTime:new Date(Be),endTime:new Date,input:void 0,output:void 0,metadata:{hits:E.records.length,durMs:_e,ids:E.records.map(S=>S.id).join(","),mode:d.mode,halves:E.halves},requestId:u,conversationId:b,sessionId:f})),e.toolDebug)for(let S of Mt({toolCallId:ne("memory"),messageId:G,query:ue,status:Ye?"degraded":L.length>0?"hit":"miss",...L.length>0?{records:L}:{},...Fe?{error:Fe}:{},durMs:Date.now()-Be}))w(S)}else if(e.toolDebug&&m&&!te)for(let E of Mt({toolCallId:ne("memory"),messageId:G,query:ue,status:"skipped",reason:"intent"}))w(E);let Me,st;if(te&&i==="accelerated"&&e.skills&&e.skills.length>0){let E=Date.now(),L=Kr({text:ue,history:X,skills:e.skills});h.skillMs=Date.now()-E,x.emit("skill_injection",{action:L.action,...L.action!=="none"?{skill:L.skill.name}:{}}),L.action==="injected"?(Me={name:L.skill.name,description:L.skill.description},st=Ur(L.skill),Ci.info(`inject ${L.skill.name}(accelerated 命中,注入当前轮 user 消息前部)`)):L.action==="duplicate"&&(st=Hr(L.skill),Ci.info(`skip ${L.skill.name}(会话内已注入,去重——重申会话级恒真约束)`)),L.action!=="none"&&t.emitCustomSpan({spanId:ne("sp_skill"),traceId:u,type:ve.GENERIC,name:`skill: ${L.skill.name}`,startTime:new Date,endTime:new Date,metadata:{action:L.action,...L.skill.description?{description:L.skill.description}:{}},requestId:u,...b?{conversationId:b}:{},sessionId:f})}let Mn={role:"user",content:vr({...te?{cardDecision:c}:{},...Nt.length>0?{preToolBlocks:lo(Pt)}:{},...Ee?{memoryBlock:Ee}:{},...st?{skillBlock:st}:{}},Ve)};s(X,[Mn]);for(let E of Dt){let L;try{L=E.accepts?.(E.result)!==!1}catch{L=!1}L&&Se.preToolDone.add(E.key)}if(Me){let E=ne("skill");for(let L of so(Me,E,G))w(L)}let Re;te?Re=await lt.run({pool:Pe.pool},()=>Le(X,f,u,G,w,be.signal,b,A,B?.text,k,R,!de)):(w({type:K.TEXT_MESSAGE_START,messageId:G,role:"assistant"}),Re=B?.text??"",Re&&w({type:K.TEXT_MESSAGE_CONTENT,messageId:G,delta:Re}),w({type:K.TEXT_MESSAGE_END,messageId:G}),s(X,[{role:"assistant",content:Re}]));for(let E of B?.cards??[])await q({cardType:E.cardType,data:E.data,conversationId:f,messageId:G},Pe);B?.cards?.length&&x.emit("cards_flushed",{selected:B.cards.map(E=>({cardType:E.cardType})),emitFailed:0,source:"handler"});let Q;if(b&&e.saveMessage){let E=ie.get(u)?.emitted;_o.info("conversationId=%s requestId=%s query=%s answerLen=%d mediaItems=%d cards=%d",b,u,R.slice(0,50),Re.length,M?.length||0,E?.length||0);try{Q=await e.saveMessage({conversationId:b,query:R,answer:Re,mediaItems:M,outerBusinessId:u,...E&&E.length>0?{cards:E}:{},...Me?{skills:[Me]}:{},...Xe.length>0?{preTools:Xe}:{}}),x.emit("save_message",{savedMessageId:Q})}catch(L){_o.error("ERROR:",L.message),x.emit("save_message",{error:L.message})}}else _o.info("SKIPPED: no conversationId or saveMessage");w({type:K.RUN_FINISHED,threadId:ee,runId:u,rawEvent:{requestId:u,...Q&&{savedMessageId:Q}}}),V=Re.length,r.info(`finish durMs=${Date.now()-y} textLen=${Re.length} cards=${ie.get(u)?.emitted.length??0} saved=${Q??"no"}`)}catch(B){_=B,Rd.error("error:",B),r.error(`fail durMs=${Date.now()-y} err=${B?.message??String(B)}`),t.emitErrorSpan({requestId:u,conversationId:b,sessionId:f,name:"agent stream error",error:B,metadata:{model:e.modelName}}),w({type:K.RUN_ERROR,threadId:ee,runId:u,rawEvent:{requestId:u},message:B?.message||"AI 回复失败,请重试"})}finally{t.emitCustomSpan({spanId:ne("sp_runsummary"),traceId:u,type:ve.GENERIC,name:"run-summary",startTime:new Date(y),endTime:new Date,input:void 0,output:void 0,metadata:{outcome:_?"error":be.signal.aborted?"abort":"ok",...k.firstVisibleMs!==void 0?{firstVisibleMs:k.firstVisibleMs}:{},...Object.keys(h).length>0?{preLlm:h}:{}},requestId:u,...b?{conversationId:b}:{},sessionId:f}),await x.finish({outcome:_?"error":be.signal.aborted?"abort":"ok",durMs:Date.now()-y,answerLen:V,..._?{error:_?.message??String(_)}:{},...k.firstVisibleMs!==void 0?{firstVisibleMs:k.firstVisibleMs}:{},...Object.keys(h).length>0?{preLlm:h}:{}},y),$(f,u),ie.delete(u),W.get(f)===u&&W.delete(f)}}async function Ge(f,R,w,M,N,b,A){let u=Mi(b),y=Date.now(),h={},k={runStartMs:y};Ri.enterWith({requestId:u,...b?{conversationId:b}:{},threadKey:f}),r.info(`start form=${w} surfaceId=${R} model=${e.modelName}`);let x=Zn({runId:u,...b?{conversationId:b}:{},...e.modelName?{model:e.modelName}:{},entry:"form",surfaceId:R,formId:w});xt.enterWith(x),eo();let _,V=0;x.emit("run_start",{runId:u,...b?{conversationId:b}:{},...e.modelName?{model:e.modelName}:{},entry:"form",surfaceId:R,formId:w,formData:M,earlyExecution:!1});let ee=f,Se=O.get(f)??{history:[],nextCardRef:0,preToolDone:new Set};O.set(f,Se);let X=Se.history,Pe={pool:Mr({allocateRef:()=>`c${++Se.nextCardRef}`}),emitted:[]};ie.set(u,Pe),W.set(f,u);let I=ne("formSubmit");s(X,[{role:"assistant",content:[{type:"tool-call",toolCallId:I,toolName:jt,input:{surfaceId:R,formId:w}}]},{role:"tool",content:[{type:"tool-result",toolCallId:I,toolName:jt,output:{type:"json",value:M}}]}]),Oe(f,N),N({type:K.RUN_STARTED,threadId:ee,runId:u});let be=ne("msg");try{let G;if(m&&A?.identity&&A.identity.source!=="anonymous"){let Ie=d?.resolveScope?.(A.attributes??{}),te=Date.now(),ue=[...Xr(X)].reverse().find(Z=>Z.role==="user"&&ze(Z.content).trim().length>0),Ve=ue?ze(ue.content):"",Y;try{Y=await Ht(p,()=>Qt({userId:A.identity.userId,...Ie?{scope:Ie}:{},query:Ve},{store:d.store,topK:d.topK}))}catch(Z){let le=Date.now()-te;_t.warn(`recall degraded (form): ${Z?.message??String(Z)}`),Y={records:[],halves:{search:{status:"failed",durMs:le},list:{status:"failed",durMs:le}},cache:"miss",degraded:!0,error:Z?.message??String(Z)}}let pe=Date.now()-te;if(x.emit("memory_recall",{durMs:pe,hits:Y.records.length,...Y.records.length>0?{ids:Y.records.map(Z=>Z.id).join(",")}:{},...Y.degraded?{degraded:!0,error:Y.error}:{},mode:d.mode,halves:Y.halves,cache:Y.cache},te),Y.records.length>0&&(G=er(Y.records,d.maxCharsPerRecord),_t.info(`inject (form) hits=${Y.records.length}`)),h.recallMs=pe,e.toolDebug)for(let Z of Mt({toolCallId:ne("memory"),messageId:be,query:Ve,status:Y.degraded?"degraded":Y.records.length>0?"hit":"miss",...Y.records.length>0?{records:Y.records}:{},...Y.error?{error:Y.error}:{},durMs:pe}))N(Z)}s(X,[{role:"user",content:vr({cardDecision:c,...G?{memoryBlock:G}:{}},"")}]);let B=await lt.run({pool:Pe.pool},()=>Le(X,f,u,be,N,void 0,b,A,void 0,k,void 0,!1)),de;if(b&&e.saveMessage){let Ie=ie.get(u)?.emitted;wi.info("conversationId=%s requestId=%s answerLen=%d cards=%d",b,u,B.length,Ie?.length||0);try{de=await e.saveMessage({conversationId:b,query:`[表单提交] ${w}`,answer:B,...Ie&&Ie.length>0?{cards:Ie}:{}}),x.emit("save_message",{savedMessageId:de})}catch(te){wi.error("ERROR:",te.message),x.emit("save_message",{error:te.message})}}N({type:K.RUN_FINISHED,threadId:ee,runId:u,rawEvent:{requestId:u,...de&&{savedMessageId:de}}}),V=B.length,r.info(`finish durMs=${Date.now()-y} textLen=${B.length} cards=${ie.get(u)?.emitted.length??0} saved=${de??"no"}`)}catch(G){_=G,Cd.error("error:",G),r.error(`fail durMs=${Date.now()-y} err=${G?.message??String(G)}`),t.emitErrorSpan({requestId:u,conversationId:b,sessionId:f,name:"form submit error",error:G,metadata:{model:e.modelName}}),N({type:K.RUN_ERROR,threadId:ee,runId:u,rawEvent:{requestId:u},message:G?.message||"AI 回复失败,请重试"})}finally{t.emitCustomSpan({spanId:ne("sp_runsummary"),traceId:u,type:ve.GENERIC,name:"run-summary",startTime:new Date(y),endTime:new Date,input:void 0,output:void 0,metadata:{outcome:_?"error":"ok",...k.firstVisibleMs!==void 0?{firstVisibleMs:k.firstVisibleMs}:{},...Object.keys(h).length>0?{preLlm:h}:{}},requestId:u,...b?{conversationId:b}:{},sessionId:f}),await x.finish({outcome:_?"error":"ok",durMs:Date.now()-y,answerLen:V,..._?{error:_?.message??String(_)}:{},...k.firstVisibleMs!==void 0?{firstVisibleMs:k.firstVisibleMs}:{},...Object.keys(h).length>0?{preLlm:h}:{}},y),$(f,u),ie.delete(u),W.get(f)===u&&W.delete(f)}}return{chat:qe,submitForm:Ge,cancelRun:ht,quarantineThread:yt,emitCard:fe,registerSession:Oe,unregisterSession:nt,listSkills:()=>(e.skills??[]).map(f=>({name:f.name,description:f.description,routingTerms:f.routingTerms})),listPreTools:()=>(e.preTools??[]).map(f=>({toolId:f.tool.id??"",description:f.tool.description??"",routing:f.routing}))}}import{collectIntentRoutes as Pd}from"@tbox.cn/app-sdk-server";import{createServerLogger as Pi}from"@tbox.cn/app-sdk-server";var Nd=Pi("SKILL"),fn=Pi("PRETOOL"),Li=Symbol("tbox.llmInputHardened");function Dd(e){return!!e&&typeof e=="object"&&("_def"in e||"_zod"in e)}function Ni(e){let t={};for(let[r,n]of Object.entries(e)){let o=n;if(o[Li]||!Dd(o.inputSchema)){t[r]=n;continue}let s=Object.create(Object.getPrototypeOf(n),Object.getOwnPropertyDescriptors(n));s.inputSchema=jn(o.inputSchema),o.strict===void 0&&(s.strict=!1),s[Li]=!0,t[r]=s}return t}async function Di(e,t={}){let r=e.tools.getAll(),n={};t.loadPlugins&&(n=(await t.loadPlugins()).tools);let o={...r,...n};return{tools:Ni(o),rawTools:o}}function $i(e,t){let r=new Map;for(let n of e)r.has(n.name)||r.set(n.name,n);for(let n of t)r.has(n.name)&&Nd.warn(`应用 skill "${n.name}" 覆盖模块同名 skill`),r.set(n.name,n);return[...r.values()]}function Bi(e,t){let r=new Map;for(let n of e)r.has(n.tool.id)||r.set(n.tool.id,n);for(let n of t)r.has(n.tool.id)&&fn.warn(`应用 pre-tool "${n.tool.id}" 覆盖模块同名声明`),r.set(n.tool.id,n);return[...r.values()]}function Fi(e,t){let r=[];for(let n of e){let o=n?.tool?.id;if(!o){fn.warn("pre-tool 声明缺 tool.id,跳过该声明");continue}if(!t[o]){fn.warn(`toolId "${o}" 未注册(工具集无此工具),跳过该声明`);continue}if(t[o]!==n.tool){fn.warn(`toolId "${o}" 声明引用与工具集实例不一致(双实例分裂),跳过该声明`);continue}r.push(n)}return r}async function $d(e,t){let r=await Di(e,t),n=e.cards.getAll(),o=Pd(e.handlers.getAll()),s=[...t.intentRoutes??[],...o],i=mn(t.maxCardsPerTurn),l=cr(t.runBudget),a=t.memory?(()=>{let d=Qe(t.memory.store);return{save:d.save,search:d.search,delete:d.delete}})():void 0,c=t.memory&&t.memoryInstructions?`${t.instructions}
|
|
73
|
+
|
|
74
|
+
${t.memoryInstructions}`:t.instructions;return vo({instructions:c+`
|
|
75
|
+
|
|
76
|
+
`+Pn({maxCards:i,maxSteps:l,...a?{memory:a}:{}}),model:t.model,tools:r.tools,cardRegistry:n,traceExporter:t.traceExporter,modelName:t.modelName,fileUrlPrefix:t.fileUrlPrefix,saveMessage:t.saveMessage,intentRoutes:s.length>0?s:void 0,handlerDispatch:t.handlerDispatch,skillMode:t.skillMode,skills:$i(e.skills.getAll(),t.skills??[]),preTools:Fi(Bi(e.preTools.getAll(),t.preTools??[]),r.rawTools),preToolTimeoutMs:t.preToolTimeoutMs,preToolContext:e,runBudget:t.runBudget,cardActionAttacher:t.cardActionAttacher,maxCardsPerTurn:i,...t.memory?{memory:t.memory}:{},toolDebug:t.toolDebug,earlyToolExecution:t.earlyToolExecution,...t.stepControl?{stepControl:t.stepControl}:{}})}function Bd(e){let t={};return e.cards&&e.cards.length>0&&(t.cards=e.cards),e.skills&&e.skills.length>0&&(t.skills=e.skills),e.preTools&&e.preTools.length>0&&(t.preTools=e.preTools),Object.keys(t).length>0?t:void 0}import{WebSocketServer as Fd,WebSocket as ji}from"ws";import{EventType as ur}from"@ag-ui/core";import{AuthError as Po}from"@tbox.cn/app-sdk-server";import{normalizeContextEnvelope as jd}from"@tbox.cn/app-sdk-server";import{createServerLogger as yn,runLogScope as Ud}from"@tbox.cn/app-sdk-server";import{toNoticeText as Ui}from"@tbox.cn/app-sdk-server";import{TBOX_NOTICE_EVENT_NAME as Ki,nextKeepaliveAction as Kd,KEEPALIVE_MISS_LIMIT as Hd}from"@tbox.cn/app-contracts";import{ScopeSessionError as qd}from"@tbox.cn/app-sdk-server";var ke=yn("WS"),At=yn("WS:HELLO"),Gd=yn("WS:SEND_MESSAGE"),dr=yn("WS:UI_ACTION"),Vd=4002;function Xd(e,t={}){let r=new Fd({noServer:!0,maxPayload:1048576});return r.on("connection",n=>{ke.info("Client connected");let o=!0;n.on("pong",()=>{o=!0});let s=setInterval(()=>{if(!o){n.terminate();return}o=!1,n.readyState===ji.OPEN&&n.ping()},3e4),i=Date.now(),l=!1,a=t.keepalive?.enabled!==!1,c=Math.max(100,t.keepalive?.intervalMs??3e4),d=a?setInterval(()=>{let P=Kd(Date.now()-i,c);if(P==="dead"){if(!l)return;ke.warn(`keepalive stale (idle >= ${c*Hd}ms), terminate`);for(let F of m)ke.warn(` registered thread key: ${F}`);v>0&&ke.warn(` queue depth at terminate: ${v}`),n.terminate();return}P==="ping"&&De(n,{type:"PING"})},c):null,p=null,m=new Set,g=null,C=Promise.resolve(),v=0;n.on("message",P=>{let F=null,U;try{F=JSON.parse(P.toString())}catch(D){U=D}if(F){if(i=Date.now(),(F.type==="PING"||F.type==="PONG")&&(l=!0),F.type==="PING"){De(n,{type:"PONG",...F.ts!==void 0?{ts:F.ts}:{}});return}if(F.type==="PONG")return}v++,C=C.then(async()=>{try{if(!F){De(n,{type:ur.RUN_ERROR,message:`Invalid message: ${U.message}`});return}await Yd(n,F,e,{auth:t.auth,connAuth:p,registeredKeys:m,getCurrentConversation:()=>g,setCurrentConversation:D=>g=D,bind:D=>p=D},t)}catch(D){De(n,{type:ur.RUN_ERROR,message:`Invalid message: ${D.message}`})}finally{v--}})}),n.on("close",()=>{clearInterval(s),d&&clearInterval(d);for(let P of m)e.unregisterSession(P);m.clear(),ke.info("Client disconnected")}),n.on("error",P=>{ke.error("Error:",P.message)})}),r}function gn(e){if(!e.connAuth)throw Po.unauthorized("connection not authenticated: HELLO first");return e.connAuth}function Oo(e,t){ke.warn("%s rejected: no conversation established (RUN before NEW/RESUME)",t),De(e,{type:ur.RUN_ERROR,code:"CONVERSATION_NOT_ESTABLISHED",message:"会话未建立:请先发 NEW_CONVERSATION(新开)或 RESUME_CONVERSATION(重连)"})}function Lo(e,t){De(e,{type:ur.CUSTOM,name:Ki,value:{...Ui(t)}})}async function Yd(e,t,r,n,o={}){switch(t.type){case"HELLO":{if(!n.auth){At.warn("auth not configured; binding anonymous (degraded mode)"),n.bind({identity:{userId:`anonymous_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,source:"anonymous"}});break}try{let s=await n.auth.authenticate(t.token),i=jd(t.context)??o.defaultContext;if(i&&o.enhanceContext)try{let c=await o.enhanceContext(i);c&&typeof c=="object"?i=c:At.warn("enhanceContext returned non-object, using original context")}catch(c){At.warn("enhanceContext failed, using original context:",c.message)}let l={...s,...i?{attributes:i}:{}};n.bind(l);let a=o.scopeSessions&&i?o.scopeSessions.bootstrap({identity:l.identity,...l.credentials?{credentials:l.credentials}:{},attributes:l.attributes??{}}):void 0;if(a&&(l.scopeSessionId=a.sessionId),a||o.toolDebug||o.chatConfig){let c={type:"HELLO_ACK",...a?{mallScope:a.scopeFlat}:{},chatConfig:o.chatConfig??{quickCommands:[]},...o.toolDebug?{toolDebug:!0}:{}};De(e,c)}At.info("identity=%s source=%s credentials=%s context=%s",s.identity.userId,s.identity.source,s.credentials?s.credentials.token?"(token)":"(tokenless)":"(none)",i?"(set)":"(none)")}catch(s){if(s instanceof qd){At.warn("scope rejected:",s.message),e.close(Vd,"SCOPE_INVALID");return}let i=s instanceof Po?s:Po.unauthorized(s.message);At.warn("rejected: %s",i.message),e.close(4001,"AUTH_FAILED")}break}case"NEW_CONVERSATION":case"RESUME_CONVERSATION":{let s=gn(n),i=t.type==="NEW_CONVERSATION";if(s.identity.source==="anonymous"){ke.warn("%s rejected: anonymous identity",i?"NEW":"RESUME"),Lo(e,new Error("当前身份不可建立会话,请先登录"));break}let l=n.getCurrentConversation();l&&r.cancelRun(l,void 0);let a=o.conversationAgentId??process.env.TBOX_APP_ID;if(!o.conversationService||!a){ke.warn("%s failed: conversationService/agentId not configured",i?"NEW":"RESUME"),Lo(e,new Error("会话服务未配置(TBOX_API_KEY/TBOX_APP_ID 缺失)"));break}try{let c=i?await o.conversationService.createConversation(a,s.identity.userId):await o.conversationService.getOrCreateConversation(a,s.identity.userId);n.setCurrentConversation(c),n.registeredKeys.add(c),ke.info("%s conversationId=%s userId=%s",i?"NEW":"RESUME",c,s.identity.userId)}catch(c){ke.error("%s failed:",i?"NEW":"RESUME",c.message),Lo(e,c)}break}case"SEND_MESSAGE":{let s=gn(n),i=n.getCurrentConversation();if(!i){Oo(e,"SEND_MESSAGE");break}n.registeredKeys.add(i),Gd.info("conversationId=%s contentLen=%d mediaItems=%d",i,t.content.length,t.mediaItems?.length||0),await r.chat(i,t.content,l=>De(e,l),t.mediaItems,t.inputMethod,i,s);break}case"CANCEL_RUN":{gn(n);let s=n.getCurrentConversation();s&&r.cancelRun(s,t.runId);break}case"UI_ACTION":{let s=gn(n),i=n.getCurrentConversation(),l=a=>De(e,a);switch(t.action.type){case"sendMessage":if(!i){Oo(e,"UI_ACTION.sendMessage");break}n.registeredKeys.add(i),dr.info("conversationId=%s surfaceId=%s action=sendMessage",i,t.surfaceId),await r.chat(i,t.action.value,l,void 0,"card-action",i,s);break;case"submitForm":if(!i){Oo(e,"UI_ACTION.submitForm");break}dr.info("conversationId=%s surfaceId=%s action=submitForm",i,t.surfaceId),await r.submitForm(i,t.surfaceId,t.action.formId,t.formData??{},l,i,s);break;case"openLink":break;case"moduleAction":{if(Ud.enterWith({requestId:`act_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,...i?{conversationId:i}:{},...i?{threadKey:i}:{}}),!o.moduleActions){dr.warn("moduleAction 未装配分发器,忽略");break}if(!s.scopeSessionId){dr.warn("moduleAction 无 scope 会话(HELLO 未 bootstrap),忽略");break}try{await o.moduleActions.dispatch({token:t.action.contextToken,actionId:t.action.actionId,sessionId:s.scopeSessionId,surfaceId:t.surfaceId,ctx:{identity:s.identity,...i?{conversationId:i}:{},...s.credentials?{credentials:s.credentials}:{},...s.attributes?{attributes:s.attributes}:{}},...t.formData?{formData:t.formData}:{},emit:l})}catch(a){dr.warn("moduleAction failed:",a.message),De(e,{type:ur.CUSTOM,name:Ki,value:{...Ui(a),surfaceId:t.surfaceId||void 0}})}break}}break}default:{let s=t;ke.warn("unknown event type:",s?.type,JSON.stringify(t).slice(0,200));break}}}function De(e,t){e.readyState===ji.OPEN&&e.send(JSON.stringify(t))}import{createTool as zd}from"@mastra/core/tools";import{z as Jd}from"zod";function pr(e){if(Array.isArray(e))return e.map(r=>pr(r));if(typeof e!="object"||e===null)return e;let t={};for(let[r,n]of Object.entries(e))if(n!==null){if(typeof n=="string")try{let o=JSON.parse(n);if(o===null)continue;if(typeof o=="number"&&/^\d+$/.test(n.trim())){t[r]=n;continue}if(typeof o!="string"){t[r]=pr(o);continue}}catch{}t[r]=pr(n)}return t}function Wd(e){let t=Jd.preprocess(pr,e.inputSchema);return zd({id:e.id,description:e.description,inputSchema:t,execute:async r=>({summary:r,cards:[{cardType:e.cardType,data:r,...e.note?{note:e.note}:{}}]})})}import{mkdir as Zd,readFile as Hi,writeFile as Qd}from"fs/promises";import qi from"path";var No=class{async save(t){}async load(t){return[]}},Do=class{constructor(t=".tbox/card-snapshots"){this.dir=t}dir;fileFor(t){let r=t.replace(/[^a-zA-Z0-9_-]/g,"_");return qi.join(this.dir,`${r}.json`)}async save(t){if(t.cards.length===0)return;let r=this.fileFor(t.sessionId);await Zd(qi.dirname(r),{recursive:!0});let n=[];try{n=JSON.parse(await Hi(r,"utf8"))}catch{n=[]}let o=new Map;for(let s of n)o.set(s.id,s);for(let s of t.cards)o.set(s.id,s);await Qd(r,JSON.stringify([...o.values()],null,2),"utf8")}async load(t){try{return JSON.parse(await Hi(this.fileFor(t),"utf8"))}catch{return[]}}};import{readFileSync as eu}from"fs";import{join as tu}from"path";import{z as $e}from"zod";import{expandEnvVars as ru}from"@tbox.cn/app-sdk-server";import{assertNoInlineSecrets as nu}from"@tbox.cn/app-contracts";import{createServerLogger as ou}from"@tbox.cn/app-sdk-server";var $o=ou("app-config"),su=$e.object({enableImageUpload:$e.boolean().default(!0),enableVideoUpload:$e.boolean().default(!0),enableTTS:$e.boolean().default(!0),enableVoiceInput:$e.boolean().default(!0),defaultInputMode:$e.enum(["TEXT","VOICE"]).default("TEXT"),quickCommands:$e.array($e.object({label:$e.string(),query:$e.string()}).passthrough()).default([])}),Gi={enableImageUpload:!0,enableVideoUpload:!0,enableTTS:!0,enableVoiceInput:!0,defaultInputMode:"TEXT",quickCommands:[]};function iu(e){let t=tu(e,"chat.json"),r;try{r=JSON.parse(ru(eu(t,"utf8"),process.env,t))}catch(o){return o.code==="ENOENT"?$o.warn(`chat.json 缺失(文件:${t})——回退默认 chat 配置`):$o.warn(`chat.json 解析失败(${o.message},文件:${t})——回退默认 chat 配置`),Gi}try{nu(r)}catch(o){throw new Error(`${t}: ${o.message}`)}let n=su.safeParse(r);return n.success?n.data:($o.warn(`chat.json 校验失败(${n.error.message},文件:${t})——回退默认 chat 配置`),Gi)}function au(e){return{quickCommands:e.quickCommands.map(({label:t,query:r})=>({label:t,prompt:r})),settings:{enableImageUpload:e.enableImageUpload,enableVideoUpload:e.enableVideoUpload,enableTTS:e.enableTTS,enableVoiceInput:e.enableVoiceInput,defaultInputMode:e.defaultInputMode}}}import{readFileSync as lu}from"fs";import{join as cu}from"path";import{parse as du,printParseErrorCode as uu}from"jsonc-parser";import{z as mr}from"zod";import{assertNoInlineSecrets as pu}from"@tbox.cn/app-contracts";import{createServerLogger as mu}from"@tbox.cn/app-sdk-server";var fu=mu("app-config"),Bo="你是智能助手,帮助用户完成日常问答与业务事务。",gu=mr.strictObject({instructions:mr.array(mr.string()).min(1),memoryInstructions:mr.array(mr.string()).min(1).optional()});function fr(e,t){return fu.error(`agent.jsonc ${e}(文件:${t})——回退 SDK 默认提示词`),{instructions:Bo}}function yu(e,t){return e.slice(0,Math.max(0,t)).split(`
|
|
77
|
+
`).length}function Vi(e){return e.join(`
|
|
78
|
+
`).trim()}function hu(e){let t=cu(e,"agent.jsonc"),r;try{r=lu(t,"utf8")}catch(a){return a.code==="ENOENT"?{instructions:Bo}:fr(`读取失败:${a.message}`,t)}let n=[],o=du(r,n,{allowTrailingComma:!0});if(n.length>0)return fr(`解析失败:第 ${yu(r,n[0].offset)} 行 ${uu(n[0].error)}`,t);try{pu(o)}catch(a){throw new Error(`${t}: ${a.message}`)}let s=gu.safeParse(o);if(!s.success)return fr(`校验失败:${s.error.message}`,t);let i=Vi(s.data.instructions);if(!i)return fr("instructions 拼接后为空白",t);let l=s.data.memoryInstructions?Vi(s.data.memoryInstructions):"";return s.data.memoryInstructions&&!l?fr("memoryInstructions 拼接后为空白",t):{instructions:i,...l?{memoryInstructions:l}:{}}}import{TboxConversationClient as Ru}from"@tbox.cn/app-sdk-server";import{createServerLogger as vt}from"@tbox.cn/app-sdk-server";var Xi="…[已截断]";function jo(e,t){let r=[...e];if(r.length<=t)return e;let n=[...Xi].length,o=r.slice(0,Math.max(0,t-n)).join("")+Xi,s=[...o];return s.length<=t?o:s.slice(0,t).join("")}function Sn(e,t=6e4){return jo(e,t)}function Tn(e){try{return JSON.stringify(e)}catch{return null}}function Fo(e,t){if(typeof e=="string")return jo(e,t.strCap);if(Array.isArray(e))return(e.length>t.arrayCap?e.slice(0,Math.max(1,t.arrayCap)):e).map(n=>Fo(n,t));if(e!==null&&typeof e=="object"){let r={};for(let[n,o]of Object.entries(e))r[n]=Fo(o,t);return r}return e}function Tu(e){return t=>Array.isArray(t.skills)?{...t,skills:t.skills.map(r=>{if(r===null||typeof r!="object")return r;let n=r;return typeof n.description=="string"?{...n,description:jo(n.description,e)}:n})}:t}function Su(e){return t=>{if(!(e in t))return t;let r={...t};return delete r[e],r}}function hn(e,t){return r=>Array.isArray(r[e])?{...r,[e]:r[e].map(n=>Fo(n,t))}:r}function bu(){return e=>Array.isArray(e.preTools)?{...e,preTools:e.preTools.map(t=>{if(t===null||typeof t!="object")return t;let r={...t};return delete r.result,r})}:e}function Iu(){return e=>!Array.isArray(e.preTools)||e.preTools.length===0?e:{...e,preTools:e.preTools.slice(0,-1)}}var Yi=new WeakMap;function Eu(){return e=>{if(!Array.isArray(e.cards)||e.cards.length===0)return e;let t=-1,r=-1;return e.cards.forEach((n,o)=>{let s;if(n!==null&&typeof n=="object"){let i=Yi.get(n);i!==void 0?s=i:(s=Tn(n)?.length??0,Yi.set(n,s))}else s=Tn(n)?.length??0;s>=r&&(r=s,t=o)}),{...e,cards:e.cards.filter((n,o)=>o!==t)}}}var xu=[{id:"capSkillDescriptions",fn:Tu(120)},{id:"dropSkills",fn:Su("skills")},{id:"trimPreTools",fn:hn("preTools",{strCap:300,arrayCap:50})},{id:"dropPreToolResults",fn:bu()},{id:"dropPreToolRecords",fn:Iu()},{id:"trimCardsL1",fn:hn("cards",{strCap:400,arrayCap:60})},{id:"trimCardsL2",fn:hn("cards",{strCap:200,arrayCap:30})},{id:"trimCardsL3",fn:hn("cards",{strCap:100,arrayCap:15})},{id:"dropLargestCard",fn:Eu()},{id:"dropAll",fn:()=>({})}];function zi(e,t=6e4){let r=Tn(e);if(r===null)return{value:{},stage:"unserializable",beforeChars:-1,afterChars:2};if(r.length<=t)return{value:e,beforeChars:r.length,afterChars:r.length};let n=e,o=r,s;for(let{id:i,fn:l}of xu){for(;o.length>t;){let a=l(n),c=Tn(a);if(c===null||c===o)break;n=a,o=c,s=i}if(o.length<=t)break}return{value:n,stage:s,beforeChars:r.length,afterChars:o.length}}var Cu=vt("CONV:SERVICE"),bn=vt("CONV:SERVICE:getOrCreate"),Ji=vt("CONV:SERVICE:create"),wu=vt("CONV:SERVICE:save"),gr=vt("CONV:PRUNE"),Uo=vt("CONV:SERVICE:list"),yr=class{client;constructor(t){this.client=new Ru({apiKey:t}),Cu.info("initialized with apiKey:",t.slice(0,8)+"...")}async getOrCreateConversation(t,r){bn.info("agentId=%s userId=%s",t,r);let n=await this.client.listConversations({agentId:t,userId:r,pageNum:1,pageSize:1});if(bn.info("listConversations result:",JSON.stringify(n)),n.success&&n.data?.data?.length){let o=n.data.data[0].id;if(o)return bn.info("found existing:",o),o}return bn.info("no existing, creating new"),this.createConversation(t,r)}async createConversation(t,r){Ji.info("agentId=%s userId=%s",t,r);let n=await this.client.createConversation({agentId:t,userId:r});if(Ji.info("SDK response:",JSON.stringify(n)),!n.success)throw new Error(n.errorMsg||"Failed to create conversation");return n.data}async saveMessage(t){let r=ku(t);wu.info("conversationId=%s answerLen=%d inputs=%s extraParams=%s",r.conversationId,r.answer.length,r.inputs?"yes":"no",r.extraParams?"yes":"no");let n=await this.client.saveMessage(r);if(!n.success)throw new Error(n.errorMsg||`Failed to save message (code: ${n.errorCode})`);return n.data}async listMessages(t){Uo.info("params:",JSON.stringify(t));let r=await this.client.listMessages(t);if(Uo.info("SDK response: success=%s totalCount=%s dataLength=%s",r.success,r.data?.totalCount,r.data?.data?.length),!r.success)throw Uo.error("ERROR:",r.errorMsg,r.errorCode),new Error(r.errorMsg||"Failed to list messages");return r.data}};function ku(e){let t=e.query==null||e.query.trim()==="",r=t?"[空消息]":Sn(e.query);t?gr.warn("prune field=query blank-replaced"):r!==e.query&&gr.warn(`prune field=query before=${e.query.length} after=${r.length}`);let n=Sn(e.answer);n!==e.answer&&gr.warn(`prune field=answer before=${e.answer.length} after=${n.length}`);let o=e.inputs;if(o!==void 0){let i=zi(o);i.stage!==void 0&&(gr.warn(`prune field=inputs before=${i.beforeChars} after=${i.afterChars} stage=${i.stage}`),o=i.value)}let s=e.extraParams!==void 0?Sn(e.extraParams):void 0;return s!==e.extraParams&&gr.warn(`prune field=extraParams before=${e.extraParams.length} after=${s.length}`),{...e,query:r,answer:n,...o!==void 0?{inputs:o}:{},...s!==void 0?{extraParams:s}:{}}}import{Router as sp}from"express";import{Router as Mu}from"express";var In=Mu();In.get("/",(e,t)=>{t.json({status:"ok",timestamp:new Date().toISOString()})});import{Router as _u}from"express";import{TboxAppClient as Au}from"@tbox.cn/app-sdk-server";import{getRequestContext as vu}from"@tbox.cn/app-sdk-server";import{createServerLogger as Ou}from"@tbox.cn/app-sdk-server";var Lu=Ou("TBOX"),En=_u();En.get("/session",async(e,t)=>{let r=process.env.TBOX_API_KEY,n=process.env.TBOX_APP_ID;if(!r||!n){t.status(503).json({error:"TBOX_API_KEY or TBOX_APP_ID not configured"});return}let o=vu(e);if(!o){t.status(401).json({error:"unauthorized",code:"AUTH_UNAUTHORIZED"});return}if(o.identity.source==="anonymous"){t.status(403).json({error:"anonymous cannot generate session",code:"AUTH_FORBIDDEN"});return}let s=o.identity.userId;try{let l=await new Au({apiKey:r}).generateSession({appId:n,userId:s});l.success&&l.data?t.json({tboxSessionId:l.data.sessionId,channel:l.data.channel,appId:n}):t.status(500).json({error:l.errorMsg||"Session generation failed"})}catch(i){Lu.error("Session error:",i),t.status(500).json({error:"Internal error"})}});import Pu from"express";import{Router as Nu}from"express";import{TboxUploadClient as Du}from"@tbox.cn/app-sdk-server";import{getRequestContext as $u}from"@tbox.cn/app-sdk-server";import{createServerLogger as Bu}from"@tbox.cn/app-sdk-server";var xn=Bu("TBOX:UPLOAD"),Fu=3e5,ju=new Set(["image","video","audio","file"]);function Uu(e){if(e)try{return decodeURIComponent(e)}catch{return e}}function Wi(e={}){let t=Nu(),r=e.limit??"60mb";return t.post("/upload",Pu.raw({type:()=>!0,limit:r}),async(n,o)=>{let s=n.header("x-tbox-session-id"),i=n.header("x-tbox-channel"),l=n.header("x-tbox-appid"),a=n.header("x-tbox-file-type")??"file",c=Uu(n.header("x-tbox-file-name"));if(!s||!i||!l){o.status(400).json({error:"missing tbox session headers (x-tbox-session-id / x-tbox-channel / x-tbox-app-id)"});return}if(!ju.has(a)){o.status(400).json({error:`invalid x-tbox-file-type: ${a}`});return}if(!Buffer.isBuffer(n.body)||n.body.length===0){o.status(400).json({error:"empty request body"});return}let d=$u(n)?.identity?.userId;xn.info("identity=%s fileType=%s size=%d",d,a,n.body.length);try{let m=await new Du({session:{sessionId:s,channel:i,appId:l},timeout:Fu}).upload({file:new Blob([n.body],{type:n.header("content-type")??"application/octet-stream"}),fileType:a,fileName:c});m.success&&m.data?(xn.info("ok fileId=%s safed=%s",m.data.fileId,m.data.safed),o.json(m.data)):(xn.warn("upstream rejected: errorCode=%s",m.errorCode),o.status(502).json({error:m.errorMsg||"upload failed",errorCode:m.errorCode}))}catch(p){xn.error("upstream error:",p.message),o.status(502).json({error:"upstream request failed",errorCode:"UPSTREAM_ERROR"})}}),t.use((n,o,s,i)=>{if(n?.status===413){s.status(413).json({error:"payload too large",errorCode:"PAYLOAD_TOO_LARGE"});return}i(n)}),t}import Ku from"express";import{Router as Hu}from"express";import{TboxAsrClient as qu}from"@tbox.cn/app-sdk-server";import{createServerLogger as Gu}from"@tbox.cn/app-sdk-server";var Ko=Gu("TBOX:ASR"),Vu=6e4;function Zi(e={}){let t=Hu(),r=e.limit??"10mb";return t.post("/asr",Ku.json({type:()=>!0,limit:r}),async(n,o)=>{let s=n.header("x-tbox-session-id"),i=n.header("x-tbox-channel"),l=n.header("x-tbox-appid");if(!s||!i||!l){o.status(400).json({error:"missing tbox session headers (x-tbox-session-id / x-tbox-channel / x-tbox-app-id)"});return}let a=n.body??{};if(typeof a.base64_audio!="string"||a.base64_audio.length===0){o.status(400).json({error:"missing base64_audio"});return}try{let d=await new qu({session:{sessionId:s,channel:i,appId:l},timeout:Vu}).recognize({base64_audio:a.base64_audio,...typeof a.audio_format=="string"&&a.audio_format?{audio_format:a.audio_format}:{},...typeof a.sample_rate=="string"&&a.sample_rate?{sample_rate:a.sample_rate}:{}});d.success&&d.data?(Ko.info("ok len=%d",a.base64_audio.length),o.json(d.data)):(Ko.warn("upstream rejected: errorCode=%s",d.errorCode),o.status(502).json({error:d.errorMsg||"asr failed",errorCode:d.errorCode}))}catch(c){Ko.error("upstream error:",c.message),o.status(502).json({error:"upstream request failed",errorCode:"UPSTREAM_ERROR"})}}),t.use((n,o,s,i)=>{if(n?.status===413){s.status(413).json({error:"payload too large",errorCode:"PAYLOAD_TOO_LARGE"});return}i(n)}),t}import Xu from"express";import{Router as Yu}from"express";import{TboxFeedbackClient as zu}from"@tbox.cn/app-sdk-server";import{createServerLogger as Ju}from"@tbox.cn/app-sdk-server";var Ho=Ju("TBOX:FEEDBACK"),Wu=15e3,Zu=new Set(["LIKE","DISLIKE","CANCEL"]);function Qi(e={}){let t=Yu(),r=e.limit??"64kb";return t.post("/feedback",Xu.json({type:()=>!0,limit:r}),async(n,o)=>{let s=n.header("x-tbox-session-id"),i=n.header("x-tbox-channel"),l=n.header("x-tbox-appid");if(!s||!i||!l){o.status(400).json({error:"missing tbox session headers (x-tbox-session-id / x-tbox-channel / x-tbox-app-id)"});return}let a=n.body??{};if(typeof a.requestId!="string"||a.requestId.length===0){o.status(400).json({error:"missing requestId"});return}if(typeof a.feedback!="string"||!Zu.has(a.feedback)){o.status(400).json({error:`invalid feedback: ${String(a.feedback)}`});return}try{let d=await new zu({session:{sessionId:s,channel:i,appId:l},timeout:Wu}).addTag({requestId:a.requestId,feedback:a.feedback});d.success?(Ho.info("ok requestId=%s feedback=%s",a.requestId,a.feedback),o.json(d.data??{success:!0})):(Ho.warn("upstream rejected: errorCode=%s",d.errorCode),o.status(502).json({error:d.errorMsg||"feedback failed",errorCode:d.errorCode}))}catch(c){Ho.error("upstream error:",c.message),o.status(502).json({error:"upstream request failed",errorCode:"UPSTREAM_ERROR"})}}),t.use((n,o,s,i)=>{if(n?.status===413){s.status(413).json({error:"payload too large",errorCode:"PAYLOAD_TOO_LARGE"});return}i(n)}),t}import{Router as Qu}from"express";import{getRequestContext as ep}from"@tbox.cn/app-sdk-server";import{createServerLogger as tp}from"@tbox.cn/app-sdk-server";var ft=tp("CONV:MESSAGES");function qo(e){let t=Qu(),r=i=>i.map(l=>to(l,e.ctx.cards)),n=null,o;function s(){let i=process.env.TBOX_API_KEY;return i?((!n||o!==i)&&(n=new yr(i),o=i),n):null}return t.get("/messages",async(i,l)=>{let{beforeId:a,pageNo:c,pageSize:d}=i.query,p=ep(i);if(!p){ft.info("REJECTED: no auth context (token required)"),l.status(401).json({error:"unauthorized",code:"AUTH_UNAUTHORIZED"});return}if(p.identity.source==="anonymous"){ft.info("REJECTED: anonymous identity"),l.status(403).json({error:"anonymous cannot read messages",code:"AUTH_FORBIDDEN"});return}let m=p.identity.userId,g=process.env.TBOX_APP_ID;if(!g){ft.info("REJECTED: agentId not resolved"),l.status(503).json({error:"agentId is required (TBOX_APP_ID env)"});return}let C=s();if(!C){ft.info("REJECTED: TBOX_API_KEY not configured"),l.status(503).json({error:"TBOX_API_KEY not configured"});return}try{let v={agentId:g,userId:m,...a&&{beforeId:a},...c&&{pageNo:Number(c)},...d&&{pageSize:Number(d)}};ft.info("calling listMessages with:",JSON.stringify(v));let P=await C.listMessages(v),F=P.data??[],U=F.map(D=>{let O=D?.inputs?.cards??[],H=D?.inputs?.skills??[],j=D?.inputs?.preTools??[];return{...D,...O.length>0?{cards:r(O)}:{},...H.length>0?{skills:H}:{},...j.length>0?{preTools:j}:{}}});ft.info("SUCCESS totalCount:",P.totalCount,"dataLength:",F.length,"withCards:",U.filter(D=>D.cards).length,"withSkills:",U.filter(D=>D.skills).length,"withPreTools:",U.filter(D=>D.preTools).length),l.json({...P,data:U})}catch(v){ft.error("ERROR:",v),l.status(500).json({error:v.message})}}),t}import{Router as rp}from"express";import{MEMORY_ERROR_CODES as Rn}from"@tbox.cn/app-contracts";import{getRequestContext as np}from"@tbox.cn/app-sdk-server";import{createServerLogger as op}from"@tbox.cn/app-sdk-server";var Cn=op("MEMORY:ROUTE"),ea=["preference","fact","episode"];function ta(e){if(e===void 0||e===""||e===null)return{};if(typeof e!="string")return{error:"scope 必须是 JSON 对象字符串"};let t;try{t=JSON.parse(e)}catch{return{error:"scope 不是合法 JSON"}}if(t===null||typeof t!="object"||Array.isArray(t))return{error:"scope 必须是 JSON 对象"};let r={};for(let[n,o]of Object.entries(t)){if(typeof o!="string")return{error:`scope.${n} 必须是字符串`};r[n]=o}return{scope:r}}function Go(e){let t=rp(),r=Qe(e.store);function n(o,s){let i=np(o);if(!i){s.status(401).json({error:"unauthorized",code:"AUTH_UNAUTHORIZED"});return}if(i.identity.source==="anonymous"){s.status(403).json({error:"anonymous cannot access memory",code:"AUTH_FORBIDDEN"});return}return{userId:i.identity.userId}}return t.get("/",async(o,s)=>{let i=n(o,s);if(!i)return;if(!r.list){s.status(501).json({error:"memory list not available",code:Rn.KB_LIST_FIELDSORT_NOT_SUPPORTED});return}let{scope:l,error:a}=ta(o.query.scope);if(a){s.status(400).json({error:a});return}let c=o.query.kind;if(c!==void 0&&!ea.includes(c)){s.status(400).json({error:`kind 必须是 ${ea.join("|")}`});return}let d=o.query.limit,p=d!==void 0&&d!==""&&Number.isFinite(Number(d))?Math.max(1,Math.min(200,Math.floor(Number(d)))):void 0;try{let m=await e.store.list({userId:i.userId,...l?{scope:l}:{},...p?{limit:p}:{}}),g=c?m.filter(C=>C.kind===c):m;Cn.info(`list userId=${i.userId} total=${m.length} filtered=${g.length}`),s.json({records:g})}catch(m){if(m.name==="MemoryStoreUnsupportedError"){s.status(501).json({error:m.message,code:m.code});return}if(m.name==="MemoryUnavailableError"){s.status(503).json({error:m.message,code:Rn.MEMORY_KB_VALIDATION_FAILED});return}Cn.error("list 失败:",m.message),s.status(500).json({error:m.message})}}),t.delete("/:id",async(o,s)=>{let i=n(o,s);if(!i)return;if(!r.delete){s.status(501).json({error:"memory delete not available",code:Rn.KB_SEGMENT_DELETE_NOT_SUPPORTED});return}let{scope:l,error:a}=ta(o.query.scope);if(a){s.status(400).json({error:a});return}try{let c=await e.store.delete({userId:i.userId,...l?{scope:l}:{},id:o.params.id});Cn.info(`delete userId=${i.userId} id=${o.params.id} ok=${c}`),s.json({deleted:c})}catch(c){if(c.name==="MemoryStoreUnsupportedError"){s.status(501).json({error:c.message,code:c.code});return}if(c.name==="MemoryUnavailableError"){s.status(503).json({error:c.message,code:Rn.MEMORY_KB_VALIDATION_FAILED});return}Cn.error("delete 失败:",c.message),s.status(500).json({error:c.message})}}),t}function ip(e){let t=sp();return t.use((r,n,o)=>{n.set("Cache-Control","no-store"),o()}),t.use("/auth",e.auth.router),t.use("/health",In),t.use("/tbox",En),t.use("/tbox",Wi()),t.use("/tbox",Zi()),t.use("/tbox",Qi()),t.use("/conversation",qo({ctx:e.ctx})),e.memory&&t.use("/memory",Go({store:e.memory})),t.use((r,n)=>{n.status(404).json({error:"Not Found"})}),t}import{WebSocketServer as cp,WebSocket as gt}from"ws";import{TboxTtsClient as Yo}from"@tbox.cn/app-sdk-server";import{TboxTtsClient as ap}from"@tbox.cn/app-sdk-server";import{createServerLogger as lp}from"@tbox.cn/app-sdk-server";var Ot=lp("TTS-Config"),hr=null;function wn(){if(!hr){let e=Date.now();(!process.env.TTS_AUTH_URL||!process.env.TTS_APPKEY)&&Ot.warn("TTS_AUTH_URL/TTS_APPKEY 未配置,TTS 鉴权将失败(CONFIGURATION_ERROR);请配置环境变量后重试"),Ot.info("Creating new TboxTtsClient...",{createTs:e,authUrl:process.env.TTS_AUTH_URL});let t=ap.create({apiKey:process.env.TBOX_API_KEY||"",appId:process.env.TBOX_APP_ID||"",userId:`tts-proxy-${e}`,appkey:process.env.TTS_APPKEY||"",authUrl:process.env.TTS_AUTH_URL||"",timeout:15e3}).then(r=>(Ot.info("TboxTtsClient created successfully",{createTs:e,elapsed:Date.now()-e}),r)).catch(r=>{throw Ot.error("TboxTtsClient.create() failed:",r.message,{createTs:e}),hr=null,r});return hr=t,t}return Ot.info("Returning cached TboxTtsClient"),hr}function Vo(){Ot.info("Resetting cached TTS client (will create fresh on next call)"),hr=null}import{createServerLogger as dp}from"@tbox.cn/app-sdk-server";var J=dp("TTS");function up(){let e=new cp({noServer:!0});return e.on("connection",t=>{J.info("Client connected");let r=null,n=!1,o=[];t.on("message",async s=>{try{let i=JSON.parse(s.toString());switch(J.info("Client message:",i.type,i.type==="TTS_TEXT"?`(${(i.text||"").length} chars)`:""),i.type){case"START_TTS":n=!1,o.length=0,Xo(r),r=null,await mp(t,i,a=>{r=a},()=>{n=!0,J.info("start_ack received, flushing",o.length,"pending messages");for(let a of o)r?.readyState===gt.OPEN&&(J.info("Flushing pending:",a.slice(0,200)),r.send(a));o.length=0});break;case"TTS_TEXT":if(!i.text)break;let l=Yo.buildTextPayload(i.text);n&&r?.readyState===gt.OPEN?(J.info("Sending text to upstream:",l.slice(0,200)),r.send(l)):(J.info("Buffering text (upstream not ready):",l.slice(0,100)),o.push(l));break;case"TTS_FINISH":{let a=Yo.buildStopPayload();n&&r?.readyState===gt.OPEN?(J.info("Sending stop to upstream"),r.send(a)):(J.info("Buffering stop (upstream not ready)"),o.push(a));break}}}catch(i){J.error("Message handling error:",i.message),ra(t,{actionType:"failed",error:i.message})}}),t.on("close",()=>{J.info("Client disconnected"),Xo(r),r=null}),t.on("error",s=>{J.error("Client error:",s.message),Xo(r),r=null})}),e}async function pp(){J.info("fetchAuthWithRetry: starting first attempt...");let e=await wn(),t=await e.fetchAuth();if(J.info("fetchAuth result:",{success:t.success,hasData:!!t.data,errorCode:t.errorCode,errorMsg:t.errorMsg}),!t.success||!t.data){if(J.warn(`Auth failed (${t.errorCode}: ${t.errorMsg}), resetting client and retrying...`),Vo(),e=await wn(),J.info("fetchAuthWithRetry: retrying with fresh client..."),t=await e.fetchAuth(),J.info("fetchAuth retry result:",{success:t.success,hasData:!!t.data,errorCode:t.errorCode,errorMsg:t.errorMsg}),!t.success||!t.data)throw new Error(`TTS auth failed: ${t.errorCode??"UNKNOWN"} - ${t.errorMsg??"No auth data"}`);J.info("Auth retry succeeded")}return{ttsClient:e,authData:t.data}}async function mp(e,t,r,n){let{ttsClient:o,authData:s}=await pp(),i=o.buildUpstreamUrl(s);J.info("Connecting upstream:",i.replace(/Digest=[^&]+/,"Digest=***"));let l=new gt(i);r(l),l.on("open",()=>{let a=Yo.buildPayload(t.config||{});J.info("Upstream connected, sending init payload:",JSON.stringify(a)),l.send(JSON.stringify(a))}),l.on("message",(a,c)=>{if(c){let d=Buffer.isBuffer(a)?a:Buffer.from(a);J.info(`Upstream binary frame: ${d.byteLength} bytes`)}else{let d=a.toString();J.info("Upstream text frame:",d);try{JSON.parse(d).actionType==="start_ack"&&n()}catch{}}e.readyState===gt.OPEN&&(c?e.send(a,{binary:!0}):e.send(a.toString()))}),l.on("close",(a,c)=>{J.info(`Upstream disconnected: code=${a} reason=${c.toString()}`)}),l.on("error",a=>{J.error("Upstream error:",a.message),ra(e,{actionType:"failed",error:a.message})})}function Xo(e){e&&e.readyState===gt.OPEN&&e.close()}function ra(e,t){e.readyState===gt.OPEN&&e.send(JSON.stringify(t))}import{createOpenAICompatible as Bp}from"@ai-sdk/openai-compatible";import{createServerLogger as Fp}from"@tbox.cn/app-sdk-server";import{mkdir as fp,rename as gp,writeFile as yp}from"fs/promises";import{dirname as hp,join as Jo}from"path";import{createServerLogger as Tp}from"@tbox.cn/app-sdk-server";var Sp=Tp("LOCALLOG"),bp=new Set(["authorization","proxy-authorization","x-api-key","api-key","x-goog-api-key","cookie","set-cookie"]);function Ip(e){return e.length<=8?"*".repeat(e.length):`${e.slice(0,4)}...${e.slice(-4)}`}function na(e){let t={};for(let[r,n]of Object.entries(e)){let o=r.toLowerCase(),s=Array.isArray(n)?n.join(", "):String(n??"");t[r]=bp.has(o)?Ip(s):s}return t}function sa(e,t){if(t<=0)return{text:e,truncated:!1};if(Buffer.byteLength(e,"utf-8")<=t)return{text:e,truncated:!1};let r="",n=0;for(let o of e){let s=Buffer.byteLength(o,"utf-8");if(n+s>t)break;r+=o,n+=s}return{text:r,truncated:!0}}function kn(e){return e<1024?`${e}B`:e<1024*1024?`${(e/1024).toFixed(1)}KB`:`${(e/(1024*1024)).toFixed(1)}MB`}function Ep(e,t,r,n){let o;try{o=new URL(t)}catch{o={pathname:t,search:""}}let s=[`${e} ${o.pathname}${o.search??""} HTTP/1.1`];for(let[i,l]of Object.entries(r))s.push(`${i}: ${l}`);return s.push("",n),s.join(`
|
|
79
|
+
`)}function oa(e,t,r,n){let o=[`HTTP/1.1 ${e} ${t||""}`.trimEnd()];for(let[s,i]of Object.entries(r))o.push(`${s}: ${i}`);return o.push("",n),o.join(`
|
|
80
|
+
`)}function zo(e){if(!e)return{};if(e instanceof Headers){let t={};return e.forEach((r,n)=>{t[n]=r}),t}if(Array.isArray(e)){let t={};for(let r of e){let n=r[0],o=r[1]??"";n!==void 0&&(t[n]=o)}return t}if(typeof e=="object"){let t={};for(let[r,n]of Object.entries(e))t[r]=Array.isArray(n)?n.join(", "):String(n??"");return t}return{}}function xp(e){return e==null?{text:"",isReal:!0}:typeof e=="string"?{text:e,isReal:!0}:e instanceof Uint8Array?{text:new TextDecoder().decode(e),isReal:!0}:typeof Buffer<"u"&&Buffer.isBuffer(e)?{text:e.toString("utf-8"),isReal:!0}:{text:`[unserializable body: ${typeof e}]`,isReal:!1}}function Rp(e){try{let t=e.split(`
|
|
81
|
+
`);for(let r=t.length-1;r>=0;r--){let n=t[r];if(!n.startsWith("data:"))continue;let o=n.slice(5).trim();if(!o||o==="[DONE]")continue;let s=JSON.parse(o);if(s===null||typeof s!="object")continue;let i=s.usage,a=s.choices?.[0]?.finish_reason;if(i!==void 0||a!==void 0)return{...i!==void 0?{usage:i}:{},...a!==void 0?{finishReason:a}:{}}}}catch{}return{}}var Wo=class{constructor(t,r,n,o,s){this.logDir=t;this.ts=r;this.runSeg=n;this.attempt=o;this.maxFileBytes=s;this.partFilename=`${r}${n}-a${o}.http.part`,this.partPath=Jo(t,this.partFilename);let i;this.done=new Promise(l=>{i=l}),this._doneResolve=i}logDir;ts;runSeg;attempt;maxFileBytes;partPath;partFilename;buf="";byteCount=0;finalized=!1;disabled=!1;finalizedFile=null;_ioChain=Promise.resolve();done;_doneResolve;finalFilename(t){return`${this.ts}${this.runSeg}-a${this.attempt}-${t}.http`}append(t){if(!(this.finalized||this.disabled)){if(this.maxFileBytes>0){if(this.byteCount>=this.maxFileBytes)return;if(this.byteCount+Buffer.byteLength(t,"utf-8")>this.maxFileBytes){let{text:n}=sa(t,this.maxFileBytes-this.byteCount);this.buf+=n,this.buf+=`
|
|
82
|
+
[truncated at ${kn(this.maxFileBytes)}]
|
|
83
|
+
`,this.byteCount=this.maxFileBytes;return}}this.buf+=t,this.byteCount=this.byteCount+(this.maxFileBytes>0?Buffer.byteLength(t,"utf-8"):0)}}writeMeta(t){for(let[r,n]of Object.entries(t))this.append(`# ${r}: ${n}
|
|
84
|
+
`)}writeRequest(t){this.append(t),this._flushToPartAsync()}writeResponse(t,r,n){this.append(`
|
|
85
|
+
######## RESPONSE (header: ${t.toFixed(0)}ms, body: ${r.toFixed(0)}ms) ########
|
|
86
|
+
|
|
87
|
+
`),this.append(n)}writeTrailer(t,r,n,o,s){this.append(`
|
|
88
|
+
# duration: ${t.toFixed(0)}ms
|
|
89
|
+
`),this.append(`# header-ttfb: ${r.toFixed(0)}ms
|
|
90
|
+
`),this.append(`# ttfb: ${n.toFixed(0)}ms
|
|
91
|
+
`),this.append(`# body-size: request=${kn(o)}, response=${kn(s)}
|
|
92
|
+
`)}async finalize(t){if(this.finalized)return this.finalizedFile;if(this.finalized=!0,!this.disabled){this._flushToPartAsync();let r=Jo(this.logDir,this.finalFilename(t)),n=this.partPath;await new Promise(o=>{this._ioChain=this._ioChain.then(async()=>{try{await gp(n,r),this.finalizedFile=this.finalFilename(t)}catch{this.finalizedFile=this.partFilename}o()})})}return this._ioChain=this._ioChain.then(()=>this._doneResolve()),this.finalizedFile??this.partFilename}async abort(){return this.finalized?this.finalizedFile:(this.finalized=!0,this.disabled||(this._flushToPartAsync(),this.finalizedFile=this.partFilename),this._ioChain=this._ioChain.then(()=>this._doneResolve()),this.finalizedFile)}_flushToPartAsync(){if(this.buf.length===0)return;let t=this.buf,r=this.partPath;this._ioChain=this._ioChain.then(async()=>{if(!this.disabled)try{await fp(hp(r),{recursive:!0}),await yp(r,t,"utf-8")}catch(n){this.disabled=!0,Sp.warn(`call-log 写失败,本调用停写:${n?.message??String(n)}`)}})}};function Cp(){return new Date().toISOString().slice(0,10)}function Tr(){return globalThis.performance?.now()??Date.now()}function ia(e=globalThis.fetch){if(!Ue().enabled)return e;let t=0;return async function(o,s){let i=Ue();if(!i.enabled)return e(o,s);let l=xt.getStore(),a=!!l?.dir,c=a?l.dir:Jo(i.dataRoot,i.appId,"_no-conv",Cp()),d=hs(),p=a?l.reserveCallIndex():++t,m=a&&l.runId?`_${Ts(l.runId)}`:"",g=s?.method??"POST",C,v={};typeof o=="string"||o instanceof URL?C=o instanceof URL?o.toString():o:(C=o.url,g=s?.method??o.method,v=zo(o.headers)),s?.headers&&(v={...v,...zo(s.headers)});let{text:P,isReal:F}=xp(s?.body),U=F?Buffer.byteLength(P,"utf-8"):0,D="";try{let $=JSON.parse(P);if($&&typeof $=="object"){let q=$.model;typeof q=="string"&&(D=q)}}catch{}let O=new Wo(c,d,m,p,i.maxFileBytes);a&&l.addPendingCall(O.done),O.writeMeta({time:new Date().toISOString(),...a&&l.runId?{run:l.runId}:{},...l?.conversationId?{conversation:l.conversationId}:{},...D?{model:D}:{},attempt:String(p)}),O.writeRequest(Ep(g,C,na(v),P));let H=Tr(),j;try{j=await e(o,s)}catch($){throw O.writeMeta({error:`fetch failed: ${String($)}`}),O.abort(),$}let se=Tr()-H,ie=na(zo(j.headers)),W=j.status,me=j.headers.get("via")??void 0,Oe=$=>{let{output:q}=Jn($.usage),fe=$.durationMs-$.ttfbMs,ae=q!==void 0&&q>0&&fe>0?Math.round(q/fe*1e3):void 0;l?.llmCall({callIndex:p,status:W,durationMs:Math.round($.durationMs),headerTtfbMs:Math.round(se),ttfbMs:Math.round($.ttfbMs),reqBytes:U,resBytes:$.resBytes,model:D,...ae!==void 0?{tps:ae}:{},...$.finishReason?{finishReason:$.finishReason}:{},...$.usage!==void 0?{usage:$.usage}:{},...$.file?{file:$.file}:{},...$.interrupted?{interrupted:!0}:{},...$.via?{via:$.via}:{}},H)};if(!j.body){O.writeResponse(se,se,oa(W,j.statusText,ie,""));let $=Tr()-H;O.writeTrailer($,se,se,U,0);let q=await O.finalize(W);return Oe({durationMs:$,ttfbMs:se,resBytes:0,file:q,...me?{via:me}:{}}),j}let[nt,yt]=j.body.tee(),ht=new Response(nt,{status:j.status,statusText:j.statusText,headers:j.headers});return(async()=>{let $=0,q=0,fe=[],ae=0,Le=!1,qe=!1,Ge=null;try{Ge=yt.getReader();let u=new TextDecoder;for(;;){let{done:y,value:h}=await Ge.read();if(y)break;if(h&&(q===0&&(q=Tr()-H),$+=h.byteLength,!Le)){let k=u.decode(h,{stream:!0}),x=Buffer.byteLength(k,"utf-8");ae+x<=i.maxFileBytes?(fe.push(k),ae+=x):Le=!0}}Le||fe.push(u.decode())}catch(u){fe.push(`
|
|
93
|
+
[stream interrupted: ${String(u)}]
|
|
94
|
+
`),qe=!0}finally{Ge?.releaseLock()}let f=fe.join(""),{text:R,truncated:w}=sa(f,i.maxFileBytes);O.writeResponse(se,q,oa(W,j.statusText,ie,R)),(w||Le)&&O.writeMeta({note:`response body truncated at ${kn(i.maxFileBytes)}`}),qe&&O.writeMeta({status:"stream-interrupted"});let M=Tr()-H;O.writeTrailer(M,se,q,U,$);let{usage:N,finishReason:b}=Rp(f),A=await O.finalize(W);Oe({durationMs:M,ttfbMs:q,resBytes:$,file:A,...b?{finishReason:b}:{},...N!==void 0?{usage:N}:{},...qe?{interrupted:!0}:{},...me?{via:me}:{}})})().catch(()=>{O.abort().catch(()=>{})}),ht}}var wp="X-Affinity-Session",kp="prompt_cache_key";function aa(){return process.env.TBOX_LLM_AFFINITY!=="off"}function la(e){return zr(e,()=>{if(!aa())return{};let t=Ke.getStore();return t?{[wp]:t}:{}})}function ca(){if(!aa())return null;let e=Ke.getStore();return e?{[kp]:e}:null}import{Agent as Mp}from"undici";function _p(){return process.env.TBOX_LLM_CONN_BIND!=="off"}function Ap(){return new Mp({connections:1,keepAliveTimeout:12e4,headersTimeout:6e4})}function vp(e,t,r,n){let o=e.get(r);return o||(o={agent:n(),lastUsedAt:Date.now()},e.set(r,o),e.size>t&&Op(e)),o.lastUsedAt=Date.now(),o.agent}function Op(e){let t=null,r=1/0;for(let[n,o]of e)o.lastUsedAt<r&&(r=o.lastUsedAt,t=n);if(t){let n=e.get(t);e.delete(t),n.agent.close().catch(()=>{})}}var Lp=new Map,Pp=256;function da(e=globalThis.fetch,t={}){let r=t.registry??Lp,n=t.cap??Pp,o=t.agentFactory??Ap;return(s,i)=>{let l=Ke.getStore();if(!_p()||!l)return e(s,i);let a;try{a=vp(r,n,l,o)}catch{return e(s,i)}return e(s,{...i,dispatcher:a})}}function Np(){return process.env.TBOX_LLM_COOKIE_AFFINITY!=="off"}var Dp=new Map,$p=1024;function ua(e,t={}){let r=t.store??Dp,n=t.cap??$p,o=zr(e,()=>{let s=Ke.getStore(),i=s?r.get(s):void 0;return i?{cookie:i}:{}});return async(s,i)=>{let l=Ke.getStore();if(!Np()||!l)return e(s,i);let a=await o(s,i);try{let c=a.headers.getSetCookie();if(c.length>0){let d=c.map(p=>p.split(";")[0].trim()).filter(p=>p.includes("="));if(d.length>0&&(r.set(l,d.join("; ")),r.size>n)){let p=r.keys().next().value;p!==void 0&&r.delete(p)}}}catch{}return a}}var Zo=Fp("model-providers");function jp(e){return e==="auto"?null:typeof e=="object"?e:{enable_thinking:e,chat_template_kwargs:{enable_thinking:e},thinking:{type:e?"enabled":"disabled"}}}function Up(e={}){let t=e.configPath??qt;function r(){return Gt(t).modelName??process.env.APP_AI_MODEL_NAME??""}let n=null;function o(){if(!n){let s=process.env.APP_AI_BASE_URL||"",i=process.env.APP_AI_API_KEY||"";Zo.info("baseURL:",s),Zo.info("apiKey:",i?"(set)":"(empty)"),n=Bp({name:"tbox",baseURL:s,apiKey:i,fetch:la(ua(ia(da()))),transformRequestBody:l=>{let a=ca(),c=jp(zs(t)),d=Js(t),p=l;return a&&(p={...p,...a}),c&&(p={...p,...c}),d!=="auto"&&(p={...p,parallel_tool_calls:d}),p}})}return n}return{getModel(s){let i=r()||s;return Zo.info("using model:",i),o().chatModel(i)},resolveModelName(){return r()}}}import{createPluginIntegration as Kp}from"@tbox.cn/agent-plugin";import{loadMastraPluginTools as Hp}from"@tbox.cn/agent-plugin/mastra";import{resolve as qp}from"path";function Gp(e={}){let t=e.configPath??qp(process.cwd(),"../../config/plugins.json"),r=e.apiKey??(()=>process.env.TBOX_API_KEY),n=Kp({config:{path:t},apiKey:r});return{integration:n,readConfig:()=>n.readConfig(),runConfiguredTool:(o,s)=>n.runConfiguredTool(o,s),loadTools:async o=>{let s=await Hp(n,{reservedToolIds:o.reservedToolIds});return{tools:s.tools,references:s.references}}}}import{Router as Wp,json as Zp}from"express";import{getRequestContext as Qp}from"@tbox.cn/app-sdk-server";import{createServerLogger as em}from"@tbox.cn/app-sdk-server";function Sr(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Vp(e){return typeof e!="object"||e===null?"non-object":(e.constructor?.name??"")||"unknown"}function Lt(e,t,r,n,o){if(typeof e!="object"||e===null)return;if("shape"in e&&Sr(e.shape)){if(!Sr(t))return;let l=e.shape;for(let[a,c]of Object.entries(t)){let d=l[a];if(d===void 0){o.violations.push({label:n,path:r,key:a});continue}Lt(d,c,r?`${r}.${a}`:a,n,o)}return}let s=e.unwrap;if(typeof s=="function"){try{Lt(s.call(e),t,r,n,o)}catch{o.blindSpots.push({label:n,path:r,reason:"unwrap() 调用失败"})}return}if("element"in e&&e.element){if(Array.isArray(t)){let l=e.element;t.forEach((a,c)=>Lt(l,a,`${r}[${c}]`,n,o));return}Sr(t)&&o.blindSpots.push({label:n,path:r,reason:"element 节点遇到对象值(record/类型不匹配),子树不检查"});return}if("options"in e){(Sr(t)||Array.isArray(t))&&o.blindSpots.push({label:n,path:r,reason:"union 分支选择无法静态判定"});return}let i=e.schema;if(i&&typeof i=="object"){Lt(i,t,r,n,o);return}(Sr(t)||Array.isArray(t))&&o.blindSpots.push({label:n,path:r,reason:`未识别 schema 节点(${Vp(e)}),子树不检查`})}function Qo(e){let t={violations:[],blindSpots:[]},r=e.dataSchema;Lt(r,e.sampleData,"","初始态",t);for(let n of e.samples??[])Lt(r,n.data,"",n.label,t);return t}var oe=class extends Error{constructor(r,n,o){super(o);this.status=r;this.code=n;this.name="PreviewActionError"}status;code},Xp="(未声明)",pa="初始态";function Yp(e){return{actionId:e.actionId,...e.label!==void 0?{label:e.label}:{},...e.kind!==void 0?{kind:e.kind}:{},...e.value!==void 0?{value:e.value}:{},...e.visible!==void 0?{visible:e.visible}:{},...e.url!==void 0?{url:e.url}:{},...e.style!==void 0?{style:e.style}:{},...e.enabled!==void 0?{enabled:e.enabled}:{},...e.disabledReason!==void 0?{disabledReason:e.disabledReason}:{}}}function es(e){return e?.issues?.[0]?.message??e?.message??""}function ma(e,t,r){let n=[];r?.length&&n.push(...r);let o=e.dataSchema.safeParse(t.data);o.success||n.push(`schema: ${es(o.error)||"未通过 dataSchema 校验"}`);let s,i;try{s=e.project?.(t.data)}catch(l){i=`信封投影失败:${l.message}`}return{...t,...n.length?{issues:n}:{},...s?{envelope:s}:{},...i?{envelopeError:i}:{}}}function zp(e){let t=Qo(e),r=new Map;for(let n of t.violations){let o=r.get(n.label)??[];o.push(`shape: ${n.path?`${n.path}.`:""}${n.key} 不在 dataSchema shape 内(将被剥离)`),r.set(n.label,o)}return r}function ga(e){let t=new Map;for(let n of e.cardActions.getAll().values()){if(n.hidden)continue;let o=t.get(n.cardType)??[];o.push(Yp(n)),t.set(n.cardType,o)}let r=[];for(let[n,o]of Object.entries(e.cards.getAll())){let s=zp(o),i=ma(o,{label:pa,data:o.sampleData,initial:!0},s.get(pa)),l=(o.samples??[]).map(a=>ma(o,{label:a.label,...a.note!==void 0?{note:a.note}:{},...a.group!==void 0?{group:a.group}:{},data:a.data,...a.isHistory!==void 0?{isHistory:a.isHistory}:{},...a.noTokens!==void 0?{noTokens:a.noTokens}:{}},s.get(a.label)));r.push({moduleId:e.cards.ownerOf(n)??Xp,cardType:n,displayName:o.displayName,description:o.description,actions:t.get(n)??[],samples:[i,...l]})}return r.sort((n,o)=>n.moduleId===o.moduleId?n.cardType.localeCompare(o.cardType):n.moduleId.localeCompare(o.moduleId)),{cards:r}}var Jp=0;function fa(e,t,r,n){let o=e.cards.resolve(t);if(!o)throw new oe(500,"result_schema_invalid",`结果卡类型未注册:${t}`);let s=o.dataSchema.safeParse(r);if(!s.success)throw new oe(500,"result_schema_invalid",`结果数据未通过 ${t} dataSchema 校验:${es(s.error)||"校验失败"}`);let i;try{i=o.project?.(s.data)}catch(l){throw new oe(500,"result_project_failed",`信封投影失败:${l.message}`)}return{id:n,cardType:t,data:s.data,status:"ready",schemaVersion:o.schemaVersion??1,meta:{createdAt:Date.now()},...i??{}}}async function ya(e,t,r){if(t.identity.source==="anonymous")throw new oe(403,"anonymous_write","匿名身份不可执行卡片动作(预览面)");let n=e.cardActions.get(r.actionId);if(!n)throw new oe(404,"unknown_action",`未知动作:${r.actionId}`);if(n.cardType!==r.cardType)throw new oe(400,"card_type_mismatch",`动作 ${r.actionId} 属于 ${n.cardType},与来源卡 ${r.cardType} 不一致`);if(n.kind==="sendMessage"||n.kind==="openLink")throw new oe(400,"client_only_action",`动作 ${r.actionId} 为纯客户端语义(${n.kind}),不经服务端执行`);let o=r.input&&typeof r.input=="object"&&!Array.isArray(r.input)?r.input:{},s=o;if(n.inputSchema){let a=n.inputSchema.safeParse(o);if(!a.success)throw new oe(400,"input_invalid",`入参校验失败:${es(a.error)||"校验失败"}`);s=a.data}if(!n.execute)throw new oe(400,"no_execute",`动作 ${r.actionId} 无服务端执行体`);let i;try{i=await n.execute(s,t)}catch(a){throw new oe(500,"execute_failed",a.message)}if(!i||typeof i!="object")throw new oe(500,"result_invalid","动作结果形状非法");if(i.card&&i.update)throw new oe(500,"result_invalid","card 与 update 互斥");let l={...i.text!==void 0?{text:i.text}:{},...i.effects?{effects:i.effects}:{}};if(i.update){if(!r.surfaceId)throw new oe(500,"result_invalid","原地更新需要来源卡 surfaceId");return{ok:!0,kind:"update",card:fa(e,n.cardType,i.update.data,r.surfaceId),...l}}return i.card?{ok:!0,kind:"card",card:fa(e,i.card.cardType,i.card.data,`preview-result-${++Jp}`),...l}:{ok:!0,kind:"none",...l}}var ha=em("tbox-dev");function tm(e,t){if(process.env.NODE_ENV==="production")return;let r=Wp();r.use((n,o,s)=>{o.set("Cache-Control","no-store"),s()}),r.get("/cards",(n,o)=>{o.json(ga(t.ctx))}),r.post("/card-action",(n,o)=>{let s=n.body??{},i=s?.cardType,l=s?.actionId,a=s?.surfaceId;if(typeof i!="string"||typeof l!="string"||typeof a!="string"){o.status(400).json({ok:!1,error:"bad_request: cardType/actionId/surfaceId 必填"});return}let c=Qp(n);if(!c){o.status(401).json({ok:!1,error:"unauthorized: 缺少请求上下文"});return}ya(t.ctx,c,{cardType:i,actionId:l,surfaceId:a,...s.input!==void 0?{input:s.input}:{}}).then(d=>o.json(d)).catch(d=>{if(d instanceof oe){o.status(d.status).json({ok:!1,error:`${d.code}: ${d.message}`});return}ha.warn("card-action error:",d),o.status(500).json({ok:!1,error:`internal: ${d.message}`})})}),r.use((n,o)=>{o.status(404).json({ok:!1,error:"not_found"})}),e.use("/_tbox/api",Zp(),t.auth.middleware,r),ha.info("/_tbox/api 已挂载(卡片预览:/_tbox/card-preview)")}export{Br as BROAD_ROUTING_TERMS,bt as BUILTIN_HYGIENE_NAMES,Er as CARDS_SPEC,Ia as CARD_DECISION_HOLD_LIMIT,z as CARD_DECISION_TAG,$n as CARD_EMISSION_HINT_ACTIONS,kr as CARD_EMISSION_HINT_BASE,us as CARD_EMISSION_HINT_KEYWORD,yr as ConversationService,_n as DECISION_HOLD_LIMIT,Bo as DEFAULT_INSTRUCTIONS,Eo as DEFAULT_KNOWLEDGE_MEMORY_CAPABILITIES,fo as DEFAULT_LIST_TTL_MS,qt as DEFAULT_LLM_PROVIDER_CONFIG_PATH,Ir as DEFAULT_MAX_CARDS_PER_TURN,go as DEFAULT_MAX_ENTRIES,Ks as DEFAULT_MAX_PRE_TOOLS_PER_RUN,Wt as DEFAULT_MEMORY_MAX_CHARS_PER_RECORD,ir as DEFAULT_MEMORY_RECALL_TIMEOUT_MS,tn as DEFAULT_MEMORY_TOP_K,ar as DEFAULT_MEMORY_VALIDATE_TIMEOUT_MS,Ct as DEFAULT_PRE_TOOL_TIMEOUT_MS,Kt as DEFAULT_SKILL_MODE,ba as DROP_BODY_SOFT_LIMIT,Rr as EARLY_EXECUTION_MARKER,jt as FORM_SUBMIT_TOOL_ID,Do as FileCardPersistenceBackend,ns as HYGIENE_TAG_NORMALIZE,Fn as INTERNAL_TOOL,et as KB_SCOPE_GLOBAL,So as KNOWLEDGE_DEFAULT_BASE_URL,tt as KnowledgeBootstrapError,he as KnowledgeOpenapiError,dt as MEMORY_IMPORTANCE_BASE,xo as MEMORY_KB_INDEX_COLUMNS,an as MEMORY_KB_SCHEMA,Ro as MEMORY_KB_SEED_CSV,Xt as MEMORY_LIST_DEFAULT_LIMIT,Yt as MEMORY_LIST_MAX_LIMIT,Vt as MEMORY_MAX_PER_USER,nr as MemoryStoreUnsupportedError,sr as MemoryUnavailableError,No as MessageEmbeddedBackend,Us as PRE_TOOL_HISTORY_LIMIT,Vr as PreToolTimeoutError,oe as PreviewActionError,Un as TBOX_FILE_URL_PREFIX,vn as THINK_SPECS,On as TOOL_CALL_TEXT_SPECS,Bt as TOOL_CARDS_FIELD,Na as TOOL_CARD_DESCRIPTOR_SCHEMA,Lr as TboxTraceExporter,nc as applySkillReminder,di as bootstrapMemoryKnowledgeBase,Nn as buildCardDecisionReminder,$s as buildInjectedUserContent,Mt as buildMemoryRecallToolCallEvents,er as buildMemoryReminder,Bd as buildMessageInputs,Pn as buildPlatformInstructions,Yr as buildPreToolCallEndEvents,co as buildPreToolCallStartEvents,lo as buildPreToolDirectives,Bs as buildRecapUserContent,Hr as buildSkillRecapReminder,Ur as buildSkillReminder,so as buildSkillToolCallEvents,Kn as buildUserContent,Dn as captureToolCards,mn as clampMaxCards,Zt as clampMemoryMaxChars,kt as clampMemoryTopK,pr as coerceStringifiedFields,vr as composeTurnUserContent,Ea as createCardDecisionStripper,Mr as createCardPool,Wd as createCardTool,vo as createChatEngine,qo as createConversationRouter,$d as createEngineFromContext,cn as createGatedMemoryStore,wt as createInMemoryMemoryStore,Fl as createIntentDispatcher,sn as createKnowledgeMemoryStore,rr as createKnowledgeOpenapiTransport,Go as createMemoryRouter,nn as createMemoryTools,Up as createModelProvider,ip as createPlatformApiRouter,Gp as createPluginIntegration,Di as createSdkToolRuntime,It as createStreamTagEngine,Ka as createTool,ud as createToolExecContext,up as createTtsProxy,Xd as createWsServer,Ln as decideCards,Kr as decideSkillInjection,dc as definePreTool,rs as envelopeTag,uo as executePreTool,Ha as extractImageUrls,Qo as findSampleShapeViolations,vl as formSubmitTool,Jt as generateMemoryId,Zr as getLastRecallCacheState,yi as getToolRequestContext,Mo as getToolRunMetadata,wn as getTtsClient,Ni as hardenToolsForLlm,zt as hashContent,In as healthRouter,St as hygieneXmlTag,tm as installTboxDev,Ba as internalTool,hu as loadAgentPromptConfig,iu as loadChatConfig,vs as loadLocalSkills,Vl as loadModuleSkills,Fr as matchIntent,Qe as memoryStoreCapabilities,Bi as mergePreTools,$i as mergeSkills,Fi as normalizePreTools,Ar as omitInternal,os as pickFallbackCard,Xr as projectHistory,Qt as recallMemories,dd as requireToolRequestContext,Vo as resetTtsClient,Md as resolveEarlyToolExecution,cr as resolveMaxSteps,rn as resolveMemoryEngineOptions,dn as resolveMemoryRecallTimeout,Co as resolveMemoryStore,pi as resolveMemoryStoreGuarded,wo as resolveMemoryValidateMode,ko as resolveMemoryValidateTimeout,cc as resolvePreToolTimeout,Zl as resolveSkillMode,po as resolveTagSpecs,kd as resolveToolDebug,to as restoreCardSnapshot,_r as sanitizeLlmToolInput,Ns as scanInjectedSkills,xe as scopeToKey,ao as selectPreTools,ec as selectSkill,io as stableStringify,ze as stripSystemReminderBlocks,En as tboxSessionRouter,Pr as tboxTraceExporter,ro as toCardSnapshot,oo as toMastraSkill,au as toWsChatConfig,xr as tokenizeTagBody,lt as toolCardScope,ln as validateMemoryKnowledgeBase,ja as withCardEmissionHint,Ht as withDeadline,Fa as withEarlyExecution,jn as withLlmInputSanitize,ri as withRecallCache,Bn as wrapToolsForCardCapture,ts as xmlTag,An as xmlTagDecision};
|