databricks-mason 0.1.4.dev0__tar.gz → 0.1.5.dev0__tar.gz

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 (59) hide show
  1. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/PKG-INFO +79 -10
  2. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/README.md +74 -7
  3. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/pyproject.toml +13 -3
  4. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/__init__.py +12 -1
  5. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/agent_project.py +54 -2
  6. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/deploy.py +93 -33
  7. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/dev.py +29 -5
  8. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/init.py +201 -31
  9. databricks_mason-0.1.5.dev0/src/databricks_mason/lakebase_durability_store.py +78 -0
  10. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/memory.py +8 -3
  11. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/runtime/__init__.py +8 -2
  12. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/__init__.py +1 -0
  13. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/app.py +227 -0
  14. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/attempt.py +140 -0
  15. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/recovery.py +112 -0
  16. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/runtime.py +167 -0
  17. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/store.py +783 -0
  18. databricks_mason-0.1.5.dev0/src/databricks_mason/runtime/durability/types.py +189 -0
  19. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/sessions.py +12 -3
  20. databricks_mason-0.1.4.dev0/src/databricks_mason/runtime/background.py +0 -37
  21. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/.gitignore +0 -0
  22. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/NOTICE +0 -0
  23. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/_api_client.py +0 -0
  24. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/_pagination.py +0 -0
  25. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/auth.py +0 -0
  26. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/cli.py +0 -0
  27. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/client.py +0 -0
  28. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/errors.py +0 -0
  29. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/help.py +0 -0
  30. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/langgraph/__init__.py +0 -0
  31. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/langgraph/mcp.py +0 -0
  32. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/langgraph/memory.py +0 -0
  33. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/langgraph/session_store.py +0 -0
  34. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/mcp.py +0 -0
  35. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/memory_store.py +0 -0
  36. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/memory_store_access.py +0 -0
  37. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/models.py +0 -0
  38. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/openai/__init__.py +0 -0
  39. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/openai/mcp.py +0 -0
  40. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/openai/memory.py +0 -0
  41. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/openai/sessions.py +0 -0
  42. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/project_config.py +0 -0
  43. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/py.typed +0 -0
  44. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/render.py +0 -0
  45. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/runtime/session_store_client.py +0 -0
  46. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/runtime/tool_manifest.py +0 -0
  47. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/runtime/tracing.py +0 -0
  48. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/runtime/workspace.py +0 -0
  49. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/sandbox.py +0 -0
  50. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/session_store.py +0 -0
  51. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/session_store_access.py +0 -0
  52. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/store_access.py +0 -0
  53. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/templates/python_tool_langgraph.py +0 -0
  54. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/templates/python_tool_test.py +0 -0
  55. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/templates/sandbox_mcp.py +0 -0
  56. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/templates/sandbox_mcp_langgraph.py +0 -0
  57. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/timefmt.py +0 -0
  58. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/tools.py +0 -0
  59. {databricks_mason-0.1.4.dev0 → databricks_mason-0.1.5.dev0}/src/databricks_mason/tracing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: databricks-mason
3
- Version: 0.1.4.dev0
3
+ Version: 0.1.5.dev0
4
4
  Summary: Databricks integration for Mason
5
5
  Author-email: Databricks <agent-feedback@databricks.com>
6
6
  License-File: NOTICE
@@ -14,6 +14,7 @@ Requires-Dist: tomli>=2.0
14
14
  Requires-Dist: tomlkit>=0.13
15
15
  Provides-Extra: runtime
16
16
  Requires-Dist: databricks-agents>=1.9.3; extra == 'runtime'
17
+ Requires-Dist: databricks-ai-bridge[memory]>=0.21.0; extra == 'runtime'
17
18
  Requires-Dist: databricks-langchain>=0.17.0; extra == 'runtime'
18
19
  Requires-Dist: fastapi>=0.129.0; extra == 'runtime'
19
20
  Requires-Dist: langchain-mcp-adapters>=0.2.1; extra == 'runtime'
@@ -21,15 +22,16 @@ Requires-Dist: langchain>=1.0.0; extra == 'runtime'
21
22
  Requires-Dist: langgraph>=1.1.0; extra == 'runtime'
22
23
  Requires-Dist: mlflow>=3.10.1; extra == 'runtime'
23
24
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25.0; extra == 'runtime'
24
- Requires-Dist: uuid-utils>=0.10.0; extra == 'runtime'
25
+ Requires-Dist: uvicorn>=0.20.0; extra == 'runtime'
25
26
  Provides-Extra: runtime-openai
26
27
  Requires-Dist: databricks-agents>=1.9.3; extra == 'runtime-openai'
28
+ Requires-Dist: databricks-ai-bridge[memory]>=0.21.0; extra == 'runtime-openai'
27
29
  Requires-Dist: databricks-openai>=0.13.0; extra == 'runtime-openai'
28
30
  Requires-Dist: fastapi>=0.129.0; extra == 'runtime-openai'
29
31
  Requires-Dist: mlflow>=3.10.1; extra == 'runtime-openai'
30
32
  Requires-Dist: openai-agents>=0.7.0; extra == 'runtime-openai'
31
33
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25.0; extra == 'runtime-openai'
32
- Requires-Dist: uuid-utils>=0.10.0; extra == 'runtime-openai'
34
+ Requires-Dist: uvicorn>=0.20.0; extra == 'runtime-openai'
33
35
  Provides-Extra: tracing
34
36
  Requires-Dist: mlflow[databricks]>=3.10.1; extra == 'tracing'
35
37
  Description-Content-Type: text/markdown
@@ -62,6 +64,12 @@ For tracing commands, install Mason with tracing extras:
62
64
  pip install 'databricks-mason[tracing]'
63
65
  ```
64
66
 
67
+ For the SDK-hosted durable agent application, install the runtime extra:
68
+
69
+ ```sh
70
+ pip install 'databricks-mason[runtime]'
71
+ ```
72
+
65
73
  ## Shell completion
66
74
  Add this to `~/.zshrc`:
67
75
  ```sh
@@ -142,13 +150,74 @@ transport will be replaced by the generated `WorkspaceClient.mason` service when
142
150
  is released, without changing this public surface. Deployment, sandbox, tracing, and
143
151
  the existing CLI commands remain separate.
144
152
 
153
+ ## Agent application
154
+
155
+ `AgentApp` provides Mason's invocation HTTP contract, including foreground, streaming, background,
156
+ polling, and event endpoints. By default its state is process-local. Set `durable_runtime=True` to
157
+ use Lakebase persistence, heartbeats, and crash recovery after deployment:
158
+
159
+ ```python
160
+ from databricks_mason import AgentApp, DurableAgentContext
161
+
162
+ app = AgentApp(durable_runtime=True)
163
+
164
+
165
+ @app.invoke
166
+ async def invoke(input: object, context: DurableAgentContext) -> object:
167
+ return await run_agent(input, session_id=context.session_id)
168
+
169
+
170
+ @app.on_recovery
171
+ async def recover(input: object, context: DurableAgentContext) -> object:
172
+ return await recover_agent(input, session_id=context.session_id)
173
+ ```
174
+
175
+ The Mason server exposes `POST /api/invocations`, `GET /api/invocations/{invocation_id}`, and
176
+ `GET /api/invocations/{invocation_id}/events?after={cursor}`. Databricks Apps bearer-token requests
177
+ must use `/api/` routes
178
+ ([Apps documentation](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/connect-local)).
179
+ The client supplies a UUID `id`, which is also the idempotency key for every invocation mode:
180
+
181
+ - foreground sync returns `200` with the result under `output`;
182
+ - background sync returns `202` with a status URL;
183
+ - foreground streaming returns `200` server-sent events; and
184
+ - background streaming returns `202` with status and event URLs.
185
+
186
+ `input` and `output` may be any JSON value. Transport fields are not passed to the callback. A
187
+ top-level `session_id` is rejected, but a framework template may carry its own stable application
188
+ session inside `input`. Polling uses only the invocation ID and relies on Databricks Apps
189
+ authentication. Without the durable runtime, request state and events exist only in the serving
190
+ process and horizontally scaled clients need sticky routing. With the durable runtime, Mason
191
+ persists the input, attempt status, heartbeats, lifecycle events, application events, and output.
192
+
193
+ Durability is enabled by default for both framework templates. Mason writes the durability binding
194
+ to `agent.toml`, and `mason deploy` then attaches one Lakebase database for runtime durability,
195
+ chosen in this order:
196
+
197
+ 1. Reuse the configured Session Store's Lakebase database.
198
+ 2. Otherwise reuse or provision a dedicated `<app>-durability` Lakebase project.
199
+
200
+ Mason adds only its `databricks_mason_runtime_<app-hash>` schema and tables to the selected database,
201
+ giving each app one owned schema. A replacement worker claims a stale heartbeat and calls the
202
+ `@app.on_recovery` handler. If that handler is omitted, startup warns that automatic crash recovery
203
+ is disabled; register the same function for both decorators when replaying the initial invocation is
204
+ safe. Agent checkpoint restoration and idempotent external side effects remain the developer's
205
+ responsibility.
206
+
207
+ Bare `mason init`, `--framework langgraph`, and `--framework openai` scaffold `AgentApp` with its
208
+ durable runtime enabled. Pass `--no-durable-runtime` for the same Mason HTTP contract with
209
+ process-local state and no Lakebase provisioning. Pass `--server custom` for a minimal FastAPI
210
+ server with one foreground `/invocations` route and no Mason `AgentApp`. Use `--disable-chat-app`
211
+ independently for API-only Mason server output.
212
+
145
213
  ## Commands
146
214
 
147
215
  ```text
148
216
  mason [-p <profile>] [-o text|json]
149
217
  login [--profile P]
150
218
  logout
151
- init [--framework openai|langgraph] [--disable-chat-app]
219
+ init [--framework openai|langgraph] [--server mason|custom]
220
+ [--no-durable-runtime] [--disable-chat-app]
152
221
  [--profile P] [--repo URL] [--ref REF] [directory]
153
222
  dev [--source PATH] [--prepare-environment] [--app-port PORT]
154
223
  [--with-traces C.S]
@@ -173,7 +242,7 @@ mason [-p <profile>] [-o text|json]
173
242
  add uc-function FUNCTION [--name NAME] [--source PATH]
174
243
  add python NAME [--source PATH]
175
244
  list [--source PATH]
176
- deploy <name> --source PATH [--with-traces C.S]
245
+ deploy <name> --source PATH [--with-traces C.S] [--instances N]
177
246
  deployments list | get | logs | start | stop | delete
178
247
  ```
179
248
 
@@ -252,7 +321,7 @@ mason init --framework langgraph \
252
321
  --profile <profile> \
253
322
  ./my-agent
254
323
  cd ./my-agent
255
- uv run start-server
324
+ mason dev
256
325
  ```
257
326
 
258
327
  The chat app includes synchronous, SSE streaming, background polling, Session Store, Memory Store,
@@ -271,10 +340,10 @@ mason --profile <profile> deploy mason-agent-demo --source .
271
340
  exists. The agent reads the bound stores from `agent.toml` at runtime; `deploy` grants the app's
272
341
  service principal access to them.)
273
342
 
274
- The Databricks Apps `__Host-databricks-app-router` cookie is both the sticky routing key and the
275
- application session id. The browser sends it automatically; API clients must reuse it as a cookie.
276
- Request bodies never carry `session_id`. A localhost-only `mason-local-session` cookie provides the
277
- same behavior outside Databricks Apps. TODO: move to `X-Routing-Key` when Apps supports it.
343
+ The chat UI generates a stable application session UUID in browser local storage, places it inside
344
+ the durable invocation's opaque `input`, and creates a fresh invocation UUID per turn. The
345
+ `__Host-databricks-app-router` cookie remains independent: API clients may reuse it for sticky
346
+ replica routing, but it is neither authentication nor the template's application session state.
278
347
 
279
348
  The generated `README.md` documents every request the client makes: config discovery, sync and SSE
280
349
  invocations, background submission and polling, session transcript loading, HITL resume, and memory
@@ -26,6 +26,12 @@ For tracing commands, install Mason with tracing extras:
26
26
  pip install 'databricks-mason[tracing]'
27
27
  ```
28
28
 
29
+ For the SDK-hosted durable agent application, install the runtime extra:
30
+
31
+ ```sh
32
+ pip install 'databricks-mason[runtime]'
33
+ ```
34
+
29
35
  ## Shell completion
30
36
  Add this to `~/.zshrc`:
31
37
  ```sh
@@ -106,13 +112,74 @@ transport will be replaced by the generated `WorkspaceClient.mason` service when
106
112
  is released, without changing this public surface. Deployment, sandbox, tracing, and
107
113
  the existing CLI commands remain separate.
108
114
 
115
+ ## Agent application
116
+
117
+ `AgentApp` provides Mason's invocation HTTP contract, including foreground, streaming, background,
118
+ polling, and event endpoints. By default its state is process-local. Set `durable_runtime=True` to
119
+ use Lakebase persistence, heartbeats, and crash recovery after deployment:
120
+
121
+ ```python
122
+ from databricks_mason import AgentApp, DurableAgentContext
123
+
124
+ app = AgentApp(durable_runtime=True)
125
+
126
+
127
+ @app.invoke
128
+ async def invoke(input: object, context: DurableAgentContext) -> object:
129
+ return await run_agent(input, session_id=context.session_id)
130
+
131
+
132
+ @app.on_recovery
133
+ async def recover(input: object, context: DurableAgentContext) -> object:
134
+ return await recover_agent(input, session_id=context.session_id)
135
+ ```
136
+
137
+ The Mason server exposes `POST /api/invocations`, `GET /api/invocations/{invocation_id}`, and
138
+ `GET /api/invocations/{invocation_id}/events?after={cursor}`. Databricks Apps bearer-token requests
139
+ must use `/api/` routes
140
+ ([Apps documentation](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/connect-local)).
141
+ The client supplies a UUID `id`, which is also the idempotency key for every invocation mode:
142
+
143
+ - foreground sync returns `200` with the result under `output`;
144
+ - background sync returns `202` with a status URL;
145
+ - foreground streaming returns `200` server-sent events; and
146
+ - background streaming returns `202` with status and event URLs.
147
+
148
+ `input` and `output` may be any JSON value. Transport fields are not passed to the callback. A
149
+ top-level `session_id` is rejected, but a framework template may carry its own stable application
150
+ session inside `input`. Polling uses only the invocation ID and relies on Databricks Apps
151
+ authentication. Without the durable runtime, request state and events exist only in the serving
152
+ process and horizontally scaled clients need sticky routing. With the durable runtime, Mason
153
+ persists the input, attempt status, heartbeats, lifecycle events, application events, and output.
154
+
155
+ Durability is enabled by default for both framework templates. Mason writes the durability binding
156
+ to `agent.toml`, and `mason deploy` then attaches one Lakebase database for runtime durability,
157
+ chosen in this order:
158
+
159
+ 1. Reuse the configured Session Store's Lakebase database.
160
+ 2. Otherwise reuse or provision a dedicated `<app>-durability` Lakebase project.
161
+
162
+ Mason adds only its `databricks_mason_runtime_<app-hash>` schema and tables to the selected database,
163
+ giving each app one owned schema. A replacement worker claims a stale heartbeat and calls the
164
+ `@app.on_recovery` handler. If that handler is omitted, startup warns that automatic crash recovery
165
+ is disabled; register the same function for both decorators when replaying the initial invocation is
166
+ safe. Agent checkpoint restoration and idempotent external side effects remain the developer's
167
+ responsibility.
168
+
169
+ Bare `mason init`, `--framework langgraph`, and `--framework openai` scaffold `AgentApp` with its
170
+ durable runtime enabled. Pass `--no-durable-runtime` for the same Mason HTTP contract with
171
+ process-local state and no Lakebase provisioning. Pass `--server custom` for a minimal FastAPI
172
+ server with one foreground `/invocations` route and no Mason `AgentApp`. Use `--disable-chat-app`
173
+ independently for API-only Mason server output.
174
+
109
175
  ## Commands
110
176
 
111
177
  ```text
112
178
  mason [-p <profile>] [-o text|json]
113
179
  login [--profile P]
114
180
  logout
115
- init [--framework openai|langgraph] [--disable-chat-app]
181
+ init [--framework openai|langgraph] [--server mason|custom]
182
+ [--no-durable-runtime] [--disable-chat-app]
116
183
  [--profile P] [--repo URL] [--ref REF] [directory]
117
184
  dev [--source PATH] [--prepare-environment] [--app-port PORT]
118
185
  [--with-traces C.S]
@@ -137,7 +204,7 @@ mason [-p <profile>] [-o text|json]
137
204
  add uc-function FUNCTION [--name NAME] [--source PATH]
138
205
  add python NAME [--source PATH]
139
206
  list [--source PATH]
140
- deploy <name> --source PATH [--with-traces C.S]
207
+ deploy <name> --source PATH [--with-traces C.S] [--instances N]
141
208
  deployments list | get | logs | start | stop | delete
142
209
  ```
143
210
 
@@ -216,7 +283,7 @@ mason init --framework langgraph \
216
283
  --profile <profile> \
217
284
  ./my-agent
218
285
  cd ./my-agent
219
- uv run start-server
286
+ mason dev
220
287
  ```
221
288
 
222
289
  The chat app includes synchronous, SSE streaming, background polling, Session Store, Memory Store,
@@ -235,10 +302,10 @@ mason --profile <profile> deploy mason-agent-demo --source .
235
302
  exists. The agent reads the bound stores from `agent.toml` at runtime; `deploy` grants the app's
236
303
  service principal access to them.)
237
304
 
238
- The Databricks Apps `__Host-databricks-app-router` cookie is both the sticky routing key and the
239
- application session id. The browser sends it automatically; API clients must reuse it as a cookie.
240
- Request bodies never carry `session_id`. A localhost-only `mason-local-session` cookie provides the
241
- same behavior outside Databricks Apps. TODO: move to `X-Routing-Key` when Apps supports it.
305
+ The chat UI generates a stable application session UUID in browser local storage, places it inside
306
+ the durable invocation's opaque `input`, and creates a fresh invocation UUID per turn. The
307
+ `__Host-databricks-app-router` cookie remains independent: API clients may reuse it for sticky
308
+ replica routing, but it is neither authentication nor the template's application session state.
242
309
 
243
310
  The generated `README.md` documents every request the client makes: config discovery, sync and SSE
244
311
  invocations, background submission and polling, session transcript loading, HITL resume, and memory
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "databricks-mason"
3
- version = "0.1.4.dev0"
3
+ version = "0.1.5.dev0"
4
4
  description = "Databricks integration for Mason"
5
5
  authors = [
6
6
  { name="Databricks", email="agent-feedback@databricks.com" },
@@ -27,24 +27,26 @@ tracing = [
27
27
  # OpenAI Agents SDK adapter (databricks_mason.openai). Both carry the shared framework-neutral stack
28
28
  # (databricks_mason.runtime); the framework SDKs differ, so an agent installs only the one it uses.
29
29
  runtime = [
30
+ "databricks-ai-bridge[memory]>=0.21.0",
30
31
  "databricks-langchain>=0.17.0",
31
32
  "langgraph>=1.1.0",
32
33
  "langchain>=1.0.0",
33
34
  "langchain-mcp-adapters>=0.2.1",
34
35
  "fastapi>=0.129.0",
35
36
  "mlflow>=3.10.1",
36
- "uuid-utils>=0.10.0",
37
37
  "opentelemetry-exporter-otlp-proto-grpc>=1.25.0",
38
38
  "databricks-agents>=1.9.3",
39
+ "uvicorn>=0.20.0",
39
40
  ]
40
41
  runtime-openai = [
42
+ "databricks-ai-bridge[memory]>=0.21.0",
41
43
  "openai-agents>=0.7.0",
42
44
  "databricks-openai>=0.13.0",
43
45
  "fastapi>=0.129.0",
44
46
  "mlflow>=3.10.1",
45
- "uuid-utils>=0.10.0",
46
47
  "opentelemetry-exporter-otlp-proto-grpc>=1.25.0",
47
48
  "databricks-agents>=1.9.3",
49
+ "uvicorn>=0.20.0",
48
50
  ]
49
51
 
50
52
  [project.scripts]
@@ -57,7 +59,12 @@ dev = [
57
59
  { include-group = "tests" },
58
60
  ]
59
61
  tests = [
62
+ "databricks-ai-bridge[memory]>=0.21.0",
63
+ "fastapi>=0.129.0",
64
+ "httpx>=0.28.1",
60
65
  "pytest==9.0.2",
66
+ "pytest-asyncio==1.3.0",
67
+ "uvicorn>=0.20.0",
61
68
  ]
62
69
 
63
70
  [build-system]
@@ -75,6 +82,9 @@ include = [
75
82
  [tool.hatch.build.targets.wheel]
76
83
  packages = ["src/databricks_mason"]
77
84
 
85
+ [tool.uv.sources]
86
+ databricks-ai-bridge = { path = "../..", editable = true }
87
+
78
88
  [tool.ruff]
79
89
  include = ["pyproject.toml", "src/**/*.py", "tests/**/*.py"]
80
90
  extend = "../../pyproject.toml"
@@ -8,6 +8,8 @@ from databricks_mason.session_store import Session, SessionItem, SessionStore
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from databricks_mason.runtime import (
11
+ AgentApp,
12
+ DurableAgentContext,
11
13
  configure_tracing,
12
14
  tag_session,
13
15
  workspace_client,
@@ -22,6 +24,8 @@ __all__ = [
22
24
  "Session",
23
25
  "SessionItem",
24
26
  "SessionStore",
27
+ "AgentApp",
28
+ "DurableAgentContext",
25
29
  "configure_tracing",
26
30
  "tag_session",
27
31
  "workspace_client",
@@ -29,7 +33,14 @@ __all__ = [
29
33
  ]
30
34
 
31
35
  _RUNTIME_REEXPORTS = frozenset(
32
- {"configure_tracing", "tag_session", "workspace_client", "workspace_headers"}
36
+ {
37
+ "AgentApp",
38
+ "DurableAgentContext",
39
+ "configure_tracing",
40
+ "tag_session",
41
+ "workspace_client",
42
+ "workspace_headers",
43
+ }
33
44
  )
34
45
 
35
46
 
@@ -18,6 +18,7 @@ from databricks_mason.errors import AgentCliError
18
18
  from databricks_mason.runtime.tool_manifest import MEMORY_STORE_TABLE, SESSION_STORE_TABLE
19
19
 
20
20
  _SCHEMA_VERSION = 1
21
+ _DURABILITY_TABLE = "durability"
21
22
  _SUPPORTED_FRAMEWORKS = {"langgraph", "openai"}
22
23
  _SUPPORTED_SCOPE_KINDS = {"table", "volume", "workspace"}
23
24
  _SUPPORTED_PERMISSIONS = {"read_only", "read_write"}
@@ -201,6 +202,16 @@ def _store_name_from_manifest(value: object, table: str) -> str | None:
201
202
  return _required_string(cast(Mapping[str, Any], value).get("name"), f"[{table}] name")
202
203
 
203
204
 
205
+ def _durability_from_manifest(value: object) -> bool:
206
+ if value is None:
207
+ return False
208
+ if not isinstance(value, Mapping):
209
+ raise AgentCliError("agent.toml [durability] must be a table.")
210
+ if cast(Mapping[str, Any], value).get("enabled") is not True:
211
+ raise AgentCliError("agent.toml [durability] must set enabled = true.")
212
+ return True
213
+
214
+
204
215
  def _store_id_from_manifest(value: object) -> str | None:
205
216
  """Read the optional bare store ``id`` from a ``[memory_store]`` table, or None if absent."""
206
217
  if not isinstance(value, Mapping):
@@ -296,6 +307,8 @@ class AgentProject:
296
307
  memory_store: str | None = None,
297
308
  session_store: str | None = None,
298
309
  memory_store_id: str | None = None,
310
+ deployment_name: str | None = None,
311
+ durability_enabled: bool = False,
299
312
  ) -> None:
300
313
  self.root = root
301
314
  self.path = root / "agent.toml"
@@ -307,6 +320,9 @@ class AgentProject:
307
320
  self.memory_store = memory_store
308
321
  self.session_store = session_store
309
322
  self.memory_store_id = memory_store_id
323
+ # The deployment's base name (`mason deploy` prefixes it with `mason-`); None until named.
324
+ self.deployment_name = deployment_name
325
+ self.durability_enabled = durability_enabled
310
326
 
311
327
  @classmethod
312
328
  def load(cls, root: pathlib.Path | str) -> "AgentProject":
@@ -333,6 +349,11 @@ class AgentProject:
333
349
  framework = _required_string(agent.get("framework"), "agent.framework")
334
350
  if framework not in _SUPPORTED_FRAMEWORKS:
335
351
  raise AgentCliError(f"Unsupported Mason framework {framework!r}.")
352
+ deployment_name = agent.get("deployment_name")
353
+ if deployment_name is not None and not (
354
+ isinstance(deployment_name, str) and deployment_name
355
+ ):
356
+ raise AgentCliError("agent.toml [agent] deployment_name must be a non-empty string.")
336
357
  raw_tools = document.get("tools", [])
337
358
  if not isinstance(raw_tools, list):
338
359
  raise AgentCliError("agent.toml tools must be an array of tables.")
@@ -347,6 +368,7 @@ class AgentProject:
347
368
  session_store = _store_name_from_manifest(
348
369
  document.get(SESSION_STORE_TABLE), SESSION_STORE_TABLE
349
370
  )
371
+ durability_enabled = _durability_from_manifest(document.get(_DURABILITY_TABLE))
350
372
  return cls(
351
373
  project_root,
352
374
  document,
@@ -355,10 +377,18 @@ class AgentProject:
355
377
  memory_store,
356
378
  session_store,
357
379
  memory_store_id,
380
+ str(deployment_name) if deployment_name is not None else None,
381
+ durability_enabled,
358
382
  )
359
383
 
360
384
  @classmethod
361
- def create(cls, root: pathlib.Path | str, *, framework: str) -> "AgentProject":
385
+ def create(
386
+ cls,
387
+ root: pathlib.Path | str,
388
+ *,
389
+ framework: str,
390
+ durability_enabled: bool = False,
391
+ ) -> "AgentProject":
362
392
  if framework not in _SUPPORTED_FRAMEWORKS:
363
393
  raise AgentCliError(f"Unsupported Mason framework {framework!r}.")
364
394
  project_root = pathlib.Path(root).expanduser().resolve()
@@ -368,7 +398,29 @@ class AgentProject:
368
398
  agent = tomlkit.table()
369
399
  agent.add("framework", framework)
370
400
  document.add("agent", agent)
371
- return cls(project_root, document, framework, [])
401
+ if durability_enabled:
402
+ durability = tomlkit.table()
403
+ durability.add("enabled", True)
404
+ document.add(_DURABILITY_TABLE, durability)
405
+ return cls(
406
+ project_root,
407
+ document,
408
+ framework,
409
+ [],
410
+ durability_enabled=durability_enabled,
411
+ )
412
+
413
+ def set_deployment_name(self, name: str) -> bool:
414
+ """Record the deployment's base name under [agent].deployment_name. True if it changed."""
415
+ name = _required_string(name, "[agent] deployment_name")
416
+ if self.deployment_name == name:
417
+ return False
418
+ agent = self._document.get("agent")
419
+ if not isinstance(agent, Mapping):
420
+ raise AgentCliError("agent.toml must declare an [agent] table.")
421
+ agent["deployment_name"] = name
422
+ self.deployment_name = name
423
+ return True
372
424
 
373
425
  def add_tool(self, spec: ToolSpec) -> bool:
374
426
  for existing in self.tools: