Skip to main content
Authenticated routes require an X-API-Key header set to your ENVIRONMENT_API_KEY (run uvx synth-ai setup to provision credentials). SFT task apps serve two purposes: expose the standard HTTP interface and emit supervision data that downstream tooling can filter, validate, and upload. Document the pieces below when building a new task. Supervised data capture
  • Store each conversation as a JSONL record validated by validate_training_jsonl / validate_jsonl_or_raise:
    {
        "messages": list[{
            "role": str,
            "content": str | list | dict | null,
            "tool_calls": list,
            "tool_call_id": str | null,
            "name": str | null,
            "reasoning": str | null,
            "raw_content": str | null,
            "extra": object
        }],
        "tools": list,
        "tool_choice": object | null,
        "metadata": object,
        "extra": object
    }
    
  • Honour tracing environment flags:
    • TASKAPP_TRACING_ENABLED: enable supervised logging.
    • TASKAPP_SFT_OUTPUT_DIR: write JSONL batches via unique_sft_path.
    • TURSO_LOCAL_DB_URL / SQLD_DB_PATH: route traces to the configured store.
  • Provide trace filtering knobs through FilterConfig so tooling can query by score, model, or split before exporting to JSONL.
Training payload pipeline
  • Supply TOML configs that build_sft_payload accepts (data paths, model allowlist, hyperparameters).
  • After filtering, call FtClient.upload_training_file, then launch jobs with FtClient.create_sft_job and FtClient.start_job.
Task app metadata expectations
  • Expose a TaskAppConfig whose base_task_info, describe_taskset(), and provide_task_instances() fields describe the supervision dataset (task descriptors, environment ids, seeds, splits).
  • Ensure rollout() responses keep pipeline_metadata.inference_url and every info.meta.inference_url in sync with a ?cid=... token so traces correlate with upstream inference logs.
  • If you intend to host on Modal, package a Modal app script and ModalTaskAppConfig (identical requirements to RL deployments) so traces can be collected remotely.
FastAPI endpoints:
  • /
    • Method: GET
    • Returns:
    { "status": "ok", "service": str }
    
  • /health
    • Method: GET
    • Returns:
    {
        "healthy": bool,
        "auth": {
            "required": bool,
            "expected_prefix": str
        }
    }
    
  • /info
    • Method: GET
    • Returns:
    {
        "service": {
            "task": {
                "id": str,
                "name": str,
                "version": str
            },
            "version": str
        },
        "dataset": {
            "id": str,
            "splits": list[str],
            "default_split": str
        },
        "rubrics": {
            "outcome": { "sections": list },
            "events": { "sections": list }
        },
        "inference": {
            "url": str,
            "model": str
        },
        "limits": {
            "max_llm_calls": int,
            "max_turns": int
        }
    }
    
  • /task_info
    • Method: GET
    • Query params: seed (int, repeatable) or seeds (array[int])
    • No seed returns:
    {
        "taskset": {
            "id": str,
            "split": str,
            "cardinality": int,
            "metadata": object
        }
    }
    
    • With seed(s) returns:
    {
        "task": {
            "id": str,
            "name": str,
            "description": str,
            "version": str
        },
        "environment": str,
        "dataset": {
            "id": str,
            "name": str,
            "split": str,
            "version": str
        },
        "rubric": {
            "id": str,
            "name": str,
            "sections": list
        },
        "inference": {
            "model": str,
            "base_url": str
        },
        "limits": {
            "max_llm_calls": int,
            "max_turns": int,
            "timeout_seconds": int
        },
        "task_metadata": object
    }
    
  • /rollout
    • Method: POST
    • Body: RolloutRequest (used to collect supervised traces)
    • Returns:
    {
        "run_id": str,
        "trajectories": [
            {
                "env_id": str,
                "policy_id": str,
                "steps": [
                    {
                        "obs": object,
                        "tool_calls": list,
                        "reward": float | null,
                        "done": bool,
                        "truncated": bool | null,
                        "info": {
                            "meta": {
                                "inference_url": str
                            }
                        }
                    }
                ],
                "final": object | null,
                "length": int,
                "inference_url": str,
                "decision_samples": list | null
            }
        ],
        "branches": object,
        "metrics": {
            "episode_returns": list[float],
            "mean_return": float,
            "num_steps": int,
            "num_episodes": int,
            "outcome_score": float | null,
            "events_score": float | null,
            "details": object
        },
        "aborted": bool,
        "ops_executed": int,
        "trace_correlation_id": str | null,
        "trace": object | null,
        "pipeline_metadata": {
            "inference_url": str
        }
    }