@markusylisiurunen/tau 0.3.67 → 0.3.69
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/dist/core/personas.js +47 -3
- package/dist/core/personas.js.map +1 -1
- package/dist/core/static/tau_docs/remote-sessions.md +1 -1
- package/dist/core/static/tau_docs/telegram.md +3 -3
- package/dist/core/static/tau_docs/tui.md +2 -2
- package/dist/core/telegram/adapter.js +26 -10
- package/dist/core/telegram/adapter.js.map +1 -1
- package/dist/core/utils/gemini_speech.js +1 -1
- package/dist/core/utils/gemini_transcription.js +1 -1
- package/dist/core/utils/openai_transcription.js +72 -22
- package/dist/core/utils/openai_transcription.js.map +1 -1
- package/dist/core/utils/speech_to_text.js +17 -24
- package/dist/core/utils/speech_to_text.js.map +1 -1
- package/dist/core/version.js +2 -2
- package/dist/diff_tool/app/dist/assets/{angular-html-BeSCPCet.js → angular-html-GYtPR4ZN.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{angular-ts-M6ucwcXp.js → angular-ts-CP8tBFCL.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{apl-BTy2T_s_.js → apl-DlYjD5SW.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{astro-cFE44UBz.js → astro-D8wjxID2.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{blade-BSzl0tbR.js → blade-DwY1HngW.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{c-wBFdKaz6.js → c-CAILAMk6.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{chapel-b-MisDxs.js → chapel-VXP46g0K.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{cobol-dLRFXfHq.js → cobol-BwAQKs_L.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{coffee-DY5l5u2h.js → coffee-DeNZ8VRy.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{cpp-DjXgSTII.js → cpp-CF9ADHZh.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{crystal-CP6xOayN.js → crystal-Dlr9u7o6.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{css-xaNrTKYV.js → css-DqAHzxWB.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{edge-BOmlY556.js → edge-ds7vvsur.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{elixir-DcKGE0v2.js → elixir-Es7Jrt6x.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{elm-Cr3UN5CN.js → elm-D11ntXWx.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{erb-B0s1W7oL.js → erb-BqfIFYyn.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{git-rebase-BicxzMm4.js → git-rebase-BNJHcUvp.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{glimmer-js-ODVU1BSP.js → glimmer-js-DNpIS5IN.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{glimmer-ts-BjlaPEbT.js → glimmer-ts-Bv4OLkK5.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{glsl-DARqrBAL.js → glsl-BrwGmSBp.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{graphql-9AgTO0pa.js → graphql-BNCK5rQk.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{hack-a62s-UZ0.js → hack-DuFQc5W0.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{haml-D2r7a_kb.js → haml-DfSIBmXD.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{handlebars-CIj0uB_t.js → handlebars-97zL-LWI.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{html-D8D8vyLW.js → html-5cQu52Yo.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{html-derivative-CLdYoNWv.js → html-derivative-BtDKJ__D.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{http-BHeQHXaH.js → http-DDVZeUrK.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{hurl-CHiE6F8G.js → hurl-jYWcmpTH.js} +1 -1
- package/dist/diff_tool/app/dist/assets/index-B1D38aHD.js +1559 -0
- package/dist/diff_tool/app/dist/assets/{java-vZct0aFW.js → java-DztsnWnX.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{javascript-CYtnIw0K.js → javascript-B9237BHu.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{jinja-CLfmA9uq.js → jinja-8JSK8Y6a.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{jison-XTtTo0I_.js → jison-B5IknAGj.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{json-GZxy-acy.js → json-DRnIZCq8.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{jsx-C7hyhPZ0.js → jsx-CFiWn8fZ.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{julia-BmMkiSmK.js → julia-BtFBdMTG.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{just-RxJWAQxh.js → just-C14ODGGY.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{latex-poGrpwNW.js → latex-DeaaLUFy.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{liquid-Bi2qx1OK.js → liquid-HEBlYFrk.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{lua-CKOivslC.js → lua-CR87cBpR.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{marko-B71GrBHJ.js → marko-Eh01TuqB.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{mdc-DFiDlus5.js → mdc-B6RhKbU2.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{nginx-ByKHg69_.js → nginx-VWZdkDqr.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{nim-BwiP7WMs.js → nim-CHz86e8d.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{org-Cy_LFEd1.js → org-VhIfCSLb.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{perl-L6AmMgUk.js → perl-aD0uyR3K.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{php-r2zLMjgX.js → php-DgAIzA1E.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{pug-BCKOpP4a.js → pug-DrOOTekJ.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{qml-BGFEfuZ-.js → qml-CBowC-In.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{r-25U_CdGU.js → r-BDVQ17do.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{razor-SIQ_YLlC.js → razor-3Cui7XJA.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{regexp-DCxK7MQQ.js → regexp-CGlnek7r.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{rst-9_Rowq3o.js → rst-BJ8-NYKF.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{ruby-O5wpMn8A.js → ruby-CYg2GUU3.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{sas-C-k458kN.js → sas-DfcBvB-I.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{scss-BwP9aXVf.js → scss-S7r2xNkU.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{shellscript-BFMLRpod.js → shellscript-U4EOW3nV.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{shellsession-DlRPuye4.js → shellsession-DYrNCgPk.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{soy-C5Ch5nY5.js → soy-B25GTE01.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{sql-BHt0XWX7.js → sql-CrqkYif6.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{stata-CgvX5dGK.js → stata-CMX2LAnU.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{surrealql-Cj3grwXO.js → surrealql-DDFKL5G0.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{svelte-DveFys-B.js → svelte-CLZCBtO7.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{templ-DmoziF6W.js → templ-BKLVAgyX.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{tex-CQEH3eWy.js → tex-DbqBQGS7.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{ts-tags-CyATrp4W.js → ts-tags-B9kA6WQP.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{tsx-SmI3BYI2.js → tsx-CxQG0405.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{twig-CZdHY8II.js → twig-0z1Xause.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{typescript-BEXbDl0M.js → typescript-R3tpeET4.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{typst-DVVDEOeR.js → typst-DiHSix3p.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{vue-cLMg-8kU.js → vue-C-Pb_COm.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{vue-html-DsBku6bW.js → vue-html-CA18u2Ne.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{vue-vine-CJ-uTo5p.js → vue-vine-CMnXmPqz.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{xml-DFarLFG4.js → xml-5qEjbdVg.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{xsl-C-KcDKTd.js → xsl-CeJj5xD1.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{yaml-C-7s0ZGy.js → yaml-C2k4Cqy8.js} +1 -1
- package/dist/diff_tool/app/dist/index.html +1 -1
- package/dist/host/hosted_ephemeral_agent_session.js +18 -4
- package/dist/host/hosted_ephemeral_agent_session.js.map +1 -1
- package/dist/host/local_session_host.js +54 -7
- package/dist/host/local_session_host.js.map +1 -1
- package/dist/host/session_protocol_handler.js +29 -2
- package/dist/host/session_protocol_handler.js.map +1 -1
- package/dist/protocol/session_protocol.js +22 -5
- package/dist/protocol/session_protocol.js.map +1 -1
- package/dist/tui/listen_capture.js +0 -1
- package/dist/tui/listen_capture.js.map +1 -1
- package/dist/tui/session_chat_controller.js +255 -39
- package/dist/tui/session_chat_controller.js.map +1 -1
- package/dist/tui/ui/footer.js +1 -1
- package/dist/tui/ui/footer.js.map +1 -1
- package/package.json +9 -9
- package/dist/diff_tool/app/dist/assets/index-ryW0IvBs.js +0 -1565
|
@@ -10,7 +10,7 @@ import { TOOL_NAME_BASH } from "../core/tools/tool_names.js";
|
|
|
10
10
|
import { REASONING_LEVELS } from "../core/types.js";
|
|
11
11
|
import { formatAdaptiveNumber, formatCwd, formatTokenWindow } from "../core/utils/format.js";
|
|
12
12
|
import { extractAssistantText } from "../core/utils/messages.js";
|
|
13
|
-
import { getSpeechToTextStreamingSampleRate, } from "../core/utils/speech_to_text.js";
|
|
13
|
+
import { getSpeechToTextStreamingSampleRate, SPEECH_TO_TEXT_CLIENT_MAX_DURATION_MS, } from "../core/utils/speech_to_text.js";
|
|
14
14
|
import { collectSpeechToTextContext } from "../core/utils/speech_to_text_context.js";
|
|
15
15
|
import { hasAutoCompactionContinuationMetadata } from "../core/utils/user_metadata.js";
|
|
16
16
|
import { APP_VERSION } from "../core/version.js";
|
|
@@ -25,7 +25,7 @@ import { InterruptLifecycle } from "./chat_controller/interrupt_lifecycle.js";
|
|
|
25
25
|
import { formatDurationMs, formatFooterTokenCount, formatSessionCost, } from "./chat_controller/status_format.js";
|
|
26
26
|
import { copyTextToClipboard } from "./clipboard.js";
|
|
27
27
|
import { DOUBLE_PRESS_WINDOW_MS } from "./constants.js";
|
|
28
|
-
import { cleanupListenTempFile, createListenTempFilePath, createListenTranscription, deleteListenTempFile, getSpeechToTextApiKey, getSpeechToTextApiKeyErrorMessage, getSpeechToTextProvider, LISTEN_CAPTURE_START_TIMEOUT_MS,
|
|
28
|
+
import { cleanupListenTempFile, createListenTempFilePath, createListenTranscription, deleteListenTempFile, getSpeechToTextApiKey, getSpeechToTextApiKeyErrorMessage, getSpeechToTextProvider, LISTEN_CAPTURE_START_TIMEOUT_MS, LISTEN_RECORDING_MIN_BYTES, readListenAudio, startListenAudioCapture, } from "./listen_capture.js";
|
|
29
29
|
import { createSdkDiffSnapshotDeps, createSdkToolExecutionBackend, } from "./session_tool_execution_backend.js";
|
|
30
30
|
import { runSpeechPlaybackTask } from "./speech_playback.js";
|
|
31
31
|
const LISTEN_CAPTURE_START_CANCELLED = Symbol("listen capture start cancelled");
|
|
@@ -76,7 +76,7 @@ export class SessionChatController {
|
|
|
76
76
|
turnTimer;
|
|
77
77
|
lastEmptySubmitAt;
|
|
78
78
|
listenRecording;
|
|
79
|
-
|
|
79
|
+
retainedListenAudio;
|
|
80
80
|
listenTransition;
|
|
81
81
|
listenStartupAbortController;
|
|
82
82
|
activeListenTranscription;
|
|
@@ -641,7 +641,7 @@ export class SessionChatController {
|
|
|
641
641
|
]);
|
|
642
642
|
return;
|
|
643
643
|
}
|
|
644
|
-
const
|
|
644
|
+
const retainedAudio = this.retainedListenAudio;
|
|
645
645
|
let audioPath;
|
|
646
646
|
let transcription;
|
|
647
647
|
let abortController;
|
|
@@ -666,11 +666,11 @@ export class SessionChatController {
|
|
|
666
666
|
if (this.listenStartupAbortController === abortController) {
|
|
667
667
|
this.listenStartupAbortController = undefined;
|
|
668
668
|
}
|
|
669
|
-
if (
|
|
669
|
+
if (retainedAudio) {
|
|
670
670
|
try {
|
|
671
|
-
await deleteListenTempFile(
|
|
672
|
-
if (this.
|
|
673
|
-
this.
|
|
671
|
+
await deleteListenTempFile(retainedAudio.audioPath);
|
|
672
|
+
if (this.retainedListenAudio === retainedAudio) {
|
|
673
|
+
this.retainedListenAudio = undefined;
|
|
674
674
|
}
|
|
675
675
|
}
|
|
676
676
|
catch (error) {
|
|
@@ -680,13 +680,14 @@ export class SessionChatController {
|
|
|
680
680
|
await cleanupListenTempFile(audioPath);
|
|
681
681
|
this.view.addTranscriptNotice("failed to replace retained recording", "error", [
|
|
682
682
|
error.message,
|
|
683
|
-
`recording retained at ${
|
|
683
|
+
`recording retained at ${retainedAudio.audioPath}`,
|
|
684
684
|
]);
|
|
685
685
|
return;
|
|
686
686
|
}
|
|
687
687
|
}
|
|
688
688
|
const recording = {
|
|
689
689
|
audioPath,
|
|
690
|
+
startedAt: Date.now(),
|
|
690
691
|
stopRequested: false,
|
|
691
692
|
abortController,
|
|
692
693
|
completion,
|
|
@@ -696,7 +697,7 @@ export class SessionChatController {
|
|
|
696
697
|
if (this.listenRecording !== recording || this.listenTransition)
|
|
697
698
|
return;
|
|
698
699
|
void this.runListenTransition(() => this.stopListenCapture());
|
|
699
|
-
},
|
|
700
|
+
}, SPEECH_TO_TEXT_CLIENT_MAX_DURATION_MS);
|
|
700
701
|
this.listenRecording = recording;
|
|
701
702
|
this.view.setEditorInputEnabled(false);
|
|
702
703
|
this.refreshStatus();
|
|
@@ -761,39 +762,42 @@ export class SessionChatController {
|
|
|
761
762
|
await cleanupListenTempFile(recording.audioPath);
|
|
762
763
|
return;
|
|
763
764
|
}
|
|
764
|
-
|
|
765
|
+
const durationMs = Math.min(Math.max(Date.now() - recording.startedAt, 0), SPEECH_TO_TEXT_CLIENT_MAX_DURATION_MS);
|
|
766
|
+
await this.transcribeListenAudioFile(recording.audioPath, durationMs, recording.transcription);
|
|
765
767
|
}
|
|
766
768
|
async retryRetainedListenAudio() {
|
|
767
769
|
if (this.listenRecording || this.listenTransition || this.listenActivityLabel) {
|
|
768
770
|
this.view.showFooterNotice("speech recording state change already in progress", "default");
|
|
769
771
|
return;
|
|
770
772
|
}
|
|
771
|
-
const
|
|
772
|
-
if (!
|
|
773
|
+
const retainedAudio = this.retainedListenAudio;
|
|
774
|
+
if (!retainedAudio) {
|
|
773
775
|
this.view.showFooterNotice("no failed speech recording to retry", "default");
|
|
774
776
|
return;
|
|
775
777
|
}
|
|
776
|
-
await this.runListenTransition(() => this.transcribeListenAudioFile(audioPath));
|
|
778
|
+
await this.runListenTransition(() => this.transcribeListenAudioFile(retainedAudio.audioPath, retainedAudio.durationMs));
|
|
777
779
|
}
|
|
778
780
|
async discardRetainedListenAudio() {
|
|
779
781
|
if (this.listenRecording || this.listenTransition || this.listenActivityLabel) {
|
|
780
782
|
this.view.showFooterNotice("speech recording state change already in progress", "default");
|
|
781
783
|
return;
|
|
782
784
|
}
|
|
783
|
-
const
|
|
784
|
-
if (!
|
|
785
|
+
const retainedAudio = this.retainedListenAudio;
|
|
786
|
+
if (!retainedAudio) {
|
|
785
787
|
this.view.showFooterNotice("no failed speech recording to discard", "default");
|
|
786
788
|
return;
|
|
787
789
|
}
|
|
788
790
|
try {
|
|
789
|
-
await deleteListenTempFile(audioPath);
|
|
790
|
-
this.
|
|
791
|
+
await deleteListenTempFile(retainedAudio.audioPath);
|
|
792
|
+
if (this.retainedListenAudio === retainedAudio) {
|
|
793
|
+
this.retainedListenAudio = undefined;
|
|
794
|
+
}
|
|
791
795
|
this.view.showFooterNotice("discarded retained speech recording", "default");
|
|
792
796
|
}
|
|
793
797
|
catch (error) {
|
|
794
798
|
this.view.addTranscriptNotice("failed to discard speech recording", "error", [
|
|
795
799
|
error.message,
|
|
796
|
-
`recording retained at ${audioPath}`,
|
|
800
|
+
`recording retained at ${retainedAudio.audioPath}`,
|
|
797
801
|
]);
|
|
798
802
|
}
|
|
799
803
|
}
|
|
@@ -806,7 +810,17 @@ export class SessionChatController {
|
|
|
806
810
|
speechToTextDeps: this.speechToTextDeps,
|
|
807
811
|
});
|
|
808
812
|
}
|
|
809
|
-
async transcribeListenAudioFile(audioPath, transcription) {
|
|
813
|
+
async transcribeListenAudioFile(audioPath, durationMs, transcription) {
|
|
814
|
+
if (durationMs > SPEECH_TO_TEXT_CLIENT_MAX_DURATION_MS) {
|
|
815
|
+
transcription?.abort();
|
|
816
|
+
this.retainedListenAudio = { audioPath, durationMs };
|
|
817
|
+
this.view.addTranscriptNotice("failed to transcribe speech", "error", [
|
|
818
|
+
"audio is longer than 20 minutes",
|
|
819
|
+
`recording retained at ${audioPath}`,
|
|
820
|
+
"run /listen discard to delete it",
|
|
821
|
+
]);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
810
824
|
let audio;
|
|
811
825
|
try {
|
|
812
826
|
audio = await readListenAudio(audioPath);
|
|
@@ -816,8 +830,8 @@ export class SessionChatController {
|
|
|
816
830
|
this.view.addTranscriptNotice("failed to read speech recording", "error", [
|
|
817
831
|
error.message,
|
|
818
832
|
]);
|
|
819
|
-
if (this.
|
|
820
|
-
this.
|
|
833
|
+
if (this.retainedListenAudio?.audioPath === audioPath) {
|
|
834
|
+
this.retainedListenAudio = undefined;
|
|
821
835
|
}
|
|
822
836
|
await cleanupListenTempFile(audioPath);
|
|
823
837
|
return;
|
|
@@ -825,8 +839,8 @@ export class SessionChatController {
|
|
|
825
839
|
if (audio.byteLength < LISTEN_RECORDING_MIN_BYTES) {
|
|
826
840
|
transcription?.abort();
|
|
827
841
|
this.view.showFooterNotice("recording too short, try again", "default");
|
|
828
|
-
if (this.
|
|
829
|
-
this.
|
|
842
|
+
if (this.retainedListenAudio?.audioPath === audioPath) {
|
|
843
|
+
this.retainedListenAudio = undefined;
|
|
830
844
|
}
|
|
831
845
|
await cleanupListenTempFile(audioPath);
|
|
832
846
|
return;
|
|
@@ -842,7 +856,7 @@ export class SessionChatController {
|
|
|
842
856
|
mimeType: "audio/wav",
|
|
843
857
|
});
|
|
844
858
|
this.view.insertEditorTextAtCursor(text);
|
|
845
|
-
this.
|
|
859
|
+
this.retainedListenAudio = undefined;
|
|
846
860
|
try {
|
|
847
861
|
await deleteListenTempFile(audioPath);
|
|
848
862
|
}
|
|
@@ -854,7 +868,7 @@ export class SessionChatController {
|
|
|
854
868
|
}
|
|
855
869
|
}
|
|
856
870
|
catch (error) {
|
|
857
|
-
this.
|
|
871
|
+
this.retainedListenAudio = { audioPath, durationMs };
|
|
858
872
|
this.view.addTranscriptNotice("failed to transcribe speech", "error", [
|
|
859
873
|
error.message,
|
|
860
874
|
`recording retained at ${audioPath}`,
|
|
@@ -1130,10 +1144,13 @@ export class SessionChatController {
|
|
|
1130
1144
|
return false;
|
|
1131
1145
|
}
|
|
1132
1146
|
try {
|
|
1147
|
+
if (this.tryApplyFastSnapshotStateDelta(delta)) {
|
|
1148
|
+
return true;
|
|
1149
|
+
}
|
|
1133
1150
|
if (this.tryApplyFastContentAppendDelta(delta)) {
|
|
1134
1151
|
return true;
|
|
1135
1152
|
}
|
|
1136
|
-
if (this.
|
|
1153
|
+
if (this.tryApplyFastTimelineDelta(delta)) {
|
|
1137
1154
|
return true;
|
|
1138
1155
|
}
|
|
1139
1156
|
if (this.tryApplyFastAgentDelta(delta)) {
|
|
@@ -1166,6 +1183,33 @@ export class SessionChatController {
|
|
|
1166
1183
|
}
|
|
1167
1184
|
return true;
|
|
1168
1185
|
}
|
|
1186
|
+
tryApplyFastSnapshotStateDelta(delta) {
|
|
1187
|
+
if (delta.delta.type !== "snapshot.patch" ||
|
|
1188
|
+
delta.delta.changes.length === 0 ||
|
|
1189
|
+
delta.delta.changes.some((change) => {
|
|
1190
|
+
switch (change.type) {
|
|
1191
|
+
case "agent-state.set":
|
|
1192
|
+
case "lifecycle.set":
|
|
1193
|
+
case "goal.set":
|
|
1194
|
+
case "cost.set":
|
|
1195
|
+
case "settings.set":
|
|
1196
|
+
case "turn.set":
|
|
1197
|
+
case "timeline.advance":
|
|
1198
|
+
case "operation.set":
|
|
1199
|
+
case "operation.remove":
|
|
1200
|
+
return false;
|
|
1201
|
+
default:
|
|
1202
|
+
return true;
|
|
1203
|
+
}
|
|
1204
|
+
})) {
|
|
1205
|
+
return false;
|
|
1206
|
+
}
|
|
1207
|
+
this.snapshot = applySessionProtocolDelta(this.snapshot, delta);
|
|
1208
|
+
this.observedSessionRevision = Math.max(this.observedSessionRevision, this.snapshot.revision);
|
|
1209
|
+
this.updateStreamingStateFromSnapshot(this.snapshot);
|
|
1210
|
+
this.refreshStatus();
|
|
1211
|
+
return true;
|
|
1212
|
+
}
|
|
1169
1213
|
tryApplyFastContentAppendDelta(delta) {
|
|
1170
1214
|
if (delta.delta.type !== "snapshot.patch" || delta.delta.changes.length !== 1) {
|
|
1171
1215
|
return false;
|
|
@@ -1202,6 +1246,128 @@ export class SessionChatController {
|
|
|
1202
1246
|
}
|
|
1203
1247
|
return true;
|
|
1204
1248
|
}
|
|
1249
|
+
tryApplyFastTimelineDelta(delta) {
|
|
1250
|
+
if (delta.delta.type !== "snapshot.patch" || delta.delta.changes.length === 0) {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
const previousSnapshot = this.snapshot;
|
|
1254
|
+
const affectedMessageIds = new Set();
|
|
1255
|
+
const affectedToolIds = new Set();
|
|
1256
|
+
const appendedNoticeIds = new Set();
|
|
1257
|
+
let hasTimelineChange = false;
|
|
1258
|
+
for (const change of delta.delta.changes) {
|
|
1259
|
+
switch (change.type) {
|
|
1260
|
+
case "agent-state.set":
|
|
1261
|
+
case "lifecycle.set":
|
|
1262
|
+
case "goal.set":
|
|
1263
|
+
case "cost.set":
|
|
1264
|
+
case "settings.set":
|
|
1265
|
+
case "turn.set":
|
|
1266
|
+
case "timeline.advance":
|
|
1267
|
+
case "operation.set":
|
|
1268
|
+
case "operation.remove":
|
|
1269
|
+
break;
|
|
1270
|
+
case "message.append":
|
|
1271
|
+
case "message.replace":
|
|
1272
|
+
hasTimelineChange = true;
|
|
1273
|
+
affectedMessageIds.add(change.message.id);
|
|
1274
|
+
break;
|
|
1275
|
+
case "message.content.append":
|
|
1276
|
+
hasTimelineChange = true;
|
|
1277
|
+
affectedMessageIds.add(change.messageId);
|
|
1278
|
+
break;
|
|
1279
|
+
case "timeline.append":
|
|
1280
|
+
hasTimelineChange = true;
|
|
1281
|
+
if (change.item.type === "message") {
|
|
1282
|
+
affectedMessageIds.add(change.item.messageId);
|
|
1283
|
+
}
|
|
1284
|
+
else if (change.item.type === "tool") {
|
|
1285
|
+
affectedToolIds.add(change.item.toolId);
|
|
1286
|
+
}
|
|
1287
|
+
else if (change.item.type === "notice") {
|
|
1288
|
+
appendedNoticeIds.add(change.item.id);
|
|
1289
|
+
}
|
|
1290
|
+
break;
|
|
1291
|
+
case "tool.set":
|
|
1292
|
+
hasTimelineChange = true;
|
|
1293
|
+
affectedToolIds.add(change.tool.id);
|
|
1294
|
+
break;
|
|
1295
|
+
case "facet.set":
|
|
1296
|
+
if (change.facet.kind !== "tau.tool-ui-events" || change.facet.subject.type !== "tool") {
|
|
1297
|
+
return false;
|
|
1298
|
+
}
|
|
1299
|
+
hasTimelineChange = true;
|
|
1300
|
+
affectedToolIds.add(change.facet.subject.id);
|
|
1301
|
+
break;
|
|
1302
|
+
default:
|
|
1303
|
+
return false;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
if (!hasTimelineChange) {
|
|
1307
|
+
return false;
|
|
1308
|
+
}
|
|
1309
|
+
const nextSnapshot = applySessionProtocolDelta(previousSnapshot, delta);
|
|
1310
|
+
this.snapshot = nextSnapshot;
|
|
1311
|
+
this.observedSessionRevision = Math.max(this.observedSessionRevision, nextSnapshot.revision);
|
|
1312
|
+
const remainingMessageIds = new Set(affectedMessageIds);
|
|
1313
|
+
const affectedMessages = new Map();
|
|
1314
|
+
for (const messageId of affectedMessageIds) {
|
|
1315
|
+
const message = nextSnapshot.messages.find((entry) => entry.id === messageId);
|
|
1316
|
+
if (message) {
|
|
1317
|
+
affectedMessages.set(messageId, message);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
const timelineItems = [...nextSnapshot.timeline.items, ...this.ephemeralTimelineItems.values()]
|
|
1321
|
+
.filter((item) => {
|
|
1322
|
+
if (item.type === "message") {
|
|
1323
|
+
return affectedMessageIds.has(item.messageId);
|
|
1324
|
+
}
|
|
1325
|
+
if (item.type === "tool") {
|
|
1326
|
+
return affectedToolIds.has(item.toolId);
|
|
1327
|
+
}
|
|
1328
|
+
return item.type === "notice" && appendedNoticeIds.has(item.id);
|
|
1329
|
+
})
|
|
1330
|
+
.sort((left, right) => left.sequence - right.sequence);
|
|
1331
|
+
for (const item of timelineItems) {
|
|
1332
|
+
if (item.type === "message" && remainingMessageIds.delete(item.messageId)) {
|
|
1333
|
+
const message = affectedMessages.get(item.messageId);
|
|
1334
|
+
if (message) {
|
|
1335
|
+
this.syncProtocolMessage(message);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
else if (item.type === "tool" && affectedToolIds.has(item.toolId)) {
|
|
1339
|
+
const tool = nextSnapshot.tools[item.toolId];
|
|
1340
|
+
if (tool) {
|
|
1341
|
+
this.upsertRenderedMessage(item.id, {
|
|
1342
|
+
type: "tool",
|
|
1343
|
+
tool: buildToolUiModel(nextSnapshot, tool),
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
else if (item.type === "notice" && appendedNoticeIds.has(item.id)) {
|
|
1348
|
+
this.upsertRenderedMessage(item.id, {
|
|
1349
|
+
type: "transcript_notice",
|
|
1350
|
+
title: item.notice.presentation.title,
|
|
1351
|
+
...(item.notice.presentation.content
|
|
1352
|
+
? { content: item.notice.presentation.content }
|
|
1353
|
+
: {}),
|
|
1354
|
+
tone: item.notice.severity === "error" ? "error" : "default",
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
for (const messageId of remainingMessageIds) {
|
|
1359
|
+
const message = affectedMessages.get(messageId);
|
|
1360
|
+
if (message) {
|
|
1361
|
+
this.syncProtocolMessage(message);
|
|
1362
|
+
}
|
|
1363
|
+
else {
|
|
1364
|
+
this.removeProtocolMessage(messageId);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
this.updateStreamingStateFromSnapshot(nextSnapshot);
|
|
1368
|
+
this.refreshStatus();
|
|
1369
|
+
return true;
|
|
1370
|
+
}
|
|
1205
1371
|
tryApplyFastAgentDelta(delta) {
|
|
1206
1372
|
if (delta.delta.type !== "snapshot.patch") {
|
|
1207
1373
|
return false;
|
|
@@ -1221,20 +1387,70 @@ export class SessionChatController {
|
|
|
1221
1387
|
this.refreshStatus();
|
|
1222
1388
|
return true;
|
|
1223
1389
|
}
|
|
1224
|
-
|
|
1225
|
-
if (
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
return false;
|
|
1390
|
+
syncProtocolMessage(message) {
|
|
1391
|
+
if (this.hiddenHistoryEntryIds.has(message.id) || !this.isMessageProjected(message.id)) {
|
|
1392
|
+
this.removeProtocolMessage(message.id);
|
|
1393
|
+
return;
|
|
1229
1394
|
}
|
|
1230
|
-
const
|
|
1231
|
-
if (
|
|
1232
|
-
|
|
1395
|
+
const model = this.buildProtocolMessageModel(message);
|
|
1396
|
+
if (model) {
|
|
1397
|
+
this.upsertRenderedMessage(message.id, model);
|
|
1233
1398
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1399
|
+
else {
|
|
1400
|
+
this.removeRenderedProtocolItems([message.id]);
|
|
1401
|
+
}
|
|
1402
|
+
const outcomeNotice = getMessageOutcomeNotice(message);
|
|
1403
|
+
const outcomeNoticeId = `presentation:failure:${message.id}`;
|
|
1404
|
+
const interruptionNoticeId = `presentation:interruption:${message.id}`;
|
|
1405
|
+
if (outcomeNotice) {
|
|
1406
|
+
this.upsertRenderedMessage(outcomeNotice.id, {
|
|
1407
|
+
type: "transcript_notice",
|
|
1408
|
+
title: outcomeNotice.title,
|
|
1409
|
+
...(outcomeNotice.content ? { content: outcomeNotice.content } : {}),
|
|
1410
|
+
tone: outcomeNotice.severity === "error" ? "error" : "default",
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
if (outcomeNotice?.id !== outcomeNoticeId) {
|
|
1414
|
+
this.removeRenderedProtocolItems([outcomeNoticeId]);
|
|
1415
|
+
}
|
|
1416
|
+
if (outcomeNotice?.id !== interruptionNoticeId) {
|
|
1417
|
+
this.removeRenderedProtocolItems([interruptionNoticeId]);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
removeProtocolMessage(messageId) {
|
|
1421
|
+
this.removeRenderedProtocolItems([
|
|
1422
|
+
messageId,
|
|
1423
|
+
`presentation:failure:${messageId}`,
|
|
1424
|
+
`presentation:interruption:${messageId}`,
|
|
1425
|
+
]);
|
|
1426
|
+
}
|
|
1427
|
+
upsertRenderedMessage(protocolId, model) {
|
|
1428
|
+
const viewMessageId = this.getViewMessageId(protocolId);
|
|
1429
|
+
if (this.renderedMessageIds.includes(viewMessageId)) {
|
|
1430
|
+
if (model.type === "assistant" || model.type === "assistant_partial") {
|
|
1431
|
+
this.view.updateAssistantMessage(viewMessageId, model);
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
this.view.updateMessage(viewMessageId, model);
|
|
1435
|
+
}
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
this.renderedMessageIds.push(this.view.addMessage(model, viewMessageId));
|
|
1439
|
+
}
|
|
1440
|
+
removeRenderedProtocolItems(protocolIds) {
|
|
1441
|
+
this.removeRenderedMessages(protocolIds.flatMap((id) => {
|
|
1442
|
+
const viewMessageId = this.viewMessageIds.get(id);
|
|
1443
|
+
return viewMessageId ? [viewMessageId] : [];
|
|
1444
|
+
}));
|
|
1445
|
+
}
|
|
1446
|
+
removeRenderedMessages(ids) {
|
|
1447
|
+
const idsToRemove = ids.filter((id) => this.renderedMessageIds.includes(id));
|
|
1448
|
+
if (idsToRemove.length === 0) {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
const idSet = new Set(idsToRemove);
|
|
1452
|
+
this.renderedMessageIds.splice(0, this.renderedMessageIds.length, ...this.renderedMessageIds.filter((id) => !idSet.has(id)));
|
|
1453
|
+
this.view.removeMessages(idsToRemove);
|
|
1238
1454
|
}
|
|
1239
1455
|
getViewMessageId(protocolId) {
|
|
1240
1456
|
const existingId = this.viewMessageIds.get(protocolId);
|