
    5pjO<                        % S r SSKJr  SSKrSSKrSSKrSSKJr  SSKJ	r	  SSK
Jr  SSKJr  SS	KJrJr  \R"                  " S
5      r\" 1 Sk5      rS\S'   SrS\S'   \ " S S5      5       rSS jr " S S5      rg)a  HTTP client for ModelScope Hub agent-repository API.

Endpoints:

* ``GET  /openapi/v1/users/me``                            -> login
* ``GET  /openapi/v1/agents/{path}/{name}``                -> repo metadata
* ``POST /openapi/v1/agents``                              -> create empty agent
* ``GET  /api/v1/agents/{path}/{name}/repo/files``         -> list files
* ``GET  /agents/{path}/{name}/resolve/{rev}/{file}``      -> file download
* ``POST /api/v1/repos/agents/{id}/commit/{rev}``          -> commit files (normal/lfs)
* ``POST /api/v1/repos/agents/{id}/info/lfs/objects/batch`` -> LFS batch verify
* ``DELETE /api/v1/agents/{path}/{name}/repo/file``        -> delete file
    )annotationsN)	dataclass   )OpenAPIClient)	HubConfig)
Visibility)AuthenticationErrorNotExistErrorzmodelscope_hub.agent>4   .7z.gz.h5.ot.pb.pt.xz.aac.bin.bmp.bz2.ftz.gif.jpg.lz4.mp3.mp4.npy.npz.ogg.pcm.pkl.png.pth.rar.raw.sam.tar.tgz.wav.zip.zst.ckpt.flac.jack.jpeg.onnx.tiff.wasm.webm.webp.arrow.audio.jsonl.model.joblib.pickle.tflite.mlmodel.msgpack.parquet.safetensorszfrozenset[str]_LFS_EXTENSIONSi   int_LFS_SIZE_THRESHOLDc                  <    \ rS rSr% SrS\S'   S\S'   SrS\S'   S	rg
)RemoteFileInfo\   z4Metadata for a single file in the remote repository.strpathsha256Fboolis_lfs N)__name__
__module____qualname____firstlineno____doc____annotations__rI   __static_attributes__rJ       U/var/www/html/pdf-tiff/venv/lib/python3.13/site-packages/modelscope_hub/agent/_api.pyrC   rC   \   s    >
IKFDrR   rC   c                    [         R                  R                  U 5      S   R                  5       nU[        ;   a  gU[
        :  a  gg)zDetermine whether a file should use LFS upload.

A file is considered LFS if:
1. Its extension is in the known LFS extension set, OR
2. Its size exceeds the LFS threshold (1 MB).
   TF)osrF   splitextlowerr?   rA   )	file_pathsizeexts      rS   is_lfs_filer\   e   s@     ''

9
%a
(
.
.
0C
o!!rR   c                  T   \ rS rSrSr   SSS.       SS jjjrSS jrSS jrSSS jjrSSS	 jjr	SSS
 jjr
SS S jjrS!S jr SSS.         S"S jjjr S#           S$S jjrS%S jrS&S jr   S'               S(S jjr S)           S*S jjrSrg)+AgentApit   a  HTTP client for ModelScope Hub agent-repository API.

This is the primary programmatic interface for interacting with agent
repositories on ModelScope Hub.

Parameters
----------
config : HubConfig or None
    Pre-built configuration. When provided, *endpoint* and *token* are
    ignored and the config is used directly.
endpoint : str or None
    Hub API endpoint (fallback: HubConfig default).
token : str or None
    API token (fallback: HubConfig default / ``ms login``).
timeout : int
    HTTP request timeout in seconds.
N)configc                  U=(       d	    [        XS9U l        U R                  R                  =(       d    SR                  S5      U l        U R                  R
                  U l        X0l        [        U R                  [        U5      S9U l	        g )N)endpointtoken /)r`   timeout)
r   _configrb   rstripserverrc   rf   r   float_openapi)selfrb   rc   rf   r`   s        rS   __init__AgentApi.__init__   sb     JH!J||,,2::3?\\''
%T\\5>RrR   c                    U R                   R                  SSU SU 3SS9$ ! [         a     g[         aL    U R                   SU SU S3n U R                   R                  SUS	S	S
.SS9  O! [         a      gf = f0 s $ f = f)a  Repo metadata or None if the repo does not exist (404).

The ``/openapi/v1/agents`` metadata endpoint rejects anonymous
callers (401) even for public repos. In that case fall back to the
public ``/api/v1`` file-tree endpoint as an existence probe so that
anonymous downloads of public repos keep working; the fallback
carries no ``Framework`` metadata, which only authenticated flows
(e.g. the upload framework guard) consume.
GET/agents/re   F)require_tokenN/api/v1/agents//repo/files1)	page_sizepageurlparamsrr   )rk   requestr
   r	   ri   )rl   rF   name	probe_urls       rS   	repo_infoAgentApi.repo_info   s    	==(((4&$0HX](^^ 	" 	;;-tfAdV;OI%%!),c:"'	 &  ! I	s8    # 
BBA.-B.
A<8B;A<<BBc                (    U R                  X5      SL$ )z&True if the repo exists, False on 404.N)r~   )rl   rF   r|   s      rS   
check_repoAgentApi.check_repo   s    ~~d)55rR   c                  ^
 / nU(       a  UR                  SSU/S.5        UUSSUS.nU R                   S3nU R                  R                  SXeS	S
9m
[	        T
[
        5      (       a  T
[        T
5      S.$ [	        T
[        5      (       a\  [        U
4S jS 5       / 5      n[	        U[
        5      (       d  / n[        U
4S jS 5       [        U5      5      n [        U5      n	XyS.$ / SS.$ ! [        [        4 a    [        U5      n	 N&f = f)a  List agent repositories (PUT /api/v1/dolphin/agents).

Queries the dolphin search endpoint. When *owner* is given it is sent as
a ``Path contains`` criterion (the group filter). Returns a dict with
'items' (list of agent metadata dicts) and 'total_count' (int).
Pathcontains)Category	PredicateStringValuesrd   Default)PageSize
PageNumberQuerySort	Criterionz/api/v1/dolphin/agentsPUTF)ry   	json_bodyrr   )itemstotal_countc              3  <   >#    U  H  oT;   d  M
  TU   v   M     g 7fNrJ   .0kdatas     rS   	<genexpr>'AgentApi.list_agents.<locals>.<genexpr>   s     a"SQ\`W`a"Ss   	)	AgentListAgentsagentsDatar   c              3  L   >#    U  H  oT;   d  M
  TU   c  M  TU   v   M     g 7fr   rJ   r   s     rS   r   r      s)     n"HQQUIZ^_`Zaa"Hs   	$$$)
TotalCountTotalr   r   )appendri   rk   r{   
isinstancelistlendictnextr@   
ValueError	TypeError)rl   ownerpage_numberrv   	criterionbodylist_urlr   	total_valtotalr   s             @rS   list_agentsAgentApi.list_agents   s"    !#	 &!+%*G "%"
 kk]"89}}$$UX]$^dD!!!#d)<<dD!!a"SaE eT**n"HnE
I#I #99A.. 	* #E
#s   C, ,D
	D
c                    [         R                  R                  [         R                  R                  4nXE;  a  [	        SU SU< 35      eXUS.nU(       a  X6S'   U R
                  R                  SSUS9$ )a  Create an empty agent (POST /agents).

The server creates a bare repository.  Files are added separately via
:meth:`commit_files`.

Args:
    framework: Optional product/framework identifier stored with the
               repo (e.g. "qoder", "nanobot").  Defaults to server-side
               default when omitted.
    visibility: Repository visibility, ``"public"`` (default) or
                ``"private"``.
zvisibility must be one of z, got )rF   r|   
visibility	frameworkPOSTz/agents)r   )r   PUBLIClabelPRIVATEr   rk   r{   )rl   rF   r|   r   r   allowedr   s          rS   create_repoAgentApi.create_repo   sv     $$**J,>,>,D,DE$9'&WXX"
K )}}$$VY$$GGrR   c                    U R                  XU5      nU Vs/ s H  oUS   S:X  d  M  US   (       d  M  US   PM      sn$ s  snf )z;All file paths in the repo, recursing into sub-directories.typeblobrF   )_fetch_tree_entries)rl   rF   r|   revisionentrieses         rS   list_repo_filesAgentApi.list_repo_files   sC    **4x@#*P7ai6.A	ai	&	7PPPs   ??	?c                   U R                  XU5      n/ nU Hf  nUS   S:w  d
  US   (       d  M  UR                  [        US   UR                  S5      =(       d    S[	        UR                  SS5      5      S95        Mh     U$ )	z+All blob files with sha256 and is_lfs flag.r   r   rF   rG   rd   rI   F)rF   rG   rI   )r   r   rC   getrH   )rl   rF   r|   r   r   resultsitems          rS   list_repo_files_detailAgentApi.list_repo_files_detail   s~    **4x@(*DF|v%T&\NNf88H-35 9:  rR   c                   SnSnSn/ nU R                    SU SU S3n U R                  R                  SUS[        U5      [        U5      US	.S
S9n	/ n
[	        U	[
        5      (       a3  U	R                  S5      =(       d    U	R                  S5      =(       d    / n
O[	        U	[        5      (       a  U	n
U
 H  n[	        U[
        5      (       d  M  UR                  UR                  S5      =(       d    UR                  S5      =(       d    SUR                  S5      =(       d    UR                  S5      =(       d    SUR                  S5      =(       d    UR                  S5      =(       d    S[        UR                  S5      =(       d    UR                  S5      =(       d    S
5      S.5        M     [        U
5      U:  a   U$ US-  nXF:  a  [        R                  SUUU5         U$ GM  )zFFetch and normalize the repo file tree from the API (with pagination).rU   d   2   rs   re   rt   rp   true)	recursiverv   rw   r   Frx   Treestreesr   rF   rd   Typer   Sha256rG   IsLfsrI   )rF   r   rG   rI   zIPagination limit reached (%d pages) for %s/%s; results may be incomplete.)ri   rk   r{   rE   r   r   r   r   r   rH   r   loggerwarning)rl   rF   r|   r   rw   rv   	max_pagesall_entriesr   r   rawr   s               rS   r   AgentApi._fetch_tree_entries  s   		"$kk]/$qkJ==((!'!$YI (	 $ ) 
D C$%%hhw'B488G+<BD$''!$--"" $ 0 JDHHV4D J $ 0 JDHHV4D J"&((8"4"P8J"Pb"&txx'8'WDHHX<N'WRW"X	  3x)#  AID_	 W rR   F)binaryc          	         U R                    SU SU SU SU 3	nU R                  R                  SUSSS9nU(       a  UR                  $ UR                  $ )zJDownload one repo file.

Returns bytes when *binary=True*, otherwise str.
rq   re   z	/resolve/rp   F)ry   unwraprr   )ri   rk   r{   contenttext)rl   rF   r|   rY   r   r   dl_urlresps           rS   download_repo_fileAgentApi.download_repo_fileB  s]     KK=avYxj)U}}$$UuTY$Z%t||44994rR   c                l    U R                    SU SU SU 3nXSS.nU R                  R                  SXgS9$ )a  Commit file changes via POST /api/v1/repos/agents/{path}/{name}/commit/{revision}.

Each action dict should contain:
  - action: "create" | "update" | "delete"
  - path: file path in repo
  - type: "normal" | "lfs"  (for create/update)
  - size: file size in bytes (for create/update)
  - sha256: sha256 hash (required for lfs; empty string for normal)
  - content: base64-encoded content (for normal) or empty (for lfs)
  - encoding: "base64" (for normal) or "" (for lfs)
/api/v1/repos/agents/re   z/commit/)commit_messageactionsr   ry   r   ri   rk   r{   )rl   rF   r|   r   r   r   
commit_urlr   s           rS   commit_filesAgentApi.commit_filesO  sG     }$9$qhxjY
"0E}}$$V$LLrR   c                `   U R                    SU SU S3nSX4S./S.nU R                  R                  SXVS9n/ n[        U[        5      (       a  UR                  S	5      =(       d    / nU(       d  g
US   R                  S0 5      R                  S0 5      n	U	R                  S5      =(       d    S
$ )zLFS batch verify and return upload URL (or None if already exists).

POST /api/v1/repos/agents/{path}/{name}/info/lfs/objects/batch
Returns the upload href if the server needs the blob, None otherwise.
r   re   z/info/lfs/objects/batchupload)oidrZ   )	operationobjectsr   r   r   Nr   r   href)ri   rk   r{   r   r   r   )
rl   rF   r|   r   rZ   	batch_urlr   r   r   upload_infos
             rS   	lfs_batchAgentApi.lfs_batcha  s     {{m#8avE\]	! #23
 }}$$V$K dD!!hhy)/RGajnnY377"Ev&.$.rR   c                n    U R                   R                  SUUSS0SS[        U R                  S5      S9  g)z&PUT binary data to the LFS upload URL.r   zContent-Typezapplication/octet-streamFi,  )ry   r   headersrr   r   rf   N)rk   r{   maxrf   )rl   
upload_urlr   s      rS   lfs_upload_blobAgentApi.lfs_upload_blobw  s?    #%?@c* 	 	
rR   c                    [         R                  " U5      R                  5       n[        U5      n	U R	                  XX5      n
U
(       a  U R                  X5        UUSU	USSS./nU R                  XXUS9$ )zFull LFS upload flow: batch verify -> PUT blob -> commit reference.

Combines lfs_batch + lfs_upload_blob + commit_files for one file.
lfsrd   )actionrF   r   rZ   rG   r   encoding)r   r   )hashlibrG   	hexdigestr   r   r   r   )rl   rF   r|   rY   r   r   r   r   r   rZ   r   r   s               rS   upload_lfs_fileAgentApi.upload_lfs_file  s     nnW%//17| ^^D:
  5
 !!

   WXf ggrR   c                    U R                    SU SU S3nUUU=(       d    SU 3S.nU R                  R                  SXgS9$ )zLDelete a file from the repo.

DELETE /api/v1/agents/{path}/{name}/repo/file
rs   re   z
/repo/filezDelete )branchrY   r   DELETEr   r   )rl   rF   r|   rY   r   r   
delete_urlr   s           rS   delete_fileAgentApi.delete_file  sX     }OD64&
K
",E')0E

 }}$$X:$NNrR   )rg   rk   ri   rf   rc   )NN<   )rb   
str | Nonerc   r  rf   r@   r`   zHubConfig | None)rF   rE   r|   rE   returnzdict | None)rF   rE   r|   rE   r  rH   )NrU   
   )r   r  r   r@   rv   r@   r  r   )Npublic)
rF   rE   r|   rE   r   r  r   rE   r  r   )master)rF   rE   r|   rE   r   rE   r  z	list[str])rF   rE   r|   rE   r   rE   r  zlist[RemoteFileInfo])rF   rE   r|   rE   r   rE   r  
list[dict])
rF   rE   r|   rE   rY   rE   r   rE   r   rH   )r  sync)rF   rE   r|   rE   r   r  r   rE   r   rE   r  r   )
rF   rE   r|   rE   r   rE   rZ   r@   r  r  )r   rE   r   bytesr  None)creater  r  )rF   rE   r|   rE   rY   rE   r   r  r   rE   r   rE   r   rE   r  r   )r  N)rF   rE   r|   rE   rY   rE   r   rE   r   r  r  r   )rK   rL   rM   rN   rO   rm   r~   r   r   r   r   r   r   r   r   r   r   r  r
  rQ   rJ   rR   rS   r^   r^   t   s   (  $ 	S $(SS S 	S !S 66+/ZH*Q
 3l EM	5`e	5	5"	5/2	5>A	5Y]	5 jpMM"M-7MCFMcfM	M$/,

$  $#h#h #h 	#h
 #h #h #h #h 
#hL lpOO"O/2O>AO^hO	O OrR   r^   )rY   rE   rZ   r@   r  rH   )rO   
__future__r   r  loggingrV   dataclassesr   rk   r   r`   r   	constantsr   errorsr	   r
   	getLoggerr   	frozensetr?   rP   rA   rC   r\   r^   rJ   rR   rS   <module>r     s    #   	 ! $  " 7			1	2 #,57# 7t + S *   AO AOrR   