libretto 0.5.5 → 0.6.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 (110) hide show
  1. package/README.md +23 -10
  2. package/README.template.md +23 -10
  3. package/dist/cli/cli.js +10 -0
  4. package/dist/cli/commands/ai.js +77 -2
  5. package/dist/cli/commands/browser.js +98 -8
  6. package/dist/cli/commands/execution.js +152 -56
  7. package/dist/cli/commands/setup.js +390 -0
  8. package/dist/cli/commands/snapshot.js +2 -2
  9. package/dist/cli/commands/status.js +62 -0
  10. package/dist/cli/core/{snapshot-api-config.js → ai-model.js} +81 -7
  11. package/dist/cli/core/api-snapshot-analyzer.js +7 -5
  12. package/dist/cli/core/browser.js +202 -36
  13. package/dist/cli/core/{ai-config.js → config.js} +14 -79
  14. package/dist/cli/core/context.js +1 -25
  15. package/dist/cli/core/deploy-artifact.js +121 -61
  16. package/dist/cli/core/providers/browserbase.js +53 -0
  17. package/dist/cli/core/providers/index.js +48 -0
  18. package/dist/cli/core/providers/kernel.js +46 -0
  19. package/dist/cli/core/providers/libretto-cloud.js +58 -0
  20. package/dist/cli/core/readonly-exec.js +231 -0
  21. package/dist/{shared/llm/client.js → cli/core/resolve-model.js} +4 -68
  22. package/dist/cli/core/session.js +53 -0
  23. package/dist/cli/core/skill-version.js +73 -0
  24. package/dist/cli/core/telemetry.js +1 -54
  25. package/dist/cli/index.js +1 -7
  26. package/dist/cli/router.js +4 -4
  27. package/dist/cli/workers/run-integration-runtime.js +19 -13
  28. package/dist/cli/workers/run-integration-worker-protocol.js +5 -2
  29. package/dist/index.d.ts +2 -4
  30. package/dist/index.js +2 -2
  31. package/dist/runtime/extract/extract.d.ts +2 -2
  32. package/dist/runtime/extract/extract.js +4 -2
  33. package/dist/runtime/extract/index.d.ts +1 -1
  34. package/dist/runtime/recovery/agent.d.ts +2 -3
  35. package/dist/runtime/recovery/agent.js +5 -3
  36. package/dist/runtime/recovery/errors.d.ts +2 -3
  37. package/dist/runtime/recovery/errors.js +4 -2
  38. package/dist/runtime/recovery/index.d.ts +1 -2
  39. package/dist/runtime/recovery/recovery.d.ts +2 -3
  40. package/dist/runtime/recovery/recovery.js +3 -3
  41. package/dist/shared/debug/pause.js +4 -21
  42. package/dist/shared/run/api.d.ts +2 -0
  43. package/dist/shared/run/browser.d.ts +9 -1
  44. package/dist/shared/run/browser.js +43 -3
  45. package/dist/shared/state/index.d.ts +1 -1
  46. package/dist/shared/state/index.js +2 -0
  47. package/dist/shared/state/session-state.d.ts +20 -1
  48. package/dist/shared/state/session-state.js +12 -2
  49. package/dist/shared/workflow/workflow.d.ts +2 -1
  50. package/dist/shared/workflow/workflow.js +16 -9
  51. package/package.json +17 -16
  52. package/scripts/postinstall.mjs +13 -11
  53. package/scripts/skills-libretto.mjs +14 -4
  54. package/skills/AGENTS.md +11 -0
  55. package/skills/libretto/SKILL.md +30 -9
  56. package/skills/libretto/references/auth-profiles.md +1 -1
  57. package/skills/libretto/references/code-generation-rules.md +3 -3
  58. package/skills/libretto/references/configuration-file-reference.md +11 -6
  59. package/skills/libretto-readonly/SKILL.md +95 -0
  60. package/src/cli/cli.ts +10 -0
  61. package/src/cli/commands/ai.ts +111 -1
  62. package/src/cli/commands/browser.ts +111 -9
  63. package/src/cli/commands/execution.ts +181 -74
  64. package/src/cli/commands/setup.ts +516 -0
  65. package/src/cli/commands/snapshot.ts +2 -2
  66. package/src/cli/commands/status.ts +79 -0
  67. package/src/cli/core/{snapshot-api-config.ts → ai-model.ts} +154 -14
  68. package/src/cli/core/api-snapshot-analyzer.ts +7 -5
  69. package/src/cli/core/browser.ts +242 -35
  70. package/src/cli/core/{ai-config.ts → config.ts} +14 -108
  71. package/src/cli/core/context.ts +1 -45
  72. package/src/cli/core/deploy-artifact.ts +141 -71
  73. package/src/cli/core/providers/browserbase.ts +57 -0
  74. package/src/cli/core/providers/index.ts +62 -0
  75. package/src/cli/core/providers/kernel.ts +49 -0
  76. package/src/cli/core/providers/libretto-cloud.ts +61 -0
  77. package/src/cli/core/providers/types.ts +9 -0
  78. package/src/cli/core/readonly-exec.ts +284 -0
  79. package/src/{shared/llm/client.ts → cli/core/resolve-model.ts} +3 -85
  80. package/src/cli/core/session.ts +75 -2
  81. package/src/cli/core/skill-version.ts +93 -0
  82. package/src/cli/core/telemetry.ts +0 -52
  83. package/src/cli/index.ts +0 -6
  84. package/src/cli/router.ts +4 -4
  85. package/src/cli/workers/run-integration-runtime.ts +18 -16
  86. package/src/cli/workers/run-integration-worker-protocol.ts +4 -1
  87. package/src/index.ts +1 -7
  88. package/src/runtime/extract/extract.ts +6 -5
  89. package/src/runtime/recovery/agent.ts +5 -4
  90. package/src/runtime/recovery/errors.ts +4 -3
  91. package/src/runtime/recovery/recovery.ts +4 -4
  92. package/src/shared/debug/pause.ts +4 -23
  93. package/src/shared/run/browser.ts +50 -1
  94. package/src/shared/state/index.ts +2 -0
  95. package/src/shared/state/session-state.ts +10 -0
  96. package/src/shared/workflow/workflow.ts +24 -13
  97. package/dist/cli/commands/init.js +0 -286
  98. package/dist/cli/commands/logs.js +0 -117
  99. package/dist/shared/llm/ai-sdk-adapter.d.ts +0 -22
  100. package/dist/shared/llm/ai-sdk-adapter.js +0 -49
  101. package/dist/shared/llm/client.d.ts +0 -13
  102. package/dist/shared/llm/index.d.ts +0 -5
  103. package/dist/shared/llm/index.js +0 -6
  104. package/dist/shared/llm/types.d.ts +0 -67
  105. package/src/cli/commands/init.ts +0 -331
  106. package/src/cli/commands/logs.ts +0 -128
  107. package/src/shared/llm/ai-sdk-adapter.ts +0 -81
  108. package/src/shared/llm/index.ts +0 -3
  109. package/src/shared/llm/types.ts +0 -63
  110. /package/dist/{shared/llm → cli/core/providers}/types.js +0 -0
@@ -1,4 +1,3 @@
1
- import { generateObject } from "ai";
2
1
  const GEMINI_API_KEY_ENV_VARS = [
3
2
  "GEMINI_API_KEY",
4
3
  "GOOGLE_GENERATIVE_AI_API_KEY"
@@ -108,76 +107,13 @@ async function getProviderModel(provider, modelId) {
108
107
  }
109
108
  }
110
109
  }
111
- function convertUserContentParts(parts) {
112
- return parts.map((part) => {
113
- if (part.type === "text") {
114
- return { type: "text", text: part.text };
115
- }
116
- return {
117
- type: "image",
118
- image: part.image,
119
- ...part.mediaType ? { mediaType: part.mediaType } : {}
120
- };
121
- });
122
- }
123
- function convertAssistantContentParts(parts) {
124
- return parts.filter(
125
- (part) => part.type === "text"
126
- ).map((part) => ({ type: "text", text: part.text }));
127
- }
128
- function convertMessages(messages) {
129
- return messages.map((msg) => {
130
- if (msg.role === "user") {
131
- if (typeof msg.content === "string") {
132
- return { role: "user", content: msg.content };
133
- }
134
- return {
135
- role: "user",
136
- content: convertUserContentParts(msg.content)
137
- };
138
- }
139
- if (typeof msg.content === "string") {
140
- return { role: "assistant", content: msg.content };
141
- }
142
- return {
143
- role: "assistant",
144
- content: convertAssistantContentParts(msg.content)
145
- };
146
- });
147
- }
148
- function createLLMClient(model) {
110
+ async function resolveModel(model) {
149
111
  const { provider, modelId } = parseModel(model);
150
- let modelPromise = null;
151
- const getModel = () => {
152
- modelPromise ??= getProviderModel(provider, modelId);
153
- return modelPromise;
154
- };
155
- return {
156
- async generateObject(opts) {
157
- const aiModel = await getModel();
158
- const result = await generateObject({
159
- model: aiModel,
160
- prompt: opts.prompt,
161
- schema: opts.schema,
162
- temperature: opts.temperature ?? 0
163
- });
164
- return result.object;
165
- },
166
- async generateObjectFromMessages(opts) {
167
- const aiModel = await getModel();
168
- const result = await generateObject({
169
- model: aiModel,
170
- messages: convertMessages(opts.messages),
171
- schema: opts.schema,
172
- temperature: opts.temperature ?? 0
173
- });
174
- return result.object;
175
- }
176
- };
112
+ return getProviderModel(provider, modelId);
177
113
  }
178
114
  export {
179
- createLLMClient,
180
115
  hasProviderCredentials,
181
116
  missingProviderCredentialsMessage,
182
- parseModel
117
+ parseModel,
118
+ resolveModel
183
119
  };
@@ -13,6 +13,7 @@ import {
13
13
  LIBRETTO_SESSIONS_DIR
14
14
  } from "./context.js";
15
15
  import {
16
+ SessionAccessModeSchema,
16
17
  SESSION_STATE_VERSION,
17
18
  parseSessionStateContent,
18
19
  serializeSessionState
@@ -28,6 +29,9 @@ function generateSessionName() {
28
29
  }
29
30
  return `ses-${id}`;
30
31
  }
32
+ function resolveSessionAccessMode(state) {
33
+ return SessionAccessModeSchema.parse(state?.mode);
34
+ }
31
35
  function logFileForSession(session) {
32
36
  validateSessionName(session);
33
37
  const dir = getSessionDir(session);
@@ -85,6 +89,21 @@ function listSessionsWithStateFile() {
85
89
  function listActiveSessions() {
86
90
  return listSessionsWithStateFile();
87
91
  }
92
+ function listRunningSessions() {
93
+ const sessions = listSessionsWithStateFile();
94
+ const running = [];
95
+ for (const name of sessions) {
96
+ const state = readSessionState(name);
97
+ if (!state) continue;
98
+ if (state.provider) {
99
+ running.push(state);
100
+ continue;
101
+ }
102
+ if (state.pid == null || !isPidRunning(state.pid)) continue;
103
+ running.push(state);
104
+ }
105
+ return running;
106
+ }
88
107
  function throwSessionNotFoundError(session) {
89
108
  const active = listActiveSessions();
90
109
  const lines = [`No session "${session}" found.`];
@@ -132,10 +151,34 @@ function writeSessionState(state, logger) {
132
151
  logger?.info("session-state-write", {
133
152
  session: state.session,
134
153
  stateFile,
154
+ mode: state.mode,
135
155
  port: state.port,
136
156
  pid: state.pid
137
157
  });
138
158
  }
159
+ function setSessionMode(session, mode, logger) {
160
+ const state = readSessionStateOrThrow(session);
161
+ const normalizedMode = SessionAccessModeSchema.parse(mode);
162
+ if (state.mode === normalizedMode) {
163
+ return state;
164
+ }
165
+ const nextState = {
166
+ ...state,
167
+ mode: normalizedMode
168
+ };
169
+ writeSessionState(nextState, logger);
170
+ return nextState;
171
+ }
172
+ function assertSessionAllowsCommand(state, commandName, allowedModes) {
173
+ const mode = resolveSessionAccessMode(state);
174
+ if (allowedModes.includes(mode)) {
175
+ return;
176
+ }
177
+ const supportedModes = [...allowedModes].join(", ");
178
+ throw new Error(
179
+ `Command "${commandName}" is blocked for session "${state.session}" because it is in ${mode} mode. Allowed modes for this command: ${supportedModes}. Run \`libretto session-mode write-access --session ${state.session}\` to unlock the session.`
180
+ );
181
+ }
139
182
  function clearSessionState(session, logger) {
140
183
  const stateFile = getStateFilePath(session);
141
184
  if (!existsSync(stateFile)) {
@@ -168,6 +211,11 @@ function setSessionStatus(session, status, logger) {
168
211
  function assertSessionAvailableForStart(session, logger) {
169
212
  const existingState = readSessionState(session, logger);
170
213
  if (!existingState) return;
214
+ if (existingState.provider && existingState.cdpEndpoint) {
215
+ throw new Error(
216
+ `Session "${session}" is already open via ${existingState.provider.name} provider. Close it first with: libretto close --session ${session}`
217
+ );
218
+ }
171
219
  if (existingState.pid == null || !isPidRunning(existingState.pid)) {
172
220
  setSessionStatus(session, "exited", logger);
173
221
  return;
@@ -181,15 +229,20 @@ export {
181
229
  SESSION_BROWSER_AGENT,
182
230
  SESSION_DEV_SERVER,
183
231
  SESSION_STATE_VERSION,
232
+ assertSessionAllowsCommand,
184
233
  assertSessionAvailableForStart,
185
234
  assertSessionStateExistsOrThrow,
186
235
  clearSessionState,
187
236
  generateSessionName,
188
237
  getStateFilePath,
238
+ isPidRunning,
239
+ listRunningSessions,
189
240
  listSessionsWithStateFile,
190
241
  logFileForSession,
191
242
  readSessionState,
192
243
  readSessionStateOrThrow,
244
+ resolveSessionAccessMode,
245
+ setSessionMode,
193
246
  setSessionStatus,
194
247
  validateSessionName,
195
248
  writeSessionState
@@ -0,0 +1,73 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { REPO_ROOT } from "./context.js";
5
+ const INSTALLED_SKILL_PATHS = [
6
+ [".agents", "skills", "libretto", "SKILL.md"],
7
+ [".claude", "skills", "libretto", "SKILL.md"]
8
+ ];
9
+ let cachedCliVersion = null;
10
+ function readCurrentCliVersion() {
11
+ if (cachedCliVersion) {
12
+ return cachedCliVersion;
13
+ }
14
+ const packageJsonPath = fileURLToPath(
15
+ new URL("../../../package.json", import.meta.url)
16
+ );
17
+ const manifest = JSON.parse(
18
+ readFileSync(packageJsonPath, "utf8")
19
+ );
20
+ if (!manifest.version) {
21
+ throw new Error(
22
+ `Unable to determine current libretto version from ${packageJsonPath}.`
23
+ );
24
+ }
25
+ cachedCliVersion = manifest.version;
26
+ return cachedCliVersion;
27
+ }
28
+ function readInstalledSkillVersion(skillPath) {
29
+ if (!existsSync(skillPath)) {
30
+ return null;
31
+ }
32
+ const contents = readFileSync(skillPath, "utf8");
33
+ const frontmatterMatch = contents.match(/^---\r?\n([\s\S]*?)\r?\n---/);
34
+ if (!frontmatterMatch) {
35
+ return null;
36
+ }
37
+ const metadataBlock = frontmatterMatch[1].match(
38
+ /^metadata:\s*\r?\n((?:[ \t]+.*(?:\r?\n|$))*)/m
39
+ )?.[1];
40
+ if (!metadataBlock) {
41
+ return null;
42
+ }
43
+ const versionMatch = metadataBlock.match(
44
+ /^[ \t]+version:\s*["']?([^"'\r\n]+)["']?\s*$/m
45
+ );
46
+ return versionMatch?.[1]?.trim() ?? null;
47
+ }
48
+ function findInstalledSkillVersionMismatch() {
49
+ const cliVersion = readCurrentCliVersion();
50
+ for (const relativePathParts of INSTALLED_SKILL_PATHS) {
51
+ const skillPath = join(REPO_ROOT, ...relativePathParts);
52
+ const installedVersion = readInstalledSkillVersion(skillPath);
53
+ if (installedVersion && installedVersion !== cliVersion) {
54
+ return { installedVersion, cliVersion };
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ function warnIfInstalledSkillOutOfDate() {
60
+ try {
61
+ const mismatch = findInstalledSkillVersionMismatch();
62
+ if (!mismatch) {
63
+ return;
64
+ }
65
+ console.error(
66
+ `Warning: Your agent skill (${mismatch.installedVersion}) is out of date with your Libretto CLI (${mismatch.cliVersion}). Please run \`npx libretto setup\` to update your skills to the correct version.`
67
+ );
68
+ } catch {
69
+ }
70
+ }
71
+ export {
72
+ warnIfInstalledSkillOutOfDate
73
+ };
@@ -1,8 +1,7 @@
1
1
  import {
2
2
  appendFileSync,
3
3
  existsSync,
4
- readFileSync,
5
- writeFileSync
4
+ readFileSync
6
5
  } from "node:fs";
7
6
  import {
8
7
  getSessionActionsLogPath,
@@ -34,30 +33,6 @@ function readNetworkLog(session, opts = {}) {
34
33
  }
35
34
  return entries;
36
35
  }
37
- function formatNetworkEntry(e) {
38
- const time = e.ts.replace(/.*T/, "").replace(/\.\d+Z$/, "");
39
- const duration = e.durationMs != null ? `${e.durationMs}ms` : "?ms";
40
- const size = e.size != null ? `${e.size}B` : "";
41
- const parts = [
42
- `[${time}]`,
43
- `${e.status}`,
44
- `${e.method.padEnd(6)}`,
45
- e.url,
46
- duration,
47
- size
48
- ].filter(Boolean);
49
- let line = parts.join(" ");
50
- if (e.postData) {
51
- line += `
52
- body: ${e.postData.substring(0, 120)}${e.postData.length > 120 ? "..." : ""}`;
53
- }
54
- return line;
55
- }
56
- function clearNetworkLog(session) {
57
- assertSessionStateExistsOrThrow(session);
58
- const logPath = getSessionNetworkLogPath(session);
59
- writeFileSync(logPath, "");
60
- }
61
36
  function parentLogAction(session, entry) {
62
37
  try {
63
38
  const record = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry };
@@ -99,30 +74,6 @@ function readActionLog(session, opts = {}) {
99
74
  }
100
75
  return entries;
101
76
  }
102
- function formatActionEntry(e) {
103
- const time = e.ts.replace(/.*T/, "").replace(/\.\d+Z$/, "");
104
- const src = e.source.toUpperCase().padEnd(5);
105
- const displaySelector = e.bestSemanticSelector || e.selector;
106
- const parts = [`[${time}]`, `[${src}]`, e.action];
107
- if (displaySelector) parts.push(displaySelector);
108
- if (e.targetSelector && e.targetSelector !== displaySelector) {
109
- parts.push(`target=${e.targetSelector}`);
110
- }
111
- if (e.nearbyText) parts.push(`text="${e.nearbyText}"`);
112
- if (e.coordinates) {
113
- parts.push(`@(${e.coordinates.x},${e.coordinates.y})`);
114
- }
115
- if (e.value) parts.push(`"${e.value}"`);
116
- if (e.url) parts.push(e.url);
117
- if (e.duration != null) parts.push(`${e.duration}ms`);
118
- if (!e.success) parts.push(`ERROR: ${e.error || "unknown"}`);
119
- return parts.join(" ");
120
- }
121
- function clearActionLog(session) {
122
- assertSessionStateExistsOrThrow(session);
123
- const logPath = getSessionActionsLogPath(session);
124
- writeFileSync(logPath, "");
125
- }
126
77
  const LOCATOR_ACTION_METHODS = [
127
78
  "click",
128
79
  "dblclick",
@@ -367,10 +318,6 @@ function wrapPageForActionLogging(page, session, pageId, onActivity) {
367
318
  }
368
319
  }
369
320
  export {
370
- clearActionLog,
371
- clearNetworkLog,
372
- formatActionEntry,
373
- formatNetworkEntry,
374
321
  parentLogAction,
375
322
  readActionLog,
376
323
  readNetworkLog,
package/dist/cli/index.js CHANGED
@@ -1,14 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { runLibrettoCLI } from "./cli.js";
3
- import {
4
- maybeConfigureLLMClientFactoryFromEnv,
5
- setLLMClientFactory
6
- } from "./core/context.js";
7
3
  import { runClose } from "./commands/browser.js";
8
- maybeConfigureLLMClientFactoryFromEnv();
9
4
  void runLibrettoCLI();
10
5
  export {
11
6
  runClose,
12
- runLibrettoCLI,
13
- setLLMClientFactory
7
+ runLibrettoCLI
14
8
  };
@@ -2,17 +2,17 @@ import { aiCommands } from "./commands/ai.js";
2
2
  import { browserCommands } from "./commands/browser.js";
3
3
  import { deployCommand } from "./commands/deploy.js";
4
4
  import { executionCommands } from "./commands/execution.js";
5
- import { initCommand } from "./commands/init.js";
6
- import { logCommands } from "./commands/logs.js";
5
+ import { setupCommand } from "./commands/setup.js";
6
+ import { statusCommand } from "./commands/status.js";
7
7
  import { snapshotCommand } from "./commands/snapshot.js";
8
8
  import { SimpleCLI } from "./framework/simple-cli.js";
9
9
  const cliRoutes = {
10
10
  ...browserCommands,
11
11
  deploy: deployCommand,
12
12
  ...executionCommands,
13
- ...logCommands,
14
13
  ai: aiCommands,
15
- init: initCommand,
14
+ setup: setupCommand,
15
+ status: statusCommand,
16
16
  snapshot: snapshotCommand
17
17
  };
18
18
  function createCLIApp() {
@@ -4,7 +4,7 @@ import { cwd } from "node:process";
4
4
  import { isAbsolute, resolve } from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import {
7
- getWorkflowFromModuleExports,
7
+ getDefaultWorkflowFromModuleExports,
8
8
  getWorkflowsFromModuleExports,
9
9
  instrumentContext,
10
10
  launchBrowser
@@ -89,7 +89,7 @@ function getAbsoluteIntegrationPath(integrationPath) {
89
89
  }
90
90
  return absolutePath;
91
91
  }
92
- async function loadWorkflowByName(absolutePath, workflowName) {
92
+ async function loadDefaultWorkflow(absolutePath) {
93
93
  let loadedModule;
94
94
  try {
95
95
  loadedModule = await import(pathToFileURL(absolutePath).href);
@@ -101,16 +101,20 @@ ${TSCONFIG_HINT}` : "";
101
101
  `Failed to import integration module at ${absolutePath}: ${message}${compileHint}`
102
102
  );
103
103
  }
104
- const workflow = getWorkflowFromModuleExports(loadedModule, workflowName);
105
- if (workflow) {
106
- return workflow;
104
+ const defaultWorkflow = getDefaultWorkflowFromModuleExports(loadedModule);
105
+ if (defaultWorkflow) {
106
+ return defaultWorkflow;
107
107
  }
108
- const availableWorkflows = getWorkflowsFromModuleExports(loadedModule).map(
108
+ const availableWorkflowNames = getWorkflowsFromModuleExports(loadedModule).map(
109
109
  (candidate) => candidate.name
110
110
  );
111
- const detail = availableWorkflows.length > 0 ? ` Available workflows: ${availableWorkflows.join(", ")}` : ' No workflows found in this file. Export a workflow() instance from "libretto" directly or via `export const workflows = { ... }`.';
111
+ if (availableWorkflowNames.length === 0) {
112
+ throw new Error(
113
+ `No default-exported workflow found in ${absolutePath}. Export the workflow with \`export default workflow("name", handler)\`.`
114
+ );
115
+ }
112
116
  throw new Error(
113
- `Workflow "${workflowName}" not found in ${absolutePath}.${detail}`
117
+ `No default-exported workflow found in ${absolutePath}. libretto run only uses the file's default export. Available named workflows: ${availableWorkflowNames.join(", ")}`
114
118
  );
115
119
  }
116
120
  async function installHeadedWorkflowVisualization(args) {
@@ -122,7 +126,7 @@ async function installHeadedWorkflowVisualization(args) {
122
126
  async function runIntegrationInternal(args, options) {
123
127
  const { logger } = options;
124
128
  const absolutePath = getAbsoluteIntegrationPath(args.integrationPath);
125
- const workflow = await loadWorkflowByName(absolutePath, args.workflowName);
129
+ const workflow = await loadDefaultWorkflow(absolutePath);
126
130
  const signalPaths = getPauseSignalPaths(args.session);
127
131
  await removeSignalIfExists(signalPaths.pausedSignalPath);
128
132
  await removeSignalIfExists(signalPaths.resumeSignalPath);
@@ -130,11 +134,11 @@ async function runIntegrationInternal(args, options) {
130
134
  await removeSignalIfExists(signalPaths.failedSignalPath);
131
135
  const restoreStdout = mirrorStdoutToFile(signalPaths.outputSignalPath);
132
136
  console.log(
133
- `Running workflow "${args.workflowName}" from ${absolutePath} (${args.headless ? "headless" : "headed"})...`
137
+ `Running workflow "${workflow.name}" from ${absolutePath} (${args.headless ? "headless" : "headed"})...`
134
138
  );
135
139
  const integrationLogger = logger.withScope("integration-run", {
136
140
  integrationPath: absolutePath,
137
- workflowName: args.workflowName,
141
+ workflowName: workflow.name,
138
142
  session: args.session
139
143
  });
140
144
  const authProfileDomain = args.authProfileDomain;
@@ -153,7 +157,10 @@ async function runIntegrationInternal(args, options) {
153
157
  sessionName: args.session,
154
158
  headless: args.headless,
155
159
  storageStatePath,
156
- viewport: args.viewport
160
+ viewport: args.viewport,
161
+ accessMode: args.accessMode,
162
+ cdpEndpoint: args.cdpEndpoint,
163
+ provider: args.provider
157
164
  });
158
165
  if (!args.headless && args.visualize !== false) {
159
166
  await installHeadedWorkflowVisualization({
@@ -208,7 +215,6 @@ async function runIntegrationInternal(args, options) {
208
215
  JSON.stringify({ completedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
209
216
  "utf8"
210
217
  );
211
- console.log("Integration completed.");
212
218
  return { status: "completed" };
213
219
  } finally {
214
220
  restoreStdout();
@@ -1,13 +1,16 @@
1
1
  import { z } from "zod";
2
+ import { SessionAccessModeSchema } from "../../shared/state/index.js";
2
3
  const RunIntegrationWorkerRequestSchema = z.object({
3
4
  integrationPath: z.string().min(1),
4
- workflowName: z.string().min(1),
5
5
  session: z.string().min(1),
6
6
  params: z.unknown(),
7
7
  headless: z.boolean(),
8
8
  visualize: z.boolean().default(true),
9
9
  authProfileDomain: z.string().optional(),
10
- viewport: z.object({ width: z.number(), height: z.number() }).optional()
10
+ viewport: z.object({ width: z.number(), height: z.number() }).optional(),
11
+ accessMode: SessionAccessModeSchema.default("write-access"),
12
+ cdpEndpoint: z.string().optional(),
13
+ provider: z.object({ name: z.string(), sessionId: z.string() }).optional()
11
14
  });
12
15
  export {
13
16
  RunIntegrationWorkerRequestSchema
package/dist/index.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  export { LogOptions, Logger, LoggerApi, LoggerSink, MinimalLogger, defaultLogger } from './shared/logger/logger.js';
2
2
  export { createFileLogSink, jsonlConsoleSink, prettyConsoleSink } from './shared/logger/sinks.js';
3
- export { LLMClient, Message, MessageContentPart } from './shared/llm/types.js';
4
- export { createLLMClientFromModel } from './shared/llm/ai-sdk-adapter.js';
5
3
  export { SESSION_STATE_VERSION, SessionState, SessionStateFile, SessionStateFileSchema, SessionStatus, SessionStatusSchema, parseSessionStateContent, parseSessionStateData, serializeSessionState } from './shared/state/session-state.js';
6
4
  export { executeRecoveryAgent } from './runtime/recovery/agent.js';
7
5
  export { attemptWithRecovery } from './runtime/recovery/recovery.js';
@@ -14,7 +12,7 @@ export { InstrumentationOptions, InstrumentedPage, installInstrumentation, instr
14
12
  export { GhostCursorOptions, ensureGhostCursor, ghostClick, hideGhostCursor, moveGhostCursor } from './shared/visualization/ghost-cursor.js';
15
13
  export { HighlightOptions, clearHighlights, ensureHighlightLayer, showHighlight } from './shared/visualization/highlight.js';
16
14
  export { BrowserSession, LaunchBrowserArgs, launchBrowser } from './shared/run/browser.js';
17
- export { ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, workflow } from './shared/workflow/workflow.js';
15
+ export { ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, workflow } from './shared/workflow/workflow.js';
18
16
  import 'zod';
19
- import 'ai';
20
17
  import 'playwright';
18
+ import 'ai';
package/dist/index.js CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  prettyConsoleSink,
10
10
  jsonlConsoleSink
11
11
  } from "./shared/logger/sinks.js";
12
- import { createLLMClientFromModel } from "./shared/llm/ai-sdk-adapter.js";
13
12
  import {
14
13
  SESSION_STATE_VERSION,
15
14
  SessionStatusSchema,
@@ -54,6 +53,7 @@ import {
54
53
  launchBrowser
55
54
  } from "./shared/run/api.js";
56
55
  import {
56
+ getDefaultWorkflowFromModuleExports,
57
57
  getWorkflowFromModuleExports,
58
58
  getWorkflowsFromModuleExports,
59
59
  isLibrettoWorkflow,
@@ -86,7 +86,6 @@ export {
86
86
  attemptWithRecovery,
87
87
  clearHighlights,
88
88
  createFileLogSink,
89
- createLLMClientFromModel,
90
89
  defaultLogger,
91
90
  detectSubmissionError,
92
91
  downloadAndSave,
@@ -95,6 +94,7 @@ export {
95
94
  ensureHighlightLayer,
96
95
  executeRecoveryAgent,
97
96
  extractFromPage,
97
+ getDefaultWorkflowFromModuleExports,
98
98
  getWorkflowFromModuleExports,
99
99
  getWorkflowsFromModuleExports,
100
100
  ghostClick,
@@ -1,13 +1,13 @@
1
1
  import { Page } from 'playwright';
2
2
  import z from 'zod';
3
3
  import { MinimalLogger } from '../../shared/logger/logger.js';
4
- import { LLMClient } from '../../shared/llm/types.js';
4
+ import { LanguageModel } from 'ai';
5
5
 
6
6
  type ExtractOptions<T extends z.ZodType> = {
7
7
  page: Page;
8
8
  instruction: string;
9
9
  schema: T;
10
- llmClient: LLMClient;
10
+ model: LanguageModel;
11
11
  logger?: MinimalLogger;
12
12
  /** Optional CSS selector to scope extraction to a specific element. */
13
13
  selector?: string;
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  defaultLogger
3
3
  } from "../../shared/logger/logger.js";
4
+ import { generateObject } from "ai";
4
5
  async function extractFromPage(options) {
5
6
  const {
6
7
  page,
@@ -8,7 +9,7 @@ async function extractFromPage(options) {
8
9
  schema,
9
10
  selector,
10
11
  logger = defaultLogger,
11
- llmClient
12
+ model
12
13
  } = options;
13
14
  let screenshot;
14
15
  let domContent;
@@ -49,7 +50,8 @@ ${domContent}
49
50
  </html>` : ""}
50
51
 
51
52
  Extract the requested information from the screenshot and return it in the specified format. Be precise and only extract what is visible.`;
52
- const result = await llmClient.generateObjectFromMessages({
53
+ const { object: result } = await generateObject({
54
+ model,
53
55
  schema,
54
56
  messages: [
55
57
  {
@@ -2,4 +2,4 @@ export { ExtractOptions, extractFromPage } from './extract.js';
2
2
  import 'playwright';
3
3
  import 'zod';
4
4
  import '../../shared/logger/logger.js';
5
- import '../../shared/llm/types.js';
5
+ import 'ai';
@@ -1,13 +1,12 @@
1
1
  import { Page } from 'playwright';
2
2
  import { MinimalLogger } from '../../shared/logger/logger.js';
3
- import { LLMClient } from '../../shared/llm/types.js';
4
- import 'zod';
3
+ import { LanguageModel } from 'ai';
5
4
 
6
5
  /**
7
6
  * Executes a vision-based recovery agent to recover from browser automation failures.
8
7
  * Takes a screenshot, sends it to the LLM with the instruction, and executes
9
8
  * the LLM's suggested browser actions.
10
9
  */
11
- declare function executeRecoveryAgent(page: Page, instruction: string, logger?: MinimalLogger, llmClient?: LLMClient): Promise<void>;
10
+ declare function executeRecoveryAgent(page: Page, instruction: string, logger?: MinimalLogger, model?: LanguageModel): Promise<void>;
12
11
 
13
12
  export { executeRecoveryAgent };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  defaultLogger
3
3
  } from "../../shared/logger/logger.js";
4
+ import { generateObject } from "ai";
4
5
  function delay(ms) {
5
6
  return new Promise((resolve) => setTimeout(resolve, ms));
6
7
  }
@@ -137,8 +138,8 @@ const recoveryActionSchema = z.object({
137
138
  })
138
139
  ])
139
140
  });
140
- async function executeRecoveryAgent(page, instruction, logger, llmClient) {
141
- if (!llmClient) {
141
+ async function executeRecoveryAgent(page, instruction, logger, model) {
142
+ if (!model) {
142
143
  return;
143
144
  }
144
145
  const log = logger ?? defaultLogger;
@@ -158,7 +159,8 @@ async function executeRecoveryAgent(page, instruction, logger, llmClient) {
158
159
  }
159
160
  const maxSteps = 3;
160
161
  for (let step = 1; step <= maxSteps; step++) {
161
- const result = await llmClient.generateObjectFromMessages({
162
+ const { object: result } = await generateObject({
163
+ model,
162
164
  schema: recoveryActionSchema,
163
165
  messages: [
164
166
  {
@@ -1,7 +1,6 @@
1
1
  import { Page } from 'playwright';
2
2
  import { MinimalLogger } from '../../shared/logger/logger.js';
3
- import { LLMClient } from '../../shared/llm/types.js';
4
- import 'zod';
3
+ import { LanguageModel } from 'ai';
5
4
 
6
5
  /**
7
6
  * Known error type for classifying submission errors.
@@ -26,6 +25,6 @@ type DetectedSubmissionError = {
26
25
  * @returns DetectedSubmissionError if a known error is matched
27
26
  * @throws The original error if no known error matches
28
27
  */
29
- declare function detectSubmissionError(page: Page, error: unknown, logContext: string, llmClient: LLMClient, knownErrors?: KnownSubmissionError[], logger?: MinimalLogger): Promise<DetectedSubmissionError>;
28
+ declare function detectSubmissionError(page: Page, error: unknown, logContext: string, model: LanguageModel, knownErrors?: KnownSubmissionError[], logger?: MinimalLogger): Promise<DetectedSubmissionError>;
30
29
 
31
30
  export { type DetectedSubmissionError, type KnownSubmissionError, detectSubmissionError };