agent-lab-sdk 0.1.35__py3-none-any.whl → 0.1.49__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ import os
2
+ from typing import Optional
3
+ import logging
4
+ import requests
5
+ from urllib.parse import urljoin
6
+ from pydantic import BaseModel
7
+ import httpx
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class FileUploadResponse(BaseModel):
13
+ """Ответ от сервиса загрузки файлов"""
14
+ id: Optional[str] = None
15
+ bucket: Optional[str] = None
16
+ key: Optional[str] = None
17
+ storage: Optional[str] = None
18
+ absolute_path: str
19
+
20
+
21
+
22
+ def _get_upload_path(root: str):
23
+ return urljoin(root, "files/v2/upload")
24
+
25
+ def upload_file(filename: str, file_bytes: bytes) -> Optional[FileUploadResponse]:
26
+ """
27
+ Загружает файл в бинарном формате через v2 API и возвращает информацию о загруженном файле.
28
+
29
+ Args:
30
+ filename: имя файла
31
+ file_bytes: содержимое файла в виде байтов
32
+
33
+ Returns:
34
+ FileUploadResponse с информацией о файле или None в случае ошибки
35
+ """
36
+
37
+ ai_agent = os.getenv("AGENT_SERVICE_NAME")
38
+ if not ai_agent:
39
+ raise ValueError("AGENT_SERVICE_NAME environment variable is required")
40
+
41
+ gateway_url = os.getenv("STORAGE_PROVIDER_AGW_URL", "http://localhost")
42
+ url = _get_upload_path(gateway_url)
43
+
44
+ headers = {
45
+ "x-agent-id": ai_agent,
46
+ "Content-Type": "application/octet-stream"
47
+ }
48
+
49
+ params = {
50
+ "name": filename
51
+ }
52
+
53
+ try:
54
+ response = requests.post(
55
+ url,
56
+ headers=headers,
57
+ params=params,
58
+ data=file_bytes
59
+ )
60
+ response.raise_for_status()
61
+
62
+ if response.status_code == 200:
63
+ data = response.json()
64
+ return FileUploadResponse(
65
+ id=data.get("id", ""),
66
+ bucket=data.get("bucket", ""),
67
+ key=data.get("key", ""),
68
+ storage=data.get("storage", ""),
69
+ absolute_path=data.get("absolutePath", "")
70
+ )
71
+
72
+ except requests.exceptions.RequestException as e:
73
+ print(f"Ошибка при загрузке файла через v2 API: {e}")
74
+
75
+ return None
76
+
77
+
78
+ async def async_upload_file(filename: str, file_bytes: bytes, timeout=30.) -> Optional[FileUploadResponse]:
79
+ """
80
+ Асинхронная версия upload_file
81
+
82
+ Args:
83
+ filename: имя файла
84
+ file_bytes: содержимое файла в виде байтов
85
+
86
+ Returns:
87
+ FileUploadResponse с информацией о файле или None в случае ошибки
88
+ """
89
+
90
+ ai_agent = os.getenv("AGENT_SERVICE_NAME")
91
+ if not ai_agent:
92
+ raise ValueError("AGENT_SERVICE_NAME environment variable is required")
93
+
94
+ gateway_url = os.getenv("STORAGE_PROVIDER_AGW_URL", "http://localhost")
95
+ url = _get_upload_path(gateway_url)
96
+
97
+ headers = {"x-agent-id": ai_agent, "Content-Type": "application/octet-stream"}
98
+ params = {"name": filename}
99
+
100
+ logger.debug(
101
+ f"V2 upload request, filename: {filename}, size: {len(file_bytes)}, url: {url}, agent-id: {ai_agent}"
102
+ )
103
+ try:
104
+ async with httpx.AsyncClient(verify=False, trust_env=True) as client:
105
+ response = await client.post(
106
+ url=url,
107
+ headers=headers,
108
+ params=params,
109
+ content=file_bytes,
110
+ timeout=timeout,
111
+ )
112
+ response.raise_for_status()
113
+
114
+ data = response.json()
115
+ return FileUploadResponse(
116
+ id=data.get("id", ""),
117
+ bucket=data.get("bucket", ""),
118
+ key=data.get("key", ""),
119
+ storage=data.get("storage", ""),
120
+ absolute_path=data.get("absolutePath", ""),
121
+ )
122
+
123
+ except httpx.HTTPStatusError as err:
124
+ try:
125
+ error_text = err.response.text
126
+ except httpx.StreamError:
127
+ error_text = "empty_stream"
128
+ logger.error(f"HTTP Status Error: {err.response.status_code} - {error_text}")
129
+ except httpx.HTTPError as err:
130
+ logger.error(f"Unable to upload filename: {filename} because of {err}")
131
+ logger.exception(f"Upload error: {err}, filename: {filename}")
132
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-lab-sdk
3
- Version: 0.1.35
3
+ Version: 0.1.49
4
4
  Summary: SDK для работы с Agent Lab
5
5
  Author-email: Andrew Ohurtsov <andermirik@yandex.com>
6
6
  License: Proprietary and Confidential — All Rights Reserved
@@ -25,6 +25,7 @@ Requires-Dist: prometheus-client
25
25
  Requires-Dist: langchain
26
26
  Requires-Dist: httpx
27
27
  Requires-Dist: orjson
28
+ Requires-Dist: cloudpickle
28
29
  Dynamic: license-file
29
30
 
30
31
  # Agent Lab SDK
@@ -219,7 +220,32 @@ from agent_lab_sdk.storage import store_file_in_sd_asset
219
220
  store_file_in_storage("my-agent-name-filename.png", file_b64, "giga-agents")
220
221
  ```
221
222
 
222
- ### 4.2 AGW Checkpointer
223
+ ### 4.2 V2 File Upload
224
+
225
+ Новый v2 API для загрузки файлов через Agent Gateway с поддержкой бинарных данных и автоматическим выбором сервиса хранения.
226
+
227
+ ```python
228
+ from agent_lab_sdk.storage import upload_file, FileUploadResponse
229
+
230
+ # Загрузка из байтов
231
+ with open("document.pdf", "rb") as f:
232
+ file_bytes = f.read()
233
+ result: FileUploadResponse = upload_file("document.pdf", file_bytes)
234
+
235
+ # Результат - Pydantic модель с информацией о файле
236
+ print(f"File ID: {result.id}")
237
+ print(f"Absolute Path: {result.absolute_path}")
238
+ print(f"Storage: {result.storage}")
239
+ ```
240
+
241
+ #### Переменные окружения для V2 Upload
242
+
243
+ | Переменная | Описание | Значение по умолчанию |
244
+ | -------------------------- | ---------------------------------- | --------------------- |
245
+ | `AGENT_SERVICE_NAME` | Имя сервиса агента (обязательно) | - |
246
+ | `STORAGE_PROVIDER_AGW_URL` | URL Agent Gateway | `http://localhost` |
247
+
248
+ ### 4.3 AGW Checkpointer
223
249
 
224
250
  AGW поддерживает langgraph checkpoint API и в SDK представлен `AsyncAGWCheckpointSaver`, который позволяет сохранять состояние графа в AGW напрямую.
225
251
 
@@ -236,7 +262,7 @@ from typing import List, Annotated
236
262
  from pydantic import BaseModel, Field
237
263
  from agent_lab_sdk.schema import (
238
264
  MainInput, StringInput, StringArrayInput, NumberInput,
239
- SelectInput, CheckboxInput, FileInput, FilesInput, SelectOption
265
+ SelectInput, CheckboxInput, FileInput, FilesInput, SelectOption, Visibility
240
266
  )
241
267
 
242
268
  class AgentState(BaseModel):
@@ -247,7 +273,8 @@ class AgentState(BaseModel):
247
273
  title: Annotated[str, StringInput(
248
274
  default="Без названия",
249
275
  title="Заголовок",
250
- description="Название для вашего запроса"
276
+ description="Название для вашего запроса",
277
+ visibility=Visibility.ALWAYS # или visibility="always"
251
278
  )]
252
279
 
253
280
  # Массив строк
@@ -288,31 +315,35 @@ class AgentState(BaseModel):
288
315
  # Загрузка одного файла
289
316
  document: Annotated[str, FileInput(
290
317
  title="Документ",
291
- file_extensions=".pdf,.docx,.txt"
318
+ file_extensions=".pdf,.docx,.txt",
319
+ view="button" # или "dropzone" для drag-and-drop,
320
+ max_size_mb=15.0 # применяем ограничение максимального размера для одного файла
292
321
  )]
293
-
322
+
294
323
  # Загрузка нескольких файлов
295
324
  attachments: Annotated[List[str], FilesInput(
296
325
  title="Прикрепленные файлы",
297
326
  file_extensions=".pdf,.csv,.xlsx",
298
- group="Файлы"
327
+ group="Файлы",
328
+ view="dropzone" # область перетаскивания файлов,
329
+ max_size_mb=15.0 # применяем ограничение максимального размера для всех файлов
299
330
  )]
300
331
  ```
301
332
 
302
333
  #### Доступные фабричные функции
303
334
 
304
- | Тип | Описание | Основные параметры |
305
- |--------------------------|-----------------------------------|---------------------------------------------------------------------|
306
- | `MainInput` | Основное поле ввода | `placeholder` |
307
- | `StringInput` | Текстовое поле | `default`, `title`, `description`, `hidden`, `depends` |
308
- | `StringArrayInput` | Массив строк | `placeholder`, `title`, `description`, `group`, `hidden`, `depends` |
309
- | `StringArrayInputInline` | Массив строк в одной строке ввода | `placeholder`, `title`, `description`, `group`, `hidden`, `depends` |
310
- | `NumberInput` | Числовое поле | `default`, `title`, `description`, `hidden`, `depends` |
311
- | `SelectInput` | Выпадающий список | `items`, `title`, `group`, `default`, `hidden`, `depends` |
312
- | `CheckboxInput` | Чекбокс | `title`, `group`, `description`, `default`, `hidden`, `depends` |
313
- | `SwitchInput` | Switch | `title`, `group`, `description`, `default`, `hidden`, `depends` |
314
- | `FileInput` | Загрузка одного файла | `title`, `file_extensions`, `group`, `hidden`, `depends` |
315
- | `FilesInput` | Загрузка нескольких файлов | `title`, `file_extensions`, `group`, `hidden`, `depends`, `limit` |
335
+ | Тип | Описание | Основные параметры |
336
+ |--------------------------|-----------------------------------|--------------------------------------------------------------------------------------------|
337
+ | `MainInput` | Основное поле ввода | `placeholder`, `visibility` |
338
+ | `StringInput` | Текстовое поле | `default`, `title`, `description`, `hidden`, `depends`, `visibility` |
339
+ | `StringArrayInput` | Массив строк | `placeholder`, `title`, `description`, `group`, `hidden`, `depends`, `visibility` |
340
+ | `StringArrayInputInline` | Массив строк в одной строке ввода | `placeholder`, `title`, `description`, `group`, `hidden`, `depends`, `visibility` |
341
+ | `NumberInput` | Числовое поле | `default`, `title`, `description`, `hidden`, `depends`, `visibility` |
342
+ | `SelectInput` | Выпадающий список | `items`, `title`, `group`, `default`, `hidden`, `depends`, `visibility` |
343
+ | `CheckboxInput` | Чекбокс | `title`, `group`, `description`, `default`, `hidden`, `depends`, `visibility` |
344
+ | `SwitchInput` | Switch | `title`, `group`, `description`, `default`, `hidden`, `depends`, `visibility` |
345
+ | `FileInput` | Загрузка одного файла | `title`, `file_extensions`, `group`, `hidden`, `depends`, `view`, `visibility`, `max_size_mb` |
346
+ | `FilesInput` | Загрузка нескольких файлов | `title`, `file_extensions`, `group`, `hidden`, `depends`, `limit`, `view`, `visibility`, `max_size_mb` |
316
347
 
317
348
  #### Группировка полей
318
349
 
@@ -345,9 +376,81 @@ class TaskConfig(BaseModel):
345
376
  )]
346
377
  ```
347
378
 
379
+ #### Управление видимостью полей
380
+
381
+ Параметр `visibility` контролирует, когда поле отображается в интерфейсе. Доступные значения:
382
+
383
+ ```python
384
+ from agent_lab_sdk.schema import Visibility
385
+
386
+ # Enum с тремя значениями:
387
+ Visibility.ALWAYS # "always" - поле всегда доступно для ввода (по умолчанию)
388
+ Visibility.START # "start" - поле доступно для ввода только при старте
389
+ Visibility.AFTER_START # "after_start" - поле доступно для ввода после старта
390
+ ```
391
+
392
+ **Пример использования:**
393
+
394
+ ```python
395
+ class AgentConfig(BaseModel):
396
+ # Всегда доступно для ввода поле
397
+ query: Annotated[str, MainInput(
398
+ placeholder="Введите запрос",
399
+ visibility=Visibility.ALWAYS
400
+ )]
401
+
402
+ # Поле доступно для ввода только при первом запуске
403
+ api_key: Annotated[str, StringInput(
404
+ title="API ключ",
405
+ description="Ключ для доступа к внешнему API",
406
+ visibility=Visibility.START
407
+ )]
408
+
409
+ # Поле появляется после первого сообщения
410
+ session_id: Annotated[str, StringInput(
411
+ title="ID сессии",
412
+ description="Идентификатор текущей сессии",
413
+ visibility=Visibility.AFTER_START,
414
+ hidden=True
415
+ )]
416
+ ```
417
+
418
+ Можно также передавать строковые значения напрямую:
419
+
420
+ ```python
421
+ title: Annotated[str, StringInput(
422
+ title="Заголовок",
423
+ visibility="always" # эквивалентно Visibility.ALWAYS
424
+ )]
425
+ ```
426
+
348
427
  ### 5.2. LogMessage
349
428
 
350
- TODO: описание LogMessage
429
+ `LogMessage` вспомогательное сообщение для потоковой передачи логов из узлов LangGraph / LangChain. Экземпляры создаются как обычные сообщения чата, но получают тип `log`, поэтому фронтенд может отображать их отдельно от ответов модели.
430
+
431
+ - Импортируется из `agent_lab_sdk.schema`.
432
+ - По умолчанию наследуется от `langchain.schema.AIMessage` и устанавливает `additional_kwargs={"type": "log"}`.
433
+ - Если установить переменную окружения `IS_LOG_MESSAGE_CUSTOM=true`, будет использоваться наследник `BaseMessage` с явным типом `log`.
434
+
435
+ Переменная окружения `IS_LOG_MESSAGE_CUSTOM` на текущий момент установлена для всех агентов в значение `true`
436
+
437
+ #### Пример использования со `StreamWriter`
438
+
439
+ ```python
440
+ from langgraph.graph import MessagesState
441
+ from langgraph.types import StreamWriter
442
+ from agent_lab_sdk.schema import LogMessage
443
+
444
+ async def run(state: MessagesState, writer: StreamWriter) -> MessagesState:
445
+ writer(LogMessage("Запускаю обработку запроса"))
446
+
447
+ # ... полезная работа здесь ...
448
+
449
+ writer(LogMessage("Обработка завершена"))
450
+ return state
451
+ ```
452
+
453
+ Вызов `writer(LogMessage(...))` отправляет лог во время выполнения шага графа, позволяя клиенту сразу видеть прогресс.
351
454
 
352
455
  ## 6. Сборка и публикация
353
456
 
@@ -1,20 +1,22 @@
1
1
  agent_lab_sdk/__init__.py,sha256=1Dlmv-wuz1QuciymKtYtX7jXzr_fkeGTe7aENfEDl3E,108
2
2
  agent_lab_sdk/langgraph/checkpoint/__init__.py,sha256=DnKwR1LwbaQ3qhb124lE-tnojrUIVcCdNzHEHwgpL5M,86
3
- agent_lab_sdk/langgraph/checkpoint/agw_saver.py,sha256=K4ni4x6bMibkC9PphEll7RLtbKbaHCGTz0uM6ouQaV0,13763
3
+ agent_lab_sdk/langgraph/checkpoint/agw_saver.py,sha256=21IkZ7aZrmYUpd3fmMuc4IhfQaDntoSWbRKnYlFjieY,32721
4
+ agent_lab_sdk/langgraph/checkpoint/serde.py,sha256=UTSYbTbhBeL1CAr-XMbaH3SSIx9TeiC7ak22duXvqkw,5175
4
5
  agent_lab_sdk/llm/__init__.py,sha256=Yo9MbYdHS1iX05A9XiJGwWN1Hm4IARGav9mNFPrtDeA,376
5
6
  agent_lab_sdk/llm/agw_token_manager.py,sha256=_bPPI8muaEa6H01P8hHQOJHiiivaLd8N_d3OT9UT_80,4787
6
7
  agent_lab_sdk/llm/gigachat_token_manager.py,sha256=nlOxHcwJovsmM4cpI4fwMrYjoSeMjelDaHTipXsrUuA,8282
7
- agent_lab_sdk/llm/llm.py,sha256=HIp97-rs8Xcxokgptgh6bCfkIx7UJUFOYdGbpi7SsSg,1949
8
+ agent_lab_sdk/llm/llm.py,sha256=xL6FYyzjx22w_HnGK0ygGJTGr_OEz9EB6JWyYztprg4,2018
8
9
  agent_lab_sdk/llm/throttled.py,sha256=faccDXiKkmFFfZkVrxFQDHxHutAAivsKDEpYlygfuqU,8019
9
10
  agent_lab_sdk/metrics/__init__.py,sha256=G4VSlzKwupPMM4c6vZaF1rnd0KusKarezDMjli9pVFw,57
10
11
  agent_lab_sdk/metrics/metrics.py,sha256=_XTT9vMG7T0u_D2pL371wm8GoBU5fodJ45D2RACnBJw,3439
11
- agent_lab_sdk/schema/__init__.py,sha256=bHSyXQYkcB9fWBlziWodXR_IzC5nKrdKzrCpyVWNY9o,521
12
- agent_lab_sdk/schema/input_types.py,sha256=e75nRW7Dz_RHk5Yia8DkFfbqMafsLQsQrJPfzQhpIBw,9123
12
+ agent_lab_sdk/schema/__init__.py,sha256=cDVmQG5eYd2qO7DtDTt_YCISQyUXjLprUZ6KvKESKtU,554
13
+ agent_lab_sdk/schema/input_types.py,sha256=kXSGxRGSNLN76qRw3MoIHC0fWP-tRvQSrrokHhTA_dE,12398
13
14
  agent_lab_sdk/schema/log_message.py,sha256=nadi6lZGRuDSPmfbYs9QPpRJUT9Pfy8Y7pGCvyFF5Mw,638
14
- agent_lab_sdk/storage/__init__.py,sha256=ik1_v1DMTwehvcAEXIYxuvLuCjJCa3y5qAuJqoQpuSA,81
15
+ agent_lab_sdk/storage/__init__.py,sha256=HAtUoqg3k0irqPMewayadVA9aXJOmYSxRr6a5J1scT0,174
15
16
  agent_lab_sdk/storage/storage.py,sha256=ELpt7GRwFD-aWa6ctinfA_QwcvzWLvKS0Wz8FlxVqAs,2075
16
- agent_lab_sdk-0.1.35.dist-info/licenses/LICENSE,sha256=_TRXHkF3S9ilWBPdZcHLI_S-PRjK0L_SeOb2pcPAdV4,417
17
- agent_lab_sdk-0.1.35.dist-info/METADATA,sha256=U8K4oMgtKBD5uMVi3RhDRkkdSUIjZF1y3GcLgvCzN-g,17884
18
- agent_lab_sdk-0.1.35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- agent_lab_sdk-0.1.35.dist-info/top_level.txt,sha256=E1efqkJ89KNmPBWdLzdMHeVtH0dYyCo4fhnSb81_15I,14
20
- agent_lab_sdk-0.1.35.dist-info/RECORD,,
17
+ agent_lab_sdk/storage/storage_v2.py,sha256=53T6iY0C4ukL1BtNwmTTnp4Om59TwnapSLN4m5PWytM,4239
18
+ agent_lab_sdk-0.1.49.dist-info/licenses/LICENSE,sha256=_TRXHkF3S9ilWBPdZcHLI_S-PRjK0L_SeOb2pcPAdV4,417
19
+ agent_lab_sdk-0.1.49.dist-info/METADATA,sha256=Tiq1yN6IuGnA53ee850-41k5B25geq_coVF7hPPUh5k,23388
20
+ agent_lab_sdk-0.1.49.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ agent_lab_sdk-0.1.49.dist-info/top_level.txt,sha256=E1efqkJ89KNmPBWdLzdMHeVtH0dYyCo4fhnSb81_15I,14
22
+ agent_lab_sdk-0.1.49.dist-info/RECORD,,