vamp-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.
- vamp_cli/__init__.py +0 -0
- vamp_cli/agent/__init__.py +0 -0
- vamp_cli/agent/context_sync.py +72 -0
- vamp_cli/agent/graph.py +159 -0
- vamp_cli/agent/instructions.py +18 -0
- vamp_cli/agent/nodes.py +375 -0
- vamp_cli/agent/roles.py +8 -0
- vamp_cli/agent/runtime/__init__.py +0 -0
- vamp_cli/agent/runtime/runtime.py +133 -0
- vamp_cli/agent/state.py +55 -0
- vamp_cli/agent/status.py +17 -0
- vamp_cli/config/__init__.py +0 -0
- vamp_cli/config/loader.py +152 -0
- vamp_cli/config/schema.py +82 -0
- vamp_cli/llm/__init__.py +0 -0
- vamp_cli/llm/adapter.py +52 -0
- vamp_cli/llm/adapter_registry.py +26 -0
- vamp_cli/llm/debug_callbacks.py +18 -0
- vamp_cli/llm/router.py +247 -0
- vamp_cli/llm/usage.py +170 -0
- vamp_cli/logging_setup/logging_setup.py +37 -0
- vamp_cli/main.py +1023 -0
- vamp_cli/persistence/__init__.py +29 -0
- vamp_cli/persistence/compaction.py +372 -0
- vamp_cli/persistence/emitter.py +371 -0
- vamp_cli/persistence/event_log.py +303 -0
- vamp_cli/persistence/fork.py +81 -0
- vamp_cli/persistence/loader.py +616 -0
- vamp_cli/persistence/transcript.py +160 -0
- vamp_cli/prompts/prompts.py +182 -0
- vamp_cli/sandbox/__init__.py +0 -0
- vamp_cli/sandbox/base.py +22 -0
- vamp_cli/sandbox/config.py +16 -0
- vamp_cli/sandbox/docker.py +293 -0
- vamp_cli/sandbox/manager.py +31 -0
- vamp_cli/sandbox/result.py +14 -0
- vamp_cli/sandbox/terminal.py +151 -0
- vamp_cli/tools/__init__.py +0 -0
- vamp_cli/tools/base.py +44 -0
- vamp_cli/tools/diagnostic.py +120 -0
- vamp_cli/tools/execute_cmd.py +16 -0
- vamp_cli/tools/files.py +652 -0
- vamp_cli/tools/registry.py +163 -0
- vamp_cli/tools/tools_classes.py +622 -0
- vamp_cli/utils/__init__.py +0 -0
- vamp_cli/utils/error_codes.py +7 -0
- vamp_cli/utils/ignore.py +36 -0
- vamp_cli/utils/sha_256.py +32 -0
- vamp_cli/utils/token_tracker.py +31 -0
- vamp_cli/workspace/__init__.py +0 -0
- vamp_cli/workspace/workspace.py +16 -0
- vamp_cli-0.1.0.dist-info/METADATA +317 -0
- vamp_cli-0.1.0.dist-info/RECORD +57 -0
- vamp_cli-0.1.0.dist-info/WHEEL +5 -0
- vamp_cli-0.1.0.dist-info/entry_points.txt +2 -0
- vamp_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- vamp_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# registry.py
|
|
2
|
+
from typing import Dict, List, Optional, Any
|
|
3
|
+
from vamp_cli.tools.base import Tools
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ToolRegistry:
|
|
7
|
+
"""
|
|
8
|
+
Registry mapping tool names -> tool instances.
|
|
9
|
+
|
|
10
|
+
Tools are expected to inherit from `Tools` (exposing `name`,
|
|
11
|
+
`description`, `input_schema`, `schema()` and `run()`).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
self._tools: Dict[str, Tools] = {}
|
|
16
|
+
|
|
17
|
+
# ------------------------------------------------------------------
|
|
18
|
+
# Registration
|
|
19
|
+
# ------------------------------------------------------------------
|
|
20
|
+
def register(self, tool: Tools) -> None:
|
|
21
|
+
"""Register a single tool. Raises if the name is already taken."""
|
|
22
|
+
if not getattr(tool, "name", None):
|
|
23
|
+
raise ValueError("Tool must define a non-empty `name`.")
|
|
24
|
+
if tool.name in self._tools:
|
|
25
|
+
raise ValueError(f"Tool '{tool.name}' is already registered.")
|
|
26
|
+
self._tools[tool.name] = tool
|
|
27
|
+
|
|
28
|
+
def register_many(self, tools: List[Tools]) -> None:
|
|
29
|
+
"""Register several tools at once (atomic: fails on first conflict)."""
|
|
30
|
+
for tool in tools:
|
|
31
|
+
self.register(tool)
|
|
32
|
+
|
|
33
|
+
def unregister(self, name: str) -> None:
|
|
34
|
+
"""Remove a tool by name. Raises KeyError if not found."""
|
|
35
|
+
if name not in self._tools:
|
|
36
|
+
raise KeyError(f"Tool '{name}' not found.")
|
|
37
|
+
del self._tools[name]
|
|
38
|
+
|
|
39
|
+
def clear(self) -> None:
|
|
40
|
+
"""Remove all registered tools."""
|
|
41
|
+
self._tools.clear()
|
|
42
|
+
|
|
43
|
+
# ------------------------------------------------------------------
|
|
44
|
+
# Lookup
|
|
45
|
+
# ------------------------------------------------------------------
|
|
46
|
+
def get_tool(self, name: str) -> Dict[str, Tools]:
|
|
47
|
+
"""
|
|
48
|
+
Return a single tool as `{name: tool_object}`.
|
|
49
|
+
Raises KeyError if the tool is not registered.
|
|
50
|
+
"""
|
|
51
|
+
if name not in self._tools:
|
|
52
|
+
raise KeyError(f"Tool '{name}' not found.")
|
|
53
|
+
return {name: self._tools[name]}
|
|
54
|
+
|
|
55
|
+
def get_optional_tool(self, name: str) -> Optional[Dict[str, Tools]]:
|
|
56
|
+
"""
|
|
57
|
+
Return `{name: tool_object}` if registered, otherwise None.
|
|
58
|
+
"""
|
|
59
|
+
tool = self._tools.get(name)
|
|
60
|
+
return {name: tool} if tool is not None else None
|
|
61
|
+
|
|
62
|
+
def get_tools(self, names: List[str]) -> Dict[str, Tools]:
|
|
63
|
+
"""
|
|
64
|
+
Resolve a list of tool names to `{name: tool_object}`.
|
|
65
|
+
|
|
66
|
+
- Missing tools are skipped silently.
|
|
67
|
+
- Duplicate names collapse into a single entry.
|
|
68
|
+
"""
|
|
69
|
+
resolved: Dict[str, Tools] = {}
|
|
70
|
+
for name in names:
|
|
71
|
+
tool = self._tools.get(name)
|
|
72
|
+
if tool is not None:
|
|
73
|
+
resolved[name] = tool
|
|
74
|
+
return resolved
|
|
75
|
+
|
|
76
|
+
def get_tools_strict(self, names: List[str]) -> Dict[str, Tools]:
|
|
77
|
+
"""
|
|
78
|
+
Same as `get_tools` but raises KeyError listing every missing name.
|
|
79
|
+
"""
|
|
80
|
+
missing = [n for n in names if n not in self._tools]
|
|
81
|
+
if missing:
|
|
82
|
+
raise KeyError(f"Tool(s) not found: {', '.join(missing)}")
|
|
83
|
+
return {n: self._tools[n] for n in names}
|
|
84
|
+
|
|
85
|
+
def get_all_tools(self) -> Dict[str, Tools]:
|
|
86
|
+
"""Return every registered tool as `{name: tool_object}`."""
|
|
87
|
+
return dict(self._tools)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_tool_list(self, names: Optional[List[str]] = None) -> List[Tools]:
|
|
91
|
+
"""
|
|
92
|
+
Return Tools **objects as a list** — the shape ModelRouter.get expects.
|
|
93
|
+
Unknown names are skipped. Order preserved. Duplicates collapse.
|
|
94
|
+
"""
|
|
95
|
+
if names is None:
|
|
96
|
+
return list(self._tools.values())
|
|
97
|
+
seen: set[str] = set()
|
|
98
|
+
out: List[Tools] = []
|
|
99
|
+
for n in names:
|
|
100
|
+
if n in seen:
|
|
101
|
+
continue
|
|
102
|
+
tool = self._tools.get(n)
|
|
103
|
+
if tool is not None:
|
|
104
|
+
out.append(tool)
|
|
105
|
+
seen.add(n)
|
|
106
|
+
return out
|
|
107
|
+
|
|
108
|
+
def get_openai_tools(self, names: Optional[List[str]] = None) -> List[Dict[str, Any]]:
|
|
109
|
+
"""Ready-to-bind OpenAI-format tool list."""
|
|
110
|
+
return [t.to_openai_tool() for t in self.get_tool_list(names)]
|
|
111
|
+
|
|
112
|
+
# ------------------------------------------------------------------
|
|
113
|
+
# Introspection
|
|
114
|
+
# ------------------------------------------------------------------
|
|
115
|
+
def has_tool(self, name: str) -> bool:
|
|
116
|
+
"""True if a tool with the given name is registered."""
|
|
117
|
+
return name in self._tools
|
|
118
|
+
|
|
119
|
+
def list_tool_names(self) -> List[str]:
|
|
120
|
+
"""All registered tool names."""
|
|
121
|
+
return list(self._tools.keys())
|
|
122
|
+
|
|
123
|
+
def get_schemas(self, names: Optional[List[str]] = None) -> List[dict]:
|
|
124
|
+
"""
|
|
125
|
+
Return schemas for the given names (or all tools when names is None).
|
|
126
|
+
Suitable for passing to the LLM as the tool/function list.
|
|
127
|
+
"""
|
|
128
|
+
if names is None:
|
|
129
|
+
tools = self._tools.values()
|
|
130
|
+
else:
|
|
131
|
+
tools = (self._tools[n] for n in names if n in self._tools)
|
|
132
|
+
return [tool.schema() for tool in tools]
|
|
133
|
+
|
|
134
|
+
def __len__(self) -> int:
|
|
135
|
+
return len(self._tools)
|
|
136
|
+
|
|
137
|
+
def __contains__(self, name: str) -> bool:
|
|
138
|
+
return name in self._tools
|
|
139
|
+
|
|
140
|
+
def __iter__(self):
|
|
141
|
+
return iter(self._tools)
|
|
142
|
+
|
|
143
|
+
def __repr__(self) -> str:
|
|
144
|
+
return f"ToolRegistry(tools={self.list_tool_names()})"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
async def call(self, name: str, args: dict[str, Any]) -> str:
|
|
149
|
+
if name not in self._tools:
|
|
150
|
+
raise KeyError(f"Tool '{name}' not found.")
|
|
151
|
+
return await self._tools[name].arun(**args)
|
|
152
|
+
|
|
153
|
+
def is_parallel_safe(self, name: str) -> bool:
|
|
154
|
+
if name not in self._tools:
|
|
155
|
+
raise KeyError(f"Tool '{name}' not found.")
|
|
156
|
+
return self._tools[name].parallel_safe
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# used in agent langraph loop if llm demands a tool
|
|
161
|
+
|
|
162
|
+
# tool_obj = registry.get_tool(name)[name] # dict as you specified
|
|
163
|
+
# result = tool_obj.run(**json.loads(tool_call["function"]["arguments"]))
|