@cocorograph/hub-agent 0.6.13 → 0.6.15
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/package.json +1 -1
- package/src/claude-stream-bridge.mjs +65 -4
package/package.json
CHANGED
|
@@ -150,6 +150,13 @@ class ClaudeStreamSession {
|
|
|
150
150
|
/** 常駐 query を起動済みか (二重起動防止)。 */
|
|
151
151
|
this._residentStarted = false
|
|
152
152
|
|
|
153
|
+
/** 改修3: per-message セッションで busy 中に届いた送信を退避する pending キュー。
|
|
154
|
+
* 常駐 query 化 (改修2) とは別レイヤー。resume チェーンは維持したまま、現ターン
|
|
155
|
+
* 完了時 (finally) に先頭から drain して次ターンを自動発火する。 */
|
|
156
|
+
this._pendingMessages = []
|
|
157
|
+
/** 改修3: 直近 browser へ通知した pending 件数 (変化時のみ queue_state を emit する)。 */
|
|
158
|
+
this._lastEmittedQueueCount = 0
|
|
159
|
+
|
|
153
160
|
/** @type {Map<string, {resolve: (decision: object) => void}>} permission 応答待ち */
|
|
154
161
|
this._permissionResolvers = new Map()
|
|
155
162
|
/** 現在ターン実行中か (多重 query 防止) */
|
|
@@ -271,7 +278,8 @@ class ClaudeStreamSession {
|
|
|
271
278
|
|
|
272
279
|
/**
|
|
273
280
|
* ユーザーメッセージ 1 件を 1 query() として実行する。
|
|
274
|
-
*
|
|
281
|
+
* 既存ターン実行中 (busy) は破棄せず pending キューへ退避し、現ターン完了時に drain する
|
|
282
|
+
* (改修3)。常駐 query 対象 (新規セッション) は InputQueue へ積む (改修2)。
|
|
275
283
|
*/
|
|
276
284
|
async sendMessage(message) {
|
|
277
285
|
if (this._closed) return
|
|
@@ -297,14 +305,23 @@ class ClaudeStreamSession {
|
|
|
297
305
|
}
|
|
298
306
|
|
|
299
307
|
// 従来 per-message: 1 メッセージ = 1 query (resume チェーン)。既存セッション (resume) 用。
|
|
308
|
+
// 改修3: busy 中の送信は破棄せず pending キューへ退避し、現ターン完了時に drain する
|
|
309
|
+
// (ターミナル流の「積む→待機→順次実行」)。常駐 query 化はしないので暴走リスクは増えない。
|
|
300
310
|
if (this._busy) {
|
|
301
|
-
this.
|
|
302
|
-
|
|
303
|
-
|
|
311
|
+
this._pendingMessages.push(prompt)
|
|
312
|
+
this.logger?.info(
|
|
313
|
+
{ stream_id: this.stream_id, queued: this._pendingMessages.length },
|
|
314
|
+
"claude busy, message queued",
|
|
304
315
|
)
|
|
316
|
+
this._emitQueueState()
|
|
305
317
|
return
|
|
306
318
|
}
|
|
319
|
+
return this._runPerMessage(prompt)
|
|
320
|
+
}
|
|
307
321
|
|
|
322
|
+
/** per-message 1 ターンを実行する (resume チェーン)。busy 中に届いた送信は sendMessage
|
|
323
|
+
* が pending キューへ退避し、本メソッドの finally で drain する。 */
|
|
324
|
+
async _runPerMessage(prompt) {
|
|
308
325
|
this._busy = true
|
|
309
326
|
this._abortController = new AbortController()
|
|
310
327
|
let aborted = false
|
|
@@ -397,10 +414,52 @@ class ClaudeStreamSession {
|
|
|
397
414
|
} finally {
|
|
398
415
|
this.onReap?.()
|
|
399
416
|
}
|
|
417
|
+
} else {
|
|
418
|
+
// 改修3: busy 中に積まれた pending を順次発火 (per-message resume チェーン維持)。
|
|
419
|
+
// 停止 (abort) 後も温存したキューはそのまま流す。
|
|
420
|
+
this._drainPending()
|
|
400
421
|
}
|
|
401
422
|
}
|
|
402
423
|
}
|
|
403
424
|
|
|
425
|
+
/** 改修3: pending キューの先頭を取り出して次の per-message ターンを発火する。
|
|
426
|
+
* 各ターンの finally から呼ばれ、キューが空になるまで resume チェーンが続く。 */
|
|
427
|
+
_drainPending() {
|
|
428
|
+
if (this._closed || this._busy) return
|
|
429
|
+
if (this._pendingMessages.length === 0) {
|
|
430
|
+
this._emitQueueState()
|
|
431
|
+
return
|
|
432
|
+
}
|
|
433
|
+
const next = this._pendingMessages.shift()
|
|
434
|
+
this._emitQueueState()
|
|
435
|
+
this._runPerMessage(next).catch((err) => {
|
|
436
|
+
this.logger?.error(
|
|
437
|
+
{ stream_id: this.stream_id, err: err?.message },
|
|
438
|
+
"drain runPerMessage threw",
|
|
439
|
+
)
|
|
440
|
+
})
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** 改修3: pending キューの現状を browser へ通知する (送信待ちチップ表示用)。
|
|
444
|
+
* onEvent 経由で claude.event(event.type="queue_state") として届く。 */
|
|
445
|
+
_emitQueueState() {
|
|
446
|
+
const count = this._pendingMessages.length
|
|
447
|
+
// 件数が変わらないなら通知しない (空→空の冗長 emit を抑止)。
|
|
448
|
+
if (count === this._lastEmittedQueueCount) return
|
|
449
|
+
this._lastEmittedQueueCount = count
|
|
450
|
+
try {
|
|
451
|
+
// messages は全文を載せる。frontend は実行開始 (drain) 時にこれを user バブルへ
|
|
452
|
+
// 昇格させるため、ここで切り詰めると本文が欠ける。チップの省略表示は CSS 側で行う。
|
|
453
|
+
this.onEvent?.({
|
|
454
|
+
type: "queue_state",
|
|
455
|
+
pending: count,
|
|
456
|
+
messages: [...this._pendingMessages],
|
|
457
|
+
})
|
|
458
|
+
} catch {
|
|
459
|
+
/* ignore */
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
404
463
|
/** 改修2: 常駐 query を 1 回だけ起動し、streaming input キューから複数ターンを処理する。
|
|
405
464
|
* system/init は最初の 1 回のみ (毎ターン init = 文脈/キャッシュ温め直しを解消)。各ターンは
|
|
406
465
|
* result で _busy=false にするが query は継続し次 input を待つ。close (inputQueue.close) で
|
|
@@ -513,6 +572,8 @@ class ClaudeStreamSession {
|
|
|
513
572
|
/** セッション終了。新規ターンを止め、実行中なら中断し、watcher も停止する。 */
|
|
514
573
|
close() {
|
|
515
574
|
this._closed = true
|
|
575
|
+
// 改修3: 未処理の pending を破棄 (セッション終了後に drain しないため)。
|
|
576
|
+
this._pendingMessages = []
|
|
516
577
|
// 常駐 query は input キューを閉じて generator を終わらせ query を完走させる。
|
|
517
578
|
if (this._inputQueue) this._inputQueue.close()
|
|
518
579
|
this.abortTurn()
|