@schlenkr/ragents 0.1.7 → 0.1.9

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 (187) hide show
  1. package/apps/server/src/config-definition.ts +24 -2
  2. package/apps/server/src/config.ts +0 -6
  3. package/apps/server/src/host-api.json +3 -10
  4. package/apps/server/src/host-api.ts +6 -7
  5. package/apps/server/src/plugin-build/build.ts +28 -5
  6. package/apps/server/src/plugin-build/plugin-description.ts +1 -1
  7. package/apps/server/src/plugin-build/typecheck.ts +2 -2
  8. package/apps/server/src/plugin-support/language-server/plugin.ts +8 -7
  9. package/apps/server/src/plugin-support/language-server/tools.ts +7 -6
  10. package/apps/server/src/plugin-support/model-aliases.ts +55 -25
  11. package/apps/server/src/plugin-support/plugin-folder.ts +2 -1
  12. package/apps/server/src/plugin-support/product-relay.ts +10 -2
  13. package/apps/server/src/plugin-support/workspace-sandbox-host.ts +18 -9
  14. package/apps/server/src/profile/bundle-manifest.ts +7 -3
  15. package/apps/server/src/profile/compose.ts +6 -0
  16. package/apps/server/src/profile/plugin-discovery.ts +6 -1
  17. package/apps/server/src/profile/provisioning.ts +6 -5
  18. package/apps/server/src/ragents/engine.ts +18 -12
  19. package/apps/server/src/ragents/host-services.ts +4 -0
  20. package/apps/server/src/ragents/session.ts +1 -1
  21. package/apps/server/src/server.ts +1 -0
  22. package/apps/server/tsconfig.json +2 -0
  23. package/apps/web/dist/assets/{highlighted-body-KPVGNVTW-CFhTJEmH.js → highlighted-body-KPVGNVTW-xXXhTDbh.js} +1 -1
  24. package/apps/web/dist/assets/{main-DlzW4t4c.js → main-C7JeZFjs.js} +1 -1
  25. package/apps/web/dist/assets/{mermaid-HWGCJPDP-kxkB991i.js → mermaid-HWGCJPDP-DfsU5ofC.js} +2 -2
  26. package/apps/web/dist/assets/{runPanel-BJEFQ__w.js → runPanel-ZT6TPDLM.js} +1 -1
  27. package/apps/web/dist/help/guide-clients.html +14 -6
  28. package/apps/web/dist/help/guide-clients.md +14 -6
  29. package/apps/web/dist/help/guide-distributed.html +12 -4
  30. package/apps/web/dist/help/guide-distributed.md +12 -4
  31. package/apps/web/dist/help/guide-getting-started.html +12 -8
  32. package/apps/web/dist/help/guide-getting-started.md +12 -8
  33. package/apps/web/dist/help/guide-plugins.html +6 -2
  34. package/apps/web/dist/help/guide-plugins.md +6 -2
  35. package/apps/web/dist/help/guide-runtime.html +2 -1
  36. package/apps/web/dist/help/guide-runtime.md +2 -1
  37. package/apps/web/dist/help/index.html +3328 -1135
  38. package/apps/web/dist/host-web.json +4 -4
  39. package/apps/web/dist/index.html +2 -2
  40. package/apps/web/dist/run-panel.html +2 -2
  41. package/apps/web/src/StartTiles.tsx +1 -1
  42. package/bundles/ragents.activity/ragents-bundle.json +3 -3
  43. package/bundles/ragents.actor-programs/ragents-bundle.json +3 -3
  44. package/bundles/ragents.ask/ragents-bundle.json +4 -4
  45. package/bundles/ragents.ask/server/index.js +42 -11
  46. package/bundles/ragents.ask/server/index.js.map +3 -3
  47. package/bundles/ragents.ask/web/chunks/chunk-WFN4374U.js +2 -0
  48. package/bundles/ragents.ask/web/chunks/chunk-WFN4374U.js.map +7 -0
  49. package/bundles/ragents.ask/web/classes.json +1 -1
  50. package/bundles/ragents.ask/web/exports/ask-payload.js +1 -1
  51. package/bundles/ragents.ask/web/index.js +1 -1
  52. package/bundles/ragents.ask/web/index.js.map +3 -3
  53. package/bundles/ragents.browser/executor/index.mjs +357 -0
  54. package/bundles/ragents.browser/executor/index.mjs.map +7 -0
  55. package/bundles/ragents.browser/ragents-bundle.json +5 -8
  56. package/bundles/ragents.browser/server/chunks/{chunk-2GKLLCBE.js → chunk-CWLX4VA5.js} +1 -1
  57. package/bundles/ragents.browser/server/chunks/chunk-CWLX4VA5.js.map +7 -0
  58. package/bundles/ragents.browser/server/exports/server/contract.js +1 -1
  59. package/bundles/ragents.browser/server/index.js +20 -9
  60. package/bundles/ragents.browser/server/index.js.map +4 -4
  61. package/bundles/ragents.documents/ragents-bundle.json +3 -3
  62. package/bundles/ragents.lsp-fsharp/executor/index.mjs +68 -0
  63. package/bundles/ragents.lsp-fsharp/executor/index.mjs.map +7 -0
  64. package/bundles/ragents.lsp-fsharp/ragents-bundle.json +5 -9
  65. package/bundles/ragents.lsp-fsharp/server/index.js +21 -6
  66. package/bundles/ragents.lsp-fsharp/server/index.js.map +4 -4
  67. package/bundles/ragents.lsp-roslyn/executor/index.mjs +68 -0
  68. package/bundles/ragents.lsp-roslyn/executor/index.mjs.map +7 -0
  69. package/bundles/ragents.lsp-roslyn/ragents-bundle.json +6 -8
  70. package/bundles/ragents.lsp-roslyn/server/index.js +54 -15
  71. package/bundles/ragents.lsp-roslyn/server/index.js.map +4 -4
  72. package/bundles/ragents.lsp-typescript/executor/index.mjs +49 -0
  73. package/bundles/ragents.lsp-typescript/executor/index.mjs.map +7 -0
  74. package/bundles/ragents.lsp-typescript/ragents-bundle.json +5 -7
  75. package/bundles/ragents.lsp-typescript/server/index.js +22 -2
  76. package/bundles/ragents.lsp-typescript/server/index.js.map +3 -3
  77. package/bundles/ragents.model-relay/ragents-bundle.json +4 -4
  78. package/bundles/ragents.model-relay/server/index.js +3 -2
  79. package/bundles/ragents.model-relay/server/index.js.map +2 -2
  80. package/bundles/ragents.orchestration/ragents-bundle.json +3 -3
  81. package/bundles/ragents.overseer/ragents-bundle.json +3 -3
  82. package/bundles/ragents.processes/ragents-bundle.json +3 -3
  83. package/bundles/ragents.product/ragents-bundle.json +3 -3
  84. package/bundles/ragents.profile-distribution/ragents-bundle.json +4 -4
  85. package/bundles/ragents.profile-distribution/server/index.js +1 -1
  86. package/bundles/ragents.profile-distribution/server/index.js.map +2 -2
  87. package/bundles/ragents.reference/ragents-bundle.json +3 -3
  88. package/bundles/ragents.todo/ragents-bundle.json +3 -3
  89. package/bundles/ragents.transcript/ragents-bundle.json +3 -3
  90. package/bundles/ragents.watch/ragents-bundle.json +3 -3
  91. package/bundles/ragents.workspace/ragents-bundle.json +11 -5
  92. package/bundles/ragents.workspace/server/index.js +101 -28
  93. package/bundles/ragents.workspace/server/index.js.map +3 -3
  94. package/bundles/ragents.workspace/web/classes.json +1 -1
  95. package/bundles/ragents.workspace/web/index.js +1 -1
  96. package/bundles/ragents.workspace/web/index.js.map +3 -3
  97. package/package.json +2 -2
  98. package/packages/agent/dist/core/agent-settings.d.ts +1 -7
  99. package/packages/agent/dist/core/compaction/compaction.d.ts +17 -13
  100. package/packages/agent/dist/core/model-runtime.d.ts +5 -4
  101. package/packages/agent/dist/core/provider-composer.d.ts +2 -1
  102. package/packages/agent/dist/core/tools/bash.d.ts +9 -3
  103. package/packages/agent/dist/index.d.ts +1 -1
  104. package/packages/agent/src/core/agent-settings.ts +1 -4
  105. package/packages/agent/src/core/compaction/compaction.ts +68 -30
  106. package/packages/agent/src/core/model-runtime.ts +12 -5
  107. package/packages/agent/src/core/provider-composer.ts +5 -0
  108. package/packages/agent/src/core/tools/bash.ts +36 -30
  109. package/packages/agent/src/index.ts +3 -0
  110. package/packages/ai/dist/types.d.ts +11 -0
  111. package/packages/ai/src/types.ts +12 -0
  112. package/packages/ragents/src/agents/plugins.ts +5 -0
  113. package/packages/ragents/src/domain/event-semantics.ts +3 -0
  114. package/packages/ragents/src/domain/event-validation.ts +15 -2
  115. package/packages/ragents/src/domain/events.ts +3 -0
  116. package/packages/ragents/src/domain/model.ts +2 -0
  117. package/packages/ragents/src/domain/projection.ts +1 -0
  118. package/packages/ragents/src/drivers/agent-runtime.ts +1 -1
  119. package/packages/ragents/src/drivers/agent-turn.ts +8 -6
  120. package/packages/ragents/src/index.ts +1 -0
  121. package/packages/ragents/src/plugin-host.ts +58 -10
  122. package/packages/ragents/src/plugin-types.ts +7 -2
  123. package/packages/ragents/src/runtime/decisions/inputs.ts +6 -2
  124. package/packages/ragents/src/runtime/journal-storage.ts +5 -4
  125. package/packages/workspace-executor/package.json +0 -1
  126. package/packages/workspace-executor/src/bash-launch.ts +56 -10
  127. package/packages/workspace-executor/src/context.ts +4 -0
  128. package/packages/workspace-executor/src/contributions.ts +150 -0
  129. package/packages/workspace-executor/src/executor.ts +1 -1
  130. package/packages/workspace-executor/src/index.ts +16 -19
  131. package/packages/workspace-executor/src/language-server/host.ts +3 -0
  132. package/packages/workspace-executor/src/language-server/module.ts +12 -2
  133. package/packages/workspace-executor/src/language-server/roots.ts +0 -5
  134. package/packages/workspace-executor/src/modules.ts +7 -6
  135. package/packages/workspace-executor/src/sandbox-tools.ts +3 -9
  136. package/packages/workspace-executor/src/shell-platform.ts +14 -3
  137. package/packages/workspace-executor/src/tools.ts +0 -3
  138. package/plugins/ragents.ask/ask-payload.ts +9 -0
  139. package/plugins/ragents.ask/server/ask-service.ts +53 -13
  140. package/plugins/ragents.ask/web/AskActionView.tsx +3 -2
  141. package/plugins/ragents.browser/executor/index.ts +5 -0
  142. package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/module.ts +25 -31
  143. package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/playwright.ts +9 -23
  144. package/plugins/ragents.browser/provision.ts +1 -1
  145. package/plugins/ragents.browser/server/browser.ts +3 -3
  146. package/plugins/ragents.browser/server/contract.ts +2 -2
  147. package/plugins/ragents.browser/server/index.ts +1 -1
  148. package/plugins/ragents.lsp-fsharp/executor.ts +80 -0
  149. package/plugins/ragents.lsp-fsharp/provision.ts +1 -1
  150. package/plugins/ragents.lsp-fsharp/server/index.ts +2 -2
  151. package/plugins/ragents.lsp-roslyn/executor.ts +64 -0
  152. package/plugins/ragents.lsp-roslyn/provision.ts +1 -1
  153. package/plugins/ragents.lsp-roslyn/server/index.ts +28 -5
  154. package/plugins/ragents.lsp-roslyn/server/solution-on-start.ts +18 -6
  155. package/plugins/ragents.lsp-typescript/executor.ts +50 -0
  156. package/plugins/ragents.lsp-typescript/server/index.ts +2 -2
  157. package/plugins/ragents.model-relay/server/config.ts +1 -1
  158. package/plugins/ragents.model-relay/server/relay.ts +4 -2
  159. package/plugins/ragents.profile-distribution/server/archive.ts +2 -1
  160. package/plugins/ragents.workspace/client/workspace-client.ts +111 -28
  161. package/plugins/ragents.workspace/contract.ts +33 -2
  162. package/plugins/ragents.workspace/server/binding.ts +10 -4
  163. package/plugins/ragents.workspace/server/clients.ts +56 -9
  164. package/plugins/ragents.workspace/server/config.ts +9 -0
  165. package/plugins/ragents.workspace/server/index.ts +13 -4
  166. package/plugins/ragents.workspace/server/runtime.ts +10 -0
  167. package/plugins/ragents.workspace/server/shell-platform.ts +6 -5
  168. package/plugins/ragents.workspace/web/WorkspaceBinding.tsx +1 -1
  169. package/ragents.config.core.ts +4 -1
  170. package/ragents.config.showcase.ts +4 -1
  171. package/scripts/agent/journal.ts +3 -1
  172. package/scripts/package/build-package.ts +3 -1
  173. package/scripts/package/publish-package.ts +4 -3
  174. package/scripts/provision/run-provision.ts +2 -2
  175. package/scripts/workspace-client/run-workspace-client.ts +7 -4
  176. package/apps/web/dist/help/screenshots/release-checklist-vscode.png +0 -0
  177. package/apps/web/dist/help/screenshots/release-checklist-web.png +0 -0
  178. package/bundles/ragents.ask/web/chunks/chunk-HGFDGTNC.js +0 -2
  179. package/bundles/ragents.ask/web/chunks/chunk-HGFDGTNC.js.map +0 -7
  180. package/bundles/ragents.browser/server/chunks/chunk-2GKLLCBE.js.map +0 -7
  181. package/packages/workspace-executor/src/language-server/adapters/fsharp.ts +0 -60
  182. package/packages/workspace-executor/src/language-server/adapters/index.ts +0 -7
  183. package/packages/workspace-executor/src/language-server/adapters/roslyn.ts +0 -56
  184. package/packages/workspace-executor/src/language-server/adapters/typescript.ts +0 -74
  185. package/packages/workspace-executor/src/language-server/solution.ts +0 -13
  186. /package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/contract.ts +0 -0
  187. /package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/pages.ts +0 -0
@@ -0,0 +1,357 @@
1
+ import { createRequire as __ragentsCreateRequire } from "node:module";
2
+ const require = __ragentsCreateRequire(import.meta.url);
3
+
4
+ // executor/contract.ts
5
+ var BROWSER_OPERATIONS = {
6
+ open: "browser.open",
7
+ snapshot: "browser.snapshot",
8
+ viewport: "browser.viewport",
9
+ click: "browser.click",
10
+ fill: "browser.fill",
11
+ select: "browser.select",
12
+ press: "browser.press",
13
+ check: "browser.check",
14
+ screenshot: "browser.screenshot",
15
+ state: "browser.state",
16
+ close: "browser.close"
17
+ };
18
+ var BROWSER_EXECUTABLE_VARIABLE = "BROWSER_EXECUTABLE_PATH";
19
+
20
+ // executor/pages.ts
21
+ var errorText = (error) => error instanceof Error ? error.message : String(error);
22
+ var endedError = () => new Error("Der Browserdienst dieses Executors ist beendet.");
23
+ var maxSnapshotLength = 4e4;
24
+ var ambiguityHint = "W\xE4hle mit nth (0-basiert) oder first: true im Ziel einen Treffer, oder pr\xFCfe die Anzahl mit count in browser_check.";
25
+ var withAmbiguityHint = (error) => {
26
+ if (error instanceof Error && error.message.includes("strict mode violation")) throw new Error(`${error.message}
27
+ ${ambiguityHint}`, { cause: error });
28
+ throw error;
29
+ };
30
+ var browserLocator = (page, target) => {
31
+ const selectors = [target.role, target.label, target.text, target.testId, target.css].filter((value) => value !== void 0);
32
+ if (selectors.length !== 1 || target.name !== void 0 && target.role === void 0) {
33
+ throw new Error("Ein Browserziel braucht genau role (optional name), label, text, testId oder css.");
34
+ }
35
+ if (target.nth !== void 0 && target.first) throw new Error("Ein Browserziel verwendet entweder nth oder first, nicht beides.");
36
+ const root = target.frame ? page.frameLocator(target.frame) : page;
37
+ const base = target.role ? root.getByRole(target.role, { name: target.name, exact: true }) : target.label ? root.getByLabel(target.label, { exact: true }) : target.text ? root.getByText(target.text, { exact: true }) : target.testId ? root.getByTestId(target.testId) : root.locator(target.css);
38
+ return target.first ? base.first() : target.nth !== void 0 ? base.nth(target.nth) : base;
39
+ };
40
+ var BrowserPages = class {
41
+ #options;
42
+ #sessions = /* @__PURE__ */ new Map();
43
+ #shutDown = false;
44
+ constructor(options) {
45
+ this.#options = options;
46
+ }
47
+ async open(runId, url, viewport, signal) {
48
+ if (this.#shutDown) throw endedError();
49
+ const parsed = new URL(url);
50
+ if (!["http:", "https:"].includes(parsed.protocol)) throw new Error("browser_open braucht eine HTTP- oder HTTPS-Adresse.");
51
+ signal?.throwIfAborted();
52
+ if (!this.#sessions.has(runId)) this.#start(runId, viewport);
53
+ return this.#perform(runId, signal, async (session, page) => {
54
+ this.#resetEvidence(session);
55
+ const response = await page.goto(parsed.href, { waitUntil: "domcontentloaded" });
56
+ if (response && !response.ok()) throw new Error(`Browsernavigation fehlgeschlagen: HTTP ${response.status()} (${page.url()}).`);
57
+ return this.#snapshot(session, page);
58
+ });
59
+ }
60
+ snapshot(runId, signal) {
61
+ return this.#perform(runId, signal, (session, page) => this.#snapshot(session, page));
62
+ }
63
+ viewport(runId, viewport, signal) {
64
+ return this.#perform(runId, signal, async (session, page) => {
65
+ await page.setViewportSize(viewport);
66
+ return this.#snapshot(session, page);
67
+ });
68
+ }
69
+ click(runId, target, signal) {
70
+ return this.#action(runId, target, signal, (locator) => locator.click());
71
+ }
72
+ fill(runId, target, value, signal) {
73
+ return this.#action(runId, target, signal, (locator) => locator.fill(value));
74
+ }
75
+ select(runId, target, label, signal) {
76
+ return this.#action(runId, target, signal, (locator) => locator.selectOption({ label }));
77
+ }
78
+ press(runId, target, key, signal) {
79
+ return this.#action(runId, target, signal, (locator) => locator.press(key));
80
+ }
81
+ check(runId, input, signal) {
82
+ return this.#perform(runId, signal, async (session, page) => {
83
+ session.checked = false;
84
+ if (!input.target && input.text === void 0 && input.url === void 0 && input.noErrors !== true) {
85
+ throw new Error("browser_check braucht mindestens target, text, url oder noErrors: true.");
86
+ }
87
+ if (input.count !== void 0 && (!input.target || input.target.nth !== void 0 || input.target.first)) {
88
+ throw new Error("count in browser_check braucht ein target ohne nth oder first und z\xE4hlt dessen sichtbare Treffer.");
89
+ }
90
+ const timeout = this.#options.checkTimeoutMs;
91
+ const assertions = [];
92
+ if (input.target && input.count !== void 0) {
93
+ const visible = browserLocator(page, input.target).filter({ visible: true });
94
+ const found = await this.#waitForCount(visible, input.count, timeout);
95
+ if (found !== input.count) throw new Error(`Erwartet ${input.count} sichtbare Treffer, gefunden ${found}.`);
96
+ assertions.push(`${input.count} sichtbare Treffer`);
97
+ } else if (input.target) {
98
+ const locator = browserLocator(page, input.target);
99
+ await locator.waitFor({ state: "visible", timeout }).catch(withAmbiguityHint);
100
+ assertions.push("Ziel ist sichtbar");
101
+ if (input.text !== void 0) {
102
+ try {
103
+ await locator.filter({ hasText: input.text }).waitFor({ state: "visible", timeout });
104
+ } catch (error) {
105
+ throw new Error(`Erwarteter Text fehlt im Ziel: ${input.text}`, { cause: error });
106
+ }
107
+ assertions.push(`Text im Ziel: ${input.text}`);
108
+ }
109
+ } else if (input.text !== void 0) {
110
+ await page.getByText(input.text, { exact: false }).first().waitFor({ state: "visible", timeout });
111
+ assertions.push(`Sichtbarer Text: ${input.text}`);
112
+ }
113
+ if (input.url !== void 0) {
114
+ await page.waitForURL(input.url, { timeout });
115
+ assertions.push(`Adresse: ${input.url}`);
116
+ }
117
+ if (input.noErrors !== false) {
118
+ if (session.errors.length > 0) throw new Error(`Browserfehler: ${session.errors.join("\n")}`);
119
+ assertions.push("Keine erfassten Browser- oder Netzwerkfehler seit der Navigation");
120
+ }
121
+ session.checked = true;
122
+ return { url: page.url(), assertions };
123
+ });
124
+ }
125
+ /** Nimmt die Seite als PNG auf und liefert es Base64-kodiert; `id` merkt sich die Seite als aktuelle Aufnahme. */
126
+ screenshot(runId, id, fullPage, signal) {
127
+ return this.#perform(runId, signal, async (session, page) => {
128
+ const image = await page.screenshot({ fullPage, type: "png", timeout: this.#options.timeoutMs });
129
+ session.screenshots.push(id);
130
+ return image.toString("base64");
131
+ });
132
+ }
133
+ /** Der Stand der Seite, ohne auf laufende Aktionen zu warten; ohne offene Seite `null`. */
134
+ state(runId) {
135
+ const session = this.#sessions.get(runId);
136
+ return session && !session.closed && session.page ? this.#stateOf(session, session.page) : null;
137
+ }
138
+ async close(runId) {
139
+ const session = this.#sessions.get(runId);
140
+ if (!session) return;
141
+ session.closed = true;
142
+ this.#sessions.delete(runId);
143
+ const browser = await session.browser.catch(() => void 0);
144
+ if (browser) await browser.close();
145
+ await session.queue;
146
+ }
147
+ /** Schließt jeden Browser; danach startet keiner mehr, weil niemand ihn schließen würde. */
148
+ async shutdown() {
149
+ this.#shutDown = true;
150
+ const results = await Promise.allSettled([...this.#sessions.keys()].map((runId) => this.close(runId)));
151
+ const failed = results.find((result) => result.status === "rejected");
152
+ if (failed) throw failed.reason;
153
+ }
154
+ #start(runId, viewport) {
155
+ const session = {
156
+ browser: this.#launch(runId),
157
+ viewport,
158
+ queue: Promise.resolve(),
159
+ closed: false,
160
+ checked: false,
161
+ errors: [],
162
+ failedRequests: /* @__PURE__ */ new Set(),
163
+ screenshots: []
164
+ };
165
+ this.#sessions.set(runId, session);
166
+ void session.browser.catch(() => {
167
+ session.closed = true;
168
+ if (this.#sessions.get(runId) === session) this.#sessions.delete(runId);
169
+ });
170
+ }
171
+ async #launch(runId) {
172
+ return this.#options.launch(runId);
173
+ }
174
+ async #waitForCount(locator, expected, timeout) {
175
+ const deadline = Date.now() + timeout;
176
+ let found = await locator.count();
177
+ while (found !== expected && Date.now() < deadline) {
178
+ await new Promise((resolve) => setTimeout(resolve, 100));
179
+ found = await locator.count();
180
+ }
181
+ return found;
182
+ }
183
+ #resetEvidence(session) {
184
+ session.checked = false;
185
+ session.screenshots = [];
186
+ session.errors = [];
187
+ session.failedRequests = /* @__PURE__ */ new Set();
188
+ }
189
+ async #page(session) {
190
+ if (session.closed) throw new Error("Der Browser wurde beendet.");
191
+ if (session.page) return session.page;
192
+ const browser = await session.browser;
193
+ if (session.closed) throw new Error("Der Browser wurde beendet.");
194
+ const context = await browser.newContext({ viewport: session.viewport });
195
+ context.setDefaultTimeout(this.#options.timeoutMs);
196
+ context.setDefaultNavigationTimeout(this.#options.timeoutMs);
197
+ const page = await context.newPage();
198
+ const addError = (text) => {
199
+ session.errors.push(text.slice(0, 2e3));
200
+ if (session.errors.length > 100) session.errors.shift();
201
+ };
202
+ const addRequestError = (url, text) => {
203
+ if (session.failedRequests.has(url)) return;
204
+ session.failedRequests.add(url);
205
+ addError(text);
206
+ };
207
+ page.on("console", (message) => {
208
+ if (message.type() !== "error") return;
209
+ const source = message.text().startsWith("Failed to load resource") ? message.location().url : "";
210
+ if (source) addRequestError(source, `Konsole: ${message.text()} (${source})`);
211
+ else addError(`Konsole: ${message.text()}`);
212
+ });
213
+ page.on("pageerror", (error) => addError(`JavaScript: ${error.message}`));
214
+ page.on("requestfailed", (request) => addRequestError(request.url(), `Netzwerk: ${request.method()} ${request.url()} ${request.failure()?.errorText}`));
215
+ page.on("response", (response) => {
216
+ if (response.status() >= 400) addRequestError(response.url(), `HTTP ${response.status()}: ${response.url()}`);
217
+ });
218
+ page.on("framenavigated", (frame) => {
219
+ if (frame === page.mainFrame()) this.#resetEvidence(session);
220
+ });
221
+ page.on("popup", (popup) => {
222
+ addError(`Die Anwendung hat ein neues Fenster ge\xF6ffnet: ${popup.url()}. Popups werden nicht bedient.`);
223
+ void popup.close().catch((error) => addError(`Fenster schlie\xDFen: ${errorText(error)}`));
224
+ });
225
+ session.page = page;
226
+ return page;
227
+ }
228
+ #perform(runId, signal, action) {
229
+ if (this.#shutDown) return Promise.reject(endedError());
230
+ const session = this.#sessions.get(runId);
231
+ if (!session || session.closed) return Promise.reject(new Error("F\xFCr diesen Run ist kein Browser offen. Zuerst browser_open aufrufen."));
232
+ const pending = session.queue.then(async () => {
233
+ signal?.throwIfAborted();
234
+ const abort = () => {
235
+ void this.close(runId).catch((error) => console.error("Browserstopp fehlgeschlagen:", errorText(error)));
236
+ };
237
+ signal?.addEventListener("abort", abort, { once: true });
238
+ try {
239
+ const page = await this.#page(session);
240
+ signal?.throwIfAborted();
241
+ const result = await action(session, page);
242
+ signal?.throwIfAborted();
243
+ if (session.closed) throw new Error("Der Browser wurde beendet.");
244
+ return { result, page: this.#stateOf(session, page) };
245
+ } finally {
246
+ signal?.removeEventListener("abort", abort);
247
+ }
248
+ });
249
+ session.queue = pending.then(() => void 0, () => void 0);
250
+ return pending;
251
+ }
252
+ #action(runId, target, signal, action) {
253
+ return this.#perform(runId, signal, async (session, page) => {
254
+ session.checked = false;
255
+ session.screenshots = [];
256
+ await action(browserLocator(page, target)).catch(withAmbiguityHint);
257
+ return this.#snapshot(session, page);
258
+ });
259
+ }
260
+ #stateOf(session, page) {
261
+ return { url: page.url(), checked: session.checked, errors: [...session.errors], screenshots: [...session.screenshots] };
262
+ }
263
+ async #snapshot(session, page) {
264
+ const snapshot = await page.locator("body").ariaSnapshot({ mode: "ai", timeout: this.#options.timeoutMs });
265
+ return {
266
+ url: page.url(),
267
+ title: await page.title(),
268
+ snapshot: snapshot.slice(0, maxSnapshotLength),
269
+ truncated: snapshot.length > maxSnapshotLength,
270
+ errors: [...session.errors]
271
+ };
272
+ }
273
+ };
274
+
275
+ // executor/playwright.ts
276
+ import { constants } from "node:fs";
277
+ import { access } from "node:fs/promises";
278
+ import { pathToFileURL } from "node:url";
279
+ var hostPlaywright = async (machine, hostRoot) => {
280
+ const loaded = await import(pathToFileURL(machine.hostPackageFile(hostRoot, "playwright-core")).href);
281
+ return loaded.default;
282
+ };
283
+ var browserExecutable = async (playwright, environment = process.env) => {
284
+ const configured = environment[BROWSER_EXECUTABLE_VARIABLE];
285
+ const candidate = configured ? configured : playwright.chromium.executablePath();
286
+ if (await access(candidate, constants.X_OK).then(() => true, () => false)) return candidate;
287
+ throw new Error((configured ? `${BROWSER_EXECUTABLE_VARIABLE} nennt ${configured}; dort gibt es auf diesem Rechner keinen ausf\xFChrbaren Browser. ` : `Auf diesem Rechner gibt es keinen ausf\xFChrbaren Browser: ${BROWSER_EXECUTABLE_VARIABLE} ist nicht gesetzt und Chromium fehlt unter ${candidate}. `) + `Ein Arbeitsplatz holt Chromium mit pnpm provision --workspace, ein Server mit pnpm provision <profil>; ${BROWSER_EXECUTABLE_VARIABLE} nennt einen vorhandenen Chrome, auf einem Server in der Profilsektion ragents.browser, auf einem Arbeitsplatz in seiner Umgebung.`);
288
+ };
289
+ var launchChromium = async (machine, hostRoot, runId, timeoutMs) => {
290
+ const playwright = await hostPlaywright(machine, hostRoot);
291
+ return playwright.chromium.launch({
292
+ executablePath: await browserExecutable(playwright),
293
+ headless: true,
294
+ timeout: timeoutMs,
295
+ env: machine.processEnvironment(runId)
296
+ });
297
+ };
298
+
299
+ // executor/module.ts
300
+ var BROWSER_TIMEOUT_MS = 15e3;
301
+ var browserModule = (machine, options = {}) => (host) => {
302
+ const invalid = (message) => machine.operationError("browser-input-invalid", message, 400);
303
+ const fieldsOf = (input) => {
304
+ if (typeof input !== "object" || input === null || Array.isArray(input)) throw invalid("Die Eingabe einer Browseroperation ist ein Objekt");
305
+ return input;
306
+ };
307
+ const textOf = (input, key) => {
308
+ const value = fieldsOf(input)[key];
309
+ if (typeof value !== "string") throw invalid(`Die Browseroperation braucht ${key} als Text`);
310
+ return value;
311
+ };
312
+ const targetOf = (input) => {
313
+ const value = fieldsOf(input).target;
314
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw invalid("Die Browseroperation braucht ein Ziel");
315
+ return value;
316
+ };
317
+ const viewportOf = (input) => {
318
+ const { width, height } = fieldsOf(input);
319
+ if (typeof width !== "number" || typeof height !== "number" || !Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {
320
+ throw invalid("Ein Viewport braucht Breite und H\xF6he als positive ganze Zahlen");
321
+ }
322
+ return { width, height };
323
+ };
324
+ const timeoutMs = options.timeoutMs ?? BROWSER_TIMEOUT_MS;
325
+ const pages = new BrowserPages({
326
+ launch: options.launch ?? (async (runId) => launchChromium(machine, (await host.contextFor(runId)).hostRoot, runId, timeoutMs)),
327
+ timeoutMs,
328
+ checkTimeoutMs: options.checkTimeoutMs ?? Math.min(5e3, timeoutMs)
329
+ });
330
+ return {
331
+ operations: {
332
+ [BROWSER_OPERATIONS.open]: ({ runId, input, signal }) => pages.open(runId, textOf(input, "url"), viewportOf(fieldsOf(input).viewport), signal),
333
+ [BROWSER_OPERATIONS.snapshot]: ({ runId, signal }) => pages.snapshot(runId, signal),
334
+ [BROWSER_OPERATIONS.viewport]: ({ runId, input, signal }) => pages.viewport(runId, viewportOf(input), signal),
335
+ [BROWSER_OPERATIONS.click]: ({ runId, input, signal }) => pages.click(runId, targetOf(input), signal),
336
+ [BROWSER_OPERATIONS.fill]: ({ runId, input, signal }) => pages.fill(runId, targetOf(input), textOf(input, "value"), signal),
337
+ [BROWSER_OPERATIONS.select]: ({ runId, input, signal }) => pages.select(runId, targetOf(input), textOf(input, "label"), signal),
338
+ [BROWSER_OPERATIONS.press]: ({ runId, input, signal }) => pages.press(runId, targetOf(input), textOf(input, "key"), signal),
339
+ [BROWSER_OPERATIONS.check]: ({ runId, input, signal }) => pages.check(runId, fieldsOf(input), signal),
340
+ [BROWSER_OPERATIONS.screenshot]: ({ runId, input, signal }) => pages.screenshot(runId, textOf(input, "id"), fieldsOf(input).fullPage === true, signal),
341
+ [BROWSER_OPERATIONS.state]: async ({ runId }) => pages.state(runId),
342
+ [BROWSER_OPERATIONS.close]: async ({ runId }) => {
343
+ await pages.close(runId);
344
+ return null;
345
+ }
346
+ },
347
+ stopRun: (runId) => pages.close(runId),
348
+ shutdown: () => pages.shutdown()
349
+ };
350
+ };
351
+
352
+ // executor/index.ts
353
+ var executor = (machine) => ({ modules: [browserModule(machine)] });
354
+ export {
355
+ executor
356
+ };
357
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../plugins/ragents.browser/executor/contract.ts", "../../../plugins/ragents.browser/executor/pages.ts", "../../../plugins/ragents.browser/executor/playwright.ts", "../../../plugins/ragents.browser/executor/module.ts", "../../../plugins/ragents.browser/executor/index.ts"],
4
+ "sourcesContent": ["export const BROWSER_OPERATIONS = {\n open: \"browser.open\",\n snapshot: \"browser.snapshot\",\n viewport: \"browser.viewport\",\n click: \"browser.click\",\n fill: \"browser.fill\",\n select: \"browser.select\",\n press: \"browser.press\",\n check: \"browser.check\",\n screenshot: \"browser.screenshot\",\n state: \"browser.state\",\n close: \"browser.close\",\n} as const;\n\n/** Nennt einen eigenen Chrome; auf einem Server setzt ihn die Profilsektion `ragents.browser`, auf einem Arbeitsplatz seine Umgebung. */\nexport const BROWSER_EXECUTABLE_VARIABLE = \"BROWSER_EXECUTABLE_PATH\";\n\nexport interface BrowserTarget {\n role?: string;\n name?: string;\n label?: string;\n text?: string;\n testId?: string;\n css?: string;\n frame?: string;\n nth?: number;\n first?: boolean;\n}\n\nexport interface BrowserViewport {\n width: number;\n height: number;\n}\n\nexport interface BrowserSnapshot {\n url: string;\n title: string;\n snapshot: string;\n truncated: boolean;\n errors: string[];\n}\n\nexport interface BrowserCheck {\n target?: BrowserTarget;\n text?: string;\n url?: string;\n count?: number;\n noErrors?: boolean;\n}\n\n/** Was eine bestandene Pr\u00FCfung belegt; die Zeit setzt, wer die Evidenz des Runs h\u00E4lt. */\nexport interface BrowserCheckResult {\n url: string;\n assertions: string[];\n}\n\n/** Der Stand der Seite nach einer Operation; der Aufrufer h\u00E4lt daraus die Evidenz des Runs. */\nexport interface BrowserPageState {\n url: string;\n /** Seit der letzten Aktion oder Navigation hat eine Pr\u00FCfung bestanden. */\n checked: boolean;\n errors: string[];\n /** Die Kennungen der Aufnahmen seit der letzten Aktion oder Navigation, so wie der Aufrufer sie vergeben hat. */\n screenshots: string[];\n}\n\n/** Das Ergebnis einer Operation an der Seite und der Stand, in dem sie die Seite hinterl\u00E4sst. */\nexport interface BrowserStep<T> {\n result: T;\n page: BrowserPageState;\n}\n", "import type { Browser, Locator, Page } from \"playwright-core\";\nimport type {\n BrowserCheck,\n BrowserCheckResult,\n BrowserPageState,\n BrowserSnapshot,\n BrowserStep,\n BrowserTarget,\n BrowserViewport,\n} from \"./contract.js\";\n\ninterface BrowserSession {\n readonly browser: Promise<Browser>;\n readonly viewport: BrowserViewport;\n page?: Page;\n queue: Promise<void>;\n closed: boolean;\n checked: boolean;\n errors: string[];\n /** Adressen, deren fehlgeschlagene Anfrage schon gemeldet ist; HTTP-Status, Konsole und Netzwerk melden dieselbe Ursache nur einmal. */\n failedRequests: Set<string>;\n screenshots: string[];\n}\n\nexport interface BrowserPagesOptions {\n launch: (runId: string) => Promise<Browser>;\n timeoutMs: number;\n checkTimeoutMs: number;\n}\n\nconst errorText = (error: unknown): string => error instanceof Error ? error.message : String(error);\nconst endedError = (): Error => new Error(\"Der Browserdienst dieses Executors ist beendet.\");\nconst maxSnapshotLength = 40_000;\nconst ambiguityHint = \"W\u00E4hle mit nth (0-basiert) oder first: true im Ziel einen Treffer, oder pr\u00FCfe die Anzahl mit count in browser_check.\";\n\nconst withAmbiguityHint = (error: unknown): never => {\n if (error instanceof Error && error.message.includes(\"strict mode violation\")) throw new Error(`${error.message}\\n${ambiguityHint}`, { cause: error });\n throw error;\n};\n\nexport const browserLocator = (page: Page, target: BrowserTarget): Locator => {\n const selectors = [target.role, target.label, target.text, target.testId, target.css].filter((value) => value !== undefined);\n if (selectors.length !== 1 || (target.name !== undefined && target.role === undefined)) {\n throw new Error(\"Ein Browserziel braucht genau role (optional name), label, text, testId oder css.\");\n }\n if (target.nth !== undefined && target.first) throw new Error(\"Ein Browserziel verwendet entweder nth oder first, nicht beides.\");\n const root = target.frame ? page.frameLocator(target.frame) : page;\n const base = target.role ? root.getByRole(target.role as Parameters<Page[\"getByRole\"]>[0], { name: target.name, exact: true })\n : target.label ? root.getByLabel(target.label, { exact: true })\n : target.text ? root.getByText(target.text, { exact: true })\n : target.testId ? root.getByTestId(target.testId)\n : root.locator(target.css!);\n return target.first ? base.first() : target.nth !== undefined ? base.nth(target.nth) : base;\n};\n\n/** Je Run ein Browser mit einer Seite auf dieser Maschine; die Aktionen eines Runs laufen der Reihe nach. */\nexport class BrowserPages {\n readonly #options: BrowserPagesOptions;\n readonly #sessions = new Map<string, BrowserSession>();\n #shutDown = false;\n\n constructor(options: BrowserPagesOptions) {\n this.#options = options;\n }\n\n async open(runId: string, url: string, viewport: BrowserViewport, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n if (this.#shutDown) throw endedError();\n const parsed = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsed.protocol)) throw new Error(\"browser_open braucht eine HTTP- oder HTTPS-Adresse.\");\n signal?.throwIfAborted();\n if (!this.#sessions.has(runId)) this.#start(runId, viewport);\n return this.#perform(runId, signal, async (session, page) => {\n this.#resetEvidence(session);\n const response = await page.goto(parsed.href, { waitUntil: \"domcontentloaded\" });\n if (response && !response.ok()) throw new Error(`Browsernavigation fehlgeschlagen: HTTP ${response.status()} (${page.url()}).`);\n return this.#snapshot(session, page);\n });\n }\n\n snapshot(runId: string, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#perform(runId, signal, (session, page) => this.#snapshot(session, page));\n }\n\n viewport(runId: string, viewport: BrowserViewport, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#perform(runId, signal, async (session, page) => {\n await page.setViewportSize(viewport);\n return this.#snapshot(session, page);\n });\n }\n\n click(runId: string, target: BrowserTarget, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#action(runId, target, signal, (locator) => locator.click());\n }\n\n fill(runId: string, target: BrowserTarget, value: string, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#action(runId, target, signal, (locator) => locator.fill(value));\n }\n\n select(runId: string, target: BrowserTarget, label: string, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#action(runId, target, signal, (locator) => locator.selectOption({ label }));\n }\n\n press(runId: string, target: BrowserTarget, key: string, signal?: AbortSignal): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#action(runId, target, signal, (locator) => locator.press(key));\n }\n\n check(runId: string, input: BrowserCheck, signal?: AbortSignal): Promise<BrowserStep<BrowserCheckResult>> {\n return this.#perform(runId, signal, async (session, page) => {\n session.checked = false;\n if (!input.target && input.text === undefined && input.url === undefined && input.noErrors !== true) {\n throw new Error(\"browser_check braucht mindestens target, text, url oder noErrors: true.\");\n }\n if (input.count !== undefined && (!input.target || input.target.nth !== undefined || input.target.first)) {\n throw new Error(\"count in browser_check braucht ein target ohne nth oder first und z\u00E4hlt dessen sichtbare Treffer.\");\n }\n const timeout = this.#options.checkTimeoutMs;\n const assertions: string[] = [];\n if (input.target && input.count !== undefined) {\n const visible = browserLocator(page, input.target).filter({ visible: true });\n const found = await this.#waitForCount(visible, input.count, timeout);\n if (found !== input.count) throw new Error(`Erwartet ${input.count} sichtbare Treffer, gefunden ${found}.`);\n assertions.push(`${input.count} sichtbare Treffer`);\n } else if (input.target) {\n const locator = browserLocator(page, input.target);\n await locator.waitFor({ state: \"visible\", timeout }).catch(withAmbiguityHint);\n assertions.push(\"Ziel ist sichtbar\");\n if (input.text !== undefined) {\n try { await locator.filter({ hasText: input.text }).waitFor({ state: \"visible\", timeout }); }\n catch (error) { throw new Error(`Erwarteter Text fehlt im Ziel: ${input.text}`, { cause: error }); }\n assertions.push(`Text im Ziel: ${input.text}`);\n }\n } else if (input.text !== undefined) {\n await page.getByText(input.text, { exact: false }).first().waitFor({ state: \"visible\", timeout });\n assertions.push(`Sichtbarer Text: ${input.text}`);\n }\n if (input.url !== undefined) {\n await page.waitForURL(input.url, { timeout });\n assertions.push(`Adresse: ${input.url}`);\n }\n if (input.noErrors !== false) {\n if (session.errors.length > 0) throw new Error(`Browserfehler: ${session.errors.join(\"\\n\")}`);\n assertions.push(\"Keine erfassten Browser- oder Netzwerkfehler seit der Navigation\");\n }\n session.checked = true;\n return { url: page.url(), assertions };\n });\n }\n\n /** Nimmt die Seite als PNG auf und liefert es Base64-kodiert; `id` merkt sich die Seite als aktuelle Aufnahme. */\n screenshot(runId: string, id: string, fullPage: boolean, signal?: AbortSignal): Promise<BrowserStep<string>> {\n return this.#perform(runId, signal, async (session, page) => {\n const image = await page.screenshot({ fullPage, type: \"png\", timeout: this.#options.timeoutMs });\n session.screenshots.push(id);\n return image.toString(\"base64\");\n });\n }\n\n /** Der Stand der Seite, ohne auf laufende Aktionen zu warten; ohne offene Seite `null`. */\n state(runId: string): BrowserPageState | null {\n const session = this.#sessions.get(runId);\n return session && !session.closed && session.page ? this.#stateOf(session, session.page) : null;\n }\n\n async close(runId: string): Promise<void> {\n const session = this.#sessions.get(runId);\n if (!session) return;\n session.closed = true;\n this.#sessions.delete(runId);\n const browser = await session.browser.catch(() => undefined);\n if (browser) await browser.close();\n await session.queue;\n }\n\n /** Schlie\u00DFt jeden Browser; danach startet keiner mehr, weil niemand ihn schlie\u00DFen w\u00FCrde. */\n async shutdown(): Promise<void> {\n this.#shutDown = true;\n const results = await Promise.allSettled([...this.#sessions.keys()].map((runId) => this.close(runId)));\n const failed = results.find((result): result is PromiseRejectedResult => result.status === \"rejected\");\n if (failed) throw failed.reason;\n }\n\n #start(runId: string, viewport: BrowserViewport): void {\n const session: BrowserSession = {\n browser: this.#launch(runId),\n viewport,\n queue: Promise.resolve(),\n closed: false,\n checked: false,\n errors: [],\n failedRequests: new Set(),\n screenshots: [],\n };\n this.#sessions.set(runId, session);\n void session.browser.catch(() => {\n session.closed = true;\n if (this.#sessions.get(runId) === session) this.#sessions.delete(runId);\n });\n }\n\n async #launch(runId: string): Promise<Browser> {\n return this.#options.launch(runId);\n }\n\n async #waitForCount(locator: Locator, expected: number, timeout: number): Promise<number> {\n const deadline = Date.now() + timeout;\n let found = await locator.count();\n while (found !== expected && Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n found = await locator.count();\n }\n return found;\n }\n\n #resetEvidence(session: BrowserSession): void {\n session.checked = false;\n session.screenshots = [];\n session.errors = [];\n session.failedRequests = new Set();\n }\n\n async #page(session: BrowserSession): Promise<Page> {\n if (session.closed) throw new Error(\"Der Browser wurde beendet.\");\n if (session.page) return session.page;\n const browser = await session.browser;\n if (session.closed) throw new Error(\"Der Browser wurde beendet.\");\n const context = await browser.newContext({ viewport: session.viewport });\n context.setDefaultTimeout(this.#options.timeoutMs);\n context.setDefaultNavigationTimeout(this.#options.timeoutMs);\n const page = await context.newPage();\n const addError = (text: string) => {\n session.errors.push(text.slice(0, 2000));\n if (session.errors.length > 100) session.errors.shift();\n };\n const addRequestError = (url: string, text: string) => {\n if (session.failedRequests.has(url)) return;\n session.failedRequests.add(url);\n addError(text);\n };\n page.on(\"console\", (message) => {\n if (message.type() !== \"error\") return;\n const source = message.text().startsWith(\"Failed to load resource\") ? message.location().url : \"\";\n if (source) addRequestError(source, `Konsole: ${message.text()} (${source})`);\n else addError(`Konsole: ${message.text()}`);\n });\n page.on(\"pageerror\", (error) => addError(`JavaScript: ${error.message}`));\n page.on(\"requestfailed\", (request) => addRequestError(request.url(), `Netzwerk: ${request.method()} ${request.url()} ${request.failure()?.errorText}`));\n page.on(\"response\", (response) => { if (response.status() >= 400) addRequestError(response.url(), `HTTP ${response.status()}: ${response.url()}`); });\n page.on(\"framenavigated\", (frame) => { if (frame === page.mainFrame()) this.#resetEvidence(session); });\n page.on(\"popup\", (popup) => {\n addError(`Die Anwendung hat ein neues Fenster ge\u00F6ffnet: ${popup.url()}. Popups werden nicht bedient.`);\n void popup.close().catch((error) => addError(`Fenster schlie\u00DFen: ${errorText(error)}`));\n });\n session.page = page;\n return page;\n }\n\n #perform<T>(runId: string, signal: AbortSignal | undefined, action: (session: BrowserSession, page: Page) => Promise<T>): Promise<BrowserStep<T>> {\n if (this.#shutDown) return Promise.reject(endedError());\n const session = this.#sessions.get(runId);\n if (!session || session.closed) return Promise.reject(new Error(\"F\u00FCr diesen Run ist kein Browser offen. Zuerst browser_open aufrufen.\"));\n const pending = session.queue.then(async () => {\n signal?.throwIfAborted();\n const abort = () => { void this.close(runId).catch((error) => console.error(\"Browserstopp fehlgeschlagen:\", errorText(error))); };\n signal?.addEventListener(\"abort\", abort, { once: true });\n try {\n const page = await this.#page(session);\n signal?.throwIfAborted();\n const result = await action(session, page);\n signal?.throwIfAborted();\n if (session.closed) throw new Error(\"Der Browser wurde beendet.\");\n return { result, page: this.#stateOf(session, page) };\n } finally {\n signal?.removeEventListener(\"abort\", abort);\n }\n });\n session.queue = pending.then(() => undefined, () => undefined);\n return pending;\n }\n\n #action(runId: string, target: BrowserTarget, signal: AbortSignal | undefined, action: (locator: Locator) => Promise<unknown>): Promise<BrowserStep<BrowserSnapshot>> {\n return this.#perform(runId, signal, async (session, page) => {\n session.checked = false;\n session.screenshots = [];\n await action(browserLocator(page, target)).catch(withAmbiguityHint);\n return this.#snapshot(session, page);\n });\n }\n\n #stateOf(session: BrowserSession, page: Page): BrowserPageState {\n return { url: page.url(), checked: session.checked, errors: [...session.errors], screenshots: [...session.screenshots] };\n }\n\n async #snapshot(session: BrowserSession, page: Page): Promise<BrowserSnapshot> {\n const snapshot = await page.locator(\"body\").ariaSnapshot({ mode: \"ai\", timeout: this.#options.timeoutMs });\n return { url: page.url(), title: await page.title(), snapshot: snapshot.slice(0, maxSnapshotLength),\n truncated: snapshot.length > maxSnapshotLength, errors: [...session.errors] };\n }\n}\n", "import { constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Browser } from \"playwright-core\";\nimport type { WorkspaceExecutorMachine } from \"@ragents/workspace-executor\";\nimport { BROWSER_EXECUTABLE_VARIABLE } from \"./contract.js\";\n\ntype Playwright = typeof import(\"playwright-core\");\n\n/** playwright-core liegt in den node_modules des Hosts dieser Maschine und wird erst im Aufruf geladen, nie mit dem Beitrag. */\nexport const hostPlaywright = async (machine: WorkspaceExecutorMachine, hostRoot: string | undefined): Promise<Playwright> => {\n const loaded = await import(pathToFileURL(machine.hostPackageFile(hostRoot, \"playwright-core\")).href) as { default: Playwright };\n return loaded.default;\n};\n\n/** Der Chrome dieser Maschine: der aus ihrer Umgebung, sonst das Chromium, das die Provisionierung f\u00FCr playwright-core holt. */\nexport const browserExecutable = async (playwright: Playwright, environment: NodeJS.ProcessEnv = process.env): Promise<string> => {\n const configured = environment[BROWSER_EXECUTABLE_VARIABLE];\n const candidate = configured ? configured : playwright.chromium.executablePath();\n if (await access(candidate, constants.X_OK).then(() => true, () => false)) return candidate;\n throw new Error((configured\n ? `${BROWSER_EXECUTABLE_VARIABLE} nennt ${configured}; dort gibt es auf diesem Rechner keinen ausf\u00FChrbaren Browser. `\n : `Auf diesem Rechner gibt es keinen ausf\u00FChrbaren Browser: ${BROWSER_EXECUTABLE_VARIABLE} ist nicht gesetzt und Chromium fehlt unter ${candidate}. `)\n + \"Ein Arbeitsplatz holt Chromium mit pnpm provision --workspace, ein Server mit pnpm provision <profil>; \"\n + `${BROWSER_EXECUTABLE_VARIABLE} nennt einen vorhandenen Chrome, auf einem Server in der Profilsektion ragents.browser, `\n + \"auf einem Arbeitsplatz in seiner Umgebung.\");\n};\n\n/** Startet Chrome headless mit der Umgebung dieser Maschine und dem Marker des Runs, damit die Prozessanzeige ihn zuordnet. */\nexport const launchChromium = async (machine: WorkspaceExecutorMachine, hostRoot: string | undefined, runId: string, timeoutMs: number): Promise<Browser> => {\n const playwright = await hostPlaywright(machine, hostRoot);\n return playwright.chromium.launch({\n executablePath: await browserExecutable(playwright),\n headless: true,\n timeout: timeoutMs,\n env: machine.processEnvironment(runId),\n });\n};\n", "import type { Browser } from \"playwright-core\";\nimport type { WorkspaceExecutorMachine, WorkspaceModuleFactory } from \"@ragents/workspace-executor\";\nimport { BROWSER_OPERATIONS, type BrowserCheck, type BrowserTarget, type BrowserViewport } from \"./contract.js\";\nimport { BrowserPages } from \"./pages.js\";\nimport { launchChromium } from \"./playwright.js\";\n\nconst BROWSER_TIMEOUT_MS = 15_000;\n\nexport interface BrowserModuleOptions {\n /** Startet den Browser eines Runs; ohne Angabe Chrome \u00FCber playwright-core aus dem Host dieser Maschine. */\n launch?: (runId: string) => Promise<Browser>;\n timeoutMs?: number;\n checkTimeoutMs?: number;\n}\n\n/** Der Browser eines Runs auf dieser Maschine: Seite, Aktionen, Pr\u00FCfungen und Aufnahmen; Evidenz und Ablage h\u00E4lt der Aufrufer. */\nexport const browserModule = (machine: WorkspaceExecutorMachine, options: BrowserModuleOptions = {}): WorkspaceModuleFactory => (host) => {\n const invalid = (message: string): Error => machine.operationError(\"browser-input-invalid\", message, 400);\n const fieldsOf = (input: unknown): Readonly<Record<string, unknown>> => {\n if (typeof input !== \"object\" || input === null || Array.isArray(input)) throw invalid(\"Die Eingabe einer Browseroperation ist ein Objekt\");\n return input as Readonly<Record<string, unknown>>;\n };\n const textOf = (input: unknown, key: string): string => {\n const value = fieldsOf(input)[key];\n if (typeof value !== \"string\") throw invalid(`Die Browseroperation braucht ${key} als Text`);\n return value;\n };\n const targetOf = (input: unknown): BrowserTarget => {\n const value = fieldsOf(input).target;\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) throw invalid(\"Die Browseroperation braucht ein Ziel\");\n return value as BrowserTarget;\n };\n const viewportOf = (input: unknown): BrowserViewport => {\n const { width, height } = fieldsOf(input);\n if (typeof width !== \"number\" || typeof height !== \"number\" || !Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw invalid(\"Ein Viewport braucht Breite und H\u00F6he als positive ganze Zahlen\");\n }\n return { width, height };\n };\n const timeoutMs = options.timeoutMs ?? BROWSER_TIMEOUT_MS;\n const pages = new BrowserPages({\n launch: options.launch ?? (async (runId) => launchChromium(machine, (await host.contextFor(runId)).hostRoot, runId, timeoutMs)),\n timeoutMs,\n checkTimeoutMs: options.checkTimeoutMs ?? Math.min(5_000, timeoutMs),\n });\n return {\n operations: {\n [BROWSER_OPERATIONS.open]: ({ runId, input, signal }) =>\n pages.open(runId, textOf(input, \"url\"), viewportOf(fieldsOf(input).viewport), signal),\n [BROWSER_OPERATIONS.snapshot]: ({ runId, signal }) => pages.snapshot(runId, signal),\n [BROWSER_OPERATIONS.viewport]: ({ runId, input, signal }) => pages.viewport(runId, viewportOf(input), signal),\n [BROWSER_OPERATIONS.click]: ({ runId, input, signal }) => pages.click(runId, targetOf(input), signal),\n [BROWSER_OPERATIONS.fill]: ({ runId, input, signal }) => pages.fill(runId, targetOf(input), textOf(input, \"value\"), signal),\n [BROWSER_OPERATIONS.select]: ({ runId, input, signal }) => pages.select(runId, targetOf(input), textOf(input, \"label\"), signal),\n [BROWSER_OPERATIONS.press]: ({ runId, input, signal }) => pages.press(runId, targetOf(input), textOf(input, \"key\"), signal),\n [BROWSER_OPERATIONS.check]: ({ runId, input, signal }) => pages.check(runId, fieldsOf(input) as BrowserCheck, signal),\n [BROWSER_OPERATIONS.screenshot]: ({ runId, input, signal }) =>\n pages.screenshot(runId, textOf(input, \"id\"), fieldsOf(input).fullPage === true, signal),\n [BROWSER_OPERATIONS.state]: async ({ runId }) => pages.state(runId),\n [BROWSER_OPERATIONS.close]: async ({ runId }) => {\n await pages.close(runId);\n return null;\n },\n },\n stopRun: (runId) => pages.close(runId),\n shutdown: () => pages.shutdown(),\n };\n};\n", "import type { WorkspaceExecutorContribution } from \"@ragents/workspace-executor\";\nimport { browserModule } from \"./module.js\";\n\n/** Der Browser l\u00E4uft dort, wo der Arbeitsbereich des Runs liegt: im Executor des Servers oder in dem des Arbeitsplatzes. */\nexport const executor: WorkspaceExecutorContribution = (machine) => ({ modules: [browserModule(machine)] });\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
- "format": 3,
2
+ "format": 4,
3
3
  "id": "ragents.browser",
4
- "api": 6,
4
+ "api": 7,
5
5
  "hostNames": {
6
6
  "server": {
7
7
  "@ragents/engine": [
@@ -22,10 +22,6 @@
22
22
  "@ragents/host/ragents/document-store": [
23
23
  "documentStoreToken"
24
24
  ],
25
- "@ragents/workspace-executor": [
26
- "BROWSER_EXECUTABLE_VARIABLE",
27
- "BROWSER_OPERATIONS"
28
- ],
29
25
  "playwright-core": [
30
26
  "chromium"
31
27
  ],
@@ -35,9 +31,10 @@
35
31
  },
36
32
  "web": {}
37
33
  },
38
- "stand": "d0c11bff127c8ef2beda57eee9baee70c28425e7bf76471034f57905f897e4e0",
39
- "sourceStand": "3029e6a53c84be5678c03791e39563dce94aae4383518b48983e894c2b83df53",
34
+ "stand": "7da41ec4995b51a143b3e7d7c32f231db7b4ac353fe01df9bd0f02fb7b2c2eaf",
35
+ "sourceStand": "2b63191b5a2bff6a8f4f0dece586671a44df7be033a54975cb4617dca4e22325",
40
36
  "server": "server/index.js",
37
+ "executor": "executor/index.mjs",
41
38
  "exports": {
42
39
  "server": {
43
40
  "server/contract": "server/exports/server/contract.js"
@@ -8,4 +8,4 @@ var browserRuntimeToken = serviceToken("ragents.browser.runtime");
8
8
  export {
9
9
  browserRuntimeToken
10
10
  };
11
- //# sourceMappingURL=chunk-2GKLLCBE.js.map
11
+ //# sourceMappingURL=chunk-CWLX4VA5.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../plugins/ragents.browser/server/contract.ts"],
4
+ "sourcesContent": ["import { serviceToken } from \"@ragents/engine\";\nimport type { BrowserSnapshot } from \"../executor/contract.js\";\n\nexport type { BrowserSnapshot, BrowserTarget } from \"../executor/contract.js\";\n\nexport interface BrowserEvidence {\n checkedAt?: string;\n url?: string;\n screenshots: { name: string; url: string }[];\n currentScreenshots: { name: string; url: string }[];\n errors: string[];\n}\n\n/** Wer eine Operation an der Seite ausl\u00F6st: bei einem Werkzeugaufruf dessen Kennung, dazu der Abbruch. */\nexport interface BrowserCallOptions {\n signal?: AbortSignal;\n toolCallId?: string;\n}\n\nexport interface BrowserRuntime {\n open: (runId: string, url: string, options?: BrowserCallOptions) => Promise<BrowserSnapshot>;\n evidence: (runId: string) => BrowserEvidence;\n}\n\nexport const browserRuntimeToken = serviceToken<BrowserRuntime>(\"ragents.browser.runtime\");\n"],
5
+ "mappings": ";;;;AAAA,SAAS,oBAAoB;AAwBtB,IAAM,sBAAsB,aAA6B,yBAAyB;",
6
+ "names": []
7
+ }
@@ -2,7 +2,7 @@ import { createRequire as __ragentsCreateRequire } from "node:module";
2
2
  const require = __ragentsCreateRequire(import.meta.url);
3
3
  import {
4
4
  browserRuntimeToken
5
- } from "../../chunks/chunk-2GKLLCBE.js";
5
+ } from "../../chunks/chunk-CWLX4VA5.js";
6
6
  export {
7
7
  browserRuntimeToken
8
8
  };
@@ -2,20 +2,32 @@ import { createRequire as __ragentsCreateRequire } from "node:module";
2
2
  const require = __ragentsCreateRequire(import.meta.url);
3
3
  import {
4
4
  browserRuntimeToken
5
- } from "./chunks/chunk-2GKLLCBE.js";
5
+ } from "./chunks/chunk-CWLX4VA5.js";
6
6
 
7
7
  // server/index.ts
8
- import { BROWSER_EXECUTABLE_VARIABLE } from "@ragents/workspace-executor";
9
8
  import { sandboxServicesToken } from "@ragents/host/plugin-support/workspace-sandbox-host.js";
10
9
  import { documentStoreToken } from "@ragents/host/ragents/document-store.js";
11
10
 
11
+ // executor/contract.ts
12
+ var BROWSER_OPERATIONS = {
13
+ open: "browser.open",
14
+ snapshot: "browser.snapshot",
15
+ viewport: "browser.viewport",
16
+ click: "browser.click",
17
+ fill: "browser.fill",
18
+ select: "browser.select",
19
+ press: "browser.press",
20
+ check: "browser.check",
21
+ screenshot: "browser.screenshot",
22
+ state: "browser.state",
23
+ close: "browser.close"
24
+ };
25
+ var BROWSER_EXECUTABLE_VARIABLE = "BROWSER_EXECUTABLE_PATH";
26
+
12
27
  // server/browser.ts
13
28
  import { randomUUID } from "node:crypto";
14
29
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
15
30
  import path from "node:path";
16
- import {
17
- BROWSER_OPERATIONS
18
- } from "@ragents/workspace-executor";
19
31
  import { documentsApiPrefix } from "@ragents/plugins/ragents.documents/contract";
20
32
  var DEFAULT_VIEWPORT = { width: 1920, height: 1080 };
21
33
  var capturePath = (id) => `browser/${id}.png`;
@@ -439,7 +451,6 @@ import { spawn } from "node:child_process";
439
451
  import { access, constants } from "node:fs/promises";
440
452
  import path2 from "node:path";
441
453
  import { chromium } from "playwright-core";
442
- import { BROWSER_EXECUTABLE_VARIABLE as BROWSER_EXECUTABLE_VARIABLE2 } from "@ragents/workspace-executor";
443
454
  import {
444
455
  hostPackageFolder,
445
456
  provisionGap,
@@ -455,12 +466,12 @@ var install = (log) => new Promise((resolve, reject) => {
455
466
  });
456
467
  var createBrowserProvision = () => ({
457
468
  check: async () => {
458
- const configured = process.env[BROWSER_EXECUTABLE_VARIABLE2];
469
+ const configured = process.env[BROWSER_EXECUTABLE_VARIABLE];
459
470
  if (configured) {
460
- return await executable(configured) ? provisionReady : provisionGap("browser", `${BROWSER_EXECUTABLE_VARIABLE2} nennt ${configured}; dort gibt es keinen ausf\xFChrbaren Browser`, false);
471
+ return await executable(configured) ? provisionReady : provisionGap("browser", `${BROWSER_EXECUTABLE_VARIABLE} nennt ${configured}; dort gibt es keinen ausf\xFChrbaren Browser`, false);
461
472
  }
462
473
  const bundled = chromium.executablePath();
463
- return await executable(bundled) ? provisionReady : provisionGap("chromium", `Chromium fehlt unter ${bundled}; entweder ${BROWSER_EXECUTABLE_VARIABLE2} auf einen vorhandenen Chrome setzen (auf einem Server in der Profilsektion ragents.browser, auf einem Arbeitsplatz in seiner Umgebung) oder die Provisionierung den Browser laden lassen`, true);
474
+ return await executable(bundled) ? provisionReady : provisionGap("chromium", `Chromium fehlt unter ${bundled}; entweder ${BROWSER_EXECUTABLE_VARIABLE} auf einen vorhandenen Chrome setzen (auf einem Server in der Profilsektion ragents.browser, auf einem Arbeitsplatz in seiner Umgebung) oder die Provisionierung den Browser laden lassen`, true);
464
475
  },
465
476
  apply: async (_target, log) => {
466
477
  const state = await createBrowserProvision().check("");