@databricks/appkit 0.35.2 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +1 -0
- package/dist/appkit/package.js +1 -1
- package/dist/core/appkit.d.ts.map +1 -1
- package/dist/core/appkit.js +8 -35
- package/dist/core/appkit.js.map +1 -1
- package/dist/plugin/plugin.d.ts +12 -4
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js +57 -24
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/plugins/agents/agents.d.ts +56 -3
- package/dist/plugins/agents/agents.d.ts.map +1 -1
- package/dist/plugins/agents/agents.js +160 -8
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/agents/schemas.js +0 -1
- package/dist/plugins/agents/schemas.js.map +1 -1
- package/dist/plugins/server/react-source-loc-vite-plugin.js +68 -0
- package/dist/plugins/server/react-source-loc-vite-plugin.js.map +1 -0
- package/dist/plugins/server/vite-dev-server.js +3 -0
- package/dist/plugins/server/vite-dev-server.js.map +1 -1
- package/docs/api/appkit/Variable.agents.md +1 -1
- package/docs/api/appkit.md +6 -6
- package/docs/plugins/agents.md +8 -4
- package/package.json +6 -5
- package/sbom.cdx.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { Lang, parse } from "@ast-grep/napi";
|
|
3
|
+
import MagicString from "magic-string";
|
|
4
|
+
|
|
5
|
+
//#region src/plugins/server/react-source-loc-vite-plugin.ts
|
|
6
|
+
const JSX_ELEMENT_MATCHER = { rule: { any: [{ kind: "jsx_opening_element" }, { kind: "jsx_self_closing_element" }] } };
|
|
7
|
+
function cleanModuleId(id) {
|
|
8
|
+
return id.split("?")[0].split("#")[0];
|
|
9
|
+
}
|
|
10
|
+
function shouldTransform(id) {
|
|
11
|
+
if (id.includes("\0")) return false;
|
|
12
|
+
if (id.includes("node_modules")) return false;
|
|
13
|
+
return /\.[jt]sx$/.test(cleanModuleId(id));
|
|
14
|
+
}
|
|
15
|
+
function isNativeJsxTag(name) {
|
|
16
|
+
const kind = name.kind();
|
|
17
|
+
if (kind === "member_expression") return false;
|
|
18
|
+
if (kind === "jsx_namespace_name") return false;
|
|
19
|
+
if (kind === "identifier") {
|
|
20
|
+
const tagName = name.text();
|
|
21
|
+
if (!tagName) return false;
|
|
22
|
+
return /^[a-z]/.test(tagName);
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
function hasDataSourceAttribute(node) {
|
|
27
|
+
for (const attr of node.fieldChildren("attribute")) {
|
|
28
|
+
if (!attr.is("jsx_attribute")) continue;
|
|
29
|
+
for (const child of attr.children()) if (child.is("property_identifier") && child.text() === "data-source") return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Injects `data-source="<file>:<line>:<col>"` on native JSX elements so editors
|
|
35
|
+
* can map DOM nodes back to source locations.
|
|
36
|
+
*/
|
|
37
|
+
function reactSourceLocPlugin(options) {
|
|
38
|
+
const projectRoot = path.resolve(options.projectRoot);
|
|
39
|
+
return {
|
|
40
|
+
name: "react-source-loc",
|
|
41
|
+
enforce: "pre",
|
|
42
|
+
apply: "serve",
|
|
43
|
+
transform(code, id) {
|
|
44
|
+
if (!shouldTransform(id)) return;
|
|
45
|
+
const cleanId = cleanModuleId(id);
|
|
46
|
+
const root = parse(Lang.Tsx, code).root();
|
|
47
|
+
const s = new MagicString(code);
|
|
48
|
+
const relPath = path.relative(projectRoot, cleanId);
|
|
49
|
+
for (const node of root.findAll(JSX_ELEMENT_MATCHER)) {
|
|
50
|
+
const name = node.field("name");
|
|
51
|
+
if (!name || !isNativeJsxTag(name)) continue;
|
|
52
|
+
if (hasDataSourceAttribute(node)) continue;
|
|
53
|
+
const nodeRange = node.range();
|
|
54
|
+
const value = `${relPath}:${nodeRange.start.line + 1}:${nodeRange.start.column}`;
|
|
55
|
+
s.appendLeft(name.range().end.index, ` data-source="${value}"`);
|
|
56
|
+
}
|
|
57
|
+
if (!s.hasChanged()) return;
|
|
58
|
+
return {
|
|
59
|
+
code: s.toString(),
|
|
60
|
+
map: s.generateMap({ hires: true })
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { reactSourceLocPlugin };
|
|
68
|
+
//# sourceMappingURL=react-source-loc-vite-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-source-loc-vite-plugin.js","names":[],"sources":["../../../src/plugins/server/react-source-loc-vite-plugin.ts"],"sourcesContent":["import path from \"node:path\";\nimport { Lang, parse, type SgNode } from \"@ast-grep/napi\";\nimport MagicString from \"magic-string\";\nimport type { Plugin } from \"vite\";\n\nconst JSX_ELEMENT_MATCHER = {\n rule: {\n any: [\n { kind: \"jsx_opening_element\" },\n { kind: \"jsx_self_closing_element\" },\n ],\n },\n};\n\ninterface ReactSourceLocPluginOptions {\n /** Absolute app root used for data-source relative paths (typically `process.cwd()`). */\n projectRoot: string;\n}\n\nfunction cleanModuleId(id: string): string {\n return id.split(\"?\")[0].split(\"#\")[0];\n}\n\nfunction shouldTransform(id: string): boolean {\n if (id.includes(\"\\0\")) return false;\n if (id.includes(\"node_modules\")) return false;\n return /\\.[jt]sx$/.test(cleanModuleId(id));\n}\n\nfunction isNativeJsxTag(name: SgNode): boolean {\n const kind = name.kind();\n if (kind === \"member_expression\") return false;\n if (kind === \"jsx_namespace_name\") return false;\n if (kind === \"identifier\") {\n const tagName = name.text();\n if (!tagName) return false;\n return /^[a-z]/.test(tagName);\n }\n return false;\n}\n\nfunction hasDataSourceAttribute(node: SgNode): boolean {\n for (const attr of node.fieldChildren(\"attribute\")) {\n if (!attr.is(\"jsx_attribute\")) continue;\n for (const child of attr.children()) {\n if (child.is(\"property_identifier\") && child.text() === \"data-source\") {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Injects `data-source=\"<file>:<line>:<col>\"` on native JSX elements so editors\n * can map DOM nodes back to source locations.\n */\nexport function reactSourceLocPlugin(\n options: ReactSourceLocPluginOptions,\n): Plugin {\n const projectRoot = path.resolve(options.projectRoot);\n\n return {\n name: \"react-source-loc\",\n enforce: \"pre\",\n apply: \"serve\",\n\n transform(code, id) {\n if (!shouldTransform(id)) return;\n\n const cleanId = cleanModuleId(id);\n const root = parse(Lang.Tsx, code).root();\n const s = new MagicString(code);\n const relPath = path.relative(projectRoot, cleanId);\n\n for (const node of root.findAll(JSX_ELEMENT_MATCHER)) {\n const name = node.field(\"name\");\n if (!name || !isNativeJsxTag(name)) continue;\n if (hasDataSourceAttribute(node)) continue;\n\n const nodeRange = node.range();\n const value = `${relPath}:${nodeRange.start.line + 1}:${nodeRange.start.column}`;\n s.appendLeft(name.range().end.index, ` data-source=\"${value}\"`);\n }\n\n if (!s.hasChanged()) return;\n\n return {\n code: s.toString(),\n map: s.generateMap({ hires: true }),\n };\n },\n };\n}\n"],"mappings":";;;;;AAKA,MAAM,sBAAsB,EAC1B,MAAM,EACJ,KAAK,CACH,EAAE,MAAM,uBAAuB,EAC/B,EAAE,MAAM,4BAA4B,CACrC,EACF,EACF;AAOD,SAAS,cAAc,IAAoB;AACzC,QAAO,GAAG,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;;AAGrC,SAAS,gBAAgB,IAAqB;AAC5C,KAAI,GAAG,SAAS,KAAK,CAAE,QAAO;AAC9B,KAAI,GAAG,SAAS,eAAe,CAAE,QAAO;AACxC,QAAO,YAAY,KAAK,cAAc,GAAG,CAAC;;AAG5C,SAAS,eAAe,MAAuB;CAC7C,MAAM,OAAO,KAAK,MAAM;AACxB,KAAI,SAAS,oBAAqB,QAAO;AACzC,KAAI,SAAS,qBAAsB,QAAO;AAC1C,KAAI,SAAS,cAAc;EACzB,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,SAAS,KAAK,QAAQ;;AAE/B,QAAO;;AAGT,SAAS,uBAAuB,MAAuB;AACrD,MAAK,MAAM,QAAQ,KAAK,cAAc,YAAY,EAAE;AAClD,MAAI,CAAC,KAAK,GAAG,gBAAgB,CAAE;AAC/B,OAAK,MAAM,SAAS,KAAK,UAAU,CACjC,KAAI,MAAM,GAAG,sBAAsB,IAAI,MAAM,MAAM,KAAK,cACtD,QAAO;;AAIb,QAAO;;;;;;AAOT,SAAgB,qBACd,SACQ;CACR,MAAM,cAAc,KAAK,QAAQ,QAAQ,YAAY;AAErD,QAAO;EACL,MAAM;EACN,SAAS;EACT,OAAO;EAEP,UAAU,MAAM,IAAI;AAClB,OAAI,CAAC,gBAAgB,GAAG,CAAE;GAE1B,MAAM,UAAU,cAAc,GAAG;GACjC,MAAM,OAAO,MAAM,KAAK,KAAK,KAAK,CAAC,MAAM;GACzC,MAAM,IAAI,IAAI,YAAY,KAAK;GAC/B,MAAM,UAAU,KAAK,SAAS,aAAa,QAAQ;AAEnD,QAAK,MAAM,QAAQ,KAAK,QAAQ,oBAAoB,EAAE;IACpD,MAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,QAAI,CAAC,QAAQ,CAAC,eAAe,KAAK,CAAE;AACpC,QAAI,uBAAuB,KAAK,CAAE;IAElC,MAAM,YAAY,KAAK,OAAO;IAC9B,MAAM,QAAQ,GAAG,QAAQ,GAAG,UAAU,MAAM,OAAO,EAAE,GAAG,UAAU,MAAM;AACxE,MAAE,WAAW,KAAK,OAAO,CAAC,IAAI,OAAO,iBAAiB,MAAM,GAAG;;AAGjE,OAAI,CAAC,EAAE,YAAY,CAAE;AAErB,UAAO;IACL,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,YAAY,EAAE,OAAO,MAAM,CAAC;IACpC;;EAEJ"}
|
|
@@ -5,6 +5,7 @@ import { mergeConfigDedup } from "../../utils/vite-config-merge.js";
|
|
|
5
5
|
import { BaseServer } from "./base-server.js";
|
|
6
6
|
import { appKitServingTypesPlugin } from "../../type-generator/serving/vite-plugin.js";
|
|
7
7
|
import { appKitTypesPlugin } from "../../type-generator/vite-plugin.js";
|
|
8
|
+
import { reactSourceLocPlugin } from "./react-source-loc-vite-plugin.js";
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import fs from "node:fs";
|
|
10
11
|
|
|
@@ -40,6 +41,7 @@ var ViteDevServer = class extends BaseServer {
|
|
|
40
41
|
const { createServer: createViteServer, loadConfigFromFile, mergeConfig } = await import("vite");
|
|
41
42
|
const react = await import("@vitejs/plugin-react");
|
|
42
43
|
const clientRoot = this.findClientRoot();
|
|
44
|
+
const projectRoot = process.cwd();
|
|
43
45
|
const userConfig = (await loadConfigFromFile({
|
|
44
46
|
mode: "development",
|
|
45
47
|
command: "serve"
|
|
@@ -58,6 +60,7 @@ var ViteDevServer = class extends BaseServer {
|
|
|
58
60
|
},
|
|
59
61
|
plugins: [
|
|
60
62
|
react.default(),
|
|
63
|
+
reactSourceLocPlugin({ projectRoot }),
|
|
61
64
|
appKitTypesPlugin(),
|
|
62
65
|
appKitServingTypesPlugin()
|
|
63
66
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-dev-server.js","names":[],"sources":["../../../src/plugins/server/vite-dev-server.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type express from \"express\";\nimport type { ViteDevServer as ViteDevServerType } from \"vite\";\nimport { ServerError } from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport { appKitServingTypesPlugin } from \"../../type-generator/serving/vite-plugin\";\nimport { appKitTypesPlugin } from \"../../type-generator/vite-plugin\";\nimport { mergeConfigDedup } from \"../../utils\";\nimport { BaseServer } from \"./base-server\";\nimport type { PluginClientConfigs, PluginEndpoints } from \"./utils\";\n\nconst logger = createLogger(\"server:vite\");\n\n/**\n * Vite dev server for the AppKit.\n *\n * This class is responsible for serving the Vite dev server for the development server.\n * It also handles the index.html file for the development server.\n *\n * @example\n * ```ts\n * const viteDevServer = new ViteDevServer(app, endpoints);\n * await viteDevServer.setup();\n * ```\n */\nexport class ViteDevServer extends BaseServer {\n private vite: ViteDevServerType | null;\n\n constructor(\n app: express.Application,\n endpoints: PluginEndpoints = {},\n pluginConfigs: PluginClientConfigs = {},\n ) {\n super(app, endpoints, pluginConfigs);\n this.vite = null;\n }\n\n /**\n * Setup the Vite dev server.\n *\n * This method sets up the Vite dev server and the index.html file for the development server.\n *\n * @returns\n */\n async setup() {\n const {\n createServer: createViteServer,\n loadConfigFromFile,\n mergeConfig,\n } = await import(\"vite\");\n const react = await import(\"@vitejs/plugin-react\");\n\n const clientRoot = this.findClientRoot();\n\n const loadedConfig = await loadConfigFromFile(\n {\n mode: \"development\",\n command: \"serve\",\n },\n undefined,\n clientRoot,\n );\n\n const userConfig = loadedConfig?.config ?? {};\n const viteClientPort = process.env.VITE_CLIENT_PORT;\n const serverHmr = viteClientPort\n ? { hmr: { clientPort: viteClientPort } }\n : {};\n\n const coreConfig = {\n configFile: false,\n root: clientRoot,\n server: {\n middlewareMode: true,\n ...serverHmr,\n watch: {\n useFsEvents: true,\n ignored: [\"**/node_modules/**\", \"!**/node_modules/@databricks/**\"],\n },\n },\n plugins: [\n react.default(),\n appKitTypesPlugin(),\n appKitServingTypesPlugin(),\n ],\n appType: \"custom\",\n };\n\n const mergedConfigs = mergeConfigDedup(userConfig, coreConfig, mergeConfig);\n this.vite = await createViteServer(mergedConfigs);\n\n this.app.use(this.vite.middlewares);\n\n this.app.use(\"*\", async (req, res, next) => {\n if (\n req.originalUrl.startsWith(\"/api\") ||\n req.originalUrl.startsWith(\"/query\")\n ) {\n return next();\n }\n const vite = this.vite;\n this.validateVite(vite);\n\n try {\n const indexPath = path.resolve(clientRoot, \"index.html\");\n let html = fs.readFileSync(indexPath, \"utf-8\");\n html = html.replace(\"<body>\", `<body>${this.getConfigScript()}`);\n html = await vite.transformIndexHtml(req.originalUrl, html);\n res.status(200).set({ \"Content-Type\": \"text/html\" }).end(html);\n } catch (e) {\n vite.ssrFixStacktrace(e as Error);\n next(e);\n }\n });\n }\n\n /** Close the Vite dev server. */\n async close() {\n await this.vite?.close();\n }\n\n /** Find the client root. */\n private findClientRoot(): string {\n const cwd = process.cwd();\n const candidates = [\"client\", \"src\", \"app\", \"frontend\", \".\"];\n\n for (const dir of candidates) {\n const fullPath = path.resolve(cwd, dir);\n const hasViteConfig =\n fs.existsSync(path.join(fullPath, \"vite.config.ts\")) ||\n fs.existsSync(path.join(fullPath, \"vite.config.js\"));\n const hasIndexHtml = fs.existsSync(path.join(fullPath, \"index.html\"));\n\n if (hasViteConfig && hasIndexHtml) {\n logger.debug(\"Vite dev server: using client root %s\", fullPath);\n return fullPath;\n }\n }\n\n throw ServerError.clientDirectoryNotFound(candidates);\n }\n\n // type assertion to ensure vite is not null\n private validateVite(\n vite: ViteDevServerType | null,\n ): asserts vite is ViteDevServerType {\n if (!vite) {\n throw ServerError.viteNotInitialized();\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"vite-dev-server.js","names":[],"sources":["../../../src/plugins/server/vite-dev-server.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type express from \"express\";\nimport type { ViteDevServer as ViteDevServerType } from \"vite\";\nimport { ServerError } from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport { appKitServingTypesPlugin } from \"../../type-generator/serving/vite-plugin\";\nimport { appKitTypesPlugin } from \"../../type-generator/vite-plugin\";\nimport { mergeConfigDedup } from \"../../utils\";\nimport { BaseServer } from \"./base-server\";\nimport { reactSourceLocPlugin } from \"./react-source-loc-vite-plugin\";\nimport type { PluginClientConfigs, PluginEndpoints } from \"./utils\";\n\nconst logger = createLogger(\"server:vite\");\n\n/**\n * Vite dev server for the AppKit.\n *\n * This class is responsible for serving the Vite dev server for the development server.\n * It also handles the index.html file for the development server.\n *\n * @example\n * ```ts\n * const viteDevServer = new ViteDevServer(app, endpoints);\n * await viteDevServer.setup();\n * ```\n */\nexport class ViteDevServer extends BaseServer {\n private vite: ViteDevServerType | null;\n\n constructor(\n app: express.Application,\n endpoints: PluginEndpoints = {},\n pluginConfigs: PluginClientConfigs = {},\n ) {\n super(app, endpoints, pluginConfigs);\n this.vite = null;\n }\n\n /**\n * Setup the Vite dev server.\n *\n * This method sets up the Vite dev server and the index.html file for the development server.\n *\n * @returns\n */\n async setup() {\n const {\n createServer: createViteServer,\n loadConfigFromFile,\n mergeConfig,\n } = await import(\"vite\");\n const react = await import(\"@vitejs/plugin-react\");\n\n const clientRoot = this.findClientRoot();\n const projectRoot = process.cwd();\n\n const loadedConfig = await loadConfigFromFile(\n {\n mode: \"development\",\n command: \"serve\",\n },\n undefined,\n clientRoot,\n );\n\n const userConfig = loadedConfig?.config ?? {};\n const viteClientPort = process.env.VITE_CLIENT_PORT;\n const serverHmr = viteClientPort\n ? { hmr: { clientPort: viteClientPort } }\n : {};\n\n const coreConfig = {\n configFile: false,\n root: clientRoot,\n server: {\n middlewareMode: true,\n ...serverHmr,\n watch: {\n useFsEvents: true,\n ignored: [\"**/node_modules/**\", \"!**/node_modules/@databricks/**\"],\n },\n },\n plugins: [\n react.default(),\n reactSourceLocPlugin({ projectRoot }),\n appKitTypesPlugin(),\n appKitServingTypesPlugin(),\n ],\n appType: \"custom\",\n };\n\n const mergedConfigs = mergeConfigDedup(userConfig, coreConfig, mergeConfig);\n this.vite = await createViteServer(mergedConfigs);\n\n this.app.use(this.vite.middlewares);\n\n this.app.use(\"*\", async (req, res, next) => {\n if (\n req.originalUrl.startsWith(\"/api\") ||\n req.originalUrl.startsWith(\"/query\")\n ) {\n return next();\n }\n const vite = this.vite;\n this.validateVite(vite);\n\n try {\n const indexPath = path.resolve(clientRoot, \"index.html\");\n let html = fs.readFileSync(indexPath, \"utf-8\");\n html = html.replace(\"<body>\", `<body>${this.getConfigScript()}`);\n html = await vite.transformIndexHtml(req.originalUrl, html);\n res.status(200).set({ \"Content-Type\": \"text/html\" }).end(html);\n } catch (e) {\n vite.ssrFixStacktrace(e as Error);\n next(e);\n }\n });\n }\n\n /** Close the Vite dev server. */\n async close() {\n await this.vite?.close();\n }\n\n /** Find the client root. */\n private findClientRoot(): string {\n const cwd = process.cwd();\n const candidates = [\"client\", \"src\", \"app\", \"frontend\", \".\"];\n\n for (const dir of candidates) {\n const fullPath = path.resolve(cwd, dir);\n const hasViteConfig =\n fs.existsSync(path.join(fullPath, \"vite.config.ts\")) ||\n fs.existsSync(path.join(fullPath, \"vite.config.js\"));\n const hasIndexHtml = fs.existsSync(path.join(fullPath, \"index.html\"));\n\n if (hasViteConfig && hasIndexHtml) {\n logger.debug(\"Vite dev server: using client root %s\", fullPath);\n return fullPath;\n }\n }\n\n throw ServerError.clientDirectoryNotFound(candidates);\n }\n\n // type assertion to ensure vite is not null\n private validateVite(\n vite: ViteDevServerType | null,\n ): asserts vite is ViteDevServerType {\n if (!vite) {\n throw ServerError.viteNotInitialized();\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;aAI2C;AAS3C,MAAM,SAAS,aAAa,cAAc;;;;;;;;;;;;;AAc1C,IAAa,gBAAb,cAAmC,WAAW;CAC5C,AAAQ;CAER,YACE,KACA,YAA6B,EAAE,EAC/B,gBAAqC,EAAE,EACvC;AACA,QAAM,KAAK,WAAW,cAAc;AACpC,OAAK,OAAO;;;;;;;;;CAUd,MAAM,QAAQ;EACZ,MAAM,EACJ,cAAc,kBACd,oBACA,gBACE,MAAM,OAAO;EACjB,MAAM,QAAQ,MAAM,OAAO;EAE3B,MAAM,aAAa,KAAK,gBAAgB;EACxC,MAAM,cAAc,QAAQ,KAAK;EAWjC,MAAM,cATe,MAAM,mBACzB;GACE,MAAM;GACN,SAAS;GACV,EACD,QACA,WACD,GAEgC,UAAU,EAAE;EAC7C,MAAM,iBAAiB,QAAQ,IAAI;AA0BnC,OAAK,OAAO,MAAM,iBADI,iBAAiB,YApBpB;GACjB,YAAY;GACZ,MAAM;GACN,QAAQ;IACN,gBAAgB;IAChB,GATc,iBACd,EAAE,KAAK,EAAE,YAAY,gBAAgB,EAAE,GACvC,EAAE;IAQF,OAAO;KACL,aAAa;KACb,SAAS,CAAC,sBAAsB,kCAAkC;KACnE;IACF;GACD,SAAS;IACP,MAAM,SAAS;IACf,qBAAqB,EAAE,aAAa,CAAC;IACrC,mBAAmB;IACnB,0BAA0B;IAC3B;GACD,SAAS;GACV,EAE8D,YAAY,CAC1B;AAEjD,OAAK,IAAI,IAAI,KAAK,KAAK,YAAY;AAEnC,OAAK,IAAI,IAAI,KAAK,OAAO,KAAK,KAAK,SAAS;AAC1C,OACE,IAAI,YAAY,WAAW,OAAO,IAClC,IAAI,YAAY,WAAW,SAAS,CAEpC,QAAO,MAAM;GAEf,MAAM,OAAO,KAAK;AAClB,QAAK,aAAa,KAAK;AAEvB,OAAI;IACF,MAAM,YAAY,KAAK,QAAQ,YAAY,aAAa;IACxD,IAAI,OAAO,GAAG,aAAa,WAAW,QAAQ;AAC9C,WAAO,KAAK,QAAQ,UAAU,SAAS,KAAK,iBAAiB,GAAG;AAChE,WAAO,MAAM,KAAK,mBAAmB,IAAI,aAAa,KAAK;AAC3D,QAAI,OAAO,IAAI,CAAC,IAAI,EAAE,gBAAgB,aAAa,CAAC,CAAC,IAAI,KAAK;YACvD,GAAG;AACV,SAAK,iBAAiB,EAAW;AACjC,SAAK,EAAE;;IAET;;;CAIJ,MAAM,QAAQ;AACZ,QAAM,KAAK,MAAM,OAAO;;;CAI1B,AAAQ,iBAAyB;EAC/B,MAAM,MAAM,QAAQ,KAAK;EACzB,MAAM,aAAa;GAAC;GAAU;GAAO;GAAO;GAAY;GAAI;AAE5D,OAAK,MAAM,OAAO,YAAY;GAC5B,MAAM,WAAW,KAAK,QAAQ,KAAK,IAAI;GACvC,MAAM,gBACJ,GAAG,WAAW,KAAK,KAAK,UAAU,iBAAiB,CAAC,IACpD,GAAG,WAAW,KAAK,KAAK,UAAU,iBAAiB,CAAC;GACtD,MAAM,eAAe,GAAG,WAAW,KAAK,KAAK,UAAU,aAAa,CAAC;AAErE,OAAI,iBAAiB,cAAc;AACjC,WAAO,MAAM,yCAAyC,SAAS;AAC/D,WAAO;;;AAIX,QAAM,YAAY,wBAAwB,WAAW;;CAIvD,AAAQ,aACN,MACmC;AACnC,MAAI,CAAC,KACH,OAAM,YAAY,oBAAoB"}
|
|
@@ -5,7 +5,7 @@ const agents: ToPlugin<typeof AgentsPlugin, AgentsPluginConfig, string>;
|
|
|
5
5
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
|
-
Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts
|
|
8
|
+
Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts `POST /invocations` and `POST /responses` (aliased non-streaming invoke endpoints) plus `POST /chat` (streaming, HITL-capable).
|
|
9
9
|
|
|
10
10
|
## Example[](#example "Direct link to Example")
|
|
11
11
|
|
package/docs/api/appkit.md
CHANGED
|
@@ -109,12 +109,12 @@ Documentation merge entry for Typedoc — combines the stable `@databricks/appki
|
|
|
109
109
|
|
|
110
110
|
## Variables[](#variables "Direct link to Variables")
|
|
111
111
|
|
|
112
|
-
| Variable | Description
|
|
113
|
-
| ------------------------------------------------------------------- |
|
|
114
|
-
| [agents](./docs/api/appkit/Variable.agents.md) | Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts
|
|
115
|
-
| [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data.
|
|
116
|
-
| [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace
|
|
117
|
-
| [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data.
|
|
112
|
+
| Variable | Description |
|
|
113
|
+
| ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
114
|
+
| [agents](./docs/api/appkit/Variable.agents.md) | Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts `POST /invocations` and `POST /responses` (aliased non-streaming invoke endpoints) plus `POST /chat` (streaming, HITL-capable). |
|
|
115
|
+
| [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data. |
|
|
116
|
+
| [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace |
|
|
117
|
+
| [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data. |
|
|
118
118
|
|
|
119
119
|
## Functions[](#functions "Direct link to Functions")
|
|
120
120
|
|
package/docs/plugins/agents.md
CHANGED
|
@@ -4,7 +4,7 @@ Beta plugin
|
|
|
4
4
|
|
|
5
5
|
This plugin is currently **beta**. APIs may change between minor releases. Import from `@databricks/appkit/beta`. See [Plugin Stability Tiers](./docs/plugins/stability.md).
|
|
6
6
|
|
|
7
|
-
The `agents` plugin turns a Databricks AppKit app into an AI-agent host. It loads agent definitions from markdown on disk (one folder per agent: `config/agents/<id>/agent.md`), from TypeScript (`createAgent(def)`), or both, and exposes them at `POST /invocations` alongside routes for
|
|
7
|
+
The `agents` plugin turns a Databricks AppKit app into an AI-agent host. It loads agent definitions from markdown on disk (one folder per agent: `config/agents/<id>/agent.md`), from TypeScript (`createAgent(def)`), or both, and exposes them at `POST /invocations` and `POST /responses` (non-streaming, aliases) alongside `POST /chat` (streaming) and routes for thread management, cancellation, and HITL approval.
|
|
8
8
|
|
|
9
9
|
This page covers the full lifecycle. For the hand-written primitives (`tool()`, `mcpServer()`), see [tools](./docs/plugins/server.md).
|
|
10
10
|
|
|
@@ -30,7 +30,7 @@ await createApp({
|
|
|
30
30
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
That alone gives you a live HTTP server with `POST /invocations` wired to a markdown-driven agent.
|
|
33
|
+
That alone gives you a live HTTP server with `POST /invocations` (and its alias `POST /responses`) wired to a markdown-driven agent. Use `POST /chat` instead when you want the streaming, HITL-capable surface.
|
|
34
34
|
|
|
35
35
|
## Level 1: drop a markdown agent package[](#level-1-drop-a-markdown-agent-package "Direct link to Level 1: drop a markdown agent package")
|
|
36
36
|
|
|
@@ -66,7 +66,11 @@ On startup the plugin:
|
|
|
66
66
|
|
|
67
67
|
The agent starts with **no tools**. Tools are opt-in — declare them in frontmatter (Level 2 below) or opt into auto-inherit explicitly with `agents({ autoInheritTools: { file: true } })`. See "Auto-inherit posture" further down for what that costs and why it's off by default.
|
|
68
68
|
|
|
69
|
-
Requests land at `POST /invocations` with an OpenAI Responses-compatible body. Every tool call runs through `asUser(req)` so SQL executes as the requesting user, file access respects Unity Catalog ACLs, and telemetry spans are created automatically.
|
|
69
|
+
Requests land at `POST /invocations` (or its alias `POST /responses`) with an OpenAI Responses-compatible body. These endpoints run the agent to completion and return a single JSON response — no SSE. Streaming clients should use `POST /chat`. Every tool call runs through `asUser(req)` so SQL executes as the requesting user, file access respects Unity Catalog ACLs, and telemetry spans are created automatically.
|
|
70
|
+
|
|
71
|
+
No HITL on `/invocations` and `/responses`
|
|
72
|
+
|
|
73
|
+
The non-streaming invoke surface has no way to surface a mid-call approval prompt back to the caller. When `approval.requireForDestructive` is enabled (default) and the resolved agent has any tool annotated with a mutating effect (`effect: "write" | "update" | "destructive"`, or the legacy `destructive: true`), `POST /invocations` and `POST /responses` reject the request with HTTP 400 before the adapter runs. Move HITL-capable agents to `POST /chat`, or disable approval via `agents({ approval: { requireForDestructive: false } })` for autonomous back-office agents.
|
|
70
74
|
|
|
71
75
|
## Level 2: scope tools in frontmatter[](#level-2-scope-tools-in-frontmatter "Direct link to Level 2: scope tools in frontmatter")
|
|
72
76
|
|
|
@@ -386,7 +390,7 @@ The route enforces that the decider is the stream owner: an approve from a diffe
|
|
|
386
390
|
|
|
387
391
|
The plugin enforces a handful of caps to protect a single-instance deployment from runaway prompts, misbehaving clients, or prompt-injected delegation cycles. Some are static (enforced by the request schema) and some are configurable via `agents({ limits: { ... } })`.
|
|
388
392
|
|
|
389
|
-
**Static caps** (applied at `POST /chat` and `POST /
|
|
393
|
+
**Static caps** (applied at `POST /chat`, `POST /invocations`, and `POST /responses` request parsing):
|
|
390
394
|
|
|
391
395
|
| Field | Cap | Why |
|
|
392
396
|
| ------------------------------------ | ----------------- | ----------------------------------------------------------------------------- |
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@databricks/appkit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.37.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"appkit": "./bin/appkit.js"
|
|
9
|
+
},
|
|
7
10
|
"packageManager": "pnpm@10.21.0",
|
|
8
11
|
"license": "Apache-2.0",
|
|
9
12
|
"repository": {
|
|
@@ -65,6 +68,7 @@
|
|
|
65
68
|
"express": "4.22.0",
|
|
66
69
|
"get-port": "7.2.0",
|
|
67
70
|
"js-yaml": "4.1.1",
|
|
71
|
+
"magic-string": "0.30.21",
|
|
68
72
|
"obug": "2.1.1",
|
|
69
73
|
"pg": "8.18.0",
|
|
70
74
|
"picocolors": "1.1.1",
|
|
@@ -90,8 +94,5 @@
|
|
|
90
94
|
"vite": "npm:rolldown-vite@7.1.14"
|
|
91
95
|
},
|
|
92
96
|
"module": "./dist/index.js",
|
|
93
|
-
"publishConfig": {}
|
|
94
|
-
"bin": {
|
|
95
|
-
"appkit": "./bin/appkit.js"
|
|
96
|
-
}
|
|
97
|
+
"publishConfig": {}
|
|
97
98
|
}
|