@qfei-design/make-ai-assistant 0.2.10 → 0.2.12
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/PUBLIC_API.md +2 -2
- package/README.md +5 -6
- package/dist/make-app.cjs +1 -1
- package/dist/make-app.d.ts +1 -1
- package/dist/make-app.mjs +418 -416
- package/dist/react/conversation-controls.d.ts +6 -1
- package/dist/react/use-attachments.d.ts +8 -1
- package/dist/react.cjs +4 -4
- package/dist/react.mjs +1437 -1399
- package/dist/styles.css +363 -113
- package/docs/make-app-integration.md +4 -4
- package/examples/make-app/README.md +1 -1
- package/package.json +1 -1
package/PUBLIC_API.md
CHANGED
|
@@ -175,7 +175,7 @@ UI 会拒绝孤立、迟到、重复或跨 run 混入的事件,避免静默丢
|
|
|
175
175
|
|
|
176
176
|
`/make-app` 导出 `createMakeAppAssistantTransport`、`MakeAppAssistantTransportOptions`、`MakeAppAssistantScope`、`MakeAppAssistantEventSourceFactory` 及相关结构类型。完整回调与接线示例见 [当前 Make App 合同](docs/make-app-integration.md)。
|
|
177
177
|
|
|
178
|
-
宿主注入 resolveScope
|
|
178
|
+
宿主注入 resolveScope、会话/SSE/上传语义回调及可选的 readContent:listAgents、createChat、listChats、getChat、updateChat、deleteChat、loadHistory、sendMessage、getResponse、cancelResponse、setFeedback、startUpload、getUpload、uploadPart、completeUpload、eventSourceFactory。JSON 回调返回裸对象,204 返回 void;宿主能够无损读取二进制时再提供 readContent,并返回 Uint8Array。
|
|
179
179
|
|
|
180
180
|
`resolveScope(context)` 返回 appKey、agentId 和随登录身份变化的 identityKey。包只用于作用域绑定与缓存失效,服务器仍独立鉴权。每个异步回调接受 AbortSignal;包不提供部署 URL、不读 Cookie、不导入认证 SDK。
|
|
181
181
|
|
|
@@ -183,7 +183,7 @@ UI 会拒绝孤立、迟到、重复或跨 run 混入的事件,避免静默丢
|
|
|
183
183
|
|
|
184
184
|
输入 message 可携带 parts;响应事件增加 response.accepted/state/output_item.added/output_text.delta/output_item.done/snapshot/reconciled/terminal。每个 Run、item 和 part 的身份独立,持久助手 messageId 用于反馈。`AssistantConversationState.responses` 保存响应集合;输入可以合并到同一 Run,不按调用次数伪造 Turn。
|
|
185
185
|
|
|
186
|
-
features 增加 conversationManagement、feedback、attachments、modelInputKinds。Make App 的 newConversation/remoteCancellation 为 true,regeneration 为 false
|
|
186
|
+
features 增加 conversationManagement、feedback、attachments、modelInputKinds。Make App 的 newConversation/remoteCancellation 和 attachments 为 true,regeneration 为 false;modelInputKinds 是宿主对模型输入的声明,附件的实际接受与拒绝由服务端处理。未注入 readContent 时 transport 不暴露该方法,React UI 也不展示无效的下载/预览按钮。historyLimit 范围 1—200;maxEventCharacters 默认 1,000,000;重连由 adapter 单独负责。完整快照属于覆盖,不能当新 delta。
|
|
187
187
|
|
|
188
188
|
根入口导出 AssistantContentPart、AssistantMedia、AssistantChat、AssistantChatPage、AssistantAgent、AssistantFeedback、AssistantUpload、AssistantResponseSnapshot、AssistantResponseEvent 等类型,仍无 React/DOM File 依赖。文件读取与 Object URL 留在 React/宿主边界。
|
|
189
189
|
|
package/README.md
CHANGED
|
@@ -66,10 +66,9 @@ export function AppAssistant() {
|
|
|
66
66
|
覆盖默认的 `Make` 品牌,面板会显示为“{品牌名} AI 助手”;传入 `title` 时则使用完整标题覆盖。
|
|
67
67
|
`assistantName` 可覆盖 AI 消息显示名称。这些显示配置只用于 React UI,不会随会话上下文发送到
|
|
68
68
|
AI transport;进度和可重试错误会显示在对应的 AI 回合中。
|
|
69
|
-
`subtitle`
|
|
70
|
-
`privacyNotice`
|
|
71
|
-
|
|
72
|
-
`title` 属性。头栏默认高度为 50px,可通过 `headerHeight` 属性或 `--make-ai-header-height` 主题变量覆盖。
|
|
69
|
+
头栏仅展示居中的助手图标与 AI 标题,长标题会省略显示并保留原文 `title` 属性。`subtitle` 与
|
|
70
|
+
`privacyNotice` 继续接受旧调用传入的值以保持兼容,但不会参与渲染或发送到 AI transport。头栏默认高度为 50px,
|
|
71
|
+
可通过 `headerHeight` 属性或 `--make-ai-header-height` 主题变量覆盖。
|
|
73
72
|
|
|
74
73
|
## Theme integration
|
|
75
74
|
|
|
@@ -205,11 +204,11 @@ const assistantTransport = createMakeAppAssistantTransport({
|
|
|
205
204
|
});
|
|
206
205
|
```
|
|
207
206
|
|
|
208
|
-
`makeAppAiClient`
|
|
207
|
+
`makeAppAiClient` 实现 Agent/Chat 管理、分页历史、消息、响应快照、独立取消、反馈、上传和 EventSource,并可在宿主具备无损二进制认证读取能力时注入原件读取。完整类型与示例见 [Make App 接入说明](docs/make-app-integration.md) 和 [宿主示例](examples/make-app/main.tsx)。网络与认证由宿主注入,identityKey 随当前用户/租户变化。
|
|
209
208
|
|
|
210
209
|
内置面板支持持久会话列表、新建、改名、置顶/删除、反馈与附件队列。历史 cursor=-1 从最早事件正向分页,空可见页仍可能存在后续事件。首次加载不隐式建会话,用户新建或主动发送才创建。item/part 增量、完整文本覆盖、快照恢复和持久 messageId 对账由包统一处理。
|
|
211
210
|
|
|
212
|
-
停止显示“停止中”,直到服务端确认终态;中断订阅不取消后台 Run。当前 Make App 不提供重新生成语义,也不传 context/capabilities 或伪造 Artifact
|
|
211
|
+
停止显示“停止中”,直到服务端确认终态;中断订阅不取消后台 Run。当前 Make App 不提供重新生成语义,也不传 context/capabilities 或伪造 Artifact。附件入口固定为“上传文件或图片”;modelInputKinds 仅描述宿主模型能力,服务端根据消息 parts 决定是否接受媒体类型。单条消息文本最多 8 KiB UTF-8,最多 32 个 parts。
|
|
213
212
|
|
|
214
213
|
Make Console 可以使用独立 adapter:
|
|
215
214
|
|
package/dist/make-app.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./conversation-Cvh-IVRV.cjs"),A=r=>{const i=t.protocolText(r,36);if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(i))throw new Error("Invalid Make App request: UUID");return i},x=r=>{const i=t.protocolText(r,512,!0);if(new TextEncoder().encode(i).length>512||/[\r\n/\\]/.test(i))throw new Error("Invalid Make App request: filename");return i},E=(r,i,n)=>{const d=t.protocolRecord(r);if(t.protocolKeys(d,["chatId","appKey","agentId","title","status","revision","pinned","pinnedAt","createdAt","lastActivityAt"]),d.appKey!==i.appKey||d.agentId!==i.agentId||n&&d.chatId!==n||!["active","deleted"].includes(String(d.status)))throw new Error("Invalid Make App response: chat scope");return{chatId:t.protocolId(d.chatId),appKey:i.appKey,agentId:i.agentId,title:t.protocolText(d.title,255,!0),status:d.status,revision:t.protocolInteger(d.revision,1),pinned:t.protocolBoolean(d.pinned),pinnedAt:d.pinnedAt==null?null:t.protocolText(d.pinnedAt,64),createdAt:t.protocolText(d.createdAt,64),lastActivityAt:t.protocolText(d.lastActivityAt,64)}},U=(r,i)=>{const n=t.protocolRecord(r),d=t.protocolArray(n.chats,100).map(u=>E(u,i));if(new Set(d.map(u=>u.chatId)).size!==d.length)throw new Error("Invalid Make App response: duplicate chat");const p=t.protocolText(n.nextCursor,8192,!0),I=t.protocolBoolean(n.hasMore);if(I!==!!p)throw new Error("Invalid Make App response: chat cursor");return{chats:d,nextCursor:p,hasMore:I}},P=(r,i,n)=>{const d=t.protocolRecord(r),p=t.protocolInteger(d.nextCursor,-1),I=t.protocolBoolean(d.hasMore);if(p<n||I&&p<=n)throw new Error("Invalid Make App response: history cursor did not advance");let u=0,l=n;const w=new Set,f=t.protocolArray(d.messages,200).map(m=>{const y=t.protocolRecord(m);if(y.role!=="user"&&y.role!=="assistant")throw new Error("Invalid Make App response: history role");const g=t.protocolInteger(y.cursor);if(g<=l||g>p)throw new Error("Invalid Make App response: history order");l=g;const o=y.messageId!==void 0,e=o?t.protocolId(y.messageId):`history-${i}-${g}`;if(w.has(e))throw new Error("Invalid Make App response: duplicate message");w.add(e);const s=t.protocolText(y.text,1e5,!0);if(u+=[...s].length,u>1e6)throw new Error("Invalid Make App response: history budget");return{id:e,role:y.role,content:s,persistent:o,cursor:g,createdAt:t.protocolText(y.createdAt,64),...y.responseId===void 0?{}:{responseId:t.protocolId(y.responseId)},...y.parts===void 0?{}:{parts:t.parseContentParts(y.parts)},...y.feedback===void 0?{}:{feedback:t.parseFeedback(y.feedback)}}});return{threadId:i,messages:f,nextCursor:p,hasMore:I}},M=(r,i)=>{const n=t.parseResponseSnapshot(r);if(n.chatId!==i.chatId||n.responseId!==i.responseId)throw new Error("Invalid Make App response: response scope");return n},b=(r,i)=>{const n=t.protocolRecord(r);if(!["uploading","ready","cancelled"].includes(String(n.status))||i&&n.id!==i)throw new Error("Invalid Make App response: upload");const d=t.protocolInteger(n.sizeBytes,0,64<<20),p=t.protocolInteger(n.partSize,1<<20,1<<20),I=t.protocolArray(n.completedParts,64).map(l=>t.protocolInteger(l,0,Math.max(0,Math.ceil(d/p)-1)));if(new Set(I).size!==I.length)throw new Error("Invalid Make App response: repeated upload part");const u={id:t.protocolId(n.id),status:n.status,name:x(n.name),contentType:t.protocolText(n.contentType,256),sizeBytes:d,partSize:p,completedParts:I};if(u.status==="ready"){const l=t.protocolRecord(n.content);if(l.kind!=="reference"||l.sizeBytes!==d||!/^[0-9a-f]{64}$/.test(String(l.digestSha256)))throw new Error("Invalid Make App response: content receipt");u.content={kind:"reference",contentRef:t.protocolId(l.contentRef),sizeBytes:d,digestSha256:String(l.digestSha256)}}return u},D=r=>{const i=t.protocolId(r.threadId),n=A(r.message.id);let d,p;if(r.message.parts!==void 0){const I=t.parseContentParts(r.message.parts);if(!I.length)throw new Error("Invalid Make App request: empty parts");const u=new Set;for(const l of I){const w=A(l.id);if(u.has(w))throw new Error("Invalid Make App request: duplicate part");if(u.add(w),l.kind!=="text"){l.name!==void 0&&x(l.name);const f=l.media.contentType;if(!/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(f)||l.kind!=="file"&&(!f.startsWith(`${l.kind}/`)||f==="image/svg+xml"))throw new Error("Invalid Make App request: media type")}}if(p=I.filter(l=>l.kind==="text").map(l=>l.text).join(""),!p.trim()&&I.every(l=>l.kind==="text"))throw new Error("Invalid Make App request: empty input");d={chatId:i,messageId:n,parts:I}}else p=t.protocolText(r.message.content,8192),d={chatId:i,messageId:n,text:p};if(new TextEncoder().encode(p).length>8192||new TextEncoder().encode(JSON.stringify(d)).length>65536)throw new Error("输入内容过长,请控制在 8 KiB 文本和 32 个附件/文本片段以内");return d},O=()=>{const r=[];let i,n=!1,d;return{push(p){if(!n)if(i){const I=i;i=void 0,I.resolve({done:!1,value:p})}else r.length>=4096?this.fail(new Error("响应事件积压超过限制,请恢复对话")):r.push(p)},fail(p){d=p,n=!0,r.length=0,i?.reject(p),i=void 0},close(){n=!0,r.length=0,i?.resolve({done:!0,value:void 0}),i=void 0},next(){return d?Promise.reject(d):r.length?Promise.resolve({done:!1,value:r.shift()}):n?Promise.resolve({done:!0,value:void 0}):new Promise((p,I)=>{i={resolve:p,reject:I}})}}},C=(r,i)=>new Promise(n=>{if(i?.aborted){n();return}const d=()=>{clearTimeout(p),i?.removeEventListener("abort",d),n()},p=setTimeout(d,r);i?.addEventListener("abort",d,{once:!0})}),R=r=>{if(!/^\d{1,20}-\d{1,20}$/.test(r))throw new Error("Invalid Make App response: stream cursor");return r.split("-").map(BigInt)},B=(r,i)=>{const[n,d]=R(r),[p,I]=R(i);return n>p||n===p&&d>I},T=r=>{const i=r;return[400,401,403,404].includes(i?.status??i?.response?.status??0)||["AI_FORBIDDEN","AI_AUTH_REQUIRED","AI_AUTH_EXPIRED","AI_NOT_FOUND","AI_RESPONSE_NOT_FOUND"].includes(i?.code??"")||r instanceof Error&&r.message.startsWith("Invalid ")},F=["response.subscribed","response.state","response.output_item.added","response.output_text.delta","response.output_item.done","response.reset","response.snapshot","response.completed","response.failed","response.cancelled"];async function*q(r,i,n){if(n?.aborted)return;let d=r.cursor??"0-0";R(d);let p=0,I=!1,u=0;const l=new Map;yield{type:"response.state",chatId:r.chatId,responseId:r.responseId,status:"queued"};async function*w(f,m){if(f==="completed"){let y=r.historyCursor??-1,g=0;const o=[];let e=!0;for(;e&&!n?.aborted;){if(++g>200)throw new Error("历史恢复超过单次预算,请继续加载历史");const s=await i.loadHistory(r,y,n);for(const a of s.messages)if(a.responseId===r.responseId&&a.role==="assistant"&&a.persistent){const{artifacts:c,...h}=a;o.push(t.parseStoredMessage(h))}if(e=s.hasMore??!1,e&&(s.nextCursor??-1)<=y)throw new Error("Invalid Make App response: history cursor");y=s.nextCursor??y}if(n?.aborted)return;if(!o.length)throw new Error("回答已完成,历史尚未同步,请恢复对话");yield{type:"response.reconciled",chatId:r.chatId,responseId:r.responseId,messages:o}}yield{type:"response.terminal",chatId:r.chatId,responseId:r.responseId,status:f,...m?{code:m}:{}}}for(;!n?.aborted;){if(p>3){if(++u>600)throw new Error("响应连接中断,请恢复对话");let a;try{a=await i.getResponse(r,n)}catch(c){if(n?.aborted)return;if(T(c))throw c}if(a&&(yield{type:"response.snapshot",snapshot:a},t.isResponseTerminal(a.status))){yield*w(a.status);return}await C(Math.max(1e3,i.reconnectDelayMs),n);continue}const f=O();let m=0,y=!1;const g=i.eventSourceFactory({chatId:r.chatId,responseId:r.responseId,cursor:d},{withCredentials:!0}),o=F.map(a=>{const c=h=>{if(!(y||n?.aborted)){if(h.data.length>i.maxEventCharacters*2||[...h.data].length>i.maxEventCharacters||m+h.data.length>4e6){y=!0,g.close(),f.fail(new Error("Make App assistant SSE event exceeds maxEventCharacters"));return}m+=h.data.length,f.push({name:a,raw:h.data,id:h.lastEventId})}};return g.addEventListener(a,c),{name:a,listener:c}});g.onerror=()=>{!y&&!n?.aborted&&(y=!0,g.close(),f.push({reconnect:!0}))};const e=()=>{y=!0,g.close(),f.close()};n?.addEventListener("abort",e,{once:!0}),n?.aborted&&e();try{for(;!n?.aborted;){const a=await f.next();if(a.done)return;const c=a.value;if("reconnect"in c)break;if(m-=c.raw.length,c.id&&!B(c.id,d)){if(l.has(c.id)&&l.get(c.id)!==c.raw)throw new Error("Invalid Make App response: conflicting stream replay");continue}const h=t.protocolRecord(JSON.parse(c.raw));if(t.protocolId(h.responseId)!==r.responseId)throw new Error("Invalid Make App response: stream scope");if(c.name!=="response.subscribed"){if(c.name==="response.reset"){I=!0;continue}if(c.name==="response.snapshot"){const v=M(h,r);if(yield{type:"response.snapshot",snapshot:v},t.isResponseTerminal(v.status)){yield*w(v.status);return}}else if(c.name==="response.completed"||c.name==="response.cancelled"){yield*w(c.name==="response.completed"?"completed":"cancelled");return}else if(c.name==="response.failed"){if(h.code==="AI_UPSTREAM_ERROR"){y=!0,g.close();break}if(h.code==="AI_FORBIDDEN"||h.code==="AI_AUTH_EXPIRED")throw Object.assign(new Error("当前身份无法继续读取响应"),{code:h.code,status:h.code==="AI_FORBIDDEN"?403:401});yield*w("failed",typeof h.code=="string"?h.code:void 0);return}else c.name==="response.state"?yield t.parseAssistantEvent({type:c.name,chatId:r.chatId,...h}):I||(yield t.parseAssistantEvent({type:c.name,...h}));c.id&&(d=c.id,l.set(c.id,c.raw),l.size>512&&l.delete(l.keys().next().value))}}}finally{g.onerror=null,g.close(),f.close();for(const{name:a,listener:c}of o)g.removeEventListener(a,c);n?.removeEventListener("abort",e)}if(n?.aborted||(p+=1,console.info("[make-ai-assistant] response reconnect",{attempt:p}),await C(Math.min(i.reconnectDelayMs*2**(p-1),5e3),n),n?.aborted))return;let s;try{s=await i.getResponse(r,n)}catch(a){if(n?.aborted)return;if(T(a))throw a}if(s&&t.isResponseTerminal(s.status)){yield{type:"response.snapshot",snapshot:s},yield*w(s.status);return}I&&(p=4)}}const K=()=>Object.assign(new Error("Operation aborted"),{name:"AbortError"}),S=r=>{if(r?.aborted)throw K()},z=r=>{const i=t.protocolInteger(r.historyLimit??100,1,200),n=t.protocolInteger(r.maxEventCharacters??1e6,1,4e6),d=t.protocolInteger(r.reconnectDelayMs??500,1,3e4),p=o=>{const e=r.resolveScope(o);return{appKey:t.protocolId(e.appKey),agentId:t.protocolId(e.agentId),identityKey:t.protocolId(e.identityKey)}},I=o=>{const e=p(o);return`${e.identityKey}\0${e.appKey}\0${e.agentId}`},u=async(o,e,s,a)=>{S(a);const c=I(o);console.info("[make-ai-assistant] Make App operation start",{operation:e});try{const h=await s();if(S(a),c!==I(o))throw K();return h}catch(h){throw console.warn("[make-ai-assistant] Make App operation failed",{operation:e,errorType:h instanceof Error?h.name:typeof h}),h}},l=o=>({chatId:t.protocolId(o.chatId)}),w=o=>({...l(o),responseId:t.protocolId(o.responseId)}),f=o=>({...l(o),uploadId:t.protocolId(o.uploadId)}),m=async(o,e,s,a)=>u(o,"loadHistory",async()=>P(await r.loadHistory({chatId:t.protocolId(e),cursor:t.protocolInteger(s,-1),limit:i},{signal:a}),e,s),a),y=async(o,e,s)=>u(o,"getResponse",async()=>M(await r.getResponse(w(e),{signal:s}),e),s),g=(o,e,s)=>{const a=I(o),c=s?.signal;return(async function*(){for await(const h of q(e,{eventSourceFactory:r.eventSourceFactory,getResponse:(v,k)=>y(o,v,k),loadHistory:(v,k,_)=>m(o,v.chatId,k,_),maxEventCharacters:n,reconnectDelayMs:d},c)){if(c?.aborted||a!==I(o))return;yield h}})()};return{features:{history:!0,newConversation:!0,remoteCancellation:!0,regeneration:!1,conversationManagement:!0,feedback:!0,attachments:!0,modelInputKinds:r.modelInputKinds??["text"]},scopeKey:I,listAgents:(o,e)=>u(o,"listAgents",async()=>{const s=p(o),a=t.protocolRecord(await r.listAgents({appKey:s.appKey},{signal:e?.signal}));return t.protocolArray(a.agents,1e3).map(c=>{const h=t.protocolRecord(c);if(h.appKey!==s.appKey)throw new Error("Invalid Make App response: agent scope");return{agentId:t.protocolId(h.agentId),appKey:s.appKey,name:t.protocolText(h.name)}})},e?.signal),listConversations:(o,e,s)=>u(o,"listChats",async()=>{const{appKey:a,agentId:c}=p(o);return U(await r.listChats({appKey:a,agentId:c,...e?.cursor?{cursor:t.protocolText(e.cursor,8192)}:{},limit:t.protocolInteger(e?.limit??50,1,100)},{signal:s?.signal}),{appKey:a,agentId:c})},s?.signal),createConversation:(o,e,s)=>u(o,"createChat",async()=>{const{appKey:a,agentId:c}=p(o),h={appKey:a,agentId:c,requestId:A(e.requestId),...e.title===void 0?{}:{title:t.protocolText(e.title.trim(),255)}};return E(await r.createChat(h,{signal:s?.signal}),{appKey:a,agentId:c})},s?.signal),getConversation:(o,e,s)=>u(o,"getChat",async()=>E(await r.getChat(l(e),{signal:s?.signal}),p(o),e.chatId),s?.signal),updateConversation:(o,e,s)=>u(o,"updateChat",async()=>{const a={...l(e),expectedRevision:t.protocolInteger(e.expectedRevision,1)};if(e.title!==void 0&&(a.title=t.protocolText(e.title.trim(),255)),e.pinned!==void 0){if(typeof e.pinned!="boolean")throw new Error("Invalid Make App request: pinned");a.pinned=e.pinned}if(a.title===void 0&&a.pinned===void 0)throw new Error("Invalid Make App request: empty patch");return E(await r.updateChat(a,{signal:s?.signal}),p(o),e.chatId)},s?.signal),deleteConversation:(o,e,s)=>u(o,"deleteChat",()=>r.deleteChat({...l(e),expectedRevision:t.protocolInteger(e.expectedRevision,1)},{signal:s?.signal}),s?.signal),loadConversation:async(o,e)=>e?.threadId?m(o,e.threadId,e.cursor??-1,e.signal):{messages:[]},getResponse:(o,e,s)=>y(o,e,s?.signal),cancelResponse:(o,e,s)=>u(o,"cancelResponse",async()=>M(await r.cancelResponse(w(e),{signal:s?.signal}),e),s?.signal),setFeedback:(o,e,s)=>u(o,"setFeedback",async()=>{if(!["like","dislike","none"].includes(e.rating))throw new Error("Invalid Make App request: rating");const a=t.protocolText(e.reason??"",128,!0).trim(),c=t.protocolText(e.comment??"",4e3,!0).trim();if(e.rating!=="dislike"&&(a||c))throw new Error("Invalid Make App request: feedback detail");return t.parseFeedback(await r.setFeedback({...l(e),messageId:t.protocolId(e.messageId),requestId:A(e.requestId),rating:e.rating,...a?{reason:a}:{},...c?{comment:c}:{}},{signal:s?.signal}))},s?.signal),startUpload:(o,e,s)=>u(o,"startUpload",async()=>b(await r.startUpload({...l(e),fileId:A(e.fileId),name:x(e.name),contentType:t.protocolText(e.contentType,256),sizeBytes:t.protocolInteger(e.sizeBytes,0,64<<20),...e.digestSha256?{digestSha256:t.protocolText(e.digestSha256,64)}:{}},{signal:s?.signal})),s?.signal),getUpload:(o,e,s)=>u(o,"getUpload",async()=>b(await r.getUpload(f(e),{signal:s?.signal}),e.uploadId),s?.signal),uploadPart:(o,e,s)=>u(o,"uploadPart",()=>{if(!(e.bytes instanceof Uint8Array)||e.bytes.byteLength>1<<20)throw new Error("Invalid Make App request: upload bytes");return r.uploadPart({...f(e),part:t.protocolInteger(e.part,0,63),bytes:e.bytes},{signal:s?.signal})},s?.signal),completeUpload:(o,e,s)=>u(o,"completeUpload",async()=>b(await r.completeUpload(f(e),{signal:s?.signal}),e.uploadId),s?.signal),readContent:(o,e,s)=>u(o,"readContent",async()=>{const a=await r.readContent({...l(e),contentRef:t.protocolId(e.contentRef)},{signal:s?.signal});if(!(a instanceof Uint8Array)||a.byteLength>64<<20)throw new Error("Invalid Make App response: content bytes");return a},s?.signal),watchResponse:g,async*run(o,e){if(e?.signal?.aborted)return;const s=D(o),a=await u(o.context,"sendMessage",async()=>t.protocolRecord(await r.sendMessage(s,{signal:e?.signal})),e?.signal);if(a.chatId!==s.chatId)throw new Error("Invalid Make App response: accepted chat");const c=t.protocolId(a.responseId),h=t.protocolInteger(a.acceptedCursor);yield{type:"response.accepted",chatId:s.chatId,responseId:c,messageId:s.messageId,acceptedCursor:h},yield*g(o.context,{chatId:s.chatId,responseId:c,historyCursor:h},e)}}};exports.createMakeAppAssistantTransport=z;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./conversation-Cvh-IVRV.cjs"),E=o=>{const a=r.protocolText(o,36);if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(a))throw new Error("Invalid Make App request: UUID");return a},T=o=>{const a=r.protocolText(o,512,!0);if(new TextEncoder().encode(a).length>512||/[\r\n/\\]/.test(a))throw new Error("Invalid Make App request: filename");return a},k=(o,a,n)=>{const c=r.protocolRecord(o);if(r.protocolKeys(c,["chatId","appKey","agentId","title","status","revision","pinned","pinnedAt","createdAt","lastActivityAt"]),c.appKey!==a.appKey||c.agentId!==a.agentId||n&&c.chatId!==n||!["active","deleted"].includes(String(c.status)))throw new Error("Invalid Make App response: chat scope");return{chatId:r.protocolId(c.chatId),appKey:a.appKey,agentId:a.agentId,title:r.protocolText(c.title,255,!0),status:c.status,revision:r.protocolInteger(c.revision,1),pinned:r.protocolBoolean(c.pinned),pinnedAt:c.pinnedAt==null?null:r.protocolText(c.pinnedAt,64),createdAt:r.protocolText(c.createdAt,64),lastActivityAt:r.protocolText(c.lastActivityAt,64)}},D=(o,a)=>{const n=r.protocolRecord(o),c=r.protocolArray(n.chats,100).map(g=>k(g,a));if(new Set(c.map(g=>g.chatId)).size!==c.length)throw new Error("Invalid Make App response: duplicate chat");const d=r.protocolText(n.nextCursor,8192,!0),h=r.protocolBoolean(n.hasMore);if(h!==!!d)throw new Error("Invalid Make App response: chat cursor");return{chats:c,nextCursor:d,hasMore:h}},O=(o,a,n)=>{const c=r.protocolRecord(o),d=r.protocolInteger(c.nextCursor,-1),h=r.protocolBoolean(c.hasMore);if(d<n||h&&d<=n)throw new Error("Invalid Make App response: history cursor did not advance");let g=0,p=n;const u=new Set,I=r.protocolArray(c.messages,200).map(v=>{const l=r.protocolRecord(v);if(l.role!=="user"&&l.role!=="assistant")throw new Error("Invalid Make App response: history role");const f=r.protocolInteger(l.cursor);if(f<=p||f>d)throw new Error("Invalid Make App response: history order");p=f;const A=l.messageId!==void 0,m=A?r.protocolId(l.messageId):`history-${a}-${f}`;if(u.has(m))throw new Error("Invalid Make App response: duplicate message");u.add(m);const s=r.protocolText(l.text,1e5,!0);if(g+=[...s].length,g>1e6)throw new Error("Invalid Make App response: history budget");return{id:m,role:l.role,content:s,persistent:A,cursor:f,createdAt:r.protocolText(l.createdAt,64),...l.responseId===void 0?{}:{responseId:r.protocolId(l.responseId)},...l.parts===void 0?{}:{parts:r.parseContentParts(l.parts)},...l.feedback===void 0?{}:{feedback:r.parseFeedback(l.feedback)}}});return{threadId:a,messages:I,nextCursor:d,hasMore:h}},x=(o,a)=>{const n=r.parseResponseSnapshot(o);if(n.chatId!==a.chatId||n.responseId!==a.responseId)throw new Error("Invalid Make App response: response scope");return n},R=(o,a)=>{const n=r.protocolRecord(o);if(!["uploading","ready","cancelled"].includes(String(n.status))||a&&n.id!==a)throw new Error("Invalid Make App response: upload");const c=r.protocolInteger(n.sizeBytes,0,64<<20),d=r.protocolInteger(n.partSize,1<<20,1<<20),h=r.protocolArray(n.completedParts,64).map(p=>r.protocolInteger(p,0,Math.max(0,Math.ceil(c/d)-1)));if(new Set(h).size!==h.length)throw new Error("Invalid Make App response: repeated upload part");const g={id:r.protocolId(n.id),status:n.status,name:T(n.name),contentType:r.protocolText(n.contentType,256),sizeBytes:c,partSize:d,completedParts:h};if(g.status==="ready"){const p=r.protocolRecord(n.content);if(p.kind!=="reference"||p.sizeBytes!==c||!/^[0-9a-f]{64}$/.test(String(p.digestSha256)))throw new Error("Invalid Make App response: content receipt");g.content={kind:"reference",contentRef:r.protocolId(p.contentRef),sizeBytes:c,digestSha256:String(p.digestSha256)}}return g},B=o=>{const a=r.protocolId(o.threadId),n=E(o.message.id);let c,d;if(o.message.parts!==void 0){const h=r.parseContentParts(o.message.parts);if(!h.length)throw new Error("Invalid Make App request: empty parts");const g=new Set;for(const p of h){const u=E(p.id);if(g.has(u))throw new Error("Invalid Make App request: duplicate part");if(g.add(u),p.kind!=="text"){p.name!==void 0&&T(p.name);const I=p.media.contentType;if(!/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(I)||p.kind!=="file"&&(!I.startsWith(`${p.kind}/`)||I==="image/svg+xml"))throw new Error("Invalid Make App request: media type")}}if(d=h.filter(p=>p.kind==="text").map(p=>p.text).join(""),!d.trim()&&h.every(p=>p.kind==="text"))throw new Error("Invalid Make App request: empty input");c={chatId:a,messageId:n,parts:h}}else d=r.protocolText(o.message.content,8192),c={chatId:a,messageId:n,text:d};if(new TextEncoder().encode(d).length>8192||new TextEncoder().encode(JSON.stringify(c)).length>65536)throw new Error("输入内容过长,请控制在 8 KiB 文本和 32 个附件/文本片段以内");return c},F=()=>{const o=[];let a,n=!1,c;return{push(d){if(!n)if(a){const h=a;a=void 0,h.resolve({done:!1,value:d})}else o.length>=4096?this.fail(new Error("响应事件积压超过限制,请恢复对话")):o.push(d)},fail(d){c=d,n=!0,o.length=0,a?.reject(d),a=void 0},close(){n=!0,o.length=0,a?.resolve({done:!0,value:void 0}),a=void 0},next(){return c?Promise.reject(c):o.length?Promise.resolve({done:!1,value:o.shift()}):n?Promise.resolve({done:!0,value:void 0}):new Promise((d,h)=>{a={resolve:d,reject:h}})}}},S=(o,a)=>new Promise(n=>{if(a?.aborted){n();return}const c=()=>{clearTimeout(d),a?.removeEventListener("abort",c),n()},d=setTimeout(c,o);a?.addEventListener("abort",c,{once:!0})}),C=o=>{if(!/^\d{1,20}-\d{1,20}$/.test(o))throw new Error("Invalid Make App response: stream cursor");return o.split("-").map(BigInt)},q=(o,a)=>{const[n,c]=C(o),[d,h]=C(a);return n>d||n===d&&c>h},K=o=>{const a=o;return[400,401,403,404].includes(a?.status??a?.response?.status??0)||["AI_FORBIDDEN","AI_AUTH_REQUIRED","AI_AUTH_EXPIRED","AI_NOT_FOUND","AI_RESPONSE_NOT_FOUND"].includes(a?.code??"")||o instanceof Error&&o.message.startsWith("Invalid ")},z=["response.subscribed","response.state","response.output_item.added","response.output_text.delta","response.output_item.done","response.reset","response.snapshot","response.completed","response.failed","response.cancelled"];async function*$(o,a,n){if(n?.aborted)return;let c=o.cursor??"0-0";C(c);let d=0,h=!1,g=0;const p=new Map;yield{type:"response.state",chatId:o.chatId,responseId:o.responseId,status:"queued"};async function*u(I,v){if(I==="completed"){let l=o.historyCursor??-1,f=0;const A=[];let m=!0;for(;m&&!n?.aborted;){if(++f>200)throw new Error("历史恢复超过单次预算,请继续加载历史");const s=await a.loadHistory(o,l,n);for(const e of s.messages)if(e.responseId===o.responseId&&e.role==="assistant"&&e.persistent){const{artifacts:t,...i}=e;A.push(r.parseStoredMessage(i))}if(m=s.hasMore??!1,m&&(s.nextCursor??-1)<=l)throw new Error("Invalid Make App response: history cursor");l=s.nextCursor??l}if(n?.aborted)return;if(!A.length)throw new Error("回答已完成,历史尚未同步,请恢复对话");yield{type:"response.reconciled",chatId:o.chatId,responseId:o.responseId,messages:A}}yield{type:"response.terminal",chatId:o.chatId,responseId:o.responseId,status:I,...v?{code:v}:{}}}for(;!n?.aborted;){if(d>3){if(++g>600)throw new Error("响应连接中断,请恢复对话");let e;try{e=await a.getResponse(o,n)}catch(t){if(n?.aborted)return;if(K(t))throw t}if(e&&(yield{type:"response.snapshot",snapshot:e},r.isResponseTerminal(e.status))){yield*u(e.status);return}await S(Math.max(1e3,a.reconnectDelayMs),n);continue}const I=F();let v=0,l=!1;const f=a.eventSourceFactory({chatId:o.chatId,responseId:o.responseId,cursor:c},{withCredentials:!0}),A=z.map(e=>{const t=i=>{if(!(l||n?.aborted)){if(i.data.length>a.maxEventCharacters*2||[...i.data].length>a.maxEventCharacters||v+i.data.length>4e6){l=!0,f.close(),I.fail(new Error("Make App assistant SSE event exceeds maxEventCharacters"));return}v+=i.data.length,I.push({name:e,raw:i.data,id:i.lastEventId})}};return f.addEventListener(e,t),{name:e,listener:t}});f.onerror=()=>{!l&&!n?.aborted&&(l=!0,f.close(),I.push({reconnect:!0}))};const m=()=>{l=!0,f.close(),I.close()};n?.addEventListener("abort",m,{once:!0}),n?.aborted&&m();try{for(;!n?.aborted;){const e=await I.next();if(e.done)return;const t=e.value;if("reconnect"in t)break;if(v-=t.raw.length,t.id&&!q(t.id,c)){if(p.has(t.id)&&p.get(t.id)!==t.raw)throw new Error("Invalid Make App response: conflicting stream replay");continue}const i=r.protocolRecord(JSON.parse(t.raw));if(r.protocolId(i.responseId)!==o.responseId)throw new Error("Invalid Make App response: stream scope");if(t.name!=="response.subscribed"){if(t.name==="response.reset"){h=!0;continue}if(t.name==="response.snapshot"){const y=x(i,o);if(yield{type:"response.snapshot",snapshot:y},r.isResponseTerminal(y.status)){yield*u(y.status);return}}else if(t.name==="response.completed"||t.name==="response.cancelled"){yield*u(t.name==="response.completed"?"completed":"cancelled");return}else if(t.name==="response.failed"){if(i.code==="AI_UPSTREAM_ERROR"){l=!0,f.close();break}if(i.code==="AI_FORBIDDEN"||i.code==="AI_AUTH_EXPIRED")throw Object.assign(new Error("当前身份无法继续读取响应"),{code:i.code,status:i.code==="AI_FORBIDDEN"?403:401});yield*u("failed",typeof i.code=="string"?i.code:void 0);return}else t.name==="response.state"?yield r.parseAssistantEvent({type:t.name,chatId:o.chatId,...i}):h||(yield r.parseAssistantEvent({type:t.name,...i}));t.id&&(c=t.id,p.set(t.id,t.raw),p.size>512&&p.delete(p.keys().next().value))}}}finally{f.onerror=null,f.close(),I.close();for(const{name:e,listener:t}of A)f.removeEventListener(e,t);n?.removeEventListener("abort",m)}if(n?.aborted||(d+=1,console.info("[make-ai-assistant] response reconnect",{attempt:d}),await S(Math.min(a.reconnectDelayMs*2**(d-1),5e3),n),n?.aborted))return;let s;try{s=await a.getResponse(o,n)}catch(e){if(n?.aborted)return;if(K(e))throw e}if(s&&r.isResponseTerminal(s.status)){yield{type:"response.snapshot",snapshot:s},yield*u(s.status);return}h&&(d=4)}}const U=()=>Object.assign(new Error("Operation aborted"),{name:"AbortError"}),_=o=>{if(o?.aborted)throw U()},L=o=>{const a=r.protocolInteger(o.historyLimit??100,1,200),n=r.protocolInteger(o.maxEventCharacters??1e6,1,4e6),c=r.protocolInteger(o.reconnectDelayMs??500,1,3e4),d=o.modelInputKinds??["text"],h=o.readContent,g=s=>{const e=o.resolveScope(s);return{appKey:r.protocolId(e.appKey),agentId:r.protocolId(e.agentId),identityKey:r.protocolId(e.identityKey)}},p=s=>{const e=g(s);return`${e.identityKey}\0${e.appKey}\0${e.agentId}`},u=async(s,e,t,i)=>{_(i);const y=p(s);console.info("[make-ai-assistant] Make App operation start",{operation:e});try{const w=await t();if(_(i),y!==p(s))throw U();return w}catch(w){throw console.warn("[make-ai-assistant] Make App operation failed",{operation:e,errorType:w instanceof Error?w.name:typeof w}),w}},I=s=>({chatId:r.protocolId(s.chatId)}),v=s=>({...I(s),responseId:r.protocolId(s.responseId)}),l=s=>({...I(s),uploadId:r.protocolId(s.uploadId)}),f=async(s,e,t,i)=>u(s,"loadHistory",async()=>O(await o.loadHistory({chatId:r.protocolId(e),cursor:r.protocolInteger(t,-1),limit:a},{signal:i}),e,t),i),A=async(s,e,t)=>u(s,"getResponse",async()=>x(await o.getResponse(v(e),{signal:t}),e),t),m=(s,e,t)=>{const i=p(s),y=t?.signal;return(async function*(){for await(const w of $(e,{eventSourceFactory:o.eventSourceFactory,getResponse:(b,M)=>A(s,b,M),loadHistory:(b,M,P)=>f(s,b.chatId,M,P),maxEventCharacters:n,reconnectDelayMs:c},y)){if(y?.aborted||i!==p(s))return;yield w}})()};return{features:{history:!0,newConversation:!0,remoteCancellation:!0,regeneration:!1,conversationManagement:!0,feedback:!0,attachments:!0,modelInputKinds:d},scopeKey:p,listAgents:(s,e)=>u(s,"listAgents",async()=>{const t=g(s),i=r.protocolRecord(await o.listAgents({appKey:t.appKey},{signal:e?.signal}));return r.protocolArray(i.agents,1e3).map(y=>{const w=r.protocolRecord(y);if(w.appKey!==t.appKey)throw new Error("Invalid Make App response: agent scope");return{agentId:r.protocolId(w.agentId),appKey:t.appKey,name:r.protocolText(w.name)}})},e?.signal),listConversations:(s,e,t)=>u(s,"listChats",async()=>{const{appKey:i,agentId:y}=g(s);return D(await o.listChats({appKey:i,agentId:y,...e?.cursor?{cursor:r.protocolText(e.cursor,8192)}:{},limit:r.protocolInteger(e?.limit??50,1,100)},{signal:t?.signal}),{appKey:i,agentId:y})},t?.signal),createConversation:(s,e,t)=>u(s,"createChat",async()=>{const{appKey:i,agentId:y}=g(s),w={appKey:i,agentId:y,requestId:E(e.requestId),...e.title===void 0?{}:{title:r.protocolText(e.title.trim(),255)}};return k(await o.createChat(w,{signal:t?.signal}),{appKey:i,agentId:y})},t?.signal),getConversation:(s,e,t)=>u(s,"getChat",async()=>k(await o.getChat(I(e),{signal:t?.signal}),g(s),e.chatId),t?.signal),updateConversation:(s,e,t)=>u(s,"updateChat",async()=>{const i={...I(e),expectedRevision:r.protocolInteger(e.expectedRevision,1)};if(e.title!==void 0&&(i.title=r.protocolText(e.title.trim(),255)),e.pinned!==void 0){if(typeof e.pinned!="boolean")throw new Error("Invalid Make App request: pinned");i.pinned=e.pinned}if(i.title===void 0&&i.pinned===void 0)throw new Error("Invalid Make App request: empty patch");return k(await o.updateChat(i,{signal:t?.signal}),g(s),e.chatId)},t?.signal),deleteConversation:(s,e,t)=>u(s,"deleteChat",()=>o.deleteChat({...I(e),expectedRevision:r.protocolInteger(e.expectedRevision,1)},{signal:t?.signal}),t?.signal),loadConversation:async(s,e)=>e?.threadId?f(s,e.threadId,e.cursor??-1,e.signal):{messages:[]},getResponse:(s,e,t)=>A(s,e,t?.signal),cancelResponse:(s,e,t)=>u(s,"cancelResponse",async()=>x(await o.cancelResponse(v(e),{signal:t?.signal}),e),t?.signal),setFeedback:(s,e,t)=>u(s,"setFeedback",async()=>{if(!["like","dislike","none"].includes(e.rating))throw new Error("Invalid Make App request: rating");const i=r.protocolText(e.reason??"",128,!0).trim(),y=r.protocolText(e.comment??"",4e3,!0).trim();if(e.rating!=="dislike"&&(i||y))throw new Error("Invalid Make App request: feedback detail");return r.parseFeedback(await o.setFeedback({...I(e),messageId:r.protocolId(e.messageId),requestId:E(e.requestId),rating:e.rating,...i?{reason:i}:{},...y?{comment:y}:{}},{signal:t?.signal}))},t?.signal),startUpload:(s,e,t)=>u(s,"startUpload",async()=>R(await o.startUpload({...I(e),fileId:E(e.fileId),name:T(e.name),contentType:r.protocolText(e.contentType,256),sizeBytes:r.protocolInteger(e.sizeBytes,0,64<<20),...e.digestSha256?{digestSha256:r.protocolText(e.digestSha256,64)}:{}},{signal:t?.signal})),t?.signal),getUpload:(s,e,t)=>u(s,"getUpload",async()=>R(await o.getUpload(l(e),{signal:t?.signal}),e.uploadId),t?.signal),uploadPart:(s,e,t)=>u(s,"uploadPart",()=>{if(!(e.bytes instanceof Uint8Array)||e.bytes.byteLength>1<<20)throw new Error("Invalid Make App request: upload bytes");return o.uploadPart({...l(e),part:r.protocolInteger(e.part,0,63),bytes:e.bytes},{signal:t?.signal})},t?.signal),completeUpload:(s,e,t)=>u(s,"completeUpload",async()=>R(await o.completeUpload(l(e),{signal:t?.signal}),e.uploadId),t?.signal),...h?{readContent:(s,e,t)=>u(s,"readContent",async()=>{const i=await h({...I(e),contentRef:r.protocolId(e.contentRef)},{signal:t?.signal});if(!(i instanceof Uint8Array)||i.byteLength>64<<20)throw new Error("Invalid Make App response: content bytes");return i},t?.signal)}:{},watchResponse:m,async*run(s,e){if(e?.signal?.aborted)return;const t=B(s),i=await u(s.context,"sendMessage",async()=>r.protocolRecord(await o.sendMessage(t,{signal:e?.signal})),e?.signal);if(i.chatId!==t.chatId)throw new Error("Invalid Make App response: accepted chat");const y=r.protocolId(i.responseId),w=r.protocolInteger(i.acceptedCursor);yield{type:"response.accepted",chatId:t.chatId,responseId:y,messageId:t.messageId,acceptedCursor:w},yield*m(s.context,{chatId:t.chatId,responseId:y,historyCursor:w},e)}}};exports.createMakeAppAssistantTransport=L;
|
package/dist/make-app.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ export interface MakeAppAssistantTransportOptions {
|
|
|
64
64
|
bytes: Uint8Array;
|
|
65
65
|
}, options: AssistantCallOptions): Promise<void>;
|
|
66
66
|
completeUpload(input: AssistantUploadRef, options: AssistantCallOptions): Promise<unknown>;
|
|
67
|
-
readContent(input: AssistantChatRef & {
|
|
67
|
+
readContent?(input: AssistantChatRef & {
|
|
68
68
|
contentRef: string;
|
|
69
69
|
}, options: AssistantCallOptions): Promise<Uint8Array>;
|
|
70
70
|
}
|