Skip to content

Commit 4b2a1fc

Browse files
committed
Add Tuning Engines model provider sample
1 parent 6168ebc commit 4b2a1fc

4 files changed

Lines changed: 159 additions & 2 deletions

File tree

openai_agents/model_providers/README.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,32 @@ The example uses Anthropic Claude by default but can be modified to use other Li
3030

3131
Find more LiteLLM providers at: https://docs.litellm.ai/docs/providers
3232

33+
#### Tuning Engines
34+
Uses a custom `ModelProvider` to route OpenAI Agents SDK model calls through the Tuning Engines OpenAI-compatible gateway.
35+
36+
Set your Tuning Engines inference key and, optionally, the tenant model alias to use:
37+
38+
```bash
39+
export TUNING_ENGINES_API_KEY="sk-te-..."
40+
export TUNING_ENGINES_MODEL="your-model-alias"
41+
# Optional, defaults to https://api.tuningengines.com/v1
42+
export TUNING_ENGINES_BASE_URL="https://api.tuningengines.com/v1"
43+
```
44+
45+
Start the Tuning Engines provider worker:
46+
47+
```bash
48+
uv run openai_agents/model_providers/run_tuning_engines_worker.py
49+
```
50+
51+
Then run the example in a separate terminal:
52+
53+
```bash
54+
uv run openai_agents/model_providers/run_tuning_engines_workflow.py
55+
```
56+
57+
Use a model alias that is available to the configured Tuning Engines inference key.
58+
3359
### Extra
3460

3561
#### GPT-OSS with Ollama
@@ -63,5 +89,4 @@ uv run openai_agents/model_providers/run_gpt_oss_workflow.py
6389

6490
- **Custom Example Agent** - Custom OpenAI client integration
6591
- **Custom Example Global** - Global default client configuration
66-
- **Custom Example Provider** - Custom ModelProvider pattern
67-
- **LiteLLM Provider** - Interactive model/API key input
92+
- **LiteLLM Provider** - Interactive model/API key input
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import asyncio
2+
import os
3+
from datetime import timedelta
4+
from typing import Optional
5+
6+
from agents import (
7+
Model,
8+
ModelProvider,
9+
OpenAIChatCompletionsModel,
10+
set_tracing_disabled,
11+
)
12+
from openai import AsyncOpenAI
13+
from temporalio.client import Client
14+
from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin
15+
from temporalio.worker import Worker
16+
17+
from openai_agents.model_providers.workflows.tuning_engines_workflow import (
18+
TuningEnginesWorkflow,
19+
)
20+
21+
TUNING_ENGINES_BASE_URL = os.environ.get(
22+
"TUNING_ENGINES_BASE_URL", "https://api.tuningengines.com/v1"
23+
)
24+
TUNING_ENGINES_MODEL = os.environ.get("TUNING_ENGINES_MODEL")
25+
TUNING_ENGINES_API_KEY = os.environ.get("TUNING_ENGINES_API_KEY")
26+
27+
if not TUNING_ENGINES_API_KEY:
28+
raise RuntimeError("Set TUNING_ENGINES_API_KEY before starting this worker")
29+
30+
tuning_engines_client = AsyncOpenAI(
31+
base_url=TUNING_ENGINES_BASE_URL,
32+
api_key=TUNING_ENGINES_API_KEY,
33+
)
34+
35+
36+
class TuningEnginesModelProvider(ModelProvider):
37+
def get_model(self, model_name: Optional[str]) -> Model:
38+
model = OpenAIChatCompletionsModel(
39+
model=TUNING_ENGINES_MODEL or model_name or "tuning-engines-default",
40+
openai_client=tuning_engines_client,
41+
)
42+
return model
43+
44+
45+
async def main():
46+
# Disable Agents SDK tracing — the default exporter sends traces to OpenAI's
47+
# backend, which requires an OpenAI API key not available in these samples.
48+
# Call here rather than in the workflow because it's a global side effect.
49+
set_tracing_disabled(disabled=True)
50+
51+
client = await Client.connect(
52+
"localhost:7233",
53+
plugins=[
54+
OpenAIAgentsPlugin(
55+
model_params=ModelActivityParameters(
56+
start_to_close_timeout=timedelta(seconds=30)
57+
),
58+
model_provider=TuningEnginesModelProvider(),
59+
),
60+
],
61+
)
62+
63+
worker = Worker(
64+
client,
65+
task_queue="openai-agents-model-providers-task-queue",
66+
workflows=[
67+
TuningEnginesWorkflow,
68+
],
69+
)
70+
await worker.run()
71+
72+
73+
if __name__ == "__main__":
74+
asyncio.run(main())
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import asyncio
2+
3+
from temporalio.client import Client
4+
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin
5+
6+
from openai_agents.model_providers.workflows.tuning_engines_workflow import (
7+
TuningEnginesWorkflow,
8+
)
9+
10+
11+
async def main():
12+
client = await Client.connect(
13+
"localhost:7233",
14+
plugins=[
15+
OpenAIAgentsPlugin(),
16+
],
17+
)
18+
19+
result = await client.execute_workflow(
20+
TuningEnginesWorkflow.run,
21+
"Explain why a governed model gateway is useful in production.",
22+
id="tuning-engines-workflow-id",
23+
task_queue="openai-agents-model-providers-task-queue",
24+
)
25+
print(f"Result: {result}")
26+
27+
28+
if __name__ == "__main__":
29+
asyncio.run(main())
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
from agents import Agent, Runner, function_tool
4+
from temporalio import workflow
5+
6+
7+
@workflow.defn
8+
class TuningEnginesWorkflow:
9+
@workflow.run
10+
async def run(self, prompt: str) -> str:
11+
@function_tool
12+
def summarize_gateway_policy(topic: str):
13+
return (
14+
f"For {topic}, keep model access scoped, log usage, and route "
15+
"through approved tenant model aliases."
16+
)
17+
18+
agent = Agent(
19+
name="Assistant",
20+
instructions=(
21+
"You explain production AI gateway tradeoffs clearly and use the "
22+
"policy summary tool when governance is relevant."
23+
),
24+
model="tuning-engines-default",
25+
tools=[summarize_gateway_policy],
26+
)
27+
28+
result = await Runner.run(agent, prompt)
29+
return result.final_output

0 commit comments

Comments
 (0)