summaryrefslogtreecommitdiffhomepage
path: root/packages/transport-http/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-28 12:59:07 +0900
committerAdam Malczewski <[email protected]>2026-06-28 12:59:07 +0900
commit71c635f7d8ee01a2b23d5ddfdfc4bff043980052 (patch)
tree1285beba4405e8d0955dcee340a1180aa6ce3a46 /packages/transport-http/src
parentb83aa8ddbb7023ae9dd0332b4989d4baa11522af (diff)
downloaddispatch-71c635f7d8ee01a2b23d5ddfdfc4bff043980052.tar.gz
dispatch-71c635f7d8ee01a2b23d5ddfdfc4bff043980052.zip
feat(workspace-star): starred workspace priority for concurrency limiting
Diffstat (limited to 'packages/transport-http/src')
-rw-r--r--packages/transport-http/src/app.ts53
-rw-r--r--packages/transport-http/src/extension.ts1
2 files changed, 54 insertions, 0 deletions
diff --git a/packages/transport-http/src/app.ts b/packages/transport-http/src/app.ts
index 0fcc8f0..0d42e06 100644
--- a/packages/transport-http/src/app.ts
+++ b/packages/transport-http/src/app.ts
@@ -1489,6 +1489,59 @@ export function createApp(opts: CreateServerOptions): Hono {
}
});
+ // ─── Star/unstar workspace (concurrency priority) ───────────────────────────
+ // Starred workspaces receive PRIORITY in the concurrency limiter queue —
+ // their agents jump ahead of agents from non-starred workspaces. The
+ // starred state is persisted in the conversation store AND the in-memory
+ // cache in the concurrency service is notified so already-queued agents
+ // are re-prioritized immediately.
+
+ app.put("/workspaces/:id/star", async (c) => {
+ const workspaceId = c.req.param("id");
+ if (!isValidWorkspaceSlug(workspaceId)) {
+ return c.json(
+ {
+ error: "Workspace id must be a valid slug (lowercase alphanumeric + hyphens, 1–40 chars)",
+ },
+ 400,
+ );
+ }
+ try {
+ const workspace = await opts.conversationStore.setWorkspaceStarred(workspaceId, true);
+ // Notify the concurrency service's in-memory cache so queued agents
+ // from this workspace jump ahead immediately.
+ opts.concurrencyService?.notifyWorkspaceStarred(workspaceId, true);
+ log.info("workspaces: starred", { workspaceId });
+ const response: WorkspaceResponse = workspace;
+ return c.json(response, 200);
+ } catch (err) {
+ log.error("workspaces: star failure", { err, workspaceId });
+ return c.json({ error: "Failed to star workspace" }, 500);
+ }
+ });
+
+ app.delete("/workspaces/:id/star", async (c) => {
+ const workspaceId = c.req.param("id");
+ if (!isValidWorkspaceSlug(workspaceId)) {
+ return c.json(
+ {
+ error: "Workspace id must be a valid slug (lowercase alphanumeric + hyphens, 1–40 chars)",
+ },
+ 400,
+ );
+ }
+ try {
+ const workspace = await opts.conversationStore.setWorkspaceStarred(workspaceId, false);
+ opts.concurrencyService?.notifyWorkspaceStarred(workspaceId, false);
+ log.info("workspaces: unstarred", { workspaceId });
+ const response: WorkspaceResponse = workspace;
+ return c.json(response, 200);
+ } catch (err) {
+ log.error("workspaces: unstar failure", { err, workspaceId });
+ return c.json({ error: "Failed to unstar workspace" }, 500);
+ }
+ });
+
// ─── Heartbeat (per-workspace AI loop) ─────────────────────────────────────
// The config + run history for a workspace's heartbeat loop. Delegated to
// the HeartbeatService (provided by the `heartbeat` extension). When
diff --git a/packages/transport-http/src/extension.ts b/packages/transport-http/src/extension.ts
index f46fca5..5bf16b3 100644
--- a/packages/transport-http/src/extension.ts
+++ b/packages/transport-http/src/extension.ts
@@ -72,6 +72,7 @@ export const manifest: Manifest = {
"/workspaces/:id/heartbeat",
"/workspaces/:id/heartbeat/runs",
"/workspaces/:id/heartbeat/runs/:runId/stop",
+ "/workspaces/:id/star",
"/workspaces/:id/title",
],
},