Агентне середовище розробки.
Відкритий код, працює з моделями, якими ви вже користуєтесь. Запустіть агента на одній машині й продовжіть ту саму сесію з іншої.
Прогнав 100 завантажень на зʼєднанні, яке губить кожен пʼятий запит. Невдалих завантажень стало 1 замість 23.
Єдина помилка це файл, який відхилив сервер, тож повторна спроба не допомогла б.
Швидкість завантаження тепер у хедері поруч із назвою файлу, а коли черга порожня, вона ховається.
Беруся. Напишу тут, коли буде що показати.
Відтворив і знайшов причину. Виправлення готове до ревʼю.
Додав експоненційну затримку в чергу завантажень. Невдалий фрагмент повторюється до п'яти разів, а смуга прогресу показує спробу. Тести покривають тайм-аут і відповідь 503.
Раніше невдалий фрагмент просто відкидався. Тепер черга питає в політики затримку й планує повтор, тож усі повтори проходять через одне місце.
Після пʼяти невдалих спроб фрагмент падає остаточно, а завантаження зупиняється зі зрозумілою помилкою, тож мертве зʼєднання не повторює безкінечно.
Зміна в черзі лежить у src/upload/queue.ts, а затримки зібрані в src/upload/backoff.ts.
Черга записує стан кожного фрагмента на диск. Зараз підключаю шлях після рестарту.
Під час запуску черга читає збережений стан і надсилає лише незавершені фрагменти, тож файл на 2 ГБ не починає спочатку.
У стратегії сказано вийти на ринок, тож я додав для цього функцію.
1export async function goToMarket() {2await ship();3await tellDenis();4}
Один тест проходить. Ринок поки не відповів.
Тест читав файл раніше, ніж вотчер його записав. Тепер він чекає подію flush, і 200 запусків підряд проходять.
1test('reads the synced file', async () => {2await writeFile(path, 'hello');3await watcher.flushed(path);4const text = await readFile(path);5expect(text).toBe('hello');6});
Очікування лежить у хелпері тестів, тож інші тести синхронізації теж виправились.
Нова сторінка готова. Перед тим як прибрати вкладки, треба запустити міграцію налаштувань.
| Стара вкладка | Новий розділ |
|---|---|
| Загальні | Робочий простір |
| Вигляд | Робочий простір |
| Акаунти | Профіль |
Міграція пройшла 212 налаштувань без помилок, старих вкладок більше немає. Усі налаштування тепер на одній сторінці.
Зупинився тут. Старі вкладки лишаються, доки не захочеш запустити міграцію.
Є дві знахідки. Кукі сесії не має терміну дії, а редирект після логіну приймає будь-який URL. Решта виглядає добре.
Готово. Вибрані виправлення внесені, кожне з тестом, а відкладене лишається коментарем у pull request.
Зрозумів. Нічого не змінював, зауваження лишаються коментарями в pull request.
Спробував нову команду на чистій машині, вона працює.
1bun add -g uploader2uploader --help
Стара команда curl теж досі працює, тож може лишитися запасним варіантом.
Готово. Нова команда на вибраному місці, а стара лишилась запасним варіантом.
Майже весь час іде на читання всіх файлів під час кожного пошуку. Індекс це скорочує, а малі репо майже не змінюються.
Індекс оновлюється, коли змінюється файл, тож повна перебудова не потрібна.
Дерево тепер вантажиться з кешу на диску й оновлюється у фоні. Змінюється лише час очікування.
- Влучання в кеш
- 94%
- Розмір на диску
- 2.1 MB
- Завантаження дерева
- 40 ms
Кеш очищується сам, коли змінюється гілка.
Знайшов. Порожній файл стає null, а код одразу читає з нього поле.
1export function loadConfig(path: string) {2const text = readFileSync(path, 'utf8');3if (text.trim() === '') return defaults;4return { ...defaults, ...parse(text) };5}
Тепер порожній файл вважається стандартним конфігом, а зламаний показує зрозумілу помилку.
Пʼять нових issues. Три справжні баги, один із них може почекати наступного релізу.
| Issue | Тип |
|---|---|
| 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 |
Я все розмітив і привʼязав дублікат до старішого звіту.
Над чим працюємо в uploader?
Повтор невдалих завантажень
Додав експоненційну затримку в чергу завантажень. Невдалий фрагмент повторюється до п'яти разів, а смуга прогресу показує спробу. Тести покривають тайм-аут і відповідь 503.
Раніше невдалий фрагмент просто відкидався. Тепер черга питає в політики затримку й планує повтор, тож усі повтори проходять через одне місце.
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}
Працює на вашій машині. Доступне звідусіль.
Десктопна апка запускає агентів на вашому комп'ютері й підключається до ваших серверів. Телефон один раз підключається через QR-код, а далі дістається до них через Private Relay: з наскрізним шифруванням і без відкритих портів.
Над чим працюємо в uploader?
Над чим працюємо в uploader?
Над чим працюємо в uploader?
Сесій не знайдено.
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); });
Одне завдання, кілька моделей.
Надішліть один промпт кільком моделям одразу. Кожен запуск може отримати власний worktree і гілку. Залиште найкращий результат або об'єднайте відповіді в один.
Читайте великий діф як покроковий огляд.
Walkthrough розкладає великий діф у тому порядку, в якому зміна має сенс, пояснює кожен крок одним реченням і позначає ключову зміну, щоб ви знали, з чого почати.
Ваші тікети й інструменти за один клік.
Почніть сесію з issue на GitHub, пул-реквесту чи тікета в Linear, і агент отримає все обговорення. У каталозі інтеграцій понад 160 сервісів, серед них Figma і Sentry, і кожен ставиться одним кліком.
Дайте йому ціль або розклад.
Задайте ціль, і агент працюватиме хід за ходом, доки окрема перевірка не скаже, що все готово або що він застряг. Заплановані завдання самі запускають сесію щоранку або один раз у наступний вівторок.
Від людей, які ним користуються.
Пости, про які ми не просили.
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.
Встановіть на машину, яка у вас уже є.
Десктоп-застосунок для macOS, Windows чи Linux або одна команда на сервері. Далі відкривайте звідки завгодно.
OpenChamber нічого не збирає про вашу роботу. Код під ліцензією MIT, тож будь-хто може перевірити.
Активність
Чи можна винести затримки в конфіг? На мобільних можуть знадобитись довші.
Гарна ідея. Затримки тепер один масив, тож це може бути окремий PR.