Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Extend app_type

Revision ID: 863f8ebc200f
Revises: 3b5f5652f611
Create Date: 2025-01-08 10:24:00
"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = "863f8ebc200f"
down_revision: Union[str, None] = "3b5f5652f611"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


# The table/column that uses the enum
TABLE = "app_db"
COLUMN = "app_type"
TYPE_NAME = "app_type_enum"
TYPE_TEMP = "app_type_enum_temp"

# Exact labels
ORIGINAL = (
"CHAT_TEMPLATE",
"COMPLETION_TEMPLATE",
"CHAT_SERVICE",
"COMPLETION_SERVICE",
"CUSTOM",
)
EXTENDED = ORIGINAL + ("SDK_CUSTOM",)


def _create_enum(name: str, labels: tuple[str, ...]) -> None:
labels_sql = ",".join(f"'{v}'" for v in labels)
op.execute(f"CREATE TYPE {name} AS ENUM ({labels_sql})")


def _retype_column(to_type: str) -> None:
op.execute(
f"""
ALTER TABLE {TABLE}
ALTER COLUMN {COLUMN}
TYPE {to_type}
USING {COLUMN}::text::{to_type}
"""
)


def upgrade():
# 1) Create the replacement enum with ALL desired values
_create_enum(TYPE_TEMP, EXTENDED)

# 2) Point the column to the tmp type
_retype_column(TYPE_TEMP)

# 3) Drop old type and rename tmp to the canonical name
op.execute(f"DROP TYPE {TYPE_NAME}")
op.execute(f"ALTER TYPE {TYPE_TEMP} RENAME TO {TYPE_NAME}")


def downgrade():
# 1) Recreate the enum WITHOUT the added values
_create_enum(TYPE_TEMP, ORIGINAL)

# 2) Point the column back to the original label set
_retype_column(TYPE_TEMP)

# 3) Drop current type and rename tmp back to the canonical name
op.execute(f"DROP TYPE {TYPE_NAME}")
op.execute(f"ALTER TYPE {TYPE_TEMP} RENAME TO {TYPE_NAME}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""migrate data.script from string to object

Revision ID: baa02d66a365
Revises: 863f8ebc200f
Create Date: 2025-11-06 15:49:00
"""

from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = "baa02d66a365"
down_revision: Union[str, None] = "863f8ebc200f"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# Convert data.script from a JSON string to:
# {"content": <old string>, "runtime": "python"}
op.execute(
sa.text(
"""
UPDATE public.workflow_revisions
SET data = jsonb_set(
data::jsonb,
'{script}',
jsonb_build_object(
'content', data->>'script',
'runtime', 'python'
)
)::json
WHERE data->>'script' IS NOT NULL
AND json_typeof(data->'script') = 'string';
"""
)
)


def downgrade() -> None:
# Revert only objects shaped like:
# {"content": <string>, "runtime": "python"} -> "<string>"
op.execute(
sa.text(
"""
UPDATE public.workflow_revisions
SET data = jsonb_set(
data::jsonb,
'{script}',
to_jsonb( (data->'script'->>'content') )
)::json
WHERE json_typeof(data->'script') = 'object'
AND (data->'script') ? 'content'
AND json_typeof(data->'script'->'content') = 'string'
AND (
(data->'script' ? 'runtime') IS FALSE
OR (data->'script'->>'runtime') = 'python'
);
"""
)
)
Empty file.
98 changes: 98 additions & 0 deletions api/ee/tests/manual/evaluations/sdk/openai_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# /// script
# dependencies = ["agenta", "openai-agents", "openinference-instrumentation-openai-agents", "ipdb", "opentelemetry-api", "opentelemetry-sdk"]
# ///

from agents import (
Agent,
InputGuardrail,
GuardrailFunctionOutput,
Runner,
WebSearchTool,
run_demo_loop,
)
from agents.exceptions import InputGuardrailTripwireTriggered
from pydantic import BaseModel
import asyncio
from dotenv import load_dotenv
import os

load_dotenv()
import agenta as ag

# from openinference.instrumentation.openai_agents import OpenAIAgentsInstrumentor
# from opentelemetry import trace
# from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor
# from opentelemetry.sdk.trace import ReadableSpan
# from opentelemetry.sdk.trace.export import SpanProcessor
# from opentelemetry.trace import Span
from typing import Optional

# os.environ["AGENTA_API_KEY"] = ""

# ag.init()
# OpenAIAgentsInstrumentor().instrument()


class AgentaQuestionOutput(BaseModel):
is_agenta_question: bool
reasoning: str


guardrail_agent = Agent(
name="Guardrail check",
instructions="Check if the user is asking something about Agenta, the LLMOps platform. Their question might be ambiguous, so you need to be careful.",
output_type=AgentaQuestionOutput,
model="gpt-4o-mini",
)

web_research_agent = Agent(
name="Web Research Agent",
handoff_description="Specialist agent for web research. You will use this agent to research the user's question when the documentation is not enough. You mainly search the websites agenta.ai and docs.agenta.ai",
instructions="You will search the web to answer the user's question about Agenta, the LLMOps platform.",
tools=[
WebSearchTool(),
],
model="gpt-4o-mini",
)


async def guardrail_function(ctx, agent, input_data):
result = await Runner.run(guardrail_agent, input_data, context=ctx.context)
final_output = result.final_output_as(AgentaQuestionOutput)
return GuardrailFunctionOutput(
output_info=final_output,
tripwire_triggered=not final_output.is_agenta_question,
)


triage_agent = Agent(
name="Triage Agent",
instructions="You determine which agent to use based on the user's question on agenta",
handoffs=[web_research_agent],
input_guardrails=[
InputGuardrail(guardrail_function=guardrail_function),
],
model="gpt-4o-mini",
)

# async def main():
# # Example 1: History question
# # agent = Agent(name="Assistant", instructions="You are a helpful assistant.")
# await run_demo_loop(triage_agent)

# # try:
# # result = await Runner.run(triage_agent, "What is the meaning of life?")
# # import ipdb; ipdb.set_trace()
# # print(result.final_output)
# # except InputGuardrailTripwireTriggered as e:
# # print("Guardrail blocked this input:", e)

# # # Example 2: General/philosophical question
# # try:
# # result = await Runner.run(triage_agent, "What is the meaning of life?")
# # print(result.final_output)
# # except InputGuardrailTripwireTriggered as e:
# # print("Guardrail blocked this input:", e)

# if __name__ == "__main__":
# asyncio.run(main())
Loading
Loading