mastracode 0.31.1-alpha.0 → 0.31.1-alpha.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # mastracode
2
2
 
3
+ ## 0.31.1-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed a stuck ask_user question box after the underlying run failed: the prompt is now dismissed automatically instead of accepting an answer that could never be delivered. ([#19444](https://github.com/mastra-ai/mastra/pull/19444))
8
+
9
+ - Updated dependencies [[`8b20926`](https://github.com/mastra-ai/mastra/commit/8b20926cd59e2ba3d66458e062fa0e6e2ada3e68), [`f9717e4`](https://github.com/mastra-ai/mastra/commit/f9717e4a381500042d088577347a787b0ec8caff), [`74faf8b`](https://github.com/mastra-ai/mastra/commit/74faf8bd9c1018f2492653c06b1e25fc8300e9e6), [`1fadac4`](https://github.com/mastra-ai/mastra/commit/1fadac44537caeefe81f9f775ae2f2f3d94e9069), [`970c032`](https://github.com/mastra-ai/mastra/commit/970c032502751ee5dd4d0b603331d9838cb538fc), [`792ec9a`](https://github.com/mastra-ai/mastra/commit/792ec9a0869bab8274cf5e0ed2840738737a1607), [`712b864`](https://github.com/mastra-ai/mastra/commit/712b864aa1ed12b14c54390ec17b69de163c37f7), [`8f7a5de`](https://github.com/mastra-ai/mastra/commit/8f7a5dedc246cdc938bb65516703cf9b27b03756), [`c0bec73`](https://github.com/mastra-ai/mastra/commit/c0bec732c93d1a22ae5e51ed66cf8cacca8bd6a6)]:
10
+ - @mastra/core@1.52.0-alpha.2
11
+ - @mastra/code-sdk@0.2.0-alpha.2
12
+ - @mastra/mcp@1.15.0-alpha.0
13
+
14
+ ## 0.31.1-alpha.1
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies:
19
+ - @mastra/core@1.51.1-alpha.1
20
+ - @mastra/code-sdk@0.1.1-alpha.1
21
+
3
22
  ## 0.31.1-alpha.0
4
23
 
5
24
  ### Patch Changes
@@ -6,9 +6,11 @@ import { loadSettings, MASTRA_GATEWAY_PROVIDER, resolveThreadActiveModelPackId,
6
6
  import { fetchLatestVersion, isNewerVersion, detectPackageManager, fetchChangelog, runUpdate, getInstallCommand } from '@mastra/code-sdk/utils/update-check';
7
7
  import { visibleWidth, Box, Text, Spacer, Input, Container, fuzzyFilter, getKeybindings, Markdown, ProcessTerminal, TUI, truncateToWidth, Editor, matchesKey, CombinedAutocompleteProvider, SelectList, wrapTextWithAnsi, SettingsList, parseKey } from '@earendil-works/pi-tui';
8
8
  import { processSlashCommand } from '@mastra/code-sdk/utils/slash-command-processor';
9
+ import { createGoalReminderSignal } from '@mastra/code-sdk/goal-signal';
9
10
  import { mastraBrand } from '@mastra/code-sdk/theme-palette';
10
11
  export { mastraBrand } from '@mastra/code-sdk/theme-palette';
11
12
  import chalk15 from 'chalk';
13
+ import { GoalManager, DEFAULT_MAX_TURNS } from '@mastra/code-sdk/goal-manager';
12
14
  import { resolveSTTModel, sttModelsForProvider, sttProviders, defaultModelForProvider, DEFAULT_STT_MODEL } from '@mastra/code-sdk/voice/stt-registry';
13
15
  import { Readable } from 'stream';
14
16
  import { DeepgramVoice } from '@mastra/voice-deepgram';
@@ -818,276 +820,6 @@ var ModelSelectorComponent = class extends Box {
818
820
  return this.searchInput;
819
821
  }
820
822
  };
821
- var DEFAULT_MAX_TURNS = 50;
822
- var THREAD_GOAL_KEY = "goal";
823
- var GoalManager = class {
824
- /** Synchronous in-memory view of the active objective record (source of truth is ThreadState). */
825
- record = null;
826
- /** Display-only active-timer accounting (not persisted to the objective record). */
827
- activeStartedAt = null;
828
- activeDurationMs = 0;
829
- persistGoalOnNextThreadCreate = false;
830
- // ---------------------------------------------------------------------------
831
- // Synchronous TUI surface
832
- // ---------------------------------------------------------------------------
833
- getGoal() {
834
- if (!this.record) return null;
835
- const { judgeModelId, maxTurns } = this.effectiveSettings(this.record);
836
- return {
837
- id: this.record.id,
838
- objective: this.record.objective,
839
- status: this.record.status,
840
- turnsUsed: this.record.runsUsed,
841
- maxTurns,
842
- judgeModelId,
843
- startedAt: new Date(this.record.startedAt).toISOString(),
844
- activeStartedAt: this.activeStartedAt ?? void 0,
845
- activeDurationMs: this.activeDurationMs
846
- };
847
- }
848
- isActive() {
849
- return this.record?.status === "active";
850
- }
851
- persistOnNextThreadCreate() {
852
- this.persistGoalOnNextThreadCreate = true;
853
- }
854
- consumePersistOnNextThreadCreate() {
855
- if (!this.persistGoalOnNextThreadCreate) return false;
856
- this.persistGoalOnNextThreadCreate = false;
857
- return true;
858
- }
859
- startActiveTimer() {
860
- if (this.record?.status === "active" && !this.activeStartedAt) {
861
- this.activeStartedAt = (/* @__PURE__ */ new Date()).toISOString();
862
- }
863
- }
864
- stopActiveTimer() {
865
- if (!this.activeStartedAt) return;
866
- const startedMs = Date.parse(this.activeStartedAt);
867
- if (Number.isFinite(startedMs)) {
868
- this.activeDurationMs += Math.max(0, Date.now() - startedMs);
869
- }
870
- this.activeStartedAt = null;
871
- }
872
- /** Reset active-timer accounting to zero (e.g. for an untriggered plan goal). */
873
- resetActiveTimer() {
874
- this.activeStartedAt = null;
875
- this.activeDurationMs = 0;
876
- }
877
- // ---------------------------------------------------------------------------
878
- // Objective lifecycle (ThreadState-backed via the agent)
879
- // ---------------------------------------------------------------------------
880
- /**
881
- * Set a new objective. Persists to ThreadState via `agent.setObjective` and
882
- * updates the in-memory view. Only the provided settings are persisted into
883
- * the record; unset ones fall back to the agent's `goal` config at read time.
884
- */
885
- async setGoal(state, objective, judgeModelId, maxTurns = DEFAULT_MAX_TURNS) {
886
- const threadId = state.session.thread.getId();
887
- const agent = this.getAgent(state);
888
- const now = Date.now();
889
- const id = randomUUID();
890
- if (agent && threadId) {
891
- const persisted = await agent.setObjective(objective, {
892
- id,
893
- threadId,
894
- resourceId: state.session.identity.getResourceId(),
895
- ...judgeModelId ? { judgeModelId } : {},
896
- maxRuns: maxTurns
897
- });
898
- this.record = persisted ? { ...persisted, id: persisted.id ?? id } : this.localRecord(objective, judgeModelId, maxTurns, now, id);
899
- } else {
900
- this.record = this.localRecord(objective, judgeModelId, maxTurns, now, id);
901
- }
902
- this.activeStartedAt = new Date(now).toISOString();
903
- this.activeDurationMs = 0;
904
- return this.getGoal();
905
- }
906
- /**
907
- * Update the judge model / max-runs defaults. Persists into the active record
908
- * (so the override is remembered in thread state) when a goal is set.
909
- */
910
- async updateJudgeDefaults(state, judgeModelId, maxTurns) {
911
- if (!this.record) return null;
912
- const threadId = state.session.thread.getId();
913
- const agent = this.getAgent(state);
914
- if (agent && threadId) {
915
- const updated = await agent.updateObjectiveOptions({
916
- threadId,
917
- ...judgeModelId ? { judgeModelId } : {},
918
- maxRuns: maxTurns
919
- });
920
- if (updated) this.record = { ...updated, id: this.record.id };
921
- } else {
922
- this.record = {
923
- ...this.record,
924
- ...judgeModelId ? { judgeModelId } : {},
925
- maxRuns: maxTurns,
926
- updatedAt: Date.now()
927
- };
928
- }
929
- return this.getGoal();
930
- }
931
- pause(reason) {
932
- if (this.record && this.record.status === "active") {
933
- this.stopActiveTimer();
934
- this.record = { ...this.record, status: "paused", pausedReason: reason, updatedAt: Date.now() };
935
- }
936
- return this.getGoal();
937
- }
938
- resume() {
939
- if (this.record && this.record.status === "paused") {
940
- this.record = { ...this.record, status: "active", pausedReason: void 0, updatedAt: Date.now() };
941
- this.startActiveTimer();
942
- }
943
- return this.getGoal();
944
- }
945
- markDone() {
946
- if (this.record) {
947
- this.stopActiveTimer();
948
- this.record = { ...this.record, status: "done", updatedAt: Date.now() };
949
- }
950
- }
951
- clear() {
952
- this.record = null;
953
- this.activeStartedAt = null;
954
- this.activeDurationMs = 0;
955
- this.persistGoalOnNextThreadCreate = false;
956
- }
957
- /**
958
- * Sync the latest objective record from ThreadState into the in-memory view.
959
- * Called from the `goal` stream-chunk handler after each evaluation.
960
- */
961
- applyEvaluation(update) {
962
- if (!this.record) return null;
963
- this.record = { ...this.record, runsUsed: update.runsUsed, status: update.status, updatedAt: Date.now() };
964
- if (update.status !== "active") this.stopActiveTimer();
965
- return this.getGoal();
966
- }
967
- // ---------------------------------------------------------------------------
968
- // Persistence
969
- // ---------------------------------------------------------------------------
970
- /**
971
- * Persist the active objective to ThreadState via the agent. The objective
972
- * record is the source of truth; the legacy thread-metadata key is cleared so
973
- * stale state from older sessions does not resurface.
974
- */
975
- async saveToThread(state) {
976
- const threadId = state.session.thread.getId();
977
- const agent = this.getAgent(state);
978
- try {
979
- if (agent && threadId) {
980
- if (this.record) {
981
- const updated = await agent.updateObjectiveOptions({
982
- threadId,
983
- status: this.record.status,
984
- ...this.record.pausedReason ? { pausedReason: this.record.pausedReason } : {},
985
- ...this.record.judgeModelId ? { judgeModelId: this.record.judgeModelId } : {},
986
- ...this.record.maxRuns !== void 0 ? { maxRuns: this.record.maxRuns } : {}
987
- });
988
- if (!updated) {
989
- const desiredStatus = this.record.status;
990
- await agent.setObjective(this.record.objective, {
991
- id: this.record.id,
992
- threadId,
993
- resourceId: state.session.identity.getResourceId(),
994
- ...this.record.judgeModelId ? { judgeModelId: this.record.judgeModelId } : {},
995
- ...this.record.maxRuns !== void 0 ? { maxRuns: this.record.maxRuns } : {}
996
- });
997
- if (desiredStatus !== "active") {
998
- await agent.updateObjectiveOptions({
999
- threadId,
1000
- status: desiredStatus,
1001
- ...this.record.pausedReason ? { pausedReason: this.record.pausedReason } : {}
1002
- });
1003
- }
1004
- }
1005
- } else {
1006
- await agent.clearObjective({ threadId });
1007
- }
1008
- }
1009
- await state.session.thread.setSetting({ key: THREAD_GOAL_KEY, value: void 0 });
1010
- } catch {
1011
- }
1012
- }
1013
- /**
1014
- * Load the objective from ThreadState (called on thread switch). Falls back to
1015
- * the legacy thread-metadata goal for threads created before this migration.
1016
- */
1017
- async loadFromThread(state) {
1018
- this.persistGoalOnNextThreadCreate = false;
1019
- this.activeStartedAt = null;
1020
- this.activeDurationMs = 0;
1021
- const threadId = state.session.thread.getId();
1022
- const agent = this.getAgent(state);
1023
- if (agent && threadId) {
1024
- try {
1025
- const record = await agent.getObjective({ threadId });
1026
- if (record) {
1027
- this.record = { ...record, id: record.id ?? randomUUID() };
1028
- return;
1029
- }
1030
- } catch {
1031
- }
1032
- }
1033
- this.record = null;
1034
- }
1035
- /**
1036
- * Legacy entry point retained for thread-switch call sites that only have the
1037
- * thread metadata available. Hydrates from a previously-persisted GoalState.
1038
- */
1039
- loadFromThreadMetadata(metadata) {
1040
- const saved = metadata?.[THREAD_GOAL_KEY];
1041
- this.persistGoalOnNextThreadCreate = false;
1042
- this.activeStartedAt = null;
1043
- this.activeDurationMs = 0;
1044
- if (saved && saved.objective && saved.status) {
1045
- this.record = {
1046
- objective: saved.objective,
1047
- status: saved.status,
1048
- runsUsed: saved.turnsUsed ?? 0,
1049
- maxRuns: saved.maxTurns ?? DEFAULT_MAX_TURNS,
1050
- judgeModelId: saved.judgeModelId ?? "",
1051
- startedAt: saved.startedAt ? Date.parse(saved.startedAt) || Date.now() : Date.now(),
1052
- updatedAt: Date.now(),
1053
- id: saved.id ?? randomUUID()
1054
- };
1055
- this.activeDurationMs = saved.activeDurationMs ?? 0;
1056
- } else {
1057
- this.record = null;
1058
- }
1059
- }
1060
- // ---------------------------------------------------------------------------
1061
- // Private
1062
- // ---------------------------------------------------------------------------
1063
- getAgent(state) {
1064
- try {
1065
- return state.controller.getCurrentAgent(state.session);
1066
- } catch {
1067
- return void 0;
1068
- }
1069
- }
1070
- /** Resolve effective judge model + max runs (record value → settings default). */
1071
- effectiveSettings(record) {
1072
- const settings = loadSettings();
1073
- return {
1074
- judgeModelId: record.judgeModelId ?? settings.models.goalJudgeModel ?? "",
1075
- maxTurns: record.maxRuns ?? settings.models.goalMaxTurns ?? DEFAULT_MAX_TURNS
1076
- };
1077
- }
1078
- localRecord(objective, judgeModelId, maxTurns, now, id) {
1079
- return {
1080
- objective,
1081
- status: "active",
1082
- runsUsed: 0,
1083
- maxRuns: maxTurns,
1084
- ...judgeModelId ? { judgeModelId } : {},
1085
- startedAt: now,
1086
- updatedAt: now,
1087
- id
1088
- };
1089
- }
1090
- };
1091
823
  function parseSizeValue(value, total) {
1092
824
  if (typeof value === "number") return value;
1093
825
  const match = value?.match(/^(\d+(?:\.\d+)?)%$/);
@@ -1527,18 +1259,6 @@ async function startGoal(ctx, objective, judgeModelId, maxTurns, options = {}) {
1527
1259
  ctx.showError(`Goal paused \u2014 failed to start: ${err instanceof Error ? err.message : String(err)}`);
1528
1260
  }
1529
1261
  }
1530
- function createGoalReminderSignal(goal) {
1531
- return {
1532
- type: "system-reminder",
1533
- contents: goal.objective,
1534
- attributes: { type: "goal" },
1535
- metadata: {
1536
- goalId: goal.id,
1537
- maxTurns: goal.maxTurns,
1538
- judgeModelId: goal.judgeModelId
1539
- }
1540
- };
1541
- }
1542
1262
 
1543
1263
  // src/tui/components/help-overlay.ts
1544
1264
  function getCommands(modes) {
@@ -3854,6 +3574,17 @@ var AskQuestionInlineComponent = class _AskQuestionInlineComponent extends Conta
3854
3574
  this.borderedBox.setCancelled();
3855
3575
  this.onCancel?.();
3856
3576
  }
3577
+ /**
3578
+ * Retract the question without invoking any submit/cancel callback. Used when
3579
+ * the underlying tool suspension was cancelled (the suspended run died, e.g.
3580
+ * its snapshot failed to persist), so an answer could never be delivered.
3581
+ */
3582
+ dismiss() {
3583
+ if (this.answered) return;
3584
+ this.answered = true;
3585
+ this.focused = false;
3586
+ this.borderedBox.setCancelled();
3587
+ }
3857
3588
  handleInput(data) {
3858
3589
  if (this.answered) return;
3859
3590
  if (this.selectList) {
@@ -16372,10 +16103,39 @@ function processNextInlineQuestion(state) {
16372
16103
  async function handleAskQuestion(ctx, toolCallId, question, options, selectionMode) {
16373
16104
  const { state } = ctx;
16374
16105
  return new Promise((resolve) => {
16106
+ let cancelled = false;
16107
+ let retract = () => {
16108
+ };
16109
+ const unsubscribeCancel = state.session.subscribe?.((event) => {
16110
+ if (event.type !== "tool_suspension_cancelled" || event.toolCallId !== toolCallId) return;
16111
+ if (cancelled) return;
16112
+ cancelled = true;
16113
+ unsubscribeCancel();
16114
+ retract();
16115
+ resolve();
16116
+ }) ?? (() => {
16117
+ });
16118
+ const finish = () => {
16119
+ unsubscribeCancel();
16120
+ resolve();
16121
+ };
16375
16122
  if (state.options.inlineQuestions) {
16376
16123
  const askUserComponent = state.pendingAskUserComponents?.get(toolCallId) ?? state.lastAskUserComponent;
16377
16124
  state.pendingAskUserComponents?.delete(toolCallId);
16125
+ let shownComponent = askUserComponent;
16126
+ retract = () => {
16127
+ shownComponent?.dismiss();
16128
+ if (state.activeInlineQuestion === shownComponent) {
16129
+ state.activeInlineQuestion = void 0;
16130
+ processNextInlineQuestion(state);
16131
+ }
16132
+ state.ui.requestRender();
16133
+ };
16378
16134
  const activate = () => {
16135
+ if (cancelled) {
16136
+ processNextInlineQuestion(state);
16137
+ return;
16138
+ }
16379
16139
  try {
16380
16140
  let questionComponent;
16381
16141
  if (askUserComponent) {
@@ -16388,19 +16148,19 @@ async function handleAskQuestion(ctx, toolCallId, question, options, selectionMo
16388
16148
  onSubmit: (answer) => {
16389
16149
  state.activeInlineQuestion = void 0;
16390
16150
  state.session.respondToToolSuspension({ toolCallId, resumeData: answer });
16391
- resolve();
16151
+ finish();
16392
16152
  processNextInlineQuestion(state);
16393
16153
  },
16394
16154
  onSubmitMulti: (answers) => {
16395
16155
  state.activeInlineQuestion = void 0;
16396
16156
  state.session.respondToToolSuspension({ toolCallId, resumeData: answers });
16397
- resolve();
16157
+ finish();
16398
16158
  processNextInlineQuestion(state);
16399
16159
  },
16400
16160
  onCancel: () => {
16401
16161
  state.activeInlineQuestion = void 0;
16402
16162
  state.session.respondToToolSuspension({ toolCallId, resumeData: "(skipped)" });
16403
- resolve();
16163
+ finish();
16404
16164
  processNextInlineQuestion(state);
16405
16165
  }
16406
16166
  });
@@ -16415,19 +16175,19 @@ async function handleAskQuestion(ctx, toolCallId, question, options, selectionMo
16415
16175
  onSubmit: (answer) => {
16416
16176
  state.activeInlineQuestion = void 0;
16417
16177
  state.session.respondToToolSuspension({ toolCallId, resumeData: answer });
16418
- resolve();
16178
+ finish();
16419
16179
  processNextInlineQuestion(state);
16420
16180
  },
16421
16181
  onSubmitMulti: (answers) => {
16422
16182
  state.activeInlineQuestion = void 0;
16423
16183
  state.session.respondToToolSuspension({ toolCallId, resumeData: answers });
16424
- resolve();
16184
+ finish();
16425
16185
  processNextInlineQuestion(state);
16426
16186
  },
16427
16187
  onCancel: () => {
16428
16188
  state.activeInlineQuestion = void 0;
16429
16189
  state.session.respondToToolSuspension({ toolCallId, resumeData: "(skipped)" });
16430
- resolve();
16190
+ finish();
16431
16191
  processNextInlineQuestion(state);
16432
16192
  }
16433
16193
  },
@@ -16435,6 +16195,7 @@ async function handleAskQuestion(ctx, toolCallId, question, options, selectionMo
16435
16195
  );
16436
16196
  state.chatContainer.addChild(questionComponent);
16437
16197
  }
16198
+ shownComponent = questionComponent;
16438
16199
  state.activeInlineQuestion = questionComponent;
16439
16200
  state.ui.requestRender();
16440
16201
  state.chatContainer.invalidate();
@@ -16442,7 +16203,7 @@ async function handleAskQuestion(ctx, toolCallId, question, options, selectionMo
16442
16203
  } catch {
16443
16204
  state.activeInlineQuestion = void 0;
16444
16205
  state.session.respondToToolSuspension({ toolCallId, resumeData: "(skipped)" });
16445
- resolve();
16206
+ finish();
16446
16207
  processNextInlineQuestion(state);
16447
16208
  }
16448
16209
  };
@@ -16452,6 +16213,10 @@ async function handleAskQuestion(ctx, toolCallId, question, options, selectionMo
16452
16213
  activate();
16453
16214
  }
16454
16215
  } else {
16216
+ retract = () => {
16217
+ state.ui.hideOverlay();
16218
+ state.ui.requestRender();
16219
+ };
16455
16220
  const dialog = new AskQuestionDialogComponent({
16456
16221
  question,
16457
16222
  options,
@@ -16461,17 +16226,17 @@ async function handleAskQuestion(ctx, toolCallId, question, options, selectionMo
16461
16226
  onSubmit: (answer) => {
16462
16227
  state.ui.hideOverlay();
16463
16228
  state.session.respondToToolSuspension({ toolCallId, resumeData: answer });
16464
- resolve();
16229
+ finish();
16465
16230
  },
16466
16231
  onSubmitMulti: (answers) => {
16467
16232
  state.ui.hideOverlay();
16468
16233
  state.session.respondToToolSuspension({ toolCallId, resumeData: answers });
16469
- resolve();
16234
+ finish();
16470
16235
  },
16471
16236
  onCancel: () => {
16472
16237
  state.ui.hideOverlay();
16473
16238
  state.session.respondToToolSuspension({ toolCallId, resumeData: "(skipped)" });
16474
- resolve();
16239
+ finish();
16475
16240
  }
16476
16241
  });
16477
16242
  showModalOverlay(state.ui, dialog, { widthPercent: 0.7 });
@@ -21791,5 +21556,5 @@ Would you like to update now?`;
21791
21556
  };
21792
21557
 
21793
21558
  export { AssistantMessageComponent, LoginDialogComponent, LoginSelectorComponent, MastraTUI, ModelSelectorComponent, OMProgressComponent, ToolExecutionComponentEnhanced, UserMessageComponent, applyThemeMode, createTUIState, detectTerminalTheme, formatOMStatus, getEditorTheme, getMarkdownTheme, getThemeMode, mastra, restoreTerminalForeground, theme };
21794
- //# sourceMappingURL=chunk-DOIRTZT6.js.map
21795
- //# sourceMappingURL=chunk-DOIRTZT6.js.map
21559
+ //# sourceMappingURL=chunk-EDKUI55Y.js.map
21560
+ //# sourceMappingURL=chunk-EDKUI55Y.js.map