Newton C 2.6 Fusion Model — Multimodal /query in One Hop
Single stateless POST to /query for text, image, or video reasoning against the C 2.6 fusion checkpoint. No Lens session, no batch pipeline, no SSE. One call → one response.
When to Apply
- User wants to describe / classify / extract structure from an image with one API call
- User wants the same for a short video in a single
/querycall - User wants stateless multimodal reasoning (no per-session warmup, no orphan cleanup)
- User wants JSON output from a multimodal input (the prompt is the schema)
- User is building a serverless / per-request handler where a streaming Lens session would be the wrong shape
Do not use this skill when:
- The workload is live, streaming video → text from a long-running camera feed — a session-based activity monitor is the right shape, not stateless
/query - The workload is a large multi-file batch job
- The task is time-series classification via embeddings (KNN / anomaly detection)
The Model Identifier
Newton::c2_6_8b_fp8_260424d7a55d5e
The full Newton:: prefix and the _fp8_ segment are required. Variants that omit either are rejected with 400 invalid_model_version:
c2_6_8b_fp8_260424d7a55d5e ❌ missing Newton:: prefix
Newton::c2_6_8b_260424d7a55d5e ❌ missing _fp8_
c2_6_8b_260424d7a55d5e ❌ both missing
This was probed end-to-end against https://api.u1.archetypeai.app/v0.5/query on prod.
Endpoint
POST {ATAI_API_ENDPOINT}/v0.5/query
Authorization: Bearer <API_KEY>
Content-Type: application/json
Both ATAI_API_KEY and ATAI_API_ENDPOINT are required — there is no default endpoint, so a wrong-deployment mistake fails loudly at startup instead of silently at query time. Prod is https://api.u1.archetypeai.app/v0.5. The same endpoint serves all three modalities below — what changes is the request body.
Wire Shapes
Text + JSON
{
"query": "Classify the operational state. Respond with ONLY the JSON object.",
"instruction_prompt": "You output {\"state\": \"...\", \"confidence\": <0..1>}.",
"file_ids": [],
"model": "Newton::c2_6_8b_fp8_260424d7a55d5e",
"max_new_tokens": 300
}
- Put the system turn in
instruction_prompt. That is the only field C 2.6 honors — a directive sent in the legacysystem_promptfield alone is silently ignored (verified againstNewton::c2_6_8b_fp8_260424d7a55d5e: the same directive is obeyed ininstruction_promptand dropped insystem_prompt), so omitsystem_promptentirely. - JSON output: put the schema in
instruction_prompt, the input inquery, and explicitly tell the model not to wrap in markdown fences. The model otherwise often returnsjson ....
For reasoning over an attached text file: upload it as text/plain (a .txt file) via /v0.5/files, then put the filename in file_ids. The model then sees the file contents in its prompt context. Critical: this only works for text/plain. A file uploaded as text/csv (a .csv) is accepted and stored byte-identically, but its contents never reach the model on /query — it silently confabulates from priors (see the gotcha below and csv_vs_txt_proof.py). application/json uploads are rejected outright. So put tabular data in a .txt, or inline it in query.
See text_query.py for runnable demos of all three patterns. Its examples are framed as smart-home WiFi flow analysis; the attached flow log in example 3 is real data from the GHOST-IoT dataset (Anagnostopoulos et al., Sensors 2020, DOI:10.3390/s20226600) — see the script's docstring for full attribution.
Image
Two attachment paths, both reach the same fusion model — pick by use case — plus a flag for sending several images at once:
(a) Upload + reference by filename in file_ids — best when the same image is reused across queries (one upload, many /query calls):
curl -X POST $ATAI_API_ENDPOINT/v0.5/files \
-H "Authorization: Bearer $ATAI_API_KEY" \
-F "file=@dashboard.png;type=image/png"
{
"query": "Describe this image in three bullets.",
"instruction_prompt": "...",
"file_ids": ["dashboard.png"],
"model": "Newton::c2_6_8b_fp8_260424d7a55d5e",
"max_new_tokens": 300
}
(b) Inline base64 in a data.base64_img event — best for one-shot calls where the upload roundtrip is wasted:
{
"query": "What is in this image? One sentence.",
"instruction_prompt": "...",
"file_ids": [],
"model": "Newton::c2_6_8b_fp8_260424d7a55d5e",
"max_new_tokens": 200,
"events": [
{
"type": "data.base64_img",
"event_data": {
"contents": "<base64 string>",
"mime_type": "image/png"
}
}
]
}
(c) Multiple images — set multi_image: true for multi-image mode: each attachment is an independent image (before/after, multi-view, "is the same person in these images?"), not frames of a video. Platform limit: 16 images max per request. Without multi_image: true, an image list means "frames of one video" and requires query_metadata (see the Video section); lacking both, the request fails with 400 query_failed:
{
"query": "Image 1 is the bench BEFORE the task; image 2 is DURING. What changed?",
"instruction_prompt": "...",
"file_ids": ["assembly_before.png", "assembly_after.png"],
"model": "Newton::c2_6_8b_fp8_260424d7a55d5e",
"max_new_tokens": 400,
"multi_image": true
}
See image_query.py for runnable demos of all three paths.
Video
C 2.6 reasons over video on /query two ways. This distinguishes it from the C 2.4 / 2.5 text checkpoints, which accept an .mp4 but ignore the frames and reply "I can't see videos."
(a) .mp4 + max_frames — upload the clip, and GPQ decodes and uniformly samples it server-side before the model sees the frames. No client-side video tooling needed:
curl -X POST $ATAI_API_ENDPOINT/v0.5/files \
-H "Authorization: Bearer $ATAI_API_KEY" \
-F "file=@clip.mp4;type=video/mp4"
{
"query": "Evaluate the assembly steps shown in the attached video.",
"instruction_prompt": "<task / inspection prompt>",
"file_ids": ["clip.mp4"],
"model": "Newton::c2_6_8b_fp8_260424d7a55d5e",
"max_new_tokens": 500,
"max_frames": 32
}
(b) Client-sampled frames + query_metadata — send the frames yourself (one data.base64_img event each, or image file_ids), set multi_image: false, and include a query_metadata block with the video-metadata triple. The query_metadata block is what makes this work — without it the request fails with 400 query_failed:
{
"query": "This is a short video. Describe the sequence of actions in order.",
"instruction_prompt": "...",
"model": "Newton::c2_6_8b_fp8_260424d7a55d5e",
"multi_image": false,
"max_new_tokens": 150,
"events": [
{"type": "data.base64_img", "event_data": {"contents": "<frame_0 base64>"}},
{"type": "data.base64_img", "event_data": {"contents": "<frame_1 base64>"}}
],
"query_metadata": {"raw_fps": 1.0, "frames_indices": [0, 1], "total_num_frames": 2}
}
Both shapes verified live (the file_ids variant of (b) works too). Notes:
max_frames— frames GPQ samples uniformly from the video before feeding the model. Default 32, platform max 64. Increase for longer / higher-detail clips; decrease to cap latency. Values above 64 fail silently: the request returns 200, but the video is dropped and the model confabulates a scene from priors (verified:max_frames: 80on the assembly clip described "a person holding a smartphone"). Stay at ≤ 64.- Timeout — set the client request timeout to at least 600s. Video latency scales with
max_framesand clip length; default 30–60s timeouts will trip on non-trivial clips. .mp4-direct on C 2.6 is a recent platform change. Earlier the.mp4path silently dropped the frames for every model (a known GPQ bug), so older notes say "video doesn't work on/query." On C 2.6 today it does, viamax_frames.multi_imageselects between video and multi-image mode.multi_image: false(withquery_metadata) = the attached images are frames of one video.multi_image: true= multi-image mode — the images are independent (before/after, multi-view), andquery_metadatais not needed.
See video_query.py for runnable demos of both paths (mp4 direct, a max_frames tradeoff, and a frame-list demo) using a worker-assembly PASS/FAIL inspection prompt.
Generation Parameters
All C-model generations via /query accept sampling controls in the request body (verified accepted + honored on prod with C 2.6):
| Param | Default | Notes |
|---|---|---|
max_new_tokens |
256 | Hard ceiling on generated tokens (~4 chars each) — stops mid-sentence at the cap |
temperature |
— | 0.0 = greedy/deterministic-ish; 0.7–1.0 for creative output. Capped at 2.0 |
do_sample |
true |
Master switch: false forces greedy decoding (temperature → 0, top_p/top_k stripped) — use for reproducibility |
repetition_penalty |
1.0 | Multiplicative logit penalty on already-emitted tokens; try 1.1–1.3 if the model loops on a phrase or repeats numbers |
presence_penalty |
0.0 | Additive penalty on any token that has appeared at least once (frequency-independent). Range ≈ −2..+2. C 2.6 only |
top_p |
0.8 | Nucleus sampling — keep the smallest token set with cumulative probability ≥ top_p |
top_k |
— | Hard cap on candidate tokens per step (applied before top_p); 0 disables |
For "extract X"-style tasks, do_sample: false (or temperature: 0.0) plus a tight max_new_tokens is the right starting point.
Reproducibility caveat (verified): the sampling knobs are honored — on the same prompt, 5 runs gave 2 distinct outputs greedy (do_sample: false), 3 distinct at defaults, 5 distinct at temperature: 1.9 — but greedy is not bit-deterministic on this deployment (fp8 numerics / batching sit outside the decoder), contrary to the platform note that do_sample: false output "is deterministic given the prompt". On borderline judgments the residual wobble is enough to flip the answer: the same greedy assembly-inspection body returned all-PASS on one run and two FAILs on another. If a verdict matters, aggregate over a few calls rather than trusting one.
Latency Budgets
Observed against prod with the sample assets in references/sample_assets/:
| Modality | Body | p50 | Notes |
|---|---|---|---|
| Text only | {"query": "...", "file_ids": []} |
~500 ms | Confirmed during model-identifier probing |
| Text + JSON output | instruction prompt has schema | ~600 ms | Same shape, slightly longer with verbose schema |
Image via file_ids |
one 1.9 MB PNG | ~1.3–1.9 s | observed (wind-turbines.png) |
| Image via inline base64 | same | ~0.8–2.5 s | base64 inflates the request; scales with image size |
Two images, multi_image: true |
2 × ~400 KB PNG | ~2.9 s | before/after comparison (assembly frames) |
Video, mp4 + max_frames=32 |
~31 s assembly clip | ~2–6 s | server-side decode/sample |
Video, 2 frames + query_metadata |
2 × ~400 KB PNG | ~1.9 s | client-sampled frame-list path |
Numbers are smoke-test order-of-magnitude. Production data may be 5–10× heavier and proportionally slower.
Response Shape
{
"query_id": "...",
"status": "completed",
"inference_time_sec": 0.42,
"query_response_time_sec": 0.49,
"response": {
"response": ["<the model output as a string>"]
}
}
Walk payload["response"]["response"][0] as the canonical extraction path. The reference scripts' extract_text() helper handles every shape variant we've seen.
Common Pitfalls
- Wrong model identifier.
c2_6_8b_fp8_260424d7a55d5ewithoutNewton::returns400 invalid_model_version. So does the variant without_fp8_. Always use the fullNewton::c2_6_8b_fp8_260424d7a55d5e. - JSON wrapped in markdown fences. The model sometimes returns
json ...even when explicitly told not to. Either parse defensively (text.strip().removeprefix("```json").removesuffix("```")) or restate the no-fences rule in the user query as well asinstruction_prompt. - Video timeout. Default
requests.posttimeout of 30–60s will fail on anything but trivial clips. Set timeout ≥ 600s. - Multiple images without
multi_image: trueneed thequery_metadatatriple. A list of images defaults to "frames of one video" — but that path requiresquery_metadata: {"raw_fps": ..., "frames_indices": [...], "total_num_frames": N}in the body; without it the request fails with400 query_failed(the error doesn't hint at the missing field). For independent images (before/after, multi-view), setmulti_image: trueinstead — max 16 images, noquery_metadataneeded. max_framesabove 64 fails silently. The platform max is 64.max_frames: 80still returns 200, but the video never reaches the model — it confabulates a scene from priors (same failure mode as the CSV gotcha below). Keepmax_frames≤ 64.- "Video doesn't work on
/query" is stale. Older notes say C 2.6 (and 2.4/2.5) can't see video. That was a GPQ bug that silently dropped.mp4frames before any model. C 2.6 reads video now via.mp4+max_frames— verified. The 2.4/2.5 text checkpoints still ignore frames. file_idstakes the filename, not thefil_...uid. On upload the API returns both{"file_id": "<filename>", "file_uid": "fil_..."}./queryresolvesfile_idsby the filename (thefile_idvalue, e.g."dashboard.png"), not thefil_...file_uid. Passing thefile_uidfails with a misleading400 unsupported_file_type("Found unsupported file type with file: fil_…") — it looks like a content-type problem but is really the wrong identifier. Verified:file_ids=["wind-turbines.png"]→ 200;file_ids=["fil_…"]→ 400.- Text attachments must be
text/plain, nottext/csv. A.csvupload (text/csv) is accepted, stored byte-for-byte, and returnsstatus: completed— but its contents never reach the model on/query; the model silently confabulates from priors (e.g. answers "TCP"/"port 80" for an all-SSH file). The identical bytes uploaded as.txt(text/plain) are read faithfully. There is no warning — the failure is silent, so you can only catch it by validating the answer. Upload tabular/text data as.txt, or inline it inquery. Verify yourself withcsv_vs_txt_proof.py(.txtreads 5/5,.csv0/5 on identical content).application/jsonuploads are rejected with400 invalid_file_type. - Mixed-modality calls. You can attach both an image and a video file_id, but the fusion model's attention is finite. Stick to one modality per call for predictable results.
Local Setup
# In a virtualenv (system pythons are often PEP 668 "externally managed"):
python3 -m venv .venv && source .venv/bin/activate
pip install -r skills/atai-newton-fusion-model/references/requirements.txt
# Drop a .env at the repo root (or anywhere up the tree from the run dir).
# BOTH variables are required — there is no default endpoint:
cat > .env <<EOF
ATAI_API_KEY=sk_...
ATAI_API_ENDPOINT=https://api.u1.archetypeai.app/v0.5
EOF
python skills/atai-newton-fusion-model/references/text_query.py
python skills/atai-newton-fusion-model/references/image_query.py
python skills/atai-newton-fusion-model/references/video_query.py
The scripts are built on the official Archetype AI python client (pip install archetypeai): uploads go through client.files.local.upload(...), base64 encoding through archetypeai.utils.base64_encode(...) (utf-8), and each script creates one client and passes it into the helpers. They auto-load .env if python-dotenv is installed — find_dotenv() walks up from cwd so the file works at the repo root, the project root, or inside references/. Without python-dotenv, the scripts fall back to plain environment variables (export ATAI_API_KEY=... ATAI_API_ENDPOINT=...).
File Layout
skills/atai-newton-fusion-model/
├── SKILL.md ← this file
├── references/
│ ├── _common.py ← shared helpers on the official archetypeai client
│ ├── text_query.py ← 3 text patterns (plain, JSON output, .txt flow-log attachment)
│ ├── image_query.py ← 4 image patterns (file_ids, base64, JSON extraction, multi-image)
│ ├── video_query.py ← 3 video patterns (mp4 direct, max_frames tradeoff, frame list + query_metadata)
│ ├── csv_vs_txt_proof.py ← diagnostic: proves text/csv attachments aren't read, text/plain are
│ ├── requirements.txt ← runtime deps (pip install -r requirements.txt)
│ ├── .env.example ← copy to .env and fill in
│ └── sample_assets/
│ ├── wind-turbines.png ← AI-generated photo (default for image_query.py)
│ ├── assembly_before.png / assembly_after.png ← frames from the clip below (multi-image demo)
│ ├── 1_pass_2_pass_3_pass_B.mp4 ← assembly-inspection clip (default for video_query.py)
│ └── README.md ← provenance of the samples
└── tests/
└── test_references.py ← network-free unit tests (python -m unittest)