---
title: "frame.ask@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/frame.ask"
updated: null
---

# frame.ask@1 · OpenVibe.Services

HTML: [frame.ask@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/frame.ask)

# FrameAskRequest `frame.ask@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: network
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/frame/ask.v1.json`](/docs/contracts/frame.ask.json)

frame.ask@1: the body of POST /api/frame/ask. One question on the chosen model, with the Search Fabric's results for the chosen sources in its prompt; the answer is a Network run whose AG-UI events are at GET /api/v1/runs/:id/events, and its ANSWER event carries { answer, citations: \[{ n, title, url, site }\] }. A person only: the person's own token pays OpenVibe.AI. model names a row from frame.choices@1, or its id (the OpenVibe source); omitted, the task's recommended choice answers. sources are what the answer may read: web (OpenVibe's index, then the paid ladder), openvibe (the network scope), mine (the person's own things) and page (the site's context). depth deep asks Search's deep ladder and gives the answer longer output. refs are typed references and files are Media ids; both go to the model on this turn.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `text` | string | yes | The question. | - `minLength 1`<br>- `maxLength 8000` |
| `model` | one of |  |  |  |
| `refs` | array of object |  |  | - `items: no other fields` |
| `refs[].kind` | string | yes |  | - `maxLength 40` |
| `refs[].id` | string | yes |  | - `maxLength 100` |
| `refs[].title` | string |  |  | - `maxLength 200` |
| `refs[].url` | string |  |  | - `format uri`<br>- `maxLength 2048` |
| `files` | array of one of |  |  |  |
| `sources` | array of enum |  |  | - `unique items`<br>- `default ["web"]`<br>- `items: one of "web", "openvibe", "mine", "page"` |
| `depth` | enum |  |  | - `one of "quick", "balanced", "deep"`<br>- `default "balanced"` |
| `context` | object |  |  | - `no other fields` |
| `context.site` | string |  |  | - `maxLength 253` |
| `context.url` | string |  |  | - `format uri`<br>- `maxLength 2048` |
| `context.title` | string |  |  | - `maxLength 300` |
| `context.kind` | string |  |  | - `maxLength 40` |
| `context.id` | string |  |  | - `maxLength 200` |
| `context.text` | string |  | The page's text, when the site passes it. | - `maxLength 8000` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: balanced

~~~~
{
  "text": "What changed in the search fabric this week?",
  "model": {
    "model": "openai/gpt-5-mini",
    "source": "openvibe"
  },
  "sources": [
    "web",
    "openvibe",
    "page"
  ],
  "depth": "balanced",
  "refs": [
    {
      "kind": "post",
      "id": "p_1",
      "title": "A post",
      "url": "https://openvibe.community/p/1"
    }
  ],
  "files": [
    "med_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3"
  ],
  "context": {
    "site": "openvibe.community",
    "url": "https://openvibe.community/p/1",
    "title": "A post",
    "kind": "post",
    "id": "p_1",
    "text": "The page."
  }
}
~~~~

Rejected: no-text

~~~~
{
  "sources": [
    "web"
  ],
  "depth": "balanced"
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('frame.ask@1', value);   // { valid, errors: [{ path, message }] }
~~~~
