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 @@
|
|
|
1
|
+
"""Agent Bricks CLI and project tooling."""
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""A `click.Group` subclass carrying the facelift's `--help` upgrades.
|
|
2
|
+
|
|
3
|
+
1. **"Did you mean?" on unknown commands.** Click's default dead-ends with
|
|
4
|
+
``Error: No such command 'foo'.``. `AgentBricksGroup` turns that into the CLI's diagnostic grammar —
|
|
5
|
+
``error: unknown command `foo``` — plus up to three ranked suggestions and a ``--help`` pointer,
|
|
6
|
+
so a typo resolves itself instead of stranding the user.
|
|
7
|
+
|
|
8
|
+
2. **Grouped command listing.** On the root group, commands are listed by intent
|
|
9
|
+
(SETUP / DEVELOP / SHIP) instead of one flat alphabetical dump — the fix for the "blank-page
|
|
10
|
+
problem". Subgroups keep Click's default single-section listing.
|
|
11
|
+
|
|
12
|
+
3. **Grayed `--help`.** `AgentBricksHelpFormatter` renders section headings and description text in the
|
|
13
|
+
muted secondary color (and headings uppercased, colon-less), reserving the terminal's default
|
|
14
|
+
foreground for the command/option names — so the page reads as scannable structure, not a wall
|
|
15
|
+
of equal-weight text. Installed on every command via `AgentBricksContext`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import difflib
|
|
21
|
+
import inspect
|
|
22
|
+
from typing import Iterable, Optional
|
|
23
|
+
|
|
24
|
+
import click
|
|
25
|
+
|
|
26
|
+
from databricks_agentbricks.errors import AgentCliError
|
|
27
|
+
|
|
28
|
+
# Ordered intent sections for the root command list. Each command name must be a real subcommand;
|
|
29
|
+
# any not registered is silently skipped, so this stays robust if the command set changes.
|
|
30
|
+
CommandSections = tuple[tuple[str, tuple[str, ...]], ...]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def dim(text: str) -> str:
|
|
34
|
+
"""Recede `text` for `--help` output (the facelift graying of headings and descriptions).
|
|
35
|
+
|
|
36
|
+
Uses the terminal's adaptive "dim" attribute (ANSI SGR 2) rather than a fixed gray hex. A fixed
|
|
37
|
+
shade tuned for the design mock's dark background washes out on a light terminal (and on
|
|
38
|
+
terminals without 24-bit color), which made the help hard to read; SGR 2 dims relative to the
|
|
39
|
+
reader's own foreground, so secondary text stays legible on both light and dark backgrounds
|
|
40
|
+
while the command/option names — left at full intensity — still stand out.
|
|
41
|
+
|
|
42
|
+
``click.style`` emits the code on a TTY and ``click.echo`` strips it when output is piped or
|
|
43
|
+
``NO_COLOR`` is set. Shared with `help.py` so the epilog (getting-started / examples) recedes to
|
|
44
|
+
match the formatter-rendered sections.
|
|
45
|
+
"""
|
|
46
|
+
return click.style(text, dim=True)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class _FlushEpilog:
|
|
50
|
+
"""Render the epilog flush-left instead of one indent level in.
|
|
51
|
+
|
|
52
|
+
Click's default `format_epilog` wraps the epilog in `with formatter.indentation():`, so an
|
|
53
|
+
epilog section heading (our `GETTING STARTED` / `EXAMPLES`) lands two columns to the right of
|
|
54
|
+
the real sections (`OPTIONS` / `SETUP` / …). We treat those blocks as first-class grayed
|
|
55
|
+
sections, so they should sit flush-left like the others, with their content at the same 2-space
|
|
56
|
+
column as command rows. Dropping the extra `indentation()` does exactly that.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
epilog: Optional[str]
|
|
60
|
+
|
|
61
|
+
def format_epilog(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
|
|
62
|
+
if self.epilog:
|
|
63
|
+
formatter.write_paragraph()
|
|
64
|
+
formatter.write_text(inspect.cleandoc(self.epilog))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AgentBricksGroup(_FlushEpilog, click.Group):
|
|
68
|
+
"""Group with typo suggestions and (optionally) an intent-grouped command listing."""
|
|
69
|
+
|
|
70
|
+
# Set only on the root group. When present, `format_commands` renders these sections instead of
|
|
71
|
+
# Click's flat "Commands:" list.
|
|
72
|
+
command_sections: Optional[CommandSections] = None
|
|
73
|
+
|
|
74
|
+
def resolve_command(self, ctx: click.Context, args: list[str]):
|
|
75
|
+
try:
|
|
76
|
+
return super().resolve_command(ctx, args)
|
|
77
|
+
except click.UsageError:
|
|
78
|
+
# Click raises `UsageError("No such command '<name>'.")`; re-render it in the CLI's
|
|
79
|
+
# diagnostic grammar with suggestions. The offending token is the first arg.
|
|
80
|
+
name = args[0] if args else ""
|
|
81
|
+
raise self._unknown_command_error(ctx, name) from None
|
|
82
|
+
|
|
83
|
+
def _unknown_command_error(self, ctx: click.Context, name: str) -> AgentCliError:
|
|
84
|
+
invocation = ctx.command_path or "ab"
|
|
85
|
+
# Repeating the executable as a command is a common paste typo — call it out directly.
|
|
86
|
+
program = invocation.split(maxsplit=1)[0]
|
|
87
|
+
if ctx.parent is None and name == program:
|
|
88
|
+
return AgentCliError(
|
|
89
|
+
f"unknown command `{name}`",
|
|
90
|
+
hint=f"you typed `{name}` twice — drop the extra `{name}` (run `{invocation} --help`)",
|
|
91
|
+
)
|
|
92
|
+
suggestions = difflib.get_close_matches(name, self.list_commands(ctx), n=3, cutoff=0.5)
|
|
93
|
+
if suggestions:
|
|
94
|
+
quoted = ", ".join(f"`{s}`" for s in suggestions)
|
|
95
|
+
hint = f"did you mean {quoted}? (run `{invocation} --help` to see all commands)"
|
|
96
|
+
else:
|
|
97
|
+
hint = f"run `{invocation} --help` to see available commands"
|
|
98
|
+
return AgentCliError(f"unknown command `{name}`", hint=hint)
|
|
99
|
+
|
|
100
|
+
def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
|
|
101
|
+
if not self.command_sections:
|
|
102
|
+
super().format_commands(ctx, formatter)
|
|
103
|
+
return
|
|
104
|
+
listed: set[str] = set()
|
|
105
|
+
for label, names in self.command_sections:
|
|
106
|
+
rows: list[tuple[str, str]] = []
|
|
107
|
+
for name in names:
|
|
108
|
+
command = self.get_command(ctx, name)
|
|
109
|
+
if command is None or command.hidden:
|
|
110
|
+
continue
|
|
111
|
+
listed.add(name)
|
|
112
|
+
rows.append((name, command.get_short_help_str(limit=60)))
|
|
113
|
+
if rows:
|
|
114
|
+
with formatter.section(label):
|
|
115
|
+
formatter.write_dl(rows)
|
|
116
|
+
# Any command not placed in a section still needs to appear, so nothing goes missing if a
|
|
117
|
+
# new command is added without updating the section map.
|
|
118
|
+
leftovers: list[tuple[str, str]] = []
|
|
119
|
+
for name in self.list_commands(ctx):
|
|
120
|
+
if name in listed:
|
|
121
|
+
continue
|
|
122
|
+
command = self.get_command(ctx, name)
|
|
123
|
+
if command is None or command.hidden:
|
|
124
|
+
continue
|
|
125
|
+
leftovers.append((name, command.get_short_help_str(limit=60)))
|
|
126
|
+
if leftovers:
|
|
127
|
+
with formatter.section("Other commands"):
|
|
128
|
+
formatter.write_dl(leftovers)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class AgentBricksHelpFormatter(click.HelpFormatter):
|
|
132
|
+
"""A help formatter that grays the page's structure.
|
|
133
|
+
|
|
134
|
+
Section headings render uppercase, colon-less, and in the muted secondary color; description
|
|
135
|
+
text (the second column of every option/command list) renders in the same secondary color. The
|
|
136
|
+
command and option *names* keep the terminal's default foreground, so the eye lands on what's
|
|
137
|
+
runnable. Command docstrings (the intro prose) are left untouched so the most important text
|
|
138
|
+
stays at full contrast.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
def write_heading(self, heading: str) -> None:
|
|
142
|
+
self.write(f"{'':>{self.current_indent}}{dim(heading.upper())}\n")
|
|
143
|
+
|
|
144
|
+
def write_dl(
|
|
145
|
+
self,
|
|
146
|
+
rows: Iterable[tuple[str, str]],
|
|
147
|
+
col_max: int = 30,
|
|
148
|
+
col_spacing: int = 2,
|
|
149
|
+
) -> None:
|
|
150
|
+
# Gray only the description column. Click ≥8.4 measures column widths and wraps with
|
|
151
|
+
# `term_len` (ANSI-aware), so styling the description doesn't disturb alignment or wrapping.
|
|
152
|
+
grayed = [(term, dim(desc) if desc else desc) for term, desc in rows]
|
|
153
|
+
super().write_dl(grayed, col_max=col_max, col_spacing=col_spacing)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class AgentBricksCommand(_FlushEpilog, click.Command):
|
|
157
|
+
"""A leaf command whose `EXAMPLES` epilog renders flush-left, like the section headings."""
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class AgentBricksContext(click.Context):
|
|
161
|
+
"""Context that renders help through `AgentBricksHelpFormatter`."""
|
|
162
|
+
|
|
163
|
+
formatter_class = AgentBricksHelpFormatter
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _usage_error_show(self: click.exceptions.UsageError, file=None) -> None:
|
|
167
|
+
"""Render a Click usage error (bad/unknown option, missing or extra argument) in the agentbricks
|
|
168
|
+
diagnostic grammar, matching the errors we raise ourselves.
|
|
169
|
+
|
|
170
|
+
Click's own `UsageError.show` prints `Error: <msg>` plus a `Usage:` / `Try … --help` block.
|
|
171
|
+
`format_message()` already includes Click's own "Did you mean …?" for a mistyped option, so we
|
|
172
|
+
keep the message verbatim and add the agentbricks `error:` keyword and an indented `help:` pointer.
|
|
173
|
+
"""
|
|
174
|
+
# Local imports avoid a module-load cycle (render/errors import from click, not from here).
|
|
175
|
+
from rich.console import Console
|
|
176
|
+
|
|
177
|
+
from databricks_agentbricks import errors, render
|
|
178
|
+
|
|
179
|
+
invocation = self.ctx.command_path if self.ctx is not None else "ab"
|
|
180
|
+
message = self.format_message()
|
|
181
|
+
hint = f"run `{invocation} --help` to see the available options and arguments"
|
|
182
|
+
if errors._OUTPUT_MODE == "json":
|
|
183
|
+
import json
|
|
184
|
+
|
|
185
|
+
click.echo(json.dumps({"error": {"message": message, "hint": hint}}, indent=2), err=True)
|
|
186
|
+
return
|
|
187
|
+
render.diagnostic("error", message, help=hint, con=Console(stderr=True))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def apply_group_class(root: click.Group, sections: CommandSections) -> None:
|
|
191
|
+
"""Upgrade the whole command tree in place: `AgentBricksGroup` on every group (typo suggestions +
|
|
192
|
+
the intent-grouped root listing) and `AgentBricksContext` on every command (grayed `--help`), and
|
|
193
|
+
route Click's own usage errors through the agentbricks diagnostic grammar.
|
|
194
|
+
|
|
195
|
+
Reassigning ``__class__`` upgrades the already-built Click groups (their instance layout is
|
|
196
|
+
compatible), so this works without rewiring how commands are declared across the codebase.
|
|
197
|
+
"""
|
|
198
|
+
_upgrade(root)
|
|
199
|
+
assert isinstance(root, AgentBricksGroup) # _upgrade just set root.__class__ = AgentBricksGroup
|
|
200
|
+
root.command_sections = sections
|
|
201
|
+
# Override once: every UsageError subclass (NoSuchOption, BadParameter, MissingParameter, …)
|
|
202
|
+
# inherits `show`, so parse-time errors render like the ones we raise. Keeps Click's `main()`
|
|
203
|
+
# intact (exit codes, --help, broken-pipe/abort handling), unlike wrapping the entry point.
|
|
204
|
+
click.exceptions.UsageError.show = _usage_error_show # type: ignore[method-assign]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _upgrade(command: click.Command) -> None:
|
|
208
|
+
# Every command — groups and leaves — renders help through AgentBricksContext, and every epilog
|
|
209
|
+
# renders flush-left (AgentBricksGroup / AgentBricksCommand both mix in _FlushEpilog).
|
|
210
|
+
command.context_class = AgentBricksContext
|
|
211
|
+
if isinstance(command, click.Group):
|
|
212
|
+
if not isinstance(command, AgentBricksGroup):
|
|
213
|
+
command.__class__ = AgentBricksGroup
|
|
214
|
+
for child in command.commands.values():
|
|
215
|
+
_upgrade(child)
|
|
216
|
+
elif not isinstance(command, AgentBricksCommand):
|
|
217
|
+
command.__class__ = AgentBricksCommand
|