libretto 0.6.12 → 0.6.13
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.
- package/README.md +3 -8
- package/README.template.md +3 -8
- package/dist/cli/cli.js +0 -23
- package/dist/cli/commands/browser.js +1 -7
- package/dist/cli/commands/setup.js +1 -294
- package/dist/cli/commands/snapshot.js +9 -99
- package/dist/cli/commands/status.js +1 -41
- package/dist/cli/core/browser.js +3 -3
- package/dist/cli/core/config.js +3 -6
- package/dist/cli/core/daemon/daemon.js +25 -64
- package/dist/cli/core/daemon/snapshot.js +2 -29
- package/dist/cli/core/experiments.js +1 -28
- package/dist/cli/index.js +0 -2
- package/dist/cli/router.js +0 -2
- package/dist/shared/instrumentation/instrument.js +4 -4
- package/docs/releasing.md +8 -6
- package/package.json +2 -1
- package/skills/libretto/SKILL.md +17 -19
- package/skills/libretto/references/configuration-file-reference.md +6 -12
- package/skills/libretto/references/pages-and-page-targeting.md +1 -1
- package/skills/libretto-readonly/SKILL.md +2 -9
- package/src/cli/cli.ts +0 -24
- package/src/cli/commands/browser.ts +1 -7
- package/src/cli/commands/setup.ts +1 -380
- package/src/cli/commands/snapshot.ts +8 -136
- package/src/cli/commands/status.ts +1 -49
- package/src/cli/core/browser.ts +3 -3
- package/src/cli/core/config.ts +3 -6
- package/src/cli/core/daemon/daemon.ts +25 -67
- package/src/cli/core/daemon/ipc.ts +5 -16
- package/src/cli/core/daemon/snapshot.ts +1 -43
- package/src/cli/core/experiments.ts +9 -38
- package/src/cli/core/resolve-model.ts +5 -0
- package/src/cli/core/workflow-runtime.ts +1 -0
- package/src/cli/index.ts +0 -1
- package/src/cli/router.ts +0 -2
- package/src/shared/instrumentation/instrument.ts +4 -4
- package/dist/cli/commands/ai.js +0 -110
- package/dist/cli/core/ai-model.js +0 -195
- package/dist/cli/core/api-snapshot-analyzer.js +0 -86
- package/dist/cli/core/snapshot-analyzer.js +0 -667
- package/scripts/summarize-evals.mjs +0 -135
- package/src/cli/commands/ai.ts +0 -144
- package/src/cli/core/ai-model.ts +0 -301
- package/src/cli/core/api-snapshot-analyzer.ts +0 -110
- package/src/cli/core/snapshot-analyzer.ts +0 -856
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { readSnapshotModel } from "./config.js";
|
|
2
|
-
import { LIBRETTO_CONFIG_PATH } from "./context.js";
|
|
3
|
-
import { librettoCommand } from "../../shared/package-manager.js";
|
|
4
|
-
import {
|
|
5
|
-
hasProviderCredentials,
|
|
6
|
-
parseModel
|
|
7
|
-
} from "./resolve-model.js";
|
|
8
|
-
import { parseDotEnvAssignment } from "../../shared/env/load-env.js";
|
|
9
|
-
const DEFAULT_SNAPSHOT_MODELS = {
|
|
10
|
-
openai: "openai/gpt-5.4",
|
|
11
|
-
anthropic: "anthropic/claude-sonnet-4-6",
|
|
12
|
-
google: "google/gemini-3-flash-preview",
|
|
13
|
-
vertex: "vertex/gemini-2.5-flash",
|
|
14
|
-
openrouter: "openrouter/free"
|
|
15
|
-
};
|
|
16
|
-
function detectProviderEnvVar(provider, env = process.env) {
|
|
17
|
-
switch (provider) {
|
|
18
|
-
case "openai":
|
|
19
|
-
return env.OPENAI_API_KEY?.trim() ? "OPENAI_API_KEY" : null;
|
|
20
|
-
case "anthropic":
|
|
21
|
-
return env.ANTHROPIC_API_KEY?.trim() ? "ANTHROPIC_API_KEY" : null;
|
|
22
|
-
case "google":
|
|
23
|
-
if (env.GEMINI_API_KEY?.trim()) return "GEMINI_API_KEY";
|
|
24
|
-
if (env.GOOGLE_GENERATIVE_AI_API_KEY?.trim())
|
|
25
|
-
return "GOOGLE_GENERATIVE_AI_API_KEY";
|
|
26
|
-
return null;
|
|
27
|
-
case "vertex":
|
|
28
|
-
if (env.GOOGLE_CLOUD_PROJECT?.trim()) return "GOOGLE_CLOUD_PROJECT";
|
|
29
|
-
if (env.GCLOUD_PROJECT?.trim()) return "GCLOUD_PROJECT";
|
|
30
|
-
return null;
|
|
31
|
-
case "openrouter":
|
|
32
|
-
return env.OPENROUTER_API_KEY?.trim() ? "OPENROUTER_API_KEY" : null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
class SnapshotApiUnavailableError extends Error {
|
|
36
|
-
constructor(message) {
|
|
37
|
-
super(message);
|
|
38
|
-
this.name = "SnapshotApiUnavailableError";
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function providerSetupSentence(provider) {
|
|
42
|
-
switch (provider) {
|
|
43
|
-
case "openai":
|
|
44
|
-
return "Add OPENAI_API_KEY to .env or as a shell environment variable.";
|
|
45
|
-
case "anthropic":
|
|
46
|
-
return "Add ANTHROPIC_API_KEY to .env or as a shell environment variable.";
|
|
47
|
-
case "google":
|
|
48
|
-
return "Add GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY to .env or as a shell environment variable.";
|
|
49
|
-
case "vertex":
|
|
50
|
-
return "Add GOOGLE_CLOUD_PROJECT or GCLOUD_PROJECT to .env or as a shell environment variable, and make sure application default credentials are configured.";
|
|
51
|
-
case "openrouter":
|
|
52
|
-
return "Add OPENROUTER_API_KEY to .env or as a shell environment variable.";
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function defaultModelCommandLine() {
|
|
56
|
-
return librettoCommand(
|
|
57
|
-
"ai configure openai | anthropic | gemini | vertex | openrouter"
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
function providerMissingCredentialSummary(provider) {
|
|
61
|
-
switch (provider) {
|
|
62
|
-
case "openai":
|
|
63
|
-
return "OPENAI_API_KEY is missing";
|
|
64
|
-
case "anthropic":
|
|
65
|
-
return "ANTHROPIC_API_KEY is missing";
|
|
66
|
-
case "google":
|
|
67
|
-
return "GEMINI_API_KEY and GOOGLE_GENERATIVE_AI_API_KEY are missing";
|
|
68
|
-
case "vertex":
|
|
69
|
-
return "GOOGLE_CLOUD_PROJECT and GCLOUD_PROJECT are missing";
|
|
70
|
-
case "openrouter":
|
|
71
|
-
return "OPENROUTER_API_KEY is missing";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function noSnapshotApiConfiguredMessage() {
|
|
75
|
-
return [
|
|
76
|
-
"Failed to analyze snapshot because no snapshot analyzer is configured.",
|
|
77
|
-
`Add OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY, GOOGLE_CLOUD_PROJECT, or OPENROUTER_API_KEY to .env or as a shell environment variable, or choose a default model with \`${defaultModelCommandLine()}\`.`,
|
|
78
|
-
`For more info, run \`${librettoCommand("setup")}\`.`
|
|
79
|
-
].join(" ");
|
|
80
|
-
}
|
|
81
|
-
function missingProviderSnapshotMessage(selection) {
|
|
82
|
-
const configuredSource = selection.source === "config" ? ` in ${LIBRETTO_CONFIG_PATH}` : " from process env or .env";
|
|
83
|
-
return [
|
|
84
|
-
`Failed to analyze snapshot because ${selection.provider} is configured${configuredSource}, but ${providerMissingCredentialSummary(selection.provider)}.`,
|
|
85
|
-
providerSetupSentence(selection.provider),
|
|
86
|
-
`For more info, run \`${librettoCommand("setup")}\`.`
|
|
87
|
-
].join(" ");
|
|
88
|
-
}
|
|
89
|
-
function inferAutoSnapshotModel() {
|
|
90
|
-
const providersInPriorityOrder = [
|
|
91
|
-
"openai",
|
|
92
|
-
"anthropic",
|
|
93
|
-
"google",
|
|
94
|
-
"vertex",
|
|
95
|
-
"openrouter"
|
|
96
|
-
];
|
|
97
|
-
for (const provider of providersInPriorityOrder) {
|
|
98
|
-
const envVar = detectProviderEnvVar(provider);
|
|
99
|
-
if (!envVar) continue;
|
|
100
|
-
return {
|
|
101
|
-
model: DEFAULT_SNAPSHOT_MODELS[provider],
|
|
102
|
-
provider,
|
|
103
|
-
source: `env:${envVar}`
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
function resolveSnapshotApiModel(snapshotModel = readSnapshotModel()) {
|
|
109
|
-
if (snapshotModel) {
|
|
110
|
-
const { provider } = parseModel(snapshotModel);
|
|
111
|
-
return {
|
|
112
|
-
model: snapshotModel,
|
|
113
|
-
provider,
|
|
114
|
-
source: "config"
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
return inferAutoSnapshotModel();
|
|
118
|
-
}
|
|
119
|
-
function resolveSnapshotApiModelOrThrow(snapshotModel = readSnapshotModel()) {
|
|
120
|
-
const selection = resolveSnapshotApiModel(snapshotModel);
|
|
121
|
-
if (!selection) {
|
|
122
|
-
throw new SnapshotApiUnavailableError(noSnapshotApiConfiguredMessage());
|
|
123
|
-
}
|
|
124
|
-
if (!hasProviderCredentials(selection.provider)) {
|
|
125
|
-
throw new SnapshotApiUnavailableError(
|
|
126
|
-
missingProviderSnapshotMessage(selection)
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
return selection;
|
|
130
|
-
}
|
|
131
|
-
function isSnapshotApiUnavailableError(error) {
|
|
132
|
-
return error instanceof SnapshotApiUnavailableError;
|
|
133
|
-
}
|
|
134
|
-
function readSnapshotModelSafely(configPath) {
|
|
135
|
-
try {
|
|
136
|
-
return { ok: true, model: readSnapshotModel(configPath) };
|
|
137
|
-
} catch (err) {
|
|
138
|
-
return {
|
|
139
|
-
ok: false,
|
|
140
|
-
message: err instanceof Error ? err.message : String(err)
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
function resolveAiSetupStatus(configPath = LIBRETTO_CONFIG_PATH) {
|
|
145
|
-
const result = readSnapshotModelSafely(configPath);
|
|
146
|
-
if (!result.ok) {
|
|
147
|
-
return { kind: "invalid-config", message: result.message };
|
|
148
|
-
}
|
|
149
|
-
if (result.model) {
|
|
150
|
-
let selection;
|
|
151
|
-
try {
|
|
152
|
-
selection = resolveSnapshotApiModel(result.model);
|
|
153
|
-
} catch (err) {
|
|
154
|
-
return {
|
|
155
|
-
kind: "invalid-config",
|
|
156
|
-
message: err instanceof Error ? err.message : String(err)
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
if (!selection) {
|
|
160
|
-
return { kind: "unconfigured" };
|
|
161
|
-
}
|
|
162
|
-
if (hasProviderCredentials(selection.provider)) {
|
|
163
|
-
return {
|
|
164
|
-
kind: "ready",
|
|
165
|
-
model: selection.model,
|
|
166
|
-
provider: selection.provider,
|
|
167
|
-
source: selection.source
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
return {
|
|
171
|
-
kind: "configured-missing-credentials",
|
|
172
|
-
model: selection.model,
|
|
173
|
-
provider: selection.provider
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
const envSelection = resolveSnapshotApiModel(null);
|
|
177
|
-
if (envSelection && hasProviderCredentials(envSelection.provider)) {
|
|
178
|
-
return {
|
|
179
|
-
kind: "ready",
|
|
180
|
-
model: envSelection.model,
|
|
181
|
-
provider: envSelection.provider,
|
|
182
|
-
source: envSelection.source
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
return { kind: "unconfigured" };
|
|
186
|
-
}
|
|
187
|
-
export {
|
|
188
|
-
DEFAULT_SNAPSHOT_MODELS,
|
|
189
|
-
SnapshotApiUnavailableError,
|
|
190
|
-
isSnapshotApiUnavailableError,
|
|
191
|
-
parseDotEnvAssignment,
|
|
192
|
-
resolveAiSetupStatus,
|
|
193
|
-
resolveSnapshotApiModel,
|
|
194
|
-
resolveSnapshotApiModelOrThrow
|
|
195
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { generateObject } from "ai";
|
|
3
|
-
import { resolveModel } from "./resolve-model.js";
|
|
4
|
-
import {
|
|
5
|
-
InterpretResultSchema,
|
|
6
|
-
buildInlinePromptSelection,
|
|
7
|
-
getMimeType,
|
|
8
|
-
readFileAsBase64
|
|
9
|
-
} from "./snapshot-analyzer.js";
|
|
10
|
-
import { readSnapshotModel } from "./config.js";
|
|
11
|
-
import { resolveSnapshotApiModelOrThrow } from "./ai-model.js";
|
|
12
|
-
async function runApiInterpret(args, logger, snapshotModel = readSnapshotModel()) {
|
|
13
|
-
const selection = resolveSnapshotApiModelOrThrow(snapshotModel);
|
|
14
|
-
logger.info("api-interpret-start", {
|
|
15
|
-
objective: args.objective,
|
|
16
|
-
pngPath: args.pngPath,
|
|
17
|
-
htmlPath: args.htmlPath,
|
|
18
|
-
condensedHtmlPath: args.condensedHtmlPath,
|
|
19
|
-
model: selection.model,
|
|
20
|
-
modelSource: selection.source
|
|
21
|
-
});
|
|
22
|
-
const fullHtmlContent = readFileSync(args.htmlPath, "utf-8");
|
|
23
|
-
const condensedHtmlContent = readFileSync(args.condensedHtmlPath, "utf-8");
|
|
24
|
-
const promptSelection = buildInlinePromptSelection(
|
|
25
|
-
args,
|
|
26
|
-
fullHtmlContent,
|
|
27
|
-
condensedHtmlContent,
|
|
28
|
-
selection.model
|
|
29
|
-
);
|
|
30
|
-
logger.info("api-interpret-dom-selection", {
|
|
31
|
-
configuredModel: promptSelection.stats.configuredModel,
|
|
32
|
-
fullDomEstimatedTokens: promptSelection.stats.fullDomEstimatedTokens,
|
|
33
|
-
condensedDomEstimatedTokens: promptSelection.stats.condensedDomEstimatedTokens,
|
|
34
|
-
contextWindowTokens: promptSelection.budget.contextWindowTokens,
|
|
35
|
-
promptBudgetTokens: promptSelection.budget.promptBudgetTokens,
|
|
36
|
-
selectedDom: promptSelection.domSource,
|
|
37
|
-
selectedHtmlEstimatedTokens: promptSelection.htmlEstimatedTokens,
|
|
38
|
-
selectedPromptEstimatedTokens: promptSelection.promptEstimatedTokens,
|
|
39
|
-
selectionReason: promptSelection.selectionReason,
|
|
40
|
-
truncated: promptSelection.truncated
|
|
41
|
-
});
|
|
42
|
-
const imageBase64 = readFileAsBase64(args.pngPath);
|
|
43
|
-
const imageMimeType = getMimeType(args.pngPath);
|
|
44
|
-
const imageBytes = Buffer.from(imageBase64, "base64");
|
|
45
|
-
const model = await resolveModel(selection.model);
|
|
46
|
-
const { object: result } = await generateObject({
|
|
47
|
-
model,
|
|
48
|
-
schema: InterpretResultSchema,
|
|
49
|
-
messages: [
|
|
50
|
-
{
|
|
51
|
-
role: "user",
|
|
52
|
-
content: [
|
|
53
|
-
{ type: "text", text: promptSelection.prompt },
|
|
54
|
-
{
|
|
55
|
-
type: "image",
|
|
56
|
-
image: imageBytes,
|
|
57
|
-
mediaType: imageMimeType
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
}
|
|
61
|
-
],
|
|
62
|
-
temperature: 0.1
|
|
63
|
-
});
|
|
64
|
-
const parsed = InterpretResultSchema.parse(result);
|
|
65
|
-
logger.info("api-interpret-success", {
|
|
66
|
-
selectorCount: parsed.selectors.length,
|
|
67
|
-
answer: parsed.answer.slice(0, 200)
|
|
68
|
-
});
|
|
69
|
-
console.log("");
|
|
70
|
-
console.log("Analysis:");
|
|
71
|
-
console.log(parsed.answer);
|
|
72
|
-
if (parsed.selectors.length > 0) {
|
|
73
|
-
console.log("");
|
|
74
|
-
console.log("Selectors:");
|
|
75
|
-
parsed.selectors.forEach((selector, index) => {
|
|
76
|
-
console.log(` ${index + 1}. ${selector.label}: ${selector.selector}`);
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
if (parsed.notes?.trim()) {
|
|
80
|
-
console.log("");
|
|
81
|
-
console.log(`Notes: ${parsed.notes.trim()}`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export {
|
|
85
|
-
runApiInterpret
|
|
86
|
-
};
|