Skip to content

Commit cf2be42

Browse files
[dx] Improve Agent file upload DX with error hook and example
1 parent 4350bd3 commit cf2be42

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

examples/agent_with_file_upload.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# To run the example:
2+
# poetry install
3+
# poetry run python examples/agent_with_file_upload.py
4+
5+
from glean.api_client import Glean, models
6+
import os
7+
8+
9+
def main():
10+
with Glean(
11+
api_token=os.getenv("GLEAN_API_TOKEN", ""),
12+
domain=os.getenv("GLEAN_DOMAIN", "customerName"),
13+
) as glean:
14+
15+
# 1. Upload the file first
16+
file_content = b"name,role\nAlice,Engineer\nBob,Manager"
17+
18+
upload_result = glean.client.chat.upload_files(
19+
files=[
20+
models.File(
21+
file_name="employees.csv",
22+
content=file_content
23+
)
24+
]
25+
)
26+
27+
# 2. Get the ID (string) from the response
28+
file_id = upload_result.files[0].id
29+
30+
# 3. Run the agent passing the file ID (NOT the file object)
31+
res = glean.client.agents.run(
32+
agent_id=os.getenv("GLEAN_AGENT_ID", "<agent-id>"),
33+
input={
34+
# Pass the file ID string to the input parameter
35+
"file": file_id,
36+
"query": "Who is the manager?"
37+
}
38+
)
39+
40+
print(res)
41+
42+
if __name__ == "__main__":
43+
main()
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""Custom hook to provide helpful error messages for agent file upload issues."""
2+
3+
from typing import Optional, Tuple, Union
4+
import httpx
5+
from glean.api_client._hooks.types import AfterErrorContext, AfterErrorHook
6+
7+
8+
class AgentFileUploadErrorHook(AfterErrorHook):
9+
"""
10+
Hook that detects when users incorrectly pass file objects to agents.run()
11+
and provides clear guidance on the correct two-step upload workflow.
12+
13+
This hook intercepts 400 errors from agent run operations that contain
14+
"permission" in the error message, which typically indicates a file was
15+
passed incorrectly instead of a file ID.
16+
"""
17+
18+
def after_error(
19+
self,
20+
hook_ctx: AfterErrorContext,
21+
response: Optional[httpx.Response],
22+
error: Optional[Exception],
23+
) -> Union[Tuple[Optional[httpx.Response], Optional[Exception]], Exception]:
24+
"""
25+
Intercept agent run errors and enhance them with helpful file upload guidance.
26+
27+
Args:
28+
hook_ctx: Context about the operation being performed
29+
response: The HTTP response (if available)
30+
error: The exception that was raised
31+
32+
Returns:
33+
Either a tuple of (response, error) to continue normal error handling,
34+
or a new Exception to replace the original error.
35+
"""
36+
# Only intercept 400 errors from agent run operations
37+
if (
38+
response is not None
39+
and response.status_code == 400
40+
and hook_ctx.operation_id in ["createAndWaitRun", "createAndStreamRun"]
41+
):
42+
error_message = str(error) if error else ""
43+
44+
# Check if this looks like a file upload error
45+
# (API returns "permission" error when file objects are passed incorrectly)
46+
if "permission" in error_message.lower():
47+
# Create enhanced error message with clear instructions
48+
enhanced_message = (
49+
"Agent file upload error: When using agents with file inputs, "
50+
"you must follow a two-step process:\n"
51+
"\n"
52+
"1. First, upload files using client.chat.upload_files():\n"
53+
" from glean.api_client import models\n"
54+
" \n"
55+
" # Upload the file\n"
56+
" upload_result = client.chat.upload_files(\n"
57+
" files=[\n"
58+
" models.File(\n"
59+
" file_name='data.csv',\n"
60+
" content=file_content # bytes or file-like object\n"
61+
" )\n"
62+
" ]\n"
63+
" )\n"
64+
"\n"
65+
"2. Then, pass the returned file IDs (not file objects) in the input field:\n"
66+
" result = client.agents.run(\n"
67+
" agent_id='<agent-id>',\n"
68+
" input={\n"
69+
" 'my_file': upload_result.files[0].id # Use the file ID string\n"
70+
" }\n"
71+
" )\n"
72+
"\n"
73+
"For a complete example, see: examples/agent_with_file_upload.py\n"
74+
f"\nOriginal error: {error_message}"
75+
)
76+
77+
# Return new exception with enhanced message
78+
return Exception(enhanced_message)
79+
80+
# Pass through all other errors unchanged
81+
return response, error

src/glean/api_client/_hooks/registration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from .types import Hooks
22
from .multipart_fix_hook import MultipartFileFieldFixHook
3+
from .agent_file_upload_error_hook import AgentFileUploadErrorHook
34

45

56
# This file is only ever generated once on the first generation and then is free to be modified.
@@ -15,3 +16,6 @@ def init_hooks(hooks: Hooks):
1516

1617
# Register hook to fix multipart file field names that incorrectly have '[]' suffix
1718
hooks.register_sdk_init_hook(MultipartFileFieldFixHook())
19+
20+
# Register hook to provide helpful error messages for agent file upload issues
21+
hooks.register_after_error_hook(AgentFileUploadErrorHook())

0 commit comments

Comments
 (0)