Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0f7d653
feat(work): queue primitives for tasks
jerelvelarde Oct 28, 2026
79c07f6
feat(tasks): a table and store for tasks
jerelvelarde Oct 28, 2026
8941266
fix(toolkit): name a lock refused on a turn's first ask
jerelvelarde Oct 29, 2026
5abbd15
feat(tasks): Start on a suggestion opens a task of its own
jerelvelarde Oct 29, 2026
efe31e7
feat(tasks): start_task, and the + on Tasks
jerelvelarde Oct 29, 2026
f0c169c
feat(tasks): a task's report
jerelvelarde Oct 29, 2026
4bbadf6
test(tasks): hold the busy-off signal to its order, and the clock
jerelvelarde Oct 29, 2026
831a168
fix(tasks): a task's reply ends in plain sentences, and asks only whe…
jerelvelarde Oct 29, 2026
e9712be
fix(tasks): a task's last line speaks to the person, and says nothing…
jerelvelarde Oct 29, 2026
f44896d
fix(tasks): a task waiting on you says so in plain words
jerelvelarde Oct 29, 2026
11045c7
fix(tasks): only a person's own conversation can start a task
jerelvelarde Oct 29, 2026
923edb0
fix(tasks): a long closing question still reads as Needs you
jerelvelarde Oct 29, 2026
c5325fa
fix(tasks): read one person's task turns through an index
jerelvelarde Oct 29, 2026
525a5a8
fix(tasks): Allow once carries its turn on in the task's order
jerelvelarde Oct 29, 2026
b2c2ac9
fix(tasks): cap how many task turns run at once
jerelvelarde Oct 29, 2026
09906ed
fix(tasks): a turn carried on in a task's conversation is the task's …
jerelvelarde Oct 29, 2026
348d9d4
fix(channels): a channel read says which task it is the conversation of
jerelvelarde Oct 29, 2026
442eed9
fix(tasks): a task's why is the person's reason, never the Bot's
jerelvelarde Oct 30, 2026
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
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Newest first. `Unreleased` is what is on `main` and not yet tagged.

## Unreleased

**Before upgrading.** Sixteen things change for an existing deployment:
**Before upgrading.** Seventeen things change for an existing deployment:
- Bots now share one computer per person instead of each having its own. Migration
`0069_isolated_bots` adds `agent_profiles.isolated`, off for every existing Bot. With the
supervisor (laptop, Desktop, Compose), a person's computer is created the first time one of their
Expand Down Expand Up @@ -64,6 +64,9 @@ Newest first. `Unreleased` is what is on `main` and not yet tagged.
research run replaces them.
- Migration `0062_action_policy_labels` adds a `labels` column to `action_policies`, defaulting to
empty. Existing boundary rules keep working and show as "Custom rule" until somebody names them.
- Migration `0070_tasks` adds one table, `tasks`, naming each task's conversation (below), and one
index to `work_items`. The table starts empty. A suggestion started before the upgrade and still
queued opens a task when it runs, rather than running in the conversation it was suggested in.
- On Helm's `shared` computer and the docker-compose `agent-computer`, each Bot's files now live in
`computers/<Bot id>` on the workspace volume (below). Files saved before the upgrade stay at the
root of the volume, where no Bot sees them; move them into a Bot's folder to give them back.
Expand All @@ -78,6 +81,20 @@ Newest first. `Unreleased` is what is on `main` and not yet tagged.
`COMPUTER_MEMORY_HIGH_PERCENT=0` and `COMPUTER_TAB_IDLE_MS=0` (Helm: `computers.memoryHighPercent`
and `computers.tabIdleMs`) keep the old behaviour.

### Started work gets a conversation of its own

Start on a suggestion now opens a task: a new conversation with the Bot where the work runs, so the
conversation the suggestion came from stays as it was. A task's status is worked out from the work
queue and the approval and question inboxes on every read. A turn that fails is tried once more, then
reads as failed with the reason in plain words and can be tried again; replying in a task's
conversation steers it, in order, even across a restart. The new `/api/tasks` routes serve it.

A Bot OpenBot runs itself now hands anything bigger than a quick answer to a task of its own
(`start_task`) and answers "On it" where it was asked. A Bot behind a remote agent framework is not
offered the tool; its tasks start from its suggestions, or from `POST /api/tasks`, which starts one
with any of the person's Bots. `GET /api/tasks/:id/report` reads a task's conversation back as its
report: the person's decisions and replies, and the Bot's update as each turn ended, in order.

### A computer closes browsers nobody is using when its memory runs high

A computer runs one browser for each Bot that is browsing, and the only limits were a count and half
Expand Down
1 change: 1 addition & 0 deletions server/drizzle.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default defineConfig({
"./src/db/schema/shared-use.ts",
"./src/db/schema/identity.ts",
"./src/db/schema/recorder.ts",
"./src/db/schema/tasks.ts",
],
out: "./drizzle",
dbCredentials: {
Expand Down
25 changes: 25 additions & 0 deletions server/drizzle/0070_tasks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
CREATE TABLE "tasks" (
"id" text PRIMARY KEY NOT NULL,
"owner_user_id" text NOT NULL,
"bot_id" text NOT NULL,
"channel_id" text NOT NULL,
"title" text NOT NULL,
"why" text,
"origin" text NOT NULL,
"suggestion_id" text,
"source_app" text,
"source_link" text,
"resolved_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "tasks_origin_check" CHECK ("tasks"."origin" IN ('asked', 'suggestion'))
);
--> statement-breakpoint
ALTER TABLE "tasks" ADD CONSTRAINT "tasks_owner_user_id_users_id_fk" FOREIGN KEY ("owner_user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tasks" ADD CONSTRAINT "tasks_bot_id_agents_id_fk" FOREIGN KEY ("bot_id") REFERENCES "public"."agents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tasks" ADD CONSTRAINT "tasks_channel_id_channels_id_fk" FOREIGN KEY ("channel_id") REFERENCES "public"."channels"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tasks" ADD CONSTRAINT "tasks_suggestion_id_proactive_suggestions_id_fk" FOREIGN KEY ("suggestion_id") REFERENCES "public"."proactive_suggestions"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "tasks_owner_created_idx" ON "tasks" USING btree ("owner_user_id","created_at");--> statement-breakpoint
CREATE UNIQUE INDEX "tasks_channel_idx" ON "tasks" USING btree ("channel_id");--> statement-breakpoint
CREATE UNIQUE INDEX "tasks_suggestion_idx" ON "tasks" USING btree ("suggestion_id");--> statement-breakpoint
CREATE INDEX "work_items_owner_task_idx" ON "work_items" USING btree ("kind",("payload"->>'ownerUserId'),("payload"->>'taskId'));
Loading
Loading