# Переменные и макросы AgentUI Этот файл — простая шпаргалка по переменным/макросам, которые можно использовать в шаблонах узла ProviderCall и в Prompt Blocks. Правила ввода: - Квадратные макросы [[...]] — простая подстановка. Хорошо подходят для строк и для URL/заголовков. - Фигурные {{ ... }} — «джинджа‑лайт»: умеют фильтр |default(...), корректно вставляют объекты и массивы внутрь JSON без лишних кавычек. - Любые значения, вставляемые в JSON через макросы, приводятся к корректному JSON когда это возможно. Служебные файлы/строки реализации: - Рендеринг и макросы: [render_template_simple()](agentui/pipeline/executor.py:125) - Провайдерный узел с формированием PROMPT: [ProviderCallNode.run()](agentui/pipeline/executor.py:565) --- ## Общие переменные контекста - [[model]] — активная модель (строка) - [[vendor_format]] — openai | gemini | claude | unknown - [[system]] — системный текст, если был во входящем запросе - [[params.temperature]], [[params.max_tokens]], [[params.top_p]], [[params.stop]] - [[chat.last_user]] — последнее user‑сообщение - [[chat.messages]] — массив унифицированных сообщений - [[incoming.path]] — путь входящего HTTP‑запроса - [[incoming.query]] — строка query (?a=1&b=2) - [[incoming.query_params]] — объект query, например {"key":"..."} - [[incoming.headers]] — заголовки входящего запроса - [[incoming.json]] — JSON‑тело входящего запроса клиента - [[incoming.api_keys.authorization]] — значение Authorization (если есть) - [[incoming.api_keys.key]] — значение ?key=... в URL (удобно для Gemini) - [[incoming.api_keys.secret]] — запасной слот Те же поля доступны через {{ ... }}: например {{ params.temperature|default(0.7) }}, {{ incoming.json }} и т.д. --- ## Макросы OUT (выходы нод) Доступ к выходам нод возможен в двух формах: ### 1) Короткая форма (best‑effort текст) - [[OUT1]] — «текст» из ноды n1 - [[OUT2]] — из ноды n2 и т.д. Что делает «best‑effort текст»: - Если нода вернула response_text или text — берётся он - Если нода вернула объект провайдера: - OpenAI: choices[0].message.content - Gemini: candidates[0].content.parts[0].text - Claude: content[].text (склейка) - Если ничего из выше не подошло — выполняется глубокий поиск текстовых полей ("text"/"content") Реализация: [_best_text_from_outputs()](agentui/pipeline/executor.py:45) и подстановка коротких OUT: [render_template_simple()](agentui/pipeline/executor.py:155) ### 2) Полная форма (точный путь) - [[OUT:n1.result]] — целиком результат ноды n1 - [[OUT:n1.result.candidates.0.content.parts.0.text]] — конкретный путь - Эквивалент через фигурные скобки: {{ OUT.n1.result.candidates.0.content.parts.0.text }} Совет: используйте короткий [[OUTx]] если нужно «просто текст». Используйте полную форму, если нужен конкретный фрагмент/массив. --- ## Единый фрагмент [[PROMPT]] [[PROMPT]] — это уже собранный JSON‑фрагмент из ваших Prompt Blocks. Он зависит от выбранного провайдера ноды: - OpenAI → "messages": [...] - Gemini → "contents": [...], "systemInstruction": {...} - Claude → "system": "...", "messages": [...] Как использовать внутри JSON‑шаблона: { "model": "{{ model }}", [[PROMPT]], "temperature": {{ params.temperature|default(0.7) }} } Вы также можете использовать сырьевые структуры: - {{ pm.messages }} - {{ pm.contents }} - {{ pm.systemInstruction }} - {{ pm.system_text }} Но рекомендуемый путь — [[PROMPT]]: меньше шансов сломать JSON. --- ## Примеры по провайдерам ### OpenAI (/v1/chat/completions) { "model": "{{ model }}", [[PROMPT]], "temperature": {{ incoming.json.temperature|default(params.temperature|default(0.7)) }}, "top_p": {{ incoming.json.top_p|default(params.top_p|default(1)) }}, "max_tokens": {{ incoming.json.max_tokens|default(params.max_tokens|default(256)) }}, "stop": {{ incoming.json.stop|default(params.stop|default([])) }} } ### Gemini (/v1beta/models/{model}:generateContent?key=...) { "model": "{{ model }}", [[PROMPT]], "safetySettings": {{ incoming.json.safetySettings|default([]) }}, "generationConfig": { "temperature": {{ incoming.json.generationConfig.temperature|default(params.temperature|default(0.7)) }}, "topP": {{ incoming.json.generationConfig.topP|default(params.top_p|default(1)) }}, "maxOutputTokens": {{ incoming.json.generationConfig.maxOutputTokens|default(params.max_tokens|default(256)) }}, "stopSequences": {{ incoming.json.generationConfig.stopSequences|default(params.stop|default([])) }} } } ### Claude (/v1/messages) { "model": "{{ model }}", [[PROMPT]], "temperature": {{ incoming.json.temperature|default(params.temperature|default(0.7)) }}, "top_p": {{ incoming.json.top_p|default(params.top_p|default(1)) }}, "max_tokens": {{ incoming.json.max_tokens|default(params.max_tokens|default(256)) }} } --- ## Частые кейсы 1) Взять текст пользователя из входящего запроса и передать в Prompt Blocks - Gemini: [[VAR:incoming.json.contents.0.parts.0.text]] - OpenAI: [[VAR:incoming.json.messages.0.content]] - Claude: [[VAR:incoming.json.messages.0.content.0.text]] 2) Переписать ответ предыдущей ноды «как текст» - [[OUT1]] — если предыдущая нода имеет id n1 3) Добавить ключ Gemini из query в endpoint - /v1beta/models/{{ model }}:generateContent?key=[[VAR:incoming.api_keys.key]] --- ## Почему местами нужны {{ ... }} Внутри JSON нам важно вставлять объекты/массивы без кавычек и иметь дефолты: - {{ pm.contents }} — вставит массив как массив - {{ params.temperature|default(0.7) }} — если нет значения, подставится 0.7 Квадратные [[...]] хорошо подходят для строк/простых значений и для URL/заголовков. --- ## Отладка - Проверьте лог DEBUG в консоли: ProviderCallNode показывает провайдера, URL и первые 400 символов тела запроса. - Если «ничего не подставилось»: - убедитесь, что не подаёте входной payload в ProviderCall (иначе шаблон игнорируется); - проверьте валидность JSON после подстановок; - проверьте, что макрос написан корректно (OUT против OUTn). --- ## Мини‑FAQ В: Почему [[OUT1]] пустой? О: Возможно, нода n1 не вернула текстового поля, и глубокий поиск не нашёл текста. Уточните путь через полную форму [[OUT:n1....]]. В: Можно ли получить весь «сырой» ответ? О: [[OUT:n1.result]] — вернёт весь JSON результата ноды n1. В: Почему фигурные скобки иногда обязательны? О: Они умеют |default(...) и корректно вставляют объекты/массивы внутрь JSON. --- ## Ссылки на реализацию - Макросы/рендер: [render_template_simple()](agentui/pipeline/executor.py:125) - Единый [[PROMPT]]: [ProviderCallNode.run()](agentui/pipeline/executor.py:604) - Короткий [[OUTx]] и извлечение текста: [render_template_simple()](agentui/pipeline/executor.py:155), [_best_text_from_outputs()](agentui/pipeline/executor.py:45) Удачного редактирования!