databricks-agent-notebooks 0.2.2__tar.gz → 0.3.0__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.
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/PKG-INFO +1 -1
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/pyproject.toml +7 -1
- databricks_agent_notebooks-0.3.0/src/databricks_agent_notebooks/__init__.py +10 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/cli.py +5 -26
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/execution/executor.py +26 -18
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/README.md +179 -55
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/agent_doctor.md +53 -28
- databricks_agent_notebooks-0.3.0/src/databricks_agent_notebooks/for_agents/scripts/agent-nb-run.sh +122 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/connect.py +27 -2
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks.egg-info/PKG-INFO +1 -1
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks.egg-info/SOURCES.txt +1 -0
- databricks_agent_notebooks-0.2.2/src/databricks_agent_notebooks/__init__.py +0 -5
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/LICENSE +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/README.md +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/setup.cfg +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/__main__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/_constants.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/config/__init__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/config/frontmatter.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/execution/__init__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/execution/injection.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/execution/lineage.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/execution/rendering.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/examples/scala/package_cells_scaffold.md +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/examples/scala/src/api/implementation/Api.scala +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/examples/scala/src/api/stable/Api.scala +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/examples/smoke/python_select_one.md +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/examples/smoke/scala_select_one.md +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/package_cell_instructions.md +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/for_agents/scala_development.md +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/formats/__init__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/formats/conversion.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/formats/dbr_source.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/integrations/__init__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/integrations/databricks/__init__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/integrations/databricks/clusters.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/__init__.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/doctor.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/home.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/inventory.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/kernel.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/launcher.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/manifest.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks/runtime/scala_connect.py +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks.egg-info/dependency_links.txt +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks.egg-info/entry_points.txt +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks.egg-info/requires.txt +0 -0
- {databricks_agent_notebooks-0.2.2 → databricks_agent_notebooks-0.3.0}/src/databricks_agent_notebooks.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "databricks-agent-notebooks"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Standalone notebook conversion and local runtime tooling for the databricks-agent-notebooks repository."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -52,6 +52,12 @@ agent-notebook = "databricks_agent_notebooks.cli:main"
|
|
|
52
52
|
testpaths = ["tests"]
|
|
53
53
|
addopts = "-q"
|
|
54
54
|
pythonpath = ["src"]
|
|
55
|
+
markers = [
|
|
56
|
+
"integration: Fast integration tests (CLI smoke, no side effects)",
|
|
57
|
+
"slow: Slow tests (kernel downloads, package installs, real execution)",
|
|
58
|
+
"spark: Tests requiring local PySpark installation",
|
|
59
|
+
"databricks: Tests requiring live Databricks workspace credentials",
|
|
60
|
+
]
|
|
55
61
|
|
|
56
62
|
[tool.setuptools]
|
|
57
63
|
package-dir = { "" = "src" }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Standalone Databricks notebook conversion and execution tooling."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("databricks-agent-notebooks")
|
|
7
|
+
except PackageNotFoundError:
|
|
8
|
+
__version__ = "0.0.0-dev"
|
|
9
|
+
|
|
10
|
+
__all__ = ["__version__"]
|
|
@@ -15,6 +15,7 @@ import tempfile
|
|
|
15
15
|
from importlib import resources
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
|
+
from databricks_agent_notebooks import __version__
|
|
18
19
|
from databricks_agent_notebooks.config.frontmatter import DatabricksConfig, merge_config
|
|
19
20
|
from databricks_agent_notebooks.execution.executor import RawProgressValue, emit_progress_signal, execute_notebook
|
|
20
21
|
from databricks_agent_notebooks.execution.injection import inject_cells
|
|
@@ -75,6 +76,10 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
75
76
|
epilog=_agent_docs_epilog(),
|
|
76
77
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
77
78
|
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--version", action="version",
|
|
81
|
+
version=f"%(prog)s {__version__}",
|
|
82
|
+
)
|
|
78
83
|
subparsers = parser.add_subparsers(dest="command")
|
|
79
84
|
|
|
80
85
|
# -- run --
|
|
@@ -565,18 +570,6 @@ def _print_doctor_checks(checks: list[Check]) -> list[Check]:
|
|
|
565
570
|
return [check for check in checks if check.status == "fail"]
|
|
566
571
|
|
|
567
572
|
|
|
568
|
-
def _cmd_kernels_doctor(args: argparse.Namespace) -> int:
|
|
569
|
-
"""Run environment validation checks."""
|
|
570
|
-
checks = _run_kernels_doctor_checks(args)
|
|
571
|
-
failures = _print_doctor_checks(checks)
|
|
572
|
-
if failures:
|
|
573
|
-
print(f"\n{len(failures)} check(s) failed.", file=sys.stderr)
|
|
574
|
-
return 1
|
|
575
|
-
|
|
576
|
-
print("\nAll checks passed.")
|
|
577
|
-
return 0
|
|
578
|
-
|
|
579
|
-
|
|
580
573
|
def _cmd_kernels(args: argparse.Namespace) -> int:
|
|
581
574
|
handler = _KERNEL_HANDLERS.get(args.kernels_command)
|
|
582
575
|
if handler is None:
|
|
@@ -601,18 +594,6 @@ def _cmd_runtimes_list(_args: argparse.Namespace) -> int:
|
|
|
601
594
|
return 0
|
|
602
595
|
|
|
603
596
|
|
|
604
|
-
def _cmd_runtimes_doctor(_args: argparse.Namespace) -> int:
|
|
605
|
-
"""Validate managed runtime receipts rooted under runtime-home."""
|
|
606
|
-
checks = _run_runtimes_doctor_checks()
|
|
607
|
-
failures = _print_doctor_checks(checks)
|
|
608
|
-
if failures:
|
|
609
|
-
print(f"\n{len(failures)} check(s) failed.", file=sys.stderr)
|
|
610
|
-
return 1
|
|
611
|
-
|
|
612
|
-
print("\nAll checks passed.")
|
|
613
|
-
return 0
|
|
614
|
-
|
|
615
|
-
|
|
616
597
|
def _cmd_runtimes(args: argparse.Namespace) -> int:
|
|
617
598
|
handler = _RUNTIME_HANDLERS.get(args.runtimes_command)
|
|
618
599
|
if handler is None:
|
|
@@ -640,12 +621,10 @@ _KERNEL_HANDLERS = {
|
|
|
640
621
|
"install": _cmd_kernels_install,
|
|
641
622
|
"list": _cmd_kernels_list,
|
|
642
623
|
"remove": _cmd_kernels_remove,
|
|
643
|
-
"doctor": _cmd_kernels_doctor,
|
|
644
624
|
}
|
|
645
625
|
|
|
646
626
|
_RUNTIME_HANDLERS = {
|
|
647
627
|
"list": _cmd_runtimes_list,
|
|
648
|
-
"doctor": _cmd_runtimes_doctor,
|
|
649
628
|
}
|
|
650
629
|
|
|
651
630
|
|
|
@@ -33,8 +33,7 @@ except ModuleNotFoundError: # pragma: no cover - exercised via packaging verifi
|
|
|
33
33
|
install_ipykernel = None
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
HEARTBEAT_INTERVAL_SECONDS =
|
|
37
|
-
REDACTED_CELL_SNIPPET = "[source redacted]"
|
|
36
|
+
HEARTBEAT_INTERVAL_SECONDS = 60.0
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
class RawProgressValue(str):
|
|
@@ -133,18 +132,11 @@ def _build_cell_label(cell: nbformat.NotebookNode, lines: list[str]) -> str:
|
|
|
133
132
|
return f"[{cell_type} cell]"
|
|
134
133
|
|
|
135
134
|
|
|
136
|
-
def _build_cell_snippet(_cell: nbformat.NotebookNode, lines: list[str]) -> str:
|
|
137
|
-
if not lines:
|
|
138
|
-
return "[empty cell]"
|
|
139
|
-
return REDACTED_CELL_SNIPPET
|
|
140
|
-
|
|
141
|
-
|
|
142
135
|
def _describe_cell(cell: nbformat.NotebookNode, *, cell_index: int) -> dict[str, object]:
|
|
143
136
|
lines = _iter_meaningful_lines(cell.source)
|
|
144
137
|
return {
|
|
145
138
|
"cell_index": cell_index + 1,
|
|
146
139
|
"cell_label": _build_cell_label(cell, lines),
|
|
147
|
-
"cell_snippet": _build_cell_snippet(cell, lines),
|
|
148
140
|
}
|
|
149
141
|
|
|
150
142
|
|
|
@@ -366,7 +358,7 @@ def _execute_notebook_subprocess(
|
|
|
366
358
|
result_path = Path(result_file.name)
|
|
367
359
|
|
|
368
360
|
try:
|
|
369
|
-
|
|
361
|
+
process = subprocess.Popen(
|
|
370
362
|
_subprocess_command(
|
|
371
363
|
python_executable=python_executable,
|
|
372
364
|
notebook_path=notebook_path,
|
|
@@ -376,14 +368,30 @@ def _execute_notebook_subprocess(
|
|
|
376
368
|
timeout=timeout,
|
|
377
369
|
allow_errors=allow_errors,
|
|
378
370
|
),
|
|
379
|
-
|
|
371
|
+
stdout=subprocess.PIPE,
|
|
372
|
+
stderr=subprocess.PIPE,
|
|
380
373
|
text=True,
|
|
381
|
-
check=False,
|
|
382
374
|
)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
375
|
+
|
|
376
|
+
stderr_lines: list[str] = []
|
|
377
|
+
|
|
378
|
+
def _stream_stderr() -> None:
|
|
379
|
+
assert process.stderr is not None
|
|
380
|
+
for line in process.stderr:
|
|
381
|
+
print(line, end="", file=sys.stderr, flush=True)
|
|
382
|
+
stderr_lines.append(line)
|
|
383
|
+
|
|
384
|
+
stderr_thread = threading.Thread(target=_stream_stderr, daemon=True)
|
|
385
|
+
stderr_thread.start()
|
|
386
|
+
|
|
387
|
+
stdout_text = process.stdout.read() if process.stdout else ""
|
|
388
|
+
process.wait()
|
|
389
|
+
stderr_thread.join()
|
|
390
|
+
|
|
391
|
+
if stdout_text:
|
|
392
|
+
print(stdout_text, end="", file=sys.stdout)
|
|
393
|
+
|
|
394
|
+
stderr_text = "".join(stderr_lines).strip()
|
|
387
395
|
|
|
388
396
|
if result_path.is_file():
|
|
389
397
|
payload = json.loads(result_path.read_text(encoding="utf-8"))
|
|
@@ -399,7 +407,7 @@ def _execute_notebook_subprocess(
|
|
|
399
407
|
success=False,
|
|
400
408
|
output_path=output_path,
|
|
401
409
|
duration_seconds=time.monotonic() - start,
|
|
402
|
-
error=
|
|
410
|
+
error=stderr_text or f"Managed runtime execution failed with exit code {process.returncode}",
|
|
403
411
|
)
|
|
404
412
|
finally:
|
|
405
413
|
result_path.unlink(missing_ok=True)
|
|
@@ -417,7 +425,7 @@ def execute_notebook(
|
|
|
417
425
|
if output_path is None:
|
|
418
426
|
output_path = notebook_path.with_suffix(".executed.ipynb")
|
|
419
427
|
|
|
420
|
-
if python_executable is not None and python_executable.resolve() !=
|
|
428
|
+
if python_executable is not None and str(python_executable.resolve().parent.parent) != sys.prefix:
|
|
421
429
|
return _execute_notebook_subprocess(
|
|
422
430
|
notebook_path,
|
|
423
431
|
output_path=output_path,
|
|
@@ -20,9 +20,8 @@ Usually safe in a sandbox:
|
|
|
20
20
|
|
|
21
21
|
- `agent-notebook help`
|
|
22
22
|
- `agent-notebook render ...`
|
|
23
|
-
- `agent-notebook
|
|
23
|
+
- `agent-notebook doctor`
|
|
24
24
|
- `agent-notebook runtimes list`
|
|
25
|
-
- `agent-notebook runtimes doctor`
|
|
26
25
|
|
|
27
26
|
Usually safe only when outbound artifact downloads are allowed:
|
|
28
27
|
|
|
@@ -63,9 +62,17 @@ agent-notebook run notebook.md --profile prod --cluster 0123-456789-abcdef
|
|
|
63
62
|
agent-notebook run notebook.md --profile prod --cluster my-cluster
|
|
64
63
|
```
|
|
65
64
|
|
|
66
|
-
If the `run` command cannot resolve a cluster name, its error message will
|
|
65
|
+
If the `run` command cannot resolve a cluster name, its error message will
|
|
67
66
|
include helpful fuzzy matches for clusters you can present to the user.
|
|
68
67
|
|
|
68
|
+
On large workspaces with many clusters, the 30-second cluster-listing timeout
|
|
69
|
+
may expire before an exact match is found. When this happens, `agent-notebook`
|
|
70
|
+
returns fuzzy name suggestions based on partial results received before the
|
|
71
|
+
timeout. Inspect these suggestions — the full cluster name (e.g.,
|
|
72
|
+
`"rnd-alpha [engineering]"` instead of `"rnd-alpha"`) usually resolves the
|
|
73
|
+
issue. Passing a cluster ID is the deterministic path for cluster-based
|
|
74
|
+
execution and is never subject to timeouts.
|
|
75
|
+
|
|
69
76
|
The only time `agent-notebook clusters` is appropriate is during the initial
|
|
70
77
|
`agent_doctor.md` readiness flow to verify live Databricks connectivity. Once
|
|
71
78
|
you know the cluster name, pass it to `--cluster` and move on.
|
|
@@ -81,6 +88,8 @@ Recommended agent policy:
|
|
|
81
88
|
- run only the Databricks-facing command outside the sandbox when needed
|
|
82
89
|
- if sandboxed notebook startup fails around IPython or Jupyter runtime state,
|
|
83
90
|
check whether the sandbox needs write access to `~/.ipython`
|
|
91
|
+
- for Scala notebooks, the Almond kernel requires write access to
|
|
92
|
+
`~/Library/Caches/Almond/` on macOS
|
|
84
93
|
|
|
85
94
|
## Progress model
|
|
86
95
|
|
|
@@ -98,43 +107,126 @@ Current progress model:
|
|
|
98
107
|
|
|
99
108
|
## Timeouts
|
|
100
109
|
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
### Notebook cell timeout (`--timeout`)
|
|
111
|
+
|
|
112
|
+
Only set `--timeout` if you have a high-confidence real upper bound for the cell
|
|
113
|
+
or notebook you are running. Otherwise, you risk losing valuable work due to
|
|
114
|
+
factors you cannot control: cluster startup/resizing, node availability, task
|
|
115
|
+
failure and re-execution, resource contention from other jobs.
|
|
116
|
+
|
|
117
|
+
`--timeout` is per-cell, not per-notebook.
|
|
118
|
+
|
|
119
|
+
### Agent environment timeout
|
|
103
120
|
|
|
104
|
-
|
|
105
|
-
|
|
121
|
+
Your agent environment's shell tool has its own timeout — the maximum duration a
|
|
122
|
+
single foreground command can run before being killed. In Claude Code, this is
|
|
123
|
+
600 seconds (10 minutes). If a foreground `agent-notebook run` exceeds this
|
|
124
|
+
ceiling, the process is killed and the work is lost.
|
|
125
|
+
|
|
126
|
+
This is why long-running execution patterns (below) default to non-blocking: they
|
|
127
|
+
decouple the notebook run from the shell tool's timeout.
|
|
106
128
|
|
|
107
129
|
## Long-running runs
|
|
108
130
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
Unless you have a concrete reason to expect a short run (e.g., a familiar
|
|
132
|
+
serverless smoke notebook you have run before), treat every notebook run as
|
|
133
|
+
potentially long. Cluster startup, serverless warmup, queueing, autoscaling,
|
|
134
|
+
dependency setup, and shared compute contention can all stretch runtimes
|
|
135
|
+
unpredictably.
|
|
136
|
+
|
|
137
|
+
### Execution helper script
|
|
138
|
+
|
|
139
|
+
A parameterizable wrapper script ships with this package at
|
|
140
|
+
`for_agents/scripts/agent-nb-run.sh`. It handles path computation (log path,
|
|
141
|
+
rendered output path, stem), output directory creation, early validation, and
|
|
142
|
+
tee-to-log — so you do not need to reconstruct these details from examples.
|
|
143
|
+
|
|
144
|
+
Use it as the command in any of the patterns below. It forwards all arguments to
|
|
145
|
+
`agent-notebook run` unchanged.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
agent-nb-run.sh <notebook> --profile <profile> [--output-dir <dir>] [--cluster <name>] [--format md] [...]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Quick reference: which pattern to use
|
|
152
|
+
|
|
153
|
+
| Environment | Default pattern | Use foreground only when |
|
|
154
|
+
|-------------|----------------|------------------------|
|
|
155
|
+
| Claude Code | `run_in_background` | You know the run will finish in under 5 minutes |
|
|
156
|
+
| Codex | PTY session | N/A — PTY has no fixed timeout |
|
|
157
|
+
| Standard shell | `nohup` detached | You will wait interactively |
|
|
158
|
+
|
|
159
|
+
### Claude Code
|
|
160
|
+
|
|
161
|
+
Two non-blocking patterns, in preference order.
|
|
162
|
+
|
|
163
|
+
**Pattern 1: `run_in_background` (preferred)**
|
|
164
|
+
|
|
165
|
+
Non-blocking — the session stays interactive and Claude Code notifies on
|
|
166
|
+
completion. No fixed timeout ceiling; the run continues until it finishes.
|
|
167
|
+
|
|
168
|
+
Use the Bash tool with `run_in_background: true`:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Use with Bash tool parameter: run_in_background: true
|
|
172
|
+
agent-nb-run.sh path/to/notebook.md \
|
|
173
|
+
--profile <profile> \
|
|
174
|
+
--format md \
|
|
175
|
+
--output-dir tmp/run-output
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The script emits the log path and output directory to stderr at startup. Read the
|
|
179
|
+
log file to check progress while the run is active.
|
|
180
|
+
|
|
181
|
+
**Pattern 2: `nohup` detached**
|
|
182
|
+
|
|
183
|
+
Best for fire-and-forget — runs survive session termination. Useful when
|
|
184
|
+
operating as a sub-agent or in a short-lived session.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
nohup agent-nb-run.sh path/to/notebook.md \
|
|
188
|
+
--profile <profile> \
|
|
189
|
+
--format md \
|
|
190
|
+
--output-dir tmp/run-output \
|
|
191
|
+
> /dev/null 2>&1 &
|
|
192
|
+
echo "PID: $!"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The script tees output to its own log file, so redirecting to `/dev/null` is
|
|
196
|
+
safe — nothing is lost.
|
|
197
|
+
|
|
198
|
+
**Note on foreground:** Foreground execution blocks the session and is subject to
|
|
199
|
+
the 10-minute timeout ceiling. Only use foreground when you have strong
|
|
200
|
+
confidence the run will finish in under 5 minutes (e.g., a known-quick
|
|
201
|
+
serverless smoke notebook you have run before).
|
|
112
202
|
|
|
113
|
-
|
|
203
|
+
### Codex
|
|
114
204
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- use a detached pattern when cluster startup, serverless warmup, autoscaling,
|
|
118
|
-
queueing, dependency setup, or shared-compute contention could materially
|
|
119
|
-
stretch runtime
|
|
120
|
-
- skip detaching only when you have a concrete reason to expect a short run
|
|
205
|
+
`nohup` detachment is unreliable in Codex — background processes may be killed
|
|
206
|
+
after the tool call returns. Use a persistent PTY session instead.
|
|
121
207
|
|
|
122
|
-
|
|
208
|
+
Start the command in a PTY session (`tty: true`), then poll with empty
|
|
209
|
+
`write_stdin` calls to check progress:
|
|
123
210
|
|
|
124
211
|
```bash
|
|
125
|
-
|
|
126
|
-
OUTPUT_DIR=tmp/run-output
|
|
127
|
-
STEM="$(basename "$NOTEBOOK")"
|
|
128
|
-
STEM="${STEM%.*}"
|
|
129
|
-
LOG_PATH="$OUTPUT_DIR/$STEM.run.log"
|
|
130
|
-
RENDER_PATH="$OUTPUT_DIR/$STEM.executed.md"
|
|
131
|
-
|
|
132
|
-
mkdir -p "$OUTPUT_DIR"
|
|
133
|
-
nohup agent-notebook run "$NOTEBOOK" \
|
|
212
|
+
agent-nb-run.sh path/to/notebook.md \
|
|
134
213
|
--profile <profile> \
|
|
135
214
|
--format md \
|
|
136
|
-
--output-dir
|
|
137
|
-
|
|
215
|
+
--output-dir tmp/run-output
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The PTY session has no fixed timeout — the command runs until completion.
|
|
219
|
+
|
|
220
|
+
### Standard shell / non-agent environments
|
|
221
|
+
|
|
222
|
+
Use the `nohup` detached pattern:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
nohup agent-nb-run.sh path/to/notebook.md \
|
|
226
|
+
--profile <profile> \
|
|
227
|
+
--format md \
|
|
228
|
+
--output-dir tmp/run-output \
|
|
229
|
+
> /dev/null 2>&1 &
|
|
138
230
|
echo "PID: $!"
|
|
139
231
|
```
|
|
140
232
|
|
|
@@ -142,25 +234,19 @@ Add `--cluster <cluster-name-or-id>` when the user context requires cluster
|
|
|
142
234
|
compute. The name is auto-resolved to a cluster ID — do not call
|
|
143
235
|
`agent-notebook clusters` first.
|
|
144
236
|
|
|
145
|
-
|
|
146
|
-
a shared `run.log`. That avoids collisions when multiple detached runs write
|
|
147
|
-
into the same output directory.
|
|
148
|
-
|
|
149
|
-
Those variable names are illustrative, not required. If you use a different
|
|
150
|
-
pattern, keep the same idea: compute the log path and rendered-output path once,
|
|
151
|
-
then reuse those exact paths when you poll status later.
|
|
237
|
+
### Monitoring (all environments)
|
|
152
238
|
|
|
153
|
-
|
|
239
|
+
After launching a non-blocking run, use these to check status:
|
|
154
240
|
|
|
155
|
-
-
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
241
|
+
- **Process liveness:** `ps -p <pid> -o pid=,command=` or
|
|
242
|
+
`pgrep -lf "agent-notebook run"` (macOS) /
|
|
243
|
+
`pgrep -af "agent-notebook run"` (Linux)
|
|
244
|
+
- **Progress:** `tail -f <log-path>` (the execution helper reports the log path
|
|
245
|
+
at startup)
|
|
246
|
+
- **Completion:** the rendered output file (e.g., `<stem>.executed.md`) appears
|
|
247
|
+
in the output directory when the run finishes successfully
|
|
248
|
+
- **Side effects:** if earlier cells have already written durable side effects
|
|
249
|
+
elsewhere, you can often inspect those while the notebook is still running
|
|
164
250
|
|
|
165
251
|
### Intermediate progress monitoring
|
|
166
252
|
|
|
@@ -267,23 +353,61 @@ The packaged examples live under `examples/` beside these docs. They are small
|
|
|
267
353
|
reference artifacts you can reuse directly instead of recreating notebooks or
|
|
268
354
|
pattern files from memory.
|
|
269
355
|
|
|
270
|
-
##
|
|
356
|
+
## Detecting the Databricks environment
|
|
357
|
+
|
|
358
|
+
Code running on Databricks sometimes needs to detect that it is on Databricks
|
|
359
|
+
rather than a local Spark session. The reliable approach — working on both
|
|
360
|
+
clusters and serverless — is to check for the presence of any Spark session
|
|
361
|
+
configuration key containing `.databricks.`:
|
|
362
|
+
|
|
363
|
+
**Python:**
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
is_databricks = any(".databricks." in k for k in spark.conf.getAll.keys())
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Scala:**
|
|
271
370
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
371
|
+
```scala
|
|
372
|
+
val isDatabricks = spark.conf.getAll.keys.exists(_.contains(".databricks."))
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Persistence and version checking
|
|
376
|
+
|
|
377
|
+
You MUST persist key facts about `agent-notebook` to your memory system. The
|
|
378
|
+
specific items to persist are listed in `agent_doctor.md` step 2 (local
|
|
275
379
|
knowledge) and step 6 (Databricks-specific context) — both provide fill-in
|
|
276
380
|
templates.
|
|
277
381
|
|
|
382
|
+
If you already have `agent-notebook` in memory or instructions, run
|
|
383
|
+
`agent-notebook --version` and compare against your stored version. If versions
|
|
384
|
+
differ, re-run the agent_doctor flow to refresh. Check both your memory system
|
|
385
|
+
and any persistent instructions (CLAUDE.md, AGENTS.md, etc.) — stale
|
|
386
|
+
instructions are as problematic as stale memory.
|
|
387
|
+
|
|
388
|
+
In a non-interactive session where you cannot prompt the user, refresh local
|
|
389
|
+
knowledge (doctor steps 1-2) and skip steps that require user input (workspace
|
|
390
|
+
selection, smoke tests).
|
|
391
|
+
|
|
278
392
|
This is not optional. Reading and summarizing is not sufficient — your session
|
|
279
|
-
knowledge is ephemeral. If you do not persist, the next session will
|
|
280
|
-
|
|
393
|
+
knowledge is ephemeral. If you do not persist, the next session will repeat
|
|
394
|
+
this entire discovery process from scratch, wasting the user's time.
|
|
281
395
|
|
|
282
396
|
## DECISION REQUIRED: agent doctor
|
|
283
397
|
|
|
284
|
-
|
|
398
|
+
Check your memory system and persistent instructions for `agent-notebook`
|
|
399
|
+
context. Then:
|
|
400
|
+
|
|
401
|
+
1. **No stored context:** this is your first encounter — you MUST continue
|
|
402
|
+
reading `agent_doctor.md`
|
|
403
|
+
2. **Stored context exists:** run `agent-notebook --version` and compare against
|
|
404
|
+
your stored version. If versions differ, or stored paths no longer exist,
|
|
405
|
+
continue reading `agent_doctor.md` to refresh
|
|
406
|
+
3. **Version matches and paths exist:** you are current — skip the doctor
|
|
285
407
|
|
|
286
|
-
|
|
287
|
-
|
|
408
|
+
When continuing to `agent_doctor.md`:
|
|
409
|
+
- In an interactive session, complete the full flow
|
|
410
|
+
- In a non-interactive session, complete steps 1-2 (local checks and persistence
|
|
411
|
+
refresh) and skip steps that require user input
|
|
288
412
|
- DO NOT stop to complete the conversation turn
|
|
289
413
|
- DO NOT return to the user with a summary of this README
|
|
@@ -33,17 +33,32 @@ Interpretation:
|
|
|
33
33
|
|
|
34
34
|
## 2. Persist local knowledge
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
If the README version check (above) already confirmed your stored version
|
|
37
|
+
matches the installed version and stored paths exist, skip to step 3.
|
|
38
|
+
|
|
39
|
+
Otherwise — whether this is a fresh install, a version mismatch, or missing
|
|
40
|
+
memory — persist using the template below.
|
|
41
|
+
|
|
42
|
+
The template below is the authoritative schema. Your stored memory and
|
|
43
|
+
instructions are a cache. If you have existing agent-notebook context, compare
|
|
44
|
+
each field below against your stored values: update changed values, add fields
|
|
45
|
+
present here but missing, and remove fields you have that this template no
|
|
46
|
+
longer includes. Check both your memory system and any persistent instructions
|
|
47
|
+
(CLAUDE.md, AGENTS.md, etc.) — stale instructions are as problematic as stale
|
|
48
|
+
memory.
|
|
49
|
+
|
|
50
|
+
Do this NOW, before proceeding to Databricks probes — those may require user
|
|
51
|
+
input, and agents frequently stop at interaction gates without persisting.
|
|
39
52
|
|
|
40
53
|
Save a memory containing at minimum:
|
|
41
54
|
|
|
42
55
|
- **Tool:** `agent-notebook` at `<which agent-notebook path>`
|
|
56
|
+
- **Version:** `<output of agent-notebook --version>`
|
|
43
57
|
- **Agent docs:** `<this directory's absolute path>`
|
|
58
|
+
- **Execution helper:** `<absolute path to for_agents/scripts/agent-nb-run.sh>`
|
|
44
59
|
- **Local readiness:** doctor check pass/fail per check, versions discovered (runtimes, kernel, Java)
|
|
45
60
|
- **Scala support:** both cluster-backed and serverless; serverless defaults to Scala 2.13
|
|
46
|
-
- **Operational pattern:**
|
|
61
|
+
- **Operational pattern:** non-blocking execution for cluster-targeted runs (see README for environment-specific pattern)
|
|
47
62
|
|
|
48
63
|
Then proceed to step 3.
|
|
49
64
|
|
|
@@ -76,6 +91,12 @@ Interpretation:
|
|
|
76
91
|
uses a 30-second cluster-listing timeout budget rather than waiting
|
|
77
92
|
indefinitely for a slow workspace response. Note that listing clusters in
|
|
78
93
|
large workspaces can generate more than a gigabyte of output.
|
|
94
|
+
- On large workspaces, the 30-second timeout may expire before an exact cluster
|
|
95
|
+
name match is found during `run --cluster <name>`. When this happens, the
|
|
96
|
+
tool returns fuzzy name suggestions from partial results. Inspect these
|
|
97
|
+
suggestions — the full cluster name (e.g., `"rnd-alpha [engineering]"` instead
|
|
98
|
+
of `"rnd-alpha"`) usually resolves the issue. Passing a cluster ID instead of
|
|
99
|
+
a name is the deterministic path and is never subject to timeouts.
|
|
79
100
|
- If networking or certificate failures appear only inside the agent sandbox,
|
|
80
101
|
notify the user that the command likely needs a narrower unsandboxed path.
|
|
81
102
|
|
|
@@ -110,10 +131,13 @@ language, so you do not need to create new `.py` or `.scala` files first.
|
|
|
110
131
|
|
|
111
132
|
### Serverless Python
|
|
112
133
|
|
|
113
|
-
This is the default Python smoke path because serverless should usually start
|
|
134
|
+
This is the default Python smoke path because serverless should usually start
|
|
135
|
+
quickly and have available resources for a quick notebook. If this is your first
|
|
136
|
+
run or you are unsure of timing, use the long-running pattern from the README
|
|
137
|
+
instead of foreground.
|
|
114
138
|
|
|
115
139
|
```bash
|
|
116
|
-
agent-
|
|
140
|
+
agent-nb-run.sh <installed-for_agents>/examples/smoke/python_select_one.md \
|
|
117
141
|
--profile <profile> \
|
|
118
142
|
--output-dir <writable-output-root> \
|
|
119
143
|
--format md
|
|
@@ -121,45 +145,46 @@ agent-notebook run <installed-for_agents>/examples/smoke/python_select_one.md \
|
|
|
121
145
|
|
|
122
146
|
### Cluster-targeted Python
|
|
123
147
|
|
|
124
|
-
If the user requested cluster-targeted Python execution in step 4, use a
|
|
148
|
+
If the user requested cluster-targeted Python execution in step 4, use a
|
|
149
|
+
non-blocking run. Cluster startup can add minutes — always use your
|
|
150
|
+
environment's long-running pattern (see the README "Long-running runs" section).
|
|
125
151
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
STEM="$(basename "$NOTEBOOK")"
|
|
130
|
-
STEM="${STEM%.*}"
|
|
152
|
+
Use the execution helper script (`for_agents/scripts/agent-nb-run.sh`) with your
|
|
153
|
+
environment's non-blocking pattern. Example using `nohup` (Claude Code, standard
|
|
154
|
+
shells):
|
|
131
155
|
|
|
132
|
-
|
|
133
|
-
nohup agent-
|
|
156
|
+
```bash
|
|
157
|
+
nohup agent-nb-run.sh \
|
|
158
|
+
<installed-for_agents>/examples/smoke/python_select_one.md \
|
|
134
159
|
--profile <profile> \
|
|
135
160
|
--cluster <cluster-name-or-id-from-strong-context-or-user> \
|
|
136
|
-
--output-dir
|
|
161
|
+
--output-dir <writable-output-root> \
|
|
137
162
|
--format md \
|
|
138
|
-
>
|
|
163
|
+
> /dev/null 2>&1 &
|
|
139
164
|
echo "PID: $!"
|
|
140
165
|
```
|
|
141
166
|
|
|
167
|
+
For Claude Code, `run_in_background: true` is preferred over `nohup`. For Codex,
|
|
168
|
+
use a PTY session instead — `nohup` is unreliable in Codex.
|
|
169
|
+
|
|
142
170
|
### Scala
|
|
143
171
|
|
|
144
|
-
If the user confirmed Scala notebook work in step 4, verify Scala execution
|
|
172
|
+
If the user confirmed Scala notebook work in step 4, verify Scala execution
|
|
173
|
+
using the same non-blocking pattern as cluster-targeted Python:
|
|
145
174
|
|
|
146
175
|
```bash
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
STEM="$(basename "$NOTEBOOK")"
|
|
150
|
-
STEM="${STEM%.*}"
|
|
151
|
-
|
|
152
|
-
mkdir -p "$OUTPUT_DIR"
|
|
153
|
-
nohup agent-notebook run "$NOTEBOOK" \
|
|
176
|
+
nohup agent-nb-run.sh \
|
|
177
|
+
<installed-for_agents>/examples/smoke/scala_select_one.md \
|
|
154
178
|
--profile <profile> \
|
|
155
179
|
--cluster <cluster-name-or-id-from-strong-context-or-user> \
|
|
156
|
-
--
|
|
157
|
-
--output-dir "$OUTPUT_DIR" \
|
|
180
|
+
--output-dir <writable-output-root> \
|
|
158
181
|
--format md \
|
|
159
|
-
>
|
|
182
|
+
> /dev/null 2>&1 &
|
|
160
183
|
echo "PID: $!"
|
|
161
184
|
```
|
|
162
185
|
|
|
186
|
+
For Claude Code, use `run_in_background: true`. For Codex, use a PTY session.
|
|
187
|
+
|
|
163
188
|
### Rules
|
|
164
189
|
|
|
165
190
|
- DO NOT modify the installed example notebooks!
|
|
@@ -174,7 +199,7 @@ Update your earlier memory to include:
|
|
|
174
199
|
|
|
175
200
|
- **Profiles verified:** `<list profiles that passed smoke test>`
|
|
176
201
|
- **Default compute:** `<serverless if available, else cluster name/id>`
|
|
177
|
-
- **
|
|
202
|
+
- **Non-blocking execution needed:** `<default yes; only skip for runs with predictably short duration such as known-quick serverless smoke notebooks or lightweight metadata queries>`
|
|
178
203
|
- **Workspace constraints:** `<any discovered limitations>`
|
|
179
204
|
- **Cluster name resolution:** cluster names can be passed directly to `--cluster`
|
|
180
205
|
without calling `agent-notebook clusters` first — the `run` command auto-resolves names
|
databricks_agent_notebooks-0.3.0/src/databricks_agent_notebooks/for_agents/scripts/agent-nb-run.sh
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# agent-nb-run.sh — execution helper for agent-notebook run
|
|
3
|
+
#
|
|
4
|
+
# Handles path computation, output directory creation, early validation,
|
|
5
|
+
# and tee-to-log so agents can remember one script path instead of
|
|
6
|
+
# reconstructing commands from documentation.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# agent-nb-run.sh <notebook> --profile <profile> [--output-dir <dir>] [...]
|
|
10
|
+
#
|
|
11
|
+
# All arguments are forwarded to `agent-notebook run`. The script only
|
|
12
|
+
# parses what it needs for its own logic (notebook path, --profile,
|
|
13
|
+
# --output-dir, --format); everything else passes through unchanged.
|
|
14
|
+
#
|
|
15
|
+
# The agent wraps this script in their environment's non-blocking pattern:
|
|
16
|
+
# Claude Code: run_in_background: true
|
|
17
|
+
# nohup: nohup agent-nb-run.sh ... > /dev/null 2>&1 &
|
|
18
|
+
# Codex: start in PTY session (tty: true)
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
die() { echo "agent-nb-run: error: $1" >&2; exit 1; }
|
|
23
|
+
|
|
24
|
+
# --- Parse arguments we need; collect all args for forwarding ---
|
|
25
|
+
|
|
26
|
+
NOTEBOOK=""
|
|
27
|
+
PROFILE_FOUND=false
|
|
28
|
+
OUTPUT_DIR=""
|
|
29
|
+
FORMAT="md"
|
|
30
|
+
|
|
31
|
+
# We need the positional notebook arg and a few flags for our own logic.
|
|
32
|
+
# Everything gets forwarded to agent-notebook run via "$@".
|
|
33
|
+
args=("$@")
|
|
34
|
+
i=0
|
|
35
|
+
while [ $i -lt ${#args[@]} ]; do
|
|
36
|
+
arg="${args[$i]}"
|
|
37
|
+
# Handle --flag=value syntax: split into flag and value
|
|
38
|
+
val=""
|
|
39
|
+
case "$arg" in
|
|
40
|
+
--*=*)
|
|
41
|
+
val="${arg#*=}"
|
|
42
|
+
arg="${arg%%=*}"
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
case "$arg" in
|
|
46
|
+
--profile)
|
|
47
|
+
PROFILE_FOUND=true
|
|
48
|
+
if [ -z "$val" ]; then i=$((i + 1)); fi
|
|
49
|
+
;;
|
|
50
|
+
--output-dir)
|
|
51
|
+
if [ -n "$val" ]; then
|
|
52
|
+
OUTPUT_DIR="$val"
|
|
53
|
+
else
|
|
54
|
+
i=$((i + 1))
|
|
55
|
+
if [ $i -lt ${#args[@]} ]; then
|
|
56
|
+
OUTPUT_DIR="${args[$i]}"
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
;;
|
|
60
|
+
--format)
|
|
61
|
+
if [ -n "$val" ]; then
|
|
62
|
+
FORMAT="$val"
|
|
63
|
+
else
|
|
64
|
+
i=$((i + 1))
|
|
65
|
+
if [ $i -lt ${#args[@]} ]; then
|
|
66
|
+
FORMAT="${args[$i]}"
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
;;
|
|
70
|
+
--cluster|--timeout|--language|--allow-errors|--no-inject-session)
|
|
71
|
+
# Known flags that take a value — skip the value token
|
|
72
|
+
if [ -z "$val" ]; then i=$((i + 1)); fi
|
|
73
|
+
;;
|
|
74
|
+
-*)
|
|
75
|
+
# Unknown flags (forwarded as-is, assumed no value)
|
|
76
|
+
;;
|
|
77
|
+
*)
|
|
78
|
+
# First non-flag argument is the notebook path
|
|
79
|
+
if [ -z "$NOTEBOOK" ]; then
|
|
80
|
+
NOTEBOOK="${args[$i]}"
|
|
81
|
+
fi
|
|
82
|
+
;;
|
|
83
|
+
esac
|
|
84
|
+
i=$((i + 1))
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
# --- Validate early, before any side effects ---
|
|
88
|
+
|
|
89
|
+
[ -n "$NOTEBOOK" ] || die "notebook path is required (first positional argument)"
|
|
90
|
+
[ -f "$NOTEBOOK" ] || die "notebook not found: $NOTEBOOK"
|
|
91
|
+
$PROFILE_FOUND || die "--profile is required"
|
|
92
|
+
|
|
93
|
+
# --- Compute paths ---
|
|
94
|
+
|
|
95
|
+
STEM="$(basename "$NOTEBOOK")"
|
|
96
|
+
STEM="${STEM%.*}"
|
|
97
|
+
|
|
98
|
+
if [ -z "$OUTPUT_DIR" ]; then
|
|
99
|
+
OUTPUT_DIR="tmp/${STEM}-output"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
LOG_PATH="$OUTPUT_DIR/$STEM.run.log"
|
|
103
|
+
|
|
104
|
+
mkdir -p "$OUTPUT_DIR"
|
|
105
|
+
|
|
106
|
+
# --- Emit machine-readable status block ---
|
|
107
|
+
# Written to stderr (visible in agent tool output) and to the log file header.
|
|
108
|
+
|
|
109
|
+
_status() {
|
|
110
|
+
echo "agent-nb-run: $1" >&2
|
|
111
|
+
echo "agent-nb-run: $1" >> "$LOG_PATH"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
: > "$LOG_PATH" # create/truncate log file
|
|
115
|
+
_status "notebook=$NOTEBOOK"
|
|
116
|
+
_status "output-dir=$OUTPUT_DIR"
|
|
117
|
+
_status "log=$LOG_PATH"
|
|
118
|
+
_status "stem=$STEM"
|
|
119
|
+
|
|
120
|
+
# --- Run agent-notebook, tee-ing all output to the log file ---
|
|
121
|
+
|
|
122
|
+
agent-notebook run "$@" 2>&1 | tee -a "$LOG_PATH"
|
|
@@ -26,7 +26,7 @@ _LINE_RE = re.compile(r"(?P<major>\d+)\.(?P<minor>\d+)")
|
|
|
26
26
|
SERVERLESS_CONNECT_OVERRIDE_ENV_VAR = "DATABRICKS_AGENT_NOTEBOOKS_SERVERLESS_CONNECT_LINE"
|
|
27
27
|
SERVERLESS_RUNTIME_CACHE_FILENAME = "serverless-runtime-policy-cache.json"
|
|
28
28
|
_SERVERLESS_RUNTIME_CACHE_VERSION = "1"
|
|
29
|
-
_DEFAULT_SERVERLESS_CONNECT_LINES = ("16.4",
|
|
29
|
+
_DEFAULT_SERVERLESS_CONNECT_LINES = ("16.4",)
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def _normalize_major_minor_line(value: str, *, label: str) -> str:
|
|
@@ -104,9 +104,32 @@ def _runtime_python_executable(install_root: Path) -> Path:
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
def _default_package_install_target() -> list[str]:
|
|
107
|
+
# Development install: editable from source tree
|
|
107
108
|
package_root = Path(__file__).resolve().parents[3]
|
|
108
109
|
if (package_root / "pyproject.toml").is_file():
|
|
109
110
|
return ["-e", str(package_root)]
|
|
111
|
+
|
|
112
|
+
# Global/tool install: find original source via distribution metadata
|
|
113
|
+
try:
|
|
114
|
+
from importlib.metadata import distribution
|
|
115
|
+
dist = distribution("databricks-agent-notebooks")
|
|
116
|
+
direct_url_text = dist.read_text("direct_url.json")
|
|
117
|
+
if direct_url_text:
|
|
118
|
+
url_info = json.loads(direct_url_text)
|
|
119
|
+
url = url_info.get("url", "")
|
|
120
|
+
if url.startswith("file://"):
|
|
121
|
+
source_path = Path(url.removeprefix("file://"))
|
|
122
|
+
if (source_path / "pyproject.toml").is_file():
|
|
123
|
+
return [str(source_path)]
|
|
124
|
+
except Exception:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
if __version__ == "0.0.0-dev":
|
|
128
|
+
raise RuntimeError(
|
|
129
|
+
"Cannot determine a valid install target for databricks-agent-notebooks: "
|
|
130
|
+
"package metadata is unavailable and no source tree was found. "
|
|
131
|
+
"Install the package first ('uv pip install -e .') or set PYTHONPATH to the source tree."
|
|
132
|
+
)
|
|
110
133
|
return [f"databricks-agent-notebooks=={__version__}"]
|
|
111
134
|
|
|
112
135
|
|
|
@@ -266,12 +289,14 @@ def materialize_managed_runtime(
|
|
|
266
289
|
python_executable = _runtime_python_executable(install_root)
|
|
267
290
|
receipt_path = runtime_receipt_path(resolved_home, spec.runtime_id)
|
|
268
291
|
|
|
292
|
+
venv_just_created = False
|
|
269
293
|
if not python_executable.is_file():
|
|
270
294
|
venv_dir = python_executable.parent.parent
|
|
271
295
|
install_root.mkdir(parents=True, exist_ok=True)
|
|
272
296
|
subprocess_run([sys.executable, "-m", "venv", str(venv_dir)], check=True)
|
|
297
|
+
venv_just_created = True
|
|
273
298
|
|
|
274
|
-
if
|
|
299
|
+
if venv_just_created or not receipt_path.is_file():
|
|
275
300
|
subprocess_run([str(python_executable), "-m", "pip", "install", "--upgrade", "pip"], check=True)
|
|
276
301
|
subprocess_run(
|
|
277
302
|
[
|
|
@@ -27,6 +27,7 @@ src/databricks_agent_notebooks/for_agents/examples/scala/src/api/implementation/
|
|
|
27
27
|
src/databricks_agent_notebooks/for_agents/examples/scala/src/api/stable/Api.scala
|
|
28
28
|
src/databricks_agent_notebooks/for_agents/examples/smoke/python_select_one.md
|
|
29
29
|
src/databricks_agent_notebooks/for_agents/examples/smoke/scala_select_one.md
|
|
30
|
+
src/databricks_agent_notebooks/for_agents/scripts/agent-nb-run.sh
|
|
30
31
|
src/databricks_agent_notebooks/formats/__init__.py
|
|
31
32
|
src/databricks_agent_notebooks/formats/conversion.py
|
|
32
33
|
src/databricks_agent_notebooks/formats/dbr_source.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|