AiFO AiFO مستندات AiFO

نمای کلی

POST /v1/responses یک endpoint سازگار با OpenAI Responses است. با تغییر base URL، API Key و model در OpenAI SDK می‌توانید از AiFO استفاده کنید. Gateway از providerهای OpenAI و OpenRouter پشتیبانی می‌کند، اما ادعای parity کامل با OpenAI Responses را ندارد.

  • ورودی متنی (string) و structured با input_text
  • input_image با image_url (https یا data URL)
  • input_file.file_id متعلق به AiFO (file_…) — نه شناسهٔ provider با پیشوند file-
  • Structured outputs از طریق text.format (مثلاً json_schema) — passthrough به upstream
  • OpenAI stateful: store / previous_response_id و GET/DELETE /v1/responses/:id (proxy به upstream)
  • streaming با eventهای بومی Responses (از جمله رویدادهای reasoning بدون strip)
  • OpenAI: object reasoning opaque passthrough؛ itemهای type=reasoning برای replay؛ include مثل reasoning.encrypted_content
  • OpenRouter: فقط reasoning.effort؛ item type=reasoning در input → unsupported_feature
  • function tools و hosted tools: web_search / web_search_preview؛ روی OpenRouter همچنین web_fetch؛ file_search فقط OpenAI (vector_store_ids passthrough)
  • include، max_tool_calls و parallel_tool_calls برای کنترل هزینه و citations
  • مدل‌های بدون responses.endpoint=supported → unsupported_endpoint

Structured outputs

برای خروجی ساخت‌یافته، text.format را مطابق OpenAI Responses بفرستید. AiFO schema را validate یا اجرا نمی‌کند؛ object را opaque به upstream پاس می‌دهد. پشتیبانی وابسته به مدل/provider است.

{
  "model": "gpt-4o-mini",
  "input": "Extract the person's name and age",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "person",
      "schema": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "age": { "type": "number" }
        },
        "required": ["name", "age"],
        "additionalProperties": false
      },
      "strict": true
    }
  }
}

Stateful Responses (OpenAI)

روی مدل‌های OpenAI با capability stateful، می‌توانید store: true بفرستید و در درخواست بعدی previous_response_id را پاس دهید. وضعیت در upstream OpenAI نگه داشته می‌شود؛ AiFO persistence مکالمه ندارد. بازیابی و حذف هم فقط proxy به OpenAI است: GET و DELETE /v1/responses/:id.

curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "نام من آرمین است.",
    "store": true
  }'

# سپس با previous_response_id ادامه دهید:
curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "اسم من چیست؟",
    "previous_response_id": "resp_..."
  }'

# بازیابی / حذف (فقط OpenAI upstream):
# GET    https://api.aifoapp.ir/v1/responses/resp_...
# DELETE https://api.aifoapp.ir/v1/responses/resp_...
from openai import OpenAI

client = OpenAI(base_url="https://api.aifoapp.ir/v1", api_key="aifo_sk_live_YOUR_API_KEY")
first = client.responses.create(
    model="gpt-4o-mini",
    input="نام من آرمین است.",
    store=True,
)
second = client.responses.create(
    model="gpt-4o-mini",
    input="اسم من چیست؟",
    previous_response_id=first.id,
)
print(second.output_text)
# client.responses.retrieve(first.id)
# client.responses.delete(first.id)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

const first = await client.responses.create({
  model: "gpt-4o-mini",
  input: "نام من آرمین است.",
  store: true,
});
const second = await client.responses.create({
  model: "gpt-4o-mini",
  input: "اسم من چیست؟",
  previous_response_id: first.id,
});
console.log(second.output_text);
// await client.responses.retrieve(first.id);
// await client.responses.delete(first.id);
const OpenAI = require("openai");

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

async function main() {
  const first = await client.responses.create({
    model: "gpt-4o-mini",
    input: "نام من آرمین است.",
    store: true,
  });
  const second = await client.responses.create({
    model: "gpt-4o-mini",
    input: "اسم من چیست؟",
    previous_response_id: first.id,
  });
  console.log(second.output_text);
}
main();

File search (OpenAI)

tool از نوع file_search فقط روی OpenAI (با capability hostedTools.fileSearch) پشتیبانی می‌شود. vector_store_ids باید متعلق به حساب upstream OpenAI باشند (پیشوند vs_…). AiFO vector store نمی‌سازد، CRUD /v1/vector_stores ندارد و RAG داخلی اجرا نمی‌کند — فقط passthrough.

curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "خلاصه اسناد مرتبط با قرارداد را بگو",
    "tools": [{
      "type": "file_search",
      "vector_store_ids": ["vs_..."]
    }]
  }'
from openai import OpenAI

client = OpenAI(base_url="https://api.aifoapp.ir/v1", api_key="aifo_sk_live_YOUR_API_KEY")
resp = client.responses.create(
    model="gpt-4o-mini",
    input="خلاصه اسناد مرتبط با قرارداد را بگو",
    tools=[{
        "type": "file_search",
        "vector_store_ids": ["vs_..."],
    }],
)
print(resp.output_text)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

const resp = await client.responses.create({
  model: "gpt-4o-mini",
  input: "خلاصه اسناد مرتبط با قرارداد را بگو",
  tools: [{
    type: "file_search",
    vector_store_ids: ["vs_..."],
  }],
});
console.log(resp.output_text);
const OpenAI = require("openai");

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

async function main() {
  const resp = await client.responses.create({
    model: "gpt-4o-mini",
    input: "خلاصه اسناد مرتبط با قرارداد را بگو",
    tools: [{
      type: "file_search",
      vector_store_ids: ["vs_..."],
    }],
  });
  console.log(resp.output_text);
}
main();

Reasoning

فیلد reasoning وابسته به provider است. روی OpenAI، object به‌صورت opaque پاس می‌شود (effort، summary، include مثل reasoning.encrypted_content) و itemهای type=reasoning در input برای replay پشتیبانی می‌شوند. روی OpenRouter فقط reasoning.effort پذیرفته می‌شود؛ item type=reasoning در input رد می‌شود.

curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "o4-mini",
    "input": "یک معما حل کن",
    "reasoning": { "effort": "medium", "summary": "auto" },
    "include": ["reasoning.encrypted_content"]
  }'
from openai import OpenAI

client = OpenAI(base_url="https://api.aifoapp.ir/v1", api_key="aifo_sk_live_YOUR_API_KEY")
resp = client.responses.create(
    model="o4-mini",
    input="یک معما حل کن",
    reasoning={"effort": "medium", "summary": "auto"},
    include=["reasoning.encrypted_content"],
)
print(resp.output_text)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

const resp = await client.responses.create({
  model: "o4-mini",
  input: "یک معما حل کن",
  reasoning: { effort: "medium", summary: "auto" },
  include: ["reasoning.encrypted_content"],
});
console.log(resp.output_text);
const OpenAI = require("openai");

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

async function main() {
  const resp = await client.responses.create({
    model: "o4-mini",
    input: "یک معما حل کن",
    reasoning: { effort: "medium", summary: "auto" },
    include: ["reasoning.encrypted_content"],
  });
  console.log(resp.output_text);
}
main();

Web search

برای جستجوی وب، tool میزبانی‌شدهٔ web_search را در tools بفرستید. AiFO خودش موتور search اجرا نمی‌کند؛ درخواست به OpenAI یا OpenRouter proxy می‌شود. روی OpenRouter، type به openrouter:web_search بازنویسی می‌شود. برای دیدن منابع، include را با web_search_call.action.sources ست کنید. هزینهٔ چندبارهٔ search ممکن است بالا برود — max_tool_calls و search_context_size: low|medium را در نظر بگیرید.

curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "آخرین قیمت بیت‌کوین چقدر است؟",
    "tools": [{ "type": "web_search", "search_context_size": "medium" }],
    "include": ["web_search_call.action.sources"],
    "max_tool_calls": 3
  }'
from openai import OpenAI

client = OpenAI(base_url="https://api.aifoapp.ir/v1", api_key="aifo_sk_live_YOUR_API_KEY")
resp = client.responses.create(
    model="gpt-4o-mini",
    input="آخرین قیمت بیت‌کوین چقدر است؟",
    tools=[{"type": "web_search", "search_context_size": "medium"}],
    include=["web_search_call.action.sources"],
    max_tool_calls=3,
)
print(resp.output_text)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

const resp = await client.responses.create({
  model: "gpt-4o-mini",
  input: "آخرین قیمت بیت‌کوین چقدر است؟",
  tools: [{ type: "web_search", search_context_size: "medium" }],
  include: ["web_search_call.action.sources"],
  max_tool_calls: 3,
});
console.log(resp.output_text);
const OpenAI = require("openai");

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

async function main() {
  const resp = await client.responses.create({
    model: "gpt-4o-mini",
    input: "آخرین قیمت بیت‌کوین چقدر است؟",
    tools: [{ type: "web_search", search_context_size: "medium" }],
    include: ["web_search_call.action.sources"],
    max_tool_calls: 3,
  });
  console.log(resp.output_text);
}
main();

نمونهٔ OpenAI

curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "سلام! یک جمله کوتاه بنویس."
  }'
from openai import OpenAI

client = OpenAI(base_url="https://api.aifoapp.ir/v1", api_key="aifo_sk_live_YOUR_API_KEY")
resp = client.responses.create(
    model="gpt-4o-mini",
    input="سلام! یک جمله کوتاه بنویس.",
)
print(resp.output_text)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

const resp = await client.responses.create({
  model: "gpt-4o-mini",
  input: "سلام! یک جمله کوتاه بنویس.",
});
console.log(resp.output_text);
const OpenAI = require("openai");

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

async function main() {
  const resp = await client.responses.create({
    model: "gpt-4o-mini",
    input: "سلام! یک جمله کوتاه بنویس.",
  });
  console.log(resp.output_text);
}
main();

نمونهٔ OpenRouter (از طریق AiFO)

مدل‌هایی مثل openai/gpt-4o-mini روی OpenRouter وقتی responses.endpoint در پروفایل مؤثر supported باشد، از همان /v1/responses AiFO قابل فراخوانی‌اند. مدل‌های بدون این قابلیت با unsupported_endpoint رد می‌شوند.

curl https://api.aifoapp.ir/v1/responses \
  -H "Authorization: Bearer aifo_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "input": "Reply with exactly: ok"
  }'
from openai import OpenAI

client = OpenAI(base_url="https://api.aifoapp.ir/v1", api_key="aifo_sk_live_YOUR_API_KEY")
resp = client.responses.create(
    model="openai/gpt-4o-mini",
    input="Reply with exactly: ok",
)
print(resp.output_text)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

const resp = await client.responses.create({
  model: "openai/gpt-4o-mini",
  input: "Reply with exactly: ok",
});
console.log(resp.output_text);
const OpenAI = require("openai");

const client = new OpenAI({
  baseURL: "https://api.aifoapp.ir/v1",
  apiKey: "aifo_sk_live_YOUR_API_KEY",
});

async function main() {
  const stream = await client.responses.create({
    model: "openai/gpt-4o-mini",
    input: "Say hi",
    stream: true,
  });
  for await (const event of stream) {
    console.log(event.type);
  }
}
main();

فایل AiFO در Responses

پس از آپلود با POST /v1/files، شناسهٔ file_… را در input_file بفرستید. Gateway قبل از wallet reserve فایل را از MinIO خصوصی می‌خواند و به صورت inline file_data برای OpenAI یا OpenRouter ارسال می‌کند. شناسهٔ AiFO هرگز خام به provider نمی‌رسد.

{
  "model": "openai/gpt-4o-mini",
  "input": [{
    "role": "user",
    "content": [
      { "type": "input_text", "text": "خلاصه این PDF را بگو" },
      { "type": "input_file", "file_id": "file_..." }
    ]
  }]
}

Streaming

با stream:true رویدادهای بومی Responses (مثل response.created، response.output_text.delta، response.completed) به‌صورت SSE فوروارد می‌شوند. درخواست نامعتبر قبل از reserve و قبل از ارسال headerهای SSE رد می‌شود.

محدودیت‌ها و تفاوت provider

  • OpenAI + OpenRouter (beta، model-gated)؛ بدون claim parity کامل
  • OpenAI: store / previous_response_id / GET·DELETE responses و reasoning item replay به‌صورت upstream passthrough
  • OpenRouter: reasoning فقط effort؛ بدون reasoning input items؛ بدون store/previous_response_id
  • بدون MCP، computer_use، code_interpreter، یا persistence مکالمه در AiFO
  • file_search روی OpenAI: passthrough با vector_store_ids متعلق به upstream (بدون vector DB داخلی AiFO)؛ روی OpenRouter unsupported
  • بدون آپلود به OpenAI Files API یا provider file mapping؛ بدون CRUD /v1/vector_stores در gateway