================================================================================
EXPLORER 0
================================================================================

--- INPUT PROMPT ---

You are an environment design expert helping to build realistic tool ecosystems for AI agents.

We are building an environment for an AI agent that will assist a user with tasks in a specific domain. You need to propose a COMPONENT (a specific service or system) and then propose tools for that component.

<environment>
A dryland research facility monitoring soil moisture, ephemeral pools, and reptile populations
</environment>

<user>
A herpetologist tracking sidewinder rattlesnake movements
</user>

<existing_components>

Component: Movebank (movebank)
  - movebank_list_animals: Lists animals registered in Movebank. Optionally filters by species or a substring match on the animal name. Returns all animals that match the criteria and includes all fields for each animal. If no filters are provided, returns all animals. If no animals match, returns an empty list. Does not modify data.
    Parameters:
      - species (string) (optional): Exact species name or code to filter animals (e.g., 'Crotalus cerastes').
      - name_query (string) (optional): Case-insensitive substring to match in animal names.
  - movebank_get_tracks: Retrieves movement tracks from Movebank. You can filter by specific track IDs, by animal IDs, and/or by a geographic bounding box defined as [min_lon, min_lat, max_lon, max_lat]. If multiple filters are supplied, only tracks that satisfy all filters are returned. If no filters are provided, returns all tracks. Returns full records (track_id, animal_id, geometry, notes) for every matching track; does not modify data.
    Parameters:
      - track_ids (array) (optional): List of Movebank track IDs to retrieve.
      - animal_ids (array) (optional): List of animal IDs to retrieve tracks for.
      - bbox (array) (optional): Geographic bounding box [min_lon, min_lat, max_lon, max_lat] to select tracks that intersect this area.
  - movebank_upload_track: Creates a new track or updates an existing one for an animal in Movebank. If track_id is provided and exists, the geometry (GeoJSON LineString) and notes are overwritten; otherwise a new track is created and a new track_id is returned. Requires a valid animal_id and a well-formed GeoJSON LineString string for geometry. Notes can include field observations or context, and will be stored as free text. Returns the full saved track record (track_id, animal_id, geometry, notes).
    Parameters:
      - track_id (string) (optional): Existing track ID to update; if omitted, a new track will be created.
      - animal_id (string) (required): Animal ID this track belongs to.
      - geometry (string) (required): GeoJSON LineString representing the track path.
      - notes (string) (optional): Free-text notes to associate with the track.
  - movebank_attach_tag_to_animal: Attaches or reassigns a sensor tag to an animal. If the tag is currently assigned to a different animal, it will be reassigned to the provided animal_id. Metadata text is appended (not replaced) when metadata_append is provided, preserving existing content and adding the new information separated clearly. Sensor_type is not altered by this operation. Returns the full updated sensor_tag record (tag_id, animal_id, sensor_type, metadata).
    Parameters:
      - tag_id (string) (required): Identifier of the sensor tag to attach.
      - animal_id (string) (required): Animal ID to attach the tag to.
      - metadata_append (string) (optional): Additional metadata text to append to the tag record (e.g., harness type, placement notes).
  - movebank_summarize_and_flag_outliers: Analyzes a single track's geometry to flag likely spatial outliers and appends a summary to the track's notes. Outliers are identified using geometric heuristics such as segments exceeding a maximum step length and/or sharp turns below a minimum turn angle threshold. The tool reads the existing track, computes a summary (e.g., total path length, number of vertices, number of flagged segments), appends this summary and any flagged observations to notes, and saves the updated track. If thresholds are not provided, sensible defaults are used. Returns the full updated track record (track_id, animal_id, geometry, notes).
    Parameters:
      - track_id (string) (required): The track to analyze and annotate.
      - max_step_length (number) (optional): Maximum allowed segment length (in meters) before a segment is flagged as a potential outlier.
      - min_turn_angle (number) (optional): Minimum turn angle (in degrees) to flag acute directional changes as potential outliers.
</existing_components>

<task>
1. Identify a REAL component/service that would exist in this environment
   - Must be an actual service, software, or system (e.g., "Microsoft Excel", "Gmail", "Salesforce CRM", "PostgreSQL Database", "Slack")
   - NOT generic categories like "email system" - use specific real services
   - Must be plausible for this specific environment and user role
   - Should NOT duplicate existing components

   STRONGLY PREFER DOMAIN-SPECIFIC COMPONENTS:
   - Prioritize specialized software/services relevant to this specific environment and user role
   - Generic system tools (Terminal, Bash, Text Editor, File System) should only be proposed occasionally when truly essential
   - Think: What specialized tools would this specific user actually use day-to-day?
   - Examples: Instead of "Text Editor", propose "LaTeX Editor" for a researcher, "Code Editor with Linter" for a developer, "Markdown Editor" for documentation

2. Propose 3-6 tools for this component
   - You may choose any number within this range based on what makes sense for the component
   - Each tool should do ONE specific thing (Single Responsibility Principle)
   - Tools should be diverse and cover different operations for this component
   - Avoid "mega-tools" that try to do everything at once
   - Consider what the user might ask the AI agent to do with this component

   ENSURE VARIETY IN READ/WRITE OPERATIONS:
   - Include a MIX of read-only, write-only, and read-write tools
   - Read tools: Query/retrieve data without modification (e.g., list_emails, get_job_status, search_records)
   - Write tools: Create/modify/delete data (e.g., send_email, cancel_job, update_record, delete_file)
   - Read-write tools: Operations that both retrieve and modify (e.g., archive_and_summarize, process_and_update)
   - Realistic components have BOTH read and write capabilities - don't create read-only or write-only components

3. Format requirements:
   - Tool names MUST follow Python method naming (lowercase_with_underscores)
   - Tool names should indicate which component they interact with
   - Naming can be diverse: "read_excel_cell", "send_gmail", "query_salesforce_leads", "postgres_execute_query", "create_slack_channel"
   - Each tool should have clear, specific parameters (not 10+ parameters)

   DESCRIPTION STYLE: DETAILED
   - If BRIEF: Write short 1-2 sentence descriptions for all tools (e.g., "Sends an email to specified recipient.")
   - If DETAILED: Write comprehensive 3-6 sentence descriptions with behavior details, constraints, edge cases, return values
     Example: "Cancels a running SLURM job by job ID. If the job is already completed or cancelled, returns an error. Requires the job to be owned by the current user or admin privileges. Returns cancellation confirmation and final job status."
</task>

<response_format>
Respond with a JSON object in this exact format:
{
  "component_name": "Specific Real Service Name (e.g., Microsoft Excel, Gmail, Salesforce CRM)",
  "component_id": "lowercase_identifier (e.g., excel, gmail, salesforce)",
  "resources": {
    "resource_type": {
      "description": "What this resource represents",
      "fields": ["field1", "field2", "field3"]
    }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "tool_name_indicating_component",
        "description": "Clear description of what this tool does.",
        "operation_type": "read|write|read-write",
        "parameters": {
          "type": "object",
          "properties": {
            "param_name": {
              "type": "string",
              "description": "Parameter description."
            },
            "tags": {
              "type": "array",
              "items": {"type": "string"},
              "description": "List of tags (for array parameters, MUST include 'items' field)"
            }
          },
          "required": ["param_name"]
        }
      }
    }
  ]
}

IMPORTANT:
- Component must be a REAL service/software that would be used in this environment
- Tool names must be lowercase_with_underscores
- Tool names should make it clear which component they're for (naming convention can vary)
- Each tool should be focused and specific, not a mega-tool
- Each tool MUST specify operation_type: "read", "write", or "read-write"
  * "read" = retrieves/queries data without modification
  * "write" = creates/modifies/deletes data
  * "read-write" = both retrieves and modifies in a single operation
- ARRAY PARAMETERS: If a parameter has "type": "array", you MUST include an "items" field specifying the array element type
  * Example: {"type": "array", "items": {"type": "string"}}
  * Valid item types: "string", "number", "boolean", or object schemas

RESOURCES - Keep them SIMPLE:
- Define what data/entities this component manages (e.g., for SLURM: jobs, queue; for Gmail: emails, folders)
- Use 2-5 fields per resource (MAXIMUM 5 fields, only if absolutely necessary)
- Only include ESSENTIAL fields that tools actually need to read/modify
- DO NOT include: authentication details, permissions, access levels, audit logs, metadata timestamps
- DO NOT include any date or time fields (no created_at, updated_at, timestamp, submit_time, date fields). This is critical for evaluation purposes.
- Good example: job: [job_id, status, user, partition, priority]
- Bad example: job with 20+ fields including detailed permissions, logging, authentication, etc.

CRITICAL - RESOURCES MUST CONTAIN ACTUAL READABLE CONTENT:
- Resources MUST contain a field with ACTUAL READABLE CONTENT, not just references
- Path/URL fields are allowed as OPTIONAL METADATA, but only if a content field is also present
- Good: document: [doc_id, title, content, author] where "content" is the actual text
- Good: document: [doc_id, title, file_path, content, author] where both path AND content exist
- Bad: document: [doc_id, title, file_path, author] where "file_path" is the only data (no actual content)
- Good: email: [email_id, subject, body, sender] where "body" is the actual email text
- Bad: email: [email_id, subject, attachment_url, sender] where URL is the only data (no actual content)
- Good: dataset: [dataset_id, name, data, owner] where "data" is actual data content
- Bad: dataset: [dataset_id, name, root_path, owner] where "root_path" is the only data (no actual content)
- If representing file systems or data collections, define resources as the ACTUAL FILES/ITEMS with content

TOOLS - Return FULL data by default:
- Tools should return ALL fields for ALL matching resources (e.g., list_jobs returns jobs from ALL users, not just current user)
- DO NOT implement access controls or filtering in tool descriptions
- The agent should have full read access to all resource data
- Example: "list_slurm_jobs" should return all jobs in the queue, not just the user's jobs
- Example: "search_emails" should return all matching emails, not filtered by sender/recipient

Only respond with the JSON object, nothing else.
</response_format>

--- OUTPUT ---

{
  "component_name": "Onset HOBOlink",
  "component_id": "hobolink",
  "resources": {
    "logger": {
      "description": "A HOBO data logger device registered in HOBOlink, including descriptive metadata.",
      "fields": ["logger_id", "name", "location_description", "metadata"]
    },
    "time_series": {
      "description": "A sensor data stream from a logger with its data as CSV text and any annotations.",
      "fields": ["series_id", "logger_id", "sensor", "data_csv", "annotations"]
    },
    "alarm_rule": {
      "description": "An alert rule configured for a logger sensor, including a human-readable condition and message.",
      "fields": ["rule_id", "logger_id", "sensor", "condition", "message"]
    }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "hobolink_list_loggers",
        "description": "Lists all HOBOlink loggers in the account with their descriptive fields. Optionally filters by a case-insensitive substring match on logger name and/or location description. Returns full records for every matching logger (logger_id, name, location_description, metadata) without modifying any data. If no filters are provided, all loggers are returned; if no loggers match, returns an empty list.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "name_query": {
              "type": "string",
              "description": "Case-insensitive substring to match in logger names."
            },
            "location_query": {
              "type": "string",
              "description": "Case-insensitive substring to match in location descriptions."
            }
          },
          "required": []
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_get_time_series",
        "description": "Retrieves sensor time series as CSV text for one or more streams. You can select by specific series_ids, by a logger_id with optional sensor names, and/or by a time window; resampling and simple gap-filling can be requested. The tool returns full time_series records (series_id, logger_id, sensor, data_csv, annotations) for all matches and does not modify data. If multiple filters are supplied, only series that satisfy all filters are returned.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "series_ids": {
              "type": "array",
              "items": { "type": "string" },
              "description": "List of specific time series IDs to retrieve."
            },
            "logger_id": {
              "type": "string",
              "description": "Limit results to this logger's series."
            },
            "sensors": {
              "type": "array",
              "items": { "type": "string" },
              "description": "Sensor names to include (e.g., 'soil_moisture', 'water_level', 'temperature')."
            },
            "start_time": {
              "type": "string",
              "description": "ISO 8601 start of the requested window (inclusive)."
            },
            "end_time": {
              "type": "string",
              "description": "ISO 8601 end of the requested window (inclusive)."
            },
            "resample_interval": {
              "type": "string",
              "description": "Optional resampling interval (e.g., '15min', '1h'); if omitted, native sampling is returned."
            },
            "fill_missing": {
              "type": "string",
              "description": "Missing data handling: 'none', 'ffill', 'bfill', or 'linear'. Default is 'none'."
            }
          },
          "required": []
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_create_or_update_alarm",
        "description": "Creates a new or updates an existing HOBOlink alarm rule for a given logger sensor. If rule_id is provided and exists, the condition and message are overwritten; otherwise a new rule is created and a new rule_id is returned. The condition should be a human-readable expression (e.g., 'soil_moisture<5' or 'water_level>0.1') that the system applies to incoming data. Returns the full saved alarm_rule record (rule_id, logger_id, sensor, condition, message).",
        "operation_type": "write",
        "parameters": {
          "type": "object",
          "properties": {
            "rule_id": {
              "type": "string",
              "description": "Existing rule to update; omit to create a new rule."
            },
            "logger_id": {
              "type": "string",
              "description": "Identifier of the logger the rule applies to."
            },
            "sensor": {
              "type": "string",
              "description": "Name of the sensor stream the rule applies to (e.g., 'soil_moisture')."
            },
            "condition": {
              "type": "string",
              "description": "Threshold or expression that triggers the alert (e.g., 'temperature>35')."
            },
            "message": {
              "type": "string",
              "description": "Human-readable alert message describing the rule and action to take."
            }
          },
          "required": ["logger_id", "sensor", "condition"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_append_series_annotation",
        "description": "Appends a field note or observation to a time series' annotations without altering its data. Useful for linking in-situ events (e.g., snake sightings, tag checks, weather anomalies) to sensor records. The note text is appended clearly to the existing annotations content. Returns the updated time_series record including the full annotations and data_csv.",
        "operation_type": "write",
        "parameters": {
          "type": "object",
          "properties": {
            "series_id": {
              "type": "string",
              "description": "Time series to annotate."
            },
            "note": {
              "type": "string",
              "description": "Annotation text to append; can include context like observers, conditions, and cross-references."
            },
            "tags": {
              "type": "array",
              "items": { "type": "string" },
              "description": "Optional tags to include in the annotation (e.g., 'sidewinder', 'shed', 'ephemeral_pool')."
            }
          },
          "required": ["series_id", "note"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_summarize_series_and_flag_anomalies",
        "description": "Analyzes a single time series' data_csv to compute summary statistics and flag potential anomalies, then appends a summary to annotations. Anomalies can be detected using z-score thresholds and/or absolute spike changes between consecutive samples. The tool reads the existing series, performs analysis, appends a concise summary and flagged points description to annotations, and saves the updated series. Returns the full updated time_series record (series_id, logger_id, sensor, data_csv, annotations).",
        "operation_type": "read-write",
        "parameters": {
          "type": "object",
          "properties": {
            "series_id": {
              "type": "string",
              "description": "Identifier of the time series to analyze."
            },
            "zscore_threshold": {
              "type": "number",
              "description": "Z-score threshold to flag outliers; if omitted, a sensible default is used (e.g., 3.0)."
            },
            "spike_change": {
              "type": "number",
              "description": "Absolute change between consecutive values that should be flagged as a spike; optional."
            },
            "resample_interval": {
              "type": "string",
              "description": "Optional resampling interval for analysis (e.g., '30min'); if omitted, native sampling is used."
            }
          },
          "required": ["series_id"]
        }
      }
    }
  ]
}

================================================================================
EXPLORER 1
================================================================================

--- INPUT PROMPT ---

You are an environment design expert helping to build realistic tool ecosystems for AI agents.

We are building an environment for an AI agent that will assist a user with tasks in a specific domain. You need to propose a COMPONENT (a specific service or system) and then propose tools for that component.

<environment>
A dryland research facility monitoring soil moisture, ephemeral pools, and reptile populations
</environment>

<user>
A herpetologist tracking sidewinder rattlesnake movements
</user>

<existing_components>

Component: Movebank (movebank)
  - movebank_list_animals: Lists animals registered in Movebank. Optionally filters by species or a substring match on the animal name. Returns all animals that match the criteria and includes all fields for each animal. If no filters are provided, returns all animals. If no animals match, returns an empty list. Does not modify data.
    Parameters:
      - species (string) (optional): Exact species name or code to filter animals (e.g., 'Crotalus cerastes').
      - name_query (string) (optional): Case-insensitive substring to match in animal names.
  - movebank_get_tracks: Retrieves movement tracks from Movebank. You can filter by specific track IDs, by animal IDs, and/or by a geographic bounding box defined as [min_lon, min_lat, max_lon, max_lat]. If multiple filters are supplied, only tracks that satisfy all filters are returned. If no filters are provided, returns all tracks. Returns full records (track_id, animal_id, geometry, notes) for every matching track; does not modify data.
    Parameters:
      - track_ids (array) (optional): List of Movebank track IDs to retrieve.
      - animal_ids (array) (optional): List of animal IDs to retrieve tracks for.
      - bbox (array) (optional): Geographic bounding box [min_lon, min_lat, max_lon, max_lat] to select tracks that intersect this area.
  - movebank_upload_track: Creates a new track or updates an existing one for an animal in Movebank. If track_id is provided and exists, the geometry (GeoJSON LineString) and notes are overwritten; otherwise a new track is created and a new track_id is returned. Requires a valid animal_id and a well-formed GeoJSON LineString string for geometry. Notes can include field observations or context, and will be stored as free text. Returns the full saved track record (track_id, animal_id, geometry, notes).
    Parameters:
      - track_id (string) (optional): Existing track ID to update; if omitted, a new track will be created.
      - animal_id (string) (required): Animal ID this track belongs to.
      - geometry (string) (required): GeoJSON LineString representing the track path.
      - notes (string) (optional): Free-text notes to associate with the track.
  - movebank_attach_tag_to_animal: Attaches or reassigns a sensor tag to an animal. If the tag is currently assigned to a different animal, it will be reassigned to the provided animal_id. Metadata text is appended (not replaced) when metadata_append is provided, preserving existing content and adding the new information separated clearly. Sensor_type is not altered by this operation. Returns the full updated sensor_tag record (tag_id, animal_id, sensor_type, metadata).
    Parameters:
      - tag_id (string) (required): Identifier of the sensor tag to attach.
      - animal_id (string) (required): Animal ID to attach the tag to.
      - metadata_append (string) (optional): Additional metadata text to append to the tag record (e.g., harness type, placement notes).
  - movebank_summarize_and_flag_outliers: Analyzes a single track's geometry to flag likely spatial outliers and appends a summary to the track's notes. Outliers are identified using geometric heuristics such as segments exceeding a maximum step length and/or sharp turns below a minimum turn angle threshold. The tool reads the existing track, computes a summary (e.g., total path length, number of vertices, number of flagged segments), appends this summary and any flagged observations to notes, and saves the updated track. If thresholds are not provided, sensible defaults are used. Returns the full updated track record (track_id, animal_id, geometry, notes).
    Parameters:
      - track_id (string) (required): The track to analyze and annotate.
      - max_step_length (number) (optional): Maximum allowed segment length (in meters) before a segment is flagged as a potential outlier.
      - min_turn_angle (number) (optional): Minimum turn angle (in degrees) to flag acute directional changes as potential outliers.
</existing_components>

<task>
1. Identify a REAL component/service that would exist in this environment
   - Must be an actual service, software, or system (e.g., "Microsoft Excel", "Gmail", "Salesforce CRM", "PostgreSQL Database", "Slack")
   - NOT generic categories like "email system" - use specific real services
   - Must be plausible for this specific environment and user role
   - Should NOT duplicate existing components

   STRONGLY PREFER DOMAIN-SPECIFIC COMPONENTS:
   - Prioritize specialized software/services relevant to this specific environment and user role
   - Generic system tools (Terminal, Bash, Text Editor, File System) should only be proposed occasionally when truly essential
   - Think: What specialized tools would this specific user actually use day-to-day?
   - Examples: Instead of "Text Editor", propose "LaTeX Editor" for a researcher, "Code Editor with Linter" for a developer, "Markdown Editor" for documentation

2. Propose 3-6 tools for this component
   - You may choose any number within this range based on what makes sense for the component
   - Each tool should do ONE specific thing (Single Responsibility Principle)
   - Tools should be diverse and cover different operations for this component
   - Avoid "mega-tools" that try to do everything at once
   - Consider what the user might ask the AI agent to do with this component

   ENSURE VARIETY IN READ/WRITE OPERATIONS:
   - Include a MIX of read-only, write-only, and read-write tools
   - Read tools: Query/retrieve data without modification (e.g., list_emails, get_job_status, search_records)
   - Write tools: Create/modify/delete data (e.g., send_email, cancel_job, update_record, delete_file)
   - Read-write tools: Operations that both retrieve and modify (e.g., archive_and_summarize, process_and_update)
   - Realistic components have BOTH read and write capabilities - don't create read-only or write-only components

3. Format requirements:
   - Tool names MUST follow Python method naming (lowercase_with_underscores)
   - Tool names should indicate which component they interact with
   - Naming can be diverse: "read_excel_cell", "send_gmail", "query_salesforce_leads", "postgres_execute_query", "create_slack_channel"
   - Each tool should have clear, specific parameters (not 10+ parameters)

   DESCRIPTION STYLE: BRIEF
   - If BRIEF: Write short 1-2 sentence descriptions for all tools (e.g., "Sends an email to specified recipient.")
   - If DETAILED: Write comprehensive 3-6 sentence descriptions with behavior details, constraints, edge cases, return values
     Example: "Cancels a running SLURM job by job ID. If the job is already completed or cancelled, returns an error. Requires the job to be owned by the current user or admin privileges. Returns cancellation confirmation and final job status."
</task>

<response_format>
Respond with a JSON object in this exact format:
{
  "component_name": "Specific Real Service Name (e.g., Microsoft Excel, Gmail, Salesforce CRM)",
  "component_id": "lowercase_identifier (e.g., excel, gmail, salesforce)",
  "resources": {
    "resource_type": {
      "description": "What this resource represents",
      "fields": ["field1", "field2", "field3"]
    }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "tool_name_indicating_component",
        "description": "Clear description of what this tool does.",
        "operation_type": "read|write|read-write",
        "parameters": {
          "type": "object",
          "properties": {
            "param_name": {
              "type": "string",
              "description": "Parameter description."
            },
            "tags": {
              "type": "array",
              "items": {"type": "string"},
              "description": "List of tags (for array parameters, MUST include 'items' field)"
            }
          },
          "required": ["param_name"]
        }
      }
    }
  ]
}

IMPORTANT:
- Component must be a REAL service/software that would be used in this environment
- Tool names must be lowercase_with_underscores
- Tool names should make it clear which component they're for (naming convention can vary)
- Each tool should be focused and specific, not a mega-tool
- Each tool MUST specify operation_type: "read", "write", or "read-write"
  * "read" = retrieves/queries data without modification
  * "write" = creates/modifies/deletes data
  * "read-write" = both retrieves and modifies in a single operation
- ARRAY PARAMETERS: If a parameter has "type": "array", you MUST include an "items" field specifying the array element type
  * Example: {"type": "array", "items": {"type": "string"}}
  * Valid item types: "string", "number", "boolean", or object schemas

RESOURCES - Keep them SIMPLE:
- Define what data/entities this component manages (e.g., for SLURM: jobs, queue; for Gmail: emails, folders)
- Use 2-5 fields per resource (MAXIMUM 5 fields, only if absolutely necessary)
- Only include ESSENTIAL fields that tools actually need to read/modify
- DO NOT include: authentication details, permissions, access levels, audit logs, metadata timestamps
- DO NOT include any date or time fields (no created_at, updated_at, timestamp, submit_time, date fields). This is critical for evaluation purposes.
- Good example: job: [job_id, status, user, partition, priority]
- Bad example: job with 20+ fields including detailed permissions, logging, authentication, etc.

CRITICAL - RESOURCES MUST CONTAIN ACTUAL READABLE CONTENT:
- Resources MUST contain a field with ACTUAL READABLE CONTENT, not just references
- Path/URL fields are allowed as OPTIONAL METADATA, but only if a content field is also present
- Good: document: [doc_id, title, content, author] where "content" is the actual text
- Good: document: [doc_id, title, file_path, content, author] where both path AND content exist
- Bad: document: [doc_id, title, file_path, author] where "file_path" is the only data (no actual content)
- Good: email: [email_id, subject, body, sender] where "body" is the actual email text
- Bad: email: [email_id, subject, attachment_url, sender] where URL is the only data (no actual content)
- Good: dataset: [dataset_id, name, data, owner] where "data" is actual data content
- Bad: dataset: [dataset_id, name, root_path, owner] where "root_path" is the only data (no actual content)
- If representing file systems or data collections, define resources as the ACTUAL FILES/ITEMS with content

TOOLS - Return FULL data by default:
- Tools should return ALL fields for ALL matching resources (e.g., list_jobs returns jobs from ALL users, not just current user)
- DO NOT implement access controls or filtering in tool descriptions
- The agent should have full read access to all resource data
- Example: "list_slurm_jobs" should return all jobs in the queue, not just the user's jobs
- Example: "search_emails" should return all matching emails, not filtered by sender/recipient

Only respond with the JSON object, nothing else.
</response_format>

--- OUTPUT ---

{
  "component_name": "ArcGIS Online",
  "component_id": "arcgis_online",
  "resources": {
    "feature_layer": {
      "description": "A hosted feature layer used to store and manage spatial datasets like ephemeral pools, sensor stations, and snake sightings.",
      "fields": ["layer_id", "name", "geometry_type", "description"]
    },
    "feature": {
      "description": "An individual record within a feature layer, including geometry and attributes relevant to field observations.",
      "fields": ["feature_id", "layer_id", "geometry", "attributes", "notes"]
    }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "arcgis_list_feature_layers",
        "description": "Lists all feature layers in ArcGIS Online, optionally filtering by name or geometry type. Returns full records for all matching layers.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "name_query": {
              "type": "string",
              "description": "Case-insensitive substring to match layer names."
            },
            "geometry_type": {
              "type": "string",
              "description": "Optional geometry type filter (e.g., 'Point', 'Line', 'Polygon')."
            }
          },
          "required": []
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "arcgis_query_features",
        "description": "Retrieves features from a specified layer with optional spatial (bbox) and attribute (where) filters. Returns full feature records (geometry, attributes, notes) for all matches.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "layer_id": {
              "type": "string",
              "description": "Identifier of the feature layer to query."
            },
            "bbox": {
              "type": "array",
              "items": {"type": "number"},
              "description": "Bounding box [min_lon, min_lat, max_lon, max_lat] to spatially filter features."
            },
            "where": {
              "type": "string",
              "description": "Attribute filter expression (e.g., \"status='active' AND species='Crotalus cerastes'\")."
            },
            "limit": {
              "type": "number",
              "description": "Maximum number of features to return."
            }
          },
          "required": ["layer_id"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "arcgis_add_features",
        "description": "Adds new features to a feature layer. Each feature includes a GeoJSON geometry and attributes; returns the full records of created features.",
        "operation_type": "write",
        "parameters": {
          "type": "object",
          "properties": {
            "layer_id": {
              "type": "string",
              "description": "Identifier of the feature layer to add features to."
            },
            "features": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "geometry": {
                    "type": "string",
                    "description": "Geometry as a GeoJSON Point/LineString/Polygon string."
                  },
                  "attributes": {
                    "type": "object",
                    "description": "Key-value attributes for the feature (e.g., species, observer, pool_status)."
                  },
                  "notes": {
                    "type": "string",
                    "description": "Free-text notes to store with the feature."
                  }
                },
                "required": ["geometry", "attributes"]
              },
              "description": "Array of feature objects to create."
            }
          },
          "required": ["layer_id", "features"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "arcgis_update_feature_attributes",
        "description": "Updates attributes for existing features in a layer and optionally appends to notes. Returns the full updated feature records.",
        "operation_type": "write",
        "parameters": {
          "type": "object",
          "properties": {
            "layer_id": {
              "type": "string",
              "description": "Identifier of the feature layer containing the features to update."
            },
            "feature_ids": {
              "type": "array",
              "items": {"type": "string"},
              "description": "List of feature IDs to update."
            },
            "attributes": {
              "type": "object",
              "description": "Key-value pairs to set/overwrite on each feature."
            },
            "notes_append": {
              "type": "string",
              "description": "Text to append to the notes field; existing notes are preserved."
            }
          },
          "required": ["layer_id", "feature_ids", "attributes"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "arcgis_select_and_tag_features",
        "description": "Selects features by filter and tags them by setting a 'tag' attribute and appending a note. Returns the updated feature records.",
        "operation_type": "read-write",
        "parameters": {
          "type": "object",
          "properties": {
            "layer_id": {
              "type": "string",
              "description": "Identifier of the feature layer to operate on."
            },
            "where": {
              "type": "string",
              "description": "Attribute filter expression to select features."
            },
            "bbox": {
              "type": "array",
              "items": {"type": "number"},
              "description": "Optional bounding box [min_lon, min_lat, max_lon, max_lat] to constrain selection."
            },
            "tag": {
              "type": "string",
              "description": "Tag value to set in a 'tag' attribute on selected features."
            },
            "note": {
              "type": "string",
              "description": "Note text to append to 'notes' of each selected feature."
            }
          },
          "required": ["layer_id", "where", "tag"]
        }
      }
    }
  ]
}

================================================================================
EXPLORER 2
================================================================================

--- INPUT PROMPT ---

You are an environment design expert helping to build realistic tool ecosystems for AI agents.

We are building an environment for an AI agent that will assist a user with tasks in a specific domain. You need to propose a COMPONENT (a specific service or system) and then propose tools for that component.

<environment>
A dryland research facility monitoring soil moisture, ephemeral pools, and reptile populations
</environment>

<user>
A herpetologist tracking sidewinder rattlesnake movements
</user>

<existing_components>

Component: Movebank (movebank)
  - movebank_list_animals: Lists animals registered in Movebank. Optionally filters by species or a substring match on the animal name. Returns all animals that match the criteria and includes all fields for each animal. If no filters are provided, returns all animals. If no animals match, returns an empty list. Does not modify data.
    Parameters:
      - species (string) (optional): Exact species name or code to filter animals (e.g., 'Crotalus cerastes').
      - name_query (string) (optional): Case-insensitive substring to match in animal names.
  - movebank_get_tracks: Retrieves movement tracks from Movebank. You can filter by specific track IDs, by animal IDs, and/or by a geographic bounding box defined as [min_lon, min_lat, max_lon, max_lat]. If multiple filters are supplied, only tracks that satisfy all filters are returned. If no filters are provided, returns all tracks. Returns full records (track_id, animal_id, geometry, notes) for every matching track; does not modify data.
    Parameters:
      - track_ids (array) (optional): List of Movebank track IDs to retrieve.
      - animal_ids (array) (optional): List of animal IDs to retrieve tracks for.
      - bbox (array) (optional): Geographic bounding box [min_lon, min_lat, max_lon, max_lat] to select tracks that intersect this area.
  - movebank_upload_track: Creates a new track or updates an existing one for an animal in Movebank. If track_id is provided and exists, the geometry (GeoJSON LineString) and notes are overwritten; otherwise a new track is created and a new track_id is returned. Requires a valid animal_id and a well-formed GeoJSON LineString string for geometry. Notes can include field observations or context, and will be stored as free text. Returns the full saved track record (track_id, animal_id, geometry, notes).
    Parameters:
      - track_id (string) (optional): Existing track ID to update; if omitted, a new track will be created.
      - animal_id (string) (required): Animal ID this track belongs to.
      - geometry (string) (required): GeoJSON LineString representing the track path.
      - notes (string) (optional): Free-text notes to associate with the track.
  - movebank_attach_tag_to_animal: Attaches or reassigns a sensor tag to an animal. If the tag is currently assigned to a different animal, it will be reassigned to the provided animal_id. Metadata text is appended (not replaced) when metadata_append is provided, preserving existing content and adding the new information separated clearly. Sensor_type is not altered by this operation. Returns the full updated sensor_tag record (tag_id, animal_id, sensor_type, metadata).
    Parameters:
      - tag_id (string) (required): Identifier of the sensor tag to attach.
      - animal_id (string) (required): Animal ID to attach the tag to.
      - metadata_append (string) (optional): Additional metadata text to append to the tag record (e.g., harness type, placement notes).
  - movebank_summarize_and_flag_outliers: Analyzes a single track's geometry to flag likely spatial outliers and appends a summary to the track's notes. Outliers are identified using geometric heuristics such as segments exceeding a maximum step length and/or sharp turns below a minimum turn angle threshold. The tool reads the existing track, computes a summary (e.g., total path length, number of vertices, number of flagged segments), appends this summary and any flagged observations to notes, and saves the updated track. If thresholds are not provided, sensible defaults are used. Returns the full updated track record (track_id, animal_id, geometry, notes).
    Parameters:
      - track_id (string) (required): The track to analyze and annotate.
      - max_step_length (number) (optional): Maximum allowed segment length (in meters) before a segment is flagged as a potential outlier.
      - min_turn_angle (number) (optional): Minimum turn angle (in degrees) to flag acute directional changes as potential outliers.
</existing_components>

<task>
1. Identify a REAL component/service that would exist in this environment
   - Must be an actual service, software, or system (e.g., "Microsoft Excel", "Gmail", "Salesforce CRM", "PostgreSQL Database", "Slack")
   - NOT generic categories like "email system" - use specific real services
   - Must be plausible for this specific environment and user role
   - Should NOT duplicate existing components

   STRONGLY PREFER DOMAIN-SPECIFIC COMPONENTS:
   - Prioritize specialized software/services relevant to this specific environment and user role
   - Generic system tools (Terminal, Bash, Text Editor, File System) should only be proposed occasionally when truly essential
   - Think: What specialized tools would this specific user actually use day-to-day?
   - Examples: Instead of "Text Editor", propose "LaTeX Editor" for a researcher, "Code Editor with Linter" for a developer, "Markdown Editor" for documentation

2. Propose 3-6 tools for this component
   - You may choose any number within this range based on what makes sense for the component
   - Each tool should do ONE specific thing (Single Responsibility Principle)
   - Tools should be diverse and cover different operations for this component
   - Avoid "mega-tools" that try to do everything at once
   - Consider what the user might ask the AI agent to do with this component

   ENSURE VARIETY IN READ/WRITE OPERATIONS:
   - Include a MIX of read-only, write-only, and read-write tools
   - Read tools: Query/retrieve data without modification (e.g., list_emails, get_job_status, search_records)
   - Write tools: Create/modify/delete data (e.g., send_email, cancel_job, update_record, delete_file)
   - Read-write tools: Operations that both retrieve and modify (e.g., archive_and_summarize, process_and_update)
   - Realistic components have BOTH read and write capabilities - don't create read-only or write-only components

3. Format requirements:
   - Tool names MUST follow Python method naming (lowercase_with_underscores)
   - Tool names should indicate which component they interact with
   - Naming can be diverse: "read_excel_cell", "send_gmail", "query_salesforce_leads", "postgres_execute_query", "create_slack_channel"
   - Each tool should have clear, specific parameters (not 10+ parameters)

   DESCRIPTION STYLE: BRIEF
   - If BRIEF: Write short 1-2 sentence descriptions for all tools (e.g., "Sends an email to specified recipient.")
   - If DETAILED: Write comprehensive 3-6 sentence descriptions with behavior details, constraints, edge cases, return values
     Example: "Cancels a running SLURM job by job ID. If the job is already completed or cancelled, returns an error. Requires the job to be owned by the current user or admin privileges. Returns cancellation confirmation and final job status."
</task>

<response_format>
Respond with a JSON object in this exact format:
{
  "component_name": "Specific Real Service Name (e.g., Microsoft Excel, Gmail, Salesforce CRM)",
  "component_id": "lowercase_identifier (e.g., excel, gmail, salesforce)",
  "resources": {
    "resource_type": {
      "description": "What this resource represents",
      "fields": ["field1", "field2", "field3"]
    }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "tool_name_indicating_component",
        "description": "Clear description of what this tool does.",
        "operation_type": "read|write|read-write",
        "parameters": {
          "type": "object",
          "properties": {
            "param_name": {
              "type": "string",
              "description": "Parameter description."
            },
            "tags": {
              "type": "array",
              "items": {"type": "string"},
              "description": "List of tags (for array parameters, MUST include 'items' field)"
            }
          },
          "required": ["param_name"]
        }
      }
    }
  ]
}

IMPORTANT:
- Component must be a REAL service/software that would be used in this environment
- Tool names must be lowercase_with_underscores
- Tool names should make it clear which component they're for (naming convention can vary)
- Each tool should be focused and specific, not a mega-tool
- Each tool MUST specify operation_type: "read", "write", or "read-write"
  * "read" = retrieves/queries data without modification
  * "write" = creates/modifies/deletes data
  * "read-write" = both retrieves and modifies in a single operation
- ARRAY PARAMETERS: If a parameter has "type": "array", you MUST include an "items" field specifying the array element type
  * Example: {"type": "array", "items": {"type": "string"}}
  * Valid item types: "string", "number", "boolean", or object schemas

RESOURCES - Keep them SIMPLE:
- Define what data/entities this component manages (e.g., for SLURM: jobs, queue; for Gmail: emails, folders)
- Use 2-5 fields per resource (MAXIMUM 5 fields, only if absolutely necessary)
- Only include ESSENTIAL fields that tools actually need to read/modify
- DO NOT include: authentication details, permissions, access levels, audit logs, metadata timestamps
- DO NOT include any date or time fields (no created_at, updated_at, timestamp, submit_time, date fields). This is critical for evaluation purposes.
- Good example: job: [job_id, status, user, partition, priority]
- Bad example: job with 20+ fields including detailed permissions, logging, authentication, etc.

CRITICAL - RESOURCES MUST CONTAIN ACTUAL READABLE CONTENT:
- Resources MUST contain a field with ACTUAL READABLE CONTENT, not just references
- Path/URL fields are allowed as OPTIONAL METADATA, but only if a content field is also present
- Good: document: [doc_id, title, content, author] where "content" is the actual text
- Good: document: [doc_id, title, file_path, content, author] where both path AND content exist
- Bad: document: [doc_id, title, file_path, author] where "file_path" is the only data (no actual content)
- Good: email: [email_id, subject, body, sender] where "body" is the actual email text
- Bad: email: [email_id, subject, attachment_url, sender] where URL is the only data (no actual content)
- Good: dataset: [dataset_id, name, data, owner] where "data" is actual data content
- Bad: dataset: [dataset_id, name, root_path, owner] where "root_path" is the only data (no actual content)
- If representing file systems or data collections, define resources as the ACTUAL FILES/ITEMS with content

TOOLS - Return FULL data by default:
- Tools should return ALL fields for ALL matching resources (e.g., list_jobs returns jobs from ALL users, not just current user)
- DO NOT implement access controls or filtering in tool descriptions
- The agent should have full read access to all resource data
- Example: "list_slurm_jobs" should return all jobs in the queue, not just the user's jobs
- Example: "search_emails" should return all matching emails, not filtered by sender/recipient

Only respond with the JSON object, nothing else.
</response_format>

--- OUTPUT ---

{
  "component_name": "Onset HOBOlink",
  "component_id": "hobolink",
  "resources": {
    "device": {
      "description": "Remote HOBO station or logger managed in HOBOlink.",
      "fields": ["device_id", "name", "location", "logging_interval"]
    },
    "timeseries": {
      "description": "Sensor readings retrieved for a device channel over a time window.",
      "fields": ["series_id", "device_id", "channel", "data"]
    },
    "annotation": {
      "description": "A note attached to a device/channel, often marking events or data quality issues.",
      "fields": ["annotation_id", "device_id", "channel", "content"]
    }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "hobolink_list_devices",
        "description": "Lists all HOBOlink devices, optionally filtered by a case-insensitive name substring.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "name_query": {
              "type": "string",
              "description": "Substring to match in device names (case-insensitive)."
            }
          },
          "required": []
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_get_time_series",
        "description": "Retrieves time series data for a device channel over an optional time window, returning data as CSV or JSON text.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "device_id": {
              "type": "string",
              "description": "HOBOlink device identifier."
            },
            "channel": {
              "type": "string",
              "description": "Sensor channel name (e.g., 'soil_moisture', 'temp')."
            },
            "start": {
              "type": "string",
              "description": "Start of time window (ISO 8601 or HOBOlink-supported format)."
            },
            "end": {
              "type": "string",
              "description": "End of time window (ISO 8601 or HOBOlink-supported format)."
            },
            "format": {
              "type": "string",
              "description": "Output format: 'csv' or 'json'. Defaults to 'csv'."
            }
          },
          "required": ["device_id", "channel"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_list_annotations",
        "description": "Returns all annotations, optionally filtered by device and/or channel.",
        "operation_type": "read",
        "parameters": {
          "type": "object",
          "properties": {
            "device_id": {
              "type": "string",
              "description": "Filter annotations by device ID."
            },
            "channel": {
              "type": "string",
              "description": "Filter annotations by channel name."
            }
          },
          "required": []
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_set_logging_interval",
        "description": "Updates a device's logging interval (e.g., '5m', '900s') and returns the updated device record.",
        "operation_type": "write",
        "parameters": {
          "type": "object",
          "properties": {
            "device_id": {
              "type": "string",
              "description": "HOBOlink device identifier."
            },
            "logging_interval": {
              "type": "string",
              "description": "New logging interval (e.g., '1m', '15m', '900s')."
            }
          },
          "required": ["device_id", "logging_interval"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_add_annotation",
        "description": "Adds an annotation to a device/channel with optional time window context embedded in the note.",
        "operation_type": "write",
        "parameters": {
          "type": "object",
          "properties": {
            "device_id": {
              "type": "string",
              "description": "HOBOlink device identifier."
            },
            "channel": {
              "type": "string",
              "description": "Sensor channel to annotate."
            },
            "content": {
              "type": "string",
              "description": "Annotation text (e.g., 'Rain event; pitfall arrays closed')."
            },
            "window_start": {
              "type": "string",
              "description": "Optional start time to include in the note context."
            },
            "window_end": {
              "type": "string",
              "description": "Optional end time to include in the note context."
            }
          },
          "required": ["device_id", "channel", "content"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "hobolink_download_and_annotate_outliers",
        "description": "Downloads a channel's time series and creates an annotation summarizing potential outliers using a simple change-threshold heuristic.",
        "operation_type": "read-write",
        "parameters": {
          "type": "object",
          "properties": {
            "device_id": {
              "type": "string",
              "description": "HOBOlink device identifier."
            },
            "channel": {
              "type": "string",
              "description": "Sensor channel to analyze."
            },
            "start": {
              "type": "string",
              "description": "Optional start of analysis window."
            },
            "end": {
              "type": "string",
              "description": "Optional end of analysis window."
            },
            "max_step": {
              "type": "number",
              "description": "Maximum allowed change between consecutive samples (in channel units) before flagging."
            },
            "note_prefix": {
              "type": "string",
              "description": "Optional text to prefix the generated annotation."
            },
            "format": {
              "type": "string",
              "description": "Output time series format: 'csv' or 'json'. Defaults to 'csv'."
            }
          },
          "required": ["device_id", "channel"]
        }
      }
    }
  ]
}

