This reference describes the Python SDK available when you write custom functions in GraphN. Functions run in isolated Firecracker microVMs on Python 3.12 with a configurable memory budget (memory_mb, 256–512 MB, default 512 MB). All SDK methods that perform I/O are async — use await when you call them.
Getting started with functions
Follow these steps to go from an empty function to a working test run:
Open a workspace — Select the workspace where you want the function to live.
Create a function — In the sidebar, click Functions, then create a new function. The editor opens with main.py and requirements.txt.
Function editor showing main.py, requirements.txt, and the test terminal with Run Test button
Define the entry point — In main.py, decorate exactly one async function with @function. Add type hints for each parameter; the workflow passes JSON fields that match those names.
Use the SDK — Call chat, vision, models, kb, storage, and conversion with await (see the sections below).
Save — Use the editor save action so the function version is stored.
Wire the workflow — Open your workflow, add a step that calls this function, and map inputs to the parameter names you defined.
Test — In the test terminal at the bottom of the function editor, enter a JSON object whose keys match your function parameters and click Run Test. The result is the serialized return value of your entry function.
Tip: Write a short docstring on the entry function. Agents and tooling use it to understand what the function does.
Environment and imports
In the function editor, the platform preloads the @function decorator (alias: tool) and the module instances: chat, vision, models, kb, storage, conversion, veo, nanobanana, and media_tools. You also have access to configure_model and get_model_config for advanced model routing.
You do not need import statements at the top of main.py for these names. If you split code into multiple files in the same function package, import what you need from foundry_helpers (for example from foundry_helpers import kb, storage).
Return JSON-serializable values from your entry function (str, int, float, bool, None, dicts, and lists of those types). The Run tab displays the serialized result.
Warning: Typical workflow and agent calls enforce execution limits on the order of one minute. The optional @function(timeout=…) value is advisory metadata; the real limit depends on the caller.
LLM chat completions via an OpenAI-compatible HTTP API. Uses built-in model aliases or custom models registered with configure_model / models.configure.
Returns:str — OCR-style extracted text (uses a low temperature internally).
Example:
python
ocr =await vision.extract_text(scan_image_b64)
Models module (models) and global helpers
Built-in aliases
The function runtime resolves model aliases through the platform model registry (app/models/config.yaml). Commonly used built-in aliases:
Scroll horizontally to compare
Alias
Type
Notes
qwen3-80b
Chat
Default chat model; same as the agent model picker's Qwen3 80B Instruct (131K context).
qwen3-235b
Chat
Largest MoE chat model (262K context) for the hardest reasoning and long-context tasks.
qwen3-coder
Chat
Code-specialized MoE model for agentic software-engineering workflows (262K context).
qwen3-vl
Vision
Default vision model; same as the agent model picker's Qwen3.5 9B Vision (image+video).
qwen3.8-27b
Chat/Vision
Dense 27B VL for harder coding and agentic work; Qwen3.8 27B (image+video).
This is not the complete set — your deployment also registers models such as gpt-oss-120b, gemma-4, and nemotron-3-super, plus any models you have imported. Call models.list_available() for the live list, or see the Models reference for the full picker. You can register additional aliases with configure_model or models.configure.
When called without cursor, returns a plain list[dict] of all knowledge bases (backward compatible). When cursor is provided (pass "" for the first page), returns a paginated envelope: {"items": [...], "has_more": bool, "next_cursor": "..."}. When has_more is false, next_cursor is omitted. Pass next_cursor as cursor to fetch the next page.
Example:
python
all_kbs =await kb.list_kbs()# Paginatedpage =await kb.list_kbs(limit=10, cursor="")for kb_item in page["items"]:print(kb_item["name"])
When called without cursor, returns a plain list[dict] (backward compatible). With cursor, returns {"items": [...], "has_more": bool, "next_cursor": "..."}.
Returns:list[dict] or paginated envelope — documents with id, filename, metadata, chunk_count, etc.
Example:
python
docs =await kb.list_documents("kb_abc123")
kb.batch_get
python
asyncdefbatch_get(ids:list[str])->dict
Returns:dict — {"total": N, "succeeded": N, "failed": N, "results": [...]}.
Each item in results has {"id": "...", "success": bool}. On success, a "knowledgebase" key contains the full KB dict. On failure, an "error" key contains {"code": "not_found"|"forbidden"|..., "message": "..."}.
kb.batch_update
python
asyncdefbatch_update(items:list[dict])->dict
Each item must contain "id" and any updatable fields ("name", "description", "chunk_size", "chunk_overlap").
Returns:dict — {"total": N, "succeeded": N, "failed": N, "results": [...]}.
Example:
python
result =await kb.batch_update([{"id":"kb_1","name":"Renamed KB"},{"id":"kb_2","description":"Updated desc"},])
kb.batch_delete
python
asyncdefbatch_delete(ids:list[str])->dict
Permanently deletes each KB via the same cascade as kb.delete. Vectors, document metadata, ingest bookkeeping, and the KB record are required cleanup; cancellation of in-flight ingest and media-object cleanup are best-effort. There is no soft-delete. Partial success is possible — check results.
Returns:dict — {"total": N, "succeeded": N, "failed": N, "results": [...]}.
Returns:dict — {"total": N, "succeeded": N, "failed": N, "results": [...]}.
Each item in results has {"id": "...", "success": bool}. On success, a "document" key contains the full document dict. On failure, an "error" key contains {"code": "...", "message": "..."}.
Downloads an object from a storage bucket and uploads it to the KB. Skips duplicate ingest when the same source_path (or matching original_path in metadata) already exists.
Returns:dict — includes document_id, chunk_count, filename, source_path, and skipped: True when deduplicated.
Permanently deletes the knowledge base. There is no soft-delete or restore. A successful call purges all vectors and document metadata, removes ingest bookkeeping, and deletes the KB record. Cancellation of in-flight async ingest and cleanup of media objects under the KB prefix are best-effort.
Also available from the UI (Knowledge Bases), CLI (graphn kb delete <id> [--force]), and MCP (graphn_kb_delete).
Returns:bool — True on success (HTTP 200 or 204).
Example:
python
await kb.delete("kb_abc123")
Storage module (storage)
Object storage scoped to your workspace. Use storage IDs (bucket names) and keys (object paths). Calls use the platform-injected credentials; you do not configure API keys in code.
Returns:list[str] — store names. Each name is the storage_id used by upload/download/create. Do not treat items as dicts. For status, description, and object counts, use list_store_details().
Returns:list[dict] — each record has id (always equal to name, the storage_id), plus display_name, description, status, object_count, and total_size_bytes.
Deprecated alias of list_store_details(). Returns: the same records (id equals name, plus status/description/counts).
Example:
python
rows =await storage.list_storages()
Conversion module (conversion)
PDF and image conversion to markdown via the document conversion service. Source files must live in storage; results are written back to storage and optionally ingested into a KB.
SDK methods raise standard Python exceptions when something goes wrong — for example httpx.HTTPStatusError from failed HTTP calls, ValueError for invalid IDs or empty uploads, FileNotFoundError when a storage object is missing, RuntimeError or ConnectionError for service errors, and TimeoutError when polling jobs exceed their limits.
Catch exceptions you can handle and return a clear message or fallback result.
Unhandled exceptions propagate to the platform: the function step fails, and the error message is surfaced in the run output.
Note: Do not rely on bare except: in production code — catch specific exception types or Exception, and log or return useful context.
Pip dependencies
List third-party packages in requirements.txt (one package per line, standard pip syntax). The platform installs these when building the function environment. Only add libraries you need; prefer the built-in SDK for LLM, vision, KB, storage, and conversion flows when possible.
Additional modules
The following sections cover veo, nanobanana, and media_tools. Prefer these over any older video / image helper names.
Veo 3.1 video generation (veo)
Generate videos with native audio using Google Veo 3.1. The model produces synchronized speech and sound directly -- no separate TTS step needed. The module proxies through the backend so your function never touches GCP credentials.
Returns a dict with video_id, status, storage_path, and storage_id. Pass storage_path (with storage_id) to veo.extend to chain another segment.
python
result =await veo.generate("A woman presenting a product on camera", resolution="1080p")print(result["storage_path"])# generated/videos/veo/<exec_id>/<hash>.mp4
Generate a video using a reference image as the first frame (image-to-video). Same parameters as generate plus image_source (local path or storage path).
python
avatar =await nanobanana.generate("professional woman, business attire")result =await veo.generate_from_image("The woman speaks to the camera about quarterly results", avatar["storage_path"], storage_id=avatar["storage_id"],)
Extend an existing video by approximately 7 seconds. Each call produces a continuation from the last second of the input video. Use this to checkpoint long videos: if any single extension fails or your function is interrupted, you only lose the in-flight ~7s, not the entire chain.
Scroll horizontally to compare
Parameter
Type
Default
Description
prompt
str
(required)
Text prompt guiding the extension
video_source
str
(required)
Storage path returned by a previous generate or extend call (storage_path field), or a local file path to an mp4
resolution
str
"720p"
"720p" or "1080p"
person_generation
str
"allow_adult"
Person generation policy
storage_id
str
""
Workspace storage that contains video_source (also where the new segment is uploaded). Required when video_source is a storage path
Returns a dict with video_id, status, storage_path, and storage_id. Pass storage_path back to veo.extend to keep chaining.
python
initial =await veo.generate("A woman speaking to camera")extended =await veo.extend("She continues explaining the topic", initial["storage_path"], storage_id=initial["storage_id"],)
Generate a long video by automatically chaining an initial generation with multiple extensions. Maximum duration is approximately 148 seconds (8s initial + 20 extensions of 7s each).
Scroll horizontally to compare
Parameter
Type
Default
Description
prompt
str
(required)
Text prompt for the entire video
target_duration
int
30
Desired length in seconds (5-148)
image_base64
str | None
None
Optional base64-encoded first-frame image
aspect_ratio
str
"16:9"
"16:9" or "9:16"
resolution
str
"720p"
"720p" or "1080p"
person_generation
str
"allow_adult"
Person generation policy
storage_id
str
""
Workspace storage to upload result to
Returns a dict with video_id, status, storage_path, storage_id, segment_paths (one storage path per segment, in order -- pass any to veo.extend to fork from that segment), segments, and estimated_duration.
Note: Each extension takes 60-80 seconds of wall time. A 30-second video requires 3 extensions and takes approximately 4-5 minutes.
Generate avatar and character images using Nano Banana (Gemini Flash Image). Useful for creating reference images to feed into veo.generate_from_image.
Replace a video's audio track with a different audio file. The output length matches the shorter of the two inputs.
Tip: Veo 3.1 generates video with native audio, so you usually don't need this for avatar workflows. Use it when you need to swap audio on pre-existing video files.
Scroll horizontally to compare
Parameter
Type
Default
Description
video_source
str
(required)
Local path or storage path to the video file
audio_source
str
(required)
Local path or storage path to the audio file
storage_id
str
""
Workspace storage to upload result to
python
final =await media_tools.replace_audio("videos/original.mp4","audio/soundtrack.wav", storage_id="default",)