@mindstudio-ai/remy 0.1.200 → 0.1.201
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/README.md +12 -1
- package/dist/headless.d.ts +9 -7
- package/dist/headless.js +86 -37
- package/dist/index.js +86 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -308,14 +308,24 @@ Return the full conversation history.
|
|
|
308
308
|
|
|
309
309
|
Messages with `hidden: true` were generated by `runCommand` actions and should not be displayed in the UI.
|
|
310
310
|
|
|
311
|
+
The response also includes `queuedMessages` — the current pending-queue snapshot (possibly empty) — so a client can render the queue immediately on connect/reconnect. Live changes after that arrive via `queue_changed`.
|
|
312
|
+
|
|
311
313
|
#### `cancel`
|
|
312
314
|
|
|
313
|
-
Cancel the current turn. The cancel command gets `completed(success:true)`. The in-flight message command (if any) gets its own `completed(success:false, error:"cancelled")`.
|
|
315
|
+
Cancel the current turn. The cancel command gets `completed(success:true)`; any queued messages are flushed and returned on it as `cancelledMessages`. The in-flight message command (if any) gets its own `completed(success:false, error:"cancelled")`.
|
|
314
316
|
|
|
315
317
|
```json
|
|
316
318
|
{"action": "cancel", "requestId": "r3"}
|
|
317
319
|
```
|
|
318
320
|
|
|
321
|
+
#### `cancelQueued`
|
|
322
|
+
|
|
323
|
+
Cancel pending **queued** messages without touching the in-flight turn. Omit `id` to cancel all queued user messages, or pass `id` (the `requestId` of a queued message) to cancel just that one. Only user messages are cancellable — chained and background messages are part of a system chain and are never removed. Responds with `completed(success:true, cancelledQueued:[...])` listing what was removed; a `queue_changed` event also fires with the updated queue.
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
{"action": "cancelQueued", "requestId": "r6", "id": "r2"}
|
|
327
|
+
```
|
|
328
|
+
|
|
319
329
|
#### `clear`
|
|
320
330
|
|
|
321
331
|
Clear conversation history and delete the session file.
|
|
@@ -342,6 +352,7 @@ Events are emitted as newline-delimited JSON. Command responses include `request
|
|
|
342
352
|
|-------|--------|-------------|
|
|
343
353
|
| `ready` | | Headless mode initialized, ready for input |
|
|
344
354
|
| `session_restored` | `messageCount` | Previous session loaded |
|
|
355
|
+
| `queue_changed` | `queuedMessages` | Queue contents changed (any push/shift/drain/cancel). Carries the full current snapshot — an empty array when the queue drains. The live queue-state signal; for the initial snapshot on connect/reconnect, read `queuedMessages` from `get_history`. |
|
|
345
356
|
| `stopping` | | Shutdown initiated |
|
|
346
357
|
| `stopped` | | Shutdown complete |
|
|
347
358
|
|
package/dist/headless.d.ts
CHANGED
|
@@ -68,14 +68,9 @@ declare class HeadlessSession {
|
|
|
68
68
|
start(): Promise<void>;
|
|
69
69
|
private shutdown;
|
|
70
70
|
private emit;
|
|
71
|
-
/**
|
|
72
|
-
*
|
|
73
|
-
* `queuedMessages` if the queue has items (sandbox uses this to know the
|
|
74
|
-
* agent is still busy with pipeline work).
|
|
75
|
-
*/
|
|
71
|
+
/** Emit a `completed` event and mark completedEmitted. Queue state is
|
|
72
|
+
* surfaced separately via the `queue_changed` event, not on `completed`. */
|
|
76
73
|
private emitCompleted;
|
|
77
|
-
/** Returns `{ queuedMessages }` when the queue is non-empty, else empty object. */
|
|
78
|
-
private queueFields;
|
|
79
74
|
/** Dispatch a simple (non-streaming) command: call handler, emit response + completed. */
|
|
80
75
|
private dispatchSimple;
|
|
81
76
|
/** Persist sessionStats + queue snapshot to .remy-stats.json. */
|
|
@@ -138,6 +133,13 @@ declare class HeadlessSession {
|
|
|
138
133
|
private handleChangeModels;
|
|
139
134
|
/** Cancel the running turn and drain the queue. Returns the drained items. */
|
|
140
135
|
private handleCancel;
|
|
136
|
+
/**
|
|
137
|
+
* Remove pending queued messages — all user messages, or one by id.
|
|
138
|
+
* Only `source: 'user'` items are removable; chained and background
|
|
139
|
+
* messages are part of a system chain and are never cancellable. Does
|
|
140
|
+
* not affect the in-flight turn (use `cancel` for that).
|
|
141
|
+
*/
|
|
142
|
+
private handleCancelQueued;
|
|
141
143
|
private handleStdinLine;
|
|
142
144
|
}
|
|
143
145
|
|
package/dist/headless.js
CHANGED
|
@@ -7248,6 +7248,24 @@ var MessageQueue = class {
|
|
|
7248
7248
|
this.onChange?.();
|
|
7249
7249
|
return all;
|
|
7250
7250
|
}
|
|
7251
|
+
/**
|
|
7252
|
+
* Remove all items matching `predicate`. Fires onChange only if something
|
|
7253
|
+
* was removed. Returns the removed items.
|
|
7254
|
+
*/
|
|
7255
|
+
removeWhere(predicate) {
|
|
7256
|
+
const removed = [];
|
|
7257
|
+
this.items = this.items.filter((item) => {
|
|
7258
|
+
if (predicate(item)) {
|
|
7259
|
+
removed.push(item);
|
|
7260
|
+
return false;
|
|
7261
|
+
}
|
|
7262
|
+
return true;
|
|
7263
|
+
});
|
|
7264
|
+
if (removed.length > 0) {
|
|
7265
|
+
this.onChange?.();
|
|
7266
|
+
}
|
|
7267
|
+
return removed;
|
|
7268
|
+
}
|
|
7251
7269
|
/** Copy of current queue contents (for surfacing on events). */
|
|
7252
7270
|
snapshot() {
|
|
7253
7271
|
return [...this.items];
|
|
@@ -7298,6 +7316,24 @@ function resolveAction(text) {
|
|
|
7298
7316
|
next
|
|
7299
7317
|
};
|
|
7300
7318
|
}
|
|
7319
|
+
function getActionChain(startName) {
|
|
7320
|
+
const chain = [];
|
|
7321
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7322
|
+
let name = startName;
|
|
7323
|
+
while (name && !seen.has(name)) {
|
|
7324
|
+
seen.add(name);
|
|
7325
|
+
chain.push(name);
|
|
7326
|
+
let body;
|
|
7327
|
+
try {
|
|
7328
|
+
body = readAsset("automatedActions", `${name}.md`);
|
|
7329
|
+
} catch {
|
|
7330
|
+
break;
|
|
7331
|
+
}
|
|
7332
|
+
const fm = body.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
7333
|
+
name = fm?.[1].match(/^\s*next:\s*(\w+)\s*$/m)?.[1];
|
|
7334
|
+
}
|
|
7335
|
+
return chain;
|
|
7336
|
+
}
|
|
7301
7337
|
|
|
7302
7338
|
// src/headless/index.ts
|
|
7303
7339
|
var log14 = createLogger("headless");
|
|
@@ -7368,14 +7404,16 @@ var HeadlessSession = class {
|
|
|
7368
7404
|
baseUrl: this.opts.baseUrl
|
|
7369
7405
|
});
|
|
7370
7406
|
const resumed = loadSession(this.state);
|
|
7371
|
-
this.queue = new MessageQueue(loadQueue(), () =>
|
|
7407
|
+
this.queue = new MessageQueue(loadQueue(), () => {
|
|
7408
|
+
this.persistStats();
|
|
7409
|
+
this.emit("queue_changed", { queuedMessages: this.queue.snapshot() });
|
|
7410
|
+
});
|
|
7372
7411
|
if (resumed) {
|
|
7373
7412
|
this.emit("session_restored", {
|
|
7374
7413
|
messageCount: this.state.messages.length,
|
|
7375
7414
|
...this.state.models && { models: this.state.models },
|
|
7376
7415
|
modelSurfaces: MODEL_SURFACES,
|
|
7377
|
-
allowedModelsByType: ALLOWED_MODELS_BY_TYPE
|
|
7378
|
-
...this.queueFields()
|
|
7416
|
+
allowedModelsByType: ALLOWED_MODELS_BY_TYPE
|
|
7379
7417
|
});
|
|
7380
7418
|
}
|
|
7381
7419
|
triggerBrandExtraction(
|
|
@@ -7425,7 +7463,7 @@ var HeadlessSession = class {
|
|
|
7425
7463
|
});
|
|
7426
7464
|
process.on("SIGTERM", this.shutdown);
|
|
7427
7465
|
process.on("SIGINT", this.shutdown);
|
|
7428
|
-
this.emit("ready"
|
|
7466
|
+
this.emit("ready");
|
|
7429
7467
|
}
|
|
7430
7468
|
shutdown = () => {
|
|
7431
7469
|
this.emit("stopping");
|
|
@@ -7449,19 +7487,12 @@ var HeadlessSession = class {
|
|
|
7449
7487
|
}
|
|
7450
7488
|
process.stdout.write(line);
|
|
7451
7489
|
}
|
|
7452
|
-
/**
|
|
7453
|
-
*
|
|
7454
|
-
* `queuedMessages` if the queue has items (sandbox uses this to know the
|
|
7455
|
-
* agent is still busy with pipeline work).
|
|
7456
|
-
*/
|
|
7490
|
+
/** Emit a `completed` event and mark completedEmitted. Queue state is
|
|
7491
|
+
* surfaced separately via the `queue_changed` event, not on `completed`. */
|
|
7457
7492
|
emitCompleted(rid, data) {
|
|
7458
|
-
this.emit("completed", { ...data
|
|
7493
|
+
this.emit("completed", { ...data }, rid);
|
|
7459
7494
|
this.completedEmitted = true;
|
|
7460
7495
|
}
|
|
7461
|
-
/** Returns `{ queuedMessages }` when the queue is non-empty, else empty object. */
|
|
7462
|
-
queueFields() {
|
|
7463
|
-
return this.queue.length > 0 ? { queuedMessages: this.queue.snapshot() } : {};
|
|
7464
|
-
}
|
|
7465
7496
|
/** Dispatch a simple (non-streaming) command: call handler, emit response + completed. */
|
|
7466
7497
|
dispatchSimple(requestId, eventName, handler) {
|
|
7467
7498
|
try {
|
|
@@ -7639,11 +7670,7 @@ var HeadlessSession = class {
|
|
|
7639
7670
|
});
|
|
7640
7671
|
return;
|
|
7641
7672
|
case "turn_cancelled": {
|
|
7642
|
-
this.emit(
|
|
7643
|
-
"completed",
|
|
7644
|
-
{ success: false, error: "cancelled", ...this.queueFields() },
|
|
7645
|
-
rid
|
|
7646
|
-
);
|
|
7673
|
+
this.emit("completed", { success: false, error: "cancelled" }, rid);
|
|
7647
7674
|
this.completedEmitted = true;
|
|
7648
7675
|
return;
|
|
7649
7676
|
}
|
|
@@ -7767,7 +7794,7 @@ var HeadlessSession = class {
|
|
|
7767
7794
|
* message — `running` stays held across the queue drain so no user
|
|
7768
7795
|
* message can slip in mid-pipeline.
|
|
7769
7796
|
*/
|
|
7770
|
-
async runSingleTurn(parsed, requestId) {
|
|
7797
|
+
async runSingleTurn(parsed, requestId, fromChain = false) {
|
|
7771
7798
|
this.currentRequestId = requestId;
|
|
7772
7799
|
this.currentAbort = new AbortController();
|
|
7773
7800
|
this.completedEmitted = false;
|
|
@@ -7815,16 +7842,18 @@ var HeadlessSession = class {
|
|
|
7815
7842
|
onboardingState,
|
|
7816
7843
|
parsed.viewContext
|
|
7817
7844
|
);
|
|
7818
|
-
if (resolved?.next) {
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7845
|
+
if (resolved?.next && !fromChain) {
|
|
7846
|
+
for (const step of getActionChain(resolved.next)) {
|
|
7847
|
+
this.queue.push({
|
|
7848
|
+
command: {
|
|
7849
|
+
action: "message",
|
|
7850
|
+
text: sentinel(step),
|
|
7851
|
+
onboardingState
|
|
7852
|
+
},
|
|
7853
|
+
source: "chain",
|
|
7854
|
+
enqueuedAt: Date.now()
|
|
7855
|
+
});
|
|
7856
|
+
}
|
|
7828
7857
|
}
|
|
7829
7858
|
try {
|
|
7830
7859
|
await runTurn({
|
|
@@ -7882,11 +7911,6 @@ var HeadlessSession = class {
|
|
|
7882
7911
|
source: "user",
|
|
7883
7912
|
enqueuedAt: Date.now()
|
|
7884
7913
|
});
|
|
7885
|
-
this.emit(
|
|
7886
|
-
"queued",
|
|
7887
|
-
{ position: this.queue.length, ...this.queueFields() },
|
|
7888
|
-
requestId
|
|
7889
|
-
);
|
|
7890
7914
|
return;
|
|
7891
7915
|
}
|
|
7892
7916
|
this.running = true;
|
|
@@ -7934,7 +7958,7 @@ var HeadlessSession = class {
|
|
|
7934
7958
|
continue;
|
|
7935
7959
|
}
|
|
7936
7960
|
const nextRid = next.command.requestId ?? `${next.source}-${Date.now()}`;
|
|
7937
|
-
await this.runSingleTurn(next.command, nextRid);
|
|
7961
|
+
await this.runSingleTurn(next.command, nextRid, next.source === "chain");
|
|
7938
7962
|
}
|
|
7939
7963
|
}
|
|
7940
7964
|
/**
|
|
@@ -7998,6 +8022,17 @@ var HeadlessSession = class {
|
|
|
7998
8022
|
}
|
|
7999
8023
|
return this.queue.drain();
|
|
8000
8024
|
}
|
|
8025
|
+
/**
|
|
8026
|
+
* Remove pending queued messages — all user messages, or one by id.
|
|
8027
|
+
* Only `source: 'user'` items are removable; chained and background
|
|
8028
|
+
* messages are part of a system chain and are never cancellable. Does
|
|
8029
|
+
* not affect the in-flight turn (use `cancel` for that).
|
|
8030
|
+
*/
|
|
8031
|
+
handleCancelQueued(id) {
|
|
8032
|
+
return this.queue.removeWhere(
|
|
8033
|
+
(item) => item.source === "user" && (id === void 0 || item.command.requestId === id)
|
|
8034
|
+
);
|
|
8035
|
+
}
|
|
8001
8036
|
//////////////////////////////////////////////////////////////////////////////
|
|
8002
8037
|
// Stdin router
|
|
8003
8038
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -8062,7 +8097,11 @@ var HeadlessSession = class {
|
|
|
8062
8097
|
...this.state.models && { models: this.state.models },
|
|
8063
8098
|
modelSurfaces: MODEL_SURFACES,
|
|
8064
8099
|
allowedModelsByType: ALLOWED_MODELS_BY_TYPE,
|
|
8065
|
-
|
|
8100
|
+
// Current queue snapshot for connect/reconnect — get_history is the
|
|
8101
|
+
// on-demand "current state" query. Always an array (possibly empty),
|
|
8102
|
+
// matching the queue_changed convention so the client reconciles the
|
|
8103
|
+
// same way from both; live mutations are pushed via queue_changed.
|
|
8104
|
+
queuedMessages: this.queue.snapshot()
|
|
8066
8105
|
}));
|
|
8067
8106
|
return;
|
|
8068
8107
|
}
|
|
@@ -8106,6 +8145,16 @@ var HeadlessSession = class {
|
|
|
8106
8145
|
);
|
|
8107
8146
|
return;
|
|
8108
8147
|
}
|
|
8148
|
+
if (action === "cancelQueued") {
|
|
8149
|
+
const id = parsed.id;
|
|
8150
|
+
const removed = this.handleCancelQueued(id);
|
|
8151
|
+
this.emit(
|
|
8152
|
+
"completed",
|
|
8153
|
+
{ success: true, cancelledQueued: removed },
|
|
8154
|
+
requestId
|
|
8155
|
+
);
|
|
8156
|
+
return;
|
|
8157
|
+
}
|
|
8109
8158
|
if (action === "stop_tool") {
|
|
8110
8159
|
const id = parsed.id;
|
|
8111
8160
|
const mode = parsed.mode ?? "hard";
|
package/dist/index.js
CHANGED
|
@@ -8013,6 +8013,24 @@ var init_messageQueue = __esm({
|
|
|
8013
8013
|
this.onChange?.();
|
|
8014
8014
|
return all;
|
|
8015
8015
|
}
|
|
8016
|
+
/**
|
|
8017
|
+
* Remove all items matching `predicate`. Fires onChange only if something
|
|
8018
|
+
* was removed. Returns the removed items.
|
|
8019
|
+
*/
|
|
8020
|
+
removeWhere(predicate) {
|
|
8021
|
+
const removed = [];
|
|
8022
|
+
this.items = this.items.filter((item) => {
|
|
8023
|
+
if (predicate(item)) {
|
|
8024
|
+
removed.push(item);
|
|
8025
|
+
return false;
|
|
8026
|
+
}
|
|
8027
|
+
return true;
|
|
8028
|
+
});
|
|
8029
|
+
if (removed.length > 0) {
|
|
8030
|
+
this.onChange?.();
|
|
8031
|
+
}
|
|
8032
|
+
return removed;
|
|
8033
|
+
}
|
|
8016
8034
|
/** Copy of current queue contents (for surfacing on events). */
|
|
8017
8035
|
snapshot() {
|
|
8018
8036
|
return [...this.items];
|
|
@@ -8064,6 +8082,24 @@ function resolveAction(text) {
|
|
|
8064
8082
|
next
|
|
8065
8083
|
};
|
|
8066
8084
|
}
|
|
8085
|
+
function getActionChain(startName) {
|
|
8086
|
+
const chain = [];
|
|
8087
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8088
|
+
let name = startName;
|
|
8089
|
+
while (name && !seen.has(name)) {
|
|
8090
|
+
seen.add(name);
|
|
8091
|
+
chain.push(name);
|
|
8092
|
+
let body;
|
|
8093
|
+
try {
|
|
8094
|
+
body = readAsset("automatedActions", `${name}.md`);
|
|
8095
|
+
} catch {
|
|
8096
|
+
break;
|
|
8097
|
+
}
|
|
8098
|
+
const fm = body.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
8099
|
+
name = fm?.[1].match(/^\s*next:\s*(\w+)\s*$/m)?.[1];
|
|
8100
|
+
}
|
|
8101
|
+
return chain;
|
|
8102
|
+
}
|
|
8067
8103
|
var NON_ACTION_SENTINELS;
|
|
8068
8104
|
var init_resolve = __esm({
|
|
8069
8105
|
"src/automatedActions/resolve.ts"() {
|
|
@@ -8168,14 +8204,16 @@ var init_headless = __esm({
|
|
|
8168
8204
|
baseUrl: this.opts.baseUrl
|
|
8169
8205
|
});
|
|
8170
8206
|
const resumed = loadSession(this.state);
|
|
8171
|
-
this.queue = new MessageQueue(loadQueue(), () =>
|
|
8207
|
+
this.queue = new MessageQueue(loadQueue(), () => {
|
|
8208
|
+
this.persistStats();
|
|
8209
|
+
this.emit("queue_changed", { queuedMessages: this.queue.snapshot() });
|
|
8210
|
+
});
|
|
8172
8211
|
if (resumed) {
|
|
8173
8212
|
this.emit("session_restored", {
|
|
8174
8213
|
messageCount: this.state.messages.length,
|
|
8175
8214
|
...this.state.models && { models: this.state.models },
|
|
8176
8215
|
modelSurfaces: MODEL_SURFACES,
|
|
8177
|
-
allowedModelsByType: ALLOWED_MODELS_BY_TYPE
|
|
8178
|
-
...this.queueFields()
|
|
8216
|
+
allowedModelsByType: ALLOWED_MODELS_BY_TYPE
|
|
8179
8217
|
});
|
|
8180
8218
|
}
|
|
8181
8219
|
triggerBrandExtraction(
|
|
@@ -8225,7 +8263,7 @@ var init_headless = __esm({
|
|
|
8225
8263
|
});
|
|
8226
8264
|
process.on("SIGTERM", this.shutdown);
|
|
8227
8265
|
process.on("SIGINT", this.shutdown);
|
|
8228
|
-
this.emit("ready"
|
|
8266
|
+
this.emit("ready");
|
|
8229
8267
|
}
|
|
8230
8268
|
shutdown = () => {
|
|
8231
8269
|
this.emit("stopping");
|
|
@@ -8249,19 +8287,12 @@ var init_headless = __esm({
|
|
|
8249
8287
|
}
|
|
8250
8288
|
process.stdout.write(line);
|
|
8251
8289
|
}
|
|
8252
|
-
/**
|
|
8253
|
-
*
|
|
8254
|
-
* `queuedMessages` if the queue has items (sandbox uses this to know the
|
|
8255
|
-
* agent is still busy with pipeline work).
|
|
8256
|
-
*/
|
|
8290
|
+
/** Emit a `completed` event and mark completedEmitted. Queue state is
|
|
8291
|
+
* surfaced separately via the `queue_changed` event, not on `completed`. */
|
|
8257
8292
|
emitCompleted(rid, data) {
|
|
8258
|
-
this.emit("completed", { ...data
|
|
8293
|
+
this.emit("completed", { ...data }, rid);
|
|
8259
8294
|
this.completedEmitted = true;
|
|
8260
8295
|
}
|
|
8261
|
-
/** Returns `{ queuedMessages }` when the queue is non-empty, else empty object. */
|
|
8262
|
-
queueFields() {
|
|
8263
|
-
return this.queue.length > 0 ? { queuedMessages: this.queue.snapshot() } : {};
|
|
8264
|
-
}
|
|
8265
8296
|
/** Dispatch a simple (non-streaming) command: call handler, emit response + completed. */
|
|
8266
8297
|
dispatchSimple(requestId, eventName, handler) {
|
|
8267
8298
|
try {
|
|
@@ -8439,11 +8470,7 @@ var init_headless = __esm({
|
|
|
8439
8470
|
});
|
|
8440
8471
|
return;
|
|
8441
8472
|
case "turn_cancelled": {
|
|
8442
|
-
this.emit(
|
|
8443
|
-
"completed",
|
|
8444
|
-
{ success: false, error: "cancelled", ...this.queueFields() },
|
|
8445
|
-
rid
|
|
8446
|
-
);
|
|
8473
|
+
this.emit("completed", { success: false, error: "cancelled" }, rid);
|
|
8447
8474
|
this.completedEmitted = true;
|
|
8448
8475
|
return;
|
|
8449
8476
|
}
|
|
@@ -8567,7 +8594,7 @@ var init_headless = __esm({
|
|
|
8567
8594
|
* message — `running` stays held across the queue drain so no user
|
|
8568
8595
|
* message can slip in mid-pipeline.
|
|
8569
8596
|
*/
|
|
8570
|
-
async runSingleTurn(parsed, requestId) {
|
|
8597
|
+
async runSingleTurn(parsed, requestId, fromChain = false) {
|
|
8571
8598
|
this.currentRequestId = requestId;
|
|
8572
8599
|
this.currentAbort = new AbortController();
|
|
8573
8600
|
this.completedEmitted = false;
|
|
@@ -8615,16 +8642,18 @@ var init_headless = __esm({
|
|
|
8615
8642
|
onboardingState,
|
|
8616
8643
|
parsed.viewContext
|
|
8617
8644
|
);
|
|
8618
|
-
if (resolved?.next) {
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8645
|
+
if (resolved?.next && !fromChain) {
|
|
8646
|
+
for (const step of getActionChain(resolved.next)) {
|
|
8647
|
+
this.queue.push({
|
|
8648
|
+
command: {
|
|
8649
|
+
action: "message",
|
|
8650
|
+
text: sentinel(step),
|
|
8651
|
+
onboardingState
|
|
8652
|
+
},
|
|
8653
|
+
source: "chain",
|
|
8654
|
+
enqueuedAt: Date.now()
|
|
8655
|
+
});
|
|
8656
|
+
}
|
|
8628
8657
|
}
|
|
8629
8658
|
try {
|
|
8630
8659
|
await runTurn({
|
|
@@ -8682,11 +8711,6 @@ var init_headless = __esm({
|
|
|
8682
8711
|
source: "user",
|
|
8683
8712
|
enqueuedAt: Date.now()
|
|
8684
8713
|
});
|
|
8685
|
-
this.emit(
|
|
8686
|
-
"queued",
|
|
8687
|
-
{ position: this.queue.length, ...this.queueFields() },
|
|
8688
|
-
requestId
|
|
8689
|
-
);
|
|
8690
8714
|
return;
|
|
8691
8715
|
}
|
|
8692
8716
|
this.running = true;
|
|
@@ -8734,7 +8758,7 @@ var init_headless = __esm({
|
|
|
8734
8758
|
continue;
|
|
8735
8759
|
}
|
|
8736
8760
|
const nextRid = next.command.requestId ?? `${next.source}-${Date.now()}`;
|
|
8737
|
-
await this.runSingleTurn(next.command, nextRid);
|
|
8761
|
+
await this.runSingleTurn(next.command, nextRid, next.source === "chain");
|
|
8738
8762
|
}
|
|
8739
8763
|
}
|
|
8740
8764
|
/**
|
|
@@ -8798,6 +8822,17 @@ var init_headless = __esm({
|
|
|
8798
8822
|
}
|
|
8799
8823
|
return this.queue.drain();
|
|
8800
8824
|
}
|
|
8825
|
+
/**
|
|
8826
|
+
* Remove pending queued messages — all user messages, or one by id.
|
|
8827
|
+
* Only `source: 'user'` items are removable; chained and background
|
|
8828
|
+
* messages are part of a system chain and are never cancellable. Does
|
|
8829
|
+
* not affect the in-flight turn (use `cancel` for that).
|
|
8830
|
+
*/
|
|
8831
|
+
handleCancelQueued(id) {
|
|
8832
|
+
return this.queue.removeWhere(
|
|
8833
|
+
(item) => item.source === "user" && (id === void 0 || item.command.requestId === id)
|
|
8834
|
+
);
|
|
8835
|
+
}
|
|
8801
8836
|
//////////////////////////////////////////////////////////////////////////////
|
|
8802
8837
|
// Stdin router
|
|
8803
8838
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -8862,7 +8897,11 @@ var init_headless = __esm({
|
|
|
8862
8897
|
...this.state.models && { models: this.state.models },
|
|
8863
8898
|
modelSurfaces: MODEL_SURFACES,
|
|
8864
8899
|
allowedModelsByType: ALLOWED_MODELS_BY_TYPE,
|
|
8865
|
-
|
|
8900
|
+
// Current queue snapshot for connect/reconnect — get_history is the
|
|
8901
|
+
// on-demand "current state" query. Always an array (possibly empty),
|
|
8902
|
+
// matching the queue_changed convention so the client reconciles the
|
|
8903
|
+
// same way from both; live mutations are pushed via queue_changed.
|
|
8904
|
+
queuedMessages: this.queue.snapshot()
|
|
8866
8905
|
}));
|
|
8867
8906
|
return;
|
|
8868
8907
|
}
|
|
@@ -8906,6 +8945,16 @@ var init_headless = __esm({
|
|
|
8906
8945
|
);
|
|
8907
8946
|
return;
|
|
8908
8947
|
}
|
|
8948
|
+
if (action === "cancelQueued") {
|
|
8949
|
+
const id = parsed.id;
|
|
8950
|
+
const removed = this.handleCancelQueued(id);
|
|
8951
|
+
this.emit(
|
|
8952
|
+
"completed",
|
|
8953
|
+
{ success: true, cancelledQueued: removed },
|
|
8954
|
+
requestId
|
|
8955
|
+
);
|
|
8956
|
+
return;
|
|
8957
|
+
}
|
|
8909
8958
|
if (action === "stop_tool") {
|
|
8910
8959
|
const id = parsed.id;
|
|
8911
8960
|
const mode = parsed.mode ?? "hard";
|