pasou commited on
Commit
bda5779
·
verified ·
1 Parent(s): bc86bb7

Upload agents.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. agents.md +184 -0
agents.md ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Integration Guide – **openai‑agents‑python** with **Hugging Face CLI**
2
+
3
+ This guide demonstrates idiomatic patterns for invoking `huggingface-cli` commands *from* an **OpenAI Agents SDK** tool, including best practices for streaming, error handling, sandboxing, and leveraging Codex‑like code‑execution helpers.
4
+
5
+ ---
6
+
7
+ ## 1. Quick Start Snippet
8
+
9
+ ```python
10
+ from agents import Agent
11
+ from agents.tool import function_tool
12
+ from agents.run import Runner
13
+ import asyncio, json, textwrap
14
+
15
+ HF_TIMEOUT = 30 # seconds
16
+
17
+ class HFCLIExecutor(Agent):
18
+ name = "AG-EXEC-CLI"
19
+
20
+ @function_tool(name="run_hf_cli", description="Run huggingface-cli commands")
21
+ async def run_hf_cli(self, cmd: str, args: list[str] = []) -> dict:
22
+ """Execute huggingface‑cli <cmd> <args> and return structured result"""
23
+ proc = await asyncio.create_subprocess_exec(
24
+ "huggingface-cli", cmd, *args,
25
+ stdout=asyncio.subprocess.PIPE,
26
+ stderr=asyncio.subprocess.PIPE,
27
+ )
28
+ try:
29
+ stdout, stderr = await asyncio.wait_for(proc.communicate(), HF_TIMEOUT)
30
+ except asyncio.TimeoutError:
31
+ proc.kill()
32
+ return {"exit": -1, "error": "timeout"}
33
+ exit_code = proc.returncode
34
+ # Attempt to parse JSON block if present
35
+ stdout_str = stdout.decode()
36
+ if "{" in stdout_str and "}" in stdout_str:
37
+ try:
38
+ json_block = json.loads(stdout_str[stdout_str.find("{"): stdout_str.rfind("}") + 1])
39
+ parsed = json_block
40
+ except json.JSONDecodeError:
41
+ parsed = stdout_str.strip()
42
+ else:
43
+ parsed = stdout_str.strip()
44
+ return {
45
+ "exit": exit_code,
46
+ "stdout": parsed,
47
+ "stderr": stderr.decode().strip(),
48
+ }
49
+
50
+ if __name__ == "__main__":
51
+ # ad‑hoc run for local dev
52
+ print(asyncio.run(Runner.run(agent=HFCLIExecutor(), input="run_hf_cli cmd='whoami'")))
53
+ ```
54
+
55
+ ### Why this pattern?
56
+
57
+ * **asyncio.create\_subprocess\_exec** avoids blocking the event loop used by other agents.
58
+ * **wait\_for** enforces a hard timeout to keep MCP requests bounded.
59
+ * Outputs are *attempt‑parsed* to JSON if the CLI supports `--json` (e.g., `models list --json`).
60
+
61
+ ---
62
+
63
+ ## 2. Hugging Face CLI JSON‑Friendly Flags
64
+
65
+ | Command | Recommended Flags | Returns JSON? | |
66
+ | --------------- | ---------------------------------------- | --------------- | ------- |
67
+ | `models list` | `--author <org> --sort downloads --json` | ✅ | |
68
+ | `datasets list` | `--json` | ✅ | |
69
+ | `spaces list` | `--json` | ✅ | |
70
+ | `whoami` | *(none)* | ❌ (parse stderr | stdout) |
71
+
72
+ Always pass `--json` when available to make parsing trivial.
73
+
74
+ ---
75
+
76
+ ## 3. Codex Tooling Synergy
77
+
78
+ The **OpenAI Codex Playground** or GPT‑4o‑code model can auto‑generate wrappers for new CLI commands:
79
+
80
+ ```python
81
+ # in a dev notebook
82
+ from openai import OpenAI
83
+ client = OpenAI()
84
+
85
+ generated = client.chat.completions.create(
86
+ model="gpt-4o-code", # Codex style
87
+ messages=[
88
+ {"role": "user", "content": "Write an asyncio Python wrapper for 'huggingface-cli datasets list --json'"}
89
+ ],
90
+ )
91
+ print(generated.choices[0].message.content)
92
+ ```
93
+
94
+ **Tip**: integrate this generation step into `AG-CORE-ORCH` to auto‑scaffold wrappers for infrequent commands.
95
+
96
+ ---
97
+
98
+ ## 4. Authentication Lifecycle Pattern
99
+
100
+ ```python
101
+ class HFAuthMixin:
102
+ async def ensure_login(self, token: str):
103
+ # cache token in Redis or Agent memory
104
+ cached = self.memory.get("hf_token")
105
+ if cached == token:
106
+ return
107
+ await self.run_hf_cli("login", ["--token", token])
108
+ self.memory["hf_token"] = token
109
+ ```
110
+
111
+ Call `ensure_login()` before executing any command requiring auth.
112
+
113
+ ---
114
+
115
+ ## 5. Streaming Large Outputs
116
+
117
+ For listings returning thousands of models, stream lines to the bus:
118
+
119
+ ```python
120
+ async for line in proc.stdout:
121
+ await ctx.emit("stream", line.decode())
122
+ ```
123
+
124
+ Down‑stream agent (`AG-OBS-MON`) or the gateway can chunk‑forward to HTTP clients (Server‑Sent Events or chunked‑transfer).
125
+
126
+ ---
127
+
128
+ ## 6. Error Classification Matrix
129
+
130
+ | Exit Code | Likely Cause | Retry? |
131
+ | --------- | ------------------------------ | ------------- |
132
+ | `0` | success | ─ |
133
+ | `1` | bad flag / auth error | ❌ |
134
+ | `126/127` | command not found / permission | ❌ (ops alert) |
135
+ | `-1` | timeout (killed) | ✅ once |
136
+
137
+ Map these statuses in `AG-CORE-ORCH` to the Failure & Retry Policy (see `agents.md`).
138
+
139
+ ---
140
+
141
+ ## 7. Embedding CLI Logic as Tools vs. External Subprocess
142
+
143
+ * **Pros of subprocess**: decoupled from Python API stability; mirrors real user workflows.
144
+ * **Cons**: slower than `huggingface_hub` SDK for bulk fetches; parsing required.
145
+
146
+ *Recommendation*: keep CLI path for *agentic text* fidelity but optionally fall back to direct SDK calls where performance critical (future optimisation ticket).
147
+
148
+ ---
149
+
150
+ ## 8. Unit Test Template (pytest‑asyncio)
151
+
152
+ ```python
153
+ import pytest, asyncio
154
+ from agents.exec_cli import HFCLIExecutor
155
+
156
+ @pytest.mark.asyncio
157
+ async def test_models_list_json():
158
+ agent = HFCLIExecutor()
159
+ out = await agent.run_hf_cli("models", ["list", "--limit", "1", "--json"])
160
+ assert out["exit"] == 0
161
+ assert isinstance(out["stdout"], list)
162
+ ```
163
+
164
+ ## 9. Delegating via Handoff
165
+
166
+
167
+ Use the `handoff()` helper to create a chat agent that delegates CLI work to another agent. The SDK's `run_demo_loop` utility preserves conversation history between turns.
168
+
169
+ ```python
170
+ from agents.repl import run_demo_loop
171
+ class HFChatAgent(Agent):
172
+ def __init__(self, cli_agent: HFCLIExecutor):
173
+ super().__init__(name="HF-CHAT", tools=[
174
+ handoff(cli_agent, tool_name_override="hf_cli_agent")
175
+ ])
176
+
177
+
178
+ # example interactive session with memory
179
+ asyncio.run(run_demo_loop(HFChatAgent(HFCLIExecutor())))
180
+ ```
181
+
182
+ ---
183
+
184
+ *Last updated: 2025‑06‑28*