Skip to content

Fix parentAgent for facet-only parents#1548

Merged
threepointone merged 2 commits into
mainfrom
fix-parent-agent-facet-proxy
May 18, 2026
Merged

Fix parentAgent for facet-only parents#1548
threepointone merged 2 commits into
mainfrom
fix-parent-agent-facet-proxy

Conversation

@threepointone
Copy link
Copy Markdown
Contributor

@threepointone threepointone commented May 18, 2026

Summary

This PR fixes Agent#parentAgent(Cls) for nested sub-agent trees where the immediate parent is itself a Durable Object facet rather than a top-level bound Durable Object namespace.

Before this change, parentAgent(Cls) only knew how to resolve top-level parents through env[Cls.name]. That worked for simple Root -> Child trees, but it broke for deeper Root -> OuterFacet -> InnerFacet trees because InnerFacet.parentAgent(OuterFacet) tried to find a top-level OuterFacet namespace even though OuterFacet is intentionally facet-only.

What changed

  • parentAgent(Cls) still validates that Cls.name matches the recorded direct parent class in parentPath.
  • Top-level parent lookup now prefers env[Cls.name] and falls back to the Worker exports namespace by exported class name.
    • This preserves the normal env-binding path.
    • It also supports custom Durable Object binding names, as long as the class is exported under its constructor name.
    • Both candidates are validated as Durable Object namespaces before use.
  • Facet-only direct parents now resolve through a root bridge:
    • the child records its root-first parentPath
    • parentAgent() opens the top-level root namespace
    • internal calls walk the recorded facet path one hop at a time using each parent facet's own ctx.facets
  • Normal HTTP .fetch() calls on a facet-parent stub are supported through the same internal bridge as RPC methods.
  • WebSocket upgrade requests through parentAgent().fetch() now fail early with a clear error because WebSocket handles cannot be serialized over RPC yet. External /sub/... routing remains the supported WebSocket path.
  • getSubAgentByName() now reuses the same internal method invocation helper, keeping stub method dispatch consistent.

Docs

  • Updated docs/sub-agents.md to explain:
    • top-level vs facet-parent parentAgent() resolution
    • custom binding-name support via Worker exports
    • normal HTTP .fetch() support
    • WebSocket upgrade limitation for parentAgent().fetch()
    • the difference between internal parentAgent(Cls) calls and external /sub/... routing
  • Updated design/sub-agent-routing.md as the living design doc.
  • Added a current-behavior note to design/rfc-sub-agent-routing.md so readers do not rely on the older RFC wording for current parentAgent() behavior.
  • Updated the multi-AI-chat example README wording from “typed RPC stub” to “typed parent stub.”

Tests

Added Workers regressions covering:

  • direct top-level parent lookup still works
  • top-level parent lookup works when the Durable Object binding name differs from the class name
  • parentAgent() throws clearly when called from a top-level, non-facet agent
  • wrong-class protection still catches direct-parent mismatches
  • doubly nested facets resolve the direct parent, not the root
  • facet-only direct parent RPC calls work
  • facet-parent normal HTTP .fetch() works
  • facet-parent .fetch() works with a real Request object
  • deeper recursive facet-parent bridge calls work
  • deeper facet-parent HTTP .fetch() works
  • facet-parent WebSocket upgrade requests throw the intended clear error

Validation

  • npm run test:workers --workspace agents -- src/tests/sub-agent.test.ts passed: 86 tests
  • npm run check passed
    • The command still reports the existing sherif warning about examples/think-slide-deck/package.json missing, but exits successfully.

Made with Cursor


Open in Devin Review

Allow parentAgent() to resolve an immediate parent even when that parent is itself a facet rather than a top-level Durable Object binding. The helper now validates the recorded direct parent, resolves top-level parents through env or worker exports, and uses a root bridge to walk the recorded facet path for facet parents.

This also documents the internal parentAgent() behavior, keeps WebSocket upgrades on externally routed sub-agent URLs for now, and adds Workers regressions for custom binding names, nested facet parents, normal HTTP fetch, Request objects, and unsupported WebSocket upgrades.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 18, 2026

🦋 Changeset detected

Latest commit: dd5a550

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 18, 2026

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1548

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1548

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1548

hono-agents

npm i https://pkg.pr.new/hono-agents@1548

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1548

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1548

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1548

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1548

commit: dd5a550

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

Add a Researcher facet under each multi-ai-chat Chat so the example exercises parentAgent(Chat) from a facet-only direct parent in a real app flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
@threepointone threepointone merged commit ce2af34 into main May 18, 2026
4 checks passed
@threepointone threepointone deleted the fix-parent-agent-facet-proxy branch May 18, 2026 11:41
@github-actions github-actions Bot mentioned this pull request May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant