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
124 changes: 124 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,130 @@ async def main():
asyncio.run(main())
```

### Strands Agents Integration (optional)

Installation:

```bash
pip install 'portkey-ai[strands]'
```

Usage with Strands:

```python
from strands.agent import Agent
from portkey_ai.integrations.strands import PortkeyStrands

model = PortkeyStrands(
api_key="PORTKEY_API_KEY",
model_id="@openai/gpt-4o-mini",
# base_url="https://api.portkey.ai/v1", ## Optional
)

agent = Agent(model=model)

import asyncio

async def main():
result = await agent.invoke_async("Tell me a short programming joke.")
print(getattr(result, "text", result))

asyncio.run(main())
```

### Google ADK Integration (optional)

Installation:

```bash
pip install 'portkey-ai[adk]'
```

Usage with ADK:

```python
import asyncio
from google.adk.models.llm_request import LlmRequest
from google.genai import types
from portkey_ai.integrations.adk import PortkeyAdk

llm = PortkeyAdk(
api_key="PORTKEY_API_KEY",
model="@openai/gpt-4o-mini",
# base_url="https://api.portkey.ai/v1", ## Optional
)

req = LlmRequest(
model="@openai/gpt-4o-mini",
contents=[
types.Content(
role="user",
parts=[types.Part.from_text(text="Tell me a short programming joke.")],
)
],
)

async def main():
# Print only partial chunks to avoid duplicate final output
async for resp in llm.generate_content_async(req, stream=True):
if getattr(resp, "partial", False) and resp.content and resp.content.parts:
for p in resp.content.parts:
if getattr(p, "text", None):
print(p.text, end="")
print()

asyncio.run(main())
```

Non-streaming example (single final response):

```python
import asyncio
from google.adk.models.llm_request import LlmRequest
from google.genai import types
from portkey_ai.integrations.adk import PortkeyAdk

llm = PortkeyAdk(
api_key="PORTKEY_API_KEY",
model="@openai/gpt-4o-mini",
)

req = LlmRequest(
model="@openai/gpt-4o-mini",
contents=[
types.Content(
role="user",
parts=[types.Part.from_text(text="Give me a one-line programming joke (final only).")],
)
],
)

async def main():
final_text = []
async for resp in llm.generate_content_async(req, stream=False):
if resp.content and resp.content.parts:
for p in resp.content.parts:
if getattr(p, "text", None):
final_text.append(p.text)
print("".join(final_text))

asyncio.run(main())
```

Configuration notes:

- **system_role**: By default, the adapter sends the system instruction as a `developer` role message to align with ADK. If your provider expects a strict `system` role, pass `system_role="system"` when constructing `PortkeyAdk`.

```python
llm = PortkeyAdk(
model="@openai/gpt-4o-mini",
api_key="PORTKEY_API_KEY",
system_role="system", # switch from default "developer"
)
```

- **Tools**: When tools are present in the ADK request, the adapter sets `tool_choice="auto"` to enable function calling by default (mirrors the Strands adapter behavior).

## Compatibility with OpenAI SDK

Portkey currently supports all the OpenAI methods, including the legacy ones.
Expand Down
53 changes: 53 additions & 0 deletions examples/hello_world_portkey_adk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import asyncio
import os
import sys
from typing import List

try:
from google.adk.models.llm_request import LlmRequest
from google.genai import types
from portkey_ai.integrations.adk import PortkeyAdk
except Exception: # pragma: no cover - example script
print("This example requires the 'adk' extra: pip install 'portkey-ai[adk]'")
raise


def build_request(model: str) -> "LlmRequest": # type: ignore[name-defined]
return LlmRequest(
model=model,
contents=[
types.Content(
role="user",
parts=[
types.Part.from_text(
text="Give me a one-line programming joke (final only)."
)
],
)
],
)


async def main() -> None:
api_key = os.environ.get("PORTKEY_API_KEY")
model = os.environ.get("MODEL_SLUG", "@openai/gpt-4o-mini")

if not api_key:
print("Set PORTKEY_API_KEY in your environment.", file=sys.stderr)
sys.exit(1)

llm = PortkeyAdk(api_key=api_key, model=model)

# Non-streaming: returns a single final response
req = build_request(model)
final_text: List[str] = []
async for resp in llm.generate_content_async(req, stream=False):
if resp.content and getattr(resp.content, "parts", None):
for p in resp.content.parts:
if getattr(p, "text", None):
final_text.append(p.text)
print("".join(final_text))


if __name__ == "__main__": # pragma: no cover - example script
asyncio.run(main())
44 changes: 44 additions & 0 deletions examples/hello_world_portkey_strands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import asyncio
import os
import sys

try:
from portkey_ai.integrations.strands import PortkeyStrands
except Exception:
print(
"This example requires the 'strands' extra: pip install 'portkey-ai[strands]'",
file=sys.stderr,
)
raise


async def main() -> None:
api_key = os.environ.get("PORTKEY_API_KEY")
model_id = os.environ.get("MODEL_SLUG", "@openai/gpt-4o-mini")

if not api_key:
print("Set PORTKEY_API_KEY in your environment.", file=sys.stderr)
sys.exit(1)

model = PortkeyStrands(
api_key=api_key, # type: ignore[arg-type]
model_id=model_id, # type: ignore[arg-type]
)

# Minimal Strands-compatible message list (no Agent required)
messages = [
{"role": "user", "content": "Tell me a short programming joke."},
]

print(f"Streaming with model: {model_id}")
async for event in model.stream(messages=messages):
# Events follow the Strands stream event shape produced by our adapter.
if isinstance(event, dict) and "contentBlockDelta" in event:
delta = event["contentBlockDelta"].get("delta", {})
if isinstance(delta, dict) and "text" in delta:
print(delta["text"], end="")
print("\n-- stream done --")


if __name__ == "__main__": # pragma: no cover - example script
asyncio.run(main())
4 changes: 4 additions & 0 deletions portkey_ai/integrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Integrations namespace.

Optional adapters for third-party frameworks live here. Install extras to use.
"""
Loading
Loading