AiOffer ai.offer@1

Generated at from openvibe-contracts v0.419.0 and openvibe-sdk v0.161.0.

Version
1.0.0
Owner
ai
Visibility
first-party
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/ai/offer.v1.json

ai.offer@1: one community AI offer, a person's machine (OpenVibe Link's ai plugin, "Offer to the network") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.

Fields

FieldTypeRequiredDescriptionConstraints
offer_idstringyes`ai:<machine_id>`: one offer per machine.
  • pattern ^ai:dev_[0-9A-HJKMNP-TV-Z]{26}$
machine_idstringyesThe machine that answers (for a pool, its head).
  • pattern ^dev_[0-9A-HJKMNP-TV-Z]{26}$
ownerstringyesThe machine's owner, who earns the offer's credits (a self-served run earns none).
  • pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$
modelsarray of stringyesThe models offered, as the machine's model server names them.
  • minItems 1
  • maxItems 40
  • items: minLength 1
  • items: maxLength 200
hoursobjectyesThe local-time window the offer is open; start equal to end is all day, and an overnight window wraps.
  • no other fields
hours.startstringyes
  • pattern ^([01][0-9]|2[0-3]):[0-5][0-9]$
hours.endstringyes
  • pattern ^([01][0-9]|2[0-3]):[0-5][0-9]$
hours.tzstringyesAn IANA time zone, such as Europe/Paris, or UTC.
  • minLength 1
  • maxLength 64
concurrencyintegeryesHow many requests may run at once; another is refused as busy, never queued.
  • minimum 1
  • maximum 8
priceobjectyesCredits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.
  • no other fields
price.in_per_millionnumberyes
  • minimum 0
  • maximum 1000000
price.out_per_millionnumberyes
  • minimum 0
  • maximum 1000000
audienceenumyesWho may use it: everyone, the owner's followers, or one group (`group`).
  • one of "everyone", "followers", "group"
groupstring | nullyesThe group's id when the audience is `group`, otherwise null.
  • maxLength 80
readybooleanyesWhether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch.
healthobjectyes
  • no other fields
health.statusenumyes
  • one of "up", "degraded", "down"
health.checked_atstring
  • format date-time
poolai.offer-poolPresent when the offer is served by a pool of the owner's machines (ai.offer-pool@1).

Examples

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

Valid: group-audience
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "qwen3:8b"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "group",
  "group": "grp_friends",
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  }
}
Valid: pool-waiting-for-approvals
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "llama-3.3-70b-instruct-q4_k_m"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": false,
  "health": {
    "status": "down"
  },
  "pool": {
    "machines": [
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
    ],
    "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
  }
}
Valid: pool
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "llama-3.3-70b-instruct-q4_k_m"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  },
  "pool": {
    "machines": [
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
    ],
    "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
  }
}
Valid: single-machine
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "qwen3:8b"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  }
}
Rejected: extra-field
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "llama-3.3-70b-instruct-q4_k_m"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  },
  "pool": {
    "machines": [
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
    ],
    "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
  },
  "private_key": "not-permitted"
}
Rejected: missing-owner
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "models": [
    "llama-3.3-70b-instruct-q4_k_m"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  },
  "pool": {
    "machines": [
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
    ],
    "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
  }
}
Rejected: offer-id-not-a-machine
{
  "offer_id": "ai:everything",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "qwen3:8b"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  }
}
Rejected: one-machine-pool
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "llama-3.3-70b-instruct-q4_k_m"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  },
  "pool": {
    "machines": [
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
    ],
    "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
  }
}
Rejected: pool-with-address
{
  "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
  "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "models": [
    "llama-3.3-70b-instruct-q4_k_m"
  ],
  "hours": {
    "start": "22:00",
    "end": "08:00",
    "tz": "Europe/Paris"
  },
  "concurrency": 1,
  "price": {
    "in_per_million": 0.2,
    "out_per_million": 0.6
  },
  "audience": "everyone",
  "group": null,
  "ready": true,
  "health": {
    "status": "up",
    "checked_at": "2026-11-07T10:00:00.000Z"
  },
  "pool": {
    "machines": [
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
      "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
    ],
    "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
    "address": "192.168.1.20/24"
  }
}

Validate

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