agent-browser 0.1.3 → 0.3.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 (224) hide show
  1. package/AGENTS.md +26 -0
  2. package/README.md +68 -11
  3. package/benchmark/benchmark.ts +521 -0
  4. package/benchmark/run.ts +322 -0
  5. package/bin/agent-browser +0 -0
  6. package/cli/Cargo.lock +114 -0
  7. package/cli/Cargo.toml +17 -0
  8. package/cli/src/main.rs +332 -0
  9. package/cli/target/.rustc_info.json +1 -0
  10. package/cli/target/CACHEDIR.TAG +3 -0
  11. package/cli/target/release/.cargo-lock +0 -0
  12. package/cli/target/release/.fingerprint/agent-browser-5894536b887e2ce7/bin-agent-browser +1 -0
  13. package/cli/target/release/.fingerprint/agent-browser-5894536b887e2ce7/bin-agent-browser.json +1 -0
  14. package/cli/target/release/.fingerprint/agent-browser-5894536b887e2ce7/dep-bin-agent-browser +0 -0
  15. package/cli/target/release/.fingerprint/agent-browser-5894536b887e2ce7/invoked.timestamp +1 -0
  16. package/cli/target/release/.fingerprint/agent-browser-5894536b887e2ce7/output-bin-agent-browser +2 -0
  17. package/cli/target/release/.fingerprint/itoa-653b9192107a1caa/dep-lib-itoa +0 -0
  18. package/cli/target/release/.fingerprint/itoa-653b9192107a1caa/invoked.timestamp +1 -0
  19. package/cli/target/release/.fingerprint/itoa-653b9192107a1caa/lib-itoa +1 -0
  20. package/cli/target/release/.fingerprint/itoa-653b9192107a1caa/lib-itoa.json +1 -0
  21. package/cli/target/release/.fingerprint/libc-0303d277881093f4/build-script-build-script-build +1 -0
  22. package/cli/target/release/.fingerprint/libc-0303d277881093f4/build-script-build-script-build.json +1 -0
  23. package/cli/target/release/.fingerprint/libc-0303d277881093f4/dep-build-script-build-script-build +0 -0
  24. package/cli/target/release/.fingerprint/libc-0303d277881093f4/invoked.timestamp +1 -0
  25. package/cli/target/release/.fingerprint/libc-b8c0d8e35a1980d3/run-build-script-build-script-build +1 -0
  26. package/cli/target/release/.fingerprint/libc-b8c0d8e35a1980d3/run-build-script-build-script-build.json +1 -0
  27. package/cli/target/release/.fingerprint/libc-d843359d3dd4757b/dep-lib-libc +0 -0
  28. package/cli/target/release/.fingerprint/libc-d843359d3dd4757b/invoked.timestamp +1 -0
  29. package/cli/target/release/.fingerprint/libc-d843359d3dd4757b/lib-libc +1 -0
  30. package/cli/target/release/.fingerprint/libc-d843359d3dd4757b/lib-libc.json +1 -0
  31. package/cli/target/release/.fingerprint/memchr-dcaf8011940d18dd/dep-lib-memchr +0 -0
  32. package/cli/target/release/.fingerprint/memchr-dcaf8011940d18dd/invoked.timestamp +1 -0
  33. package/cli/target/release/.fingerprint/memchr-dcaf8011940d18dd/lib-memchr +1 -0
  34. package/cli/target/release/.fingerprint/memchr-dcaf8011940d18dd/lib-memchr.json +1 -0
  35. package/cli/target/release/.fingerprint/proc-macro2-291b57751730d5b3/build-script-build-script-build +1 -0
  36. package/cli/target/release/.fingerprint/proc-macro2-291b57751730d5b3/build-script-build-script-build.json +1 -0
  37. package/cli/target/release/.fingerprint/proc-macro2-291b57751730d5b3/dep-build-script-build-script-build +0 -0
  38. package/cli/target/release/.fingerprint/proc-macro2-291b57751730d5b3/invoked.timestamp +1 -0
  39. package/cli/target/release/.fingerprint/proc-macro2-a753b344a6b4aa98/dep-lib-proc_macro2 +0 -0
  40. package/cli/target/release/.fingerprint/proc-macro2-a753b344a6b4aa98/invoked.timestamp +1 -0
  41. package/cli/target/release/.fingerprint/proc-macro2-a753b344a6b4aa98/lib-proc_macro2 +1 -0
  42. package/cli/target/release/.fingerprint/proc-macro2-a753b344a6b4aa98/lib-proc_macro2.json +1 -0
  43. package/cli/target/release/.fingerprint/proc-macro2-fc2999f6676f03db/run-build-script-build-script-build +1 -0
  44. package/cli/target/release/.fingerprint/proc-macro2-fc2999f6676f03db/run-build-script-build-script-build.json +1 -0
  45. package/cli/target/release/.fingerprint/quote-352ae41707d371c9/run-build-script-build-script-build +1 -0
  46. package/cli/target/release/.fingerprint/quote-352ae41707d371c9/run-build-script-build-script-build.json +1 -0
  47. package/cli/target/release/.fingerprint/quote-7d13be3cbe4f9de4/build-script-build-script-build +1 -0
  48. package/cli/target/release/.fingerprint/quote-7d13be3cbe4f9de4/build-script-build-script-build.json +1 -0
  49. package/cli/target/release/.fingerprint/quote-7d13be3cbe4f9de4/dep-build-script-build-script-build +0 -0
  50. package/cli/target/release/.fingerprint/quote-7d13be3cbe4f9de4/invoked.timestamp +1 -0
  51. package/cli/target/release/.fingerprint/quote-833e6725e0f7d298/dep-lib-quote +0 -0
  52. package/cli/target/release/.fingerprint/quote-833e6725e0f7d298/invoked.timestamp +1 -0
  53. package/cli/target/release/.fingerprint/quote-833e6725e0f7d298/lib-quote +1 -0
  54. package/cli/target/release/.fingerprint/quote-833e6725e0f7d298/lib-quote.json +1 -0
  55. package/cli/target/release/.fingerprint/serde-b8c046c16de48f41/run-build-script-build-script-build +1 -0
  56. package/cli/target/release/.fingerprint/serde-b8c046c16de48f41/run-build-script-build-script-build.json +1 -0
  57. package/cli/target/release/.fingerprint/serde-d35d32ab52b82a81/build-script-build-script-build +1 -0
  58. package/cli/target/release/.fingerprint/serde-d35d32ab52b82a81/build-script-build-script-build.json +1 -0
  59. package/cli/target/release/.fingerprint/serde-d35d32ab52b82a81/dep-build-script-build-script-build +0 -0
  60. package/cli/target/release/.fingerprint/serde-d35d32ab52b82a81/invoked.timestamp +1 -0
  61. package/cli/target/release/.fingerprint/serde-d6fb44202dad3efd/dep-lib-serde +0 -0
  62. package/cli/target/release/.fingerprint/serde-d6fb44202dad3efd/invoked.timestamp +1 -0
  63. package/cli/target/release/.fingerprint/serde-d6fb44202dad3efd/lib-serde +1 -0
  64. package/cli/target/release/.fingerprint/serde-d6fb44202dad3efd/lib-serde.json +1 -0
  65. package/cli/target/release/.fingerprint/serde_core-0f7ba2581c8c0423/dep-lib-serde_core +0 -0
  66. package/cli/target/release/.fingerprint/serde_core-0f7ba2581c8c0423/invoked.timestamp +1 -0
  67. package/cli/target/release/.fingerprint/serde_core-0f7ba2581c8c0423/lib-serde_core +1 -0
  68. package/cli/target/release/.fingerprint/serde_core-0f7ba2581c8c0423/lib-serde_core.json +1 -0
  69. package/cli/target/release/.fingerprint/serde_core-74db491143173930/run-build-script-build-script-build +1 -0
  70. package/cli/target/release/.fingerprint/serde_core-74db491143173930/run-build-script-build-script-build.json +1 -0
  71. package/cli/target/release/.fingerprint/serde_core-f043ae3f4b601577/build-script-build-script-build +1 -0
  72. package/cli/target/release/.fingerprint/serde_core-f043ae3f4b601577/build-script-build-script-build.json +1 -0
  73. package/cli/target/release/.fingerprint/serde_core-f043ae3f4b601577/dep-build-script-build-script-build +0 -0
  74. package/cli/target/release/.fingerprint/serde_core-f043ae3f4b601577/invoked.timestamp +1 -0
  75. package/cli/target/release/.fingerprint/serde_derive-a5d13e0e658ceae3/dep-lib-serde_derive +0 -0
  76. package/cli/target/release/.fingerprint/serde_derive-a5d13e0e658ceae3/invoked.timestamp +1 -0
  77. package/cli/target/release/.fingerprint/serde_derive-a5d13e0e658ceae3/lib-serde_derive +1 -0
  78. package/cli/target/release/.fingerprint/serde_derive-a5d13e0e658ceae3/lib-serde_derive.json +1 -0
  79. package/cli/target/release/.fingerprint/serde_json-a8467019a959068f/run-build-script-build-script-build +1 -0
  80. package/cli/target/release/.fingerprint/serde_json-a8467019a959068f/run-build-script-build-script-build.json +1 -0
  81. package/cli/target/release/.fingerprint/serde_json-bfa3f43b57842d41/build-script-build-script-build +1 -0
  82. package/cli/target/release/.fingerprint/serde_json-bfa3f43b57842d41/build-script-build-script-build.json +1 -0
  83. package/cli/target/release/.fingerprint/serde_json-bfa3f43b57842d41/dep-build-script-build-script-build +0 -0
  84. package/cli/target/release/.fingerprint/serde_json-bfa3f43b57842d41/invoked.timestamp +1 -0
  85. package/cli/target/release/.fingerprint/serde_json-f61651a65bf0eb31/dep-lib-serde_json +0 -0
  86. package/cli/target/release/.fingerprint/serde_json-f61651a65bf0eb31/invoked.timestamp +1 -0
  87. package/cli/target/release/.fingerprint/serde_json-f61651a65bf0eb31/lib-serde_json +1 -0
  88. package/cli/target/release/.fingerprint/serde_json-f61651a65bf0eb31/lib-serde_json.json +1 -0
  89. package/cli/target/release/.fingerprint/syn-6f9a22f8c7f909b0/dep-lib-syn +0 -0
  90. package/cli/target/release/.fingerprint/syn-6f9a22f8c7f909b0/invoked.timestamp +1 -0
  91. package/cli/target/release/.fingerprint/syn-6f9a22f8c7f909b0/lib-syn +1 -0
  92. package/cli/target/release/.fingerprint/syn-6f9a22f8c7f909b0/lib-syn.json +1 -0
  93. package/cli/target/release/.fingerprint/unicode-ident-60c57228d30a23d0/dep-lib-unicode_ident +0 -0
  94. package/cli/target/release/.fingerprint/unicode-ident-60c57228d30a23d0/invoked.timestamp +1 -0
  95. package/cli/target/release/.fingerprint/unicode-ident-60c57228d30a23d0/lib-unicode_ident +1 -0
  96. package/cli/target/release/.fingerprint/unicode-ident-60c57228d30a23d0/lib-unicode_ident.json +1 -0
  97. package/cli/target/release/.fingerprint/zmij-60b0e0e9d7c08f71/run-build-script-build-script-build +1 -0
  98. package/cli/target/release/.fingerprint/zmij-60b0e0e9d7c08f71/run-build-script-build-script-build.json +1 -0
  99. package/cli/target/release/.fingerprint/zmij-9501bcbd6d8b933c/dep-lib-zmij +0 -0
  100. package/cli/target/release/.fingerprint/zmij-9501bcbd6d8b933c/invoked.timestamp +1 -0
  101. package/cli/target/release/.fingerprint/zmij-9501bcbd6d8b933c/lib-zmij +1 -0
  102. package/cli/target/release/.fingerprint/zmij-9501bcbd6d8b933c/lib-zmij.json +1 -0
  103. package/cli/target/release/.fingerprint/zmij-aa602f885104061e/build-script-build-script-build +1 -0
  104. package/cli/target/release/.fingerprint/zmij-aa602f885104061e/build-script-build-script-build.json +1 -0
  105. package/cli/target/release/.fingerprint/zmij-aa602f885104061e/dep-build-script-build-script-build +0 -0
  106. package/cli/target/release/.fingerprint/zmij-aa602f885104061e/invoked.timestamp +1 -0
  107. package/cli/target/release/agent-browser +0 -0
  108. package/cli/target/release/agent-browser.d +1 -0
  109. package/cli/target/release/build/libc-0303d277881093f4/build-script-build +0 -0
  110. package/cli/target/release/build/libc-0303d277881093f4/build_script_build-0303d277881093f4 +0 -0
  111. package/cli/target/release/build/libc-0303d277881093f4/build_script_build-0303d277881093f4.d +5 -0
  112. package/cli/target/release/build/libc-b8c0d8e35a1980d3/invoked.timestamp +1 -0
  113. package/cli/target/release/build/libc-b8c0d8e35a1980d3/output +25 -0
  114. package/cli/target/release/build/libc-b8c0d8e35a1980d3/root-output +1 -0
  115. package/cli/target/release/build/libc-b8c0d8e35a1980d3/stderr +0 -0
  116. package/cli/target/release/build/proc-macro2-291b57751730d5b3/build-script-build +0 -0
  117. package/cli/target/release/build/proc-macro2-291b57751730d5b3/build_script_build-291b57751730d5b3 +0 -0
  118. package/cli/target/release/build/proc-macro2-291b57751730d5b3/build_script_build-291b57751730d5b3.d +5 -0
  119. package/cli/target/release/build/proc-macro2-fc2999f6676f03db/invoked.timestamp +1 -0
  120. package/cli/target/release/build/proc-macro2-fc2999f6676f03db/output +23 -0
  121. package/cli/target/release/build/proc-macro2-fc2999f6676f03db/root-output +1 -0
  122. package/cli/target/release/build/proc-macro2-fc2999f6676f03db/stderr +0 -0
  123. package/cli/target/release/build/quote-352ae41707d371c9/invoked.timestamp +1 -0
  124. package/cli/target/release/build/quote-352ae41707d371c9/output +2 -0
  125. package/cli/target/release/build/quote-352ae41707d371c9/root-output +1 -0
  126. package/cli/target/release/build/quote-352ae41707d371c9/stderr +0 -0
  127. package/cli/target/release/build/quote-7d13be3cbe4f9de4/build-script-build +0 -0
  128. package/cli/target/release/build/quote-7d13be3cbe4f9de4/build_script_build-7d13be3cbe4f9de4 +0 -0
  129. package/cli/target/release/build/quote-7d13be3cbe4f9de4/build_script_build-7d13be3cbe4f9de4.d +5 -0
  130. package/cli/target/release/build/serde-b8c046c16de48f41/invoked.timestamp +1 -0
  131. package/cli/target/release/build/serde-b8c046c16de48f41/out/private.rs +6 -0
  132. package/cli/target/release/build/serde-b8c046c16de48f41/output +13 -0
  133. package/cli/target/release/build/serde-b8c046c16de48f41/root-output +1 -0
  134. package/cli/target/release/build/serde-b8c046c16de48f41/stderr +0 -0
  135. package/cli/target/release/build/serde-d35d32ab52b82a81/build-script-build +0 -0
  136. package/cli/target/release/build/serde-d35d32ab52b82a81/build_script_build-d35d32ab52b82a81 +0 -0
  137. package/cli/target/release/build/serde-d35d32ab52b82a81/build_script_build-d35d32ab52b82a81.d +5 -0
  138. package/cli/target/release/build/serde_core-74db491143173930/invoked.timestamp +1 -0
  139. package/cli/target/release/build/serde_core-74db491143173930/out/private.rs +5 -0
  140. package/cli/target/release/build/serde_core-74db491143173930/output +11 -0
  141. package/cli/target/release/build/serde_core-74db491143173930/root-output +1 -0
  142. package/cli/target/release/build/serde_core-74db491143173930/stderr +0 -0
  143. package/cli/target/release/build/serde_core-f043ae3f4b601577/build-script-build +0 -0
  144. package/cli/target/release/build/serde_core-f043ae3f4b601577/build_script_build-f043ae3f4b601577 +0 -0
  145. package/cli/target/release/build/serde_core-f043ae3f4b601577/build_script_build-f043ae3f4b601577.d +5 -0
  146. package/cli/target/release/build/serde_json-a8467019a959068f/invoked.timestamp +1 -0
  147. package/cli/target/release/build/serde_json-a8467019a959068f/output +3 -0
  148. package/cli/target/release/build/serde_json-a8467019a959068f/root-output +1 -0
  149. package/cli/target/release/build/serde_json-a8467019a959068f/stderr +0 -0
  150. package/cli/target/release/build/serde_json-bfa3f43b57842d41/build-script-build +0 -0
  151. package/cli/target/release/build/serde_json-bfa3f43b57842d41/build_script_build-bfa3f43b57842d41 +0 -0
  152. package/cli/target/release/build/serde_json-bfa3f43b57842d41/build_script_build-bfa3f43b57842d41.d +5 -0
  153. package/cli/target/release/build/zmij-60b0e0e9d7c08f71/invoked.timestamp +1 -0
  154. package/cli/target/release/build/zmij-60b0e0e9d7c08f71/output +3 -0
  155. package/cli/target/release/build/zmij-60b0e0e9d7c08f71/root-output +1 -0
  156. package/cli/target/release/build/zmij-60b0e0e9d7c08f71/stderr +0 -0
  157. package/cli/target/release/build/zmij-aa602f885104061e/build-script-build +0 -0
  158. package/cli/target/release/build/zmij-aa602f885104061e/build_script_build-aa602f885104061e +0 -0
  159. package/cli/target/release/build/zmij-aa602f885104061e/build_script_build-aa602f885104061e.d +5 -0
  160. package/cli/target/release/deps/agent_browser-5894536b887e2ce7 +0 -0
  161. package/cli/target/release/deps/agent_browser-5894536b887e2ce7.d +5 -0
  162. package/cli/target/release/deps/itoa-653b9192107a1caa.d +8 -0
  163. package/cli/target/release/deps/libc-d843359d3dd4757b.d +45 -0
  164. package/cli/target/release/deps/libitoa-653b9192107a1caa.rlib +0 -0
  165. package/cli/target/release/deps/libitoa-653b9192107a1caa.rmeta +0 -0
  166. package/cli/target/release/deps/liblibc-d843359d3dd4757b.rlib +0 -0
  167. package/cli/target/release/deps/liblibc-d843359d3dd4757b.rmeta +0 -0
  168. package/cli/target/release/deps/libmemchr-dcaf8011940d18dd.rlib +0 -0
  169. package/cli/target/release/deps/libmemchr-dcaf8011940d18dd.rmeta +0 -0
  170. package/cli/target/release/deps/libproc_macro2-a753b344a6b4aa98.rlib +0 -0
  171. package/cli/target/release/deps/libproc_macro2-a753b344a6b4aa98.rmeta +0 -0
  172. package/cli/target/release/deps/libquote-833e6725e0f7d298.rlib +0 -0
  173. package/cli/target/release/deps/libquote-833e6725e0f7d298.rmeta +0 -0
  174. package/cli/target/release/deps/libserde-d6fb44202dad3efd.rlib +0 -0
  175. package/cli/target/release/deps/libserde-d6fb44202dad3efd.rmeta +0 -0
  176. package/cli/target/release/deps/libserde_core-0f7ba2581c8c0423.rlib +0 -0
  177. package/cli/target/release/deps/libserde_core-0f7ba2581c8c0423.rmeta +0 -0
  178. package/cli/target/release/deps/libserde_derive-a5d13e0e658ceae3.dylib +0 -0
  179. package/cli/target/release/deps/libserde_json-f61651a65bf0eb31.rlib +0 -0
  180. package/cli/target/release/deps/libserde_json-f61651a65bf0eb31.rmeta +0 -0
  181. package/cli/target/release/deps/libsyn-6f9a22f8c7f909b0.rlib +0 -0
  182. package/cli/target/release/deps/libsyn-6f9a22f8c7f909b0.rmeta +0 -0
  183. package/cli/target/release/deps/libunicode_ident-60c57228d30a23d0.rlib +0 -0
  184. package/cli/target/release/deps/libunicode_ident-60c57228d30a23d0.rmeta +0 -0
  185. package/cli/target/release/deps/libzmij-9501bcbd6d8b933c.rlib +0 -0
  186. package/cli/target/release/deps/libzmij-9501bcbd6d8b933c.rmeta +0 -0
  187. package/cli/target/release/deps/memchr-dcaf8011940d18dd.d +30 -0
  188. package/cli/target/release/deps/proc_macro2-a753b344a6b4aa98.d +17 -0
  189. package/cli/target/release/deps/quote-833e6725e0f7d298.d +13 -0
  190. package/cli/target/release/deps/serde-d6fb44202dad3efd.d +14 -0
  191. package/cli/target/release/deps/serde_core-0f7ba2581c8c0423.d +27 -0
  192. package/cli/target/release/deps/serde_derive-a5d13e0e658ceae3.d +34 -0
  193. package/cli/target/release/deps/serde_json-f61651a65bf0eb31.d +22 -0
  194. package/cli/target/release/deps/syn-6f9a22f8c7f909b0.d +49 -0
  195. package/cli/target/release/deps/unicode_ident-60c57228d30a23d0.d +8 -0
  196. package/cli/target/release/deps/zmij-9501bcbd6d8b933c.d +8 -0
  197. package/dist/actions.d.ts.map +1 -1
  198. package/dist/actions.js +46 -35
  199. package/dist/actions.js.map +1 -1
  200. package/dist/browser.d.ts +30 -1
  201. package/dist/browser.d.ts.map +1 -1
  202. package/dist/browser.js +59 -0
  203. package/dist/browser.js.map +1 -1
  204. package/dist/cli-light.d.ts +11 -0
  205. package/dist/cli-light.d.ts.map +1 -0
  206. package/dist/cli-light.js +409 -0
  207. package/dist/cli-light.js.map +1 -0
  208. package/dist/index.js +13 -8
  209. package/dist/index.js.map +1 -1
  210. package/dist/protocol.d.ts.map +1 -1
  211. package/dist/protocol.js +4 -0
  212. package/dist/protocol.js.map +1 -1
  213. package/dist/snapshot.d.ts +63 -0
  214. package/dist/snapshot.d.ts.map +1 -0
  215. package/dist/snapshot.js +298 -0
  216. package/dist/snapshot.js.map +1 -0
  217. package/package.json +6 -4
  218. package/src/actions.ts +50 -36
  219. package/src/browser.ts +70 -0
  220. package/src/cli-light.ts +457 -0
  221. package/src/index.ts +13 -8
  222. package/src/protocol.ts +4 -0
  223. package/src/snapshot.ts +380 -0
  224. package/tsconfig.json +12 -3
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * Comprehensive Benchmark: agent-browser vs playwright-mcp
4
+ *
5
+ * Tests realistic AI agent workflows on real websites.
6
+ */
7
+
8
+ import { execSync, spawn } from 'child_process';
9
+ import * as path from 'path';
10
+
11
+ interface Result {
12
+ tool: string;
13
+ workflow: string;
14
+ operation: string;
15
+ timeMs: number;
16
+ outputBytes: number;
17
+ }
18
+
19
+ const results: Result[] = [];
20
+
21
+ function formatTime(ms: number): string {
22
+ if (ms < 1000) return `${ms.toFixed(0)}ms`;
23
+ return `${(ms / 1000).toFixed(2)}s`;
24
+ }
25
+
26
+ function formatBytes(bytes: number): string {
27
+ if (bytes < 1024) return `${bytes}B`;
28
+ return `${(bytes / 1024).toFixed(1)}KB`;
29
+ }
30
+
31
+ // ============================================================================
32
+ // Agent-Browser Runner
33
+ // ============================================================================
34
+
35
+ function runAB(args: string[], session: string = 'bench'): { ms: number; output: string } {
36
+ const start = performance.now();
37
+ let output = '';
38
+ try {
39
+ output = execSync(`./bin/agent-browser ${args.join(' ')}`, {
40
+ stdio: 'pipe',
41
+ timeout: 30000,
42
+ env: { ...process.env, AGENT_BROWSER_SESSION: session },
43
+ }).toString();
44
+ } catch (e: any) {
45
+ output = e.stdout?.toString() || e.message || '';
46
+ }
47
+ return { ms: performance.now() - start, output };
48
+ }
49
+
50
+ // ============================================================================
51
+ // Playwright-MCP Runner
52
+ // ============================================================================
53
+
54
+ interface MCPClient {
55
+ call: (tool: string, args: Record<string, unknown>) => Promise<{ ms: number; output: string }>;
56
+ close: () => void;
57
+ }
58
+
59
+ async function createMCPClient(): Promise<MCPClient> {
60
+ const mcpPath = path.join(process.cwd(), 'opensrc/repos/github.com/microsoft/playwright-mcp/cli.js');
61
+ const proc = spawn('node', [mcpPath, '--headless'], { stdio: ['pipe', 'pipe', 'pipe'] });
62
+
63
+ let buffer = '';
64
+ let requestId = 0;
65
+ const pending = new Map<number, { resolve: (v: any) => void; reject: (e: Error) => void }>();
66
+
67
+ proc.stdout!.on('data', (data: Buffer) => {
68
+ buffer += data.toString();
69
+ const lines = buffer.split('\n');
70
+ buffer = lines.pop() || '';
71
+ for (const line of lines) {
72
+ if (!line.trim()) continue;
73
+ try {
74
+ const msg = JSON.parse(line);
75
+ if (msg.id !== undefined && pending.has(msg.id)) {
76
+ pending.get(msg.id)!.resolve(msg);
77
+ pending.delete(msg.id);
78
+ }
79
+ } catch {}
80
+ }
81
+ });
82
+
83
+ const send = (method: string, params: Record<string, unknown>): Promise<any> => {
84
+ const id = ++requestId;
85
+ return new Promise((resolve, reject) => {
86
+ pending.set(id, { resolve, reject });
87
+ proc.stdin!.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
88
+ setTimeout(() => {
89
+ if (pending.has(id)) {
90
+ pending.delete(id);
91
+ reject(new Error('Timeout'));
92
+ }
93
+ }, 30000);
94
+ });
95
+ };
96
+
97
+ // Initialize
98
+ await send('initialize', {
99
+ protocolVersion: '2024-11-05',
100
+ capabilities: {},
101
+ clientInfo: { name: 'benchmark', version: '1.0.0' },
102
+ });
103
+ proc.stdin!.write(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized', params: {} }) + '\n');
104
+
105
+ return {
106
+ call: async (tool: string, args: Record<string, unknown>) => {
107
+ const start = performance.now();
108
+ const result = await send('tools/call', { name: tool, arguments: args });
109
+ return { ms: performance.now() - start, output: JSON.stringify(result) };
110
+ },
111
+ close: () => proc.kill(),
112
+ };
113
+ }
114
+
115
+ // ============================================================================
116
+ // Workflows
117
+ // ============================================================================
118
+
119
+ interface Workflow {
120
+ name: string;
121
+ description: string;
122
+ steps: Array<{
123
+ name: string;
124
+ ab: string[];
125
+ mcp: { tool: string; args: Record<string, unknown> };
126
+ }>;
127
+ }
128
+
129
+ const workflows: Workflow[] = [
130
+ {
131
+ name: 'Wikipedia Research',
132
+ description: 'Navigate Wikipedia, read content, follow links',
133
+ steps: [
134
+ { name: 'Navigate', ab: ['open', 'https://en.wikipedia.org/wiki/Artificial_intelligence'], mcp: { tool: 'browser_navigate', args: { url: 'https://en.wikipedia.org/wiki/Artificial_intelligence' } } },
135
+ { name: 'Snapshot', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
136
+ { name: 'Get title', ab: ['get', 'title'], mcp: { tool: 'browser_snapshot', args: {} } },
137
+ { name: 'Snapshot 2', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
138
+ { name: 'Click link', ab: ['click', 'a[href="/wiki/Machine_learning"]'], mcp: { tool: 'browser_click', args: { element: 'Machine learning', ref: 'internal link' } } },
139
+ { name: 'Snapshot 3', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
140
+ ],
141
+ },
142
+ {
143
+ name: 'GitHub Browse',
144
+ description: 'Browse a GitHub repository',
145
+ steps: [
146
+ { name: 'Navigate', ab: ['open', 'https://github.com/anthropics/anthropic-cookbook'], mcp: { tool: 'browser_navigate', args: { url: 'https://github.com/anthropics/anthropic-cookbook' } } },
147
+ { name: 'Snapshot', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
148
+ { name: 'Get URL', ab: ['get', 'url'], mcp: { tool: 'browser_snapshot', args: {} } },
149
+ { name: 'Eval (stars)', ab: ['eval', 'document.querySelector("#repo-stars-counter-star")?.textContent'], mcp: { tool: 'browser_snapshot', args: {} } },
150
+ { name: 'Snapshot 2', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
151
+ ],
152
+ },
153
+ {
154
+ name: 'Hacker News',
155
+ description: 'Browse Hacker News front page',
156
+ steps: [
157
+ { name: 'Navigate', ab: ['open', 'https://news.ycombinator.com'], mcp: { tool: 'browser_navigate', args: { url: 'https://news.ycombinator.com' } } },
158
+ { name: 'Snapshot', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
159
+ { name: 'Eval (count)', ab: ['eval', 'document.querySelectorAll(".athing").length'], mcp: { tool: 'browser_snapshot', args: {} } },
160
+ { name: 'Snapshot 2', ab: ['snapshot', '-i'], mcp: { tool: 'browser_snapshot', args: {} } },
161
+ { name: 'Get title', ab: ['get', 'title'], mcp: { tool: 'browser_snapshot', args: {} } },
162
+ ],
163
+ },
164
+ ];
165
+
166
+ // ============================================================================
167
+ // Run Benchmarks
168
+ // ============================================================================
169
+
170
+ async function runAgentBrowser(workflow: Workflow, session: string): Promise<void> {
171
+ // Cleanup
172
+ try { runAB(['close'], session); } catch {}
173
+ await sleep(100);
174
+
175
+ for (const step of workflow.steps) {
176
+ const r = runAB(step.ab, session);
177
+ results.push({
178
+ tool: 'agent-browser',
179
+ workflow: workflow.name,
180
+ operation: step.name,
181
+ timeMs: r.ms,
182
+ outputBytes: r.output.length,
183
+ });
184
+ }
185
+
186
+ try { runAB(['close'], session); } catch {}
187
+ }
188
+
189
+ async function runPlaywrightMCP(workflow: Workflow): Promise<void> {
190
+ let client: MCPClient | null = null;
191
+ try {
192
+ client = await createMCPClient();
193
+
194
+ for (const step of workflow.steps) {
195
+ const r = await client.call(step.mcp.tool, step.mcp.args);
196
+ results.push({
197
+ tool: 'playwright-mcp',
198
+ workflow: workflow.name,
199
+ operation: step.name,
200
+ timeMs: r.ms,
201
+ outputBytes: r.output.length,
202
+ });
203
+ }
204
+
205
+ await client.call('browser_close', {});
206
+ } catch (e) {
207
+ console.log(` ⚠️ MCP error: ${e}`);
208
+ } finally {
209
+ client?.close();
210
+ }
211
+ }
212
+
213
+ // ============================================================================
214
+ // Reporting
215
+ // ============================================================================
216
+
217
+ function printResults(): void {
218
+ console.log('\n' + '═'.repeat(80));
219
+ console.log('📊 DETAILED RESULTS');
220
+ console.log('═'.repeat(80));
221
+
222
+ for (const workflow of workflows) {
223
+ console.log(`\n📋 ${workflow.name}`);
224
+ console.log('─'.repeat(70));
225
+ console.log('│ Operation │ agent-browser │ playwright-mcp │ Diff │');
226
+ console.log('├────────────────────┼───────────────┼────────────────┼───────────┤');
227
+
228
+ let abTotal = 0, mcpTotal = 0;
229
+
230
+ for (const step of workflow.steps) {
231
+ const ab = results.find(r => r.tool === 'agent-browser' && r.workflow === workflow.name && r.operation === step.name);
232
+ const mcp = results.find(r => r.tool === 'playwright-mcp' && r.workflow === workflow.name && r.operation === step.name);
233
+
234
+ const abTime = ab?.timeMs || 0;
235
+ const mcpTime = mcp?.timeMs || 0;
236
+ abTotal += abTime;
237
+ mcpTotal += mcpTime;
238
+
239
+ const diff = mcpTime - abTime;
240
+ const diffStr = diff > 0 ? `+${formatTime(diff)}` : formatTime(diff);
241
+
242
+ console.log(`│ ${step.name.padEnd(18)} │ ${formatTime(abTime).padEnd(13)} │ ${formatTime(mcpTime).padEnd(14)} │ ${diffStr.padEnd(9)} │`);
243
+ }
244
+
245
+ console.log('├────────────────────┼───────────────┼────────────────┼───────────┤');
246
+ const totalDiff = mcpTotal - abTotal;
247
+ const totalDiffStr = totalDiff > 0 ? `+${formatTime(totalDiff)}` : formatTime(totalDiff);
248
+ console.log(`│ ${'TOTAL'.padEnd(18)} │ ${formatTime(abTotal).padEnd(13)} │ ${formatTime(mcpTotal).padEnd(14)} │ ${totalDiffStr.padEnd(9)} │`);
249
+ console.log('└────────────────────┴───────────────┴────────────────┴───────────┘');
250
+ }
251
+
252
+ // Summary
253
+ const abTotalAll = results.filter(r => r.tool === 'agent-browser').reduce((s, r) => s + r.timeMs, 0);
254
+ const mcpTotalAll = results.filter(r => r.tool === 'playwright-mcp').reduce((s, r) => s + r.timeMs, 0);
255
+ const abOps = results.filter(r => r.tool === 'agent-browser').length;
256
+ const mcpOps = results.filter(r => r.tool === 'playwright-mcp').length;
257
+
258
+ console.log('\n' + '═'.repeat(80));
259
+ console.log('📈 SUMMARY');
260
+ console.log('═'.repeat(80));
261
+ console.log(`\n Workflows tested: ${workflows.length}`);
262
+ console.log(` Total operations: ${abOps} (agent-browser), ${mcpOps} (playwright-mcp)`);
263
+ console.log(`\n agent-browser total: ${formatTime(abTotalAll)} (${(abTotalAll / abOps).toFixed(0)}ms avg/op)`);
264
+ console.log(` playwright-mcp total: ${formatTime(mcpTotalAll)} (${(mcpTotalAll / mcpOps).toFixed(0)}ms avg/op)`);
265
+
266
+ if (abTotalAll < mcpTotalAll) {
267
+ console.log(`\n ✅ agent-browser is ${((mcpTotalAll - abTotalAll) / 1000).toFixed(2)}s faster overall`);
268
+ } else {
269
+ console.log(`\n ⏱️ playwright-mcp is ${((abTotalAll - mcpTotalAll) / 1000).toFixed(2)}s faster overall`);
270
+ }
271
+
272
+ // Context usage
273
+ const abBytes = results.filter(r => r.tool === 'agent-browser').reduce((s, r) => s + r.outputBytes, 0);
274
+ const mcpBytes = results.filter(r => r.tool === 'playwright-mcp').reduce((s, r) => s + r.outputBytes, 0);
275
+
276
+ console.log(`\n Context usage:`);
277
+ console.log(` agent-browser: ${formatBytes(abBytes)} (~${Math.ceil(abBytes / 4)} tokens)`);
278
+ console.log(` playwright-mcp: ${formatBytes(mcpBytes)} (~${Math.ceil(mcpBytes / 4)} tokens)`);
279
+
280
+ console.log('\n' + '═'.repeat(80));
281
+ }
282
+
283
+ function sleep(ms: number): Promise<void> {
284
+ return new Promise(r => setTimeout(r, ms));
285
+ }
286
+
287
+ // ============================================================================
288
+ // Main
289
+ // ============================================================================
290
+
291
+ async function main(): Promise<void> {
292
+ console.log('═'.repeat(80));
293
+ console.log('🚀 COMPREHENSIVE BENCHMARK: agent-browser vs playwright-mcp');
294
+ console.log('═'.repeat(80));
295
+ console.log('\nWorkflows:');
296
+ for (const w of workflows) {
297
+ console.log(` • ${w.name}: ${w.description} (${w.steps.length} steps)`);
298
+ }
299
+
300
+ console.log('\n🔨 Building...');
301
+ execSync('pnpm build', { cwd: process.cwd(), stdio: 'inherit' });
302
+
303
+ for (const workflow of workflows) {
304
+ console.log(`\n${'─'.repeat(80)}`);
305
+ console.log(`📋 Running: ${workflow.name}`);
306
+ console.log('─'.repeat(80));
307
+
308
+ console.log('\n agent-browser:');
309
+ await runAgentBrowser(workflow, `ab-${workflow.name.toLowerCase().replace(/\s+/g, '-')}`);
310
+ const abTime = results.filter(r => r.tool === 'agent-browser' && r.workflow === workflow.name).reduce((s, r) => s + r.timeMs, 0);
311
+ console.log(` ✓ Completed in ${formatTime(abTime)}`);
312
+
313
+ console.log('\n playwright-mcp:');
314
+ await runPlaywrightMCP(workflow);
315
+ const mcpTime = results.filter(r => r.tool === 'playwright-mcp' && r.workflow === workflow.name).reduce((s, r) => s + r.timeMs, 0);
316
+ console.log(` ✓ Completed in ${formatTime(mcpTime)}`);
317
+ }
318
+
319
+ printResults();
320
+ }
321
+
322
+ main().catch(console.error);
package/bin/agent-browser CHANGED
Binary file
package/cli/Cargo.lock ADDED
@@ -0,0 +1,114 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "agent-browser"
7
+ version = "0.1.0"
8
+ dependencies = [
9
+ "libc",
10
+ "serde",
11
+ "serde_json",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "itoa"
16
+ version = "1.0.17"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
19
+
20
+ [[package]]
21
+ name = "libc"
22
+ version = "0.2.180"
23
+ source = "registry+https://github.com/rust-lang/crates.io-index"
24
+ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
25
+
26
+ [[package]]
27
+ name = "memchr"
28
+ version = "2.7.6"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
31
+
32
+ [[package]]
33
+ name = "proc-macro2"
34
+ version = "1.0.105"
35
+ source = "registry+https://github.com/rust-lang/crates.io-index"
36
+ checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
37
+ dependencies = [
38
+ "unicode-ident",
39
+ ]
40
+
41
+ [[package]]
42
+ name = "quote"
43
+ version = "1.0.43"
44
+ source = "registry+https://github.com/rust-lang/crates.io-index"
45
+ checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
46
+ dependencies = [
47
+ "proc-macro2",
48
+ ]
49
+
50
+ [[package]]
51
+ name = "serde"
52
+ version = "1.0.228"
53
+ source = "registry+https://github.com/rust-lang/crates.io-index"
54
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
55
+ dependencies = [
56
+ "serde_core",
57
+ "serde_derive",
58
+ ]
59
+
60
+ [[package]]
61
+ name = "serde_core"
62
+ version = "1.0.228"
63
+ source = "registry+https://github.com/rust-lang/crates.io-index"
64
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
65
+ dependencies = [
66
+ "serde_derive",
67
+ ]
68
+
69
+ [[package]]
70
+ name = "serde_derive"
71
+ version = "1.0.228"
72
+ source = "registry+https://github.com/rust-lang/crates.io-index"
73
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
74
+ dependencies = [
75
+ "proc-macro2",
76
+ "quote",
77
+ "syn",
78
+ ]
79
+
80
+ [[package]]
81
+ name = "serde_json"
82
+ version = "1.0.149"
83
+ source = "registry+https://github.com/rust-lang/crates.io-index"
84
+ checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
85
+ dependencies = [
86
+ "itoa",
87
+ "memchr",
88
+ "serde",
89
+ "serde_core",
90
+ "zmij",
91
+ ]
92
+
93
+ [[package]]
94
+ name = "syn"
95
+ version = "2.0.114"
96
+ source = "registry+https://github.com/rust-lang/crates.io-index"
97
+ checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
98
+ dependencies = [
99
+ "proc-macro2",
100
+ "quote",
101
+ "unicode-ident",
102
+ ]
103
+
104
+ [[package]]
105
+ name = "unicode-ident"
106
+ version = "1.0.22"
107
+ source = "registry+https://github.com/rust-lang/crates.io-index"
108
+ checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
109
+
110
+ [[package]]
111
+ name = "zmij"
112
+ version = "1.0.12"
113
+ source = "registry+https://github.com/rust-lang/crates.io-index"
114
+ checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
package/cli/Cargo.toml ADDED
@@ -0,0 +1,17 @@
1
+ [package]
2
+ name = "agent-browser"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Fast browser automation CLI for AI agents"
6
+ license = "Apache-2.0"
7
+
8
+ [dependencies]
9
+ serde = { version = "1.0", features = ["derive"] }
10
+ serde_json = "1.0"
11
+ libc = "0.2"
12
+
13
+ [profile.release]
14
+ opt-level = 3
15
+ lto = true
16
+ codegen-units = 1
17
+ strip = true