Skip to content

Commit c3eb5b5

Browse files
Merge pull request #3329 from Agenta-AI/feat/sdk-variant-body-params
feat(sdk): add body param support for variant_slug and variant_version
2 parents 1fadbfe + 3a1883c commit c3eb5b5

File tree

10 files changed

+121
-73
lines changed

10 files changed

+121
-73
lines changed

sdk/agenta/sdk/middleware/config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ async def _parse_variant_ref(
224224
baggage.get("ag.refs.variant.slug")
225225
# ALTERNATIVE
226226
or request.query_params.get("variant_slug")
227+
or body.get("variant_slug")
227228
# LEGACY
228229
or baggage.get("variant_slug")
229230
or request.query_params.get("config")
@@ -234,6 +235,7 @@ async def _parse_variant_ref(
234235
baggage.get("ag.refs.variant.version")
235236
# ALTERNATIVE
236237
or request.query_params.get("variant_version")
238+
or body.get("variant_version")
237239
# LEGACY
238240
or baggage.get("variant_version")
239241
)
@@ -244,7 +246,7 @@ async def _parse_variant_ref(
244246
return Reference(
245247
id=variant_id,
246248
slug=variant_slug,
247-
version=variant_version,
249+
version=str(variant_version) if variant_version is not None else None,
248250
)
249251

250252
async def _parse_environment_ref(
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import {getEnv} from "@/oss/lib/helpers/dynamicEnv"
22

33
export default function pythonCode(appName: string, env_name: string, apiKey: string): string {
4-
return `
5-
import os
4+
return `import os
65
import agenta as ag
76
8-
os.environ["AGENTA_API_KEY"] = "${apiKey}" # Add your API key here
7+
os.environ["AGENTA_API_KEY"] = "${apiKey}"
98
os.environ["AGENTA_HOST"] = "${getEnv("NEXT_PUBLIC_AGENTA_API_URL")}"
109
1110
ag.init()
1211
config = ag.ConfigManager.get_from_registry(
1312
app_slug="${appName}",
14-
environment_slug="${env_name}"
15-
)
13+
environment_slug="${env_name}",
14+
)
1615
print(config)
1716
`
1817
}

web/oss/src/code_snippets/endpoints/fetch_config/typescript.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ const getConfig = async (appName: string, environmentSlug: string) => {
2222
},
2323
}, {
2424
headers: {
25-
'Content-Type': 'application/json',
26-
'Authorization': "ApiKey ${apiKey}", // Add your API key here
25+
'Content-Type': 'application/json',
26+
'Authorization': "ApiKey ${apiKey}",
2727
},
2828
});
2929

web/oss/src/code_snippets/endpoints/fetch_variant/curl.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import {getEnv} from "@/oss/lib/helpers/dynamicEnv"
2+
13
export const buildCurlSnippet = (
24
appSlug: string,
35
variantSlug: string,
46
variantVersion: number,
57
apiKey: string,
68
) => {
7-
return `# Fetch configuration by variant
8-
curl -X POST "https://cloud.agenta.ai/api/variants/configs/fetch" \\
9+
return `curl -X POST "${getEnv("NEXT_PUBLIC_AGENTA_API_URL")}/variants/configs/fetch" \\
910
-H "Content-Type: application/json" \\
10-
-H "Authorization: Bearer ${apiKey}" \\
11+
-H "Authorization: ApiKey ${apiKey}" \\
1112
-d '{
1213
"variant_ref": {
1314
"slug": "${variantSlug}",

web/oss/src/code_snippets/endpoints/fetch_variant/python.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ export const buildPythonSnippet = (
33
variantSlug: string,
44
variantVersion: number,
55
) => {
6-
return `# Fetch configuration by variant
7-
import agenta as ag
6+
return `import agenta as ag
87
98
config = ag.ConfigManager.get_from_registry(
109
app_slug="${appSlug}",
1110
variant_slug="${variantSlug}",
12-
variant_version=${variantVersion} # Optional: If not provided, fetches the latest version
11+
variant_version=${variantVersion},
1312
)
1413
1514
print("Fetched configuration:")
Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
1+
import {getEnv} from "@/oss/lib/helpers/dynamicEnv"
2+
13
export const buildTypescriptSnippet = (
24
appSlug: string,
35
variantSlug: string,
46
variantVersion: number,
57
apiKey: string,
68
) => {
7-
return `// Fetch configuration by variant
8-
const fetchResponse = await fetch('https://cloud.agenta.ai/api/variants/configs/fetch', {
9+
return `const fetchResponse = await fetch('${getEnv("NEXT_PUBLIC_AGENTA_API_URL")}/variants/configs/fetch', {
910
method: 'POST',
1011
headers: {
1112
'Content-Type': 'application/json',
12-
'Authorization': 'Bearer ${apiKey}'
13+
'Authorization': 'ApiKey ${apiKey}',
1314
},
1415
body: JSON.stringify({
1516
variant_ref: {
16-
slug: '${variantSlug}',
17-
version: ${variantVersion},
18-
id: null
17+
slug: '${variantSlug}',
18+
version: ${variantVersion},
19+
id: null,
1920
},
2021
application_ref: {
21-
slug: '${appSlug}',
22-
version: null,
23-
id: null
24-
}
25-
})
26-
});
22+
slug: '${appSlug}',
23+
version: null,
24+
id: null,
25+
},
26+
}),
27+
});
2728
28-
const config = await fetchResponse.json();
29-
console.log('Fetched configuration:');
30-
console.log(config);
31-
`
29+
const config = await fetchResponse.json();
30+
console.log('Fetched configuration:');
31+
console.log(config);
32+
`
3233
}

web/oss/src/code_snippets/endpoints/invoke_llm_app/curl.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ export default function cURLCode(uri: string, params: string, apiKey: string): s
22
const parsedParams = JSON.parse(params)
33
const isChat = parsedParams.messages !== undefined
44

5-
return `# Add your API key to the Authorization header
6-
curl -X POST "${uri}" \\
5+
return `curl -X POST "${uri}" \\
76
-H "Content-Type: application/json" \\
8-
-H "Authorization: ApiKey ${apiKey}" \\${isChat ? '\n-H "Baggage: ag.session.id=your_session_id" \\ # Optional: track chat sessions' : ""}
7+
-H "Authorization: ApiKey ${apiKey}" \\${isChat ? '\n-H "Baggage: ag.session.id=your_session_id" \\' : ""}
98
-d '${params}'
109
`
1110
}

web/oss/src/code_snippets/endpoints/invoke_llm_app/python.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import json
88
url = "${uri}"
99
params = ${params}
1010
headers = {
11-
"Content-Type": "application/json",
12-
"Authorization": "ApiKey ${apiKey}", # Add your API key here${isChat ? '\n "Baggage": "ag.session.id=your_session_id", # Optional: track chat sessions' : ""}
11+
"Content-Type": "application/json",
12+
"Authorization": "ApiKey ${apiKey}",${isChat ? '\n "Baggage": "ag.session.id=your_session_id",' : ""}
1313
}
1414
1515
response = requests.post(url, json=params, headers=headers)

web/oss/src/code_snippets/endpoints/invoke_llm_app/typescript.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const generate = async () => {
1111
const data = ${params};
1212
const headers = {
1313
"Content-Type": "application/json",
14-
"Authorization": "ApiKey ${apiKey}", // Add your API key here${isChat ? '\n "Baggage": "ag.session.id=your_session_id" // Optional: track chat sessions' : ""}
14+
"Authorization": "ApiKey ${apiKey}",${isChat ? '\n "Baggage": "ag.session.id=your_session_id",' : ""}
1515
};
1616
1717
const response = await axios.post(url, data, { headers });

web/oss/src/components/DeploymentsDashboard/assets/VariantUseApiContent.tsx

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import {useCallback, useEffect, useMemo, useState} from "react"
22

33
import {PythonOutlined} from "@ant-design/icons"
4-
import {FileCodeIcon, FileTsIcon} from "@phosphor-icons/react"
5-
import {Tabs, Typography} from "antd"
4+
import {FileCode, FileTs} from "@phosphor-icons/react"
5+
import {Spin, Tabs, Typography} from "antd"
66
import {useAtomValue} from "jotai"
77
import dynamic from "next/dynamic"
88

99
import {buildCurlSnippet} from "@/oss/code_snippets/endpoints/fetch_variant/curl"
1010
import {buildPythonSnippet} from "@/oss/code_snippets/endpoints/fetch_variant/python"
1111
import {buildTypescriptSnippet} from "@/oss/code_snippets/endpoints/fetch_variant/typescript"
12-
import CopyButton from "@/oss/components/CopyButton/CopyButton"
13-
import CodeBlock from "@/oss/components/DynamicCodeBlock/CodeBlock"
12+
import invokeLlmAppcURLCode from "@/oss/code_snippets/endpoints/invoke_llm_app/curl"
13+
import invokeLlmApppythonCode from "@/oss/code_snippets/endpoints/invoke_llm_app/python"
14+
import invokeLlmApptsCode from "@/oss/code_snippets/endpoints/invoke_llm_app/typescript"
15+
import LanguageCodeBlock from "@/oss/components/pages/overview/deployments/DeploymentDrawer/assets/LanguageCodeBlock"
1416
import SelectVariant from "@/oss/components/Playground/Components/Menus/SelectVariant"
1517
import VariantDetailsWithStatus from "@/oss/components/VariantDetailsWithStatus"
16-
import {currentAppAtom} from "@/oss/state/app"
18+
import {useAppId} from "@/oss/hooks/useAppId"
19+
import {currentAppAtom, useURI} from "@/oss/state/app"
20+
import {stablePromptVariablesAtomFamily} from "@/oss/state/newPlayground/core/prompts"
1721
import {revisionsByVariantIdAtomFamily, variantsAtom} from "@/oss/state/variant/atoms/fetcher"
1822
import {
1923
latestRevisionInfoByVariantIdAtomFamily,
@@ -29,13 +33,8 @@ interface VariantUseApiContentProps {
2933
initialRevisionId?: string
3034
}
3135

32-
interface CodeSnippets {
33-
python: string
34-
typescript: string
35-
bash: string
36-
}
37-
3836
const VariantUseApiContent = ({initialRevisionId}: VariantUseApiContentProps) => {
37+
const appId = useAppId()
3938
const variants = useAtomValue(variantsAtom)
4039
const revisionList = useAtomValue(revisionListAtom)
4140
const currentApp = useAtomValue(currentAppAtom)
@@ -45,6 +44,15 @@ const VariantUseApiContent = ({initialRevisionId}: VariantUseApiContentProps) =>
4544
const [selectedLang, setSelectedLang] = useState("python")
4645
const [apiKeyValue, setApiKeyValue] = useState("")
4746

47+
// Get URI for the selected variant
48+
const {data: uri, isLoading: isUriQueryLoading} = useURI(appId, selectedVariantId)
49+
const isLoading = Boolean(selectedVariantId) && isUriQueryLoading
50+
51+
// Get variable names for the selected revision
52+
const variableNames = useAtomValue(
53+
stablePromptVariablesAtomFamily(selectedRevisionId || ""),
54+
) as string[]
55+
4856
const initialRevision = useMemo(
4957
() => revisionList.find((rev) => rev.id === initialRevisionId),
5058
[initialRevisionId, revisionList],
@@ -120,13 +128,52 @@ const VariantUseApiContent = ({initialRevisionId}: VariantUseApiContentProps) =>
120128
const variantSlug =
121129
(selectedVariant as any)?.variantSlug ||
122130
selectedVariant?.variantName ||
123-
selectedRevision?.variantName ||
131+
(selectedRevision as any)?.variantName ||
124132
"my-variant-slug"
125133
const variantVersion = selectedRevision?.revision ?? latestRevision?.revision ?? 1
126134
const appSlug = (currentApp as any)?.app_slug || currentApp?.app_name || "my-app-slug"
127135
const apiKey = apiKeyValue || "YOUR_API_KEY"
128136

129-
const codeSnippets: CodeSnippets = useMemo(
137+
const invokeLlmUrl = uri ?? ""
138+
139+
// Build params for invoke LLM (with variant refs instead of environment)
140+
const params = useMemo(() => {
141+
const synthesized = variableNames.map((name) => ({name, input: name === "messages"}))
142+
143+
const mainParams: Record<string, any> = {}
144+
const secondaryParams: Record<string, any> = {}
145+
146+
synthesized.forEach((item) => {
147+
if (item.input) {
148+
mainParams[item.name] = "add_a_value"
149+
} else {
150+
secondaryParams[item.name] = "add_a_value"
151+
}
152+
})
153+
154+
const hasMessagesParam = synthesized.some((p) => p?.name === "messages")
155+
const isChat = currentApp?.app_type === "chat" || hasMessagesParam
156+
if (isChat) {
157+
mainParams["messages"] = [
158+
{
159+
role: "user",
160+
content: "",
161+
},
162+
]
163+
mainParams["inputs"] = secondaryParams
164+
} else if (Object.keys(secondaryParams).length > 0) {
165+
mainParams["inputs"] = secondaryParams
166+
}
167+
168+
// Use variant refs instead of environment
169+
mainParams["app"] = appSlug
170+
mainParams["variant_slug"] = variantSlug
171+
mainParams["variant_version"] = variantVersion
172+
173+
return JSON.stringify(mainParams, null, 2)
174+
}, [variableNames, currentApp?.app_type, appSlug, variantSlug, variantVersion])
175+
176+
const fetchConfigCodeSnippet = useMemo(
130177
() => ({
131178
python: buildPythonSnippet(appSlug, variantSlug, variantVersion),
132179
typescript: buildTypescriptSnippet(appSlug, variantSlug, variantVersion, apiKey),
@@ -135,48 +182,48 @@ const VariantUseApiContent = ({initialRevisionId}: VariantUseApiContentProps) =>
135182
[apiKey, appSlug, variantSlug, variantVersion],
136183
)
137184

138-
const renderTabChildren = useCallback(() => {
139-
const activeSnippet = codeSnippets[selectedLang as keyof CodeSnippets]
185+
const invokeLlmAppCodeSnippet = useMemo(
186+
() => ({
187+
python: invokeLlmApppythonCode(invokeLlmUrl, params, apiKeyValue || "x.xxxxxxxx"),
188+
bash: invokeLlmAppcURLCode(invokeLlmUrl, params, apiKeyValue || "x.xxxxxxxx"),
189+
typescript: invokeLlmApptsCode(invokeLlmUrl, params, apiKeyValue || "x.xxxxxxxx"),
190+
}),
191+
[apiKeyValue, invokeLlmUrl, params],
192+
)
140193

194+
const renderTabChildren = useCallback(() => {
141195
return (
142-
<div className="flex flex-col gap-3">
143-
<div className="flex items-center justify-between">
144-
<Typography.Text className="font-medium">Use API</Typography.Text>
145-
<CopyButton text={activeSnippet} icon={true} buttonText={null} />
146-
</div>
147-
<CodeBlock language={selectedLang} value={activeSnippet} />
148-
</div>
196+
<Spin spinning={isLoading}>
197+
<LanguageCodeBlock
198+
fetchConfigCodeSnippet={fetchConfigCodeSnippet}
199+
invokeLlmAppCodeSnippet={invokeLlmAppCodeSnippet}
200+
selectedLang={selectedLang}
201+
handleOpenSelectDeployVariantModal={() => {}}
202+
invokeLlmUrl={invokeLlmUrl}
203+
/>
204+
</Spin>
149205
)
150-
}, [
151-
apiKeyValue,
152-
codeSnippets,
153-
revisionList,
154-
selectedLang,
155-
selectedRevision?.id,
156-
selectedRevision?.isLatestRevision,
157-
selectedRevision?.revision,
158-
selectedRevisionId,
159-
])
206+
}, [fetchConfigCodeSnippet, invokeLlmAppCodeSnippet, invokeLlmUrl, isLoading, selectedLang])
160207

161208
const tabItems = useMemo(
162209
() => [
163210
{
164211
key: "python",
165212
label: "Python",
166-
icon: <PythonOutlined />,
167213
children: renderTabChildren(),
214+
icon: <PythonOutlined />,
168215
},
169216
{
170217
key: "typescript",
171218
label: "TypeScript",
172-
icon: <FileTsIcon size={14} />,
173219
children: renderTabChildren(),
220+
icon: <FileTs size={14} />,
174221
},
175222
{
176223
key: "bash",
177224
label: "cURL",
178-
icon: <FileCodeIcon size={14} />,
179225
children: renderTabChildren(),
226+
icon: <FileCode size={14} />,
180227
},
181228
],
182229
[renderTabChildren],
@@ -221,10 +268,10 @@ const VariantUseApiContent = ({initialRevisionId}: VariantUseApiContentProps) =>
221268
<ApiKeyInput apiKeyValue={apiKeyValue} onApiKeyChange={setApiKeyValue} />
222269
</div>
223270
<Tabs
271+
destroyOnHidden
272+
defaultActiveKey={selectedLang}
224273
items={tabItems}
225274
onChange={setSelectedLang}
226-
activeKey={selectedLang}
227-
destroyInactiveTabPane
228275
/>
229276
</div>
230277
)

0 commit comments

Comments
 (0)