mcp-server-opencode 1.1.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/build/src/index.js +14 -10
- package/build/src/index.js.map +1 -1
- package/build/src/modules/shared/instructions.d.ts +8 -1
- package/build/src/modules/shared/instructions.d.ts.map +1 -1
- package/build/src/modules/shared/instructions.js +26 -27
- package/build/src/modules/shared/instructions.js.map +1 -1
- package/build/src/modules/shared/opencode-client.d.ts +31 -3
- package/build/src/modules/shared/opencode-client.d.ts.map +1 -1
- package/build/src/modules/shared/opencode-client.js +118 -25
- package/build/src/modules/shared/opencode-client.js.map +1 -1
- package/build/src/modules/shared/permissions.d.ts +108 -0
- package/build/src/modules/shared/permissions.d.ts.map +1 -0
- package/build/src/modules/shared/permissions.js +193 -0
- package/build/src/modules/shared/permissions.js.map +1 -0
- package/build/src/modules/shared/task-registry.d.ts +11 -0
- package/build/src/modules/shared/task-registry.d.ts.map +1 -1
- package/build/src/modules/shared/task-registry.js +10 -0
- package/build/src/modules/shared/task-registry.js.map +1 -1
- package/build/src/modules/shared/usage-limits.d.ts +70 -0
- package/build/src/modules/shared/usage-limits.d.ts.map +1 -0
- package/build/src/modules/shared/usage-limits.js +296 -0
- package/build/src/modules/shared/usage-limits.js.map +1 -0
- package/build/src/modules/tools/cancel_task.d.ts.map +1 -1
- package/build/src/modules/tools/cancel_task.js +5 -0
- package/build/src/modules/tools/cancel_task.js.map +1 -1
- package/build/src/modules/tools/get_task_result.d.ts.map +1 -1
- package/build/src/modules/tools/get_task_result.js +42 -7
- package/build/src/modules/tools/get_task_result.js.map +1 -1
- package/build/src/modules/tools/list_agents.d.ts.map +1 -1
- package/build/src/modules/tools/list_agents.js +22 -4
- package/build/src/modules/tools/list_agents.js.map +1 -1
- package/build/src/modules/tools/start_server.d.ts.map +1 -1
- package/build/src/modules/tools/start_server.js +22 -2
- package/build/src/modules/tools/start_server.js.map +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
Releases before `1.2.0` predate this file and are not documented here.
|
|
9
|
+
|
|
10
|
+
## [1.2.0] — 2026-08-28
|
|
11
|
+
|
|
12
|
+
Delegated tasks could hang forever, or report `completed` after doing nothing.
|
|
13
|
+
Both are fixed, and the result payload now carries evidence of what a task
|
|
14
|
+
actually did. See `docs/incident-2026-08-21-silent-noop-tasks.md` for the full
|
|
15
|
+
report this release closes out.
|
|
16
|
+
|
|
17
|
+
### Behavior changes callers must handle
|
|
18
|
+
|
|
19
|
+
- `opencode_get_task_status` and `opencode_get_task_result` can now return two
|
|
20
|
+
new statuses: **`empty`** and **`cancelled`**. Both were previously reported
|
|
21
|
+
as `completed`. Code that switches exhaustively on task status needs a branch
|
|
22
|
+
for them; code that only special-cases `completed` will now correctly stop
|
|
23
|
+
treating a no-op or an aborted task as a success.
|
|
24
|
+
- `opencode_get_task_result` now includes a `progress` object. Previously it
|
|
25
|
+
returned only `status` and `result`.
|
|
26
|
+
- `opencode_start_server` now reports its permission posture under
|
|
27
|
+
`permissions` (`{ external_directory, auto_approved }`).
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **Permission responder for headless servers.** A headless `opencode serve`
|
|
32
|
+
has no interactive approver, so any permission resolved to `ask` blocked the
|
|
33
|
+
agent forever — the session stayed genuinely busy and the task neither
|
|
34
|
+
completed nor failed. `opencode_start_server` now passes a permission config
|
|
35
|
+
to the OpenCode server *and* subscribes to its event stream to answer every
|
|
36
|
+
request.
|
|
37
|
+
- **`OPENCODE_MCP_EXTERNAL_DIR`** selects how the delegated agent may touch
|
|
38
|
+
paths outside the directory the server was launched in. Precedence: env var >
|
|
39
|
+
`OPENCODE_MCP_EXTERNAL_DIR=<policy>` CLI arg > default.
|
|
40
|
+
- `read-only` (default) — reads outside the cwd are approved, writes rejected.
|
|
41
|
+
- `allow` — no boundary.
|
|
42
|
+
- `deny` — nothing outside the cwd is reachable.
|
|
43
|
+
|
|
44
|
+
Inside the cwd everything is auto-approved; the caller already owns that
|
|
45
|
+
directory. The config is deep-merged per permission key, so existing
|
|
46
|
+
`read` / `edit` / `bash` deny globs (secrets, keys, `.env`) survive untouched.
|
|
47
|
+
- **Side-effect evidence in `TaskProgress`**: `mutating_tool_calls` and
|
|
48
|
+
`files_touched`, collected across every assistant turn in the session.
|
|
49
|
+
`completed` with an empty `files_touched` on a task whose whole purpose was
|
|
50
|
+
writing files is the signal that catches a silent no-op.
|
|
51
|
+
- **Per-model quota annotations.** `opencode_list_agents` now returns each model
|
|
52
|
+
as `{ id, quota }` with a `per_5h` estimate and a tier (`high-volume`,
|
|
53
|
+
`balanced`, `scarce`), scraped from the OpenCode Go docs and cached on disk
|
|
54
|
+
for 24h. A sibling `models.quota_snapshot` distinguishes "this model has no
|
|
55
|
+
quota row" from "we never got the table". Overridable with
|
|
56
|
+
`OPENCODE_MCP_CACHE_DIR` and `OPENCODE_MCP_LIMITS_TTL_MS`; a failed fetch
|
|
57
|
+
falls back to the stale snapshot, so startup never depends on the network.
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- **Tasks no longer hang on a permission prompt.** Previously, any task reading
|
|
62
|
+
or writing a path outside the server cwd wedged indefinitely with no way for a
|
|
63
|
+
caller to tell "working" from "stuck".
|
|
64
|
+
- **`completed` is now a work check, not a timestamp check.** An assistant turn
|
|
65
|
+
that ended with no text and no tool calls reports `empty` instead of
|
|
66
|
+
`completed` with an empty result. A completed timestamp says the turn ended,
|
|
67
|
+
not that it did anything.
|
|
68
|
+
- **Evidence is collected across the whole session, not just the last turn.** An
|
|
69
|
+
agent's edits land in earlier turns while the final turn is usually just
|
|
70
|
+
"DONE", so reading evidence off the last message alone reported
|
|
71
|
+
`files_touched: []` for a task that had rewritten the workspace.
|
|
72
|
+
- **Cancelled tasks report `cancelled`.** `opencode_cancel_task` now records the
|
|
73
|
+
cancellation, and status derivation checks it first. An aborted session keeps
|
|
74
|
+
its completed timestamp, so a deliberately killed task was previously
|
|
75
|
+
indistinguishable from one that finished on its own. A cancelled task still
|
|
76
|
+
returns whatever it produced before the abort, `files_touched` included.
|
|
77
|
+
- **The stall guard covers the empty-turn case.** `PENDING_STALL_MS` was only
|
|
78
|
+
reachable when no assistant message existed at all; once any message existed —
|
|
79
|
+
including an empty or aborted one — the guard was bypassed permanently.
|
|
80
|
+
|
|
81
|
+
### Notes for contributors
|
|
82
|
+
|
|
83
|
+
- The generated `@opencode-ai/sdk` types lag the running binary. Verified
|
|
84
|
+
against opencode `1.18.18` with SDK `1.17.20`: the live permission event is
|
|
85
|
+
`permission.asked` (the SDK declares only `permission.updated`), its kind
|
|
86
|
+
arrives as `properties.permission` (the SDK says `type`), and the call id is
|
|
87
|
+
nested under `properties.tool.callID` (the SDK puts it at the top level).
|
|
88
|
+
Verify wire shapes against a live server before trusting a generated type — a
|
|
89
|
+
mismatch here fails silently, because a permission that is never answered just
|
|
90
|
+
hangs.
|
|
91
|
+
- Two bugs in this release passed a green unit suite and were caught only by
|
|
92
|
+
running against a live server. Mocks reproduce the contract you believe in,
|
|
93
|
+
not the one the system implements.
|
|
94
|
+
|
|
95
|
+
### Not addressed
|
|
96
|
+
|
|
97
|
+
- **F3** from the incident report: there is still no staleness signal on the
|
|
98
|
+
`running` path. `buildProgress` reports `current_tool` and
|
|
99
|
+
`current_tool_status` but no timing, so a caller has no field to compare
|
|
100
|
+
across polls to tell a slow task from a wedged one.
|
package/build/src/index.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createDelegateTaskInstructions } from "./modules/shared/instructions.js";
|
|
5
5
|
import { killAllServers } from "./modules/shared/server-registry.js";
|
|
6
6
|
import { registerTools } from "./modules/tools/index.js";
|
|
7
7
|
// Create server instance
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
8
|
+
async function createServer() {
|
|
9
|
+
const instructions = await createDelegateTaskInstructions();
|
|
10
|
+
return new McpServer({
|
|
11
|
+
name: "opencode-mcp",
|
|
12
|
+
version: "1.0.0",
|
|
13
|
+
title: "OpenCode MCP",
|
|
14
|
+
description: "MCP server that drives an OpenCode instance and delegates work asynchronously to its agents",
|
|
15
|
+
websiteUrl: "https://opencode-mcp.alejandrotechnology.com",
|
|
16
|
+
}, {
|
|
17
|
+
instructions,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
17
20
|
function shutdown(signal) {
|
|
18
21
|
console.error(`Received ${signal}, stopping tracked OpenCode servers...`);
|
|
19
22
|
killAllServers();
|
|
@@ -27,6 +30,7 @@ process.on("SIGTERM", shutdown);
|
|
|
27
30
|
// Safety net for any other exit path (uncaught exception, process.exit elsewhere).
|
|
28
31
|
process.on("exit", killAllServers);
|
|
29
32
|
async function main() {
|
|
33
|
+
const server = await createServer();
|
|
30
34
|
registerTools(server);
|
|
31
35
|
const transport = new StdioServerTransport();
|
|
32
36
|
await server.connect(transport);
|
package/build/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,yBAAyB;AACzB,KAAK,UAAU,YAAY;IACzB,MAAM,YAAY,GAAG,MAAM,8BAA8B,EAAE,CAAC;IAC5D,OAAO,IAAI,SAAS,CAClB;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,6FAA6F;QAC/F,UAAU,EAAE,8CAA8C;KAC3D,EACD;QACE,YAAY;KACb,CACF,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,MAAsB;IACtC,OAAO,CAAC,KAAK,CAAC,YAAY,MAAM,wCAAwC,CAAC,CAAC;IAC1E,cAAc,EAAE,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,yEAAyE;AACzE,kEAAkE;AAClE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,mFAAmF;AACnF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAEnC,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;IACpC,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Build the MCP server instructions.
|
|
3
|
+
*
|
|
4
|
+
* Only the spend budget is embedded from the daily snapshot: per-model quotas
|
|
5
|
+
* ride along with `opencode_list_agents`, keyed by the real model id, so they
|
|
6
|
+
* are deliberately not repeated here.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createDelegateTaskInstructions(): Promise<string>;
|
|
2
9
|
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../../src/modules/shared/instructions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../../src/modules/shared/instructions.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,MAAM,CAAC,CA2BtE"}
|
|
@@ -1,33 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Rule of thumb: exploration/mechanical → Fast tier; standard implementation → Mid tier; complex features and long agentic runs → High tier; architecture or hardest debugging → Frontier tier.
|
|
1
|
+
import { formatTierGuide, formatUsageLimits, getUsageLimits } from "./usage-limits.js";
|
|
2
|
+
const QUOTA_FALLBACK = `OpenCode Go usage limits — unavailable right now (the docs could not be fetched and no cached snapshot exists).
|
|
3
|
+
All models share a single dollar budget per 5h / week / month, so an expensive model drains it in far fewer requests.`;
|
|
4
|
+
/**
|
|
5
|
+
* Build the MCP server instructions.
|
|
6
|
+
*
|
|
7
|
+
* Only the spend budget is embedded from the daily snapshot: per-model quotas
|
|
8
|
+
* ride along with `opencode_list_agents`, keyed by the real model id, so they
|
|
9
|
+
* are deliberately not repeated here.
|
|
10
|
+
*/
|
|
11
|
+
export async function createDelegateTaskInstructions() {
|
|
12
|
+
const limits = await getUsageLimits();
|
|
13
|
+
const quotaBlock = limits ? formatUsageLimits(limits) : QUOTA_FALLBACK;
|
|
14
|
+
return `You have access to the opencode-mcp server, which lets you delegate work to OpenCode agents. Follow this workflow whenever you delegate tasks:
|
|
15
|
+
|
|
16
|
+
${quotaBlock}
|
|
17
|
+
Burning a scarce model on work a cheap model handles well is how a session runs out of budget in one shot. Default to the cheapest tier that can do the job and escalate only when the task actually demands it.
|
|
18
|
+
|
|
19
|
+
Choosing a model — pass it per task via the optional "model" input of opencode_start_task as 'providerID/modelID'. Build that string only from opencode_list_agents output: models.providers[].provider + '/' + models.providers[].models[].id, both copied verbatim. Never derive an id from a model's display name, and never assume a provider prefix — read it from the same models.providers[] entry that supplied the id. If opencode_start_task returns status "unknown_model", pick one of the available_models it returns instead of retrying a guessed id.
|
|
20
|
+
|
|
21
|
+
Every model in that output carries a quota field: per_5h (estimated requests per 5 hours) and tier. Choose by tier:
|
|
22
|
+
${formatTierGuide()}
|
|
23
|
+
Spread parallel tasks across models instead of firing every task at the same scarce one. models.providers[] is also the authority on what is actually enabled for the connected account.
|
|
26
24
|
|
|
27
25
|
Workflow:
|
|
28
26
|
1. Ensure an OpenCode server is running. If you don't already have a server_id from a previous opencode_start_server call, call opencode_start_server first.
|
|
29
|
-
2. Call opencode_list_agents with the server_id to discover the available agents (native and custom)
|
|
30
|
-
3. For each task, call opencode_start_task with the server_id and the task's prompt
|
|
27
|
+
2. Call opencode_list_agents with the server_id to discover the available agents (native and custom), the exact model ids and their quotas. Agents may have a pre-assigned model ("provider/model"); you can still override it per task.
|
|
28
|
+
3. For each task, call opencode_start_task with the server_id and the task's prompt, optionally with an agent name and/or a model override. Collect the returned task_id for every call.
|
|
31
29
|
4. Wait for completion with opencode_wait_for_task:
|
|
32
30
|
- Single task: mode "all" with the single task_id.
|
|
33
31
|
- Multiple tasks, incremental results: call it repeatedly with mode "any", removing completed task_ids each time.
|
|
@@ -36,4 +34,5 @@ Workflow:
|
|
|
36
34
|
6. Use opencode_get_task_status only for quick, non-blocking checks on a task's progress (e.g. to report status to the user) — it does not replace opencode_wait_for_task or opencode_get_task_result.
|
|
37
35
|
|
|
38
36
|
Do not call opencode_get_task_result before the task has finished, and prefer opencode_wait_for_task over polling opencode_get_task_status in a loop.`;
|
|
37
|
+
}
|
|
39
38
|
//# sourceMappingURL=instructions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../../../src/modules/shared/instructions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../../../src/modules/shared/instructions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEvF,MAAM,cAAc,GAAG;sHAC+F,CAAC;AAEvH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B;IAClD,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;IAEvE,OAAO;;EAEP,UAAU;;;;;;EAMV,eAAe,EAAE;;;;;;;;;;;;;;sJAcmI,CAAC;AACvJ,CAAC"}
|
|
@@ -10,14 +10,22 @@ export interface AssistantEntry {
|
|
|
10
10
|
info: AssistantMessage;
|
|
11
11
|
parts: Part[];
|
|
12
12
|
}
|
|
13
|
+
/** Fetch every assistant message (with its parts) for a session, oldest first. */
|
|
14
|
+
export declare function assistantEntries(client: OpencodeClient, sessionId: string): Promise<AssistantEntry[]>;
|
|
15
|
+
/** Every part the assistant emitted across the whole session, oldest first. */
|
|
16
|
+
export declare function sessionParts(entries: AssistantEntry[]): Part[];
|
|
13
17
|
/** Fetch the most recent assistant message (with its parts) for a session. */
|
|
14
18
|
export declare function lastAssistantEntry(client: OpencodeClient, sessionId: string): Promise<AssistantEntry | undefined>;
|
|
15
|
-
export type TaskStatus = "pending" | "running" | "completed" | "failed";
|
|
19
|
+
export type TaskStatus = "pending" | "running" | "completed" | "failed" | "empty" | "cancelled";
|
|
16
20
|
export interface TaskProgress {
|
|
17
21
|
/** Last ~500 chars of concatenated TextPart text from the last assistant message. */
|
|
18
22
|
text_snippet: string;
|
|
19
23
|
/** Count of ToolPart parts whose state.status is "completed". */
|
|
20
24
|
tool_calls_completed: number;
|
|
25
|
+
/** Completed tool calls that can mutate the workspace. */
|
|
26
|
+
mutating_tool_calls: number;
|
|
27
|
+
/** Distinct file paths touched by completed mutating tool calls. */
|
|
28
|
+
files_touched: string[];
|
|
21
29
|
/** Tool name of the last ToolPart whose state.status is "running" or "pending". */
|
|
22
30
|
current_tool?: string;
|
|
23
31
|
/** state.status of that tool part. */
|
|
@@ -29,13 +37,33 @@ export interface TaskStatusResult {
|
|
|
29
37
|
error?: string;
|
|
30
38
|
progress?: TaskProgress;
|
|
31
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether an assistant turn actually produced anything.
|
|
42
|
+
*
|
|
43
|
+
* A completed timestamp only says the turn ended, not that it did work: an
|
|
44
|
+
* aborted or rejected turn carries a completed timestamp with no parts at all,
|
|
45
|
+
* which is byte-for-byte indistinguishable from a task that succeeded quietly.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hasWork(parts: Part[]): boolean;
|
|
32
48
|
/**
|
|
33
49
|
* How long an idle session may stay without any assistant message before the
|
|
34
50
|
* task is considered dead (e.g. the fire-and-forget prompt was rejected).
|
|
35
51
|
*/
|
|
36
52
|
export declare const PENDING_STALL_MS = 15000;
|
|
37
|
-
/**
|
|
38
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Build a TaskProgress summary.
|
|
55
|
+
*
|
|
56
|
+
* `latest` is the current assistant turn — it drives the text snippet and the
|
|
57
|
+
* in-flight tool. `whole` is every assistant part in the session and drives the
|
|
58
|
+
* side-effect evidence, because an agent's edits land in earlier turns while
|
|
59
|
+
* the final turn is usually just "DONE". Reading evidence off the last message
|
|
60
|
+
* alone reports `files_touched: []` for a task that rewrote the workspace.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildProgress(latest: Part[], whole?: Part[]): TaskProgress;
|
|
63
|
+
/** Message returned alongside the `cancelled` status, shared by status and result. */
|
|
64
|
+
export declare const CANCELLED_TASK_MESSAGE = "the task was cancelled via opencode_cancel_task; any output below is whatever the agent produced before the abort";
|
|
65
|
+
/** Message returned alongside the `empty` status, shared by status and result. */
|
|
66
|
+
export declare const EMPTY_TURN_MESSAGE = "the session finished without producing any text or tool calls; the prompt was likely rejected or the turn was aborted";
|
|
39
67
|
export interface DeriveTaskStatusOptions {
|
|
40
68
|
includeProgress?: boolean;
|
|
41
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-client.d.ts","sourceRoot":"","sources":["../../../../src/modules/shared/opencode-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,cAAc,EACnB,KAAK,IAAI,EACV,MAAM,kBAAkB,CAAC;AAI1B,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAI5E;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,GACb;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAM3D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,8EAA8E;AAC9E,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"opencode-client.d.ts","sourceRoot":"","sources":["../../../../src/modules/shared/opencode-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,cAAc,EACnB,KAAK,IAAI,EACV,MAAM,kBAAkB,CAAC;AAI1B,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAI5E;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,GACb;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAM3D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,kFAAkF;AAClF,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,EAAE,CAAC,CAS3B;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,CAE9D;AAED,8EAA8E;AAC9E,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAErC;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,CAAC;AAEhG,MAAM,WAAW,YAAY;IAC3B,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAYD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAM9C;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAcvC;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,GAAE,IAAI,EAAW,GAAG,YAAY,CAwClF;AAED,sFAAsF;AACtF,eAAO,MAAM,sBAAsB,sHACkF,CAAC;AAEtH,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,0HAC0F,CAAC;AAE1H,MAAM,WAAW,uBAAuB;IACtC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,gBAAgB,CAAC,CA4E3B"}
|
|
@@ -18,52 +18,116 @@ export function clientForTask(taskId) {
|
|
|
18
18
|
return undefined;
|
|
19
19
|
return { client, sessionId: task.sessionId };
|
|
20
20
|
}
|
|
21
|
-
/** Fetch
|
|
22
|
-
export async function
|
|
21
|
+
/** Fetch every assistant message (with its parts) for a session, oldest first. */
|
|
22
|
+
export async function assistantEntries(client, sessionId) {
|
|
23
23
|
const res = await client.session.messages({ path: { id: sessionId } });
|
|
24
|
-
const
|
|
25
|
-
for (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return { info: entry.info, parts: entry.parts };
|
|
24
|
+
const entries = [];
|
|
25
|
+
for (const message of res.data ?? []) {
|
|
26
|
+
if (message.info.role === "assistant") {
|
|
27
|
+
entries.push({ info: message.info, parts: message.parts });
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
|
-
return
|
|
30
|
+
return entries;
|
|
31
|
+
}
|
|
32
|
+
/** Every part the assistant emitted across the whole session, oldest first. */
|
|
33
|
+
export function sessionParts(entries) {
|
|
34
|
+
return entries.flatMap((entry) => entry.parts);
|
|
35
|
+
}
|
|
36
|
+
/** Fetch the most recent assistant message (with its parts) for a session. */
|
|
37
|
+
export async function lastAssistantEntry(client, sessionId) {
|
|
38
|
+
return (await assistantEntries(client, sessionId)).at(-1);
|
|
32
39
|
}
|
|
33
40
|
const TEXT_SNIPPET_MAX_LENGTH = 500;
|
|
41
|
+
/**
|
|
42
|
+
* Tools that can change the workspace. Verified against the live tool catalog
|
|
43
|
+
* (`client.tool.ids()` on opencode 1.18.18): the patch tool is `apply_patch`,
|
|
44
|
+
* and there is no `list` tool. `task` delegates to a subagent, which can write
|
|
45
|
+
* through any of the others.
|
|
46
|
+
*/
|
|
47
|
+
const MUTATING_TOOLS = new Set(["write", "edit", "apply_patch", "bash", "task"]);
|
|
48
|
+
/**
|
|
49
|
+
* Whether an assistant turn actually produced anything.
|
|
50
|
+
*
|
|
51
|
+
* A completed timestamp only says the turn ended, not that it did work: an
|
|
52
|
+
* aborted or rejected turn carries a completed timestamp with no parts at all,
|
|
53
|
+
* which is byte-for-byte indistinguishable from a task that succeeded quietly.
|
|
54
|
+
*/
|
|
55
|
+
export function hasWork(parts) {
|
|
56
|
+
for (const part of parts) {
|
|
57
|
+
if (part.type === "text" && part.text.trim() !== "")
|
|
58
|
+
return true;
|
|
59
|
+
if (part.type === "tool")
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
34
64
|
/**
|
|
35
65
|
* How long an idle session may stay without any assistant message before the
|
|
36
66
|
* task is considered dead (e.g. the fire-and-forget prompt was rejected).
|
|
37
67
|
*/
|
|
38
68
|
export const PENDING_STALL_MS = 15_000;
|
|
39
|
-
/**
|
|
40
|
-
|
|
69
|
+
/**
|
|
70
|
+
* The workspace path a completed tool call wrote to, if it names one.
|
|
71
|
+
*
|
|
72
|
+
* Verified against a live server: `write` and `edit` carry the path as
|
|
73
|
+
* `state.input.filePath`; `bash` carries only `command`, so it counts as
|
|
74
|
+
* mutating without contributing a path.
|
|
75
|
+
*/
|
|
76
|
+
function touchedFilePath(input) {
|
|
77
|
+
const filePath = input.filePath;
|
|
78
|
+
return typeof filePath === "string" && filePath !== "" ? filePath : undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build a TaskProgress summary.
|
|
82
|
+
*
|
|
83
|
+
* `latest` is the current assistant turn — it drives the text snippet and the
|
|
84
|
+
* in-flight tool. `whole` is every assistant part in the session and drives the
|
|
85
|
+
* side-effect evidence, because an agent's edits land in earlier turns while
|
|
86
|
+
* the final turn is usually just "DONE". Reading evidence off the last message
|
|
87
|
+
* alone reports `files_touched: []` for a task that rewrote the workspace.
|
|
88
|
+
*/
|
|
89
|
+
export function buildProgress(latest, whole = latest) {
|
|
41
90
|
let text = "";
|
|
42
|
-
let toolCallsCompleted = 0;
|
|
43
91
|
let currentTool;
|
|
44
92
|
let currentToolStatus;
|
|
45
|
-
for (const part of
|
|
93
|
+
for (const part of latest) {
|
|
46
94
|
if (part.type === "text") {
|
|
47
95
|
text += part.text;
|
|
48
96
|
continue;
|
|
49
97
|
}
|
|
50
|
-
if (part.type === "tool"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
else if (part.state.status === "running" || part.state.status === "pending") {
|
|
55
|
-
currentTool = part.tool;
|
|
56
|
-
currentToolStatus = part.state.status;
|
|
57
|
-
}
|
|
98
|
+
if (part.type === "tool" &&
|
|
99
|
+
(part.state.status === "running" || part.state.status === "pending")) {
|
|
100
|
+
currentTool = part.tool;
|
|
101
|
+
currentToolStatus = part.state.status;
|
|
58
102
|
}
|
|
59
103
|
}
|
|
104
|
+
let toolCallsCompleted = 0;
|
|
105
|
+
let mutatingToolCalls = 0;
|
|
106
|
+
const filesTouched = new Set();
|
|
107
|
+
for (const part of whole) {
|
|
108
|
+
if (part.type !== "tool" || part.state.status !== "completed")
|
|
109
|
+
continue;
|
|
110
|
+
toolCallsCompleted++;
|
|
111
|
+
if (!MUTATING_TOOLS.has(part.tool))
|
|
112
|
+
continue;
|
|
113
|
+
mutatingToolCalls++;
|
|
114
|
+
const filePath = touchedFilePath(part.state.input);
|
|
115
|
+
if (filePath !== undefined)
|
|
116
|
+
filesTouched.add(filePath);
|
|
117
|
+
}
|
|
60
118
|
return {
|
|
61
119
|
text_snippet: text.slice(-TEXT_SNIPPET_MAX_LENGTH),
|
|
62
120
|
tool_calls_completed: toolCallsCompleted,
|
|
121
|
+
mutating_tool_calls: mutatingToolCalls,
|
|
122
|
+
files_touched: [...filesTouched],
|
|
63
123
|
current_tool: currentTool,
|
|
64
124
|
current_tool_status: currentToolStatus,
|
|
65
125
|
};
|
|
66
126
|
}
|
|
127
|
+
/** Message returned alongside the `cancelled` status, shared by status and result. */
|
|
128
|
+
export const CANCELLED_TASK_MESSAGE = "the task was cancelled via opencode_cancel_task; any output below is whatever the agent produced before the abort";
|
|
129
|
+
/** Message returned alongside the `empty` status, shared by status and result. */
|
|
130
|
+
export const EMPTY_TURN_MESSAGE = "the session finished without producing any text or tool calls; the prompt was likely rejected or the turn was aborted";
|
|
67
131
|
/**
|
|
68
132
|
* Derive the current status of a task by inspecting session busy state and
|
|
69
133
|
* the last assistant message. Shared by opencode_get_task_status and
|
|
@@ -71,22 +135,36 @@ export function buildProgress(parts) {
|
|
|
71
135
|
*/
|
|
72
136
|
export async function deriveTaskStatus(client, sessionId, taskId, options) {
|
|
73
137
|
const includeProgress = options?.includeProgress ?? false;
|
|
138
|
+
// Cancellation wins over everything else: an aborted session keeps its
|
|
139
|
+
// completed timestamp, so any later check would call it `completed`.
|
|
140
|
+
if (getTask(taskId)?.cancelledAt !== undefined) {
|
|
141
|
+
const entries = includeProgress ? await assistantEntries(client, sessionId) : [];
|
|
142
|
+
const latest = entries.at(-1);
|
|
143
|
+
return {
|
|
144
|
+
task_id: taskId,
|
|
145
|
+
status: "cancelled",
|
|
146
|
+
error: CANCELLED_TASK_MESSAGE,
|
|
147
|
+
progress: latest ? buildProgress(latest.parts, sessionParts(entries)) : undefined,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
74
150
|
// The status map only lists sessions that are actively working.
|
|
75
151
|
const statusRes = await client.session.status();
|
|
76
152
|
const sessionStatus = statusRes.data?.[sessionId];
|
|
77
153
|
if (sessionStatus?.type === "busy" || sessionStatus?.type === "retry") {
|
|
78
154
|
if (includeProgress) {
|
|
79
|
-
const
|
|
155
|
+
const entries = await assistantEntries(client, sessionId);
|
|
156
|
+
const latest = entries.at(-1);
|
|
80
157
|
return {
|
|
81
158
|
task_id: taskId,
|
|
82
159
|
status: "running",
|
|
83
|
-
progress:
|
|
160
|
+
progress: latest ? buildProgress(latest.parts, sessionParts(entries)) : undefined,
|
|
84
161
|
};
|
|
85
162
|
}
|
|
86
163
|
return { task_id: taskId, status: "running" };
|
|
87
164
|
}
|
|
88
165
|
// Not busy: inspect the last assistant message to tell pending from done.
|
|
89
|
-
const
|
|
166
|
+
const entries = await assistantEntries(client, sessionId);
|
|
167
|
+
const entry = entries.at(-1);
|
|
90
168
|
if (!entry) {
|
|
91
169
|
// Idle session with no assistant output: either the prompt was just accepted,
|
|
92
170
|
// or it was silently rejected (fire-and-forget) and will never run. Past the
|
|
@@ -105,12 +183,27 @@ export async function deriveTaskStatus(client, sessionId, taskId, options) {
|
|
|
105
183
|
return { task_id: taskId, status: "failed", error: entry.info.error.name };
|
|
106
184
|
}
|
|
107
185
|
if (entry.info.time.completed) {
|
|
108
|
-
|
|
186
|
+
// A completed timestamp is not a work check. An assistant turn that ended
|
|
187
|
+
// with no text and no tool calls did nothing, and reporting that as
|
|
188
|
+
// `completed` is what lets a caller build on top of unchanged files.
|
|
189
|
+
if (!hasWork(entry.parts)) {
|
|
190
|
+
return {
|
|
191
|
+
task_id: taskId,
|
|
192
|
+
status: "empty",
|
|
193
|
+
error: EMPTY_TURN_MESSAGE,
|
|
194
|
+
progress: includeProgress ? buildProgress(entry.parts, sessionParts(entries)) : undefined,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
task_id: taskId,
|
|
199
|
+
status: "completed",
|
|
200
|
+
progress: includeProgress ? buildProgress(entry.parts, sessionParts(entries)) : undefined,
|
|
201
|
+
};
|
|
109
202
|
}
|
|
110
203
|
return {
|
|
111
204
|
task_id: taskId,
|
|
112
205
|
status: "running",
|
|
113
|
-
progress: includeProgress ? buildProgress(entry.parts) : undefined,
|
|
206
|
+
progress: includeProgress ? buildProgress(entry.parts, sessionParts(entries)) : undefined,
|
|
114
207
|
};
|
|
115
208
|
}
|
|
116
209
|
//# sourceMappingURL=opencode-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-client.js","sourceRoot":"","sources":["../../../../src/modules/shared/opencode-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,oFAAoF;AACpF,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,oBAAoB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa,CAC3B,MAAc;IAEd,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;AAC/C,CAAC;AAOD,
|
|
1
|
+
{"version":3,"file":"opencode-client.js","sourceRoot":"","sources":["../../../../src/modules/shared/opencode-client.ts"],"names":[],"mappings":"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"}
|