The full result reaches the model; the echo reaches the glass. One path carries meaning, the other carries presence.
Purpose
Instrumenta tool calls produce a result that travels two distinct routes:
- The model route — the complete, lossless result (via the
toolmessage). - The UI route — a compact, human-readable echo streamed to the Pythia panel as a live status before the final answer is composed.
This document pins the contract between the Ruby oracle and the Swift file-mirror so that both routes stay truthful and neither leaks noise into the other.
The Ruby side — ui_preview
Location: Ruby/oracle/artificer.rb (class method, inside the class << self block).
def ui_preview(result, limit = 4000, name: nil)
# read_file behält seine Struktur, damit der Swift-Datei-Spiegel Pfad/Range/Inhalt
# rendern kann; andere content-tragende Ergebnisse bleiben ein kompaktes Echo.
return result if name&.to_s == 'read_file' && result.is_a?(Hash)
text = if result.is_a?(Hash)
(result[:content] || result['content'] || result.to_json).to_s
else
result.to_s
end
text.truncate(limit)
end
### Contract
| Input | Behaviour |
|---|---|
name == 'read_file' and result is a Hash |
Pass-through — the full structure (path, range, content, …) is returned untouched so the Swift file mirror can decode and render it. |
Any other Hash result |
Collapsed to result[:content] \|\| result['content'] \|\| result.to_json, truncated to limit (4000 chars). |
Non-Hash result |
result.to_s, truncated to limit. |
Invariants
namemay arrive as aStringor aSymbol;name&.to_snormalises both.limitis a positional argument that precedes thename:keyword argument. Ruby forbids a keyword argument before a positional one — the signature is(result, limit = 4000, name: nil), never(result, name: nil, limit = 4000).- The preview is cosmetic only. The model never consumes it; truncation here cannot lose information that matters to the LLM.
Call sites
Both execute_standard and execute_fallback emit the echo with the tool name:
sink&.send_status 'tool_completed', {
name:, execution_time: exec_time,
result: ui_preview(safe_result, name: name)
}
The sink is the status stream (stream or HorologiumAeternum), which re-frames
the payload for RubyBridge and ultimately PythiaPanel.
The Swift side — the file mirror
Location: AetherCodex/App/FileInstrumentViews.swift.
Decoding
ReadFileResultdecodes onlycontent/error(Decodable). Thepathis not carried in the result — it is recovered from the call arguments (args?.path ?? ""), which is why the Ruby pass-through preserves the full hash rather than collapsing it tocontentalone.PatchFileResultmirrors the same shape (ok/ error / diff statistics).
Rendering
- Both the
ReadFileViewandPatchFileViewheaders derive their subtitle from the file argument:(path as NSString).lastPathComponent— a non-optionalStringwith a?? ""fallback, so theas NSStringcast cannot crash. - The done-card is the minimal
✓ ok— no prose, per the hermetic subtraction over addition discipline.
Flow diagram
Maintenance notes
- If a new tool result needs structural rendering in Swift (not just a text
echo), extend the
ui_previewguard with itsnamerather than collapsing it, and add a matchingDecodablestruct inFileInstrumentViews.swift. - Never reorder
ui_preview’s arguments — keyword-before-positional is a Ruby syntax error. - Verify with
ruby -c Ruby/oracle/artificer.rbafter any signature change.