fix: allow user-defined interfaces as agent Props#1906
Closed
mattzcarey wants to merge 2 commits into
Closed
Conversation
Interfaces do not get implicit index signatures in TypeScript, so the Record<string, unknown> bound on Props rejected them with 'Index signature for type string is missing'. Introduce a single shared AgentProps bound (Record<string, any> — the one record shape every interface satisfies) in types.ts and use it for every props surface: the Agent, McpAgent, getAgentByName, and AgentGetOptions generics, the addMcpServer RPC overload constraint and its props option, and RPCClientTransportOptions. Generic defaults stay Record<string, unknown> so untyped usage still reads props values as unknown. Fixes #1886
🦋 Changeset detectedLatest commit: 836acfb The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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 |
agents
@cloudflare/ai-chat
@cloudflare/codemode
create-think
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
…-records Per review: no any. Props bounds become 'extends object' (interfaces satisfy object natively) on Agent, McpAgent, getAgentByName, and AgentGetOptions; Agent bridges partyserver's stricter Record<string, unknown> bound with an intersection that is erased at runtime, plus one commented value-cast at the getServerByName seam. The addMcpServer RPC overload now derives its props type from the target McpAgent via McpAgentProps<T> (NonNullable<T['props']>), so RPC props are type-checked against the agent being connected to instead of accepting any record.
Contributor
Author
|
Closing in favor of fixing the Props bound upstream in partyserver (cloudflare/partykit), where |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
Propsgeneric onAgent(and every API that carries props) was bounded byRecord<string, unknown>. Interfaces do not get implicit index signatures in TypeScript, so a well-typed interface fails that bound and users hit:exactly as reported on a
getAgentByName(ns, name, { props: config })call.Fix —
objectbounds + derived props generics (noany)Props extends object = Record<string, unknown>onAgent,McpAgent,getAgentByName, andAgentGetOptions. Interfaces satisfyobjectnatively; defaults stayRecord<string, unknown>so untyped usage still reads props values asunknown.PropsatRecord<string, unknown>(Server,getServerByName), which we can't change from this repo.Agentbridges it withextends Server<Env, Props & Record<string, unknown>>— the intersection is erased at runtime (props is a JSON bag) — andgetAgentByNamewidens the props value with one commented cast when handing off togetServerByName.addMcpServerRPC props are now derived, not loosened: the overload takesAddRpcMcpServerOptions<McpAgentProps<T>>whereMcpAgentProps<T> = NonNullable<T["props"]>reads the Props type off the targetMcpAgent. Props passed over RPC are type-checked against the agent actually being connected to — a wrong-shape props object is now a compile error (previously any record was accepted). The old bare-McpAgentconstraint also rejected typed subclasses through Durable Object stub variance; the constraint is nowT extends McpAgent<Cloudflare.Env, unknown, object>.Repro / regression tests
New compile-time test
src/tests-d/agent-props.test-d.ts, following the existingtests-d/pattern (runs under the package typecheck, which CI enforces). Written first and confirmed red on main with 6 errors matching the issue:getAgentByNamewith inferred and explicit interfacePropsAgent/McpAgentclass declarations with interfaceProps, andthis.propskeeping the interface typeaddMcpServer(name, namespace, { props })with an interface-PropsMcpAgentnamespace, plusMcpAgentProps<T>extractionProps, and wrong-shape RPC props are rejected against the target agent's declared PropsVerification
npm run checkclean (sherif, exports, oxfmt, oxlint, all 116 typecheck projects)packages/agentsruntime suite passing (types-only change)Out of scope / follow-up
routeAgentRequest'sAgentOptionspins props at the partyserver default and would need an upstream partyserver bound change (objectinstead ofRecord<string, unknown>onServer/getServerByName/routePartykitRequest) — that would also remove the intersection bridge and cast here.Fixes #1886