@tangle-network/browser-agent-driver 0.28.0 → 0.30.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/README.md +32 -0
- package/dist/brain/index.d.ts +15 -1
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +155 -14
- package/dist/brain/index.js.map +1 -1
- package/dist/cli-design-audit.d.ts +4 -0
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +144 -7
- package/dist/cli-design-audit.js.map +1 -1
- package/dist/cli-snapshot.d.ts +44 -0
- package/dist/cli-snapshot.d.ts.map +1 -0
- package/dist/cli-snapshot.js +122 -0
- package/dist/cli-snapshot.js.map +1 -0
- package/dist/cli-ui.d.ts.map +1 -1
- package/dist/cli-ui.js +15 -1
- package/dist/cli-ui.js.map +1 -1
- package/dist/cli.js +49 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/design/audit/evaluate.d.ts +69 -0
- package/dist/design/audit/evaluate.d.ts.map +1 -1
- package/dist/design/audit/evaluate.js +414 -55
- package/dist/design/audit/evaluate.js.map +1 -1
- package/dist/design/audit/pipeline.d.ts +14 -0
- package/dist/design/audit/pipeline.d.ts.map +1 -1
- package/dist/design/audit/pipeline.js +67 -2
- package/dist/design/audit/pipeline.js.map +1 -1
- package/dist/design/audit/rubric/fragments/universal-product-intent.md +48 -0
- package/dist/design/audit/rubric/loader.d.ts.map +1 -1
- package/dist/design/audit/rubric/loader.js +32 -1
- package/dist/design/audit/rubric/loader.js.map +1 -1
- package/dist/design/page-interaction.d.ts +1 -0
- package/dist/design/page-interaction.d.ts.map +1 -1
- package/dist/design/page-interaction.js +1 -1
- package/dist/design/page-interaction.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/provider-defaults.d.ts +1 -1
- package/dist/provider-defaults.d.ts.map +1 -1
- package/dist/provider-defaults.js +8 -0
- package/dist/provider-defaults.js.map +1 -1
- package/dist/runner/fan-out.d.ts +11 -0
- package/dist/runner/fan-out.d.ts.map +1 -1
- package/dist/runner/fan-out.js +27 -2
- package/dist/runner/fan-out.js.map +1 -1
- package/dist/supervisor/critic.d.ts +1 -1
- package/dist/supervisor/critic.d.ts.map +1 -1
- package/dist/supervisor/critic.js +50 -5
- package/dist/supervisor/critic.js.map +1 -1
- package/dist/supervisor/policy.js +8 -5
- package/dist/supervisor/policy.js.map +1 -1
- package/dist/telemetry/client.d.ts +42 -0
- package/dist/telemetry/client.d.ts.map +1 -0
- package/dist/telemetry/client.js +203 -0
- package/dist/telemetry/client.js.map +1 -0
- package/dist/telemetry/hash.d.ts +4 -0
- package/dist/telemetry/hash.d.ts.map +1 -0
- package/dist/telemetry/hash.js +7 -0
- package/dist/telemetry/hash.js.map +1 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +5 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/schema.d.ts +85 -0
- package/dist/telemetry/schema.d.ts.map +1 -0
- package/dist/telemetry/schema.js +13 -0
- package/dist/telemetry/schema.js.map +1 -0
- package/dist/telemetry/sink.d.ts +46 -0
- package/dist/telemetry/sink.d.ts.map +1 -0
- package/dist/telemetry/sink.js +97 -0
- package/dist/telemetry/sink.js.map +1 -0
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +2 -0
- package/dist/test-runner.js.map +1 -1
- package/dist/types.d.ts +53 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -278,11 +278,43 @@ See [Configuration Reference](./docs/guides/configuration.md) for all options.
|
|
|
278
278
|
|
|
279
279
|
```bash
|
|
280
280
|
bad run [options] # Run tasks
|
|
281
|
+
bad snapshot --url <url> # Headless accessibility-tree dump (no LLM)
|
|
281
282
|
bad design-audit [options] # Design quality analysis
|
|
282
283
|
bad view <run-dir> # Open session viewer
|
|
283
284
|
bad competitive [options] # Head-to-head framework comparison
|
|
284
285
|
```
|
|
285
286
|
|
|
287
|
+
### `bad snapshot`
|
|
288
|
+
|
|
289
|
+
Deterministic, no-LLM DOM dump. Loads a URL, dismisses consent dialogs, waits for
|
|
290
|
+
the chosen network state, emits the accessibility-tree snapshot. Intended for CI
|
|
291
|
+
and downstream quality pipelines where the agentic loop is overkill.
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
bad snapshot --url https://example.com --json --out snap.json
|
|
295
|
+
bad snapshot --url http://localhost:3000 --wait domcontentloaded
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
| Flag | Description |
|
|
299
|
+
|------|-------------|
|
|
300
|
+
| `--url URL` | URL to snapshot (required) |
|
|
301
|
+
| `--json` | Emit structured JSON instead of human-readable text |
|
|
302
|
+
| `--out FILE` | Write to file instead of stdout |
|
|
303
|
+
| `--wait load\|domcontentloaded\|networkidle\|commit` | Playwright waitUntil. Default `networkidle` |
|
|
304
|
+
| `--timeout MS` | Per-action timeout. Default `15000` |
|
|
305
|
+
| `--no-dismiss-modals` | Skip consent/cookie dialog dismissal |
|
|
306
|
+
| `--headed` | Show the browser window (default headless) |
|
|
307
|
+
|
|
308
|
+
JSON shape: `{ schemaVersion, url, finalUrl, title, snapshot, timing, dismissed, errors }`.
|
|
309
|
+
Exits non-zero on navigation failure or aria-snapshot error.
|
|
310
|
+
|
|
311
|
+
### Report schema
|
|
312
|
+
|
|
313
|
+
`<sink>/report.json` carries a top-level `schemaVersion` field. The current
|
|
314
|
+
version is `"1"`. Consumers should verify this before destructuring. Adding an
|
|
315
|
+
optional field is non-breaking; the version bumps only on removed fields,
|
|
316
|
+
renamed fields, or changed value semantics.
|
|
317
|
+
|
|
286
318
|
### Run options
|
|
287
319
|
|
|
288
320
|
| Flag | Description |
|
package/dist/brain/index.d.ts
CHANGED
|
@@ -86,7 +86,7 @@ export declare class Brain {
|
|
|
86
86
|
private generationOptions;
|
|
87
87
|
/** Get a LLM model instance, optionally with provider/model override (e.g. for CAPTCHA fallback) */
|
|
88
88
|
getLanguageModel(selection?: {
|
|
89
|
-
provider?: 'openai' | 'anthropic' | 'google';
|
|
89
|
+
provider?: 'openai' | 'anthropic' | 'google' | 'cli-bridge';
|
|
90
90
|
model?: string;
|
|
91
91
|
}): Promise<LanguageModel>;
|
|
92
92
|
/** Lazily create the LLM model instance based on provider config */
|
|
@@ -279,6 +279,20 @@ export declare class Brain {
|
|
|
279
279
|
key: string;
|
|
280
280
|
value: string;
|
|
281
281
|
}>>;
|
|
282
|
+
/**
|
|
283
|
+
* Generic text-completion entry point for non-agent uses (GEPA reflective
|
|
284
|
+
* mutation, ad-hoc rubric authoring, knowledge distillation). Returns the
|
|
285
|
+
* raw text + token usage; callers parse JSON themselves.
|
|
286
|
+
*
|
|
287
|
+
* No tool use, no decode-loop heuristics — just a single round-trip through
|
|
288
|
+
* the configured provider/model.
|
|
289
|
+
*/
|
|
290
|
+
complete(system: string, user: string, options?: {
|
|
291
|
+
maxOutputTokens?: number;
|
|
292
|
+
}): Promise<{
|
|
293
|
+
text: string;
|
|
294
|
+
tokensUsed?: number;
|
|
295
|
+
}>;
|
|
282
296
|
private parse;
|
|
283
297
|
}
|
|
284
298
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/brain/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAsB,MAAM,IAAI,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,IAAI,EAAY,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/brain/index.ts"],"names":[],"mappings":"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"}
|
package/dist/brain/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Uses Vercel AI SDK for multi-provider support (OpenAI, Anthropic, Google, Codex CLI, Claude Code).
|
|
6
6
|
*/
|
|
7
|
-
import { generateText } from 'ai';
|
|
7
|
+
import { generateText, streamText } from 'ai';
|
|
8
8
|
import { AriaSnapshotHelper } from '../drivers/snapshot.js';
|
|
9
9
|
import { resolveProviderApiKey, resolveProviderModelName, isClaudeCodeRoutedModel, ZAI_OPENAI_BASE_URL, ZAI_ANTHROPIC_BASE_URL, } from '../provider-defaults.js';
|
|
10
10
|
import { buildFirstPartyBoundaryNote } from '../domain-policy.js';
|
|
@@ -157,7 +157,13 @@ ACTIONS:
|
|
|
157
157
|
- {"action": "fanOut", "subGoals": [...]} — spawn up to 8 parallel sub-agents in separate tabs (same session/cookies). See FAN-OUT section below for full rules + worked example.
|
|
158
158
|
|
|
159
159
|
FAN-OUT — PARALLEL INVESTIGATION:
|
|
160
|
-
fanOut is the way to investigate N independent candidates in PARALLEL instead of serially. When the current page shows a list of candidates or you have a queue of independent sub-tasks, emit ONE fanOut action
|
|
160
|
+
fanOut is the way to investigate N independent candidates in PARALLEL instead of serially. When the current page shows a list of candidates or you have a queue of independent sub-tasks, emit ONE fanOut action instead of processing them one at a time. The system spawns N sub-agents in fresh tabs of the same session; they run concurrently; their results are merged and returned to you as structured JSON in the NEXT turn's feedback.
|
|
161
|
+
|
|
162
|
+
STRONGLY PREFER THE SHORTHAND FORM when every branch shares a URL + instruction template. It emits tiny JSON that can't malform:
|
|
163
|
+
|
|
164
|
+
{"action":"fanOut","baseUrl":"https://site.example/","goalTemplate":"Investigate {item} — report outcome","items":["X","Y","Z"]}
|
|
165
|
+
|
|
166
|
+
The string {item} in goalTemplate is replaced with each array entry. Labels default to the item. This is the RIGHT shape for N>=3 branches.
|
|
161
167
|
|
|
162
168
|
USE fanOut WHEN:
|
|
163
169
|
- A search returned multiple results and each needs investigation (click in / extract / return verdict per row).
|
|
@@ -386,6 +392,19 @@ Respond with ONLY a JSON object:
|
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
Score: 1-3 = poor, 4-5 = needs work, 6-7 = acceptable, 8-9 = good, 10 = excellent`;
|
|
395
|
+
const JSON_TEXT_OUTPUT = {
|
|
396
|
+
name: 'json-text',
|
|
397
|
+
responseFormat: Promise.resolve({ type: 'json' }),
|
|
398
|
+
async parseCompleteOutput({ text }) {
|
|
399
|
+
return text;
|
|
400
|
+
},
|
|
401
|
+
async parsePartialOutput({ text }) {
|
|
402
|
+
return { partial: text };
|
|
403
|
+
},
|
|
404
|
+
createElementStreamTransform() {
|
|
405
|
+
return undefined;
|
|
406
|
+
},
|
|
407
|
+
};
|
|
389
408
|
export class Brain {
|
|
390
409
|
modelCache = new Map();
|
|
391
410
|
provider;
|
|
@@ -468,7 +487,7 @@ export class Brain {
|
|
|
468
487
|
}
|
|
469
488
|
shouldSendTemperature(modelName = this.modelName) {
|
|
470
489
|
// OpenAI GPT-5 reasoning family currently rejects explicit temperature.
|
|
471
|
-
return
|
|
490
|
+
return !/(^|\/)gpt-5(?:[.-]|$)/i.test(modelName);
|
|
472
491
|
}
|
|
473
492
|
generationOptions(maxOutputTokens, selection) {
|
|
474
493
|
const providerName = selection?.provider || this.provider;
|
|
@@ -480,9 +499,20 @@ export class Brain {
|
|
|
480
499
|
providerName === 'claude-code' ||
|
|
481
500
|
providerName === 'sandbox-backend' ||
|
|
482
501
|
(providerName === 'zai-coding-plan' && isClaudeCodeRoutedModel(modelName));
|
|
502
|
+
const omitsLegacyMaxTokens = providerName === 'cli-bridge' || /(^|\/)gpt-5(?:[.-]|$)/i.test(modelName);
|
|
483
503
|
return {
|
|
484
504
|
...(this.shouldSendTemperature(modelName) ? { temperature: 0 } : {}),
|
|
485
|
-
...(isCliSpawning ? {} : { maxOutputTokens }),
|
|
505
|
+
...(isCliSpawning || omitsLegacyMaxTokens ? {} : { maxOutputTokens }),
|
|
506
|
+
...(providerName === 'openai' && /(^|\/)gpt-5(?:[.-]|$)/i.test(modelName)
|
|
507
|
+
? {
|
|
508
|
+
providerOptions: {
|
|
509
|
+
openai: {
|
|
510
|
+
forceReasoning: true,
|
|
511
|
+
maxCompletionTokens: maxOutputTokens,
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
}
|
|
515
|
+
: {}),
|
|
486
516
|
};
|
|
487
517
|
}
|
|
488
518
|
/** Get a LLM model instance, optionally with provider/model override (e.g. for CAPTCHA fallback) */
|
|
@@ -518,6 +548,20 @@ export class Brain {
|
|
|
518
548
|
model = provider(modelName);
|
|
519
549
|
break;
|
|
520
550
|
}
|
|
551
|
+
case 'cli-bridge': {
|
|
552
|
+
const { createOpenAI } = await import('@ai-sdk/openai');
|
|
553
|
+
const rawUrl = this.baseUrl || process.env.CLI_BRIDGE_URL;
|
|
554
|
+
if (!rawUrl) {
|
|
555
|
+
throw new Error('cli-bridge provider requires CLI_BRIDGE_URL or --base-url');
|
|
556
|
+
}
|
|
557
|
+
const baseURL = rawUrl.endsWith('/v1') ? rawUrl : `${rawUrl.replace(/\/+$/, '')}/v1`;
|
|
558
|
+
const provider = createOpenAI({
|
|
559
|
+
apiKey: apiKey || '',
|
|
560
|
+
baseURL,
|
|
561
|
+
});
|
|
562
|
+
model = provider.chat(modelName);
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
521
565
|
case 'codex-cli': {
|
|
522
566
|
const { codexExec } = await import('ai-sdk-provider-codex-cli');
|
|
523
567
|
const env = {};
|
|
@@ -678,13 +722,25 @@ export class Brain {
|
|
|
678
722
|
const systemForRequest = providerName === 'anthropic' || typeof system === 'string'
|
|
679
723
|
? system
|
|
680
724
|
: systemForSandbox;
|
|
681
|
-
const
|
|
725
|
+
const generationSettings = {
|
|
682
726
|
model,
|
|
683
727
|
system: systemForRequest,
|
|
684
728
|
messages,
|
|
729
|
+
...(providerName === 'cli-bridge' ? { output: JSON_TEXT_OUTPUT } : {}),
|
|
685
730
|
...this.generationOptions(maxOutputTokens, { provider: providerName, model: modelName }),
|
|
686
731
|
abortSignal: AbortSignal.timeout(this.llmTimeoutMs),
|
|
687
|
-
}
|
|
732
|
+
};
|
|
733
|
+
const result = providerName === 'cli-bridge'
|
|
734
|
+
? await (async () => {
|
|
735
|
+
const streamed = streamText(generationSettings);
|
|
736
|
+
const [text, usage, providerMetadata] = await Promise.all([
|
|
737
|
+
streamed.text,
|
|
738
|
+
streamed.totalUsage,
|
|
739
|
+
streamed.providerMetadata,
|
|
740
|
+
]);
|
|
741
|
+
return { text, usage, providerMetadata };
|
|
742
|
+
})()
|
|
743
|
+
: await generateText(generationSettings);
|
|
688
744
|
// Extract prompt-cache stats from the AI SDK's PROVIDER-AGNOSTIC fields:
|
|
689
745
|
// result.usage.inputTokenDetails.{cacheReadTokens, cacheWriteTokens}
|
|
690
746
|
//
|
|
@@ -1238,6 +1294,15 @@ ${visibleSnapshot}`;
|
|
|
1238
1294
|
raw = retryResult.text;
|
|
1239
1295
|
parsed = retryParsed;
|
|
1240
1296
|
}
|
|
1297
|
+
else if (this.baseUrl) {
|
|
1298
|
+
// Both the initial parse and the format-hint retry failed while a
|
|
1299
|
+
// custom LLM_BASE_URL is set. Strong signal the gateway is
|
|
1300
|
+
// returning a shape the scout can't consume (e.g. SSE streams,
|
|
1301
|
+
// non-JSON wrappers). Surface the likely cause instead of
|
|
1302
|
+
// burning silent retries turn after turn.
|
|
1303
|
+
console.error(`[Brain] scout_json_parse_failed: LLM_BASE_URL=${this.baseUrl} returned a response the scout could not parse even after a format-hint retry. ` +
|
|
1304
|
+
`Suggestion: switch to an Anthropic-native endpoint, or verify the gateway supports non-streaming chat/completions with { "response_format": { "type": "json_object" } }.`);
|
|
1305
|
+
}
|
|
1241
1306
|
tokensUsed = (tokensUsed ?? 0) + (retryResult.tokensUsed ?? 0);
|
|
1242
1307
|
inputTokens = (inputTokens ?? 0) + (retryResult.inputTokens ?? 0);
|
|
1243
1308
|
outputTokens = (outputTokens ?? 0) + (retryResult.outputTokens ?? 0);
|
|
@@ -1944,6 +2009,18 @@ Only include facts that are genuinely useful. Quality over quantity. Max 10 fact
|
|
|
1944
2009
|
return [];
|
|
1945
2010
|
}
|
|
1946
2011
|
}
|
|
2012
|
+
/**
|
|
2013
|
+
* Generic text-completion entry point for non-agent uses (GEPA reflective
|
|
2014
|
+
* mutation, ad-hoc rubric authoring, knowledge distillation). Returns the
|
|
2015
|
+
* raw text + token usage; callers parse JSON themselves.
|
|
2016
|
+
*
|
|
2017
|
+
* No tool use, no decode-loop heuristics — just a single round-trip through
|
|
2018
|
+
* the configured provider/model.
|
|
2019
|
+
*/
|
|
2020
|
+
async complete(system, user, options = {}) {
|
|
2021
|
+
const result = await this.generate(system, [{ role: 'user', content: user }], undefined, options.maxOutputTokens ?? 1500);
|
|
2022
|
+
return { text: result.text, tokensUsed: result.tokensUsed };
|
|
2023
|
+
}
|
|
1947
2024
|
parse(raw) {
|
|
1948
2025
|
let text = raw.trim();
|
|
1949
2026
|
// Strip markdown code blocks
|
|
@@ -1961,9 +2038,41 @@ Only include facts that are genuinely useful. Quality over quantity. Max 10 fact
|
|
|
1961
2038
|
// Gen 29: macro dispatch. The driver validates the macro name at
|
|
1962
2039
|
// execute time; here we just accept the shape.
|
|
1963
2040
|
'macro',
|
|
2041
|
+
// Gen 33: parallel fan-out. Runner handles dispatch; validator
|
|
2042
|
+
// only checks shape (subGoals[] or baseUrl+goalTemplate+items).
|
|
2043
|
+
'fanOut',
|
|
1964
2044
|
]);
|
|
2045
|
+
// Parse strategy: exact → first-{/last-} extraction.
|
|
2046
|
+
// Some OpenAI-compat gateways (router.tangle.tools, LiteLLM proxies, etc.)
|
|
2047
|
+
// wrap model output in prose preambles ("Here's your response:\n{...}")
|
|
2048
|
+
// that markdown-fence stripping doesn't catch. Fall back to extracting the
|
|
2049
|
+
// outermost object literal before giving up.
|
|
2050
|
+
let parsed = null;
|
|
2051
|
+
let parseError = '';
|
|
2052
|
+
try {
|
|
2053
|
+
parsed = JSON.parse(text);
|
|
2054
|
+
}
|
|
2055
|
+
catch (err) {
|
|
2056
|
+
parseError = err instanceof Error ? err.message : String(err);
|
|
2057
|
+
const firstBrace = text.indexOf('{');
|
|
2058
|
+
const lastBrace = text.lastIndexOf('}');
|
|
2059
|
+
if (firstBrace >= 0 && lastBrace > firstBrace) {
|
|
2060
|
+
try {
|
|
2061
|
+
parsed = JSON.parse(text.slice(firstBrace, lastBrace + 1));
|
|
2062
|
+
parseError = '';
|
|
2063
|
+
}
|
|
2064
|
+
catch { /* fall through to retry fallback */ }
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
if (!parsed) {
|
|
2068
|
+
return {
|
|
2069
|
+
// Do not hard-abort the scenario on transient JSON formatting issues.
|
|
2070
|
+
// Waiting one turn lets the loop continue and recover on the next model call.
|
|
2071
|
+
action: { action: 'wait', ms: 1000 },
|
|
2072
|
+
reasoning: `Malformed LLM JSON response (${parseError}). Retrying next turn.`,
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
1965
2075
|
try {
|
|
1966
|
-
const parsed = JSON.parse(text);
|
|
1967
2076
|
const actionObj = parsed.action && typeof parsed.action === 'object' ? parsed.action : parsed;
|
|
1968
2077
|
const actionType = typeof parsed.action === 'string' ? parsed.action : actionObj?.action;
|
|
1969
2078
|
if (!actionType) {
|
|
@@ -1972,24 +2081,24 @@ Only include facts that are genuinely useful. Quality over quantity. Max 10 fact
|
|
|
1972
2081
|
if (!VALID_ACTIONS.has(actionType)) {
|
|
1973
2082
|
throw new Error(`Unknown action "${actionType}". Valid: ${[...VALID_ACTIONS].join(', ')}`);
|
|
1974
2083
|
}
|
|
1975
|
-
const actionData = typeof parsed.action === 'object'
|
|
2084
|
+
const actionData = parsed.action && typeof parsed.action === 'object'
|
|
2085
|
+
? parsed.action
|
|
2086
|
+
: parsed;
|
|
1976
2087
|
const action = validateAction(actionType, actionData);
|
|
1977
2088
|
return {
|
|
1978
2089
|
action,
|
|
1979
2090
|
nextActions: parseNextActions(parsed, VALID_ACTIONS),
|
|
1980
|
-
reasoning: parsed.reasoning || parsed.thought || parsed.thinking,
|
|
2091
|
+
reasoning: (parsed.reasoning || parsed.thought || parsed.thinking),
|
|
1981
2092
|
plan: Array.isArray(parsed.plan) ? parsed.plan : undefined,
|
|
1982
2093
|
currentStep: typeof parsed.currentStep === 'number' ? parsed.currentStep : undefined,
|
|
1983
|
-
expectedEffect: parsed.expectedEffect || parsed.expected_effect,
|
|
2094
|
+
expectedEffect: (parsed.expectedEffect || parsed.expected_effect),
|
|
1984
2095
|
};
|
|
1985
2096
|
}
|
|
1986
2097
|
catch (err) {
|
|
1987
|
-
const
|
|
2098
|
+
const validationError = err instanceof Error ? err.message : String(err);
|
|
1988
2099
|
return {
|
|
1989
|
-
// Do not hard-abort the scenario on transient JSON formatting issues.
|
|
1990
|
-
// Waiting one turn lets the loop continue and recover on the next model call.
|
|
1991
2100
|
action: { action: 'wait', ms: 1000 },
|
|
1992
|
-
reasoning: `Malformed LLM JSON response (${
|
|
2101
|
+
reasoning: `Malformed LLM JSON response (${validationError}). Retrying next turn.`,
|
|
1993
2102
|
};
|
|
1994
2103
|
}
|
|
1995
2104
|
}
|
|
@@ -2327,6 +2436,38 @@ function validateAction(actionType, data) {
|
|
|
2327
2436
|
...(Object.keys(args).length > 0 ? { args } : {}),
|
|
2328
2437
|
};
|
|
2329
2438
|
}
|
|
2439
|
+
case 'fanOut': {
|
|
2440
|
+
// Accept either explicit subGoals[] or the shorthand
|
|
2441
|
+
// baseUrl+goalTemplate+items trio. resolveSubGoals() in
|
|
2442
|
+
// runner/fan-out.ts expands shorthand → subGoals at execute time.
|
|
2443
|
+
const subGoals = Array.isArray(data.subGoals)
|
|
2444
|
+
? data.subGoals
|
|
2445
|
+
.filter((s) => s && typeof s === 'object')
|
|
2446
|
+
.map((s) => ({
|
|
2447
|
+
url: typeof s.url === 'string' ? s.url : '',
|
|
2448
|
+
goal: typeof s.goal === 'string' ? s.goal : '',
|
|
2449
|
+
...(typeof s.label === 'string' ? { label: s.label } : {}),
|
|
2450
|
+
...(typeof s.maxTurns === 'number' ? { maxTurns: s.maxTurns } : {}),
|
|
2451
|
+
}))
|
|
2452
|
+
.filter((s) => s.url && s.goal)
|
|
2453
|
+
: undefined;
|
|
2454
|
+
const baseUrl = typeof data.baseUrl === 'string' ? data.baseUrl : undefined;
|
|
2455
|
+
const goalTemplate = typeof data.goalTemplate === 'string' ? data.goalTemplate : undefined;
|
|
2456
|
+
const items = Array.isArray(data.items) && data.items.every((i) => typeof i === 'string')
|
|
2457
|
+
? data.items
|
|
2458
|
+
: undefined;
|
|
2459
|
+
const hasExplicit = subGoals && subGoals.length > 0;
|
|
2460
|
+
const hasShorthand = baseUrl && goalTemplate && items && items.length > 0;
|
|
2461
|
+
if (!hasExplicit && !hasShorthand) {
|
|
2462
|
+
throw new Error('fanOut action requires either "subGoals" (array of {url,goal}) or the shorthand trio "baseUrl" + "goalTemplate" + "items" (non-empty string[])');
|
|
2463
|
+
}
|
|
2464
|
+
return {
|
|
2465
|
+
action: 'fanOut',
|
|
2466
|
+
...(hasExplicit ? { subGoals } : {}),
|
|
2467
|
+
...(hasShorthand ? { baseUrl, goalTemplate, items } : {}),
|
|
2468
|
+
...(typeof data.summarize === 'string' ? { summarize: data.summarize } : {}),
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
2330
2471
|
default:
|
|
2331
2472
|
throw new Error(`Unknown action type: ${actionType}`);
|
|
2332
2473
|
}
|