Workflows

    Approving or rejecting an agent plan

    Inspect the agent's proposed tool steps, drop the ones you do not want, and only then dispatch. Nothing generates until you approve.

    Versely Team8 min read

    Auto mode is the default because it is what you want when the job is small: one image, one clip, one caption. The moment the agent is about to fan a brief into six tools (generate, upscale, caption, post), auto mode is also how you spend a batch you did not mean to run. Plan mode exists for that moment. The agent still thinks. It still picks tools and fills arguments. It does not dispatch. You get a list of steps, you untick the ones that should not run, and only the rest leave the machine.

    That is an approval gate, not a preview of the pixels. Generations still cost credits when they run. What you buy by switching the toggle is the right to say no before they run.

    Auto versus Plan first

    The chat composer has two modes, labelled Auto and Plan first. Auto sends agent_mode: "auto" (the default if you omit the field). Plan first sends agent_mode: "plan". Same endpoint (POST /api/v1/agentic/chat/stream), same catalog, same credit balance. The difference is what happens when the model emits tool calls.

    In auto, those calls execute. In plan, the first round of tool calls is turned into a plan and cached. The stream sends a plan event with a plan_id, a steps array, and the agent's reasoning text, then a done event with awaiting_approval: true. Nothing in that plan has generated yet. The composer blocks the next turn until you approve or dismiss; the placeholder reads "Approve or dismiss the plan above to continue" for a reason. The server is holding the plan, and a second brief on top of an undecided one is how you get two jobs you cannot tell apart.

    Read-only tools are the exception. check_credits, get_available_models, get_generation_history, check_generation_status, list_user_workflows, get_social_accounts, and a handful of other queries auto-execute even in plan mode, because they cannot spend generation credits and the plan is worse if the agent is guessing at your balance. That is also why a Plan first turn can still show a tool card: it looked something up so the proposal would be real.

    The planning turn itself is billed as planning, against the chat model. Generation credits start after you hit run. If you want a number before that, check credits is a query the agent can run while it is still proposing. The per-step credit_estimate field is only shown when it is actually filled.

    What you are looking at on the card

    Each step has a stable id, a tool_name, a one-line description built from the arguments (model list, a truncated prompt, a platform name), a category (generation, enhancement, workflow, integration, query, analysis), the raw args, and a pending status. The reasoning above the list is the model's explanation, not a contract. The contract is the args.

    Open them. That is the whole point of the gate. A step described as "Generate video using Vidu Q3 Text to Video" is safe to approve if that is the model you wanted. It is not safe to approve because the description sounded right. The models array, the duration, the aspect ratio, and whether image_url is present are in args. If a step is post_to_social_media, the platform and the caption are in args too, which is the step most people should untick until a format has run clean.

    The multi-step automation capability is the kind of brief that belongs in Plan first: several tools, at least one of them irreversible (a post, a scheduled workflow, a batch of generations). A single "make a square product still" does not need the gate. A "make three verticals, caption them, and schedule Thursday" does, because three of those four actions spend credits and the fourth publishes.

    Plans are not durable objects. They sit in cache for five minutes. If you walk away and come back to Run, the execute endpoint returns that the plan was not found or expired, and you resubmit the brief. That is annoying once and then it trains you not to use Plan first as a parking lot. If the work needs to live longer than a coffee, it wants a saved workflow, not an unapproved plan.

    Approve some steps, reject the rest

    Everything on the card starts ticked. Unticking is cheaper than ticking six boxes, and the common case is "yes, do it." The run button sends the selected step ids as approved_step_ids. Omitted ids are marked rejected on the plan and are not executed. An empty selection is disabled in the UI; the API will run every step if you omit approved_step_ids entirely, so if you are calling execute yourself, pass the list on purpose.

    Execute is POST /api/v1/agentic/plan/execute. It is an SSE stream, same event vocabulary as chat (tool_call, generation_dispatched, plan_step_start, plan_step_complete, done). A lock on the plan_id makes a double-tap fail with PLAN_ALREADY_EXECUTING rather than dispatching twice. Already-running or already-finished plans fail with PLAN_NOT_PENDING. Reject is POST /api/v1/agentic/plan/reject: it marks the plan rejected and deletes the cache. No generation, no second chance on that plan_id. Ask again if you still want the work.

    A session that uses the gate the way it is meant to be used:

    1. Switch the composer to Plan first.
    2. Brief: "Three 9:16 product clips of the mug from the attached photo, captions on, do not post."
    3. Read the steps. Confirm the model, the image URL, the count. Untick anything that looks like post_to_social_media or schedule_workflow.
    4. Run the selected steps. Watch the same thread for the outputs.
    5. If a step fails, the plan lands partially_completed. Fix that step in a new turn; do not re-approve the whole card.

    That is also how you keep credit spend inside a budget you actually set. The gate does not make generations cheaper. It stops the unapproved steps from spending credits at all, which is the control that matters when an agent is holding a publish tool.

    Wiring the same gate in a client you own

    The web chat is one client of this API. If you are building a review view, a Slack bot, or an internal ops panel, the sequence is the same.

    # Propose
    curl -N -X POST https://api.versely.studio/api/v1/agentic/chat/stream \
      -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
      -d '{"message":"Three 9:16 mug clips from the attached photo. Do not post.","user_id":"'"$USER_ID"'","conversation_id":"'"$CONVO_ID"'","agent_mode":"plan"}'
    
    # Approve a subset
    curl -N -X POST https://api.versely.studio/api/v1/agentic/plan/execute \
      -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
      -d '{"plan_id":"'"$PLAN_ID"'","approved_step_ids":["'"$STEP_A"'","'"$STEP_B"'"],"user_id":"'"$USER_ID"'"}'
    
    # Or drop it
    curl -X POST https://api.versely.studio/api/v1/agentic/plan/reject \
      -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
      -d '{"plan_id":"'"$PLAN_ID"'","user_id":"'"$USER_ID"'"}'
    

    Auth is a Supabase JWT or a vsk_ API key, same as the rest of the agentic routes. There is no separate plan permission. Ownership is checked on execute and reject: a plan_id from someone else's user fails. Do not store plan_id in a job queue that might fire after five minutes; by then the cache is gone and you need a new propose-and-approve cycle.

    Use Auto inside a single-step loop you already trust. Use Plan first on anything that touches publish, schedule, or a batch whose credit total you have not looked at. The agent will do either. The toggle is the whole feature.

    FAQ

    Does rejecting a plan refund the planning turn?

    Reject deletes the cached plan. It does not rewind the chat turn that produced it. That turn already ran against the chat model and was billed as planning. What you avoid is every generation and publish step on the card. If you want zero spend on a half-formed brief, do not send the brief; the gate starts after the model has already proposed.

    Can I edit a step's arguments before approving?

    Not on the plan object. Untick the bad step, approve the rest, and send a follow-up that names the field you want changed. The plan is a snapshot of the tool calls the model already emitted, not a form. If the arguments are wrong in a way that would stall dispatch (a motion-control model with no driving video), rejecting that step is cheaper than approving it and watching it fail.

    What if I approve and then want to stop?

    Execute is a stream. Closing the client does not unwind work that already dispatched to a provider; those generations are real and the credits are spent. For work that is still running as a background task, cancel is a different endpoint (POST /api/v1/agentic/tasks/:taskId/cancel). The plan lock is there to prevent a second execute, not to provide an undo.

    Should scheduled workflows go through plan mode?

    A one-off "do this now" batch should. A series you already approved last week should be a saved workflow, started with a name you recognise, not a fresh plan every Monday. Plan mode is a human gate on a proposed turn. A pipeline is the gate you already passed, stored. Mixing them (re-proposing a weekly job in Plan first, then forgetting to approve before the five-minute expiry) is how Monday's content does not ship.