Files

150 lines
5.4 KiB
HTML

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WebMCP Demo - Tool Contracts</title>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<header class="topbar">
<div>
<p class="eyebrow">Runnable demo</p>
<h1>WebMCP 工具契约演示</h1>
</div>
<div class="runtime">
<span id="native-status" class="pill">检测中</span>
<a class="demo-home" href="../index.html">Demo 总览</a>
<a href="https://developer.chrome.com/docs/ai/webmcp" target="_blank" rel="noreferrer">Chrome 官方文档</a>
</div>
</header>
<main class="layout">
<section class="workspace">
<div class="intro">
<p>
这个页面模拟一个售后后台:左侧是人能操作的业务 UI,右侧是页面暴露给 Agent 的工具契约。
如果当前 Chrome 没有开启 WebMCP,本页面会使用本地 mock,让现场仍然能看清楚“工具注册”和“工具调用”的流程。
</p>
</div>
<section class="panel">
<div class="panel-head">
<div>
<p class="eyebrow">Declarative API</p>
<h2>声明式:把 HTML 表单变成工具</h2>
</div>
<span class="mode">form attributes</span>
</div>
<form
id="ticket-form"
class="business-form"
toolname="create_support_ticket"
tooldescription="Create a support ticket from user supplied issue details."
>
<label>
客户邮箱
<input name="email" type="email" required value="dev@example.com" />
</label>
<label>
问题类型
<select name="category" required>
<option value="refund">退款</option>
<option value="delivery">物流</option>
<option value="account">账号</option>
</select>
</label>
<label>
问题描述
<textarea name="description" required>订单 CHR-2026-0614 到货后发现配件缺失。</textarea>
</label>
<button type="submit">提交工单</button>
</form>
<pre class="code"><code>&lt;form
toolname="create_support_ticket"
tooldescription="Create a support ticket from user supplied issue details."&gt;
&lt;input name="email" type="email" required /&gt;
&lt;select name="category" required&gt;...&lt;/select&gt;
&lt;textarea name="description" required&gt;&lt;/textarea&gt;
&lt;/form&gt;</code></pre>
</section>
<section class="panel">
<div class="panel-head">
<div>
<p class="eyebrow">Imperative API</p>
<h2>指令式:用 JavaScript 注册业务工具</h2>
</div>
<span class="mode">registerTool()</span>
</div>
<div class="order-grid">
<article>
<span>订单号</span>
<strong>CHR-2026-0614</strong>
<small>已签收,缺件风险</small>
</article>
<article>
<span>客户等级</span>
<strong>Enterprise</strong>
<small>允许优先退款审核</small>
</article>
<article>
<span>当前状态</span>
<strong id="order-state">等待处理</strong>
<small>由工具调用更新</small>
</article>
</div>
<div class="action-row">
<button data-run-tool="lookup_order_status">运行 lookup_order_status</button>
<button data-run-tool="draft_customer_reply">运行 draft_customer_reply</button>
<button data-run-tool="approve_refund_review">运行 approve_refund_review</button>
</div>
<pre class="code"><code>navigator.modelContext.registerTool({
name: "lookup_order_status",
description: "Look up order status by order id.",
inputSchema: {
type: "object",
properties: { orderId: { type: "string" } },
required: ["orderId"]
},
execute: async ({ orderId }) =&gt; lookupOrder(orderId)
});</code></pre>
</section>
</section>
<aside class="agent">
<section class="agent-panel">
<p class="eyebrow">Agent view</p>
<h2>已暴露工具</h2>
<div id="tool-list" class="tool-list"></div>
</section>
<section class="agent-panel">
<p class="eyebrow">Run script</p>
<h2>现场演示步骤</h2>
<ol class="steps">
<li>先提交左侧表单,说明“人类 UI 仍然可用”。</li>
<li>看右侧工具列表,说明 Agent 看到的是名称、描述和 JSON Schema。</li>
<li>点击工具运行按钮,说明 Agent 不需要猜按钮位置,而是调用明确工具。</li>
<li>点击“执行复合任务”,串起查询、决策和回复草稿。</li>
</ol>
<button id="run-workflow" class="primary">执行复合任务</button>
</section>
<section class="agent-panel log-panel">
<p class="eyebrow">Execution log</p>
<h2>调用日志</h2>
<div id="log" class="log"></div>
</section>
</aside>
</main>
<script type="module" src="./app.js"></script>
</body>
</html>