@databricks/appkit 0.59.0 → 0.61.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.
Files changed (118) hide show
  1. package/NOTICE.md +11 -10
  2. package/dist/agents/databricks.js +1 -2
  3. package/dist/agents/databricks.js.map +1 -1
  4. package/dist/agents/supervisor-api.js +1 -2
  5. package/dist/agents/supervisor-api.js.map +1 -1
  6. package/dist/appkit/package.js +1 -1
  7. package/dist/cache/index.js +2 -3
  8. package/dist/cache/index.js.map +1 -1
  9. package/dist/cli/commands/doctor/bundle.js +3 -11
  10. package/dist/cli/commands/doctor/bundle.js.map +1 -1
  11. package/dist/cli/commands/doctor/databricks-client.js +18 -22
  12. package/dist/cli/commands/doctor/databricks-client.js.map +1 -1
  13. package/dist/cli/commands/registry/add.js +410 -0
  14. package/dist/cli/commands/registry/add.js.map +1 -0
  15. package/dist/cli/commands/registry/client.js +94 -0
  16. package/dist/cli/commands/registry/client.js.map +1 -0
  17. package/dist/cli/commands/registry/config-plan.js +110 -0
  18. package/dist/cli/commands/registry/config-plan.js.map +1 -0
  19. package/dist/cli/commands/registry/config-writer.js +176 -0
  20. package/dist/cli/commands/registry/config-writer.js.map +1 -0
  21. package/dist/cli/commands/registry/constants.js +62 -0
  22. package/dist/cli/commands/registry/constants.js.map +1 -0
  23. package/dist/cli/commands/registry/env-reconcile.js +116 -0
  24. package/dist/cli/commands/registry/env-reconcile.js.map +1 -0
  25. package/dist/cli/commands/registry/env-writer.js +198 -0
  26. package/dist/cli/commands/registry/env-writer.js.map +1 -0
  27. package/dist/cli/commands/registry/index.js +25 -0
  28. package/dist/cli/commands/registry/index.js.map +1 -0
  29. package/dist/cli/commands/registry/info.js +45 -0
  30. package/dist/cli/commands/registry/info.js.map +1 -0
  31. package/dist/cli/commands/registry/list.js +130 -0
  32. package/dist/cli/commands/registry/list.js.map +1 -0
  33. package/dist/cli/commands/registry/requirements.js +92 -0
  34. package/dist/cli/commands/registry/requirements.js.map +1 -0
  35. package/dist/cli/commands/registry/server-register.js +124 -0
  36. package/dist/cli/commands/registry/server-register.js.map +1 -0
  37. package/dist/cli/commands/registry/workspace-picker.js +353 -0
  38. package/dist/cli/commands/registry/workspace-picker.js.map +1 -0
  39. package/dist/cli/deploy-config.js +36 -0
  40. package/dist/cli/deploy-config.js.map +1 -0
  41. package/dist/cli/index.js +4 -0
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/connectors/context.js +1 -2
  44. package/dist/connectors/context.js.map +1 -1
  45. package/dist/connectors/files/client.js +1 -2
  46. package/dist/connectors/files/client.js.map +1 -1
  47. package/dist/connectors/genie/client.js +1 -2
  48. package/dist/connectors/genie/client.js.map +1 -1
  49. package/dist/connectors/jobs/client.js +1 -2
  50. package/dist/connectors/jobs/client.js.map +1 -1
  51. package/dist/connectors/sql-warehouse/client.js +1 -2
  52. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  53. package/dist/context/execution-context.d.ts +0 -1
  54. package/dist/context/execution-context.d.ts.map +1 -1
  55. package/dist/context/service-context.d.ts +1 -2
  56. package/dist/context/service-context.d.ts.map +1 -1
  57. package/dist/context/service-context.js +2 -3
  58. package/dist/context/service-context.js.map +1 -1
  59. package/dist/core/appkit.d.ts +1 -2
  60. package/dist/core/appkit.d.ts.map +1 -1
  61. package/dist/index.d.ts +3 -5
  62. package/dist/index.js +2 -3
  63. package/dist/plugins/agents/agents.d.ts.map +1 -1
  64. package/dist/plugins/agents/agents.js +117 -80
  65. package/dist/plugins/agents/agents.js.map +1 -1
  66. package/dist/plugins/agents/manifest.js +10 -0
  67. package/dist/plugins/agents/mlflow.js +123 -0
  68. package/dist/plugins/agents/mlflow.js.map +1 -0
  69. package/dist/plugins/agents/schemas.js +4 -2
  70. package/dist/plugins/agents/schemas.js.map +1 -1
  71. package/dist/plugins/files/plugin.js +1 -2
  72. package/dist/plugins/files/plugin.js.map +1 -1
  73. package/dist/plugins/files/types.d.ts +1 -2
  74. package/dist/plugins/files/types.d.ts.map +1 -1
  75. package/dist/plugins/jobs/types.d.ts +1 -2
  76. package/dist/plugins/jobs/types.d.ts.map +1 -1
  77. package/dist/plugins/lakebase/lakebase.js +1 -2
  78. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  79. package/dist/schemas/manifest.js +4 -4
  80. package/dist/schemas/manifest.js.map +1 -1
  81. package/dist/shared/src/index.d.ts +4 -1
  82. package/dist/shared/src/schemas/manifest.d.ts +6 -6
  83. package/dist/shared/src/workspace-client/client.js +57 -0
  84. package/dist/shared/src/workspace-client/client.js.map +1 -0
  85. package/dist/shared/src/workspace-client/errors.d.ts +2 -0
  86. package/dist/shared/src/workspace-client/errors.js +3 -0
  87. package/dist/shared/src/workspace-client/factory.d.ts +19 -0
  88. package/dist/shared/src/workspace-client/factory.d.ts.map +1 -0
  89. package/dist/shared/src/workspace-client/factory.js +24 -0
  90. package/dist/shared/src/workspace-client/factory.js.map +1 -0
  91. package/dist/shared/src/workspace-client/index.d.ts +4 -0
  92. package/dist/shared/src/workspace-client/legacy.d.ts +31 -0
  93. package/dist/shared/src/workspace-client/legacy.d.ts.map +1 -0
  94. package/dist/shared/src/workspace-client/legacy.js +23 -0
  95. package/dist/shared/src/workspace-client/legacy.js.map +1 -0
  96. package/dist/shared/src/workspace-client/types.d.ts +49 -0
  97. package/dist/shared/src/workspace-client/types.d.ts.map +1 -0
  98. package/dist/type-generator/index.js +1 -2
  99. package/dist/type-generator/index.js.map +1 -1
  100. package/dist/type-generator/query-registry.js +1 -2
  101. package/dist/type-generator/query-registry.js.map +1 -1
  102. package/dist/type-generator/serving/fetcher.js +1 -2
  103. package/dist/type-generator/serving/fetcher.js.map +1 -1
  104. package/dist/type-generator/serving/generator.js +1 -2
  105. package/dist/type-generator/serving/generator.js.map +1 -1
  106. package/dist/type-generator/vite-plugin.js +1 -2
  107. package/dist/type-generator/vite-plugin.js.map +1 -1
  108. package/dist/workspace-client/index.d.ts +4 -3
  109. package/dist/workspace-client/index.js +2 -2
  110. package/dist/workspace-client/legacy.d.ts +9 -4
  111. package/dist/workspace-client/legacy.d.ts.map +1 -1
  112. package/dist/workspace-client/legacy.js +3 -3
  113. package/dist/workspace-client/legacy.js.map +1 -1
  114. package/dist/workspace-client/types.d.ts +2 -2
  115. package/docs/api/appkit/Function.createWorkspaceClient.md +4 -4
  116. package/docs/api/appkit/Interface.WorkspaceClientOptions.md +11 -0
  117. package/package.json +6 -4
  118. package/sbom.cdx.json +1 -1
@@ -1,10 +1,9 @@
1
+ import { ConfigError } from "../shared/src/workspace-client/legacy.js";
2
+ import { createWorkspaceClient } from "../shared/src/workspace-client/factory.js";
1
3
  import { AuthenticationError } from "../errors/authentication.js";
2
4
  import { ConfigurationError } from "../errors/configuration.js";
3
5
  import { InitializationError } from "../errors/initialization.js";
4
6
  import "../errors/index.js";
5
- import { ConfigError } from "../workspace-client/legacy.js";
6
- import { createWorkspaceClient } from "../workspace-client/factory.js";
7
- import "../workspace-client/index.js";
8
7
  import { getClientOptions } from "./client-options.js";
9
8
  import { createHash } from "node:crypto";
10
9
 
@@ -1 +1 @@
1
- {"version":3,"file":"service-context.js","names":[],"sources":["../../src/context/service-context.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n AuthenticationError,\n ConfigurationError,\n InitializationError,\n} from \"../errors\";\nimport {\n type ClientOptions,\n ConfigError,\n createWorkspaceClient,\n type sql,\n type WorkspaceClient,\n} from \"../workspace-client\";\nimport { getClientOptions } from \"./client-options\";\nimport type { UserContext } from \"./user-context\";\n\n/**\n * Service context holds the service principal client and shared resources.\n * This is initialized once at app startup and shared across all requests.\n */\nexport interface ServiceContextState {\n /** WorkspaceClient authenticated as the service principal */\n client: WorkspaceClient;\n /** The service principal's user ID */\n serviceUserId: string;\n /** Promise that resolves to the warehouse ID (only present when a plugin requires `SQL_WAREHOUSE` resource) */\n warehouseId?: Promise<string>;\n /** Promise that resolves to the workspace ID */\n workspaceId: Promise<string>;\n}\n\n/**\n * ServiceContext is a singleton that manages the service principal's\n * WorkspaceClient and shared resources like warehouse/workspace IDs.\n *\n * It's initialized once at app startup and provides the foundation\n * for both service principal and user context execution.\n */\nexport class ServiceContext {\n private static instance: ServiceContextState | null = null;\n private static initPromise: Promise<ServiceContextState> | null = null;\n\n /**\n * Initialize the service context. Should be called once at app startup.\n * Safe to call multiple times - will return the same instance.\n *\n * @param options - Which shared resources to resolve (derived from plugin manifests).\n * @param client - Optional pre-configured WorkspaceClient to use instead\n * of creating one from environment credentials.\n */\n static async initialize(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n if (ServiceContext.instance) {\n return ServiceContext.instance;\n }\n\n if (ServiceContext.initPromise) {\n return ServiceContext.initPromise;\n }\n\n ServiceContext.initPromise = ServiceContext.createContext(options, client);\n ServiceContext.instance = await ServiceContext.initPromise;\n return ServiceContext.instance;\n }\n\n /**\n * Get the initialized service context.\n * @throws Error if not initialized\n */\n static get(): ServiceContextState {\n if (!ServiceContext.instance) {\n throw InitializationError.notInitialized(\n \"ServiceContext\",\n \"Call ServiceContext.initialize() first\",\n );\n }\n return ServiceContext.instance;\n }\n\n /**\n * Check if the service context has been initialized.\n */\n static isInitialized(): boolean {\n return ServiceContext.instance !== null;\n }\n\n /**\n * Create a user context from request headers.\n *\n * @param token - The user's access token from x-forwarded-access-token header\n * @param userId - The user's ID from x-forwarded-user header\n * @param userName - Optional user name\n * @throws Error if token is not provided\n */\n static createUserContext(\n token: string,\n userId: string,\n userName?: string,\n userEmail?: string,\n ): UserContext {\n if (!token) {\n throw AuthenticationError.missingToken(\"user token\");\n }\n\n const host = process.env.DATABRICKS_HOST;\n if (!host) {\n throw ConfigurationError.missingEnvVar(\"DATABRICKS_HOST\");\n }\n\n const serviceCtx = ServiceContext.get();\n\n // Create user client with the OAuth token from Databricks Apps\n // Note: We use authType: \"pat\" because the token is passed as a Bearer token\n // just like a PAT, even though it's technically an OAuth token\n const userClient = createWorkspaceClient({\n token,\n host,\n authType: \"pat\",\n clientOptions: getClientOptions(),\n });\n\n const tokenFingerprint = createHash(\"sha256\")\n .update(token)\n .digest(\"hex\")\n .slice(0, 16);\n\n return {\n client: userClient,\n userId,\n userName,\n userEmail,\n tokenFingerprint,\n warehouseId: serviceCtx.warehouseId,\n workspaceId: serviceCtx.workspaceId,\n isUserContext: true,\n };\n }\n\n /**\n * Get the client options for WorkspaceClient.\n * Exposed for testing purposes.\n */\n static getClientOptions(): ClientOptions {\n return getClientOptions();\n }\n\n private static async createContext(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n try {\n const wsClient =\n client ?? createWorkspaceClient({ clientOptions: getClientOptions() });\n\n const [resolvedWorkspaceId, currentUser, resolvedWarehouseId] =\n await Promise.all([\n ServiceContext.getWorkspaceId(wsClient),\n wsClient.currentUser.me(),\n options?.warehouseId\n ? ServiceContext.getWarehouseId(wsClient)\n : Promise.resolve(undefined as string | undefined),\n ]);\n\n if (!currentUser.id) {\n throw ConfigurationError.resourceNotFound(\"Service user ID\");\n }\n\n const warehouseId =\n options?.warehouseId && resolvedWarehouseId !== undefined\n ? Promise.resolve(resolvedWarehouseId)\n : undefined;\n\n return {\n client: wsClient,\n serviceUserId: currentUser.id,\n warehouseId,\n workspaceId: Promise.resolve(resolvedWorkspaceId),\n };\n } catch (e) {\n if (e instanceof ConfigError) {\n throw ConfigurationError.databricksAuthenticationSetupFailed(\n e.baseMessage,\n { cause: e },\n );\n }\n throw e;\n }\n }\n\n private static async getWorkspaceId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WORKSPACE_ID) {\n return process.env.DATABRICKS_WORKSPACE_ID;\n }\n\n const response = (await client.apiClient.request({\n path: \"/api/2.0/preview/scim/v2/Me\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {},\n responseHeaders: [\"x-databricks-org-id\"],\n })) as { \"x-databricks-org-id\": string };\n\n if (!response[\"x-databricks-org-id\"]) {\n throw ConfigurationError.resourceNotFound(\"Workspace ID\");\n }\n\n return response[\"x-databricks-org-id\"];\n }\n\n private static async getWarehouseId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WAREHOUSE_ID) {\n return process.env.DATABRICKS_WAREHOUSE_ID;\n }\n\n const agenticMode =\n process.env.DATABRICKS_APPS_AGENTIC_MODE === \"true\" ||\n process.env.DATABRICKS_APPS_AGENTIC_MODE === \"1\";\n\n if (process.env.NODE_ENV === \"development\" && !agenticMode) {\n const response = (await client.apiClient.request({\n path: \"/api/2.0/sql/warehouses\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {\n skip_cannot_use: \"true\",\n },\n })) as { warehouses: sql.EndpointInfo[] };\n\n const priorities: Record<sql.State, number> = {\n RUNNING: 0,\n STOPPED: 1,\n STARTING: 2,\n STOPPING: 3,\n DELETED: 99,\n DELETING: 99,\n };\n\n const warehouses = (response.warehouses || []).sort((a, b) => {\n return (\n priorities[a.state as sql.State] - priorities[b.state as sql.State]\n );\n });\n\n if (response.warehouses.length === 0) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n const firstWarehouse = warehouses[0];\n if (\n firstWarehouse.state === \"DELETED\" ||\n firstWarehouse.state === \"DELETING\" ||\n !firstWarehouse.id\n ) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n return firstWarehouse.id;\n }\n\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n /**\n * Reset the service context. Only for testing purposes.\n */\n static reset(): void {\n ServiceContext.instance = null;\n ServiceContext.initPromise = null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"service-context.js","names":[],"sources":["../../src/context/service-context.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n AuthenticationError,\n ConfigurationError,\n InitializationError,\n} from \"../errors\";\nimport {\n type ClientOptions,\n ConfigError,\n createWorkspaceClient,\n type sql,\n type WorkspaceClient,\n} from \"../workspace-client\";\nimport { getClientOptions } from \"./client-options\";\nimport type { UserContext } from \"./user-context\";\n\n/**\n * Service context holds the service principal client and shared resources.\n * This is initialized once at app startup and shared across all requests.\n */\nexport interface ServiceContextState {\n /** WorkspaceClient authenticated as the service principal */\n client: WorkspaceClient;\n /** The service principal's user ID */\n serviceUserId: string;\n /** Promise that resolves to the warehouse ID (only present when a plugin requires `SQL_WAREHOUSE` resource) */\n warehouseId?: Promise<string>;\n /** Promise that resolves to the workspace ID */\n workspaceId: Promise<string>;\n}\n\n/**\n * ServiceContext is a singleton that manages the service principal's\n * WorkspaceClient and shared resources like warehouse/workspace IDs.\n *\n * It's initialized once at app startup and provides the foundation\n * for both service principal and user context execution.\n */\nexport class ServiceContext {\n private static instance: ServiceContextState | null = null;\n private static initPromise: Promise<ServiceContextState> | null = null;\n\n /**\n * Initialize the service context. Should be called once at app startup.\n * Safe to call multiple times - will return the same instance.\n *\n * @param options - Which shared resources to resolve (derived from plugin manifests).\n * @param client - Optional pre-configured WorkspaceClient to use instead\n * of creating one from environment credentials.\n */\n static async initialize(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n if (ServiceContext.instance) {\n return ServiceContext.instance;\n }\n\n if (ServiceContext.initPromise) {\n return ServiceContext.initPromise;\n }\n\n ServiceContext.initPromise = ServiceContext.createContext(options, client);\n ServiceContext.instance = await ServiceContext.initPromise;\n return ServiceContext.instance;\n }\n\n /**\n * Get the initialized service context.\n * @throws Error if not initialized\n */\n static get(): ServiceContextState {\n if (!ServiceContext.instance) {\n throw InitializationError.notInitialized(\n \"ServiceContext\",\n \"Call ServiceContext.initialize() first\",\n );\n }\n return ServiceContext.instance;\n }\n\n /**\n * Check if the service context has been initialized.\n */\n static isInitialized(): boolean {\n return ServiceContext.instance !== null;\n }\n\n /**\n * Create a user context from request headers.\n *\n * @param token - The user's access token from x-forwarded-access-token header\n * @param userId - The user's ID from x-forwarded-user header\n * @param userName - Optional user name\n * @throws Error if token is not provided\n */\n static createUserContext(\n token: string,\n userId: string,\n userName?: string,\n userEmail?: string,\n ): UserContext {\n if (!token) {\n throw AuthenticationError.missingToken(\"user token\");\n }\n\n const host = process.env.DATABRICKS_HOST;\n if (!host) {\n throw ConfigurationError.missingEnvVar(\"DATABRICKS_HOST\");\n }\n\n const serviceCtx = ServiceContext.get();\n\n // Create user client with the OAuth token from Databricks Apps\n // Note: We use authType: \"pat\" because the token is passed as a Bearer token\n // just like a PAT, even though it's technically an OAuth token\n const userClient = createWorkspaceClient({\n token,\n host,\n authType: \"pat\",\n clientOptions: getClientOptions(),\n });\n\n const tokenFingerprint = createHash(\"sha256\")\n .update(token)\n .digest(\"hex\")\n .slice(0, 16);\n\n return {\n client: userClient,\n userId,\n userName,\n userEmail,\n tokenFingerprint,\n warehouseId: serviceCtx.warehouseId,\n workspaceId: serviceCtx.workspaceId,\n isUserContext: true,\n };\n }\n\n /**\n * Get the client options for WorkspaceClient.\n * Exposed for testing purposes.\n */\n static getClientOptions(): ClientOptions {\n return getClientOptions();\n }\n\n private static async createContext(\n options?: { warehouseId?: boolean },\n client?: WorkspaceClient,\n ): Promise<ServiceContextState> {\n try {\n const wsClient =\n client ?? createWorkspaceClient({ clientOptions: getClientOptions() });\n\n const [resolvedWorkspaceId, currentUser, resolvedWarehouseId] =\n await Promise.all([\n ServiceContext.getWorkspaceId(wsClient),\n wsClient.currentUser.me(),\n options?.warehouseId\n ? ServiceContext.getWarehouseId(wsClient)\n : Promise.resolve(undefined as string | undefined),\n ]);\n\n if (!currentUser.id) {\n throw ConfigurationError.resourceNotFound(\"Service user ID\");\n }\n\n const warehouseId =\n options?.warehouseId && resolvedWarehouseId !== undefined\n ? Promise.resolve(resolvedWarehouseId)\n : undefined;\n\n return {\n client: wsClient,\n serviceUserId: currentUser.id,\n warehouseId,\n workspaceId: Promise.resolve(resolvedWorkspaceId),\n };\n } catch (e) {\n if (e instanceof ConfigError) {\n throw ConfigurationError.databricksAuthenticationSetupFailed(\n e.baseMessage,\n { cause: e },\n );\n }\n throw e;\n }\n }\n\n private static async getWorkspaceId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WORKSPACE_ID) {\n return process.env.DATABRICKS_WORKSPACE_ID;\n }\n\n const response = (await client.apiClient.request({\n path: \"/api/2.0/preview/scim/v2/Me\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {},\n responseHeaders: [\"x-databricks-org-id\"],\n })) as { \"x-databricks-org-id\": string };\n\n if (!response[\"x-databricks-org-id\"]) {\n throw ConfigurationError.resourceNotFound(\"Workspace ID\");\n }\n\n return response[\"x-databricks-org-id\"];\n }\n\n private static async getWarehouseId(\n client: WorkspaceClient,\n ): Promise<string> {\n if (process.env.DATABRICKS_WAREHOUSE_ID) {\n return process.env.DATABRICKS_WAREHOUSE_ID;\n }\n\n const agenticMode =\n process.env.DATABRICKS_APPS_AGENTIC_MODE === \"true\" ||\n process.env.DATABRICKS_APPS_AGENTIC_MODE === \"1\";\n\n if (process.env.NODE_ENV === \"development\" && !agenticMode) {\n const response = (await client.apiClient.request({\n path: \"/api/2.0/sql/warehouses\",\n method: \"GET\",\n headers: new Headers(),\n raw: false,\n query: {\n skip_cannot_use: \"true\",\n },\n })) as { warehouses: sql.EndpointInfo[] };\n\n const priorities: Record<sql.State, number> = {\n RUNNING: 0,\n STOPPED: 1,\n STARTING: 2,\n STOPPING: 3,\n DELETED: 99,\n DELETING: 99,\n };\n\n const warehouses = (response.warehouses || []).sort((a, b) => {\n return (\n priorities[a.state as sql.State] - priorities[b.state as sql.State]\n );\n });\n\n if (response.warehouses.length === 0) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n const firstWarehouse = warehouses[0];\n if (\n firstWarehouse.state === \"DELETED\" ||\n firstWarehouse.state === \"DELETING\" ||\n !firstWarehouse.id\n ) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n return firstWarehouse.id;\n }\n\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"Please configure the DATABRICKS_WAREHOUSE_ID environment variable\",\n );\n }\n\n /**\n * Reset the service context. Only for testing purposes.\n */\n static reset(): void {\n ServiceContext.instance = null;\n ServiceContext.initPromise = null;\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,7 @@
1
1
  import { PluginConstructor, PluginData, PluginMap } from "../shared/src/plugin.js";
2
2
  import { CacheConfig } from "../shared/src/cache.js";
3
3
  import "../shared/src/index.js";
4
- import { WorkspaceClient } from "../workspace-client/types.js";
5
- import "../workspace-client/index.js";
4
+ import { WorkspaceClient } from "../workspace-client/index.js";
6
5
  import { TelemetryConfig } from "../telemetry/types.js";
7
6
  import "../telemetry/index.js";
8
7
 
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuXsB,SAAA,WACV,UAAA,CAAW,iBAAA,qBAAA,CAErB,MAAA;EACE,OAAA,GAAU,CAAA;EACV,SAAA,GAAY,eAAA;EACZ,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,eAAA;EACT,cAAA,IAAkB,MAAA,EAAQ,SAAA,CAAU,CAAA,aAAc,OAAA;EAClD,wBAAA;AAAA,IAED,OAAA,CAAQ,SAAA,CAAU,CAAA"}
1
+ {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuXsB,SAAA,WACV,UAAA,CAAW,iBAAA,qBAAA,CAErB,MAAA;EACE,OAAA,GAAU,CAAA;EACV,SAAA,GAAY,eAAA;EACZ,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,eAAA;EACT,cAAA,IAAkB,MAAA,EAAQ,SAAA,CAAU,CAAA,aAAc,OAAA;EAClD,wBAAA;AAAA,IAED,OAAA,CAAQ,SAAA,CAAU,CAAA"}
package/dist/index.d.ts CHANGED
@@ -3,12 +3,10 @@ import { BasePluginConfig, IAppRouter, PluginData, ToPlugin } from "./shared/src
3
3
  import { CacheConfig } from "./shared/src/cache.js";
4
4
  import { StreamExecutionSettings } from "./shared/src/execute.js";
5
5
  import { isSQLTypeMarker, sql } from "./shared/src/sql/helpers.js";
6
+ import { ApiError } from "./shared/src/workspace-client/errors.js";
7
+ import { createWorkspaceClient } from "./shared/src/workspace-client/factory.js";
6
8
  import "./shared/src/index.js";
7
- import { ApiError } from "./workspace-client/errors.js";
8
- import { WorkspaceClientOptions } from "./workspace-client/legacy.js";
9
- import { WorkspaceClient } from "./workspace-client/types.js";
10
- import { createWorkspaceClient } from "./workspace-client/factory.js";
11
- import "./workspace-client/index.js";
9
+ import { WorkspaceClient, WorkspaceClientOptions } from "./workspace-client/index.js";
12
10
  import { ExecutionResult } from "./plugin/execution-result.js";
13
11
  import { CacheManager } from "./cache/index.js";
14
12
  import { ITelemetry, TelemetryConfig } from "./telemetry/types.js";
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import { isSQLTypeMarker, sql } from "./shared/src/sql/helpers.js";
2
+ import { ApiError } from "./shared/src/workspace-client/errors.js";
3
+ import { createWorkspaceClient } from "./shared/src/workspace-client/factory.js";
2
4
  import { createLakebasePoolManager } from "./connectors/lakebase/pool-manager.js";
3
5
  import { AppKitError } from "./errors/base.js";
4
6
  import { AuthenticationError } from "./errors/authentication.js";
@@ -10,9 +12,6 @@ import { ServerError } from "./errors/server.js";
10
12
  import { TunnelError } from "./errors/tunnel.js";
11
13
  import { ValidationError } from "./errors/validation.js";
12
14
  import "./errors/index.js";
13
- import { ApiError } from "./workspace-client/errors.js";
14
- import { createWorkspaceClient } from "./workspace-client/factory.js";
15
- import "./workspace-client/index.js";
16
15
  import { getExecutionContext } from "./context/execution-context.js";
17
16
  import { RequestedClaimsPermissionSet, createLakebasePool, generateDatabaseCredential, getLakebaseOrmConfig, getLakebasePgConfig, getUsernameWithApiLookup, getWorkspaceClient } from "./connectors/lakebase/index.js";
18
17
  import { SeverityNumber, SpanStatusCode } from "./telemetry/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","names":[],"sources":["../../../src/plugins/agents/agents.ts"],"mappings":";;;;;;;;;;cAsIa,YAAA,SAAqB,MAAA,YAAkB,YAAA;EAAA,OAC3C,QAAA,EAAuB,cAAA;EAAA,OACvB,KAAA,EAAO,WAAA;EAAA,UAEI,MAAA,EAAQ,kBAAA;EAAA,QAElB,MAAA;EAAA,QACA,gBAAA;EAAA,QACA,aAAA;EARgB;;;;;;EAAA,QAkBhB,gBAAA;EAAA,QACA,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEI,MAAA,EAAQ,kBAAA;EA8rBJ;;;;;;;;;;EAAA,QA/pBR,oBAAA;EAAA,YAKI,sBAAA,CAAA;EA3DoB;EAAA,YAqFpB,cAAA,CAAA;EApFL;EAAA,QAuGC,gBAAA;EAtGD;;;;;;EAAA,QAgHC,WAAA;EAhGA;;;;;EAAA,QAiHA,aAAA;EAYF,KAAA,CAAA,GAAK,OAAA;EAzFH;;;;;;EAuGF,MAAA,CAAA,GAAU,OAAA;EAdL;;;;;EAAA,QAwCG,kBAAA;EAAA,QAmEN,iBAAA;EAAA,QAMM,mBAAA;EAoEA;;;;;;EAAA,QA1CN,mBAAA;EAAA,QAmBM,oBAAA;EAAA,QAuBA,cAAA;EAyUY;;;;;EAAA,QA7RZ,cAAA;EAqWE;;;;;;;;;;;EAAA,QArPR,eAAA;EA6iCM;;;;;;;;;;;;EAAA,QAjhCN,eAAA;EAAA,QAkBM,gBAAA;EAAA,QA0DA,kBAAA;EAiEd,aAAA,CAAA,GAAiB,mBAAA;EAIX,gBAAA,CAAA,GAAoB,OAAA;;;;;;;UAYlB,iBAAA;EAUR,YAAA,CAAa,MAAA,EAAQ,UAAA;EAkDrB,YAAA,CAAA,GAAgB,MAAA;EAAA,QAOF,WAAA;;;;;;;;;;;;UA6EN,gCAAA;;;;;;;;;;;UAuBM,aAAA;EAAA,QAoFA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;UA6LA,qBAAA;;;;;;;;;;;;UA6IA,gBAAA;;;;;;;;;;;;;;;UAyHA,WAAA;EAAA,QAiGA,aAAA;EAAA,QA2BA,cAAA;EAAA,QAuCA,kBAAA;EAAA,QASA,gBAAA;EAAA,QAUA,mBAAA;EAAA,QAaN,YAAA;EAAA,QASA,aAAA;EAgBF,QAAA,CAAA,GAAY,OAAA;EAQlB,OAAA,CAAA;6BAE2B,GAAA,EAAO,eAAA,KAAe,OAAA;;2BAG3B,eAAA;;;oCAGS,OAAA,CAAA,MAAA;EAAA;EAAA,QAIjB,iBAAA;AAAA;;;;;;;;;;;;;;;;cAsJH,MAAA,EAAM,QAAA,QAAA,YAAA,EAAA,kBAAA"}
1
+ {"version":3,"file":"agents.d.ts","names":[],"sources":["../../../src/plugins/agents/agents.ts"],"mappings":";;;;;;;;;;cA6Ia,YAAA,SAAqB,MAAA,YAAkB,YAAA;EAAA,OAK3C,QAAA,EAAkC,cAAA;EAAA,OAClC,KAAA,EAAO,WAAA;EAAA,UAEI,MAAA,EAAQ,kBAAA;EAAA,QAElB,MAAA;EAAA,QACA,gBAAA;EAAA,QACA,aAAA;EAZgB;;;;;;EAAA,QAsBhB,gBAAA;EAAA,QACA,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEI,MAAA,EAAQ,kBAAA;EA+rBJ;;;;;;;;;;EAAA,QAhqBR,oBAAA;EAAA,YAKI,sBAAA,CAAA;EA/DoB;EAAA,YAyFpB,cAAA,CAAA;EApFL;EAAA,QAuGC,gBAAA;EAtGD;;;;;;EAAA,QAgHC,WAAA;EAhGA;;;;;EAAA,QAiHA,aAAA;EAYF,KAAA,CAAA,GAAK,OAAA;EAzFH;;;;;;EAwGF,MAAA,CAAA,GAAU,OAAA;EAfL;;;;;EAAA,QAyCG,kBAAA;EAAA,QAmEN,iBAAA;EAAA,QAMM,mBAAA;EAoEA;;;;;;EAAA,QA1CN,mBAAA;EAAA,QAmBM,oBAAA;EAAA,QAuBA,cAAA;EAyUY;;;;;EAAA,QA7RZ,cAAA;EAqWE;;;;;;;;;;;EAAA,QArPR,eAAA;EAynCM;;;;;;;;;;;;EAAA,QA7lCN,eAAA;EAAA,QAkBM,gBAAA;EAAA,QA0DA,kBAAA;EAiEd,aAAA,CAAA,GAAiB,mBAAA;EAIX,gBAAA,CAAA,GAAoB,OAAA;;;;;;;UAYlB,iBAAA;EAUR,YAAA,CAAa,MAAA,EAAQ,UAAA;EAkDrB,YAAA,CAAA,GAAgB,MAAA;EAAA,QAOF,WAAA;;;;;;;;;;;;UA6EN,gCAAA;;;;;;;;;;;UAuBM,aAAA;EAAA,QA2FA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;UA2NA,qBAAA;;;;;;;;;;;;UA0KA,gBAAA;;;;;;;;;;;;;;;UAmIA,WAAA;EAAA,QAiGA,aAAA;EAAA,QA2BA,cAAA;EAAA,QAuCA,kBAAA;EAAA,QASA,gBAAA;EAAA,QAUA,mBAAA;EAAA,QAaN,YAAA;EAAA,QASA,aAAA;EAgBF,QAAA,CAAA,GAAY,OAAA;EAQlB,OAAA,CAAA;6BAE2B,GAAA,EAAO,eAAA,KAAe,OAAA;;2BAG3B,eAAA;;;oCAGS,OAAA,CAAA,MAAA;EAAA;EAAA,QAIjB,iBAAA;AAAA;;;;;;;;;;;;;;;;cAsJH,MAAA,EAAM,QAAA,QAAA,YAAA,EAAA,kBAAA"}
@@ -20,6 +20,7 @@ import { agentStreamDefaults } from "./defaults.js";
20
20
  import { EventChannel } from "./event-channel.js";
21
21
  import { AgentEventTranslator } from "./event-translator.js";
22
22
  import manifest_default from "./manifest.js";
23
+ import { currentTraceId, initAgentTracing, linkTraceToRun, traceAgent, traceTool } from "./mlflow.js";
23
24
  import { approvalRequestSchema, cancelRequestSchema, chatRequestSchema, invocationsRequestSchema } from "./schemas.js";
24
25
  import { InMemoryThreadStore } from "./thread-store.js";
25
26
  import { ToolApprovalGate } from "./tool-approval-gate.js";
@@ -147,6 +148,7 @@ var AgentsPlugin = class extends Plugin {
147
148
  else this.userStreamCounts.set(entry.userId, next);
148
149
  }
149
150
  async setup() {
151
+ await initAgentTracing();
150
152
  const { agents, defaultAgentName } = await this.buildAgentRegistry();
151
153
  this.agents = agents;
152
154
  this.defaultAgentName = defaultAgentName;
@@ -550,7 +552,7 @@ var AgentsPlugin = class extends Plugin {
550
552
  });
551
553
  return;
552
554
  }
553
- const { message, threadId, agent: agentName } = parsed.data;
555
+ const { message, threadId, agent: agentName, mlflowRunId } = parsed.data;
554
556
  const registered = this.resolveAgent(agentName);
555
557
  if (!registered) {
556
558
  res.status(400).json({ error: agentName ? `Agent "${agentName}" not found` : "No agent registered" });
@@ -583,7 +585,7 @@ var AgentsPlugin = class extends Plugin {
583
585
  res.status(500).json({ error: "Thread operation failed" });
584
586
  return;
585
587
  }
586
- return this._streamAgent(req, res, registered, thread, userId);
588
+ return this._streamAgent(req, res, registered, thread, userId, mlflowRunId);
587
589
  }
588
590
  /**
589
591
  * Returns the names of tools in `registered.toolIndex` whose annotations
@@ -621,7 +623,7 @@ var AgentsPlugin = class extends Plugin {
621
623
  });
622
624
  return;
623
625
  }
624
- const { input } = parsed.data;
626
+ const { input, mlflowRunId } = parsed.data;
625
627
  const registered = this.resolveAgent();
626
628
  if (!registered) {
627
629
  res.status(400).json({ error: "No agent registered" });
@@ -664,9 +666,9 @@ var AgentsPlugin = class extends Plugin {
664
666
  res.status(500).json({ error: "Thread operation failed" });
665
667
  return;
666
668
  }
667
- return this._runAgentNonStreaming(req, res, registered, thread, userId);
669
+ return this._runAgentNonStreaming(req, res, registered, thread, userId, mlflowRunId);
668
670
  }
669
- async _streamAgent(req, res, registered, thread, userId) {
671
+ async _streamAgent(req, res, registered, thread, userId, mlflowRunId) {
670
672
  const abortController = new AbortController();
671
673
  const signal = abortController.signal;
672
674
  const requestId = randomUUID();
@@ -695,37 +697,54 @@ var AgentsPlugin = class extends Plugin {
695
697
  type: "metadata",
696
698
  data: { threadId: thread.id }
697
699
  })) outboundEvents.push(evt);
698
- const pluginNames = this.context ? this.context.getPluginNames().filter((n) => n !== this.name && n !== "server") : [];
699
- const messagesWithSystem = [{
700
- id: "system",
701
- role: "system",
702
- content: composePromptForAgent(registered, this.config.baseSystemPrompt, {
703
- agentName: registered.name,
704
- pluginNames,
705
- toolNames: tools.map((t) => t.name)
706
- }),
707
- createdAt: /* @__PURE__ */ new Date()
708
- }, ...thread.messages];
709
- const fullContent = await consumeAdapterStream(registered.adapter.run({
710
- messages: messagesWithSystem,
711
- tools,
712
- threadId: thread.id,
713
- signal,
714
- extensions: buildAdapterExtensions(registered.toolIndex)
715
- }, {
716
- executeTool,
717
- signal
718
- }), {
719
- signal,
720
- onEvent: (event) => {
721
- for (const translated of translator.translate(event)) outboundEvents.push(translated);
700
+ await traceAgent(registered.name ?? "agent", { messages: thread.messages.map((m) => ({
701
+ role: m.role,
702
+ content: m.content
703
+ })) }, async (span) => {
704
+ if (mlflowRunId) linkTraceToRun(mlflowRunId);
705
+ const pluginNames = this.context ? this.context.getPluginNames().filter((n) => n !== this.name && n !== "server") : [];
706
+ const messagesWithSystem = [{
707
+ id: "system",
708
+ role: "system",
709
+ content: composePromptForAgent(registered, this.config.baseSystemPrompt, {
710
+ agentName: registered.name,
711
+ pluginNames,
712
+ toolNames: tools.map((t) => t.name)
713
+ }),
714
+ createdAt: /* @__PURE__ */ new Date()
715
+ }, ...thread.messages];
716
+ const fullContent = await consumeAdapterStream(registered.adapter.run({
717
+ messages: messagesWithSystem,
718
+ tools,
719
+ threadId: thread.id,
720
+ signal,
721
+ extensions: buildAdapterExtensions(registered.toolIndex)
722
+ }, {
723
+ executeTool,
724
+ signal
725
+ }), {
726
+ signal,
727
+ onEvent: (event) => {
728
+ for (const translated of translator.translate(event)) outboundEvents.push(translated);
729
+ }
730
+ });
731
+ if (fullContent) {
732
+ span.setOutputs({
733
+ role: "assistant",
734
+ content: fullContent
735
+ });
736
+ await this.threadStore.addMessage(thread.id, userId, {
737
+ id: randomUUID(),
738
+ role: "assistant",
739
+ content: fullContent,
740
+ createdAt: /* @__PURE__ */ new Date()
741
+ });
722
742
  }
723
- });
724
- if (fullContent) await this.threadStore.addMessage(thread.id, userId, {
725
- id: randomUUID(),
726
- role: "assistant",
727
- content: fullContent,
728
- createdAt: /* @__PURE__ */ new Date()
743
+ const mlflowTraceId = currentTraceId();
744
+ if (mlflowTraceId) for (const evt of translator.translate({
745
+ type: "metadata",
746
+ data: { mlflowTraceId }
747
+ })) outboundEvents.push(evt);
729
748
  });
730
749
  for (const evt of translator.finalize()) outboundEvents.push(evt);
731
750
  } catch (error) {
@@ -784,12 +803,14 @@ var AgentsPlugin = class extends Plugin {
784
803
  * synthesis (which would have been a coding bug given the precheck) is
785
804
  * a dropped no-op instead of a runtime crash.
786
805
  */
787
- async _runAgentNonStreaming(req, res, registered, thread, userId) {
806
+ async _runAgentNonStreaming(req, res, registered, thread, userId, mlflowRunId) {
788
807
  const abortController = new AbortController();
789
808
  const signal = abortController.signal;
790
809
  const requestId = randomUUID();
791
810
  this.trackStream(requestId, userId, abortController);
792
811
  const tools = Array.from(registered.toolIndex.values()).map((e) => e.def);
812
+ const limits = this.resolvedLimits;
813
+ let mlflowTraceId;
793
814
  const runState = {
794
815
  req,
795
816
  userId,
@@ -800,7 +821,7 @@ var AgentsPlugin = class extends Plugin {
800
821
  requireForDestructive: false,
801
822
  timeoutMs: 0
802
823
  },
803
- limits: this.resolvedLimits,
824
+ limits,
804
825
  translator: new AgentEventTranslator(),
805
826
  outboundEvents: new EventChannel(),
806
827
  toolCallsUsed: { count: 0 }
@@ -808,31 +829,44 @@ var AgentsPlugin = class extends Plugin {
808
829
  const executeTool = (name, args) => this.dispatchToolCall(runState, registered.toolIndex, name, args, 0);
809
830
  let fullContent = "";
810
831
  try {
811
- const pluginNames = this.context ? this.context.getPluginNames().filter((n) => n !== this.name && n !== "server") : [];
812
- const messagesWithSystem = [{
813
- id: "system",
814
- role: "system",
815
- content: composePromptForAgent(registered, this.config.baseSystemPrompt, {
816
- agentName: registered.name,
817
- pluginNames,
818
- toolNames: tools.map((t) => t.name)
819
- }),
820
- createdAt: /* @__PURE__ */ new Date()
821
- }, ...thread.messages];
822
- fullContent = await consumeAdapterStream(registered.adapter.run({
823
- messages: messagesWithSystem,
824
- tools,
825
- threadId: thread.id,
826
- signal
827
- }, {
828
- executeTool,
829
- signal
830
- }), { signal });
831
- if (fullContent) await this.threadStore.addMessage(thread.id, userId, {
832
- id: randomUUID(),
833
- role: "assistant",
834
- content: fullContent,
835
- createdAt: /* @__PURE__ */ new Date()
832
+ await traceAgent(registered.name ?? "agent", { messages: thread.messages.map((m) => ({
833
+ role: m.role,
834
+ content: m.content
835
+ })) }, async (span) => {
836
+ if (mlflowRunId) linkTraceToRun(mlflowRunId);
837
+ const pluginNames = this.context ? this.context.getPluginNames().filter((n) => n !== this.name && n !== "server") : [];
838
+ const messagesWithSystem = [{
839
+ id: "system",
840
+ role: "system",
841
+ content: composePromptForAgent(registered, this.config.baseSystemPrompt, {
842
+ agentName: registered.name,
843
+ pluginNames,
844
+ toolNames: tools.map((t) => t.name)
845
+ }),
846
+ createdAt: /* @__PURE__ */ new Date()
847
+ }, ...thread.messages];
848
+ fullContent = await consumeAdapterStream(registered.adapter.run({
849
+ messages: messagesWithSystem,
850
+ tools,
851
+ threadId: thread.id,
852
+ signal
853
+ }, {
854
+ executeTool,
855
+ signal
856
+ }), { signal });
857
+ if (fullContent) {
858
+ span.setOutputs({
859
+ role: "assistant",
860
+ content: fullContent
861
+ });
862
+ await this.threadStore.addMessage(thread.id, userId, {
863
+ id: randomUUID(),
864
+ role: "assistant",
865
+ content: fullContent,
866
+ createdAt: /* @__PURE__ */ new Date()
867
+ });
868
+ }
869
+ mlflowTraceId = currentTraceId();
836
870
  });
837
871
  } catch (error) {
838
872
  if (signal.aborted) {
@@ -869,6 +903,7 @@ var AgentsPlugin = class extends Plugin {
869
903
  created_at: Math.floor(Date.now() / 1e3),
870
904
  status: "completed",
871
905
  thread_id: thread.id,
906
+ ...mlflowTraceId ? { mlflow_trace_id: mlflowTraceId } : {},
872
907
  output: [message]
873
908
  });
874
909
  }
@@ -908,24 +943,26 @@ var AgentsPlugin = class extends Plugin {
908
943
  timeoutMs: runState.approvalPolicy.timeoutMs
909
944
  }) === "deny") return `Tool execution denied by user approval gate (tool: ${name}).`;
910
945
  }
911
- let result;
912
- if (entry.source === "toolkit") {
913
- if (!this.context) throw new Error("Plugin tool execution requires PluginContext; this should never happen through createApp");
914
- result = await this.context.executeTool(runState.req, entry.pluginName, entry.localName, args, runState.signal, runState.limits.toolCallTimeoutMs);
915
- } else if (entry.source === "function") {
916
- if (typeof args !== "object" || args === null || Array.isArray(args)) throw new Error(`Function tool '${name}' received non-object arguments (got ${args === null ? "null" : Array.isArray(args) ? "array" : typeof args}); expected a JSON object.`);
917
- result = await entry.functionTool.execute(args);
918
- } else if (entry.source === "mcp") {
919
- if (!this.mcpClient) throw new Error("MCP client not connected");
920
- const oboToken = runState.req.headers["x-forwarded-access-token"];
921
- const mcpAuth = typeof oboToken === "string" ? { Authorization: `Bearer ${oboToken}` } : void 0;
922
- result = await this.mcpClient.callTool(entry.mcpToolName, args, mcpAuth);
923
- } else if (entry.source === "subagent") {
924
- const childAgent = this.agents.get(entry.agentName);
925
- if (!childAgent) throw new Error(`Sub-agent not found: ${entry.agentName}`);
926
- result = await this.runSubAgent(runState, childAgent, args, depth + 1);
927
- } else if (entry.source === "hosted-supervisor") throw new Error(`Tool '${name}' is a hosted-supervisor tool and cannot be invoked from the Node process. It is executed server-side by the Databricks AI Gateway and is only reachable when the agent's model is a Supervisor API adapter.`);
928
- return normalizeToolResult(result);
946
+ return normalizeToolResult(await traceTool(name, args, async () => {
947
+ let result;
948
+ if (entry.source === "toolkit") {
949
+ if (!this.context) throw new Error("Plugin tool execution requires PluginContext; this should never happen through createApp");
950
+ result = await this.context.executeTool(runState.req, entry.pluginName, entry.localName, args, runState.signal, runState.limits.toolCallTimeoutMs);
951
+ } else if (entry.source === "function") {
952
+ if (typeof args !== "object" || args === null || Array.isArray(args)) throw new Error(`Function tool '${name}' received non-object arguments (got ${args === null ? "null" : Array.isArray(args) ? "array" : typeof args}); expected a JSON object.`);
953
+ result = await entry.functionTool.execute(args);
954
+ } else if (entry.source === "mcp") {
955
+ if (!this.mcpClient) throw new Error("MCP client not connected");
956
+ const oboToken = runState.req.headers["x-forwarded-access-token"];
957
+ const mcpAuth = typeof oboToken === "string" ? { Authorization: `Bearer ${oboToken}` } : void 0;
958
+ result = await this.mcpClient.callTool(entry.mcpToolName, args, mcpAuth);
959
+ } else if (entry.source === "subagent") {
960
+ const childAgent = this.agents.get(entry.agentName);
961
+ if (!childAgent) throw new Error(`Sub-agent not found: ${entry.agentName}`);
962
+ result = await this.runSubAgent(runState, childAgent, args, depth + 1);
963
+ } else if (entry.source === "hosted-supervisor") throw new Error(`Tool '${name}' is a hosted-supervisor tool and cannot be invoked from the Node process. It is executed server-side by the Databricks AI Gateway and is only reachable when the agent's model is a Supervisor API adapter.`);
964
+ return result;
965
+ }));
929
966
  }
930
967
  /**
931
968
  * Runs a sub-agent in response to an `agent-<key>` tool call. Returns the