@e2edev/e2e 0.2.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 +21 -0
- package/README.md +104 -0
- package/dist/agent/act-validation.d.ts +27 -0
- package/dist/agent/act-validation.d.ts.map +1 -0
- package/dist/agent/act-validation.js +121 -0
- package/dist/agent/act-validation.js.map +1 -0
- package/dist/agent/act.d.ts +27 -0
- package/dist/agent/act.d.ts.map +1 -0
- package/dist/agent/act.js +775 -0
- package/dist/agent/act.js.map +1 -0
- package/dist/agent/actions.d.ts +66 -0
- package/dist/agent/actions.d.ts.map +1 -0
- package/dist/agent/actions.js +82 -0
- package/dist/agent/actions.js.map +1 -0
- package/dist/agent/ai-sdk.d.ts +16 -0
- package/dist/agent/ai-sdk.d.ts.map +1 -0
- package/dist/agent/ai-sdk.js +59 -0
- package/dist/agent/ai-sdk.js.map +1 -0
- package/dist/agent/call-options.d.ts +10 -0
- package/dist/agent/call-options.d.ts.map +1 -0
- package/dist/agent/call-options.js +28 -0
- package/dist/agent/call-options.js.map +1 -0
- package/dist/agent/default-agent.d.ts +22 -0
- package/dist/agent/default-agent.d.ts.map +1 -0
- package/dist/agent/default-agent.js +354 -0
- package/dist/agent/default-agent.js.map +1 -0
- package/dist/agent/error.d.ts +53 -0
- package/dist/agent/error.d.ts.map +1 -0
- package/dist/agent/error.js +94 -0
- package/dist/agent/error.js.map +1 -0
- package/dist/agent/executor.d.ts +238 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +56 -0
- package/dist/agent/executor.js.map +1 -0
- package/dist/agent/index.d.ts +15 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +304 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/invocation.d.ts +194 -0
- package/dist/agent/invocation.d.ts.map +1 -0
- package/dist/agent/invocation.js +389 -0
- package/dist/agent/invocation.js.map +1 -0
- package/dist/agent/ledger.d.ts +24 -0
- package/dist/agent/ledger.d.ts.map +1 -0
- package/dist/agent/ledger.js +48 -0
- package/dist/agent/ledger.js.map +1 -0
- package/dist/agent/loop-guards.d.ts +35 -0
- package/dist/agent/loop-guards.d.ts.map +1 -0
- package/dist/agent/loop-guards.js +110 -0
- package/dist/agent/loop-guards.js.map +1 -0
- package/dist/agent/model/adapter.d.ts +97 -0
- package/dist/agent/model/adapter.d.ts.map +1 -0
- package/dist/agent/model/adapter.js +40 -0
- package/dist/agent/model/adapter.js.map +1 -0
- package/dist/agent/model/router.d.ts +36 -0
- package/dist/agent/model/router.d.ts.map +1 -0
- package/dist/agent/model/router.js +45 -0
- package/dist/agent/model/router.js.map +1 -0
- package/dist/agent/model/schema.d.ts +16 -0
- package/dist/agent/model/schema.d.ts.map +1 -0
- package/dist/agent/model/schema.js +37 -0
- package/dist/agent/model/schema.js.map +1 -0
- package/dist/agent/model/sdk.d.ts +28 -0
- package/dist/agent/model/sdk.d.ts.map +1 -0
- package/dist/agent/model/sdk.js +258 -0
- package/dist/agent/model/sdk.js.map +1 -0
- package/dist/agent/observation.d.ts +70 -0
- package/dist/agent/observation.d.ts.map +1 -0
- package/dist/agent/observation.js +174 -0
- package/dist/agent/observation.js.map +1 -0
- package/dist/agent/phases.d.ts +71 -0
- package/dist/agent/phases.d.ts.map +1 -0
- package/dist/agent/phases.js +124 -0
- package/dist/agent/phases.js.map +1 -0
- package/dist/agent/prompts.d.ts +40 -0
- package/dist/agent/prompts.d.ts.map +1 -0
- package/dist/agent/prompts.js +104 -0
- package/dist/agent/prompts.js.map +1 -0
- package/dist/agent/protocol.d.ts +31 -0
- package/dist/agent/protocol.d.ts.map +1 -0
- package/dist/agent/protocol.js +67 -0
- package/dist/agent/protocol.js.map +1 -0
- package/dist/agent/public.d.ts +12 -0
- package/dist/agent/public.d.ts.map +1 -0
- package/dist/agent/public.js +12 -0
- package/dist/agent/public.js.map +1 -0
- package/dist/agent/replay.d.ts +61 -0
- package/dist/agent/replay.d.ts.map +1 -0
- package/dist/agent/replay.js +185 -0
- package/dist/agent/replay.js.map +1 -0
- package/dist/agent/secrets.d.ts +22 -0
- package/dist/agent/secrets.d.ts.map +1 -0
- package/dist/agent/secrets.js +63 -0
- package/dist/agent/secrets.js.map +1 -0
- package/dist/agent/step-cache.d.ts +156 -0
- package/dist/agent/step-cache.d.ts.map +1 -0
- package/dist/agent/step-cache.js +301 -0
- package/dist/agent/step-cache.js.map +1 -0
- package/dist/agent/tool-loop.d.ts +51 -0
- package/dist/agent/tool-loop.d.ts.map +1 -0
- package/dist/agent/tool-loop.js +331 -0
- package/dist/agent/tool-loop.js.map +1 -0
- package/dist/agent/tool.d.ts +39 -0
- package/dist/agent/tool.d.ts.map +1 -0
- package/dist/agent/tool.js +52 -0
- package/dist/agent/tool.js.map +1 -0
- package/dist/backend/contract.d.ts +186 -0
- package/dist/backend/contract.d.ts.map +1 -0
- package/dist/backend/contract.js +65 -0
- package/dist/backend/contract.js.map +1 -0
- package/dist/backend/index.d.ts +316 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +219 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/session.d.ts +23 -0
- package/dist/backend/session.d.ts.map +1 -0
- package/dist/backend/session.js +213 -0
- package/dist/backend/session.js.map +1 -0
- package/dist/backend/surface.d.ts +83 -0
- package/dist/backend/surface.d.ts.map +1 -0
- package/dist/backend/surface.js +11 -0
- package/dist/backend/surface.js.map +1 -0
- package/dist/cache/anchors.d.ts +37 -0
- package/dist/cache/anchors.d.ts.map +1 -0
- package/dist/cache/anchors.js +89 -0
- package/dist/cache/anchors.js.map +1 -0
- package/dist/cache/context.d.ts +74 -0
- package/dist/cache/context.d.ts.map +1 -0
- package/dist/cache/context.js +82 -0
- package/dist/cache/context.js.map +1 -0
- package/dist/cache/decide.d.ts +42 -0
- package/dist/cache/decide.d.ts.map +1 -0
- package/dist/cache/decide.js +47 -0
- package/dist/cache/decide.js.map +1 -0
- package/dist/cache/identity.d.ts +113 -0
- package/dist/cache/identity.d.ts.map +1 -0
- package/dist/cache/identity.js +109 -0
- package/dist/cache/identity.js.map +1 -0
- package/dist/cache/recorder.d.ts +76 -0
- package/dist/cache/recorder.d.ts.map +1 -0
- package/dist/cache/recorder.js +143 -0
- package/dist/cache/recorder.js.map +1 -0
- package/dist/cache/relocate.d.ts +69 -0
- package/dist/cache/relocate.d.ts.map +1 -0
- package/dist/cache/relocate.js +125 -0
- package/dist/cache/relocate.js.map +1 -0
- package/dist/cache/store.d.ts +68 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/store.js +106 -0
- package/dist/cache/store.js.map +1 -0
- package/dist/cache/trace.d.ts +146 -0
- package/dist/cache/trace.d.ts.map +1 -0
- package/dist/cache/trace.js +249 -0
- package/dist/cache/trace.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +108 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +6 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +101 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/collect/collect.d.ts +44 -0
- package/dist/collect/collect.d.ts.map +1 -0
- package/dist/collect/collect.js +89 -0
- package/dist/collect/collect.js.map +1 -0
- package/dist/collect/registry.d.ts +47 -0
- package/dist/collect/registry.d.ts.map +1 -0
- package/dist/collect/registry.js +262 -0
- package/dist/collect/registry.js.map +1 -0
- package/dist/collect/select.d.ts +54 -0
- package/dist/collect/select.d.ts.map +1 -0
- package/dist/collect/select.js +230 -0
- package/dist/collect/select.js.map +1 -0
- package/dist/config/agent.d.ts +91 -0
- package/dist/config/agent.d.ts.map +1 -0
- package/dist/config/agent.js +232 -0
- package/dist/config/agent.js.map +1 -0
- package/dist/config/load.d.ts +23 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +75 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/resolve.d.ts +94 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +500 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/config/validate.d.ts +6 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +21 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/credentials.d.ts +7 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +42 -0
- package/dist/credentials.js.map +1 -0
- package/dist/expect/async.d.ts +5 -0
- package/dist/expect/async.d.ts.map +1 -0
- package/dist/expect/async.js +186 -0
- package/dist/expect/async.js.map +1 -0
- package/dist/expect/index.d.ts +7 -0
- package/dist/expect/index.d.ts.map +1 -0
- package/dist/expect/index.js +23 -0
- package/dist/expect/index.js.map +1 -0
- package/dist/expect/values.d.ts +4 -0
- package/dist/expect/values.d.ts.map +1 -0
- package/dist/expect/values.js +108 -0
- package/dist/expect/values.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/ai-trace.d.ts +151 -0
- package/dist/internal/ai-trace.d.ts.map +1 -0
- package/dist/internal/ai-trace.js +360 -0
- package/dist/internal/ai-trace.js.map +1 -0
- package/dist/internal/brands.d.ts +9 -0
- package/dist/internal/brands.d.ts.map +1 -0
- package/dist/internal/brands.js +9 -0
- package/dist/internal/brands.js.map +1 -0
- package/dist/internal/debug.d.ts +43 -0
- package/dist/internal/debug.d.ts.map +1 -0
- package/dist/internal/debug.js +102 -0
- package/dist/internal/debug.js.map +1 -0
- package/dist/internal/errors.d.ts +98 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +212 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/globs.d.ts +29 -0
- package/dist/internal/globs.d.ts.map +1 -0
- package/dist/internal/globs.js +126 -0
- package/dist/internal/globs.js.map +1 -0
- package/dist/internal/ids.d.ts +32 -0
- package/dist/internal/ids.d.ts.map +1 -0
- package/dist/internal/ids.js +124 -0
- package/dist/internal/ids.js.map +1 -0
- package/dist/internal/json-value.d.ts +15 -0
- package/dist/internal/json-value.d.ts.map +1 -0
- package/dist/internal/json-value.js +61 -0
- package/dist/internal/json-value.js.map +1 -0
- package/dist/internal/package-version.d.ts +6 -0
- package/dist/internal/package-version.d.ts.map +1 -0
- package/dist/internal/package-version.js +14 -0
- package/dist/internal/package-version.js.map +1 -0
- package/dist/internal/realm-slot.d.ts +13 -0
- package/dist/internal/realm-slot.d.ts.map +1 -0
- package/dist/internal/realm-slot.js +23 -0
- package/dist/internal/realm-slot.js.map +1 -0
- package/dist/internal/redact.d.ts +33 -0
- package/dist/internal/redact.d.ts.map +1 -0
- package/dist/internal/redact.js +56 -0
- package/dist/internal/redact.js.map +1 -0
- package/dist/internal/regexp.d.ts +10 -0
- package/dist/internal/regexp.d.ts.map +1 -0
- package/dist/internal/regexp.js +27 -0
- package/dist/internal/regexp.js.map +1 -0
- package/dist/internal/text.d.ts +39 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +66 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/internal/time.d.ts +37 -0
- package/dist/internal/time.d.ts.map +1 -0
- package/dist/internal/time.js +91 -0
- package/dist/internal/time.js.map +1 -0
- package/dist/internal/trace.d.ts +18 -0
- package/dist/internal/trace.d.ts.map +1 -0
- package/dist/internal/trace.js +46 -0
- package/dist/internal/trace.js.map +1 -0
- package/dist/internal/urls.d.ts +31 -0
- package/dist/internal/urls.d.ts.map +1 -0
- package/dist/internal/urls.js +95 -0
- package/dist/internal/urls.js.map +1 -0
- package/dist/locator/engine.d.ts +65 -0
- package/dist/locator/engine.d.ts.map +1 -0
- package/dist/locator/engine.js +164 -0
- package/dist/locator/engine.js.map +1 -0
- package/dist/locator/expression.d.ts +19 -0
- package/dist/locator/expression.d.ts.map +1 -0
- package/dist/locator/expression.js +85 -0
- package/dist/locator/expression.js.map +1 -0
- package/dist/locator/screen.d.ts +36 -0
- package/dist/locator/screen.d.ts.map +1 -0
- package/dist/locator/screen.js +281 -0
- package/dist/locator/screen.js.map +1 -0
- package/dist/report/build.d.ts +214 -0
- package/dist/report/build.d.ts.map +1 -0
- package/dist/report/build.js +346 -0
- package/dist/report/build.js.map +1 -0
- package/dist/report/code-frame.d.ts +20 -0
- package/dist/report/code-frame.d.ts.map +1 -0
- package/dist/report/code-frame.js +73 -0
- package/dist/report/code-frame.js.map +1 -0
- package/dist/report/debug-steps.d.ts +14 -0
- package/dist/report/debug-steps.d.ts.map +1 -0
- package/dist/report/debug-steps.js +85 -0
- package/dist/report/debug-steps.js.map +1 -0
- package/dist/report/list.d.ts +80 -0
- package/dist/report/list.d.ts.map +1 -0
- package/dist/report/list.js +372 -0
- package/dist/report/list.js.map +1 -0
- package/dist/report/live-status.d.ts +51 -0
- package/dist/report/live-status.d.ts.map +1 -0
- package/dist/report/live-status.js +162 -0
- package/dist/report/live-status.js.map +1 -0
- package/dist/report/write.d.ts +4 -0
- package/dist/report/write.d.ts.map +1 -0
- package/dist/report/write.js +13 -0
- package/dist/report/write.js.map +1 -0
- package/dist/run/app-process.d.ts +18 -0
- package/dist/run/app-process.d.ts.map +1 -0
- package/dist/run/app-process.js +112 -0
- package/dist/run/app-process.js.map +1 -0
- package/dist/run/artifacts.d.ts +51 -0
- package/dist/run/artifacts.d.ts.map +1 -0
- package/dist/run/artifacts.js +114 -0
- package/dist/run/artifacts.js.map +1 -0
- package/dist/run/events.d.ts +100 -0
- package/dist/run/events.d.ts.map +1 -0
- package/dist/run/events.js +59 -0
- package/dist/run/events.js.map +1 -0
- package/dist/run/execute.d.ts +119 -0
- package/dist/run/execute.d.ts.map +1 -0
- package/dist/run/execute.js +555 -0
- package/dist/run/execute.js.map +1 -0
- package/dist/run/fixtures.d.ts +40 -0
- package/dist/run/fixtures.d.ts.map +1 -0
- package/dist/run/fixtures.js +408 -0
- package/dist/run/fixtures.js.map +1 -0
- package/dist/run/in-process.d.ts +24 -0
- package/dist/run/in-process.d.ts.map +1 -0
- package/dist/run/in-process.js +120 -0
- package/dist/run/in-process.js.map +1 -0
- package/dist/run/public.d.ts +19 -0
- package/dist/run/public.d.ts.map +1 -0
- package/dist/run/public.js +11 -0
- package/dist/run/public.js.map +1 -0
- package/dist/run/realm.d.ts +52 -0
- package/dist/run/realm.d.ts.map +1 -0
- package/dist/run/realm.js +101 -0
- package/dist/run/realm.js.map +1 -0
- package/dist/run/records.d.ts +87 -0
- package/dist/run/records.d.ts.map +1 -0
- package/dist/run/records.js +3 -0
- package/dist/run/records.js.map +1 -0
- package/dist/run/retry.d.ts +18 -0
- package/dist/run/retry.d.ts.map +1 -0
- package/dist/run/retry.js +33 -0
- package/dist/run/retry.js.map +1 -0
- package/dist/run/runner.d.ts +49 -0
- package/dist/run/runner.d.ts.map +1 -0
- package/dist/run/runner.js +375 -0
- package/dist/run/runner.js.map +1 -0
- package/dist/run/scheduler.d.ts +45 -0
- package/dist/run/scheduler.d.ts.map +1 -0
- package/dist/run/scheduler.js +512 -0
- package/dist/run/scheduler.js.map +1 -0
- package/dist/run/serial.d.ts +52 -0
- package/dist/run/serial.d.ts.map +1 -0
- package/dist/run/serial.js +247 -0
- package/dist/run/serial.js.map +1 -0
- package/dist/run/sessions.d.ts +54 -0
- package/dist/run/sessions.d.ts.map +1 -0
- package/dist/run/sessions.js +221 -0
- package/dist/run/sessions.js.map +1 -0
- package/dist/run/steps.d.ts +196 -0
- package/dist/run/steps.d.ts.map +1 -0
- package/dist/run/steps.js +151 -0
- package/dist/run/steps.js.map +1 -0
- package/dist/run/unit-runner.d.ts +30 -0
- package/dist/run/unit-runner.d.ts.map +1 -0
- package/dist/run/unit-runner.js +11 -0
- package/dist/run/unit-runner.js.map +1 -0
- package/dist/run/units.d.ts +50 -0
- package/dist/run/units.d.ts.map +1 -0
- package/dist/run/units.js +103 -0
- package/dist/run/units.js.map +1 -0
- package/dist/run/worker/entry.d.ts +8 -0
- package/dist/run/worker/entry.d.ts.map +1 -0
- package/dist/run/worker/entry.js +137 -0
- package/dist/run/worker/entry.js.map +1 -0
- package/dist/run/worker/handle.d.ts +10 -0
- package/dist/run/worker/handle.d.ts.map +1 -0
- package/dist/run/worker/handle.js +74 -0
- package/dist/run/worker/handle.js.map +1 -0
- package/dist/run/worker/protocol.d.ts +129 -0
- package/dist/run/worker/protocol.d.ts.map +1 -0
- package/dist/run/worker/protocol.js +18 -0
- package/dist/run/worker/protocol.js.map +1 -0
- package/dist/run/worker/session.d.ts +69 -0
- package/dist/run/worker/session.d.ts.map +1 -0
- package/dist/run/worker/session.js +123 -0
- package/dist/run/worker/session.js.map +1 -0
- package/dist/types.d.ts +630 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI SDK adapter (spec 05-config.md). One implementation serves every
|
|
3
|
+
* provider: a `provider/model-id` reference resolves through the AI Gateway,
|
|
4
|
+
* and a caller-supplied AI SDK model instance (`openai('gpt-4o')`, a local
|
|
5
|
+
* provider, a scripted test model) is used directly. Everything after model
|
|
6
|
+
* construction — bounded requests, closed-grammar validation, usage and error
|
|
7
|
+
* translation — is provider-independent.
|
|
8
|
+
*/
|
|
9
|
+
import { GATEWAY_API_KEY_ENV, } from '../../config/agent.js';
|
|
10
|
+
import { aiSdk, loadAiSdk } from '../ai-sdk.js';
|
|
11
|
+
import { packageVersion } from '../../internal/package-version.js';
|
|
12
|
+
import { AgentError } from '../error.js';
|
|
13
|
+
import { imageTokenUpperBound, ModelOutputInvalidError, tokenUpperBound, } from './adapter.js';
|
|
14
|
+
/** Default AI Gateway base URL used when no endpoint override is configured. */
|
|
15
|
+
const DEFAULT_GATEWAY_ENDPOINT = 'https://ai-gateway.vercel.sh/v4/ai';
|
|
16
|
+
const PROVIDER_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
17
|
+
/**
|
|
18
|
+
* Provider transport retries; distinct from runner-owned model-call budget.
|
|
19
|
+
*
|
|
20
|
+
* Rate limits and 5xx bursts are the dominant cause of spurious agent-step
|
|
21
|
+
* failures, and the SDK only retries errors the provider marked retryable,
|
|
22
|
+
* honoring `retry-after` before its own exponential backoff. Raising the SDK
|
|
23
|
+
* default of 2 costs nothing on a healthy provider: `timeout` below is merged
|
|
24
|
+
* into the signal the retry loop waits on, so the step deadline — not the
|
|
25
|
+
* attempt count — bounds the whole chain.
|
|
26
|
+
*/
|
|
27
|
+
const TRANSPORT_RETRIES = 5;
|
|
28
|
+
/** Creates the adapter for one resolved model, or fails with MODEL_UNAVAILABLE. */
|
|
29
|
+
export function createModelAdapter(model) {
|
|
30
|
+
if (model === undefined) {
|
|
31
|
+
throw new AgentError('MODEL_UNAVAILABLE', 'the agent fixture requires model configuration: set agent.model or E2E_MODEL');
|
|
32
|
+
}
|
|
33
|
+
const { endpoint, flavor } = validateModel(model);
|
|
34
|
+
const adapterVersion = packageVersion(import.meta.url, '../../../package.json', '0.0.0');
|
|
35
|
+
// The AI SDK is an optional peer: the language model is constructed on the
|
|
36
|
+
// first call, after the loader has resolved (or clearly refused) it.
|
|
37
|
+
let languageModel;
|
|
38
|
+
return {
|
|
39
|
+
provenance: {
|
|
40
|
+
provider: model.provider,
|
|
41
|
+
model: model.id,
|
|
42
|
+
endpoint,
|
|
43
|
+
adapterVersion: `${flavor}/${adapterVersion}`,
|
|
44
|
+
},
|
|
45
|
+
async generate(call) {
|
|
46
|
+
const { generateText, jsonSchema, Output } = await loadAiSdk();
|
|
47
|
+
languageModel ??= instantiate(model).languageModel;
|
|
48
|
+
const images = call.images ?? [];
|
|
49
|
+
const inputBound = tokenUpperBound(call.system) +
|
|
50
|
+
tokenUpperBound(call.prompt) +
|
|
51
|
+
images.reduce((total, image) => total + imageTokenUpperBound(image), 0);
|
|
52
|
+
if (inputBound > call.maxInputTokens) {
|
|
53
|
+
throw new AgentError('STEP_BUDGET_EXHAUSTED', `model input upper bound ${inputBound} exceeds limits.maxModelTokensPerCall ${call.maxInputTokens}`);
|
|
54
|
+
}
|
|
55
|
+
let issue;
|
|
56
|
+
const schema = call.schema;
|
|
57
|
+
const settings = {
|
|
58
|
+
model: languageModel,
|
|
59
|
+
system: call.system,
|
|
60
|
+
// Text-only calls keep the plain prompt form; images require the
|
|
61
|
+
// multi-part message form, and both must carry the same instruction
|
|
62
|
+
// text in the same position relative to the system policy.
|
|
63
|
+
...(images.length === 0
|
|
64
|
+
? { prompt: call.prompt }
|
|
65
|
+
: { messages: [userMessage(call.prompt, images)] }),
|
|
66
|
+
maxOutputTokens: call.maxOutputTokens,
|
|
67
|
+
temperature: 0,
|
|
68
|
+
maxRetries: TRANSPORT_RETRIES,
|
|
69
|
+
abortSignal: call.signal,
|
|
70
|
+
timeout: call.timeoutMs,
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
if (schema === undefined) {
|
|
74
|
+
const result = await generateText(settings);
|
|
75
|
+
const parsed = parseJsonObject(result.text);
|
|
76
|
+
const validation = call.validate(parsed);
|
|
77
|
+
if (!validation.ok) {
|
|
78
|
+
throw new ModelOutputInvalidError(validation.issue, { rawText: result.text });
|
|
79
|
+
}
|
|
80
|
+
return { value: validation.value, usage: readUsage(result, inputBound) };
|
|
81
|
+
}
|
|
82
|
+
const result = await generateText({
|
|
83
|
+
...settings,
|
|
84
|
+
output: Output.object({
|
|
85
|
+
schema: jsonSchema(schema, {
|
|
86
|
+
validate: (value) => {
|
|
87
|
+
const validation = call.validate(value);
|
|
88
|
+
if (validation.ok)
|
|
89
|
+
return { success: true, value: validation.value };
|
|
90
|
+
issue = validation.issue;
|
|
91
|
+
return { success: false, error: new Error(validation.issue) };
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
name: call.schemaName,
|
|
95
|
+
}),
|
|
96
|
+
});
|
|
97
|
+
const output = result.output;
|
|
98
|
+
if (output === undefined) {
|
|
99
|
+
throw new ModelOutputInvalidError('provider returned no structured output');
|
|
100
|
+
}
|
|
101
|
+
return { value: output, usage: readUsage(result, inputBound) };
|
|
102
|
+
}
|
|
103
|
+
catch (cause) {
|
|
104
|
+
throw translateModelError(cause, issue, call.signal);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Builds the one user message of a vision call: instruction text first, then
|
|
111
|
+
* the image parts it refers to, so the text framing the pixels as data is read
|
|
112
|
+
* before them.
|
|
113
|
+
*/
|
|
114
|
+
function userMessage(prompt, images) {
|
|
115
|
+
return {
|
|
116
|
+
role: 'user',
|
|
117
|
+
content: [
|
|
118
|
+
{ type: 'text', text: prompt },
|
|
119
|
+
// A file part with an image media type, not the deprecated `image` part.
|
|
120
|
+
...images.map((image) => ({
|
|
121
|
+
type: 'file',
|
|
122
|
+
data: image.data,
|
|
123
|
+
mediaType: image.mediaType,
|
|
124
|
+
})),
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Builds the bare AI SDK language model for one resolved model reference, for
|
|
130
|
+
* callers that drive the SDK directly (the default step executor) rather than
|
|
131
|
+
* through the adapter. Fails with MODEL_UNAVAILABLE exactly like the adapter.
|
|
132
|
+
* Gateway references require the AI SDK to be loaded (loadAiSdk) first; model
|
|
133
|
+
* instances never touch it.
|
|
134
|
+
*/
|
|
135
|
+
export function instantiateLanguageModel(model) {
|
|
136
|
+
return instantiate(model).languageModel;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Validates one resolved model and derives its report provenance without
|
|
140
|
+
* touching the AI SDK, so an adapter can be constructed — and refuse clearly —
|
|
141
|
+
* before the optional peer dependency is ever loaded.
|
|
142
|
+
*/
|
|
143
|
+
function validateModel(model) {
|
|
144
|
+
if (model.kind === 'instance') {
|
|
145
|
+
// The instance owns its transport; the report records that the endpoint is
|
|
146
|
+
// whatever the provider package defaults to.
|
|
147
|
+
return { endpoint: 'provider-default', flavor: 'ai-sdk' };
|
|
148
|
+
}
|
|
149
|
+
if (!PROVIDER_PATTERN.test(model.provider)) {
|
|
150
|
+
throw new AgentError('MODEL_UNAVAILABLE', `unknown model provider "${model.provider}"; expected a gateway provider ID or an AI SDK model instance`);
|
|
151
|
+
}
|
|
152
|
+
if (model.apiKey === undefined) {
|
|
153
|
+
throw new AgentError('MODEL_UNAVAILABLE', `no model credential: set ${model.apiKeyEnv} or ${GATEWAY_API_KEY_ENV}`);
|
|
154
|
+
}
|
|
155
|
+
return { endpoint: model.endpoint ?? DEFAULT_GATEWAY_ENDPOINT, flavor: 'ai-gateway' };
|
|
156
|
+
}
|
|
157
|
+
/** Builds the AI SDK language model for one validated resolved model. */
|
|
158
|
+
function instantiate(model) {
|
|
159
|
+
if (model.kind === 'instance')
|
|
160
|
+
return { languageModel: model.model };
|
|
161
|
+
const { endpoint } = validateModel(model);
|
|
162
|
+
const gateway = aiSdk().createGateway({ apiKey: model.apiKey, baseURL: endpoint });
|
|
163
|
+
return { languageModel: gateway.languageModel(`${model.provider}/${model.id}`) };
|
|
164
|
+
}
|
|
165
|
+
function readUsage(result, inputBound) {
|
|
166
|
+
const inputTokens = result.usage?.inputTokens;
|
|
167
|
+
const outputTokens = result.usage?.outputTokens;
|
|
168
|
+
const estimatedCostUsd = readCost(result.providerMetadata);
|
|
169
|
+
if (typeof inputTokens === 'number' && typeof outputTokens === 'number') {
|
|
170
|
+
return { inputTokens, outputTokens, accounting: 'provider', estimatedCostUsd };
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
inputTokens: inputBound,
|
|
174
|
+
outputTokens: tokenUpperBound(result.text ?? ''),
|
|
175
|
+
accounting: 'adapter-upper-bound',
|
|
176
|
+
estimatedCostUsd,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Parses exactly one JSON object from response text, tolerating a code fence.
|
|
181
|
+
* Model text is never evaluated as code.
|
|
182
|
+
*/
|
|
183
|
+
function parseJsonObject(text) {
|
|
184
|
+
const trimmed = text.trim();
|
|
185
|
+
const fenced = /^```(?:json)?\s*([\s\S]*?)```$/.exec(trimmed);
|
|
186
|
+
const body = (fenced?.[1] ?? trimmed).trim();
|
|
187
|
+
try {
|
|
188
|
+
return JSON.parse(body);
|
|
189
|
+
}
|
|
190
|
+
catch (cause) {
|
|
191
|
+
throw new ModelOutputInvalidError('response text is not a single JSON value', {
|
|
192
|
+
rawText: text,
|
|
193
|
+
cause,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The AI Gateway reports per-request cost in provider metadata when available;
|
|
199
|
+
* other providers simply lack the key. `cost` is what the gateway bills; BYOK
|
|
200
|
+
* routes bill the provider key directly and report `cost: "0"`, so fall back
|
|
201
|
+
* to `marketCost`, the list-price estimate of the same request.
|
|
202
|
+
*/
|
|
203
|
+
export function readCost(metadata) {
|
|
204
|
+
const billed = parseCost(metadata?.['gateway']?.['cost']);
|
|
205
|
+
if (billed !== undefined && billed > 0)
|
|
206
|
+
return billed;
|
|
207
|
+
return parseCost(metadata?.['gateway']?.['marketCost']) ?? billed;
|
|
208
|
+
}
|
|
209
|
+
function parseCost(raw) {
|
|
210
|
+
const cost = typeof raw === 'string' ? Number(raw) : raw;
|
|
211
|
+
return typeof cost === 'number' && Number.isFinite(cost) && cost >= 0 ? cost : undefined;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Maps adapter and provider failures onto the closed agent error set. Runs
|
|
215
|
+
* only after `generate` loaded the SDK, so the cached module is available for
|
|
216
|
+
* the error-class checks.
|
|
217
|
+
*/
|
|
218
|
+
function translateModelError(rawCause, issue, signal) {
|
|
219
|
+
const { APICallError, NoObjectGeneratedError } = aiSdk();
|
|
220
|
+
const cause = unwrapRetry(rawCause);
|
|
221
|
+
if (cause instanceof AgentError)
|
|
222
|
+
return cause;
|
|
223
|
+
// Only an aborted attempt is a cancellation. A request that exceeded the
|
|
224
|
+
// remaining step budget is a timeout, which is a test failure (06-cli.md).
|
|
225
|
+
if (signal.aborted) {
|
|
226
|
+
return new AgentError('CANCELLED', 'model call cancelled', { cause });
|
|
227
|
+
}
|
|
228
|
+
if (isAbort(cause)) {
|
|
229
|
+
return new AgentError('STEP_TIMEOUT', 'model call exceeded the remaining step timeout', { cause });
|
|
230
|
+
}
|
|
231
|
+
if (NoObjectGeneratedError.isInstance(cause)) {
|
|
232
|
+
return new ModelOutputInvalidError(issue ?? 'provider response did not match the closed response grammar', { ...(cause.text !== undefined ? { rawText: cause.text } : {}), cause });
|
|
233
|
+
}
|
|
234
|
+
if (APICallError.isInstance(cause)) {
|
|
235
|
+
return new AgentError('MODEL_PROVIDER_FAILED', `model provider failed: ${cause.message}`, {
|
|
236
|
+
cause,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
return new AgentError('MODEL_PROVIDER_FAILED', `model provider failed: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Unwraps a spent transport retry chain to the attempt that actually failed,
|
|
243
|
+
* because the wrapper's message names the retry reason rather than the failure.
|
|
244
|
+
* A chain cut short by the deadline stays wrapped so it classifies as an abort.
|
|
245
|
+
*/
|
|
246
|
+
function unwrapRetry(cause) {
|
|
247
|
+
const { RetryError } = aiSdk();
|
|
248
|
+
if (!RetryError.isInstance(cause) || cause.reason === 'abort')
|
|
249
|
+
return cause;
|
|
250
|
+
return cause.lastError ?? cause;
|
|
251
|
+
}
|
|
252
|
+
function isAbort(cause) {
|
|
253
|
+
const { RetryError } = aiSdk();
|
|
254
|
+
if (RetryError.isInstance(cause) && cause.reason === 'abort')
|
|
255
|
+
return true;
|
|
256
|
+
return cause instanceof Error && (cause.name === 'AbortError' || cause.name === 'TimeoutError');
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=sdk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../../src/agent/model/sdk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** Observation capture, redaction, and model serialization (spec 09-drivers.md, 14-security.md). */
|
|
2
|
+
import type { Observation, ObservationPixels, SemanticNode } from '../backend/surface.ts';
|
|
3
|
+
/** Why pixels the caller asked for are not part of this observation. */
|
|
4
|
+
type PixelsWithheld = 'MASKING_UNPROVEN';
|
|
5
|
+
/** Masked pixel evidence cleared for model input. */
|
|
6
|
+
export interface AgentPixels extends ObservationPixels {
|
|
7
|
+
readonly maskedRegionCount: number;
|
|
8
|
+
readonly bytes: number;
|
|
9
|
+
}
|
|
10
|
+
export interface AgentObservation {
|
|
11
|
+
readonly revision: string;
|
|
12
|
+
/** Redacted, size-bounded serialization sent to the model. */
|
|
13
|
+
readonly text: string;
|
|
14
|
+
readonly bytes: number;
|
|
15
|
+
readonly nodes: ReadonlyMap<string, SemanticNode>;
|
|
16
|
+
readonly viewport: {
|
|
17
|
+
readonly width: number;
|
|
18
|
+
readonly height: number;
|
|
19
|
+
readonly scale: number;
|
|
20
|
+
};
|
|
21
|
+
readonly truncated: boolean;
|
|
22
|
+
/** Present only when the backend captured pixels and masking checks out. */
|
|
23
|
+
readonly pixels?: AgentPixels | undefined;
|
|
24
|
+
/** Set when captured pixels were dropped instead of being sent. */
|
|
25
|
+
readonly pixelsWithheld?: PixelsWithheld | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Turns one raw backend observation into redacted model input.
|
|
29
|
+
*
|
|
30
|
+
* Pixels whose masking the backend cannot prove (fewer masked regions than
|
|
31
|
+
* secure nodes) are withheld before they reach a model or disk; the semantic
|
|
32
|
+
* tree never carries secure values. Registered secret values are additionally
|
|
33
|
+
* replaced by their stable secret name.
|
|
34
|
+
*/
|
|
35
|
+
export declare function prepareObservation(observation: Observation, options: {
|
|
36
|
+
redact: (text: string) => string;
|
|
37
|
+
maxBytes: number;
|
|
38
|
+
testIdAttribute: string;
|
|
39
|
+
}): AgentObservation;
|
|
40
|
+
/**
|
|
41
|
+
* What the screen looks like, independent of which observation looked at it.
|
|
42
|
+
*
|
|
43
|
+
* Two things are dropped. Node ids, because they are minted per observation, so
|
|
44
|
+
* two looks at a screen that has not moved would never render identically. And
|
|
45
|
+
* the focus state, because focus moves on its own — the platform settling it
|
|
46
|
+
* after load, a script claiming it, a widget stealing it — without the screen
|
|
47
|
+
* having changed in any way a judgment could answer differently about. Leaving
|
|
48
|
+
* it in meant a genuinely static screen could still spend a second model call.
|
|
49
|
+
*
|
|
50
|
+
* Lives next to `formatNode` so the line grammar keeps one owner.
|
|
51
|
+
*/
|
|
52
|
+
export declare function observationShape(observation: AgentObservation): string;
|
|
53
|
+
/** What a settle loop needs from its step: the remaining clock and cancellation. */
|
|
54
|
+
interface SettleClock {
|
|
55
|
+
remainingMs(): number;
|
|
56
|
+
readonly signal: AbortSignal;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Captures until the screen shape holds still, bounded by a short ceiling and
|
|
60
|
+
* the step clock. An observation taken right after an action can be a
|
|
61
|
+
* snapshot the app is still reacting to — a fetch-backed mutation re-renders
|
|
62
|
+
* long after the action resolves — and acting or judging on it repeats
|
|
63
|
+
* actions and passes steps on pre-render state. The executor-facing observe
|
|
64
|
+
* (act.ts) settles through this loop, and replay's pre-action looks and the
|
|
65
|
+
* cache session's probes reach it through that same observe, so the pacing
|
|
66
|
+
* can never drift between them.
|
|
67
|
+
*/
|
|
68
|
+
export declare function settleObservation<T>(capture: () => Promise<T>, shapeOf: (value: T) => string, clock: SettleClock): Promise<T>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=observation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../../src/agent/observation.ts"],"names":[],"mappings":"AAAA,oGAAoG;AAEpG,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAO1F,wEAAwE;AACxE,KAAK,cAAc,GAAG,kBAAkB,CAAC;AAEzC,qDAAqD;AACrD,MAAM,WAAW,WAAY,SAAQ,iBAAiB;IACpD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,mEAAmE;IACnE,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CACtD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE;IACP,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,GACA,gBAAgB,CA6ClB;AAiED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM,CAOtE;AAMD,oFAAoF;AACpF,UAAU,WAAW;IACnB,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,EAC7B,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,CAAC,CAAC,CAaZ"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/** Observation capture, redaction, and model serialization (spec 09-drivers.md, 14-security.md). */
|
|
2
|
+
import { collapseText } from '../internal/text.js';
|
|
3
|
+
import { sleep } from '../internal/time.js';
|
|
4
|
+
/** Appended when the node walk stopped at the observation byte budget. */
|
|
5
|
+
const TRUNCATION_MARKER = '[observation truncated at the resolved observation byte limit]';
|
|
6
|
+
/**
|
|
7
|
+
* Turns one raw backend observation into redacted model input.
|
|
8
|
+
*
|
|
9
|
+
* Pixels whose masking the backend cannot prove (fewer masked regions than
|
|
10
|
+
* secure nodes) are withheld before they reach a model or disk; the semantic
|
|
11
|
+
* tree never carries secure values. Registered secret values are additionally
|
|
12
|
+
* replaced by their stable secret name.
|
|
13
|
+
*/
|
|
14
|
+
export function prepareObservation(observation, options) {
|
|
15
|
+
const nodes = new Map();
|
|
16
|
+
indexNodes(observation.tree, nodes);
|
|
17
|
+
const redact = options.redact;
|
|
18
|
+
const lines = [];
|
|
19
|
+
const encoder = new TextEncoder();
|
|
20
|
+
// The marker is reserved up front so a truncated observation still fits the
|
|
21
|
+
// budget; the budget is what keeps the request under the token ceiling.
|
|
22
|
+
const markerBytes = encoder.encode(`${TRUNCATION_MARKER}\n`).byteLength;
|
|
23
|
+
const budget = Math.max(0, options.maxBytes - markerBytes);
|
|
24
|
+
let bytes = 0;
|
|
25
|
+
let truncated = false;
|
|
26
|
+
const emit = (node, depth) => {
|
|
27
|
+
if (truncated)
|
|
28
|
+
return;
|
|
29
|
+
const line = formatNode(node, depth, redact, options.testIdAttribute);
|
|
30
|
+
const size = encoder.encode(`${line}\n`).byteLength;
|
|
31
|
+
if (lines.length > 0 && bytes + size > budget) {
|
|
32
|
+
truncated = true;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
bytes += size;
|
|
36
|
+
lines.push(line);
|
|
37
|
+
for (const child of node.children ?? [])
|
|
38
|
+
emit(child, depth + 1);
|
|
39
|
+
};
|
|
40
|
+
emit(observation.tree, 0);
|
|
41
|
+
if (truncated)
|
|
42
|
+
lines.push(TRUNCATION_MARKER);
|
|
43
|
+
const text = lines.join('\n');
|
|
44
|
+
// Every emitted line was measured with its newline; the join has one fewer
|
|
45
|
+
// and the marker was measured up front, so the size is known without a
|
|
46
|
+
// second pass over the whole tree text.
|
|
47
|
+
const textBytes = Math.max(0, bytes + (truncated ? markerBytes : 0) - 1);
|
|
48
|
+
const pixels = clearPixels(observation);
|
|
49
|
+
return {
|
|
50
|
+
revision: observation.revision,
|
|
51
|
+
text,
|
|
52
|
+
bytes: textBytes,
|
|
53
|
+
nodes,
|
|
54
|
+
viewport: observation.viewport,
|
|
55
|
+
truncated,
|
|
56
|
+
...(pixels.cleared === undefined ? {} : { pixels: pixels.cleared }),
|
|
57
|
+
...(pixels.withheld === undefined ? {} : { pixelsWithheld: pixels.withheld }),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Clears captured pixels for model input, or withholds them.
|
|
62
|
+
*
|
|
63
|
+
* Every secure node the backend observed must be covered by a masked region.
|
|
64
|
+
* When it is not, the backend masked less than it saw and the image cannot be
|
|
65
|
+
* proven redacted, so it is dropped exactly like an incompletely redacted
|
|
66
|
+
* artifact (14-security.md) — the semantic tree still goes out.
|
|
67
|
+
*/
|
|
68
|
+
function clearPixels(observation) {
|
|
69
|
+
const pixels = observation.pixels;
|
|
70
|
+
if (pixels === undefined)
|
|
71
|
+
return {};
|
|
72
|
+
const { secureNodeCount, maskedRegionCount } = observation.redaction;
|
|
73
|
+
if (maskedRegionCount < secureNodeCount)
|
|
74
|
+
return { withheld: 'MASKING_UNPROVEN' };
|
|
75
|
+
return { cleared: { ...pixels, maskedRegionCount, bytes: pixels.data.byteLength } };
|
|
76
|
+
}
|
|
77
|
+
/** Depth beyond this renders flat; deep chrome must not buy tokens with spaces. */
|
|
78
|
+
const MAX_INDENT_DEPTH = 10;
|
|
79
|
+
/**
|
|
80
|
+
* Renders one node as `#id role "name" text="..." [states]`. Role-less text
|
|
81
|
+
* holders omit the role token entirely: on a large screen they are half the
|
|
82
|
+
* lines, and the model needs their text, not a filler word.
|
|
83
|
+
*/
|
|
84
|
+
function formatNode(node, depth, redact, testIdAttribute) {
|
|
85
|
+
const parts = [`#${node.ref.id}`];
|
|
86
|
+
if (node.role !== undefined && node.role !== '')
|
|
87
|
+
parts.push(node.role);
|
|
88
|
+
if (node.name !== undefined && node.name !== '')
|
|
89
|
+
parts.push(JSON.stringify(redact(node.name)));
|
|
90
|
+
const text = node.text === undefined ? '' : collapseText(node.text);
|
|
91
|
+
if (text !== '' && text !== node.name)
|
|
92
|
+
parts.push(`text=${JSON.stringify(redact(text))}`);
|
|
93
|
+
// Disambiguators the model needs when role and name repeat. The backend has
|
|
94
|
+
// already reduced href to origin and path.
|
|
95
|
+
const testId = node.attributes?.[testIdAttribute];
|
|
96
|
+
if (testId !== undefined && testId !== '')
|
|
97
|
+
parts.push(`testid=${JSON.stringify(testId)}`);
|
|
98
|
+
const href = node.attributes?.['href'];
|
|
99
|
+
if (href !== undefined && href !== '')
|
|
100
|
+
parts.push(`href=${JSON.stringify(redact(href))}`);
|
|
101
|
+
const placeholder = node.attributes?.['placeholder'];
|
|
102
|
+
if (placeholder !== undefined && placeholder !== '' && (node.name ?? '') === '') {
|
|
103
|
+
parts.push(`placeholder=${JSON.stringify(redact(placeholder))}`);
|
|
104
|
+
}
|
|
105
|
+
if (node.states?.secure === true) {
|
|
106
|
+
parts.push('value=<secure>');
|
|
107
|
+
}
|
|
108
|
+
else if (node.value !== undefined && node.value !== '') {
|
|
109
|
+
parts.push(`value=${JSON.stringify(redact(node.value))}`);
|
|
110
|
+
}
|
|
111
|
+
if (node.inputPurpose !== undefined && node.inputPurpose !== 'none') {
|
|
112
|
+
parts.push(`purpose=${node.inputPurpose}`);
|
|
113
|
+
}
|
|
114
|
+
const states = Object.entries(node.states ?? {})
|
|
115
|
+
.filter(([, value]) => value === true)
|
|
116
|
+
.map(([key]) => key);
|
|
117
|
+
if (states.length > 0)
|
|
118
|
+
parts.push(`[${states.join(' ')}]`);
|
|
119
|
+
return `${' '.repeat(Math.min(depth, MAX_INDENT_DEPTH))}${parts.join(' ')}`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* What the screen looks like, independent of which observation looked at it.
|
|
123
|
+
*
|
|
124
|
+
* Two things are dropped. Node ids, because they are minted per observation, so
|
|
125
|
+
* two looks at a screen that has not moved would never render identically. And
|
|
126
|
+
* the focus state, because focus moves on its own — the platform settling it
|
|
127
|
+
* after load, a script claiming it, a widget stealing it — without the screen
|
|
128
|
+
* having changed in any way a judgment could answer differently about. Leaving
|
|
129
|
+
* it in meant a genuinely static screen could still spend a second model call.
|
|
130
|
+
*
|
|
131
|
+
* Lives next to `formatNode` so the line grammar keeps one owner.
|
|
132
|
+
*/
|
|
133
|
+
export function observationShape(observation) {
|
|
134
|
+
return observation.text
|
|
135
|
+
.replaceAll(/(^|\n)(\s*)#\S+/g, '$1$2')
|
|
136
|
+
.replaceAll(/ \[([^\]]*)\]/g, (_match, states) => {
|
|
137
|
+
const stable = states.split(' ').filter((state) => state !== 'focused');
|
|
138
|
+
return stable.length === 0 ? '' : ` [${stable.join(' ')}]`;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/** Poll interval and ceiling for shape-stability settling. */
|
|
142
|
+
const SETTLE_POLL_MS = 75;
|
|
143
|
+
const SETTLE_TIMEOUT_MS = 1_000;
|
|
144
|
+
/**
|
|
145
|
+
* Captures until the screen shape holds still, bounded by a short ceiling and
|
|
146
|
+
* the step clock. An observation taken right after an action can be a
|
|
147
|
+
* snapshot the app is still reacting to — a fetch-backed mutation re-renders
|
|
148
|
+
* long after the action resolves — and acting or judging on it repeats
|
|
149
|
+
* actions and passes steps on pre-render state. The executor-facing observe
|
|
150
|
+
* (act.ts) settles through this loop, and replay's pre-action looks and the
|
|
151
|
+
* cache session's probes reach it through that same observe, so the pacing
|
|
152
|
+
* can never drift between them.
|
|
153
|
+
*/
|
|
154
|
+
export async function settleObservation(capture, shapeOf, clock) {
|
|
155
|
+
let value = await capture();
|
|
156
|
+
let shape = shapeOf(value);
|
|
157
|
+
const deadlineMs = Date.now() + SETTLE_TIMEOUT_MS;
|
|
158
|
+
while (Date.now() < deadlineMs && clock.remainingMs() > SETTLE_POLL_MS) {
|
|
159
|
+
await sleep(SETTLE_POLL_MS, clock.signal);
|
|
160
|
+
value = await capture();
|
|
161
|
+
const next = shapeOf(value);
|
|
162
|
+
const stable = next === shape;
|
|
163
|
+
shape = next;
|
|
164
|
+
if (stable)
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
return value;
|
|
168
|
+
}
|
|
169
|
+
function indexNodes(node, into) {
|
|
170
|
+
into.set(node.ref.id, node);
|
|
171
|
+
for (const child of node.children ?? [])
|
|
172
|
+
indexNodes(child, into);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=observation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation.js","sourceRoot":"","sources":["../../src/agent/observation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared per-phase machinery for agent step execution. `Invocation` (the
|
|
3
|
+
* locate/judgment tier) and `ActDispatch` (the executor socket) both compose
|
|
4
|
+
* these, so event recording, `--debug` buckets, tracing, deadline semantics,
|
|
5
|
+
* and observation race-hardening cannot drift between the two paths.
|
|
6
|
+
*/
|
|
7
|
+
import { type Observation, type OperationContext } from '../backend/surface.ts';
|
|
8
|
+
import type { DebugTrace } from '../internal/debug.ts';
|
|
9
|
+
import { type Deadline } from '../internal/time.ts';
|
|
10
|
+
import type { LocatorEngine } from '../locator/engine.ts';
|
|
11
|
+
import type { StepEvent, StepRecorder } from '../run/steps.ts';
|
|
12
|
+
/**
|
|
13
|
+
* One backend operation's budget: `actionTimeout`, capped by the step clock.
|
|
14
|
+
* Bounding each call independently is what keeps a single screen that never
|
|
15
|
+
* settles from consuming the whole step: the hang costs one action timeout and
|
|
16
|
+
* a clearly attributed failure, not the test budget.
|
|
17
|
+
*/
|
|
18
|
+
export declare function boundedOperation(engine: LocatorEngine, actionTimeout: number, deadline: Deadline): OperationContext;
|
|
19
|
+
/** Records one policy decision as a child event of the current step. */
|
|
20
|
+
export declare function recordPolicyEvent(steps: StepRecorder, name: string, decision: 'allowed' | 'denied', code?: string): void;
|
|
21
|
+
/** The step recorder and optional debug trace a phase reports into. */
|
|
22
|
+
export interface PhaseHost {
|
|
23
|
+
readonly steps: StepRecorder;
|
|
24
|
+
readonly debug?: DebugTrace | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** One instrumented phase: the event kind it records and the debug bucket it feeds. */
|
|
27
|
+
export interface PhaseSpec {
|
|
28
|
+
/** Public API name of the enclosing step, e.g. `agent.assert`. */
|
|
29
|
+
readonly api: string;
|
|
30
|
+
readonly kind: StepEvent['kind'];
|
|
31
|
+
readonly phase: 'agent.observe' | 'agent.model' | 'agent.action' | 'agent.cache';
|
|
32
|
+
readonly name?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Runs one phase with uniform accounting: a child event on success and
|
|
36
|
+
* failure, one debug bucket, and translation onto the closed agent error set.
|
|
37
|
+
* Every observe/model/action phase of every agent step goes through here so
|
|
38
|
+
* the records cannot drift apart.
|
|
39
|
+
*/
|
|
40
|
+
export declare function instrumentPhase<Value>(host: PhaseHost, spec: PhaseSpec, body: () => Promise<Value>, detail?: (value: Value) => Partial<StepEvent>): Promise<Value>;
|
|
41
|
+
/**
|
|
42
|
+
* Fails when the step clock has run out.
|
|
43
|
+
*
|
|
44
|
+
* `cause` carries the failure that was being handled when the clock was found
|
|
45
|
+
* to be out, so a step that timed out mid-operation still says what the
|
|
46
|
+
* operation reported.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkStepClock(options: {
|
|
49
|
+
readonly signal: AbortSignal;
|
|
50
|
+
readonly deadline: Deadline;
|
|
51
|
+
readonly api: string;
|
|
52
|
+
readonly timeoutMs: number;
|
|
53
|
+
readonly cause?: unknown;
|
|
54
|
+
}): void;
|
|
55
|
+
/**
|
|
56
|
+
* Captures one raw observation, re-capturing while the backend reports a
|
|
57
|
+
* retryable failure and the step clock allows. A screen that navigates as it is
|
|
58
|
+
* read (a redirect, a hydration swap, a form submit still committing) makes
|
|
59
|
+
* the capture lose its document; that is a race, not a broken app, so it is
|
|
60
|
+
* re-read rather than surfaced as a failed call. `guard` is the caller's
|
|
61
|
+
* clock check, so a capture that outlives the deadline reports the step's own
|
|
62
|
+
* timeout rather than whichever transport error the truncated budget produced.
|
|
63
|
+
*/
|
|
64
|
+
export declare function retryingObserve(options: {
|
|
65
|
+
readonly observe: (operation: OperationContext) => Promise<Observation>;
|
|
66
|
+
readonly operation: () => OperationContext;
|
|
67
|
+
readonly guard: (cause?: unknown) => void;
|
|
68
|
+
readonly signal: AbortSignal;
|
|
69
|
+
readonly api: string;
|
|
70
|
+
}): Promise<Observation>;
|
|
71
|
+
//# sourceMappingURL=phases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phases.d.ts","sourceRoot":"","sources":["../../src/agent/phases.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAgB,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,QAAQ,GACjB,gBAAgB,CAElB;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,GAAG,QAAQ,EAC9B,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CAUN;AAED,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACzC;AAED,uFAAuF;AACvF,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,GAAG,cAAc,GAAG,aAAa,CAAC;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,KAAK,EACzC,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,EAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,SAAS,CAAC,GAC5C,OAAO,CAAC,KAAK,CAAC,CAyChB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CAYP;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,gBAAgB,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,gBAAgB,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,WAAW,CAAC,CAevB"}
|