Um ambiente de desenvolvimento com agentes.
É de código aberto e funciona com os modelos que você já usa. Inicie um agente em uma máquina e retome a mesma sessão de outra.
Rodei 100 uploads em uma conexão que perde uma requisição a cada cinco. Os uploads com falha caíram de 23 para 1.
A única falha foi um arquivo que o servidor recusou, então tentar de novo não ajudaria.
A velocidade de upload agora fica no cabeçalho ao lado do nome do arquivo e some quando a fila está vazia.
Já estou nisso. Volto aqui quando tiver algo para mostrar.
Reproduzi e encontrei a causa. A correção está pronta para revisão.
Adicionei backoff exponencial à fila de upload. Um bloco com falha é repetido até cinco vezes, e a barra de progresso mostra a tentativa. Os testes cobrem o timeout e o caso 503.
Antes, um bloco com falha era descartado. Agora a fila pede um atraso à política de backoff e agenda a retentativa, então todas as retentativas passam por um só lugar.
Depois de cinco tentativas, o fragmento falha de vez e o envio para com um erro claro, assim uma conexão morta não tenta para sempre.
A mudança da fila está em src/upload/queue.ts, e src/upload/backoff.ts guarda as esperas.
A fila grava o estado de cada fragmento em disco. Agora estou ligando o caminho do reinício.
Ao iniciar, a fila lê o estado salvo e envia só os fragmentos inacabados, então um arquivo de 2 GB não recomeça.
A estratégia diz para ir ao mercado, então adicionei uma função para isso.
1export async function goToMarket() {2await ship();3await tellDenis();4}
Um teste passa. O mercado ainda não respondeu.
O teste lia o arquivo antes de o watcher gravá-lo. Agora ele espera o evento de flush, e 200 execuções seguidas passam.
1test('reads the synced file', async () => {2await writeFile(path, 'hello');3await watcher.flushed(path);4const text = await readFile(path);5expect(text).toBe('hello');6});
A espera fica no helper de testes, então os outros testes de sync também ganham a correção.
A nova página está pronta. Preciso rodar a migração dos ajustes antes de remover as abas.
| Aba antiga | Nova seção |
|---|---|
| Geral | Espaço de trabalho |
| Aparência | Espaço de trabalho |
| Contas | Perfil |
A migração passou por 212 ajustes sem erros e as abas antigas sumiram. Todos os ajustes estão em uma página.
Parei aqui. As abas antigas ficam até você querer rodar a migração.
Dois achados. O cookie de sessão não expira, e o redirecionamento após o login aceita qualquer URL. O resto parece certo.
Pronto. As correções que você escolheu estão feitas, cada uma com um teste, e o que ficou para depois segue como comentário no pull request.
Entendido. Nada mudou, e os achados ficam como comentários no pull request.
Testei o novo comando em uma máquina limpa e funciona.
1bun add -g uploader2uploader --help
O comando curl antigo também continua funcionando, então pode ficar como alternativa.
Pronto. O novo comando está onde você pediu, e o antigo fica como alternativa.
Quase todo o tempo vai em ler todos os arquivos a cada busca. Um índice reduz isso, e repos pequenos quase não mudam.
O índice atualiza quando um arquivo muda, então nunca precisa ser refeito por inteiro.
A árvore agora carrega de um cache em disco e atualiza em segundo plano. Só muda a espera.
- Acertos de cache
- 94%
- Tamanho em disco
- 2.1 MB
- Carga da árvore
- 40 ms
O cache se limpa sozinho quando o branch muda.
Achei. Um arquivo vazio vira null, e o código lê um campo dele logo em seguida.
1export function loadConfig(path: string) {2const text = readFileSync(path, 'utf8');3if (text.trim() === '') return defaults;4return { ...defaults, ...parse(text) };5}
Agora um arquivo vazio conta como config padrão, e um quebrado mostra um erro claro.
Cinco issues novas. Três são bugs reais, e um pode esperar a próxima versão.
| Issue | Tipo |
|---|---|
| Upload stalls at 99% on Safari | bug |
| Crash on a file named final_final_v2_🦆.mov | bug |
| Progress bar jumps back after resume | bug |
| Drag a folder into the upload list | feature |
| Is there a size limit? Asking for a 400 GB log file | question |
Coloquei rótulos em todas e liguei a duplicada ao relato mais antigo.
No que vamos trabalhar em uploader?
Repetir uploads com falha
Adicionei backoff exponencial à fila de upload. Um bloco com falha é repetido até cinco vezes, e a barra de progresso mostra a tentativa. Os testes cobrem o timeout e o caso 503.
Antes, um bloco com falha era descartado. Agora a fila pede um atraso à política de backoff e agenda a retentativa, então todas as retentativas passam por um só lugar.
const result = await sendChunk(chunk); if (!result.ok) return fail(chunk); if (!result.ok) { const delay = backoff.next(chunk.attempt); if (delay === null) return fail(chunk); return schedule(chunk, delay); } progress.advance(chunk.size); const DELAYS = [500, 1000, 2000, 4000, 8000]; export const backoff = { next(attempt: number) { return DELAYS[attempt] ?? null; } }; 1import { backoff } from './backoff';2import { sendChunk } from './client';3import { progress } from './progress';4import type { Chunk, UploadResult } from './types';56// TODO: remove before launch (added in 2023)7const MAX_PARALLEL = 4;8const queue: Chunk[] = [];9let running = 0;1011export function enqueue(chunks: Chunk[]) {12queue.push(...chunks);13void drain();14}1516async function drain() {17while (running < MAX_PARALLEL && queue.length > 0) {18const chunk = queue.shift();19if (!chunk) return;20running += 1;21await upload(chunk);22running -= 1;23}24}2526export async function upload(chunk: Chunk): Promise<UploadResult> {27const result = await sendChunk(chunk);28if (!result.ok) {29const delay = backoff.next(chunk.attempt);30if (delay === null) return fail(chunk);31return schedule(chunk, delay);32}33progress.advance(chunk.size);34return done(chunk);35}3637function schedule(chunk: Chunk, delay: number) {38chunk.attempt += 1;39progress.retrying(chunk);40setTimeout(() => enqueue([chunk]), delay);41}
Roda na sua máquina. Acesse de qualquer lugar.
O app desktop roda agentes no seu computador e se conecta aos seus servidores. Pareie o celular uma vez com um QR code e ele chega até eles pelo Private Relay, com criptografia de ponta a ponta e sem abrir portas.
No que vamos trabalhar em uploader?
No que vamos trabalhar em uploader?
No que vamos trabalhar em uploader?
Nenhuma sessão encontrada.
const result = await sendChunk(chunk); if (!result.ok) { const delay = backoff.next(chunk.attempt); if (delay === null) return fail(chunk); return schedule(chunk, delay); }
const DELAYS = [500, 1000, 2000, 4000, 8000]; export const backoff = { next(attempt: number) { return DELAYS[attempt] ?? null; } };
test('retries a chunk after a 503', async () => { server.respondWith(503); await upload(chunk); clock.tick(500); expect(server.calls).toBe(2); });
Uma tarefa, vários modelos.
Envie o mesmo prompt para vários modelos ao mesmo tempo. Cada execução pode ter seu próprio worktree e branch. Fique com o resultado de que mais gostar ou funda as respostas em uma só.
Leia um diff grande como um roteiro.
O walkthrough coloca um diff grande na ordem em que ele faz sentido, explica cada passo em uma frase e marca a mudança principal, para você saber o que ler primeiro.
Seus tickets e ferramentas a um clique.
Comece uma sessão a partir de uma issue do GitHub, um pull request ou um ticket do Linear, e o agente recebe a conversa inteira. O catálogo de integrações tem mais de 160 serviços, entre eles Figma e Sentry, e cada um se instala com um clique.
Dê a ele uma meta ou um horário.
Defina uma meta e o agente continua trabalhando, turno após turno, até que uma verificação separada diga que terminou ou travou. As tarefas agendadas abrem uma sessão sozinhas, toda manhã ou uma vez só na próxima terça.
De quem usa.
Publicações que não pedimos.
I've had a deep experience with openchamber. I think my choice was right. This thing is really useful, smooth and silky. Go try it out quick, I strongly recommend it, no more messing around blindly.
@realchendahuang Was looking for a way to run agents from my phone, remotely on my server, other than tmux. Found OpenChamber. It is INSANELY good, highly recommended.
@NihilSineTheo Seriously, I've spent almost the whole week trying to find a tool that made sense to orchestrate agents and, as a dev (actually, a devops), openchamber is the only one that felt natural and logical.
@1un4rPunk I just want to say the app itself is phenomenal. The level of polish is just unreal. I saw OpenChamber back when it was a small project, I think maybe a couple months ago, and now it is unrecognizable. Truly amazing work. The latest release with its streaming feature is everything I could have possibly asked for and more. It is gorgeous and smooth.
Instale na máquina que você já tem.
O app de desktop no macOS, Windows ou Linux, ou um comando em um servidor. Depois, abra de onde você estiver.
O OpenChamber não coleta nada sobre o seu trabalho. O código tem licença MIT, então qualquer pessoa pode conferir.
Atividade
As esperas podem ir para a config? No celular talvez queiramos mais longas.
Boa ideia. As esperas agora são um array só, então pode ser outro PR.