Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.2] - 2026-06-29

### Changed

- 🔧 **Better formatting for tool call output.** JSON data shown in tool call results and request parameters is now pretty-printed with proper indentation, making it much easier to read at a glance.
- 🤖 **More compatible agent communication.** Fixed how Computer talks to coding agents so it works with a wider range of agent versions.

## [0.7.1] - 2026-06-26

### Changed
Expand Down
2 changes: 1 addition & 1 deletion cptr/frontend/src/lib/components/Admin/Models.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Files:
if (!rp || typeof rp !== 'object') return [];
return Object.entries(rp).map(([key, value]) => ({
key,
value: typeof value === 'object' ? JSON.stringify(value) : String(value)
value: typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)
}));
}

Expand Down
2 changes: 1 addition & 1 deletion cptr/frontend/src/lib/components/chat/PlusMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
let paramRows = $state<Array<{ key: string; value: string }>>(
Object.entries($requestParams).map(([key, value]) => ({
key,
value: typeof value === 'object' ? JSON.stringify(value) : String(value)
value: typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)
}))
);

Expand Down
24 changes: 16 additions & 8 deletions cptr/frontend/src/lib/components/chat/ToolCallCollapsible.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@
return null;
}
});
const formattedOutput = $derived.by(() => {
if (!pairedOutput?.output) return '';
try {
return JSON.stringify(JSON.parse(pairedOutput.output), null, 2);
} catch {
return pairedOutput.output;
}
});

function toggleExpanded() {
expanded = !expanded;
Expand Down Expand Up @@ -240,8 +248,8 @@
{#each Object.entries(args) as [key, value]}
<div class="flex gap-2 text-xs py-0.5">
<span class="text-gray-600 dark:text-gray-400 shrink-0">{key}</span>
<span class="text-gray-800 dark:text-gray-200 break-all">
{typeof value === 'object' ? JSON.stringify(value) : value}
<span class="text-gray-800 dark:text-gray-200 break-all whitespace-pre-wrap">
{typeof value === 'object' ? JSON.stringify(value, null, 2) : value}
</span>
</div>
{/each}
Expand All @@ -268,15 +276,15 @@
</div>
{:else}
<pre
class="text-xs text-gray-600 dark:text-gray-300 whitespace-pre-wrap break-words font-mono max-h-64 overflow-auto leading-relaxed">{pairedOutput
.output.length > 10000
? pairedOutput.output.slice(0, 10000)
: pairedOutput.output}</pre>
class="text-xs text-gray-600 dark:text-gray-300 whitespace-pre-wrap break-words font-mono max-h-64 overflow-auto leading-relaxed">{formattedOutput.length >
10000
? formattedOutput.slice(0, 10000)
: formattedOutput}</pre>
{/if}
{#if !imageToolOutput?.length && pairedOutput.output.length > 10000}
{#if !imageToolOutput?.length && formattedOutput.length > 10000}
<div class="text-[10px] text-gray-400 dark:text-gray-600 mt-1 px-1">
{$t('chat.totalChars', {
count: pairedOutput.output.length.toLocaleString()
count: formattedOutput.length.toLocaleString()
})}
</div>
{/if}
Expand Down
5 changes: 2 additions & 3 deletions cptr/utils/agents/acp.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,8 @@ async def _open_session(self) -> None:

async def _send(self, payload: dict[str, Any]) -> None:
assert self.proc is not None and self.proc.stdin is not None
data = json.dumps(payload, separators=(",", ":")).encode()
framed = b"Content-Length: " + str(len(data)).encode() + b"\r\n\r\n" + data
self.proc.stdin.write(framed)
data = json.dumps(payload, separators=(",", ":")).encode() + b"\n"
self.proc.stdin.write(data)
await self.proc.stdin.drain()

async def _reader_loop(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cptr"
version = "0.7.1"
version = "0.7.2"
description = "Your computer, from anywhere. Code, manage, and control your machine from the web."
license = {file = "LICENSE"}
readme = "README.md"
Expand Down
Loading