databricks-agentbricks 0.2.0__py3-none-any.whl
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_agentbricks/__init__.py +1 -0
- databricks_agentbricks/_group.py +217 -0
- databricks_agentbricks/agent_project.py +657 -0
- databricks_agentbricks/app_resources.py +139 -0
- databricks_agentbricks/cli/__init__.py +12 -0
- databricks_agentbricks/cli/app.py +108 -0
- databricks_agentbricks/cli/app_auth.py +198 -0
- databricks_agentbricks/cli/auth.py +142 -0
- databricks_agentbricks/cli/deploy.py +954 -0
- databricks_agentbricks/cli/dev.py +310 -0
- databricks_agentbricks/cli/endpoint.py +145 -0
- databricks_agentbricks/cli/endpoint_examples.py +33 -0
- databricks_agentbricks/cli/endpoint_output.py +53 -0
- databricks_agentbricks/cli/endpoint_request.py +71 -0
- databricks_agentbricks/cli/endpoint_transport.py +148 -0
- databricks_agentbricks/cli/help.py +467 -0
- databricks_agentbricks/cli/init.py +496 -0
- databricks_agentbricks/cli/mcp.py +75 -0
- databricks_agentbricks/cli/memory.py +520 -0
- databricks_agentbricks/cli/sandbox.py +823 -0
- databricks_agentbricks/cli/sessions.py +588 -0
- databricks_agentbricks/cli/tools.py +456 -0
- databricks_agentbricks/cli/tracing.py +724 -0
- databricks_agentbricks/databricks_cli.py +38 -0
- databricks_agentbricks/errors.py +114 -0
- databricks_agentbricks/lakebase_runtime_store.py +107 -0
- databricks_agentbricks/legacy_lakebase_runtime_store.py +74 -0
- databricks_agentbricks/project_config.py +157 -0
- databricks_agentbricks/project_types.py +55 -0
- databricks_agentbricks/py.typed +0 -0
- databricks_agentbricks/render.py +349 -0
- databricks_agentbricks/templates/agent-bricks-migrate/SKILL.md +101 -0
- databricks_agentbricks/templates/agent-langgraph/.env.example +36 -0
- databricks_agentbricks/templates/agent-langgraph/.gitignore +199 -0
- databricks_agentbricks/templates/agent-langgraph/AGENTKIT_CONTRACT.md +95 -0
- databricks_agentbricks/templates/agent-langgraph/AGENTS.md +31 -0
- databricks_agentbricks/templates/agent-langgraph/CLAUDE.md +1 -0
- databricks_agentbricks/templates/agent-langgraph/README.md +141 -0
- databricks_agentbricks/templates/agent-langgraph/agent/__init__.py +0 -0
- databricks_agentbricks/templates/agent-langgraph/agent/agent.py +177 -0
- databricks_agentbricks/templates/agent-langgraph/agent/mcps.py +27 -0
- databricks_agentbricks/templates/agent-langgraph/agent/tools/__init__.py +24 -0
- databricks_agentbricks/templates/agent-langgraph/agent/tools/sample_tool.py +15 -0
- databricks_agentbricks/templates/agent-langgraph/agent/tools/send_message.py +17 -0
- databricks_agentbricks/templates/agent-langgraph/app.yaml +15 -0
- databricks_agentbricks/templates/agent-langgraph/pyproject.toml +42 -0
- databricks_agentbricks/templates/agent-langgraph/runtime/__init__.py +0 -0
- databricks_agentbricks/templates/agent-langgraph/runtime/adapter.py +144 -0
- databricks_agentbricks/templates/agent-langgraph/runtime/main.py +25 -0
- databricks_agentbricks/templates/agent-langgraph/tests/__init__.py +0 -0
- databricks_agentbricks/templates/agent-langgraph/tests/test_agent.py +211 -0
- databricks_agentbricks/templates/agent-langgraph/tests/test_runtime.py +19 -0
- databricks_agentbricks/templates/agent-langgraph/tests/test_workspace.py +28 -0
- databricks_agentbricks/templates/agent-openai/.env.example +37 -0
- databricks_agentbricks/templates/agent-openai/.gitignore +199 -0
- databricks_agentbricks/templates/agent-openai/AGENTKIT_CONTRACT.md +107 -0
- databricks_agentbricks/templates/agent-openai/AGENTS.md +76 -0
- databricks_agentbricks/templates/agent-openai/CLAUDE.md +1 -0
- databricks_agentbricks/templates/agent-openai/README.md +143 -0
- databricks_agentbricks/templates/agent-openai/agent/__init__.py +0 -0
- databricks_agentbricks/templates/agent-openai/agent/agent.py +205 -0
- databricks_agentbricks/templates/agent-openai/agent/mcps.py +28 -0
- databricks_agentbricks/templates/agent-openai/agent/tools/__init__.py +24 -0
- databricks_agentbricks/templates/agent-openai/agent/tools/sample_tool.py +15 -0
- databricks_agentbricks/templates/agent-openai/agent/tools/send_message.py +18 -0
- databricks_agentbricks/templates/agent-openai/app.yaml +15 -0
- databricks_agentbricks/templates/agent-openai/pyproject.toml +42 -0
- databricks_agentbricks/templates/agent-openai/runtime/__init__.py +0 -0
- databricks_agentbricks/templates/agent-openai/runtime/adapter.py +188 -0
- databricks_agentbricks/templates/agent-openai/runtime/main.py +25 -0
- databricks_agentbricks/templates/agent-openai/tests/__init__.py +0 -0
- databricks_agentbricks/templates/agent-openai/tests/test_agent.py +326 -0
- databricks_agentbricks/templates/agent-openai/tests/test_runtime.py +19 -0
- databricks_agentbricks/templates/agent-openai/tests/test_workspace.py +28 -0
- databricks_agentbricks/templates/custom-agent-langgraph/.env.example +1 -0
- databricks_agentbricks/templates/custom-agent-langgraph/.gitignore +11 -0
- databricks_agentbricks/templates/custom-agent-langgraph/README.md +22 -0
- databricks_agentbricks/templates/custom-agent-langgraph/agent/__init__.py +0 -0
- databricks_agentbricks/templates/custom-agent-langgraph/agent/agent.py +27 -0
- databricks_agentbricks/templates/custom-agent-langgraph/app.yaml +1 -0
- databricks_agentbricks/templates/custom-agent-langgraph/pyproject.toml +38 -0
- databricks_agentbricks/templates/custom-agent-langgraph/runtime/__init__.py +0 -0
- databricks_agentbricks/templates/custom-agent-langgraph/runtime/main.py +31 -0
- databricks_agentbricks/templates/custom-agent-langgraph/tests/test_runtime.py +29 -0
- databricks_agentbricks/templates/custom-agent-openai/.env.example +1 -0
- databricks_agentbricks/templates/custom-agent-openai/.gitignore +11 -0
- databricks_agentbricks/templates/custom-agent-openai/README.md +22 -0
- databricks_agentbricks/templates/custom-agent-openai/agent/__init__.py +0 -0
- databricks_agentbricks/templates/custom-agent-openai/agent/agent.py +29 -0
- databricks_agentbricks/templates/custom-agent-openai/app.yaml +1 -0
- databricks_agentbricks/templates/custom-agent-openai/pyproject.toml +38 -0
- databricks_agentbricks/templates/custom-agent-openai/runtime/__init__.py +0 -0
- databricks_agentbricks/templates/custom-agent-openai/runtime/main.py +31 -0
- databricks_agentbricks/templates/custom-agent-openai/tests/test_runtime.py +29 -0
- databricks_agentbricks/templates/sandbox_mcp.py +39 -0
- databricks_agentbricks/templates/sandbox_mcp_langgraph.py +39 -0
- databricks_agentbricks/templates/ui/agent-langgraph/CHAT_APP.md +49 -0
- databricks_agentbricks/templates/ui/agent-langgraph/runtime/main.py +26 -0
- databricks_agentbricks/templates/ui/agent-langgraph/runtime/ui.py +528 -0
- databricks_agentbricks/templates/ui/agent-langgraph/tests/test_demo_ui.py +542 -0
- databricks_agentbricks/templates/ui/agent-langgraph/ui/agentbricks-mark.png +0 -0
- databricks_agentbricks/templates/ui/agent-langgraph/ui/app.js +1464 -0
- databricks_agentbricks/templates/ui/agent-langgraph/ui/index.html +281 -0
- databricks_agentbricks/templates/ui/agent-langgraph/ui/styles.css +1913 -0
- databricks_agentbricks/templates/ui/agent-openai/CHAT_APP.md +54 -0
- databricks_agentbricks/templates/ui/agent-openai/runtime/main.py +26 -0
- databricks_agentbricks/templates/ui/agent-openai/runtime/ui.py +521 -0
- databricks_agentbricks/templates/ui/agent-openai/tests/test_demo_ui.py +512 -0
- databricks_agentbricks/templates/ui/agent-openai/ui/agentbricks-mark.png +0 -0
- databricks_agentbricks/templates/ui/agent-openai/ui/app.js +1428 -0
- databricks_agentbricks/templates/ui/agent-openai/ui/index.html +281 -0
- databricks_agentbricks/templates/ui/agent-openai/ui/styles.css +1913 -0
- databricks_agentbricks/theme.py +72 -0
- databricks_agentbricks-0.2.0.dist-info/METADATA +897 -0
- databricks_agentbricks-0.2.0.dist-info/RECORD +159 -0
- databricks_agentbricks-0.2.0.dist-info/WHEEL +4 -0
- databricks_agentbricks-0.2.0.dist-info/entry_points.txt +2 -0
- databricks_agentbricks-0.2.0.dist-info/licenses/NOTICE +39 -0
- databricks_agentkit/__init__.py +67 -0
- databricks_agentkit/_api_client.py +673 -0
- databricks_agentkit/_pagination.py +25 -0
- databricks_agentkit/client.py +31 -0
- databricks_agentkit/langgraph/__init__.py +98 -0
- databricks_agentkit/langgraph/genie.py +50 -0
- databricks_agentkit/langgraph/mcp.py +216 -0
- databricks_agentkit/langgraph/memory.py +67 -0
- databricks_agentkit/langgraph/session_store.py +485 -0
- databricks_agentkit/memory_store.py +371 -0
- databricks_agentkit/models.py +330 -0
- databricks_agentkit/openai/__init__.py +93 -0
- databricks_agentkit/openai/genie.py +50 -0
- databricks_agentkit/openai/mcp.py +189 -0
- databricks_agentkit/openai/memory.py +67 -0
- databricks_agentkit/openai/sessions.py +157 -0
- databricks_agentkit/py.typed +0 -0
- databricks_agentkit/runtime/ARCHITECTURE.md +64 -0
- databricks_agentkit/runtime/README.md +184 -0
- databricks_agentkit/runtime/__init__.py +69 -0
- databricks_agentkit/runtime/app.py +316 -0
- databricks_agentkit/runtime/auth.py +149 -0
- databricks_agentkit/runtime/durability/__init__.py +1 -0
- databricks_agentkit/runtime/durability/execution.py +133 -0
- databricks_agentkit/runtime/durability/heartbeat.py +64 -0
- databricks_agentkit/runtime/durability/lakebase_runtime_store.py +648 -0
- databricks_agentkit/runtime/durability/recovery.py +70 -0
- databricks_agentkit/runtime/durability/store.py +33 -0
- databricks_agentkit/runtime/execution.py +160 -0
- databricks_agentkit/runtime/genie.py +224 -0
- databricks_agentkit/runtime/mcp_auth.py +114 -0
- databricks_agentkit/runtime/model_services.py +90 -0
- databricks_agentkit/runtime/runtime.py +273 -0
- databricks_agentkit/runtime/session_store_client.py +120 -0
- databricks_agentkit/runtime/store.py +287 -0
- databricks_agentkit/runtime/tool_manifest.py +223 -0
- databricks_agentkit/runtime/tracing.py +71 -0
- databricks_agentkit/runtime/types.py +118 -0
- databricks_agentkit/runtime/workspace.py +27 -0
- databricks_agentkit/session_store.py +434 -0
- databricks_agentkit/timefmt.py +85 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""HTTP transport and response decoding for Agent Bricks endpoint commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import http.cookiejar
|
|
6
|
+
import json
|
|
7
|
+
import time
|
|
8
|
+
import urllib.error
|
|
9
|
+
import urllib.request
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import Any, Callable, Iterable
|
|
12
|
+
|
|
13
|
+
from databricks_agentbricks.errors import AgentCliError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class EndpointRequest:
|
|
18
|
+
"""One fully materialized HTTP request."""
|
|
19
|
+
|
|
20
|
+
url: str
|
|
21
|
+
method: str
|
|
22
|
+
headers: dict[str, str]
|
|
23
|
+
body: Any
|
|
24
|
+
timeout: float
|
|
25
|
+
sse: bool = False
|
|
26
|
+
body_set: bool = False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class EndpointResponse:
|
|
31
|
+
"""HTTP response data used by endpoint rendering."""
|
|
32
|
+
|
|
33
|
+
url: str
|
|
34
|
+
status_code: int
|
|
35
|
+
headers: dict[str, str]
|
|
36
|
+
body: Any
|
|
37
|
+
elapsed_seconds: float
|
|
38
|
+
events: tuple[dict[str, Any], ...] = ()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class HttpSession:
|
|
42
|
+
"""Small stdlib HTTP client retaining cookies across polling requests."""
|
|
43
|
+
|
|
44
|
+
def __init__(self) -> None:
|
|
45
|
+
self._opener = urllib.request.build_opener(
|
|
46
|
+
urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar())
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def send(
|
|
50
|
+
self,
|
|
51
|
+
request: EndpointRequest,
|
|
52
|
+
*,
|
|
53
|
+
on_event: Callable[[dict[str, Any]], None] | None = None,
|
|
54
|
+
) -> EndpointResponse:
|
|
55
|
+
data = json.dumps(request.body).encode() if request.body_set else None
|
|
56
|
+
http_request = urllib.request.Request(
|
|
57
|
+
request.url,
|
|
58
|
+
data=data,
|
|
59
|
+
headers=request.headers,
|
|
60
|
+
method=request.method,
|
|
61
|
+
)
|
|
62
|
+
started = time.perf_counter()
|
|
63
|
+
try:
|
|
64
|
+
response = self._opener.open(http_request, timeout=request.timeout)
|
|
65
|
+
except urllib.error.HTTPError as exc:
|
|
66
|
+
response = exc
|
|
67
|
+
except (OSError, TimeoutError, urllib.error.URLError) as exc:
|
|
68
|
+
reason = getattr(exc, "reason", exc)
|
|
69
|
+
raise AgentCliError(f"Could not reach endpoint {request.url}: {reason}.") from exc
|
|
70
|
+
try:
|
|
71
|
+
headers = dict(response.headers.items())
|
|
72
|
+
content_type = response.headers.get_content_type()
|
|
73
|
+
if request.sse and content_type == "text/event-stream":
|
|
74
|
+
events = tuple(iter_sse(response, on_event=on_event))
|
|
75
|
+
body: Any = None
|
|
76
|
+
else:
|
|
77
|
+
events = ()
|
|
78
|
+
body = decode_body(response.read(), content_type)
|
|
79
|
+
status_code = response.status
|
|
80
|
+
if not isinstance(status_code, int):
|
|
81
|
+
raise AgentCliError(f"Endpoint {request.url} returned no HTTP status code.")
|
|
82
|
+
return EndpointResponse(
|
|
83
|
+
url=request.url,
|
|
84
|
+
status_code=status_code,
|
|
85
|
+
headers=headers,
|
|
86
|
+
body=body,
|
|
87
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
88
|
+
events=events,
|
|
89
|
+
)
|
|
90
|
+
finally:
|
|
91
|
+
response.close()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def iter_sse(
|
|
95
|
+
response,
|
|
96
|
+
*,
|
|
97
|
+
on_event: Callable[[dict[str, Any]], None] | None,
|
|
98
|
+
) -> Iterable[dict[str, Any]]:
|
|
99
|
+
"""Parse an SSE byte stream and optionally emit events as they arrive."""
|
|
100
|
+
event: dict[str, Any] = {}
|
|
101
|
+
data_lines: list[str] = []
|
|
102
|
+
for raw_line in response:
|
|
103
|
+
line = raw_line.decode("utf-8", errors="replace").rstrip("\r\n")
|
|
104
|
+
if not line:
|
|
105
|
+
if data_lines or event:
|
|
106
|
+
completed = _complete_event(event, data_lines)
|
|
107
|
+
if on_event is not None:
|
|
108
|
+
on_event(completed)
|
|
109
|
+
yield completed
|
|
110
|
+
event = {}
|
|
111
|
+
data_lines = []
|
|
112
|
+
continue
|
|
113
|
+
if line.startswith(":"):
|
|
114
|
+
continue
|
|
115
|
+
field, separator, value = line.partition(":")
|
|
116
|
+
if separator and value.startswith(" "):
|
|
117
|
+
value = value[1:]
|
|
118
|
+
if field == "data":
|
|
119
|
+
data_lines.append(value)
|
|
120
|
+
elif field in {"event", "id", "retry"}:
|
|
121
|
+
event[field] = value
|
|
122
|
+
if data_lines or event:
|
|
123
|
+
completed = _complete_event(event, data_lines)
|
|
124
|
+
if on_event is not None:
|
|
125
|
+
on_event(completed)
|
|
126
|
+
yield completed
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _complete_event(event: dict[str, Any], data_lines: list[str]) -> dict[str, Any]:
|
|
130
|
+
value = "\n".join(data_lines)
|
|
131
|
+
try:
|
|
132
|
+
event["data"] = json.loads(value)
|
|
133
|
+
except json.JSONDecodeError:
|
|
134
|
+
event["data"] = value
|
|
135
|
+
return event
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def decode_body(data: bytes, content_type: str) -> Any:
|
|
139
|
+
"""Decode a response as JSON when possible, otherwise return text."""
|
|
140
|
+
text = data.decode("utf-8", errors="replace")
|
|
141
|
+
if not text:
|
|
142
|
+
return None
|
|
143
|
+
if content_type == "application/json" or text[:1] in {"{", "[", '"'}:
|
|
144
|
+
try:
|
|
145
|
+
return json.loads(text)
|
|
146
|
+
except json.JSONDecodeError:
|
|
147
|
+
pass
|
|
148
|
+
return text
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
"""Discover the Agent Bricks CLI command tree and render help for nested commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Iterator
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from databricks_agentbricks._group import apply_group_class, dim
|
|
11
|
+
|
|
12
|
+
CommandPath = tuple[str, ...]
|
|
13
|
+
|
|
14
|
+
# Root commands grouped by intent, so the top-level `ab --help` reads as a workflow instead of a
|
|
15
|
+
# flat alphabetical dump. Ordered SETUP → DEVELOP → SHIP, matching the
|
|
16
|
+
# getting-started path. Any command missing here still lists under "Other commands" (see
|
|
17
|
+
# `_group.AgentBricksGroup`).
|
|
18
|
+
_COMMAND_SECTIONS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
19
|
+
("SETUP", ("login", "logout", "init")),
|
|
20
|
+
("DEVELOP", ("dev", "tools", "memory", "sessions", "tracing")),
|
|
21
|
+
("SHIP", ("deploy", "deployments")),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Each example is either a bare command, or a (command, comment) pair. The comment is a short gloss
|
|
25
|
+
# rendered beside/above the command so a first-time reader can tell what each example does without
|
|
26
|
+
# running it. See `_example_epilog` for how comments are laid out.
|
|
27
|
+
Example = str | tuple[str, str]
|
|
28
|
+
|
|
29
|
+
_EXAMPLES: dict[CommandPath, tuple[Example, ...]] = {
|
|
30
|
+
(): (
|
|
31
|
+
("ab login --profile <profile>", "authenticate and save a default profile"),
|
|
32
|
+
("ab init my-agent", "scaffold a new agent project"),
|
|
33
|
+
("cd my-agent", "enter the project directory"),
|
|
34
|
+
("ab dev", "run the agent locally with a chat UI"),
|
|
35
|
+
("ab deploy my-agent", "deploy the agent to Databricks Apps"),
|
|
36
|
+
),
|
|
37
|
+
("login",): (("ab login --profile <profile>", "save a profile as your default"),),
|
|
38
|
+
("logout",): (("ab logout", "forget the saved default profile"),),
|
|
39
|
+
("init",): (
|
|
40
|
+
("ab init my-agent", "scaffold a new agent project"),
|
|
41
|
+
(
|
|
42
|
+
"ab init --framework langgraph --existing .",
|
|
43
|
+
"prepare a coding-agent migration bundle for an existing agent",
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
("dev",): (("ab dev", "run the agent locally with a chat UI"),),
|
|
47
|
+
("memory",): (
|
|
48
|
+
("ab memory stores create --display-name agent-memory", "create a memory store"),
|
|
49
|
+
("ab memory bind agent-memory", "bind it to the agent (wired in on dev / deploy)"),
|
|
50
|
+
(
|
|
51
|
+
"ab memory entries create --store <store> --actor-id alice "
|
|
52
|
+
'--path /preferences/style.md --content "Terse, code first."',
|
|
53
|
+
"add a memory entry for an actor (--store takes the store id)",
|
|
54
|
+
),
|
|
55
|
+
(
|
|
56
|
+
'ab memory entries search --store <store> --actor-id alice --query "style"',
|
|
57
|
+
"search an actor's entries",
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
("memory", "bind"): (
|
|
61
|
+
("ab memory bind agent-memory --source .", "declare a memory store in agent.toml"),
|
|
62
|
+
),
|
|
63
|
+
("memory", "unbind"): (
|
|
64
|
+
("ab memory unbind --source .", "remove the memory store binding from agent.toml"),
|
|
65
|
+
),
|
|
66
|
+
("memory", "stores"): (("ab memory stores list", "list managed memory stores"),),
|
|
67
|
+
("memory", "stores", "create"): (
|
|
68
|
+
("ab memory stores create --display-name agent-memory", "create a memory store"),
|
|
69
|
+
),
|
|
70
|
+
("memory", "stores", "list"): (("ab memory stores list", "list managed memory stores"),),
|
|
71
|
+
("memory", "stores", "get"): (("ab memory stores get <store>", "show one store's details"),),
|
|
72
|
+
("memory", "stores", "update"): (
|
|
73
|
+
('ab memory stores update <store> --description "Agent memory"', "edit a store"),
|
|
74
|
+
),
|
|
75
|
+
("memory", "stores", "delete"): (("ab memory stores delete <store>", "delete a store"),),
|
|
76
|
+
("memory", "entries"): (
|
|
77
|
+
("ab memory entries list --store <store> --actor-id alice", "list an actor's entries"),
|
|
78
|
+
),
|
|
79
|
+
("memory", "entries", "create"): (
|
|
80
|
+
(
|
|
81
|
+
"ab memory entries create --store <store> --actor-id alice "
|
|
82
|
+
'--path /preferences/style.md --content "Terse, code first."',
|
|
83
|
+
"add a memory entry for an actor",
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
("memory", "entries", "get"): (
|
|
87
|
+
("ab memory entries get --store <store> <entry>", "show one entry"),
|
|
88
|
+
),
|
|
89
|
+
("memory", "entries", "list"): (
|
|
90
|
+
("ab memory entries list --store <store> --actor-id alice", "list an actor's entries"),
|
|
91
|
+
),
|
|
92
|
+
("memory", "entries", "search"): (
|
|
93
|
+
(
|
|
94
|
+
'ab memory entries search --store <store> --actor-id alice --query "style"',
|
|
95
|
+
"search an actor's entries",
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
("memory", "entries", "update"): (
|
|
99
|
+
(
|
|
100
|
+
'ab memory entries update --store <store> <entry> --content "Concise"',
|
|
101
|
+
"edit an entry",
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
("memory", "entries", "delete"): (
|
|
105
|
+
("ab memory entries delete --store <store> <entry>", "delete an entry"),
|
|
106
|
+
),
|
|
107
|
+
("sessions",): (
|
|
108
|
+
("ab sessions stores create --name agent-sessions", "create a session store"),
|
|
109
|
+
("ab sessions bind agent-sessions", "bind it to the agent (wired in on dev / deploy)"),
|
|
110
|
+
(
|
|
111
|
+
"ab sessions create --store agent-sessions --actor-id alice",
|
|
112
|
+
"start a session for an actor",
|
|
113
|
+
),
|
|
114
|
+
(
|
|
115
|
+
"ab sessions items append --store agent-sessions --session-id <session-id> "
|
|
116
|
+
'--data \'{"role":"user","content":"Hello"}\'',
|
|
117
|
+
"append an item to the session",
|
|
118
|
+
),
|
|
119
|
+
(
|
|
120
|
+
"ab sessions items list --store agent-sessions --session-id <session-id>",
|
|
121
|
+
"list the session's items",
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
("sessions", "bind"): (
|
|
125
|
+
("ab sessions bind agent-sessions --source .", "declare a session store in agent.toml"),
|
|
126
|
+
),
|
|
127
|
+
("sessions", "unbind"): (
|
|
128
|
+
("ab sessions unbind --source .", "remove the session store binding from agent.toml"),
|
|
129
|
+
),
|
|
130
|
+
("sessions", "stores"): (("ab sessions stores list", "list managed session stores"),),
|
|
131
|
+
("sessions", "stores", "create"): (
|
|
132
|
+
("ab sessions stores create --name agent-sessions", "create a session store"),
|
|
133
|
+
),
|
|
134
|
+
("sessions", "stores", "list"): (("ab sessions stores list", "list managed session stores"),),
|
|
135
|
+
("sessions", "stores", "get"): (
|
|
136
|
+
("ab sessions stores get agent-sessions", "show one store's details"),
|
|
137
|
+
),
|
|
138
|
+
("sessions", "stores", "update"): (
|
|
139
|
+
(
|
|
140
|
+
'ab sessions stores update agent-sessions --description "Agent sessions"',
|
|
141
|
+
"edit a store",
|
|
142
|
+
),
|
|
143
|
+
),
|
|
144
|
+
("sessions", "stores", "delete"): (
|
|
145
|
+
("ab sessions stores delete agent-sessions", "delete a store"),
|
|
146
|
+
),
|
|
147
|
+
("sessions", "items"): (
|
|
148
|
+
(
|
|
149
|
+
"ab sessions items list --store agent-sessions --session-id <session-id>",
|
|
150
|
+
"list a session's items",
|
|
151
|
+
),
|
|
152
|
+
),
|
|
153
|
+
("sessions", "items", "list"): (
|
|
154
|
+
(
|
|
155
|
+
"ab sessions items list --store agent-sessions --session-id <session-id>",
|
|
156
|
+
"list a session's items",
|
|
157
|
+
),
|
|
158
|
+
),
|
|
159
|
+
("sessions", "items", "append"): (
|
|
160
|
+
(
|
|
161
|
+
"ab sessions items append --store agent-sessions --session-id <session-id> "
|
|
162
|
+
'--data \'{"role":"user","content":"Hello"}\'',
|
|
163
|
+
"append an item to a session",
|
|
164
|
+
),
|
|
165
|
+
),
|
|
166
|
+
("sessions", "items", "pop"): (
|
|
167
|
+
(
|
|
168
|
+
"ab sessions items pop --store agent-sessions --session-id <session-id>",
|
|
169
|
+
"remove the last item",
|
|
170
|
+
),
|
|
171
|
+
),
|
|
172
|
+
("sessions", "items", "clear"): (
|
|
173
|
+
(
|
|
174
|
+
"ab sessions items clear --store agent-sessions --session-id <session-id>",
|
|
175
|
+
"remove all items",
|
|
176
|
+
),
|
|
177
|
+
),
|
|
178
|
+
("sessions", "create"): (
|
|
179
|
+
("ab sessions create --store agent-sessions --actor-id alice", "start a new session"),
|
|
180
|
+
),
|
|
181
|
+
("sessions", "list"): (
|
|
182
|
+
("ab sessions list --store agent-sessions", "list sessions in a store"),
|
|
183
|
+
),
|
|
184
|
+
("sessions", "get"): (
|
|
185
|
+
("ab sessions get <session-id> --store agent-sessions", "show one session"),
|
|
186
|
+
),
|
|
187
|
+
("sessions", "update"): (
|
|
188
|
+
(
|
|
189
|
+
"ab sessions update <session-id> --store agent-sessions "
|
|
190
|
+
'--metadata \'{"status":"reviewed"}\'',
|
|
191
|
+
"edit a session's metadata",
|
|
192
|
+
),
|
|
193
|
+
),
|
|
194
|
+
("sessions", "delete"): (
|
|
195
|
+
("ab sessions delete <session-id> --store agent-sessions", "delete a session"),
|
|
196
|
+
),
|
|
197
|
+
("sessions", "fork"): (
|
|
198
|
+
(
|
|
199
|
+
"ab sessions fork --store agent-sessions --source-session-id <session-id> "
|
|
200
|
+
"--actor-id alice",
|
|
201
|
+
"copy a session into a new one",
|
|
202
|
+
),
|
|
203
|
+
),
|
|
204
|
+
("tracing",): (
|
|
205
|
+
(
|
|
206
|
+
"ab tracing bind --experiment-name /Shared/agentbricks_traces/my-agent",
|
|
207
|
+
"bind tracing to an experiment by name",
|
|
208
|
+
),
|
|
209
|
+
("ab tracing bind --experiment-id 12345", "or by experiment id"),
|
|
210
|
+
("ab tracing unbind", "turn tracing off"),
|
|
211
|
+
),
|
|
212
|
+
("tracing", "bind"): (
|
|
213
|
+
(
|
|
214
|
+
"ab tracing bind --experiment-name /Shared/agentbricks_traces/my-agent",
|
|
215
|
+
"trace to a specific experiment by name",
|
|
216
|
+
),
|
|
217
|
+
("ab tracing bind --experiment-id 12345", "or by experiment id"),
|
|
218
|
+
),
|
|
219
|
+
("tracing", "unbind"): (("ab tracing unbind", "turn tracing off"),),
|
|
220
|
+
("tracing", "list"): (
|
|
221
|
+
(
|
|
222
|
+
"ab tracing list --experiment-name /Shared/agentbricks_traces/my-agent",
|
|
223
|
+
"list a specific experiment's traces",
|
|
224
|
+
),
|
|
225
|
+
("ab tracing list --experiment-id 12345", "or by experiment id"),
|
|
226
|
+
),
|
|
227
|
+
("tracing", "get"): (("ab tracing get <trace-id>", "show one trace"),),
|
|
228
|
+
("deploy",): (
|
|
229
|
+
("ab deploy my-agent", "deploy the agent"),
|
|
230
|
+
("ab deploy my-agent --instances 2", "deploy with two instances"),
|
|
231
|
+
),
|
|
232
|
+
("deployments",): (("ab deployments list", "list agent deployments"),),
|
|
233
|
+
("deployments", "list"): (("ab deployments list", "list agent deployments"),),
|
|
234
|
+
("deployments", "get"): (("ab deployments get agent-bricks-my-agent", "show one deployment"),),
|
|
235
|
+
("deployments", "logs"): (
|
|
236
|
+
("ab deployments logs agent-bricks-my-agent", "stream a deployment's logs"),
|
|
237
|
+
),
|
|
238
|
+
("deployments", "start"): (
|
|
239
|
+
("ab deployments start agent-bricks-my-agent", "start a deployment"),
|
|
240
|
+
),
|
|
241
|
+
("deployments", "stop"): (("ab deployments stop agent-bricks-my-agent", "stop a deployment"),),
|
|
242
|
+
("deployments", "delete"): (
|
|
243
|
+
("ab deployments delete agent-bricks-my-agent", "delete a deployment"),
|
|
244
|
+
),
|
|
245
|
+
("endpoint",): (
|
|
246
|
+
(
|
|
247
|
+
"ab endpoint invoke agent-bricks-my-agent --path /api/invocations "
|
|
248
|
+
"--json "
|
|
249
|
+
'\'{"id":"00000000-0000-4000-8000-000000000001",'
|
|
250
|
+
'"input":[{"role":"user","content":"Hello"}]}\'',
|
|
251
|
+
"invoke a deployed HTTP agent",
|
|
252
|
+
),
|
|
253
|
+
),
|
|
254
|
+
("endpoint", "invoke"): (
|
|
255
|
+
(
|
|
256
|
+
"ab endpoint invoke agent-bricks-my-agent --path /api/invocations "
|
|
257
|
+
"--json "
|
|
258
|
+
'\'{"id":"00000000-0000-4000-8000-000000000001",'
|
|
259
|
+
'"input":[{"role":"user","content":"Hello"}]}\'',
|
|
260
|
+
"invoke a deployed HTTP agent",
|
|
261
|
+
),
|
|
262
|
+
(
|
|
263
|
+
"ab endpoint invoke --url http://localhost:8000 --path /custom/run "
|
|
264
|
+
'--json \'{"input":"hello"}\'',
|
|
265
|
+
"invoke a local or arbitrary HTTP server",
|
|
266
|
+
),
|
|
267
|
+
),
|
|
268
|
+
("tools",): (
|
|
269
|
+
("ab tools add --help", "see all tool types you can add"),
|
|
270
|
+
("ab tools add sandbox --scope table:samples.nyctaxi.trips", "add a data sandbox tool"),
|
|
271
|
+
("ab tools add mcp system.ai.web_search", "add a managed MCP tool"),
|
|
272
|
+
("ab tools remove mcp system.ai.web_search", "remove a tool binding"),
|
|
273
|
+
("ab tools list", "browse available integrations to add"),
|
|
274
|
+
),
|
|
275
|
+
("tools", "add"): (
|
|
276
|
+
("ab tools add sandbox --scope table:samples.nyctaxi.trips", "add a data sandbox tool"),
|
|
277
|
+
("ab tools add mcp system.ai.web_search", "add a managed MCP tool"),
|
|
278
|
+
("ab tools add uc-function catalog.schema.lookup_ticket", "add a UC function tool"),
|
|
279
|
+
("ab tools add genie-one", "add workspace-wide Genie One tools"),
|
|
280
|
+
("ab tools add genie-agent SPACE_ID", "add tools for one Genie Space"),
|
|
281
|
+
),
|
|
282
|
+
("tools", "add", "sandbox"): (
|
|
283
|
+
("ab tools add sandbox --scope table:samples.nyctaxi.trips", "add a data sandbox tool"),
|
|
284
|
+
),
|
|
285
|
+
("tools", "add", "mcp"): (("ab tools add mcp system.ai.web_search", "add a managed MCP tool"),),
|
|
286
|
+
("tools", "add", "uc-function"): (
|
|
287
|
+
("ab tools add uc-function catalog.schema.lookup_ticket", "add a UC function tool"),
|
|
288
|
+
),
|
|
289
|
+
("tools", "remove"): (
|
|
290
|
+
("ab tools remove mcp system.ai.web_search", "remove an MCP tool by service"),
|
|
291
|
+
("ab tools remove web_search", "remove a tool by id"),
|
|
292
|
+
),
|
|
293
|
+
("tools", "list"): (
|
|
294
|
+
("ab tools list", "browse built-in recipes and system.ai MCP Services"),
|
|
295
|
+
("ab tools list --kind mcp", "discover MCP Services in system.ai"),
|
|
296
|
+
(
|
|
297
|
+
"ab tools list --kind mcp --schema main.tools",
|
|
298
|
+
"replace the default MCP schema",
|
|
299
|
+
),
|
|
300
|
+
("ab tools list --kind sandbox", "show the local recipe without authentication"),
|
|
301
|
+
("ab tools list --kind genie-one", "show the Genie One add recipe"),
|
|
302
|
+
("ab tools list --kind genie-agent", "show the Genie Agent add recipe"),
|
|
303
|
+
),
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
# Longest command we align an inline `# comment` after. Past this, a group's comments would be
|
|
307
|
+
# pushed so far right they wrap or scroll off, so we stack the comment on the line above instead.
|
|
308
|
+
_INLINE_COMMENT_MAX = 46
|
|
309
|
+
|
|
310
|
+
# Where to send a reader who wants more than the help text — best-practice CLI help links out to
|
|
311
|
+
# docs and a support/issues path. Shown only on the root `ab --help`, so subcommand help stays
|
|
312
|
+
# uncluttered.
|
|
313
|
+
_DOCS_URL = "https://github.com/databricks/databricks-ai-bridge/tree/main/integrations/agentbricks"
|
|
314
|
+
_ISSUES_URL = "https://github.com/databricks/databricks-ai-bridge/issues"
|
|
315
|
+
|
|
316
|
+
# Short, one-line descriptors for the root command list. Click renders that list as a scannable
|
|
317
|
+
# index and truncates a long first docstring line with `…`; a curated `short_help` keeps each row
|
|
318
|
+
# crisp while the command's own `--help` page still shows its full docstring. Keep these under ~45
|
|
319
|
+
# chars so they never truncate.
|
|
320
|
+
_SHORT_HELP: dict[CommandPath, str] = {
|
|
321
|
+
("login",): "Authenticate and save a default profile",
|
|
322
|
+
("logout",): "Forget the saved default profile",
|
|
323
|
+
("init",): "Scaffold a new agent project",
|
|
324
|
+
("dev",): "Run the agent locally with a chat UI",
|
|
325
|
+
("deploy",): "Deploy an agent to Databricks Apps",
|
|
326
|
+
("deployments",): "Manage deployed agents",
|
|
327
|
+
("memory",): "Manage an agent's long-term memory",
|
|
328
|
+
("sessions",): "Manage an agent's conversation sessions",
|
|
329
|
+
("tools",): "Discover integrations and manage tool bindings",
|
|
330
|
+
("tracing",): "Set up and inspect agent tracing",
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _walk(
|
|
335
|
+
command: click.Command, prefix: CommandPath = ()
|
|
336
|
+
) -> Iterator[tuple[CommandPath, click.Command]]:
|
|
337
|
+
if not isinstance(command, click.Group):
|
|
338
|
+
return
|
|
339
|
+
for name, child in command.commands.items():
|
|
340
|
+
path = (*prefix, name)
|
|
341
|
+
yield path, child
|
|
342
|
+
yield from _walk(child, path)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def _split(example: Example) -> tuple[str, str | None]:
|
|
346
|
+
"""Normalize an example into (command, comment-or-None)."""
|
|
347
|
+
if isinstance(example, tuple):
|
|
348
|
+
return example[0], example[1]
|
|
349
|
+
return example, None
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _example_epilog(examples: tuple[Example, ...]) -> str:
|
|
353
|
+
"""Render the Examples block, keeping commands left-aligned and comments legible.
|
|
354
|
+
|
|
355
|
+
Commands sit flush at a two-space indent so the block scans as a clean column. The whole group
|
|
356
|
+
uses one comment layout for consistency: if every command is short enough, comments go inline
|
|
357
|
+
(`cmd # what it does`) aligned across the group; if any command is long, all comments stack on
|
|
358
|
+
the line above their command so nothing wraps.
|
|
359
|
+
"""
|
|
360
|
+
pairs = [_split(example) for example in examples]
|
|
361
|
+
stack = any(comment and len(cmd) > _INLINE_COMMENT_MAX for cmd, comment in pairs)
|
|
362
|
+
inline_width = max((len(cmd) for cmd, comment in pairs if comment), default=0)
|
|
363
|
+
# Heading grayed + uppercased to match the formatter-rendered sections (OPTIONS/SETUP/…); the
|
|
364
|
+
# commands stay at the terminal's default foreground and the `# comments` are grayed like every
|
|
365
|
+
# other description on the page. `ljust` is computed on the plain command so alignment survives.
|
|
366
|
+
lines = ["\b", dim("EXAMPLES")]
|
|
367
|
+
for cmd, comment in pairs:
|
|
368
|
+
if not comment:
|
|
369
|
+
lines.append(f" {cmd}")
|
|
370
|
+
elif stack:
|
|
371
|
+
lines.append(f" {dim(f'# {comment}')}")
|
|
372
|
+
lines.append(f" {cmd}")
|
|
373
|
+
else:
|
|
374
|
+
lines.append(f" {cmd.ljust(inline_width)} {dim(f'# {comment}')}")
|
|
375
|
+
return "\n".join(lines)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _getting_started_epilog() -> str:
|
|
379
|
+
"""The root's numbered "Getting started" path: login → init → cd → dev → deploy.
|
|
380
|
+
|
|
381
|
+
A numbered, ordered path — rather than an unlabeled grab-bag of examples — removes the
|
|
382
|
+
"blank-page problem" for a first-time reader: it says *start here, in this order*. Reuses the
|
|
383
|
+
root happy-path examples so the path and their glosses stay in one place.
|
|
384
|
+
"""
|
|
385
|
+
pairs = [_split(example) for example in _EXAMPLES[()]]
|
|
386
|
+
width = max(len(cmd) for cmd, _ in pairs)
|
|
387
|
+
lines = ["\b", dim("GETTING STARTED")]
|
|
388
|
+
for i, (cmd, comment) in enumerate(pairs, start=1):
|
|
389
|
+
row = f" {i} {cmd.ljust(width)}"
|
|
390
|
+
if comment:
|
|
391
|
+
row += f" {dim(f'# {comment}')}"
|
|
392
|
+
lines.append(row)
|
|
393
|
+
return "\n".join(lines)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _root_epilog() -> str:
|
|
397
|
+
"""The root help footer: the numbered getting-started path, an auth note, then Docs/Issues links.
|
|
398
|
+
|
|
399
|
+
Each block is its own `\\b` paragraph so Click renders it verbatim (commands and URLs intact)
|
|
400
|
+
instead of rewrapping it.
|
|
401
|
+
"""
|
|
402
|
+
# The auth note (setup instructions) and the Docs/Issues links stay at full intensity — this is
|
|
403
|
+
# important standalone content, not the secondary command *descriptions* that the graying is for.
|
|
404
|
+
auth = "\n".join(
|
|
405
|
+
[
|
|
406
|
+
"\b",
|
|
407
|
+
"Not authenticated yet? Create a profile with the Databricks CLI first:",
|
|
408
|
+
" databricks auth login --profile <profile>",
|
|
409
|
+
"Then `ab login --profile <profile>` saves it as your default.",
|
|
410
|
+
]
|
|
411
|
+
)
|
|
412
|
+
links = "\n".join(["\b", f"Docs: {_DOCS_URL}", f"Issues: {_ISSUES_URL}"])
|
|
413
|
+
return f"{_getting_started_epilog()}\n\n{auth}\n\n{links}"
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
# A capabilities row: indent, label (single word), a 2+ space gap, then the description.
|
|
417
|
+
_CAPABILITY_ROW = re.compile(r"^(\s*)(\S+)(\s{2,})(.*)$")
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _dim_capabilities_block(help_text: str) -> str:
|
|
421
|
+
"""Gray only the *descriptions* in the root docstring's `\\b` capabilities block.
|
|
422
|
+
|
|
423
|
+
The block (Models/Tools/…) is a reference list that lives in the docstring, which the formatter
|
|
424
|
+
leaves at full contrast. Match the rest of the help page: the label column (left) stays at full
|
|
425
|
+
weight and the description recedes as secondary. A row is ``indent label description``; a
|
|
426
|
+
wrapped continuation line has no label, so it dims whole. Leading indent is preserved so
|
|
427
|
+
alignment and Click's dedent are unaffected. Scoped to the single `\\b` verbatim block (marked by
|
|
428
|
+
a lone ``\\x08``), up to the next blank line.
|
|
429
|
+
"""
|
|
430
|
+
out: list[str] = []
|
|
431
|
+
dimming = False
|
|
432
|
+
for line in help_text.split("\n"):
|
|
433
|
+
stripped = line.strip()
|
|
434
|
+
if not dimming and stripped == "\x08":
|
|
435
|
+
dimming = True
|
|
436
|
+
out.append(line)
|
|
437
|
+
elif dimming and stripped == "":
|
|
438
|
+
dimming = False
|
|
439
|
+
out.append(line)
|
|
440
|
+
elif dimming:
|
|
441
|
+
row = _CAPABILITY_ROW.match(line)
|
|
442
|
+
if row:
|
|
443
|
+
indent, label, gap, description = row.groups()
|
|
444
|
+
# Label full-weight; only the description recedes.
|
|
445
|
+
out.append(f"{indent}{label}{gap}{dim(description)}")
|
|
446
|
+
else:
|
|
447
|
+
# A wrapped continuation line (no label) is all description — dim it whole.
|
|
448
|
+
lead = line[: len(line) - len(line.lstrip(" "))]
|
|
449
|
+
out.append(lead + dim(line[len(lead) :]))
|
|
450
|
+
else:
|
|
451
|
+
out.append(line)
|
|
452
|
+
return "\n".join(out)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def configure_help(root: click.Group) -> None:
|
|
456
|
+
"""Attach curated short help and examples, and upgrade the group class (typo suggestions +
|
|
457
|
+
intent-grouped root listing)."""
|
|
458
|
+
root.epilog = _root_epilog()
|
|
459
|
+
if root.help:
|
|
460
|
+
root.help = _dim_capabilities_block(root.help)
|
|
461
|
+
for path, command in _walk(root):
|
|
462
|
+
if path in _SHORT_HELP:
|
|
463
|
+
command.short_help = _SHORT_HELP[path]
|
|
464
|
+
examples = _EXAMPLES.get(path)
|
|
465
|
+
if examples:
|
|
466
|
+
command.epilog = _example_epilog(examples)
|
|
467
|
+
apply_group_class(root, _COMMAND_SECTIONS)
|