Skip to content

AI Chat ​

AI Chat is the conversational surface in Infinia. Pick a backend, send a prompt, and read the reply token-by-token as a server-sent events (SSE) stream. While the model is working it can stream its own thinking and call plugin tools inline; finished conversations are persisted so you can reopen them later.

Backends ​

Chat runs against four backends, selected in Configuration under AI config:

ModeBackendNotes
localOllamaTalks to an external ollama serve process over its local HTTP API. The backend does not load a GGUF in-process.
openaiOpenAIStandard OpenAI API.
anthropicAnthropicAnthropic Messages API.
deepseekDeepSeekDeepSeek is OpenAI-compatible — driven through the OpenAI-style adapter.

The active mode is whatever PUT /api/ai/config last persisted; it is hot-swapped at runtime via BackendReactivator.reactivate() so a mode switch takes effect without a restart.

Context management ​

The complete transcript remains stored and visible, but the model-facing copy is automatically compacted before a long turn exceeds the provider window. FengYu estimates tokens from UTF-8 bytes; at 60% of the configured context window it summarizes the oldest complete rounds into a marked assistant context note, preserves system messages, and keeps the latest eight rounds verbatim. A summary failure is non-fatal and falls back to the original history.

Set Context Window in AI Configuration to the actual window supported by the selected model. The default is 32,768 tokens; 0 disables automatic compaction. Tool results are governed separately: a result larger than 64 KiB keeps its head and tail in model context so one tool cannot consume the remaining window, while the live SSE activity still receives the complete result.

Request flow ​

A chat turn is a two-step request: start the run, then open the SSE stream.

text
POST /api/ai/chat
  Content-Type: application/json
  X-FengYu-Token: <token>
  { "messages": [ { "role": "user", "content": "Summarize this workbook" } ],
    "permissionMode": "ask-for-approval",
    "workflowId": "<optional: bind this turn to a flow — see AI Agent → Visual flows>" }

  ◄── 200 { "streamId": "<uuid>", "activeFileRefs": [...] }

GET /api/ai/stream?streamId=<uuid>
  X-FengYu-Token: <token>
  Accept: text/event-stream

  ◄── SSE stream (see below)

The first frame on the stream is a :connected comment heartbeat — it confirms the stream is open before any events arrive.

Files and directories ​

Every conversation owns its attachments and resources — they never leak across chats. Add a file or a folder from the + menu and it joins the conversation draft as a read-only attachment (folders include their subdirectories): one chip per selection, no plugin ids, no approval card, and nothing is granted or copied until you actually send. When you send, the host takes its own copy of each attachment (the content as of that moment — later edits to the original are not picked up until you refresh) and the turn's file access is derived from those copies, then released when the turn ends. Removing a chip stops future turns from using it, while a running turn drains safely; a draft attachment you never sent is removed locally with zero server-side residue. Re-sending the same path replaces its revision; same-named files from different folders stay independent, and a late response always lands in the conversation that started it, even if you switched away. Sending is idempotent per attempt — a network retry never duplicates your message, copies, or the model call.

The Set output folder entry (desktop shells) registers where Infinia saves generated results. This authorizes the host to save there — it never widens what plugin workers can write. With an output folder set, generated files save directly and the result card offers Open and Show in Finder/Show in folder; without one, the result is kept as ready to save and you pick a location on the card. A failed save never deletes the generated file — retry is always available. Unsaved results are kept for 7 days and restored (without their folder authorization) after a restart; deleting the conversation reclaims them.

You can still type an existing absolute path in the latest user message. Typed paths become read-only resources of the same conversation-scoped registry — the model can never mint grants by mentioning a path. Flow run panels keep their own run-owned grants and are unaffected.

WARNING

The SSE endpoint is GET /api/ai/stream?streamId=.... There is no ?token= query parameter. Authenticate the stream request with the X-FengYu-Token header, the same as every other endpoint.

SSE events ​

Every event is an SSE frame named after its type. See SSE Events for the full taxonomy.

EventDataMeaning
token{text}A chunk of the assistant's reply. Concatenate to rebuild the message.
thinking{text}A chunk of the model's chain-of-thought.
toolcall: {phase:"call", name, arguments}The model decided to call a tool (plugin or built-in).
toolresult: {phase:"result", id, success, output}The tool returned. success:false carries an error in output.
done{text, tokens, tps}The turn is complete. text is the full reply; tps is tokens/sec.
error{message}The run failed. The stream ends after this frame.

A representative stream:

text
: connected

event: token
data: {"text":"Let me check "}

event: tool
data: {"phase":"call","name":"excel_analyze","arguments":"{\"filePath\":...}"}

event: tool
data: {"phase":"result","id":"...","success":true,"output":"..."}

event: token
data: {"text":"the workbook has 3 sheets."}

event: done
data: {"text":"Let me check the workbook has 3 sheets.","tokens":42,"tps":18.6}

Rendering ​

  • Thinking renders as collapsed cards — one card per thinking span, expandable on click so it stays out of the way unless you want it.
  • Tool calls render as compact activity rows such as Read FengYu Plugin Dev skill and update in place as the call runs or completes.
  • Approvals render inside the composer, directly above the text area. The transcript keeps the compact activity row instead of inserting a large approval card between messages.

Permission modes ​

The composer offers three per-turn profiles:

ModeBehaviour
Ask for approvalReads run directly; command execution, document/file changes, and external actions ask before they run.
Approve for meSafe sandboxed commands and declared reads/writes run automatically; commands detected as risky and external/network actions still ask.
Full accessRuns without tool approval and executes commands without the native file/network sandbox. Sensitive inherited environment variables are still removed.

Plugin tools declare their effect in the manifest, so the same gate covers both built-in and out-of-process plugin actions. A missing effect is handled conservatively as an external action.

Command results ​

execute_command returns stdout and stderr separately, including a truncation flag for each stream. When a stream exceeds its configured capture limit, FengYu preserves both the beginning and the end with an omitted-character marker, so trailing compiler or shell errors remain available. The legacy combined output and truncated fields remain present for compatible consumers.

Web discovery and visual browser results ​

Two host-embedded read tools keep ordinary research out of the stateful browser: web_search returns compact public-web result titles/URLs, and web_fetch retrieves bounded readable text. Both reject local/private-network targets and run as read effects. Use the desktop-only browser_* tools when the task needs navigation, page state, login context, or interaction.

browser_screenshot sends the actual PNG to Spring AI as an image/png media part after its tool response, so a vision-capable model can inspect the pixels. The same result also contains a DOM snapshot and accessibility tree for text-only models. Images are preserved in the in-memory tool history for follow-up model rounds; conversation persistence remains text-only. Gateways that only accept string content (no multimodal arrays) are handled automatically: the round is retried once without the image and the endpoint stays text-only from then on — screenshots keep arriving in the chat UI.

For interaction-heavy pages, the desktop browser surface also exposes history navigation, ref-targeted hover and bounded wheel scrolling, verified native option selection, and page-level keyboard input. A successful back/forward/reload invalidates cached refs, so the model must inspect the new page state before acting again.

Computer use (screen control) ​

Desktop builds additionally expose the computer_* family — ChatGPT-desktop-style computer use driven by java.awt.Robot inside the backend JVM: computer_screenshot captures the real screen (the PNG reaches a vision model exactly like browser_screenshot), computer_displays / computer_apps / computer_cursor_position observe the environment, and computer_click / computer_double_click / computer_mouse_move / computer_drag / computer_scroll / computer_type / computer_key inject real input; computer_key_sequence runs up to 50 ordered keys/shortcuts in one approved call for keyboard navigation. computer_app_launch and computer_app_activate open or focus applications (open -a, PowerShell Start-Process/ AppActivate, gtk-launch/wmctrl). All coordinates are logical screen points; the screenshot envelope reports the Hi-DPI scale so the model converts image pixels before clicking.

Every input-injecting call is an external effect and passes the per-turn approval gate; only observing tools (computer_screenshot, computer_displays, computer_apps, computer_cursor_position, computer_wait) classify as read. The family can be hidden entirely with the Settings → Runtime & security → Computer use switch (computerUseEnabled, default on). The same implementation runs on Windows, macOS, and Linux: Windows needs no extra permissions (app listing/launch/activation use PowerShell; UAC secure-desktop and elevated-app windows stay protected by the OS), while macOS needs Screen Recording (capture) and Accessibility (input) permissions — without them captures show wallpaper only and input is dropped silently by the OS. Captures are mirrored to .fengyu/computer-screenshots/. When no display is reachable every call degrades to a "computer use unavailable" envelope instead of throwing.

Conversations ​

Conversations are stored on the backend. All endpoints require the X-FengYu-Token header.

Method + pathBody / queryReturns
GET /api/ai/conversations—Conversation summaries, newest first.
GET /api/ai/conversations/{id}—A single conversation (title + messages).
POST /api/ai/conversations{title, messages}The created conversation with its id.
PUT /api/ai/conversations/{id}{title, messages}Replaces both title and messages wholesale.
DELETE /api/ai/conversations/{id}—Removes the conversation.

PUT is a full replace — send the complete messages array you want stored, not a delta.

Next steps ​

  • AI Agent — the plan-and-execute agent built on the same backend.
  • Configuration — set the active mode and API keys.
  • AI Tools — how plugin tools become callable from chat.

Released under the GPL-3.0 License.