@cocorograph/hub-agent 0.6.26 → 0.6.28
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 +2 -2
- package/src/claude-stream-bridge.mjs +134 -24
- package/src/main.mjs +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocorograph/hub-agent",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.28",
|
|
4
4
|
"description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
35
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.158",
|
|
36
36
|
"commander": "^12.1.0",
|
|
37
37
|
"node-pty": "^1.0.0",
|
|
38
38
|
"pino": "^9.0.0",
|
|
@@ -137,6 +137,7 @@ class ClaudeStreamSession {
|
|
|
137
137
|
permissionMode,
|
|
138
138
|
maxTurns,
|
|
139
139
|
maxThinkingTokens,
|
|
140
|
+
effort,
|
|
140
141
|
resumeSessionId,
|
|
141
142
|
resident,
|
|
142
143
|
sdk,
|
|
@@ -158,6 +159,10 @@ class ClaudeStreamSession {
|
|
|
158
159
|
this.maxTurns = typeof maxTurns === "number" ? maxTurns : null
|
|
159
160
|
this.maxThinkingTokens =
|
|
160
161
|
typeof maxThinkingTokens === "number" ? maxThinkingTokens : null
|
|
162
|
+
// Opus 4.6+ の effort パラメータ (low/medium/high/xhigh/max)。adaptive thinking と
|
|
163
|
+
// 併用して思考の深さを制御する。Opus では budget 方式 (maxThinkingTokens) は廃止
|
|
164
|
+
// 扱いのため、effort モデルでは effort + thinking:{type:'adaptive'} を使う。
|
|
165
|
+
this.effort = effort || null
|
|
161
166
|
this.sdk = sdk
|
|
162
167
|
this.logger = logger
|
|
163
168
|
this.onEvent = onEvent
|
|
@@ -204,6 +209,11 @@ class ClaudeStreamSession {
|
|
|
204
209
|
/** 改修3: 直近 browser へ通知した queue 署名 (件数 + id 列)。変化時のみ emit する。
|
|
205
210
|
* 空キューの署名 ("0:") で初期化し、空→空の冗長 emit を抑止する。 */
|
|
206
211
|
this._lastEmittedQueueSig = "0:"
|
|
212
|
+
/** ultracode (0.6.28): 常駐 query へ現在適用済みの ultracode 状態。ターン単位の
|
|
213
|
+
* ワンショット適用を applyFlagSettings で reconcile する際の差分判定に使う。
|
|
214
|
+
* query を (再)起動すると flag settings は既定に戻るため、_runResidentQuery 冒頭で
|
|
215
|
+
* false に戻す。 */
|
|
216
|
+
this._ultracodeCurrent = false
|
|
207
217
|
|
|
208
218
|
/** @type {Map<string, {resolve: (decision: object) => void}>} permission 応答待ち */
|
|
209
219
|
this._permissionResolvers = new Map()
|
|
@@ -326,7 +336,7 @@ class ClaudeStreamSession {
|
|
|
326
336
|
* 値が undefined のキーは「変更なし」として無視する (バッジ未送出時に既存値を消さない)。
|
|
327
337
|
* model に空文字/null が来たら setModel(undefined) でデフォルトへ戻す。
|
|
328
338
|
* maxThinkingTokens に 0/null が来たら setMaxThinkingTokens(null) でオフにする。 */
|
|
329
|
-
applyRuntimeOptions({ model, permissionMode, maxThinkingTokens } = {}) {
|
|
339
|
+
applyRuntimeOptions({ model, permissionMode, maxThinkingTokens, effort } = {}) {
|
|
330
340
|
const q = this._residentQuery
|
|
331
341
|
// モデル
|
|
332
342
|
if (model !== undefined) {
|
|
@@ -378,6 +388,34 @@ class ClaudeStreamSession {
|
|
|
378
388
|
}
|
|
379
389
|
}
|
|
380
390
|
}
|
|
391
|
+
// effort (Opus 4.6+)。SDK には setEffort 相当のランタイム制御メソッドが無いため、
|
|
392
|
+
// 保持値の更新のみ行う。per-message セッションは次ターンの options 構築時に
|
|
393
|
+
// this.effort を読むため即反映される。常駐 query は次 spawn (resume 再起動) 時に
|
|
394
|
+
// 反映される (= 次回セッションから切替。ユーザー要件と一致)。
|
|
395
|
+
if (effort !== undefined) {
|
|
396
|
+
this.effort = effort || null
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** モデルが Opus 4.6+ (effort / adaptive thinking 対応) かどうか。
|
|
401
|
+
* budget 方式 (maxThinkingTokens) は Opus 4.7+ で廃止扱いのため、effort モデルでは
|
|
402
|
+
* effort + thinking:{type:'adaptive'} に切り替える。 */
|
|
403
|
+
_isEffortModel() {
|
|
404
|
+
return typeof this.model === "string" && /claude-opus-4-[678]/.test(this.model)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/** 思考関連オプション (effort / adaptive thinking / 旧 budget) を options へ適用する。
|
|
408
|
+
* per-message / 常駐 query の両方から呼ぶ共通ロジック (分岐の二重定義を避ける)。 */
|
|
409
|
+
_applyThinkingOptions(options) {
|
|
410
|
+
if (this._isEffortModel()) {
|
|
411
|
+
// Opus: adaptive thinking を明示 ON にし、effort で深さを指定する。
|
|
412
|
+
// budget 方式 (maxThinkingTokens) は使わない (Opus 4.7+ で非対応)。
|
|
413
|
+
options.thinking = { type: "adaptive" }
|
|
414
|
+
if (this.effort) options.effort = this.effort
|
|
415
|
+
} else if (this.maxThinkingTokens != null) {
|
|
416
|
+
// 非 effort モデル (Sonnet / Haiku 等) は従来の budget 方式を維持。
|
|
417
|
+
options.maxThinkingTokens = this.maxThinkingTokens
|
|
418
|
+
}
|
|
381
419
|
}
|
|
382
420
|
|
|
383
421
|
/** soft detach: browser 切断時にターンを中断せずセッションを生かしたまま detached に
|
|
@@ -412,11 +450,18 @@ class ClaudeStreamSession {
|
|
|
412
450
|
* 既存ターン実行中 (busy) は破棄せず pending キューへ退避し、現ターン完了時に drain する
|
|
413
451
|
* (改修3)。常駐 query 対象 (新規セッション) は InputQueue へ積む (改修2)。
|
|
414
452
|
*/
|
|
415
|
-
async sendMessage(message) {
|
|
453
|
+
async sendMessage(message, opts = {}) {
|
|
416
454
|
if (this._closed) return
|
|
417
455
|
const prompt = extractPromptText(message)
|
|
418
456
|
if (!prompt) return
|
|
419
457
|
|
|
458
|
+
// ultracode ワンショット (0.6.28): このターンのみ xhigh effort + 常時 dynamic-workflow
|
|
459
|
+
// オーケストレーションを有効化する。セッション既定としては持たず (トークン消費が
|
|
460
|
+
// 桁違いになるため)、ターン単位でトグルし、完了後は通常状態へ戻す。
|
|
461
|
+
// per-message では options.settings に乗せ、resident では applyFlagSettings で
|
|
462
|
+
// ターン前に ON / 次ターン前に OFF へ reconcile する (詳細は _reconcileResidentUltracode)。
|
|
463
|
+
const ultracode = opts.ultracode === true
|
|
464
|
+
|
|
420
465
|
// 改修2+4: 常駐query対象セッション。
|
|
421
466
|
if (this._residentEligible) {
|
|
422
467
|
if (!this._inputQueue) this._inputQueue = new InputQueue()
|
|
@@ -425,7 +470,7 @@ class ClaudeStreamSession {
|
|
|
425
470
|
// 次を push すると SDK streaming-input で割り込み扱いになり得るため (公式 interrupt 警告)。
|
|
426
471
|
// pending は queue_state で UI (送信待ちチップ) に出す (per-message と同じ体験)。
|
|
427
472
|
if (this._busy) {
|
|
428
|
-
this._enqueuePending(prompt)
|
|
473
|
+
this._enqueuePending(prompt, ultracode)
|
|
429
474
|
this.logger?.info(
|
|
430
475
|
{ stream_id: this.stream_id, queued: this._pendingMessages.length },
|
|
431
476
|
"resident busy, message queued",
|
|
@@ -434,14 +479,18 @@ class ClaudeStreamSession {
|
|
|
434
479
|
return
|
|
435
480
|
}
|
|
436
481
|
this._busy = true
|
|
437
|
-
this._inputQueue.push(toSDKUserMessage(prompt))
|
|
438
482
|
// 改修4 (A): 死亡ガード。常駐 query が未起動 or (エラー等で) 終了済み (_residentQuery=null)
|
|
439
483
|
// なら (再)起動する。_runResidentQuery は起動時 options.resume=this.sessionId で文脈を
|
|
440
484
|
// 復元するため、途中死からの復活でも過去コンテキストは失われない。
|
|
485
|
+
// ultracode のとき: query を先に起動 (空 InputQueue なので入力待ちでブロック) し、
|
|
486
|
+
// applyFlagSettings を await してから push することで、設定適用前にターンが
|
|
487
|
+
// 消費されるレースを防ぐ。
|
|
441
488
|
if (!this._residentQuery) {
|
|
442
489
|
this._residentStarted = true
|
|
443
490
|
this._startResidentQuery()
|
|
444
491
|
}
|
|
492
|
+
await this._reconcileResidentUltracode(ultracode)
|
|
493
|
+
this._inputQueue.push(toSDKUserMessage(prompt))
|
|
445
494
|
return
|
|
446
495
|
}
|
|
447
496
|
|
|
@@ -449,7 +498,7 @@ class ClaudeStreamSession {
|
|
|
449
498
|
// 改修3: busy 中の送信は破棄せず pending キューへ退避し、現ターン完了時に drain する
|
|
450
499
|
// (ターミナル流の「積む→待機→順次実行」)。常駐 query 化はしないので暴走リスクは増えない。
|
|
451
500
|
if (this._busy) {
|
|
452
|
-
this._enqueuePending(prompt)
|
|
501
|
+
this._enqueuePending(prompt, ultracode)
|
|
453
502
|
this.logger?.info(
|
|
454
503
|
{ stream_id: this.stream_id, queued: this._pendingMessages.length },
|
|
455
504
|
"claude busy, message queued",
|
|
@@ -457,12 +506,12 @@ class ClaudeStreamSession {
|
|
|
457
506
|
this._emitQueueState()
|
|
458
507
|
return
|
|
459
508
|
}
|
|
460
|
-
return this._runPerMessage(prompt)
|
|
509
|
+
return this._runPerMessage(prompt, { ultracode })
|
|
461
510
|
}
|
|
462
511
|
|
|
463
512
|
/** per-message 1 ターンを実行する (resume チェーン)。busy 中に届いた送信は sendMessage
|
|
464
513
|
* が pending キューへ退避し、本メソッドの finally で drain する。 */
|
|
465
|
-
async _runPerMessage(prompt) {
|
|
514
|
+
async _runPerMessage(prompt, opts = {}) {
|
|
466
515
|
this._busy = true
|
|
467
516
|
this._abortController = new AbortController()
|
|
468
517
|
let aborted = false
|
|
@@ -475,9 +524,20 @@ class ClaudeStreamSession {
|
|
|
475
524
|
}
|
|
476
525
|
if (this.model) options.model = this.model
|
|
477
526
|
if (this.permissionMode) options.permissionMode = this.permissionMode
|
|
478
|
-
// Phase B: チャット SDK に効くオプション (
|
|
527
|
+
// Phase B: チャット SDK に効くオプション (ツール往復上限)。
|
|
479
528
|
if (this.maxTurns != null) options.maxTurns = this.maxTurns
|
|
480
|
-
|
|
529
|
+
// 思考オプション (effort / adaptive thinking / 旧 budget) はモデルに応じて切替。
|
|
530
|
+
this._applyThinkingOptions(options)
|
|
531
|
+
// ultracode ワンショット (0.6.28): per-message は 1 query = 1 ターンなので、
|
|
532
|
+
// このターンの options.settings (= --settings 相当 / flag settings 層) に乗せるだけで
|
|
533
|
+
// 自然に 1 ターン限定になる。次ターンは options を作り直すため通常状態に戻る。
|
|
534
|
+
if (opts.ultracode === true) {
|
|
535
|
+
options.settings = {
|
|
536
|
+
...(options.settings || {}),
|
|
537
|
+
ultracode: true,
|
|
538
|
+
enableWorkflows: true,
|
|
539
|
+
}
|
|
540
|
+
}
|
|
481
541
|
// 直前ターンまでの session_id があれば resume チェーン
|
|
482
542
|
if (this.sessionId) options.resume = this.sessionId
|
|
483
543
|
|
|
@@ -579,18 +639,21 @@ class ClaudeStreamSession {
|
|
|
579
639
|
}
|
|
580
640
|
const next = this._pendingMessages.shift()
|
|
581
641
|
this._emitQueueState([next.text])
|
|
582
|
-
this._runPerMessage(next.text).catch(
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
642
|
+
this._runPerMessage(next.text, { ultracode: next.ultracode === true }).catch(
|
|
643
|
+
(err) => {
|
|
644
|
+
this.logger?.error(
|
|
645
|
+
{ stream_id: this.stream_id, err: err?.message },
|
|
646
|
+
"drain runPerMessage threw",
|
|
647
|
+
)
|
|
648
|
+
},
|
|
649
|
+
)
|
|
588
650
|
}
|
|
589
651
|
|
|
590
|
-
/** キャンセル機能 (0.6.26): pending キューへ安定 id 付きで 1 件積む。
|
|
591
|
-
|
|
652
|
+
/** キャンセル機能 (0.6.26): pending キューへ安定 id 付きで 1 件積む。
|
|
653
|
+
* ultracode (0.6.28): ワンショット ultracode フラグもエントリに保持し、drain 時に伝播する。 */
|
|
654
|
+
_enqueuePending(prompt, ultracode = false) {
|
|
592
655
|
const id = `q${++this._queueSeq}`
|
|
593
|
-
this._pendingMessages.push({ id, text: prompt })
|
|
656
|
+
this._pendingMessages.push({ id, text: prompt, ultracode: ultracode === true })
|
|
594
657
|
return id
|
|
595
658
|
}
|
|
596
659
|
|
|
@@ -651,9 +714,38 @@ class ClaudeStreamSession {
|
|
|
651
714
|
})
|
|
652
715
|
}
|
|
653
716
|
|
|
717
|
+
/** ultracode (0.6.28): 常駐 query の ultracode 状態を目標値へ寄せる (差分時のみ
|
|
718
|
+
* applyFlagSettings を発行)。push の前に await して、設定適用前にターンが消費される
|
|
719
|
+
* レースを防ぐ。query 未起動 / applyFlagSettings 非対応 SDK では no-op。 */
|
|
720
|
+
async _reconcileResidentUltracode(desired) {
|
|
721
|
+
const want = desired === true
|
|
722
|
+
if (want === this._ultracodeCurrent) return
|
|
723
|
+
const q = this._residentQuery
|
|
724
|
+
if (!q || typeof q.applyFlagSettings !== "function") return
|
|
725
|
+
try {
|
|
726
|
+
await q.applyFlagSettings(
|
|
727
|
+
want
|
|
728
|
+
? { ultracode: true, enableWorkflows: true }
|
|
729
|
+
: { ultracode: false },
|
|
730
|
+
)
|
|
731
|
+
this._ultracodeCurrent = want
|
|
732
|
+
this.logger?.info(
|
|
733
|
+
{ stream_id: this.stream_id, ultracode: want },
|
|
734
|
+
"resident ultracode reconciled",
|
|
735
|
+
)
|
|
736
|
+
} catch (err) {
|
|
737
|
+
this.logger?.warn(
|
|
738
|
+
{ stream_id: this.stream_id, err: err?.message },
|
|
739
|
+
"applyFlagSettings ultracode failed",
|
|
740
|
+
)
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
654
744
|
/** 改修4 (A): ターン完了時に pending の先頭 1 件を InputQueue へ流す (ターンのシリアライズ)。
|
|
655
|
-
* queue_state を更新して送信待ちチップを drain させる (frontend がバブル昇格する)。
|
|
656
|
-
|
|
745
|
+
* queue_state を更新して送信待ちチップを drain させる (frontend がバブル昇格する)。
|
|
746
|
+
* ultracode (0.6.28): 次ターンの目標 ultracode 状態へ reconcile してから push する
|
|
747
|
+
* (await するため async 化。result ハンドラからは fire-and-forget で呼ばれる)。 */
|
|
748
|
+
async _drainResidentPending() {
|
|
657
749
|
if (this._closed) return
|
|
658
750
|
if (this._pendingMessages.length === 0) {
|
|
659
751
|
this._emitQueueState()
|
|
@@ -661,6 +753,7 @@ class ClaudeStreamSession {
|
|
|
661
753
|
}
|
|
662
754
|
const next = this._pendingMessages.shift()
|
|
663
755
|
this._busy = true
|
|
756
|
+
await this._reconcileResidentUltracode(next.ultracode === true)
|
|
664
757
|
this._inputQueue.push(toSDKUserMessage(next.text))
|
|
665
758
|
this._emitQueueState([next.text])
|
|
666
759
|
}
|
|
@@ -683,7 +776,11 @@ class ClaudeStreamSession {
|
|
|
683
776
|
if (this.model) options.model = this.model
|
|
684
777
|
if (this.permissionMode) options.permissionMode = this.permissionMode
|
|
685
778
|
if (this.maxTurns != null) options.maxTurns = this.maxTurns
|
|
686
|
-
|
|
779
|
+
this._applyThinkingOptions(options)
|
|
780
|
+
// ultracode (0.6.28): 新規 query は flag settings 既定 (ultracode=off) で始まる。
|
|
781
|
+
// 適用済み状態の追跡を false にリセットし、次ターンの reconcile が正しく差分判定できる
|
|
782
|
+
// ようにする (異常終了→resume 再起動時にも確実にリセット)。
|
|
783
|
+
this._ultracodeCurrent = false
|
|
687
784
|
// 改修4: 起動時に sessionId (= resumeSessionId) があれば resume チェーンで文脈を引き継ぐ。
|
|
688
785
|
// query 起動時点の値のみ有効 (起動後に確定/変化する session_id は同一 query 内で継続される)。
|
|
689
786
|
if (this.sessionId) options.resume = this.sessionId
|
|
@@ -714,7 +811,14 @@ class ClaudeStreamSession {
|
|
|
714
811
|
denyPending("turn ended")
|
|
715
812
|
this._busy = false
|
|
716
813
|
// 改修4 (A): シリアライズした pending があれば次の 1 件を InputQueue へ流す。
|
|
717
|
-
|
|
814
|
+
// ultracode (0.6.28): _drainResidentPending は applyFlagSettings を await するため
|
|
815
|
+
// async。result ハンドラ (for await ループ内) からは fire-and-forget で呼ぶ。
|
|
816
|
+
this._drainResidentPending().catch((err) =>
|
|
817
|
+
this.logger?.warn(
|
|
818
|
+
{ stream_id: this.stream_id, err: err?.message },
|
|
819
|
+
"drainResidentPending threw",
|
|
820
|
+
),
|
|
821
|
+
)
|
|
718
822
|
}
|
|
719
823
|
try {
|
|
720
824
|
this.onEvent?.(msg)
|
|
@@ -871,6 +975,7 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
871
975
|
* permissionMode?: string|null,
|
|
872
976
|
* maxTurns?: number|null,
|
|
873
977
|
* maxThinkingTokens?: number|null,
|
|
978
|
+
* effort?: string|null,
|
|
874
979
|
* resumeSessionId?: string|null,
|
|
875
980
|
* }} args
|
|
876
981
|
* @returns {{ stream_id: string, resuming: boolean }}
|
|
@@ -882,6 +987,7 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
882
987
|
permissionMode,
|
|
883
988
|
maxTurns,
|
|
884
989
|
maxThinkingTokens,
|
|
990
|
+
effort,
|
|
885
991
|
resumeSessionId,
|
|
886
992
|
resident,
|
|
887
993
|
}) {
|
|
@@ -910,6 +1016,7 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
910
1016
|
permissionMode,
|
|
911
1017
|
maxThinkingTokens:
|
|
912
1018
|
typeof maxThinkingTokens === "number" ? maxThinkingTokens : null,
|
|
1019
|
+
effort,
|
|
913
1020
|
})
|
|
914
1021
|
this.sessions.set(stream_id, live)
|
|
915
1022
|
this.logger?.info(
|
|
@@ -920,6 +1027,7 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
920
1027
|
model: live.model,
|
|
921
1028
|
permissionMode: live.permissionMode,
|
|
922
1029
|
maxThinkingTokens: live.maxThinkingTokens,
|
|
1030
|
+
effort: live.effort,
|
|
923
1031
|
},
|
|
924
1032
|
"claude stream reattached to live session",
|
|
925
1033
|
)
|
|
@@ -934,6 +1042,7 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
934
1042
|
maxTurns: typeof maxTurns === "number" ? maxTurns : null,
|
|
935
1043
|
maxThinkingTokens:
|
|
936
1044
|
typeof maxThinkingTokens === "number" ? maxThinkingTokens : null,
|
|
1045
|
+
effort: effort || null,
|
|
937
1046
|
resumeSessionId: resumeSessionId || null,
|
|
938
1047
|
resident,
|
|
939
1048
|
sdk: this.sdk,
|
|
@@ -991,14 +1100,15 @@ export class ClaudeStreamBridge extends EventEmitter {
|
|
|
991
1100
|
}
|
|
992
1101
|
|
|
993
1102
|
/** browser → claude の user メッセージ。1 件 = 1 query (resume チェーン)。 */
|
|
994
|
-
input({ stream_id, message }) {
|
|
1103
|
+
input({ stream_id, message, ultracode }) {
|
|
995
1104
|
const s = this.sessions.get(stream_id)
|
|
996
1105
|
if (!s) {
|
|
997
1106
|
this.logger?.warn({ stream_id }, "claude.input but stream missing")
|
|
998
1107
|
return false
|
|
999
1108
|
}
|
|
1000
1109
|
// 非同期でターン実行 (完了は result イベント + onEvent 経由で browser に届く)
|
|
1001
|
-
|
|
1110
|
+
// ultracode (0.6.28): このメッセージのみ ultracode ワンショットを適用するフラグ。
|
|
1111
|
+
s.sendMessage(message, { ultracode: ultracode === true }).catch((err) => {
|
|
1002
1112
|
this.logger?.error(
|
|
1003
1113
|
{ stream_id, err: err?.message },
|
|
1004
1114
|
"claude sendMessage threw unexpectedly",
|
package/src/main.mjs
CHANGED
|
@@ -756,6 +756,9 @@ async function dispatch(msg, ctx) {
|
|
|
756
756
|
typeof msg.max_thinking_tokens === "number"
|
|
757
757
|
? msg.max_thinking_tokens
|
|
758
758
|
: null,
|
|
759
|
+
// effort (Opus 4.6+): browser がチャット既定 (agent 設定由来) を送る。
|
|
760
|
+
// 空文字/未指定なら null (SDK / Claude Code 既定 = Opus は high)。
|
|
761
|
+
effort: msg.effort || ctx.config?.claude_effort || null,
|
|
759
762
|
resumeSessionId: msg.resume_session_id || null,
|
|
760
763
|
})
|
|
761
764
|
ctx.client.send({
|
|
@@ -778,6 +781,9 @@ async function dispatch(msg, ctx) {
|
|
|
778
781
|
ctx.claudeBridge.input({
|
|
779
782
|
stream_id: msg.stream_id,
|
|
780
783
|
message: msg.message,
|
|
784
|
+
// ultracode (0.6.28): browser がこのメッセージ単位で送るワンショット指定。
|
|
785
|
+
// true のときだけそのターンを xhigh effort + dynamic-workflow で実行する。
|
|
786
|
+
ultracode: msg.ultracode === true,
|
|
781
787
|
})
|
|
782
788
|
return
|
|
783
789
|
case "claude.upload": {
|