Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "api"
version = "0.72.3"
version = "0.72.4"
description = "Agenta API"
authors = [
{ name = "Mahmoud Mabrouk", email = "[email protected]" },
Expand Down
57 changes: 57 additions & 0 deletions sdk/agenta/sdk/assets.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
from typing import Dict, Optional, Tuple

from litellm import cost_calculator


supported_llm_models = {
"anthropic": [
"anthropic/claude-sonnet-4-5",
Expand Down Expand Up @@ -206,6 +211,58 @@

providers_list = list(supported_llm_models.keys())


def _get_model_costs(model: str) -> Optional[Tuple[float, float]]:
"""
Get the input and output costs per 1M tokens for a model.

Uses litellm's cost_calculator (same as tracing/inline.py) for consistency.

Args:
model: The model name (e.g., "gpt-4o" or "anthropic/claude-3-opus-20240229")

Returns:
Tuple of (input_cost, output_cost) per 1M tokens, or None if not found.
"""
try:
costs = cost_calculator.cost_per_token(
model=model,
prompt_tokens=1_000_000,
completion_tokens=1_000_000,
)
if costs:
input_cost, output_cost = costs
if input_cost > 0 or output_cost > 0:
return (input_cost, output_cost)
except Exception:
pass
return None


def _build_model_metadata() -> Dict[str, Dict[str, Dict[str, float]]]:
"""
Build metadata dictionary with costs for all supported models.

Returns:
Nested dict: {provider: {model: {"input": cost, "output": cost}}}
"""
metadata: Dict[str, Dict[str, Dict[str, float]]] = {}

for provider, models in supported_llm_models.items():
metadata[provider] = {}
for model in models:
costs = _get_model_costs(model)
if costs:
metadata[provider][model] = {
"input": costs[0],
"output": costs[1],
}

return metadata


model_metadata = _build_model_metadata()

model_to_provider_mapping = {
model: provider
for provider, models in supported_llm_models.items()
Expand Down
4 changes: 3 additions & 1 deletion sdk/agenta/sdk/middleware/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ async def _parse_variant_ref(
baggage.get("ag.refs.variant.slug")
# ALTERNATIVE
or request.query_params.get("variant_slug")
or body.get("variant_slug")
# LEGACY
or baggage.get("variant_slug")
or request.query_params.get("config")
Expand All @@ -234,6 +235,7 @@ async def _parse_variant_ref(
baggage.get("ag.refs.variant.version")
# ALTERNATIVE
or request.query_params.get("variant_version")
or body.get("variant_version")
# LEGACY
or baggage.get("variant_version")
)
Expand All @@ -244,7 +246,7 @@ async def _parse_variant_ref(
return Reference(
id=variant_id,
slug=variant_slug,
version=variant_version,
version=str(variant_version) if variant_version is not None else None,
)

async def _parse_environment_ref(
Expand Down
8 changes: 6 additions & 2 deletions sdk/agenta/sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from starlette.responses import StreamingResponse


from agenta.sdk.assets import supported_llm_models
from agenta.sdk.assets import supported_llm_models, model_metadata
from agenta.client.backend.types import AgentaNodesResponse, AgentaNodeDto


Expand All @@ -23,7 +23,11 @@ def MCField( # pylint: disable=invalid-name
) -> Field:
# Pydantic 2.12+ no longer allows post-creation mutation of field properties
if isinstance(choices, dict):
json_extra = {"choices": choices, "x-parameter": "grouped_choice"}
json_extra = {
"choices": choices,
"x-parameter": "grouped_choice",
"x-model-metadata": model_metadata,
}
elif isinstance(choices, list):
json_extra = {"choices": choices, "x-parameter": "choice"}
else:
Expand Down
2 changes: 1 addition & 1 deletion sdk/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "agenta"
version = "0.72.3"
version = "0.72.4"
description = "The SDK for agenta is an open-source LLMOps platform."
readme = "README.md"
authors = [
Expand Down
2 changes: 1 addition & 1 deletion web/ee/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agenta/ee",
"version": "0.72.3",
"version": "0.72.4",
"private": true,
"engines": {
"node": ">=18"
Expand Down
2 changes: 1 addition & 1 deletion web/oss/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agenta/oss",
"version": "0.72.3",
"version": "0.72.4",
"private": true,
"engines": {
"node": ">=18"
Expand Down
9 changes: 4 additions & 5 deletions web/oss/src/code_snippets/endpoints/fetch_config/python.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import {getEnv} from "@/oss/lib/helpers/dynamicEnv"

export default function pythonCode(appName: string, env_name: string, apiKey: string): string {
return `
import os
return `import os
import agenta as ag

os.environ["AGENTA_API_KEY"] = "${apiKey}" # Add your API key here
os.environ["AGENTA_API_KEY"] = "${apiKey}"
os.environ["AGENTA_HOST"] = "${getEnv("NEXT_PUBLIC_AGENTA_API_URL")}"

ag.init()
config = ag.ConfigManager.get_from_registry(
app_slug="${appName}",
environment_slug="${env_name}"
)
environment_slug="${env_name}",
)
print(config)
`
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const getConfig = async (appName: string, environmentSlug: string) => {
},
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': "ApiKey ${apiKey}", // Add your API key here
'Content-Type': 'application/json',
'Authorization': "ApiKey ${apiKey}",
},
});

Expand Down
7 changes: 4 additions & 3 deletions web/oss/src/code_snippets/endpoints/fetch_variant/curl.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {getEnv} from "@/oss/lib/helpers/dynamicEnv"

export const buildCurlSnippet = (
appSlug: string,
variantSlug: string,
variantVersion: number,
apiKey: string,
) => {
return `# Fetch configuration by variant
curl -X POST "https://cloud.agenta.ai/api/variants/configs/fetch" \\
return `curl -X POST "${getEnv("NEXT_PUBLIC_AGENTA_API_URL")}/variants/configs/fetch" \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer ${apiKey}" \\
-H "Authorization: ApiKey ${apiKey}" \\
-d '{
"variant_ref": {
"slug": "${variantSlug}",
Expand Down
5 changes: 2 additions & 3 deletions web/oss/src/code_snippets/endpoints/fetch_variant/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ export const buildPythonSnippet = (
variantSlug: string,
variantVersion: number,
) => {
return `# Fetch configuration by variant
import agenta as ag
return `import agenta as ag

config = ag.ConfigManager.get_from_registry(
app_slug="${appSlug}",
variant_slug="${variantSlug}",
variant_version=${variantVersion} # Optional: If not provided, fetches the latest version
variant_version=${variantVersion},
)

print("Fetched configuration:")
Expand Down
33 changes: 17 additions & 16 deletions web/oss/src/code_snippets/endpoints/fetch_variant/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import {getEnv} from "@/oss/lib/helpers/dynamicEnv"

export const buildTypescriptSnippet = (
appSlug: string,
variantSlug: string,
variantVersion: number,
apiKey: string,
) => {
return `// Fetch configuration by variant
const fetchResponse = await fetch('https://cloud.agenta.ai/api/variants/configs/fetch', {
return `const fetchResponse = await fetch('${getEnv("NEXT_PUBLIC_AGENTA_API_URL")}/variants/configs/fetch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ${apiKey}'
'Authorization': 'ApiKey ${apiKey}',
},
body: JSON.stringify({
variant_ref: {
slug: '${variantSlug}',
version: ${variantVersion},
id: null
slug: '${variantSlug}',
version: ${variantVersion},
id: null,
},
application_ref: {
slug: '${appSlug}',
version: null,
id: null
}
})
});
slug: '${appSlug}',
version: null,
id: null,
},
}),
});

const config = await fetchResponse.json();
console.log('Fetched configuration:');
console.log(config);
`
const config = await fetchResponse.json();
console.log('Fetched configuration:');
console.log(config);
`
}
5 changes: 2 additions & 3 deletions web/oss/src/code_snippets/endpoints/invoke_llm_app/curl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ export default function cURLCode(uri: string, params: string, apiKey: string): s
const parsedParams = JSON.parse(params)
const isChat = parsedParams.messages !== undefined

return `# Add your API key to the Authorization header
curl -X POST "${uri}" \\
return `curl -X POST "${uri}" \\
-H "Content-Type: application/json" \\
-H "Authorization: ApiKey ${apiKey}" \\${isChat ? '\n-H "Baggage: ag.session.id=your_session_id" \\ # Optional: track chat sessions' : ""}
-H "Authorization: ApiKey ${apiKey}" \\${isChat ? '\n-H "Baggage: ag.session.id=your_session_id" \\' : ""}
-d '${params}'
`
}
4 changes: 2 additions & 2 deletions web/oss/src/code_snippets/endpoints/invoke_llm_app/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import json
url = "${uri}"
params = ${params}
headers = {
"Content-Type": "application/json",
"Authorization": "ApiKey ${apiKey}", # Add your API key here${isChat ? '\n "Baggage": "ag.session.id=your_session_id", # Optional: track chat sessions' : ""}
"Content-Type": "application/json",
"Authorization": "ApiKey ${apiKey}",${isChat ? '\n "Baggage": "ag.session.id=your_session_id",' : ""}
}

response = requests.post(url, json=params, headers=headers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const generate = async () => {
const data = ${params};
const headers = {
"Content-Type": "application/json",
"Authorization": "ApiKey ${apiKey}", // Add your API key here${isChat ? '\n "Baggage": "ag.session.id=your_session_id" // Optional: track chat sessions' : ""}
"Authorization": "ApiKey ${apiKey}",${isChat ? '\n "Baggage": "ag.session.id=your_session_id",' : ""}
};

const response = await axios.post(url, data, { headers });
Expand Down
Loading