@coda-console/claude 1.6.1 → 1.6.3
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/agent/session.mjs +7 -2
- package/agent/waits.mjs +18 -7
- package/package.json +1 -1
package/agent/session.mjs
CHANGED
|
@@ -42,6 +42,8 @@ const denied = { behavior: 'deny', message: 'Coda 没有在请求结束前给出
|
|
|
42
42
|
// A child session's output that comes before its task, kept until the task names that session: all of it, since what streamed
|
|
43
43
|
// counts as said, a message's streamed pieces as one.
|
|
44
44
|
const CHUNKS = new Set(['agent_message_chunk', 'agent_thought_chunk']);
|
|
45
|
+
// What a turn says or does, as against what the session is (its settings, commands, title, usage).
|
|
46
|
+
const SAYING = new Set([...CHUNKS, 'tool_call', 'tool_call_update', 'plan']);
|
|
45
47
|
// How many messages sent into a prompt (steer) may be waiting to be taken at once.
|
|
46
48
|
const STEERING_LIMIT = 32;
|
|
47
49
|
|
|
@@ -109,6 +111,8 @@ export class ClaudeSession {
|
|
|
109
111
|
else early.push(update);
|
|
110
112
|
return;
|
|
111
113
|
}
|
|
114
|
+
// What a turn of Claude's own says comes after what it handles (`claim`).
|
|
115
|
+
if (sessionId === this.sessionId && SAYING.has(update.sessionUpdate)) this.waits.claim();
|
|
112
116
|
this.notify('session/update', { sessionId, update });
|
|
113
117
|
}
|
|
114
118
|
registered(sessionId) {
|
|
@@ -306,13 +310,14 @@ export class ClaudeSession {
|
|
|
306
310
|
this.begin();
|
|
307
311
|
// A subagent's request is in its session.
|
|
308
312
|
const sessionId = this.waits.childSession(context.agentID) ?? this.sessionId;
|
|
313
|
+
if (sessionId === this.sessionId) this.waits.claim();
|
|
309
314
|
return toolName === 'AskUserQuestion'
|
|
310
315
|
? this.ask('elicitation/create', questionForm({ sessionId, toolCallId: context.toolUseID, input }), signal, { behavior: 'deny', message: '问答已失效' })
|
|
311
316
|
: this.ask('session/request_permission', permissionRequest({ sessionId, toolName, input, context }), signal, denied);
|
|
312
317
|
}
|
|
313
318
|
elicitation(request, { signal }) {
|
|
314
319
|
if (!['starting', 'running'].includes(this.phase)) return Promise.resolve({ action: 'cancel' });
|
|
315
|
-
this.begin();
|
|
320
|
+
this.begin(); this.waits.claim();
|
|
316
321
|
return this.ask('elicitation/create', elicitationForm({ sessionId: this.sessionId, request }), signal, { action: 'cancel' });
|
|
317
322
|
}
|
|
318
323
|
// Asked of Coda until it answers; withdrawn (`$/cancel_request`) once the SDK no longer waits for the answer.
|
|
@@ -517,7 +522,7 @@ export class ClaudeSession {
|
|
|
517
522
|
const outcome = this.ending ?? (failed ? { failure: error } : { stopReason: cancelled ? 'cancelled' : 'end_turn' });
|
|
518
523
|
if (this.ending || !this.steering.size) this.settle(id, outcome);
|
|
519
524
|
else { this.held = id; if (cancelled || failed) this.dropRest(outcome); }
|
|
520
|
-
} else if (this.waits.handling) {
|
|
525
|
+
} else if (this.waits.handling || this.waits.unclaimed) {
|
|
521
526
|
// A turn of Claude's own has no RPC reply to fail. End its own activity as failed with the reason, rather than
|
|
522
527
|
// saying the error as an answer and marking the work complete. The task that woke it retains its own outcome.
|
|
523
528
|
this.waits.finished(error ? { error: error.message, title: error.data?._meta?.coda?.failure?.kind === 'quota_exhausted' ? '额度不足' : undefined } : {});
|
package/agent/waits.mjs
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// What a subagent launches (`parent_task_id`) is told in that subagent's session, once a wait has told Coda that session.
|
|
5
5
|
// A task that ends while no turn goes will wake Claude for its result: until a turn takes it up, or the session says idle,
|
|
6
6
|
// it is still waited on. A turn Claude begins on its own handles what woke it (`takeUp`): what its opening message names,
|
|
7
|
-
// else the tasks that ended, else the one wakeup due, else a wait of the turn's own
|
|
7
|
+
// else the tasks that ended, else the one wakeup due, else a wait of the turn's own, told only once the turn says or asks
|
|
8
|
+
// something (`claim`); what it handles ends with that turn.
|
|
8
9
|
const FINAL = { completed: 'done', failed: 'failed', killed: 'cancelled', stopped: 'cancelled', ended: 'done' };
|
|
9
10
|
const open = state => state === 'waiting' || state === 'handling';
|
|
10
11
|
const cut = (value, limit) => typeof value === 'string' && value ? value.slice(0, limit) : undefined;
|
|
@@ -143,18 +144,27 @@ export class ClaudeWaits {
|
|
|
143
144
|
takeUp({ origin, text } = {}) {
|
|
144
145
|
const pending = [...this.tasks.values()].filter(task => task.final !== undefined && task.state === 'waiting');
|
|
145
146
|
const crons = [...this.crons.values()].filter(cron => open(cron.state));
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
: [...this.tasks.values()].filter(task => origin.runId && task.runId === origin.runId
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
// What its opening message names: the wakeup that fired, the run a notice is of, the subagent a message is from.
|
|
148
|
+
const named = origin?.kind === 'task-notification' ? origin.subkind === 'scheduled-trigger' ? crons.filter(cron => cron.prompt && cron.prompt === text)
|
|
149
|
+
: [...this.tasks.values()].filter(task => origin.runId && task.runId === origin.runId)
|
|
150
|
+
: origin?.kind === 'peer' ? [...this.tasks.values()].filter(task => origin.senderTaskId && task.taskId === origin.senderTaskId) : [];
|
|
151
|
+
// Handled means ended (Coda places its card there and lets it be stopped no more): a subagent's message is the report it
|
|
152
|
+
// handed back only once it has ended; one still running says how it goes (SendMessage).
|
|
153
|
+
let handled = origin?.kind === 'peer' ? named.filter(task => pending.includes(task)) : named.filter(wait => open(wait.state));
|
|
154
|
+
// One that names nothing known is taken for what else ended, else the one wakeup due. One that names what was taken in
|
|
155
|
+
// already (Claude Code's turn for the notice of a subagent whose report an earlier turn read) or what still runs is not.
|
|
156
|
+
if (!named.length) handled = pending.sort((a, b) => a.endedAt - b.endedAt);
|
|
157
|
+
if (!named.length && !handled.length) {
|
|
151
158
|
// Which came due is not told: the one due, or else the only one there is.
|
|
152
159
|
const due = crons.filter(cron => cron.at !== null && cron.at <= this.now() + 60_000);
|
|
153
160
|
if ((due.length || crons.length) === 1) handled = due.length ? due : crons;
|
|
154
161
|
}
|
|
155
162
|
if (handled.length) for (const wait of handled) this.report(wait, 'handling');
|
|
156
|
-
|
|
163
|
+
// Nothing to take up: told as a wait of its own once it says or asks something. One that says nothing is not told at
|
|
164
|
+
// all, as that turn for a notice, which reaches no model.
|
|
165
|
+
else this.unclaimed = true;
|
|
157
166
|
}
|
|
167
|
+
claim() { if (this.unclaimed) { this.unclaimed = false; this.hold(); } }
|
|
158
168
|
hold() {
|
|
159
169
|
const own = { waitId: `turn-${++this.turns}` };
|
|
160
170
|
this.own.add(own);
|
|
@@ -164,6 +174,7 @@ export class ClaudeWaits {
|
|
|
164
174
|
finished({ error, title } = {}) {
|
|
165
175
|
// Processing a successful task's result can fail. Give that failure its own activity instead of changing the task's
|
|
166
176
|
// outcome, and leave recurring wakeups scheduled. There may already be a turn-owned activity (hold).
|
|
177
|
+
this.unclaimed = false;
|
|
167
178
|
if (error && !this.own.size) this.hold();
|
|
168
179
|
for (const task of this.tasks.values()) if (task.state === 'handling') { this.report(task, task.final ?? 'done'); task.final = undefined; }
|
|
169
180
|
for (const cron of this.crons.values()) {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"id": "claude",
|
|
4
4
|
"displayName": "Claude",
|
|
5
5
|
"description": "Claude SDK Agent:Coda 基于 Claude Agent SDK 写的 ACP 入口,一个进程一个 SDK 会话;资源页的「Claude」面板显示会话报告的额度,可从 Coda 登录。",
|
|
6
|
-
"version": "1.6.
|
|
6
|
+
"version": "1.6.3",
|
|
7
7
|
"categories": ["Agent"],
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@agentclientprotocol/sdk": "1.4.0",
|