@tangle-network/browser-agent-driver 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.
- package/LICENSE +196 -0
- package/README.md +149 -0
- package/dist/artifacts/composite-sink.d.ts +15 -0
- package/dist/artifacts/composite-sink.d.ts.map +1 -0
- package/dist/artifacts/composite-sink.js +27 -0
- package/dist/artifacts/composite-sink.js.map +1 -0
- package/dist/artifacts/filesystem-sink.d.ts +26 -0
- package/dist/artifacts/filesystem-sink.d.ts.map +1 -0
- package/dist/artifacts/filesystem-sink.js +81 -0
- package/dist/artifacts/filesystem-sink.js.map +1 -0
- package/dist/artifacts/types.d.ts +97 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +9 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/webhook-sink.d.ts +71 -0
- package/dist/artifacts/webhook-sink.d.ts.map +1 -0
- package/dist/artifacts/webhook-sink.js +117 -0
- package/dist/artifacts/webhook-sink.js.map +1 -0
- package/dist/brain/index.d.ts +149 -0
- package/dist/brain/index.d.ts.map +1 -0
- package/dist/brain/index.js +1030 -0
- package/dist/brain/index.js.map +1 -0
- package/dist/browser-launch.d.ts +27 -0
- package/dist/browser-launch.d.ts.map +1 -0
- package/dist/browser-launch.js +92 -0
- package/dist/browser-launch.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1035 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +143 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +205 -0
- package/dist/config.js.map +1 -0
- package/dist/context-budget.d.ts +14 -0
- package/dist/context-budget.d.ts.map +1 -0
- package/dist/context-budget.js +39 -0
- package/dist/context-budget.js.map +1 -0
- package/dist/design-audit.d.ts +48 -0
- package/dist/design-audit.d.ts.map +1 -0
- package/dist/design-audit.js +172 -0
- package/dist/design-audit.js.map +1 -0
- package/dist/domain-policy.d.ts +4 -0
- package/dist/domain-policy.d.ts.map +1 -0
- package/dist/domain-policy.js +69 -0
- package/dist/domain-policy.js.map +1 -0
- package/dist/drivers/block-patterns.d.ts +11 -0
- package/dist/drivers/block-patterns.d.ts.map +1 -0
- package/dist/drivers/block-patterns.js +123 -0
- package/dist/drivers/block-patterns.js.map +1 -0
- package/dist/drivers/cdp-page-state.d.ts +22 -0
- package/dist/drivers/cdp-page-state.d.ts.map +1 -0
- package/dist/drivers/cdp-page-state.js +38 -0
- package/dist/drivers/cdp-page-state.js.map +1 -0
- package/dist/drivers/cdp-snapshot.d.ts +32 -0
- package/dist/drivers/cdp-snapshot.d.ts.map +1 -0
- package/dist/drivers/cdp-snapshot.js +120 -0
- package/dist/drivers/cdp-snapshot.js.map +1 -0
- package/dist/drivers/playwright.d.ts +84 -0
- package/dist/drivers/playwright.d.ts.map +1 -0
- package/dist/drivers/playwright.js +385 -0
- package/dist/drivers/playwright.js.map +1 -0
- package/dist/drivers/snapshot.d.ts +134 -0
- package/dist/drivers/snapshot.d.ts.map +1 -0
- package/dist/drivers/snapshot.js +354 -0
- package/dist/drivers/snapshot.js.map +1 -0
- package/dist/drivers/types.d.ts +37 -0
- package/dist/drivers/types.d.ts.map +1 -0
- package/dist/drivers/types.js +5 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/env-loader.d.ts +2 -0
- package/dist/env-loader.d.ts.map +1 -0
- package/dist/env-loader.js +35 -0
- package/dist/env-loader.js.map +1 -0
- package/dist/formatters/slack.d.ts +37 -0
- package/dist/formatters/slack.d.ts.map +1 -0
- package/dist/formatters/slack.js +97 -0
- package/dist/formatters/slack.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/analyzer.d.ts +67 -0
- package/dist/memory/analyzer.d.ts.map +1 -0
- package/dist/memory/analyzer.js +265 -0
- package/dist/memory/analyzer.js.map +1 -0
- package/dist/memory/knowledge.d.ts +55 -0
- package/dist/memory/knowledge.d.ts.map +1 -0
- package/dist/memory/knowledge.js +115 -0
- package/dist/memory/knowledge.js.map +1 -0
- package/dist/memory/project-store.d.ts +43 -0
- package/dist/memory/project-store.d.ts.map +1 -0
- package/dist/memory/project-store.js +119 -0
- package/dist/memory/project-store.js.map +1 -0
- package/dist/memory/selectors.d.ts +46 -0
- package/dist/memory/selectors.d.ts.map +1 -0
- package/dist/memory/selectors.js +89 -0
- package/dist/memory/selectors.js.map +1 -0
- package/dist/memory/store.d.ts +39 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +193 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/model-pricing.d.ts +41 -0
- package/dist/model-pricing.d.ts.map +1 -0
- package/dist/model-pricing.js +197 -0
- package/dist/model-pricing.js.map +1 -0
- package/dist/multi-actor.d.ts +108 -0
- package/dist/multi-actor.d.ts.map +1 -0
- package/dist/multi-actor.js +192 -0
- package/dist/multi-actor.js.map +1 -0
- package/dist/override-pipeline.d.ts +57 -0
- package/dist/override-pipeline.d.ts.map +1 -0
- package/dist/override-pipeline.js +26 -0
- package/dist/override-pipeline.js.map +1 -0
- package/dist/personas.d.ts +19 -0
- package/dist/personas.d.ts.map +1 -0
- package/dist/personas.js +86 -0
- package/dist/personas.js.map +1 -0
- package/dist/preview.d.ts +32 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +138 -0
- package/dist/preview.js.map +1 -0
- package/dist/provider-defaults.d.ts +6 -0
- package/dist/provider-defaults.d.ts.map +1 -0
- package/dist/provider-defaults.js +40 -0
- package/dist/provider-defaults.js.map +1 -0
- package/dist/providers/sandbox-backend.d.ts +22 -0
- package/dist/providers/sandbox-backend.d.ts.map +1 -0
- package/dist/providers/sandbox-backend.js +259 -0
- package/dist/providers/sandbox-backend.js.map +1 -0
- package/dist/recovery.d.ts +91 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +500 -0
- package/dist/recovery.js.map +1 -0
- package/dist/reporters/junit.d.ts +8 -0
- package/dist/reporters/junit.d.ts.map +1 -0
- package/dist/reporters/junit.js +99 -0
- package/dist/reporters/junit.js.map +1 -0
- package/dist/run-metrics.d.ts +4 -0
- package/dist/run-metrics.d.ts.map +1 -0
- package/dist/run-metrics.js +48 -0
- package/dist/run-metrics.js.map +1 -0
- package/dist/run-state.d.ts +22 -0
- package/dist/run-state.d.ts.map +1 -0
- package/dist/run-state.js +33 -0
- package/dist/run-state.js.map +1 -0
- package/dist/runner/goal-verification.d.ts +13 -0
- package/dist/runner/goal-verification.d.ts.map +1 -0
- package/dist/runner/goal-verification.js +152 -0
- package/dist/runner/goal-verification.js.map +1 -0
- package/dist/runner/index.d.ts +12 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +18 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/overrides.d.ts +75 -0
- package/dist/runner/overrides.d.ts.map +1 -0
- package/dist/runner/overrides.js +385 -0
- package/dist/runner/overrides.js.map +1 -0
- package/dist/runner/page-analysis.d.ts +23 -0
- package/dist/runner/page-analysis.d.ts.map +1 -0
- package/dist/runner/page-analysis.js +91 -0
- package/dist/runner/page-analysis.js.map +1 -0
- package/dist/runner/runner.d.ts +66 -0
- package/dist/runner/runner.d.ts.map +1 -0
- package/dist/runner/runner.js +1314 -0
- package/dist/runner/runner.js.map +1 -0
- package/dist/runner/scout.d.ts +29 -0
- package/dist/runner/scout.d.ts.map +1 -0
- package/dist/runner/scout.js +81 -0
- package/dist/runner/scout.js.map +1 -0
- package/dist/runner/search-guidance.d.ts +31 -0
- package/dist/runner/search-guidance.d.ts.map +1 -0
- package/dist/runner/search-guidance.js +210 -0
- package/dist/runner/search-guidance.js.map +1 -0
- package/dist/runner/utils.d.ts +28 -0
- package/dist/runner/utils.d.ts.map +1 -0
- package/dist/runner/utils.js +119 -0
- package/dist/runner/utils.js.map +1 -0
- package/dist/runner.d.ts +8 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +21 -0
- package/dist/runner.js.map +1 -0
- package/dist/supervisor/critic.d.ts +29 -0
- package/dist/supervisor/critic.d.ts.map +1 -0
- package/dist/supervisor/critic.js +320 -0
- package/dist/supervisor/critic.js.map +1 -0
- package/dist/supervisor/policy.d.ts +11 -0
- package/dist/supervisor/policy.d.ts.map +1 -0
- package/dist/supervisor/policy.js +118 -0
- package/dist/supervisor/policy.js.map +1 -0
- package/dist/test-report.d.ts +15 -0
- package/dist/test-report.d.ts.map +1 -0
- package/dist/test-report.js +241 -0
- package/dist/test-report.js.map +1 -0
- package/dist/test-runner.d.ts +99 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +1075 -0
- package/dist/test-runner.js.map +1 -0
- package/dist/types.d.ts +493 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/wallet/automation.d.ts +52 -0
- package/dist/wallet/automation.d.ts.map +1 -0
- package/dist/wallet/automation.js +507 -0
- package/dist/wallet/automation.js.map +1 -0
- package/package.json +101 -0
- package/scripts/postinstall-provider-patches.mjs +52 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebhookSink — POST artifact metadata (and optionally data) to a webhook URL.
|
|
3
|
+
*
|
|
4
|
+
* Implements the ArtifactSink interface. Designed for CI/CD integrations,
|
|
5
|
+
* Slack/Discord notifications, and custom dashboards.
|
|
6
|
+
*
|
|
7
|
+
* Never throws — webhook failures are logged, not fatal (infra-as-best-effort).
|
|
8
|
+
*/
|
|
9
|
+
import type { Artifact, ArtifactSink, ArtifactManifestEntry, ArtifactType } from './types.js';
|
|
10
|
+
export interface WebhookSinkOptions {
|
|
11
|
+
/** Webhook endpoint URL */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Extra headers (e.g., auth tokens) */
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
/** Only send artifacts of these types. Undefined = send all. */
|
|
16
|
+
events?: ArtifactType[];
|
|
17
|
+
/** Base64-encode artifact data in payload (default: false) */
|
|
18
|
+
includeData?: boolean;
|
|
19
|
+
/** Skip data encoding for artifacts above this size in bytes (default: 1MB) */
|
|
20
|
+
maxPayloadBytes?: number;
|
|
21
|
+
/** Per-request timeout in ms (default: 10000) */
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
/** Number of retry attempts on failure (default: 3) */
|
|
24
|
+
retries?: number;
|
|
25
|
+
/** Transform the payload before POST. Use for Slack, Discord, Teams formatting. */
|
|
26
|
+
formatPayload?: (payload: WebhookPayload) => unknown;
|
|
27
|
+
}
|
|
28
|
+
interface WebhookArtifactPayload {
|
|
29
|
+
event: 'artifact';
|
|
30
|
+
testId: string;
|
|
31
|
+
type: ArtifactType;
|
|
32
|
+
name: string;
|
|
33
|
+
uri: string;
|
|
34
|
+
contentType: string;
|
|
35
|
+
sizeBytes: number;
|
|
36
|
+
metadata?: Record<string, string>;
|
|
37
|
+
data?: string;
|
|
38
|
+
}
|
|
39
|
+
interface WebhookSuiteCompletePayload {
|
|
40
|
+
event: 'suite:complete';
|
|
41
|
+
manifest: ArtifactManifestEntry[];
|
|
42
|
+
summary?: {
|
|
43
|
+
total: number;
|
|
44
|
+
passed: number;
|
|
45
|
+
failed: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export type WebhookPayload = WebhookArtifactPayload | WebhookSuiteCompletePayload;
|
|
49
|
+
export declare class WebhookSink implements ArtifactSink {
|
|
50
|
+
private manifest;
|
|
51
|
+
private readonly url;
|
|
52
|
+
private readonly headers;
|
|
53
|
+
private readonly events;
|
|
54
|
+
private readonly includeData;
|
|
55
|
+
private readonly maxPayloadBytes;
|
|
56
|
+
private readonly timeoutMs;
|
|
57
|
+
private readonly retries;
|
|
58
|
+
private readonly formatPayload;
|
|
59
|
+
constructor(options: WebhookSinkOptions);
|
|
60
|
+
put(artifact: Artifact): Promise<string>;
|
|
61
|
+
getManifest(): ArtifactManifestEntry[];
|
|
62
|
+
close(summary?: {
|
|
63
|
+
total: number;
|
|
64
|
+
passed: number;
|
|
65
|
+
failed: number;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
/** POST JSON with exponential backoff retry. Never throws. */
|
|
68
|
+
private post;
|
|
69
|
+
}
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=webhook-sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-sink.d.ts","sourceRoot":"","sources":["../../src/artifacts/webhook-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9F,MAAM,WAAW,kBAAkB;IACjC,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,gEAAgE;IAChE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;CACtD;AAED,UAAU,sBAAsB;IAC9B,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,2BAA2B;IACnC,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,GAAG,2BAA2B,CAAC;AAMlF,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqD;gBAEvE,OAAO,EAAE,kBAAkB;IAWjC,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAuC9C,WAAW,IAAI,qBAAqB,EAAE;IAIhC,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAavF,8DAA8D;YAChD,IAAI;CAuCnB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebhookSink — POST artifact metadata (and optionally data) to a webhook URL.
|
|
3
|
+
*
|
|
4
|
+
* Implements the ArtifactSink interface. Designed for CI/CD integrations,
|
|
5
|
+
* Slack/Discord notifications, and custom dashboards.
|
|
6
|
+
*
|
|
7
|
+
* Never throws — webhook failures are logged, not fatal (infra-as-best-effort).
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_MAX_PAYLOAD_BYTES = 1_048_576; // 1MB
|
|
10
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
11
|
+
const DEFAULT_RETRIES = 3;
|
|
12
|
+
export class WebhookSink {
|
|
13
|
+
manifest = [];
|
|
14
|
+
url;
|
|
15
|
+
headers;
|
|
16
|
+
events;
|
|
17
|
+
includeData;
|
|
18
|
+
maxPayloadBytes;
|
|
19
|
+
timeoutMs;
|
|
20
|
+
retries;
|
|
21
|
+
formatPayload;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.url = options.url;
|
|
24
|
+
this.headers = options.headers ?? {};
|
|
25
|
+
this.events = options.events ? new Set(options.events) : undefined;
|
|
26
|
+
this.includeData = options.includeData ?? false;
|
|
27
|
+
this.maxPayloadBytes = options.maxPayloadBytes ?? DEFAULT_MAX_PAYLOAD_BYTES;
|
|
28
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
29
|
+
this.retries = options.retries ?? DEFAULT_RETRIES;
|
|
30
|
+
this.formatPayload = options.formatPayload;
|
|
31
|
+
}
|
|
32
|
+
async put(artifact) {
|
|
33
|
+
const entry = {
|
|
34
|
+
testId: artifact.testId,
|
|
35
|
+
type: artifact.type,
|
|
36
|
+
name: artifact.name,
|
|
37
|
+
uri: `webhook://${this.url}/${artifact.testId}/${artifact.name}`,
|
|
38
|
+
contentType: artifact.contentType,
|
|
39
|
+
sizeBytes: artifact.data.length,
|
|
40
|
+
metadata: artifact.metadata,
|
|
41
|
+
};
|
|
42
|
+
this.manifest.push(entry);
|
|
43
|
+
// Filter by event type
|
|
44
|
+
if (this.events && !this.events.has(artifact.type)) {
|
|
45
|
+
return entry.uri;
|
|
46
|
+
}
|
|
47
|
+
const payload = {
|
|
48
|
+
event: 'artifact',
|
|
49
|
+
testId: artifact.testId,
|
|
50
|
+
type: artifact.type,
|
|
51
|
+
name: artifact.name,
|
|
52
|
+
uri: entry.uri,
|
|
53
|
+
contentType: artifact.contentType,
|
|
54
|
+
sizeBytes: artifact.data.length,
|
|
55
|
+
metadata: artifact.metadata,
|
|
56
|
+
};
|
|
57
|
+
// Optionally include base64-encoded data
|
|
58
|
+
if (this.includeData && artifact.data.length <= this.maxPayloadBytes) {
|
|
59
|
+
payload.data = artifact.data.toString('base64');
|
|
60
|
+
}
|
|
61
|
+
await this.post(payload);
|
|
62
|
+
return entry.uri;
|
|
63
|
+
}
|
|
64
|
+
getManifest() {
|
|
65
|
+
return [...this.manifest];
|
|
66
|
+
}
|
|
67
|
+
async close(summary) {
|
|
68
|
+
const payload = {
|
|
69
|
+
event: 'suite:complete',
|
|
70
|
+
manifest: this.manifest,
|
|
71
|
+
};
|
|
72
|
+
if (summary) {
|
|
73
|
+
payload.summary = summary;
|
|
74
|
+
}
|
|
75
|
+
await this.post(payload);
|
|
76
|
+
}
|
|
77
|
+
/** POST JSON with exponential backoff retry. Never throws. */
|
|
78
|
+
async post(payload) {
|
|
79
|
+
const formatted = this.formatPayload ? this.formatPayload(payload) : payload;
|
|
80
|
+
const body = JSON.stringify(formatted);
|
|
81
|
+
const baseDelay = 1000;
|
|
82
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
83
|
+
try {
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
86
|
+
const response = await fetch(this.url, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: {
|
|
89
|
+
'Content-Type': 'application/json',
|
|
90
|
+
...this.headers,
|
|
91
|
+
},
|
|
92
|
+
body,
|
|
93
|
+
signal: controller.signal,
|
|
94
|
+
});
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
if (response.ok)
|
|
97
|
+
return;
|
|
98
|
+
// Non-retryable client errors (4xx except 429)
|
|
99
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Network error or timeout — retry
|
|
105
|
+
}
|
|
106
|
+
// Exponential backoff: 1s, 2s, 4s, ...
|
|
107
|
+
if (attempt < this.retries) {
|
|
108
|
+
await sleep(baseDelay * Math.pow(2, attempt));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// All retries exhausted — silently give up (infra-as-best-effort)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function sleep(ms) {
|
|
115
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=webhook-sink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-sink.js","sourceRoot":"","sources":["../../src/artifacts/webhook-sink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Decision Engine — multimodal (vision + text), planning, verification,
|
|
3
|
+
* conversation history management, and quality evaluation.
|
|
4
|
+
*
|
|
5
|
+
* Uses Vercel AI SDK for multi-provider support (OpenAI, Anthropic, Google, Codex CLI, Claude Code).
|
|
6
|
+
*/
|
|
7
|
+
import type { ModelMessage } from 'ai';
|
|
8
|
+
import type { Action, PageState, AgentConfig, DesignFinding, GoalVerification } from '../types.js';
|
|
9
|
+
export interface BrainDecision {
|
|
10
|
+
action: Action;
|
|
11
|
+
nextActions?: Action[];
|
|
12
|
+
raw: string;
|
|
13
|
+
reasoning?: string;
|
|
14
|
+
plan?: string[];
|
|
15
|
+
currentStep?: number;
|
|
16
|
+
expectedEffect?: string;
|
|
17
|
+
tokensUsed?: number;
|
|
18
|
+
inputTokens?: number;
|
|
19
|
+
outputTokens?: number;
|
|
20
|
+
/** Which model handled this decision (for cost tracking with adaptive routing) */
|
|
21
|
+
modelUsed?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface QualityEvaluation {
|
|
24
|
+
score: number;
|
|
25
|
+
assessment: string;
|
|
26
|
+
strengths: string[];
|
|
27
|
+
issues: string[];
|
|
28
|
+
suggestions: string[];
|
|
29
|
+
raw: string;
|
|
30
|
+
tokensUsed?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface LinkScoutRecommendation {
|
|
33
|
+
selector: string;
|
|
34
|
+
reasoning: string;
|
|
35
|
+
confidence: number;
|
|
36
|
+
raw: string;
|
|
37
|
+
tokensUsed?: number;
|
|
38
|
+
}
|
|
39
|
+
export declare class Brain {
|
|
40
|
+
private modelCache;
|
|
41
|
+
private provider;
|
|
42
|
+
private modelName;
|
|
43
|
+
private adaptiveModelRouting;
|
|
44
|
+
private navModelName?;
|
|
45
|
+
private navProvider?;
|
|
46
|
+
private explicitApiKey?;
|
|
47
|
+
private baseUrl?;
|
|
48
|
+
private debug;
|
|
49
|
+
private history;
|
|
50
|
+
private maxHistoryTurns;
|
|
51
|
+
private visionEnabled;
|
|
52
|
+
private visionStrategy;
|
|
53
|
+
private llmTimeoutMs;
|
|
54
|
+
private compactFirstTurn;
|
|
55
|
+
private lastDecisionUrl?;
|
|
56
|
+
private systemPrompt;
|
|
57
|
+
private scoutModelName?;
|
|
58
|
+
private scoutProvider?;
|
|
59
|
+
private scoutUseVision;
|
|
60
|
+
private sandboxBackendType?;
|
|
61
|
+
private sandboxBackendProfile?;
|
|
62
|
+
private sandboxBackendProvider?;
|
|
63
|
+
constructor(config?: AgentConfig);
|
|
64
|
+
private resolveModelName;
|
|
65
|
+
private shouldSendTemperature;
|
|
66
|
+
private generationOptions;
|
|
67
|
+
/** Lazily create the LLM model instance based on provider config */
|
|
68
|
+
private getModel;
|
|
69
|
+
private generate;
|
|
70
|
+
/**
|
|
71
|
+
* Classify whether this turn should use the nav (cheap) model for decide().
|
|
72
|
+
*
|
|
73
|
+
* Empirically tested: routing early navigation turns to gpt-4.1-mini causes
|
|
74
|
+
* worse decisions that cascade into longer runs (more turns = more total cost).
|
|
75
|
+
* gpt-5.4 without routing is cheaper overall because it navigates more efficiently.
|
|
76
|
+
*
|
|
77
|
+
* Current strategy: nav model is ONLY used for verification (see verifyGoalCompletion),
|
|
78
|
+
* not for decide(). The flag is kept for future experiments with better routing signals.
|
|
79
|
+
*/
|
|
80
|
+
private shouldUseNavigationModel;
|
|
81
|
+
/** Reset conversation history (call between scenarios) */
|
|
82
|
+
reset(): void;
|
|
83
|
+
/** Get current conversation history */
|
|
84
|
+
getHistory(): ModelMessage[];
|
|
85
|
+
/** Inject a system-level feedback message into history */
|
|
86
|
+
injectFeedback(feedback: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Build the user message content parts — text + optional screenshot.
|
|
89
|
+
* Multimodal when vision is enabled and screenshot is available.
|
|
90
|
+
*/
|
|
91
|
+
private buildUserContent;
|
|
92
|
+
/**
|
|
93
|
+
* Compact conversation history: strip ELEMENTS blocks and screenshots
|
|
94
|
+
* from all but the most recent observation.
|
|
95
|
+
*
|
|
96
|
+
* Note: Aggressive one-line compression was tested (2026-03-08) and found
|
|
97
|
+
* counterproductive — the agent loses context about visited pages and
|
|
98
|
+
* wastes turns revisiting them. The current approach (strip snapshots,
|
|
99
|
+
* keep full text) is the empirically best balance.
|
|
100
|
+
*/
|
|
101
|
+
private compactHistory;
|
|
102
|
+
private stripElements;
|
|
103
|
+
decide(goal: string, state: PageState, extraContext?: string, turnInfo?: {
|
|
104
|
+
current: number;
|
|
105
|
+
max: number;
|
|
106
|
+
}, options?: {
|
|
107
|
+
forceVision?: boolean;
|
|
108
|
+
}): Promise<BrainDecision>;
|
|
109
|
+
/**
|
|
110
|
+
* Evaluate quality of the current page state.
|
|
111
|
+
* Takes a screenshot and asks the LLM to rate the visual quality,
|
|
112
|
+
* design, and professional polish.
|
|
113
|
+
*/
|
|
114
|
+
evaluate(state: PageState, goal: string): Promise<QualityEvaluation>;
|
|
115
|
+
recommendLinkCandidate(goal: string, state: PageState, candidates: Array<{
|
|
116
|
+
ref: string;
|
|
117
|
+
text: string;
|
|
118
|
+
score: number;
|
|
119
|
+
}>, extraContext?: string): Promise<LinkScoutRecommendation>;
|
|
120
|
+
/**
|
|
121
|
+
* Verify whether the goal was actually achieved.
|
|
122
|
+
* Separate from quality evaluation — this checks goal completion, not polish.
|
|
123
|
+
* Uses a fresh LLM call (no conversation history) to avoid self-confirmation bias.
|
|
124
|
+
*/
|
|
125
|
+
verifyGoalCompletion(state: PageState, goal: string, claimedResult: string): Promise<GoalVerification>;
|
|
126
|
+
/**
|
|
127
|
+
* Audit design quality of the current page state.
|
|
128
|
+
* Uses vision to analyze layout, typography, spacing, contrast, and UX.
|
|
129
|
+
* Returns structured findings with categories and severity levels.
|
|
130
|
+
*/
|
|
131
|
+
auditDesign(state: PageState, goal: string, checkpoints: string[]): Promise<{
|
|
132
|
+
score: number;
|
|
133
|
+
findings: DesignFinding[];
|
|
134
|
+
raw: string;
|
|
135
|
+
tokensUsed?: number;
|
|
136
|
+
}>;
|
|
137
|
+
/**
|
|
138
|
+
* Extract reusable knowledge from a completed trajectory.
|
|
139
|
+
* Asks the LLM to identify patterns, timings, reliable selectors,
|
|
140
|
+
* and app quirks from a successful run.
|
|
141
|
+
*/
|
|
142
|
+
extractKnowledge(trajectoryText: string, domain: string): Promise<Array<{
|
|
143
|
+
type: 'timing' | 'selector' | 'pattern' | 'quirk';
|
|
144
|
+
key: string;
|
|
145
|
+
value: string;
|
|
146
|
+
}>>;
|
|
147
|
+
private parse;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/brain/index.ts"],"names":[],"mappings":"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"}
|