feat: add trusted confirm and input forms

This commit is contained in:
2026-08-03 16:00:19 +08:00
parent bddf15a2d2
commit 9312b09e76
11 changed files with 492 additions and 31 deletions
+27 -2
View File
@@ -94,8 +94,28 @@ function loginFailureMessage(reason: unknown): string {
return message || "登录失败,请稍后重试。";
}
const rendererContext = new TrustedDOMRendererContext(messages, presence, (callID, submission) => {
return interactionKernel.submitToolCall(callID, new Date().toISOString(), submission).disposition === "accepted";
const rendererContext = new TrustedDOMRendererContext(messages, presence, {
submit(callID, submission) {
const transition = interactionKernel.submitToolCall(callID, new Date().toISOString(), submission);
conversationStore.replaceToolCalls(interactionKernel.snapshot().tool_calls);
if (transition.disposition === "accepted") conversationStore.clearToolDraft(callID);
return transition.disposition === "accepted";
},
cancel(callID, reason) {
const transition = interactionKernel.cancelToolCall(callID, reason, new Date().toISOString());
conversationStore.replaceToolCalls(interactionKernel.snapshot().tool_calls);
if (transition.disposition === "accepted") conversationStore.clearToolDraft(callID);
return transition.disposition === "accepted";
},
expire(callID) {
const transition = interactionKernel.expireToolCall(callID, new Date().toISOString());
conversationStore.replaceToolCalls(interactionKernel.snapshot().tool_calls);
return transition.disposition === "accepted";
},
read(callID) { return interactionKernel.snapshot().tool_calls.find(record => record.call_id === callID); },
loadDraft(callID) { return conversationStore.getToolDraft(callID); },
saveDraft(callID, values) { conversationStore.saveToolDraft(callID, values); },
clearDraft(callID) { conversationStore.clearToolDraft(callID); },
});
const rendererRegistry = new RendererRegistry<TrustedDOMRendererContext>();
rendererRegistry.register("user-message", (item, context) => context.renderUserMessage(item));
@@ -163,6 +183,9 @@ async function syncLoop(): Promise<void> {
source: "sync",
transport_id: String(message.message_seq),
});
if (result.items.some(item => item.kind === "tool-call" || item.kind === "tool-result" || item.kind === "tool-cancel")) {
conversationStore.replaceToolCalls(result.snapshot.tool_calls);
}
for (const item of result.items) {
if (conversationStore.recordIncoming(item, message.message_seq, new Date().toISOString())) renderIncoming(item);
}
@@ -209,6 +232,8 @@ $<HTMLFormElement>("#login-form").addEventListener("submit", async event => {
transport = candidateTransport;
session = { ...session, uid: body.uid, agentUID: body.agent_uid || session.agentUID, channelID: body.channel_id || session.channelID, channelType: body.channel_type || session.channelType, lastSeq: 0, active: true };
const snapshot = conversationStore.open(currentConversationKey());
interactionKernel.restoreToolCalls(snapshot.tool_calls, new Date().toISOString());
conversationStore.replaceToolCalls(interactionKernel.snapshot().tool_calls);
session.lastSeq = snapshot.cursor;
messages.replaceChildren(); rendererContext.reset();
loginView.hidden = true; chatView.hidden = false;