Skip to content

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

Draft
MarioCadenas wants to merge 1 commit into
mainfrom
agents-discovery-dx
Draft

feat(appkit): auto-discover code agents from server/agents/#533
MarioCadenas wants to merge 1 commit 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

Copy link
Copy Markdown
Contributor

📦 Bundle size report

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

@databricks/appkit

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

dist raw gzip
JS (runtime) 879 KB (+9.9 KB) 307 KB (+3.7 KB)
Type declarations 317 KB (+2.9 KB) 110 KB (+1.0 KB)
Source maps 1.7 MB (+19 KB) 572 KB (+6.4 KB)
Other 11 KB 3.7 KB
Total 2.9 MB (+31 KB) 992 KB (+11 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 2.5 KB 91 KB external 288 KB
./beta 50 KB (+1.5 KB) 458 B 51 KB (+1.5 KB) external 147 KB (+4.1 KB)
./type-generator 21 KB 0 B 21 KB external 60 KB

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 431 B
./beta client-options.js initial 219 B
./beta supervisor-api.js lazy 194 B
./beta databricks.js lazy 142 B
./beta index.js lazy 122 B
./type-generator index.js initial 21 KB

@databricks/appkit-ui

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

dist raw gzip
JS (runtime) 390 KB 130 KB
Type declarations 228 KB 83 KB
Source maps 753 KB 248 KB
CSS 16 KB 3.3 KB
Total 1.4 MB 464 KB
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

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 31710660829 -R databricks/appkit -n appkit-template-0.60.0-pr.6f47bc8-agents-discovery-dx-533 -D appkit-pr-533 \
  && unzip -o "appkit-pr-533/appkit-template-0.60.0-pr.6f47bc8-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.

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