| name | search-objects |
| description | Search, browse, and pull EDSL objects (Surveys, Results, AgentLists, etc.) from Expected Parrot cloud |
| allowed-tools | Read, Glob, Bash(python:*), AskUserQuestion, Write |
| user-invocable | true |
| arguments | search query or UUID |
Search & Pull EDSL Objects from Expected Parrot
Search, browse, and retrieve EDSL objects stored on the Expected Parrot cloud using the Coop API.
Usage
/search-objects customer survey
/search-objects 123e4567-e89b-12d3-a456-426614174000
/search-objects surveys about hiring
/search-objects
Workflow
1. Parse the Input
Determine what the user provided:
- UUID (36-char hex with dashes, pattern
8-4-4-4-12): go directly to step 4 (Retrieve)
- URL (starts with
http): extract UUID or alias, go to step 4
- Search query with type hint (e.g., "surveys about hiring", "results for experiment"): extract the object type and search keywords, go to step 2
- Search query without type hint (e.g., "customer satisfaction"): search across all types, go to step 2
- Nothing or vague: use
AskUserQuestion to ask:
Question: "What are you looking for?"
Header: "Search"
Options:
- "Browse my objects" / "See your own objects on Expected Parrot"
- "Search community" / "Search public objects shared by others"
- "Pull by UUID" / "Retrieve a specific object by its UUID or URL"
Then follow up with type/keyword questions as needed.
2. Search
Run a Python script to search using Coop().list():
from edsl import Coop
coop = Coop()
objects = coop.list(
object_type=None,
search_query="keyword",
visibility=None,
community=False,
page=1,
page_size=10,
sort_ascending=False,
)
print(f"Page {objects.current_page} of {objects.total_pages} ({objects.total_count} total)")
print(f"{'#':<4} {'Type':<15} {'Description':<50} {'Owner':<15} {'Visibility':<10} {'UUID':<36}")
print("-" * 130)
for i, obj in enumerate(objects, 1):
desc = (obj.get("description") or "")[:50]
print(f"{i:<4} {obj['object_type']:<15} {desc:<50} {obj.get('owner_username',''):<15} {obj['visibility']:<10} {obj['uuid']}")
Type extraction hints — map natural language to object_type:
- "survey(s)" →
"survey"
- "result(s)" →
"results"
- "agent(s)" / "agent list(s)" →
"agent_list" (or "agent" for single)
- "scenario(s)" / "scenario list(s)" →
"scenario_list" (or "scenario" for single)
- "question(s)" →
"question"
- "model(s)" →
"model" or "model_list"
- "cache(s)" →
"cache"
- "notebook(s)" →
"notebook"
- "macro(s)" →
"macro" or "composite_macro"
Supported object types (all 13):
agent, agent_list, cache, model, model_list, notebook, question, results, scenario, scenario_list, survey, macro, composite_macro
3. Select
If multiple results are returned, present them to the user with AskUserQuestion:
- Show up to 4 options (the top results) with description snippets as labels and type/owner as descriptions
- Include a "Search again" option if the results don't look right
- If there are more pages, mention it: "Showing page 1 of N (M total results)"
If only one result, confirm with the user before pulling, or proceed directly if the match is clearly what they asked for.
4. Retrieve
Pull the selected object using the class-level .pull() method. First determine the correct class from the object type:
from edsl.coop.utils import ObjectRegistry
edsl_class = ObjectRegistry.get_edsl_class_by_object_type(object_type)
obj = edsl_class.pull(uuid)
Or use Coop().pull() directly:
from edsl import Coop
coop = Coop()
obj = coop.pull(uuid, expected_object_type=object_type)
After pulling, display a summary based on the object type:
| Object Type | Summary to Show |
|---|
survey | Question count, question names, has rules/memory |
results | Row count, column names (answer/agent/scenario columns) |
agent_list | Agent count, trait names, sample agent traits |
agent | Agent name, trait names and values |
scenario_list | Scenario count, key names, sample values |
scenario | Key names and values |
question | Question type, name, text, options (if applicable) |
cache | Entry count |
model / model_list | Model name(s), parameters |
notebook | Cell count |
macro / composite_macro | Description, components |
Summary examples:
print(f"Survey with {len(obj)} questions: {obj.question_names}")
df = obj.to_pandas()
answer_cols = [c for c in df.columns if c.startswith('answer.')]
agent_cols = [c for c in df.columns if c.startswith('agent.')]
scenario_cols = [c for c in df.columns if c.startswith('scenario.')]
print(f"Results: {len(df)} rows, {len(answer_cols)} questions, {len(agent_cols)} agent traits, {len(scenario_cols)} scenario vars")
print(f"AgentList with {len(obj)} agents, traits: {obj.trait_names}")
print(f"ScenarioList with {len(obj)} scenarios, keys: {list(obj[0].keys()) if len(obj) > 0 else []}")
5. Save
Ask the user if and where to save locally:
Question: "Save this object locally?"
Header: "Save"
Options:
- "Yes, default filename" / "Save as {slug}.json.gz in current directory"
- "Yes, custom filename" / "Choose a filename and location"
- "No" / "Don't save, just inspect"
Generate a default filename from the description:
import re
def slugify(text, max_length=60):
text = text.lower().strip()
text = re.sub(r'[^\w\s-]', '', text)
text = re.sub(r'[\s_]+', '-', text)
text = text.strip('-')
if len(text) > max_length:
text = text[:max_length].rsplit('-', 1)[0]
return text
filename = slugify(description) + ".json.gz"
Save using the .save() method:
obj.save(filename)
print(f"Saved to: {filename}")
If "custom filename", use AskUserQuestion to get the desired filename, then save.
6. Report
Summarize what was done:
- What was found (object type, description, owner)
- File path if saved
- Quick-reference for loading it back:
from edsl import {ClassName}
obj = {ClassName}.load("{filename}")
obj = {ClassName}.pull("{uuid}")
Class Name Mapping
Map object types to import names for the load-back reference:
| Object Type | Class Name |
|---|
survey | Survey |
results | Results |
agent | Agent |
agent_list | AgentList |
scenario | Scenario |
scenario_list | ScenarioList |
question | Question |
cache | Cache |
model | Model |
model_list | ModelList |
notebook | Notebook |
macro | Macro |
composite_macro | CompositeMacro |
Pagination
If there are multiple pages of results:
if objects.total_pages > 1:
print(f"\nShowing page {objects.current_page} of {objects.total_pages} ({objects.total_count} total)")
print("Use /search-objects to search again or ask for 'next page'")
To get the next page, re-run with page=page+1.
Error Handling
- No results found: Suggest broadening the search (remove type filter, try different keywords, try
community=True)
- UUID not found: Check if it's a valid UUID format, suggest searching by description instead
- Authentication error: Remind user to set up their Expected Parrot API key (
EXPECTED_PARROT_API_KEY env var or run edsl config)
- Network error: Suggest checking internet connection and trying again
Examples
Search for surveys about customers
/search-objects surveys about customers
→ Extracts type="survey", query="customers" → runs coop.list(object_type="survey", search_query="customers") → shows results → user picks one → pulls and summarizes → offers to save
Pull by UUID
/search-objects 123e4567-e89b-12d3-a456-426614174000
→ Detects UUID → runs coop.pull(uuid) → shows summary → offers to save
Browse community objects
/search-objects
→ No input → asks what user is looking for → user picks "Search community" → asks for type/keywords → searches with community=True → shows results