npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@my-agent/react

v0.2.1

Published

`@my-agent/react` 是 React SDK 的运行时包,负责客户端、上下文、主题容器、钩子与绑定运行时的 Agent 组合层组件。纯展示原语由 `@my-agent/ui` 提供。

Readme

@my-agent/react

@my-agent/react 是 React SDK 的运行时包,负责客户端、上下文、主题容器、钩子与绑定运行时的 Agent 组合层组件。纯展示原语由 @my-agent/ui 提供。

当前导出

  • @my-agent/react:根入口,透出客户端、Provider 与组件公共 API。
  • @my-agent/react/client:客户端、认证、错误与基础类型。
  • @my-agent/react/providersSdkRootThreadProvideruseThreadContextAgentProvider 与运行时钩子。
  • @my-agent/react/componentsMessageListPromptInput 与消息渲染扩展能力。
  • @my-agent/react/styles.css:React SDK 与底层展示原语共用的样式入口,宿主应用按需引入一次。

运行时职责

createAgentClient 负责连接 Agent API,并在发送请求时解析认证头。ThreadProvider 负责线程列表、活跃线程和创建线程;开启 autoCreate 后,没有可用线程时会自动创建一个新线程。AgentProvider 绑定当前线程并装配 AI SDK 对话运行时。MessageListPromptInput 只依赖 AgentProvider 提供的运行时上下文。

线程历史来自 Mastra server 的标准 memory 接口。服务端根据认证后的 Mastra resourceId 隔离线程,客户端不会也不应该传入 resourceId

匿名请求可以继续发送 baseUrl 下的 /chat 消息,但不能跨刷新恢复“当前用户线程”。需要恢复线程历史时,宿主应用必须提供能映射到稳定 Mastra resource 的认证信息。

使用方式

如果宿主应用只需要展示原语,请直接从 @my-agent/ui 引入。例如:

import { Button, Message } from "@my-agent/ui"

需要接入 Agent runtime 时,使用客户端、线程 Provider、Agent Provider 与基础聊天组件组合:

import "@my-agent/react/styles.css"

import { createAgentClient } from "@my-agent/react/client"
import { MessageList, PromptInput } from "@my-agent/react/components"
import {
  AgentProvider,
  SdkRoot,
  ThreadProvider,
  useThreadContext,
} from "@my-agent/react/providers"

const client = createAgentClient({
  baseUrl: "https://example.com/api",
})

function ChatRuntime() {
  const { activeThreadId, isLoading } = useThreadContext()

  if (isLoading) {
    return <div>正在加载对话...</div>
  }

  if (!activeThreadId) {
    return <div>暂无可用对话</div>
  }

  return (
    <AgentProvider
      agentId="generalAgent"
      client={client}
      threadId={activeThreadId}
    >
      <MessageList />
      <PromptInput />
    </AgentProvider>
  )
}

export function App() {
  return (
    <SdkRoot>
      <ThreadProvider agentId="generalAgent" autoCreate client={client}>
        <ChatRuntime />
      </ThreadProvider>
    </SdkRoot>
  )
}

客户端工具

AgentProvider 可以接收 clientTools,让模型在对话中请求浏览器侧能力。客户端工具有几个约束:

  • 工具名必须使用 client_ 命名空间,例如 client_get_selection。不带此前缀的工具不会作为客户端工具声明或渲染器接入;实际请求仍会受服务端工具名规则约束。
  • baseUrl 下的 /chat 只做协议边界校验:最多 20 个客户端工具,clientTools 声明 JSON 序列化后不超过 50,000 字符,超过限制的请求会被拒绝。
  • inputSchema 必须是 JSON Schema object,用来描述模型传给工具的入参;根 schema 必须是 type: "object"。schema 内部关键字会透传给 AI SDK,不由 baseUrl 下的 /chat 维护 JSON Schema 子集白名单。
  • execute 在浏览器中执行,返回值必须是 JSON 可序列化值,例如 null、布尔值、数字、字符串、数组或普通对象。
  • render 是可选的,可以自定义工具消息在 MessageList 中的展示方式。
  • createClientToolRenderers(clientTools) 会把工具定义里的 render 转成 MessageRendererProvider 可识别的 toolRenderers
  • toolRenderers 按数组顺序匹配。消费者显式传入的渲染器放在 createClientToolRenderers(clientTools) 之前时,可以覆盖工具自带渲染器。
import "@my-agent/react/styles.css"

import type { ReactNode } from "react"

import { createAgentClient } from "@my-agent/react/client"
import {
  createClientToolRenderers,
  MessageList,
  MessageRendererProvider,
  PromptInput,
  type ToolPart,
  type ToolRenderer,
} from "@my-agent/react/components"
import {
  AgentProvider,
  SdkRoot,
  ThreadProvider,
  useThreadContext,
  type ClientToolRegistry,
} from "@my-agent/react/providers"

const client = createAgentClient({
  baseUrl: "https://example.com/api",
})

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null
}

function getSelectionText(part: ToolPart): string | undefined {
  if (!("output" in part) || !isRecord(part.output)) {
    return undefined
  }

  return typeof part.output.text === "string" ? part.output.text : undefined
}

const clientTools = {
  client_get_selection: {
    description: "读取用户当前选中的文本",
    inputSchema: {
      type: "object",
      properties: {},
      additionalProperties: false,
    },
    execute() {
      return {
        text: window.getSelection()?.toString() ?? "",
      }
    },
    render({ part }): ReactNode {
      if (part.state === "input-streaming" || part.state === "input-available") {
        return <div>正在读取浏览器选区...</div>
      }

      if (part.state === "output-error") {
        const errorText =
          "errorText" in part && typeof part.errorText === "string"
            ? part.errorText
            : "未知错误"

        return <div>读取浏览器选区失败:{errorText}</div>
      }

      const text = getSelectionText(part)

      return (
        <div>
          已读取浏览器选区:{text === undefined || text === "" ? "(空)" : text}
        </div>
      )
    },
  },
} satisfies ClientToolRegistry

const toolRenderers: readonly ToolRenderer[] = [
  {
    id: "host:client_get_selection",
    canRender: ({ toolName }) => toolName === "client_get_selection",
    render: () => <div>宿主应用覆盖了选区工具展示</div>,
  },
  ...createClientToolRenderers(clientTools),
]

function ChatRuntime() {
  const { activeThreadId, isLoading } = useThreadContext()

  if (isLoading) {
    return <div>正在加载对话...</div>
  }

  if (!activeThreadId) {
    return <div>暂无可用对话</div>
  }

  return (
    <AgentProvider
      agentId="generalAgent"
      client={client}
      clientTools={clientTools}
      threadId={activeThreadId}
    >
      <MessageRendererProvider toolRenderers={toolRenderers}>
        <MessageList />
        <PromptInput />
      </MessageRendererProvider>
    </AgentProvider>
  )
}

export function App() {
  return (
    <SdkRoot>
      <ThreadProvider agentId="generalAgent" autoCreate client={client}>
        <ChatRuntime />
      </ThreadProvider>
    </SdkRoot>
  )
}

构建

pnpm --filter @my-agent/react build