@markusylisiurunen/tau 0.3.21 → 0.3.22

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.
Files changed (58) hide show
  1. package/dist/core/auth/auth_storage.js +249 -23
  2. package/dist/core/auth/auth_storage.js.map +1 -1
  3. package/dist/core/auth/cli.js +66 -0
  4. package/dist/core/auth/cli.js.map +1 -1
  5. package/dist/core/auth/credential_store.js +42 -10
  6. package/dist/core/auth/credential_store.js.map +1 -1
  7. package/dist/core/auth/index.js +1 -1
  8. package/dist/core/auth/index.js.map +1 -1
  9. package/dist/core/auth/providers/openai_codex.js +46 -22
  10. package/dist/core/auth/providers/openai_codex.js.map +1 -1
  11. package/dist/core/events/types.js +1 -7
  12. package/dist/core/events/types.js.map +1 -1
  13. package/dist/core/index.js +1 -2
  14. package/dist/core/index.js.map +1 -1
  15. package/dist/core/models/catalog.js +20 -24
  16. package/dist/core/models/catalog.js.map +1 -1
  17. package/dist/core/session/compaction.js +0 -4
  18. package/dist/core/session/compaction.js.map +1 -1
  19. package/dist/core/session/core_session.js +3 -0
  20. package/dist/core/session/core_session.js.map +1 -1
  21. package/dist/core/session/pruning.js +8 -17
  22. package/dist/core/session/pruning.js.map +1 -1
  23. package/dist/core/session/runner.js +12 -2
  24. package/dist/core/session/runner.js.map +1 -1
  25. package/dist/core/session/session_engine.js +62 -38
  26. package/dist/core/session/session_engine.js.map +1 -1
  27. package/dist/core/subagents/control_plane.js +8 -9
  28. package/dist/core/subagents/control_plane.js.map +1 -1
  29. package/dist/core/version.js +1 -1
  30. package/dist/execution/cloudflare_sandbox_execution_environment.js +54 -6
  31. package/dist/execution/cloudflare_sandbox_execution_environment.js.map +1 -1
  32. package/dist/host/hosted_ephemeral_agent_session.js +19 -14
  33. package/dist/host/hosted_ephemeral_agent_session.js.map +1 -1
  34. package/dist/host/local_session_host.js +269 -97
  35. package/dist/host/local_session_host.js.map +1 -1
  36. package/dist/host/session_host.js +2 -1
  37. package/dist/host/session_host.js.map +1 -1
  38. package/dist/host/session_protocol_handler.js +34 -5
  39. package/dist/host/session_protocol_handler.js.map +1 -1
  40. package/dist/main.js +17 -15
  41. package/dist/main.js.map +1 -1
  42. package/dist/protocol/session_protocol.d.ts +0 -1
  43. package/dist/protocol/session_protocol.js +103 -5
  44. package/dist/protocol/session_protocol.js.map +1 -1
  45. package/dist/store/file_session_store.js +223 -41
  46. package/dist/store/file_session_store.js.map +1 -1
  47. package/dist/transport/stdio_session_transport.d.ts +2 -0
  48. package/dist/transport/stdio_session_transport.js +30 -3
  49. package/dist/transport/stdio_session_transport.js.map +1 -1
  50. package/dist/tui/chat_controller/diff_review_service.js +8 -5
  51. package/dist/tui/chat_controller/diff_review_service.js.map +1 -1
  52. package/dist/tui/session_chat_controller.js +113 -46
  53. package/dist/tui/session_chat_controller.js.map +1 -1
  54. package/package.json +3 -3
  55. package/dist/core/events/index.js +0 -3
  56. package/dist/core/events/index.js.map +0 -1
  57. package/dist/core/events/parser.js +0 -334
  58. package/dist/core/events/parser.js.map +0 -1
@@ -59,6 +59,8 @@ export class SessionChatController {
59
59
  isStreaming = false;
60
60
  submittedTurnInProgress = false;
61
61
  manualCompactionInProgress = false;
62
+ localDiffReviewInProgress = false;
63
+ sessionReplacementInProgress = false;
62
64
  isBashMode = false;
63
65
  isBashIncognito = false;
64
66
  isMemoryMode = false;
@@ -120,8 +122,8 @@ export class SessionChatController {
120
122
  startTurnTimer: () => this.startTurnTimer(),
121
123
  stopTurnTimer: () => this.stopTurnTimer(),
122
124
  getDiffToolConfig: () => this.resolveDiffToolConfig(),
123
- startSession: (args) => this.startDiffReviewBridge(args),
124
- onReviewReturned: (review) => void this.handleReturnedDiffReview(review),
125
+ startSession: (args) => this.startDiffReviewBridge(args, this.session, this.snapshot),
126
+ onReviewReturned: (review) => this.handleReturnedDiffReview(review, this.session),
125
127
  });
126
128
  }
127
129
  start() {
@@ -183,7 +185,7 @@ export class SessionChatController {
183
185
  if (!this.isSessionOperationActive()) {
184
186
  return true;
185
187
  }
186
- if (this.manualCompactionInProgress) {
188
+ if (this.isBlockingSessionOperationActive()) {
187
189
  return false;
188
190
  }
189
191
  const trimmed = text.trimStart();
@@ -221,6 +223,10 @@ export class SessionChatController {
221
223
  }
222
224
  this.lastEmptySubmitAt = undefined;
223
225
  if (this.isSessionOperationActive()) {
226
+ if (this.isBlockingSessionOperationActive()) {
227
+ this.view.addSystemMessage("wait for tau to become idle before submitting input", "warn");
228
+ return;
229
+ }
224
230
  if (trimmed.startsWith("/") && this.isSingleLineInput(text)) {
225
231
  const parsed = this.commandRegistry.parse(trimmed);
226
232
  if (parsed.type !== "unknown") {
@@ -471,6 +477,10 @@ export class SessionChatController {
471
477
  await this.submitUserText(trimmed);
472
478
  return;
473
479
  }
480
+ if (this.isBlockingSessionOperationActive()) {
481
+ this.view.addSystemMessage("wait for tau to become idle before submitting input", "warn");
482
+ return;
483
+ }
474
484
  this.submitSteeringText(trimmed);
475
485
  }
476
486
  submitQueuedText(text) {
@@ -795,49 +805,88 @@ export class SessionChatController {
795
805
  }
796
806
  async createNewSession() {
797
807
  if (this.isSessionOperationActive()) {
798
- this.view.addSystemMessage("cannot create a new session while a turn is running", "warn");
808
+ this.view.addSystemMessage("cannot create a new session while another session operation is running", "warn");
799
809
  return;
800
810
  }
801
811
  if (!this.createSession) {
802
812
  this.view.addSystemMessage("new session creation is unavailable", "error");
803
813
  return;
804
814
  }
815
+ const createInput = {
816
+ executionEnvironment: this.createExecutionEnvironmentInputFromSnapshot(),
817
+ personaId: this.snapshot.settings.personaId,
818
+ ...(this.snapshot.settings.reasoning !== undefined
819
+ ? { reasoning: this.snapshot.settings.reasoning }
820
+ : {}),
821
+ };
822
+ this.sessionReplacementInProgress = true;
823
+ this.refreshStatus();
824
+ let nextSession;
825
+ let nextEventUnsubscribe;
826
+ let nextPendingUserMessagesUnsubscribe;
827
+ let installed = false;
805
828
  try {
806
- const previousUnsubscribe = this.eventUnsubscribe;
807
- const previousPendingUserMessagesUnsubscribe = this.pendingUserMessagesUnsubscribe;
808
- const previousSession = this.session;
809
- const nextSession = await this.createSession({
810
- executionEnvironment: this.createExecutionEnvironmentInputFromSnapshot(),
811
- personaId: this.snapshot.settings.personaId,
812
- ...(this.snapshot.settings.reasoning !== undefined
813
- ? { reasoning: this.snapshot.settings.reasoning }
814
- : {}),
829
+ nextSession = await this.createSession(createInput);
830
+ const nextSnapshot = await nextSession.snapshot();
831
+ const pendingDeltas = [];
832
+ const pendingUserMessages = [];
833
+ let forwardEvents = false;
834
+ nextEventUnsubscribe = nextSession.onDelta((delta) => {
835
+ if (forwardEvents) {
836
+ this.onSdkDelta(delta);
837
+ }
838
+ else {
839
+ pendingDeltas.push(delta);
840
+ }
815
841
  });
816
- this.eventUnsubscribe = undefined;
817
- this.pendingUserMessagesUnsubscribe = undefined;
818
- previousUnsubscribe?.();
819
- previousPendingUserMessagesUnsubscribe?.();
820
- try {
821
- await previousSession.unobserve();
822
- }
823
- catch (detachError) {
824
- this.view.addSystemMessage(`old session unobserve failed: ${detachError.message}`, "warn");
825
- }
842
+ nextPendingUserMessagesUnsubscribe = nextSession.onPendingUserMessages((message) => {
843
+ if (forwardEvents) {
844
+ this.onSdkPendingUserMessages(message);
845
+ }
846
+ else {
847
+ pendingUserMessages.push(message);
848
+ }
849
+ });
850
+ const previousSession = this.session;
851
+ this.eventUnsubscribe?.();
852
+ this.pendingUserMessagesUnsubscribe?.();
826
853
  this.session = nextSession;
827
- this.snapshot = await this.session.snapshot();
828
- this.observedSessionRevision = this.snapshot.revision;
829
- this.eventUnsubscribe = this.session.onDelta((delta) => this.onSdkDelta(delta));
830
- this.pendingUserMessagesUnsubscribe = this.session.onPendingUserMessages((message) => this.onSdkPendingUserMessages(message));
854
+ this.snapshot = nextSnapshot;
855
+ this.observedSessionRevision = nextSnapshot.revision;
856
+ this.eventUnsubscribe = nextEventUnsubscribe;
857
+ this.pendingUserMessagesUnsubscribe = nextPendingUserMessagesUnsubscribe;
858
+ installed = true;
831
859
  this.view.resetToolUiSession();
832
860
  this.assistantMessages = [];
833
861
  this.startLocalUiSession();
834
862
  this.addSessionIdentityMessage();
835
863
  this.renderSnapshot(this.snapshot);
836
- this.refreshStatus();
864
+ for (const delta of pendingDeltas) {
865
+ this.onSdkDelta(delta);
866
+ }
867
+ for (const message of pendingUserMessages) {
868
+ this.onSdkPendingUserMessages(message);
869
+ }
870
+ forwardEvents = true;
871
+ try {
872
+ await previousSession.unobserve();
873
+ }
874
+ catch (detachError) {
875
+ this.view.addSystemMessage(`old session unobserve failed: ${detachError.message}`, "warn");
876
+ }
837
877
  }
838
878
  catch (error) {
879
+ if (!installed && nextSession) {
880
+ nextEventUnsubscribe?.();
881
+ nextPendingUserMessagesUnsubscribe?.();
882
+ await nextSession.unobserve().catch(() => undefined);
883
+ }
839
884
  this.view.addSystemMessage(`new session failed: ${error.message}`, "error");
840
885
  }
886
+ finally {
887
+ this.sessionReplacementInProgress = false;
888
+ this.refreshStatus();
889
+ }
841
890
  }
842
891
  createExecutionEnvironmentInputFromSnapshot() {
843
892
  const snapshot = this.snapshot.executionEnvironment;
@@ -1158,7 +1207,12 @@ export class SessionChatController {
1158
1207
  this.refreshStatus();
1159
1208
  }
1160
1209
  isSessionOperationActive() {
1161
- return this.isStreaming || this.submittedTurnInProgress || this.manualCompactionInProgress;
1210
+ return (this.isStreaming || this.submittedTurnInProgress || this.isBlockingSessionOperationActive());
1211
+ }
1212
+ isBlockingSessionOperationActive() {
1213
+ return (this.manualCompactionInProgress ||
1214
+ this.localDiffReviewInProgress ||
1215
+ this.sessionReplacementInProgress);
1162
1216
  }
1163
1217
  async recoverFromRevisionGap() {
1164
1218
  if (this.snapshotRecovery) {
@@ -1652,35 +1706,46 @@ export class SessionChatController {
1652
1706
  this.view.addSystemMessage("wait for tau to become idle before starting /diff.", "warn");
1653
1707
  return;
1654
1708
  }
1655
- await this.diffReviewService.start(argsText);
1709
+ const session = this.session;
1710
+ const snapshot = this.snapshot;
1711
+ this.localDiffReviewInProgress = true;
1712
+ this.refreshStatus();
1713
+ try {
1714
+ await this.diffReviewService.start(argsText, {
1715
+ startSession: (args) => this.startDiffReviewBridge(args, session, snapshot),
1716
+ onReviewReturned: (review) => this.handleReturnedDiffReview(review, session),
1717
+ });
1718
+ }
1719
+ finally {
1720
+ this.localDiffReviewInProgress = false;
1721
+ this.refreshStatus();
1722
+ }
1656
1723
  }
1657
1724
  isDiffReviewIdle() {
1658
- return (!this.isStreaming &&
1659
- !this.submittedTurnInProgress &&
1725
+ return (!this.isSessionOperationActive() &&
1660
1726
  !this.listenRecording &&
1661
1727
  !this.listenTransition &&
1662
1728
  !this.isTranscribingListen &&
1663
- !this.speakTask &&
1664
- !this.diffReviewService.isActive());
1729
+ !this.speakTask);
1665
1730
  }
1666
1731
  resolveDiffToolConfig() {
1667
1732
  return this.config.diffTool ?? this.defaultDiffTool;
1668
1733
  }
1669
- async startDiffReviewBridge(args) {
1734
+ async startDiffReviewBridge(args, session, sessionSnapshot) {
1670
1735
  const snapshot = await captureDiffReviewSnapshot({
1671
- cwd: this.snapshot.executionEnvironment.cwd,
1736
+ cwd: sessionSnapshot.executionEnvironment.cwd,
1672
1737
  source: args.source,
1673
1738
  signal: args.signal,
1674
- deps: createSessionDiffReviewSnapshotDeps(this.session),
1739
+ deps: createSessionDiffReviewSnapshotDeps(session),
1675
1740
  });
1676
- const ephemeral = await this.session.createEphemeralContext({
1741
+ const ephemeral = await session.createEphemeralContext({
1677
1742
  instructions: buildDiffReviewInstructions(snapshot),
1678
1743
  tools: ["bash", "view_image"],
1679
1744
  });
1680
1745
  const bridge = new DiffReviewBridge({
1681
1746
  snapshot,
1682
- contextWindow: this.snapshot.bootstrap.model.contextWindow,
1683
- submitThreadMessage: (options) => this.session.submitEphemeralThread({
1747
+ contextWindow: sessionSnapshot.bootstrap.model.contextWindow,
1748
+ submitThreadMessage: (options) => session.submitEphemeralThread({
1684
1749
  contextId: ephemeral.contextId,
1685
1750
  threadId: options.threadId,
1686
1751
  ...(options.forkFromThreadId ? { forkFromThreadId: options.forkFromThreadId } : {}),
@@ -1689,7 +1754,7 @@ export class SessionChatController {
1689
1754
  deps: this.deps,
1690
1755
  ...(this.diffToolLauncher ? { toolLauncher: this.diffToolLauncher } : {}),
1691
1756
  });
1692
- const unsubscribeEphemeral = this.session.onEphemeral((message) => {
1757
+ const unsubscribeEphemeral = session.onEphemeral((message) => {
1693
1758
  const event = message.event;
1694
1759
  if (event.type !== "ephemeral-agent.thread-update" ||
1695
1760
  event.contextId !== ephemeral.contextId) {
@@ -1712,18 +1777,18 @@ export class SessionChatController {
1712
1777
  }
1713
1778
  catch (error) {
1714
1779
  unsubscribeEphemeral();
1715
- await this.session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1780
+ await session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1716
1781
  await bridge.cancel("launch_failed").catch(() => undefined);
1717
1782
  await bridge.close().catch(() => undefined);
1718
1783
  throw error;
1719
1784
  }
1720
1785
  const result = bridge.result.finally(async () => {
1721
1786
  unsubscribeEphemeral();
1722
- await this.session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1787
+ await session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1723
1788
  });
1724
1789
  return { bridge, result };
1725
1790
  }
1726
- async handleReturnedDiffReview(review) {
1791
+ async handleReturnedDiffReview(review, session) {
1727
1792
  const model = {
1728
1793
  type: "user",
1729
1794
  text: review.review,
@@ -1734,10 +1799,12 @@ export class SessionChatController {
1734
1799
  this.renderedMessageIds.push(review.historyEntryId);
1735
1800
  }
1736
1801
  try {
1737
- const result = await this.session.record(formatDiffReviewUserMessage(review), {
1802
+ const result = await session.record(formatDiffReviewUserMessage(review), {
1738
1803
  historyEntryId: review.historyEntryId,
1739
1804
  });
1740
- this.syncRenderedHistory(result.snapshot);
1805
+ if (this.session === session) {
1806
+ this.syncRenderedHistory(result.snapshot);
1807
+ }
1741
1808
  }
1742
1809
  catch (error) {
1743
1810
  this.view.addSystemMessage(`failed to add diff review to session: ${error.message}`, "error");