@sogni-ai/sogni-creative-agent-skill
Version:
Sogni Creative Agent Skill: agent skill and CLI for Sogni AI image, 3D, speech, video, and music generation.
3,266 lines • 228 kB
JavaScript
// Generated by sogni-creative-agent/scripts/sync-skill-runtime.mjs.
// Do not edit manually in sogni-creative-agent-skill.
// Moved to @sogni-ai/sogni-intelligence-client/skill-runtime-source in Phase 8.4 follow-up.
// This file is kept as a thin re-export so existing internal `agent/`
// callers keep working. New code should import from the public mid-tier:
// import { ... } from '@sogni-ai/sogni-intelligence-client/skill-runtime-source';
export * from '@sogni-ai/sogni-intelligence-client/skill-runtime-source';
// Moved to @sogni-ai/sogni-intelligence-client/skill-runtime-source in Phase 8.4 follow-up.
// This file is kept as a thin re-export so existing internal `agent/`
// callers keep working. New code should import from the public mid-tier:
// import { ... } from '@sogni-ai/sogni-intelligence-client/skill-runtime-source';
export * from '@sogni-ai/sogni-intelligence-client/skill-runtime-source';
const GATING_POLICIES = [
{
"policyId": "DIAGNOSTIC_REQUEST",
"version": "1.0.0",
"trigger": {
"allOf": [
"asks_about_previous_error",
"has_prior_generation_context"
]
},
"effect": {
"forbid": [
"generate_image",
"edit_image",
"restore_photo",
"upscale_image",
"image_to_3d",
"remove_background",
"segment_image",
"apply_style",
"refine_result",
"animate_photo",
"change_angle",
"generate_video",
"sound_to_video",
"video_to_video",
"upscale_video",
"generate_music",
"generate_speech",
"extend_video",
"replace_video_segment",
"overlay_video",
"add_subtitles",
"stitch_video",
"orbit_video",
"dance_montage"
]
},
"rationale": "The latest user message asks about a previous error. Do not retry media; answer from prior tool calls and context."
},
{
"policyId": "GENERATION_DETAILS_QUERY",
"version": "1.0.0",
"trigger": {
"allOf": [
"asks_about_generation_details",
"has_prior_generation_context"
]
},
"effect": {
"forbid": [
"generate_image",
"edit_image",
"restore_photo",
"upscale_image",
"image_to_3d",
"remove_background",
"segment_image",
"apply_style",
"refine_result",
"animate_photo",
"change_angle",
"generate_video",
"sound_to_video",
"video_to_video",
"upscale_video",
"generate_music",
"generate_speech",
"extend_video",
"replace_video_segment",
"overlay_video",
"add_subtitles",
"stitch_video",
"orbit_video",
"dance_montage"
]
},
"rationale": "The latest user message asks about prior generation details. Do not create or retry media; answer only from prior tool calls."
},
{
"policyId": "TEXT_ONLY_REQUEST",
"version": "1.0.0",
"trigger": {
"allOf": [
"requests_text_only_response"
]
},
"effect": {
"forbid": [
"generate_image",
"edit_image",
"restore_photo",
"upscale_image",
"image_to_3d",
"remove_background",
"segment_image",
"apply_style",
"refine_result",
"animate_photo",
"change_angle",
"generate_video",
"sound_to_video",
"video_to_video",
"upscale_video",
"generate_music",
"generate_speech",
"extend_video",
"replace_video_segment",
"overlay_video",
"add_subtitles",
"stitch_video",
"orbit_video",
"dance_montage"
]
},
"rationale": "The latest user message requests a text-only response. Do not call any media generation tools."
},
{
"policyId": "DIAGNOSTIC_COMPLAINT",
"version": "1.0.0",
"trigger": {
"allOf": [
"requests_diagnostic_response",
"has_prior_generation_context"
]
},
"effect": {
"forbid": [
"generate_image",
"edit_image",
"restore_photo",
"upscale_image",
"image_to_3d",
"remove_background",
"segment_image",
"apply_style",
"refine_result",
"animate_photo",
"change_angle",
"generate_video",
"sound_to_video",
"video_to_video",
"upscale_video",
"generate_music",
"generate_speech",
"extend_video",
"replace_video_segment",
"overlay_video",
"add_subtitles",
"stitch_video",
"orbit_video",
"dance_montage"
]
},
"rationale": "The latest user message is a diagnostic complaint about prior output. Do not create or retry media; explain what likely went wrong."
},
{
"policyId": "UPLOADED_BASE_VIDEO_PRESENT",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"requests_video_modification"
],
"sources": {
"has_uploaded_video": "session_state",
"requests_video_modification": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
]
},
"rationale": "A user-uploaded video is the base; modify that asset directly instead of rendering a fresh clip."
},
{
"policyId": "UPLOADED_BASE_VIDEO_EXTEND",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:extend"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:extend": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
],
"require": [
"extend_video"
]
},
"rationale": "The planner identified uploaded-video extension. Use extend_video on the uploaded base; do not create a separate fresh clip."
},
{
"policyId": "UPLOADED_BASE_VIDEO_REPLACE",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:replace_segment"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:replace_segment": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
],
"require": [
"replace_video_segment"
]
},
"rationale": "The planner identified an uploaded-video segment replacement. Use replace_video_segment on the uploaded base."
},
{
"policyId": "UPLOADED_BASE_VIDEO_OVERLAY",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:overlay"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:overlay": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
],
"require": [
"overlay_video"
]
},
"rationale": "The planner identified an uploaded-video overlay. Use overlay_video on the uploaded base."
},
{
"policyId": "UPLOADED_BASE_VIDEO_SUBTITLES",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:subtitles"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:subtitles": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
],
"require": [
"add_subtitles"
]
},
"rationale": "The planner identified uploaded-video subtitles. Use add_subtitles on the uploaded base."
},
{
"policyId": "UPLOADED_BASE_VIDEO_TRANSFORM",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:transform"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:transform": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
],
"require": [
"video_to_video"
]
},
"rationale": "The planner identified an uploaded-video transform. Use video_to_video on the uploaded base."
},
{
"policyId": "UPLOADED_BASE_VIDEO_STITCH",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:stitch"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:stitch": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo"
],
"require": [
"stitch_video"
]
},
"rationale": "The planner identified uploaded-video stitching. Use stitch_video with the uploaded clips instead of rendering a fresh clip."
},
{
"policyId": "UPLOADED_BASE_VIDEO_UPSCALE",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_uploaded_video",
"video_modification:upscale"
],
"sources": {
"has_uploaded_video": "session_state",
"video_modification:upscale": "planner"
}
},
"effect": {
"forbid": [
"generate_video",
"animate_photo",
"video_to_video"
],
"require": [
"upscale_video"
]
},
"rationale": "The planner identified a pure resolution upscale of the uploaded video. Use the promptless upscale_video tool; do not re-render the clip with a generative model."
},
{
"policyId": "HAS_PERSONA_AND_REQUESTS_VIDEO",
"version": "1.1.0",
"trigger": {
"allOf": [
"has_active_persona",
"requests_persona_video_generation",
"no_persona_image_in_session"
],
"sources": {
"has_active_persona": "session_state",
"requests_persona_video_generation": "planner",
"no_persona_image_in_session": "session_state"
}
},
"effect": {
"forbid": [],
"require": [
"resolve_personas"
]
},
"rationale": "Persona videos start with resolve_personas. On MiniMax H3 reference-to-video, Seedance or Wan 3, pass the resolved persona reference images straight to generate_video as referenceImageIndices, with no edit_image step. On LTX and every other video model, render the persona with edit_image first, then animate it. Do not go text-to-video without the persona references."
},
{
"policyId": "HAS_PERSONA_AND_REQUESTS_PERSONA_IMAGE",
"version": "1.0.0",
"trigger": {
"allOf": [
"has_active_persona",
"requests_persona_image_generation"
],
"sources": {
"has_active_persona": "session_state",
"requests_persona_image_generation": "planner"
}
},
"effect": {
"forbid": [
"generate_image"
],
"require": [
"edit_image"
]
},
"rationale": "Persona images must use edit_image with the persona reference photo, never generate_image (which has no access to the persona identity)."
}
];
const REPAIR_RECIPES = [
{
"recipeId": "extend_video.duration_clamp",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "PARAMETER_INVALID",
"mode": "autoRepair",
"maxRetries": 1,
"repairNoteTemplate": "Seedance video segments cap at 15s; adjusted duration from {{requested}}s to {{clamped}}s.",
"autoRepairFields": [
"duration"
]
},
{
"recipeId": "animate_photo.all_failed",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "All animation attempts failed. Want to try a different photo or rewrite the motion prompt?"
},
{
"recipeId": "replace_video_segment.window_invalid",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "replace_video_segment needs a valid replacement window. {{message}} Please provide a shorter explicit start and end time, for example \"replace 5s to 9s\" or \"redo the last 4 seconds.\""
},
{
"recipeId": "generate_image.user_input_incomplete",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "edit_image.user_input_incomplete",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "restore_photo.user_input_incomplete",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "upscale_image.user_input_incomplete",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "image_to_3d.user_input_incomplete",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "remove_background.user_input_incomplete",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "segment_image.user_input_incomplete",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "apply_style.user_input_incomplete",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "refine_result.user_input_incomplete",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "animate_photo.user_input_incomplete",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "change_angle.user_input_incomplete",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "generate_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "sound_to_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "video_to_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "upscale_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "generate_music.user_input_incomplete",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "generate_speech.user_input_incomplete",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "extend_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "replace_video_segment.user_input_incomplete",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "overlay_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "add_subtitles.user_input_incomplete",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "stitch_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "orbit_video.user_input_incomplete",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "dance_montage.user_input_incomplete",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "USER_INPUT_INCOMPLETE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I need more details before I can run {{toolName}}. {{missingDetail}}"
},
{
"recipeId": "generate_image.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "edit_image.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "restore_photo.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "upscale_image.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "image_to_3d.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "remove_background.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "segment_image.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "apply_style.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "refine_result.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "animate_photo.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "change_angle.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "generate_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "sound_to_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "video_to_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "upscale_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "generate_music.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "generate_speech.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "extend_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "replace_video_segment.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "overlay_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "add_subtitles.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "stitch_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "orbit_video.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "dance_montage.cost_limit_exceeded",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "COST_LIMIT_EXCEEDED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs"
},
{
"recipeId": "generate_image.asset_not_found",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "edit_image.asset_not_found",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "restore_photo.asset_not_found",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "upscale_image.asset_not_found",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "image_to_3d.asset_not_found",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "remove_background.asset_not_found",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "segment_image.asset_not_found",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "apply_style.asset_not_found",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "refine_result.asset_not_found",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "animate_photo.asset_not_found",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "change_angle.asset_not_found",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "generate_video.asset_not_found",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "sound_to_video.asset_not_found",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "video_to_video.asset_not_found",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "upscale_video.asset_not_found",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "generate_music.asset_not_found",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "generate_speech.asset_not_found",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "extend_video.asset_not_found",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "replace_video_segment.asset_not_found",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "overlay_video.asset_not_found",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "add_subtitles.asset_not_found",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "stitch_video.asset_not_found",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "orbit_video.asset_not_found",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "dance_montage.asset_not_found",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "analyze_image.asset_not_found",
"version": "1.0.0",
"toolName": "analyze_image",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "analyze_video.asset_not_found",
"version": "1.0.0",
"toolName": "analyze_video",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "extract_metadata.asset_not_found",
"version": "1.0.0",
"toolName": "extract_metadata",
"errorCode": "ASSET_NOT_FOUND",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "I cannot find the asset that {{toolName}} needs. {{message}} Which uploaded or generated asset did you want?"
},
{
"recipeId": "generate_image.workflow_validation_failed",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "edit_image.workflow_validation_failed",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "restore_photo.workflow_validation_failed",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "upscale_image.workflow_validation_failed",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "image_to_3d.workflow_validation_failed",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "remove_background.workflow_validation_failed",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "segment_image.workflow_validation_failed",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "apply_style.workflow_validation_failed",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "refine_result.workflow_validation_failed",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "animate_photo.workflow_validation_failed",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "change_angle.workflow_validation_failed",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "generate_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "sound_to_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "video_to_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "upscale_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "generate_music.workflow_validation_failed",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "generate_speech.workflow_validation_failed",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "extend_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "replace_video_segment.workflow_validation_failed",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "overlay_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "add_subtitles.workflow_validation_failed",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "stitch_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "orbit_video.workflow_validation_failed",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "dance_montage.workflow_validation_failed",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "WORKFLOW_VALIDATION_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} could not run: {{message}}"
},
{
"recipeId": "generate_image.parameter_invalid",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "edit_image.parameter_invalid",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "restore_photo.parameter_invalid",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "upscale_image.parameter_invalid",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "image_to_3d.parameter_invalid",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "remove_background.parameter_invalid",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "segment_image.parameter_invalid",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "apply_style.parameter_invalid",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "refine_result.parameter_invalid",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "animate_photo.parameter_invalid",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "change_angle.parameter_invalid",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "generate_video.parameter_invalid",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "sound_to_video.parameter_invalid",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "video_to_video.parameter_invalid",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "upscale_video.parameter_invalid",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "generate_music.parameter_invalid",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "generate_speech.parameter_invalid",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "overlay_video.parameter_invalid",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "add_subtitles.parameter_invalid",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "stitch_video.parameter_invalid",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "orbit_video.parameter_invalid",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "dance_montage.parameter_invalid",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "PARAMETER_INVALID",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} rejected the arguments: {{message}}"
},
{
"recipeId": "generate_image.gpu_worker_failed",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "edit_image.gpu_worker_failed",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "restore_photo.gpu_worker_failed",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "upscale_image.gpu_worker_failed",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "image_to_3d.gpu_worker_failed",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "remove_background.gpu_worker_failed",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "segment_image.gpu_worker_failed",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "apply_style.gpu_worker_failed",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "refine_result.gpu_worker_failed",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "change_angle.gpu_worker_failed",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "generate_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "sound_to_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "video_to_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "upscale_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "generate_music.gpu_worker_failed",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "generate_speech.gpu_worker_failed",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "extend_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "replace_video_segment.gpu_worker_failed",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "overlay_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "add_subtitles.gpu_worker_failed",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "stitch_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "orbit_video.gpu_worker_failed",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "dance_montage.gpu_worker_failed",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "GPU_WORKER_FAILED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} worker failed. {{message}} Want me to try again or change the request?"
},
{
"recipeId": "generate_image.model_unavailable",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "edit_image.model_unavailable",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "restore_photo.model_unavailable",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "upscale_image.model_unavailable",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "image_to_3d.model_unavailable",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "remove_background.model_unavailable",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "segment_image.model_unavailable",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "apply_style.model_unavailable",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "refine_result.model_unavailable",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "animate_photo.model_unavailable",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "change_angle.model_unavailable",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "generate_video.model_unavailable",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "sound_to_video.model_unavailable",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "video_to_video.model_unavailable",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "upscale_video.model_unavailable",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "generate_music.model_unavailable",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "generate_speech.model_unavailable",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "extend_video.model_unavailable",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "replace_video_segment.model_unavailable",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "overlay_video.model_unavailable",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "add_subtitles.model_unavailable",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "stitch_video.model_unavailable",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "orbit_video.model_unavailable",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "dance_montage.model_unavailable",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "MODEL_UNAVAILABLE",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The model {{toolName}} wanted is offline. {{message}} Pick a different model or try again later."
},
{
"recipeId": "generate_image.permission_required",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "edit_image.permission_required",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "restore_photo.permission_required",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "upscale_image.permission_required",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "image_to_3d.permission_required",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "remove_background.permission_required",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "segment_image.permission_required",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "apply_style.permission_required",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "refine_result.permission_required",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "animate_photo.permission_required",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "change_angle.permission_required",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "generate_video.permission_required",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "sound_to_video.permission_required",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "video_to_video.permission_required",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "upscale_video.permission_required",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "generate_music.permission_required",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "generate_speech.permission_required",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "extend_video.permission_required",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "replace_video_segment.permission_required",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "overlay_video.permission_required",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "add_subtitles.permission_required",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "stitch_video.permission_required",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "orbit_video.permission_required",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "dance_montage.permission_required",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "PERMISSION_REQUIRED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} needs permission you have not granted yet. {{message}}"
},
{
"recipeId": "generate_image.safety_rewrite",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "generate_image"
},
{
"recipeId": "edit_image.safety_rewrite",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "edit_image"
},
{
"recipeId": "restore_photo.safety_rewrite",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "restore_photo"
},
{
"recipeId": "apply_style.safety_rewrite",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "apply_style"
},
{
"recipeId": "refine_result.safety_rewrite",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "refine_result"
},
{
"recipeId": "animate_photo.safety_rewrite",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "animate_photo"
},
{
"recipeId": "generate_video.safety_rewrite",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "generate_video"
},
{
"recipeId": "sound_to_video.safety_rewrite",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "sound_to_video"
},
{
"recipeId": "video_to_video.safety_rewrite",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "video_to_video"
},
{
"recipeId": "generate_music.safety_rewrite",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "generate_music"
},
{
"recipeId": "generate_speech.safety_rewrite",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "SAFETY_REJECTED",
"mode": "suggestFollowup",
"maxRetries": 1,
"repairNoteTemplate": "Content filter rejected the prompt for {{toolName}}. Try a softer phrasing or different scene.",
"suggestedFollowupTool": "generate_speech"
},
{
"recipeId": "generate_image.provider_timeout",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "edit_image.provider_timeout",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "restore_photo.provider_timeout",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "upscale_image.provider_timeout",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "image_to_3d.provider_timeout",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "remove_background.provider_timeout",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "segment_image.provider_timeout",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "apply_style.provider_timeout",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "refine_result.provider_timeout",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "animate_photo.provider_timeout",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "change_angle.provider_timeout",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "generate_video.provider_timeout",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "sound_to_video.provider_timeout",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "video_to_video.provider_timeout",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "upscale_video.provider_timeout",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "generate_music.provider_timeout",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "generate_speech.provider_timeout",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "extend_video.provider_timeout",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "replace_video_segment.provider_timeout",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "overlay_video.provider_timeout",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "add_subtitles.provider_timeout",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "stitch_video.provider_timeout",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "orbit_video.provider_timeout",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "dance_montage.provider_timeout",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "PROVIDER_TIMEOUT",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "{{toolName}} timed out. {{message}} Want me to retry, or simplify the request?"
},
{
"recipeId": "generate_image.user_cancelled",
"version": "1.0.0",
"toolName": "generate_image",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "edit_image.user_cancelled",
"version": "1.0.0",
"toolName": "edit_image",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "restore_photo.user_cancelled",
"version": "1.0.0",
"toolName": "restore_photo",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "upscale_image.user_cancelled",
"version": "1.0.0",
"toolName": "upscale_image",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "image_to_3d.user_cancelled",
"version": "1.0.0",
"toolName": "image_to_3d",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "remove_background.user_cancelled",
"version": "1.0.0",
"toolName": "remove_background",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "segment_image.user_cancelled",
"version": "1.0.0",
"toolName": "segment_image",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "apply_style.user_cancelled",
"version": "1.0.0",
"toolName": "apply_style",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "refine_result.user_cancelled",
"version": "1.0.0",
"toolName": "refine_result",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "animate_photo.user_cancelled",
"version": "1.0.0",
"toolName": "animate_photo",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "change_angle.user_cancelled",
"version": "1.0.0",
"toolName": "change_angle",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "generate_video.user_cancelled",
"version": "1.0.0",
"toolName": "generate_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "sound_to_video.user_cancelled",
"version": "1.0.0",
"toolName": "sound_to_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "video_to_video.user_cancelled",
"version": "1.0.0",
"toolName": "video_to_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "upscale_video.user_cancelled",
"version": "1.0.0",
"toolName": "upscale_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "generate_music.user_cancelled",
"version": "1.0.0",
"toolName": "generate_music",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "generate_speech.user_cancelled",
"version": "1.0.0",
"toolName": "generate_speech",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "extend_video.user_cancelled",
"version": "1.0.0",
"toolName": "extend_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "replace_video_segment.user_cancelled",
"version": "1.0.0",
"toolName": "replace_video_segment",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "overlay_video.user_cancelled",
"version": "1.0.0",
"toolName": "overlay_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "add_subtitles.user_cancelled",
"version": "1.0.0",
"toolName": "add_subtitles",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "stitch_video.user_cancelled",
"version": "1.0.0",
"toolName": "stitch_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "orbit_video.user_cancelled",
"version": "1.0.0",
"toolName": "orbit_video",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
},
{
"recipeId": "dance_montage.user_cancelled",
"version": "1.0.0",
"toolName": "dance_montage",
"errorCode": "USER_CANCELLED",
"mode": "stopAndAsk",
"maxRetries": 0,
"repairNoteTemplate": "The {{toolName}} run was cancelled by the user. I will stop here unless you ask me to try again."
}
];
const PROMPT_CONTRACTS = [
{
"contractId": "image_to_3d_v1",
"version": "1.0.0",
"toolName": "image_to_3d",
"baseDescription": "Reconstruct a downloadable GLB from an original front image, optionally with left, back and right views of the same subject at consistent height and framing. Pass each view in its named slot; never invent views or substitute screenshots. Choose mesh and texture budgets for the intended use. The output is a 3D model, so do not send it to image or video tools.",
"parameterDocs": {
"sourceImageIndex": "Front view; negative indices select uploads.",
"leftViewImageIndex": "Subject own left side toward camera (subject faces screen-left).",
"backViewImageIndex": "Subject seen from behind.",
"rightViewImageIndex": "Subject own right side toward camera (subject faces screen-right)."
}
},
{
"contractId": "remove_background_v1",
"version": "1.0.0",
"toolName": "remove_background",
"baseDescription": "Use BiRefNet to remove an existing image background while preserving the original foreground. No prompt is needed. Return a transparent PNG by default, or an alpha mask when applyMask=false.",
"parameterDocs": {
"sourceImageIndex": "Original image to isolate.",
"applyMask": "Default true: transparent cutout; false: mask."
}
},
{
"contractId": "segment_image_v1",
"version": "1.0.0",
"toolName": "segment_image",
"baseDescription": "Select objects with SAM 3 using an object description, normalized original-image points, or boxes. Text can combine with boxes. Points can combine with at most one positive box and never with text. Output a binary mask by default or an original-pixel cutout with applyMask=true; do not repaint the source.",
"parameterDocs": {
"sourceImageIndex": "Original image to select from.",
"maxInstances": "Keep the strongest N selections (1–16).",
"applyMask": "True returns a cutout; false returns a mask."
}
},
{
"contractId": "restore_photo_v1",
"version": "1.0.0",
"toolName": "restore_photo",
"baseDescription": "restore_photo edits or restores the ORIGINAL uploaded photograph. Use this for the first\nrestoration/edit on an upload, or when the user explicitly asks to start over from the\noriginal/source photo. Use refine_result for follow-up edits to an existing generated result.\n\nFor faithful restoration or a bounded repair, preserve the original people and genuinely\nuntargeted source content, including age appearance, pose and composition where unaffected\nby the requested change. A requested artistic transformation follows the brief's scope\nand recognizable identity in its new medium, not a mandatory unchanged-feature inventory.\n\nUse Dynamic Prompt syntax only when the user explicitly asks to compare multiple restoration\napproaches. Default restoration batches should keep the same prompt and vary only by seed.\nIf the user only wants a larger, higher-resolution copy without restoration or other creative\nchanges, use upscale_image instead. restore_photo is a generative edit and is not a substitute\nfor deterministic upscaling.",
"parameterDocs": {
"prompt": "Natural-language edit/restoration prompt. Preserve recognizable people and genuinely untargeted source details; realize the requested changes without adding universal physical-feature locks.",
"numberOfVariations": "Use 1 unless the user explicitly asks for multiple outputs or comparison options.",
"scale": "Set only when the user asks to upscale, enlarge, or increase resolution.",
"quality": "Omit unless the user explicitly asks for fast or high quality."
}
},
{
"contractId": "upscale_image_v1",
"version": "1.1.0",
"toolName": "upscale_image",
"baseDescription": "upscale_image performs promptless, deterministic NVIDIA RTX VSR enlargement of exactly one\nuploaded or generated image. Use it when the user asks for a larger copy, higher resolution,\n2x/3x/4x enlargement, 4K/8K/16K output, or more pixels while preserving the source composition.\n\nDo not invent a prompt and do not route a pure upscale through restore_photo, refine_result,\nedit_image, or apply_style. Those tools are generative and can change image content.\n\nOmit sourceImageIndex to use the latest generated image, falling back to the first upload.\nUse zero-based non-negative indices for generated results; -1 selects the first upload and\n-2 the second upload. Set either scale (2, 3, or 4) or targetLongestEdge (512-15360).\ntargetLongestEdge takes precedence. Never request a target at or below the source size.\nBoth 8px-aligned output edges must remain between 512 and 15360px. If a wide or tall source\nneeds a larger target to preserve its aspect ratio, use the minimum target returned by the tool.",
"parameterDocs": {
"sourceImageIndex": "Omit for the latest generated image, then first upload. Generated results are zero-based; -1/-2 select uploaded images.",
"scale": "Integer enlargement factor 2, 3, or 4. Defaults to 2 and is ignored when targetLongestEdge is set. A too-small result is rejected rather than stretched to the 512px edge minimum.",
"targetLongestEdge": "Explicit output longest edge in pixels, 512-15360. Use 7680 for 8K or 15360 for the 16K maximum. It must be larger than the source, and large enough that the other 8px-aligned edge remains at least 512px; aspect ratio is preserved."
}
},
{
"contractId": "upscale_video_v1",
"version": "1.1.0",
"toolName": "upscale_video",
"baseDescription": "upscale_video performs promptless, deterministic FlashVSR super-resolution of exactly one\nuploaded or generated video. Use it when the user asks to upscale, enlarge, sharpen, or increase\nthe resolution of an existing video, or wants a 1080p, 1440p, 2K, or HD copy of it. The output\nkeeps every source frame, the exact frame rate, the full aspect ratio, and the original audio.\n\nDo not invent a prompt and do not route a pure video upscale through video_to_video,\ngenerate_video, extend_video, or replace_video_segment; those tools re-render or edit content.\nUse video_to_video only when the user explicitly names a generative model such as Seedance for\nthe re-render. Do not use upscale_image for videos.\n\nOmit sourceVideoIndex to use the latest generated video, falling back to the most recent upload.\nUse zero-based non-negative indices for generated videos; -1 selects the first uploaded video\nand -2 the second. targetResolution is the output short edge: omit it for 1440p (or 1080p when\nthe source is too small for 1440p), and set 1080 when the user asks for 1080p or Full HD.\nThe output is at most twice the source size, so 1440p needs a source short edge of 720-768px\nand 1080p needs 540-768px. Sources must also be at most about 1344x768 pixels (768x1344 in\nportrait), 1-60 fps, and 100 MB. The server sets the maximum clip length and rejects a source\nthat is too long; never quote a length limit yourself. If the tool reports that the source is too\nlong or outside these limits, relay that error to the user instead of switching to a generative\nvideo tool. It cannot produce 4K or any size above 1440p: when the user asks for one, say so and\noffer 1440p instead of silently delivering less.\n\nThe defaults give the most stable result. Set detailPreference to sharper only when the user\nasks for a sharper, crisper, or more detailed upscale, and processingSpeed to faster only when\nthey ask for a quicker one. Leave seed out unless the user gives a seed or asks for a different\nor random variation (-1 is random). None of these options changes the price.",
"parameterDocs": {
"sourceVideoIndex": "Omit for the latest generated video, then the most recent upload. Generated videos are zero-based; -1/-2 select uploaded videos.",
"targetResolution": "Output short edge in pixels: 1440 or 1080. Omit for the default (1440, or 1080 for sources under 720px); set 1080 when the user asks for 1080p or Full HD.",
"detailPreference": "stable (default) or sharper. Set sharper only when the user asks for a sharper, crisper, or more detailed result.",
"processingSpeed": "stable (default) or faster. Set faster only when the user asks for a quicker upscale.",
"seed": "Omit for the repeatable default 0. -1 is random; otherwise an integer 0-4294967295 the user gave."
}
},
{
"contractId": "apply_style_v1",
"version": "1.0.0",
"toolName": "apply_style",
"baseDescription": "apply_style transfers an artistic style, era, franchise, medium, or photographic look onto\nan uploaded or generated image. It automatically uses the latest result unless the user\nspecifies a result number or asks for the original upload.\n\nRealize the requested visual language, including its implied shape, proportion and material\nchanges. A style donor does not silently replace the intended individual. Express likeness\nwithin the requested style. Preserve pose and composition only where the brief leaves\nthem untargeted; its implied shape, proportion and framing changes remain part of the style.\n\nUse refine_result instead when the user wants a targeted non-style edit to an existing\nresult. Use restore_photo only when they explicitly want to restart from the original upload.",
"parameterDocs": {
"prompt": "Style-transfer prompt. Name the requested visual language and express recognizable identity within it when intended. Honor explicit locks and preserve genuinely untargeted content.",
"sourceImageIndex": "Omit for the latest result. Use -1 only when the user explicitly says original/source upload.",
"scale": "Set only when the user asks to upscale, enlarge, or increase resolution."
}
},
{
"contractId": "refine_result_v1",
"version": "1.0.0",
"toolName": "refine_result",
"baseDescription": "refine_result is the default follow-up image-edit tool after generated results exist. Use it\nfor targeted changes to a prior result: color, brightness, sharpening, background changes,\nobject edits, further restoration, or small creative adjustments.\n\nDescribe only the delta. The source image already contains the subject, composition, and\nmost details. Do not rewrite the whole image unless the user asks for a broad transformation.\nKeep a referenced person recognizable when they are meant to remain the same individual.\nA broad transformation may change physical appearance, pose or framing as its brief implies;\npreserve explicitly fixed requirements and genuinely untargeted details.\n\nUse restore_photo instead only when the user explicitly asks to start over from the original\nupload. Use sourceImageIndex only when the user names a specific result.",
"parameterDocs": {
"prompt": "Targeted refinement or requested transformation, with clear source identity when relevant and preservation of explicitly fixed or genuinely untargeted content.",
"sourceImageIndex": "Omit for the latest relevant result unless the user names a specific image number.",
"numberOfVariations": "Use 1 unless the user asks to compare multiple refinement options."
}
},
{
"contractId": "orbit_video_v1",
"version": "1.0.0",
"toolName": "orbit_video",
"baseDescription": "orbit_video is a self-contained pipeline that handles angle generation, video transitions,\nand stitching internally. If the user uploaded an image, call orbit_video directly — it uses\nthe upload as the front view. If no image exists yet, generate one front-view image first,\nthen call orbit_video. Avoid pre-generating multiple angles or variations for orbit_video\nunless the user explicitly asked to review custom source angles before orbiting.\n\nORBIT DIALOGUE: When the user wants spoken dialogue in an orbit video, use the\ndialogue parameter rather than prompt. Dialogue goes in the specified segment — put\nmotion/foley in prompt. If the user says \"only in the first segment\" or \"just at the start\",\nset dialogueSegment=0 (default). Never put dialogue text in the prompt parameter — it will\nbe duplicated across all segments.\n\nORBIT ANGLES: Do NOT send the angles parameter for standard 360° orbits — omit it entirely.\nThe default (right side view, back view, left side view at 90° increments) is correct for all\nnormal orbit requests. Only send angles when the user explicitly asks for specific azimuth\npositions (e.g. \"show me from the front-right and back-left only\") or a partial orbit.\n\nORBIT DIALOGUE UPDATE: For dialogue in multiple/every orbit segment, before every 90-degree\nturn, or with per-turn sequence numbers, use the dialogues array instead of the single dialogue\nparameter. Default 360-degree orbit has 4 transitions, so provide 4 short lines in order; leave\nprompt for subject, action, ambient audio, and foley only. Preserve the real names from the\nrequest/prior result; do not invent placeholder speaker tags. For a couple/persona request\nphrased as \"us\", \"we\", or \"my wife and I\", each per-turn line should make the named people\nspeak together. When the user picks a generated image by 1-based number (\"number 3\",\n\"use #3\"), pass sourceImageIndex as that number minus one (number 3 -> sourceImageIndex=2)\ninstead of omitting it.",
"parameterDocs": {
"dialogue": "Spoken dialogue for the first/default orbit segment. Do NOT put dialogue in prompt — it repeats across all segments.",
"dialogues": "Per-segment dialogue lines array. Use for multi-segment dialogue (4 lines for full 360° orbit).",
"dialogueSegment": "Which orbit segment gets the dialogue (0-based). Default 0 = first segment.",
"angles": "Omit for standard 360° orbits. Only set for explicit azimuth positions or partial orbits.",
"sourceImageIndex": "Use uploaded image if present. If user picks by 1-based number, subtract 1."
}
},
{
"contractId": "animate_photo_v1",
"version": "1.3.1",
"toolName": "animate_photo",
"baseDescription": "animate_photo produces video from one or more source images using LTX 2.5 by default,\nwith LTX 2.3 retained as a rollback option and for Persona Voice identity workflows.\nUse videoModel=\"wan3.0-video\" when the user explicitly requests Wan 3 first-frame or\nfirst-and-last-frame generation. Wan 3 accepts one start frame and at most one end frame,\nrenders 2-30 seconds at fixed 30 fps, and supports 480P/720P/1080P output with native audio.\n\nVIDEO PROMPT QUOTING: Mark every spoken line with its speaker and a verb of speech, or a\nspeaker tag outside the quotes, e.g. CHARACTER: \"We made it.\" Put text that must appear on\nscreen in double quotes after \"reads\", e.g. a sign that reads \"OPEN 24H\", so the model can\ntell it from speech. Include logos and readable text whenever the user asks for them.\n\nDIALOGUE DURATION: Spoken dialogue in video prompts must fit the clip duration. Estimate\nat 3 words per second for natural cinematic delivery, plus ~1 second per acting beat\n(pauses, gestures, glances between lines). If the user did NOT explicitly request a specific\nduration (using default 5s), extend the duration to fit the dialogue (max 20s). If the user\nfixed the duration and their own words do not fit, keep every word: tell the user the line\nneeds about N seconds and offer to lengthen the clip or split it. Shorten only lines you wrote.\nCheck: total dialogue words ÷ 3 + beat count ≤ clip duration.\n\nLATEST GENERATED IMAGE FOLLOW-UP: When the newest user turn asks to animate, make a video,\nor make a clip from a generated image/result (for example \"the apple\", \"this one\",\n\"the latest image\"), use animate_photo with that latest generated image. Do not inherit an\nolder Seedance model, resolution, or duration from an unrelated prior turn unless the newest\nuser turn explicitly says Seedance or confirms an immediately suggested Seedance video stage.\nLTX supports exact 2-20s durations, so honor requests like 3s exactly.\n\nWORD BUDGET PER CLIP: The handler REJECTS clips whose spoken dialogue exceeds the budget\n— there is NO auto-trim, so plan dialogue lengths up-front. Hard maximum is 3.75 spoken\nwords per second. Ceilings: 5s = 18 words, 6s = 22 words, 8s = 30 words, 10s = 37 words,\n15s = 56 words, 20s = 75 words. Aim below these ceilings. If a scene's dialogue won't fit,\nraise the per-clip duration or split it across segments, keeping the user's words verbatim\n(shorten only lines you wrote) — do NOT submit and hope it works. Spoken words inside double\nquotes count toward the budget; speaker tags\nand visual/action prose are free.\n\nBATCH VIDEO PER-CLIP DURATION: For a multi-segment animate_photo batch\n(sourceImageIndices + prompts) when the user states a TOTAL video length but NO per-clip\nlength, target 15 seconds per clip when dialogue is involved, and pass that duration\nexplicitly. Example: 60s total → 4 segments × 15s, NOT 6×10s or 12×5s. There is NO 3-clip\nbatch cap: sourceImageIndices supports up to 16 clips, so keep one planned batch together\nunless the user explicitly wants isolated projects or per-output settings require it.\nDo NOT split a planned 15s dialogue scene into multiple\nshorter clips just because a retry complains about word budget; keep duration=15 and shorten\nonly lines you wrote. A user's own line keeps its words: raise the duration (up to 20s) or\ntell the user it needs about N seconds. Use 5s clips only for single short motion beats or one\nvery short spoken phrase.\nIf the user explicitly specifies a per-clip duration, honor that instead.\n\nN-VERSIONS-OF-A-VIDEO PATTERN: Avoid sequential animate_photo calls for N outputs.\nPrefer one Dynamic Prompt project when only prompt text varies, and reserve\nsourceImageIndices multi-project fan-out for source/end asset differences, isolated retry\nlifecycle, or other per-output parameter differences. Flavors:\n(A0) SAME SOURCE / PROMPT-ONLY TAKES — use sourceImageIndex, numberOfVariations=N,\nand ONE Dynamic Prompt branch in prompt: \"{full prompt 1|full prompt 2|...}\". This\nsubmits shared settings and source assets once; Sogni socket creates N jobs in one project.\n(A) SHARED CONTENT — one edit_image/generate_image call with numberOfVariations=N + {|}\nDynamic Prompts to make N distinct source images, then ONE animate_photo call with\nsourceImageIndices=[start..start+N-1] and a single shared prompt.\n(B) PER-CLIP ASSET WIRING — when each clip has DIFFERENT source images, end frames,\naudio windows, durations, dimensions, or other non-prompt parameters,\npass BOTH sourceImageIndices AND prompts (array of N strings, one per clip) in the SAME\nsingle animate_photo call. The top-level prompt is still required — pass a brief batch summary.\nFor explicit last/end-frame-only batches, reuse the image through sourceImageIndices but set\nframeRole=\"end\" and omit endImageIndex/endImageIndices. This means each listed image is the\nlast frame for its corresponding clip and no first/start frame is supplied.\nIf the user explicitly asks for Dynamic Prompt / Dynamic Template syntax, prefer flavor A0\nwhenever every output uses the same source/end assets and shared settings, even if they also\nask to stitch the completed clips afterward.\n\nCRITICAL: sourceImageIndices values MUST be read from the latest edit_image/generate_image\ntool result's startIndex field — if startIndex=3 and 4 images were generated, pass\nsourceImageIndices=[3,4,5,6], NOT [0,1,2,3]. Negative indices refer to uploaded images:\n-1 first upload, -2 second upload, -3 third upload. Use repeated -1 entries only when\nintentionally reusing the primary uploaded image. When prompts is supplied, prompts.length\nMUST equal sourceImageIndices.length.\n\nSEEDANCE UPLOADED STORYBOARD DEFAULT: If the user uploaded a storyboard, shot sheet,\nor visual trailer board and asks to make a trailer/video/movie/clip from it, do NOT use\nanimate_photo on the board image and do NOT split it into four LTX clips. Use generate_video\nwith Seedance referenceImageIndices for one continuous clip unless the user explicitly asks\nfor separate LTX clips or first-frame/last-frame animation.\n\nSCREENPLAY / STORYBOARD ANIMATE RULE: For full storyboard projects, use one\nanimate_photo batch with sourceImageIndices + prompts so each clip keeps its own exact\nscene text, stable cast anchors, and screenplay-style speaker-tagged dialogue, and all video\nclips render in parallel. Every speaking clip's video prompt must include that clip's actual\nquoted dialogue, not placeholders such as \"while speaking\", \"dialogue begins\", \"explaining\",\nor \"final line lands\". If each generated scene keyframe should be both the first and last frame\nof its own stitched segment, call animate_photo with sourceImageIndices=[start..end],\nframeRole=\"both\", prompts=[...], and OMIT endImageIndex/endImageIndices so the handler\nuses each source as its own end frame.\n\nUPLOADED REFERENCE LOOPED PROMPT-ONLY TAKES: When the user supplies one uploaded reference\nimage and asks for N clips that all reuse that same image as BOTH the first frame and last\nframe, with only the action/prompt text varying, do it in ONE Dynamic Prompt project:\nsourceImageIndex=-1, frameRole=\"both\", endImageIndex=-1, numberOfVariations=N, and prompt\nas ONE branch: \"{full prompt 1|full prompt 2|...|full prompt N}\". Do NOT use\nsourceImageIndices=[-1,-1,...] or prompts=[...] for this prompt-only shape. After the\nsingle animate_photo project completes, call stitch_video with the returned video indices\nif the user requested a final stitched video.\nEach Dynamic Prompt option must be a complete natural-language motion prompt for the video\nmodel. Do not include orchestration labels such as \"clip 1 of N\", \"overall request context\",\n\"use the uploaded image as the source frame\", \"follow the user request\", or \"make this clip\ndistinct\"; the attached first/last-frame image is already wired through arguments.\nKeep explicit shared constraints outside the branch before \"{...}\" and honor them inside every\noption, such as a locked/static camera, a set pace, the same wardrobe, or silent expression-only\nphysical performance when requested. Non-speaking expressions such as yawns, smiles, kisses, or shy\nmouth-covering gestures are acceptable when they are the requested physical performance; do not\nturn them into speech, singing, or dialogue-like lip motion.\nIf the user gives avoid/no/don't constraints for a Dynamic Prompt batch, the shared prefix before\nthe branch must include their positive equivalents, such as single-subject empty background, clean\nblank surfaces, crisp sharp focus, same room/layout continuity, silent expression-only physical\nperformance, and natural anatomically consistent hands. Do not place\nthose constraints only in negativePrompt or omit them from prompt.\nFor videoModel=\"wan22\", write motion-only visual prompts. WAN 2.2 does not generate audio,\nso omit soundtrack, ambience, room tone, music, hums, sighs, spoken words, voice, and SFX cues.\nFor videoModel=\"wan22\", \"ltx25\", and \"ltx23\", the prompt field is the positive prompt. Translate user\navoid/no/don't constraints into affirmative production constraints instead of copying negative\nphrasing into prompt. Examples: \"no people in background\" -> single subject focus with an empty\nbackground; \"no text\" -> clean blank surfaces; \"don't make it blurry\" -> crisp sharp focus;\n\"no weird hands\" -> natural anatomically consistent hands; \"don't change the room\" -> the same\nroom and layout remain consistent. Preserve exact quoted visible text or dialogue when the user\nexplicitly requests it.\n\nUPLOADED REFERENCE LOOPED SCRIPTED SKITS: When the user supplies one uploaded reference image\nand asks for several scripted/storyboard/dialogue segments to reuse that same image as BOTH\nthe first frame and last frame of each segment before stitching, do it in ONE animate_photo call:\nsourceImageIndices=[-1,-1,...], frameRole=\"both\", endImageIndex=-1 (or matching\nendImageIndices=[-1,-1,...]), duration equal to the requested per-segment duration, and\nprompts=[one full scene prompt per segment]. Each prompt must preserve the exact screenplay\nspeaker tags and quoted dialogue from that scene, e.g. HOST: \"...\" GUEST: \"...\". Do not\ndrop speaker tags, convert them to generic narration, omit the last-frame contract, analyze\nthe image first, generate new keyframes first, or split the batch into serial calls. After\nthe single animate_photo batch completes, call stitch_video with the returned video indices.\n\nFor adjacent transition chains: N images create N-1 clips — call animate_photo with\nframeRole=\"both\", sourceImageIndices=[start..end-1], endImageIndices=[start+1..end],\nprompts=[one transition prompt per adjacent pair], then stitch_video. If 5 uploaded images\nare the keyframe sequence, use sourceImageIndices=[-1,-2,-3,-4],\nendImageIndices=[-2,-3,-4,-5], frameRole=\"both\", prompts length 4, then stitch_video.\nDo NOT set endImageIndex=-1 in generated-keyframe patterns — that means every clip ends\non the primary uploaded image.\n\nUPLOADED FIRST-FRAME/LAST-FRAME TRANSITION CHAINS: If the user uploads multiple images\nand asks for a video that transitions from image to image, changes country/version every\nN seconds, or says to use first-frame/last-frame for each pair, call animate_photo directly.\nDo not call edit_image, generate_image, analyze_image, or map_assets_for_model first — the\nuploaded images are already the keyframes. For N uploaded images, create N-1 adjacent clips\nunless the user explicitly asks for a loop back to the first image. Use per-clip duration\nfrom \"every N seconds\" when present; otherwise divide the requested total by the number of\nadjacent clips. After animate_photo returns the batch videos, call stitch_video with\nthose video indices before finalizing unless the user explicitly asked to keep separate clips only.\n\nMINIMAX H3 TWO-STAGE OUTPUT: 1080p and 2K MiniMax H3 delivery is its own selector, not an option.\n\"minimax-h3-fasth3-i2v-turbo-2stage\" (first frame) and \"minimax-h3-fasth3-flf2v-turbo-2stage\"\n(first and last frame, frameRole=\"both\" with an end frame) are the two-stage FastH3 engine: FastH3\nrenders the canvas, then the worker enlarges it 2x and refines it, so the clip is delivered at\ntwice the canvas width and height with the same length and audio. targetResolution names the\ndelivered class: 1080 renders a 544px short-edge canvas (960x544 becomes 1920x1088) for 10 Spark\nper second, 1440 or omitted renders the 768p canvas for 2K (1344x768 becomes 2688x1536) for 16\nSpark per second, and 720 renders a 384px canvas (672x384 becomes 1344x768) for the regular\nFastH3 price of 4 Spark per second. The estimate prices every request. The source aspect is kept\n(a portrait source at 1080 renders 544x960 and is delivered at 1088x1920). They take the same\nprompt contract, durations and LoRAs as their FastH3 selectors. Choose them when the user asks for\n1080p, 1440p or 2K MiniMax H3 output, for two-stage output, or for the sharpest/best H3 quality;\nfor ordinary 768p FastH3 output keep the regular FastH3 selector at targetResolution 768. Never\nset 4K for H3.\n\nMINIMAX H3 KEYFRAMES: when the user wants one MiniMax H3 clip to pass through extra images at chosen moments, pass keyframes=[{imageIndex, atSeconds}] (up to 8; imageIndex indexed like endImageIndex) on that one call, and make the clip long enough that every keyframe falls strictly inside it (set duration when the default would end too soon). Say in the prompt what each keyframe shows at its time, and start a new shot at a keyframe that changes the angle, place or light. Keyframes add to the first and last frame and are not references, but the prompt names each one <Picture N>, numbered after the first/last-frame or reference pictures in time order. Two are included in the price; each additional keyframe adds a little. Only MiniMax H3 selectors take them (see the keyframes argument for which).\nOn animate_photo keyframes work with every MiniMax H3 image-to-video and first-and-last-frame selector,\nwith any frameRole; the first and last frames stay in sourceImageIndex and endImageIndex. They are the\nH3 way to make one continuous clip pass through several images. Without an explicit MiniMax H3 request,\na multi-image sequence keeps the adjacent-clip chain described above.",
"parameterDocs": {
"keyframes": "MiniMax H3 only. Pin up to 8 images at exact moments inside the video, in addition to the first/last frame. Each item is {imageIndex, atSeconds}: imageIndex uses the endImageIndex convention (negative = uploads, 0+ = generated results); atSeconds is when the video should land on that image. Keyframes must fall strictly inside the clip (not on the first or last frame) and at distinct times. Describe what each keyframe shows in the prompt at its time; a keyframe with a new angle, place or light starts a new shot. Two keyframes are included in the price; each additional keyframe adds a little. On animate_photo every MiniMax H3 image-to-video and first-and-last-frame selector takes keyframes, with any frameRole; the first and last frames stay in sourceImageIndex and endImageIndex. When one continuous H3 clip should pass through extra images, pass them here on that single call instead of chaining sourceImageIndices clips.",
"sourceImageIndices": "Batch source image indices. Read startIndex from prior generate_image/edit_image result. Negative = uploaded images (-1 = first upload). May be paired with frameRole=\"end\" only for explicit last/end-frame-only fan-out.",
"prompts": "Per-clip prompt array. Length MUST equal sourceImageIndices.length when both are set.",
"duration": "Per-clip duration in seconds. Target 15s when dialogue is involved and total length is given without per-clip spec.",
"frameRole": "Set to \"end\" for explicit last/end-frame-only fan-out; set to \"both\" for first+last frame transitions using sourceImageIndices + endImageIndices.",
"endImageIndices": "End frames for adjacent-chain transitions. N images → N-1 clips."
}
},
{
"contractId": "change_angle_v1",
"version": "1.0.0",
"toolName": "change_angle",
"baseDescription": "change_angle creates a new still image from a different camera perspective. Use when the\nuser asks for a left/right/back/three-quarter/front view, elevated/low-angle view, close-up,\nmedium shot, or wide shot of an existing image subject.\n\nThe description must be exactly one azimuth, one elevation, and one distance phrase in the\ntool schema format. Default unspecified elevation to eye-level shot and distance to medium\nshot. Use the latest result unless the user specifies another source or says original.\n\nUse orbit_video for a full video orbit. Do not pre-generate angles for orbit_video; that tool\nowns its own angle pipeline.",
"parameterDocs": {
"description": "Exact format: \"[azimuth] [elevation] [distance]\". Pick one value from each schema category.",
"sourceImageIndex": "Omit for latest result. Use -1 only when the user explicitly says original/source upload.",
"loraStrength": "Omit unless the user explicitly asks to control the strength of the angle change."
}
},
{
"contractId": "generate_video_v1",
"version": "1.6.2",
"toolName": "generate_video",
"baseDescription": "generate_video produces text-to-video clips and multimodal reference videos.\nUse for text-only video generation with no source image input. For Seedance and Wan 3, also\nuse this tool when uploaded/generated images, videos, or audio are loose references. Use\nanimate_photo when a source image must become the first frame of an LTX/WAN animation.\n\nWAN 3: Use videoModel=\"wan3.0-video\" for explicit Wan 3 requests. The same canonical model\nsupports text, up to 10 reference images, 5 reference videos, and 5 reference audios. Refer\nto loose assets in English prompts as Image 1, Video 1, and Audio 1, numbered independently\nby type. Do not bracket or @-prefix these identifiers. Wan 3 renders 2-30 seconds at fixed\n30 fps, offers 480P/720P/1080P and 16:9/4:3/1:1/3:4/9:16, and can toggle native audio.\n\nMY PERSONAS: When the user means themselves or names a saved Persona and wants it on MiniMax H3\nreference-to-video, Seedance or Wan 3, call resolve_personas, then pass the resolved persona\nreference images straight in as referenceImageIndices (the negative indices resolve_personas\nreports), with no edit_image step. Every clip carries its own references. Bind each persona to\nits images in the prompt with the model's tokens: @Image1 on Seedance, <Picture 1> on MiniMax H3,\nImage 1 on Wan 3. On LTX, a persona video animates an edit_image still with animate_photo.\n\nMINIMAX H3 SOURCE AUDIO: Every H3 R2V call with a reference video or audio must set\nsourceAudioPolicy. A specific/original/trending song is immutable: use reuse_exact, author\nthe official audio reuse task plus fully_copy, keep choreography on explicit source times,\nand stream-copy/remux the original soundtrack after rendering. Never substitute, recompose,\nremix, or add a copyright-avoidance mutation. H3 reference videos must themselves be exactly\n24 fps; normalize other rates without changing duration/audio timing before submission.\nRef2VA cannot guarantee edit-level beat sync.\n\nSEEDANCE UPLOADED STORYBOARD DEFAULT: When the user uploads a storyboard, shot sheet,\nmood board, or trailer concept image and asks to make a movie trailer/video/clip from it,\ndefault to one Seedance generate_video call with referenceImageIndices=[-1]. Do not first\nextract panels with edit_image, do not generate replacement keyframes, and do not make four\nseparate LTX animate_photo clips unless the user explicitly asks for separate clips or LTX.\nUse seedance2 when premium Spark access is available; if premium access is unavailable,\nexplain the limitation or use the best non-Seedance fallback the user accepts.\n\nEXACT / INCLUDED VIDEO PROMPTS: If the user asks for a Seedance video using uploaded or\ngenerated references and says to use a prompt exactly, pass only that literal quoted prompt\nto generate_video and set skipPromptProcessing=true plus expandPrompt=false. Do not treat\nwords inside the literal prompt, such as storyboard, script, thumbnails, or panels, as a\nrequest to create a storyboard image. If the user includes a timecoded script inside a\nvideo request, keep it in the generate_video prompt. Explicit constraints like no storyboard\npanels, no subtitles, or no captions are constraints on the video render, not instructions\nto call edit_image or generate_image.\n\nSTORYTELLING / COMMERCIAL / TRAILER PROMPTS: For creative video requests, turn the brief\ninto timed, causally connected visual beats before writing the final prompt. Default social\nvideo is 15s with a strong first 1-2s, visible escalation, and payoff; use 9:16 only when the\nuser names a vertical platform or ratio. Commercials should show audience desire/problem,\ntransformation, and proof/benefit. Trailers should follow hook → world → disruption →\nescalation → reveal. Add a CTA, brand beat, or title card only when the user asked for one or\nthe brief names a product or brand to sell.\nEvery beat must be generatable: subject, setting, action, camera, lighting, audio, and text\nrole where relevant. Avoid vague \"cinematic\" filler, feature dumps, and beautiful images with\nno visible change.\n\nVIDEO PROMPT QUOTING: Mark every spoken line with its speaker and a verb of speech. Put text\nthat must appear on screen in double quotes after \"reads\", e.g. a sign that reads \"OPEN 24H\".\nInclude logos and readable text whenever the user asks for them.\n\nSTORYBOARD TEXT: Structural headings, section numbers, slide titles, panel titles, and\ncaptions in storyboard references may become short audio-only narration/VO or\nkey-message beats, but they are not subtitles, title cards, lower thirds, or visible\noverlays unless the user explicitly asks for visible text, on-screen text, a title\ncard, subtitle, lower third, signage, or CTA. Keep narration as separate brief phrases\nwith pauses; do not concatenate storyboard labels into run-on voiceover.\n\nDIALOGUE DURATION: Spoken dialogue must fit the clip. Estimate 3 words per second\nnatural delivery plus ~1s per acting beat. Hard maximum 3.75 words/second.\nCheck: dialogue words ÷ 3 + beats ≤ duration. Do not submit oversized dialogue.\n\nLATEST USER DURATION WINS: In follow-up turns, use the newest duration the user states,\neven if a previous assistant message mentioned a longer script/runtime. For example, if\nhistory says \"the full script is 66 seconds\" but the user now says \"do a 30 second version\",\ngenerate the 30 second version. Do not ask a clarification question just because history\ncontains another duration; treat the latest user request as the override.\n\nSEEDANCE SHORT-DURATION LIMIT: Seedance supports 4-15s clips. If the user explicitly asks\nfor Seedance below 4s, do not silently round up. Ask whether they prefer a 4s Seedance clip\nor an exact-duration LTX clip. If the user did not explicitly ask for Seedance, choose the\nmodel/tool that can satisfy the requested duration exactly.\n\nPrefer Balanced R2V (minimax-h3-r2v-balanced) for MiniMax reference-to-video. For two-stage, 1080p or 2K output, prefer minimax-h3-r2v-balanced-2stage. Use Standard, LightX2V Turbo, or FastH3 Omni R2V only when explicitly requested.\nMINIMAX H3 TWO-STAGE OUTPUT: 1080p and 2K MiniMax H3 delivery is its own selector, not an option.\n\"minimax-h3-fasth3-t2v-turbo-2stage\" is the two-stage FastH3 engine: FastH3 renders the canvas,\nthen the worker enlarges it 2x and refines it, so the clip is delivered at twice the canvas width\nand height with the same length and audio. targetResolution names the delivered class: 1080\nrenders a 544px short-edge canvas (960x544 becomes 1920x1088) for 10 Spark per second, 1440 or\nomitted renders the 768p canvas for 2K (1344x768 becomes 2688x1536) for 16 Spark per second, and\n720 renders a 384px canvas (672x384 becomes 1344x768) for the regular FastH3 price of 4\nSpark per second. The estimate prices every request. It takes the same prompt contract, durations\nand LoRAs as \"minimax-h3-fasth3-t2v-turbo\". Choose it when the user asks for 1080p, 1440p or 2K\nMiniMax H3 output, for two-stage output, or for the sharpest/best H3 quality; for ordinary 768p\nFastH3 output keep the regular FastH3 selector at targetResolution 768. Never set 4K for H3.\nThe reference-to-video tiers have their own two-stage selectors: \"minimax-h3-r2v-2stage\" (Standard,\n20 steps) and \"minimax-h3-r2v-balanced-2stage\" (Balanced, 8 steps) take exactly the references, prompt\ncontract, durations and LoRAs of \"minimax-h3-r2v\" and \"minimax-h3-r2v-balanced\", deliver twice the\ncanvas, and read targetResolution the same way (1080, 1440 or omitted for 2K, 720); each bills its\ntier's rate plus the two-stage surcharge of the delivered class. Choose the Balanced one for 1080p, 1440p or 2K\nMiniMax H3 reference-to-video output, and the Standard one only when Standard is explicitly requested;\nkeep the one-stage R2V selectors for 768p.\nFastH3 Reference is the FastH3 tier's reference-to-video: \"minimax-h3-fasth3-r2v-turbo\" takes the same\nreferences, prompt contract, durations, catalog LoRAs and Personal LoRAs as \"minimax-h3-r2v\", and its\ntwo-stage form\n\"minimax-h3-fasth3-r2v-turbo-2stage\" reads targetResolution the same way as the other two-stage selectors.\n\nMINIMAX H3 KEYFRAMES: when the user wants one MiniMax H3 clip to pass through extra images at chosen moments, pass keyframes=[{imageIndex, atSeconds}] (up to 8; imageIndex indexed like endImageIndex) on that one call, and make the clip long enough that every keyframe falls strictly inside it (set duration when the default would end too soon). Say in the prompt what each keyframe shows at its time, and start a new shot at a keyframe that changes the angle, place or light. Keyframes add to the first and last frame and are not references, but the prompt names each one <Picture N>, numbered after the first/last-frame or reference pictures in time order. Two are included in the price; each additional keyframe adds a little. Only MiniMax H3 selectors take them (see the keyframes argument for which).\nOn generate_video only the MiniMax H3 reference-to-video selectors take keyframes, never text-to-video.\nKeyframe images are not references: they do not go in referenceImageIndices or the reference map, and\nR2V still needs its own image or video reference. The prompt names each keyframe <Picture N>, numbered\nafter the reference pictures in time order.",
"parameterDocs": {
"keyframes": "MiniMax H3 only. Pin up to 8 images at exact moments inside the video, in addition to the first/last frame. Each item is {imageIndex, atSeconds}: imageIndex uses the endImageIndex convention (negative = uploads, 0+ = generated results); atSeconds is when the video should land on that image. Keyframes must fall strictly inside the clip (not on the first or last frame) and at distinct times. Describe what each keyframe shows in the prompt at its time; a keyframe with a new angle, place or light starts a new shot. Two keyframes are included in the price; each additional keyframe adds a little. On generate_video only the MiniMax H3 reference-to-video selectors (minimax-h3-r2v and its turbo, balanced and two-stage forms) take keyframes; text-to-video never does, and reference-to-video has no first or last frame to pin. Keyframes are not references: they do not go in referenceImageIndices or count toward the reference limits, and R2V still needs its own image or video reference. The prompt names each keyframe <Picture N>, numbered after the reference pictures in time order.",
"prompt": "Video prompt. Quote spoken lines with their speaker; quote on-screen text after \"reads\".",
"duration": "Clip duration in seconds. Plan dialogue word count against the 3.75 words/second ceiling."
}
},
{
"contractId": "edit_image_v1",
"version": "1.0.0",
"toolName": "edit_image",
"baseDescription": "edit_image applies instruction-based edits to uploaded or generated images. Use when\nuploaded or reference images must guide identity or likeness.\n\nAssign clear reference roles: identity, base scene, pose, outfit, style, or environment.\nFor a bounded edit, describe the requested change and retain genuinely untargeted content.\nFor a creative transformation or new composition, describe the intended result and the\nchanges the complete brief implies. Match the selected model's prompt grammar below.\nWhen a referenced person or character is meant to remain the same individual, make the identity source unambiguous and depict that particular individual rather than a generic attractive face or anonymous character. For a bounded edit, change the requested elements and their necessary consequences while keeping genuinely untargeted content stable. For an artistic transformation, carry the individual's recognizable combination of identity signatures into the requested visual language. Interpret the complete brief, including the transformations its medium and character design imply; the user need not enumerate every physical change. Substantial retouching, idealization, exaggerated proportions or nonhuman abstraction can be essential to that result. Facial geometry, skin treatment, age appearance, hair, accessories, expression, pose, framing, costume and facial exposure are governed by the brief and the recognizable outcome, not a universal unchanged-feature inventory or a rule to reveal or cover the face. Honor explicitly fixed requirements. Treat source observations as descriptive evidence to interpret, not immutable locks; keep different people's identities distinct. Turn this reasoning into concrete, task-specific art direction without copying this guidance or adding a universal identity or beauty paragraph to the render prompt.\n\nKREA IDENTITY EDIT: Use model=\"krea-identity-edit\" whenever an edit of a referenced\nperson or character must keep likeness or character identity while changing clothing,\nhair or makeup, pose or position, face/head/body, background, lighting, or visual style.\nInfer that semantic intent in any language; never route from keyword or regex matching.\nAlso use it for a non-Pro single-character sheet. An explicitly requested model always\nwins. Use model=\"dark-beast-krea2-identity-edit\" only when the user explicitly requests\nthat model, its uncensored/community variant, or dark_beast_krea2_identity_edit_v1_2.\nThese models require one reference image, accept up to two context images, and work best\nat 512-2048 px. Let the model tier and worker choose current execution defaults, and do\nnot use negative prompts. Put the primary scene/base image first and an optional\nperson/detail reference second; reference them with context_image_0 and context_image_1\nwhen model_ref tokens are needed.\n\nFLUX 3 IMAGE KLEIN: Use model=\"flux-3-klein\" when the user asks for FLUX 3 or FLUX 3 Image\nKlein. It accepts 1-10 reference images and works at 256-4096 px, including 4K. Guidance is\nfixed and a negative prompt has no effect, so do not send one. Unlike the Krea delta\ninstruction, describe the whole result as a full scene caption (subject, framing, background,\nlighting) that folds the requested change into a description of the reference, and refer to\nreferences in order as the first image, the second image, and so on.\n\nKREA 2 IDENTITY EDIT PROMPTING: Use a concise 1-4 sentence delta instruction instead of\nthe generic 50-200 word expansion. Name the requested change and only the details that\nmust remain fixed; do not restate the whole image or dump a facial-feature inventory.\nWith two references, assign their roles compactly: base scene/image first, then the\nperson/detail/outfit/pose/style reference. Longer structured prompts remain appropriate\nfor character sheets, grids, editorial layouts, or exact visible text.\n\nUPLOADED IMAGE VARIANT SETS: When the user supplies a photo/portrait/reference image and\nasks for N distinct generated images deriving from that source while changing paired\nper-output details, prefer one edit_image call with sourceImageIndex=-1,\nnumberOfVariations=N, and ONE Dynamic Prompt branch with N complete options. Each option\nmust be a full concrete image prompt for one output, including the uploaded subject/reference\nanchor, requested pose or placement preservation, the specific changed appearance/style/role,\nclothing or surface details when relevant, setting/background, and any requested label text or\nvisual symbol. If one option is a remade original/preserved source and the rest are themed\nvariants, the original option should explicitly say to preserve the original clothing/wardrobe/outfit\nand background/setting, plus any requested added label, flag, logo, symbol, or prop.\nDo not call generate_image, analyze_image, or multiple serial edit_image calls first.\n\nSELECTION-GATED IMAGE STAGES: If the user asks for N image options and says they will pick\none before a later dance/video/animation, prefer one edit_image call with numberOfVariations=N\nand one Dynamic Prompt branch. After images are created, stop and ask the user to choose\nunless the user explicitly asked to run the later stage immediately.\n\nMULTI-PERSONA (COMBINED): When multiple personas must appear in the SAME scene, make\none edit_image call with all persona faces in one prompt and omit personaName.\nPer-persona splits (one call each with personaName set) are RARE — only when the user\nexplicitly asks for solo images of each person individually.\n\nSTORYBOARD IMAGE BATCH RULE: When rendering scene keyframes from a screenplay/storyboard,\nnumberOfVariations is only the count; the prompt should be one Dynamic Prompt branch with one\nfull keyframe prompt per scene:\n{scene 1 full keyframe prompt|scene 2 full keyframe prompt|...|scene N full keyframe prompt}.\nDo not set numberOfVariations=N with only the first scene prompt — that creates N versions of\nscene 1. For full project requests, one edit_image batch for all scene keyframes, then one\nanimate_photo batch for all video clips in parallel.\nException: if the storyboard/shot sheet is already uploaded and the user asks to make a\ntrailer/video/movie/clip from that uploaded board, do not extract panels or redraw keyframes.\nUse generate_video with Seedance references for one continuous clip unless the user explicitly\nasks for separate image keyframes or a storyboard sheet output.\n\nDIRECT UPLOADED GPT IMAGE STORYBOARD SHEETS: If the user uploaded reference images and\nasks for one finished GPT Image storyboard/keyframe sheet now, call edit_image directly\nwith sourceImageIndex=-1, model=\"gpt-image-2.5-sunburst\", numberOfVariations=1, and the requested\ncanvas/aspect settings. Preserve another explicit GPT Image model named by the user.\nIf the user did not explicitly specify a storyboard page/canvas/sheet\nshape, default the GPT Image 2.5 storyboard sheet pixel dimensions to a balanced grid that hosts\nthe target cell aspect ratio natively (e.g., 12 cells with 9:16 portrait video target -> ~3:4\nportrait sheet around 1728x2304; 12 cells with 16:9 landscape video target -> ~4:3 landscape\nsheet around 2304x1728; 6 cells with 9:16 target -> ~27:32 portrait sheet around 1840x2176). Do\nNOT default the sheet to 2560x1440 landscape when cells are portrait — a landscape sheet with\na portrait-cell grid physically forces cells to ~4:3 landscape and the model will not render\n9:16 portrait rectangles inside it. Keep individual scene-cell/frame areas at the target video\naspect ratio. Do not call map_assets_for_model, analyze_image, generate_image, or a separate\nplanning tool first. The uploaded files are already available as references; describe their\nroles plainly in the edit_image prompt and generate the sheet in that call.\n\nDO NOT USE edit_image FOR UPLOADED REFERENCE LOOPED VIDEO SEGMENTS: If the user says the\nsame uploaded image/reference should be reused as the first frame and last frame of each\nscripted segment/scene/clip before stitching, they are explicitly asking to animate the\nuploaded image, not to generate new storyboard keyframes. Do not call edit_image for that\nrequest. Call animate_photo once with repeated uploaded source indices and per-scene prompts.",
"parameterDocs": {
"sourceImageIndex": "Index of uploaded/generated image. Use -1 for the first uploaded image.",
"numberOfVariations": "Number of output variants. When > 1, use a Dynamic Prompt branch with one complete prompt per output.",
"prompt": "Model-native edit or composition instruction with clear reference roles. Preserve recognizable identity when intended, honor explicit locks, and realize the full requested transformation; use bounded-change preservation only for bounded edits."
}
},
{
"contractId": "generate_image_v1",
"version": "1.1.1",
"toolName": "generate_image",
"baseDescription": "generate_image creates images from text descriptions. Use for text-only image generation;\nuse edit_image when uploaded or reference images must guide identity/likeness.\nException: Z-image, Z-image Turbo, and Krea 2 Turbo image-to-image/enhancement requests\nuse generate_image with model=\"z-turbo\", model=\"z-image\", or model=\"krea-2-turbo\",\nsourceImageIndex=-1, and starting_image_strength; do not route explicit base-model\nZ-image Turbo or Krea 2 Turbo uploaded-image enhancement to edit_image because edit_image\ndoes not expose those base image-to-image models.\n\nMODEL CHOICE: If the user asks for Krea 2 Turbo, choose model=\"krea-2-turbo\". If they ask\nfor MOSS-Image or MOSS-Image SFT, choose model=\"moss-image\" for text-to-image generation.\nFor MOSS 8-step or DMD, choose model=\"moss-image-8step\" with 8 steps and guidance 1.\nBoth MOSS presets are uncensored and support compatible Personal LoRAs.\nMOSS-Image SFT does not accept uploaded image references or perform instruction editing. If they ask\nfor FLUX 3 or FLUX 3 Image Klein, choose model=\"flux-3-klein\". If they ask\nfor Dark Beast Krea 2, choose model=\"dark-beast-krea2\". If they ask for Dark Beast Z-Image\nTurbo, choose model=\"dark-beast-z-turbo\". If they ask for Chroma 1 HD, choose model=\"chroma1-hd\".\nIf they ask for anime or anime-style output without naming a model, choose model=\"one-obsession-v22\".\nBase Z-image and Krea 2 Turbo image-to-image/enhancement requests stay on generate_image with\nsourceImageIndex and starting_image_strength; identity-preserving Krea edits with reference\nphotos use edit_image instead.\n\nBATCH FAN-OUT DEFAULT (READ BEFORE ANYTHING ELSE BELOW):\nWhen the user explicitly asks for N images in the CURRENT turn, set numberOfVariations=N\nin one call. Avoid multiple serial generate_image calls unless the user explicitly wants\nindependent projects, isolated approvals, or per-output settings that cannot share one project.\nDo not omit numberOfVariations and try to \"generate the next one after this finishes\".\nTrigger phrasings:\n\"draw N\", \"make N\", \"give me N\", \"show me N\", \"render N\", \"create N\", \"generate N\",\n\"N more\", \"another N\", \"N as separate\", \"N separate images\", \"N different images\",\n\"N options\", \"N takes\", \"N versions\", \"N variations\", \"N pictures of\",\n\"all at the same time\", \"in parallel\", \"side by side as separate\".\n\nTHE PRIOR TURN DOES NOT ANCHOR THE CURRENT TURN. If the prior assistant turn used\nnumberOfVariations=1 with a composite \"N subjects in one image\" prompt, and the user\nnow says \"draw N more as separate images\" / \"as separate\" / \"separately\", DO NOT carry\nover numberOfVariations=1 from the prior call. The user is correcting that interpretation;\nset numberOfVariations=N for THIS call with one self-contained prompt per image via {|}\nDynamic Prompt branches. The new turn's count + separation language always wins over the\nprevious turn's pattern.\n\nWHEN BATCH FAN-OUT DOES NOT APPLY: numberOfVariations=1 with multiple subjects packed into\nONE prompt is correct only when the user clearly wants a SINGLE composite image (e.g.\n\"draw 2 goats in a meadow\" with no separation language, or explicit \"in one image\" / \"one\npicture of N\" / \"single image\" / \"composite\" / \"sheet\" / \"side-by-side composition\").\n\nIMAGE PROMPT ORDER: [SUBJECT] → [ATTRIBUTES] → [ACTION/POSE] → [CAMERA/FRAMING]\n→ [ENVIRONMENT] → [LIGHTING] → [STYLE/MEDIUM] → [MATERIALS/TEXTURES] →\n[SECONDARY DETAILS]. By default, start with the main subject and concrete observable\nattributes; use mood or atmosphere first only when the user explicitly asks for that shape.\nUse concrete nouns and observable adjectives — \"soft overcast daylight\" not \"nice lighting\".\nGood defaults when user is underspecified: medium shot for portraits, wide shot for\nenvironments, eye-level angle, soft natural light for realism.\n\nDYNAMIC PROMPTS: When numberOfVariations > 1 and distinct content is requested, use\nDynamic Prompt syntax to make each\nvariation meaningfully different — not just seed-different. Syntax: {a|b|c} cycles\nsequentially, {@a|b|c} picks randomly, {~a|b} paired cycling across groups. Rules: (1) Vary\nONLY what the user left unspecified — lock in everything they specified. (2) Match option\ncount to numberOfVariations so every result is unique. (3) Briefly tell the user what you're\nvarying without exposing raw {|} syntax unless the user asks to inspect the prompt.\n(4) Skip when: user wants consistency, prompt is fully\nspecified, user typed their own {|} syntax, or iterating on a specific result. (5) Do not put\nbatch counts or the words \"versions\"/\"variations\" into scene content. Preserve authored\nsubject counts and requested visible words verbatim. The prompt describes one output image;\ntyped count and grouping arguments determine batching, not words inside the prompt.\nLINKED VARIANTS: when multiple attributes must stay paired per result, use ONE top-level\nDynamic Prompt branch with one complete self-contained prompt per output. Do NOT split\nlinked fields into separate Dynamic Prompt groups. Treat every batch-wide requirement\nquantified as \"each\", \"every\", or \"all\" as a hard per-option invariant: repeat it inside\nEVERY option, including identity/pose continuity, clothing/style, the concrete setting, and\nliteral visible names, labels, captions, flags, logos, or symbols. A shared prefix or another\noption is never a substitute for a complete standalone option.\nEach option must name its actual styling, setting, accessories, and requested literal text or\nsymbol. Never emit meta-placeholders such as \"variant-specific background\", \"requested\nsymbol\", \"humorous alternate name\", or \"bake the name and symbol into the image\".\nWhen one option remakes/preserves an original and the others are themed variants, make the\noriginal option equally concrete: specify the original clothing and setting plus every\nrequested label, flag, logo, symbol, or prop; do not write only \"the original\".\n\nSELECTION-GATED IMAGE STAGES: If the user asks for N image options and says they will pick\none before a later dance/video/animation, call generate_image once with numberOfVariations=N.\nAfter images are created, stop and ask the user to choose unless the user explicitly asked\nto run the later stage immediately.\n\nIMAGE→VIDEO DIMENSION RULE: When generating an image that will feed into a video tool\n(animate_photo, sound_to_video, etc.), the image MUST be generated at the SAME aspect\nratio and dimensions as the target video. Default video aspect ratio is 16:9 landscape —\npass aspectRatio=\"16:9\" (or the user's specified/reference ratio) so the source image\nmatches the video output. Do not generate a square image for a widescreen video. Exception:\na composite GPT Image 2 storyboard/keyframe sheet for a later Seedance video is a board,\nnot a single source frame; unless the user explicitly specifies a storyboard page/canvas/sheet\nshape, default the sheet image dimensions to a balanced grid that hosts the target\nscene-cell/frame aspect natively (portrait video target -> portrait or square sheet whose\ncolumns x rows grid produces ~9:16 cells; landscape video target -> landscape sheet whose\nrows x columns grid produces ~16:9 cells). Each scene-cell/frame area preserves the target\nvideo aspect ratio.\n\nSTORYBOARD IMAGE BATCH RULE: When rendering scene keyframes from a screenplay/storyboard,\nnumberOfVariations is only the count; the prompt should be one Dynamic Prompt branch with one\nfull keyframe prompt per scene:\n{scene 1 full keyframe prompt|scene 2 full keyframe prompt|...|scene N full keyframe prompt}.\nDo not set numberOfVariations=N with only the first scene prompt — that creates N versions of\nscene 1. For full project requests, one generate_image batch for all scene keyframes, then\none animate_photo batch for all video clips in parallel.\n\nSTORYTELLING / BRAND / SOCIAL IMAGE PROMPTS: If generating a storyboard, ad concept,\ntrailer sheet, meme, creator post, or provocative social concept, make the first frame or\npanel immediately legible. Preserve the user's requested tone and audience. Use concrete\ncomposition, persona, product/brand role, caption placement, readable required text, and a\nclear visual transformation or punchline. For provocative adult social content, keep subjects\nclearly adult and consensual, avoid minor-coded styling or school-coded settings, and keep it\nPG-13/non-explicit unless a CONTENT POLICY section in the system prompt states that Unrestricted\nmode is active; then follow that section instead of the PG-13 limit. Still optimize visual\nmagnet, persona, caption bait, and replay/comment value.\n\nGPT IMAGE STORYBOARD SHEET → SEEDANCE AUTO-PROCEED: If the user asks to run the whole\nGPT Image storyboard/keyframe sheet plus Seedance workflow without approval, the FIRST\ngenerate_image call must create ONE composite storyboard/keyframe sheet, not loose concept\nart and not separate keyframes. Default to model=\"gpt-image-2.5-sunburst\" and preserve another\nexplicit GPT Image model named by the user. Use numberOfVariations=1 and a\ncompiled storyboard prompt that literally includes: \"Create exactly N sequential video\nstoryboard frames as one composite storyboard image\", \"Target final video aspect ratio: X\",\na `SCENES:` section, and exactly N concrete scene entries named `SCENE_01`, `SCENE_02`,\netc. Each scene entry must include `Visual/Action:`, `Camera/Motion:`, `Dialogue/VO:`\n(use `[no dialogue]` when silent), `Audio/SFX:`, and any reference/visible-text notes\nneeded for that scene. Do not send only a source brief, storyboard concept, or generic\nlayout instructions as the prompt; malformed compiled storyboard prompts are blocked by\nquality audit instead of being repaired at runtime. If the user does not explicitly specify\na frame count, choose N with the shared storyboard density default: at least one key visual\nbeat about every 2 seconds, rounded up and clamped to 6-16 total storyboard frames\n(for example, a 60 second commercial defaults to N=16). Unless the user explicitly specifies another\nstoryboard page/canvas/sheet shape, default the GPT Image 2 storyboard sheet pixel dimensions\nto a balanced grid that hosts the target cell aspect natively: for a 9:16 portrait video,\npick a portrait-leaning sheet whose columns x rows grid produces ~9:16 cells (e.g., 12 cells\n-> ~3:4 sheet around 1728x2304, 6 cells -> ~27:32 around 1840x2176, 9 cells -> ~9:16 around\n1504x2672); for a 16:9 landscape video, pick a landscape sheet whose rows x columns grid\nproduces ~16:9 cells (e.g., 12 cells -> ~4:3 sheet around 2304x1728). Do not force landscape\n2560x1440 when cells are portrait — a landscape sheet with a portrait-cell grid cannot host\n9:16 cells without crushing them. Preserve the requested final video aspect ratio for every\nframe area. After\nthat image completes, call generate_video once using the generated storyboard board as\n@Image1/referenceImageIndices=[0], with skipPromptProcessing=false only when the user\nexplicitly wants the storyboard text rewritten; otherwise preserve the compiled shot guide\nand use skipPromptProcessing=true, expandPrompt=false.\n\nDO NOT USE generate_image FOR UPLOADED REFERENCE LOOPED VIDEO SEGMENTS: If the user says\nthe same uploaded image/reference should be reused as the first frame and last frame of each\nscripted segment/scene/clip before stitching, they are explicitly asking to animate the\nuploaded image, not to generate new storyboard keyframes. Do not call generate_image for\nthat request. Call animate_photo once with repeated uploaded source indices and per-scene\nprompts.\n\nREUSING RESULTS: When the user asks to redo, retry, or revise (e.g., \"try a new version\",\n\"redo the video with X\"), reuse the existing source images — do NOT regenerate them unless\nthe user explicitly asks for new images or describes changes to the images themselves.\nReference the existing result indices from the prior generation. If unsure whether the user\nwants new images, ask — don't regenerate by default.",
"parameterDocs": {
"prompt": "Text description of one output image. Put the subject first. Preserve authored subject counts and requested visible words. Use Dynamic Prompt syntax for requested distinct content; a fully specified or consistent scene may use a plain prompt.",
"numberOfVariations": "Number of output images. Typed count and grouping arguments determine batching. Use Dynamic Prompt {|} syntax for requested distinct content; a fully specified or consistent scene may use a plain prompt. Preserve requested visible count or version words in the prompt.",
"aspectRatio": "For ordinary images feeding a video tool, set to match the target video aspect ratio. For composite GPT Image 2 storyboard sheets, default the sheet pixel dimensions to a balanced grid that hosts the target cell aspect natively (portrait video target -> portrait/square sheet, landscape video target -> landscape sheet) unless the user explicitly specifies a storyboard page/canvas/sheet shape; keep the target video ratio inside each frame area."
}
},
{
"contractId": "video_to_video_v1",
"version": "1.1.0",
"toolName": "video_to_video",
"baseDescription": "video_to_video transforms an uploaded video. Use for uploaded-video restyling, generative\nenhancement or remastering, motion transfer from video to image, subject replacement, edge/pose/\ndepth-guided restyle, or explicit Seedance V2V transforms. Wan 3 is not a V2V model;\nits video inputs are loose references for new generation through generate_video.\nFor a pure resolution upscale (a sharper 1080p, 1440p, 2K, or HD copy of the same video),\nuse upscale_video instead; it is promptless and keeps every frame, the frame rate, and the audio.\n\nThis tool requires an uploaded video source. Do not use it for generated video indices. For\ngenerated or uploaded partial edits use replace_video_segment; for appended time use\nextend_video; for logos/text overlays use overlay_video; for stitching use stitch_video.\n\nChoose controlMode by intent. Use detailer for generative detail enhancement without restyling\nwhen the user wants the content re-rendered rather than only more resolution.\nUse seedance-v2v only when the user asks to transform/enhance/remaster an uploaded video\nwith Seedance, including uploaded-video upscale/remaster requests that name Seedance. For detailer,\ndescribe the original scene plus quality terms, not new content.\nUse outpaint to extend/expand the frame or change aspect ratio (positional, mask-free); set\noutpaintPosition and optionally outpaintAspectRatio. Use inpaint to regenerate a region\nwhile preserving the rest. If the user supplied a mask, set maskImageIndex; otherwise\nomit maskImageIndex so execution derives one from the source video and prompt.",
"parameterDocs": {
"prompt": "Describe the target appearance in present tense. For detailer, describe the original content plus quality qualifiers only. For outpaint, describe what fills the new area; for inpaint, describe only the masked region.",
"videoSourceIndex": "Uploaded video index. Omit when there is one uploaded video; use 0 for first uploaded video or -1 if using negative upload notation.",
"controlMode": "Pick from intent: detailer for generative enhancement, seedance-v2v for explicit Seedance V2V, canny/depth for video-only control restyles, pose for motion transfer onto a reference-image subject, animate-move/replace for WAN Animate, outpaint to extend/expand the canvas, inpaint to regenerate a masked region.",
"sourceImageIndex": "Required for animate-move, animate-replace, and pose when more than one image is available; the sole reference image may be auto-selected. LTX pose always needs a reference image. Ignored by canny, depth, detailer, outpaint, and inpaint.",
"outpaintPosition": "outpaint only. Where the original frame sits in the expanded canvas (center/top/bottom/left/right); determines grow direction. Default center.",
"outpaintAspectRatio": "outpaint only, optional. Target aspect ratio (e.g. 16:9) for the expanded canvas; the canvas only grows, never crops. Set only when the user names a target shape/orientation.",
"maskImageIndex": "inpaint only, optional. 0-based index of an uploaded mask image (white = regenerate, black = preserve). Omit when the user did not provide a mask.",
"duration": "Set only when the user requests a different output length; otherwise let the tool match/cap the source duration."
}
},
{
"contractId": "extend_video_v1",
"version": "1.0.0",
"toolName": "extend_video",
"baseDescription": "Use extend_video when a video already exists in the session — whether previously rendered OR\nuploaded — and the user asks to make it longer, add a segment, or append a bumper, outro,\nintro, tag, or sting to the end (or start). Do NOT call generate_video, animate_photo, or build\na new bumper from scratch via edit_image+animate_photo+stitch_video — those render fresh\nclips and either waste the previous render or ignore the uploaded base.\n\nFor uploaded base videos, set videoIndex to a negative number (-1 for first uploaded video).\nSet duration to the ADDITIONAL seconds (not the new total).\n\nTrigger phrases: \"make it longer\", \"extend the video\", \"add another N seconds\", \"continue the\nscene\", \"add a bumper/outro/intro/tag/sting to the end (or start)\".\n\nBoth extend_video and replace_video_segment auto-detect the base video's model (Seedance\nsource → Seedance continuation; LTX source → LTX continuation; Wan source → Wan continuation), so OMIT videoModel unless\nthe user explicitly demands a different model. This applies regardless of whether the prior\nrender came from generate_video, animate_photo, sound_to_video, or video_to_video.",
"parameterDocs": {
"videoIndex": "Index of the existing video. Use -1 for first uploaded video, non-negative for generated videos.",
"duration": "ADDITIONAL seconds to add — not the new total length.",
"videoModel": "Omit to auto-detect from source video. Only set if user explicitly requests a different model."
}
},
{
"contractId": "replace_video_segment_v1",
"version": "1.0.0",
"toolName": "replace_video_segment",
"baseDescription": "Use replace_video_segment when the user wants to regenerate a specific time range of an\nexisting video: \"regenerate from Xs to Ys\", \"redo the last N seconds\", \"swap out the middle\",\n\"fix the [start/middle/end] of the video\", or \"replace the [bumper/intro/outro/end card/\ntag/sting] at the [start/end] of the video\". Use explicit startSeconds and endSeconds.\nFor relative requests like \"last 3 seconds\", resolve against the known base duration when\nduration metadata or prior tool arguments provide it. For \"bumper/end card/outro at the end\"\nwithout exact seconds, use the known storyboard timing when available; otherwise choose a\nsmall end-card window such as the final 1-3 seconds based on the base duration. If the base\nduration/window is genuinely unknown, inspect the video first or ask for the missing window;\ndo not submit ambiguous placeholder times.\n\nWhen the replacement is already another uploaded or generated video clip, still use\nreplace_video_segment but pass replacementVideoIndex. Example: \"splice video 2 into video 1\nat 5s\" means videoIndex=-1, replacementVideoIndex=-2, startSeconds=5, endSeconds=5.\nUse endSeconds=startSeconds for insertion; use a wider endSeconds only when the user says to\nreplace/remove that base-video range. Do not use stitch_video for \"into the middle\"/\"insert\"\nrequests, because stitch_video only concatenates full clips end-to-end.\n\nFor time-sliced interleaving from existing videos — \"alternate 1s from each video\", \"weave\none-second clips from video 1 and video 2\", \"cut back and forth every N seconds\" — do NOT\nuse stitch_video and do NOT omit replacementVideoIndex. Start with the first requested video\nas the base, then call replace_video_segment once for each window that should come from the\nother video. Set replacementVideoIndex to that other existing video and set\nreplacementStartSeconds/replacementEndSeconds to the next source slice from that\nreplacement video. For ordinary\nalternation, preserve the base duration: set endSeconds=startSeconds+sliceDuration, not\nendSeconds=startSeconds insertion, unless the user explicitly asks to lengthen the output by\ninserting extra slices. Skip no-op windows that already come from the base video; only splice\nwindows that should come from a different source. Example for two 10s uploads alternating every 1s starting with video\n1: replace base windows 1..2, 3..4,\n5..6, 7..8, and 9..10 with slices 0..1, 1..2, 2..3, 3..4, and 4..5 from video 2. After\neach successful splice, target the newest composite video index for the next splice.\nThe -1 time sentinel applies only to base startSeconds/endSeconds when the base duration is\nunknown. Never use -1 for replacementStartSeconds or replacementEndSeconds; source windows\nmust use concrete non-negative seconds. For uploaded/generated videos with duration metadata,\nuse that known duration directly; do not call analyze_video just to learn the clip length for\nroutine alternating slices. Do not add a final tail splice with an unknown source end — stop at\nthe known clip duration or skip a no-op tail window.\n\nDo NOT call generate_video or animate_photo to re-render an existing video just to change\npart of it (the bumper, the intro, the end card, a single scene, the last few seconds, etc.).\nUse replace_video_segment — it preserves the unchanged portion, keeps the original audio\noutside the replaced window, and costs far less.\n\nAuto-detects the base video's model, so OMIT videoModel unless the user explicitly demands\na different model. Short requested windows are supported by rendering with model-specific\nhandles and trimming the rendered clip before splicing, so still pass the user's exact\nstartSeconds/endSeconds.",
"parameterDocs": {
"startSeconds": "Start of segment to replace in seconds. Use -1 sentinel if exact base duration is unknown.",
"endSeconds": "End of segment to replace in seconds. Use the same value as startSeconds for insertion with replacementVideoIndex.",
"replacementVideoIndex": "Existing uploaded/generated replacement clip. Use negative uploaded-video indices, e.g. -2 for the second uploaded video.",
"replacementStartSeconds": "Optional start time inside replacementVideoIndex. Use with replacementEndSeconds for time-sliced interleaving. Must be concrete and >= 0; never use -1 here.",
"replacementEndSeconds": "Optional end time inside replacementVideoIndex. Must be concrete, >= 0, and greater than replacementStartSeconds; never use -1 here.",
"videoModel": "Omit to auto-detect from source. Only set if user explicitly requests a different model."
}
},
{
"contractId": "overlay_video_v1",
"version": "1.0.0",
"toolName": "overlay_video",
"baseDescription": "Use overlay_video when the user wants to overlay/place/show a logo, text, caption, or\nwatermark ON TOP OF existing video frames.\n\nFor uploaded base videos, set sourceVideoIndex=-1; for generated videos, use their\nnon-negative video index. If the overlay should last only part of the video, set the overlay\nitem's startSeconds/endSeconds (e.g. a 2s middle overlay on a 20s video: ~9s to ~11s).\nNegative startSeconds/endSeconds are relative to the end of the base video, so startSeconds=-2\nwith omitted endSeconds means the last 2 seconds.\n\nWhen the user asks to replace a video time window with an uploaded still image, screenshot,\nphoto, frame, logo, or graphic, use an image overlay for that window with widthPct=100 and\nfit=\"cover\"; do not regenerate the video segment.\n\nDo NOT use overlay_video for intro/outro/bumper/end-card/start-card requests — those add or\nregenerate video time and should use extend_video or replace_video_segment. After a successful\noverlay_video call, finalize the turn; do not call overlay_video again just to tweak default\nsize or placement unless the user asks.",
"parameterDocs": {
"sourceVideoIndex": "Use -1 for first uploaded video, non-negative index for generated videos.",
"overlays": "Use startSeconds/endSeconds for time windows. For still/screenshot replacement windows, use kind=\"image\", widthPct=100, fit=\"cover\"."
}
},
{
"contractId": "add_subtitles_v1",
"version": "1.0.0",
"toolName": "add_subtitles",
"baseDescription": "add_subtitles burns caller-supplied subtitles, captions, lyrics, or on-screen dialogue into\nan existing video. Use this when the user provides cue text/timing, pastes SRT/VTT, or asks\nto add known caption lines to a generated or uploaded video.\n\nDo not use auto_transcribe. Speech-to-text is not enabled; when the user has not supplied\nsubtitle text or timing, ask for the cue text/timing instead of calling this tool.\n\nException: if the user explicitly authorizes invented caption copy with language like\n\"make them up\", \"write captions\", \"invent subtitles\", or \"add funny captions\", create a few\nshort generic cue lines yourself and call add_subtitles. Do not ask for exact wording when\nthe user has asked you to author the captions.\n\nSplit subtitles into multiple short cues. Do not burn one paragraph across the whole clip.\nUse overlay_video instead for static title cards, labels, logos, watermarks, or non-timed text.",
"parameterDocs": {
"sourceVideoIndex": "Non-negative generated video index or negative uploaded video index. Omit/default to the latest relevant video.",
"cues": "Multiple short cues with startSeconds, endSeconds, and text. Prefer 1.5-4 seconds per cue.",
"srt": "Full SRT/VTT string. Provide either srt or cues, not both.",
"auto_transcribe": "Do not set. Ask the user for subtitle text/timing until STT is available."
}
},
{
"contractId": "stitch_video_v1",
"version": "1.0.0",
"toolName": "stitch_video",
"baseDescription": "stitch_video joins multiple video clips into one. Reference generated videos by their\n0-based video indices (from videoStartIndex in prior tool results). Reference uploaded\nvideos with negative indices in current UI order: -1 = first uploaded video, -2 = second, etc.\nWhen the user asks to stitch these/all uploaded videos and does not name a different order,\nuse the current UI order exactly: [-1,-2,...].\nIf the user explicitly names a different playback order, preserve that requested order exactly;\ndo not rewrite it back to UI order.\n\nNEVER tell the user to \"upload\" a video that was already generated in this conversation —\nstitch_video can reference them directly by index.\n\nWhen stitching results from a batch video tool, use ONLY the video indices actually returned\nby that tool. Do not infer the stitch list from the number of source images, keyframes, or\nstoryboard panels. Example: if 5 uploaded keyframes create 4 adjacent animate_photo\ntransition clips and the tool result returns videos at indices 0,1,2,3, call stitch_video\nwith videoIndices=[0,1,2,3] — never include index 4 unless a fifth video was returned.\n\nDo not use stitch_video for alternating/interleaved time slices such as \"alternate\n1s from each video\"; stitch_video joins whole clips end-to-end, while interleaving existing\nvideo slices belongs to repeated replace_video_segment calls with replacementVideoIndex and\nreplacementStartSeconds/replacementEndSeconds.\n\nNote: video_to_video requires an actual uploaded video file and cannot use generated video\nindices. Do not claim exact final runtime, dimensions, or aspect ratio after a tool finishes\nunless that value was explicitly requested by the user or explicitly returned by the tool.",
"parameterDocs": {
"videoIndices": "Ordered source video indices. Use non-negative generated-video indices from prior tool results; use negative uploaded-video indices in current UI order (-1 first uploaded video, -2 second, etc.)."
}
},
{
"contractId": "sound_to_video_v1",
"version": "1.3.0",
"toolName": "sound_to_video",
"baseDescription": "sound_to_video creates audio-synced video from an audio source. Works with uploaded audio\nfiles (mp3, m4a, wav) OR previously generated music from generate_music (auto-detected).\n\nWhen the user asks to \"turn that song/music into a video\" after generate_music, use\nsound_to_video — it will automatically find the generated audio.\n\nFor music visualization (syncing video to a specific song or audio track), use the\ngenerate_music → sound_to_video pipeline. Do NOT use animate_photo or generate_video for\naudio-driven visualization.\n\nanimate_photo and generate_video produce audio natively via LTX 2.5 or LTX 2.3 — never\npre-generate audio for those tools. sound_to_video is only for when the audio IS the primary creative\ninput driving the video output.\n\nPERSONA VOICE CLIPS: Persona voice clips returned by resolve_personas are voice identity\nreferences, not audio tracks to synchronize. If the user explicitly asks for a persona's own\nvoice, call resolve_personas first, then set voicePersonaName on generate_video (Audio ID on\nltx23, a voice reference on MiniMax H3 reference-to-video, Seedance and Wan 3) or on\nanimate_photo with ltx23 when an image/source frame should be animated. Do not call\nsound_to_video for a persona voice clip unless a separate uploaded audio track is the primary\nsync driver.\n\nMINIMAX H3 AUDIO GUIDE: only when the user asks for MiniMax H3 or FastH3 with an uploaded audio\ntrack, use sound_to_video with videoModel \"minimax-h3-fasth3-ia2v-turbo\" (first-frame image via\nsourceImageIndex), \"minimax-h3-fasth3-flfa2v-turbo\" (first frame via sourceImageIndex and last\nframe via endImageIndex) or \"minimax-h3-fasth3-a2v-turbo\" (audio only, no image). The audio\ndrives the picture from frame 0 and stays in the output. Clips are 124-362 frames at a fixed\n24 fps (about 5.2-15.1 seconds); audioStart picks the window. MiniMax H3 catalog and Personal\nLoRAs are supported across audio modes and tiers. generateAudio=false and\nnegativePrompt are not supported. Add \"-2stage\" only for 1080p, 1440p or 2K H3 output (1080 or\n1440 targetResolution); 720p-class audio output stays on the regular selector. Never use these\nin place of the LTX 2.5 defaults when the user did not ask for MiniMax H3 or FastH3.\n\nMINIMAX H3 KEYFRAMES: when the user wants one MiniMax H3 clip to pass through extra images at chosen moments, pass keyframes=[{imageIndex, atSeconds}] (up to 8; imageIndex indexed like endImageIndex) on that one call, and make the clip long enough that every keyframe falls strictly inside it (set duration when the default would end too soon). Say in the prompt what each keyframe shows at its time, and start a new shot at a keyframe that changes the angle, place or light. Keyframes add to the first and last frame and are not references, but the prompt names each one <Picture N>, numbered after the first/last-frame or reference pictures in time order. Two are included in the price; each additional keyframe adds a little. Only MiniMax H3 selectors take them (see the keyframes argument for which).\nOn sound_to_video every MiniMax H3 audio selector takes keyframes: the audio drives the performance and\nthe keyframes pin how it looks at their times. imageIndex follows endImageIndex (-1 = first upload), not\nthe 0-based upload numbering of sourceImageIndex. Set duration whenever you pass keyframes: the audio\nselectors render the shortest MiniMax H3 length that covers it (duration 6 renders 6.58 s), and every\nkeyframe must fall inside that clip.",
"parameterDocs": {
"keyframes": "MiniMax H3 only. Pin up to 8 images at exact moments inside the video, in addition to the first/last frame. Each item is {imageIndex, atSeconds}: imageIndex uses the endImageIndex convention (negative = uploads, 0+ = generated results); atSeconds is when the video should land on that image. Keyframes must fall strictly inside the clip (not on the first or last frame) and at distinct times. Describe what each keyframe shows in the prompt at its time; a keyframe with a new angle, place or light starts a new shot. Two keyframes are included in the price; each additional keyframe adds a little. On sound_to_video every MiniMax H3 audio selector takes keyframes (image + audio, first and last frame + audio, and audio only, each one- and two-stage). imageIndex follows endImageIndex here too (-1 = first upload), not the 0-based upload numbering of sourceImageIndex. Set duration whenever you pass keyframes: the clip is then the shortest MiniMax H3 length that covers it (duration 6 renders 6.58 s), and every keyframe must fall inside that. Without duration the host sizes the clip itself (to the audio from audioStart, or a 5.17 s default) and refuses keyframes that fall outside it.",
"audioSource": "Uploaded audio file or reference to a prior generate_music result. Auto-detected when omitted after generate_music.",
"endImageIndex": "Last frame for the MiniMax H3 FastH3 first/last frame + audio selectors only, indexed like animate_photo (-1 first upload, -2 second upload, non-negative generated results)."
}
},
{
"contractId": "dance_montage_v1",
"version": "1.0.0",
"toolName": "dance_montage",
"baseDescription": "dance_montage creates dance videos from an uploaded photo. Dance video requests from an\nuploaded photo go directly to dance_montage; do not call edit_image/generate_image first\nunless the user explicitly asks for a new look, outfit, generated character/image, variations,\nor persona identity prep.\n\nDance preset/vibe words like \"Barbie\", \"Metric\", \"Black Sheep\", \"Rasputin\", or \"TikTok\" are\nnot image-prep requests by themselves.\n\nSELECTION-GATED DANCE FLOW: If the user asks for N image options and says they will pick\none before the dance video, generate the image options first (generate_image or edit_image\nwith numberOfVariations=N), then stop and wait for the user to choose before calling\ndance_montage.",
"parameterDocs": {
"sourceImageIndex": "Use the uploaded photo directly (-1). Only use a generated image index if the user explicitly requested a new image first."
}
},
{
"contractId": "generate_music_v1",
"version": "1.1.0",
"toolName": "generate_music",
"baseDescription": "generate_music creates music tracks with optional lyrics, BPM, key, and style control.\n\nMUSIC CREATIVE BRIEF: Identify purpose before composing: full song, short social hook,\njingle, trailer score, background underscore, sonic logo, music video cue, or lyric video.\nDefine genre, mood, tempo/BPM, energy curve, instrumentation, vocal style, lyrical point of\nview, hook phrase, section structure, and production notes. Lyrics should be original,\nsingable, sectioned, rhythmically clear, and have a memorable hook. Brand music should make\nthe brand easier to remember without stuffing the name into every line.\n\nFor music visualization (syncing the generated track to video), chain generate_music →\nsound_to_video. Do NOT use animate_photo or generate_video for audio-driven visualization.\n\nAfter generate_music, if the user asks to \"turn that song into a video\" or similar, call\nsound_to_video next — it auto-detects the latest generated music track.",
"parameterDocs": {}
},
{
"contractId": "generate_speech_v1",
"version": "1.1.0",
"toolName": "generate_speech",
"baseDescription": "generate_speech reads written words aloud. It is text-to-speech, not music: use\ngenerate_music for songs, instrumentals and jingles.\n\nTHE PROMPT IS THE SCRIPT. Unlike every image and video tool, prompt is not a description\nof the output — it is the literal text to be spoken, character for character. Writing \"a\ncalm woman reading the news\" produces a voice saying those seven words. Put the delivery in\nvoiceDescription and the actual copy in prompt.\n\nWRITE THE SCRIPT WHEN THE USER DOES NOT. \"Read me a haiku about rain\", \"record a podcast\nintro\" and \"say something reassuring\" are requests for words you compose and then speak.\nCompose the line and pass it as prompt. Reach for compose_script only for a long or\nstructured piece; a sentence or two is yours to write.\n\nPICK THE MODEL FROM WHAT THE USER GAVE YOU. A voice clip uploaded with \"make it sound like\nme\" is model=\"clone\" with voiceSourceIndex pointing at that upload. A saved Persona's voice is\na clone source too: when the user asks for that persona's own voice, call resolve_personas and\nuse model=\"clone\" with voiceSourceIndex set to the full voice recording index it reports. A\ndescribed speaker who does not exist (\"an old lighthouse keeper\") is model=\"design\" with\nvoiceDescription. Anything else is model=\"voice\" — choose a voice from the roster and, if the\nuser described a mood or a delivery, put that in voiceDescription too.\n\nCLONING QUALITY. Set voiceTranscript whenever the words in the uploaded clip are known: it\nis the difference between a close clone and a loose one. Leave it out for a persona recording:\nthe persona's saved transcript is supplied automatically. Tell the user if their reference is\nshorter than three seconds, has music under it, or has two people talking — those are the\nthree reasons a clone comes back sounding wrong.\n\nPUNCTUATION IS PROSODY. Keep full stops, commas and question marks; they are the only pause\nand intonation control there is. Spell out numbers, dates and abbreviations the way they\nshould be read when the written form is ambiguous.\n\nTo put speech over video, generate it here and then call sound_to_video with the result.\nDo not use animate_photo or generate_video to \"say\" a line of provided text.",
"parameterDocs": {
"prompt": "The literal words to speak, verbatim. Not a description of the audio.",
"voiceDescription": "Delivery direction for model=\"voice\"; the speaker to invent for model=\"design\". Never sent with model=\"clone\".",
"voiceSourceIndex": "Which audio holds the voice to clone, same numbering as other tools use for audio: -1 is the first upload, -2 the second, and 0-based non-negative indices address audio generated earlier. A resolved persona's full voice recording uses the index resolve_personas reports. Required for model=\"clone\".",
"voiceTranscript": "What the uploaded clip says. Optional, but it makes the clone markedly closer to the source. Omit it for a persona voice recording; its saved transcript is filled in automatically."
}
},
{
"contractId": "analyze_image_v1",
"version": "1.0.0",
"toolName": "analyze_image",
"baseDescription": "analyze_image answers questions about image content, OCR, objects, style, documents, or\ncomparisons. It does not generate or modify media.\n\nUse only when the user asks to inspect, describe, read, compare, or reason about an image.\nDo not insert it as a quality-control step inside generation workflows unless the user\nexplicitly asks for analysis before continuing.\n\nFor uploaded images, negative indices refer to the upload order. For compare mode, provide\nboth sourceImageIndex and compareImageIndex.",
"parameterDocs": {
"query": "Specific question/request about the image. Preserve the user question directly.",
"analysisType": "Pick describe, ocr, objects, document, compare, or general based on the user request.",
"sourceImageIndex": "Omit to auto-select latest result or original upload. Use -1 for first uploaded image.",
"compareImageIndex": "Second image for compare mode. Use negative uploaded-image indices when comparing uploads."
}
},
{
"contractId": "analyze_video_v1",
"version": "1.0.0",
"toolName": "analyze_video",
"baseDescription": "analyze_video uses sampled frames to answer questions about an uploaded or generated video:\nsummary, timeline, visual scene description, action breakdown, or visible text.\n\nUse only when the user asks to inspect or understand a video. Do not call it as automatic\nverification after generation, and do not use it before stitch_video when the requested\ngeneration pipeline should continue.\n\nThis is visual sampled-frame analysis only. It does not transcribe audio and does not inspect\nevery frame.",
"parameterDocs": {
"query": "Specific question/request about the video. State whether summary, timeline, OCR, scene, or action detail is needed.",
"analysisType": "Pick summary, timeline, scene, action, ocr, or general based on the user request.",
"sourceVideoIndex": "Generated video index or negative uploaded-video index. Omit to auto-select latest generated video or first upload."
}
},
{
"contractId": "set_content_filter_v1",
"version": "1.0.0",
"toolName": "set_content_filter",
"baseDescription": "set_content_filter enables or disables the Safe Content Filter. Call only when the user\nexplicitly asks to change this setting. Do not toggle it as part of ordinary generation.\n\nIf disabling requires host-side confirmation, let the handler surface that permission flow;\ndo not claim the setting changed unless the tool result says it did.",
"parameterDocs": {
"enabled": "true to enable the filter, false to disable it. Only set from explicit user intent."
}
},
{
"contractId": "extract_metadata_v1",
"version": "1.0.0",
"toolName": "extract_metadata",
"baseDescription": "extract_metadata reads prompt/model/settings metadata from an uploaded media file. Use when\nthe user asks what prompt, model, seed, dimensions, or generation settings are embedded in\nan uploaded file, or when they ask to recreate/remix an uploaded file from its metadata.\n\nThis indexes uploaded files only, not prior generated results already known to chat. Do not\ncall it for ordinary visual analysis; use analyze_image or analyze_video for content.",
"parameterDocs": {
"file_index": "0-based uploaded-file index. Omit for the first uploaded file."
}
},
{
"contractId": "resolve_personas_v1",
"version": "1.1.0",
"toolName": "resolve_personas",
"baseDescription": "resolve_personas is the required first step when the user explicitly names a saved Persona\nor says to use a Persona Image, Persona reference photo, Persona Voice, registered voice,\nor voice clone. Do not answer in prose, ask a follow-up, or finalize before calling this\ntool when a listed Persona name is present.\n\nREFERENCE-TO-VIDEO PERSONAS: On MiniMax H3 reference-to-video (minimax-h3-r2v*), Seedance\n(seedance2*, seedance2-5*) or Wan 3 (wan3.0-video, wan3.0-spicy-video), pass the persona\nreference images this tool resolves (identity portrait, character sheet, full-body front,\nprofile, back, expression) straight to generate_video as referenceImageIndices, using the\nnegative uploaded indices it reports, with no edit_image step. Every clip or scene carries\nits own references. Bind each persona to its images in the prompt with the model's tokens:\n@Image1 on Seedance, <Picture 1> on MiniMax H3, Image 1 on Wan 3.\n\nDIRECT PERSONA IMAGE: On LTX and the other image-animation models, if the user says to use\nthe Persona image/reference directly/originally, call resolve_personas first, then call\nanimate_photo using the injected persona photo as an uploaded image index. For one named\nPersona, use sourceImageIndex=-1 or sourceImageIndices=[-1,...] for a multi-clip batch. Do\nnot generate a new image first when the user explicitly requested the existing Persona image\ndirectly.\n\nPERSONA VOICE: Only when the user asks for the persona's own voice, set voicePersonaName to\nthe exact resolved Persona name. On ltx23 it is Audio ID: animate_photo when an image/source\nframe should be animated, generate_video when no image source exists yet. On MiniMax H3\nreference-to-video, Seedance and Wan 3, generate_video attaches the persona's short voice\nsample as an audio reference for its timbre. A voice sample is identity, not the soundtrack.\nDo not call sound_to_video for Persona voice clips. For speech alone, clone the persona's full\nvoice recording with generate_speech (model=\"clone\", voiceSourceIndex from this tool).\n\nMULTI-CLIP PERSONA BATCHES: If the user asks for several separate clips from the same\nPersona Image, make one animate_photo call after resolve_personas with repeated persona\nsource indices, one prompt per clip, and the requested per-clip duration. If the user asks\nto stitch the clips, call stitch_video with the returned video indices after animate_photo.\n\nPERSONA IMAGE GENERATION: After resolving persona reference photos for a new persona image,\nuse edit_image rather than generate_image. Krea 2 Identity Edit and Dark Beast Krea 2 Identity\nEdit are available edit_image model choices when the request needs strong identity preservation\nfrom one or two reference photos; use concise identity locks and keep within the two-reference\nlimit.",
"parameterDocs": {
"names": "Persona names to load. Use the exact listed Persona name; call this before any Persona image/voice video or image generation."
}
},
{
"contractId": "manage_memory_v1",
"version": "1.0.0",
"toolName": "manage_memory",
"baseDescription": "manage_memory reads, writes, or deletes persistent user preferences and facts. Use write\nonly when the user states a durable preference/fact or explicitly asks you to remember\nsomething. Use read when persistent preferences are relevant before generation.\n\nDo not save transient one-off creative instructions as memory. Delete/clear actions require\nexplicit user intent; never infer memory deletion from vague dissatisfaction.",
"parameterDocs": {
"action": "read, write, or delete. Use write only for durable preferences/facts; delete only on explicit request.",
"key": "Stable concise memory key. Required for write/delete.",
"value": "Concise durable value. Required for write.",
"category": "preference for style/defaults, fact for user facts, context for project context."
}
},
{
"contractId": "create_asset_manifest_v1",
"version": "1.0.0",
"toolName": "create_asset_manifest",
"baseDescription": "create_asset_manifest resets and seeds the session asset manifest with stable asset_id\nrecords. Use at the start of workflows with multiple named uploaded/generated assets that\nwill need durable references across later prompts.\n\nDo not call this just to use ordinary uploaded images in edit_image/generate_image; those\ntools can already reference uploads. Resetting discards prior manifest entries.",
"parameterDocs": {
"assets": "Ordered assets to register. Each needs user_label and type; include must_preserve/avoid only when they matter later."
}
},
{
"contractId": "inspect_asset_v1",
"version": "1.0.0",
"toolName": "inspect_asset",
"baseDescription": "inspect_asset returns one manifest asset or the whole manifest. Use when the current\nmanifest state is unclear before referring to a generated asset by asset_id/user_label.\n\nDo not call it for ordinary uploaded references that the generation tools can use directly,\nand do not use it as a substitute for analyze_image/analyze_video content inspection.",
"parameterDocs": {
"asset_id": "Stable internal asset id. Prefer this when known.",
"user_label": "Human label to look up case-insensitively when asset_id is not known."
}
},
{
"contractId": "label_asset_v1",
"version": "1.0.0",
"toolName": "label_asset",
"baseDescription": "label_asset updates the label, description, URL, must_preserve, or avoid fields for an\nexisting manifest asset. Use when the user renames an asset, assigns a role, or when a\nprevious tool result adds durable reference constraints.\n\nDo not invent labels or preservation constraints that the user did not provide or that are\nnot present in a tool result.",
"parameterDocs": {
"asset_id": "Existing asset_id to update.",
"user_label": "New human-readable label when the user renames the asset.",
"description": "Replacement description. Keep it factual and concise.",
"must_preserve": "Replacement preservation list. Use only explicit or tool-result-backed constraints.",
"avoid": "Replacement avoid list. Use only explicit or tool-result-backed constraints."
}
},
{
"contractId": "map_assets_for_model_v1",
"version": "1.0.0",
"toolName": "map_assets_for_model",
"baseDescription": "map_assets_for_model is an inspection helper for previously generated asset-manifest entries\nwhen you need exact model_ref tokens for a later prompt.\n\nDo NOT call this for ordinary uploaded image references. If the user uploaded images and\nasks GPT Image 2 to use all uploaded assets as visual references, call edit_image directly\nwith sourceImageIndex=-1 and describe the uploaded assets/roles in the prompt. Uploaded\nreference images are already available to edit_image/generate_image; mapping them first\nwastes a tool round and may violate direct-generation requests.\n\nUse this helper only when a previous tool result produced assets in the manifest and the\nnext prompt must name those prior generated assets with provider-specific tokens.\n\nContext-conditioned image/edit models such as LTX 2.5, LTX 2.3, Wan, Qwen Image Edit, Krea 2 Identity\nEdit, and Dark Beast Krea 2 Identity Edit use zero-indexed model_ref tokens like\ncontext_image_0 and context_image_1. Use the helper output instead of hand-formatting those tokens.",
"parameterDocs": {
"model_id": "Target model for prior generated manifest refs. Do not use for plain uploaded references."
}
},
{
"contractId": "validate_asset_references_v1",
"version": "1.0.0",
"toolName": "validate_asset_references",
"baseDescription": "validate_asset_references checks a prompt for provider-specific manifest reference tokens\nand reports which resolve or dangle. Call right before dispatching a prompt that names\nmanifest assets with model_ref tokens.\n\nDo not use this for plain uploaded references. If validation finds dangling refs, repair the\nprompt or register/map the asset before running an expensive generation tool.",
"parameterDocs": {
"model_id": "Target provider/model id whose reference token format should be scanned.",
"prompt": "Prompt text about to be sent to the model."
}
},
{
"contractId": "ask_clarifying_question_v1",
"version": "1.1.0",
"toolName": "ask_clarifying_question",
"baseDescription": "ask_clarifying_question pauses the workflow and asks the user for missing required input.\nUse only when no reasonable safe default exists, when required media/content is missing, or\nwhen confirmation is required for a destructive or credit-sensitive action.\n\nFor creative briefs, do not over-question. Ask at most 3 concise high-leverage questions only\nwhen the answer would materially change audience, product promise, format/duration/platform,\ntone, required assets, dialogue/no-dialogue, safety/legal/factual claims, or credit-sensitive\nexecution. Otherwise make reasonable assumptions and continue.\n\nThis ends the turn. Do not call another tool after it. Ask short concrete question(s) and\navoid preamble.",
"parameterDocs": {
"question": "One short concrete question surfaced verbatim to the user.",
"reason": "Short telemetry tag such as missing_source_asset, ambiguous_subject, or destructive_confirm."
}
},
{
"contractId": "finalize_response_v1",
"version": "1.1.1",
"toolName": "finalize_response",
"baseDescription": "finalize_response marks the turn complete and stops the tool loop. Use after the requested\nworkflow succeeds, partially succeeds, fails with a surfaced error, or needs no tool action.\n\nWhen the user asked for a script, storyboard, ad concept, trailer, creator video, meme/parody,\nor music prompt and no media tool is required, deliver the final creative in a clean Markdown\ncontract: title, concept/objective, audience if relevant, timed beats or script, audio/text\nnotes, generation prompt(s), a CTA only when the user asked for one or the brief sells\nsomething, and brief assumptions. For revisions, apply the feedback\ndirectly while preserving approved elements and rejected constraints.\n\nDo not call any other tool after finalize_response. Keep the summary short and grounded in\nactual tool results; do not claim exact metadata that no tool returned.\nFor no-action/text-only answers, such as product, feature, model, pricing, or capability\nquestions, the summary is the final answer the user sees. Provide the substantive answer\nthere; never leave it empty and never use a placeholder like \"Done.\"",
"parameterDocs": {
"summary": "User-visible closeout. For no-action/text-only answers, include the complete substantive answer here. For media workflows, mention produced media or the concrete blocker; avoid duplicating prior tool output.",
"outcome": "success, partial, asked_user, failed, or no_action based on the actual turn outcome."
}
},
{
"contractId": "enhance_prompt_v1",
"version": "1.1.0",
"toolName": "enhance_prompt",
"baseDescription": "enhance_prompt authors a directly runnable image, video, or image-edit prompt in the native\nformat of one exact active destination model. Use it when the requested text deliverable is\nexplicitly a prompt for a named media model, including a commercial prompt. The caller must\nprovide destination_model and target_output; unknown, sunset, and omitted models fail closed.\n\nDo not use enhance_prompt when an exact active destination model is absent, or for music\ncomposition, lyrics, screenplays, storyboards, treatments, ad scripts, or multi-step workflow\nplans. Use compose_script for creative-writing artifacts, compose_lyrics or\ncompose_instrumental for music, and compose_workflow or compose_workflow_template for\nworkflows.\n\nenhance_prompt returns prompt text only. The caller is responsible for handing it to the\nmatching downstream generation tool.",
"parameterDocs": {
"prompt": "The source prompt, rough idea, or prompt revision request to enhance.",
"target_output": "Required model-specific artifact kind: image_prompt, video_prompt, edit_prompt, or model_prompt. Use model_prompt only when destination_model identifies the modality.",
"destination_model": "Required exact active model selector. Unknown and sunset models fail closed.",
"destination_tool": "Optional matching downstream generation tool for the authored prompt.",
"prompting_type": "Deprecated compatibility metadata. It never selects or overrides the prompt grammar; destination_model is authoritative.",
"model_title": "Deprecated compatibility label. It never selects or overrides the prompt grammar; destination_model is authoritative.",
"style_prompt": "Optional current style, brand, or prompt context to complement without repeating.",
"prompt_mode": "Optional model prompt adaptation mode. One of auto, preserve, expand, compress, validate, or payload.",
"duration_seconds": "Requested runtime in seconds (1-300) when authoring a video prompt.",
"aspect_ratio": "Optional target aspect ratio, such as 16:9, 9:16, 1:1, 4:5, or 21:9.",
"assets": "Optional available assets (schema max 50) the prompt may reference. The exact destination model applies smaller per-modality and total limits.",
"constraints": "Optional production, brand, model, or user constraints to preserve."
}
},
{
"contractId": "compose_lyrics_v1",
"version": "1.0.0",
"toolName": "compose_lyrics",
"baseDescription": "compose_lyrics composes vocal song lyrics and suggested musical parameters. Use for songs\nwith words, choruses, verses, jingles, vocal hooks, or lyric rewrites.\n\nDo not use compose_lyrics for instrumental-only music — use compose_instrumental instead.\nDo not use it for spoken-word scripts, ad copy, or storyboards — use compose_script. Do\nnot use it to plan a multi-step workflow — use compose_workflow.\n\ncompose_lyrics returns lyrics text plus musical guidance. The caller is responsible for\nhanding the lyrics to generate_music to actually synthesize audio.",
"parameterDocs": {
"prompt": "The song topic, mood, genre, scene, campaign, or lyric request.",
"language": "Optional language code or language name for the lyrics.",
"music_prompt": "Optional musical style context, genre, instrumentation, mood, or production direction.",
"duration_seconds": "Optional desired song duration in seconds (10-600)."
}
},
{
"contractId": "compose_instrumental_v1",
"version": "1.0.0",
"toolName": "compose_instrumental",
"baseDescription": "compose_instrumental composes an instrumental music structure and suggested musical\nparameters. Use for background scores, beds, cues, themes, and music requests without\nlyrics.\n\nDo not use compose_instrumental when the user wants sung lyrics, vocal hooks, or a jingle\nwith words — use compose_lyrics instead. Do not use it to actually render audio — the\nresponse is musical guidance; the caller hands it to generate_music for synthesis.",
"parameterDocs": {
"prompt": "The instrumental music topic, mood, genre, scene, campaign, or composition request.",
"music_prompt": "Optional musical style context, instrumentation, mood, or production direction.",
"duration_seconds": "Optional desired track duration in seconds (10-600)."
}
},
{
"contractId": "compose_script_v1",
"version": "1.1.0",
"toolName": "compose_script",
"baseDescription": "compose_script composes scripts, screenplays, storyboards, treatments, ad concepts, trailers,\nsocial shorts, campaign beats, and talking-head plans. Use it for prose, scenes, beats, or\nother script-shaped creative-writing deliverables.\n\nWhen the user explicitly asks for a directly runnable prompt for a named image or video\nmodel, use enhance_prompt instead, even when the subject is a commercial. Do not use\ncompose_script for song lyrics, instrumental composition, simple prompt authoring, or a\nrunnable multi-step workflow.\n\ncompose_script returns a creative-writing deliverable. When that deliverable will later feed\na video pipeline, destination_tool and destination_model may record the intended handoff;\nthey do not turn the result into the model's native prompt contract.",
"parameterDocs": {
"brief": "The creative writing brief, story idea, product concept, video idea, or revision request.",
"script_type": "The kind of script or creative writing artifact to produce. One of video_prompt, screenplay, storyboard, ad_script, trailer, social_short, talking_head, campaign, or revision.",
"destination_model": "Optional destination video model selector, such as ltx25, ltx23, wan22, or seedance2.",
"destination_tool": "Optional downstream tool, such as generate_video, animate_photo, sound_to_video, or video_to_video.",
"duration_seconds": "Requested runtime in seconds (1-300) for a video prompt, social short, ad, or talking-head script.",
"scene_count": "Requested number of scenes, shots, beats, or storyboard panels (1-12).",
"aspect_ratio": "Optional target aspect ratio, such as 16:9, 9:16, 1:1, 4:5, or 21:9.",
"platform": "Optional target platform or context, such as TikTok, YouTube Shorts, Instagram Reels, broadcast, landing page, game trailer, or pitch deck.",
"style": "Optional style, genre, tone, visual treatment, or brand voice to preserve.",
"first_frame_description": "Optional description of the starting frame when composing an image-to-video prompt without attached vision content.",
"first_frame_data_url": "Optional inline image data URI for the starting frame when composing an image-to-video or first-frame video prompt.",
"last_frame_data_url": "Optional inline image data URI for the ending frame when composing an image-to-video transition prompt.",
"return_format": "Requested output format. One of script, markdown, or json. Use script unless structured planning output is explicitly needed."
}
},
{
"contractId": "compose_workflow_v1",
"version": "1.0.0",
"toolName": "compose_workflow",
"baseDescription": "compose_workflow turns a creative brief into a runnable ONE-SHOT durable creative workflow\nplan (the same shape that POST /v1/creative-agent/workflows accepts). Pick this when the\nuser wants to RUN a multi-step pipeline ONCE — they will review the plan, submit it, get\nthe output, and be done. Trigger phrases: \"give me a runnable workflow plan\", \"compose a\none-shot plan\", \"compile a plan I can submit\", \"I want to run this once\", \"I do NOT need\nto save it as a template\", \"just review the steps and run it\", \"5-shot teaser, 9:16, 15s\"\nstyle concrete one-off briefs.\n\nHard line vs compose_workflow_template: if the user wants to SAVE / REUSE / NAME a\nworkflow recipe to re-run later on different inputs, use compose_workflow_template\ninstead. compose_workflow returns a one-time plan with no template wrapper; the user\nCANNOT re-run this output with different inputs without a fresh planner call.\n\nDo not use compose_workflow for ordinary creative writing artifacts — use compose_script for\nscripts, storyboards, ad concepts, or trailers. Do not use it for prompt expansion — use\nenhance_prompt. Do not use it to actually run a workflow — the response is just the plan;\nthe caller is responsible for submitting it to POST /v1/creative-agent/workflows with their\nown Idempotency-Key.\n\nThe returned plan is not idempotent on its own. Pair the eventual workflow submission with\na caller-owned Idempotency-Key. Phase 1 only supports return_format=\"json\".",
"parameterDocs": {
"brief": "Required free-form natural-language description of what the workflow should produce.",
"scene_count": "Suggested number of distinct shots/scenes (1-12). The planner may emit more steps than scenes (for example, a keyframe + clip pair per scene).",
"duration_seconds": "Target total duration in seconds for video-bearing plans (1-120).",
"aspect_ratio": "Output aspect ratio. One of 1:1, 4:3, 3:4, 16:9, 9:16, 21:9.",
"style": "Optional stylistic guidance such as \"cinematic, neon, low-key\" or \"whiteboard illustration\".",
"destination_models": "Optional preferred image/video/music model selectors (e.g. qwen, ltx25, ltx23). Each subkey is optional.",
"max_estimated_capacity_units": "Optional coarse capacity budget. If set, the planner tries to keep total estimated cost at or below this value; the API returns fits_budget=false if it cannot.",
"include_audio": "When true, include a generate_music step in the plan. Defaults to false.",
"return_format": "Reserved for future use; only \"json\" is supported in Phase 1. Omit if unsure."
}
},
{
"contractId": "compose_workflow_template_v1",
"version": "1.0.0",
"toolName": "compose_workflow_template",
"baseDescription": "compose_workflow_template turns a creative brief into a savable, parameterized workflow\ntemplate plus a concrete example plan for the inputs the planner picked. This is the\ntool to use whenever the user wants to CREATE / SAVE / DESIGN / BUILD a reusable\nworkflow recipe — not just run one once. Trigger phrases: \"create a workflow that…\",\n\"save this as a workflow\", \"make me a reusable workflow…\", \"build a workflow that…\",\n\"design a workflow…\", \"I want a recipe for…\", \"I want to be able to re-run this on…\",\n\"save as workflow\", \"turn this into a workflow\", \"workflow that takes X as input\".\n\nThe returned `template_draft` carries typed `inputs[]` (image/audio/video/text/number/\nselect/boolean), parameterized `stages[]` that reference inputs via `$inputs.NAME`\nplaceholders, and an optional `graph` layout the visual builder consumes. A sibling\n`plan` field carries a Phase-1-compatible `steps[]` rendering for the example inputs so\nthe UI can preview the workflow without round-tripping the compiler.\n\nHard line vs direct generation tools: if the user asked to MAKE / SAVE / DESIGN a\nworkflow, never call generate_video, generate_image, edit_image, animate_photo, or any\nother rendering tool directly — that consumes credits to produce one-shot media when\nthe user wanted a reusable recipe. Pick compose_workflow_template instead. After\ncompose_workflow_template returns the template_draft, you MUST immediately call\nfinalize_response next. DO NOT call any other tool after compose_workflow_template —\nno render tools \"to show a preview\", no demonstration runs, nothing. The user reviews\nthe draft in the builder UI, not in chat. Calling generate_image / generate_video /\nedit_image after compose_workflow_template is a fixture-failing mistake.\n\nHard line vs compose_workflow: if the user said \"I do not need to save it as a\ntemplate\", \"give me a runnable plan to submit\", \"one-shot\", \"just run this once\", or\nsimilar single-use phrasing — pick compose_workflow, NOT compose_workflow_template.\ncompose_workflow_template is exclusively for SAVING reusable recipes.\n\nDo not use compose_workflow_template for one-shot turn-by-turn plans — use compose_workflow\ninstead. The returned template is a draft; the caller is responsible for saving it via\nPOST /v1/creative-agent/workflows/templates and minting a stable template id.\n\nEditing an existing template: pass the full template JSON as `existing_template` together\nwith the modification brief and the planner returns a refined `template_draft` that keeps\nthe id stable, bumps the version, preserves stages the brief did not touch, and applies\nthe requested changes. This is the canonical path for \"add a music step\", \"switch the\nstoryboard model to GPT Image 2\", or \"make this 9:16 instead of 16:9\" style edits.\n\nEditing a workflow you cannot see: if the user asks to edit a saved workflow by name or\nid (e.g. \"edit the bobblehead workflow\", \"modify wf_bobblehead_tiktok\") and the\nconversation does not contain the existing template JSON, do NOT call manage_memory and\ndo NOT ask the user to paste the template — just call compose_workflow_template with the\nmodification brief and a sensible name (you may reuse the workflow id the user mentioned).\nOmit existing_template in that case. The planner composes a fresh template_draft that\nrepresents the modification; preserving stage ids only happens when existing_template is\npresent, and that is acceptable — the alternative is a wasted turn.\n\nPhase 2 supports return_format=\"json\" only. Visibility defaults to \"private\"; the \"team\"\nvisibility slot is reserved for a later milestone.",
"parameterDocs": {
"brief": "Required free-form natural-language description of what the workflow should produce. When editing an existing template, phrase the brief as the modification request (e.g. \"Add a music step at the end and make the duration 12s\").",
"name": "Required human-readable template name. Shown in the workflow library and run launcher.",
"description": "Optional template description; the planner derives one from the brief if omitted.",
"category": "Optional category (portrait, video-social, makeover, cinematic, music, analysis, custom, other). Defaults to \"custom\".",
"visibility": "Persistence visibility: \"private\" (default) or \"public\". \"team\" is reserved for a later milestone.",
"inputs": "Optional typed input declarations. When omitted, the planner LLM proposes inputs based on the brief. Each entry needs name + type; required, description, default, options, multiple, and internal are optional refinements.",
"scene_count": "Suggested number of distinct shots/scenes (1-12).",
"duration_seconds": "Target total duration in seconds for video-bearing plans (1-120).",
"aspect_ratio": "Output aspect ratio. One of 1:1, 4:3, 3:4, 16:9, 9:16, 21:9.",
"style": "Optional stylistic guidance such as \"cinematic, neon, low-key\" or \"whiteboard illustration\".",
"destination_models": "Optional preferred image/video/music model selectors (e.g. qwen, ltx25, ltx23). Each subkey is optional.",
"max_estimated_capacity_units": "Optional coarse capacity budget. The planner returns fits_budget=false if it cannot fit under the cap.",
"include_audio": "When true, include a generate_music step in the example plan. Defaults to false.",
"return_format": "Reserved for future use; only \"json\" is supported in Phase 2. Omit if unsure.",
"existing_template": "Optional full WorkflowTemplate JSON. When supplied, the planner edits this template per the brief instead of designing from scratch — preserves stage ids and unchanged stages, bumps version, and applies the requested modifications. Use this for the chat \"edit this workflow\" flow and the builder \"regenerate from prompt\" button."
}
}
];
// physically moved to
// @sogni-ai/sogni-intelligence-client/public-skill-runtime.
// This file is a thin re-export so existing internal imports of
// '../public-skill-runtime/index.js' (and downstream consumers that still
// reference the creative-agent subpath) keep working unchanged.
export * from '@sogni-ai/sogni-intelligence-client/public-skill-runtime';
// PUBLIC_SKILL_SPARK_PACKS_COST_LIMIT_OVERRIDE
import {
PUBLIC_SKILL_DEFAULT_POLICIES as SOGNI_PUBLIC_SKILL_DEFAULT_POLICIES,
PUBLIC_SKILL_DEFAULT_PROMPT_CONTRACTS as SOGNI_PUBLIC_SKILL_DEFAULT_PROMPT_CONTRACTS,
PUBLIC_SKILL_DEFAULT_REPAIR_RECIPES as SOGNI_PUBLIC_SKILL_DEFAULT_REPAIR_RECIPES,
createPublicSkillContractRuntime as createSogniPublicSkillContractRuntime,
} from '@sogni-ai/sogni-intelligence-client/public-skill-runtime';
export const PUBLIC_SKILL_DEFAULT_REPAIR_RECIPES = SOGNI_PUBLIC_SKILL_DEFAULT_REPAIR_RECIPES.map((recipe) =>
recipe.errorCode === 'COST_LIMIT_EXCEEDED'
? { ...recipe, message: "You have hit the credit limit for this turn. Buy Spark Packs to continue: https://docs.sogni.ai/pricing/#spark-packs" }
: recipe
);
export function createPublicSkillDefaultContractRuntime(input = {}) {
return createSogniPublicSkillContractRuntime({
policies: [
...SOGNI_PUBLIC_SKILL_DEFAULT_POLICIES,
...(input.policies ?? []),
],
promptContracts: [
...SOGNI_PUBLIC_SKILL_DEFAULT_PROMPT_CONTRACTS,
...(input.promptContracts ?? []),
],
repairRecipes: [
...PUBLIC_SKILL_DEFAULT_REPAIR_RECIPES,
...(input.repairRecipes ?? []),
],
});
}
// Moved to @sogni-ai/sogni-intelligence-client/skill-runtime-source in Phase 8.4 follow-up.
// This file is kept as a thin re-export so existing internal `testing/`
// callers keep working. New code should import from the public mid-tier:
// import { ... } from '@sogni-ai/sogni-intelligence-client/skill-runtime-source';
export * from '@sogni-ai/sogni-intelligence-client/skill-runtime-source';
export * from '@sogni-ai/sogni-intelligence-client/replay';
export * from '@sogni-ai/sogni-intelligence-client/replay';