Skip to content

feat: api client #1027

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/codegen/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from codegen.agents.agent import Agent
from codegen.cli.sdk.decorator import function
from codegen.cli.sdk.functions import Function
from codegen.extensions.events.codegen_app import CodegenApp
from codegen.sdk.core.codebase import Codebase
from codegen.shared.enums.programming_language import ProgrammingLanguage

__all__ = ["Codebase", "CodegenApp", "Function", "ProgrammingLanguage", "function"]
__all__ = ["Agent", "Codebase", "CodegenApp", "Function", "ProgrammingLanguage", "function"]
124 changes: 124 additions & 0 deletions src/codegen/agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Codegen Agents - Python SDK

This module provides a Python client for interacting with the Codegen AI agents API.

## Installation

The Codegen Agent SDK is included as part of the Codegen package. Ensure you have the latest version installed:

```bash
pip install codegen
```

## Usage

### Basic Example

```python
from codegen.agents.agent import Agent

# Initialize the Agent with your organization ID and API token
agent = Agent(
org_id="11", # Your organization ID
token="your_api_token_here", # Your API authentication token
base_url="https://codegen-sh-rest-api.modal.run", # Optional - defaults to this URL
)

# Run an agent with a prompt
task = agent.run(prompt="Which github repos can you currently access?")

# Check the initial status
print(task.status) # Returns the current status of the task (e.g., "queued", "in_progress", etc.)

# Refresh the task to get updated status
task.refresh()

# Check the updated status
print(task.status)

# Once task is complete, you can access the result
if task.status == "completed":
print(task.result)
```

### Agent Class

The `Agent` class is the main entry point for interacting with Codegen AI agents:

```python
Agent(token: str, org_id: Optional[int] = None, base_url: Optional[str] = CODEGEN_BASE_API_URL)
```

Parameters:

- `token` (required): Your API authentication token
- `org_id` (optional): Your organization ID. If not provided, defaults to environment variable `CODEGEN_ORG_ID` or "1"
- `base_url` (optional): API base URL. Defaults to "https://codegen-sh-rest-api.modal.run"

### Methods

#### run()

```python
run(prompt: str) -> AgentTask
```

Runs an agent with the given prompt.

Parameters:

- `prompt` (required): The instruction for the agent to execute

Returns:

- An `AgentTask` object representing the running task

#### get_status()

```python
get_status() -> Optional[Dict[str, Any]]
```

Gets the status of the current task.

Returns:

- A dictionary containing task status information (`id`, `status`, `result`), or `None` if no task has been run

### AgentTask Class

The `AgentTask` class represents a running or completed agent task:

#### Attributes

- `id`: The unique identifier for the task
- `org_id`: The organization ID
- `status`: Current status of the task (e.g., "queued", "in_progress", "completed", "failed")
- `result`: The task result (available when status is "completed")

#### Methods

##### refresh()

```python
refresh() -> None
```

Refreshes the task status from the API.

## Environment Variables

- `CODEGEN_ORG_ID`: Default organization ID (used if `org_id` is not provided)

## Error Handling

Handle potential API errors using standard try/except blocks:

```python
try:
task = agent.run(prompt="Your prompt here")
task.refresh()
print(task.status)
except Exception as e:
print(f"Error: {e}")
```
5 changes: 5 additions & 0 deletions src/codegen/agents/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Codegen Agent API module."""

from codegen.agents.agent import Agent

__all__ = ["Agent"]
94 changes: 94 additions & 0 deletions src/codegen/agents/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import os
from typing import Any, Optional

from codegen.agents.client.openapi_client.api.agents_api import AgentsApi
from codegen.agents.client.openapi_client.api_client import ApiClient
from codegen.agents.client.openapi_client.configuration import Configuration
from codegen.agents.client.openapi_client.models.agent_run_response import AgentRunResponse
from codegen.agents.client.openapi_client.models.create_agent_run_input import CreateAgentRunInput
from codegen.agents.constants import CODEGEN_BASE_API_URL


class AgentTask:
"""Represents an agent run job."""

def __init__(self, task_data: AgentRunResponse, api_client: ApiClient, org_id: int):
self.id = task_data.id
self.org_id = org_id
self.status = task_data.status
self.result = task_data.result
self.web_url = task_data.web_url
self._api_client = api_client
self._agents_api = AgentsApi(api_client)

def refresh(self) -> None:
"""Refresh the job status from the API."""
if self.id is None:
return

job_data = self._agents_api.get_agent_run_v1_organizations_org_id_agent_run_agent_run_id_get(
agent_run_id=int(self.id), org_id=int(self.org_id), authorization=f"Bearer {self._api_client.configuration.access_token}"
)

# Convert API response to dict for attribute access
job_dict = {}
if hasattr(job_data, "__dict__"):
job_dict = job_data.__dict__

Check warning on line 36 in src/codegen/agents/agent.py

View check run for this annotation

Codecov / codecov/patch

src/codegen/agents/agent.py#L36

Added line #L36 was not covered by tests
elif isinstance(job_data, dict):
job_dict = job_data

self.status = job_dict.get("status")
self.result = job_dict.get("result")


class Agent:
"""API client for interacting with Codegen AI agents."""

def __init__(self, token: str, org_id: Optional[int] = None, base_url: Optional[str] = CODEGEN_BASE_API_URL):
"""Initialize a new Agent client.

Args:
token: API authentication token
org_id: Optional organization ID. If not provided, default org will be used.
"""
self.token = token
self.org_id = org_id or int(os.environ.get("CODEGEN_ORG_ID", "1")) # Default to org ID 1 if not specified

# Configure API client
config = Configuration(host=base_url, access_token=token)
self.api_client = ApiClient(configuration=config)
self.agents_api = AgentsApi(self.api_client)

# Current job
self.current_job = None

def run(self, prompt: str) -> AgentTask:
"""Run an agent with the given prompt.

Args:
prompt: The instruction for the agent to execute

Returns:
Job: A job object representing the agent run
"""
run_input = CreateAgentRunInput(prompt=prompt)
agent_run_response = self.agents_api.create_agent_run_v1_organizations_org_id_agent_run_post(
org_id=int(self.org_id), create_agent_run_input=run_input, authorization=f"Bearer {self.token}", _headers={"Content-Type": "application/json"}
)
# Convert API response to dict for Job initialization

job = AgentTask(agent_run_response, self.api_client, self.org_id)
self.current_job = job

Check failure on line 81 in src/codegen/agents/agent.py

View workflow job for this annotation

GitHub Actions / mypy

error: Incompatible types in assignment (expression has type "AgentTask", variable has type "None") [assignment]
return job

def get_status(self) -> Optional[dict[str, Any]]:
"""Get the status of the current job.

Returns:
dict: A dictionary containing job status information,
or None if no job has been run.
"""
if self.current_job:
self.current_job.refresh()
return {"id": self.current_job.id, "status": self.current_job.status, "result": self.current_job.result, "web_url": self.current_job.web_url}
return None
62 changes: 62 additions & 0 deletions src/codegen/agents/client/.openapi-generator/FILES
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.github/workflows/python.yml
.gitignore
.gitlab-ci.yml
.openapi-generator-ignore
.travis.yml
README.md
docs/AgentRunResponse.md
docs/AgentsApi.md
docs/CreateAgentRunInput.md
docs/HTTPValidationError.md
docs/OrganizationResponse.md
docs/OrganizationSettings.md
docs/OrganizationsApi.md
docs/PageOrganizationResponse.md
docs/PageUserResponse.md
docs/UserResponse.md
docs/UsersApi.md
docs/ValidationError.md
docs/ValidationErrorLocInner.md
git_push.sh
openapi_client/__init__.py
openapi_client/api/__init__.py
openapi_client/api/agents_api.py
openapi_client/api/organizations_api.py
openapi_client/api/users_api.py
openapi_client/api_client.py
openapi_client/api_response.py
openapi_client/configuration.py
openapi_client/exceptions.py
openapi_client/models/__init__.py
openapi_client/models/agent_run_response.py
openapi_client/models/create_agent_run_input.py
openapi_client/models/http_validation_error.py
openapi_client/models/organization_response.py
openapi_client/models/organization_settings.py
openapi_client/models/page_organization_response.py
openapi_client/models/page_user_response.py
openapi_client/models/user_response.py
openapi_client/models/validation_error.py
openapi_client/models/validation_error_loc_inner.py
openapi_client/py.typed
openapi_client/rest.py
pyproject.toml
requirements.txt
setup.cfg
setup.py
test-requirements.txt
test/__init__.py
test/test_agent_run_response.py
test/test_agents_api.py
test/test_create_agent_run_input.py
test/test_http_validation_error.py
test/test_organization_response.py
test/test_organization_settings.py
test/test_organizations_api.py
test/test_page_organization_response.py
test/test_page_user_response.py
test/test_user_response.py
test/test_users_api.py
test/test_validation_error.py
test/test_validation_error_loc_inner.py
tox.ini
1 change: 1 addition & 0 deletions src/codegen/agents/client/.openapi-generator/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.12.0
22 changes: 22 additions & 0 deletions src/codegen/agents/client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# openapi-client

API for application developers

This Python directory was automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project. However it the generated code was altered to make compatible with the rest of the project.

- API version: 1.0.0

### Steps to update client directory

1. Fetch the api schema from the API endpoint \[https://codegen-sh--rest-api.modal.run/api/openapi.json\](schema file)
1. generate the client code with the following command:

```bash
openapi-generator generate -i openapi.yaml -g python -o ./client
```

3. This command will generate a lot of unused files we just need to include the files in the `openapi_client` directory to the project.

1. May need to fix the imports for `openapi_client` to be fully qualified import paths.

1. TODO: make updates more streamlined. Ideally setup this api client as it's own package so all it takes is to generate the new code, no addtional manual steps are needed.
44 changes: 44 additions & 0 deletions src/codegen/agents/client/openapi_client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# coding: utf-8

# flake8: noqa

"""
Developer API

API for application developers

The version of the OpenAPI document: 1.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
""" # noqa: E501

__version__ = "1.0.0"

# import apis into sdk package
from codegen.agents.client.openapi_client.api.agents_api import AgentsApi
from codegen.agents.client.openapi_client.api.organizations_api import OrganizationsApi
from codegen.agents.client.openapi_client.api.users_api import UsersApi

# import ApiClient
from codegen.agents.client.openapi_client.api_response import ApiResponse
from codegen.agents.client.openapi_client.api_client import ApiClient
from codegen.agents.client.openapi_client.configuration import Configuration
from codegen.agents.client.openapi_client.exceptions import OpenApiException
from codegen.agents.client.openapi_client.exceptions import ApiTypeError
from codegen.agents.client.openapi_client.exceptions import ApiValueError
from codegen.agents.client.openapi_client.exceptions import ApiKeyError
from codegen.agents.client.openapi_client.exceptions import ApiAttributeError
from codegen.agents.client.openapi_client.exceptions import ApiException

# import models into sdk package
from codegen.agents.client.openapi_client.models.agent_run_response import AgentRunResponse
from codegen.agents.client.openapi_client.models.create_agent_run_input import CreateAgentRunInput
from codegen.agents.client.openapi_client.models.http_validation_error import HTTPValidationError
from codegen.agents.client.openapi_client.models.organization_response import OrganizationResponse
from codegen.agents.client.openapi_client.models.organization_settings import OrganizationSettings
from codegen.agents.client.openapi_client.models.page_organization_response import PageOrganizationResponse
from codegen.agents.client.openapi_client.models.page_user_response import PageUserResponse
from codegen.agents.client.openapi_client.models.user_response import UserResponse
from codegen.agents.client.openapi_client.models.validation_error import ValidationError
from codegen.agents.client.openapi_client.models.validation_error_loc_inner import ValidationErrorLocInner
6 changes: 6 additions & 0 deletions src/codegen/agents/client/openapi_client/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# flake8: noqa

# import apis into api package
from codegen.agents.client.openapi_client.api.agents_api import AgentsApi
from codegen.agents.client.openapi_client.api.organizations_api import OrganizationsApi
from codegen.agents.client.openapi_client.api.users_api import UsersApi
Loading
Loading