Skip to content

Commit 39b08e1

Browse files
committed
simplify sync client to use updated list files endpoint that includes serialized content
1 parent 1e25281 commit 39b08e1

File tree

2 files changed

+34
-78
lines changed

2 files changed

+34
-78
lines changed

src/humanloop/client.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,11 @@ def __init__(
132132
self.prompts = overload_call(client=self.prompts)
133133
self.prompts = overload_call_with_local_files(
134134
client=self.prompts,
135-
use_local_files=self.use_local_files,
136-
file_type="prompt"
135+
use_local_files=self.use_local_files
137136
)
138137
self.agents = overload_call_with_local_files(
139138
client=self.agents,
140-
use_local_files=self.use_local_files,
141-
file_type="agent"
139+
use_local_files=self.use_local_files
142140
)
143141
self.flows = overload_log(client=self.flows)
144142
self.tools = overload_log(client=self.tools)

src/humanloop/sync/sync_client.py

Lines changed: 32 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -65,53 +65,6 @@ def _save_serialized_file(self, serialized_content: str, file_path: str, file_ty
6565
logger.error(f"Failed to sync {file_type} {file_path}: {str(e)}")
6666
raise
6767

68-
def _process_file(
69-
self,
70-
file: Union[PromptResponse, AgentResponse, ToolResponse, DatasetResponse, EvaluatorResponse, FlowResponse]
71-
) -> None:
72-
"""Process a single file by serializing and saving it.
73-
74-
Args:
75-
file: The file to process (must be a PromptResponse or AgentResponse)
76-
"""
77-
try:
78-
# Skip if not a prompt or agent
79-
if file.type not in ["prompt", "agent"]:
80-
logger.warning(f"Skipping unsupported file type: {file.type}")
81-
return
82-
83-
# Cast to the correct type for type checking
84-
if file.type == "prompt":
85-
file = cast(PromptResponse, file)
86-
elif file.type == "agent":
87-
file = cast(AgentResponse, file)
88-
89-
# Serialize the file based on its type
90-
try:
91-
if file.type == "prompt":
92-
serialized = self.client.prompts.serialize(id=file.id)
93-
elif file.type == "agent":
94-
serialized = self.client.agents.serialize(id=file.id)
95-
else:
96-
logger.warning(f"Skipping unsupported file type: {file.type}")
97-
return
98-
except ApiError as e:
99-
# The SDK returns the YAML content in the error body when it can't parse as JSON
100-
if e.status_code == 200:
101-
serialized = e.body
102-
else:
103-
raise
104-
except Exception as e:
105-
logger.error(f"Failed to serialize {file.type} {file.id}: {str(e)}")
106-
raise
107-
108-
# Save to local filesystem
109-
self._save_serialized_file(serialized, file.path, file.type)
110-
111-
except Exception as e:
112-
logger.error(f"Error processing file {file.path}: {str(e)}")
113-
raise
114-
11568
def pull(self) -> List[str]:
11669
"""Sync prompt and agent files from Humanloop to local filesystem.
11770
@@ -120,37 +73,42 @@ def pull(self) -> List[str]:
12073
"""
12174
successful_files = []
12275
failed_files = []
76+
page = 1
12377

124-
# Create a thread pool for processing files
125-
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
126-
futures = []
127-
page = 1
128-
129-
while True:
130-
try:
131-
response = self.client.files.list_files(type=["prompt", "agent"], page=page)
132-
133-
if len(response.records) == 0:
134-
break
135-
136-
# Submit each file for processing
137-
for file in response.records:
138-
future = executor.submit(self._process_file, file)
139-
futures.append((file.path, future))
78+
while True:
79+
try:
80+
response = self.client.files.list_files(
81+
type=["prompt", "agent"],
82+
page=page,
83+
include_content=True
84+
)
14085

141-
page += 1
142-
except Exception as e:
143-
logger.error(f"Failed to fetch page {page}: {str(e)}")
86+
if len(response.records) == 0:
14487
break
14588

146-
# Wait for all tasks to complete
147-
for file_path, future in futures:
148-
try:
149-
future.result()
150-
successful_files.append(file_path)
151-
except Exception as e:
152-
failed_files.append(file_path)
153-
logger.error(f"Task failed for {file_path}: {str(e)}")
89+
# Process each file
90+
for file in response.records:
91+
# Skip if not a prompt or agent
92+
if file.type not in ["prompt", "agent"]:
93+
logger.warning(f"Skipping unsupported file type: {file.type}")
94+
continue
95+
96+
# Skip if no content
97+
if not getattr(file, "content", None):
98+
logger.warning(f"No content found for {file.type} {getattr(file, 'id', '<unknown>')}")
99+
continue
100+
101+
try:
102+
self._save_serialized_file(file.content, file.path, file.type)
103+
successful_files.append(file.path)
104+
except Exception as e:
105+
failed_files.append(file.path)
106+
logger.error(f"Task failed for {file.path}: {str(e)}")
107+
108+
page += 1
109+
except Exception as e:
110+
logger.error(f"Failed to fetch page {page}: {str(e)}")
111+
break
154112

155113
# Log summary
156114
if successful_files:

0 commit comments

Comments
 (0)