Communitygithub.com

joshi-chinmay-016/AgentProof

使用 @Widget 和 @nitrostack/widgets SDK 將工具連結至互動式前端小工具的最佳實務(包含狀態同步、工具呼叫、顯示模式、媒體查詢和聊天動作)。

AgentProof 是什麼?

此技能專為在 AI 用戶端或 NitroStudio 中設計、建置或修改顯示自訂 React 內容的互動式使用者介面小工具而設計,提供一套完整的指引。它詳細說明了如何使用 `@Widget` 裝飾器在後端定義小工具,並將工具輸出對應至前端 React 元件。在前端,開發者可以利用 `@nitrostack/widgets` SDK 中的 `useWidgetSDK` hook 接收資料,並透過 `useWidgetState` 進行狀態管理,實現狀態在頁面重新渲染之間的自動同步。技能還涵蓋了從前端小工具直接呼叫後端 MCP 工具(`callTool`)以實現工具鏈結、動態調整小工具顯示模式(全螢幕、內嵌、子母畫面)、以及透過 `openExternal` 和 `sendFollowUpMessage` 與聊天面板進行互動。此外,它提供了媒體與無障礙查詢工具(如 `prefersReducedMotion`、`isPrimarilyTouchDevice`),並建議在 NitroStudio 中進行視覺化預覽測試,確保小工具能即時回應工具呼叫的 JSON 輸出。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/joshi-chinmay-016/AgentProof/tree/HEAD/agentproof/.agents/skills/ui-widgets

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

使用時機

當設計、建置或修改在 AI 用戶端或 NitroStudio 中顯示自訂 React 內容的互動式使用者介面小工具時,請使用此技能。


1. 後端定義 (@Widget)

若要為工具的輸出顯示一個基於 React 的小工具,請在工具方法上加上 @Widget 裝飾器。

選項:

  • 字串路由 (String Route):一個代表前端 React 應用程式中路由識別碼的簡單字串(例如 'product-card')。
  • 物件路由 (Object Route):包含以下項目的物件:
    • route(必要):路由路徑。
    • domain(選填):允許的沙箱網域。
    • csp(選填):內容安全政策指南。

範例:

import { Tool, Widget, z } from '@nitrostack/core';

export class CatalogTools {
  @Tool({
    name: 'fetch_product',
    description: '根據條碼取得產品資訊。',
    inputSchema: z.object({ barcode: z.string() }),
  })
  @Widget('product-details') // 對應到前端 "product-details" 元件
  async fetchProduct(input: { barcode: string }) {
    return {
      name: 'Super Nitro Energy Drink',
      price: 2.99,
      sku: input.barcode,
    };
  }
}

2. 前端 React 小工具 (@nitrostack/widgets)

在您的 React 小工具前端應用程式中(通常是一個 Next.js 用戶端元件),使用 useWidgetSDK hook 從用戶端主機接收輸入資料。

React 元件範例:

'use client';

import React from 'react';
import { useWidgetSDK } from '@nitrostack/widgets';

interface ProductData {
  name: string;
  price: number;
  sku: string;
}

export default function ProductDetailsWidget() {
  const { isReady, getToolOutput, theme } = useWidgetSDK();
  const data = getToolOutput<ProductData>();

  if (!isReady) {
    return <div className="loading">正在連接到主機...</div>;
  }

  if (!data) {
    return <div className="error">未收到產品資料。</div>;
  }

  return (
    <div className={`product-card ${theme === 'dark' ? 'dark' : 'light'}`}>
      <h3>{data.name}</h3>
      <p className="price">${data.price.toFixed(2)}</p>
      <span className="sku">SKU: {data.sku}</span>
    </div>
  );
}

3. 狀態管理與同步 (useWidgetState)

使用 useWidgetState 來管理並持久化用戶端小工具的狀態(例如選取的分頁、篩選值、輸入狀態)。此狀態會自動與主機應用程式上下文同步,並在頁面重新渲染之間保持持久。

範例:

import React from 'react';
import { useWidgetState } from '@nitrostack/widgets';

export default function StationPanelWidget() {
  const [state, setState] = useWidgetState(() => ({
    selectedTab: 'overview',
    showExtendedInfo: false,
  }));

  return (
    <div>
      <button onClick={() => setState({ ...state, selectedTab: 'alerts' })}>
        檢視警示
      </button>
      <p>目前分頁: {state?.selectedTab}</p>
    </div>
  );
}

4. 從小工具呼叫核心工具 (callTool)

您可以使用 callTool 直接從前端小工具呼叫其他後端 MCP 工具。這對於工具鏈結或觸發詳細稽核非常有用。

範例:

import React, { useState } from 'react';
import { useWidgetSDK } from '@nitrostack/widgets';

export default function SystemDiagnostics() {
  const { callTool, isReady } = useWidgetSDK();
  const [isRunning, setIsRunning] = useState(false);
  const [result, setResult] = useState<string | null>(null);

  const runDiagnostic = async () => {
    if (!isReady) return;
    setIsRunning(true);
    try {
      const response = await callTool('run_diagnostic', { system: 'oxygen_scrubber' });
      setResult(response.result as string);
    } catch (err) {
      setResult('診斷執行失敗。');
    } finally {
      setIsRunning(false);
    }
  };

  return (
    <button onClick={runDiagnostic} disabled={isRunning}>
      {isRunning ? '執行中...' : '執行診斷'}
    </button>
  );
}

5. 佈局與顯示控制

小工具可以動態請求尺寸模式變更(全螢幕、內嵌、子母畫面),並根據安全區域(動態島/瀏海)或最大高度限制調整佈局。

主要方法:

  • requestFullscreen():將主機小工具顯示切換為全螢幕。
  • requestInline():將主機小工具顯示切換回內嵌。
  • requestPip():將小工具浮動顯示為子母畫面。
  • requestClose():完全關閉小工具。

範例:

import React from 'react';
import { useWidgetSDK } from '@nitrostack/widgets';

export default function StatusBoard() {
  const { 
    requestFullscreen, 
    requestInline, 
    requestClose,
    displayMode,   // 響應式屬性 ('fullscreen' | 'inline' | 'pip')
    maxHeight,     // 響應式 maxHeight 限制(像素)
    getSafeArea    // 邊距資料: { top, right, bottom, left }
  } = useWidgetSDK();

  const safeArea = getSafeArea() || { top: 0, bottom: 0 };

  return (
    <div style={{ maxHeight: maxHeight || 400, paddingTop: safeArea.top }}>
      <h3>模式: {displayMode}</h3>
      <button onClick={requestFullscreen}>全螢幕</button>
      <button onClick={requestInline}>收起</button>
      <button onClick={requestClose}>關閉小工具</button>
    </div>
  );
}

6. 聊天導航與動作

小工具可以使用外部瀏覽器連結和後續提示與主機聊天面板互動。

主要方法:

  • openExternal(url):安全地在使用者的主要外部瀏覽器中開啟目標 URL。
  • sendFollowUpMessage(prompt):將訊息插入聊天流程中,並自動提交給 LLM 代理。

範例:

import React from 'react';
import { useWidgetSDK } from '@nitrostack/widgets';

export default function MissionControl() {
  const { openExternal, sendFollowUpMessage } = useWidgetSDK();

  return (
    <div>
      {/* 開啟外部文件 */}
      <button onClick={() => openExternal('https://docs.nitrostack.dev')}>
        開啟手冊
      </button>

      {/* 從小工具直接詢問 LLM 代理 */}
      <button onClick={() => sendFollowUpMessage('分析上週的任務失敗原因')}>
        請代理分析
      </button>
    </div>
  );
}

7. 媒體與無障礙查詢

SDK 提供輔助工具來查詢目標用戶端的功能,以便進行樣式或無障礙設計。

主要工具:

  • prefersReducedMotion():若用戶端設定指定減少動畫,則回傳 true。請停用動畫效果。
  • isPrimarilyTouchDevice():若裝置具有粗糙指針(例如觸控/手機),則回傳 true。請增加按鈕的目標尺寸。
  • isHoverAvailable():若指針支援懸浮狀態,則回傳 true。
  • prefersDarkColorScheme():若系統主題為深色,則回傳 true。

範例:

import React from 'react';
import { isPrimarilyTouchDevice, prefersReducedMotion } from '@nitrostack/widgets';

export default function AccessiblePanel() {
  const isTouch = isPrimarilyTouchDevice();
  const reducedMotion = prefersReducedMotion();

  return (
    <div className={reducedMotion ? 'no-animations' : 'smooth-transitions'}>
      <button style={{ padding: isTouch ? '16px' : '8px' }}>
        互動按鈕
      </button>
    </div>
  );
}

8. 測試小工具

  • 在 NitroStudio 中開啟您的專案以進行視覺預覽。
  • 從 AI 聊天或測試面板中呼叫工具,以驗證小工具是否會立即使用回傳的 JSON 結構進行更新。

相關技能