feat(iteration): implement sdk v1 miniapp runtime loop
This commit is contained in:
@@ -30,6 +30,7 @@ export type MountedChatApp = {
|
||||
messages: HTMLElement;
|
||||
loginView: HTMLElement;
|
||||
chatView: HTMLElement;
|
||||
appSessions: HTMLElement;
|
||||
presence: HTMLElement;
|
||||
rendererContext: TrustedDOMRendererContext;
|
||||
rendererRegistry: RendererRegistry<TrustedDOMRendererContext>;
|
||||
@@ -51,6 +52,7 @@ export function mountChatApp(
|
||||
const messages = query<HTMLElement>(root, "#messages");
|
||||
const loginView = query<HTMLElement>(root, "#login-view");
|
||||
const chatView = query<HTMLElement>(root, "#chat-view");
|
||||
const appSessions = query<HTMLElement>(root, "#app-sessions");
|
||||
const presence = query<HTMLElement>(root, "#presence");
|
||||
const rendererContext = new TrustedDOMRendererContext(
|
||||
messages,
|
||||
@@ -68,6 +70,7 @@ export function mountChatApp(
|
||||
messages,
|
||||
loginView,
|
||||
chatView,
|
||||
appSessions,
|
||||
presence,
|
||||
rendererContext,
|
||||
rendererRegistry,
|
||||
|
||||
@@ -19,6 +19,7 @@ export function mountChatShell(root: HTMLElement): void {
|
||||
</section>
|
||||
<section id="chat-view" class="chat-view" hidden>
|
||||
<header class="chat-header"><div class="agent"><span class="avatar">✦</span><div><strong>AI Agent</strong><small id="presence">正在连接…</small></div></div><div><button id="surface-demo" class="quiet" type="button">启用任务面板</button><button id="logout" class="quiet">退出</button></div></header>
|
||||
<section id="app-sessions" class="app-sessions" aria-label="应用子会话"></section>
|
||||
<section id="messages" class="messages" aria-live="polite"></section>
|
||||
<form id="message-form" class="composer"><textarea id="message-input" rows="1" placeholder="问问你的 AI 搭档…"></textarea><button id="send" type="submit">发送</button></form>
|
||||
</section>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,6 +12,7 @@ import type {
|
||||
ConversationItem,
|
||||
DeliveryState,
|
||||
InputForm,
|
||||
NoticeDefinition,
|
||||
JsonObject,
|
||||
ToolCallRequest,
|
||||
} from "@/runtime/protocol/lineup-v1";
|
||||
@@ -168,6 +169,10 @@ export class TrustedDOMRendererContext {
|
||||
|
||||
public renderToolCall(item: Extract<ConversationItem, { kind: "tool-call" }>): void {
|
||||
const record = this.toolInteractions?.read(item.call.call_id);
|
||||
if (item.call.tool === "notice" && item.call.notice) {
|
||||
this.renderNoticeCard(item.call, item.call.notice);
|
||||
return;
|
||||
}
|
||||
if (item.call.tool === "choice" && item.call.action_group) {
|
||||
this.renderActionGroup(item.call, item.call.action_group, record);
|
||||
return;
|
||||
@@ -183,6 +188,30 @@ export class TrustedDOMRendererContext {
|
||||
this.renderSystemMessage("收到无法安全展示的标准交互请求。");
|
||||
}
|
||||
|
||||
private renderNoticeCard(call: ToolCallRequest, notice: NoticeDefinition): void {
|
||||
const card = document.createElement("article");
|
||||
card.className = "tool-card notice-card";
|
||||
card.dataset.callId = call.call_id;
|
||||
const heading = document.createElement("strong");
|
||||
heading.textContent = call.title || "提示";
|
||||
const detail = document.createElement("p");
|
||||
detail.textContent = notice.message;
|
||||
const status = document.createElement("small");
|
||||
status.className = "tool-card-status";
|
||||
status.textContent = notice.dismiss_label ?? "已收到";
|
||||
card.append(heading, detail, status);
|
||||
this.toolCards.set(call.call_id, { card, status, controls: [] });
|
||||
this.messages.append(card);
|
||||
this.scrollLatest();
|
||||
// Toast is only an additional short reminder; the durable IM card above remains.
|
||||
const toast = document.createElement("div");
|
||||
toast.className = "notice-toast";
|
||||
toast.textContent = notice.message;
|
||||
toast.setAttribute("role", "status");
|
||||
this.messages.parentElement?.append(toast);
|
||||
globalThis.setTimeout(() => toast.remove(), 4_000);
|
||||
}
|
||||
|
||||
public renderToolResult(item: Extract<ConversationItem, { kind: "tool-result" }>): void {
|
||||
const entry = this.toolCards.get(item.result.call_id);
|
||||
if (!entry) return;
|
||||
|
||||
Reference in New Issue
Block a user