@geminixiang/mikan 1.0.0-beta.88 → 1.0.0-beta.89

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 (249) hide show
  1. package/CHANGELOG.md +33 -1370
  2. package/README.md +2 -2
  3. package/dist/adapters/commands/session-view.d.ts.map +1 -1
  4. package/dist/adapters/commands/session-view.js +4 -4
  5. package/dist/adapters/commands/session-view.js.map +1 -1
  6. package/dist/adapters/discord/bot.d.ts +4 -1
  7. package/dist/adapters/discord/bot.d.ts.map +1 -1
  8. package/dist/adapters/discord/bot.js +6 -3
  9. package/dist/adapters/discord/bot.js.map +1 -1
  10. package/dist/adapters/discord/context.d.ts.map +1 -1
  11. package/dist/adapters/discord/context.js +3 -1
  12. package/dist/adapters/discord/context.js.map +1 -1
  13. package/dist/adapters/discord/types.d.ts +1 -0
  14. package/dist/adapters/discord/types.d.ts.map +1 -1
  15. package/dist/adapters/discord/types.js.map +1 -1
  16. package/dist/adapters/github/activity.d.ts.map +1 -1
  17. package/dist/adapters/github/activity.js +7 -13
  18. package/dist/adapters/github/activity.js.map +1 -1
  19. package/dist/adapters/github/bot.d.ts +4 -1
  20. package/dist/adapters/github/bot.d.ts.map +1 -1
  21. package/dist/adapters/github/bot.js +3 -3
  22. package/dist/adapters/github/bot.js.map +1 -1
  23. package/dist/adapters/github/context.d.ts.map +1 -1
  24. package/dist/adapters/github/context.js +3 -1
  25. package/dist/adapters/github/context.js.map +1 -1
  26. package/dist/adapters/github/types.d.ts +0 -3
  27. package/dist/adapters/github/types.d.ts.map +1 -1
  28. package/dist/adapters/github/types.js.map +1 -1
  29. package/dist/adapters/intake.d.ts.map +1 -1
  30. package/dist/adapters/intake.js +12 -2
  31. package/dist/adapters/intake.js.map +1 -1
  32. package/dist/adapters/shared.d.ts +2 -1
  33. package/dist/adapters/shared.d.ts.map +1 -1
  34. package/dist/adapters/shared.js +7 -2
  35. package/dist/adapters/shared.js.map +1 -1
  36. package/dist/adapters/slack/assistant.d.ts +2 -4
  37. package/dist/adapters/slack/assistant.d.ts.map +1 -1
  38. package/dist/adapters/slack/assistant.js +10 -16
  39. package/dist/adapters/slack/assistant.js.map +1 -1
  40. package/dist/adapters/slack/bot.d.ts +5 -1
  41. package/dist/adapters/slack/bot.d.ts.map +1 -1
  42. package/dist/adapters/slack/bot.js +15 -11
  43. package/dist/adapters/slack/bot.js.map +1 -1
  44. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  45. package/dist/adapters/slack/response-lifecycle.js +1 -1
  46. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  47. package/dist/adapters/slack/task-status.d.ts.map +1 -1
  48. package/dist/adapters/slack/task-status.js +1 -2
  49. package/dist/adapters/slack/task-status.js.map +1 -1
  50. package/dist/adapters/telegram/bot.d.ts +4 -1
  51. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  52. package/dist/adapters/telegram/bot.js +3 -3
  53. package/dist/adapters/telegram/bot.js.map +1 -1
  54. package/dist/adapters/telegram/context.d.ts.map +1 -1
  55. package/dist/adapters/telegram/context.js +3 -1
  56. package/dist/adapters/telegram/context.js.map +1 -1
  57. package/dist/adapters/types.d.ts +3 -1
  58. package/dist/adapters/types.d.ts.map +1 -1
  59. package/dist/adapters/types.js.map +1 -1
  60. package/dist/adapters/web/admin/client-assets.js +1 -1
  61. package/dist/adapters/web/admin/client-assets.js.map +1 -1
  62. package/dist/adapters/web/admin/portal.d.ts +0 -1
  63. package/dist/adapters/web/admin/portal.d.ts.map +1 -1
  64. package/dist/adapters/web/admin/portal.js +26 -42
  65. package/dist/adapters/web/admin/portal.js.map +1 -1
  66. package/dist/adapters/web/admin/types.d.ts +0 -2
  67. package/dist/adapters/web/admin/types.d.ts.map +1 -1
  68. package/dist/adapters/web/admin/types.js.map +1 -1
  69. package/dist/adapters/web/login/portal.d.ts.map +1 -1
  70. package/dist/adapters/web/login/portal.js +0 -8
  71. package/dist/adapters/web/login/portal.js.map +1 -1
  72. package/dist/adapters/web/server.d.ts.map +1 -1
  73. package/dist/adapters/web/server.js +0 -1
  74. package/dist/adapters/web/server.js.map +1 -1
  75. package/dist/adapters/web/session-view/portal.d.ts +1 -2
  76. package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
  77. package/dist/adapters/web/session-view/portal.js +38 -328
  78. package/dist/adapters/web/session-view/portal.js.map +1 -1
  79. package/dist/adapters/web/session-view/types.d.ts +4 -6
  80. package/dist/adapters/web/session-view/types.d.ts.map +1 -1
  81. package/dist/adapters/web/session-view/types.js.map +1 -1
  82. package/dist/env-manifest.d.ts +0 -4
  83. package/dist/env-manifest.d.ts.map +1 -1
  84. package/dist/env-manifest.js +5 -8
  85. package/dist/env-manifest.js.map +1 -1
  86. package/dist/events/index.d.ts +2 -9
  87. package/dist/events/index.d.ts.map +1 -1
  88. package/dist/events/index.js +0 -1
  89. package/dist/events/index.js.map +1 -1
  90. package/dist/events/scheduler.d.ts +0 -1
  91. package/dist/events/scheduler.d.ts.map +1 -1
  92. package/dist/events/scheduler.js +2 -7
  93. package/dist/events/scheduler.js.map +1 -1
  94. package/dist/harness/execution-env.d.ts +1 -1
  95. package/dist/harness/execution-env.d.ts.map +1 -1
  96. package/dist/harness/execution-env.js +32 -32
  97. package/dist/harness/execution-env.js.map +1 -1
  98. package/dist/harness/index.d.ts +2 -3
  99. package/dist/harness/index.d.ts.map +1 -1
  100. package/dist/harness/index.js +0 -1
  101. package/dist/harness/index.js.map +1 -1
  102. package/dist/harness/mcp-result.d.ts +4 -3
  103. package/dist/harness/mcp-result.d.ts.map +1 -1
  104. package/dist/harness/mcp-result.js +27 -13
  105. package/dist/harness/mcp-result.js.map +1 -1
  106. package/dist/harness/mcp.d.ts.map +1 -1
  107. package/dist/harness/mcp.js +2 -4
  108. package/dist/harness/mcp.js.map +1 -1
  109. package/dist/harness/presenter.d.ts.map +1 -1
  110. package/dist/harness/presenter.js +20 -25
  111. package/dist/harness/presenter.js.map +1 -1
  112. package/dist/harness/prompt.d.ts +0 -1
  113. package/dist/harness/prompt.d.ts.map +1 -1
  114. package/dist/harness/prompt.js +3 -32
  115. package/dist/harness/prompt.js.map +1 -1
  116. package/dist/harness/run-events.d.ts.map +1 -1
  117. package/dist/harness/run-events.js +4 -12
  118. package/dist/harness/run-events.js.map +1 -1
  119. package/dist/harness/runner.d.ts.map +1 -1
  120. package/dist/harness/runner.js +35 -38
  121. package/dist/harness/runner.js.map +1 -1
  122. package/dist/harness/session.d.ts +36 -40
  123. package/dist/harness/session.d.ts.map +1 -1
  124. package/dist/harness/session.js +371 -473
  125. package/dist/harness/session.js.map +1 -1
  126. package/dist/harness/subagent.d.ts +5 -5
  127. package/dist/harness/subagent.d.ts.map +1 -1
  128. package/dist/harness/subagent.js +40 -45
  129. package/dist/harness/subagent.js.map +1 -1
  130. package/dist/harness/tools/codemode.d.ts.map +1 -1
  131. package/dist/harness/tools/codemode.js +32 -17
  132. package/dist/harness/tools/codemode.js.map +1 -1
  133. package/dist/harness/tools/history.d.ts +20 -0
  134. package/dist/harness/tools/history.d.ts.map +1 -0
  135. package/dist/harness/tools/history.js +293 -0
  136. package/dist/harness/tools/history.js.map +1 -0
  137. package/dist/harness/tools/pi-tools.d.ts +1 -1
  138. package/dist/harness/tools/pi-tools.d.ts.map +1 -1
  139. package/dist/harness/tools/pi-tools.js +47 -21
  140. package/dist/harness/tools/pi-tools.js.map +1 -1
  141. package/dist/harness/tools/secret-redaction.d.ts.map +1 -1
  142. package/dist/harness/tools/secret-redaction.js +46 -2
  143. package/dist/harness/tools/secret-redaction.js.map +1 -1
  144. package/dist/harness/tools/tool-search.d.ts +0 -2
  145. package/dist/harness/tools/tool-search.d.ts.map +1 -1
  146. package/dist/harness/tools/tool-search.js +3 -12
  147. package/dist/harness/tools/tool-search.js.map +1 -1
  148. package/dist/harness/types.d.ts +58 -16
  149. package/dist/harness/types.d.ts.map +1 -1
  150. package/dist/harness/types.js.map +1 -1
  151. package/dist/index.d.ts +3 -7
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +0 -3
  154. package/dist/index.js.map +1 -1
  155. package/dist/log.d.ts +0 -3
  156. package/dist/log.d.ts.map +1 -1
  157. package/dist/log.js +0 -15
  158. package/dist/log.js.map +1 -1
  159. package/dist/main.js +2 -2
  160. package/dist/main.js.map +1 -1
  161. package/dist/memory-capture/index.js +0 -1
  162. package/dist/memory-capture/index.js.map +1 -1
  163. package/dist/migrations/index.d.ts.map +1 -1
  164. package/dist/migrations/index.js +2 -0
  165. package/dist/migrations/index.js.map +1 -1
  166. package/dist/migrations/session-files.d.ts +3 -2
  167. package/dist/migrations/session-files.d.ts.map +1 -1
  168. package/dist/migrations/session-files.js.map +1 -1
  169. package/dist/migrations/session-v4.d.ts +77 -0
  170. package/dist/migrations/session-v4.d.ts.map +1 -0
  171. package/dist/migrations/session-v4.js +177 -0
  172. package/dist/migrations/session-v4.js.map +1 -0
  173. package/dist/migrations/sessions-sqlite.d.ts +3 -0
  174. package/dist/migrations/sessions-sqlite.d.ts.map +1 -0
  175. package/dist/migrations/sessions-sqlite.js +215 -0
  176. package/dist/migrations/sessions-sqlite.js.map +1 -0
  177. package/dist/migrations/sessions-v3.d.ts +2 -2
  178. package/dist/migrations/sessions-v3.d.ts.map +1 -1
  179. package/dist/migrations/sessions-v3.js +8 -19
  180. package/dist/migrations/sessions-v3.js.map +1 -1
  181. package/dist/migrations/types.d.ts +0 -5
  182. package/dist/migrations/types.d.ts.map +1 -1
  183. package/dist/migrations/types.js.map +1 -1
  184. package/dist/observability/sentry.d.ts +2 -9
  185. package/dist/observability/sentry.d.ts.map +1 -1
  186. package/dist/observability/sentry.js +12 -64
  187. package/dist/observability/sentry.js.map +1 -1
  188. package/dist/observability/types.d.ts +0 -16
  189. package/dist/observability/types.d.ts.map +1 -1
  190. package/dist/observability/types.js.map +1 -1
  191. package/dist/office/index.d.ts +1 -4
  192. package/dist/office/index.d.ts.map +1 -1
  193. package/dist/office/index.js +2 -14
  194. package/dist/office/index.js.map +1 -1
  195. package/dist/office/projection.d.ts.map +1 -1
  196. package/dist/office/projection.js +0 -1
  197. package/dist/office/projection.js.map +1 -1
  198. package/dist/office/types.d.ts +1 -2
  199. package/dist/office/types.d.ts.map +1 -1
  200. package/dist/office/types.js.map +1 -1
  201. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  202. package/dist/runtime/conversation-runtime.js +2 -16
  203. package/dist/runtime/conversation-runtime.js.map +1 -1
  204. package/dist/runtime/session-lifecycle.d.ts +1 -2
  205. package/dist/runtime/session-lifecycle.d.ts.map +1 -1
  206. package/dist/runtime/session-lifecycle.js +7 -16
  207. package/dist/runtime/session-lifecycle.js.map +1 -1
  208. package/dist/runtime/types.d.ts +0 -1
  209. package/dist/runtime/types.d.ts.map +1 -1
  210. package/dist/runtime/types.js.map +1 -1
  211. package/dist/sandbox/provisioner.d.ts.map +1 -1
  212. package/dist/sandbox/provisioner.js +3 -4
  213. package/dist/sandbox/provisioner.js.map +1 -1
  214. package/dist/sessions/chat-history-sync.d.ts +8 -6
  215. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  216. package/dist/sessions/chat-history-sync.js +70 -143
  217. package/dist/sessions/chat-history-sync.js.map +1 -1
  218. package/dist/sessions/compaction-summary.d.ts +4 -0
  219. package/dist/sessions/compaction-summary.d.ts.map +1 -0
  220. package/dist/sessions/compaction-summary.js +16 -0
  221. package/dist/sessions/compaction-summary.js.map +1 -0
  222. package/dist/sessions/session-key.d.ts +1 -0
  223. package/dist/sessions/session-key.d.ts.map +1 -1
  224. package/dist/sessions/session-key.js +3 -0
  225. package/dist/sessions/session-key.js.map +1 -1
  226. package/dist/sessions/session-store.d.ts +47 -29
  227. package/dist/sessions/session-store.d.ts.map +1 -1
  228. package/dist/sessions/session-store.js +578 -484
  229. package/dist/sessions/session-store.js.map +1 -1
  230. package/dist/sessions/types.d.ts +60 -46
  231. package/dist/sessions/types.d.ts.map +1 -1
  232. package/dist/sessions/types.js +1 -1
  233. package/dist/sessions/types.js.map +1 -1
  234. package/dist/settings/apply.js +2 -2
  235. package/dist/settings/apply.js.map +1 -1
  236. package/dist/types.d.ts +10 -3
  237. package/dist/types.d.ts.map +1 -1
  238. package/dist/types.js.map +1 -1
  239. package/dist/vault/index.d.ts.map +1 -1
  240. package/dist/vault/index.js +0 -3
  241. package/dist/vault/index.js.map +1 -1
  242. package/dist/vault/types.d.ts +0 -3
  243. package/dist/vault/types.d.ts.map +1 -1
  244. package/dist/vault/types.js.map +1 -1
  245. package/package.json +8 -6
  246. package/dist/sessions/store.d.ts +0 -17
  247. package/dist/sessions/store.d.ts.map +0 -1
  248. package/dist/sessions/store.js +0 -211
  249. package/dist/sessions/store.js.map +0 -1
@@ -1,28 +1,21 @@
1
- import { CONTROL_INPUT_CUSTOM_TYPE } from "./types.js";
2
- import { OFFICE_LOG_FILENAME } from "../office/index.js";
1
+ import { CONTROL_INPUT_CUSTOM_TYPE, } from "./types.js";
3
2
  import { SessionStore } from "./session-store.js";
4
3
  import * as log from "../log.js";
5
4
  import { parseJsonValue, readTextFileNoFollowIfExists } from "../file-guards.js";
6
5
  import { formatHistoryLine, stripHistoryLinePrefix, stripTriggerSignature, } from "./history-line.js";
7
- import { isPlatformHistorySession } from "./store.js";
8
- import { isThreadSessionKey } from "./session-key.js";
9
- import { archiveManagedSessionFile, createManagedSessionFile, createManagedSessionFileAtPath, extractSessionSuffix, getThreadSessionFile, openManagedSession, resolveParentSessionForThread, tryResolveCurrentSession, tryResolveThreadSession, } from "./store.js";
6
+ import { extractSessionSuffix, isThreadSessionKey } from "./session-key.js";
10
7
  const DEFAULT_RECENT_DAYS = 14;
11
8
  const DEFAULT_MAX_TOP_LEVEL_MESSAGES = 200;
12
9
  const CHAT_SYNC_CUSTOM_TYPE = "mikan.chat_sync";
13
10
  import { errorMessage, isRecord } from "../unknown-values.js";
14
- export function hasMaterializedChatSession(options) {
15
- if (!isThreadSessionKey(options.sessionKey)) {
16
- return tryResolveCurrentSession(options.office.sessionsDir) !== null;
17
- }
18
- return (tryResolveThreadSession(getThreadSessionFile(options.office.sessionsDir, options.sessionKey)) !== null);
11
+ export async function hasMaterializedChatSession(options) {
12
+ return SessionStore.exists(options.office, options.sessionKey);
19
13
  }
20
- export function registerThreadSession(options) {
14
+ export async function registerThreadSession(options) {
21
15
  if (!isThreadSessionKey(options.sessionKey))
22
- return null;
23
- const threadFile = getThreadSessionFile(options.office.sessionsDir, options.sessionKey);
24
- return (tryResolveThreadSession(threadFile) ??
25
- createManagedSessionFileAtPath(threadFile, options.cwd ?? options.office.dir, resolveParentSessionForThread(options.office.sessionsDir, extractSessionSuffix(options.sessionKey)) ?? undefined));
16
+ return;
17
+ const store = await SessionStore.open(options.office, options.sessionKey);
18
+ await store.close();
26
19
  }
27
20
  export async function waitForThreadSessionBootstrap(options) {
28
21
  const { parentSessionKey, sessionKey, hasThreadSession, isParentRunning, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), pollMs = 100, } = options;
@@ -30,10 +23,10 @@ export async function waitForThreadSessionBootstrap(options) {
30
23
  return false;
31
24
  if (sessionKey === parentSessionKey)
32
25
  return false;
33
- if (hasThreadSession())
26
+ if (await hasThreadSession())
34
27
  return false;
35
28
  let waited = false;
36
- while (isParentRunning() && !hasThreadSession()) {
29
+ while (isParentRunning() && !(await hasThreadSession())) {
37
30
  waited = true;
38
31
  await sleep(pollMs);
39
32
  }
@@ -47,24 +40,11 @@ export class ChatHistorySync {
47
40
  this.now = options.now ?? (() => new Date());
48
41
  }
49
42
  async resolveSessionScope(options) {
50
- const cwd = options.cwd ?? options.office.dir;
51
- const sessionDir = options.office.sessionsDir;
52
43
  if (!isThreadSessionKey(options.sessionKey)) {
53
- const contextFile = await this.resolveTopLevelSessionFile({
54
- office: options.office,
55
- sessionDir,
56
- cwd,
57
- currentMessageId: options.currentMessageId,
58
- });
59
- return { sessionDir, contextFile, threadRootMessage: null };
44
+ await this.bootstrapTopLevelSession(options);
45
+ return { threadRootMessage: null };
60
46
  }
61
- return this.resolveThreadSessionScope({
62
- office: options.office,
63
- sessionDir,
64
- sessionKey: options.sessionKey,
65
- cwd,
66
- currentMessageId: options.currentMessageId,
67
- });
47
+ return this.resolveThreadSessionScope(options);
68
48
  }
69
49
  async syncSessionManager(options) {
70
50
  const records = readConversationLog(options.office);
@@ -79,20 +59,15 @@ export class ChatHistorySync {
79
59
  });
80
60
  }
81
61
  async resetSession(options) {
82
- const cwd = options.cwd ?? options.office.dir;
83
- const sessionFile = isThreadSessionKey(options.sessionKey)
84
- ? resetThreadSessionFile(options.office.sessionsDir, options.sessionKey, cwd)
85
- : createManagedSessionFile(options.office.sessionsDir, cwd);
86
62
  const records = readConversationLog(options.office);
87
63
  const lastMessageId = latestSyncMessageId(records, {
88
64
  sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,
89
65
  isCommandText: this.isCommandText,
90
66
  });
91
- const sessionManager = await openManagedSession(sessionFile, cwd);
67
+ const sessionManager = await SessionStore.open(options.office, options.sessionKey);
92
68
  try {
69
+ await sessionManager.reset();
93
70
  await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {
94
- source: OFFICE_LOG_FILENAME,
95
- messageCount: 0,
96
71
  resetAt: this.now().toISOString(),
97
72
  lastMessageId: lastMessageId ? lastMessageId : undefined,
98
73
  });
@@ -100,14 +75,11 @@ export class ChatHistorySync {
100
75
  finally {
101
76
  await sessionManager.close();
102
77
  }
103
- return sessionFile;
104
78
  }
105
- async resolveTopLevelSessionFile(options) {
106
- const existing = tryResolveCurrentSession(options.sessionDir);
107
- if (existing && !isPlatformHistorySession(existing))
108
- return existing;
79
+ async bootstrapTopLevelSession(options) {
80
+ if (await SessionStore.exists(options.office, options.sessionKey))
81
+ return;
109
82
  const records = readConversationLog(options.office);
110
- const sessionFile = createManagedSessionFile(options.sessionDir, options.cwd);
111
83
  const bootstrapRecords = selectRecentTopLevelMessages(records, {
112
84
  recentDays: this.recentDays,
113
85
  maxMessages: this.maxTopLevelMessages,
@@ -115,57 +87,59 @@ export class ChatHistorySync {
115
87
  excludeMessageId: options.currentMessageId,
116
88
  isCommandText: this.isCommandText,
117
89
  });
118
- await bootstrapSessionFromLog(sessionFile, options.cwd, bootstrapRecords, latestSyncMessageId(records, {
90
+ await bootstrapSessionFromLog(options, bootstrapRecords, latestSyncMessageId(records, {
119
91
  sessionKey: null,
120
92
  excludeMessageId: options.currentMessageId,
121
93
  isCommandText: this.isCommandText,
122
94
  }));
123
- return sessionFile;
124
95
  }
125
96
  async resolveThreadSessionScope(options) {
126
- const threadFile = getThreadSessionFile(options.sessionDir, options.sessionKey);
127
97
  const threadId = extractSessionSuffix(options.sessionKey);
128
98
  const records = readConversationLog(options.office);
129
99
  const threadRootMessage = buildThreadRootSeed(findLogRecordById(records, threadId)?.message);
130
- const existing = tryResolveThreadSession(threadFile);
131
- if (existing) {
132
- return { sessionDir: options.sessionDir, contextFile: existing, threadRootMessage };
100
+ if (await SessionStore.exists(options.office, options.sessionKey)) {
101
+ return { threadRootMessage };
133
102
  }
134
- createManagedSessionFileAtPath(threadFile, options.cwd, resolveParentSessionForThread(options.sessionDir, threadId) ?? undefined);
135
- const bootstrapRecords = selectThreadBootstrapMessages(records, threadId, {
136
- recentDays: this.recentDays,
137
- maxTopLevelMessages: this.maxTopLevelMessages,
138
- now: this.now(),
139
- excludeMessageId: options.currentMessageId,
140
- isCommandText: this.isCommandText,
141
- });
142
- await bootstrapSessionFromLog(threadFile, options.cwd, bootstrapRecords, latestSyncMessageId(records, {
103
+ const filter = {
143
104
  sessionKey: options.sessionKey,
144
105
  excludeMessageId: options.currentMessageId,
145
106
  isCommandText: this.isCommandText,
146
- }));
147
- return { sessionDir: options.sessionDir, contextFile: threadFile, threadRootMessage };
107
+ };
108
+ const threadRecords = selectExistingSessionSyncMessages(records, filter);
109
+ const lastMessageId = latestSyncMessageId(records, filter);
110
+ const cause = findRunCause(records, threadId);
111
+ if (cause && cause.sessionKey !== options.sessionKey) {
112
+ const forked = await SessionStore.forkRun(options.office, options.sessionKey, cause, [
113
+ ...threadRecords.flatMap((record) => {
114
+ if (record.message.ts === threadId)
115
+ return [];
116
+ const message = buildHistorySessionMessage(record.message);
117
+ return message ? [{ type: "message", message }] : [];
118
+ }),
119
+ {
120
+ type: "custom",
121
+ customType: CHAT_SYNC_CUSTOM_TYPE,
122
+ data: { lastMessageId },
123
+ timestamp: Date.now(),
124
+ },
125
+ ]);
126
+ if (forked)
127
+ return { threadRootMessage };
128
+ }
129
+ await bootstrapSessionFromLog(options, threadRecords, lastMessageId);
130
+ return { threadRootMessage };
148
131
  }
149
132
  }
150
- function existingThreadParent(threadFile) {
151
- let header;
152
- try {
153
- header = SessionStore.readHeader(threadFile);
154
- }
155
- catch {
133
+ function findRunCause(records, threadId) {
134
+ const root = findLogRecordById(records, threadId)?.message;
135
+ if (!root)
156
136
  return undefined;
157
- }
158
- const path = header?.parentSession;
159
- const id = header?.parentSessionId;
160
- return path && id ? { path, id } : undefined;
161
- }
162
- function resetThreadSessionFile(sessionsDir, sessionKey, cwd) {
163
- const threadFile = getThreadSessionFile(sessionsDir, sessionKey);
164
- const parent = existingThreadParent(threadFile) ??
165
- resolveParentSessionForThread(sessionsDir, extractSessionSuffix(sessionKey)) ??
166
- undefined;
167
- archiveManagedSessionFile(threadFile);
168
- return createManagedSessionFileAtPath(threadFile, cwd, parent);
137
+ const answer = root.isMessagingBot
138
+ ? root
139
+ : records.find((record) => record.message.replyTo === threadId)?.message;
140
+ if (!answer?.replyTo || !answer.sessionKey)
141
+ return undefined;
142
+ return { sessionKey: answer.sessionKey, messageId: answer.replyTo };
169
143
  }
170
144
  function findLogRecordById(records, messageId) {
171
145
  for (let i = records.length - 1; i >= 0; i--) {
@@ -183,23 +157,6 @@ function selectRecentMessages(records, options) {
183
157
  .filter((record) => isRecentHistoryMessage(record.message, sinceMs))
184
158
  .slice(-options.maxMessages);
185
159
  }
186
- function selectThreadBootstrapMessages(records, threadId, options) {
187
- const scopedRecords = recordsBeforeCurrentMessage(records, options.excludeMessageId);
188
- const rootRecord = findLogRecordById(scopedRecords, threadId);
189
- const topLevelSource = rootRecord
190
- ? scopedRecords.filter((record) => record.index <= rootRecord.index)
191
- : scopedRecords;
192
- const topLevelRecords = selectRecentTopLevelMessages(topLevelSource, {
193
- recentDays: options.recentDays,
194
- maxMessages: options.maxTopLevelMessages,
195
- now: options.now,
196
- excludeMessageId: options.excludeMessageId,
197
- isCommandText: options.isCommandText,
198
- });
199
- const threadRecords = scopedRecords.filter((record) => isRenderableConversationMessage(record.message, options) &&
200
- (record.message.ts === threadId || record.message.threadTs === threadId));
201
- return dedupeAndSortRecords([...topLevelRecords, ...threadRecords]);
202
- }
203
160
  function isTopLevelHistoryMessage(message, filter) {
204
161
  if (!isRenderableConversationMessage(message, filter))
205
162
  return false;
@@ -235,6 +192,8 @@ function latestSyncMessageId(records, options) {
235
192
  function isRenderableConversationMessage(message, filter) {
236
193
  if (filter.excludeMessageId && message.ts === filter.excludeMessageId)
237
194
  return false;
195
+ if (message.isMessagingBot && message.sessionKey)
196
+ return false;
238
197
  if (!message.isMessagingBot && filter.isCommandText(message.text ?? ""))
239
198
  return false;
240
199
  return !!message.text?.trim();
@@ -265,15 +224,11 @@ function sortTime(record) {
265
224
  }
266
225
  return record.index;
267
226
  }
268
- async function bootstrapSessionFromLog(sessionFile, cwd, records, lastMessageId = records.at(-1)?.message.ts) {
269
- if (records.length === 0 && !lastMessageId)
270
- return;
271
- const sessionManager = await openManagedSession(sessionFile, cwd);
227
+ async function bootstrapSessionFromLog(session, records, lastMessageId = records.at(-1)?.message.ts) {
228
+ const sessionManager = await SessionStore.open(session.office, session.sessionKey);
272
229
  try {
273
230
  await appendLogRecordsToSession(sessionManager, records);
274
231
  await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {
275
- source: OFFICE_LOG_FILENAME,
276
- messageCount: records.length,
277
232
  lastMessageId,
278
233
  });
279
234
  }
@@ -283,7 +238,7 @@ async function bootstrapSessionFromLog(sessionFile, cwd, records, lastMessageId
283
238
  }
284
239
  async function syncSessionManagerFromLog(sessionManager, records, historyWindow) {
285
240
  if (records.length === 0)
286
- return { appended: 0 };
241
+ return;
287
242
  const existingEntries = await sessionManager.getEntries();
288
243
  const resetAt = getLatestChatSyncResetAt(existingEntries);
289
244
  const controlledIds = new Set(existingEntries.flatMap((entry) => {
@@ -300,22 +255,16 @@ async function syncSessionManagerFromLog(sessionManager, records, historyWindow)
300
255
  : -1;
301
256
  const syncCandidates = selectRecentMessages(eligibleRecords.slice(lastSyncedIndex + 1), historyWindow);
302
257
  if (syncCandidates.length === 0)
303
- return { appended: 0 };
258
+ return;
304
259
  const represented = buildRepresentedMessageCounts(existingEntries);
305
260
  const newRecords = syncCandidates.filter((record) => !consumeRepresentedLogMessage(record, represented));
306
261
  if (newRecords.length === 0)
307
- return { appended: 0 };
262
+ return;
308
263
  const lastMessageId = syncCandidates.at(-1)?.message.ts;
309
264
  await appendLogRecordsToSession(sessionManager, newRecords);
310
265
  await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {
311
- source: OFFICE_LOG_FILENAME,
312
- messageCount: newRecords.length,
313
266
  lastMessageId,
314
267
  });
315
- return {
316
- appended: newRecords.length,
317
- lastMessageId,
318
- };
319
268
  }
320
269
  async function appendLogRecordsToSession(sessionManager, records) {
321
270
  for (const record of records) {
@@ -368,7 +317,10 @@ function consumeRepresentedLogMessage(record, counts) {
368
317
  const comparable = comparableLogMessage(record.message);
369
318
  if (!comparable)
370
319
  return false;
371
- const key = counts.get(comparable) ? comparable : presentedAnswerKey(comparable, counts);
320
+ const asChatLine = `user:${comparable.slice(comparable.indexOf(":") + 1)}`;
321
+ const key = counts.get(comparable)
322
+ ? comparable
323
+ : (presentedAnswerKey(comparable, counts) ?? (counts.get(asChatLine) ? asChatLine : undefined));
372
324
  if (!key)
373
325
  return false;
374
326
  counts.set(key, (counts.get(key) ?? 0) - 1);
@@ -427,23 +379,10 @@ function buildHistorySessionMessage(message) {
427
379
  const text = historyMessageText(message);
428
380
  if (!text)
429
381
  return null;
430
- const timestamp = parseMessageTimestamp(message);
431
- if (!message.isMessagingBot) {
432
- return {
433
- role: "user",
434
- content: [{ type: "text", text: formatHistoryMessage(message) }],
435
- timestamp,
436
- };
437
- }
438
382
  return {
439
- role: "assistant",
440
- content: [{ type: "text", text }],
441
- api: "platform-history",
442
- provider: "platform-history",
443
- model: "platform-history",
444
- usage: zeroUsage(),
445
- stopReason: "stop",
446
- timestamp,
383
+ role: "user",
384
+ content: [{ type: "text", text: formatHistoryMessage({ ...message, text }) }],
385
+ timestamp: parseMessageTimestamp(message) ?? Date.now(),
447
386
  };
448
387
  }
449
388
  function buildThreadRootSeed(message) {
@@ -453,8 +392,6 @@ function buildThreadRootSeed(message) {
453
392
  text: message.text,
454
393
  userName: message.userName,
455
394
  user: message.user,
456
- loggedAt: message.date ? new Date(message.date).getTime() : undefined,
457
- isMessagingBot: message.isMessagingBot,
458
395
  };
459
396
  }
460
397
  function parseMessageTimestamp(message) {
@@ -477,17 +414,7 @@ function formatHistoryMessage(message) {
477
414
  text: message.text?.trim() ?? "",
478
415
  });
479
416
  }
480
- function zeroUsage() {
481
- return {
482
- input: 0,
483
- output: 0,
484
- cacheRead: 0,
485
- cacheWrite: 0,
486
- totalTokens: 0,
487
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
488
- };
489
- }
490
- function readConversationLog(office) {
417
+ export function readConversationLog(office) {
491
418
  const logFile = office.logPath;
492
419
  const raw = readTextFileNoFollowIfExists(logFile);
493
420
  if (raw === undefined)
@@ -1 +1 @@
1
- {"version":3,"file":"chat-history-sync.js","sourceRoot":"","sources":["../../src/sessions/chat-history-sync.ts"],"names":[],"mappings":"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","sourcesContent":["import { CONTROL_INPUT_CUSTOM_TYPE, type SessionEntry } from \"./types.js\";\nimport { OFFICE_LOG_FILENAME } from \"../office/index.js\";\nimport type { Office } from \"../office/types.js\";\nimport { SessionStore } from \"./session-store.js\";\nimport type { ConversationLogMessage } from \"../types.js\";\nimport * as log from \"../log.js\";\nimport { parseJsonValue, readTextFileNoFollowIfExists } from \"../file-guards.js\";\nimport {\n formatHistoryLine,\n stripHistoryLinePrefix,\n stripTriggerSignature,\n} from \"./history-line.js\";\nimport { isPlatformHistorySession } from \"./store.js\";\nimport { isThreadSessionKey } from \"./session-key.js\";\nimport {\n archiveManagedSessionFile,\n createManagedSessionFile,\n createManagedSessionFileAtPath,\n extractSessionSuffix,\n getThreadSessionFile,\n openManagedSession,\n resolveParentSessionForThread,\n tryResolveCurrentSession,\n tryResolveThreadSession,\n} from \"./store.js\";\n\nconst DEFAULT_RECENT_DAYS = 14;\nconst DEFAULT_MAX_TOP_LEVEL_MESSAGES = 200;\nconst CHAT_SYNC_CUSTOM_TYPE = \"mikan.chat_sync\";\n\ntype SessionAppendMessage = Parameters<SessionStore[\"appendMessage\"]>[0];\n\nimport type {\n ChatHistorySyncOptions,\n HasMaterializedSessionOptions,\n RegisterThreadSessionOptions,\n ResetChatSessionOptions,\n ResolveChatSessionScopeOptions,\n SyncChatSessionOptions,\n ThreadBootstrapWaitOptions,\n ChatSyncReport,\n LogRecord,\n ParentSessionRef,\n ResolvedSessionScope,\n ThreadRootMessage,\n} from \"./types.js\";\nimport { errorMessage, isRecord } from \"../unknown-values.js\";\n\nexport function hasMaterializedChatSession(options: HasMaterializedSessionOptions): boolean {\n if (!isThreadSessionKey(options.sessionKey)) {\n return tryResolveCurrentSession(options.office.sessionsDir) !== null;\n }\n return (\n tryResolveThreadSession(\n getThreadSessionFile(options.office.sessionsDir, options.sessionKey),\n ) !== null\n );\n}\n\nexport function registerThreadSession(options: RegisterThreadSessionOptions): string | null {\n if (!isThreadSessionKey(options.sessionKey)) return null;\n\n const threadFile = getThreadSessionFile(options.office.sessionsDir, options.sessionKey);\n return (\n tryResolveThreadSession(threadFile) ??\n createManagedSessionFileAtPath(\n threadFile,\n options.cwd ?? options.office.dir,\n resolveParentSessionForThread(\n options.office.sessionsDir,\n extractSessionSuffix(options.sessionKey),\n ) ?? undefined,\n )\n );\n}\n\nexport async function waitForThreadSessionBootstrap(\n options: ThreadBootstrapWaitOptions,\n): Promise<boolean> {\n const {\n parentSessionKey,\n sessionKey,\n hasThreadSession,\n isParentRunning,\n sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)),\n pollMs = 100,\n } = options;\n\n if (!isThreadSessionKey(sessionKey)) return false;\n if (sessionKey === parentSessionKey) return false;\n if (hasThreadSession()) return false;\n\n let waited = false;\n while (isParentRunning() && !hasThreadSession()) {\n waited = true;\n await sleep(pollMs);\n }\n\n return waited;\n}\n\nexport class ChatHistorySync {\n private readonly recentDays: number;\n private readonly maxTopLevelMessages: number;\n private readonly now: () => Date;\n private readonly isCommandText: (text: string) => boolean;\n\n constructor(options: ChatHistorySyncOptions) {\n this.isCommandText = options.isCommandText;\n this.recentDays = options.recentDays ?? DEFAULT_RECENT_DAYS;\n this.maxTopLevelMessages = options.maxTopLevelMessages ?? DEFAULT_MAX_TOP_LEVEL_MESSAGES;\n this.now = options.now ?? (() => new Date());\n }\n\n async resolveSessionScope(\n options: ResolveChatSessionScopeOptions,\n ): Promise<ResolvedSessionScope> {\n const cwd = options.cwd ?? options.office.dir;\n const sessionDir = options.office.sessionsDir;\n\n if (!isThreadSessionKey(options.sessionKey)) {\n const contextFile = await this.resolveTopLevelSessionFile({\n office: options.office,\n sessionDir,\n cwd,\n currentMessageId: options.currentMessageId,\n });\n return { sessionDir, contextFile, threadRootMessage: null };\n }\n\n return this.resolveThreadSessionScope({\n office: options.office,\n sessionDir,\n sessionKey: options.sessionKey,\n cwd,\n currentMessageId: options.currentMessageId,\n });\n }\n\n async syncSessionManager(options: SyncChatSessionOptions): Promise<ChatSyncReport> {\n const records = readConversationLog(options.office);\n return syncSessionManagerFromLog(\n options.sessionManager,\n selectExistingSessionSyncMessages(records, {\n sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n }),\n {\n recentDays: this.recentDays,\n maxMessages: this.maxTopLevelMessages,\n now: this.now(),\n },\n );\n }\n\n async resetSession(options: ResetChatSessionOptions): Promise<string> {\n const cwd = options.cwd ?? options.office.dir;\n const sessionFile = isThreadSessionKey(options.sessionKey)\n ? resetThreadSessionFile(options.office.sessionsDir, options.sessionKey, cwd)\n : createManagedSessionFile(options.office.sessionsDir, cwd);\n const records = readConversationLog(options.office);\n const lastMessageId = latestSyncMessageId(records, {\n sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,\n isCommandText: this.isCommandText,\n });\n const sessionManager = await openManagedSession(sessionFile, cwd);\n try {\n await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {\n source: OFFICE_LOG_FILENAME,\n messageCount: 0,\n resetAt: this.now().toISOString(),\n lastMessageId: lastMessageId ? lastMessageId : undefined,\n });\n } finally {\n await sessionManager.close();\n }\n return sessionFile;\n }\n\n private async resolveTopLevelSessionFile(options: {\n office: Office;\n sessionDir: string;\n cwd: string;\n currentMessageId?: string;\n }): Promise<string> {\n const existing = tryResolveCurrentSession(options.sessionDir);\n if (existing && !isPlatformHistorySession(existing)) return existing;\n const records = readConversationLog(options.office);\n\n const sessionFile = createManagedSessionFile(options.sessionDir, options.cwd);\n const bootstrapRecords = selectRecentTopLevelMessages(records, {\n recentDays: this.recentDays,\n maxMessages: this.maxTopLevelMessages,\n now: this.now(),\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n });\n await bootstrapSessionFromLog(\n sessionFile,\n options.cwd,\n bootstrapRecords,\n latestSyncMessageId(records, {\n sessionKey: null,\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n }),\n );\n return sessionFile;\n }\n\n private async resolveThreadSessionScope(options: {\n office: Office;\n sessionDir: string;\n sessionKey: string;\n cwd: string;\n currentMessageId?: string;\n }): Promise<ResolvedSessionScope> {\n const threadFile = getThreadSessionFile(options.sessionDir, options.sessionKey);\n const threadId = extractSessionSuffix(options.sessionKey);\n const records = readConversationLog(options.office);\n const threadRootMessage = buildThreadRootSeed(findLogRecordById(records, threadId)?.message);\n const existing = tryResolveThreadSession(threadFile);\n if (existing) {\n return { sessionDir: options.sessionDir, contextFile: existing, threadRootMessage };\n }\n\n createManagedSessionFileAtPath(\n threadFile,\n options.cwd,\n resolveParentSessionForThread(options.sessionDir, threadId) ?? undefined,\n );\n const bootstrapRecords = selectThreadBootstrapMessages(records, threadId, {\n recentDays: this.recentDays,\n maxTopLevelMessages: this.maxTopLevelMessages,\n now: this.now(),\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n });\n await bootstrapSessionFromLog(\n threadFile,\n options.cwd,\n bootstrapRecords,\n latestSyncMessageId(records, {\n sessionKey: options.sessionKey,\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n }),\n );\n\n return { sessionDir: options.sessionDir, contextFile: threadFile, threadRootMessage };\n }\n}\n\nfunction existingThreadParent(threadFile: string): ParentSessionRef | undefined {\n let header;\n try {\n header = SessionStore.readHeader(threadFile);\n } catch {\n return undefined;\n }\n const path = header?.parentSession;\n const id = header?.parentSessionId;\n return path && id ? { path, id } : undefined;\n}\n\nfunction resetThreadSessionFile(sessionsDir: string, sessionKey: string, cwd: string): string {\n const threadFile = getThreadSessionFile(sessionsDir, sessionKey);\n const parent =\n existingThreadParent(threadFile) ??\n resolveParentSessionForThread(sessionsDir, extractSessionSuffix(sessionKey)) ??\n undefined;\n archiveManagedSessionFile(threadFile);\n return createManagedSessionFileAtPath(threadFile, cwd, parent);\n}\n\nfunction findLogRecordById(records: LogRecord[], messageId: string): LogRecord | undefined {\n for (let i = records.length - 1; i >= 0; i--) {\n if (records[i]?.message.ts === messageId) return records[i];\n }\n return undefined;\n}\n\nfunction selectRecentTopLevelMessages(\n records: LogRecord[],\n options: {\n recentDays: number;\n maxMessages: number;\n now: Date;\n excludeMessageId?: string;\n isCommandText: (text: string) => boolean;\n },\n): LogRecord[] {\n return selectRecentMessages(\n recordsBeforeCurrentMessage(records, options.excludeMessageId).filter((record) =>\n isTopLevelHistoryMessage(record.message, options),\n ),\n options,\n );\n}\n\nfunction selectRecentMessages(records: LogRecord[], options: HistoryWindow): LogRecord[] {\n const sinceMs = options.now.getTime() - options.recentDays * 24 * 60 * 60 * 1000;\n return records\n .filter((record) => isRecentHistoryMessage(record.message, sinceMs))\n .slice(-options.maxMessages);\n}\n\nfunction selectThreadBootstrapMessages(\n records: LogRecord[],\n threadId: string,\n options: {\n recentDays: number;\n maxTopLevelMessages: number;\n now: Date;\n excludeMessageId?: string;\n isCommandText: (text: string) => boolean;\n },\n): LogRecord[] {\n const scopedRecords = recordsBeforeCurrentMessage(records, options.excludeMessageId);\n const rootRecord = findLogRecordById(scopedRecords, threadId);\n const topLevelSource = rootRecord\n ? scopedRecords.filter((record) => record.index <= rootRecord.index)\n : scopedRecords;\n const topLevelRecords = selectRecentTopLevelMessages(topLevelSource, {\n recentDays: options.recentDays,\n maxMessages: options.maxTopLevelMessages,\n now: options.now,\n excludeMessageId: options.excludeMessageId,\n isCommandText: options.isCommandText,\n });\n const threadRecords = scopedRecords.filter(\n (record) =>\n isRenderableConversationMessage(record.message, options) &&\n (record.message.ts === threadId || record.message.threadTs === threadId),\n );\n\n return dedupeAndSortRecords([...topLevelRecords, ...threadRecords]);\n}\n\nfunction isTopLevelHistoryMessage(\n message: ConversationLogMessage,\n filter: RenderableMessageFilter,\n): boolean {\n if (!isRenderableConversationMessage(message, filter)) return false;\n return !message.threadTs;\n}\n\nfunction isRecentHistoryMessage(message: ConversationLogMessage, sinceMs: number): boolean {\n if (!message.date) return true;\n const dateMs = new Date(message.date).getTime();\n return !Number.isFinite(dateMs) || dateMs >= sinceMs;\n}\n\nfunction selectExistingSessionSyncMessages(\n records: LogRecord[],\n options: RenderableMessageFilter & { sessionKey: string | null },\n): LogRecord[] {\n const threadId = options.sessionKey ? extractSessionSuffix(options.sessionKey) : null;\n return dedupeAndSortRecords(\n recordsBeforeCurrentMessage(records, options.excludeMessageId).filter((record) => {\n if (!isRenderableConversationMessage(record.message, options)) return false;\n if (!threadId) return !record.message.threadTs;\n return record.message.ts === threadId || record.message.threadTs === threadId;\n }),\n );\n}\n\nfunction recordsBeforeCurrentMessage(records: LogRecord[], currentMessageId?: string): LogRecord[] {\n if (!currentMessageId) return records;\n const currentRecord = findLogRecordById(records, currentMessageId);\n if (!currentRecord) return records;\n return records.filter((record) => record.index < currentRecord.index);\n}\n\nfunction latestSyncMessageId(\n records: LogRecord[],\n options: RenderableMessageFilter & { sessionKey: string | null },\n): string | undefined {\n return selectExistingSessionSyncMessages(records, options).at(-1)?.message.ts;\n}\n\ninterface RenderableMessageFilter {\n excludeMessageId?: string;\n isCommandText: (text: string) => boolean;\n}\n\nfunction isRenderableConversationMessage(\n message: ConversationLogMessage,\n filter: RenderableMessageFilter,\n): boolean {\n if (filter.excludeMessageId && message.ts === filter.excludeMessageId) return false;\n if (!message.isMessagingBot && filter.isCommandText(message.text ?? \"\")) return false;\n return !!message.text?.trim();\n}\n\nfunction dedupeAndSortRecords(records: LogRecord[]): LogRecord[] {\n const byKey = new Map<string, LogRecord>();\n for (const record of records) {\n byKey.set(record.message.ts ?? `line:${record.index}`, record);\n }\n\n return Array.from(byKey.values()).toSorted((a, b) => {\n const aTime = sortTime(a);\n const bTime = sortTime(b);\n if (aTime !== bTime) return aTime - bTime;\n return a.index - b.index;\n });\n}\n\nfunction sortTime(record: LogRecord): number {\n if (record.message.date) {\n const dateMs = new Date(record.message.date).getTime();\n if (Number.isFinite(dateMs)) return dateMs;\n }\n\n if (record.message.ts) {\n const tsMs = Number(record.message.ts) * 1000;\n if (Number.isFinite(tsMs)) return tsMs;\n }\n\n return record.index;\n}\n\nasync function bootstrapSessionFromLog(\n sessionFile: string,\n cwd: string,\n records: LogRecord[],\n lastMessageId = records.at(-1)?.message.ts,\n): Promise<void> {\n if (records.length === 0 && !lastMessageId) return;\n\n const sessionManager = await openManagedSession(sessionFile, cwd);\n try {\n await appendLogRecordsToSession(sessionManager, records);\n await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {\n source: OFFICE_LOG_FILENAME,\n messageCount: records.length,\n lastMessageId,\n });\n } finally {\n await sessionManager.close();\n }\n}\n\ninterface HistoryWindow {\n recentDays: number;\n maxMessages: number;\n now: Date;\n}\n\nasync function syncSessionManagerFromLog(\n sessionManager: SessionStore,\n records: LogRecord[],\n historyWindow: HistoryWindow,\n): Promise<ChatSyncReport> {\n if (records.length === 0) return { appended: 0 };\n\n const existingEntries = await sessionManager.getEntries();\n const resetAt = getLatestChatSyncResetAt(existingEntries);\n const controlledIds = new Set(\n existingEntries.flatMap((entry) => {\n if (\n entry.type !== \"custom\" ||\n entry.customType !== CONTROL_INPUT_CUSTOM_TYPE ||\n !isRecord(entry.data)\n )\n return [];\n return typeof entry.data.messageId === \"string\" ? [entry.data.messageId] : [];\n }),\n );\n const eligibleRecords = records.filter(\n (record) =>\n !controlledIds.has(record.message.ts ?? \"\") && (!resetAt || isAfterReset(record, resetAt)),\n );\n const lastSyncedMessageId = getLatestChatSyncMessageId(existingEntries);\n const lastSyncedIndex = lastSyncedMessageId\n ? eligibleRecords.findIndex((record) => record.message.ts === lastSyncedMessageId)\n : -1;\n const syncCandidates = selectRecentMessages(\n eligibleRecords.slice(lastSyncedIndex + 1),\n historyWindow,\n );\n if (syncCandidates.length === 0) return { appended: 0 };\n\n const represented = buildRepresentedMessageCounts(existingEntries);\n const newRecords = syncCandidates.filter(\n (record) => !consumeRepresentedLogMessage(record, represented),\n );\n if (newRecords.length === 0) return { appended: 0 };\n\n const lastMessageId = syncCandidates.at(-1)?.message.ts;\n await appendLogRecordsToSession(sessionManager, newRecords);\n await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {\n source: OFFICE_LOG_FILENAME,\n messageCount: newRecords.length,\n lastMessageId,\n });\n return {\n appended: newRecords.length,\n lastMessageId,\n };\n}\n\nasync function appendLogRecordsToSession(\n sessionManager: SessionStore,\n records: LogRecord[],\n): Promise<void> {\n for (const record of records) {\n const message = buildHistorySessionMessage(record.message);\n if (message) await sessionManager.appendMessage(message);\n }\n}\n\nfunction isChatSyncMarker(entry: SessionEntry): entry is Extract<SessionEntry, { type: \"custom\" }> {\n return entry.type === \"custom\" && entry.customType === CHAT_SYNC_CUSTOM_TYPE;\n}\n\nfunction markerResetAt(entry: SessionEntry): number | undefined {\n if (!isChatSyncMarker(entry)) return undefined;\n if (!isRecord(entry.data) || typeof entry.data.resetAt !== \"string\") return undefined;\n const resetAt = new Date(entry.data.resetAt).getTime();\n return Number.isFinite(resetAt) ? resetAt : undefined;\n}\n\nfunction getLatestChatSyncResetAt(entries: SessionEntry[]): number | undefined {\n for (const entry of entries.toReversed()) {\n const resetAt = markerResetAt(entry);\n if (resetAt !== undefined) return resetAt;\n }\n return undefined;\n}\n\nfunction isAfterReset(record: LogRecord, resetAt: number): boolean {\n if (!record.message.date) return false;\n const messageTime = new Date(record.message.date).getTime();\n return Number.isFinite(messageTime) && messageTime >= resetAt;\n}\n\nfunction getLatestChatSyncMessageId(entries: SessionEntry[]): string | undefined {\n const marker = entries.toReversed().find(isChatSyncMarker);\n const lastMessageId = isRecord(marker?.data) ? marker.data.lastMessageId : undefined;\n return typeof lastMessageId === \"string\" ? lastMessageId : undefined;\n}\n\nfunction buildRepresentedMessageCounts(entries: SessionEntry[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const entry of entries) {\n const comparable = comparableSessionMessage(entry);\n if (!comparable) continue;\n counts.set(comparable, (counts.get(comparable) ?? 0) + 1);\n }\n return counts;\n}\n\nfunction consumeRepresentedLogMessage(record: LogRecord, counts: Map<string, number>): boolean {\n const comparable = comparableLogMessage(record.message);\n if (!comparable) return false;\n\n const key = counts.get(comparable) ? comparable : presentedAnswerKey(comparable, counts);\n if (!key) return false;\n counts.set(key, (counts.get(key) ?? 0) - 1);\n return true;\n}\n\nfunction presentedAnswerKey(comparable: string, counts: Map<string, number>): string | undefined {\n if (!comparable.startsWith(ASSISTANT_KEY_PREFIX)) return undefined;\n const posted = comparable.slice(ASSISTANT_KEY_PREFIX.length);\n for (const [key, count] of counts) {\n if (count <= 0 || !key.startsWith(ASSISTANT_KEY_PREFIX)) continue;\n const answer = key.slice(ASSISTANT_KEY_PREFIX.length);\n if (posted.endsWith(`\\n\\n${answer}`)) return key;\n }\n return undefined;\n}\n\nconst ASSISTANT_KEY_PREFIX = \"assistant:\";\n\nfunction comparableSessionMessage(entry: SessionEntry): string | null {\n if (entry.type !== \"message\") return null;\n const role = entry.message.role;\n if (role !== \"user\" && role !== \"assistant\") return null;\n\n const raw = getSessionMessageText(entry);\n const text = normalizeComparableText(role === \"assistant\" ? stripTriggerSignature(raw) : raw);\n if (!text) return null;\n return `${role}:${text}`;\n}\n\nfunction comparableLogMessage(message: ConversationLogMessage): string | null {\n const text = historyMessageText(message);\n if (!text) return null;\n return `${message.isMessagingBot ? \"assistant\" : \"user\"}:${normalizeComparableText(text)}`;\n}\n\nfunction historyMessageText(message: ConversationLogMessage): string {\n const text = message.text?.trim() ?? \"\";\n return message.isMessagingBot ? stripTriggerSignature(text) : text;\n}\n\nfunction getSessionMessageText(entry: SessionEntry): string {\n if (entry.type !== \"message\" || !(\"content\" in entry.message)) return \"\";\n const content = entry.message.content;\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((part) => (part.type === \"text\" && \"text\" in part ? part.text : \"\"))\n .join(\"\\n\");\n}\n\nconst normalizeComparableText = stripHistoryLinePrefix;\n\nfunction buildHistorySessionMessage(message: ConversationLogMessage): SessionAppendMessage | null {\n const text = historyMessageText(message);\n if (!text) return null;\n\n const timestamp = parseMessageTimestamp(message);\n if (!message.isMessagingBot) {\n return {\n role: \"user\",\n content: [{ type: \"text\", text: formatHistoryMessage(message) }],\n timestamp,\n } as SessionAppendMessage;\n }\n\n return {\n role: \"assistant\",\n content: [{ type: \"text\", text }],\n api: \"platform-history\",\n provider: \"platform-history\",\n model: \"platform-history\",\n usage: zeroUsage(),\n stopReason: \"stop\",\n timestamp,\n } as SessionAppendMessage;\n}\n\nfunction buildThreadRootSeed(\n message: ConversationLogMessage | undefined,\n): ThreadRootMessage | null {\n if (!message) return null;\n return {\n text: message.text,\n userName: message.userName,\n user: message.user,\n loggedAt: message.date ? new Date(message.date).getTime() : undefined,\n isMessagingBot: message.isMessagingBot,\n };\n}\n\nfunction parseMessageTimestamp(message: ConversationLogMessage): number | undefined {\n if (message.date) {\n const dateMs = new Date(message.date).getTime();\n if (Number.isFinite(dateMs)) return dateMs;\n }\n\n if (message.ts) {\n const tsMs = Number(message.ts) * 1000;\n if (Number.isFinite(tsMs)) return tsMs;\n }\n\n return undefined;\n}\n\nfunction formatHistoryMessage(message: ConversationLogMessage): string {\n return formatHistoryLine({\n date: message.date ? new Date(message.date) : undefined,\n userName: message.userName || message.user,\n text: message.text?.trim() ?? \"\",\n });\n}\n\nfunction zeroUsage(): object {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n };\n}\n\nfunction readConversationLog(office: Office): LogRecord[] {\n const logFile = office.logPath;\n const raw = readTextFileNoFollowIfExists(logFile);\n if (raw === undefined) return [];\n\n const records: LogRecord[] = [];\n for (const [index, line] of raw.trim().split(\"\\n\").filter(Boolean).entries()) {\n const message = parseLogLine(line, logFile, index + 1);\n if (message) records.push({ message, index });\n }\n return coalesceMessagingBotLogChunks(records);\n}\n\nfunction parseLogLine(\n line: string,\n logFile: string,\n lineNumber: number,\n): ConversationLogMessage | undefined {\n try {\n return parseJsonValue(\n line,\n (value): value is ConversationLogMessage => isRecord(value),\n (detail, kind) => (kind === \"shape\" ? \"expected a JSON object\" : detail),\n );\n } catch (err) {\n log.logWarning(`Skipping malformed log entry at ${logFile}:${lineNumber}`, errorMessage(err));\n return undefined;\n }\n}\n\nfunction coalesceMessagingBotLogChunks(records: LogRecord[]): LogRecord[] {\n const coalesced: LogRecord[] = [];\n for (const record of records) {\n const previous = coalesced.at(-1);\n if (previous && canCoalesceMessagingBotLogChunk(previous.message, record.message)) {\n previous.message.text = `${previous.message.text ?? \"\"}${record.message.text ?? \"\"}`;\n continue;\n }\n coalesced.push({ ...record, message: { ...record.message } });\n }\n return coalesced;\n}\n\nfunction canCoalesceMessagingBotLogChunk(\n previous: ConversationLogMessage,\n current: ConversationLogMessage,\n): boolean {\n return (\n previous.isMessagingBot === true &&\n current.isMessagingBot === true &&\n !!previous.ts &&\n previous.ts === current.ts &&\n previous.threadTs === current.threadTs &&\n previous.user === current.user\n );\n}\n"]}
1
+ {"version":3,"file":"chat-history-sync.js","sourceRoot":"","sources":["../../src/sessions/chat-history-sync.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Message } from \"@earendil-works/pi-ai\";\nimport {\n CONTROL_INPUT_CUSTOM_TYPE,\n type ImportedSessionEntry,\n type SessionEntry,\n} from \"./types.js\";\nimport type { Office } from \"../office/types.js\";\nimport { SessionStore } from \"./session-store.js\";\nimport type { ConversationLogMessage } from \"../types.js\";\nimport * as log from \"../log.js\";\nimport { parseJsonValue, readTextFileNoFollowIfExists } from \"../file-guards.js\";\nimport {\n formatHistoryLine,\n stripHistoryLinePrefix,\n stripTriggerSignature,\n} from \"./history-line.js\";\nimport { extractSessionSuffix, isThreadSessionKey } from \"./session-key.js\";\n\nconst DEFAULT_RECENT_DAYS = 14;\nconst DEFAULT_MAX_TOP_LEVEL_MESSAGES = 200;\nconst CHAT_SYNC_CUSTOM_TYPE = \"mikan.chat_sync\";\n\nimport type {\n ChatHistorySyncOptions,\n HasMaterializedSessionOptions,\n RegisterThreadSessionOptions,\n ResetChatSessionOptions,\n ResolveChatSessionScopeOptions,\n SyncChatSessionOptions,\n ThreadBootstrapWaitOptions,\n LogRecord,\n ResolvedSessionScope,\n ThreadRootMessage,\n} from \"./types.js\";\nimport { errorMessage, isRecord } from \"../unknown-values.js\";\n\nexport async function hasMaterializedChatSession(\n options: HasMaterializedSessionOptions,\n): Promise<boolean> {\n return SessionStore.exists(options.office, options.sessionKey);\n}\n\nexport async function registerThreadSession(options: RegisterThreadSessionOptions): Promise<void> {\n if (!isThreadSessionKey(options.sessionKey)) return;\n const store = await SessionStore.open(options.office, options.sessionKey);\n await store.close();\n}\n\nexport async function waitForThreadSessionBootstrap(\n options: ThreadBootstrapWaitOptions,\n): Promise<boolean> {\n const {\n parentSessionKey,\n sessionKey,\n hasThreadSession,\n isParentRunning,\n sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)),\n pollMs = 100,\n } = options;\n\n if (!isThreadSessionKey(sessionKey)) return false;\n if (sessionKey === parentSessionKey) return false;\n if (await hasThreadSession()) return false;\n\n let waited = false;\n while (isParentRunning() && !(await hasThreadSession())) {\n waited = true;\n await sleep(pollMs);\n }\n\n return waited;\n}\n\nexport class ChatHistorySync {\n private readonly recentDays: number;\n private readonly maxTopLevelMessages: number;\n private readonly now: () => Date;\n private readonly isCommandText: (text: string) => boolean;\n\n constructor(options: ChatHistorySyncOptions) {\n this.isCommandText = options.isCommandText;\n this.recentDays = options.recentDays ?? DEFAULT_RECENT_DAYS;\n this.maxTopLevelMessages = options.maxTopLevelMessages ?? DEFAULT_MAX_TOP_LEVEL_MESSAGES;\n this.now = options.now ?? (() => new Date());\n }\n\n async resolveSessionScope(\n options: ResolveChatSessionScopeOptions,\n ): Promise<ResolvedSessionScope> {\n if (!isThreadSessionKey(options.sessionKey)) {\n await this.bootstrapTopLevelSession(options);\n return { threadRootMessage: null };\n }\n return this.resolveThreadSessionScope(options);\n }\n\n async syncSessionManager(options: SyncChatSessionOptions): Promise<void> {\n const records = readConversationLog(options.office);\n return syncSessionManagerFromLog(\n options.sessionManager,\n selectExistingSessionSyncMessages(records, {\n sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n }),\n {\n recentDays: this.recentDays,\n maxMessages: this.maxTopLevelMessages,\n now: this.now(),\n },\n );\n }\n\n async resetSession(options: ResetChatSessionOptions): Promise<void> {\n const records = readConversationLog(options.office);\n const lastMessageId = latestSyncMessageId(records, {\n sessionKey: isThreadSessionKey(options.sessionKey) ? options.sessionKey : null,\n isCommandText: this.isCommandText,\n });\n const sessionManager = await SessionStore.open(options.office, options.sessionKey);\n try {\n await sessionManager.reset();\n await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {\n resetAt: this.now().toISOString(),\n lastMessageId: lastMessageId ? lastMessageId : undefined,\n });\n } finally {\n await sessionManager.close();\n }\n }\n\n private async bootstrapTopLevelSession(options: ResolveChatSessionScopeOptions): Promise<void> {\n if (await SessionStore.exists(options.office, options.sessionKey)) return;\n const records = readConversationLog(options.office);\n const bootstrapRecords = selectRecentTopLevelMessages(records, {\n recentDays: this.recentDays,\n maxMessages: this.maxTopLevelMessages,\n now: this.now(),\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n });\n await bootstrapSessionFromLog(\n options,\n bootstrapRecords,\n latestSyncMessageId(records, {\n sessionKey: null,\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n }),\n );\n }\n\n private async resolveThreadSessionScope(\n options: ResolveChatSessionScopeOptions,\n ): Promise<ResolvedSessionScope> {\n const threadId = extractSessionSuffix(options.sessionKey);\n const records = readConversationLog(options.office);\n const threadRootMessage = buildThreadRootSeed(findLogRecordById(records, threadId)?.message);\n if (await SessionStore.exists(options.office, options.sessionKey)) {\n return { threadRootMessage };\n }\n const filter = {\n sessionKey: options.sessionKey,\n excludeMessageId: options.currentMessageId,\n isCommandText: this.isCommandText,\n };\n const threadRecords = selectExistingSessionSyncMessages(records, filter);\n const lastMessageId = latestSyncMessageId(records, filter);\n const cause = findRunCause(records, threadId);\n if (cause && cause.sessionKey !== options.sessionKey) {\n const forked = await SessionStore.forkRun(options.office, options.sessionKey, cause, [\n ...threadRecords.flatMap((record): ImportedSessionEntry[] => {\n if (record.message.ts === threadId) return [];\n const message = buildHistorySessionMessage(record.message);\n return message ? [{ type: \"message\", message }] : [];\n }),\n {\n type: \"custom\",\n customType: CHAT_SYNC_CUSTOM_TYPE,\n data: { lastMessageId },\n timestamp: Date.now(),\n },\n ]);\n if (forked) return { threadRootMessage };\n }\n await bootstrapSessionFromLog(options, threadRecords, lastMessageId);\n return { threadRootMessage };\n }\n}\n\nfunction findRunCause(\n records: LogRecord[],\n threadId: string,\n): { sessionKey: string; messageId: string } | undefined {\n const root = findLogRecordById(records, threadId)?.message;\n if (!root) return undefined;\n const answer = root.isMessagingBot\n ? root\n : records.find((record) => record.message.replyTo === threadId)?.message;\n if (!answer?.replyTo || !answer.sessionKey) return undefined;\n return { sessionKey: answer.sessionKey, messageId: answer.replyTo };\n}\n\nfunction findLogRecordById(records: LogRecord[], messageId: string): LogRecord | undefined {\n for (let i = records.length - 1; i >= 0; i--) {\n if (records[i]?.message.ts === messageId) return records[i];\n }\n return undefined;\n}\n\nfunction selectRecentTopLevelMessages(\n records: LogRecord[],\n options: {\n recentDays: number;\n maxMessages: number;\n now: Date;\n excludeMessageId?: string;\n isCommandText: (text: string) => boolean;\n },\n): LogRecord[] {\n return selectRecentMessages(\n recordsBeforeCurrentMessage(records, options.excludeMessageId).filter((record) =>\n isTopLevelHistoryMessage(record.message, options),\n ),\n options,\n );\n}\n\nfunction selectRecentMessages(records: LogRecord[], options: HistoryWindow): LogRecord[] {\n const sinceMs = options.now.getTime() - options.recentDays * 24 * 60 * 60 * 1000;\n return records\n .filter((record) => isRecentHistoryMessage(record.message, sinceMs))\n .slice(-options.maxMessages);\n}\n\nfunction isTopLevelHistoryMessage(\n message: ConversationLogMessage,\n filter: RenderableMessageFilter,\n): boolean {\n if (!isRenderableConversationMessage(message, filter)) return false;\n return !message.threadTs;\n}\n\nfunction isRecentHistoryMessage(message: ConversationLogMessage, sinceMs: number): boolean {\n if (!message.date) return true;\n const dateMs = new Date(message.date).getTime();\n return !Number.isFinite(dateMs) || dateMs >= sinceMs;\n}\n\nfunction selectExistingSessionSyncMessages(\n records: LogRecord[],\n options: RenderableMessageFilter & { sessionKey: string | null },\n): LogRecord[] {\n const threadId = options.sessionKey ? extractSessionSuffix(options.sessionKey) : null;\n return dedupeAndSortRecords(\n recordsBeforeCurrentMessage(records, options.excludeMessageId).filter((record) => {\n if (!isRenderableConversationMessage(record.message, options)) return false;\n if (!threadId) return !record.message.threadTs;\n return record.message.ts === threadId || record.message.threadTs === threadId;\n }),\n );\n}\n\nfunction recordsBeforeCurrentMessage(records: LogRecord[], currentMessageId?: string): LogRecord[] {\n if (!currentMessageId) return records;\n const currentRecord = findLogRecordById(records, currentMessageId);\n if (!currentRecord) return records;\n return records.filter((record) => record.index < currentRecord.index);\n}\n\nfunction latestSyncMessageId(\n records: LogRecord[],\n options: RenderableMessageFilter & { sessionKey: string | null },\n): string | undefined {\n return selectExistingSessionSyncMessages(records, options).at(-1)?.message.ts;\n}\n\ninterface RenderableMessageFilter {\n excludeMessageId?: string;\n isCommandText: (text: string) => boolean;\n}\n\nfunction isRenderableConversationMessage(\n message: ConversationLogMessage,\n filter: RenderableMessageFilter,\n): boolean {\n if (filter.excludeMessageId && message.ts === filter.excludeMessageId) return false;\n if (message.isMessagingBot && message.sessionKey) return false;\n if (!message.isMessagingBot && filter.isCommandText(message.text ?? \"\")) return false;\n return !!message.text?.trim();\n}\n\nfunction dedupeAndSortRecords(records: LogRecord[]): LogRecord[] {\n const byKey = new Map<string, LogRecord>();\n for (const record of records) {\n byKey.set(record.message.ts ?? `line:${record.index}`, record);\n }\n\n return Array.from(byKey.values()).toSorted((a, b) => {\n const aTime = sortTime(a);\n const bTime = sortTime(b);\n if (aTime !== bTime) return aTime - bTime;\n return a.index - b.index;\n });\n}\n\nfunction sortTime(record: LogRecord): number {\n if (record.message.date) {\n const dateMs = new Date(record.message.date).getTime();\n if (Number.isFinite(dateMs)) return dateMs;\n }\n\n if (record.message.ts) {\n const tsMs = Number(record.message.ts) * 1000;\n if (Number.isFinite(tsMs)) return tsMs;\n }\n\n return record.index;\n}\n\nasync function bootstrapSessionFromLog(\n session: { office: Office; sessionKey: string },\n records: LogRecord[],\n lastMessageId = records.at(-1)?.message.ts,\n): Promise<void> {\n const sessionManager = await SessionStore.open(session.office, session.sessionKey);\n try {\n await appendLogRecordsToSession(sessionManager, records);\n await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {\n lastMessageId,\n });\n } finally {\n await sessionManager.close();\n }\n}\n\ninterface HistoryWindow {\n recentDays: number;\n maxMessages: number;\n now: Date;\n}\n\nasync function syncSessionManagerFromLog(\n sessionManager: SessionStore,\n records: LogRecord[],\n historyWindow: HistoryWindow,\n): Promise<void> {\n if (records.length === 0) return;\n\n const existingEntries = await sessionManager.getEntries();\n const resetAt = getLatestChatSyncResetAt(existingEntries);\n const controlledIds = new Set(\n existingEntries.flatMap((entry) => {\n if (\n entry.type !== \"custom\" ||\n entry.customType !== CONTROL_INPUT_CUSTOM_TYPE ||\n !isRecord(entry.data)\n )\n return [];\n return typeof entry.data.messageId === \"string\" ? [entry.data.messageId] : [];\n }),\n );\n const eligibleRecords = records.filter(\n (record) =>\n !controlledIds.has(record.message.ts ?? \"\") && (!resetAt || isAfterReset(record, resetAt)),\n );\n const lastSyncedMessageId = getLatestChatSyncMessageId(existingEntries);\n const lastSyncedIndex = lastSyncedMessageId\n ? eligibleRecords.findIndex((record) => record.message.ts === lastSyncedMessageId)\n : -1;\n const syncCandidates = selectRecentMessages(\n eligibleRecords.slice(lastSyncedIndex + 1),\n historyWindow,\n );\n if (syncCandidates.length === 0) return;\n\n const represented = buildRepresentedMessageCounts(existingEntries);\n const newRecords = syncCandidates.filter(\n (record) => !consumeRepresentedLogMessage(record, represented),\n );\n if (newRecords.length === 0) return;\n\n const lastMessageId = syncCandidates.at(-1)?.message.ts;\n await appendLogRecordsToSession(sessionManager, newRecords);\n await sessionManager.appendCustomEntry(CHAT_SYNC_CUSTOM_TYPE, {\n lastMessageId,\n });\n}\n\nasync function appendLogRecordsToSession(\n sessionManager: SessionStore,\n records: LogRecord[],\n): Promise<void> {\n for (const record of records) {\n const message = buildHistorySessionMessage(record.message);\n if (message) await sessionManager.appendMessage(message);\n }\n}\n\nfunction isChatSyncMarker(entry: SessionEntry): entry is Extract<SessionEntry, { type: \"custom\" }> {\n return entry.type === \"custom\" && entry.customType === CHAT_SYNC_CUSTOM_TYPE;\n}\n\nfunction markerResetAt(entry: SessionEntry): number | undefined {\n if (!isChatSyncMarker(entry)) return undefined;\n if (!isRecord(entry.data) || typeof entry.data.resetAt !== \"string\") return undefined;\n const resetAt = new Date(entry.data.resetAt).getTime();\n return Number.isFinite(resetAt) ? resetAt : undefined;\n}\n\nfunction getLatestChatSyncResetAt(entries: SessionEntry[]): number | undefined {\n for (const entry of entries.toReversed()) {\n const resetAt = markerResetAt(entry);\n if (resetAt !== undefined) return resetAt;\n }\n return undefined;\n}\n\nfunction isAfterReset(record: LogRecord, resetAt: number): boolean {\n if (!record.message.date) return false;\n const messageTime = new Date(record.message.date).getTime();\n return Number.isFinite(messageTime) && messageTime >= resetAt;\n}\n\nfunction getLatestChatSyncMessageId(entries: SessionEntry[]): string | undefined {\n const marker = entries.toReversed().find(isChatSyncMarker);\n const lastMessageId = isRecord(marker?.data) ? marker.data.lastMessageId : undefined;\n return typeof lastMessageId === \"string\" ? lastMessageId : undefined;\n}\n\nfunction buildRepresentedMessageCounts(entries: SessionEntry[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const entry of entries) {\n const comparable = comparableSessionMessage(entry);\n if (!comparable) continue;\n counts.set(comparable, (counts.get(comparable) ?? 0) + 1);\n }\n return counts;\n}\n\nfunction consumeRepresentedLogMessage(record: LogRecord, counts: Map<string, number>): boolean {\n const comparable = comparableLogMessage(record.message);\n if (!comparable) return false;\n\n const asChatLine = `user:${comparable.slice(comparable.indexOf(\":\") + 1)}`;\n const key = counts.get(comparable)\n ? comparable\n : (presentedAnswerKey(comparable, counts) ?? (counts.get(asChatLine) ? asChatLine : undefined));\n if (!key) return false;\n counts.set(key, (counts.get(key) ?? 0) - 1);\n return true;\n}\n\nfunction presentedAnswerKey(comparable: string, counts: Map<string, number>): string | undefined {\n if (!comparable.startsWith(ASSISTANT_KEY_PREFIX)) return undefined;\n const posted = comparable.slice(ASSISTANT_KEY_PREFIX.length);\n for (const [key, count] of counts) {\n if (count <= 0 || !key.startsWith(ASSISTANT_KEY_PREFIX)) continue;\n const answer = key.slice(ASSISTANT_KEY_PREFIX.length);\n if (posted.endsWith(`\\n\\n${answer}`)) return key;\n }\n return undefined;\n}\n\nconst ASSISTANT_KEY_PREFIX = \"assistant:\";\n\nfunction comparableSessionMessage(entry: SessionEntry): string | null {\n if (entry.type !== \"message\") return null;\n const role = entry.message.role;\n if (role !== \"user\" && role !== \"assistant\") return null;\n\n const raw = getSessionMessageText(entry);\n const text = normalizeComparableText(role === \"assistant\" ? stripTriggerSignature(raw) : raw);\n if (!text) return null;\n return `${role}:${text}`;\n}\n\nfunction comparableLogMessage(message: ConversationLogMessage): string | null {\n const text = historyMessageText(message);\n if (!text) return null;\n return `${message.isMessagingBot ? \"assistant\" : \"user\"}:${normalizeComparableText(text)}`;\n}\n\nfunction historyMessageText(message: ConversationLogMessage): string {\n const text = message.text?.trim() ?? \"\";\n return message.isMessagingBot ? stripTriggerSignature(text) : text;\n}\n\nfunction getSessionMessageText(entry: SessionEntry): string {\n if (entry.type !== \"message\" || !(\"content\" in entry.message)) return \"\";\n const content = entry.message.content;\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((part) => (part.type === \"text\" && \"text\" in part ? part.text : \"\"))\n .join(\"\\n\");\n}\n\nconst normalizeComparableText = stripHistoryLinePrefix;\n\nfunction buildHistorySessionMessage(message: ConversationLogMessage): Message | null {\n const text = historyMessageText(message);\n if (!text) return null;\n return {\n role: \"user\",\n content: [{ type: \"text\", text: formatHistoryMessage({ ...message, text }) }],\n timestamp: parseMessageTimestamp(message) ?? Date.now(),\n };\n}\n\nfunction buildThreadRootSeed(\n message: ConversationLogMessage | undefined,\n): ThreadRootMessage | null {\n if (!message) return null;\n return {\n text: message.text,\n userName: message.userName,\n user: message.user,\n };\n}\n\nfunction parseMessageTimestamp(message: ConversationLogMessage): number | undefined {\n if (message.date) {\n const dateMs = new Date(message.date).getTime();\n if (Number.isFinite(dateMs)) return dateMs;\n }\n\n if (message.ts) {\n const tsMs = Number(message.ts) * 1000;\n if (Number.isFinite(tsMs)) return tsMs;\n }\n\n return undefined;\n}\n\nfunction formatHistoryMessage(message: ConversationLogMessage): string {\n return formatHistoryLine({\n date: message.date ? new Date(message.date) : undefined,\n userName: message.userName || message.user,\n text: message.text?.trim() ?? \"\",\n });\n}\n\nexport function readConversationLog(office: Office): LogRecord[] {\n const logFile = office.logPath;\n const raw = readTextFileNoFollowIfExists(logFile);\n if (raw === undefined) return [];\n\n const records: LogRecord[] = [];\n for (const [index, line] of raw.trim().split(\"\\n\").filter(Boolean).entries()) {\n const message = parseLogLine(line, logFile, index + 1);\n if (message) records.push({ message, index });\n }\n return coalesceMessagingBotLogChunks(records);\n}\n\nfunction parseLogLine(\n line: string,\n logFile: string,\n lineNumber: number,\n): ConversationLogMessage | undefined {\n try {\n return parseJsonValue(\n line,\n (value): value is ConversationLogMessage => isRecord(value),\n (detail, kind) => (kind === \"shape\" ? \"expected a JSON object\" : detail),\n );\n } catch (err) {\n log.logWarning(`Skipping malformed log entry at ${logFile}:${lineNumber}`, errorMessage(err));\n return undefined;\n }\n}\n\nfunction coalesceMessagingBotLogChunks(records: LogRecord[]): LogRecord[] {\n const coalesced: LogRecord[] = [];\n for (const record of records) {\n const previous = coalesced.at(-1);\n if (previous && canCoalesceMessagingBotLogChunk(previous.message, record.message)) {\n previous.message.text = `${previous.message.text ?? \"\"}${record.message.text ?? \"\"}`;\n continue;\n }\n coalesced.push({ ...record, message: { ...record.message } });\n }\n return coalesced;\n}\n\nfunction canCoalesceMessagingBotLogChunk(\n previous: ConversationLogMessage,\n current: ConversationLogMessage,\n): boolean {\n return (\n previous.isMessagingBot === true &&\n current.isMessagingBot === true &&\n !!previous.ts &&\n previous.ts === current.ts &&\n previous.threadTs === current.threadTs &&\n previous.user === current.user\n );\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
+ export declare function wrapCompactionSummary(summary: string): string;
3
+ export declare function compactionSummaryOf(message: AgentMessage): string | undefined;
4
+ //# sourceMappingURL=compaction-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction-summary.d.ts","sourceRoot":"","sources":["../../src/sessions/compaction-summary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAMlE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAS7E"}
@@ -0,0 +1,16 @@
1
+ const COMPACTION_SUMMARY_PREFIX = "The conversation history before this point was compacted into the following summary:\n\n<summary>\n";
2
+ const COMPACTION_SUMMARY_SUFFIX = "\n</summary>";
3
+ export function wrapCompactionSummary(summary) {
4
+ return COMPACTION_SUMMARY_PREFIX + summary + COMPACTION_SUMMARY_SUFFIX;
5
+ }
6
+ export function compactionSummaryOf(message) {
7
+ if (message.role !== "user")
8
+ return undefined;
9
+ const text = typeof message.content === "string"
10
+ ? message.content
11
+ : message.content.map((part) => (part.type === "text" ? part.text : "")).join("");
12
+ if (!text.startsWith(COMPACTION_SUMMARY_PREFIX) || !text.endsWith(COMPACTION_SUMMARY_SUFFIX))
13
+ return undefined;
14
+ return text.slice(COMPACTION_SUMMARY_PREFIX.length, -COMPACTION_SUMMARY_SUFFIX.length);
15
+ }
16
+ //# sourceMappingURL=compaction-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction-summary.js","sourceRoot":"","sources":["../../src/sessions/compaction-summary.ts"],"names":[],"mappings":"AAEA,MAAM,yBAAyB,GAC7B,qGAAqG,CAAC;AACxG,MAAM,yBAAyB,GAAG,cAAc,CAAC;AAEjD,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,OAAO,yBAAyB,GAAG,OAAO,GAAG,yBAAyB,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAqB;IACvD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,IAAI,GACR,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;QACjC,CAAC,CAAC,OAAO,CAAC,OAAO;QACjB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtF,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAC1F,OAAO,SAAS,CAAC;IACnB,OAAO,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,MAAM,EAAE,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC;AACzF,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\n\nconst COMPACTION_SUMMARY_PREFIX =\n \"The conversation history before this point was compacted into the following summary:\\n\\n<summary>\\n\";\nconst COMPACTION_SUMMARY_SUFFIX = \"\\n</summary>\";\n\nexport function wrapCompactionSummary(summary: string): string {\n return COMPACTION_SUMMARY_PREFIX + summary + COMPACTION_SUMMARY_SUFFIX;\n}\n\nexport function compactionSummaryOf(message: AgentMessage): string | undefined {\n if (message.role !== \"user\") return undefined;\n const text =\n typeof message.content === \"string\"\n ? message.content\n : message.content.map((part) => (part.type === \"text\" ? part.text : \"\")).join(\"\");\n if (!text.startsWith(COMPACTION_SUMMARY_PREFIX) || !text.endsWith(COMPACTION_SUMMARY_SUFFIX))\n return undefined;\n return text.slice(COMPACTION_SUMMARY_PREFIX.length, -COMPACTION_SUMMARY_SUFFIX.length);\n}\n"]}
@@ -15,4 +15,5 @@ export declare function conversationIdOf(sessionKey: string): string;
15
15
  export declare function threadSuffixOf(sessionKey: string): string | null;
16
16
  export declare function resolveChatSessionKey(options: ResolveSessionKeyOptions): string;
17
17
  export declare function inferConversationKind(platform: string, conversationId: string): ConversationKind;
18
+ export declare function extractSessionSuffix(sessionKey: string): string;
18
19
  //# sourceMappingURL=session-key.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-key.d.ts","sourceRoot":"","sources":["../../src/sessions/session-key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAyB3D,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAS1E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,qCAAqC,CACnD,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,MAAM,CAYR;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,MAAM,CAMT;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAgB/E;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAchG"}
1
+ {"version":3,"file":"session-key.d.ts","sourceRoot":"","sources":["../../src/sessions/session-key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAyB3D,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAS1E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,qCAAqC,CACnD,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,MAAM,CAYR;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,MAAM,CAMT;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAgB/E;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAchG;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D"}
@@ -85,4 +85,7 @@ export function inferConversationKind(platform, conversationId) {
85
85
  }
86
86
  return "shared";
87
87
  }
88
+ export function extractSessionSuffix(sessionKey) {
89
+ return assertSessionSuffix(threadSuffixOf(sessionKey) ?? sessionKey);
90
+ }
88
91
  //# sourceMappingURL=session-key.js.map