@markusylisiurunen/tau 0.3.36 → 0.3.38

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 (127) hide show
  1. package/README.md +93 -17
  2. package/dist/core/agent/agent_runtime.js +22 -0
  3. package/dist/core/agent/agent_runtime.js.map +1 -1
  4. package/dist/core/auth/cli.js +10 -0
  5. package/dist/core/auth/cli.js.map +1 -1
  6. package/dist/core/auth/providers/openai_codex.js +36 -16
  7. package/dist/core/auth/providers/openai_codex.js.map +1 -1
  8. package/dist/core/cli.js +4 -1
  9. package/dist/core/cli.js.map +1 -1
  10. package/dist/core/config/builtin_themes.js +0 -93
  11. package/dist/core/config/builtin_themes.js.map +1 -1
  12. package/dist/core/config/client_tools.js +109 -0
  13. package/dist/core/config/client_tools.js.map +1 -0
  14. package/dist/core/config/content_loader.js +3 -1
  15. package/dist/core/config/content_loader.js.map +1 -1
  16. package/dist/core/config/index.js +1 -1
  17. package/dist/core/config/index.js.map +1 -1
  18. package/dist/core/config/schema.js +100 -1
  19. package/dist/core/config/schema.js.map +1 -1
  20. package/dist/core/history/cli.js +90 -0
  21. package/dist/core/history/cli.js.map +1 -0
  22. package/dist/core/history/config.js +11 -0
  23. package/dist/core/history/config.js.map +1 -0
  24. package/dist/core/history/history_manager.js +170 -0
  25. package/dist/core/history/history_manager.js.map +1 -0
  26. package/dist/core/history/local_history_store.js +407 -0
  27. package/dist/core/history/local_history_store.js.map +1 -0
  28. package/dist/core/history/remote_history_client.js +152 -0
  29. package/dist/core/history/remote_history_client.js.map +1 -0
  30. package/dist/core/history/replication.js +89 -0
  31. package/dist/core/history/replication.js.map +1 -0
  32. package/dist/core/history/setup.js +187 -0
  33. package/dist/core/history/setup.js.map +1 -0
  34. package/dist/core/history/transcript.js +39 -0
  35. package/dist/core/history/transcript.js.map +1 -0
  36. package/dist/core/history/types.js +2 -0
  37. package/dist/core/history/types.js.map +1 -0
  38. package/dist/core/models/tau_model_overrides.js +63 -4
  39. package/dist/core/models/tau_model_overrides.js.map +1 -1
  40. package/dist/core/personas.js +2 -1
  41. package/dist/core/personas.js.map +1 -1
  42. package/dist/core/runtime/chat_runtime.js +9 -0
  43. package/dist/core/runtime/chat_runtime.js.map +1 -1
  44. package/dist/core/static/code_mode/history/documentation.md +133 -0
  45. package/dist/core/static/code_mode/history/sandbox_runner.mjs +108 -0
  46. package/dist/core/static/code_mode/web/documentation.md +7 -7
  47. package/dist/core/subagents/agent_supervisor.js +1 -1
  48. package/dist/core/subagents/agent_supervisor.js.map +1 -1
  49. package/dist/core/subagents/registry.js +2 -1
  50. package/dist/core/subagents/registry.js.map +1 -1
  51. package/dist/core/subagents/types.js +2 -1
  52. package/dist/core/subagents/types.js.map +1 -1
  53. package/dist/core/telegram/adapter.js +30 -0
  54. package/dist/core/telegram/adapter.js.map +1 -1
  55. package/dist/core/telegram/session_manager.js +143 -26
  56. package/dist/core/telegram/session_manager.js.map +1 -1
  57. package/dist/core/tools/catalog.js +11 -2
  58. package/dist/core/tools/catalog.js.map +1 -1
  59. package/dist/core/tools/history.js +125 -0
  60. package/dist/core/tools/history.js.map +1 -0
  61. package/dist/core/tools/spawn_agent.js +1 -0
  62. package/dist/core/tools/spawn_agent.js.map +1 -1
  63. package/dist/core/tools/tool_names.js +2 -0
  64. package/dist/core/tools/tool_names.js.map +1 -1
  65. package/dist/core/tools/web.js +1 -1
  66. package/dist/core/tools/web.js.map +1 -1
  67. package/dist/core/utils/repository.js +44 -0
  68. package/dist/core/utils/repository.js.map +1 -0
  69. package/dist/core/utils/spawn_capture.js +58 -22
  70. package/dist/core/utils/spawn_capture.js.map +1 -1
  71. package/dist/core/utils/user_metadata.js +14 -0
  72. package/dist/core/utils/user_metadata.js.map +1 -1
  73. package/dist/core/version.js +1 -1
  74. package/dist/history/worker/index.js +989 -0
  75. package/dist/history/worker/index.js.map +1 -0
  76. package/dist/host/local_session_host.js +285 -179
  77. package/dist/host/local_session_host.js.map +1 -1
  78. package/dist/main.js +40 -8
  79. package/dist/main.js.map +1 -1
  80. package/dist/protocol/session_protocol.d.ts +4 -1
  81. package/dist/protocol/session_protocol.js +14 -6
  82. package/dist/protocol/session_protocol.js.map +1 -1
  83. package/dist/sdk/index.d.ts +1 -1
  84. package/dist/sdk/index.js.map +1 -1
  85. package/dist/sdk/local_client.js +5 -0
  86. package/dist/sdk/local_client.js.map +1 -1
  87. package/dist/sdk/session.js +22 -3
  88. package/dist/sdk/session.js.map +1 -1
  89. package/dist/store/session_snapshot_migrations.js +65 -1
  90. package/dist/store/session_snapshot_migrations.js.map +1 -1
  91. package/dist/transport/in_process_session_transport.js +3 -0
  92. package/dist/transport/in_process_session_transport.js.map +1 -1
  93. package/dist/transport/index.d.ts +1 -1
  94. package/dist/transport/index.js.map +1 -1
  95. package/dist/transport/session_protocol_transport_helpers.js +10 -0
  96. package/dist/transport/session_protocol_transport_helpers.js.map +1 -1
  97. package/dist/transport/session_transport.d.ts +2 -0
  98. package/dist/transport/stdio_session_transport.d.ts +3 -1
  99. package/dist/transport/stdio_session_transport.js +13 -6
  100. package/dist/transport/stdio_session_transport.js.map +1 -1
  101. package/dist/transport/websocket_session_transport.d.ts +3 -1
  102. package/dist/transport/websocket_session_transport.js +11 -2
  103. package/dist/transport/websocket_session_transport.js.map +1 -1
  104. package/dist/tui/chat_controller/diff_review_service.js +12 -11
  105. package/dist/tui/chat_controller/diff_review_service.js.map +1 -1
  106. package/dist/tui/chat_controller/diff_review_user_message.js +1 -0
  107. package/dist/tui/chat_controller/diff_review_user_message.js.map +1 -1
  108. package/dist/tui/chat_controller/history_message_model.js +4 -1
  109. package/dist/tui/chat_controller/history_message_model.js.map +1 -1
  110. package/dist/tui/chat_view.js +0 -11
  111. package/dist/tui/chat_view.js.map +1 -1
  112. package/dist/tui/command_client_tools.js +80 -0
  113. package/dist/tui/command_client_tools.js.map +1 -0
  114. package/dist/tui/session_chat_app.js +26 -6
  115. package/dist/tui/session_chat_app.js.map +1 -1
  116. package/dist/tui/session_chat_controller.js +68 -71
  117. package/dist/tui/session_chat_controller.js.map +1 -1
  118. package/dist/tui/session_creation_attributes.js +66 -0
  119. package/dist/tui/session_creation_attributes.js.map +1 -0
  120. package/dist/tui/ui/theme/palette.js +0 -3
  121. package/dist/tui/ui/theme/palette.js.map +1 -1
  122. package/dist/tui/ui/theme/theme.js.map +1 -1
  123. package/dist/tui/ui/user_message.js +4 -10
  124. package/dist/tui/ui/user_message.js.map +1 -1
  125. package/package.json +1 -1
  126. package/dist/tui/memory_mode.js +0 -24
  127. package/dist/tui/memory_mode.js.map +0 -1
@@ -1,4 +1,3 @@
1
- import { randomUUID } from "node:crypto";
2
1
  import { dirname } from "node:path/posix";
3
2
  import { createCommandRegistry, } from "../core/commands/index.js";
4
3
  import { getGoogleApiKey } from "../core/config/index.js";
@@ -26,7 +25,6 @@ import { formatDurationMs, formatSessionCost } from "./chat_controller/status_fo
26
25
  import { copyTextToClipboard } from "./clipboard.js";
27
26
  import { DOUBLE_PRESS_WINDOW_MS } from "./constants.js";
28
27
  import { cleanupListenTempFile, createListenTempFilePath, getSpeechToTextApiKey, getSpeechToTextApiKeyErrorMessage, LISTEN_RECORDING_MAX_DURATION_MS, LISTEN_RECORDING_MIN_BYTES, readListenAudio, startListenAudioCapture, transcribeListenAudio, } from "./listen_capture.js";
29
- import { formatDefaultMemoryModeFilePath, formatMemoryModeUserMessage } from "./memory_mode.js";
30
28
  import { createSdkDiffSnapshotDeps, createSdkToolExecutionBackend, } from "./session_tool_execution_backend.js";
31
29
  import { runSpeechPlaybackTask } from "./speech_playback.js";
32
30
  const CAFFEINATE_COMMAND = "/usr/bin/caffeinate";
@@ -35,6 +33,7 @@ export class SessionChatController {
35
33
  session;
36
34
  createSession;
37
35
  targetLabel;
36
+ configuredClientToolNames;
38
37
  config;
39
38
  defaultDiffTool;
40
39
  diffToolLauncher;
@@ -47,7 +46,6 @@ export class SessionChatController {
47
46
  snapshot;
48
47
  renderedMessageIds = [];
49
48
  hiddenHistoryEntryIds = new Set();
50
- clientRenderedUserMessages = new Map();
51
49
  observedSessionRevision;
52
50
  eventUnsubscribe;
53
51
  pendingUserMessagesUnsubscribe;
@@ -62,7 +60,6 @@ export class SessionChatController {
62
60
  sessionReplacementInProgress = false;
63
61
  isBashMode = false;
64
62
  isBashIncognito = false;
65
- isMemoryMode = false;
66
63
  showThinking = false;
67
64
  compactToolUi = true;
68
65
  commandHint;
@@ -85,6 +82,7 @@ export class SessionChatController {
85
82
  this.createSession = options.createSession;
86
83
  this.snapshot = options.snapshot;
87
84
  this.targetLabel = options.targetLabel;
85
+ this.configuredClientToolNames = options.configuredClientToolNames ?? [];
88
86
  this.config = options.config ?? {};
89
87
  this.defaultDiffTool = options.defaultDiffTool;
90
88
  this.diffToolLauncher = options.diffToolLauncher;
@@ -269,20 +267,7 @@ export class SessionChatController {
269
267
  }
270
268
  return;
271
269
  }
272
- if (this.isSingleLineInput(text) && trimmed.startsWith("#")) {
273
- const request = trimmed.slice(1).trim();
274
- if (!request) {
275
- this.view.addSystemMessage("memory mode request was empty.", "warn");
276
- return;
277
- }
278
- const agentsFilePath = formatDefaultMemoryModeFilePath(this.snapshot.executionEnvironment.cwd);
279
- await this.submitUserText(request, {
280
- textForModel: formatMemoryModeUserMessage(agentsFilePath, request),
281
- kind: "memory",
282
- });
283
- return;
284
- }
285
- await this.submitUserText(trimmed);
270
+ await this.runSessionTurn(() => this.session.submit(trimmed));
286
271
  }
287
272
  async onUserInput(text) {
288
273
  await this.handleSubmit(text);
@@ -302,21 +287,17 @@ export class SessionChatController {
302
287
  handleEditorChange(text) {
303
288
  const wasBash = this.isBashMode;
304
289
  const wasBashIncognito = this.isBashIncognito;
305
- const wasMemory = this.isMemoryMode;
306
290
  const previousCommandHint = this.commandHint;
307
291
  if (text.trim().length > 0) {
308
292
  this.lastEmptySubmitAt = undefined;
309
293
  }
310
294
  const trimmed = text.trimStart();
311
- const isSingleLine = this.isSingleLineInput(text);
312
295
  const isIncognito = trimmed.startsWith("!!");
313
296
  this.isBashIncognito = isIncognito;
314
297
  this.isBashMode = trimmed.startsWith("!") && !isIncognito;
315
- this.isMemoryMode = isSingleLine && trimmed.startsWith("#");
316
298
  this.commandHint = this.getCommandHintForInput(text);
317
299
  if (wasBash !== this.isBashMode ||
318
300
  wasBashIncognito !== this.isBashIncognito ||
319
- wasMemory !== this.isMemoryMode ||
320
301
  previousCommandHint !== this.commandHint) {
321
302
  this.refreshStatus();
322
303
  }
@@ -357,6 +338,10 @@ export class SessionChatController {
357
338
  if (this.snapshot.catalog.skills.length > 0) {
358
339
  parts.push(`${this.snapshot.catalog.skills.length} skills`);
359
340
  }
341
+ if (this.configuredClientToolNames.length > 0) {
342
+ const count = this.configuredClientToolNames.length;
343
+ parts.push(`${count} client tool${count === 1 ? "" : "s"}`);
344
+ }
360
345
  return parts.join(" · ");
361
346
  }
362
347
  buildStartupIntroBody() {
@@ -364,7 +349,6 @@ export class SessionChatController {
364
349
  "type `/help` for commands and keybindings",
365
350
  "mention files with `@`, agents and skills with `@@`",
366
351
  "run bash commands with `!` or `!!`",
367
- "use `#` to update AGENTS.md",
368
352
  ];
369
353
  if (this.snapshot.catalog.skills.length > 0) {
370
354
  lines.push("", "skills:");
@@ -380,21 +364,15 @@ export class SessionChatController {
380
364
  lines.push(` ${agentsFile}`);
381
365
  }
382
366
  }
367
+ if (this.configuredClientToolNames.length > 0) {
368
+ lines.push("", "client tools:");
369
+ for (const clientToolName of this.configuredClientToolNames) {
370
+ lines.push(` ${clientToolName}`);
371
+ }
372
+ }
383
373
  lines.push("", this.formatSessionIdentityText());
384
374
  return lines;
385
375
  }
386
- async submitUserText(text, options = {}) {
387
- const historyEntryId = `session-user-${randomUUID()}`;
388
- const model = {
389
- type: "user",
390
- text,
391
- ...(options.kind ? { kind: options.kind } : {}),
392
- };
393
- this.clientRenderedUserMessages.set(historyEntryId, model);
394
- this.view.addMessage(model, historyEntryId);
395
- this.renderedMessageIds.push(historyEntryId);
396
- await this.runSessionTurn(() => this.session.submit(options.textForModel ?? text, { historyEntryId }));
397
- }
398
376
  async retryTurn() {
399
377
  await this.runSessionTurn(() => this.session.retry());
400
378
  }
@@ -492,7 +470,7 @@ export class SessionChatController {
492
470
  return;
493
471
  }
494
472
  if (!this.isSessionOperationActive()) {
495
- await this.submitUserText(trimmed);
473
+ await this.runSessionTurn(() => this.session.submit(trimmed));
496
474
  return;
497
475
  }
498
476
  if (this.isBlockingSessionOperationActive()) {
@@ -502,9 +480,7 @@ export class SessionChatController {
502
480
  this.submitSteeringText(trimmed);
503
481
  }
504
482
  submitQueuedText(text) {
505
- void this.session
506
- .queue(text, { historyEntryId: `session-queue-${randomUUID()}` })
507
- .catch((error) => {
483
+ void this.session.queue(text).catch((error) => {
508
484
  if (!this.isPendingMessageCancellation(error)) {
509
485
  this.view.addSystemMessage(`queueing failed: ${formatSessionError(error)}`, "error");
510
486
  }
@@ -833,6 +809,12 @@ export class SessionChatController {
833
809
  }
834
810
  const createInput = {
835
811
  executionEnvironment: this.createExecutionEnvironmentInputFromSnapshot(),
812
+ attributes: {
813
+ source: "tui",
814
+ ...(this.snapshot.attributes.repository
815
+ ? { repository: this.snapshot.attributes.repository }
816
+ : {}),
817
+ },
836
818
  personaId: this.snapshot.settings.personaId,
837
819
  ...(this.snapshot.settings.reasoning !== undefined
838
820
  ? { reasoning: this.snapshot.settings.reasoning }
@@ -1052,9 +1034,17 @@ export class SessionChatController {
1052
1034
  this.snapshot = snapshot;
1053
1035
  this.observedSessionRevision = Math.max(this.observedSessionRevision, snapshot.revision);
1054
1036
  this.assistantMessages = [];
1055
- const messages = getTimelineMessages(snapshot);
1056
- for (const entry of messages) {
1057
- this.renderProtocolMessage(entry);
1037
+ for (const item of getRenderableTimelineItems(snapshot)) {
1038
+ if (item.type === "notice") {
1039
+ this.renderedMessageIds.push(this.view.addMessage({
1040
+ type: "system",
1041
+ text: item.text,
1042
+ kind: item.severity === "info" ? "muted" : item.severity,
1043
+ }, item.id));
1044
+ }
1045
+ else {
1046
+ this.renderProtocolMessage(item.message);
1047
+ }
1058
1048
  }
1059
1049
  this.syncSnapshotToolAndAgentUi(snapshot);
1060
1050
  }
@@ -1079,38 +1069,41 @@ export class SessionChatController {
1079
1069
  syncRenderedHistory(snapshot) {
1080
1070
  this.snapshot = snapshot;
1081
1071
  this.observedSessionRevision = Math.max(this.observedSessionRevision, snapshot.revision);
1082
- const messages = getTimelineMessages(snapshot);
1083
- const snapshotIds = new Set(messages.map((entry) => entry.id));
1072
+ const items = getRenderableTimelineItems(snapshot);
1073
+ const snapshotIds = new Set(items.map((item) => item.id));
1084
1074
  const staleIds = this.renderedMessageIds.filter((id) => !snapshotIds.has(id));
1085
1075
  if (staleIds.length > 0) {
1086
1076
  this.view.removeMessages(staleIds);
1087
- for (const id of staleIds) {
1088
- this.clientRenderedUserMessages.delete(id);
1089
- }
1090
1077
  }
1091
1078
  const renderedIds = new Set(this.renderedMessageIds);
1092
1079
  this.renderedMessageIds.splice(0, this.renderedMessageIds.length, ...this.renderedMessageIds.filter((id) => snapshotIds.has(id)));
1093
- for (const entry of messages) {
1094
- if (this.hiddenHistoryEntryIds.has(entry.id)) {
1095
- if (!renderedIds.has(entry.id)) {
1096
- this.renderedMessageIds.push(entry.id);
1080
+ for (const item of items) {
1081
+ if (item.type === "message" && this.hiddenHistoryEntryIds.has(item.id)) {
1082
+ if (!renderedIds.has(item.id)) {
1083
+ this.renderedMessageIds.push(item.id);
1097
1084
  }
1098
1085
  continue;
1099
1086
  }
1100
- const model = this.clientRenderedUserMessages.get(entry.id) ?? this.buildProtocolMessageModel(entry);
1087
+ const model = item.type === "notice"
1088
+ ? {
1089
+ type: "system",
1090
+ text: item.text,
1091
+ kind: item.severity === "info" ? "muted" : item.severity,
1092
+ }
1093
+ : this.buildProtocolMessageModel(item.message);
1101
1094
  if (!model) {
1102
1095
  continue;
1103
1096
  }
1104
- if (renderedIds.has(entry.id)) {
1097
+ if (renderedIds.has(item.id)) {
1105
1098
  if (model.type === "assistant") {
1106
- this.view.updateAssistantMessage(entry.id, model);
1099
+ this.view.updateAssistantMessage(item.id, model);
1107
1100
  }
1108
1101
  else {
1109
- this.view.updateMessage(entry.id, model);
1102
+ this.view.updateMessage(item.id, model);
1110
1103
  }
1111
1104
  }
1112
1105
  else {
1113
- this.renderedMessageIds.push(this.view.addMessage(model, entry.id));
1106
+ this.renderedMessageIds.push(this.view.addMessage(model, item.id));
1114
1107
  }
1115
1108
  }
1116
1109
  this.assistantMessages = this.collectAssistantMessages(snapshot);
@@ -1250,7 +1243,6 @@ export class SessionChatController {
1250
1243
  }
1251
1244
  startLocalUiSession() {
1252
1245
  this.hiddenHistoryEntryIds.clear();
1253
- this.clientRenderedUserMessages.clear();
1254
1246
  this.renderedMessageIds.splice(0);
1255
1247
  this.view.addMessage({ type: "session_divider", label: "new session" });
1256
1248
  }
@@ -1548,8 +1540,6 @@ export class SessionChatController {
1548
1540
  return "bash_incognito";
1549
1541
  if (this.isBashMode)
1550
1542
  return "bash";
1551
- if (this.isMemoryMode)
1552
- return "memory";
1553
1543
  return "normal";
1554
1544
  }
1555
1545
  getSessionOperationStatusHint() {
@@ -1795,15 +1785,6 @@ export class SessionChatController {
1795
1785
  return { bridge, result };
1796
1786
  }
1797
1787
  async handleReturnedDiffReview(review, session) {
1798
- const model = {
1799
- type: "user",
1800
- text: review.review,
1801
- kind: "review",
1802
- };
1803
- this.clientRenderedUserMessages.set(review.historyEntryId, model);
1804
- if (!this.renderedMessageIds.includes(review.historyEntryId)) {
1805
- this.renderedMessageIds.push(review.historyEntryId);
1806
- }
1807
1788
  try {
1808
1789
  const result = await session.record(formatDiffReviewUserMessage(review), {
1809
1790
  historyEntryId: review.historyEntryId,
@@ -1813,7 +1794,13 @@ export class SessionChatController {
1813
1794
  }
1814
1795
  }
1815
1796
  catch (error) {
1816
- this.view.addSystemMessage(`failed to add diff review to session: ${error.message}`, "error");
1797
+ const reviewWasCommitted = this.session === session &&
1798
+ this.snapshot.messages.some((entry) => entry.id === review.historyEntryId &&
1799
+ entry.state === "committed" &&
1800
+ entry.message.role === "user");
1801
+ if (!reviewWasCommitted) {
1802
+ throw error;
1803
+ }
1817
1804
  }
1818
1805
  }
1819
1806
  startRewindFlow() {
@@ -1923,14 +1910,24 @@ function formatSessionError(error) {
1923
1910
  : undefined;
1924
1911
  return cause && cause !== message ? `${message}: ${cause}` : message;
1925
1912
  }
1926
- function getTimelineMessages(snapshot) {
1913
+ function getRenderableTimelineItems(snapshot) {
1927
1914
  const messagesById = new Map(snapshot.messages.map((message) => [message.id, message]));
1928
1915
  return snapshot.timeline.flatMap((item) => {
1916
+ if (item.type === "notice") {
1917
+ return [
1918
+ {
1919
+ type: "notice",
1920
+ id: item.id,
1921
+ severity: item.notice.severity,
1922
+ text: item.notice.text,
1923
+ },
1924
+ ];
1925
+ }
1929
1926
  if (item.type !== "message") {
1930
1927
  return [];
1931
1928
  }
1932
1929
  const message = messagesById.get(item.messageId);
1933
- return message ? [message] : [];
1930
+ return message ? [{ type: "message", id: message.id, message }] : [];
1934
1931
  });
1935
1932
  }
1936
1933
  function isMessageInTimeline(snapshot, messageId) {