tinker-agent 2.5.0 → 2.7.0

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 (36) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +30 -7
  3. package/package.json +1 -1
  4. package/src/agent/loop.ts +22 -0
  5. package/src/agent/runtime-session.ts +158 -0
  6. package/src/cli/main.ts +2 -0
  7. package/src/cli/public-config-contract.ts +1 -1
  8. package/src/cli/tui-runner.tsx +16 -1
  9. package/src/events/stdout-event-printer.ts +14 -0
  10. package/src/events/types.ts +9 -0
  11. package/src/memory/contracts.ts +46 -0
  12. package/src/memory/memory-coordinator.ts +445 -4
  13. package/src/memory/memory-create-tool.ts +117 -0
  14. package/src/memory/memory-delete-tool.ts +88 -0
  15. package/src/memory/memory-store.ts +239 -0
  16. package/src/memory/memory-update-tool.ts +142 -0
  17. package/src/observation/observation-builder.ts +70 -0
  18. package/src/session/session-clone-helpers.ts +249 -0
  19. package/src/session/session-compatibility-codec.ts +401 -0
  20. package/src/session/session-store-contracts.ts +304 -0
  21. package/src/session/session-store-filesystem.ts +245 -0
  22. package/src/session/session-store-record-codecs.ts +1064 -0
  23. package/src/session/session-store-value-codecs.ts +156 -0
  24. package/src/session/session-store.ts +234 -3023
  25. package/src/session/session-tool-result-codec.ts +594 -0
  26. package/src/tools/ask-user.ts +100 -0
  27. package/src/tools/grep.ts +1 -3
  28. package/src/tools/registry.ts +30 -0
  29. package/src/tools/types.ts +71 -0
  30. package/src/tui/app.tsx +35 -5
  31. package/src/tui/components/ask-user.tsx +61 -0
  32. package/src/tui/components/footer.tsx +14 -1
  33. package/src/tui/components/prompt-input.tsx +4 -0
  34. package/src/tui/components/resume-session-picker.tsx +118 -37
  35. package/src/tui/event-store.ts +57 -0
  36. package/src/tui/tui-session-controller.ts +8 -0
@@ -282,6 +282,33 @@ export function reduceTuiProjection(
282
282
  : "failed",
283
283
  }),
284
284
  );
285
+ case "tool.user_question.requested":
286
+ return updateActiveTurn(state, event, policy, (turn) =>
287
+ updateTurnItem(
288
+ turn,
289
+ toolCallRef(requireEventString(event.toolCallId, "AskUser toolCallId")),
290
+ (item) => ({ ...item, text: `AskUser -> ${event.data.question}` }),
291
+ ),
292
+ );
293
+ case "tool.user_question.resolved":
294
+ return updateActiveTurn(state, event, policy, (turn) =>
295
+ appendTurnItem(turn, {
296
+ id: `answer-${event.toolCallId}-${event.eventSequence}`,
297
+ label: "answer",
298
+ text:
299
+ event.data.outcome === "selected"
300
+ ? event.data.answer
301
+ : event.data.outcome === "dismissed"
302
+ ? "dismissed"
303
+ : "cancelled",
304
+ status:
305
+ event.data.outcome === "selected"
306
+ ? "ok"
307
+ : event.data.outcome === "dismissed"
308
+ ? "info"
309
+ : "cancelled",
310
+ }),
311
+ );
285
312
  case "bash.task.backgrounded":
286
313
  case "bash.task.stopping":
287
314
  case "bash.task.finished":
@@ -800,6 +827,12 @@ function toolCallSummary(input: { name: string; args: unknown }): string {
800
827
  if (input.name === "MemorySearch") {
801
828
  return `MemorySearch ${memorySearchDetail(input.args)}`.trim();
802
829
  }
830
+ if (input.name === "MemoryCreate") {
831
+ return "MemoryCreate";
832
+ }
833
+ if (input.name === "MemoryUpdate" || input.name === "MemoryDelete") {
834
+ return `${input.name} ${memoryMutationId(input.args) ?? ""}`.trim();
835
+ }
803
836
  if (input.name === "WebFetch") {
804
837
  return `WebFetch ${toolUrl(input.args) ?? ""}`.trim();
805
838
  }
@@ -816,6 +849,10 @@ function toolCallSummary(input: { name: string; args: unknown }): string {
816
849
  if (input.name === "Wait") {
817
850
  return `Wait ${toolSeconds(input.args) ?? ""}`.trim();
818
851
  }
852
+ if (input.name === "AskUser") {
853
+ const question = stringProperty(asRecord(input.args), "question");
854
+ return `AskUser${question === undefined ? "" : ` -> ${question}`}`;
855
+ }
819
856
  if (input.name === "Skill") {
820
857
  return `Skill ${stringProperty(asRecord(input.args), "name") ?? ""}`.trim();
821
858
  }
@@ -915,6 +952,12 @@ function toolRawResultSummary(name: string, args: unknown, raw: ToolRawResult):
915
952
  return base;
916
953
  }
917
954
  return raw.memory === null ? `${base} -> not found` : `${base} -> found`;
955
+ case "memory_create":
956
+ case "memory_update":
957
+ case "memory_delete":
958
+ return raw.ok
959
+ ? `${name} ${raw.memoryId} -> ${raw.status.replaceAll("_", " ")}`
960
+ : base;
918
961
  case "skill":
919
962
  if (!raw.ok) {
920
963
  return `${base} failed -> ${boundedToolError(raw.error)}`;
@@ -954,6 +997,8 @@ function toolRawResultSummary(name: string, args: unknown, raw: ToolRawResult):
954
997
  }
955
998
  case "wait":
956
999
  return raw.ok ? `${base} -> done` : base;
1000
+ case "ask_user":
1001
+ return base;
957
1002
  case "mcp":
958
1003
  case "generic":
959
1004
  return base;
@@ -1005,7 +1050,11 @@ function toolRawResultBashDetail(raw: ToolRawResult): Pick<TimelineItem, "bash">
1005
1050
  case "context_maintenance":
1006
1051
  case "memory_search":
1007
1052
  case "memory_get":
1053
+ case "memory_create":
1054
+ case "memory_update":
1055
+ case "memory_delete":
1008
1056
  case "wait":
1057
+ case "ask_user":
1009
1058
  case "skill":
1010
1059
  case "mcp":
1011
1060
  case "generic":
@@ -1047,7 +1096,11 @@ function toolRawResultDiff(
1047
1096
  case "context_maintenance":
1048
1097
  case "memory_search":
1049
1098
  case "memory_get":
1099
+ case "memory_create":
1100
+ case "memory_update":
1101
+ case "memory_delete":
1050
1102
  case "wait":
1103
+ case "ask_user":
1051
1104
  case "skill":
1052
1105
  case "mcp":
1053
1106
  case "generic":
@@ -1127,6 +1180,10 @@ function memorySearchDetail(args: unknown): string {
1127
1180
  return parts.join(" ");
1128
1181
  }
1129
1182
 
1183
+ function memoryMutationId(args: unknown): string | undefined {
1184
+ return stringProperty(asRecord(args), "id");
1185
+ }
1186
+
1130
1187
  function toolKeywords(args: unknown): string | undefined {
1131
1188
  const limit = 120;
1132
1189
  const value = asRecord(args).keywords;
@@ -5,6 +5,8 @@ import type {
5
5
  import type {
6
6
  ExecuteTurnInput,
7
7
  AcceptedTurn,
8
+ AskUserSnapshot,
9
+ AskUserResolution,
8
10
  BashGuardSnapshot,
9
11
  RuntimeSession,
10
12
  RuntimeSkillsSnapshot,
@@ -52,6 +54,9 @@ export type TuiSessionBinding = {
52
54
  subscribeBashGuard(listener: () => void): () => void;
53
55
  setYoloMode(enabled: boolean): void;
54
56
  resolveBashConfirmation(decision: "allow" | "deny"): Promise<void>;
57
+ askUser(): AskUserSnapshot;
58
+ subscribeAskUser(listener: () => void): () => void;
59
+ resolveAskUser(response: AskUserResolution): Promise<void>;
55
60
  };
56
61
 
57
62
  export type TuiSessionController = {
@@ -262,6 +267,9 @@ export function managedTuiBinding(input: {
262
267
  setYoloMode: (enabled) => input.runtimeSession.setYoloMode(enabled),
263
268
  resolveBashConfirmation: (decision) =>
264
269
  input.runtimeSession.resolveBashConfirmation(decision),
270
+ askUser: () => input.runtimeSession.askUser(),
271
+ subscribeAskUser: (listener) => input.runtimeSession.subscribeAskUser(listener),
272
+ resolveAskUser: (response) => input.runtimeSession.resolveAskUser(response),
265
273
  };
266
274
  }
267
275