Автономный ReAct-агент на Microsoft Agent Framework (Microsoft.Agents.AI +
Microsoft.Agents.AI.Harness). Бэкенд — Ollama Cloud через OllamaSharp (авторизация
Bearer-ключом). Агент работает в выбранной пользователем рабочей папке: читает и правит
файлы, ищет по содержимому, выполняет команды PowerShell и Python-код в песочнице.
В решении три проекта:
| Проект | Что это |
|---|---|
Harness.Core |
библиотека (net10.0) — весь агент: AgentHost, плагины, трассировка, настройки, а также поставляемые skills/, agents/, dotnet-scripts/, plugin-examples/ |
MyHarness |
WinForms-приложение (net10.0-windows) — чат-окно с Markdown в WebView2 |
HarnessCli |
консольное приложение (net10.0, SharpConsoleUI) — то же окно чата в терминале |
Оба приложения — это только UI поверх Harness.Core: логика агента, набор
инструментов, плагины, навыки и персоны у них общие.
- Тёмная тема, компоновка в стиле десктопного приложения Claude: сайдбар сессий слева, строка меню сверху, лог чата с полем ввода, строка состояния снизу.
- Сайдбар сессий: список рабочих папок; кнопка «+» у папки создаёт в ней новую сессию. Между сессиями можно переключаться в любой момент — стенограмма каждой сессии сохраняется и восстанавливается при переключении.
- Несколько рабочих папок одновременно: каждая папка получает собственный экземпляр
агента (
AgentHost) со своей песочницей, shell-исполнителем и HTTP-клиентом. Новая папка добавляется кнопкой «📁 Папка…». - Рендеринг Markdown: ответы ассистента отображаются как Markdown (Markdig) в тёмном WebView2. Реплики пользователя, рассуждения (reasoning), вызовы инструментов, ошибки и служебные сообщения — цветные блоки. Вывод стримится и добавляется пакетами (без мерцания); ссылки открываются в браузере по умолчанию.
- Выбор модели: меню «Модель» заполняется списком моделей с сервера Ollama
(
/api/tags); есть пункт «Ввести имя модели…» для ручного ввода. Переключение действует со следующего сообщения, история диалога сохраняется. Модель из secret.json /OLLAMA_MODEL_NAMEостаётся стартовой по умолчанию. - Динамическое контекстное окно: при выборе модели её реальный размер контекста
запрашивается у сервера (
/api/show, поле*.context_length), и бюджеты токенов агента подстраиваются автоматически (например, 1 000 000 токенов для glm-5.2). Если окно изменилось, агент пересоздаётся, а все сессии переносятся на него без потери истории. Для моделей, не сообщающих контекст, используется значение по умолчанию — 131 072 токена. - Режимы
plan/execute: переключаются в меню «Режим» (по умолчанию —execute). - Меню «Ресурсы»: показывает всё, до чего агент дотягивается прямо сейчас — агенты
(
agents/*/AGENTS.md), навыки (skills/*/SKILL.md), плагины (plugins/*/plugin.cs) и dotnet-скрипты (scripts/*.csв рабочей папке). Рядом с названием — количество, во всплывающей подсказке — краткое описание и путь. Список строится при каждом открытии, поэтому плагин или скрипт, созданный агентом в этой же сессии, появляется сразу. Клик подставляет готовый запрос в поле ввода (не отправляет — можно дописать задачу). - Подтверждение инструментов: перед записью файлов, запуском PowerShell или Python
показывается модальный диалог с четырьмя вариантами: разрешить / всегда разрешать
инструмент / всегда разрешать с этими аргументами / отклонить.
Read-only-вызовы
file_accessодобряются автоматически. - Автоподтверждение («авторазрешения» в меню «Режим»): опциональный режим, в котором все запросы инструментов одобряются без диалога.
- Строка состояния: текущая рабочая папка, использование токенов, индикатор занятости.
- Запоминание рабочей папки: последняя папка сохраняется в
%LocalAppData%\MyHarness\settings.jsonи подставляется при следующем запуске; если файла нет или папка удалена — показывается диалог выбора папки.
Консольный порт того же окна на SharpConsoleUI — структура и возможности те же: сайдбар сессий слева, строка меню сверху («Сессия», «Модель», «Режим», «Ресурсы»), стримящийся лог чата с полем ввода и строка состояния снизу. Ответы ассистента рендерятся как Markdown средствами терминала. Отличия от WinForms-версии:
- Рабочая папка берётся из аргумента командной строки (
HarnessCli <папка>), иначе из сохранённых настроек (%LocalAppData%\HarnessCli\settings.json), иначе запрашивается в диалоге выбора папки уже внутри окна. - Горячие клавиши:
Ctrl+N— новая сессия,Ctrl+O— рабочая папка,Ctrl+P— авторазрешения,Ctrl+Q— выход. HarnessCli --helpпечатает краткую справку и выходит.
- Цикл ReAct: рассуждение → выбор инструмента → действие → анализ наблюдения, повторяется до выполнения запроса.
- Контекстное окно — динамическое, по данным модели с сервера Ollama (131 072 токена, если модель его не сообщает). Бюджет вывода — до 16 384 токенов (не больше четверти контекстного окна), reasoning effort — Medium.
- Сэмплирование зафиксировано:
temperature 0,top_p 1,seed 0— иначе бэкенд применяет свои значения по умолчанию (0.8 / 0.9) и модель выдумывает правдоподобные факты. - Встроенные провайдеры Harness: todo-список, режимы агента, файловая память, подтверждение инструментов, навыки (skills); дополнительно — CodeAct (Python) и сведения об окружении shell в системном промпте.
- Hosted web-search у Ollama нет. Локальный поиск по рабочей папке —
search_files; живой доступ в интернет даёт плагинweb-search(инструментыweb_search/web_fetch).
| Инструмент | Что делает | Подтверждение |
|---|---|---|
file_access |
чтение / запись / список / редактирование файлов в рабочей папке | чтение — автоматически, запись — диалог |
search_files |
рекурсивный поиск по содержимому рабочей папки (regex, без учёта регистра, до 200 совпадений, строки обрезаются до 200 символов; .git, bin, obj, node_modules и бинарные файлы пропускаются) |
не требуется |
web_search / web_fetch |
поиск в интернете и загрузка текста страницы (плагин web-search) |
не требуется |
run_shell |
команды PowerShell в дочернем процессе; рабочий каталог — рабочая папка; deny-list опасных команд (rm -rf, sudo, fork-бомбы, mkfs, запись в /dev/sd*, Format-Volume); таймаут 30 с |
диалог |
execute_code |
Python в песочнице Hyperlight (WASM) — изолированное выполнение кода | диалог |
Плюс файловая память (agent-files/ рядом с exe — заметки, переживающие перезапуск)
и todo-инструменты.
Агент умеет решать задачи C#-скриптами — file-based программами .NET 10 (один .cs-файл
с top-level statements, без csproj; NuGet-пакеты — директивой #:package Имя@Версия).
- Все скрипты сохраняются только в папке
scripts/внутри рабочей папки. - Запуск через
run_shell:dotnet run scripts\имя.cs -- <аргументы>. - При первом запуске в
scripts/копируются примеры изdotnet-scripts/(существующие файлы никогда не перезаписываются):hello.cs— минимальный скрипт (аргументы командной строки, вывод);sysinfo.cs— сведения о системе и дисках (BCL, LINQ);todo-report.cs— обход файлов, поиск TODO, Markdown-отчёт.
- Для запуска скриптов на машине нужен .NET 10 SDK (
dotnetв PATH).
Лежат в Harness.Core, копируются в выходной каталог обоих приложений при сборке
и обнаруживаются агентом во время работы:
skills/<навык>/SKILL.md— навыки, загружаемые по мере необходимости:dotnet-script— сценарий работы с C#-скриптами;research— сценарий исследования.
agents/<имя>/AGENTS.md— документы-персоны (роли), которые агент читает черезrun_shell, когда принимает роль:coder,researcher,weather;dotnet-scripter— пишет и отлаживает произвольные C#-скрипты;dotnet-analyst— анализ данных (CSV/JSON/логи) только через выполняемый код;dotnet-automator— повторяемые файловые автоматизации (dry-run по умолчанию, изменения только с--apply, резервные копии).
Плагины — C#-файлы в plugins\<имя>\plugin.cs рядом с exe; приложение само
компилирует их (Roslyn, без csproj). Два типа:
- одноразовые (
IOneShotPlugin) — становятся инструментами агента (Microsoft.Extensions.AI.AIFunction):CreateHandlerвозвращает делегат, чьи параметры с атрибутами[Description]образуют схему инструмента; - резидентные (
IResidentPlugin) — загружаются вместе с приложением,StartAsyncработает всё время,GetTools()отдаёт их инструменты агенту.
Компиляция и загрузка плагинов требуют JIT, поэтому в NativeAOT-сборке плагины
недоступны: инструменты plugin_create / plugin_load не предлагаются агенту,
остальное приложение работает как обычно.
Агент может сам создавать плагины инструментом plugin_create; плагин
загружается сразу, без перезапуска приложения (горячая загрузка, инструменты
доступны со следующего сообщения), существующую папку поднимает plugin_load.
Обновление кода уже загруженного плагина требует перезапуска.
Плагины взаимодействуют с агентом через IPluginContext:
AskAgentAsync(message) передаёт запрос пользователя агенту и возвращает его
ответ (у каждого плагина своя постоянная сессия; tool-подтверждения в этом
канале одобряются автоматически), а Log(message) пишет в
plugins\<имя>\plugin.log и дублируется в окно чата (🔌).
Примеры: hello_once (одноразовый инструмент с параметром) и telegram-bot
(резидентный backend Telegram-бота: входящие сообщения пересылаются агенту,
ответы возвращаются в чат; инструмент telegram_send; токен — token.txt
в папке плагина или переменная TELEGRAM_BOT_TOKEN). Исходники примеров —
Harness.Core\plugin-examples\; контракты плагинов лежат в namespace
Harness.Core.Plugins.
OpenTelemetry-трассы (включая HTTP-инструментирование) пишутся в файлы
traces_*.log в папке traces рядом с exe. Имя источника задаёт приложение —
MyHarness или HarnessCli (параметр AgentHost.CreateAsync).
Логи приложения (Serilog) — в папке logs рядом с exe: app-YYYYMMDD.log,
ротация по дням, хранится 30 файлов. Все обработчики исключений пишут сюда.
Конфигурация бэкенда Ollama читается из secret.json. Файл создаётся рядом с csproj
приложения — MyHarness\secret.json и/или HarnessCli\secret.json, у каждого свой
(он в .gitignore и при сборке копируется в выходной каталог; читается из каталога exe).
Требуемая структура — вложенная секция Ollama (имена полей без учёта регистра):
{
"Ollama": {
"Endpoint": "https://ollama.com",
"Model": "glm-5.2:cloud",
"ApiKey": "<ваш ключ Ollama Cloud>"
}
}| Поле | Обязательное | Значение по умолчанию | Описание |
|---|---|---|---|
Ollama.Endpoint |
нет | https://ollama.com |
Базовый URL сервера Ollama (Cloud или локальный). |
Ollama.Model |
нет | glm-5.2:cloud |
Стартовая модель; в UI её можно сменить в любой момент. |
Ollama.ApiKey |
да | — | API-ключ Ollama Cloud; передаётся как Bearer-токен. Без него приложение не запустится. |
Правила:
- Файл обязателен: если
secret.jsonне найден рядом с exe, приложение падает при создании агента с понятным сообщением об ошибке. - Плоские ключи (например,
"OLLAMA_API_KEY": "..."на верхнем уровне) не читаются — нужна именно вложенная секцияOllama. - Переменные окружения имеют приоритет над secret.json:
OLLAMA_ENDPOINT,OLLAMA_MODEL_NAME,OLLAMA_API_KEY.
Общее для обоих приложений:
- .NET 10 SDK (и для сборки, и для dotnet-скриптов агента);
- PowerShell для инструмента
run_shell; - ключ Ollama Cloud (или локальный сервер Ollama с совместимым API).
Дополнительно для MyHarness: Windows (net10.0-windows, WinForms) и WebView2 Runtime
(на Windows 11 обычно уже установлен). HarnessCli собирается под net10.0 и не зависит
от WinForms.
WinForms-версия:
dotnet run --project MyHarness
- При первом запуске выберите рабочую папку в диалоге (далее она запоминается).
- Общайтесь с агентом в чат-окне; запросы на выполнение инструментов подтверждайте в появляющихся диалогах (или включите авторазрешения в меню «Режим»).
- Модель и режим (
plan/execute) переключаются в строке меню; новые папки — кнопкой «📁 Папка…», новые сессии — кнопкой «+» в сайдбаре.
Консольная версия (рабочую папку можно передать аргументом):
dotnet run --project HarnessCli -- C:\путь\к\рабочей\папке
Вся не-UI часть вынесена в библиотеку Harness.Core; оба приложения (WinForms и
консольное) — это только UI поверх неё.
Harness.Core/ — общая библиотека (net10.0), ссылаются оба приложения
├── AgentHost.cs — сборка агента: бэкенд Ollama, инструменты, песочница, трассировка
├── AppSettings.cs — сохранение последней рабочей папки (%LocalAppData%\<имя приложения>)
├── Plugins/ — контракты плагинов и PluginManager (компиляция Roslyn, горячая загрузка)
├── Tracing/ — OpenTelemetry: провайдер и файловый экспортёр спанов
├── agents/ — персоны (AGENTS.md), копируются к exe обоих приложений
├── skills/ — навыки (SKILL.md), копируются к exe обоих приложений
├── dotnet-scripts/ — примеры C#-скриптов, при первом запуске копируются в <рабочая папка>\scripts
└── plugin-examples/ — примеры плагинов, копируются к exe как plugins\
MyHarness/ — WinForms-приложение
├── Program.cs — точка входа: выбор/восстановление рабочей папки, запуск окна
├── UI/
│ ├── MainForm.cs — чат-окно: сессии, модель, режим, цикл подтверждений
│ ├── MarkdownViewer.cs — лог чата: Markdown в WebView2, цветные блоки, стриминг
│ ├── ToolApprovalDialog.cs — диалог подтверждения инструмента (4 варианта)
│ └── Theme.cs — тёмная тема
└── secret.json — ключ и настройки Ollama (в .gitignore)
HarnessCli/ — консольное приложение (SharpConsoleUI)
├── Program.cs — точка входа: рабочая папка из аргумента/настроек, запуск окна
├── UI/
│ ├── MainWindow.cs — чат-окно: сессии, модель, режим, цикл подтверждений
│ ├── AppDialogs.cs — диалоги (подтверждение инструмента, выбор папки и модели)
│ └── TranscriptLog.cs — лог чата
└── secret.json — ключ и настройки Ollama (в .gitignore)