最新资讯
dev.to Pando:OpenAI 如何通过放宽跨分支一致性,让 Git 支撑 Agent 速度的推送 dev.to 为能花钱或签发的 Agent 做威胁建模 dev.to Linux 本地提权:OpenAI 报告的 948 项发现 unite.ai NVIDIA 以 Vera CPU 对比 x86:聚焦 Agent 速度与能效容量 techmeme.com 消息称 NVIDIA 接触 Apollo,拟将 Brightspeed 的 130 多栋建筑改造为小型数据中心 thenewstack.io Factory 收购 HumanLayer,并称其为一个月内第三起 AI 编程初创收购 blogs.nvidia.com NVIDIA 称 Vera CPU 兼顾高吞吐与最快 Agent 性能 www.youtube.com Netflix 如何评估没有标准答案的 AI 任务 nytimes.com OpenAI 承诺让当地社区在数据中心项目中拥有更多话语权 unite.ai 约 60 万块 NVIDIA H200 因北京进口审批滞留香港 techcrunch.com Meta 称美国用户现可与 Muse AI 头像视频通话 theinformation.com Nvidia 应对数据中心阻力的变通方案:改造旧电话局建筑
多元动态
登录 注册
智能体 developers.cloudflare.com · @Cloudflare Developers

Cloudflare Agents SDK 新增内部主机名:无需公网 URL 即可在浏览器预览开发服务器

原文 我的收藏

Cloudflare Agents SDK 引入 internal hostnames 能力,让 Agent 的持久化浏览器可访问仅由 Agent 自身提供的站点(如 preview.internal),请求被路由到 Durable Object 而非公网。每个内部主机带 fetch 函数,可使用对象绑定与状态,也可通过 service binding 直连其他 Worker;支持 target schema 让模型选择端口或目录。该能力独立于 Agent harness,提供 Pi Durable、AI SDK、TanStack AI 适配器,需 Agents SDK v0.31.0 及以上。

AI推荐理由 Cloudflare Agents SDK 官方文档更新,给出 internal hostnames 的具体机制(browser.assignHost、fetchInternalHost、service binding 直连 Worker)和可运行代码示例,信息密度高、来源可信。局限是仅为预览能力,未提供性能或安全验证数据,且需 Agents SDK v0.31.0 以上。

78

正文

Agents that build websites need to check their work in a real browser. Internal hostnames let your agent's browser preview a dev server running in a container without exposing that server to the public Internet. With internal hostnames, the [persistent browser](https://developers.cloudflare.com/agents/tools/browser/) in the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/) can open sites that only your agent serves. Give the browser hostnames such as `preview.internal`, and its requests to them go to your agent instead of the Internet. The model can check a dev server in its sandbox, a folder in its workspace, or another Worker in the same browser it uses for the web, and nothing is exposed publicly. ![An animated diagram of three kinds of hostname: example.com goes out to the Internet; the model points preview.internal at port 5173 with browser.assignHost(), then the browser opens it and your agent serves it from the sandbox; and api.internal goes straight to another Worker, skipping your agent](https://developers.cloudflare.com/cdn-cgi/image/onerror=redirect,width=960,height=524,format=svg/_astro/browser-internal-hostnames.FAVHfafR.svg) Each internal host has a `fetch` function that runs in your Durable Object, so it can use the object's bindings and state. A host can also send its requests straight to another Worker through a service binding. Add a `target` schema to a host, and the model chooses what it serves, such as which port or which folder. Internal hostnames are a capability of the browser, independent of your agent harness. Use the built-in adapters for Pi Durable, AI SDK, and TanStack AI, or connect another harness by implementing a tool with [`browser.session()`](https://developers.cloudflare.com/agents/tools/browser/#use-another-harness). No prebuilt adapter is required. This example adds a private dev-server preview to a [Pi Durable agent](https://developers.cloudflare.com/agents/tools/browser/#use-it-with-pi-durable). Start with that guide's packages, bindings, and request handler, and install [Agents SDK v0.31.0 ↗︎](https://github.com/cloudflare/agents/releases/tag/agents%400.31.0) or later. The example has three parts: * **Browser configuration:** `internalHosts` defines how the browser reaches the dev server. * **Durable Object wiring:** Lifecycle and `fetchInternalHost()` connect the browser to your application. * **Harness integration:** `browserTool` from `agents/browser/pi` registers the tool with Pi. ``` import { DurableObject } from "cloudflare:workers"; import { createModels } from "@earendil-works/pi-ai/models"; import { createRegistry, Harness } from "@earendil-works/pi-durable"; import { Browser, browserRun } from "agents/browser"; import { browserTool } from "agents/browser/pi"; import { PiHarness } from "agents/harness/pi"; import { Lifecycle } from "agents/lifecycle"; import { createAI } from "agents/models/pi-ai"; import { z } from "zod"; // Your own code: reach a port on your sandbox and return its Response. import { fetchSandboxPort } from "./hosts"; // Browser Run calls back into your Worker through this entrypoint. export { InternalHostRouter } from "agents/browser"; export class BrowserAssistant extends DurableObject { ai = createAI({ binding: this.env.AI }); registry = createRegistry(); browser = new Browser({ provider: browserRun(this.env.BROWSER, { internalHosts: { router: this.ctx.exports.InternalHostRouter, hosts: { "preview.internal": { description: "Your dev servers", // What the model passes to browser.assignHost() to choose // what this host serves. fetch receives it as its second argument. target: z.object({ port: z.number().int().min(1024) }), fetch: (request, { port }) => fetchSandboxPort(port, request), }, }, }, }), }); harness = new PiHarness({ harness: ({ storage, context, onWake }) => { const models = createModels(); models.setProvider(this.ai.provider); this.registry.install({ name: "browser", tools: [ browserTool({ browser: this.browser, loader: this.env.LOADER }), ], }); return Harness.open( storage, { models, registry: this.registry, onWake }, context, ); }, defaults: { model: this.ai("@cf/zai-org/glm-5.3-flash") }, }); lifecycle = Lifecycle.install(this).use(this.browser).use(this.harness); // InternalHostRouter calls this method to reach your Browser. fetchInternalHost(message) { return this.browser.fetchInternalHost(message); } async ask(prompt) { const { text } = await this.harness.prompt(prompt); return text; } } ``` ``` import { DurableObject } from "cloudflare:workers"; import { createModels } from "@earendil-works/pi-ai/models"; import { createRegistry, Harness } from "@earendil-works/pi-durable"; import { Browser, browserRun, type InternalHostMessage } from "agents/browser"; import { browserTool } from "agents/browser/pi"; import { PiHarness } from "agents/harness/pi"; import { Lifecycle } from "agents/lifecycle"; import { createAI } from "agents/models/pi-ai"; import { z } from "zod"; // Your own code: reach a port on your sandbox and return its Response. import { fetchSandboxPort } from "./hosts"; // Browser Run calls back into your Worker through this entrypoint. export { InternalHostRouter } from "agents/browser"; export class BrowserAssistant extends DurableObject { ai = createAI({ binding: this.env.AI }); registry = createRegistry(); browser = new Browser({ provider: browserRun(this.env.BROWSER, { internalHosts: { router: this.ctx.exports.InternalHostRouter, hosts: { "preview.internal": { description: "Your dev servers", // What the model passes to browser.assignHost() to choose // what this host serves. fetch receives it as its second argument. target: z.object({ port: z.number().int().min(1024) }), fetch: (request, { port }) => fetchSandboxPort(port, request), }, }, }, }), }); harness = new PiHarness({ harness: ({ storage, context, onWake }) => { const models = createModels(); models.setProvider(this.ai.provider); this.registry.install({ name: "browser", tools: [ browserTool({ browser: this.browser, loader: this.env.LOADER }), ], }); return Harness.open( storage, { models, registry: this.registry, onWake }, context, ); }, defaults: { model: this.ai("@cf/zai-org/glm-5.3-flash") }, }); lifecycle = Lifecycle.install(this).use(this.browser).use(this.harness); // InternalHostRouter calls this method to reach your Browser. fetchInternalHost(message: InternalHostMessage) { return this.browser.fetchInternalHost(message); } async ask(prompt: string) { const { text } = await this.harness.prompt(prompt); return text; } } ``` To use another harness, keep the browser configuration. Choose a [browser-tool adapter](https://developers.cloudflare.com/agents/tools/browser/#use-another-harness) if one is available, or implement a tool using `browser.session()`. `browserTool` tells the model about each host, including the schema of its `target`. Because `preview.internal` has a `target` schema, the model can choose which port it serves. To check its dev server, the model calls `browser.assignHost()` with a target that matches the schema, such as `{ port: 5173 }`, and opens the URL it gets back: ``` const { url } = await browser.assignHost({ host: "preview.internal", target: { port: 5173 }, }); await browser.cdp({ method: "Page.navigate", params: { url }, sessionId: "active", }); ``` The target is checked against the schema and stored, so it lasts across turns, browser restarts, and redeploys. Each request to `http://preview.internal/` then calls the host's `fetch` function with `{ port: 5173 }`. This release also simplifies `browserTool`. It runs the model's code in its own [Dynamic Worker](https://developers.cloudflare.com/dynamic-workers/) and no longer needs a `CodemodeRuntime` export. Refer to the [v0.31.0 upgrade notes ↗︎](https://github.com/cloudflare/agents/releases/tag/agents%400.31.0) if you already use `browserTool`. For the complete example, limits, and security guidance, refer to [Internal hostnames](https://developers.cloudflare.com/agents/tools/browser/#internal-hostnames).

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容