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
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

The `frontal` package provides synchronous and asynchronous Python clients for
the Frontal API. Services are available on the client as typed attributes such
as `client.ai`, `client.agents`, and `client.workflows`.
as `client.ai`, `client.agents`, `client.functions`, and `client.workflows`.

## Install

Expand Down Expand Up @@ -54,7 +54,7 @@ environment header, and debug logging. The SDK does not load `.env` files.

## What is included

- All 370 operations in `contracts/sdk-endpoints.json`, grouped by service.
- All 383 operations in `contracts/sdk-endpoints.json`, grouped by service.
- HTTPX sync and async transports with bounded GET retries, request IDs,
pagination helpers, polling, raw bytes, multipart uploads, and SSE streams.
- Pydantic v2 request models and validation for JSON-compatible payloads.
Expand All @@ -69,10 +69,14 @@ only when replaying that operation is safe. If you provide an `httpx.Client` or
For JSON writes, omitting `body` sends no request body; pass `body=None` to send
the JSON value `null`, and `body={}` to send an empty JSON object.

The OpenAPI snapshots define the operation inventory but do not include
service-specific request and response schemas for most endpoints. The SDK
does not guess those payload shapes; define request models with `APIModel` and
use `PageResult[T]` for paginated responses where applicable.
The endpoint inventory records the SDK's hand-written routes. OpenAPI snapshots
provide an additional contract baseline, but they omit the Functions routes
and most endpoint-specific request and response schemas. The Functions models
follow the TypeScript Functions package; other unmodeled operation payloads
use the recursive `JSONValue` type.

The [Functions API guide](docs/FUNCTIONS.md) covers function definitions,
versions, deployment, invocation, execution results, and cancellation.

The SDK uses resource-oriented names and semantic path arguments.

Expand Down
66 changes: 66 additions & 0 deletions contracts/sdk-endpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,72 @@
"path": "/data/transformations/transformations/{param}/executions"
}
],
"functions": [
{
"method": "DELETE",
"path": "/functions/{param}"
},
{
"method": "GET",
"path": "/functions"
},
{
"method": "GET",
"path": "/functions/{param}"
},
{
"method": "GET",
"path": "/functions/executions"
},
{
"method": "GET",
"path": "/functions/executions/{param}"
},
{
"method": "GET",
"path": "/functions/executions/{param}/result"
},
{
"method": "GET",
"path": "/functions/{param}/versions"
},
{
"method": "GET",
"path": "/functions/{param}/versions/{param}"
},
{
"method": "GET",
"path": "/functions/{param}/versions/{param}/deployment/status"
},
{
"method": "PATCH",
"path": "/functions/{param}"
},
{
"method": "POST",
"path": "/functions"
},
{
"method": "POST",
"path": "/functions/executions/{param}/cancel"
},
{
"method": "POST",
"path": "/functions/invoke"
},
{
"method": "POST",
"path": "/functions/invoke-async"
},
{
"method": "POST",
"path": "/functions/{param}/versions/{param}/deploy"
},
{
"method": "POST",
"path": "/functions/{param}/versions/{param}/publish"
}
],
"governance": [
{
"method": "DELETE",
Expand Down
69 changes: 69 additions & 0 deletions docs/FUNCTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Functions API

`Frontal` and `AsyncFrontal` expose the Functions service as
`client.functions`. It uses the shared client configuration and HTTPX transport:
the default API URL is `https://api.frontal.dev/v1`, the default timeout is 30
seconds, and the default retry count is three. Pass `api_key`, `base_url`,
`timeout`, and `max_retries` to either client to override those values. The API
key is sent as Bearer authentication.

## Create and invoke

Function definitions require `name`, `runtime` (`nodejs20`, `nodejs22`, or
`python311`), and `entrypoint`. Optional fields include `description`, `source`,
`input_schema`, `output_schema`, `dependencies`, `env_vars`, `secrets`,
`memory` in MB, `timeout` in seconds, and `permissions` with `ontology` and
`actions` string arrays. Schema and invocation data accept arbitrary nested JSON
objects.

```python
from frontal_sdk import (
Frontal,
FunctionInvocationInput,
FunctionInvocationResult,
FunctionResource,
)

with Frontal(api_key="frt_your_api_key") as client:
created = (
client.functions.define("hello-world")
.runtime("nodejs22")
.entrypoint("index.handler")
.input_schema({"type": "object", "properties": {"name": {"type": "string"}}})
.create()
)
function = FunctionResource.model_validate(created)
raw_result = client.functions.executions.invoke(
FunctionInvocationInput(
function_id=function.id,
input={"name": "World", "metadata": {"requestTag": "sample"}},
)
)
result = FunctionInvocationResult.model_validate(raw_result)
print(result.result)
```

The same resources work with `AsyncFrontal`; await calls such as
`client.functions.executions.invoke(...)`. `client.functions.versions` provides
`list`, `get`, and `publish`; `client.functions.deployments` provides `deploy`
and `status`; `client.functions.executions` provides `invoke`, `invoke_async`,
`get`, `get_result`, `list`, and `cancel`.

List methods accept the API's cursor names through `query=`, for example:
`client.functions.list(query={"cursor": "next", "limit": 25})`. Execution
filters use `functionId` and `status` in the query mapping.

## Errors

Functions requests use the shared typed SDK errors. HTTP 400 and 422 responses
raise `ValidationError`; 401 and 403 raise `AuthenticationError`; 404 raises
`NotFoundError`; 409 raises `ConflictError`; 429 raises `RateLimitError`; and
5xx responses raise `ServerError`. Connection and timeout failures raise
`NetworkError` and `TimeoutError`. Errors expose `status_code`, `code`,
`request_id`, `details`, `transient`, and `safe_to_retry`; rate limit errors
also expose `retry_after`. The SDK does not automatically retry function write
requests when replay could repeat an accepted operation.

The Functions routes are recorded in `contracts/sdk-endpoints.json` from the
TypeScript Functions client and its package tests. The currently checked-in
OpenAPI snapshots do not contain these routes.
14 changes: 7 additions & 7 deletions docs/OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ client to tune transport behavior. See [architecture](ARCHITECTURE.md) and

Each client exposes the same service attributes:

`ai`, `agents`, `workflows`, `audit`, `auth`, `billing`, `blob`, `connectors`,
`data`, `governance`, `lineage`, `observability`, `ontology`, `pipelines`,
`schedules`, and `webhooks`.
`ai`, `agents`, `functions`, `workflows`, `audit`, `auth`, `billing`, `blob`,
`connectors`, `data`, `governance`, `lineage`, `observability`, `ontology`,
`pipelines`, `schedules`, and `webhooks`.

The AI service adds normalized helpers such as `generate_text`, `stream_text`,
`embed`, `generate_object`, `generate_speech`, `generate_image`,
Expand All @@ -63,8 +63,8 @@ endpoint methods from the SDK inventory.
## Types and API boundaries

Public models are exported from `frontal_sdk` and `frontal_sdk.models`. The
client validates typed AI, agent, workflow, pagination, and error boundaries
with Pydantic. Many raw API operations have no operation-specific schema in the
OpenAPI snapshots, so their request and response values use the recursive
`JSONValue` type rather than guessed models. See [API resources](RESOURCES.md)
client validates typed AI, agent, Functions, workflow, pagination, and error
boundaries with Pydantic. Many raw API operations have no operation-specific
schema in the OpenAPI snapshots, so their request and response values use the
recursive `JSONValue` type rather than guessed models. See [API resources](RESOURCES.md)
for route naming and payload conventions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- [Overview](OVERVIEW.md) — install, clients, service attributes, and type boundaries.
- [Architecture](ARCHITECTURE.md) — package layout, config, transport, and retries.
- [API resources](RESOURCES.md) — AI helpers, builders, and endpoint methods.
- [Functions API](FUNCTIONS.md) — function definitions, invocations, and executions.
- [Testing](TESTING.md) — offline RESPX coverage and runnable documentation.
- [Developer guide](DEVELOPERS.md) and [onboarding](ONBOARDING.md) — repository workflow.
- [Security](SECURITY.md), [publishing](PUBLISHING.md), and [releasing](RELEASING.md).
Expand Down
12 changes: 12 additions & 0 deletions docs/RESOURCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
| --- | --- |
| `ai` | AI generation and gateway operations |
| `agents` | Agent definitions and runs |
| `functions` | Function definitions, versions, deployments, and executions |
| `workflows` | Workflow definitions and executions |
| `audit`, `auth`, `billing` | Audit events, authentication, and billing |
| `blob`, `connectors`, `data` | Files, integrations, and data operations |
Expand Down Expand Up @@ -59,6 +60,17 @@ an execution, list executions, and poll one to a terminal state. The same
accessors work with `AsyncFrontal`; await their results and use `async for` for
streams.

## Functions

Use `client.functions.define(name)` to build and create a validated function,
or pass a `FunctionDefinition` to `client.functions.create()`. Invoke a
function with `client.functions.executions.invoke()` or start an asynchronous
execution with `invoke_async()`. Versions, deployment status, results, and
cancellation are grouped under `client.functions.versions`,
`client.functions.deployments`, and `client.functions.executions`. The sync and
async clients expose the same methods. See the [Functions API guide](FUNCTIONS.md)
for fields, configuration, errors, and an end-to-end example.

## Endpoint methods

Each service also exposes methods corresponding to the committed inventory.
Expand Down
2 changes: 2 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Each script closes its HTTPX client when finished.
| [`quickstart.py`](./quickstart.py) | Synchronous text generation |
| [`async_quickstart.py`](./async_quickstart.py) | Async text generation with `AsyncFrontal` |
| [`define_agent.py`](./define_agent.py) | Validated agent builder and scoped access |
| [`create_function.py`](./create_function.py) | Function definition and invocation |
| [`create_workflow.py`](./create_workflow.py) | Workflow creation and triggering an execution |

Run scripts from the repository root after installing the development extra:
Expand All @@ -18,6 +19,7 @@ uv sync --extra dev
uv run python examples/quickstart.py
uv run python examples/async_quickstart.py
uv run python examples/define_agent.py
uv run python examples/create_function.py
uv run python examples/create_workflow.py
```

Expand Down
35 changes: 35 additions & 0 deletions examples/create_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Create a Frontal function and invoke it with JSON input."""

from frontal_sdk import (
Frontal,
FunctionInvocationInput,
FunctionInvocationResult,
FunctionResource,
)


def main() -> None:
with Frontal() as client:
created = (
client.functions.define("hello-world")
.runtime("nodejs22")
.entrypoint("index.handler")
.description("Return a greeting")
.input_schema(
{"type": "object", "properties": {"name": {"type": "string"}}}
)
.create()
)
function = FunctionResource.model_validate(created)
raw_result = client.functions.executions.invoke(
FunctionInvocationInput(
function_id=function.id,
input={"name": "World", "metadata": {"source": "example"}},
)
)
result = FunctionInvocationResult.model_validate(raw_result)
print(result.result)


if __name__ == "__main__":
main()
34 changes: 34 additions & 0 deletions frontal_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@
EmbedResult,
ErrorField,
ErrorResponse,
FunctionDefinition,
FunctionDeploymentStatus,
FunctionExecution,
FunctionExecutionListResponse,
FunctionInvocationAccepted,
FunctionInvocationInput,
FunctionInvocationResult,
FunctionListResponse,
FunctionPagination,
FunctionPermission,
FunctionResource,
FunctionRuntime,
FunctionStatus,
FunctionVersion,
FunctionVersionListResponse,
GenerateImageOptions,
GenerateImageResult,
GenerateObjectResult,
Expand Down Expand Up @@ -63,6 +78,8 @@
from frontal_sdk.resources import (
AgentAccessor,
AgentBuilder,
FunctionAccessor,
FunctionBuilder,
WorkflowAccessor,
WorkflowBuilder,
tool,
Expand Down Expand Up @@ -90,6 +107,23 @@
"EmbedResult",
"Frontal",
"FrontalError",
"FunctionAccessor",
"FunctionBuilder",
"FunctionDefinition",
"FunctionDeploymentStatus",
"FunctionExecution",
"FunctionExecutionListResponse",
"FunctionInvocationAccepted",
"FunctionInvocationInput",
"FunctionInvocationResult",
"FunctionListResponse",
"FunctionPagination",
"FunctionPermission",
"FunctionResource",
"FunctionRuntime",
"FunctionStatus",
"FunctionVersion",
"FunctionVersionListResponse",
"GenerateImageOptions",
"GenerateImageResult",
"GenerateObjectResult",
Expand Down
7 changes: 7 additions & 0 deletions frontal_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Blob,
Connectors,
Data,
Functions,
Governance,
Lineage,
Observability,
Expand Down Expand Up @@ -112,6 +113,9 @@ def __init__(
Connectors(http)
)
self.data: Data[JSONValue, bytes, Iterator[ServerEvent]] = Data(http)
self.functions: Functions[JSONValue, bytes, Iterator[ServerEvent]] = Functions(
http
)
self.governance: Governance[JSONValue, bytes, Iterator[ServerEvent]] = (
Governance(http)
)
Expand Down Expand Up @@ -197,6 +201,9 @@ def __init__(
self.data: Data[_AsyncJSONResult, _AsyncBytesResult, _AsyncStreamResult] = Data(
http
)
self.functions: Functions[
_AsyncJSONResult, _AsyncBytesResult, _AsyncStreamResult
] = Functions(http)
self.governance: Governance[
_AsyncJSONResult, _AsyncBytesResult, _AsyncStreamResult
] = Governance(http)
Expand Down
Loading
Loading