Środowisko pracy sterowane agentami.
Open source, działa z modelami, których już używasz. Uruchom agenta na jednej maszynie, a tę samą sesję podejmij z innej.
Puściłem 100 wysyłek przez połączenie, które gubi co piąte żądanie. Nieudane wysyłki spadły z 23 do 1.
Jedyny błąd to plik odrzucony przez serwer, więc ponowienie nie mogło pomóc.
Prędkość wysyłania jest teraz w nagłówku obok nazwy pliku i znika, gdy kolejka jest pusta.
Zabieram się za to. Napiszę tutaj, gdy będzie co pokazać.
Odtworzyłem to i znalazłem przyczynę. Poprawka jest gotowa do review.
Dodałem wykładniczy backoff do kolejki uploadu. Nieudany fragment jest ponawiany do pięciu razy, a pasek postępu pokazuje próbę. Testy obejmują timeout i odpowiedź 503.
Wcześniej nieudany fragment był odrzucany. Teraz kolejka pyta politykę backoffu o opóźnienie i planuje ponowienie, więc wszystkie ponowienia przechodzą przez jedno miejsce.
Po pięciu nieudanych próbach fragment zawodzi na dobre, a wysyłka kończy się czytelnym błędem, więc martwe połączenie nie ponawia bez końca.
Zmiana w kolejce jest w src/upload/queue.ts, a src/upload/backoff.ts trzyma opóźnienia.
Kolejka zapisuje stan każdego fragmentu na dysku. Teraz podpinam ścieżkę po restarcie.
Przy starcie kolejka czyta zapisany stan i wysyła tylko niedokończone fragmenty, więc plik 2 GB nie zaczyna od nowa.
Strategia mówi, żeby wejść na rynek, więc dodałem do tego funkcję.
1export async function goToMarket() {2await ship();3await tellDenis();4}
Jeden test przechodzi. Rynek jeszcze nie odpowiedział.
Test czytał plik, zanim watcher go zapisał. Teraz czeka na zdarzenie flush i przechodzi 200 razy z rzędu.
1test('reads the synced file', async () => {2await writeFile(path, 'hello');3await watcher.flushed(path);4const text = await readFile(path);5expect(text).toBe('hello');6});
Czekanie jest w helperze testów, więc pozostałe testy synchronizacji też zyskują poprawkę.
Nowa strona jest gotowa. Przed usunięciem kart muszę uruchomić migrację ustawień.
| Stara karta | Nowa sekcja |
|---|---|
| Ogólne | Obszar roboczy |
| Wygląd | Obszar roboczy |
| Konta | Profil |
Migracja objęła 212 ustawień bez błędów, a stare karty zniknęły. Wszystkie ustawienia są na jednej stronie.
Zatrzymuję się tutaj. Stare karty zostają, dopóki nie zechcesz uruchomić migracji.
Dwie uwagi. Ciasteczko sesji nie wygasa, a przekierowanie po logowaniu przyjmuje dowolny URL. Reszta wygląda dobrze.
Gotowe. Wybrane poprawki są już w kodzie, każda z testem, a odłożone zostają jako komentarze w pull requeście.
Rozumiem. Nic nie zmieniłem, a ustalenia zostają jako komentarze w pull requeście.
Sprawdziłem nowe polecenie na czystej maszynie i działa.
1bun add -g uploader2uploader --help
Stare polecenie curl też nadal działa, więc może zostać jako rezerwa.
Gotowe. Nowe polecenie jest we wskazanym miejscu, a stare zostaje jako rezerwa.
Większość czasu idzie na czytanie wszystkich plików przy każdym wyszukiwaniu. Indeks to skraca, a małe repo prawie się nie zmieniają.
Indeks aktualizuje się przy zmianie pliku, więc nigdy nie trzeba go przebudowywać w całości.
Drzewo ładuje się teraz z cache na dysku i odświeża w tle. Zmienia się tylko czas czekania.
- Trafienia w cache
- 94%
- Rozmiar na dysku
- 2.1 MB
- Czas ładowania drzewa
- 40 ms
Cache czyści się sam przy zmianie gałęzi.
Znalezione. Pusty plik daje null, a kod od razu czyta z niego pole.
1export function loadConfig(path: string) {2const text = readFileSync(path, 'utf8');3if (text.trim() === '') return defaults;4return { ...defaults, ...parse(text) };5}
Teraz pusty plik liczy się jako konfiguracja domyślna, a uszkodzony pokazuje czytelny błąd.
Pięć nowych issues. Trzy to prawdziwe błędy, a jeden może poczekać do następnego wydania.
| Issue | Rodzaj |
|---|---|
| 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 |
Oznaczyłem wszystkie i połączyłem duplikat ze starszym zgłoszeniem.
Nad czym pracujemy w uploader?
Ponawianie nieudanych uploadów
Dodałem wykładniczy backoff do kolejki uploadu. Nieudany fragment jest ponawiany do pięciu razy, a pasek postępu pokazuje próbę. Testy obejmują timeout i odpowiedź 503.
Wcześniej nieudany fragment był odrzucany. Teraz kolejka pyta politykę backoffu o opóźnienie i planuje ponowienie, więc wszystkie ponowienia przechodzą przez jedno miejsce.
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}
Działa na twojej maszynie. Dostęp z dowolnego miejsca.
Aplikacja desktopowa uruchamia agentów na twoim komputerze i łączy się z twoimi serwerami. Telefon parujesz raz kodem QR, a potem łączy się z nimi przez Private Relay, z szyfrowaniem end-to-end i bez otwierania portów.
Nad czym pracujemy w uploader?
Nad czym pracujemy w uploader?
Nad czym pracujemy w uploader?
Nie znaleziono sesji.
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); });
Jedno zadanie, kilka modeli.
Wyślij ten sam prompt do kilku modeli naraz. Każde uruchomienie może dostać własny worktree i gałąź. Zachowaj wynik, który najbardziej ci odpowiada, albo połącz odpowiedzi w jedną.
Czytaj duży diff jako przewodnik.
Walkthrough układa duży diff w kolejności, w której zmiana ma sens, objaśnia każdy krok jednym zdaniem i oznacza kluczową zmianę, żebyś wiedział, od czego zacząć.
Twoje zgłoszenia i narzędzia o jedno kliknięcie.
Zacznij sesję od issue na GitHubie, pull requesta albo zgłoszenia w Linear, a agent dostanie cały wątek. Katalog integracji ma ponad 160 usług, w tym Figmę i Sentry, i każdą instalujesz jednym kliknięciem.
Daj mu cel albo harmonogram.
Ustaw cel, a agent pracuje tura po turze, dopóki osobna kontrola nie uzna, że skończył albo utknął. Zaplanowane zadania same otwierają sesję, każdego ranka albo raz, w przyszły wtorek.
Desktop, telefon, przeglądarka, edytor.
Od ludzi, którzy tego używają.
Wpisy, o które nie prosiliśmy.
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.
Zainstaluj na maszynie, którą już masz.
Aplikacja na komputer z macOS, Windows lub Linuksem albo jedno polecenie na serwerze. Potem otwieraj, skąd tylko jesteś.
OpenChamber nie zbiera nic o twojej pracy. Kod jest na licencji MIT, więc każdy może to sprawdzić.
Aktywność
Czy opóźnienia mogą trafić do konfiguracji? Na telefonach możemy chcieć dłuższych.
Dobry pomysł. Opóźnienia to teraz jedna tablica, więc może to być kolejny PR.