Skip to content

feat(appkit): auto-discover code agents from server/agents/ - #533

Draft
MarioCadenas wants to merge 2 commits into
mainfrom
agents-discovery-dx
Draft

feat(appkit): auto-discover code agents from server/agents/#533
MarioCadenas wants to merge 2 commits into
mainfrom
agents-discovery-dx

Conversation

@MarioCadenas

Copy link
Copy Markdown
Collaborator

What

Code agents are now auto-discovered from server/agents/, symmetric with markdown agents in config/agents/. A file that export default createAgent(...) is discovered at startup — its id is the filename — so the plugin call collapses to agents() with no agent map and no import.

- // server/agents/helper.ts
- export const helper = createAgent({ name: 'helper', instructions, tools });
- // server/server.ts
- import { helper } from './agents/helper';
- agents({ agents: { helper } })          // id restated; hand-built map
+ // server/agents/helper.ts   ← id IS the filename
+ export default createAgent({ instructions, tools });
+ // server/server.ts
+ agents()                                 // no import, no map

How

  • Runtime scan, resolved by NODE_ENV. Dev scans server/agents/*.ts under tsx; a bundled server scans the compiled dist/agents (or build/agents) *.js. The NODE_ENV guard keeps a stale build dir from shadowing live sources in dev.
  • Branded detection. createAgent stamps a non-enumerable Symbol.for("appkit.agent") on its result; the loader keeps branded exports and skips helpers / bundler chunks. One agent per file.
  • Prod bundling (the trap this avoids). A runtime scan of a dynamic path is dropped by the bundler. Instead, the template's tsdown config lists server/agents/*.ts as build entries, so the compiled dist/agents/*.js exist for the scan. Static bundling was the alternative considered and rejected (import.meta.glob crashes tsx in dev).

Backward compatibility

  • agents({ agents: { ... } }) still works and emits a one-time deprecation warning.
  • createAgent({ name }) is still honored.
  • Markdown discovery (config/agents/) is unchanged — it stays a runtime data scan.

Also in this PR

  • Migrates the dev-playground reference app to the new pattern (4 code agents → server/agents/*.ts; build emits build/agents/*.mjs).

Verification

  • pnpm -r typecheck clean · pnpm check (biome) 0 errors · appkit + shared 3388 tests pass · pnpm build + pnpm docs:build succeed.
  • E2E: discovery verified in both npm run dev (tsx, .ts) and a bundled node dist/agents/*.js run.
  • dev-playground tsc error count unchanged (2046 → 2046 — pre-existing client/*.tsx noise, none in the new files); its server builds and prod-discovers all four agents.

Not verified here

  • dev-playground Playwright integration tests + a live deploy (both need a Databricks workspace).

Open follow-ups

  • Changelog entry (release-it derives it from the commit).
  • Optional: unify markdown agents under server/agents/ (breaking; deferred — the config/agents/ convention was kept to avoid breaking existing apps).

Draft — opening for early review.

Drop-in code agents: a file `server/agents/<id>.ts` that
`export default createAgent(...)` is discovered at startup — the agent id
is the filename, so there is no agent map and no import at the call site
(`agents()`). Symmetric with markdown agents in `config/agents/`.

Discovery is a runtime scan resolved by NODE_ENV: dev scans
`server/agents/*.ts` under tsx; a bundled server scans the compiled
`dist/agents` (or `build/agents`) `*.js`. `createAgent` brands its result
(`Symbol.for("appkit.agent")`) so the loader picks the agent out of a
module's exports and skips helpers and bundler chunks. The template's
tsdown config lists `server/agents/*.ts` as build entries so the compiled
files exist for the production scan (a runtime scan of a dynamic path
would be dropped by the bundler — the trap this avoids).

Backward compatible: `agents({ agents: { ... } })` still works and emits a
one-time deprecation warning; `createAgent({ name })` is still honored;
markdown discovery is unchanged.

Also migrates the dev-playground reference app to the new pattern.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 851 KB (+11 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 880 KB (+11 KB) 307 KB (+4.3 KB)
Type declarations 318 KB (+3.1 KB) 110 KB (+1.2 KB)
Source maps 1.7 MB (+21 KB) 573 KB (+7.5 KB)
Other 11 KB 3.7 KB
Total 2.9 MB (+35 KB) 994 KB (+13 KB)
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 88 KB (+18 B) 2.5 KB 91 KB (+18 B) external 288 KB (+48 B)
./beta 50 KB (+1.6 KB) 456 B (-2 B) 51 KB (+1.6 KB) external 147 KB (+4.2 KB)
./type-generator 21 KB (+41 B) 0 B 21 KB (+41 B) external 61 KB (+48 B)

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 84 KB
. utils.js initial 4.0 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 34 KB
./beta stream-manager.js initial 5.8 KB
./beta wide-event-emitter.js initial 3.2 KB
./beta databricks.js initial 3.0 KB
./beta configuration.js initial 2.1 KB
./beta service-context.js initial 1.3 KB
./beta client.js initial 434 B
./beta client-options.js initial 219 B
./beta supervisor-api.js lazy 192 B
./beta databricks.js lazy 141 B
./beta index.js lazy 123 B
./type-generator index.js initial 21 KB

@databricks/appkit-ui

npm tarball (packed): 342 KB (+351 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 390 KB 130 KB
Type declarations 228 KB (+412 B) 83 KB (+360 B)
Source maps 753 KB 248 KB
CSS 16 KB 3.3 KB
Total 1.4 MB (+412 B) 465 KB (+360 B)
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
./js 5.3 KB 49 KB 55 KB 208 KB 14 KB
./js/beta 20 B 0 B 20 B 0 B 0 B
./react 432 KB 49 KB 480 KB 1.3 MB 175 KB
./react/beta 1.0 KB 0 B 1.0 KB 0 B 1.9 KB

Chunks:

Entry Chunk Load Size (gz)
./js index.js initial 5.2 KB
./js chunk initial 120 B
./js apache-arrow lazy 49 KB
./js/beta beta.js initial 20 B
./react index.js initial 430 KB
./react tslib initial 2.1 KB
./react apache-arrow lazy 49 KB
./react/beta beta.js initial 1.0 KB

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 31810597809 -R databricks/appkit -n appkit-template-0.60.0-pr.1e6b0e5-agents-discovery-dx-533 -D appkit-pr-533 \
  && unzip -o "appkit-pr-533/appkit-template-0.60.0-pr.1e6b0e5-agents-discovery-dx-533.zip" -d "appkit-pr-533" \
  && databricks apps init --template "appkit-pr-533"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

- Resolve the code-agents dir built-first and NODE_ENV-independently
  (prefer dist/agents|build/agents .js; fall back to server/agents .ts
  only when no built dir exists). Fixes a boot crash where a compiled
  server run without NODE_ENV=production imported .ts under plain Node.
- Loader gracefully skips (warns) when it cannot import a module for lack
  of a TS loader, instead of crashing setup.
- Drop the phantom `appkit generate-agents` command from the deprecation
  JSDoc and the scaffold template — discovery is a runtime scan.
- Discovered id colliding with the deprecated agents({ agents }) map now
  warns and lets discovery win, rather than throwing at boot on upgrade.
- Document that createAgent brands (mutates) its input; de-noise the
  prod zero-agents warning when the deprecated map is in use; template
  tsdown clean:true so a deleted agent can't linger in dist/agents.
- Extract resolveCodeAgentsDir as a pure function and unit-test the
  built-first ordering, override, and fallback; add map-only and
  defaultAgent-not-registered regression tests.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
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