
    PL
jR                       U d Z ddlmZ ddlZddlZddlmZmZmZm	Z	 ddl
mZmZmZmZmZ ddlmZmZ  ej        e          Zddd	d
ddd
ddddd
idddddd
 ee          dedd
 ee          dedd
ddddddddd
ddd
dgddZd ed!<   dBd#ZdCd%ZdCd&ZdDd(Zd) ZdEd,ZdFd0ZdGd2Z dHd4Z!dId7Z"d8Z#dJd<Z$dBd=Z% ej&        dd>ee"eg d?d@e%A	  	         dS )Ku>  
Video Generation Tool
=====================

Single ``video_generate`` tool that dispatches to a plugin-registered
video generation provider. Mirrors the ``image_generate`` design:

- ``agent/video_gen_provider.py`` defines the :class:`VideoGenProvider` ABC.
- ``agent/video_gen_registry.py`` holds the active providers (populated by
  plugins at import time).
- Each provider lives under ``plugins/video_gen/<name>/``.

The tool itself is intentionally backend-agnostic and ships **no in-tree
provider** — turn on a backend by enabling a plugin (``hermes plugins
enable video_gen/<name>``) and selecting it in ``hermes tools`` → Video
Generation.

Unified surface
---------------
One tool covers the common cases — text-to-video, image-to-video, video
edit, video extend — with a compact schema:

    prompt                   text instruction (required for generate/edit)
    operation                "generate" | "edit" | "extend"
    image_url                drives image-to-video when operation=generate
    video_url                source video for edit/extend
    reference_image_urls     list, up to provider-declared cap
    duration                 seconds (provider clamps)
    aspect_ratio             "16:9" | "9:16" | "1:1" | ...
    resolution               "480p" | "540p" | "720p" | "1080p"
    negative_prompt          optional (Pixverse/Kling style)
    audio                    optional (Veo3/Pixverse pricing tier)
    seed                     optional
    model                    optional, override the active provider's default

Providers ignore parameters they do not support. The tool layer does
**lightweight** validation (type/required-prompt) and lets each provider
do its own clamping inside :meth:`VideoGenProvider.generate` — that keeps
the tool surface stable as new providers ship with different capabilities.
    )annotationsN)AnyDictListOptional)COMMON_ASPECT_RATIOSCOMMON_RESOLUTIONSDEFAULT_ASPECT_RATIODEFAULT_RESOLUTIONerror_response)registry
tool_errorvideo_generateuG   (rebuilt at get_definitions() time — see _build_dynamic_video_schema)objectstringz\Text instruction describing the desired video, motion, subject, style, camera movement, etc.)typedescriptionzOptional public URL of a still image. When provided, the active backend routes to its image-to-video endpoint (animate the image); when omitted, it routes to text-to-video. Pass either a URL the user supplied or a path/URL from the conversation.arrayr   zOptional list of reference image URLs (style or character refs). Only supported by some backends; the active backend's description below indicates whether this is honored and what the max is.)r   itemsr   integerzDesired video duration in seconds. Providers clamp to their supported range (commonly 4-15s). Omit to use the provider's default.z<Output aspect ratio. Providers clamp to their supported set.)r   enumr   defaultz:Output resolution. Providers clamp to their supported set.u   Optional negative prompt — content to avoid in the output. Supported by Pixverse, Kling, and similar; ignored by providers that do not support it.booleanzkOptional audio generation toggle. Supported by Veo3 and Pixverse (affects pricing tier); ignored elsewhere.z<Optional seed for reproducible outputs (provider-dependent).u   Optional model override. If omitted, the user's configured ``video_gen.model`` (set via `hermes tools` → Video Generation) is used. Models that the active provider does not know are rejected.)
prompt	image_urlreference_image_urlsdurationaspect_ratio
resolutionnegative_promptaudioseedmodelr   )r   
propertiesrequired)namer   
parametersDict[str, Any]VIDEO_GENERATE_SCHEMAreturnc                    	 ddl m}   |             }t          |t                    r|                    d          nd }t          |t                    r|ni S # t
          $ r'}t                              d|           i cY d }~S d }~ww xY w)Nr   )load_config	video_genz#Could not read video_gen config: %s)hermes_cli.configr,   
isinstancedictget	Exceptionloggerdebug)r,   cfgsectionexcs       ?/home/kuhnn/.hermes/hermes-agent/tools/video_generation_tool.py_read_video_gen_sectionr9      s    111111kmm*4S$*?*?I#''+&&&T$Wd33;ww;   :C@@@						s   AA 
B!B=BBOptional[str]c                     t                                          d          } t          | t                    r(|                                 r|                                 S d S )Nproviderr9   r1   r/   strstripvalues    r8   _read_configured_video_providerrB      sO    #%%))*55E% %++-- {{}}4    c                     t                                          d          } t          | t                    r(|                                 r|                                 S d S )Nr#   r=   r@   s    r8   _read_configured_video_modelrE      sO    #%%))'22E% %++-- {{}}4rC   boolc                     	 ddl m}  ddlm}  |              |             D ]*}	 |                                r dS # t
          $ r Y 'w xY wn# t
          $ r Y nw xY wdS )zReturn True when at least one registered provider reports available.

    Triggers plugin discovery (idempotent) so user-installed plugins are
    visible to the toolset gate.
    r   )list_providers_ensure_plugins_discoveredTF)agent.video_gen_registryrH   hermes_cli.pluginsrJ   is_availabler2   )rH   rJ   r<   s      r8   #check_video_generation_requirementsrN      s    ;;;;;;AAAAAA""$$$&(( 	 	H((**  44    		    5s6   "A =A A 
A
A 	A

A 
AAc                     	 ddl m}  ddlm}  |              |             }| |d            |             }|S # t          $ r&}t
                              d|           Y d}~dS d}~ww xY w)u   Return the active provider object or None.

    Forces plugin discovery before checking the registry — handles cases
    where a long-lived session was started before a plugin was installed.
    r   )get_active_providerrI   NT)forcez(video_gen provider resolution failed: %s)rK   rP   rL   rJ   r2   r3   r4   )rP   rJ   r<   r7   s       r8   _resolve_active_providerrR      s    @@@@@@AAAAAA""$$$&&((&&T2222**,,H   ?EEEttttts   9< 
A,A''A,
configuredr>   c                    | r*d|  d}t          j        t          |d|                     S d}t          j        t          |d                    S )Nzvideo_gen.provider='u   ' is set but no plugin registered that name. Run `hermes plugins list` to see installed video gen backends, or `hermes tools` → Video Generation to pick one.provider_not_registered)error
error_typer<   u{   No video generation backend is configured. Run `hermes tools` → Video Generation to enable one (xAI, FAL, or Google Veo).no_provider_configured)rV   rW   )jsondumpsr   )rS   msgs     r8   _missing_provider_errorr\      s     
': ' ' ' 	 z.";
 
 
   	
	D  :n6     rC   rA   r   Optional[int]c                f    | | dk    rd S 	 t          |           S # t          t          f$ r Y d S w xY w)N )int	TypeError
ValueErrorr@   s    r8   _coerce_intrc     sL    }t5zzz"   tts    00Optional[bool]c                    | d S t          | t                    r| S t          | t                    r2|                                                                 }|dv rdS |dv rdS d S )N>   1onyestrueT>   0noofffalseF)r/   rF   r>   r?   lower)rA   vs     r8   _coerce_boolrp     su    }t% % KKMM!!***4+++54rC   Optional[List[str]]c                ,   | d S t          | t                    r| g} t          | t          t          f          sd S g }| D ]R}t          |t                    r;|                                r'|                    |                                           S|pd S N)r/   r>   listtupler?   append)rA   outitems      r8   _normalize_reference_imagesry   (  s    }t% edE]++ tC % %dC   	%TZZ\\ 	%JJtzz||$$$;$rC   args_kwc                `   |                      d          pd                                }|                      d          pd                                pd }t          |                      d                    }t          |                      d                    }|                      d          pt                                          pt          }|                      d          pt
                                          pt
          }|                      d          pd                                pd }t          |                      d	                    }	t          |                      d
                    }
|                      d          pd                                pd }|st          d          S t                      }t                      }|t          |          S |p!t                      p|                                }||||||||	|
d	}d |                                D             }	  |j        dd|i|}n# t          $ r}t                               dt%          |dd          |           t'          j        t+          dt%          |dd           ddt%          |dd          |pd|                    cY d }~S d }~wt,          $ r}t                               dt%          |dd          |           t'          j        t+          dt%          |dd           d| dt%          |dd          |pd|                    cY d }~S d }~ww xY wt/          |t0                    s7t'          j        t+          ddt%          |dd          |pd|                    S t'          j        |          S )Nr   r_   r   r   r   r   r   r    r!   r"   r#   z'prompt is required for video generation)	r#   r   r   r   r   r   r    r!   r"   c                    i | ]
\  }}|||S rs    ).0kro   s      r8   
<dictcomp>z*_handle_video_generate.<locals>.<dictcomp>]  s    ???tq!arC   zBvideo_gen provider '%s' rejected kwargs (signature too narrow): %sr&   ?z
Provider 'z\' signature is out of date with the video_generate schema. Report this to the plugin author.provider_contract)rV   rW   r<   r#   r   z"video_gen provider '%s' raised: %sz	' error: provider_exceptionz#Provider returned a non-dict resultr~   )r1   r?   ry   rc   r
   r   rp   r   rB   rR   r\   rE   default_modelr   generatera   r3   warninggetattrrY   rZ   r   r2   r/   r0   )rz   r{   r   r   r   r   r   r   r    r!   r"   model_overriderS   r<   r#   kwargsresultr7   s                     r8   _handle_video_generater   6  s   hhx  &B--//F+&&,"3355=I6txx@V7W7WXX488J//00HHH^,,D0DKKMMeQeL((<((>,>EEGG]K]Jxx 1228b??AAITO'**++Etxx''((Dhhw''-24466>$N
  ECDDD 122J'))H&z222 X:<<X@V@V@X@XE  4$ *
 
F @?v||~~???F"";;&;F;;    	PHfc**C	
 	
 	
 z.)WXvs;; ) ) ) +Xvr22+2

 

 

 
 
 
	 
	 
	 
	 
	 
	    0Hfc**C	
 	
 	
 z.Mwx==MMMM+Xvr22+2
 
 
   	 	 	 	 	 	 fd## z.7*Xvr22+2
 
 
   	 :fs2   *H; ;
MA4J?9M?MA6MMMu  Generate a video from a text prompt (text-to-video) or animate a still image (image-to-video) using the user's configured video generation backend. Pass `image_url` to animate that image; omit it to generate from text alone. The backend auto-routes to the right endpoint. The backend and model family are user-configured via `hermes tools` → Video Generation; the agent does not pick them. Long-running generations may take 30 seconds to several minutes — the call blocks until the video is ready. Returns either an HTTP URL or an absolute file path in the `video` field; display it with markdown ![description](url-or-path) and the gateway will deliver it.
model_metabackend_caps	List[str]c                    g }t          |                     d          pg           }|                     d          }|r|                    |           d|v rd|vr|                    d           nd|v rd|vr|                    d           |S )u   Pull human-readable caveats out of one model's catalog metadata.

    Only surfaces things that meaningfully differ from the backend's
    overall capabilities — repeating defaults is noise.
    
modalitiesmodalityimagetextu]   this model is image-to-video only — image_url is REQUIRED; text-only calls will be rejectedu?   this model is text-to-video only — image_url is not supported)setr1   addrv   )r   r   caveatsr   r   s        r8   _format_model_caveatsr     s     GZ^^L117R88J~~j))H !x   *z!9!9/	
 	
 	
 	
 
:		'";";M	
 	
 	
 NrC   c                    t           g} t                      }t                      }|s,|                     d           dd                    |           iS 	 ddlm} ddlm}  |              ||          }n# t          $ r d}Y nw xY w|0|                     d| d	           dd                    |           iS 	 |
                                pi }n# t          $ r i }Y nw xY w	 |                                pg }n# t          $ r g }Y nw xY w|p|                                t          fd
|D             i           }|j        }	d|	 }
r|
d z  }
|                     |
           t          ||          D ]}|                     d|            t!          |                    d          pg           }d|v r.d|v r*|                    d          s|                     d           |                    d          r1|                     dd                    |d                               |                    d          r1|                     dd                    |d                               |                    d          r=|                    d          r(|                     d|d          d|d          d           |                    d          r|                     d           |                    d          r|                     d           |                    d           pd}|r|                     d!| d"           dd                    |           iS )#a\  Build a description that reflects the active backend's actual surface.

    Cheap: reads config (already memoized by the caller), asks the active
    provider for `capabilities()` and the active model's catalog entry,
    and formats a few lines of prose. Falls back to the generic
    description when no provider is configured or registered.
    u}   
No video backend is configured. Calls will return an error until the user picks one via `hermes tools` → Video Generation.r   
r   )get_providerrI   Nz
Active backend: uI    (plugin not yet loaded — the tool will retry discovery on first call).c              3  x   K   | ]4}t          |t                    |                    d           k    0|V  5dS )idN)r/   r0   r1   )r   mactive_models     r8   	<genexpr>z._build_dynamic_video_schema.<locals>.<genexpr>  sF      RRqjD11RaeeDkk\6Q6Q6Q6Q6Q6QRRrC   u    · model: z- r   r   r   r   uk   - supports both text-to-video (omit image_url) and image-to-video (pass image_url) — routes automaticallyaspect_ratiosz- aspect_ratio choices: z, resolutionsz- resolution choices: min_durationmax_durationz- duration range: -ssupports_audioz@- audio: pass `audio=true` to enable native audio (pricing tier)supports_negative_promptz- negative_prompt: supportedmax_reference_imagesz- reference_image_urls: up to z images)_GENERIC_DESCRIPTIONrB   rE   rv   joinrK   r   rL   rJ   r2   capabilitieslist_modelsr   nextdisplay_namer   r   r1   )partsrS   configured_modelr   rJ   r<   capsmodelsr   backend_labellinecr   max_refsr   s                 @r8   _build_dynamic_video_schemar     sC    --E022J355 1P	
 	
 	
 tyy//00999999AAAAAA""$$$<
++    9 9 9 9	
 	
 	
 tyy//00$$&&,"   %%''-2    $?x'='='?'?LRRRRFRRR
 J
 )M///D -,l,,,	LL #:t44  X!XX
 TXXl++1r22J: 5 5jnnZ>X>X 5G	
 	
 	

 xx   TR		$:O0P0PRRSSSxx PNdii]8K.L.LNNOOOxx 
DHH^$<$< 
On!5OO^8LOOO	
 	
 	
 xx !! YWXXXxx*++ 53444xx.//41H IGhGGGHHH499U++,,s6   !A7 7BB<C C"!C"&C= =DDr-   Fu   🎬)	r&   toolsetschemahandlercheck_fnrequires_envis_asyncemojidynamic_schema_overrides)r*   r(   )r*   r:   )r*   rF   )rS   r:   r*   r>   )rA   r   r*   r]   )rA   r   r*   rd   )rA   r   r*   rq   )rz   r(   r{   r   r*   r>   )r   r(   r   r(   r*   r   )'__doc__
__future__r   rY   loggingtypingr   r   r   r   agent.video_gen_providerr   r	   r
   r   r   tools.registryr   r   	getLogger__name__r3   rt   r)   __annotations__r9   rB   rE   rN   rR   r\   rc   rp   ry   r   r   r   r   registerr~   rC   r8   <module>r      sd  ' ' 'R # " " " " "   , , , , , , , , , , , ,              0 / / / / / / /		8	$	$  ] !<  !;	 	   (+;		% 	% "*  !122 0  !/00 .  !C    "J  ""  !; YU
 U
l JqY Yc) c)  c c c cV	 	 	 	         6  *   4         S S S SP	L    :W- W- W- W-~  	 "0
8
 
 
 
 
 
rC   