@cocorograph/hub-agent 0.6.16 → 0.6.17
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 +94 -4
package/package.json
CHANGED
|
@@ -268,14 +268,89 @@ class ClaudeStreamSession {
|
|
|
268
268
|
/** 再アタッチ: 走行中(または生存中)セッションに新しい stream_id を紐付け直し、
|
|
269
269
|
* idle 撤去タイマーを止める。以降のターンイベントはこの stream_id 経由で新しい
|
|
270
270
|
* browser 接続へライブに流れる (= 通常の生成中表示と同じ)。再アタッチ前の確定分は
|
|
271
|
-
* browser 側の jsonl hydrate (history.request) で復元するため、ここでは replay しない。
|
|
272
|
-
|
|
271
|
+
* browser 側の jsonl hydrate (history.request) で復元するため、ここでは replay しない。
|
|
272
|
+
*
|
|
273
|
+
* 改修5 (2026-05-29): モデル/権限/拡張思考のターン切替。再アタッチ時に opts で
|
|
274
|
+
* 新しい値が渡され、現在値と異なれば applyRuntimeOptions で反映する。これにより
|
|
275
|
+
* 入力欄下バッジの変更が「同一セッション(常駐 query)を維持したまま次ターンから」
|
|
276
|
+
* 効くようになる。従来は reattach が stream_id だけ差し替えていたため、起動済み
|
|
277
|
+
* query の model/permission/thinking は初期値のまま変わらなかった (バッジが効かない
|
|
278
|
+
* 不具合の原因)。 */
|
|
279
|
+
reattach(stream_id, opts = undefined) {
|
|
273
280
|
this.stream_id = stream_id
|
|
274
281
|
this._detached = false
|
|
275
282
|
if (this._idleTimer) {
|
|
276
283
|
clearTimeout(this._idleTimer)
|
|
277
284
|
this._idleTimer = null
|
|
278
285
|
}
|
|
286
|
+
if (opts) this.applyRuntimeOptions(opts)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** 改修5: モデル/権限/拡張思考をランタイムに切り替える。
|
|
290
|
+
*
|
|
291
|
+
* - 保持フィールド (this.model/permissionMode/maxThinkingTokens) を更新する。これは
|
|
292
|
+
* 常駐 query が異常終了して resume 再起動する際 (_runResidentQuery) に最新値で
|
|
293
|
+
* 再 spawn させるため、および per-message セッションが次ターンの options に反映する
|
|
294
|
+
* ため。
|
|
295
|
+
* - 起動済みの常駐 query があれば SDK の制御メソッド (setModel / setPermissionMode /
|
|
296
|
+
* setMaxThinkingTokens) を呼び、プロセス再起動なしで次ターンから即反映する
|
|
297
|
+
* (公式 streaming input mode のランタイム制御。stdin に control_request を流す)。
|
|
298
|
+
*
|
|
299
|
+
* 値が undefined のキーは「変更なし」として無視する (バッジ未送出時に既存値を消さない)。
|
|
300
|
+
* model に空文字/null が来たら setModel(undefined) でデフォルトへ戻す。
|
|
301
|
+
* maxThinkingTokens に 0/null が来たら setMaxThinkingTokens(null) でオフにする。 */
|
|
302
|
+
applyRuntimeOptions({ model, permissionMode, maxThinkingTokens } = {}) {
|
|
303
|
+
const q = this._residentQuery
|
|
304
|
+
// モデル
|
|
305
|
+
if (model !== undefined) {
|
|
306
|
+
const next = model || null
|
|
307
|
+
if (next !== this.model) {
|
|
308
|
+
this.model = next
|
|
309
|
+
if (q && typeof q.setModel === "function") {
|
|
310
|
+
q.setModel(next || undefined).catch((err) =>
|
|
311
|
+
this.logger?.warn(
|
|
312
|
+
{ err: err?.message, stream_id: this.stream_id },
|
|
313
|
+
"setModel failed",
|
|
314
|
+
),
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// 権限モード
|
|
320
|
+
if (permissionMode !== undefined) {
|
|
321
|
+
const next = permissionMode || null
|
|
322
|
+
if (next !== this.permissionMode) {
|
|
323
|
+
this.permissionMode = next
|
|
324
|
+
// setPermissionMode は有効な mode を要求する。null/空 (=未指定へ戻す) は
|
|
325
|
+
// SDK 側に「解除」API が無いため、保持値の更新のみ (次回 spawn で既定に従う)。
|
|
326
|
+
if (next && q && typeof q.setPermissionMode === "function") {
|
|
327
|
+
q.setPermissionMode(next).catch((err) =>
|
|
328
|
+
this.logger?.warn(
|
|
329
|
+
{ err: err?.message, stream_id: this.stream_id },
|
|
330
|
+
"setPermissionMode failed",
|
|
331
|
+
),
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// 拡張思考予算
|
|
337
|
+
if (maxThinkingTokens !== undefined) {
|
|
338
|
+
const next =
|
|
339
|
+
typeof maxThinkingTokens === "number" && maxThinkingTokens > 0
|
|
340
|
+
? maxThinkingTokens
|
|
341
|
+
: null
|
|
342
|
+
if (next !== this.maxThinkingTokens) {
|
|
343
|
+
this.maxThinkingTokens = next
|
|
344
|
+
if (q && typeof q.setMaxThinkingTokens === "function") {
|
|
345
|
+
q.setMaxThinkingTokens(next).catch((err) =>
|
|
346
|
+
this.logger?.warn(
|
|
347
|
+
{ err: err?.message, stream_id: this.stream_id },
|
|
348
|
+
"setMaxThinkingTokens failed",
|
|
349
|
+
),
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
279
354
|
}
|
|
280
355
|
|
|
281
356
|
/** soft detach: browser 切断時にターンを中断せずセッションを生かしたまま detached に
|
|
@@ -740,10 +815,25 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
740
815
|
const live = this._liveBySession.get(resumeSessionId)
|
|
741
816
|
if (live && !live._closed) {
|
|
742
817
|
this.sessions.delete(live.stream_id)
|
|
743
|
-
|
|
818
|
+
// 改修5: 再アタッチ時に model/permission/maxThinkingTokens を引き継ぎ反映する。
|
|
819
|
+
// browser はバッジ変更時に新しい値を載せた claude.attach を同一 resume で送る
|
|
820
|
+
// ため、ここで適用すると常駐 query を維持したまま次ターンから切り替わる。
|
|
821
|
+
live.reattach(stream_id, {
|
|
822
|
+
model,
|
|
823
|
+
permissionMode,
|
|
824
|
+
maxThinkingTokens:
|
|
825
|
+
typeof maxThinkingTokens === "number" ? maxThinkingTokens : null,
|
|
826
|
+
})
|
|
744
827
|
this.sessions.set(stream_id, live)
|
|
745
828
|
this.logger?.info(
|
|
746
|
-
{
|
|
829
|
+
{
|
|
830
|
+
stream_id,
|
|
831
|
+
resume: resumeSessionId,
|
|
832
|
+
busy: live._busy,
|
|
833
|
+
model: live.model,
|
|
834
|
+
permissionMode: live.permissionMode,
|
|
835
|
+
maxThinkingTokens: live.maxThinkingTokens,
|
|
836
|
+
},
|
|
747
837
|
"claude stream reattached to live session",
|
|
748
838
|
)
|
|
749
839
|
return { stream_id, resuming: true, reattached: true }
|