Chat API

核心的對話 API,處理所有 Agent 互動

概述

Chat API 是 Lens OS SDK 的核心端點,負責處理所有 Agent 對話。它接收用戶訊息,透過 SSE (Server-Sent Events) 串流回應,包含 Agent 思考過程、工具呼叫、最終回答。

資料流程

SSE 串流流程
Client                    Server                    LLM
  │                         │                        │
  │  POST /chat             │                        │
  │ ───────────────────────►│                        │
  │                         │  Request completion    │
  │                         │ ──────────────────────►│
  │                         │                        │
  │  SSE: tool_call         │◄─ Tool call needed ────│
  │◄────────────────────────│                        │
  │                         │  Execute tool          │
  │                         │ ────────┐              │
  │                         │◄────────┘              │
  │  SSE: tool_result       │                        │
  │◄────────────────────────│  Return result         │
  │                         │ ──────────────────────►│
  │  SSE: text              │◄─ Final response ──────│
  │◄────────────────────────│                        │
  │  SSE: done              │                        │
  │◄────────────────────────│                        │

流程說明:

  • Client → Server:前端發送 POST 請求到 Chat API
  • Server → LLM:SDK 將訊息發送給 LLM 模型
  • tool_call:LLM 判斷需要執行工具時,發送工具呼叫事件
  • Execute tool:後端執行對應的 Tool Executor
  • tool_result:工具執行完成,回傳結果給 LLM
  • text:LLM 生成最終回應文字
  • done:對話完成

基本設定

最簡單的設定:只需兩個 API Key,直接匯出 POST

src/app/api/lens/agent/chat/route.ts
import { createAgentHandler } from "@lens-os/sdk/server";

const handler = createAgentHandler({
  apiKey: process.env.LENS_OS_API_KEY!,
  openaiKey: process.env.LENS_MODEL_API_KEY!,
});

export const { POST } = handler;

加入用戶驗證

需要驗證身份時,在 POST handler 中注入 userId,讓 SDK 能區分不同用戶的對話歷史與 Session。 以下以 NextAuth.js 為例,其他驗證方案只需替換取得 userId 的方式即可。

src/app/api/lens/agent/chat/route.ts
import { createAgentHandler } from "@lens-os/sdk/server";
import { auth } from "@/auth";

const handler = createAgentHandler({
  apiKey: process.env.LENS_OS_API_KEY!,
  openaiKey: process.env.LENS_MODEL_API_KEY!,
});

export async function POST(req: Request) {
  // 1. 驗證身份
  const session = await auth();
  if (!session?.user) {
    return new Response(JSON.stringify({ error: "Unauthorized" }), {
      status: 401,
      headers: { "Content-Type": "application/json" },
    });
  }

  // 2. 注入 userId(讓 SDK 能區分不同用戶的對話歷史)
  const userId = session.user.id || "default-user";
  const body = await req.json();

  return handler.POST(
    new Request(req.url, {
      method: "POST",
      headers: req.headers,
      body: JSON.stringify({ ...body, userId }),
    })
  );
}

Note

userId 決定 Session 的歸屬。不注入時所有用戶共享同一 Session 空間。

加入自訂工具

透過 toolExecutors 掛載工具,Agent 在對話中會自動判斷何時呼叫它們。

src/app/api/lens/agent/chat/route.ts
import { createAgentHandler } from "@lens-os/sdk/server";
import type { ToolExecutorConfig } from "@lens-os/sdk";

const tools: Record<string, ToolExecutorConfig> = {
  // 在這裡定義你的工具,詳見 工具執行器 文檔
};

const handler = createAgentHandler({
  apiKey: process.env.LENS_OS_API_KEY!,
  openaiKey: process.env.LENS_MODEL_API_KEY!,

  // 掛載自訂工具,Agent 可在對話中呼叫
  toolExecutors: tools,

  // 選填:進階設定
  model: process.env.LENS_MODEL_NAME || "gpt-4o",
  maxTurns: 10,
  debug: process.env.NODE_ENV === "development",
});

export const { POST } = handler;

Tip

請參考 工具執行器 文檔了解如何建立工具。

Handler 設定選項

選項類型預設值說明
apiKeystring必填Lens OS API Key
openaiKeystring必填LLM API Key
openaiBaseUrlstring""LLM API Base URL
modelstring"gpt-4o"LLM 模型名稱
maxTurnsnumber10最大工具呼叫輪數
debugbooleanfalse開啟詳細 log
toolExecutorsobject{}工具執行器

Request Body

前端 sendMessage 會送出以下格式的請求:

Request
interface ChatRequest {
  message: string;           // 用戶訊息
  sessionId?: string;        // Session ID(自動產生)
  userId?: string;           // 用戶 ID(由後端注入)
  context?: {
    currentUrl?: string;     // 目前頁面 URL
    pageState?: PageState;   // 頁面狀態(視覺辨識用)
  };
}

Response 格式

回應為 SSE 串流,每個事件格式如下:

SSE Events
// 文字回應
{ "type": "text", "content": "讓我幫你搜尋..." }

// 工具呼叫開始
{ "type": "tool_call", "name": "product_search", "parameters": { "query": "TypeScript" } }

// 工具執行完成
{ "type": "tool_result", "name": "product_search", "result": { ... } }

// 錯誤
{ "type": "error", "error": "Something went wrong" }

// 完成
{ "type": "done" }

各事件類型說明:

  • text:Agent 的文字回應,可能分多次傳送
  • tool_call:Agent 開始執行某個工具
  • tool_result:工具執行完成,包含結果
  • error:發生錯誤
  • done:整個對話回合完成

錯誤處理

建議加入完整的錯誤處理:

route.ts
export async function POST(req: Request) {
  try {
    const session = await auth();
    if (!session?.user) {
      return new Response(
        JSON.stringify({ error: "Unauthorized" }),
        { status: 401 }
      );
    }

    const body = await req.json();
    // ... handler logic

  } catch (error) {
    console.error("[Chat API] Error:", error);

    return new Response(
      JSON.stringify({
        error: error instanceof Error ? error.message : "Internal error",
      }),
      { status: 500 }
    );
  }
}

下一步