Skip to content

feat(appkit): add model_service resource and use it in the agents plugin - #705

Open
MarioCadenas wants to merge 11 commits into
mainfrom
work/34-add-model-service-resource-rep
Open

MarioCadenas wants to merge 11 commits into
mainfrom
work/34-add-model-service-resource-rep

Conversation

@MarioCadenas

@MarioCadenas MarioCadenas commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

What

Adds the new Databricks Apps model_service resource (a Unity Catalog securable of type MODEL_SERVICE, from databricks-eng/universe#2571640) and makes it the agents plugin's default-model resource.

Changes

  • Resource type: model_service in resourceTypeSchema, permission EXECUTE. In databricks.yml it binds as uc_securable with securable_type: MODEL_SERVICE, mapping name to securable_full_name. Generated types, JSON schemas, plugin create defaults and docs updated.
  • Agents plugin: the optional default-LLM resource is now model_service (agents-model-service, env DATABRICKS_MODEL_SERVICE_NAME, value catalog.schema.name). The agents plugin and standalone runAgent read that env first and still fall back to DATABRICKS_SERVING_ENDPOINT_NAME, so existing apps keep working.
  • Routing: adapterFromModelString sends any dotted name to the AI Gateway (fromAiGateway), not only system.*. Model services are catalog.schema.name, and serving endpoint names cannot contain dots, so no existing endpoint changes route. To force a dotted name onto a serving endpoint, pass a pre-built adapter.
  • appkit plugin add picker: opens on the system.ai model services, with "Browse other catalogs..." for a catalog, schema, model service drill-down. Uses databricks ai-gateway list-model-services, so it needs a CLI that has that command; otherwise it falls back to manual entry. --set / --from-plan accept any catalog.schema.name.
  • appkit doctor: existence check for model_service (GET /api/2.1/unity-catalog/model-services/{name}).

Not changed

  • The serving plugin stays on serving_endpoint. It is deprecated, and it calls /serving-endpoints/{name}/invocations, which a model service is not.
  • No SCOPE_BY_TYPE entry for model_service, so the agents resource no longer carries a user API scope. Agents that run on behalf of the user may need ai-gateway; not added until confirmed.

Why the picker is a drill-down

A flat walk over every catalog and schema did not finish in 10 minutes on dogfood (1158 catalogs), and finding system by paging is slow, so the picker opens on system.ai and leaves the rest one pick away.

Testing

  • Unit tests: schema and binding, picker steps (open on system.ai, browse, --set), doctor check, routing, agents env default.
  • pnpm check, pnpm -r typecheck, pnpm test, docs build: green.
  • Live on dogfood: doctor passes for system.ai.gpt-5-mini and reports NOT_FOUND for a made-up name; the system.ai listing returns 70 services; runAgent with DATABRICKS_MODEL_SERVICE_NAME=system.ai.gpt-5-mini answered through the AI Gateway.

Task: KIT-34 (app-kit/34)

This pull request and its description were written by Isaac.

MarioCadenas and others added 5 commits November 4, 2026 11:19
…fault model

Add the MODEL_SERVICE UC securable as a model_service resource type (EXECUTE,
bound as uc_securable), a picker lister that walks catalogs and schemas, and
switch the agents plugin's default-model resource to it. Dotted model names
now route to the AI Gateway; DATABRICKS_SERVING_ENDPOINT_NAME stays a fallback.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
A full catalogs x schemas walk did not finish in 10 minutes on a large
workspace and one rejected schema name aborted it. List model services like
volumes instead: catalog, then schema, then ai-gateway list-model-services.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Finding system among thousands of catalogs is slow, so list system.ai model
services first, with a "Browse other catalogs..." entry for the full
catalog/schema drill-down. --set still accepts any catalog.schema.name.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas MarioCadenas changed the title Add model_service resource; replace serving_endpoint feat(appkit): add model_service resource and use it in the agents plugin Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

📦 Bundle size report

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

@databricks/appkit

npm tarball (packed): 1.2 MB (+246 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 1.3 MB (+520 B) 462 KB (+112 B)
Type declarations 468 KB (+3.3 KB) 169 KB (+69 B)
Source maps 2.5 MB (+995 B) 863 KB (+80 B)
Other 11 KB 3.7 KB
Total 4.3 MB (+4.8 KB) 1.5 MB (+261 B)
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 107 KB (+74 B) 2.5 KB 110 KB (+74 B) external 347 KB (+234 B)
./beta 103 KB (+87 B) 484 B 104 KB (+87 B) external 311 KB (+341 B)
./testing 46 KB (+35 B) 33 KB 79 KB (+35 B) external 229 KB (+232 B)
./tsdown 520 B 0 B 520 B external 813 B
./type-generator 26 KB 0 B 26 KB external 74 KB

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 103 KB
. utils.js initial 4.6 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 83 KB
./beta modular.js initial 6.0 KB
./beta stream-manager.js initial 5.9 KB
./beta service-context.js initial 4.3 KB
./beta databricks.js initial 3.3 KB
./beta client.js initial 646 B
./beta index.js initial 20 B
./beta supervisor-api.js lazy 192 B
./beta databricks.js lazy 177 B
./beta index.js lazy 115 B
./testing manifest.js initial 33 KB
./testing index.js initial 10 KB
./testing wide-event-emitter.js initial 2.9 KB
./testing index.js lazy 29 KB
./testing remote-tunnel-manager.js lazy 2.5 KB
./testing utils.js lazy 1.8 KB
./tsdown index.js initial 520 B
./type-generator index.js initial 26 KB

@databricks/appkit-ui

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

dist raw gzip
JS (runtime) 429 KB 147 KB
Type declarations 267 KB 98 KB
Source maps 848 KB 285 KB
CSS 16 KB 3.2 KB
Total 1.5 MB 533 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 2.1 KB 0 B 2.1 KB 0 B 5.0 KB
./react 434 KB 49 KB 483 KB 1.3 MB 177 KB
./react/beta 4.9 KB 0 B 4.9 KB 0 B 12 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 2.1 KB
./react index.js initial 432 KB
./react tslib initial 2.1 KB
./react apache-arrow lazy 49 KB
./react/beta beta.js initial 4.9 KB

@github-actions

github-actions Bot commented Nov 4, 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 42808264577 -R databricks/appkit -n appkit-template-0.91.2-pr.3a37fb1-work-34-add-model-service-resource-rep-705 -D appkit-pr-705 \
  && unzip -o "appkit-pr-705/appkit-template-0.91.2-pr.3a37fb1-work-34-add-model-service-resource-rep-705.zip" -d "appkit-pr-705" \
  && databricks apps init --template "appkit-pr-705"

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.

Merge the two return branches in listParentContextStep and trim the comments
added for model_service to one line each. The model service picker opens on
system.ai because finding the system catalog among thousands is slow.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas
MarioCadenas marked this pull request as ready for review November 4, 2026 14:52
@MarioCadenas
MarioCadenas requested a review from a team as a code owner November 4, 2026 14:52
@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 6 · Fail · 1 critical, 1 minor

Does the change do what the task asked? No. Gate: major and worse must be fixed.

The model_service resource type, its uc_securable MODEL_SERVICE/EXECUTE binding, the picker, the doctor check and the agents plugin switch are built, and the 262 related tests pass. The serving plugin is still on serving_endpoint, but the task says plainly to replace it in both plugins. The closing note cites a human decision to keep it, but there is no human message in the task log that confirms this.

Required

  • critical: The serving plugin still declares serving_endpoint, not model_service, but the task says to replace it in both the serving and agents plugins. (packages/appkit/src/plugins/serving/manifest.json:11)
    Proof: The manifest has "type": "serving_endpoint" at line 11; the diff since 05c51e2 has no file under plugins/serving; said-by.jsonl has no human message saying serving stays as is (only the agent's closing-note says so). If that human decision is real, downgrade this.

Not required (below the gate)

  • minor: Model services are listed by drilling down through the CLI rather than through a paginated ListModelServices in the workspace client, which is what item 2 asked for. (packages/shared/src/cli/commands/registry/workspace-picker.ts)
    Proof: The diff stat shows no file under packages/shared/src/workspace-client.

@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 7 · Pass · 1 minor, 1 trivial

Does the change do what the task asked? Yes. Gate: major and worse must be fixed.

model_service is added to the schema, DABs binding (uc_securable, MODEL_SERVICE, EXECUTE), doctor, the CLI picker (catalog > schema > ai-gateway list-model-services, prefix stripped) and the agents manifest and runtime env fallback, with tests that pass. The serving plugin staying on serving_endpoint and the CLI-based lister are human-settled decisions, so I don't count them as gaps.

Not required (below the gate)

  • minor: Default-model routing widened from the system.* prefix to any dotted string, so any dotted value in DATABRICKS_SERVING_ENDPOINT_NAME or model now goes to AI Gateway instead of Model Serving. (packages/appkit/src/agents/databricks.ts adapterFromModelString)
    Proof: Diff: model.startsWith("system.") became model.includes("."); serving endpoint names cannot contain dots, so the impact is limited to invalid inputs.
  • trivial: run-agent's no-model fallback still surfaces the DATABRICKS_SERVING_ENDPOINT_NAME error text, while the agents plugin now names DATABRICKS_MODEL_SERVICE_NAME. (packages/appkit/src/core/agent/run-agent.ts resolveAdapter)
    Proof: Read the diff: the comment and fromModelServing error path are unchanged.

@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 8 · Pass · 1 minor, 1 trivial

Does the change do what the task asked? Yes. Gate: major and worse must be fixed.

The model_service resource type, its uc_securable MODEL_SERVICE/EXECUTE binding, the paginated picker lister with prefix stripping, and the agents plugin and runAgent wiring are all in place and tested. The serving plugin stays on serving_endpoint, which the human settled. The one real gap: the agents resource no longer carries a user_api_scope, because model_service has no SCOPE_BY_TYPE entry.

Not required (below the gate)

  • minor: model_service has no SCOPE_BY_TYPE entry, so the template's agents resource lost its "scope": "model-serving" and OBO agents get no user_api_scope for the default model. (packages/shared/src/schemas/manifest.ts:57 and template/appkit.plugins.json (agents optional resource))
    Proof: git diff 34b41cc...HEAD -- template/appkit.plugins.json shows the removed "scope": "model-serving" line; SCOPE_BY_TYPE has no model_service key. The agent flagged it as unconfirmed.
  • trivial: Routing changed from startsWith("system.") to includes("."), so any dotted model string now goes to AI Gateway. Safe because serving-endpoint names cannot contain dots, but it is a behavior change. (packages/appkit/src/agents/databricks.ts:1015)
    Proof: Read in the diff.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 9 · Fail · 1 critical, 1 minor

Does the change do what the task asked? No. Gate: major and worse must be fixed.

The schema, DABs binding, CLI picker drill-down and agents plugin wiring for model_service are in place and their tests pass. But the serving plugin still declares serving_endpoint, which the task plainly asked to replace, and the lister was built as a CLI drill-down instead of the requested workspace-client SDK lister.

Required

  • critical: The serving plugin manifest still declares a serving_endpoint resource (CAN_QUERY); the task said to replace it with model_service in the serving and agents plugins. (packages/appkit/src/plugins/serving/manifest.json:11, template/appkit.plugins.json:486)
    Proof: git diff 34b41cc...HEAD -- packages/appkit/src/plugins/serving is empty; rg shows "type": "serving_endpoint" at serving/manifest.json:11 and template/appkit.plugins.json:486

Not required (below the gate)

  • minor: No workspace-client ListModelServices or SDK_LISTERS entry was added; model services are listed through a CLI PARENT_CONTEXT_CHAINS drill-down (databricks ai-gateway list-model-services), so the picker depends on the CLI having that command. (packages/shared/src/cli/commands/registry/workspace-picker.ts:363; packages/shared/src/workspace-client (unchanged))
    Proof: git diff 34b41cc...HEAD -- packages/shared/src/workspace-client is empty

@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 10 · Fail · 1 major, 3 minor

Does the change do what the task asked? No. Gate: major and worse must be fixed.

The model_service resource, its uc_securable/MODEL_SERVICE/EXECUTE binding, the picker lister, the doctor check and the agents plugin wiring are all built, and the targeted tests and typecheck pass. The serving plugin still uses serving_endpoint. The task said to replace it there too; the PR explains why it did not (the serving plugin calls /serving-endpoints/{name}/invocations), but a human has to accept that change of scope. The 3 red CI checks fail on template npm installs blocked by jfrog's 7-day age rule, and the branch does not cause them.

Required

  • major: The serving plugin manifest still declares serving_endpoint; the task said to replace it with model_service in both the serving and agents plugins. (packages/appkit/src/plugins/serving/manifest.json:11)
    Proof: rg shows "type": "serving_endpoint" in the serving manifest and in template/appkit.plugins.json:486. The PR body says this was left out on purpose because serving calls the invocations URL, which a model service does not have.

Not required (below the gate)

  • minor: The lister is a CLI drill-down in PARENT_CONTEXT_CHAINS (databricks ai-gateway list-model-services). The task asked for a workspace-client method plus an SDK_LISTERS entry, and the branch adds nothing under packages/shared/src/workspace-client. (packages/shared/src/cli/commands/registry/workspace-picker.ts:363)
    Proof: git diff --stat 34b41cc...HEAD has no workspace-client files.
  • minor: PR feat(appkit): add model_service resource and use it in the agents plugin #705 is not a draft; the task asked for a draft PR. (PR #705)
    Proof: gh pr view 705 --json isDraft returned false.
  • minor: adapterFromModelString now sends any dotted name to the AI Gateway, not only system.* names. That is broader than the task asked for; the PR documents it and gives a workaround. (packages/appkit/src/agents/databricks.ts:1015)
    Proof: Seen in the diff: startsWith("system.") became includes(".").

The v0.91.2 template sync locked OpenTelemetry 2.12.1/0.223.1,
semantic-conventions 1.45.0 and import-in-the-middle 3.6.0, which the
registry blocks for 7 days after release, so template installs failed with
403. Regenerated both locks through the curated registry (identical
integrity hashes), with resolved URLs on registry.npmjs.org.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 11 · Pass · 1 pre-existing

Does the change do what the task asked? Yes. Gate: major and worse must be fixed.

The model_service resource, its uc_securable/MODEL_SERVICE/EXECUTE binding, the lister, and the agents plugin wiring are in place, and their tests pass. The serving plugin stays on serving_endpoint, which the human decided. This round only changes the lockfiles: every resolved URL is on registry.npmjs.org and none points at the internal mirror. CI on this commit was still running when I reviewed it.

Not required (there before this change)

  • minor: The lockfile fix depends on the release bot's next template sync not re-pinning versions that are under the registry's 7-day block, so the template CI failure can come back. (template/package-lock.json, template/pnpm-lock.yaml)
    Proof: The agent says so itself, and the commit message confirms the bot owns these files.

CI's registry blocks versions for 7 days and also rejected the @babel,
@swc/helpers and electron-to-chromium releases from 2-4 November. Re-resolve
both template locks with a 2026-11-02 cutoff (@databricks/* exempt, CI packs
those locally).

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas

Copy link
Copy Markdown
Collaborator Author

Review 12 · Pass · 1 minor

Does the change do what the task asked? Yes. Gate: major and worse must be fixed.

The model_service feature is in place: schema, binding, lister/picker, doctor check, and agents wiring, with tests passing. The human decided the serving plugin stays on serving_endpoint. This round only re-resolves the template lockfiles; the sampled versions predate the 8-day cutoff and template/package.json is unchanged, but CI on this commit was still pending when I checked.

Not required (below the gate)

  • minor: The lockfile fix holds only until the release bot's next template sync pins versions newer than the registry's cooldown, so the template CI failure can come back. (template/package-lock.json, template/pnpm-lock.yaml)
    Proof: Lockfiles were hand-resolved with a date cutoff and @swc/helpers was pinned by hand to 0.5.23; nothing in the sync process keeps that in place.

This branch has not been deployed

No deployments
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