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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 43 additions & 16 deletions src/components/docs/ApiExplorer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,27 @@
* target pages and extracts .apg data to update the drawer in-place (no page reload).
*/
import { tabNavigation } from '../../lib/navigation.ts';
import { apiNavigation } from '../../lib/api-navigation.ts';
// Build a href → method lookup from api-navigation.ts (source of truth for HTTP methods)
const methodByHref: Record<string, string> = {};
for (const group of apiNavigation) {
for (const item of group.items) {
if (item.href && item.method) {
methodByHref[item.href] = item.method;
}
}
}

// Extract the API tab navigation at build time
const apiTab = tabNavigation.find(t => t.tab === 'API');
const apiGroups = apiTab ? apiTab.groups : [];

// Flatten the API groups into a structure suitable for the sidebar:
// { group: string, items: { title: string, href: string, method?: string }[] }[]
// { group: string, items: { title: string, href: string, method: string }[] }[]
interface SidebarEndpoint {
title: string;
href: string;
method: string;
}
interface SidebarGroup {
group: string;
Expand All @@ -29,7 +40,7 @@ function flattenItems(items: any[]): SidebarEndpoint[] {
const result: SidebarEndpoint[] = [];
for (const item of items) {
if (item.href && item.href !== '/docs/api') {
result.push({ title: item.title, href: item.href });
result.push({ title: item.title, href: item.href, method: methodByHref[item.href] || 'GET' });
}
if (item.items) {
result.push(...flattenItems(item.items));
Expand Down Expand Up @@ -476,8 +487,8 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);

for (var j = 0; j < groupItems.length; j++) {
var ep = groupItems[j];
// Infer method from title
var method = inferMethodFromTitle(ep.title);
// Use method from api-navigation.ts (baked in at build time), fall back to title inference
var method = ep.method || inferMethodFromTitle(ep.title);
var isActive = ep.href === window.location.pathname.replace(/\/$/, '');
html += '<a href="' + esc(ep.href) + '" class="apx-sidebar-link' + (isActive ? ' apx-active' : '') + '" data-href="' + esc(ep.href) + '">';
html += '<span class="apx-sidebar-method apx-sm-' + method.toLowerCase() + '">' + shortMethod(method) + '</span>';
Expand All @@ -494,7 +505,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);

function inferMethodFromTitle(title) {
var t = title.toLowerCase();
if (t.indexOf('create') === 0 || t.indexOf('add') === 0 || t.indexOf('submit') === 0 || t.indexOf('apply') === 0 || t.indexOf('bulk') === 0 || t.indexOf('upload') === 0 || t.indexOf('run') === 0 || t.indexOf('execute') === 0 || t.indexOf('send') === 0 || t.indexOf('generate') === 0 || t.indexOf('clone') === 0) return 'POST';
if (t.indexOf('create') === 0 || t.indexOf('add') === 0 || t.indexOf('submit') === 0 || t.indexOf('apply') === 0 || t.indexOf('bulk') === 0 || t.indexOf('upload') === 0 || t.indexOf('run') === 0 || t.indexOf('execute') === 0 || t.indexOf('send') === 0 || t.indexOf('generate') === 0 || t.indexOf('clone') === 0 || t.indexOf('rerun') === 0 || t.indexOf('cancel') === 0 || t.indexOf('duplicate') === 0 || t.indexOf('restore') === 0 || t.indexOf('pause') === 0 || t.indexOf('unpause') === 0 || t.indexOf('release') === 0 || t.indexOf('assign') === 0 || t.indexOf('complete') === 0 || t.indexOf('skip') === 0 || t.indexOf('fetch') === 0 || t.indexOf('export') === 0) return 'POST';
if (t.indexOf('update') === 0 || t.indexOf('edit') === 0 || t.indexOf('merge') === 0) return 'PATCH';
if (t.indexOf('delete') === 0 || t.indexOf('remove') === 0) return 'DELETE';
return 'GET';
Expand Down Expand Up @@ -680,13 +691,29 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
function buildBodyForm(body, method) {
if (!bodySection || !bodyFields) return;

if (!body || typeof body !== 'object' || Array.isArray(body) || !/POST|PUT|PATCH/.test(method)) {
if (!/POST|PUT|PATCH|DELETE/.test(method)) {
bodySection.style.display = 'none';
bodyFields.innerHTML = '';
if (bodyIntro) bodyIntro.style.display = 'none';
return;
}

// Merge ParamField body metadata keys into body so fields documented
// via <ParamField body="..."> but missing from requestBody still appear.
body = body && typeof body === 'object' && !Array.isArray(body) ? Object.assign({}, body) : {};
for (var mk in currentBodyMeta) {
if (currentBodyMeta.hasOwnProperty(mk) && mk.indexOf('.') === -1 && !(mk in body)) {
var mt = currentBodyMeta[mk].type || 'string';
if (/array|list/i.test(mt)) body[mk] = [];
else if (/object/i.test(mt)) body[mk] = {};
else if (/bool/i.test(mt)) body[mk] = false;
else if (/int|number|double|float/i.test(mt)) body[mk] = 0;
else body[mk] = '';
}
}
// Keep currentReqBody in sync so optional picker and code gen use merged body
currentReqBody = body;

var keys = Object.keys(body);
if (keys.length === 0) {
bodySection.style.display = 'none';
Expand Down Expand Up @@ -2011,7 +2038,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
} else {
lines.push(' -H "Authorization: Bearer ' + authInfo.token + '"');
}
if (body && /POST|PUT|PATCH/.test(method)) {
if (body && /POST|PUT|PATCH|DELETE/.test(method)) {
lines[lines.length - 1] += ' \\';
lines.push(' -H "Content-Type: application/json" \\');
lines.push(" -d '" + JSON.stringify(body, null, 2).replace(/'/g, "'\\''") + "'");
Expand All @@ -2026,7 +2053,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
if (parts.length > 1 && method === 'GET') sdkMethod = 'get';
var apiKeyVal = isApiKey ? authInfo.apiKey : authInfo.token;
var lines = ['from fi.client import FutureAGI', '', 'client = FutureAGI(api_key="' + apiKeyVal + '")', ''];
if (body && typeof body === 'object' && /POST|PUT|PATCH/.test(method)) {
if (body && typeof body === 'object' && /POST|PUT|PATCH|DELETE/.test(method)) {
lines.push('response = client.' + resource + '.' + sdkMethod + '(');
var bKeys = Object.keys(body);
for (var ki = 0; ki < bKeys.length; ki++) {
Expand All @@ -2047,16 +2074,16 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
headerStr = ' headers={"Authorization": "Bearer ' + authInfo.token + '"},';
}
var lines = ['import requests', '', 'response = requests.' + method.toLowerCase() + '(', ' "' + url + '",', headerStr];
if (body && /POST|PUT|PATCH/.test(method)) lines.push(' json=' + JSON.stringify(body, null, 4) + ',');
if (body && /POST|PUT|PATCH|DELETE/.test(method)) lines.push(' json=' + JSON.stringify(body, null, 4) + ',');
lines.push(')'); lines.push('print(response.json())');
return lines.join('\n');
}
if (lang === 'go') {
var lines = ['package main', '', 'import (', ' "bytes"', ' "fmt"', ' "io"', ' "net/http"'];
if (body && /POST|PUT|PATCH/.test(method)) lines.push(' "encoding/json"');
if (body && /POST|PUT|PATCH|DELETE/.test(method)) lines.push(' "encoding/json"');
lines.push(')', '');
lines.push('func main() {');
if (body && /POST|PUT|PATCH/.test(method)) {
if (body && /POST|PUT|PATCH|DELETE/.test(method)) {
lines.push(' body, _ := json.Marshal(' + JSON.stringify(body) + ')');
lines.push(' req, _ := http.NewRequest("' + method + '", "' + url + '", bytes.NewBuffer(body))');
} else {
Expand Down Expand Up @@ -2089,7 +2116,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
builderLines.push(' .header("Authorization", "Bearer ' + authInfo.token + '")');
}
builderLines.push(' .header("Content-Type", "application/json")');
if (body && /POST|PUT|PATCH/.test(method)) {
if (body && /POST|PUT|PATCH|DELETE/.test(method)) {
builderLines.push(' .' + method + '(HttpRequest.BodyPublishers.ofString(' + JSON.stringify(JSON.stringify(body)) + '))');
} else if (method === 'DELETE') {
builderLines.push(' .DELETE()');
Expand All @@ -2105,7 +2132,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
}
if (lang === 'php') {
var lines = ['<?php', '', '$ch = curl_init();', 'curl_setopt($ch, CURLOPT_URL, "' + url + '");', 'curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);'];
if (/POST|PUT|PATCH/.test(method)) {
if (/POST|PUT|PATCH|DELETE/.test(method)) {
lines.push('curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "' + method + '");');
} else if (method === 'DELETE') {
lines.push('curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");');
Expand All @@ -2121,7 +2148,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
lines.push('curl_setopt($ch, CURLOPT_HTTPHEADER, [');
lines.push(phpHeaders.join(',\n'));
lines.push(']);');
if (body && /POST|PUT|PATCH/.test(method)) {
if (body && /POST|PUT|PATCH|DELETE/.test(method)) {
lines.push("curl_setopt($ch, CURLOPT_POSTFIELDS, '" + JSON.stringify(body, null, 2).replace(/'/g, "\\'") + "');");
}
lines.push('');
Expand All @@ -2145,7 +2172,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
lines.push('request["Authorization"] = "Bearer ' + authInfo.token + '"');
}
lines.push('request["Content-Type"] = "application/json"');
if (body && /POST|PUT|PATCH/.test(method)) {
if (body && /POST|PUT|PATCH|DELETE/.test(method)) {
lines.push('request.body = ' + JSON.stringify(JSON.stringify(body, null, 2)));
}
lines.push('');
Expand All @@ -2163,7 +2190,7 @@ const sidebarDataJson = JSON.stringify(sidebarGroups);
var lines = ['const response = await fetch("' + url + '", {', ' method: "' + method + '",', ' headers: {'];
lines = lines.concat(jsHeaders);
lines.push(' },');
if (body && /POST|PUT|PATCH/.test(method)) lines.push(' body: JSON.stringify(' + JSON.stringify(body, null, 4) + '),');
if (body && /POST|PUT|PATCH|DELETE/.test(method)) lines.push(' body: JSON.stringify(' + JSON.stringify(body, null, 4) + '),');
lines.push('});'); lines.push('const data = await response.json();');
return lines.join('\n');
}
Expand Down
8 changes: 4 additions & 4 deletions src/components/docs/ApiPlayground.astro
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ const respJson = responseExample ? JSON.stringify(responseExample, null, 2) : nu
var b=hiddenFields ? Object.assign({}, requestBody, hiddenFields) : requestBody;
if(lang==='curl'){
var r=['curl '+u+' \\',' -H "Authorization: Bearer '+t+'"'];
if(b&&/POST|PUT|PATCH/.test(m)){
if(b&&/POST|PUT|PATCH|DELETE/.test(m)){
r[r.length-1]+=' \\';
r.push(' -H "Content-Type: application/json" \\');
r.push(" -d '"+JSON.stringify(b,null,2)+"'");
Expand All @@ -221,7 +221,7 @@ const respJson = responseExample ? JSON.stringify(responseExample, null, 2) : nu
var r = ['from fi.client import FutureAGI', ''];
r.push('client = FutureAGI(api_key="' + t + '")');
r.push('');
if (b && /POST|PUT|PATCH/.test(m)) {
if (b && /POST|PUT|PATCH|DELETE/.test(m)) {
r.push('response = client.' + resource + '.' + sdkMethod + '(');
var bKeys = Object.keys(b);
for (var ki = 0; ki < bKeys.length; ki++) {
Expand All @@ -238,13 +238,13 @@ const respJson = responseExample ? JSON.stringify(responseExample, null, 2) : nu
}
if(lang==='python'){
var r=['import requests','','response = requests.'+m.toLowerCase()+'(',' "'+u+'",',' headers={"Authorization": "Bearer '+t+'"},'];
if(b&&/POST|PUT|PATCH/.test(m)) r.push(' json='+JSON.stringify(b,null,4)+',');
if(b&&/POST|PUT|PATCH|DELETE/.test(m)) r.push(' json='+JSON.stringify(b,null,4)+',');
r.push(')');r.push('print(response.json())');
return r.join('\n');
}
// javascript
var r=['const response = await fetch("'+u+'", {',' method: "'+m+'",',' headers: {',' "Authorization": "Bearer '+t+'",',' "Content-Type": "application/json",',' },'];
if(b&&/POST|PUT|PATCH/.test(m)) r.push(' body: JSON.stringify('+JSON.stringify(b,null,4)+'),');
if(b&&/POST|PUT|PATCH|DELETE/.test(m)) r.push(' body: JSON.stringify('+JSON.stringify(b,null,4)+'),');
r.push('});');r.push('const data = await response.json();');
return r.join('\n');
}
Expand Down
19 changes: 2 additions & 17 deletions src/lib/api-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,6 @@ export const apiNavigation: ApiNavGroup[] = [
"href": "/docs/api/test-executions/getperformancesummary",
"method": "GET"
},
{
"title": "Get eval explanation summary",
"href": "/docs/api/test-executions/getevalexplanationsummary",
"method": "GET"
},
{
"title": "Cancel test execution",
"href": "/docs/api/test-executions/cancelexecution",
Expand All @@ -281,20 +276,10 @@ export const apiNavigation: ApiNavGroup[] = [
"title": "Rerun call executions",
"href": "/docs/api/test-executions/reruncalls",
"method": "POST"
}
]
},
{
"title": "Call Executions",
"items": [
{
"title": "Get call execution details",
"href": "/docs/api/call-executions/getcallexecutiondetails",
"method": "GET"
},
{
"title": "Compare execution sessions",
"href": "/docs/api/call-executions/getsessioncomparison",
"title": "Get call execution details",
"href": "/docs/api/test-executions/getcallexecutiondetails",
"method": "GET"
}
]
Expand Down
9 changes: 1 addition & 8 deletions src/lib/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1112,16 +1112,9 @@ export const tabNavigation: NavTab[] = [
{ title: 'Get Execution Details', href: '/docs/api/test-executions/gettestexecutiondetails' },
{ title: 'Get Execution KPIs', href: '/docs/api/test-executions/getkpis' },
{ title: 'Get Performance Summary', href: '/docs/api/test-executions/getperformancesummary' },
{ title: 'Get Eval Explanation', href: '/docs/api/test-executions/getevalexplanationsummary' },
{ title: 'Cancel Execution', href: '/docs/api/test-executions/cancelexecution' },
{ title: 'Rerun Calls', href: '/docs/api/test-executions/reruncalls' },
]
},
{
title: 'Call Executions',
items: [
{ title: 'Get Call Details', href: '/docs/api/call-executions/getcallexecutiondetails' },
{ title: 'Compare Sessions', href: '/docs/api/call-executions/getsessioncomparison' },
{ title: 'Get Call Details', href: '/docs/api/test-executions/getcallexecutiondetails' },
]
},
{
Expand Down
84 changes: 0 additions & 84 deletions src/pages/docs/api/call-executions/getsessioncomparison.mdx

This file was deleted.

3 changes: 0 additions & 3 deletions src/pages/docs/api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ Get your API key from the [Future AGI Dashboard](https://app.futureagi.com/setti
<Card title="Test Executions" href="/docs/api/test-executions/gettestexecutiondetails" icon="code">
Test execution tracking and analytics
</Card>
<Card title="Call Executions" href="/docs/api/call-executions/getcallexecutiondetails" icon="code">
Individual call execution details
</Card>
<Card title="Datasets" href="/docs/api/datasets/create-dataset" icon="code">
Dataset creation, modification, and data management
</Card>
Expand Down
Loading