sessionLog.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. var sessionLog_exports = {};
  30. __export(sessionLog_exports, {
  31. SessionLog: () => SessionLog
  32. });
  33. module.exports = __toCommonJS(sessionLog_exports);
  34. var import_fs = __toESM(require("fs"));
  35. var import_path = __toESM(require("path"));
  36. var import_log = require("../log");
  37. var import_config = require("./config");
  38. class SessionLog {
  39. constructor(sessionFolder) {
  40. this._ordinal = 0;
  41. this._pendingEntries = [];
  42. this._sessionFileQueue = Promise.resolve();
  43. this._folder = sessionFolder;
  44. this._file = import_path.default.join(this._folder, "session.md");
  45. }
  46. static async create(config, clientInfo) {
  47. const sessionFolder = await (0, import_config.outputFile)(config, clientInfo, `session-${Date.now()}`, { origin: "code", reason: "Saving session" });
  48. await import_fs.default.promises.mkdir(sessionFolder, { recursive: true });
  49. console.error(`Session: ${sessionFolder}`);
  50. return new SessionLog(sessionFolder);
  51. }
  52. logResponse(response) {
  53. const entry = {
  54. timestamp: performance.now(),
  55. toolCall: {
  56. toolName: response.toolName,
  57. toolArgs: response.toolArgs,
  58. result: response.result(),
  59. isError: response.isError()
  60. },
  61. code: response.code(),
  62. tabSnapshot: response.tabSnapshot()
  63. };
  64. this._appendEntry(entry);
  65. }
  66. logUserAction(action, tab, code, isUpdate) {
  67. code = code.trim();
  68. if (isUpdate) {
  69. const lastEntry = this._pendingEntries[this._pendingEntries.length - 1];
  70. if (lastEntry?.userAction?.name === action.name) {
  71. lastEntry.userAction = action;
  72. lastEntry.code = code;
  73. return;
  74. }
  75. }
  76. if (action.name === "navigate") {
  77. const lastEntry = this._pendingEntries[this._pendingEntries.length - 1];
  78. if (lastEntry?.tabSnapshot?.url === action.url)
  79. return;
  80. }
  81. const entry = {
  82. timestamp: performance.now(),
  83. userAction: action,
  84. code,
  85. tabSnapshot: {
  86. url: tab.page.url(),
  87. title: "",
  88. ariaSnapshot: action.ariaSnapshot || "",
  89. modalStates: [],
  90. consoleMessages: [],
  91. downloads: []
  92. }
  93. };
  94. this._appendEntry(entry);
  95. }
  96. _appendEntry(entry) {
  97. this._pendingEntries.push(entry);
  98. if (this._flushEntriesTimeout)
  99. clearTimeout(this._flushEntriesTimeout);
  100. this._flushEntriesTimeout = setTimeout(() => this._flushEntries(), 1e3);
  101. }
  102. async _flushEntries() {
  103. clearTimeout(this._flushEntriesTimeout);
  104. const entries = this._pendingEntries;
  105. this._pendingEntries = [];
  106. const lines = [""];
  107. for (const entry of entries) {
  108. const ordinal = (++this._ordinal).toString().padStart(3, "0");
  109. if (entry.toolCall) {
  110. lines.push(
  111. `### Tool call: ${entry.toolCall.toolName}`,
  112. `- Args`,
  113. "```json",
  114. JSON.stringify(entry.toolCall.toolArgs, null, 2),
  115. "```"
  116. );
  117. if (entry.toolCall.result) {
  118. lines.push(
  119. entry.toolCall.isError ? `- Error` : `- Result`,
  120. "```",
  121. entry.toolCall.result,
  122. "```"
  123. );
  124. }
  125. }
  126. if (entry.userAction) {
  127. const actionData = { ...entry.userAction };
  128. delete actionData.ariaSnapshot;
  129. delete actionData.selector;
  130. delete actionData.signals;
  131. lines.push(
  132. `### User action: ${entry.userAction.name}`,
  133. `- Args`,
  134. "```json",
  135. JSON.stringify(actionData, null, 2),
  136. "```"
  137. );
  138. }
  139. if (entry.code) {
  140. lines.push(
  141. `- Code`,
  142. "```js",
  143. entry.code,
  144. "```"
  145. );
  146. }
  147. if (entry.tabSnapshot) {
  148. const fileName = `${ordinal}.snapshot.yml`;
  149. import_fs.default.promises.writeFile(import_path.default.join(this._folder, fileName), entry.tabSnapshot.ariaSnapshot).catch(import_log.logUnhandledError);
  150. lines.push(`- Snapshot: ${fileName}`);
  151. }
  152. lines.push("", "");
  153. }
  154. this._sessionFileQueue = this._sessionFileQueue.then(() => import_fs.default.promises.appendFile(this._file, lines.join("\n")));
  155. }
  156. }
  157. // Annotate the CommonJS export names for ESM import in node:
  158. 0 && (module.exports = {
  159. SessionLog
  160. });