Skip to content

feat(test): export loadRouteModule(id) from agent-bundle/test (#493) - #499

Merged
ScriptedAlchemy merged 2 commits into
mainfrom
fix/493-load-route-module
Sep 4, 2026
Merged

feat(test): export loadRouteModule(id) from agent-bundle/test (#493)#499
ScriptedAlchemy merged 2 commits into
mainfrom
fix/493-load-route-module

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Fixes #493.

What

agent-bundle/test now exports loadRouteModule(id, { manifest? }) (packages/agent-bundle/src/test/render.ts): the evaluated module behind one compiled route id, resolved through the same registered loader renderRoute uses (registeredRouteLoader — previously internal). The manifest-route resolution renderRoute already did was factored into a shared loadManifestRouteModule, so both entry points report the same route-not-found, unsupported-route-kind (App routes), and manifest-unavailable (no registry / foreign manifest with the digest mismatch report) diagnostics.

The return is the module namespace object itself — LoadedRouteModule<Id>: inputSchema / resultSchema by reference (typed as RouteModuleSchema<RegisteredRouteInput<Id>> / RouteModuleSchema<RegisteredRouteResult<Id>> once .agent-bundle/routes.d.ts is in the program), config, default (optional: a plain .ts script exports main), plus an index signature for any other named export. The id parameter uses the same RouteTargetConstraint shape as renderRoute (#456), so a literal id that is not registered is a compile error naming the registered ids.

Consumer code this replaces

movie-library tests/support/route-modules.ts (120 lines: 47 static import * as mN from '../../src/mcp/<server>/tools/<tool>.tsx' plus a Map, "Regenerate the list when a placement changes") consumed by tests/surface/routes.test.ts for expect(module.inputSchema).toBe(operation.inputSchema) / resultSchema instanceof z.ZodObject / typeof module.default === 'function' / config equality. With this PR that suite is for (const route of Object.values(testManifest().routes)) { const module = await loadRouteModule(route.id); … } inside the agentBundleRstest() pool.

Tests

  • packages/agent-bundle/tests/route-unit/load-route-module.test.ts (new): tool module identity (inputSchema/resultSchema/default are the very instances the statically imported module holds; config equals the manifest's extracted config); sweep of every non-App, non-script route id plus cli:report, rendered script:summary, and plain script:checksum (main, no default); one instance per route and the rendered document value parses through the loaded resultSchema; unknown id → route-not-found listing compiled ids; App route → unsupported-route-kind; foreign manifest → manifest-unavailable with the registered-digest mismatch report.
  • packages/agent-bundle/tests/route-register-typegen.test.ts: assertions.ts now also loads a module by literal id and reads inputSchema.parse(...).query: string / resultSchema.parse(...).hits: number without casts, plus a string-typed id degrading to unknown; new wrong-load-id.ts asserts the rejection names the registered ids.

Ran: pnpm lint, pnpm typecheck, pnpm test:unit (3104), pnpm test:route-unit (52), pnpm test:projection (146), integration-pool route-register-typegen + public-api (8), pnpm docs:site:build (parity OK).

Docs

  • website/docs/{en,zh}/guide/development/testing.mdx: new loadRouteModule paragraph + example beside testManifest().
  • packages/agent-bundle/README.md testing section; agent-bundle/test module header table.
  • API reference regenerates from the new exports via TypeDoc.

Changeset

.changeset/493-load-route-module.mdpatch for agent-bundle.

Review status

Codex reviewed 718786b1d and opened two threads; both are addressed in the follow-up commit (no PR comments are posted from this side by instruction — answers live here):

  • render.ts:569 — "Accept literal script IDs in the loader type." Correct: executableRoutes in routes/typegen.ts excludes graph.scripts, so script: ids never enter RegisteredRouteId. Fixed with a dedicated LoadRouteModuleConstraint<Target> = string extends Target ? string : RegisteredRouteId | \script:${string}`: registered kinds stay literal-checked, script:literals are admitted (unchecked, since they are not registered), dynamicstringstays legal. Spelled inline so the rejection still lists the registered ids. Adding scripts to the typegen registration itself would also changerenderRoute's typing and touches the typegen other in-flight PRs are working in, so it is left as a separate follow-up. Typegen test now asserts loadRouteModule('script:anything')compiles against a registered project and that the wrong-id rejection lists"event:tool/after" | "tool:curator/find" | "tool:curator/status" | `script:${string}``; docs say so.
  • testing.mdx:103 — "Filter schema-less routes from the documentation example." Correct; the loop now iterates tool/prompt/resource routes only (with a comment that event routes and scripts export no schemas) and also asserts resultSchema. Same in zh.

Latest head reviewed by Codex: 718786b1d. Rebased onto main (bf1d1eef4) over the #456 follow-up that extended the same typegen test. Rebased again onto main (60f75c1e7) cleanly. Unreviewed head at merge time (if no fresh review arrives): 15fe1accd.

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 15fe1ac

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

This PR includes changesets to release 1 package
Name Type
agent-bundle 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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T01:22:15.828806Z 718786b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@499
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@499
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@499

commit: 15fe1ac

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 718786b1d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

* are not loadable here (`unsupported-route-kind`).
*/
export const loadRouteModule = async <Target extends string>(
routeId: (Target & RouteTargetConstraint<Target>) | RouteTargetConstraint<Target>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept literal script IDs in the loader type

When a consumer has generated route registration plus a conventional src/scripts/foo.ts[x], this constraint rejects loadRouteModule('script:foo') at compile time: executableRoutes in packages/agent-bundle/src/routes/typegen.ts:10-16 excludes graph.scripts, so script IDs never enter RegisteredRouteId. This contradicts the new API's runtime behavior and documentation that scripts are loadable; include script IDs in the registration or use a constraint that admits compiled script literals.

AGENTS.md reference: AGENTS.md:L78-L81

Useful? React with 👍 / 👎.

Comment on lines +100 to +103
for (const route of Object.values(testManifest().routes)) {
if (route.kind === 'app') continue; // browser builds load at the browser level
const module = await loadRouteModule(route.id);
expect(module.inputSchema).toBeInstanceOf(z.ZodObject);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter schema-less routes from the documentation example

When the manifest contains an event route or a script without inputSchema, this advertised all-routes loop fails because it excludes only Apps and then requires every remaining module to expose a Zod input schema. Those schemas are optional by contract, and the added test explicitly verifies that script:summary has no inputSchema; filter to schema-backed routes or condition the assertion on the export being present.

AGENTS.md reference: AGENTS.md:L78-L81

Useful? React with 👍 / 👎.

@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/493-load-route-module branch from 59f991c to 492b9f6 Compare September 4, 2026 02:50
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/493-load-route-module branch from 492b9f6 to 15fe1ac Compare September 4, 2026 03:35
@ScriptedAlchemy
ScriptedAlchemy merged commit 5c00b3e into main Sep 4, 2026
13 checks passed
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.

agent-bundle/test: export loadRouteModule(id) so consumers stop static-importing every route module for schema-identity suites (xref rows 3 & 11)

1 participant