bat-cli 0.1.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.
- add/__init__.py +3 -0
- add/client.py +16 -0
- bat_cli-0.1.0.dist-info/METADATA +231 -0
- bat_cli-0.1.0.dist-info/RECORD +47 -0
- bat_cli-0.1.0.dist-info/WHEEL +5 -0
- bat_cli-0.1.0.dist-info/entry_points.txt +2 -0
- bat_cli-0.1.0.dist-info/top_level.txt +8 -0
- build/__init__.py +3 -0
- build/build.py +79 -0
- cli.py +260 -0
- create/__init__.py +3 -0
- create/agent.py +312 -0
- create/templates/agent/.dockerignore +3 -0
- create/templates/agent/.env.template +4 -0
- create/templates/agent/.python-version +1 -0
- create/templates/agent/Dockerfile +37 -0
- create/templates/agent/Makefile +34 -0
- create/templates/agent/README.md +1 -0
- create/templates/agent/__main__.py +2 -0
- create/templates/agent/agent.json.template +12 -0
- create/templates/agent/agent.spec +45 -0
- create/templates/agent/config.yaml +1 -0
- create/templates/agent/llm_client.py.template +36 -0
- create/templates/agent/pyproject.toml.template +9 -0
- create/templates/agent/src/__init__.py +0 -0
- create/templates/agent/src/graph.py +50 -0
- create/templates/agent/src/llm_clients/__init__.py +0 -0
- create/templates/agent/tests/__init__.py +0 -0
- eval/__init__.py +1 -0
- eval/commands.py +562 -0
- eval/engine/__init__.py +1 -0
- eval/engine/adapter.py +251 -0
- eval/engine/bench_runner.py +149 -0
- eval/engine/contracts.py +115 -0
- eval/engine/eval_config.py +294 -0
- eval/engine/evaluator.py +85 -0
- eval/engine/metrics/__init__.py +1 -0
- eval/engine/metrics/llm_evaluators.py +383 -0
- eval/engine/metrics/metrics.py +135 -0
- eval/engine/metrics/qualitative_helpers.py +64 -0
- eval/engine/orchestrator.py +157 -0
- eval/engine/plotter.py +347 -0
- image_defaults.py +80 -0
- push/__init__.py +3 -0
- push/push.py +58 -0
- set/__init__.py +3 -0
- set/env.py +50 -0
create/agent.py
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
BAT_ADK_VERSION = "2026.4.23"
|
|
7
|
+
|
|
8
|
+
TEMPLATES_DIR = Path(__file__).resolve().parent / "templates" / "agent"
|
|
9
|
+
_DYNAMIC_TEMPLATE_FILES = {
|
|
10
|
+
".env.template",
|
|
11
|
+
"agent.json.template",
|
|
12
|
+
"agent.spec",
|
|
13
|
+
"Dockerfile",
|
|
14
|
+
"Makefile",
|
|
15
|
+
"llm_client.py.template",
|
|
16
|
+
"pyproject.toml.template",
|
|
17
|
+
"src/graph.py",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _load_static_templates() -> dict[str, str]:
|
|
22
|
+
templates: dict[str, str] = {}
|
|
23
|
+
for template_path in sorted(TEMPLATES_DIR.rglob("*")):
|
|
24
|
+
if not template_path.is_file():
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
relative_path = template_path.relative_to(TEMPLATES_DIR).as_posix()
|
|
28
|
+
if (
|
|
29
|
+
relative_path in _DYNAMIC_TEMPLATE_FILES
|
|
30
|
+
or "__pycache__" in template_path.parts
|
|
31
|
+
or template_path.suffix == ".pyc"
|
|
32
|
+
):
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
templates[relative_path] = template_path.read_text(encoding="utf-8")
|
|
36
|
+
|
|
37
|
+
return templates
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _render_template(template_file: str, replacements: dict[str, str]) -> str:
|
|
41
|
+
template_path = TEMPLATES_DIR / template_file
|
|
42
|
+
if not template_path.exists():
|
|
43
|
+
raise FileNotFoundError(f"Template file not found: {template_path}")
|
|
44
|
+
|
|
45
|
+
rendered = template_path.read_text(encoding="utf-8")
|
|
46
|
+
for key, value in replacements.items():
|
|
47
|
+
rendered = rendered.replace(f"__{key}__", value)
|
|
48
|
+
|
|
49
|
+
return rendered
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _normalize_name(raw: str, style: Literal["project", "snake", "pascal"]) -> str:
|
|
53
|
+
if style == "pascal":
|
|
54
|
+
name = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", raw)
|
|
55
|
+
name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
|
|
56
|
+
name = re.sub(r"[^A-Za-z0-9]+", "_", name)
|
|
57
|
+
name = re.sub(r"_+", "_", name).strip("_")
|
|
58
|
+
parts = [part for part in name.split("_") if part]
|
|
59
|
+
if parts and parts[-1].lower() == "agent":
|
|
60
|
+
parts = parts[:-1]
|
|
61
|
+
if not parts:
|
|
62
|
+
return ""
|
|
63
|
+
return "".join(part[:1].upper() + part[1:] for part in parts)
|
|
64
|
+
|
|
65
|
+
separator = "-" if style == "project" else "_"
|
|
66
|
+
name = re.sub(r"([A-Z]+)([A-Z][a-z])", rf"\1{separator}\2", raw)
|
|
67
|
+
name = re.sub(r"([a-z0-9])([A-Z])", rf"\1{separator}\2", name)
|
|
68
|
+
name = re.sub(r"[^A-Za-z0-9]+", separator, name)
|
|
69
|
+
collapsed_separator = re.escape(separator)
|
|
70
|
+
name = re.sub(rf"{collapsed_separator}+", separator, name).strip(separator)
|
|
71
|
+
|
|
72
|
+
if style == "project":
|
|
73
|
+
project_name = (name or "agent").lower()
|
|
74
|
+
if project_name.endswith("-agent"):
|
|
75
|
+
project_name = project_name[: -len("-agent")]
|
|
76
|
+
return project_name or "agent"
|
|
77
|
+
return name.lower()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _build_pyproject_content(agent_dir_name: str) -> str:
|
|
81
|
+
project_name = _normalize_name(agent_dir_name, "project")
|
|
82
|
+
return _render_template(
|
|
83
|
+
"pyproject.toml.template",
|
|
84
|
+
{
|
|
85
|
+
"BAT_ADK_VERSION": BAT_ADK_VERSION,
|
|
86
|
+
"PROJECT_DESCRIPTION": f"{project_name.upper()} Agent",
|
|
87
|
+
"PROJECT_NAME": project_name,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _build_agent_spec_content(agent_dir_name: str) -> str:
|
|
93
|
+
return _render_template(
|
|
94
|
+
"agent.spec",
|
|
95
|
+
{
|
|
96
|
+
"PROJECT_NAME": _normalize_name(agent_dir_name, "project"),
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _build_dockerfile_content(agent_dir_name: str) -> str:
|
|
102
|
+
return _render_template(
|
|
103
|
+
"Dockerfile",
|
|
104
|
+
{
|
|
105
|
+
"PROJECT_NAME": _normalize_name(agent_dir_name, "project"),
|
|
106
|
+
},
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _build_makefile_content(agent_dir_name: str) -> str:
|
|
111
|
+
return _render_template(
|
|
112
|
+
"Makefile",
|
|
113
|
+
{
|
|
114
|
+
"PROJECT_NAME": _normalize_name(agent_dir_name, "project"),
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _build_graph_content(agent_dir_name: str, clients: list[str] | None) -> str:
|
|
120
|
+
resolved_clients = _resolve_client_specs(clients)
|
|
121
|
+
agent_class_name = _normalize_name(agent_dir_name, "pascal") or "Agent"
|
|
122
|
+
|
|
123
|
+
client_imports = "\n".join(
|
|
124
|
+
f"from .llm_clients.{file_stem} import {class_name}"
|
|
125
|
+
for file_stem, class_name in resolved_clients
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
setup_blocks: list[str] = []
|
|
129
|
+
|
|
130
|
+
for file_stem, class_name in resolved_clients:
|
|
131
|
+
|
|
132
|
+
setup_blocks.append(
|
|
133
|
+
"\n".join(
|
|
134
|
+
[
|
|
135
|
+
f" self.{file_stem} = {class_name}(",
|
|
136
|
+
" tools=[],",
|
|
137
|
+
" )",
|
|
138
|
+
]
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
return _render_template(
|
|
143
|
+
"src/graph.py",
|
|
144
|
+
{
|
|
145
|
+
"AGENT_CLASS_NAME": agent_class_name,
|
|
146
|
+
"CLIENT_IMPORTS": client_imports,
|
|
147
|
+
"CLIENT_SETUP": "\n\n".join(setup_blocks),
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _build_agent_json_content(agent_dir_name: str) -> str:
|
|
153
|
+
return _render_template(
|
|
154
|
+
"agent.json.template",
|
|
155
|
+
{
|
|
156
|
+
"AGENT_NAME": agent_dir_name,
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _build_env_template_content(
|
|
162
|
+
*,
|
|
163
|
+
port: int,
|
|
164
|
+
model: str,
|
|
165
|
+
model_provider: str,
|
|
166
|
+
) -> str:
|
|
167
|
+
return _render_template(
|
|
168
|
+
".env.template",
|
|
169
|
+
{
|
|
170
|
+
"PORT": str(port),
|
|
171
|
+
"MODEL": model,
|
|
172
|
+
"MODEL_PROVIDER": model_provider,
|
|
173
|
+
},
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _build_llm_client_content(class_name: str) -> str:
|
|
178
|
+
return _render_template(
|
|
179
|
+
"llm_client.py.template",
|
|
180
|
+
{
|
|
181
|
+
"CLASS_NAME": class_name,
|
|
182
|
+
},
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _resolve_client_specs(clients: list[str] | None) -> list[tuple[str, str]]:
|
|
187
|
+
if not clients:
|
|
188
|
+
return [("example_client", "ExampleClient")]
|
|
189
|
+
|
|
190
|
+
resolved: list[tuple[str, str]] = []
|
|
191
|
+
seen: set[str] = set()
|
|
192
|
+
|
|
193
|
+
for raw_name in clients:
|
|
194
|
+
snake_name = _normalize_name(raw_name, "snake")
|
|
195
|
+
if not snake_name:
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
file_stem = snake_name if snake_name.endswith("_client") else f"{snake_name}_client"
|
|
199
|
+
if file_stem in seen:
|
|
200
|
+
continue
|
|
201
|
+
|
|
202
|
+
pascal_name = _normalize_name(raw_name, "pascal")
|
|
203
|
+
if not pascal_name:
|
|
204
|
+
continue
|
|
205
|
+
class_name = pascal_name if pascal_name.endswith("Client") else f"{pascal_name}Client"
|
|
206
|
+
|
|
207
|
+
seen.add(file_stem)
|
|
208
|
+
resolved.append((file_stem, class_name))
|
|
209
|
+
|
|
210
|
+
return resolved or [("example_client", "ExampleClient")]
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _write_llm_clients(
|
|
214
|
+
llm_clients_dir: Path,
|
|
215
|
+
*,
|
|
216
|
+
clients: list[str] | None,
|
|
217
|
+
force: bool,
|
|
218
|
+
) -> list[Path]:
|
|
219
|
+
created: list[Path] = []
|
|
220
|
+
for file_stem, class_name in _resolve_client_specs(clients):
|
|
221
|
+
client_path = llm_clients_dir / f"{file_stem}.py"
|
|
222
|
+
if client_path.exists() and not force:
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
client_path.parent.mkdir(parents=True, exist_ok=True)
|
|
226
|
+
client_path.write_text(_build_llm_client_content(class_name), encoding="utf-8")
|
|
227
|
+
created.append(client_path)
|
|
228
|
+
|
|
229
|
+
return created
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def create_agent_scaffold(
|
|
233
|
+
target_dir: Path,
|
|
234
|
+
*,
|
|
235
|
+
force: bool = False,
|
|
236
|
+
clients: list[str] | None = None,
|
|
237
|
+
port: int = 9900,
|
|
238
|
+
model: str = "gpt-4o-mini",
|
|
239
|
+
model_provider: str = "openai",
|
|
240
|
+
) -> list[Path]:
|
|
241
|
+
if target_dir.exists() and any(target_dir.iterdir()) and not force:
|
|
242
|
+
raise FileExistsError(
|
|
243
|
+
f"Target directory '{target_dir}' already exists and is not empty. "
|
|
244
|
+
"Use --force to overwrite files."
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
248
|
+
|
|
249
|
+
created: list[Path] = []
|
|
250
|
+
for relative_path, content in _load_static_templates().items():
|
|
251
|
+
file_path = target_dir / relative_path
|
|
252
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
253
|
+
|
|
254
|
+
if file_path.exists() and not force:
|
|
255
|
+
continue
|
|
256
|
+
|
|
257
|
+
file_path.write_text(content, encoding="utf-8")
|
|
258
|
+
created.append(file_path)
|
|
259
|
+
|
|
260
|
+
pyproject_path = target_dir / "pyproject.toml"
|
|
261
|
+
|
|
262
|
+
if force or not pyproject_path.exists():
|
|
263
|
+
pyproject_path.write_text(_build_pyproject_content(target_dir.name), encoding="utf-8")
|
|
264
|
+
created.append(pyproject_path)
|
|
265
|
+
|
|
266
|
+
agent_json_path = target_dir / "agent.json"
|
|
267
|
+
if force or not agent_json_path.exists():
|
|
268
|
+
agent_json_path.write_text(_build_agent_json_content(target_dir.name), encoding="utf-8")
|
|
269
|
+
created.append(agent_json_path)
|
|
270
|
+
|
|
271
|
+
env_path = target_dir / ".env"
|
|
272
|
+
if force or not env_path.exists():
|
|
273
|
+
env_path.write_text(
|
|
274
|
+
_build_env_template_content(
|
|
275
|
+
port=port,
|
|
276
|
+
model=model,
|
|
277
|
+
model_provider=model_provider,
|
|
278
|
+
),
|
|
279
|
+
encoding="utf-8",
|
|
280
|
+
)
|
|
281
|
+
created.append(env_path)
|
|
282
|
+
|
|
283
|
+
agent_spec_path = target_dir / "agent.spec"
|
|
284
|
+
if force or not agent_spec_path.exists():
|
|
285
|
+
agent_spec_path.write_text(_build_agent_spec_content(target_dir.name), encoding="utf-8")
|
|
286
|
+
created.append(agent_spec_path)
|
|
287
|
+
|
|
288
|
+
dockerfile_path = target_dir / "Dockerfile"
|
|
289
|
+
if force or not dockerfile_path.exists():
|
|
290
|
+
dockerfile_path.write_text(_build_dockerfile_content(target_dir.name), encoding="utf-8")
|
|
291
|
+
created.append(dockerfile_path)
|
|
292
|
+
|
|
293
|
+
makefile_path = target_dir / "Makefile"
|
|
294
|
+
if force or not makefile_path.exists():
|
|
295
|
+
makefile_path.write_text(_build_makefile_content(target_dir.name), encoding="utf-8")
|
|
296
|
+
created.append(makefile_path)
|
|
297
|
+
|
|
298
|
+
graph_path = target_dir / "src" / "graph.py"
|
|
299
|
+
if force or not graph_path.exists():
|
|
300
|
+
graph_path.write_text(_build_graph_content(target_dir.name, clients), encoding="utf-8")
|
|
301
|
+
created.append(graph_path)
|
|
302
|
+
|
|
303
|
+
created.extend(
|
|
304
|
+
_write_llm_clients(
|
|
305
|
+
target_dir / "src" / "llm_clients",
|
|
306
|
+
clients=clients,
|
|
307
|
+
force=force,
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return created
|
|
312
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
FROM ghcr.io/astral-sh/uv:python3.12-bookworm AS base
|
|
2
|
+
FROM debian:bookworm-slim AS runtime
|
|
3
|
+
|
|
4
|
+
# Stage 1: Builder
|
|
5
|
+
FROM base AS builder
|
|
6
|
+
|
|
7
|
+
# Install objdump
|
|
8
|
+
RUN apt-get update && \
|
|
9
|
+
apt-get install -y --no-install-recommends \
|
|
10
|
+
binutils
|
|
11
|
+
|
|
12
|
+
# Copy app files
|
|
13
|
+
WORKDIR /app
|
|
14
|
+
COPY . .
|
|
15
|
+
|
|
16
|
+
# Install dependencies
|
|
17
|
+
RUN uv lock
|
|
18
|
+
RUN uv sync --locked
|
|
19
|
+
|
|
20
|
+
# Build the binary
|
|
21
|
+
RUN uv add pyinstaller
|
|
22
|
+
RUN uv run pyinstaller agent.spec
|
|
23
|
+
|
|
24
|
+
# Strip the binary
|
|
25
|
+
RUN strip dist/__PROJECT_NAME__
|
|
26
|
+
|
|
27
|
+
# Stage 2: Runtime
|
|
28
|
+
FROM runtime
|
|
29
|
+
|
|
30
|
+
# Copy built binary
|
|
31
|
+
COPY --from=builder /app/dist/__PROJECT_NAME__ /app/
|
|
32
|
+
COPY --from=builder /app/agent.json /app/
|
|
33
|
+
COPY --from=builder /app/config.yaml /app/
|
|
34
|
+
|
|
35
|
+
# Entrypoint
|
|
36
|
+
WORKDIR /app
|
|
37
|
+
ENTRYPOINT ["./__PROJECT_NAME__"]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
KUBE_CONFIG := ~/.kube/config
|
|
2
|
+
DOCKER_REGISTRY ?= INSERT_YOUR_DOCKER_REGISTRY_HERE
|
|
3
|
+
VERSION ?= $(shell git describe --tags --always --abbrev --dirty)
|
|
4
|
+
|
|
5
|
+
PORT ?= 9900
|
|
6
|
+
REPO ?= YOUR_REPOSITORY/__PROJECT_NAME__
|
|
7
|
+
TAG ?= latest
|
|
8
|
+
IMAGE := $(DOCKER_REGISTRY)/$(REPO):$(TAG)
|
|
9
|
+
|
|
10
|
+
.PHONY: build run push clean
|
|
11
|
+
|
|
12
|
+
build:
|
|
13
|
+
@echo "Building __PROJECT_NAME__ Agent Docker image with tag: $(IMAGE) - Version: $(VERSION)"
|
|
14
|
+
docker build $(if $(NO_CACHE),--no-cache) \
|
|
15
|
+
--build-arg VERSION=$(VERSION) \
|
|
16
|
+
--tag $(IMAGE) .
|
|
17
|
+
@echo "__PROJECT_NAME__ Agent Docker image built successfully."
|
|
18
|
+
|
|
19
|
+
run:
|
|
20
|
+
docker run --rm \
|
|
21
|
+
-it \
|
|
22
|
+
--env-file .env \
|
|
23
|
+
--network host \
|
|
24
|
+
-p $(PORT):$(PORT) \
|
|
25
|
+
-v $(KUBE_CONFIG):/root/.kube/config:ro \
|
|
26
|
+
$(IMAGE)
|
|
27
|
+
|
|
28
|
+
push:
|
|
29
|
+
@echo "Pushing __PROJECT_NAME__ Agent Docker image with tag: $(IMAGE)"
|
|
30
|
+
docker push $(IMAGE)
|
|
31
|
+
@echo "__PROJECT_NAME__ Agent Docker image pushed successfully."
|
|
32
|
+
|
|
33
|
+
clean:
|
|
34
|
+
docker rmi $(IMAGE) || true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Example BAT Agent
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- mode: python ; coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
datas = [
|
|
4
|
+
('src', 'src'),
|
|
5
|
+
]
|
|
6
|
+
|
|
7
|
+
a = Analysis(
|
|
8
|
+
['__main__.py'],
|
|
9
|
+
pathex=[],
|
|
10
|
+
binaries=[],
|
|
11
|
+
datas=datas,
|
|
12
|
+
hiddenimports=[
|
|
13
|
+
'br_rapp_sdk',
|
|
14
|
+
'br_rapp_sdk.common',
|
|
15
|
+
],
|
|
16
|
+
hookspath=[],
|
|
17
|
+
hooksconfig={},
|
|
18
|
+
runtime_hooks=[],
|
|
19
|
+
excludes=[],
|
|
20
|
+
noarchive=False,
|
|
21
|
+
optimize=0,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
pyz = PYZ(a.pure)
|
|
25
|
+
|
|
26
|
+
exe = EXE(
|
|
27
|
+
pyz,
|
|
28
|
+
a.scripts,
|
|
29
|
+
a.binaries,
|
|
30
|
+
a.datas,
|
|
31
|
+
[],
|
|
32
|
+
name='__PROJECT_NAME__',
|
|
33
|
+
debug=False,
|
|
34
|
+
bootloader_ignore_signals=False,
|
|
35
|
+
strip=False,
|
|
36
|
+
upx=True,
|
|
37
|
+
upx_exclude=[],
|
|
38
|
+
runtime_tmpdir=None,
|
|
39
|
+
console=True,
|
|
40
|
+
disable_windowed_traceback=False,
|
|
41
|
+
argv_emulation=False,
|
|
42
|
+
target_arch=None,
|
|
43
|
+
codesign_identity=None,
|
|
44
|
+
entitlements_file=None,
|
|
45
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
checkpoints: false
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from bat.chat_model_client import ChatModelClient, ChatModelClientConfig
|
|
2
|
+
from langchain_core.messages import HumanMessage
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class __CLASS_NAME__(ChatModelClient):
|
|
6
|
+
|
|
7
|
+
SYSTEM_INSTRUCTIONS = (
|
|
8
|
+
"INSERT INSTRUCTIONS HERE"
|
|
9
|
+
)
|
|
10
|
+
USER_INSTRUCTIONS = (
|
|
11
|
+
"USER QUERY: {message}"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
tools,
|
|
17
|
+
):
|
|
18
|
+
super().__init__(
|
|
19
|
+
system_instructions=self.SYSTEM_INSTRUCTIONS,
|
|
20
|
+
chat_model_config=ChatModelClientConfig.from_env(client_name="__CLASS_NAME__"),
|
|
21
|
+
tools=tools,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def invoke(
|
|
25
|
+
self,
|
|
26
|
+
query: str,
|
|
27
|
+
) -> str:
|
|
28
|
+
"""Format the query based on what the client needs to do."""
|
|
29
|
+
input_message = HumanMessage(
|
|
30
|
+
content=self.USER_INSTRUCTIONS.format(
|
|
31
|
+
message=query,
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
response = super().invoke(input_message)
|
|
35
|
+
response_content = response.content.strip()
|
|
36
|
+
return response_content
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from bat.agent import AgentGraph, AgentState, AgentTaskResult, AgentTaskStatus
|
|
2
|
+
from bat.prebuilt import ReActLoop
|
|
3
|
+
from langgraph.graph import START, END
|
|
4
|
+
from typing import Optional, Self
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
7
|
+
__CLIENT_IMPORTS__
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class __AGENT_CLASS_NAME__AgentState(AgentState):
|
|
11
|
+
query: str
|
|
12
|
+
response: Optional[str] = None
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
@override
|
|
16
|
+
def from_query(
|
|
17
|
+
cls,
|
|
18
|
+
query: str,
|
|
19
|
+
) -> Self:
|
|
20
|
+
return cls(query=query)
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def to_task_result(
|
|
24
|
+
self,
|
|
25
|
+
) -> AgentTaskResult:
|
|
26
|
+
return AgentTaskResult(
|
|
27
|
+
task_status=(
|
|
28
|
+
AgentTaskStatus.AGENT_TASK_STATUS_COMPLETED
|
|
29
|
+
if self.response
|
|
30
|
+
else AgentTaskStatus.AGENT_TASK_STATUS_WORKING
|
|
31
|
+
),
|
|
32
|
+
content=self.response or "Generating response...",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class __AGENT_CLASS_NAME__AgentGraph(AgentGraph):
|
|
37
|
+
@override
|
|
38
|
+
def setup(
|
|
39
|
+
self,
|
|
40
|
+
config,
|
|
41
|
+
) -> None:
|
|
42
|
+
#Client setup
|
|
43
|
+
__CLIENT_SETUP__
|
|
44
|
+
|
|
45
|
+
# Graph wiring
|
|
46
|
+
self.graph_builder.add_edge(
|
|
47
|
+
START,
|
|
48
|
+
END,
|
|
49
|
+
)
|
|
50
|
+
|
|
File without changes
|
|
File without changes
|
eval/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Evaluation command package for bat-cli."""
|