clay-server 3.4.0-beta.20 → 3.4.0-beta.21
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.
|
@@ -98,10 +98,15 @@ function attachSessionPair(ctx) {
|
|
|
98
98
|
token.delivered = true;
|
|
99
99
|
var failure = token.failure || null;
|
|
100
100
|
var response = token.response || "";
|
|
101
|
-
var text
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
var text;
|
|
102
|
+
if (token.interrupted) {
|
|
103
|
+
text = "[Worker execution interrupted] The user interrupted the Worker mid-turn. Its work is PARTIAL and unverified — do not treat it as finished. Review what was done and decide next steps with the user.";
|
|
104
|
+
} else {
|
|
105
|
+
text = "A Worker task delegated through send_to_partner has finished.\n\n" +
|
|
106
|
+
"Original task:\n" + token.message + "\n\n" +
|
|
107
|
+
(failure ? "Worker error:\n" + failure : "Worker result:\n" + (response || "(No text response was recorded.)")) +
|
|
108
|
+
"\n\nReview the result, verify it as needed, and continue the task.";
|
|
109
|
+
}
|
|
105
110
|
sm.sendAndRecord(caller, {
|
|
106
111
|
type: "user_message",
|
|
107
112
|
text: text,
|
|
@@ -146,6 +151,7 @@ function attachSessionPair(ctx) {
|
|
|
146
151
|
}
|
|
147
152
|
token.response = responseText(partner.history || [], token.startIndex);
|
|
148
153
|
token.failure = errorSince(partner.history || [], token.startIndex);
|
|
154
|
+
token.interrupted = !token.failure && !!partner._lastTurnInterrupted;
|
|
149
155
|
finishDelegation(group, caller, partner, token);
|
|
150
156
|
return resumeDriverWithResult(caller, partner, token);
|
|
151
157
|
}
|
|
@@ -165,8 +171,9 @@ function attachSessionPair(ctx) {
|
|
|
165
171
|
clearInterval(timer);
|
|
166
172
|
finishDelegation(group, caller, partner, token);
|
|
167
173
|
var failure = errorSince(partner.history || [], token.startIndex);
|
|
174
|
+
var interrupted = !failure && !!partner._lastTurnInterrupted;
|
|
168
175
|
resolve({
|
|
169
|
-
status: failure ? "error" : "complete",
|
|
176
|
+
status: failure ? "error" : (interrupted ? "interrupted" : "complete"),
|
|
170
177
|
response: responseText(partner.history || [], token.startIndex),
|
|
171
178
|
error: failure || undefined,
|
|
172
179
|
});
|
|
@@ -260,7 +267,7 @@ function attachSessionPair(ctx) {
|
|
|
260
267
|
var count = Number.isFinite(args.lastTurns) ? Math.floor(args.lastTurns) : 1;
|
|
261
268
|
count = Math.max(1, Math.min(5, count));
|
|
262
269
|
return toolResult({
|
|
263
|
-
status: resolved.partner.isProcessing ? "running" : "idle",
|
|
270
|
+
status: resolved.partner.isProcessing ? "running" : (resolved.partner._lastTurnInterrupted ? "interrupted" : "idle"),
|
|
264
271
|
partnerId: resolved.partner.localId,
|
|
265
272
|
title: resolved.partner.title || "New Session",
|
|
266
273
|
turns: recentTurns(resolved.partner, count),
|
|
@@ -383,7 +390,7 @@ function attachSessionPair(ctx) {
|
|
|
383
390
|
var group = store.groupForMember(session.localId);
|
|
384
391
|
var pairPrompt = "";
|
|
385
392
|
if (group && group.pair && group.pair.driverId === session.localId) {
|
|
386
|
-
pairPrompt = "You are the Driver in a two-agent pair. The tools send_to_partner and read_partner are provided directly to you. Use send_to_partner to delegate concrete bounded work to the Worker. A completed Worker turn leaves the Worker session available for more work. If review or user feedback requires corrections to the Worker's implementation, delegate a follow-up turn to that Worker instead of editing the Worker-owned files yourself. If send_to_partner reports that the Worker is no longer available, create a replacement with spawn_sessions and delegate the remaining implementation rather than taking it over. If a non-waiting delegation finishes later, Clay pushes the result back and resumes you automatically; use read_partner only when you need an interim status check. Integrate and verify the final outcome. Do not search the project for implementations of these tools, and do not delegate work that must be performed sequentially in this same session.";
|
|
393
|
+
pairPrompt = "You are the Driver in a two-agent pair. The tools send_to_partner and read_partner are provided directly to you. Use send_to_partner to delegate concrete bounded work to the Worker. A completed Worker turn leaves the Worker session available for more work. If a Worker turn is interrupted, its work is partial and unverified; review it and decide next steps with the user. If review or user feedback requires corrections to the Worker's implementation, delegate a follow-up turn to that Worker instead of editing the Worker-owned files yourself. If send_to_partner reports that the Worker is no longer available, create a replacement with spawn_sessions and delegate the remaining implementation rather than taking it over. If a non-waiting delegation finishes later, Clay pushes the result back and resumes you automatically; use read_partner only when you need an interim status check. Integrate and verify the final outcome. Do not search the project for implementations of these tools, and do not delegate work that must be performed sequentially in this same session.";
|
|
387
394
|
}
|
|
388
395
|
return [pairPrompt, workerProposal.getSystemPrompt(session)].filter(Boolean).join("\n\n");
|
|
389
396
|
}
|
|
@@ -319,7 +319,7 @@ function attachSessionSpawn(ctx) {
|
|
|
319
319
|
statuses.push({
|
|
320
320
|
localId: session.localId,
|
|
321
321
|
title: session.title || "New Session",
|
|
322
|
-
status: session.isProcessing ? "running" : (hasSessionError(session) ? "error" : "done"),
|
|
322
|
+
status: session.isProcessing ? "running" : (session._lastTurnInterrupted ? "interrupted" : (hasSessionError(session) ? "error" : "done")),
|
|
323
323
|
turnCount: session.turnCount || 0,
|
|
324
324
|
lastActivity: session.lastActivity || session.createdAt || 0,
|
|
325
325
|
});
|
|
@@ -248,6 +248,8 @@ function attachWorkerProposal(ctx) {
|
|
|
248
248
|
var followup;
|
|
249
249
|
if (result.status === "complete") {
|
|
250
250
|
followup = "[Worker execution completed]\nReview and verify the Worker's result. The Worker session remains available: if the implementation needs corrections or additional edits, send a follow-up with send_to_partner instead of taking over the Worker-owned files yourself. If that Worker is no longer available, create a replacement with spawn_sessions for the remaining implementation.\n\n" + (result.response || "The Worker completed without a text summary.");
|
|
251
|
+
} else if (result.status === "interrupted") {
|
|
252
|
+
followup = "[Worker execution interrupted]\nThe user interrupted the Worker mid-turn. Its work is PARTIAL and unverified — do not treat it as finished. Review what was done and decide next steps with the user.";
|
|
251
253
|
} else if (result.status === "running") {
|
|
252
254
|
followup = "[Worker execution is still running]\nUse read_partner to inspect progress before completing the task.";
|
|
253
255
|
} else {
|
|
@@ -95,6 +95,7 @@ function statusLabel(status) {
|
|
|
95
95
|
if (status === "starting") return "Starting Worker";
|
|
96
96
|
if (status === "running") return "Worker running";
|
|
97
97
|
if (status === "completed") return "Completed";
|
|
98
|
+
if (status === "interrupted") return "Interrupted";
|
|
98
99
|
if (status === "declined") return "Continuing here";
|
|
99
100
|
if (status === "error") return "Needs attention";
|
|
100
101
|
return "Suggested by Fable";
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -885,6 +885,7 @@ function createSDKBridge(opts) {
|
|
|
885
885
|
console.log("[sdk-bridge] processQueryStream ended: isProcessing=" + session.isProcessing + " taskStopRequested=" + session.taskStopRequested);
|
|
886
886
|
var stillOwnsRuntime = session.queryInstance === myQueryInstance;
|
|
887
887
|
if (session.isProcessing && session.taskStopRequested && stillOwnsRuntime) {
|
|
888
|
+
session._lastTurnInterrupted = true;
|
|
888
889
|
session.isProcessing = false;
|
|
889
890
|
session._awaitingTurnResult = false;
|
|
890
891
|
session._queuedTurnCount = 0;
|
|
@@ -922,6 +923,7 @@ function createSDKBridge(opts) {
|
|
|
922
923
|
session._queuedTurnCount = 0;
|
|
923
924
|
onProcessingChanged();
|
|
924
925
|
if (err.name === "AbortError" || (myAbortController && myAbortController.signal.aborted) || session.taskStopRequested) {
|
|
926
|
+
session._lastTurnInterrupted = true;
|
|
925
927
|
if (!session.destroying) {
|
|
926
928
|
sendAndRecord(session, { type: "thinking_stop" });
|
|
927
929
|
var interruptMsg2 = (session.vendor && session.vendor !== "claude")
|
|
@@ -1189,6 +1191,7 @@ function createSDKBridge(opts) {
|
|
|
1189
1191
|
// Wrapper: marks the boot window so pushMessage can buffer instead of
|
|
1190
1192
|
// dropping messages that arrive while createQuery is still awaiting.
|
|
1191
1193
|
async function startQuery(session, text, images, linuxUser) {
|
|
1194
|
+
delete session._lastTurnInterrupted;
|
|
1192
1195
|
session._queryStarting = true;
|
|
1193
1196
|
try {
|
|
1194
1197
|
return await startQueryInner(session, text, images, linuxUser);
|
|
@@ -1707,6 +1710,7 @@ function createSDKBridge(opts) {
|
|
|
1707
1710
|
console.error("[sdk-bridge] QueryHandle rejected message for session " + session.localId + ":", e.message || e);
|
|
1708
1711
|
}
|
|
1709
1712
|
if (delivered) {
|
|
1713
|
+
delete session._lastTurnInterrupted;
|
|
1710
1714
|
if (session._awaitingTurnResult) {
|
|
1711
1715
|
session._queuedTurnCount = (session._queuedTurnCount || 0) + 1;
|
|
1712
1716
|
} else {
|
package/package.json
CHANGED