@pcamarajr/scout 0.6.0 → 0.7.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.
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ import type { ScoutConfig } from "../config.js";
3
+ import type { Step, Verdict } from "../types.js";
4
+ import { BrowserSession } from "./browser.js";
5
+ /** Normalized result every engine adapter maps into its own SDK shape. */
6
+ export interface ToolResult {
7
+ text: string;
8
+ isError?: boolean;
9
+ }
10
+ /**
11
+ * Engine-neutral tool definition. Both the Agent SDK and the AI SDK engines
12
+ * consume this single source of truth — neither SDK type leaks in here.
13
+ */
14
+ export interface ScoutTool {
15
+ name: string;
16
+ description: string;
17
+ /**
18
+ * Zod object input schema. The AI SDK consumes it directly as `inputSchema`;
19
+ * the Agent SDK adapter passes `schema.shape` (its `tool()` wants a raw shape).
20
+ */
21
+ schema: z.ZodObject;
22
+ handler: (args: unknown) => Promise<ToolResult>;
23
+ }
24
+ /**
25
+ * Context the tool factory closes over. `record` collects deterministic Steps,
26
+ * `setVerdict` is the verdict sink (scout_verdict writes here as a side effect,
27
+ * exactly like the original closure-over-`verdict` design), and `session`/
28
+ * `config` drive the actual browser actions.
29
+ */
30
+ export interface ScoutToolContext {
31
+ session: BrowserSession;
32
+ config: ScoutConfig;
33
+ record: (step: Step) => void;
34
+ setVerdict: (verdict: {
35
+ verdict: Verdict;
36
+ reason: string;
37
+ }) => void;
38
+ }
39
+ /**
40
+ * Builds the 9 browser tools + scout_verdict as engine-neutral definitions.
41
+ * The Portuguese descriptions/messages are intentionally verbatim from the
42
+ * original ai-runner — they are part of the verifier's behavior and are tracked
43
+ * for a separate English-sweep chore, NOT to be translated here.
44
+ */
45
+ export declare function createScoutTools(ctx: ScoutToolContext): ScoutTool[];
@@ -0,0 +1,151 @@
1
+ import { z } from "zod";
2
+ import { resolveEnvValue } from "./browser.js";
3
+ import { relativizeUrl } from "./engines/types.js";
4
+ const ok = (text) => ({ text });
5
+ const fail = (error) => ({
6
+ text: `ERRO: ${error instanceof Error ? error.message : String(error)}`,
7
+ isError: true,
8
+ });
9
+ /**
10
+ * Builds the 9 browser tools + scout_verdict as engine-neutral definitions.
11
+ * The Portuguese descriptions/messages are intentionally verbatim from the
12
+ * original ai-runner — they are part of the verifier's behavior and are tracked
13
+ * for a separate English-sweep chore, NOT to be translated here.
14
+ */
15
+ export function createScoutTools(ctx) {
16
+ const { session, config, record, setVerdict } = ctx;
17
+ const afterAction = async () => {
18
+ const snap = await session.snapshot();
19
+ return session.formatSnapshot(snap);
20
+ };
21
+ const define = (name, description, schema, handler) => ({
22
+ name,
23
+ description,
24
+ schema,
25
+ handler: (args) => handler(schema.parse(args)),
26
+ });
27
+ return [
28
+ define("browser_navigate", "Navega para uma URL (absoluta ou relativa ao baseUrl do app). Para tokens/segredos na URL use placeholder $ENV:VAR_NAME — resolvido em runtime, nunca passa por você.", z.object({ url: z.string().describe("Ex: /login, /renovar?token=$ENV:TOKEN ou https://...") }), async ({ url }) => {
29
+ try {
30
+ await session.navigate(url);
31
+ record({ kind: "navigate", url: relativizeUrl(url, config.baseUrl) });
32
+ return ok(await afterAction());
33
+ }
34
+ catch (e) {
35
+ return fail(e);
36
+ }
37
+ }),
38
+ define("browser_snapshot", "Retorna o estado atual da página: URL, título, elementos interativos numerados [ref] e texto visível. Use sempre que precisar decidir a próxima ação.", z.object({}), async () => {
39
+ try {
40
+ return ok(await afterAction());
41
+ }
42
+ catch (e) {
43
+ return fail(e);
44
+ }
45
+ }),
46
+ define("browser_click", "Clica no elemento identificado pelo [ref] do último snapshot.", z.object({ ref: z.number().int().describe("Ref numérico do snapshot") }), async ({ ref }) => {
47
+ try {
48
+ const target = await session.click(ref);
49
+ record({ kind: "click", target });
50
+ return ok(`Cliquei em ${target.description}.\n\n${await afterAction()}`);
51
+ }
52
+ catch (e) {
53
+ return fail(e);
54
+ }
55
+ }),
56
+ define("browser_fill", "Preenche um campo. Para credenciais/segredos use placeholder $ENV:VAR_NAME — o valor real vem do ambiente e nunca passa por você.", z.object({
57
+ ref: z.number().int(),
58
+ value: z.string().describe("Texto literal ou $ENV:VAR_NAME"),
59
+ }), async ({ ref, value }) => {
60
+ try {
61
+ const target = await session.fill(ref, resolveEnvValue(value));
62
+ record({ kind: "fill", target, value });
63
+ return ok(`Preenchi ${target.description}.`);
64
+ }
65
+ catch (e) {
66
+ return fail(e);
67
+ }
68
+ }),
69
+ define("browser_select", "Seleciona uma opção em um <select> pelo value ou label.", z.object({ ref: z.number().int(), value: z.string() }), async ({ ref, value }) => {
70
+ try {
71
+ const target = await session.select(ref, resolveEnvValue(value));
72
+ record({ kind: "select", target, value });
73
+ return ok(`Selecionei "${value}" em ${target.description}.\n\n${await afterAction()}`);
74
+ }
75
+ catch (e) {
76
+ return fail(e);
77
+ }
78
+ }),
79
+ define("browser_press", "Pressiona uma tecla (Enter, Escape, Tab, ArrowDown...).", z.object({ key: z.string() }), async ({ key }) => {
80
+ try {
81
+ await session.press(key);
82
+ record({ kind: "press", key });
83
+ return ok(await afterAction());
84
+ }
85
+ catch (e) {
86
+ return fail(e);
87
+ }
88
+ }),
89
+ define("browser_wait_for", "Espera texto aparecer na página OU a URL conter um trecho. Use após ações que disparam carregamento.", z.object({
90
+ text: z.string().optional().describe("Texto que deve ficar visível"),
91
+ urlContains: z.string().optional().describe("Trecho esperado na URL"),
92
+ }), async ({ text, urlContains }) => {
93
+ try {
94
+ if (text) {
95
+ await session.waitForText(text);
96
+ record({ kind: "waitForText", text });
97
+ }
98
+ if (urlContains) {
99
+ await session.waitForUrl(urlContains);
100
+ record({ kind: "waitForUrl", pattern: urlContains });
101
+ }
102
+ return ok(await afterAction());
103
+ }
104
+ catch (e) {
105
+ return fail(e);
106
+ }
107
+ }),
108
+ define("browser_assert", "Registra uma verificação do comportamento esperado. Use para CADA expectativa do cenário — essas asserções viram o teste determinístico.", z.object({
109
+ visibleText: z.string().optional().describe("Texto que DEVE estar visível"),
110
+ notVisibleText: z.string().optional().describe("Texto que NÃO deve estar visível"),
111
+ urlContains: z.string().optional().describe("Trecho que a URL deve conter"),
112
+ }), async ({ visibleText, notVisibleText, urlContains }) => {
113
+ try {
114
+ if (visibleText) {
115
+ await session.assertVisible(visibleText);
116
+ record({ kind: "assertVisible", text: visibleText });
117
+ }
118
+ if (notVisibleText) {
119
+ await session.assertNotVisible(notVisibleText);
120
+ record({ kind: "assertNotVisible", text: notVisibleText });
121
+ }
122
+ if (urlContains) {
123
+ await session.assertUrl(urlContains);
124
+ record({ kind: "assertUrl", pattern: urlContains });
125
+ }
126
+ return ok("Asserção passou.");
127
+ }
128
+ catch (e) {
129
+ return fail(e);
130
+ }
131
+ }),
132
+ define("browser_screenshot", "Captura screenshot como evidência. Use em momentos-chave (estado final, paywall, erro encontrado).", z.object({ label: z.string().describe("Rótulo curto, ex: 'paywall-exibido'") }), async ({ label }) => {
133
+ try {
134
+ await session.screenshot(label);
135
+ record({ kind: "screenshot", label });
136
+ return ok(`Screenshot "${label}" salvo.`);
137
+ }
138
+ catch (e) {
139
+ return fail(e);
140
+ }
141
+ }),
142
+ define("scout_verdict", "OBRIGATÓRIO ao final: registra o veredito da verificação. Após chamar, encerre.", z.object({
143
+ verdict: z.enum(["verified", "failed", "partial", "blocked"]),
144
+ reason: z.string().describe("Justificativa objetiva, citando o que foi observado"),
145
+ }), async (args) => {
146
+ setVerdict(args);
147
+ return ok("Veredito registrado. Encerre agora.");
148
+ }),
149
+ ];
150
+ }
151
+ //# sourceMappingURL=agent-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-tools.js","sourceRoot":"","sources":["../../src/runner/agent-tools.ts"],"names":[],"mappings":"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"}
@@ -1,40 +1,16 @@
1
1
  import type { ScoutConfig } from "../config.js";
2
- import type { Scenario, Step, Verdict } from "../types.js";
2
+ import type { Scenario } from "../types.js";
3
+ import { describeNoVerdict, relativizeUrl, type AiRunOutcome, type QueryEndInfo } from "./engines/types.js";
3
4
  import { BrowserSession } from "./browser.js";
4
- export interface AiRunOutcome {
5
- verdict: Verdict;
6
- reason: string;
7
- steps: Step[];
8
- transcript: string[];
9
- /**
10
- * Set when the runner itself failed to produce a verdict (agent never called
11
- * scout_verdict) — NOT a UI judgment. Callers may retry and must report it
12
- * as an infrastructure failure, never as "the scenario is blocked by the UI".
13
- */
14
- runnerFailure?: string;
15
- }
16
- /** How the SDK query ended, for no-verdict diagnostics. */
17
- export interface QueryEndInfo {
18
- subtype: string;
19
- numTurns?: number;
20
- errors?: string[];
21
- }
5
+ export { describeNoVerdict, relativizeUrl };
6
+ export type { AiRunOutcome, QueryEndInfo };
22
7
  /**
23
- * Human-readable cause for a run that ended without scout_verdict.
24
- * Distinguishes runner-infrastructure causes (turn budget, SDK errors) from
25
- * an agent that simply stopped talking.
26
- */
27
- export declare function describeNoVerdict(end: QueryEndInfo | undefined, maxTurns: number): string;
28
- /**
29
- * Records navigation relative to the configured baseUrl so cached scripts
30
- * survive --base-url / SCOUT_BASE_URL pointing at another server. URLs that
31
- * merely share the prefix (http://localhost:3000x) or live on other hosts
32
- * stay absolute.
33
- */
34
- export declare function relativizeUrl(url: string, baseUrl: string): string;
35
- /**
36
- * AI-driven run: a Claude agent navigates the real browser to verify the
37
- * scenario. Every successful action is recorded as a deterministic Step so
38
- * subsequent runs can replay without the LLM.
8
+ * AI-driven run, engine-neutral orchestrator. A Claude agent (via the Agent SDK
9
+ * by default, or the Vercel AI SDK when selected) navigates the real browser to
10
+ * verify the scenario. Every successful action is recorded as a deterministic
11
+ * Step so subsequent runs can replay without the LLM.
12
+ *
13
+ * Verdict capture, the forced-verdict rescue, and outcome assembly live HERE,
14
+ * above both engines, so behavior is identical regardless of engine.
39
15
  */
40
16
  export declare function runWithAgent(session: BrowserSession, scenario: Scenario, config: ScoutConfig): Promise<AiRunOutcome>;
@@ -1,187 +1,30 @@
1
- import { createSdkMcpServer, query, tool } from "@anthropic-ai/claude-agent-sdk";
2
- import { z } from "zod";
3
- import { resolveEnvValue } from "./browser.js";
1
+ import { inferProvider } from "../credentials.js";
2
+ import { createScoutTools } from "./agent-tools.js";
3
+ import { selectEngine } from "./engines/index.js";
4
+ import { describeNoVerdict, relativizeUrl, } from "./engines/types.js";
5
+ // Re-exported from their new home so existing importers (src/index.ts, callers)
6
+ // keep working unchanged.
7
+ export { describeNoVerdict, relativizeUrl };
4
8
  /**
5
- * Human-readable cause for a run that ended without scout_verdict.
6
- * Distinguishes runner-infrastructure causes (turn budget, SDK errors) from
7
- * an agent that simply stopped talking.
8
- */
9
- export function describeNoVerdict(end, maxTurns) {
10
- if (!end)
11
- return "a sessão do agente terminou sem emitir resultado (subprocesso morreu?)";
12
- switch (end.subtype) {
13
- case "error_max_turns":
14
- return `o agente estourou o limite de ${maxTurns} turns sem chamar scout_verdict`;
15
- case "error_during_execution":
16
- return `erro durante a execução do agente${end.errors?.length ? `: ${end.errors.join("; ")}` : ""}`;
17
- case "success":
18
- return "o agente encerrou normalmente sem chamar scout_verdict";
19
- default:
20
- return `a sessão do agente terminou com "${end.subtype}"${end.errors?.length ? `: ${end.errors.join("; ")}` : ""}`;
21
- }
22
- }
23
- /**
24
- * Records navigation relative to the configured baseUrl so cached scripts
25
- * survive --base-url / SCOUT_BASE_URL pointing at another server. URLs that
26
- * merely share the prefix (http://localhost:3000x) or live on other hosts
27
- * stay absolute.
28
- */
29
- export function relativizeUrl(url, baseUrl) {
30
- const base = baseUrl.replace(/\/+$/, "");
31
- if (url === base || url === `${base}/`)
32
- return "/";
33
- if (url.startsWith(base)) {
34
- const rest = url.slice(base.length);
35
- if (rest.startsWith("/") || rest.startsWith("?") || rest.startsWith("#"))
36
- return rest;
37
- }
38
- return url;
39
- }
40
- /**
41
- * AI-driven run: a Claude agent navigates the real browser to verify the
42
- * scenario. Every successful action is recorded as a deterministic Step so
43
- * subsequent runs can replay without the LLM.
9
+ * AI-driven run, engine-neutral orchestrator. A Claude agent (via the Agent SDK
10
+ * by default, or the Vercel AI SDK when selected) navigates the real browser to
11
+ * verify the scenario. Every successful action is recorded as a deterministic
12
+ * Step so subsequent runs can replay without the LLM.
13
+ *
14
+ * Verdict capture, the forced-verdict rescue, and outcome assembly live HERE,
15
+ * above both engines, so behavior is identical regardless of engine.
44
16
  */
45
17
  export async function runWithAgent(session, scenario, config) {
46
18
  const steps = [];
47
19
  const transcript = [];
48
20
  let verdict;
49
- const record = (step) => steps.push(step);
50
- const afterAction = async () => {
51
- const snap = await session.snapshot();
52
- return session.formatSnapshot(snap);
53
- };
54
- const ok = (text) => ({ content: [{ type: "text", text }] });
55
- const fail = (error) => ({
56
- content: [{ type: "text", text: `ERRO: ${error instanceof Error ? error.message : String(error)}` }],
57
- isError: true,
58
- });
59
- const browserServer = createSdkMcpServer({
60
- name: "browser",
61
- version: "1.0.0",
62
- tools: [
63
- tool("browser_navigate", "Navega para uma URL (absoluta ou relativa ao baseUrl do app). Para tokens/segredos na URL use placeholder $ENV:VAR_NAME — resolvido em runtime, nunca passa por você.", { url: z.string().describe("Ex: /login, /renovar?token=$ENV:TOKEN ou https://...") }, async ({ url }) => {
64
- try {
65
- await session.navigate(url);
66
- record({ kind: "navigate", url: relativizeUrl(url, config.baseUrl) });
67
- return ok(await afterAction());
68
- }
69
- catch (e) {
70
- return fail(e);
71
- }
72
- }),
73
- tool("browser_snapshot", "Retorna o estado atual da página: URL, título, elementos interativos numerados [ref] e texto visível. Use sempre que precisar decidir a próxima ação.", {}, async () => {
74
- try {
75
- return ok(await afterAction());
76
- }
77
- catch (e) {
78
- return fail(e);
79
- }
80
- }),
81
- tool("browser_click", "Clica no elemento identificado pelo [ref] do último snapshot.", { ref: z.number().int().describe("Ref numérico do snapshot") }, async ({ ref }) => {
82
- try {
83
- const target = await session.click(ref);
84
- record({ kind: "click", target });
85
- return ok(`Cliquei em ${target.description}.\n\n${await afterAction()}`);
86
- }
87
- catch (e) {
88
- return fail(e);
89
- }
90
- }),
91
- tool("browser_fill", "Preenche um campo. Para credenciais/segredos use placeholder $ENV:VAR_NAME — o valor real vem do ambiente e nunca passa por você.", {
92
- ref: z.number().int(),
93
- value: z.string().describe("Texto literal ou $ENV:VAR_NAME"),
94
- }, async ({ ref, value }) => {
95
- try {
96
- const target = await session.fill(ref, resolveEnvValue(value));
97
- record({ kind: "fill", target, value });
98
- return ok(`Preenchi ${target.description}.`);
99
- }
100
- catch (e) {
101
- return fail(e);
102
- }
103
- }),
104
- tool("browser_select", "Seleciona uma opção em um <select> pelo value ou label.", { ref: z.number().int(), value: z.string() }, async ({ ref, value }) => {
105
- try {
106
- const target = await session.select(ref, resolveEnvValue(value));
107
- record({ kind: "select", target, value });
108
- return ok(`Selecionei "${value}" em ${target.description}.\n\n${await afterAction()}`);
109
- }
110
- catch (e) {
111
- return fail(e);
112
- }
113
- }),
114
- tool("browser_press", "Pressiona uma tecla (Enter, Escape, Tab, ArrowDown...).", { key: z.string() }, async ({ key }) => {
115
- try {
116
- await session.press(key);
117
- record({ kind: "press", key });
118
- return ok(await afterAction());
119
- }
120
- catch (e) {
121
- return fail(e);
122
- }
123
- }),
124
- tool("browser_wait_for", "Espera texto aparecer na página OU a URL conter um trecho. Use após ações que disparam carregamento.", {
125
- text: z.string().optional().describe("Texto que deve ficar visível"),
126
- urlContains: z.string().optional().describe("Trecho esperado na URL"),
127
- }, async ({ text, urlContains }) => {
128
- try {
129
- if (text) {
130
- await session.waitForText(text);
131
- record({ kind: "waitForText", text });
132
- }
133
- if (urlContains) {
134
- await session.waitForUrl(urlContains);
135
- record({ kind: "waitForUrl", pattern: urlContains });
136
- }
137
- return ok(await afterAction());
138
- }
139
- catch (e) {
140
- return fail(e);
141
- }
142
- }),
143
- tool("browser_assert", "Registra uma verificação do comportamento esperado. Use para CADA expectativa do cenário — essas asserções viram o teste determinístico.", {
144
- visibleText: z.string().optional().describe("Texto que DEVE estar visível"),
145
- notVisibleText: z.string().optional().describe("Texto que NÃO deve estar visível"),
146
- urlContains: z.string().optional().describe("Trecho que a URL deve conter"),
147
- }, async ({ visibleText, notVisibleText, urlContains }) => {
148
- try {
149
- if (visibleText) {
150
- await session.assertVisible(visibleText);
151
- record({ kind: "assertVisible", text: visibleText });
152
- }
153
- if (notVisibleText) {
154
- await session.assertNotVisible(notVisibleText);
155
- record({ kind: "assertNotVisible", text: notVisibleText });
156
- }
157
- if (urlContains) {
158
- await session.assertUrl(urlContains);
159
- record({ kind: "assertUrl", pattern: urlContains });
160
- }
161
- return ok("Asserção passou.");
162
- }
163
- catch (e) {
164
- return fail(e);
165
- }
166
- }),
167
- tool("browser_screenshot", "Captura screenshot como evidência. Use em momentos-chave (estado final, paywall, erro encontrado).", { label: z.string().describe("Rótulo curto, ex: 'paywall-exibido'") }, async ({ label }) => {
168
- try {
169
- await session.screenshot(label);
170
- record({ kind: "screenshot", label });
171
- return ok(`Screenshot "${label}" salvo.`);
172
- }
173
- catch (e) {
174
- return fail(e);
175
- }
176
- }),
177
- tool("scout_verdict", "OBRIGATÓRIO ao final: registra o veredito da verificação. Após chamar, encerre.", {
178
- verdict: z.enum(["verified", "failed", "partial", "blocked"]),
179
- reason: z.string().describe("Justificativa objetiva, citando o que foi observado"),
180
- }, async (args) => {
181
- verdict = args;
182
- return ok("Veredito registrado. Encerre agora.");
183
- }),
184
- ],
21
+ const tools = createScoutTools({
22
+ session,
23
+ config,
24
+ record: (step) => steps.push(step),
25
+ setVerdict: (v) => {
26
+ verdict = v;
27
+ },
185
28
  });
186
29
  const profileInfo = scenario.profile
187
30
  ? `Sessão autenticada com o profile "${scenario.profile}"${config.profiles[scenario.profile]?.description ? ` (${config.profiles[scenario.profile].description})` : ""}. Você JÁ está logado — não faça login de novo a menos que o cenário peça.`
@@ -214,65 +57,29 @@ Regras:
214
57
  - Não re-preencha um campo que você já preencheu, a menos que a página tenha limpado o valor — cada ação sua vira um passo do script gravado, e passos duplicados são ruído que fragiliza o replay.
215
58
  - Seja econômico: não explore além do cenário. Seu orçamento é de ${config.maxTurns} ações.
216
59
  - Se você está repetindo tentativas sem progresso (overlay bloqueando, elemento que não aparece), PARE e chame scout_verdict (partial ou blocked) explicando o obstáculo — um veredito parcial vale mais que morrer sem veredito.`;
217
- const baseOptions = {
60
+ const userPrompt = `Verifique este cenário de QA:\n\n## ${scenario.name}\n\n${scenario.scenario}${scenario.notes ? `\n\nNotas: ${scenario.notes}` : ""}`;
61
+ const provider = inferProvider(config.model);
62
+ const engine = selectEngine(provider, config.engine);
63
+ const run = await engine.run({
64
+ provider,
218
65
  model: config.model,
219
66
  systemPrompt,
220
- mcpServers: { browser: browserServer },
221
- allowedTools: ["mcp__browser__*"],
222
- tools: [],
223
- settingSources: [],
224
- permissionMode: "bypassPermissions",
225
- };
226
- let sessionId;
227
- let endInfo;
228
- /** Drains a query, collecting transcript/session/end info. Always aborts at the end so no claude-agent-sdk subprocess outlives the run. */
229
- const drain = async (q, controller) => {
230
- try {
231
- for await (const message of q) {
232
- if ("session_id" in message && message.session_id)
233
- sessionId = message.session_id;
234
- if (message.type === "assistant") {
235
- for (const block of message.message.content) {
236
- if (block.type === "text" && block.text.trim())
237
- transcript.push(block.text.trim());
238
- }
239
- }
240
- if (message.type === "result") {
241
- endInfo = {
242
- subtype: message.subtype,
243
- numTurns: message.num_turns,
244
- errors: "errors" in message ? message.errors : undefined,
245
- };
246
- break;
247
- }
248
- }
249
- }
250
- finally {
251
- controller.abort();
252
- }
253
- };
254
- const mainController = new AbortController();
255
- try {
256
- await drain(query({
257
- prompt: `Verifique este cenário de QA:\n\n## ${scenario.name}\n\n${scenario.scenario}${scenario.notes ? `\n\nNotas: ${scenario.notes}` : ""}`,
258
- options: { ...baseOptions, maxTurns: config.maxTurns, abortController: mainController },
259
- }), mainController);
260
- }
261
- catch (error) {
262
- endInfo = { subtype: "sdk_error", errors: [error instanceof Error ? error.message : String(error)] };
263
- }
67
+ userPrompt,
68
+ tools,
69
+ maxTurns: config.maxTurns,
70
+ });
71
+ transcript.push(...run.transcript);
72
+ let endInfo = run.end;
264
73
  // Forced-verdict rescue: the agent died mute (typically error_max_turns).
265
74
  // Resume the same session with a tiny turn budget and demand scout_verdict
266
75
  // with whatever it observed — a partial verdict beats a silent death.
267
76
  const mainCause = verdict ? undefined : describeNoVerdict(endInfo, config.maxTurns);
268
- if (!verdict && sessionId) {
77
+ if (!verdict) {
269
78
  transcript.push(`[scout] Agente encerrou sem veredito (${mainCause}) — resgate: exigindo scout_verdict com o que foi observado.`);
270
- const rescueController = new AbortController();
271
79
  try {
272
- await drain(query({
273
- prompt: "Sua verificação atingiu o limite de ações. NÃO execute mais nenhuma ação de browser. Chame scout_verdict AGORA com base no que você já observou: 'partial' se a verificação ficou incompleta, 'blocked' se você nem chegou ao fluxo, 'failed'/'verified' apenas se já tinha evidência suficiente.",
274
- options: { ...baseOptions, maxTurns: 4, resume: sessionId, abortController: rescueController },
275
- }), rescueController);
80
+ const rescue = await run.resume("Sua verificação atingiu o limite de ações. NÃO execute mais nenhuma ação de browser. Chame scout_verdict AGORA com base no que você já observou: 'partial' se a verificação ficou incompleta, 'blocked' se você nem chegou ao fluxo, 'failed'/'verified' apenas se já tinha evidência suficiente.", 4);
81
+ transcript.push(...rescue.transcript);
82
+ endInfo = rescue.end;
276
83
  }
277
84
  catch (error) {
278
85
  transcript.push(`[scout] Resgate de veredito falhou: ${error instanceof Error ? error.message : String(error)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"ai-runner.js","sourceRoot":"","sources":["../../src/runner/ai-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai-runner.js","sourceRoot":"","sources":["../../src/runner/ai-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { type FinishReason, type LanguageModel } from "ai";
2
+ import type { AiProvider } from "../../credentials.js";
3
+ import type { AgentEngine, EngineRunSpec, EngineSession, QueryEndInfo } from "./types.js";
4
+ /**
5
+ * Optional injection seam. Production leaves `model` unset and we resolve the
6
+ * provider model from the spec's provider + model id; tests pass a
7
+ * MockLanguageModelV3 so the tool-calling loop runs deterministically with no
8
+ * network.
9
+ */
10
+ export interface AiSdkEngineOptions {
11
+ model?: LanguageModel;
12
+ }
13
+ /**
14
+ * Maps a provider + model id onto the matching AI SDK `LanguageModel`.
15
+ *
16
+ * anthropic → @ai-sdk/anthropic
17
+ * openai → @ai-sdk/openai
18
+ * google → @ai-sdk/google when a Gemini/Generative-AI API key is present;
19
+ * otherwise @ai-sdk/google-vertex (keyless, via Application Default
20
+ * Credentials). The split is driven by the same credential ladder
21
+ * `detectAiCredentials("google")` reports, so the engine and
22
+ * `scout doctor` agree on which sub-provider runs.
23
+ *
24
+ * For Vertex we pass `project` from GOOGLE_CLOUD_PROJECT when set (the provider
25
+ * otherwise reads GOOGLE_VERTEX_PROJECT) and default `location` to
26
+ * GOOGLE_VERTEX_LOCATION or "us-central1" — the Vertex provider requires a
27
+ * location eagerly at model construction, so we supply a sensible default to
28
+ * keep the keyless path zero-config. ADC itself comes from google-auth-library.
29
+ */
30
+ export declare function resolveModel(provider: AiProvider, modelId: string): LanguageModel;
31
+ /**
32
+ * Second engine, built on the Vercel AI SDK. It runs the SAME engine-neutral
33
+ * ScoutTool set through `generateText`'s tool-calling loop, against Anthropic,
34
+ * Google (Gemini API key or Vertex ADC) or OpenAI — selected per the spec's
35
+ * provider via {@link resolveModel}. The shared orchestrator owns prompts,
36
+ * verdict capture and the forced-verdict rescue — this class only drives the SDK
37
+ * loop and maps the SDK's `finishReason` into the QueryEndInfo vocabulary the
38
+ * rescue understands.
39
+ */
40
+ export declare class AiSdkEngine implements AgentEngine {
41
+ private readonly opts;
42
+ constructor(opts?: AiSdkEngineOptions);
43
+ run(spec: EngineRunSpec): Promise<EngineSession>;
44
+ }
45
+ /**
46
+ * Maps the AI SDK `finishReason` onto the QueryEndInfo.subtype vocabulary that
47
+ * {@link describeNoVerdict} and the forced-verdict rescue already speak.
48
+ *
49
+ * tool-calls / length → "error_max_turns" (hit the step budget mid-flight)
50
+ * stop → "success" (model ended its turn cleanly)
51
+ * error / content-filter / other → "error_during_execution"
52
+ *
53
+ * Rationale: when the loop stops on `tool-calls` it means `stopWhen` cut it off
54
+ * with a tool call still pending — i.e. it would have kept going, the budget ran
55
+ * out (exactly the Agent SDK's `error_max_turns`). `length` is the token-budget
56
+ * analog. Only a clean `stop` means the model chose to end its turn.
57
+ */
58
+ export declare function toEndInfo(finishReason: FinishReason, numTurns: number): QueryEndInfo;