Skip to content

Helpers & body builders

Errors

FaigError

Bases: RuntimeError

An HTTP status >= 400 from FortiAIGate. body is the raw response text, data its decoded JSON (None if it is not JSON), code the gateway's OpenAI-style error.code and field the field a 409/422 names.

Raised as the subclass for its status (NotFound, Conflict, ...), so except FaigError still catches every one.

method instance-attribute

method

path instance-attribute

path

status instance-attribute

status

body instance-attribute

body

data instance-attribute

data: Any

code instance-attribute

code: str | None

field instance-attribute

field: str | None

AuthError

Bases: FaigError

401 or 403: bad credentials, an expired session that would not renew, a rejected virtual key, or a call the account's role may not make.

NotFound

Bases: FaigError

404: no such object (or path).

ModelNotAvailable

Bases: NotFound

The gateway's 404 for a model the virtual key is not granted (code: model_not_found). available_models(key) lists what it may call.

Conflict

Bases: FaigError

409: a name already used in the workspace (field names it), or an approval that lost a race.

ValidationError

Bases: FaigError

400 or 422: the body was refused; the message usually lists what is allowed.

RateLimited

Bases: FaigError

429: a key's rpm/tpm limit. 8.0.2 sends no Retry-After; set rate_limit_wait on the client to wait and retry instead of raising.

ServerError

Bases: FaigError

5xx from the appliance or an upstream provider.

error_for

error_for(method: str, path: str, status: int, body: str) -> FaigError

The FaigError subclass for an HTTP status (and gateway error code).

Results

Ensured

Bases: NamedTuple

What an ensure_* call did. action is created, updated or unchanged; record is the object as it now stands; secret is a new virtual key's one-time secret (None otherwise).

record instance-attribute

record: dict[str, Any]

action instance-attribute

action: str

secret class-attribute instance-attribute

secret: str | None

id property

id: str

changed property

changed: bool

Renewed

Bases: NamedTuple

What renew_virtual_key did. The key keeps its id; secret is its new one-time secret. method is rotated (the key was active) or extended_and_rotated (it had expired, so its expiry was moved to expires_at first: 8.0.2 rotates only an active key).

record instance-attribute

record: dict[str, Any]

method instance-attribute

method: str

secret instance-attribute

secret: str | None

key_id instance-attribute

key_id: str

old_status instance-attribute

old_status: str

expires_at class-attribute instance-attribute

expires_at: str | None

id property

id: str

Body builders

regex_detector_body

regex_detector_body(name: str, rules: Iterable[tuple[str, str, str]], description: str = '') -> dict[str, Any]

rules: [(rule_name, pattern, disposition)]. Fills BOTH regexRules (the editor's grouping) and the flat rules list the engine matches on.

dlp_detector_body

dlp_detector_body(name: str, categories: Iterable[str], disposition: str = 'block', threshold: float = 0.7, description: str = '') -> dict[str, Any]

categories: DLP label names as dlp_labels() spells them.

ai_detector_body

ai_detector_body(name: str, rules: Iterable[tuple[Any, ...]], action: str = 'block', description: str = '') -> dict[str, Any]

A Natural Language detector: the engine judges text against plain-language descriptions. rules: [(rule_name, violate_if)] or [(rule_name, violate_if, exempt_if)], where each is a string or a list of strings. Like a regex detector it fills BOTH aiRules (the editor's grouping) and the flat rules list the engine matches on.

guardrail_body

guardrail_body(name: str, detector_ids: list[str], description: str = '', *, deny_suspicious_characters: bool = False) -> dict[str, Any]

Workflow

approve_new

approve_new(admin: FortiAIGate, ws_id: WsRef, kind: str, obj: Mapping[str, Any]) -> JSON

Walk a workspace object draft -> pending -> active, or approve an active one's pending change. Losing the race to another approver (it is no longer pending) is not an error.

Responses

items

items(data: JSON) -> list[dict[str, Any]]

A list endpoint's records, whether it answers a bare list or {"items": [...]}.

rank_items

rank_items(data: JSON, end: str = 'top') -> list[dict[str, Any]]

The rows of a usage_rankings/cost_rankings result. The API answers items, or top and bottom lists for end="both", or only meta when nothing was used in the window.

breakdown_items

breakdown_items(data: JSON) -> list[dict[str, Any]]

The rows of a usage_breakdown/cost_breakdown result. A key, user or workspace splits by models; a model splits by consumers (usage) or spenders (cost), each {"count", "items"}.

blocked

blocked(completion: JSON) -> bool

Did a guardrail block this chat completion?

collect_stream

collect_stream(chunks: Iterable[Mapping[str, Any]]) -> ChatCompletion

Join chat_completion_stream chunks into one chat.completion: each choice's message.content is its deltas joined, finish_reason the last one given. A non-streamed completion passes through unchanged.

secret_from_response

secret_from_response(data: JSON) -> str | None

The one-time faig_... secret in a create or rotate response, if any.

key_id_from_secret

key_id_from_secret(secret: str) -> str

A virtual key secret embeds its record id: faig_<uuid-no-dashes>_.... Anything else is a ValueError rather than a made-up id.

key_update_body

key_update_body(record: Mapping[str, Any]) -> dict[str, Any]

A virtual-key record (as read) reduced to what an update may send. A read returns policyIds as {"id", "assignedByOrg"} objects; the update takes plain id strings.

origin

origin(url: str) -> str

host, https://host, https://host/api -> https://host. Any path, query or fragment is dropped, so the console address (.../ui) or the gateway's chat URL works as well as the bare host.

Constants

Name Value Use
ROLE_MEMBER "org_member" default role for invite (8.0.2 rejects plain member)
ROLE_ADMIN "org_admin" org administrator
QUEUE_KIND {"guardrail": "guardrails", ...} review-queue type -> the approve / reject kind
LOG_PAGE 50 default page size for the log iterators (the console's)