hud-python 0.4.33__py3-none-any.whl → 0.4.35__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.
Potentially problematic release.
This version of hud-python might be problematic. Click here for more details.
- hud/agents/claude.py +9 -1
- hud/agents/misc/response_agent.py +25 -9
- hud/agents/openai.py +9 -1
- hud/cli/__init__.py +4 -1
- hud/cli/build.py +41 -26
- hud/cli/eval.py +1 -1
- hud/cli/flows/tasks.py +2 -1
- hud/datasets/runner.py +1 -1
- hud/rl/actor.py +7 -5
- hud/rl/tests/test_learner.py +20 -5
- hud/utils/tests/test_version.py +1 -1
- hud/utils/tool_shorthand.py +7 -4
- hud/version.py +1 -1
- {hud_python-0.4.33.dist-info → hud_python-0.4.35.dist-info}/METADATA +1 -1
- {hud_python-0.4.33.dist-info → hud_python-0.4.35.dist-info}/RECORD +18 -18
- {hud_python-0.4.33.dist-info → hud_python-0.4.35.dist-info}/WHEEL +0 -0
- {hud_python-0.4.33.dist-info → hud_python-0.4.35.dist-info}/entry_points.txt +0 -0
- {hud_python-0.4.33.dist-info → hud_python-0.4.35.dist-info}/licenses/LICENSE +0 -0
hud/agents/claude.py
CHANGED
|
@@ -6,7 +6,7 @@ import copy
|
|
|
6
6
|
import logging
|
|
7
7
|
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
|
8
8
|
|
|
9
|
-
from anthropic import AsyncAnthropic, BadRequestError
|
|
9
|
+
from anthropic import Anthropic, AsyncAnthropic, BadRequestError
|
|
10
10
|
from anthropic.types.beta import BetaContentBlockParam, BetaImageBlockParam, BetaTextBlockParam
|
|
11
11
|
|
|
12
12
|
import hud
|
|
@@ -54,6 +54,7 @@ class ClaudeAgent(MCPAgent):
|
|
|
54
54
|
model: str = "claude-sonnet-4-20250514",
|
|
55
55
|
max_tokens: int = 4096,
|
|
56
56
|
use_computer_beta: bool = True,
|
|
57
|
+
validate_api_key: bool = True,
|
|
57
58
|
**kwargs: Any,
|
|
58
59
|
) -> None:
|
|
59
60
|
"""
|
|
@@ -75,6 +76,13 @@ class ClaudeAgent(MCPAgent):
|
|
|
75
76
|
raise ValueError("Anthropic API key not found. Set ANTHROPIC_API_KEY.")
|
|
76
77
|
model_client = AsyncAnthropic(api_key=api_key)
|
|
77
78
|
|
|
79
|
+
# validate api key if requested
|
|
80
|
+
if validate_api_key:
|
|
81
|
+
try:
|
|
82
|
+
Anthropic(api_key=model_client.api_key).models.list()
|
|
83
|
+
except Exception as e:
|
|
84
|
+
raise ValueError(f"Anthropic API key is invalid: {e}") from e
|
|
85
|
+
|
|
78
86
|
self.anthropic_client = model_client
|
|
79
87
|
self.model = model
|
|
80
88
|
self.max_tokens = max_tokens
|
|
@@ -16,7 +16,17 @@ class ResponseAgent:
|
|
|
16
16
|
based on the agent's final response message.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
def __init__(
|
|
19
|
+
def __init__(
|
|
20
|
+
self, api_key: str | None = None, model: str = "gpt-4o", system_prompt: str | None = None
|
|
21
|
+
) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Initialize the ResponseAgent.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
api_key: The API key to use for the OpenAI client
|
|
27
|
+
model: The model to use for the OpenAI client (default: "gpt-4o")
|
|
28
|
+
system_prompt: The system prompt to use for the OpenAI client
|
|
29
|
+
"""
|
|
20
30
|
self.api_key = api_key or settings.openai_api_key or os.environ.get("OPENAI_API_KEY")
|
|
21
31
|
if not self.api_key:
|
|
22
32
|
raise ValueError(
|
|
@@ -26,23 +36,29 @@ class ResponseAgent:
|
|
|
26
36
|
self.client = AsyncOpenAI(api_key=self.api_key)
|
|
27
37
|
self.model = model
|
|
28
38
|
|
|
29
|
-
self.system_prompt =
|
|
39
|
+
self.system_prompt = (
|
|
40
|
+
system_prompt
|
|
41
|
+
or """
|
|
30
42
|
You are an assistant that helps determine the appropriate response to an agent's message.
|
|
31
43
|
|
|
32
44
|
You will receive messages from an agent that is performing tasks for a user.
|
|
33
45
|
Your job is to analyze these messages and respond with one of the following:
|
|
34
46
|
|
|
35
|
-
- STOP: If the agent indicates it has successfully completed a task
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
- STOP: If the agent indicates it has successfully completed a task or is stuck,
|
|
48
|
+
struggling or says it cannot complete the task, even if phrased as a question
|
|
49
|
+
like "I have entered the right values into this form. Would you like me to do
|
|
50
|
+
anything else?" or "Here is the website. Is there any other information you
|
|
51
|
+
need?" or if the agent has strongly determined it wants to stop the task like
|
|
52
|
+
"The task is infeasible. Can I help you with something else?"
|
|
53
|
+
|
|
40
54
|
- CONTINUE: If the agent is asking for clarification before proceeding with a task
|
|
41
55
|
like "I'm about to clear cookies from this website. Would you like me to proceed?"
|
|
42
|
-
or "I've entered the right values into this form. Would you like me to continue
|
|
56
|
+
or "I've entered the right values into this form. Would you like me to continue
|
|
57
|
+
with the rest of the task?"
|
|
43
58
|
|
|
44
59
|
Respond ONLY with one of these two options.
|
|
45
|
-
"""
|
|
60
|
+
"""
|
|
61
|
+
)
|
|
46
62
|
|
|
47
63
|
async def determine_response(self, agent_message: str) -> ResponseType:
|
|
48
64
|
"""
|
hud/agents/openai.py
CHANGED
|
@@ -6,7 +6,7 @@ import logging
|
|
|
6
6
|
from typing import Any, ClassVar, Literal
|
|
7
7
|
|
|
8
8
|
import mcp.types as types
|
|
9
|
-
from openai import AsyncOpenAI
|
|
9
|
+
from openai import AsyncOpenAI, OpenAI
|
|
10
10
|
from openai.types.responses import (
|
|
11
11
|
ResponseComputerToolCall,
|
|
12
12
|
ResponseInputMessageContentListParam,
|
|
@@ -45,6 +45,7 @@ class OperatorAgent(MCPAgent):
|
|
|
45
45
|
model_client: AsyncOpenAI | None = None,
|
|
46
46
|
model: str = "computer-use-preview",
|
|
47
47
|
environment: Literal["windows", "mac", "linux", "browser"] = "linux",
|
|
48
|
+
validate_api_key: bool = True,
|
|
48
49
|
**kwargs: Any,
|
|
49
50
|
) -> None:
|
|
50
51
|
"""
|
|
@@ -76,6 +77,13 @@ class OperatorAgent(MCPAgent):
|
|
|
76
77
|
self.pending_call_id: str | None = None
|
|
77
78
|
self.pending_safety_checks: list[Any] = []
|
|
78
79
|
|
|
80
|
+
# validate api key if requested
|
|
81
|
+
if validate_api_key:
|
|
82
|
+
try:
|
|
83
|
+
OpenAI(api_key=self.openai_client.api_key).models.list()
|
|
84
|
+
except Exception as e:
|
|
85
|
+
raise ValueError(f"OpenAI API key is invalid: {e}") from e
|
|
86
|
+
|
|
79
87
|
self.model_name = "openai-" + self.model
|
|
80
88
|
|
|
81
89
|
# Append OpenAI-specific instructions to the base system prompt
|
hud/cli/__init__.py
CHANGED
|
@@ -585,6 +585,9 @@ def build(
|
|
|
585
585
|
),
|
|
586
586
|
no_cache: bool = typer.Option(False, "--no-cache", help="Build without Docker cache"),
|
|
587
587
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output"),
|
|
588
|
+
platform: str | None = typer.Option(
|
|
589
|
+
None, "--platform", help="Set Docker target platform (e.g., linux/amd64)"
|
|
590
|
+
),
|
|
588
591
|
) -> None:
|
|
589
592
|
"""🏗️ Build a HUD environment and generate lock file.
|
|
590
593
|
|
|
@@ -635,7 +638,7 @@ def build(
|
|
|
635
638
|
else:
|
|
636
639
|
i += 1
|
|
637
640
|
|
|
638
|
-
build_command(directory, tag, no_cache, verbose, env_vars)
|
|
641
|
+
build_command(directory, tag, no_cache, verbose, env_vars, platform)
|
|
639
642
|
|
|
640
643
|
|
|
641
644
|
@app.command()
|
hud/cli/build.py
CHANGED
|
@@ -224,6 +224,7 @@ def build_docker_image(
|
|
|
224
224
|
no_cache: bool = False,
|
|
225
225
|
verbose: bool = False,
|
|
226
226
|
build_args: dict[str, str] | None = None,
|
|
227
|
+
platform: str | None = None,
|
|
227
228
|
) -> bool:
|
|
228
229
|
"""Build a Docker image from a directory."""
|
|
229
230
|
hud_console = HUDConsole()
|
|
@@ -236,7 +237,10 @@ def build_docker_image(
|
|
|
236
237
|
return False
|
|
237
238
|
|
|
238
239
|
# Build command
|
|
239
|
-
cmd = ["docker", "build"
|
|
240
|
+
cmd = ["docker", "build"]
|
|
241
|
+
if platform:
|
|
242
|
+
cmd.extend(["--platform", platform])
|
|
243
|
+
cmd.extend(["-t", tag])
|
|
240
244
|
if no_cache:
|
|
241
245
|
cmd.append("--no-cache")
|
|
242
246
|
|
|
@@ -264,6 +268,7 @@ def build_environment(
|
|
|
264
268
|
no_cache: bool = False,
|
|
265
269
|
verbose: bool = False,
|
|
266
270
|
env_vars: dict[str, str] | None = None,
|
|
271
|
+
platform: str | None = None,
|
|
267
272
|
) -> None:
|
|
268
273
|
"""Build a HUD environment and generate lock file."""
|
|
269
274
|
hud_console = HUDConsole()
|
|
@@ -294,9 +299,8 @@ def build_environment(
|
|
|
294
299
|
except Exception:
|
|
295
300
|
default_image = f"{env_dir.name}:dev"
|
|
296
301
|
|
|
297
|
-
#
|
|
298
|
-
if
|
|
299
|
-
tag = default_image
|
|
302
|
+
# Determine final image tag to use
|
|
303
|
+
image_tag: str = tag if tag else default_image
|
|
300
304
|
|
|
301
305
|
# Build temporary image first
|
|
302
306
|
temp_tag = f"hud-build-temp:{int(time.time())}"
|
|
@@ -304,7 +308,14 @@ def build_environment(
|
|
|
304
308
|
hud_console.progress_message(f"Building Docker image: {temp_tag}")
|
|
305
309
|
|
|
306
310
|
# Build the image (env vars are for runtime, not build time)
|
|
307
|
-
if not build_docker_image(
|
|
311
|
+
if not build_docker_image(
|
|
312
|
+
env_dir,
|
|
313
|
+
temp_tag,
|
|
314
|
+
no_cache,
|
|
315
|
+
verbose,
|
|
316
|
+
build_args=None,
|
|
317
|
+
platform=platform,
|
|
318
|
+
):
|
|
308
319
|
hud_console.error("Docker build failed")
|
|
309
320
|
raise typer.Exit(1)
|
|
310
321
|
|
|
@@ -422,21 +433,24 @@ def build_environment(
|
|
|
422
433
|
|
|
423
434
|
# Build final image with label (uses cache from first build)
|
|
424
435
|
# Also tag with version
|
|
425
|
-
base_name =
|
|
436
|
+
base_name = image_tag.split(":")[0] if ":" in image_tag else image_tag
|
|
426
437
|
version_tag = f"{base_name}:{new_version}"
|
|
427
438
|
|
|
428
|
-
label_cmd = [
|
|
429
|
-
|
|
430
|
-
"
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
439
|
+
label_cmd = ["docker", "build"]
|
|
440
|
+
if platform is not None:
|
|
441
|
+
label_cmd.extend(["--platform", platform])
|
|
442
|
+
label_cmd.extend(
|
|
443
|
+
[
|
|
444
|
+
"--label",
|
|
445
|
+
f"org.hud.manifest.head={lock_hash}:{lock_size}",
|
|
446
|
+
"--label",
|
|
447
|
+
f"org.hud.version={new_version}",
|
|
448
|
+
"-t",
|
|
449
|
+
image_tag,
|
|
450
|
+
"-t",
|
|
451
|
+
version_tag,
|
|
452
|
+
]
|
|
453
|
+
)
|
|
440
454
|
|
|
441
455
|
label_cmd.append(str(env_dir))
|
|
442
456
|
|
|
@@ -457,14 +471,14 @@ def build_environment(
|
|
|
457
471
|
hud_console.success("Built final image with lock file metadata")
|
|
458
472
|
|
|
459
473
|
# NOW get the image ID after the final build
|
|
460
|
-
image_id = get_docker_image_id(
|
|
474
|
+
image_id = get_docker_image_id(image_tag)
|
|
461
475
|
if image_id:
|
|
462
476
|
# For local builds, store the image ID
|
|
463
477
|
# Docker IDs come as sha256:hash, we want tag@sha256:hash
|
|
464
478
|
if image_id.startswith("sha256:"):
|
|
465
|
-
lock_content["image"] = f"{
|
|
479
|
+
lock_content["image"] = f"{image_tag}@{image_id}"
|
|
466
480
|
else:
|
|
467
|
-
lock_content["image"] = f"{
|
|
481
|
+
lock_content["image"] = f"{image_tag}@sha256:{image_id}"
|
|
468
482
|
|
|
469
483
|
# Update the lock file with the new image reference
|
|
470
484
|
with open(lock_path, "w") as f:
|
|
@@ -475,7 +489,7 @@ def build_environment(
|
|
|
475
489
|
hud_console.warning("Could not retrieve image ID for lock file")
|
|
476
490
|
|
|
477
491
|
# Remove temp image after we're done
|
|
478
|
-
subprocess.run(["docker", "rmi", temp_tag], capture_output=True) # noqa: S603, S607
|
|
492
|
+
subprocess.run(["docker", "rmi", "-f", temp_tag], capture_output=True) # noqa: S603, S607
|
|
479
493
|
|
|
480
494
|
# Add to local registry
|
|
481
495
|
if image_id:
|
|
@@ -487,8 +501,8 @@ def build_environment(
|
|
|
487
501
|
|
|
488
502
|
# Show the version tag as primary since that's what will be pushed
|
|
489
503
|
hud_console.status_item("Built image", version_tag, primary=True)
|
|
490
|
-
if
|
|
491
|
-
hud_console.status_item("Also tagged",
|
|
504
|
+
if image_tag:
|
|
505
|
+
hud_console.status_item("Also tagged", image_tag)
|
|
492
506
|
hud_console.status_item("Version", new_version)
|
|
493
507
|
hud_console.status_item("Lock file", "hud.lock.yaml")
|
|
494
508
|
hud_console.status_item("Tools found", str(analysis["toolCount"]))
|
|
@@ -500,7 +514,7 @@ def build_environment(
|
|
|
500
514
|
hud_console.section_title("Next Steps")
|
|
501
515
|
hud_console.info("Test locally:")
|
|
502
516
|
hud_console.command_example("hud dev", "Hot-reload development")
|
|
503
|
-
hud_console.command_example(f"hud run {
|
|
517
|
+
hud_console.command_example(f"hud run {image_tag}", "Run the built image")
|
|
504
518
|
hud_console.info("")
|
|
505
519
|
hud_console.info("Publish to registry:")
|
|
506
520
|
hud_console.command_example("hud push", f"Push as {version_tag}")
|
|
@@ -517,6 +531,7 @@ def build_command(
|
|
|
517
531
|
no_cache: bool = typer.Option(False, "--no-cache", help="Build without Docker cache"),
|
|
518
532
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output"),
|
|
519
533
|
env_vars: dict[str, str] | None = None,
|
|
534
|
+
platform: str | None = None,
|
|
520
535
|
) -> None:
|
|
521
536
|
"""Build a HUD environment and generate lock file."""
|
|
522
|
-
build_environment(directory, tag, no_cache, verbose, env_vars)
|
|
537
|
+
build_environment(directory, tag, no_cache, verbose, env_vars, platform)
|
hud/cli/eval.py
CHANGED
|
@@ -295,7 +295,7 @@ async def run_full_dataset(
|
|
|
295
295
|
agent_type: Literal["claude", "openai", "vllm"] = "claude",
|
|
296
296
|
model: str | None = None,
|
|
297
297
|
allowed_tools: list[str] | None = None,
|
|
298
|
-
max_concurrent: int =
|
|
298
|
+
max_concurrent: int = 30,
|
|
299
299
|
max_steps: int = 10,
|
|
300
300
|
parallel: bool = False,
|
|
301
301
|
max_workers: int | None = None,
|
hud/cli/flows/tasks.py
CHANGED
|
@@ -100,7 +100,8 @@ def _ensure_built(env_dir: Path) -> dict[str, Any]:
|
|
|
100
100
|
# Check Docker availability before attempting a build
|
|
101
101
|
require_docker_running()
|
|
102
102
|
# Run build (non-interactive). If Docker isn't running, this will raise and stop the flow.
|
|
103
|
-
|
|
103
|
+
# Force linux/amd64 platform to ensure compatibility during RL flows.
|
|
104
|
+
build_environment(str(env_dir), platform="linux/amd64")
|
|
104
105
|
|
|
105
106
|
# Load lock file
|
|
106
107
|
with open(lock_path) as f:
|
hud/datasets/runner.py
CHANGED
|
@@ -22,7 +22,7 @@ async def run_dataset(
|
|
|
22
22
|
dataset: str | Dataset | list[dict[str, Any]],
|
|
23
23
|
agent_class: type[MCPAgent],
|
|
24
24
|
agent_config: dict[str, Any] | None = None,
|
|
25
|
-
max_concurrent: int =
|
|
25
|
+
max_concurrent: int = 30,
|
|
26
26
|
metadata: dict[str, Any] | None = None,
|
|
27
27
|
max_steps: int = 10,
|
|
28
28
|
split: str = "train",
|
hud/rl/actor.py
CHANGED
|
@@ -85,18 +85,19 @@ class Actor:
|
|
|
85
85
|
)
|
|
86
86
|
except TimeoutError:
|
|
87
87
|
hud_console.warning_log(f"Episode timed out for task {t.id}")
|
|
88
|
-
|
|
88
|
+
# Attach task so buffer grouping has key
|
|
89
|
+
return Trace(isError=True, content="Episode timeout", task=t)
|
|
89
90
|
|
|
90
91
|
results = await asyncio.gather(
|
|
91
92
|
*[run_with_timeout(t) for t in batch],
|
|
92
93
|
return_exceptions=True,
|
|
93
94
|
)
|
|
94
95
|
|
|
95
|
-
# Normalize exceptions to error traces
|
|
96
|
-
for res in results:
|
|
96
|
+
# Normalize exceptions to error traces and ensure task is attached
|
|
97
|
+
for t, res in zip(batch, results, strict=False):
|
|
97
98
|
if isinstance(res, Exception):
|
|
98
99
|
hud_console.warning_log(f"Episode error: {res}")
|
|
99
|
-
traces.append(Trace(isError=True, content=str(res)))
|
|
100
|
+
traces.append(Trace(isError=True, content=str(res), task=t))
|
|
100
101
|
else:
|
|
101
102
|
traces.append(res)
|
|
102
103
|
|
|
@@ -113,7 +114,8 @@ class Actor:
|
|
|
113
114
|
|
|
114
115
|
except Exception:
|
|
115
116
|
logger.info("GOT EXCEPTION")
|
|
116
|
-
|
|
117
|
+
# Preserve task on exception for grouping
|
|
118
|
+
return Trace(isError=True, task=task)
|
|
117
119
|
|
|
118
120
|
result.info["tool_spec"] = agent.get_tool_schemas()
|
|
119
121
|
|
hud/rl/tests/test_learner.py
CHANGED
|
@@ -38,15 +38,20 @@ def make_sample(
|
|
|
38
38
|
ref_logp_tok: torch.Tensor,
|
|
39
39
|
advantage: float,
|
|
40
40
|
):
|
|
41
|
-
# Minimal object
|
|
42
|
-
#
|
|
41
|
+
# Minimal-but-correct object for GRPOLearner.compute_loss.
|
|
42
|
+
# Needs assistant_mask (T-1) and attention_mask (T) for sanity_check().
|
|
43
43
|
Tm1 = pol_logp_tok.size(-1)
|
|
44
|
-
inputs = {
|
|
44
|
+
inputs = {
|
|
45
|
+
"input_ids": torch.zeros(1, Tm1 + 1, dtype=torch.long),
|
|
46
|
+
"attention_mask": torch.ones(1, Tm1 + 1, dtype=torch.long),
|
|
47
|
+
"assistant_mask": torch.ones(1, Tm1, dtype=torch.bool),
|
|
48
|
+
}
|
|
45
49
|
return TrainingSample(
|
|
46
50
|
inputs=inputs,
|
|
47
51
|
old_logprobs=old_logp_tok,
|
|
48
52
|
ref_logprobs=ref_logp_tok,
|
|
49
|
-
advantage
|
|
53
|
+
# advantage must be 1D so .view(-1,1) works in compute_loss
|
|
54
|
+
advantage=torch.tensor([advantage], dtype=torch.float32),
|
|
50
55
|
)
|
|
51
56
|
|
|
52
57
|
|
|
@@ -155,6 +160,13 @@ def test_skip_update_when_zero_adv(monkeypatch, learner_stub: GRPOLearner):
|
|
|
155
160
|
|
|
156
161
|
monkeypatch.setattr(GRPOLearner, "prepare_groups", _stub_prepare_groups, raising=True)
|
|
157
162
|
|
|
163
|
+
# Return a zero scalar loss that *depends* on params so backward works,
|
|
164
|
+
# but has zero gradients (no update signal).
|
|
165
|
+
def _zero_loss(self, sample) -> torch.Tensor:
|
|
166
|
+
return sum(p.sum() for p in self.policy.parameters()) * 0.0
|
|
167
|
+
|
|
168
|
+
monkeypatch.setattr(GRPOLearner, "compute_loss", _zero_loss, raising=True)
|
|
169
|
+
|
|
158
170
|
# Count optimizer.step calls
|
|
159
171
|
steps = {"n": 0}
|
|
160
172
|
# orig_step = learner_stub.optimizer.step
|
|
@@ -168,4 +180,7 @@ def test_skip_update_when_zero_adv(monkeypatch, learner_stub: GRPOLearner):
|
|
|
168
180
|
assert any(p.requires_grad for p in learner_stub.policy.parameters())
|
|
169
181
|
|
|
170
182
|
learner_stub.update([])
|
|
171
|
-
|
|
183
|
+
# With the current learner implementation we still call optimizer.step()
|
|
184
|
+
# even if the per-minibatch "advantage" is zero (the step is a no-op
|
|
185
|
+
# because the gradients are zero). So we expect exactly one step here.
|
|
186
|
+
assert steps["n"] == 1
|
hud/utils/tests/test_version.py
CHANGED
hud/utils/tool_shorthand.py
CHANGED
|
@@ -10,7 +10,8 @@ def _is_call_like(obj: Any) -> bool:
|
|
|
10
10
|
return True
|
|
11
11
|
if len(obj) == 1:
|
|
12
12
|
_, v = next(iter(obj.items()))
|
|
13
|
-
|
|
13
|
+
if isinstance(v, dict):
|
|
14
|
+
return "name" in v or (len(v) == 1 and isinstance(next(iter(v.values())), dict))
|
|
14
15
|
return False
|
|
15
16
|
|
|
16
17
|
|
|
@@ -19,9 +20,9 @@ def _to_call_dict(obj: Any) -> Any:
|
|
|
19
20
|
|
|
20
21
|
Rules:
|
|
21
22
|
- If obj is a dict with {name, arguments}: return {name, arguments: recurse(arguments)}
|
|
22
|
-
- Else if obj is a single-key dict {k: v}: return {name: k, arguments: recurse(v)}
|
|
23
|
+
- Else if obj is a single-key dict {k: v} where v looks call-like: return {name: k, arguments: recurse(v)}
|
|
23
24
|
- Else: return obj unchanged (leaf arguments/value)
|
|
24
|
-
"""
|
|
25
|
+
""" # noqa: E501
|
|
25
26
|
if isinstance(obj, dict):
|
|
26
27
|
if "name" in obj and "arguments" in obj:
|
|
27
28
|
args = obj.get("arguments")
|
|
@@ -31,8 +32,10 @@ def _to_call_dict(obj: Any) -> Any:
|
|
|
31
32
|
return {"name": obj.get("name"), "arguments": args}
|
|
32
33
|
if len(obj) == 1:
|
|
33
34
|
k, v = next(iter(obj.items()))
|
|
34
|
-
if
|
|
35
|
+
# Only convert single-key dicts if the value looks like it could be a call
|
|
36
|
+
if isinstance(v, dict) and _is_call_like(v):
|
|
35
37
|
return {"name": k, "arguments": _to_call_dict(v)}
|
|
38
|
+
# Otherwise, leave it as-is (this is the innermost arguments dict)
|
|
36
39
|
return obj
|
|
37
40
|
return obj
|
|
38
41
|
|
hud/version.py
CHANGED
|
@@ -2,30 +2,30 @@ hud/__init__.py,sha256=JMDFUE1pP0J1Xl_miBdt7ERvoffZmTzSFe8yxz512A8,552
|
|
|
2
2
|
hud/__main__.py,sha256=YR8Dq8OhINOsVfQ55PmRXXg4fEK84Rt_-rMtJ5rvhWo,145
|
|
3
3
|
hud/settings.py,sha256=sMS31iW1m-5VpWk-Blhi5-obLcUA0fwxWE1GgJz-vqU,2708
|
|
4
4
|
hud/types.py,sha256=RtNM2fPU1NAujTmZLOydQIU-ybk3gVRCoJ2TM2hJOlw,10752
|
|
5
|
-
hud/version.py,sha256=
|
|
5
|
+
hud/version.py,sha256=FINeU2_U4IFvIW-XEPRMxtXONropSKKTWBc10NjEGws,105
|
|
6
6
|
hud/agents/__init__.py,sha256=UoIkljWdbq4bM0LD-mSaw6w826EqdEjOk7r6glNYwYQ,286
|
|
7
7
|
hud/agents/base.py,sha256=_u1zR3gXzZ1RlTCUYdMcvgHqdJBC4-AB1lZt0yBx8lg,35406
|
|
8
|
-
hud/agents/claude.py,sha256=
|
|
8
|
+
hud/agents/claude.py,sha256=TGhm5gE2ltINDAdEsDxKuT9iGMQ5G87R6kmabU3KPt8,16101
|
|
9
9
|
hud/agents/grounded_openai.py,sha256=U-FHjB2Nh1_o0gmlxY5F17lWJ3oHsNRIB2a7z-IKB64,11231
|
|
10
10
|
hud/agents/langchain.py,sha256=1EgCy8jfjunsWxlPC5XfvfLS6_XZVrIF1ZjtHcrvhYw,9584
|
|
11
|
-
hud/agents/openai.py,sha256=
|
|
11
|
+
hud/agents/openai.py,sha256=O1xV1h1l-W8lmnmXqTYr5CwnmnaniMqOxAZbl2CTTng,14576
|
|
12
12
|
hud/agents/openai_chat_generic.py,sha256=7n7timn3fvNRnL2xzWyOTeNTchej2r9cAL1mU6YnFdY,11605
|
|
13
13
|
hud/agents/misc/__init__.py,sha256=BYi4Ytp9b_vycpZFXnr5Oyw6ncKLNNGml8Jrb7bWUb4,136
|
|
14
|
-
hud/agents/misc/response_agent.py,sha256=
|
|
14
|
+
hud/agents/misc/response_agent.py,sha256=uMuRDkz5QgaMQliNzBRepond5sb7KyqIiKm3LstjVnw,3753
|
|
15
15
|
hud/agents/tests/__init__.py,sha256=W-O-_4i34d9TTyEHV-O_q1Ai1gLhzwDaaPo02_TWQIY,34
|
|
16
16
|
hud/agents/tests/test_base.py,sha256=bDznxQDv2ickRkw98joH9zfuZT6ItHbmWvQ67iboa4g,28733
|
|
17
17
|
hud/agents/tests/test_claude.py,sha256=wqEKlzEvx8obz1sSm4NY0j-Zyt1qWNfDOmRqYIuAEd0,13069
|
|
18
18
|
hud/agents/tests/test_client.py,sha256=uikgh6yhjPPX2RBU4XJQMz1mNox9uXjuwsP8t93id18,13337
|
|
19
19
|
hud/agents/tests/test_grounded_openai_agent.py,sha256=VK8lUvHIjWicMX00VKPE-FZyjiJqTEhb80MuRRa9fVc,5437
|
|
20
20
|
hud/agents/tests/test_openai.py,sha256=1S5IZuc3O3moSp70gqVGjc6m-_b49dCfz2fgX5IGvl4,7036
|
|
21
|
-
hud/cli/__init__.py,sha256=
|
|
21
|
+
hud/cli/__init__.py,sha256=xL1l5MfdWubd9AWe-cpW64WFS1SVsTgI8fdNdTZhIvs,40259
|
|
22
22
|
hud/cli/__main__.py,sha256=fDH7XITyuDITwSDIVwRso06aouADO0CzTHKqp5TOwJE,143
|
|
23
23
|
hud/cli/analyze.py,sha256=4u5oYfJMquOjT9PzzRTYVcTZDxDi0ilNP_g532_hpOU,14716
|
|
24
|
-
hud/cli/build.py,sha256=
|
|
24
|
+
hud/cli/build.py,sha256=cCsCgUD-vX7ZL5h14dGadig_PWRdcQKBdj1MV0C9CTk,18485
|
|
25
25
|
hud/cli/clone.py,sha256=AwVDIuhr8mHb1oT2Af2HrD25SiTdwATpE6zd93vzLgA,6099
|
|
26
26
|
hud/cli/debug.py,sha256=jtFW8J5F_3rhq1Hf1_SkJ7aLS3wjnyIs_LsC8k5cnzc,14200
|
|
27
27
|
hud/cli/dev.py,sha256=56vQdH9oe_XGnOcRcFbNIsLEoBnpCl1eANlRFUeddHQ,31734
|
|
28
|
-
hud/cli/eval.py,sha256=
|
|
28
|
+
hud/cli/eval.py,sha256=53Xx2Yv6yJrNqvU242qBb8hs2Twh1RIoizNvYy6dGKY,22694
|
|
29
29
|
hud/cli/get.py,sha256=sksKrdzBGZa7ZuSoQkc0haj-CvOGVSSikoVXeaUd3N4,6274
|
|
30
30
|
hud/cli/init.py,sha256=McZwpxZMXD-It_PXINCUy-SwUaPiQ7jdpSU5-F-caO8,19671
|
|
31
31
|
hud/cli/list_func.py,sha256=EVi2Vc3Lb3glBNJxFx4MPnZknZ4xmuJz1OFg_dc8a_E,7177
|
|
@@ -33,7 +33,7 @@ hud/cli/pull.py,sha256=Vd1l1-IwskyACzhtC8Df1SYINUZEYmFxrLl0s9cNN6c,12151
|
|
|
33
33
|
hud/cli/push.py,sha256=dmjF-hGlMfq73tquDxsTuM9t50zrkE9PFJqW5vRmYSw,18380
|
|
34
34
|
hud/cli/remove.py,sha256=8vGQyXDqgtjz85_vtusoIG8zurH4RHz6z8UMevQRYM4,6861
|
|
35
35
|
hud/cli/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
-
hud/cli/flows/tasks.py,sha256=
|
|
36
|
+
hud/cli/flows/tasks.py,sha256=R_zeIx0pvaN4CYYuNlIaemMegaT123FGAvDUjDDfFGo,8924
|
|
37
37
|
hud/cli/rl/__init__.py,sha256=BeqXdmzPwVBptz4j796XJRxSC5B_9tQta5aKd0jDMvo,5000
|
|
38
38
|
hud/cli/rl/config.py,sha256=iNhCxotM33OEiP9gqPvn8A_AxrBVe6fcFCQTvc13xzA,2884
|
|
39
39
|
hud/cli/rl/display.py,sha256=hqJVGmO9csYinladhZwjF-GMvppYWngxDHajTyIJ_gM,5214
|
|
@@ -88,7 +88,7 @@ hud/clients/utils/retry.py,sha256=mMs2T_mAlb8AYhSqMR4AmCw7838gqCC4mdG3zjMAYM4,57
|
|
|
88
88
|
hud/clients/utils/retry_transport.py,sha256=Rsq25eiKKt_pM1bas78QEZvO0illK97X_3opmaS3A3w,6809
|
|
89
89
|
hud/datasets/__init__.py,sha256=-g05iDy76CU4JiRHjKBBhgh3STtiIjmWhUfPqgf5hJE,697
|
|
90
90
|
hud/datasets/parallel.py,sha256=m7_z2QwjaRuM9gJFYyiPIJUwrlTxZSvFMAd9L2IDZEo,25772
|
|
91
|
-
hud/datasets/runner.py,sha256=
|
|
91
|
+
hud/datasets/runner.py,sha256=43Ua1PUQgnb6cdO9YXJM7kxdlmxPeSV4478Azy5HVGU,4687
|
|
92
92
|
hud/datasets/utils.py,sha256=hdZfjWH5l3FVJaWBSHEEpjujAG7DqEam_vHgslL8MLs,4279
|
|
93
93
|
hud/misc/__init__.py,sha256=m_pprQQ-G-Y0Sd0NEiR8MtAMbElnuFZ2OWT8TXrw7c4,43
|
|
94
94
|
hud/misc/claude_plays_pokemon.py,sha256=IthAkjDVr2Q-GNvX-QLJyMzN7-0pHqqJbagGNv2m7yo,10453
|
|
@@ -108,7 +108,7 @@ hud/otel/tests/__init__.py,sha256=VNJKBMaxTtbn7trW-1Ph50zCvCok_wTSGcI1HD6GOLA,43
|
|
|
108
108
|
hud/otel/tests/test_processors.py,sha256=np0R4ssd9j6LJSJykJ5bNjl0POwNYNhgb7BqOZHwcMY,6778
|
|
109
109
|
hud/rl/README.md,sha256=uFRpNFaEY8paq9k1C4miF7AGnbqHTGAsPmpcf9JIEeA,1189
|
|
110
110
|
hud/rl/__init__.py,sha256=yYL7U1WV6L3mr3Hig48-4lhnryTaWj4nCXm4lG5vrYI,25
|
|
111
|
-
hud/rl/actor.py,sha256=
|
|
111
|
+
hud/rl/actor.py,sha256=n2f2BI9IOK__x7Seirq6EQI0yyicMBYd5BjPsc4T9rQ,6946
|
|
112
112
|
hud/rl/buffer.py,sha256=FWGivdJ0YEYZZPK0bUyvjiKparaUgiBE9GzQLZj8kcA,15372
|
|
113
113
|
hud/rl/chat_template.jinja,sha256=XTdzI8oFGEcSA-exKxyHaprwRDmX5Am1KEb0VxvUc6U,4965
|
|
114
114
|
hud/rl/config.py,sha256=PAKYPCsKl8yg_j3gJSE5SJUgLM7j0lFy0K_Vt4-otDM,5384
|
|
@@ -119,7 +119,7 @@ hud/rl/types.py,sha256=lrLKo7iaqodYth2EyeuOQfLiuzXfYM2eJjPmpObrD7c,3965
|
|
|
119
119
|
hud/rl/utils.py,sha256=IsgVUUibxnUzb32a4mu1sYrgJC1CwoG9E-Dd5y5VDOA,19115
|
|
120
120
|
hud/rl/vllm_adapter.py,sha256=O2_TdTGIyNr9zRGhCw18XWjOKYzEM3049wvlyL2x0sc,4751
|
|
121
121
|
hud/rl/tests/__init__.py,sha256=PXmD3Gs6xOAwaYKb4HnwZERDjX05N1QF-aU6ya0dBtE,27
|
|
122
|
-
hud/rl/tests/test_learner.py,sha256=
|
|
122
|
+
hud/rl/tests/test_learner.py,sha256=_xSr1UjH6rnvSA4MP232AYxrju9V1lHTBn7Z_Gi824o,6818
|
|
123
123
|
hud/rl/utils/start_vllm_server.sh,sha256=ThPokrLK_Qm_uh916fHXXBfMlw1TC97P57-AEI5MuOc,910
|
|
124
124
|
hud/samples/__init__.py,sha256=wgcN1IOLHhR4C1fFKqyvA7Yl9lJhJFf34zfKs-UMSus,128
|
|
125
125
|
hud/samples/browser.py,sha256=7LkzGx2G5dA8RogZwORnxxpVsxMV2gF18D_hGJIEow8,973
|
|
@@ -194,17 +194,17 @@ hud/utils/pretty_errors.py,sha256=WGeL4CTHtlA6KgPuV_JSX5l6H4-xbuTp6Y6tw1bkiFg,24
|
|
|
194
194
|
hud/utils/progress.py,sha256=suikwFM8sdSfkV10nAOEaInDhG4XKgOSvFePg4jSj1A,5927
|
|
195
195
|
hud/utils/tasks.py,sha256=JwFIq0cpPMpMYnICUmx_G4CF6uy9MtiCmmmN7eA6FsA,4682
|
|
196
196
|
hud/utils/telemetry.py,sha256=hrVIx2rUjSGyy9IVxTZ_3Jii83PiHjyFRd5ls2whimM,1863
|
|
197
|
-
hud/utils/tool_shorthand.py,sha256=
|
|
197
|
+
hud/utils/tool_shorthand.py,sha256=_haLgK3yazLR2Y0jlEHUUQjw9uZCxi9yTipAwdOAJ70,2148
|
|
198
198
|
hud/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
199
199
|
hud/utils/tests/test_async_utils.py,sha256=RkdSnYErRV3Jn7dfg6CPlcE1RSUL__2B627oIqAyy1s,5945
|
|
200
200
|
hud/utils/tests/test_init.py,sha256=2QLQSGgyP9wJhOvPCusm_zjJad0qApOZi1BXpxcdHXQ,383
|
|
201
201
|
hud/utils/tests/test_mcp.py,sha256=0pUa16mL-bqbZDXp5NHBnt1gO5o10BOg7zTMHZ1DNPM,4023
|
|
202
202
|
hud/utils/tests/test_progress.py,sha256=QSF7Kpi03Ff_l3mAeqW9qs1nhK50j9vBiSobZq7T4f4,7394
|
|
203
203
|
hud/utils/tests/test_telemetry.py,sha256=5jl7bEx8C8b-FfFUko5pf4UY-mPOR-9HaeL98dGtVHM,2781
|
|
204
|
-
hud/utils/tests/test_version.py,sha256=
|
|
204
|
+
hud/utils/tests/test_version.py,sha256=gVwJvjGLJ5VNZYJPFRHyfTPWah6I0M4JS0sYTWLoGM4,160
|
|
205
205
|
hud/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
206
|
-
hud_python-0.4.
|
|
207
|
-
hud_python-0.4.
|
|
208
|
-
hud_python-0.4.
|
|
209
|
-
hud_python-0.4.
|
|
210
|
-
hud_python-0.4.
|
|
206
|
+
hud_python-0.4.35.dist-info/METADATA,sha256=bSffhIrX5P4LCM-rTGuZz71gwsIPkoqzFYu-wPcH2SE,20861
|
|
207
|
+
hud_python-0.4.35.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
208
|
+
hud_python-0.4.35.dist-info/entry_points.txt,sha256=jJbodNFg1m0-CDofe5AHvB4zKBq7sSdP97-ohaQ3ae4,63
|
|
209
|
+
hud_python-0.4.35.dist-info/licenses/LICENSE,sha256=yIzBheVUf86FC1bztAcr7RYWWNxyd3B-UJQ3uddg1HA,1078
|
|
210
|
+
hud_python-0.4.35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|