Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/decisions-providers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@browserbasehq/stagehand-extension": patch
"@browserbasehq/stagehand-go": patch
"@browserbasehq/stagehand": patch
"@browserbasehq/stagehand-python": patch
---

The experimental `experimentalDecisions` path can use other decision models: `provider: "cloudflare"` (Clef on Workers AI, needs `accountId`), `"perplexity"` (Decider) or `"openai"` (Decisions API preview), next to the default `"typesafe"` (Jev). Answers from every provider are validated before they are acted on.
24 changes: 20 additions & 4 deletions packages/evals/initStagehand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,29 @@ export async function initStagehand({
experimentalDecisions = { apiKey: "instrument-only", enabled: false };
}
if (process.env.EVAL_DECISIONS === "1") {
const typesafeApiKey = resolveKey("TYPESAFE_API_KEY").value;
if (!typesafeApiKey) {
throw new Error("Stagehand init: EVAL_DECISIONS=1 requires TYPESAFE_API_KEY");
// EVAL_DECISIONS_PROVIDER: typesafe (default) | cloudflare | perplexity | openai
const provider = process.env.EVAL_DECISIONS_PROVIDER ?? "typesafe";
const keyName = {
typesafe: "TYPESAFE_API_KEY",
cloudflare: "CLOUDFLARE_API_TOKEN",
perplexity: "PERPLEXITY_API_KEY",
openai: "OPENAI_API_KEY",
}[provider];
if (!keyName) throw new Error(`Stagehand init: unknown EVAL_DECISIONS_PROVIDER "${provider}"`);
const decisionsApiKey = resolveKey(keyName).value;
if (!decisionsApiKey) {
throw new Error(
`Stagehand init: EVAL_DECISIONS=1 with provider "${provider}" requires ${keyName}`,
);
}
if (provider === "cloudflare" && !process.env.CLOUDFLARE_ACCOUNT_ID) {
throw new Error('Stagehand init: provider "cloudflare" requires CLOUDFLARE_ACCOUNT_ID');
}
const actConfidence = Number(process.env.EVAL_DECISIONS_CONFIDENCE);
experimentalDecisions = {
apiKey: typesafeApiKey,
...(provider === "typesafe" ? {} : { provider }),
apiKey: decisionsApiKey,
...(provider === "cloudflare" ? { accountId: process.env.CLOUDFLARE_ACCOUNT_ID } : {}),
...(process.env.EVAL_DECISIONS_MODEL ? { model: process.env.EVAL_DECISIONS_MODEL } : {}),
...(Number.isFinite(actConfidence) && process.env.EVAL_DECISIONS_CONFIDENCE
? { actConfidence }
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/controllers/stagehandController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export function createStagehandController(
systemPrompt: state.initParams.systemPrompt,
cache: cacheService.buildCacheContext(state.initParams),
gateway,
// Separate opt-in: this sends the extracted data to TypeSafe.
// Separate opt-in: this sends the extracted data to the decision provider.
decisions:
state.initParams.experimentalDecisions?.extract &&
state.initParams.experimentalDecisions.extract !== "off" &&
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/services/actService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
import { redactor } from "./decisions/args.js";
import type { DecisionsToolDeps } from "./decisions/toolAct.js";
import { focusOutline, parseOutline } from "./decisions/tree.js";
import type { JsonValue } from "./decisions/typesafeClient.js";
import type { JsonValue } from "./decisions/client.js";
import * as llmService from "./llmService.js";
import { disabledCacheMetadata, zeroStagehandResultUsage } from "./resultUsage.js";

Expand Down
85 changes: 61 additions & 24 deletions packages/extension/services/decisions/README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/extension/services/decisions/cacheCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Action } from "@browserbasehq/stagehand-protocol/types";
import { trimTrailingTextNode } from "../../utils.js";
import { ask, round, type AskContext, type Snapshot } from "./pick.js";
import { describeCandidate } from "./tree.js";
import { noulAnswer } from "./typesafeClient.js";
import { noulAnswer } from "./client.js";

/**
* Cached actions replay blind: a selector that still resolves, but now points
Expand Down
Loading
Loading