clay-server 3.2.0 → 3.2.1
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/lib/sdk-bridge.js +73 -48
- package/lib/yoke/adapters/claude.js +19 -3
- package/lib/yoke/adapters/codex.js +5 -2
- package/lib/yoke/adapters/kiro.js +5 -2
- package/lib/yoke/interface.js +1 -1
- package/package.json +1 -1
package/lib/sdk-bridge.js
CHANGED
|
@@ -972,7 +972,8 @@ function createSDKBridge(opts) {
|
|
|
972
972
|
// Only clean up if the session still references OUR resources.
|
|
973
973
|
// A rewind + new startQuery may have already replaced these with
|
|
974
974
|
// a newer query — clobbering them would kill the new query.
|
|
975
|
-
|
|
975
|
+
var ownsRuntime = session.queryInstance === myQueryInstance;
|
|
976
|
+
if (ownsRuntime) {
|
|
976
977
|
try {
|
|
977
978
|
if (typeof session.queryInstance.close === "function") {
|
|
978
979
|
session.queryInstance.close();
|
|
@@ -982,55 +983,57 @@ function createSDKBridge(opts) {
|
|
|
982
983
|
}
|
|
983
984
|
if (session.messageQueue === myMessageQueue) session.messageQueue = null;
|
|
984
985
|
if (session.abortController === myAbortController) session.abortController = null;
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
var
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
986
|
+
if (ownsRuntime) {
|
|
987
|
+
session.taskStopRequested = false;
|
|
988
|
+
session.pendingPermissions = {};
|
|
989
|
+
// Preserve MCP-mode AskUserQuestion entries across turn boundaries.
|
|
990
|
+
// The MCP path is intentionally stateless: the tool returns immediately
|
|
991
|
+
// ("card posted, end your turn") and the user's answer is expected to
|
|
992
|
+
// arrive as a brand-new user_message on the *next* turn. That means the
|
|
993
|
+
// pending entry MUST survive this finally block. Without it, the
|
|
994
|
+
// ask_user_response handler can't find the toolId and silently drops
|
|
995
|
+
// the answer. canUseTool-mode entries (Claude's native path) still hold
|
|
996
|
+
// an open SDK permission callback that dies with the query, so those
|
|
997
|
+
// are correctly cleared here.
|
|
998
|
+
var keepAskUser = {};
|
|
999
|
+
for (var _tid in session.pendingAskUser) {
|
|
1000
|
+
var _pending = session.pendingAskUser[_tid];
|
|
1001
|
+
if (_pending && _pending.mode === "mcp") keepAskUser[_tid] = _pending;
|
|
1002
|
+
}
|
|
1003
|
+
session.pendingAskUser = keepAskUser;
|
|
1004
|
+
session.pendingElicitations = {};
|
|
1003
1005
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1006
|
+
// Auto-continue on rate limit (scheduler sessions, or user setting)
|
|
1007
|
+
// Mark session as done processing so the late rate_limit_event handler
|
|
1008
|
+
// can detect the race condition and schedule auto-continue itself.
|
|
1009
|
+
session.isProcessing = false;
|
|
1008
1010
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1011
|
+
var didScheduleAutoContinue = false;
|
|
1012
|
+
var acEnabled = session.onQueryComplete || (typeof opts.getAutoContinueSetting === "function" && opts.getAutoContinueSetting(session));
|
|
1013
|
+
if (session.rateLimitResetsAt && session.rateLimitResetsAt > Date.now()
|
|
1014
|
+
&& acEnabled && !session.destroying) {
|
|
1015
|
+
var acResetsAt = session.rateLimitResetsAt;
|
|
1016
|
+
session.rateLimitResetsAt = null;
|
|
1017
|
+
session.rateLimitAutoContinuePending = true;
|
|
1018
|
+
didScheduleAutoContinue = true;
|
|
1019
|
+
console.log("[sdk-bridge] Rate limited, scheduling auto-continue via scheduleMessage for session " + session.localId);
|
|
1020
|
+
if (typeof opts.scheduleMessage === "function") {
|
|
1021
|
+
opts.scheduleMessage(session, "continue", acResetsAt);
|
|
1022
|
+
}
|
|
1023
|
+
} else if (acEnabled && !session.destroying) {
|
|
1024
|
+
// Log why auto-continue was not scheduled (for debugging)
|
|
1025
|
+
console.log("[sdk-bridge] Query done, auto-continue enabled but not scheduled: rateLimitResetsAt=" +
|
|
1026
|
+
session.rateLimitResetsAt + " (will rely on late rate_limit_event handler)");
|
|
1020
1027
|
}
|
|
1021
|
-
} else if (acEnabled && !session.destroying) {
|
|
1022
|
-
// Log why auto-continue was not scheduled (for debugging)
|
|
1023
|
-
console.log("[sdk-bridge] Query done, auto-continue enabled but not scheduled: rateLimitResetsAt=" +
|
|
1024
|
-
session.rateLimitResetsAt + " (will rely on late rate_limit_event handler)");
|
|
1025
|
-
}
|
|
1026
1028
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1029
|
+
// Ralph Loop: notify completion so loop orchestrator can proceed
|
|
1030
|
+
if (session.onQueryComplete && !didScheduleAutoContinue) {
|
|
1031
|
+
console.log("[sdk-bridge] Calling onQueryComplete for session " + session.localId + " (title: " + (session.title || "?") + ")");
|
|
1032
|
+
try {
|
|
1033
|
+
session.onQueryComplete(session);
|
|
1034
|
+
} catch (err) {
|
|
1035
|
+
console.error("[sdk-bridge] onQueryComplete error:", err.message || err);
|
|
1036
|
+
}
|
|
1034
1037
|
}
|
|
1035
1038
|
}
|
|
1036
1039
|
}
|
|
@@ -1620,8 +1623,30 @@ function createSDKBridge(opts) {
|
|
|
1620
1623
|
}
|
|
1621
1624
|
// Route through QueryHandle (works for both in-process and worker paths)
|
|
1622
1625
|
if (session.queryInstance && typeof session.queryInstance.pushMessage === "function") {
|
|
1623
|
-
session.queryInstance
|
|
1624
|
-
|
|
1626
|
+
var activeQuery = session.queryInstance;
|
|
1627
|
+
var activeAbortController = session.abortController;
|
|
1628
|
+
var activeMessageQueue = session.messageQueue;
|
|
1629
|
+
var delivered = false;
|
|
1630
|
+
try {
|
|
1631
|
+
// Older third-party adapters returned undefined. Preserve compatibility
|
|
1632
|
+
// while requiring built-in adapters to return false for a closed input.
|
|
1633
|
+
delivered = activeQuery.pushMessage(text, images) !== false;
|
|
1634
|
+
} catch (e) {
|
|
1635
|
+
console.error("[sdk-bridge] QueryHandle rejected message for session " + session.localId + ":", e.message || e);
|
|
1636
|
+
}
|
|
1637
|
+
if (delivered) return true;
|
|
1638
|
+
|
|
1639
|
+
// The handle object can outlive its underlying input queue or worker.
|
|
1640
|
+
// Retire it before the caller starts a resumed replacement query; the
|
|
1641
|
+
// old stream's finally block compares object identity and cannot clobber
|
|
1642
|
+
// the replacement resources.
|
|
1643
|
+
try {
|
|
1644
|
+
if (typeof activeQuery.close === "function") activeQuery.close();
|
|
1645
|
+
} catch (e) {}
|
|
1646
|
+
if (session.queryInstance === activeQuery) session.queryInstance = null;
|
|
1647
|
+
if (session.abortController === activeAbortController) session.abortController = null;
|
|
1648
|
+
if (session.messageQueue === activeMessageQueue) session.messageQueue = null;
|
|
1649
|
+
return false;
|
|
1625
1650
|
}
|
|
1626
1651
|
if (session._queryStarting) {
|
|
1627
1652
|
session.pendingPush = session.pendingPush || [];
|
|
@@ -53,7 +53,7 @@ function createMessageQueue() {
|
|
|
53
53
|
var ended = false;
|
|
54
54
|
return {
|
|
55
55
|
push: function(msg) {
|
|
56
|
-
if (ended) return;
|
|
56
|
+
if (ended) return false;
|
|
57
57
|
if (waiting) {
|
|
58
58
|
var resolve = waiting;
|
|
59
59
|
waiting = null;
|
|
@@ -61,6 +61,7 @@ function createMessageQueue() {
|
|
|
61
61
|
} else {
|
|
62
62
|
queue.push(msg);
|
|
63
63
|
}
|
|
64
|
+
return true;
|
|
64
65
|
},
|
|
65
66
|
end: function() {
|
|
66
67
|
ended = true;
|
|
@@ -346,6 +347,7 @@ function flattenEvent(raw) {
|
|
|
346
347
|
// Wraps a raw SDK query object with the YOKE QueryHandle interface.
|
|
347
348
|
// Events are flattened via flattenEvent before yielding.
|
|
348
349
|
function createQueryHandle(rawQuery, messageQueue, abortController) {
|
|
350
|
+
var closed = false;
|
|
349
351
|
var handle = {
|
|
350
352
|
// Opaque adapter state (null for in-process queries)
|
|
351
353
|
_adapterState: null,
|
|
@@ -356,14 +358,19 @@ function createQueryHandle(rawQuery, messageQueue, abortController) {
|
|
|
356
358
|
return {
|
|
357
359
|
next: function() {
|
|
358
360
|
return rawIter.next().then(function(result) {
|
|
361
|
+
if (result.done) closed = true;
|
|
359
362
|
if (result.done) return result;
|
|
360
363
|
return { value: flattenEvent(result.value), done: false };
|
|
364
|
+
}, function(err) {
|
|
365
|
+
closed = true;
|
|
366
|
+
throw err;
|
|
361
367
|
});
|
|
362
368
|
},
|
|
363
369
|
};
|
|
364
370
|
},
|
|
365
371
|
|
|
366
372
|
pushMessage: function(text, images) {
|
|
373
|
+
if (closed) return false;
|
|
367
374
|
var content = [];
|
|
368
375
|
if (images && images.length > 0) {
|
|
369
376
|
for (var i = 0; i < images.length; i++) {
|
|
@@ -374,7 +381,7 @@ function createQueryHandle(rawQuery, messageQueue, abortController) {
|
|
|
374
381
|
}
|
|
375
382
|
}
|
|
376
383
|
if (text) content.push({ type: "text", text: text });
|
|
377
|
-
messageQueue.push({ type: "user", message: { role: "user", content: content } });
|
|
384
|
+
return messageQueue.push({ type: "user", message: { role: "user", content: content } });
|
|
378
385
|
},
|
|
379
386
|
|
|
380
387
|
setModel: function(model) {
|
|
@@ -443,12 +450,14 @@ function createQueryHandle(rawQuery, messageQueue, abortController) {
|
|
|
443
450
|
},
|
|
444
451
|
|
|
445
452
|
abort: function() {
|
|
453
|
+
closed = true;
|
|
446
454
|
if (abortController) {
|
|
447
455
|
try { abortController.abort(); } catch (e) {}
|
|
448
456
|
}
|
|
449
457
|
},
|
|
450
458
|
|
|
451
459
|
close: function() {
|
|
460
|
+
closed = true;
|
|
452
461
|
try { messageQueue.end(); } catch (e) {}
|
|
453
462
|
if (rawQuery && typeof rawQuery.close === "function") {
|
|
454
463
|
try { rawQuery.close(); } catch (e) {}
|
|
@@ -457,6 +466,7 @@ function createQueryHandle(rawQuery, messageQueue, abortController) {
|
|
|
457
466
|
|
|
458
467
|
// End the message queue without closing the raw query
|
|
459
468
|
endInput: function() {
|
|
469
|
+
closed = true;
|
|
460
470
|
try { messageQueue.end(); } catch (e) {}
|
|
461
471
|
},
|
|
462
472
|
|
|
@@ -987,6 +997,7 @@ function createWorkerQueryHandle(worker, canUseTool, onElicitation, callMcpTool,
|
|
|
987
997
|
},
|
|
988
998
|
|
|
989
999
|
pushMessage: function(text, images) {
|
|
1000
|
+
if (iterEnded || (worker.process && (worker.process.killed || worker.process.exitCode != null))) return false;
|
|
990
1001
|
var content = [];
|
|
991
1002
|
if (images && images.length > 0) {
|
|
992
1003
|
for (var i = 0; i < images.length; i++) {
|
|
@@ -998,7 +1009,12 @@ function createWorkerQueryHandle(worker, canUseTool, onElicitation, callMcpTool,
|
|
|
998
1009
|
}
|
|
999
1010
|
if (text) content.push({ type: "text", text: text });
|
|
1000
1011
|
var userMsg = { type: "user", message: { role: "user", content: content } };
|
|
1001
|
-
|
|
1012
|
+
try {
|
|
1013
|
+
worker.send({ type: "push_message", content: userMsg });
|
|
1014
|
+
return true;
|
|
1015
|
+
} catch (e) {
|
|
1016
|
+
return false;
|
|
1017
|
+
}
|
|
1002
1018
|
},
|
|
1003
1019
|
|
|
1004
1020
|
setModel: function(model) {
|
|
@@ -738,7 +738,7 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
738
738
|
var handlerEntry = null;
|
|
739
739
|
|
|
740
740
|
function pushMessageToQueue(msg) {
|
|
741
|
-
if (messageQueueEnded) return;
|
|
741
|
+
if (messageQueueEnded) return false;
|
|
742
742
|
if (messageWaiting) {
|
|
743
743
|
var resolve = messageWaiting;
|
|
744
744
|
messageWaiting = null;
|
|
@@ -746,6 +746,7 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
746
746
|
} else {
|
|
747
747
|
messageQueue.push(msg);
|
|
748
748
|
}
|
|
749
|
+
return true;
|
|
749
750
|
}
|
|
750
751
|
|
|
751
752
|
function waitForMessage() {
|
|
@@ -1119,6 +1120,7 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
1119
1120
|
},
|
|
1120
1121
|
|
|
1121
1122
|
pushMessage: function(text, images) {
|
|
1123
|
+
if (iteratorDone || state.done || messageQueueEnded) return false;
|
|
1122
1124
|
var input;
|
|
1123
1125
|
if (images && images.length > 0) {
|
|
1124
1126
|
input = [];
|
|
@@ -1134,8 +1136,9 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
1134
1136
|
if (!state.loopStarted) {
|
|
1135
1137
|
state.loopStarted = true;
|
|
1136
1138
|
runQueryLoop(input);
|
|
1139
|
+
return true;
|
|
1137
1140
|
} else {
|
|
1138
|
-
pushMessageToQueue(input);
|
|
1141
|
+
return pushMessageToQueue(input);
|
|
1139
1142
|
}
|
|
1140
1143
|
},
|
|
1141
1144
|
|
|
@@ -449,7 +449,7 @@ function createKiroQueryHandle(acp, queryOpts) {
|
|
|
449
449
|
var messageQueueEnded = false;
|
|
450
450
|
|
|
451
451
|
function pushMessageToQueue(msg) {
|
|
452
|
-
if (messageQueueEnded) return;
|
|
452
|
+
if (messageQueueEnded) return false;
|
|
453
453
|
if (messageWaiting) {
|
|
454
454
|
var resolve = messageWaiting;
|
|
455
455
|
messageWaiting = null;
|
|
@@ -457,6 +457,7 @@ function createKiroQueryHandle(acp, queryOpts) {
|
|
|
457
457
|
} else {
|
|
458
458
|
messageQueue.push(msg);
|
|
459
459
|
}
|
|
460
|
+
return true;
|
|
460
461
|
}
|
|
461
462
|
function waitForMessage() {
|
|
462
463
|
if (messageQueue.length > 0) return Promise.resolve(messageQueue.shift());
|
|
@@ -737,6 +738,7 @@ function createKiroQueryHandle(acp, queryOpts) {
|
|
|
737
738
|
},
|
|
738
739
|
|
|
739
740
|
pushMessage: function(text, images) {
|
|
741
|
+
if (iteratorDone || state.done || messageQueueEnded) return false;
|
|
740
742
|
var input = [];
|
|
741
743
|
if (images && images.length > 0) {
|
|
742
744
|
for (var i = 0; i < images.length; i++) {
|
|
@@ -752,8 +754,9 @@ function createKiroQueryHandle(acp, queryOpts) {
|
|
|
752
754
|
if (!state.loopStarted) {
|
|
753
755
|
state.loopStarted = true;
|
|
754
756
|
runQueryLoop(payload);
|
|
757
|
+
return true;
|
|
755
758
|
} else {
|
|
756
|
-
pushMessageToQueue(payload);
|
|
759
|
+
return pushMessageToQueue(payload);
|
|
757
760
|
}
|
|
758
761
|
},
|
|
759
762
|
|
package/lib/yoke/interface.js
CHANGED
|
@@ -35,7 +35,7 @@ var TOOL_POLICIES = ["ask", "allow-all"];
|
|
|
35
35
|
*
|
|
36
36
|
* QueryHandle shape:
|
|
37
37
|
* [Symbol.asyncIterator]() - yields SDK events (raw in Phase 3, normalized later)
|
|
38
|
-
* .pushMessage(text, images)
|
|
38
|
+
* .pushMessage(text, images) - boolean; false when the handle cannot accept input
|
|
39
39
|
* .setModel(model)
|
|
40
40
|
* .setEffort(effort)
|
|
41
41
|
* .setToolPolicy(policy) - "ask" | "allow-all"
|
package/package.json
CHANGED