hud-python 0.4.48__py3-none-any.whl → 0.4.50__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/server/server.py CHANGED
@@ -133,7 +133,9 @@ class MCPServer(FastMCP):
133
133
  FastMCP ``FunctionTool`` interface.
134
134
  """
135
135
 
136
- def __init__(self, *, name: str | None = None, **fastmcp_kwargs: Any) -> None:
136
+ def __init__(
137
+ self, name: str | None = None, instructions: str | None = None, **fastmcp_kwargs: Any
138
+ ) -> None:
137
139
  # Store shutdown function placeholder before super().__init__
138
140
  self._shutdown_fn: Callable | None = None
139
141
 
@@ -179,7 +181,7 @@ class MCPServer(FastMCP):
179
181
 
180
182
  fastmcp_kwargs["lifespan"] = _lifespan
181
183
 
182
- super().__init__(name=name, **fastmcp_kwargs)
184
+ super().__init__(name=name, instructions=instructions, **fastmcp_kwargs)
183
185
  self._initializer_fn: Callable | None = None
184
186
  self._did_init = False
185
187
  self._replaced_server = False
@@ -382,90 +384,255 @@ class MCPServer(FastMCP):
382
384
 
383
385
  return _wrapper
384
386
 
387
+ def include_router(
388
+ self,
389
+ router: FastMCP,
390
+ prefix: str | None = None,
391
+ hidden: bool = False,
392
+ **kwargs: Any,
393
+ ) -> None:
394
+ """Include a router's tools/resources with optional hidden dispatcher pattern.
395
+
396
+ Uses import_server for fast static composition (unlike mount which is slower).
397
+
398
+ Args:
399
+ router: FastMCP router to include
400
+ prefix: Optional prefix for tools/resources (ignored if hidden=True)
401
+ hidden: If True, wrap in HiddenRouter (single dispatcher tool that calls sub-tools)
402
+ **kwargs: Additional arguments passed to import_server()
403
+
404
+ Examples:
405
+ # Direct include - tools appear at top level
406
+ mcp.include_router(tools_router)
407
+
408
+ # Prefixed include - tools get prefix
409
+ mcp.include_router(admin_router, prefix="admin")
410
+
411
+ # Hidden include - single dispatcher tool
412
+ mcp.include_router(setup_router, hidden=True)
413
+ """
414
+ if not hidden:
415
+ # Synchronous composition - directly copy tools/resources
416
+ self._sync_import_router(router, hidden=False, prefix=prefix, **kwargs)
417
+ return
418
+
419
+ # Hidden pattern: wrap in HiddenRouter before importing
420
+ from .router import HiddenRouter
421
+
422
+ # Import the hidden router (synchronous)
423
+ self._sync_import_router(HiddenRouter(router), hidden=True, prefix=prefix, **kwargs)
424
+
425
+ def _sync_import_router(
426
+ self,
427
+ router: FastMCP,
428
+ hidden: bool = False,
429
+ prefix: str | None = None,
430
+ **kwargs: Any,
431
+ ) -> None:
432
+ """Synchronously import tools/resources from a router.
433
+
434
+ This is a synchronous alternative to import_server for use at module import time.
435
+ """
436
+ import re
437
+
438
+ # Import tools directly - use internal dict to preserve keys
439
+ tools = (
440
+ router._tool_manager._tools.items() if not hidden else router._sync_list_tools().items() # type: ignore
441
+ )
442
+ for key, tool in tools:
443
+ # Validate tool name
444
+ if not re.match(r"^[a-zA-Z0-9_-]{1,128}$", key):
445
+ raise ValueError(
446
+ f"Tool name '{key}' must match ^[a-zA-Z0-9_-]{{1,128}}$ "
447
+ "(letters, numbers, underscore, hyphen only, 1-128 chars)"
448
+ )
449
+
450
+ new_key = f"{prefix}_{key}" if prefix else key
451
+ self._tool_manager._tools[new_key] = tool
452
+
453
+ # Import resources directly
454
+ for key, resource in router._resource_manager._resources.items():
455
+ new_key = f"{prefix}_{key}" if prefix else key
456
+ self._resource_manager._resources[new_key] = resource
457
+
458
+ # Import prompts directly
459
+ for key, prompt in router._prompt_manager._prompts.items():
460
+ new_key = f"{prefix}_{key}" if prefix else key
461
+ self._prompt_manager._prompts[new_key] = prompt
462
+ # await self.import_server(hidden_router, prefix=None, **kwargs)
463
+
385
464
  def _register_hud_helpers(self) -> None:
386
- """Register HUD helper HTTP routes.
465
+ """Register development helper endpoints.
387
466
 
388
467
  This adds:
389
- - GET /hud - Overview of available endpoints
390
- - GET /hud/tools - List all registered tools with their schemas
391
- - GET /hud/resources - List all registered resources
392
- - GET /hud/prompts - List all registered prompts
468
+ - GET /docs - Interactive documentation and tool testing
469
+ - POST /api/tools/{name} - REST wrappers for MCP tools
470
+ - GET /openapi.json - OpenAPI spec for REST endpoints
393
471
  """
394
472
 
395
- @self.custom_route("/hud/tools", methods=["GET"])
396
- async def list_tools(request: Request) -> Response:
397
- """List all registered tools with their names, descriptions, and schemas."""
398
- tools = []
399
- # _tools is a mapping of tool_name -> FunctionTool/Tool instance
473
+ # Register REST wrapper for each tool
474
+ def create_tool_endpoint(key: str) -> Any:
475
+ """Create a REST endpoint for an MCP tool."""
476
+
477
+ async def tool_endpoint(request: Request) -> Response:
478
+ """Call MCP tool via REST endpoint."""
479
+ try:
480
+ data = await request.json()
481
+ except Exception:
482
+ data = {}
483
+
484
+ try:
485
+ result = await self._tool_manager.call_tool(key, data)
486
+
487
+ # Recursively serialize MCP objects
488
+ def serialize_obj(obj: Any) -> Any:
489
+ """Recursively serialize MCP objects to JSON-compatible format."""
490
+ if obj is None or isinstance(obj, (str, int, float, bool)):
491
+ return obj
492
+ if isinstance(obj, (list, tuple)):
493
+ return [serialize_obj(item) for item in obj]
494
+ if isinstance(obj, dict):
495
+ return {k: serialize_obj(v) for k, v in obj.items()}
496
+ if hasattr(obj, "model_dump"):
497
+ # Pydantic v2
498
+ return serialize_obj(obj.model_dump())
499
+ if hasattr(obj, "dict"):
500
+ # Pydantic v1
501
+ return serialize_obj(obj.dict())
502
+ if hasattr(obj, "__dict__"):
503
+ # Dataclass or regular class
504
+ return serialize_obj(obj.__dict__)
505
+ # Fallback: convert to string
506
+ return str(obj)
507
+
508
+ serialized = serialize_obj(result)
509
+ return JSONResponse({"success": True, "result": serialized})
510
+ except Exception as e:
511
+ return JSONResponse({"success": False, "error": str(e)}, status_code=400)
512
+
513
+ return tool_endpoint
514
+
515
+ for tool_key in self._tool_manager._tools.keys(): # noqa: SIM118
516
+ endpoint = create_tool_endpoint(tool_key)
517
+ self.custom_route(f"/api/tools/{tool_key}", methods=["POST"])(endpoint)
518
+
519
+ @self.custom_route("/openapi.json", methods=["GET"])
520
+ async def openapi_spec(request: Request) -> Response:
521
+ """Generate OpenAPI spec from MCP tools."""
522
+ spec = {
523
+ "openapi": "3.1.0",
524
+ "info": {
525
+ "title": f"{self.name or 'MCP Server'} - Testing API",
526
+ "version": "1.0.0",
527
+ "description": (
528
+ "REST API wrappers for testing MCP tools. "
529
+ "These endpoints are for development/testing only. "
530
+ "Agents should connect via MCP protocol (JSON-RPC over stdio/HTTP)."
531
+ ),
532
+ },
533
+ "paths": {},
534
+ }
535
+
536
+ # Convert each MCP tool to an OpenAPI path
400
537
  for tool_key, tool in self._tool_manager._tools.items():
401
- tool_data = {"name": tool_key}
402
538
  try:
403
- # Prefer converting to MCP model for consistent fields
404
539
  mcp_tool = tool.to_mcp_tool()
405
- tool_data["description"] = getattr(mcp_tool, "description", "")
406
- if hasattr(mcp_tool, "inputSchema") and mcp_tool.inputSchema:
407
- tool_data["input_schema"] = mcp_tool.inputSchema # type: ignore[assignment]
408
- if hasattr(mcp_tool, "outputSchema") and mcp_tool.outputSchema:
409
- tool_data["output_schema"] = mcp_tool.outputSchema # type: ignore[assignment]
410
- except Exception:
411
- # Fallback to direct attributes on FunctionTool
412
- tool_data["description"] = getattr(tool, "description", "")
413
- params = getattr(tool, "parameters", None)
414
- if params:
415
- tool_data["input_schema"] = params
416
- tools.append(tool_data)
417
-
418
- return JSONResponse({"server": self.name, "tools": tools, "count": len(tools)})
419
-
420
- @self.custom_route("/hud/resources", methods=["GET"])
421
- async def list_resources(request: Request) -> Response:
422
- """List all registered resources."""
423
- resources = []
424
- for resource_key, resource in self._resource_manager._resources.items():
425
- resource_data = {
426
- "uri": resource_key,
427
- "name": resource.name,
428
- "description": resource.description,
429
- "mimeType": resource.mime_type,
430
- }
431
- resources.append(resource_data)
432
-
433
- return JSONResponse(
434
- {"server": self.name, "resources": resources, "count": len(resources)}
435
- )
540
+ input_schema = mcp_tool.inputSchema or {"type": "object"}
541
+
542
+ spec["paths"][f"/api/tools/{tool_key}"] = {
543
+ "post": {
544
+ "summary": tool_key,
545
+ "description": mcp_tool.description or "",
546
+ "operationId": f"call_{tool_key}",
547
+ "requestBody": {
548
+ "required": True,
549
+ "content": {"application/json": {"schema": input_schema}},
550
+ },
551
+ "responses": {
552
+ "200": {
553
+ "description": "Success",
554
+ "content": {
555
+ "application/json": {
556
+ "schema": {
557
+ "type": "object",
558
+ "properties": {
559
+ "success": {"type": "boolean"},
560
+ "result": {"type": "object"},
561
+ },
562
+ }
563
+ }
564
+ },
565
+ }
566
+ },
567
+ }
568
+ }
569
+ except Exception as e:
570
+ logger.warning("Failed to generate spec for %s: %s", tool_key, e)
571
+
572
+ return JSONResponse(spec)
573
+
574
+ @self.custom_route("/docs", methods=["GET"])
575
+ async def docs_page(request: Request) -> Response:
576
+ """Interactive documentation page."""
577
+ import base64
578
+ import json
436
579
 
437
- @self.custom_route("/hud/prompts", methods=["GET"])
438
- async def list_prompts(request: Request) -> Response:
439
- """List all registered prompts."""
440
- prompts = []
441
- for prompt_key, prompt in self._prompt_manager._prompts.items():
442
- prompt_data = {
443
- "name": prompt_key,
444
- "description": prompt.description,
445
- }
446
- # Check if it has arguments
447
- if hasattr(prompt, "arguments") and prompt.arguments:
448
- prompt_data["arguments"] = [
449
- {"name": arg.name, "description": arg.description, "required": arg.required}
450
- for arg in prompt.arguments
451
- ]
452
- prompts.append(prompt_data)
453
-
454
- return JSONResponse({"server": self.name, "prompts": prompts, "count": len(prompts)})
455
-
456
- @self.custom_route("/hud", methods=["GET"])
457
- async def hud_info(request: Request) -> Response:
458
- """Show available HUD helper endpoints."""
459
580
  base_url = str(request.base_url).rstrip("/")
460
- return JSONResponse(
461
- {
462
- "name": "HUD MCP Development Helpers",
463
- "server": self.name,
464
- "endpoints": {
465
- "tools": f"{base_url}/hud/tools",
466
- "resources": f"{base_url}/hud/resources",
467
- "prompts": f"{base_url}/hud/prompts",
468
- },
469
- "description": "These endpoints help you inspect your MCP server during development.", # noqa: E501
470
- }
471
- )
581
+ tool_count = len(self._tool_manager._tools)
582
+ resource_count = len(self._resource_manager._resources)
583
+
584
+ # Generate Cursor deeplink
585
+ server_config = {"url": f"{base_url}/mcp"}
586
+ config_json = json.dumps(server_config, indent=2)
587
+ config_base64 = base64.b64encode(config_json.encode()).decode()
588
+ cursor_deeplink = f"cursor://anysphere.cursor-deeplink/mcp/install?name={self.name or 'mcp-server'}&config={config_base64}" # noqa: E501
589
+
590
+ html = f"""
591
+ <!DOCTYPE html>
592
+ <html lang="en">
593
+ <head>
594
+ <meta charset="UTF-8">
595
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
596
+ <title>{self.name or "MCP Server"} - Documentation</title>
597
+ <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
598
+ <style>
599
+ body {{ margin: 0; padding: 0; font-family: monospace; }}
600
+ .header {{ padding: 1.5rem; border-bottom: 1px solid #e0e0e0; background: #fafafa; }}
601
+ .header h1 {{ margin: 0 0 0.5rem 0; font-size: 1.5rem; color: #000; }}
602
+ .header .info {{ margin: 0.25rem 0; color: #666; font-size: 0.9rem; }}
603
+ .header .warning {{ margin: 0.75rem 0 0 0; padding: 0.5rem; background: #fff3cd; border-left: 3px solid #ffc107; color: #856404; font-size: 0.85rem; }}
604
+ .header a {{ color: #000; text-decoration: underline; }}
605
+ .header a:hover {{ color: #666; }}
606
+ .topbar {{ display: none; }}
607
+ </style>
608
+ </head>
609
+ <body>
610
+ <div class="header">
611
+ <h1>{self.name or "MCP Server"} - Development Tools</h1>
612
+ <div class="info">MCP Endpoint (use this with agents): <a href="{base_url}/mcp">{base_url}/mcp</a></div>
613
+ <div class="info">Tools: {tool_count} | Resources: {resource_count}</div>
614
+ <div class="info">Add to Cursor: <a href="{cursor_deeplink}">Click here to install</a></div>
615
+ <div class="warning">
616
+ ⚠️ The REST API below is for testing only. Agents connect via MCP protocol at <code>{base_url}/mcp</code>
617
+ </div>
618
+ </div>
619
+
620
+ <div id="swagger-ui"></div>
621
+ <script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
622
+ <script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-standalone-preset.js"></script>
623
+ <script>
624
+ window.onload = function() {{
625
+ SwaggerUIBundle({{
626
+ url: '/openapi.json',
627
+ dom_id: '#swagger-ui',
628
+ deepLinking: true,
629
+ presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
630
+ layout: "StandaloneLayout",
631
+ tryItOutEnabled: true
632
+ }})
633
+ }}
634
+ </script>
635
+ </body>
636
+ </html>
637
+ """ # noqa: E501
638
+ return Response(content=html, media_type="text/html")
hud/tools/base.py CHANGED
@@ -144,7 +144,11 @@ _INTERNAL_PREFIX = "int_"
144
144
 
145
145
 
146
146
  class BaseHub(FastMCP):
147
- """A composition-friendly FastMCP server that holds an internal tool dispatcher."""
147
+ """A composition-friendly FastMCP server that holds an internal tool dispatcher.
148
+
149
+ Note: BaseHub can be used standalone or to wrap existing routers. For the newer
150
+ FastAPI-like pattern, consider using HiddenRouter from hud.server instead.
151
+ """
148
152
 
149
153
  env: Any
150
154
 
@@ -167,6 +171,10 @@ class BaseHub(FastMCP):
167
171
  Optional long-lived environment object. Stored on the server
168
172
  instance (``layer.env``) and therefore available to every request
169
173
  via ``ctx.fastmcp.env``.
174
+ title:
175
+ Optional title for the dispatcher tool.
176
+ description:
177
+ Optional description for the dispatcher tool.
170
178
  meta:
171
179
  Metadata to include in MCP tool listing.
172
180
  """
hud/tools/bash.py CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import os
5
5
  import sys
6
- from typing import TYPE_CHECKING, Any
6
+ from typing import TYPE_CHECKING
7
7
 
8
8
  from .base import BaseTool
9
9
  from .types import ContentResult, ToolError
@@ -140,7 +140,7 @@ class BashTool(BaseTool):
140
140
  self.env = value
141
141
 
142
142
  async def __call__(
143
- self, command: str | None = None, restart: bool = False, **kwargs: Any
143
+ self, command: str | None = None, restart: bool = False
144
144
  ) -> list[ContentBlock]:
145
145
  if restart:
146
146
  if self.session:
hud/tools/edit.py CHANGED
@@ -1,16 +1,13 @@
1
- from __future__ import annotations
2
-
3
1
  from collections import defaultdict
4
2
  from pathlib import Path
5
- from typing import TYPE_CHECKING, Any, Literal, get_args
3
+ from typing import Literal, get_args
4
+
5
+ from mcp.types import ContentBlock
6
6
 
7
7
  from .base import BaseTool
8
8
  from .types import ContentResult, ToolError
9
9
  from .utils import maybe_truncate, run
10
10
 
11
- if TYPE_CHECKING:
12
- from mcp.types import ContentBlock
13
-
14
11
  Command = Literal[
15
12
  "view",
16
13
  "create",
@@ -56,7 +53,6 @@ class EditTool(BaseTool):
56
53
  old_str: str | None = None,
57
54
  new_str: str | None = None,
58
55
  insert_line: int | None = None,
59
- **kwargs: Any,
60
56
  ) -> list[ContentBlock]:
61
57
  _path = Path(path)
62
58
  self.validate_path(command, _path)
hud/utils/hud_console.py CHANGED
@@ -38,9 +38,26 @@ TEXT = "bright_white" # Off-white that's readable on dark, not too bright on li
38
38
  SECONDARY = "rgb(108,113,196)" # Muted blue-purple for secondary text
39
39
 
40
40
 
41
+ # HUD Symbol System - Minimal 3-category system with default colors
42
+ class Symbols:
43
+ """Unicode symbols for consistent CLI output with default colors."""
44
+
45
+ # Info/Items - Use for all informational lines (gold)
46
+ ITEM = f"[{GOLD}]•[/{GOLD}]"
47
+
48
+ # Status - Use for state/completion (green)
49
+ SUCCESS = f"[{GREEN}]●[/{GREEN}]"
50
+
51
+ # Flow/Special - Use for transitions and important notes (gold)
52
+ FLOW = f"[{GOLD}]⟿[/{GOLD}]"
53
+
54
+
41
55
  class HUDConsole:
42
56
  """Design system for HUD CLI output."""
43
57
 
58
+ # Make symbols easily accessible
59
+ sym = Symbols
60
+
44
61
  def __init__(self, logger: logging.Logger | None = None) -> None:
45
62
  """Initialize the design system.
46
63
 
@@ -547,6 +564,32 @@ class HUDConsole:
547
564
  """
548
565
  return questionary.confirm(message, default=default).ask()
549
566
 
567
+ # Symbol-based output methods
568
+ def symbol(self, symbol: str, message: str, color: str = GOLD, stderr: bool = True) -> None:
569
+ """Print a message with a colored symbol prefix.
570
+
571
+ Args:
572
+ symbol: Symbol to use (use Symbols.* constants)
573
+ message: Message text
574
+ color: Color for the symbol (default: gold)
575
+ stderr: If True, output to stderr
576
+ """
577
+ console = self._stderr_console if stderr else self._stdout_console
578
+ console.print(f"[{color}]{symbol}[/{color}] {message}")
579
+
580
+ def detail(self, message: str, stderr: bool = True) -> None:
581
+ """Print an indented detail line with gold pointer symbol."""
582
+ console = self._stderr_console if stderr else self._stdout_console
583
+ console.print(f" [{GOLD}]{Symbols.ITEM}[/{GOLD}] {message}")
584
+
585
+ def flow(self, message: str, stderr: bool = True) -> None:
586
+ """Print a flow/transition message with wave symbol."""
587
+ self.symbol(Symbols.FLOW, message, GOLD, stderr)
588
+
589
+ def note(self, message: str, stderr: bool = True) -> None:
590
+ """Print an important note with asterism symbol."""
591
+ self.symbol(Symbols.ITEM, message, GOLD, stderr)
592
+
550
593
 
551
594
  # Global design instance for convenience
552
595
  class _ProgressContext:
@@ -5,4 +5,4 @@ def test_import():
5
5
  """Test that the package can be imported."""
6
6
  import hud
7
7
 
8
- assert hud.__version__ == "0.4.48"
8
+ assert hud.__version__ == "0.4.50"
hud/version.py CHANGED
@@ -4,4 +4,4 @@ Version information for the HUD SDK.
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- __version__ = "0.4.48"
7
+ __version__ = "0.4.50"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hud-python
3
- Version: 0.4.48
3
+ Version: 0.4.50
4
4
  Summary: SDK for the HUD platform.
5
5
  Project-URL: Homepage, https://github.com/hud-evals/hud-python
6
6
  Project-URL: Bug Tracker, https://github.com/hud-evals/hud-python/issues
@@ -2,11 +2,11 @@ hud/__init__.py,sha256=JMDFUE1pP0J1Xl_miBdt7ERvoffZmTzSFe8yxz512A8,552
2
2
  hud/__main__.py,sha256=YR8Dq8OhINOsVfQ55PmRXXg4fEK84Rt_-rMtJ5rvhWo,145
3
3
  hud/settings.py,sha256=disObWa-DgXzoDcCDp3y1dTPaNsbR0IvoMJL9Eg4zyo,3947
4
4
  hud/types.py,sha256=KCVrglSG0VK-AUCFgG5CLgDcYqokvYgZG1r2Bsc-tBg,11155
5
- hud/version.py,sha256=g5fdXaHwGZt72TVKdIdjmUYOAUSz_noNuMRswjk0MNw,105
5
+ hud/version.py,sha256=n0UAZxOUNvgBT83XVdXaBuxxtW1D_o4cgeK4Myy1HO8,105
6
6
  hud/agents/__init__.py,sha256=UoIkljWdbq4bM0LD-mSaw6w826EqdEjOk7r6glNYwYQ,286
7
- hud/agents/base.py,sha256=PvOLtATNFVSfyNHy7RwCFD-eL4oYqVVYibi8WXHMYC4,31654
7
+ hud/agents/base.py,sha256=5G8Aio50KlDMGi3RjIlzK6fNHlY8YK9y5jhhHTUN5CE,31626
8
8
  hud/agents/claude.py,sha256=0zje6de9_H-QlyDf05BnvtwoLPFnYgXhHgQGEAjwktU,16006
9
- hud/agents/grounded_openai.py,sha256=U-FHjB2Nh1_o0gmlxY5F17lWJ3oHsNRIB2a7z-IKB64,11231
9
+ hud/agents/grounded_openai.py,sha256=UC_Z0BP1fvThB95cCYqvMgaQLYXFYB_8zlawwIphruY,11247
10
10
  hud/agents/langchain.py,sha256=1EgCy8jfjunsWxlPC5XfvfLS6_XZVrIF1ZjtHcrvhYw,9584
11
11
  hud/agents/lite_llm.py,sha256=_3wbUiYCp7q8Vyu9rhaoJDvmb_bsyUsLYWP3iQJ2bHo,2239
12
12
  hud/agents/openai.py,sha256=O1xV1h1l-W8lmnmXqTYr5CwnmnaniMqOxAZbl2CTTng,14576
@@ -20,29 +20,29 @@ hud/agents/tests/test_claude.py,sha256=0nZnfsbGoECvsLPdmaRnc9jVmrehVvc3kxeyiCQI2
20
20
  hud/agents/tests/test_client.py,sha256=uikgh6yhjPPX2RBU4XJQMz1mNox9uXjuwsP8t93id18,13337
21
21
  hud/agents/tests/test_grounded_openai_agent.py,sha256=VK8lUvHIjWicMX00VKPE-FZyjiJqTEhb80MuRRa9fVc,5437
22
22
  hud/agents/tests/test_openai.py,sha256=dnAFAoBKZf-5dtDpj6UC3q7oZv2tdMFcniPU0emfImw,8020
23
- hud/cli/__init__.py,sha256=JU7NR-If1Q7wLBojku1S8Z17OKLMy1FC-rGdZFmctRY,46230
23
+ hud/cli/__init__.py,sha256=D32zOZKmp-KDTtXj7H2uYPTh-fOmnwGmIitHAU6eVKs,41422
24
24
  hud/cli/__main__.py,sha256=fDH7XITyuDITwSDIVwRso06aouADO0CzTHKqp5TOwJE,143
25
25
  hud/cli/analyze.py,sha256=4u5oYfJMquOjT9PzzRTYVcTZDxDi0ilNP_g532_hpOU,14716
26
- hud/cli/build.py,sha256=h-4SAoe3j8Pth3mPYf26vh7q1Do5JADlvKKwkZrf2AU,19551
26
+ hud/cli/build.py,sha256=aFFWGtO1sQeTonvLsuMeDKG62IkakASbsP7FonGYuxc,22381
27
27
  hud/cli/clone.py,sha256=AwVDIuhr8mHb1oT2Af2HrD25SiTdwATpE6zd93vzLgA,6099
28
28
  hud/cli/debug.py,sha256=jtFW8J5F_3rhq1Hf1_SkJ7aLS3wjnyIs_LsC8k5cnzc,14200
29
- hud/cli/dev.py,sha256=2zUeVz5S__WrV-DLSDqOlQawcJS7eYPKiDRVUaJ8mAk,31579
29
+ hud/cli/dev.py,sha256=mZW66fbtnCHplwGf1UWy72qfVYXnjPBUqVFAOD4v9Hg,23012
30
30
  hud/cli/eval.py,sha256=b91oYXBpODe_R2sRTWItjGceYSzSP5keKVLMkC7uc-Q,26926
31
31
  hud/cli/get.py,sha256=sksKrdzBGZa7ZuSoQkc0haj-CvOGVSSikoVXeaUd3N4,6274
32
- hud/cli/init.py,sha256=YkWxkIDCnhnxGGpbm7IvYMcfDqWuO1X9wxDxE4k-9ew,9721
32
+ hud/cli/init.py,sha256=Iz0fcE8ao50xChCKwbapTwjAPRY0ZDqV6XHLsvCpRC4,9952
33
33
  hud/cli/list_func.py,sha256=EVi2Vc3Lb3glBNJxFx4MPnZknZ4xmuJz1OFg_dc8a_E,7177
34
34
  hud/cli/pull.py,sha256=XGEZ8n60tbzLQP_8d9h7XYmzyCW0e2-Rkr3_tLG7jvw,12449
35
- hud/cli/push.py,sha256=DsXFrMtWBZ-HUxt6VoLihpklk8JJIe2gy-GA4AMg6Kw,18805
35
+ hud/cli/push.py,sha256=rWJIqHebvp3DchK-00L6G0olD3-klsobLutRW4PP_ts,19488
36
36
  hud/cli/remove.py,sha256=8vGQyXDqgtjz85_vtusoIG8zurH4RHz6z8UMevQRYM4,6861
37
37
  hud/cli/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- hud/cli/flows/tasks.py,sha256=wY2dSzBjjEzp2_GZ2wK8C65YlFo-XsKKKC7MPoqUiK8,14396
38
+ hud/cli/flows/tasks.py,sha256=95KyQgrYuZAkhne3O944nXxZVrquD6bR-vNVmrF5Tsg,17208
39
39
  hud/cli/rl/__init__.py,sha256=pGx4WGaL-yGdogJNzgEE7BtjFtT4I9CTI_UdCm49h98,5376
40
40
  hud/cli/rl/celebrate.py,sha256=trGEJn3xebexlHwFVKPJKhRujVVV8sy7TQTJvRd2p9A,5947
41
41
  hud/cli/rl/config.py,sha256=A-4WWwAS68GRKx1cP_DJ-NZD_96cFNnGwx0P3pQT1ps,3271
42
42
  hud/cli/rl/display.py,sha256=hqJVGmO9csYinladhZwjF-GMvppYWngxDHajTyIJ_gM,5214
43
43
  hud/cli/rl/gpu.py,sha256=peXS-NdUF5RyuSs0aZoCzGLboneBUpCy8f9f99WMrG0,2009
44
44
  hud/cli/rl/gpu_utils.py,sha256=0nFRrmJZzLOHh_0bjMhIsBj94PAuu95vwxLd_sa4Q5g,11202
45
- hud/cli/rl/local_runner.py,sha256=-KsZrmBpVjfrkmbPQ3IW0zQSK2dUzD2qNtrP8frY-Zk,23151
45
+ hud/cli/rl/local_runner.py,sha256=_4_Bs8UXPz5Is6PyVg_DnrG0zL_Mr-6DJ5_6jC9o0qA,23199
46
46
  hud/cli/rl/presets.py,sha256=DzOO82xL5QyzdVtlX-Do1CODMvDz9ILMPapjU92jcZg,3051
47
47
  hud/cli/rl/remote_runner.py,sha256=fKmOVKSBUWfakunfe9-HAllpUJDxfRNZwL00fPw-QTI,17837
48
48
  hud/cli/rl/rl_api.py,sha256=fvRMWQXhTSLM2zQaWWDas_u47RreH8erLgtXRKnQGeA,4350
@@ -58,10 +58,10 @@ hud/cli/tests/test_cli_main.py,sha256=0wMho9p9NcGjp0jLiUtCQh_FYdbMaCJtSY3sBbSgPw
58
58
  hud/cli/tests/test_clone.py,sha256=oC2mf-41QQVc7ODJkjrWbVPNMB2fDW3nZ6jY6w93gvQ,4458
59
59
  hud/cli/tests/test_cursor.py,sha256=ZfxAFKJesJ3UV1JBoASSRlv6BXbpvVEk_pjxUg1jnf4,9821
60
60
  hud/cli/tests/test_debug.py,sha256=bQ76d_0HJfthHBSECmGNv499ZE57CIOKsanMlNfNHGk,18036
61
- hud/cli/tests/test_eval.py,sha256=r_0SSi3o6YX2YVj1fNlHc0bUd-7sxHMksGFNodolSQg,22091
61
+ hud/cli/tests/test_eval.py,sha256=URvNJBlwgbA8MTZhMbuTmGa2TETo4TPRm_G482CSQVM,22021
62
62
  hud/cli/tests/test_list_func.py,sha256=pkG4TtJJBMi9Xk8KBNFBlGcam7kwz01IRsjfQBL2PxM,10700
63
63
  hud/cli/tests/test_main_module.py,sha256=6RhwCcdRSN2uQV6-adti40ZcLd3u-mPR1ai6wL64c6Y,1105
64
- hud/cli/tests/test_mcp_server.py,sha256=37rlL4aTDl1rFmDJOaHerIiK2NfiDktWsqgzkD1ZXnQ,3921
64
+ hud/cli/tests/test_mcp_server.py,sha256=2RzAdhHrBOn-FLsMfZ4CJd2z7xJEA-W7Ytd1RTIP_os,890
65
65
  hud/cli/tests/test_pull.py,sha256=ToSJrlfn13pYnrWWt3W_S7qFFjwvoZC2UisrZVrxujo,13155
66
66
  hud/cli/tests/test_push.py,sha256=V71KP5gEDo7Z9ccFpjidBjYliFg_KCfnZoZYbBXjguE,12875
67
67
  hud/cli/tests/test_registry.py,sha256=-o9MvQTcBElteqrg0XW8Bg59KrHCt88ZyPqeaAlyyTg,9539
@@ -70,7 +70,7 @@ hud/cli/utils/__init__.py,sha256=L6s0oNzY2LugGp9faodCPnjzM-ZUorUH05-HmYOq5hY,35
70
70
  hud/cli/utils/config.py,sha256=AnsN6FEa8V3jg3EWaqUJN38-UuYC6tVZxPfBb_5LFBs,2652
71
71
  hud/cli/utils/cursor.py,sha256=fy850p0rVp5k_1wwOCI7rK1SggbselJrywFInSQ2gio,3009
72
72
  hud/cli/utils/docker.py,sha256=oGVzPfp0Rn89o9d6tgSEziKy9GXFrYaWn_mjBmGRHe4,6326
73
- hud/cli/utils/env_check.py,sha256=TqsmwgTfMDzfP0Ii50YxDkOP4_T5nqks9JMTxIq60-s,7095
73
+ hud/cli/utils/env_check.py,sha256=qs_earFr9RDjnw6V4Fxeqno5ETOKFb8E1WKee3C3P54,7073
74
74
  hud/cli/utils/environment.py,sha256=cxsNwCfwX2PtCHht9xH_Yo5jpcqANf7h0wa3gfiy5tY,4278
75
75
  hud/cli/utils/interactive.py,sha256=sHhTjaImxlwlZ5_DTXb23Jwrjy5oJ7diB-8duhHbImU,16647
76
76
  hud/cli/utils/local_runner.py,sha256=jnPFoJu3sCq65LSUapKCkakdlEuz__96oJU_FfOYtEg,6542
@@ -81,7 +81,7 @@ hud/cli/utils/registry.py,sha256=p6IaWmhUbf0Yh6aGa3jIPoSFT2uJPTOVBLS0jpKDUqc,437
81
81
  hud/cli/utils/remote_runner.py,sha256=OOSJ6wU_gS_hJaURDfxZcyekjIIwPQKGN_Pq64tin3E,9505
82
82
  hud/cli/utils/runner.py,sha256=7HxVGa6OTflQnO0FSuRs273wnAmbm7cFRU9RTGL3-Wo,4390
83
83
  hud/cli/utils/server.py,sha256=EE5DJ0RAmXCEjMcZycpAsAxxCj6sOdIsXqPh38kK2ew,7416
84
- hud/cli/utils/source_hash.py,sha256=zQX9Dd3RIumfepxVNBpNmV8DGcWJf8GDG6TMp7waY4k,2962
84
+ hud/cli/utils/source_hash.py,sha256=EDD3KC4pLGBVoSL5UTv1GvF2TAs2ThNHNOhP_5Sbub4,2979
85
85
  hud/cli/utils/tasks.py,sha256=bpH2mQkfgKUpgh1J0NtVxMxcM1jDZk2GAAPQMcqAUz4,826
86
86
  hud/clients/README.md,sha256=XNE3mch95ozDgVqfwCGcrhlHY9CwT1GKfNANNboowto,3826
87
87
  hud/clients/__init__.py,sha256=N5M_gZv4nP7dLRwpAiaqqaxyaLieGW6397FszeG7JGw,364
@@ -134,10 +134,11 @@ hud/rl/tests/test_learner.py,sha256=LfTwB626gWurYfZv91wk8ASETBNqrLh9i_GCMP4CB3E,
134
134
  hud/rl/utils/start_vllm_server.sh,sha256=ThPokrLK_Qm_uh916fHXXBfMlw1TC97P57-AEI5MuOc,910
135
135
  hud/samples/__init__.py,sha256=wgcN1IOLHhR4C1fFKqyvA7Yl9lJhJFf34zfKs-UMSus,128
136
136
  hud/samples/browser.py,sha256=7LkzGx2G5dA8RogZwORnxxpVsxMV2gF18D_hGJIEow8,973
137
- hud/server/__init__.py,sha256=8LUwgsXO8xiViWP7uImDwcOsWLu01r5F4r8U8qH3rSY,91
137
+ hud/server/__init__.py,sha256=ZTxwhR7tMtSE14i1sONTz5UaMXURW1AYoFZMbWGBviU,134
138
138
  hud/server/context.py,sha256=6bCdSzv1FGyItu9472HbbYef279H7QuMGJDR8EtYg5Y,3210
139
139
  hud/server/low_level.py,sha256=XYs2pOJ9kN4OcJ6ahDmXM5mWkzq5wJLpKFInUYrWEok,4701
140
- hud/server/server.py,sha256=epr-yZ7XpyOe-3EPXJy2DgfU3rYCMAEebM9icDotJN4,20132
140
+ hud/server/router.py,sha256=c1dJ8CXqi_oI03WPDXqHH7jotxBY9BDIQsBQy5EoeSM,5336
141
+ hud/server/server.py,sha256=7M2tHH4wHsLfIRhbXgZVJTfJjW1cWGjeMPT_-ysVS_M,27096
141
142
  hud/server/helper/__init__.py,sha256=ZxO8VP3RZEBBp-q65VixuhzQgqEPSVzW0hEY9J9QqDA,116
142
143
  hud/server/tests/__init__.py,sha256=eEYYkxX5Hz9woXVOBJ2H2_CQoEih0vH6nRt3sH2Z8v8,49
143
144
  hud/server/tests/test_add_tool.py,sha256=9Y59LJpow3BQ31Jg7fowhV7nAeyqude9Tap9tEs_vBE,1863
@@ -164,9 +165,9 @@ hud/telemetry/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
164
165
  hud/telemetry/tests/test_replay.py,sha256=eREc6qgSJDRT1pOPdyhiEoEJ9H2yT1ospaU1RvTKlvg,1328
165
166
  hud/telemetry/tests/test_trace.py,sha256=0rxR77CjcStat3ILA9QAswieOJ3J_386QmjmNDp34oA,2486
166
167
  hud/tools/__init__.py,sha256=i6lE0GxYcPnlLLd-55ryCCHo7o9anC4RfqkuYFXvzMQ,1009
167
- hud/tools/base.py,sha256=iS7XDAxJpvvubLltEq70ZiVPeBXvTkSITyyTRJGuybc,17539
168
- hud/tools/bash.py,sha256=LJViMGb3lTGBm_gequVVTM7ySh1Xh9bOOIZXU29Lmrw,5209
169
- hud/tools/edit.py,sha256=N0AYFXp07-vAJy2li7lvHOL6hfgJOU4LL3iLSZrbRWU,12745
168
+ hud/tools/base.py,sha256=IxpnEHfxUtgz1k_w-09l65KKpDV3tQu4WdF3nZDsdwU,17854
169
+ hud/tools/bash.py,sha256=1jl7cpB1ApGXn7Hy8zghJ2fXugEol6UeN0aYUSiM2EQ,5189
170
+ hud/tools/edit.py,sha256=NYQL3coPIaG_-TP6DOpsVWFg1xcaMZwM5LtFye9WgNE,12644
170
171
  hud/tools/playwright.py,sha256=HY91JsC_6cvIa-9W14wIhjsAkAtkLPaXgUqMizTG-1c,14989
171
172
  hud/tools/response.py,sha256=t6Oc8NM4u951A1XMCBaIkFyu3VNEQ8dcWURyTygfZmA,2228
172
173
  hud/tools/submit.py,sha256=hJG2G3Oex4fz_3CsAUVhOhAA56UvDMhquB29xCT-C3M,1973
@@ -208,7 +209,7 @@ hud/utils/__init__.py,sha256=nk9Re6ls2RudAWnAHDWYbLG28AwNF4qMFYf5xQIJhQA,181
208
209
  hud/utils/agent_factories.py,sha256=cvfXByqG6gOYHtm1VGeJjCpxoLxM4aJez8rH-AerP_A,3186
209
210
  hud/utils/async_utils.py,sha256=5cKrJcnaHV2eJNxeyx0r7fPcdPTDBK7kM9-nLaF51X4,2409
210
211
  hud/utils/group_eval.py,sha256=6yXEH8ZRKkR4bBy9-QWGmjlm2IbCnTUZppEFbjTvndY,8352
211
- hud/utils/hud_console.py,sha256=ywTrzyNhWFoQN2PpzpDDKp_32b-ACDvfKQuWxDoF8iE,21898
212
+ hud/utils/hud_console.py,sha256=ms2lXk3ZhYNmpGb0Dn902SKJBYfqo8Aa9DzkkC-xGSI,23597
212
213
  hud/utils/mcp.py,sha256=pMadd7A0DH6Y_aWywKU8jVYu2pRHGPEndV2ZQFrrj60,2888
213
214
  hud/utils/pretty_errors.py,sha256=WGeL4CTHtlA6KgPuV_JSX5l6H4-xbuTp6Y6tw1bkiFg,2430
214
215
  hud/utils/progress.py,sha256=suikwFM8sdSfkV10nAOEaInDhG4XKgOSvFePg4jSj1A,5927
@@ -221,10 +222,10 @@ hud/utils/tests/test_init.py,sha256=2QLQSGgyP9wJhOvPCusm_zjJad0qApOZi1BXpxcdHXQ,
221
222
  hud/utils/tests/test_mcp.py,sha256=0pUa16mL-bqbZDXp5NHBnt1gO5o10BOg7zTMHZ1DNPM,4023
222
223
  hud/utils/tests/test_progress.py,sha256=QSF7Kpi03Ff_l3mAeqW9qs1nhK50j9vBiSobZq7T4f4,7394
223
224
  hud/utils/tests/test_telemetry.py,sha256=5jl7bEx8C8b-FfFUko5pf4UY-mPOR-9HaeL98dGtVHM,2781
224
- hud/utils/tests/test_version.py,sha256=73lvRyZvFwX4Ri3CPvVP6AYnmHx77VjpBvEW78cTxmI,160
225
+ hud/utils/tests/test_version.py,sha256=uQT6fdCFzf7lllZDCeSWGR5Rn30hErcUg843Zmw0rLs,160
225
226
  hud/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
226
- hud_python-0.4.48.dist-info/METADATA,sha256=Srag8Z0B3pI1gSvXT5VMXq1QFjTE7f6KfXeL38bn5QY,22275
227
- hud_python-0.4.48.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
228
- hud_python-0.4.48.dist-info/entry_points.txt,sha256=jJbodNFg1m0-CDofe5AHvB4zKBq7sSdP97-ohaQ3ae4,63
229
- hud_python-0.4.48.dist-info/licenses/LICENSE,sha256=yIzBheVUf86FC1bztAcr7RYWWNxyd3B-UJQ3uddg1HA,1078
230
- hud_python-0.4.48.dist-info/RECORD,,
227
+ hud_python-0.4.50.dist-info/METADATA,sha256=KE0_svesRl5c8jKKIEGoByqyaplSJNkmGj9dk4Jsan0,22275
228
+ hud_python-0.4.50.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
229
+ hud_python-0.4.50.dist-info/entry_points.txt,sha256=jJbodNFg1m0-CDofe5AHvB4zKBq7sSdP97-ohaQ3ae4,63
230
+ hud_python-0.4.50.dist-info/licenses/LICENSE,sha256=yIzBheVUf86FC1bztAcr7RYWWNxyd3B-UJQ3uddg1HA,1078
231
+ hud_python-0.4.50.dist-info/RECORD,,