fix(host): корректный возврат снимка через ImageContentBlock.FromBytes
- Data хранит base64-байты; сырые PNG-байты надо отдавать через FromBytes, иначе изображение портится на проводе (0x89 -> U+FFFD) - проверено сквозным прогоном по MCP-протоколу: connect -> document_create -> sketch_create -> add_circle -> close -> extrude_boss -> model_snapshot, получен валидный PNG (~19 КБ) цилиндра - docs/OPEN_QUESTIONS.md: конкурентность вызовов MCP и нюанс FromBytes Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,19 @@
|
|||||||
## Журнал решений по ходу
|
## Журнал решений по ходу
|
||||||
(дополняется автоматически во время работы)
|
(дополняется автоматически во время работы)
|
||||||
|
|
||||||
|
### ⚠️ Конкурентность вызовов MCP и состояние сессии
|
||||||
|
MCP-сервер обрабатывает запросы **конкурентно**. Цикл моделирования с реестром эскизов по id
|
||||||
|
(`sketch_create` → `sketch_add_*`) предполагает, что клиент **ждёт ответа** на каждый вызов перед
|
||||||
|
следующим (нормальное поведение LLM-клиентов). При «конвейерной» отправке зависимых вызовов
|
||||||
|
возможна гонка (id ещё не зарегистрирован). STA-диспетчер сериализует COM, но не порядок постановки задач.
|
||||||
|
**На проработку:** нужна ли серверная сериализация вызовов инструментов (очередь) для надёжности
|
||||||
|
stateful-сессии? Пока полагаемся на последовательное поведение клиента.
|
||||||
|
|
||||||
|
### ✅ Возврат изображения: ImageContentBlock.FromBytes
|
||||||
|
Поле `ImageContentBlock.Data` хранит **base64-байты**, а не сырые. Сырые байты PNG нужно
|
||||||
|
передавать через `ImageContentBlock.FromBytes(bytes, mimeType)` — он сам кодирует. Прямое
|
||||||
|
присваивание `Data = rawBytes` портит изображение на проводе. Исправлено в VisionTools.
|
||||||
|
|
||||||
### ✅ Снимок 3D: рендер через файл, а не resultArrayBytes
|
### ✅ Снимок 3D: рендер через файл, а не resultArrayBytes
|
||||||
`ksDocument3D.SaveAsToRasterFormat(fileName, param)` при **непустом** `fileName` возвращает TRUE,
|
`ksDocument3D.SaveAsToRasterFormat(fileName, param)` при **непустом** `fileName` возвращает TRUE,
|
||||||
пишет корректный PNG на диск, но `param.resultArrayBytes` остаётся **пустым**. Поэтому
|
пишет корректный PNG на диск, но `param.resultArrayBytes` остаётся **пустым**. Поэтому
|
||||||
|
|||||||
@@ -17,10 +17,7 @@ public sealed class VisionTools(KompasSession session, SnapshotService snapshot)
|
|||||||
{
|
{
|
||||||
await session.ConnectAsync();
|
await session.ConnectAsync();
|
||||||
var snap = await snapshot.CaptureActiveModelAsync(resolution: resolution);
|
var snap = await snapshot.CaptureActiveModelAsync(resolution: resolution);
|
||||||
return new ImageContentBlock
|
// FromBytes хранит сырые байты и сам кодирует их в base64 для поля Data.
|
||||||
{
|
return ImageContentBlock.FromBytes(snap.Bytes, snap.MimeType);
|
||||||
Data = snap.Bytes,
|
|
||||||
MimeType = snap.MimeType,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user