149 lines
5.4 KiB
HTML
149 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 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><form
|
|
toolname="create_support_ticket"
|
|
tooldescription="Create a support ticket from user supplied issue details.">
|
|
<input name="email" type="email" required />
|
|
<select name="category" required>...</select>
|
|
<textarea name="description" required></textarea>
|
|
</form></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 }) => 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>
|