sync: mnogo
This commit is contained in:
148
agentui/providers/adapters/base.py
Normal file
148
agentui/providers/adapters/base.py
Normal file
@@ -0,0 +1,148 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
|
||||
class ProviderAdapter(ABC): # [ProviderAdapter.__init__()](agentui/providers/adapters/base.py:10)
|
||||
"""
|
||||
Базовый интерфейс адаптера провайдера для ProviderCall.
|
||||
|
||||
Задачи адаптера:
|
||||
- blocks_struct_for_template: собрать pm_struct из унифицированных сообщений (Prompt Blocks)
|
||||
- normalize_segment/filter_items: привести произвольный сегмент к целевой провайдерной структуре и отфильтровать пустое
|
||||
- extract_system_text_from_obj: вытащить системный текст из произвольного сегмента (если он там есть)
|
||||
- combine_segments: слить pre_segments (prompt_preprocess) и prompt_combine с blocks_struct → итоговый pm_struct
|
||||
- prompt_fragment: собрать строку JSON-фрагмента для подстановки в [[PROMPT]]
|
||||
- default_endpoint/default_base_url: дефолты путей и базовых URL
|
||||
"""
|
||||
|
||||
name: str = "base"
|
||||
|
||||
# --- Дефолты HTTP ---
|
||||
|
||||
@abstractmethod
|
||||
def default_base_url(self) -> str:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def default_endpoint(self, model: str) -> str:
|
||||
...
|
||||
|
||||
# --- PROMPT: построение провайдерных структур ---
|
||||
|
||||
@abstractmethod
|
||||
def blocks_struct_for_template(
|
||||
self,
|
||||
unified_messages: List[Dict[str, Any]],
|
||||
context: Dict[str, Any],
|
||||
node_config: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Из унифицированных сообщений [{role, content}] (включая text+image) собрать pm_struct
|
||||
для целевого провайдера. Результат должен быть совместим с текущей логикой [[PROMPT]].
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def normalize_segment(self, obj: Any) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Привести произвольный сегмент (dict/list/str/числа) к целевому массиву элементов
|
||||
(например, messages для openai/claude или contents для gemini).
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def filter_items(self, items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Отфильтровать пустые элементы (пустые тексты и т.п.) согласно правилам провайдера.
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def extract_system_text_from_obj(self, obj: Any, render_ctx: Dict[str, Any]) -> Optional[str]:
|
||||
"""
|
||||
Вытащить системный текст из произвольного объекта фрагмента:
|
||||
- OpenAI: messages[*] role=system
|
||||
- Gemini: systemInstruction.parts[].text
|
||||
- Claude: top-level system (string/blocks)
|
||||
Возвращает строку или None.
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def combine_segments(
|
||||
self,
|
||||
blocks_struct: Dict[str, Any],
|
||||
pre_segments_raw: List[Dict[str, Any]],
|
||||
raw_segs: List[str],
|
||||
render_ctx: Dict[str, Any],
|
||||
pre_var_paths: set[str],
|
||||
render_template_simple_fn, # (s, ctx, out_map) -> str
|
||||
var_macro_fullmatch_re, # _VAR_MACRO_RE.fullmatch
|
||||
detect_vendor_fn, # detect_vendor
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Слить blocks_struct c массивами pre_segments_raw и строковыми raw_segs (prompt_combine)
|
||||
и вернуть итоговый pm_struct. Поведение должно повторять текущее (позиционирование, фильтр пустых,
|
||||
сбор системного текста).
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def prompt_fragment(self, pm_struct: Dict[str, Any], node_config: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Сформировать строку JSON-фрагмента для [[PROMPT]] по итоговому pm_struct.
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
# --- Общие утилиты для позиционирования и парсинга директив ---------------------
|
||||
|
||||
def insert_items(base: List[Any], items: List[Any], pos_spec: Optional[str]) -> List[Any]: # [insert_items()](agentui/providers/adapters/base.py:114)
|
||||
if not items:
|
||||
return base
|
||||
if not pos_spec or str(pos_spec).lower() == "append":
|
||||
base.extend(items)
|
||||
return base
|
||||
p = str(pos_spec).lower()
|
||||
if p == "prepend":
|
||||
return list(items) + base
|
||||
try:
|
||||
idx = int(pos_spec) # type: ignore[arg-type]
|
||||
if idx < 0:
|
||||
idx = len(base) + idx
|
||||
if idx < 0:
|
||||
idx = 0
|
||||
if idx > len(base):
|
||||
idx = len(base)
|
||||
return base[:idx] + list(items) + base[idx:]
|
||||
except Exception:
|
||||
base.extend(items)
|
||||
return base
|
||||
|
||||
|
||||
def split_pos_spec(s: str) -> Tuple[str, Optional[str]]: # [split_pos_spec()](agentui/providers/adapters/base.py:135)
|
||||
"""
|
||||
Отделить директиву @pos=... от тела сегмента.
|
||||
Возвращает (body, pos_spec | None).
|
||||
"""
|
||||
import re as _re
|
||||
m = _re.search(r"@pos\s*=\s*(prepend|append|-?\d+)\s*$", str(s or ""), flags=_re.IGNORECASE)
|
||||
if not m:
|
||||
return (str(s or "").strip(), None)
|
||||
body = str(s[: m.start()]).strip()
|
||||
return (body, str(m.group(1)).strip().lower())
|
||||
|
||||
|
||||
# --- Дефолтные base_url по "вендору" (используется RawForward) ------------------
|
||||
|
||||
def default_base_url_for(vendor: str) -> Optional[str]: # [default_base_url_for()](agentui/providers/adapters/base.py:149)
|
||||
v = (vendor or "").strip().lower()
|
||||
if v == "openai":
|
||||
return "https://api.openai.com"
|
||||
if v == "claude" or v == "anthropic":
|
||||
return "https://api.anthropic.com"
|
||||
if v == "gemini" or v == "gemini_image":
|
||||
return "https://generativelanguage.googleapis.com"
|
||||
return None
|
||||
Reference in New Issue
Block a user