@markusylisiurunen/tau 0.3.20 → 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 (92) 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 +114 -122
  24. package/dist/core/session/runner.js.map +1 -1
  25. package/dist/core/session/session_engine.js +67 -35
  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/tools/bash.js +5 -6
  30. package/dist/core/tools/bash.js.map +1 -1
  31. package/dist/core/tools/edit.js +88 -81
  32. package/dist/core/tools/edit.js.map +1 -1
  33. package/dist/core/tools/emit_output.js +19 -17
  34. package/dist/core/tools/emit_output.js.map +1 -1
  35. package/dist/core/tools/grep.js +5 -5
  36. package/dist/core/tools/grep.js.map +1 -1
  37. package/dist/core/tools/list.js +60 -57
  38. package/dist/core/tools/list.js.map +1 -1
  39. package/dist/core/tools/nook.js +114 -114
  40. package/dist/core/tools/nook.js.map +1 -1
  41. package/dist/core/tools/read.js +82 -79
  42. package/dist/core/tools/read.js.map +1 -1
  43. package/dist/core/tools/registry.js +6 -0
  44. package/dist/core/tools/registry.js.map +1 -1
  45. package/dist/core/tools/send_input_to_agent.js +9 -10
  46. package/dist/core/tools/send_input_to_agent.js.map +1 -1
  47. package/dist/core/tools/spawn_agent.js +23 -24
  48. package/dist/core/tools/spawn_agent.js.map +1 -1
  49. package/dist/core/tools/terminate_agent.js +7 -8
  50. package/dist/core/tools/terminate_agent.js.map +1 -1
  51. package/dist/core/tools/view_image.js +60 -57
  52. package/dist/core/tools/view_image.js.map +1 -1
  53. package/dist/core/tools/wait_for_agents.js +6 -7
  54. package/dist/core/tools/wait_for_agents.js.map +1 -1
  55. package/dist/core/tools/web_fetch.js +6 -6
  56. package/dist/core/tools/web_fetch.js.map +1 -1
  57. package/dist/core/tools/web_search.js +6 -6
  58. package/dist/core/tools/web_search.js.map +1 -1
  59. package/dist/core/tools/write.js +41 -38
  60. package/dist/core/tools/write.js.map +1 -1
  61. package/dist/core/version.js +1 -1
  62. package/dist/execution/cloudflare_sandbox_execution_environment.js +54 -6
  63. package/dist/execution/cloudflare_sandbox_execution_environment.js.map +1 -1
  64. package/dist/host/client_tool_broker.js +5 -2
  65. package/dist/host/client_tool_broker.js.map +1 -1
  66. package/dist/host/hosted_ephemeral_agent_session.js +19 -14
  67. package/dist/host/hosted_ephemeral_agent_session.js.map +1 -1
  68. package/dist/host/local_session_host.js +269 -97
  69. package/dist/host/local_session_host.js.map +1 -1
  70. package/dist/host/session_host.js +2 -1
  71. package/dist/host/session_host.js.map +1 -1
  72. package/dist/host/session_protocol_handler.js +34 -5
  73. package/dist/host/session_protocol_handler.js.map +1 -1
  74. package/dist/main.js +17 -15
  75. package/dist/main.js.map +1 -1
  76. package/dist/protocol/session_protocol.d.ts +0 -1
  77. package/dist/protocol/session_protocol.js +103 -5
  78. package/dist/protocol/session_protocol.js.map +1 -1
  79. package/dist/store/file_session_store.js +223 -41
  80. package/dist/store/file_session_store.js.map +1 -1
  81. package/dist/transport/stdio_session_transport.d.ts +2 -0
  82. package/dist/transport/stdio_session_transport.js +30 -3
  83. package/dist/transport/stdio_session_transport.js.map +1 -1
  84. package/dist/tui/chat_controller/diff_review_service.js +8 -5
  85. package/dist/tui/chat_controller/diff_review_service.js.map +1 -1
  86. package/dist/tui/session_chat_controller.js +126 -46
  87. package/dist/tui/session_chat_controller.js.map +1 -1
  88. package/package.json +3 -3
  89. package/dist/core/events/index.js +0 -3
  90. package/dist/core/events/index.js.map +0 -1
  91. package/dist/core/events/parser.js +0 -334
  92. package/dist/core/events/parser.js.map +0 -1
@@ -54,9 +54,13 @@ export class SessionChatController {
54
54
  pendingUserMessagesUnsubscribe;
55
55
  snapshotRecovery;
56
56
  snapshotRecoveryDeltas = [];
57
+ hasPendingUserMessages = false;
58
+ pendingIdleNotification = false;
57
59
  isStreaming = false;
58
60
  submittedTurnInProgress = false;
59
61
  manualCompactionInProgress = false;
62
+ localDiffReviewInProgress = false;
63
+ sessionReplacementInProgress = false;
60
64
  isBashMode = false;
61
65
  isBashIncognito = false;
62
66
  isMemoryMode = false;
@@ -118,8 +122,8 @@ export class SessionChatController {
118
122
  startTurnTimer: () => this.startTurnTimer(),
119
123
  stopTurnTimer: () => this.stopTurnTimer(),
120
124
  getDiffToolConfig: () => this.resolveDiffToolConfig(),
121
- startSession: (args) => this.startDiffReviewBridge(args),
122
- onReviewReturned: (review) => void this.handleReturnedDiffReview(review),
125
+ startSession: (args) => this.startDiffReviewBridge(args, this.session, this.snapshot),
126
+ onReviewReturned: (review) => this.handleReturnedDiffReview(review, this.session),
123
127
  });
124
128
  }
125
129
  start() {
@@ -181,7 +185,7 @@ export class SessionChatController {
181
185
  if (!this.isSessionOperationActive()) {
182
186
  return true;
183
187
  }
184
- if (this.manualCompactionInProgress) {
188
+ if (this.isBlockingSessionOperationActive()) {
185
189
  return false;
186
190
  }
187
191
  const trimmed = text.trimStart();
@@ -219,6 +223,10 @@ export class SessionChatController {
219
223
  }
220
224
  this.lastEmptySubmitAt = undefined;
221
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
+ }
222
230
  if (trimmed.startsWith("/") && this.isSingleLineInput(text)) {
223
231
  const parsed = this.commandRegistry.parse(trimmed);
224
232
  if (parsed.type !== "unknown") {
@@ -469,6 +477,10 @@ export class SessionChatController {
469
477
  await this.submitUserText(trimmed);
470
478
  return;
471
479
  }
480
+ if (this.isBlockingSessionOperationActive()) {
481
+ this.view.addSystemMessage("wait for tau to become idle before submitting input", "warn");
482
+ return;
483
+ }
472
484
  this.submitSteeringText(trimmed);
473
485
  }
474
486
  submitQueuedText(text) {
@@ -793,49 +805,88 @@ export class SessionChatController {
793
805
  }
794
806
  async createNewSession() {
795
807
  if (this.isSessionOperationActive()) {
796
- 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");
797
809
  return;
798
810
  }
799
811
  if (!this.createSession) {
800
812
  this.view.addSystemMessage("new session creation is unavailable", "error");
801
813
  return;
802
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;
803
828
  try {
804
- const previousUnsubscribe = this.eventUnsubscribe;
805
- const previousPendingUserMessagesUnsubscribe = this.pendingUserMessagesUnsubscribe;
806
- const previousSession = this.session;
807
- const nextSession = await this.createSession({
808
- executionEnvironment: this.createExecutionEnvironmentInputFromSnapshot(),
809
- personaId: this.snapshot.settings.personaId,
810
- ...(this.snapshot.settings.reasoning !== undefined
811
- ? { reasoning: this.snapshot.settings.reasoning }
812
- : {}),
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
+ }
813
841
  });
814
- this.eventUnsubscribe = undefined;
815
- this.pendingUserMessagesUnsubscribe = undefined;
816
- previousUnsubscribe?.();
817
- previousPendingUserMessagesUnsubscribe?.();
818
- try {
819
- await previousSession.unobserve();
820
- }
821
- catch (detachError) {
822
- this.view.addSystemMessage(`old session unobserve failed: ${detachError.message}`, "warn");
823
- }
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?.();
824
853
  this.session = nextSession;
825
- this.snapshot = await this.session.snapshot();
826
- this.observedSessionRevision = this.snapshot.revision;
827
- this.eventUnsubscribe = this.session.onDelta((delta) => this.onSdkDelta(delta));
828
- 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;
829
859
  this.view.resetToolUiSession();
830
860
  this.assistantMessages = [];
831
861
  this.startLocalUiSession();
832
862
  this.addSessionIdentityMessage();
833
863
  this.renderSnapshot(this.snapshot);
834
- 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
+ }
835
877
  }
836
878
  catch (error) {
879
+ if (!installed && nextSession) {
880
+ nextEventUnsubscribe?.();
881
+ nextPendingUserMessagesUnsubscribe?.();
882
+ await nextSession.unobserve().catch(() => undefined);
883
+ }
837
884
  this.view.addSystemMessage(`new session failed: ${error.message}`, "error");
838
885
  }
886
+ finally {
887
+ this.sessionReplacementInProgress = false;
888
+ this.refreshStatus();
889
+ }
839
890
  }
840
891
  createExecutionEnvironmentInputFromSnapshot() {
841
892
  const snapshot = this.snapshot.executionEnvironment;
@@ -859,7 +910,9 @@ export class SessionChatController {
859
910
  }
860
911
  }
861
912
  onSdkPendingUserMessages(message) {
913
+ this.hasPendingUserMessages = message.state.messages.length > 0;
862
914
  this.view.setPendingUserMessages(message.state.messages);
915
+ this.sendPendingIdleNotification();
863
916
  }
864
917
  onSdkDelta(delta) {
865
918
  if (this.snapshotRecovery) {
@@ -1123,6 +1176,15 @@ export class SessionChatController {
1123
1176
  return;
1124
1177
  }
1125
1178
  void this.stopTurnCaffeinate();
1179
+ this.pendingIdleNotification = true;
1180
+ this.sendPendingIdleNotification();
1181
+ }
1182
+ sendPendingIdleNotification() {
1183
+ if (!this.pendingIdleNotification || this.isStreaming || this.hasPendingUserMessages) {
1184
+ return;
1185
+ }
1186
+ this.pendingIdleNotification = false;
1187
+ this.view.sendTerminalNotification("tau is waiting for your input");
1126
1188
  }
1127
1189
  stopVisibleSessionTurn() {
1128
1190
  if (!this.isStreaming) {
@@ -1145,7 +1207,12 @@ export class SessionChatController {
1145
1207
  this.refreshStatus();
1146
1208
  }
1147
1209
  isSessionOperationActive() {
1148
- 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);
1149
1216
  }
1150
1217
  async recoverFromRevisionGap() {
1151
1218
  if (this.snapshotRecovery) {
@@ -1639,35 +1706,46 @@ export class SessionChatController {
1639
1706
  this.view.addSystemMessage("wait for tau to become idle before starting /diff.", "warn");
1640
1707
  return;
1641
1708
  }
1642
- 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
+ }
1643
1723
  }
1644
1724
  isDiffReviewIdle() {
1645
- return (!this.isStreaming &&
1646
- !this.submittedTurnInProgress &&
1725
+ return (!this.isSessionOperationActive() &&
1647
1726
  !this.listenRecording &&
1648
1727
  !this.listenTransition &&
1649
1728
  !this.isTranscribingListen &&
1650
- !this.speakTask &&
1651
- !this.diffReviewService.isActive());
1729
+ !this.speakTask);
1652
1730
  }
1653
1731
  resolveDiffToolConfig() {
1654
1732
  return this.config.diffTool ?? this.defaultDiffTool;
1655
1733
  }
1656
- async startDiffReviewBridge(args) {
1734
+ async startDiffReviewBridge(args, session, sessionSnapshot) {
1657
1735
  const snapshot = await captureDiffReviewSnapshot({
1658
- cwd: this.snapshot.executionEnvironment.cwd,
1736
+ cwd: sessionSnapshot.executionEnvironment.cwd,
1659
1737
  source: args.source,
1660
1738
  signal: args.signal,
1661
- deps: createSessionDiffReviewSnapshotDeps(this.session),
1739
+ deps: createSessionDiffReviewSnapshotDeps(session),
1662
1740
  });
1663
- const ephemeral = await this.session.createEphemeralContext({
1741
+ const ephemeral = await session.createEphemeralContext({
1664
1742
  instructions: buildDiffReviewInstructions(snapshot),
1665
1743
  tools: ["bash", "view_image"],
1666
1744
  });
1667
1745
  const bridge = new DiffReviewBridge({
1668
1746
  snapshot,
1669
- contextWindow: this.snapshot.bootstrap.model.contextWindow,
1670
- submitThreadMessage: (options) => this.session.submitEphemeralThread({
1747
+ contextWindow: sessionSnapshot.bootstrap.model.contextWindow,
1748
+ submitThreadMessage: (options) => session.submitEphemeralThread({
1671
1749
  contextId: ephemeral.contextId,
1672
1750
  threadId: options.threadId,
1673
1751
  ...(options.forkFromThreadId ? { forkFromThreadId: options.forkFromThreadId } : {}),
@@ -1676,7 +1754,7 @@ export class SessionChatController {
1676
1754
  deps: this.deps,
1677
1755
  ...(this.diffToolLauncher ? { toolLauncher: this.diffToolLauncher } : {}),
1678
1756
  });
1679
- const unsubscribeEphemeral = this.session.onEphemeral((message) => {
1757
+ const unsubscribeEphemeral = session.onEphemeral((message) => {
1680
1758
  const event = message.event;
1681
1759
  if (event.type !== "ephemeral-agent.thread-update" ||
1682
1760
  event.contextId !== ephemeral.contextId) {
@@ -1699,18 +1777,18 @@ export class SessionChatController {
1699
1777
  }
1700
1778
  catch (error) {
1701
1779
  unsubscribeEphemeral();
1702
- await this.session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1780
+ await session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1703
1781
  await bridge.cancel("launch_failed").catch(() => undefined);
1704
1782
  await bridge.close().catch(() => undefined);
1705
1783
  throw error;
1706
1784
  }
1707
1785
  const result = bridge.result.finally(async () => {
1708
1786
  unsubscribeEphemeral();
1709
- await this.session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1787
+ await session.closeEphemeralContext(ephemeral.contextId).catch(() => undefined);
1710
1788
  });
1711
1789
  return { bridge, result };
1712
1790
  }
1713
- async handleReturnedDiffReview(review) {
1791
+ async handleReturnedDiffReview(review, session) {
1714
1792
  const model = {
1715
1793
  type: "user",
1716
1794
  text: review.review,
@@ -1721,10 +1799,12 @@ export class SessionChatController {
1721
1799
  this.renderedMessageIds.push(review.historyEntryId);
1722
1800
  }
1723
1801
  try {
1724
- const result = await this.session.record(formatDiffReviewUserMessage(review), {
1802
+ const result = await session.record(formatDiffReviewUserMessage(review), {
1725
1803
  historyEntryId: review.historyEntryId,
1726
1804
  });
1727
- this.syncRenderedHistory(result.snapshot);
1805
+ if (this.session === session) {
1806
+ this.syncRenderedHistory(result.snapshot);
1807
+ }
1728
1808
  }
1729
1809
  catch (error) {
1730
1810
  this.view.addSystemMessage(`failed to add diff review to session: ${error.message}`, "error");