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
13 changes: 13 additions & 0 deletions app/src/features/chat/effort.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ describe("effort", () => {
expect(within(menu).queryByRole("button", { name: "Use recommended" })).toBeNull();
});

test("Haiku 5.5 takes effort levels, unlike Haiku 4.5", async () => {
const { fake, scout } = await openScout((bot) => {
bot.model = "haiku";
bot.modelInUse = "claude-haiku-5-5";
bot.effortDefault = "medium";
});
expect(picker().getAttribute("aria-label")).toBe("Effort: Medium");
const { menu, slider } = open();
expect(within(menu).getByText(/Recommended for Haiku 5.5/)).toBeDefined();
slideTo(slider, 0);
await waitFor(() => expect(efforts(fake)).toEqual([{ botId: scout.id, effort: "low" }]));
});

test("nothing is marked until Claude Code said the model's level", async () => {
const { fake, scout } = await openScout((bot) => {
bot.effortDefault = null;
Expand Down
2 changes: 2 additions & 0 deletions app/src/lib/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ describe("model names", () => {
test("Claude ids read as their family and version", () => {
expect(modelName("claude-opus-5-5")).toBe("Opus 5.5");
expect(modelName("claude-haiku-4-5-20251001")).toBe("Haiku 4.5");
expect(modelName("claude-haiku-5-5")).toBe("Haiku 5.5");
expect(modelFamily("claude-haiku-5-5")).toBe("haiku");
expect(modelName("claude-fable-5-1")).toBe("Fable 5.1");
expect(modelName("claude-sonnet-5")).toBe("Sonnet 5");
expect(modelFamily("claude-sonnet-5-5")).toBe("sonnet");
Expand Down
4 changes: 2 additions & 2 deletions docs/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ Itens do chat são dado pessoal como o corpo das messages: nunca vão para o log

### 8.6 Contexto da conversa

A conversa de um bot tem um tamanho máximo, a janela de contexto do modelo (1 milhão de tokens em Fable, Opus e Sonnet; 200 mil em Haiku). Tudo o que o bot leu e escreveu conta, e cada pedido ao modelo manda a conversa inteira: uma conversa cheia gasta mais do plano a cada turno. Perto do fim da janela, o Claude Code **compacta** a conversa sozinho: troca o que veio antes por um resumo e segue. O dono vê quanto da janela está em uso e pode compactar antes.
A conversa de um bot tem um tamanho máximo, a janela de contexto do modelo (1 milhão de tokens em Fable, Opus, Sonnet e Haiku 5.5; 200 mil no Haiku 4.5). O app lê o tamanho do que o Claude Code informa, não de uma tabela. Tudo o que o bot leu e escreveu conta, e cada pedido ao modelo manda a conversa inteira: uma conversa cheia gasta mais do plano a cada turno. Perto do fim da janela, o Claude Code **compacta** a conversa sozinho: troca o que veio antes por um resumo e segue. O dono vê quanto da janela está em uso e pode compactar antes.

**Quem conta é o Claude Code.** O daemon pergunta, por um pedido de controle (9.2, `get_context_usage`), e guarda a resposta em memória, por bot:

Expand Down Expand Up @@ -1165,7 +1165,7 @@ Conferência na documentação oficial (code.claude.com/docs) em 2026-09-28; esf
| Abas nas mãos do dono com o Claude Code real | 21.10 | **A verificar**: com um bot no meio de uma tarefa num site, o dono assume, abre uma aba nova em outro endereço e devolve. O bot deve ler o aviso de que a aba mudou (no erro da tool que ia agir, ou no `browser_look`), ler a aba nova e seguir a tarefa nela ou abrir de novo a página de que precisa, sem agir às cegas. Recarregar sem assumir: o bot lê "The owner reloaded the page." e continua | manual (PR) |
| Cursor do bot nas telas | 22.3 | **Testado com 2.1.284** (daemon e app de dev, Haiku, modo Manual), com o app num Edge sem janela: pedidas quatro páginas (floricultura, cafeteria, livraria, academia), o cursor seguiu o título, cada cartão, cada item de plano e cada linha de tabela enquanto o bot escrevia, e a prancheta rolou junto. Visto aqui: num `iframe` de outra origem, o script às vezes lê a página com `innerHeight` 0 e só depois recebe o tamanho (por isso a espera do `resize`); a versão escondida fala antes de ir para a frente (por isso vale a marca do quadro à mostra). O conteúdo das páginas não foi para o log | feito |
| Bot compartilha arquivos com `share_file` | 10, 8.4 | Ferramenta nossa, sem comportamento novo do Claude Code: a tool vem liberada por `--allowedTools mcp__botloft` e é carregada pelo `ToolSearch` como as outras. **Testado com 2.1.284** (daemon de dev, Haiku, modo Aceitar edições), só com a regra de 5.1 e a descrição da tool: pedido um relatório salvo na pasta de trabalho, o bot o escreveu e chamou `share_file` sozinho; pedido "me manda o relatório de novo", chamou de novo sem escrever o caminho na resposta. A primeira chamada veio com o caminho do Windows com `\` sem escape, que o próprio Claude Code recusa como JSON inválido; o bot repetiu certo. Por isso a descrição do campo pede barras normais. O conteúdo não foi para o log | feito |
| Esforço em `-p` | 7.4 | Confirmado (`cli-reference`, `model-config`, `headless`): `--effort` aceita `low`, `medium`, `high`, `xhigh`, `max` (e `ultracode`, não usado), vale só para a sessão e não é guardado; os níveis dependem do modelo (Fable, Opus e Sonnet atuais têm os cinco; Opus 4.6 e Sonnet 4.6 não têm `xhigh`); sem escolha, o padrão é `high`, menos em Opus 5.5 e Sonnet 5.5 (`medium`) e Opus 4.7 (`xhigh`); `/effort <nível>` funciona em `-p` e vale só para a sessão; as chaves `effortLevel` e `modelSettings` das settings não aceitam `max`; trocar o esforço no meio da sessão mantém o cache em Opus 5.5, Sonnet 5.5 e Fable 5.1 e o invalida nos outros (`prompt-caching`). **Testado com 2.1.284** (`--setting-sources project,local`, plano Max): `--effort max` e `xhigh` com `--model sonnet` são aplicados; um valor desconhecido só avisa no stderr e usa o padrão; `--resume` sem a flag volta ao padrão do modelo; sem a flag, Sonnet 5.5 e Opus 5.5 aplicam `medium` e Fable 5.1 `high`; Haiku 4.5 não tem níveis (o `initialize` do SDK lista `supportedEffortLevels` para os outros e nada para ele) e ignora a flag sem erro. `/effort low` mandado como mensagem troca na hora, com uma resposta sintética e sem custo, e o pedido de controle `apply_flag_settings {effortLevel}` também; o daemon reinicia o processo em vez disso. O que acontece com um nível que o modelo não tem (`xhigh` num modelo antigo) não foi visto: os apelidos do Botloft apontam para modelos com os cinco | feito |
| Esforço em `-p` | 7.4 | Confirmado (`cli-reference`, `model-config`, `headless`): `--effort` aceita `low`, `medium`, `high`, `xhigh`, `max` (e `ultracode`, não usado), vale só para a sessão e não é guardado; os níveis dependem do modelo (Fable, Opus e Sonnet atuais têm os cinco; Opus 4.6 e Sonnet 4.6 não têm `xhigh`); sem escolha, o padrão é `high`, menos em Opus 5.5 e Sonnet 5.5 (`medium`) e Opus 4.7 (`xhigh`); `/effort <nível>` funciona em `-p` e vale só para a sessão; as chaves `effortLevel` e `modelSettings` das settings não aceitam `max`; trocar o esforço no meio da sessão mantém o cache em Opus 5.5, Sonnet 5.5 e Fable 5.1 e o invalida nos outros (`prompt-caching`). **Testado com 2.1.284** (`--setting-sources project,local`, plano Max): `--effort max` e `xhigh` com `--model sonnet` são aplicados; um valor desconhecido só avisa no stderr e usa o padrão; `--resume` sem a flag volta ao padrão do modelo; sem a flag, Sonnet 5.5 e Opus 5.5 aplicam `medium` e Fable 5.1 `high`; Haiku 4.5 não tem níveis (o `initialize` do SDK lista `supportedEffortLevels` para os outros e nada para ele) e ignora a flag sem erro. **Haiku 5.5** (lido em `model-config` e na visão geral dos modelos em 2026-10-07, ainda não visto com o Claude Code real): o apelido `haiku` aponta para `claude-haiku-5-5` a partir do Claude Code 2.1.293 (antes disso, para o 4.5), com os cinco níveis, padrão `medium` e janela de 1 milhão de tokens; o app lê níveis e janela do que o Claude Code informa, então o mesmo código serve aos dois. `/effort low` mandado como mensagem troca na hora, com uma resposta sintética e sem custo, e o pedido de controle `apply_flag_settings {effortLevel}` também; o daemon reinicia o processo em vez disso. O que acontece com um nível que o modelo não tem (`xhigh` num modelo antigo) não foi visto: os apelidos do Botloft apontam para modelos com os cinco | feito |
| Pedidos de controle no stdin | 9.2 | `getContextUsage()` é documentado no Agent SDK (`agent-sdk/typescript`), com `totalTokens`, `maxTokens`, `rawMaxTokens`, `percentage`, `autoCompactThreshold` e `isAutoCompactEnabled`; o formato no fio e `get_settings` **não são documentados**. **Testado com 2.1.284**: `{"type":"control_request","request_id","request":{"subtype":"get_context_usage"}}` é respondido com `control_response` (`subtype: "success"`, o mesmo `request_id`, `response`) em até 2,5 s, antes do primeiro turno, entre turnos e durante um turno, sem `system/init` nem `result`; `get_settings` responde `{effective, sources, applied: {model, effort, ...}}`, com `effort: null` em Haiku; um `subtype` desconhecido responde `subtype: "error"`. Numa sessão retomada, a primeira resposta levou uma vez mais de 15 s. **Pelo daemon de dev** (Haiku e Sonnet): o modelo e o esforço do modelo chegaram ao app antes do primeiro turno, e `--model sonnet --effort low` apareceu na linha de comando do bot depois de `bots.setEffort` | feito |
| Uso de contexto no `stream-json` | 8.6 | Parcialmente documentado: `usage` e `modelUsage` no `result` (`agent-sdk/typescript`), janela de 1 milhão em Fable, Sonnet 5+ e Opus 4.7+ e compactação automática em cerca de 967 mil (`model-config`). **Visto com 2.1.284**: cada `assistant` traz `message.usage` (`input_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens`, `output_tokens`), e a soma dos três primeiros bate com o `totalTokens` do `get_context_usage` a menos de 1%; `result.modelUsage[modelo]` traz `contextWindow` (200000 em Haiku 4.5, 1000000 em Sonnet 5.5) e `maxOutputTokens`; `result.usage.iterations[]` traz cada pedido do turno; `autoCompactThreshold` é a janela menos 33 mil (167000, 967000; 67000 com `--autocompact 100k`, que também encolhe `maxTokens`); `/context` como mensagem devolve um `assistant` sintético com `context_usage` e abre um turno, por isso o daemon usa o pedido de controle. `total_cost_usd` é o total do processo, não do turno. **Pelo daemon de dev**: o app recebeu o tamanho ao subir o bot, a cada pedido ao modelo e no fim do turno | feito |
| Tokens do turno no `result` | 8.7 | Parcialmente documentado: `usage` no `result` (`agent-sdk/typescript`), sem dizer se é do turno ou do processo. **Testado com 2.1.284** (Haiku, um processo com dois turnos): `result.usage` é a soma dos pedidos do turno (um turno com um `Read` deu `input_tokens` 18 = 10 + 8 e `cache_read_input_tokens` 46703 = 21692 + 25011, a soma de `iterations[]`) e recomeça a cada turno; `modelUsage` e `total_cost_usd` acumulam o processo. `output_tokens` inclui `output_tokens_details.thinking_tokens`. **Visto numa instalação real** (Sonnet, 2026-09-30): o primeiro turno de um bot sete horas depois do anterior, e três minutos depois de o Botloft reiniciar, levou 11 s e deu `input_tokens` 2, `cache_creation_input_tokens` 72636, `cache_read_input_tokens` 0 e `output_tokens` 983: a conversa inteira gravada de novo no cache, que levou à conta de `reloaded` (8.7). Não verificado: se os tokens de subagentes entram nesse `usage`; a conta de `reloaded` com teste real, num turno de cache quente (deve dar 0) e num depois de o cache expirar | feito |
Expand Down
Loading