page-agent-sdk 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/page-agent-sdk.iife.js +80 -80
- package/dist/page-agent-sdk.js +7 -4
- package/dist/page-agent-sdk.umd.cjs +1 -1
- package/package.json +3 -2
- package/types/index.d.ts +2 -0
package/dist/page-agent-sdk.js
CHANGED
|
@@ -16894,6 +16894,8 @@ function ny(e, r) {
|
|
|
16894
16894
|
mcpClosers: [],
|
|
16895
16895
|
mcpServers: [],
|
|
16896
16896
|
checkpoint: h,
|
|
16897
|
+
windowOpsController: b,
|
|
16898
|
+
liveWindowProps: x,
|
|
16897
16899
|
applySnapshot(t) {
|
|
16898
16900
|
t.messages?.length && c.push(...t.messages), t.vfs && l.hydrate && l.hydrate(t.vfs), t.todos?.length && u.reset(t.todos), t.memory && !e.memory && d.reset(t.memory);
|
|
16899
16901
|
},
|
|
@@ -16944,6 +16946,7 @@ function ny(e, r) {
|
|
|
16944
16946
|
return {
|
|
16945
16947
|
id: r,
|
|
16946
16948
|
model: Yv(e.llm) ? e.llm.model ?? e.llm.modelName : e.llm.model,
|
|
16949
|
+
systemPrompt: e.systemPrompt ?? Kv,
|
|
16947
16950
|
tools: O.map((e) => ({
|
|
16948
16951
|
name: e.name,
|
|
16949
16952
|
description: e.description,
|
|
@@ -17107,14 +17110,14 @@ function ry(e) {
|
|
|
17107
17110
|
listCheckpoints: () => i.checkpoint?.list() ?? [],
|
|
17108
17111
|
hook: (e) => (i.listeners.add(e), () => i.listeners.delete(e)),
|
|
17109
17112
|
addWindowProp: (e) => {
|
|
17110
|
-
if (!windowOpsController) {
|
|
17113
|
+
if (!i.windowOpsController) {
|
|
17111
17114
|
console.warn("[page-agent-sdk] addWindowProp 忽略:windowOps 已关闭(capabilities.windowOps:false)");
|
|
17112
17115
|
return;
|
|
17113
17116
|
}
|
|
17114
|
-
windowOpsController.add(e);
|
|
17117
|
+
i.windowOpsController.add(e);
|
|
17115
17118
|
},
|
|
17116
|
-
removeWindowProp: (e) => windowOpsController ? windowOpsController.remove(e) : !1,
|
|
17117
|
-
listWindowProps: () => liveWindowProps()
|
|
17119
|
+
removeWindowProp: (e) => i.windowOpsController ? i.windowOpsController.remove(e) : !1,
|
|
17120
|
+
listWindowProps: () => i.liveWindowProps()
|
|
17118
17121
|
};
|
|
17119
17122
|
}
|
|
17120
17123
|
//#endregion
|
|
@@ -149,4 +149,4 @@ self.onmessage = async (e) => {
|
|
|
149
149
|
|
|
150
150
|
`),Wv=50;function Gv(e){return e===void 0||e===!1?null:typeof e==`string`?Hv({backend:e}):e.enabled===!1?null:Hv(e)}function Kv(e){return!!e&&typeof e==`object`&&typeof e.invoke==`function`&&typeof e.stream==`function`}var qv=new Map;function Jv(e){let t=e.content;return typeof t==`string`?t:Array.isArray(t)?t.map(e=>typeof e==`string`?e:e?.text??``).join(``):String(t??``)}function Yv(e){let t=e.summaryLlm??e.llm;if(!t)return;let n=e.summaryTemperature??.3,a=e.summaryMaxTokens??1024,o=e.summaryTimeoutMs??15e3,s;if(Kv(t))s=t;else{let r=t;if(!r.apiKey){e.summaryLlm&&console.warn(`[page-agent-sdk][summarization] summaryLlm 已配置但缺 apiKey,摘要回退主 agent 模型或零成本索引摘要`);return}s=new i.ChatOpenAI({apiKey:r.apiKey,model:r.model,temperature:n,maxTokens:a,configuration:r.baseUrl?{baseURL:r.baseUrl}:void 0})}return async e=>{let t=new AbortController,n=setTimeout(()=>t.abort(),o);try{return Jv(await s.invoke([new r.SystemMessage(`你是对话历史压缩助手。把下面按轮次索引的对话要点,改写成一段连贯、紧凑的中文摘要,保留关键事实、用户意图与已用工具,不要编造。直接输出摘要正文。`),new r.HumanMessage(e)],{signal:t.signal})).trim()}finally{clearTimeout(n)}}}function Xv(e){return e===`set_window_prop`?`set`:e===`edit_window_prop`?`edit`:e===`delete_window_prop`?`delete`:e===`restore_window_snapshot`?`restore`:null}function Zv(e){let t=e.split(`.`),n=globalThis.window;for(let e of t){if(n==null)return;n=n[e]}return n}function Qv(e,t){return{name:`sdk-events`,wrapToolCall:async(t,n)=>{let r=await n(t),i=Xv(t.name);if(i){let n=String(t.args?.path??``);e({type:`window_prop_change`,path:n,operation:i,value:n?Zv(n):void 0})}return r},afterAgent:async()=>{e({type:`message_update`,count:t.length})}}}function $v(e,r){let i=Gv(e.storage);e.debug&&i&&i.onEvent(e=>console.log(`[page-agent-sdk][storage]`,e));let a=Kv(e.llm)?void 0:e.llm,o=Vh({model:a?.model,contextWindow:e.contextWindow??a?.contextWindow,maxOutputTokens:e.maxOutputTokens??a?.maxOutputTokens});e.debug&&console.log(`[page-agent-sdk][modelCaps]`,o);let s=Yv(e);e.debug&&!s&&console.warn(`[page-agent-sdk][summarization] 未构造 llmInvoke(apiKey 缺失?),摘要回退零成本索引摘要`);let c=Yt([]),l=k_(e.vfs?.initialFiles,{persist:i?{save:e=>{B.sessionId&&i&&i.save(r,B.sessionId,{vfs:e})}}:void 0,maxBytes:e.vfs?.maxBytes}),u=og(),d=mg(e.memory||``),f={current:null},p=e.checkpoint,m=p!==void 0&&p!==!1,h=m?jg({windowPaths:(e.windowProps??[]).map(e=>e.path),vfsStore:l,todosMw:u,getTodos:()=>f.current?.getState?.()?.todos??[],messages:c,maxCheckpoints:p&&typeof p==`object`?p.maxCheckpoints:void 0}):null,g=!p||typeof p!=`object`||p.auto!==!1,_=e.capabilities,v=_?.windowOps!==!1,y=v?uv(e.windowProps||[],{onAudit:e.debug?e=>console.log(`[page-agent-sdk][window audit]`,e):void 0,maxSnapshots:e.maxSnapshots}):[],b=v?y.controller??null:null,x=()=>b?.list()??e.windowProps??[],S=new Map,C=hv(_,y,fv);C.forEach(e=>S.set(e.name,`builtin`));let w=[...e.tools||[]];w.forEach(e=>S.set(e.name,`user`));let T=e.humanConfirm!==!1&&(!e.approval||e.approval.humanConfirmTool!==!1),E=T?Cg():null;E&&S.set(xg,`builtin`);let D=m&&h?[(0,n.tool)(async()=>{let e=h.list();return e.length?h.restore()?`已回退到最近一次正常状态(checkpoint #${e[e.length-1].id})。对话历史、window 注册属性、vfs、todos 已整体还原。请基于回退后的状态重新判断并继续。`:`回退失败:无可用 checkpoint。`:`无可用 checkpoint,无法回退。`},{name:`restore_last_checkpoint`,description:`回退到最近一次正常状态(整体还原对话历史 + window 注册属性 + vfs + todos)。当本轮操作出错、页面被改坏、或走偏时调用,回到本轮起点重新来过。不传参数即回退最近一次。`,schema:t.z.object({}).optional()}),(0,n.tool)(async()=>{let e=h.list();return e.length?`可用 checkpoint:
|
|
151
151
|
`+e.map(e=>`#${e.id} [${e.label??`auto`}] 消息数=${e.messageCount} 时间=${new Date(e.timestamp).toLocaleTimeString()}`).join(`
|
|
152
|
-
`):`无可用 checkpoint。`},{name:`list_checkpoints`,description:`列出可用会话 checkpoint(回退点)。`,schema:t.z.object({}).optional()})]:[];D.forEach(e=>S.set(e.name,`builtin`));let O=[...C,...w,...E?[E]:[],...D],k=_?.planning!==!1,A=_?.skills!==!1,j=_?.vfs!==!1,M=_?.summarization!==!1,ee=_?.memory!==!1,N=_?.subagent!==!1,P=e.verify?.maxAttempts??2,F=_?.verify===!0&&e.verify?.enabled!==!1&&P>0;e.verify?.check&&_?.verify!==!0&&console.warn(`[page-agent-sdk][verify] 检测到 verify.check 但 capabilities.verify 未开启,verify 未装载`);let I=e.subagent,te=I?.allowedTools??[],L=!N||I?.enabled===!1?void 0:Bg({llm:I?.llm??e.llm,allTools:O,allowedTools:te.length?te:void 0,systemPrompt:I?.systemPrompt,temperature:I?.temperature,maxTokens:I?.maxTokens,skills:I?.skills,maxDepth:I?.maxDepth,maxParallel:I?.maxParallel,debug:e.debug}),ne=e.subagents?.length?Ug(e.subagents,{llm:e.llm,allTools:O,debug:e.debug}):void 0,re=[`get_window_prop`,`get_window_paths`,`list_window_props`,`describe_window_prop`,`fetch_document`],ie=O.filter(e=>re.includes(e.name)),R=F?Wg({check:e.verify.check??Xg({schemas:()=>Object.fromEntries(x().map(e=>[e.path,e.schema]))}),adversarial:e.verify?.adversarial?{llm:e.llm,tools:ie}:void 0}):void 0,ae=_v({..._,humanConfirm:T,subagents:e.subagents?.map(e=>({id:e.id,description:e.description,temperature:e.temperature}))},v&&!!e.windowProps?.length),oe=e.onEvent,se=new Set,ce=e=>{if(e.type!==`approval_request`){if(oe)try{oe(e)}catch{}for(let t of se)try{t(e)}catch{}}},z=[ae,...k?[u]:[],...A?[pg(e.skills||[],{readVfs:j?e=>l.files[e]?.content:void 0})]:[],...j?[I_(l)]:[],...M?[b_({...w_(e,o.contextWindow),llmInvoke:s,getRegisteredProps:()=>x().map(e=>({path:e.path,description:e.description})),preserveLastToolResults:(e.contextOptions&&e.contextOptions.preserveLastToolResults)??[`describe_window_prop`,`list_window_props`]})]:[],...ee?[d]:[],...e.permissions?.length?[yg(e.permissions)]:[],...m&&g&&h?[Mg(h)]:[],...T?[wg()]:[],...e.approval&&(e.approval.tools!==void 0||e.approval.confirm)?[bg(e.approval)]:[],...R?[R]:[],...L?[L]:[],...ne?[ne]:[],...e.middleware||[],Qv(ce,c)],le=e.maxMemoryRounds??Wv,B={agentId:r,store:i,messages:c,vfsStore:l,listeners:se,todosMw:u,memoryMw:d,agent:null,initDone:Promise.resolve(),sessionId:``,refCount:0,mcpClosers:[],mcpServers:[],checkpoint:h,applySnapshot(t){t.messages?.length&&c.push(...t.messages),t.vfs&&l.hydrate&&l.hydrate(t.vfs),t.todos?.length&&u.reset(t.todos),t.memory&&!e.memory&&d.reset(t.memory)},afterRound(){de(),fe()},async send(e){await B.initDone,c.push({role:`user`,content:e,timestamp:Date.now()});try{let e=await B.agent.invoke(c);return c.push({role:`assistant`,content:e,timestamp:Date.now()}),B.afterRound(),i&&await i.flush(),e}catch(e){throw ce({type:`error`,message:e?.message||String(e)}),e}},async switchSession(t){if(await B.initDone,!i)throw Error(`page-agent-sdk: storage 未开启,无法切换会话(请传 storage 选项)`);l.flush?.(),await i.flush();let n=t??``,a;return n?(a=await i.load(r,n),a||await i.createSession(r,e.session?.title,n)):n=await i.createSession(r,e.session?.title),B.sessionId=n,c.splice(0,c.length),l.clear?.(),u.reset([]),e.memory||d.reset(``),B.agent.debugLogs.value=[],a||=await i.load(r,n),a&&B.applySnapshot(a),e.memory&&i.save(r,B.sessionId,{memory:e.memory}),n},stream:(e,t,n)=>{if(!B.agent)throw Error(`page-agent-sdk: agent 尚未初始化完成,请先 await mount()`);let r=oe?e=>{t?.(e),ce(e)}:t;return B.agent.stream(e,r,n)},release(){if(B.refCount--,B.refCount<=0){i&&(l.flush?.(),i.flush(),i.dispose());let e=B.mcpClosers.splice(0);e.length&&Promise.allSettled(e.map(e=>e())),qv.delete(r)}},getInfo(){return{id:r,model:Kv(e.llm)?e.llm.model??e.llm.modelName:e.llm.model,tools:O.map(e=>({name:e.name,description:e.description,schema:e.schema,source:S.get(e.name)||`user`})),skills:(e.skills??[]).map(e=>({name:e.name,description:e.description})),windowProps:x().map(e=>({path:e.path,description:e.description,schema:e.schema})),memory:e.memory??``,middleware:z.map(e=>e.name),todos:(B.agent?.getState?.()?.todos??[]).map(e=>({content:e.content,status:e.status})),subagent:{enabled:!!L,maxDepth:e.subagent?.maxDepth??1,maxParallel:e.subagent?.maxParallel??4,allowedTools:e.subagent?.allowedTools??[]},verify:{enabled:!!R,maxAttempts:F?P:0,adversarial:F&&!!e.verify?.adversarial},mcp:{servers:B.mcpServers},lastCompression:B.agent?.getState?.()?.lastCompression,checkpoints:h?{enabled:!0,auto:g,list:h.list()}:void 0}}};async function ue(){if(!i)return;await i.ready;let t=e.session||{};if(t.id){B.sessionId=t.id;let e=await i.load(r,B.sessionId);e?B.applySnapshot(e):await i.createSession(r,t.title,B.sessionId)}else if(t.autoResume!==!1){let n=await i.listSessions(r);if(e.debug&&console.log(`[page-agent-sdk][restore] listSessions`,r,n.length,n.map(e=>e.sessionId)),n.length){B.sessionId=n[0].sessionId;let t=await i.load(r,B.sessionId);t?(B.applySnapshot(t),e.debug&&console.log(`[page-agent-sdk][restore] 恢复会话`,B.sessionId,`${t.messages?.length??0} msgs`)):e.debug&&console.log(`[page-agent-sdk][restore] 会话 meta 存在但快照为空`,B.sessionId)}else B.sessionId=await i.createSession(r,t.title),e.debug&&console.log(`[page-agent-sdk][restore] 新建会话(无历史)`,B.sessionId)}else B.sessionId=await i.createSession(r,t.title);e.memory&&i.save(r,B.sessionId,{memory:e.memory})}function de(){let e=u_(c,le);e.trimmed&&c.splice(e.deleteFrom,e.deleteCount,e.summary)}function fe(){if(!B.sessionId||!i)return;let t=JSON.parse(JSON.stringify(c));i.save(r,B.sessionId,{messages:t});let n=B.agent?.getState?.()?.todos??[];i.save(r,B.sessionId,{todos:n}),e.debug&&console.log(`[page-agent-sdk][persist] save`,B.sessionId,`${c.length} msgs`)}return B.initDone=(async()=>{if(await ue(),e.mcp?.length){let t=await Promise.allSettled(e.mcp.map(e=>o_(e)));B.mcpClosers=t.flatMap(e=>e.status===`fulfilled`?[e.value.close]:[]),B.mcpServers=[];let n=[];t.forEach((t,r)=>{let i=e.mcp[r],a=i.name??i.url;t.status===`fulfilled`?(B.mcpServers.push({name:a,url:i.url,toolCount:t.value.tools.length}),t.value.tools.forEach(e=>S.set(e.name,`mcp:${a}`)),n.push(...t.value.tools)):console.warn(`[page-agent-sdk][mcp] server ${a} 连接失败:`,t.reason)}),O.push(...n),e.debug&&console.log(`[page-agent-sdk][mcp] 注入 ${n.length} 个工具,${B.mcpServers.length} 个 server`)}B.agent=ig({...Kv(e.llm)?{llm:e.llm}:{apiKey:e.llm.apiKey,baseUrl:e.llm.baseUrl,model:e.llm.model,temperature:e.llm.temperature,maxTokens:e.llm.maxTokens},systemPrompt:e.systemPrompt??Uv,tools:O,middleware:z,maxToolRounds:e.maxToolRounds,maxRetries:e.maxRetries,maxParallelTools:e.maxParallelTools,contextWindow:o.contextWindow,maxOutputTokens:o.maxOutputTokens,maxVerifyAttempts:F?P:0,debug:e.debug}),f.current=B.agent})(),B}function ey(e){let t=e.id??vv();e.id||console.warn(`[page-agent-sdk] 未传 options.id,已生成随机 id "${t}"。刷新后持久化数据无法恢复,请传稳定 id。`);let n=e.streaming??!0,r=e.ui??`default`,i,a=e.shareContext?qv.get(t):void 0;a?i=a:(i=$v(e,t),e.shareContext&&qv.set(t,i)),i.refCount++;let o=null,s=null,c=null;async function l(){if(await i.initDone,r===!1){i.store&&(s=()=>{i.vfsStore.flush?.(),i.store.flush()},c=()=>{document.visibilityState===`hidden`&&i.store.flush()},typeof window<`u`&&window.addEventListener(`pagehide`,s),typeof document<`u`&&document.addEventListener(`visibilitychange`,c));return}let t=typeof e.container==`string`?document.querySelector(e.container):e.container;if(!t)throw Error(`createChatSdk: 挂载点未找到(${e.container})`);let a=i.agent.debugLogs;o=sl(xi({setup(){return()=>Ls(Fh,{fetchStream:n?i.agent.stream:void 0,fetchResponse:n?void 0:(e,t)=>i.agent.invoke(e,t),title:e.title,placeholder:e.placeholder,debugLogs:a.value,initialMessages:i.messages,getInfo:()=>i.getInfo(),onUndo:i.checkpoint?()=>i.checkpoint.restore():void 0,canUndo:i.checkpoint?()=>i.checkpoint.canRestore():void 0,onPersist:async()=>{i.afterRound(),i.store&&await i.store.flush()},onClear:()=>{i.store&&(i.sessionId=vv(),i.vfsStore.clear?.(),i.todosMw.reset([]),e.memory||i.memoryMw.reset(``),i.agent.debugLogs.value=[],i.store.createSession(i.agentId,e.session?.title,i.sessionId))}})}})),o.mount(t),i.store&&(s=()=>{i.vfsStore.flush?.(),i.store.flush()},c=()=>{document.visibilityState===`hidden`&&i.store.flush()},typeof window<`u`&&window.addEventListener(`pagehide`,s),typeof document<`u`&&document.addEventListener(`visibilitychange`,c))}function u(){s&&typeof window<`u`&&window.removeEventListener(`pagehide`,s),c&&typeof document<`u`&&document.removeEventListener(`visibilitychange`,c),s=null,c=null,o?.unmount(),o=null,i.release()}return{mount:l,unmount:u,send:i.send,switchSession:i.switchSession,stream:i.stream,inspect:i.getInfo,messages:i.messages,restoreLastCheckpoint:()=>i.checkpoint?.restore()??!1,listCheckpoints:()=>i.checkpoint?.list()??[],hook:e=>(i.listeners.add(e),()=>i.listeners.delete(e)),addWindowProp:e=>{if(!windowOpsController){console.warn(`[page-agent-sdk] addWindowProp 忽略:windowOps 已关闭(capabilities.windowOps:false)`);return}windowOpsController.add(e)},removeWindowProp:e=>windowOpsController?windowOpsController.remove(e):!1,listWindowProps:()=>liveWindowProps()}}function ty(e){return(0,n.tool)(async t=>{let n=await e.handler(t);return typeof n==`string`?n:JSON.stringify(n)},{name:e.name,description:e.description,schema:e.schema})}e.CONTEXT_PRESETS=C_,e.ChatDialog=Fh,e.CodePreview=Yd,e.HUMAN_CONFIRM_TOOL_NAME=xg,e.MessageContent=Zd,e.connectMcp=o_,e.createAgent=ig,e.createApprovalMiddleware=bg,e.createChatSdk=ey,e.createCheckpointManager=jg,e.createCheckpointMiddleware=Mg,e.createHumanConfirmMiddleware=wg,e.createHumanConfirmTool=Cg,e.createMemoryBackend=Rv,e.createSessionStore=Hv,e.createSubagentMiddleware=Bg,e.createSubagentsMiddleware=Ug,e.createUsageHintsMiddleware=_v,e.createVerifyMiddleware=Wg,e.createVfs=k_,e.createWebStorageBackend=Bv,e.createWindowOps=uv,e.createWriteBackCheck=Xg,e.defineSkill=sg,e.defineTool=ty,e.defineWindowToolset=mv,e.estimateTokens=Hh,e.extractText=r_,e.fetchDocTools=fv,e.fetchTools=pv,e.formatZodIssues=T_,e.isQuotaError=Av,e.jpEval=K_,e.jsonParseError=D_,e.offloadPassThroughChars=Wh,e.offloadThresholdChars=Uh,e.presets=x_,e.resolveContextOptions=w_,e.resolveModelCaps=Vh,e.runSandboxedScript=Z_,e.searchJson=J_,e.selectBuiltinTools=hv,e.systemPromptHelpers=S_,e.toolError=$,e.useChat=vl,Object.defineProperty(e,"z",{enumerable:!0,get:function(){return t.z}}),e.zodError=E_});
|
|
152
|
+
`):`无可用 checkpoint。`},{name:`list_checkpoints`,description:`列出可用会话 checkpoint(回退点)。`,schema:t.z.object({}).optional()})]:[];D.forEach(e=>S.set(e.name,`builtin`));let O=[...C,...w,...E?[E]:[],...D],k=_?.planning!==!1,A=_?.skills!==!1,j=_?.vfs!==!1,M=_?.summarization!==!1,ee=_?.memory!==!1,N=_?.subagent!==!1,P=e.verify?.maxAttempts??2,F=_?.verify===!0&&e.verify?.enabled!==!1&&P>0;e.verify?.check&&_?.verify!==!0&&console.warn(`[page-agent-sdk][verify] 检测到 verify.check 但 capabilities.verify 未开启,verify 未装载`);let I=e.subagent,te=I?.allowedTools??[],L=!N||I?.enabled===!1?void 0:Bg({llm:I?.llm??e.llm,allTools:O,allowedTools:te.length?te:void 0,systemPrompt:I?.systemPrompt,temperature:I?.temperature,maxTokens:I?.maxTokens,skills:I?.skills,maxDepth:I?.maxDepth,maxParallel:I?.maxParallel,debug:e.debug}),ne=e.subagents?.length?Ug(e.subagents,{llm:e.llm,allTools:O,debug:e.debug}):void 0,re=[`get_window_prop`,`get_window_paths`,`list_window_props`,`describe_window_prop`,`fetch_document`],ie=O.filter(e=>re.includes(e.name)),R=F?Wg({check:e.verify.check??Xg({schemas:()=>Object.fromEntries(x().map(e=>[e.path,e.schema]))}),adversarial:e.verify?.adversarial?{llm:e.llm,tools:ie}:void 0}):void 0,ae=_v({..._,humanConfirm:T,subagents:e.subagents?.map(e=>({id:e.id,description:e.description,temperature:e.temperature}))},v&&!!e.windowProps?.length),oe=e.onEvent,se=new Set,ce=e=>{if(e.type!==`approval_request`){if(oe)try{oe(e)}catch{}for(let t of se)try{t(e)}catch{}}},z=[ae,...k?[u]:[],...A?[pg(e.skills||[],{readVfs:j?e=>l.files[e]?.content:void 0})]:[],...j?[I_(l)]:[],...M?[b_({...w_(e,o.contextWindow),llmInvoke:s,getRegisteredProps:()=>x().map(e=>({path:e.path,description:e.description})),preserveLastToolResults:(e.contextOptions&&e.contextOptions.preserveLastToolResults)??[`describe_window_prop`,`list_window_props`]})]:[],...ee?[d]:[],...e.permissions?.length?[yg(e.permissions)]:[],...m&&g&&h?[Mg(h)]:[],...T?[wg()]:[],...e.approval&&(e.approval.tools!==void 0||e.approval.confirm)?[bg(e.approval)]:[],...R?[R]:[],...L?[L]:[],...ne?[ne]:[],...e.middleware||[],Qv(ce,c)],le=e.maxMemoryRounds??Wv,B={agentId:r,store:i,messages:c,vfsStore:l,listeners:se,todosMw:u,memoryMw:d,agent:null,initDone:Promise.resolve(),sessionId:``,refCount:0,mcpClosers:[],mcpServers:[],checkpoint:h,windowOpsController:b,liveWindowProps:x,applySnapshot(t){t.messages?.length&&c.push(...t.messages),t.vfs&&l.hydrate&&l.hydrate(t.vfs),t.todos?.length&&u.reset(t.todos),t.memory&&!e.memory&&d.reset(t.memory)},afterRound(){de(),fe()},async send(e){await B.initDone,c.push({role:`user`,content:e,timestamp:Date.now()});try{let e=await B.agent.invoke(c);return c.push({role:`assistant`,content:e,timestamp:Date.now()}),B.afterRound(),i&&await i.flush(),e}catch(e){throw ce({type:`error`,message:e?.message||String(e)}),e}},async switchSession(t){if(await B.initDone,!i)throw Error(`page-agent-sdk: storage 未开启,无法切换会话(请传 storage 选项)`);l.flush?.(),await i.flush();let n=t??``,a;return n?(a=await i.load(r,n),a||await i.createSession(r,e.session?.title,n)):n=await i.createSession(r,e.session?.title),B.sessionId=n,c.splice(0,c.length),l.clear?.(),u.reset([]),e.memory||d.reset(``),B.agent.debugLogs.value=[],a||=await i.load(r,n),a&&B.applySnapshot(a),e.memory&&i.save(r,B.sessionId,{memory:e.memory}),n},stream:(e,t,n)=>{if(!B.agent)throw Error(`page-agent-sdk: agent 尚未初始化完成,请先 await mount()`);let r=oe?e=>{t?.(e),ce(e)}:t;return B.agent.stream(e,r,n)},release(){if(B.refCount--,B.refCount<=0){i&&(l.flush?.(),i.flush(),i.dispose());let e=B.mcpClosers.splice(0);e.length&&Promise.allSettled(e.map(e=>e())),qv.delete(r)}},getInfo(){return{id:r,model:Kv(e.llm)?e.llm.model??e.llm.modelName:e.llm.model,systemPrompt:e.systemPrompt??Uv,tools:O.map(e=>({name:e.name,description:e.description,schema:e.schema,source:S.get(e.name)||`user`})),skills:(e.skills??[]).map(e=>({name:e.name,description:e.description})),windowProps:x().map(e=>({path:e.path,description:e.description,schema:e.schema})),memory:e.memory??``,middleware:z.map(e=>e.name),todos:(B.agent?.getState?.()?.todos??[]).map(e=>({content:e.content,status:e.status})),subagent:{enabled:!!L,maxDepth:e.subagent?.maxDepth??1,maxParallel:e.subagent?.maxParallel??4,allowedTools:e.subagent?.allowedTools??[]},verify:{enabled:!!R,maxAttempts:F?P:0,adversarial:F&&!!e.verify?.adversarial},mcp:{servers:B.mcpServers},lastCompression:B.agent?.getState?.()?.lastCompression,checkpoints:h?{enabled:!0,auto:g,list:h.list()}:void 0}}};async function ue(){if(!i)return;await i.ready;let t=e.session||{};if(t.id){B.sessionId=t.id;let e=await i.load(r,B.sessionId);e?B.applySnapshot(e):await i.createSession(r,t.title,B.sessionId)}else if(t.autoResume!==!1){let n=await i.listSessions(r);if(e.debug&&console.log(`[page-agent-sdk][restore] listSessions`,r,n.length,n.map(e=>e.sessionId)),n.length){B.sessionId=n[0].sessionId;let t=await i.load(r,B.sessionId);t?(B.applySnapshot(t),e.debug&&console.log(`[page-agent-sdk][restore] 恢复会话`,B.sessionId,`${t.messages?.length??0} msgs`)):e.debug&&console.log(`[page-agent-sdk][restore] 会话 meta 存在但快照为空`,B.sessionId)}else B.sessionId=await i.createSession(r,t.title),e.debug&&console.log(`[page-agent-sdk][restore] 新建会话(无历史)`,B.sessionId)}else B.sessionId=await i.createSession(r,t.title);e.memory&&i.save(r,B.sessionId,{memory:e.memory})}function de(){let e=u_(c,le);e.trimmed&&c.splice(e.deleteFrom,e.deleteCount,e.summary)}function fe(){if(!B.sessionId||!i)return;let t=JSON.parse(JSON.stringify(c));i.save(r,B.sessionId,{messages:t});let n=B.agent?.getState?.()?.todos??[];i.save(r,B.sessionId,{todos:n}),e.debug&&console.log(`[page-agent-sdk][persist] save`,B.sessionId,`${c.length} msgs`)}return B.initDone=(async()=>{if(await ue(),e.mcp?.length){let t=await Promise.allSettled(e.mcp.map(e=>o_(e)));B.mcpClosers=t.flatMap(e=>e.status===`fulfilled`?[e.value.close]:[]),B.mcpServers=[];let n=[];t.forEach((t,r)=>{let i=e.mcp[r],a=i.name??i.url;t.status===`fulfilled`?(B.mcpServers.push({name:a,url:i.url,toolCount:t.value.tools.length}),t.value.tools.forEach(e=>S.set(e.name,`mcp:${a}`)),n.push(...t.value.tools)):console.warn(`[page-agent-sdk][mcp] server ${a} 连接失败:`,t.reason)}),O.push(...n),e.debug&&console.log(`[page-agent-sdk][mcp] 注入 ${n.length} 个工具,${B.mcpServers.length} 个 server`)}B.agent=ig({...Kv(e.llm)?{llm:e.llm}:{apiKey:e.llm.apiKey,baseUrl:e.llm.baseUrl,model:e.llm.model,temperature:e.llm.temperature,maxTokens:e.llm.maxTokens},systemPrompt:e.systemPrompt??Uv,tools:O,middleware:z,maxToolRounds:e.maxToolRounds,maxRetries:e.maxRetries,maxParallelTools:e.maxParallelTools,contextWindow:o.contextWindow,maxOutputTokens:o.maxOutputTokens,maxVerifyAttempts:F?P:0,debug:e.debug}),f.current=B.agent})(),B}function ey(e){let t=e.id??vv();e.id||console.warn(`[page-agent-sdk] 未传 options.id,已生成随机 id "${t}"。刷新后持久化数据无法恢复,请传稳定 id。`);let n=e.streaming??!0,r=e.ui??`default`,i,a=e.shareContext?qv.get(t):void 0;a?i=a:(i=$v(e,t),e.shareContext&&qv.set(t,i)),i.refCount++;let o=null,s=null,c=null;async function l(){if(await i.initDone,r===!1){i.store&&(s=()=>{i.vfsStore.flush?.(),i.store.flush()},c=()=>{document.visibilityState===`hidden`&&i.store.flush()},typeof window<`u`&&window.addEventListener(`pagehide`,s),typeof document<`u`&&document.addEventListener(`visibilitychange`,c));return}let t=typeof e.container==`string`?document.querySelector(e.container):e.container;if(!t)throw Error(`createChatSdk: 挂载点未找到(${e.container})`);let a=i.agent.debugLogs;o=sl(xi({setup(){return()=>Ls(Fh,{fetchStream:n?i.agent.stream:void 0,fetchResponse:n?void 0:(e,t)=>i.agent.invoke(e,t),title:e.title,placeholder:e.placeholder,debugLogs:a.value,initialMessages:i.messages,getInfo:()=>i.getInfo(),onUndo:i.checkpoint?()=>i.checkpoint.restore():void 0,canUndo:i.checkpoint?()=>i.checkpoint.canRestore():void 0,onPersist:async()=>{i.afterRound(),i.store&&await i.store.flush()},onClear:()=>{i.store&&(i.sessionId=vv(),i.vfsStore.clear?.(),i.todosMw.reset([]),e.memory||i.memoryMw.reset(``),i.agent.debugLogs.value=[],i.store.createSession(i.agentId,e.session?.title,i.sessionId))}})}})),o.mount(t),i.store&&(s=()=>{i.vfsStore.flush?.(),i.store.flush()},c=()=>{document.visibilityState===`hidden`&&i.store.flush()},typeof window<`u`&&window.addEventListener(`pagehide`,s),typeof document<`u`&&document.addEventListener(`visibilitychange`,c))}function u(){s&&typeof window<`u`&&window.removeEventListener(`pagehide`,s),c&&typeof document<`u`&&document.removeEventListener(`visibilitychange`,c),s=null,c=null,o?.unmount(),o=null,i.release()}return{mount:l,unmount:u,send:i.send,switchSession:i.switchSession,stream:i.stream,inspect:i.getInfo,messages:i.messages,restoreLastCheckpoint:()=>i.checkpoint?.restore()??!1,listCheckpoints:()=>i.checkpoint?.list()??[],hook:e=>(i.listeners.add(e),()=>i.listeners.delete(e)),addWindowProp:e=>{if(!i.windowOpsController){console.warn(`[page-agent-sdk] addWindowProp 忽略:windowOps 已关闭(capabilities.windowOps:false)`);return}i.windowOpsController.add(e)},removeWindowProp:e=>i.windowOpsController?i.windowOpsController.remove(e):!1,listWindowProps:()=>i.liveWindowProps()}}function ty(e){return(0,n.tool)(async t=>{let n=await e.handler(t);return typeof n==`string`?n:JSON.stringify(n)},{name:e.name,description:e.description,schema:e.schema})}e.CONTEXT_PRESETS=C_,e.ChatDialog=Fh,e.CodePreview=Yd,e.HUMAN_CONFIRM_TOOL_NAME=xg,e.MessageContent=Zd,e.connectMcp=o_,e.createAgent=ig,e.createApprovalMiddleware=bg,e.createChatSdk=ey,e.createCheckpointManager=jg,e.createCheckpointMiddleware=Mg,e.createHumanConfirmMiddleware=wg,e.createHumanConfirmTool=Cg,e.createMemoryBackend=Rv,e.createSessionStore=Hv,e.createSubagentMiddleware=Bg,e.createSubagentsMiddleware=Ug,e.createUsageHintsMiddleware=_v,e.createVerifyMiddleware=Wg,e.createVfs=k_,e.createWebStorageBackend=Bv,e.createWindowOps=uv,e.createWriteBackCheck=Xg,e.defineSkill=sg,e.defineTool=ty,e.defineWindowToolset=mv,e.estimateTokens=Hh,e.extractText=r_,e.fetchDocTools=fv,e.fetchTools=pv,e.formatZodIssues=T_,e.isQuotaError=Av,e.jpEval=K_,e.jsonParseError=D_,e.offloadPassThroughChars=Wh,e.offloadThresholdChars=Uh,e.presets=x_,e.resolveContextOptions=w_,e.resolveModelCaps=Vh,e.runSandboxedScript=Z_,e.searchJson=J_,e.selectBuiltinTools=hv,e.systemPromptHelpers=S_,e.toolError=$,e.useChat=vl,Object.defineProperty(e,"z",{enumerable:!0,get:function(){return t.z}}),e.zodError=E_});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "page-agent-sdk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "框架无关的页面内 Agent JS SDK —— 以对话框形态挂载到任意网页,通过自定义 tool 读写宿主 window 属性(GET 抓文档),具备 planning/skills/虚拟工作区/快照回退/context 管理能力。Vue 打包进库,使用者无需安装 Vue。",
|
|
6
6
|
"main": "./dist/page-agent-sdk.umd.cjs",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"build:lib": "vite build",
|
|
34
34
|
"build:iife": "vite build --config vite.iife.config.ts",
|
|
35
35
|
"preview": "vite preview",
|
|
36
|
-
"test": "tsx src/core/__tests__/selftest.ts"
|
|
36
|
+
"test": "tsx src/core/__tests__/selftest.ts",
|
|
37
|
+
"test:e2e": "node tests/e2e-integration.mjs"
|
|
37
38
|
},
|
|
38
39
|
"keywords": [
|
|
39
40
|
"ai",
|
package/types/index.d.ts
CHANGED
|
@@ -103,6 +103,8 @@ export interface SubagentConfig {
|
|
|
103
103
|
export interface AgentInfo {
|
|
104
104
|
id: string;
|
|
105
105
|
model?: string;
|
|
106
|
+
/** 当前生效的 systemPrompt(默认或用户传入;仅 base 段,不含中间件 augmentPrompt,便于调试/验证默认提示词) */
|
|
107
|
+
systemPrompt: string;
|
|
106
108
|
tools: ToolInfo[];
|
|
107
109
|
skills: SkillInfo[];
|
|
108
110
|
windowProps: WindowPropInfo[];
|