omnius 1.0.664 → 1.0.666
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.
|
@@ -7,8 +7,10 @@ compaction_strategy: structured
|
|
|
7
7
|
# browser-interaction-validation
|
|
8
8
|
|
|
9
9
|
Validate user-facing browser flows with `playwright_browser` as the canonical
|
|
10
|
-
runtime. A page loading, a successful click receipt,
|
|
11
|
-
source assertions alone do **not** prove that a requested interaction
|
|
10
|
+
runtime. A page loading, a successful click receipt, an immediate screenshot,
|
|
11
|
+
or static source assertions alone do **not** prove that a requested interaction
|
|
12
|
+
worked. Some failures appear only after the page remains active. GPU and WebGL
|
|
13
|
+
failures can also differ between headless and headed browsers.
|
|
12
14
|
|
|
13
15
|
## Triggers
|
|
14
16
|
|
|
@@ -39,9 +41,12 @@ static checks separately as static evidence.
|
|
|
39
41
|
1. Use `playwright_browser` for the entire flow. Do not switch to
|
|
40
42
|
`browser_action` (Selenium) mid-flow; it is a separate browser session and
|
|
41
43
|
loses page state. Use Selenium only as an explicit legacy fallback.
|
|
42
|
-
2.
|
|
43
|
-
|
|
44
|
-
and
|
|
44
|
+
2. Start with `validate_lifecycle`. Give it the live URL, an explicit
|
|
45
|
+
postcondition, and a finite `observation_ms`. This starts diagnostics before
|
|
46
|
+
navigation and holds the page open after load. For GUI, GPU, WebGL, WebGPU,
|
|
47
|
+
canvas, or animation claims, set `headless=false` and `force_new=true`. If a
|
|
48
|
+
graphical display is unavailable, report the headed check as blocked. Do not
|
|
49
|
+
substitute a clean headless run as proof.
|
|
45
50
|
3. Choose a stable locator: prefer `data-testid`, then accessible role/name,
|
|
46
51
|
then a specific CSS selector. Avoid ordinal or broad selectors that can race
|
|
47
52
|
reactive re-renders.
|
|
@@ -52,9 +57,11 @@ static checks separately as static evidence.
|
|
|
52
57
|
Re-query after a detached-element/re-render failure; do not retry a stale
|
|
53
58
|
handle blindly. If a stable locator is unavailable, report that as a
|
|
54
59
|
product-testability finding.
|
|
55
|
-
6.
|
|
56
|
-
|
|
57
|
-
page errors, console errors,
|
|
60
|
+
6. After the action, call `observe_window` with the expected state and a finite
|
|
61
|
+
`observation_ms`. Keep the same browser session alive while delayed failures
|
|
62
|
+
surface. Review the window-scoped page errors, console errors, failed network
|
|
63
|
+
requests, DOM state, and screenshot. Use `observe_bundle` only for an
|
|
64
|
+
instantaneous session summary when a timed observation is not required.
|
|
58
65
|
7. Close by listing every requested interaction with its evidence outcome,
|
|
59
66
|
receipt/artifact references, and any precise remediation. Call
|
|
60
67
|
`task_complete` when the implementation work is done; verifier feedback is
|
package/dist/api/py-embed.js
CHANGED
|
@@ -289947,7 +289947,6 @@ init_process_lifecycle();
|
|
|
289947
289947
|
import { dirname, join, resolve as resolve2 } from "node:path";
|
|
289948
289948
|
import { homedir as homedir2, tmpdir } from "node:os";
|
|
289949
289949
|
init_vision();
|
|
289950
|
-
var dynamicImport = new Function("mod", "return import(mod)");
|
|
289951
289950
|
var PLAYWRIGHT_RUNTIME_DIR = join(homedir2(), ".omnius", "playwright-runtime");
|
|
289952
289951
|
var PLAYWRIGHT_BROWSERS_DIR = join(PLAYWRIGHT_RUNTIME_DIR, "browsers");
|
|
289953
289952
|
|
package/dist/index.js
CHANGED
|
@@ -63552,6 +63552,30 @@ function pushBounded(buf, item) {
|
|
|
63552
63552
|
if (buf.length > MAX_BUFFER)
|
|
63553
63553
|
buf.splice(0, buf.length - MAX_BUFFER);
|
|
63554
63554
|
}
|
|
63555
|
+
function captureBrowserDiagnosticCursor() {
|
|
63556
|
+
return {
|
|
63557
|
+
startedAtMs: Date.now(),
|
|
63558
|
+
consoleIndex: consoleBuffer.length,
|
|
63559
|
+
networkIndex: networkBuffer.length,
|
|
63560
|
+
errorIndex: errorBuffer.length,
|
|
63561
|
+
websocketIndex: wsBuffer.length,
|
|
63562
|
+
crashCount
|
|
63563
|
+
};
|
|
63564
|
+
}
|
|
63565
|
+
function diagnosticEntriesAfter(entries2, index, startedAtMs) {
|
|
63566
|
+
return index <= entries2.length ? entries2.slice(index) : entries2.filter((entry) => entry.ts >= startedAtMs);
|
|
63567
|
+
}
|
|
63568
|
+
function browserDiagnosticWindow(cursor) {
|
|
63569
|
+
return {
|
|
63570
|
+
startedAtMs: cursor.startedAtMs,
|
|
63571
|
+
endedAtMs: Date.now(),
|
|
63572
|
+
console: diagnosticEntriesAfter(consoleBuffer, cursor.consoleIndex, cursor.startedAtMs),
|
|
63573
|
+
network: diagnosticEntriesAfter(networkBuffer, cursor.networkIndex, cursor.startedAtMs),
|
|
63574
|
+
errors: diagnosticEntriesAfter(errorBuffer, cursor.errorIndex, cursor.startedAtMs),
|
|
63575
|
+
websockets: diagnosticEntriesAfter(wsBuffer, cursor.websocketIndex, cursor.startedAtMs),
|
|
63576
|
+
crashCount: Math.max(0, crashCount - cursor.crashCount)
|
|
63577
|
+
};
|
|
63578
|
+
}
|
|
63555
63579
|
function which(cmd) {
|
|
63556
63580
|
try {
|
|
63557
63581
|
const out = execFileSync("which", [cmd], {
|
|
@@ -63663,6 +63687,11 @@ function asOptionalBoolean(value2) {
|
|
|
63663
63687
|
function defaultPlaywrightHeadless() {
|
|
63664
63688
|
return asOptionalBoolean(process.env["OMNIUS_PLAYWRIGHT_HEADLESS"] ?? process.env["OMNIUS_BROWSER_HEADLESS"]) ?? true;
|
|
63665
63689
|
}
|
|
63690
|
+
function hasGraphicalBrowserDisplay() {
|
|
63691
|
+
if (process.platform !== "linux")
|
|
63692
|
+
return true;
|
|
63693
|
+
return Boolean(process.env["DISPLAY"]?.trim() || process.env["WAYLAND_DISPLAY"]?.trim());
|
|
63694
|
+
}
|
|
63666
63695
|
async function installPlaywrightBrowser() {
|
|
63667
63696
|
try {
|
|
63668
63697
|
mkdirSync18(PLAYWRIGHT_RUNTIME_DIR, { recursive: true });
|
|
@@ -63927,37 +63956,6 @@ function attachDiagnosticListeners(p2) {
|
|
|
63927
63956
|
} catch {
|
|
63928
63957
|
}
|
|
63929
63958
|
});
|
|
63930
|
-
if (!initScriptInstalled) {
|
|
63931
|
-
try {
|
|
63932
|
-
p2.addInitScript(`(() => {
|
|
63933
|
-
if (window.__browserEvents) return;
|
|
63934
|
-
window.__browserEvents = [];
|
|
63935
|
-
const push = (evt) => {
|
|
63936
|
-
window.__browserEvents.push(evt);
|
|
63937
|
-
if (window.__browserEvents.length > 2000) window.__browserEvents.splice(0, window.__browserEvents.length - 2000);
|
|
63938
|
-
};
|
|
63939
|
-
const origError = console.error;
|
|
63940
|
-
console.error = function() {
|
|
63941
|
-
push({ ts: Date.now(), type: "console:error", text: Array.from(arguments).map(String).join(" ").slice(0, 2000) });
|
|
63942
|
-
return origError.apply(console, arguments);
|
|
63943
|
-
};
|
|
63944
|
-
const origWarn = console.warn;
|
|
63945
|
-
console.warn = function() {
|
|
63946
|
-
push({ ts: Date.now(), type: "console:warn", text: Array.from(arguments).map(String).join(" ").slice(0, 2000) });
|
|
63947
|
-
return origWarn.apply(console, arguments);
|
|
63948
|
-
};
|
|
63949
|
-
window.onerror = function(msg, source, lineno, colno, err) {
|
|
63950
|
-
push({ ts: Date.now(), type: "onerror", text: String(msg).slice(0, 2000), stack: err instanceof Error ? (err.stack || "").slice(0, 3000) : "" });
|
|
63951
|
-
};
|
|
63952
|
-
window.onunhandledrejection = function(evt) {
|
|
63953
|
-
const r = evt.reason;
|
|
63954
|
-
push({ ts: Date.now(), type: "unhandledRejection", text: String(r?.message ?? r ?? "unknown").slice(0, 2000), stack: typeof r?.stack === "string" ? r.stack.slice(0, 3000) : "" });
|
|
63955
|
-
};
|
|
63956
|
-
})()`);
|
|
63957
|
-
initScriptInstalled = true;
|
|
63958
|
-
} catch {
|
|
63959
|
-
}
|
|
63960
|
-
}
|
|
63961
63959
|
}
|
|
63962
63960
|
function clearDiagnosticBuffers() {
|
|
63963
63961
|
consoleBuffer = [];
|
|
@@ -64145,6 +64143,9 @@ async function runBrowserLocatorAction(pageHandle, selector, index, timeout2, ac
|
|
|
64145
64143
|
async function waitForBrowserExpectation(pageHandle, expectation, timeout2) {
|
|
64146
64144
|
await pageHandle.locator(expectation).first().waitFor({ state: "visible", timeout: timeout2 });
|
|
64147
64145
|
}
|
|
64146
|
+
async function browserExpectationIsVisible(pageHandle, expectation) {
|
|
64147
|
+
return Boolean(await pageHandle.locator(expectation).first().isVisible().catch(() => false));
|
|
64148
|
+
}
|
|
64148
64149
|
async function runBrowserInteractionWithEvidence(input) {
|
|
64149
64150
|
const before = await captureBrowserInteractionSnapshot(input.pageHandle);
|
|
64150
64151
|
let performed = null;
|
|
@@ -64736,6 +64737,169 @@ async function findBrowserVisualCandidate(pageHandle, target, visualX, visualY,
|
|
|
64736
64737
|
}
|
|
64737
64738
|
return candidates.filter((candidate) => includeOffscreen || candidate["visible"] === true).sort((a2, b) => Number(b["score"] ?? 0) - Number(a2["score"] ?? 0))[0] ?? null;
|
|
64738
64739
|
}
|
|
64740
|
+
async function captureBrowserObservation(input) {
|
|
64741
|
+
const html = await input.pageHandle.content();
|
|
64742
|
+
const readableText = await input.pageHandle.evaluate(`(() => {
|
|
64743
|
+
const clone = document.body ? document.body.cloneNode(true) : document.documentElement.cloneNode(true);
|
|
64744
|
+
clone.querySelectorAll("script, style, noscript, svg, path").forEach(el => el.remove());
|
|
64745
|
+
return clone.innerText || clone.textContent || "";
|
|
64746
|
+
})()`);
|
|
64747
|
+
const summary = downsampleDom(html);
|
|
64748
|
+
lastDomSummarySelectors = extractDomSummarySelectors(summary);
|
|
64749
|
+
const screenshotBuffer = await input.pageHandle.screenshot({
|
|
64750
|
+
fullPage: input.fullPage
|
|
64751
|
+
});
|
|
64752
|
+
const screenshotPath = saveBuffer(input.outputPath || defaultArtifactPath(input.action, "png"), screenshotBuffer);
|
|
64753
|
+
const viewport = input.pageHandle.viewportSize?.() ?? {
|
|
64754
|
+
width: 0,
|
|
64755
|
+
height: 0
|
|
64756
|
+
};
|
|
64757
|
+
const diagnostics = input.cursor ? browserDiagnosticWindow(input.cursor) : {
|
|
64758
|
+
startedAtMs: input.startMs,
|
|
64759
|
+
endedAtMs: Date.now(),
|
|
64760
|
+
console: [...consoleBuffer],
|
|
64761
|
+
network: [...networkBuffer],
|
|
64762
|
+
errors: [...errorBuffer],
|
|
64763
|
+
websockets: [...wsBuffer],
|
|
64764
|
+
crashCount
|
|
64765
|
+
};
|
|
64766
|
+
const consoleErrors = diagnostics.console.filter((entry) => /error/i.test(entry.type)).slice(-30);
|
|
64767
|
+
const consoleWarnings = diagnostics.console.filter((entry) => /warn/i.test(entry.type)).slice(-30);
|
|
64768
|
+
const networkFailures = diagnostics.network.filter((entry) => entry.ok === false || (entry.status ?? 0) >= 400).slice(-30);
|
|
64769
|
+
const pageErrors = diagnostics.errors.slice(-30);
|
|
64770
|
+
const gate = classifyBrowserGate({
|
|
64771
|
+
url: input.pageHandle.url(),
|
|
64772
|
+
html,
|
|
64773
|
+
text: String(readableText ?? ""),
|
|
64774
|
+
network: diagnostics.network,
|
|
64775
|
+
errors: diagnostics.errors
|
|
64776
|
+
});
|
|
64777
|
+
const actualObservationMs = Math.max(0, diagnostics.endedAtMs - diagnostics.startedAtMs);
|
|
64778
|
+
const runtimeFailureCount = consoleErrors.length + pageErrors.length + networkFailures.length + diagnostics.crashCount;
|
|
64779
|
+
const blocked = gate.kind === "captcha" || gate.kind === "bot_challenge";
|
|
64780
|
+
const contradicted = input.expectationSatisfied === false || runtimeFailureCount > 0;
|
|
64781
|
+
const verification = blocked ? {
|
|
64782
|
+
status: "blocked",
|
|
64783
|
+
confidence: gate.confidence,
|
|
64784
|
+
reason: `Browser observation was blocked by gate=${gate.kind}.`
|
|
64785
|
+
} : contradicted ? {
|
|
64786
|
+
status: "contradicted",
|
|
64787
|
+
confidence: 0.96,
|
|
64788
|
+
reason: input.expectationSatisfied === false ? `The declared postcondition was not observed: ${input.expectation}.` : `The browser emitted ${runtimeFailureCount} runtime failure signal(s) during the observation window.`,
|
|
64789
|
+
nextSuggestedObservation: "Fix the concrete console/page/network failure, then rerun validate_lifecycle or observe_window in the same browser mode."
|
|
64790
|
+
} : input.expectationSatisfied === true ? {
|
|
64791
|
+
status: "proven",
|
|
64792
|
+
confidence: 0.9,
|
|
64793
|
+
reason: `The declared postcondition remained visible and no browser runtime failures appeared during the ${actualObservationMs}ms observation window.`
|
|
64794
|
+
} : {
|
|
64795
|
+
status: "inconclusive",
|
|
64796
|
+
confidence: 0.58,
|
|
64797
|
+
reason: `The browser remained under observation for ${actualObservationMs}ms, but no explicit postcondition was evaluated.`,
|
|
64798
|
+
nextSuggestedObservation: "Repeat with expect set to a state-specific selector before making a user-visible success claim."
|
|
64799
|
+
};
|
|
64800
|
+
const mode = browserHeadless === false ? "headed" : "headless";
|
|
64801
|
+
const evidenceEvent = createEvidenceEvent({
|
|
64802
|
+
sessionId: playwrightSessionId ?? void 0,
|
|
64803
|
+
tool: "playwright_browser",
|
|
64804
|
+
action: input.action,
|
|
64805
|
+
surface: "browser",
|
|
64806
|
+
claim: input.expectation ? `Browser postcondition: ${input.expectation}` : "Timed browser runtime observation",
|
|
64807
|
+
after: createEvidenceObservation({
|
|
64808
|
+
screenshotPath,
|
|
64809
|
+
screenshotHash: sha256Buffer(screenshotBuffer),
|
|
64810
|
+
width: viewport.width,
|
|
64811
|
+
height: viewport.height,
|
|
64812
|
+
url: input.pageHandle.url(),
|
|
64813
|
+
title: await input.pageHandle.title(),
|
|
64814
|
+
domSummaryHash: sha256Text(summary),
|
|
64815
|
+
readableTextHash: sha256Text(String(readableText ?? "")),
|
|
64816
|
+
visibleTextExcerpt: clipEvidenceText(readableText, 500),
|
|
64817
|
+
consoleErrorCount: consoleErrors.length,
|
|
64818
|
+
pageErrorCount: pageErrors.length,
|
|
64819
|
+
networkFailureCount: networkFailures.length,
|
|
64820
|
+
gateKind: gate.kind,
|
|
64821
|
+
gateConfidence: gate.confidence,
|
|
64822
|
+
gateEvidence: gate.evidence,
|
|
64823
|
+
metadata: {
|
|
64824
|
+
mode,
|
|
64825
|
+
engine: "playwright",
|
|
64826
|
+
requestedObservationMs: input.requestedObservationMs,
|
|
64827
|
+
actualObservationMs,
|
|
64828
|
+
diagnosticsScope: input.cursor ? "window" : "session",
|
|
64829
|
+
consoleWarningCount: consoleWarnings.length,
|
|
64830
|
+
websocketEventCount: diagnostics.websockets.length,
|
|
64831
|
+
crashCount: diagnostics.crashCount,
|
|
64832
|
+
expectation: input.expectation,
|
|
64833
|
+
expectationSatisfied: input.expectationSatisfied
|
|
64834
|
+
}
|
|
64835
|
+
}),
|
|
64836
|
+
verification
|
|
64837
|
+
});
|
|
64838
|
+
const bundle = {
|
|
64839
|
+
schema: "omnius.browser-observation-window.v1",
|
|
64840
|
+
id: timestampSlug(),
|
|
64841
|
+
engine: "playwright",
|
|
64842
|
+
mode,
|
|
64843
|
+
url: input.pageHandle.url(),
|
|
64844
|
+
title: await input.pageHandle.title(),
|
|
64845
|
+
viewport,
|
|
64846
|
+
screenshotPath,
|
|
64847
|
+
observationWindow: {
|
|
64848
|
+
requestedMs: input.requestedObservationMs,
|
|
64849
|
+
actualMs: actualObservationMs,
|
|
64850
|
+
startedAt: new Date(diagnostics.startedAtMs).toISOString(),
|
|
64851
|
+
endedAt: new Date(diagnostics.endedAtMs).toISOString(),
|
|
64852
|
+
diagnosticsScope: input.cursor ? "window" : "session"
|
|
64853
|
+
},
|
|
64854
|
+
expectation: input.expectation ?? null,
|
|
64855
|
+
expectationSatisfied: input.expectationSatisfied ?? null,
|
|
64856
|
+
expectationError: input.expectationError ?? null,
|
|
64857
|
+
gate,
|
|
64858
|
+
consoleErrors,
|
|
64859
|
+
consoleWarnings,
|
|
64860
|
+
networkFailures,
|
|
64861
|
+
pageErrors,
|
|
64862
|
+
websocketEvents: diagnostics.websockets.slice(-30),
|
|
64863
|
+
crashes: diagnostics.crashCount,
|
|
64864
|
+
domSummary: summary.slice(0, 12e3),
|
|
64865
|
+
evidenceEvents: [evidenceEvent]
|
|
64866
|
+
};
|
|
64867
|
+
const failureDetails = [
|
|
64868
|
+
...consoleErrors.map((entry) => `console ${entry.type}: ${entry.text}${entry.loc ? ` (${entry.loc})` : ""}`),
|
|
64869
|
+
...pageErrors.map((entry) => `page error: ${entry.message}`),
|
|
64870
|
+
...networkFailures.map((entry) => `network: ${entry.method} ${entry.status ?? "FAILED"} ${entry.url}${entry.failure ? ` (${entry.failure})` : ""}`)
|
|
64871
|
+
].slice(0, 30);
|
|
64872
|
+
const output2 = [
|
|
64873
|
+
"Browser observation bundle",
|
|
64874
|
+
`URL: ${bundle.url}`,
|
|
64875
|
+
`Title: ${bundle.title}`,
|
|
64876
|
+
`Mode: ${mode}`,
|
|
64877
|
+
`Observation window: ${actualObservationMs}ms (${input.cursor ? "window-scoped" : "session-scoped"} diagnostics)`,
|
|
64878
|
+
`Viewport: ${viewport.width}x${viewport.height}`,
|
|
64879
|
+
`Screenshot: ${screenshotPath}`,
|
|
64880
|
+
`Gate: ${gate.kind} (${gate.confidence.toFixed(2)})${gate.evidence.length ? ` — ${gate.evidence.join("; ")}` : ""}`,
|
|
64881
|
+
`Console errors: ${consoleErrors.length}`,
|
|
64882
|
+
`Console warnings: ${consoleWarnings.length}`,
|
|
64883
|
+
`Page errors: ${pageErrors.length}`,
|
|
64884
|
+
`Network failures: ${networkFailures.length}`,
|
|
64885
|
+
`Verification: ${verification.status} — ${verification.reason}`,
|
|
64886
|
+
...failureDetails.length > 0 ? ["", "--- Runtime failures ---", ...failureDetails] : [],
|
|
64887
|
+
"",
|
|
64888
|
+
"--- DOM Summary ---",
|
|
64889
|
+
summary.slice(0, 6e3)
|
|
64890
|
+
].join("\n");
|
|
64891
|
+
const shouldFail = input.failOnRuntimeErrors && contradicted;
|
|
64892
|
+
return {
|
|
64893
|
+
success: !shouldFail,
|
|
64894
|
+
output: output2,
|
|
64895
|
+
...shouldFail ? {
|
|
64896
|
+
error: `Browser lifecycle validation failed: ${runtimeFailureCount} runtime failure signal(s)${input.expectationSatisfied === false ? "; declared postcondition was not observed" : ""}.`
|
|
64897
|
+
} : {},
|
|
64898
|
+
llmContent: JSON.stringify(bundle, null, 2),
|
|
64899
|
+
evidenceEvents: [evidenceEvent],
|
|
64900
|
+
durationMs: Date.now() - input.startMs
|
|
64901
|
+
};
|
|
64902
|
+
}
|
|
64739
64903
|
function ok(output2, start2, skipDiag = false) {
|
|
64740
64904
|
const diag = skipDiag ? "" : formatDiagnosticSummary();
|
|
64741
64905
|
return {
|
|
@@ -64748,7 +64912,7 @@ ${diag}` : output2,
|
|
|
64748
64912
|
function fail(error, start2) {
|
|
64749
64913
|
return { success: false, output: "", error, durationMs: Date.now() - start2 };
|
|
64750
64914
|
}
|
|
64751
|
-
var pw, browser, context, page, browserHeadless, playwrightSessionId, playwrightSessionSequence, MAX_BUFFER, consoleBuffer, networkBuffer, errorBuffer, wsBuffer, crashCount,
|
|
64915
|
+
var pw, browser, context, page, browserHeadless, playwrightSessionId, playwrightSessionSequence, MAX_BUFFER, consoleBuffer, networkBuffer, errorBuffer, wsBuffer, crashCount, lastDomSummarySelectors, dynamicImport, PLAYWRIGHT_RUNTIME_DIR, PLAYWRIGHT_BROWSERS_DIR, PLAYWRIGHT_CHROMIUM_INSTALL_ARGS, PlaywrightBrowserTool;
|
|
64752
64916
|
var init_playwright_browser = __esm({
|
|
64753
64917
|
"packages/execution/dist/tools/playwright-browser.js"() {
|
|
64754
64918
|
"use strict";
|
|
@@ -64769,15 +64933,18 @@ var init_playwright_browser = __esm({
|
|
|
64769
64933
|
errorBuffer = [];
|
|
64770
64934
|
wsBuffer = [];
|
|
64771
64935
|
crashCount = 0;
|
|
64772
|
-
initScriptInstalled = false;
|
|
64773
64936
|
lastDomSummarySelectors = /* @__PURE__ */ new Map();
|
|
64774
|
-
dynamicImport =
|
|
64937
|
+
dynamicImport = (mod3) => import(
|
|
64938
|
+
/* @vite-ignore */
|
|
64939
|
+
mod3
|
|
64940
|
+
);
|
|
64775
64941
|
PLAYWRIGHT_RUNTIME_DIR = join22(homedir7(), ".omnius", "playwright-runtime");
|
|
64776
64942
|
PLAYWRIGHT_BROWSERS_DIR = join22(PLAYWRIGHT_RUNTIME_DIR, "browsers");
|
|
64777
64943
|
PLAYWRIGHT_CHROMIUM_INSTALL_ARGS = ["playwright", "install", "chromium"];
|
|
64778
64944
|
PlaywrightBrowserTool = class {
|
|
64779
64945
|
name = "playwright_browser";
|
|
64780
|
-
|
|
64946
|
+
modelFacingSummary = "Validate a live UI in one persistent Playwright session. For GUI, GPU, WebGL, WebGPU, canvas, or animation claims, use validate_lifecycle with headless=false, force_new=true, an explicit expect, and a finite observation_ms. Use observe_window after interactions. Inspect delayed console, page, network, DOM, and screenshot evidence. A clean headless or immediate load is not headed lifecycle proof.";
|
|
64947
|
+
description = "Persistent Playwright browser lifecycle validation with timed console, page-error, network, DOM, and screenshot capture. Launches a persistent headless Chromium session by default, with optional visible/headed mode when a GUI display is available. Beyond navigation/interaction, this tool buffers everything the running app emits (console messages, network requests, JS exceptions, accessibility tree) so the agent can verify what is ACTUALLY happening — not just what the build/test reports. Auto-installs Playwright + Chromium on first use without sudo or OS package manager escalation. Diagnostic actions: validate_lifecycle, observe_window, observe_bundle, dom_summary, dom, console_logs, network_log, page_errors, websocket_log, a11y_snapshot, bounding_box, query_all, performance, cookies, storage, viewport, clear_diagnostics. Interaction actions: navigate, click, visual_click, fill, type, press, select, check, hover. Use fill with a selector or natural-language target for form fields; avoid raw evaluate for form filling because direct .value assignment does not fire app input/change events. For state-changing interactions, pass expect as a Playwright selector for the visible post-action state (for example text=Stop Simulation). A dispatched click without an asserted postcondition is recorded as inconclusive, not completion proof. Selectors are strict by default: when a selector matches more than one element, use a more specific selector or index (zero-based). Detached/re-rendered elements are re-queried once before failing. This is a separate browser/runtime from browser_action; once you start a workflow here, continue here unless you intentionally navigate browser_action to the same URL. Every result carries a typed runtime-session receipt; use hardware_prerequisite before declaring a WebSerial, WebUSB, camera, or microphone interaction blocked by a real device/permission boundary. Capture actions: screenshot, pdf, content, innerText, innerHTML, getAttribute, evaluate. Loopback URLs (localhost, 127.0.0.1, ::1) are allowed for local development servers; private LAN and metadata URLs remain blocked. Workflow for user-facing work: start/serve the system with the stack-native tool, then run validate_lifecycle against the real URL with an explicit expect and observation_ms. For GPU, WebGL, WebGPU, canvas, animation, or failures seen in a normal GUI browser, use headless=false and force_new=true; a clean headless run does not verify headed GPU behavior. Use observe_window after interactions to keep the same browser alive while delayed failures surface, then inspect page_errors, console_logs, network_log, DOM/accessibility, and screenshot evidence before completion. Build/typecheck/test output is only one layer; runtime browser evidence is required when the delivered artifact is a page, app, dashboard, game, form, visualization, or other UI. Repeat navigate/act/observe until the actual user flow is clean.";
|
|
64781
64948
|
parameters = {
|
|
64782
64949
|
type: "object",
|
|
64783
64950
|
properties: {
|
|
@@ -64824,12 +64991,14 @@ var init_playwright_browser = __esm({
|
|
|
64824
64991
|
"storage",
|
|
64825
64992
|
"viewport",
|
|
64826
64993
|
"observe_bundle",
|
|
64994
|
+
"observe_window",
|
|
64995
|
+
"validate_lifecycle",
|
|
64827
64996
|
"visual_click",
|
|
64828
64997
|
"hardware_prerequisite",
|
|
64829
64998
|
"clear_diagnostics",
|
|
64830
64999
|
"close"
|
|
64831
65000
|
],
|
|
64832
|
-
description: "Action to perform:\n- navigate: go to a URL\n- click: click element by selector\n- fill: clear input and type text by selector, or by natural-language target when selector is absent\n- type: type text character by character into a selector, or into the currently focused element after visual_click\n- press: press a key (Enter, Tab, Escape, etc.)\n- screenshot: capture the headless browser page, not the desktop; use value to choose the output file path\n- observe_bundle: capture URL/title/viewport, DOM summary, a11y, diagnostics, screenshot, and gate assessment\n- visual_click: browser screenshot -> Moondream point -> elementFromPoint -> human-like Playwright mouse click -> post-action screenshot\n- hardware_prerequisite: record whether a WebSerial/WebUSB/media flow has the browser capability, secure context, and required physical/user-gesture prerequisite; it never pretends hardware was exercised\n- evaluate: run JavaScript in page context\n- content: get page text content (readable, stripped)\n- dom: get raw page HTML (truncated)\n- dom_summary: compact interactive DOM summary with selectors\n- innerText: get innerText of a specific element\n- select: select dropdown option by value\n- check/uncheck: toggle checkbox\n- hover: hover over element\n- wait: wait for a selector to appear, or sleep for timeout ms when no selector is provided\n- waitForNavigation: wait for page navigation to complete\n- waitForSelector: wait for element matching selector\n- title: get page title\n- url: get current URL\n- getAttribute: get element attribute value\n- innerHTML: get element's innerHTML\n- textContent: get element's textContent\n- goBack/goForward/reload: browser navigation\n- pdf: save page as PDF\n- close: close browser session"
|
|
65001
|
+
description: "Action to perform:\n- navigate: go to a URL\n- click: click element by selector\n- fill: clear input and type text by selector, or by natural-language target when selector is absent\n- type: type text character by character into a selector, or into the currently focused element after visual_click\n- press: press a key (Enter, Tab, Escape, etc.)\n- screenshot: capture the headless browser page, not the desktop; use value to choose the output file path\n- observe_bundle: capture URL/title/viewport, DOM summary, a11y, diagnostics, screenshot, and gate assessment\n- observe_window: keep the current browser/page alive for observation_ms, then return only diagnostics emitted during that time window plus DOM/screenshot evidence\n- validate_lifecycle: start a fresh headed browser by default, clear diagnostics, navigate to url, hold it for observation_ms, and fail on delayed console/page/network errors; use this for GUI/GPU/WebGL validation\n- visual_click: browser screenshot -> Moondream point -> elementFromPoint -> human-like Playwright mouse click -> post-action screenshot\n- hardware_prerequisite: record whether a WebSerial/WebUSB/media flow has the browser capability, secure context, and required physical/user-gesture prerequisite; it never pretends hardware was exercised\n- evaluate: run JavaScript in page context\n- content: get page text content (readable, stripped)\n- dom: get raw page HTML (truncated)\n- dom_summary: compact interactive DOM summary with selectors\n- innerText: get innerText of a specific element\n- select: select dropdown option by value\n- check/uncheck: toggle checkbox\n- hover: hover over element\n- wait: wait for a selector to appear, or sleep for timeout ms when no selector is provided\n- waitForNavigation: wait for page navigation to complete\n- waitForSelector: wait for element matching selector\n- title: get page title\n- url: get current URL\n- getAttribute: get element attribute value\n- innerHTML: get element's innerHTML\n- textContent: get element's textContent\n- goBack/goForward/reload: browser navigation\n- pdf: save page as PDF\n- close: close browser session"
|
|
64833
65002
|
},
|
|
64834
65003
|
url: {
|
|
64835
65004
|
type: "string",
|
|
@@ -64895,6 +65064,14 @@ var init_playwright_browser = __esm({
|
|
|
64895
65064
|
type: "number",
|
|
64896
65065
|
description: "Milliseconds to wait for expect after the action (defaults to timeout)."
|
|
64897
65066
|
},
|
|
65067
|
+
observation_ms: {
|
|
65068
|
+
type: "number",
|
|
65069
|
+
description: "Milliseconds to keep the instantiated page alive while collecting delayed diagnostics. Defaults to 8000 for validate_lifecycle and 5000 for observe_window; maximum 120000."
|
|
65070
|
+
},
|
|
65071
|
+
start_delay_ms: {
|
|
65072
|
+
type: "number",
|
|
65073
|
+
description: "Optional delay before opening an observe_window diagnostic window. Use this only when the requested lifecycle has an explicit warm-up phase; maximum 60000."
|
|
65074
|
+
},
|
|
64898
65075
|
hardware_capability: {
|
|
64899
65076
|
type: "string",
|
|
64900
65077
|
enum: ["web_serial", "web_usb", "camera", "microphone"],
|
|
@@ -64906,7 +65083,7 @@ var init_playwright_browser = __esm({
|
|
|
64906
65083
|
},
|
|
64907
65084
|
headless: {
|
|
64908
65085
|
type: "boolean",
|
|
64909
|
-
description: "Launch mode for a new browser session.
|
|
65086
|
+
description: "Launch mode for a new browser session. Normal actions default to true; validate_lifecycle defaults to false. For GUI/GPU/WebGL claims, set false explicitly. A headless result cannot verify headed graphics behavior."
|
|
64910
65087
|
},
|
|
64911
65088
|
force_new: {
|
|
64912
65089
|
type: "boolean",
|
|
@@ -64948,8 +65125,12 @@ var init_playwright_browser = __esm({
|
|
|
64948
65125
|
const expectationTimeout = typeof args.expect_timeout === "number" ? Math.max(1, Math.min(12e4, Math.round(args.expect_timeout))) : timeout2;
|
|
64949
65126
|
const width = typeof args.width === "number" ? Math.max(320, Math.min(3840, Math.round(args.width))) : void 0;
|
|
64950
65127
|
const height = typeof args.height === "number" ? Math.max(240, Math.min(2160, Math.round(args.height))) : void 0;
|
|
64951
|
-
const
|
|
64952
|
-
const
|
|
65128
|
+
const requestedHeadless = asOptionalBoolean(args.headless);
|
|
65129
|
+
const validatesFullLifecycle = action === "validate_lifecycle";
|
|
65130
|
+
const headless = requestedHeadless ?? (validatesFullLifecycle ? false : void 0);
|
|
65131
|
+
const forceNew = asOptionalBoolean(args.force_new) === true || validatesFullLifecycle;
|
|
65132
|
+
const observationMs = typeof args.observation_ms === "number" ? Math.max(0, Math.min(12e4, Math.round(args.observation_ms))) : validatesFullLifecycle ? 8e3 : 5e3;
|
|
65133
|
+
const startDelayMs = typeof args.start_delay_ms === "number" ? Math.max(0, Math.min(6e4, Math.round(args.start_delay_ms))) : 0;
|
|
64953
65134
|
const visualTarget = typeof args.target === "string" && args.target.trim() ? args.target.trim() : typeof args.text === "string" && args.text.trim() ? args.text.trim() : "";
|
|
64954
65135
|
const preferredVisionModel = normalizeVisionModelName(args.vision_model);
|
|
64955
65136
|
const delayMs = typeof args.delay_ms === "number" ? Math.max(0, Math.min(3e4, Math.round(args.delay_ms))) : 700;
|
|
@@ -64964,6 +65145,9 @@ var init_playwright_browser = __esm({
|
|
|
64964
65145
|
durationMs: Date.now() - start2
|
|
64965
65146
|
};
|
|
64966
65147
|
}
|
|
65148
|
+
if (headless === false && !hasGraphicalBrowserDisplay()) {
|
|
65149
|
+
return fail("Headed Chromium was required, but no graphical DISPLAY or WAYLAND_DISPLAY is available. Report headed GUI/GPU validation as blocked; do not substitute a clean headless run.", start2);
|
|
65150
|
+
}
|
|
64967
65151
|
const err = await ensureBrowser({ headless, forceNew });
|
|
64968
65152
|
if (err)
|
|
64969
65153
|
return {
|
|
@@ -65689,7 +65873,14 @@ ${JSON.stringify(data, null, 2)}`, start2);
|
|
|
65689
65873
|
}
|
|
65690
65874
|
return fail(`viewport: provide "WxH" (e.g. "375x667") or a Playwright device name (e.g. "iPhone 13")`, start2);
|
|
65691
65875
|
}
|
|
65692
|
-
case "
|
|
65876
|
+
case "validate_lifecycle": {
|
|
65877
|
+
if (!url)
|
|
65878
|
+
return fail("url is required", start2);
|
|
65879
|
+
try {
|
|
65880
|
+
await validateNetworkEgressUrl(url, { allowLoopback: true });
|
|
65881
|
+
} catch (err2) {
|
|
65882
|
+
return fail(networkEgressErrorMessage(err2), start2);
|
|
65883
|
+
}
|
|
65693
65884
|
if (width || height) {
|
|
65694
65885
|
const current = page.viewportSize?.() ?? {
|
|
65695
65886
|
width: 1280,
|
|
@@ -65700,87 +65891,107 @@ ${JSON.stringify(data, null, 2)}`, start2);
|
|
|
65700
65891
|
height: height ?? current.height ?? 720
|
|
65701
65892
|
});
|
|
65702
65893
|
}
|
|
65703
|
-
|
|
65704
|
-
const
|
|
65705
|
-
|
|
65706
|
-
|
|
65707
|
-
|
|
65708
|
-
})()`);
|
|
65709
|
-
const summary = downsampleDom(html);
|
|
65710
|
-
lastDomSummarySelectors = extractDomSummarySelectors(summary);
|
|
65711
|
-
const screenshotPath = saveBuffer(outputPath3 || defaultArtifactPath("observe", "png"), await page.screenshot({ fullPage: args.full_page === true }));
|
|
65712
|
-
const viewport = page.viewportSize?.() ?? { width: 0, height: 0 };
|
|
65713
|
-
const gate = classifyBrowserGate({
|
|
65714
|
-
url: page.url(),
|
|
65715
|
-
html,
|
|
65716
|
-
text: String(readableText ?? ""),
|
|
65717
|
-
network: networkBuffer,
|
|
65718
|
-
errors: errorBuffer
|
|
65894
|
+
clearDiagnosticBuffers();
|
|
65895
|
+
const cursor = captureBrowserDiagnosticCursor();
|
|
65896
|
+
await page.goto(url, {
|
|
65897
|
+
waitUntil: "domcontentloaded",
|
|
65898
|
+
timeout: timeout2
|
|
65719
65899
|
});
|
|
65720
|
-
|
|
65721
|
-
|
|
65722
|
-
const
|
|
65723
|
-
|
|
65724
|
-
|
|
65725
|
-
|
|
65726
|
-
|
|
65727
|
-
|
|
65728
|
-
|
|
65729
|
-
|
|
65730
|
-
|
|
65731
|
-
|
|
65732
|
-
|
|
65733
|
-
|
|
65734
|
-
|
|
65735
|
-
}
|
|
65736
|
-
|
|
65737
|
-
|
|
65900
|
+
let expectationSatisfied;
|
|
65901
|
+
let expectationError;
|
|
65902
|
+
const expectationProbe = expectation ? waitForBrowserExpectation(page, expectation, Math.min(expectationTimeout, Math.max(1, observationMs))).then(() => {
|
|
65903
|
+
expectationSatisfied = true;
|
|
65904
|
+
}).catch((err2) => {
|
|
65905
|
+
expectationSatisfied = false;
|
|
65906
|
+
expectationError = err2 instanceof Error ? err2.message : String(err2);
|
|
65907
|
+
}) : Promise.resolve();
|
|
65908
|
+
await Promise.all([
|
|
65909
|
+
page.waitForTimeout(observationMs),
|
|
65910
|
+
expectationProbe
|
|
65911
|
+
]);
|
|
65912
|
+
if (expectation && expectationSatisfied === true && !await browserExpectationIsVisible(page, expectation)) {
|
|
65913
|
+
expectationSatisfied = false;
|
|
65914
|
+
expectationError = "The declared postcondition was visible during the window but was not visible at the end of it.";
|
|
65915
|
+
}
|
|
65916
|
+
return captureBrowserObservation({
|
|
65917
|
+
pageHandle: page,
|
|
65918
|
+
action: "validate_lifecycle",
|
|
65919
|
+
startMs: start2,
|
|
65920
|
+
outputPath: outputPath3,
|
|
65921
|
+
fullPage: args.full_page === true,
|
|
65922
|
+
cursor,
|
|
65923
|
+
requestedObservationMs: observationMs,
|
|
65924
|
+
expectation,
|
|
65925
|
+
expectationSatisfied,
|
|
65926
|
+
expectationError,
|
|
65927
|
+
failOnRuntimeErrors: true
|
|
65928
|
+
});
|
|
65929
|
+
}
|
|
65930
|
+
case "observe_window": {
|
|
65931
|
+
if (startDelayMs > 0)
|
|
65932
|
+
await page.waitForTimeout(startDelayMs);
|
|
65933
|
+
if (width || height) {
|
|
65934
|
+
const current = page.viewportSize?.() ?? {
|
|
65935
|
+
width: 1280,
|
|
65936
|
+
height: 720
|
|
65937
|
+
};
|
|
65938
|
+
await page.setViewportSize({
|
|
65939
|
+
width: width ?? current.width ?? 1280,
|
|
65940
|
+
height: height ?? current.height ?? 720
|
|
65941
|
+
});
|
|
65942
|
+
}
|
|
65943
|
+
const cursor = captureBrowserDiagnosticCursor();
|
|
65944
|
+
let expectationSatisfied;
|
|
65945
|
+
let expectationError;
|
|
65946
|
+
const expectationProbe = expectation ? waitForBrowserExpectation(page, expectation, Math.min(expectationTimeout, Math.max(1, observationMs))).then(() => {
|
|
65947
|
+
expectationSatisfied = true;
|
|
65948
|
+
}).catch((err2) => {
|
|
65949
|
+
expectationSatisfied = false;
|
|
65950
|
+
expectationError = err2 instanceof Error ? err2.message : String(err2);
|
|
65951
|
+
}) : Promise.resolve();
|
|
65952
|
+
await Promise.all([
|
|
65953
|
+
page.waitForTimeout(observationMs),
|
|
65954
|
+
expectationProbe
|
|
65955
|
+
]);
|
|
65956
|
+
if (expectation && expectationSatisfied === true && !await browserExpectationIsVisible(page, expectation)) {
|
|
65957
|
+
expectationSatisfied = false;
|
|
65958
|
+
expectationError = "The declared postcondition was visible during the window but was not visible at the end of it.";
|
|
65959
|
+
}
|
|
65960
|
+
return captureBrowserObservation({
|
|
65961
|
+
pageHandle: page,
|
|
65962
|
+
action: "observe_window",
|
|
65963
|
+
startMs: start2,
|
|
65964
|
+
outputPath: outputPath3,
|
|
65965
|
+
fullPage: args.full_page === true,
|
|
65966
|
+
cursor,
|
|
65967
|
+
requestedObservationMs: observationMs,
|
|
65968
|
+
expectation,
|
|
65969
|
+
expectationSatisfied,
|
|
65970
|
+
expectationError,
|
|
65971
|
+
failOnRuntimeErrors: true
|
|
65972
|
+
});
|
|
65973
|
+
}
|
|
65974
|
+
case "observe_bundle": {
|
|
65975
|
+
if (width || height) {
|
|
65976
|
+
const current = page.viewportSize?.() ?? {
|
|
65977
|
+
width: 1280,
|
|
65978
|
+
height: 720
|
|
65979
|
+
};
|
|
65980
|
+
await page.setViewportSize({
|
|
65981
|
+
width: width ?? current.width ?? 1280,
|
|
65982
|
+
height: height ?? current.height ?? 720
|
|
65983
|
+
});
|
|
65984
|
+
}
|
|
65985
|
+
return captureBrowserObservation({
|
|
65986
|
+
pageHandle: page,
|
|
65738
65987
|
action: "observe_bundle",
|
|
65739
|
-
|
|
65740
|
-
|
|
65741
|
-
|
|
65742
|
-
|
|
65743
|
-
|
|
65744
|
-
|
|
65745
|
-
title: bundle.title,
|
|
65746
|
-
domSummaryHash: sha256Text(summary),
|
|
65747
|
-
readableTextHash: sha256Text(String(readableText ?? "")),
|
|
65748
|
-
visibleTextExcerpt: clipEvidenceText(readableText, 500),
|
|
65749
|
-
consoleErrorCount: bundle.consoleErrors.length,
|
|
65750
|
-
pageErrorCount: errors.length,
|
|
65751
|
-
networkFailureCount: networkFailures.length,
|
|
65752
|
-
gateKind: gate.kind,
|
|
65753
|
-
gateConfidence: gate.confidence,
|
|
65754
|
-
gateEvidence: gate.evidence,
|
|
65755
|
-
metadata: { mode: bundle.mode, engine: "playwright" }
|
|
65756
|
-
}),
|
|
65757
|
-
verification: {
|
|
65758
|
-
status: gate.kind === "captcha" || gate.kind === "bot_challenge" ? "blocked" : "inconclusive",
|
|
65759
|
-
confidence: gate.kind === "captcha" || gate.kind === "bot_challenge" ? gate.confidence : 0.5,
|
|
65760
|
-
reason: gate.kind === "none" ? "Fresh browser observation captured; no specific completion claim was evaluated." : `Fresh browser observation captured with gate=${gate.kind}.`
|
|
65761
|
-
}
|
|
65988
|
+
startMs: start2,
|
|
65989
|
+
outputPath: outputPath3,
|
|
65990
|
+
fullPage: args.full_page === true,
|
|
65991
|
+
requestedObservationMs: 0,
|
|
65992
|
+
expectation,
|
|
65993
|
+
failOnRuntimeErrors: false
|
|
65762
65994
|
});
|
|
65763
|
-
const modelBundle = { ...bundle, evidenceEvents: [evidenceEvent] };
|
|
65764
|
-
return {
|
|
65765
|
-
success: true,
|
|
65766
|
-
output: [
|
|
65767
|
-
"Browser observation bundle",
|
|
65768
|
-
`URL: ${bundle.url}`,
|
|
65769
|
-
`Title: ${bundle.title}`,
|
|
65770
|
-
`Mode: ${bundle.mode}`,
|
|
65771
|
-
`Viewport: ${viewport.width}x${viewport.height}`,
|
|
65772
|
-
`Screenshot: ${screenshotPath}`,
|
|
65773
|
-
`Gate: ${gate.kind} (${gate.confidence.toFixed(2)})${gate.evidence.length ? ` — ${gate.evidence.join("; ")}` : ""}`,
|
|
65774
|
-
`Console warnings/errors: ${bundle.consoleErrors.length}`,
|
|
65775
|
-
`Network failures: ${networkFailures.length}`,
|
|
65776
|
-
"",
|
|
65777
|
-
"--- DOM Summary ---",
|
|
65778
|
-
summary.slice(0, 6e3)
|
|
65779
|
-
].join("\n"),
|
|
65780
|
-
llmContent: JSON.stringify(modelBundle, null, 2),
|
|
65781
|
-
evidenceEvents: [evidenceEvent],
|
|
65782
|
-
durationMs: Date.now() - start2
|
|
65783
|
-
};
|
|
65784
65995
|
}
|
|
65785
65996
|
case "visual_click": {
|
|
65786
65997
|
if (!visualTarget)
|
|
@@ -66068,7 +66279,9 @@ ${JSON.stringify(data, null, 2)}`, start2);
|
|
|
66068
66279
|
].filter(Boolean).join("\n"),
|
|
66069
66280
|
llmContent: JSON.stringify(bundle, null, 2),
|
|
66070
66281
|
evidenceEvents: [evidenceEvent],
|
|
66071
|
-
...expectationSatisfied === false ? {
|
|
66282
|
+
...expectationSatisfied === false ? {
|
|
66283
|
+
error: `Postcondition not observed: ${expectation}. ${expectationError?.slice(0, 500) ?? ""}`.trim()
|
|
66284
|
+
} : {},
|
|
66072
66285
|
durationMs: Date.now() - start2
|
|
66073
66286
|
};
|
|
66074
66287
|
}
|
|
@@ -659396,13 +659609,13 @@ ${context2 ?? ""}`;
|
|
|
659396
659609
|
critique2 = this._buildVisualAdversaryCritique({
|
|
659397
659610
|
evidence: `${inconclusiveEvent.tool}/${inconclusiveEvent.action} produced only inconclusive proof: ${inconclusiveEvent.verification?.reason ?? "no reason"}`,
|
|
659398
659611
|
hypothesis: "The browser action may have worked, but the current evidence is not strong enough to prove the user-visible event.",
|
|
659399
|
-
correctiveAction: 'Run playwright_browser({action:"
|
|
659612
|
+
correctiveAction: 'Run playwright_browser({action:"observe_window", observation_ms:5000, expect:"..."}) after the action. Verify the expected state plus window-scoped console, page, network, DOM, and screenshot evidence.'
|
|
659400
659613
|
});
|
|
659401
659614
|
} else if (events.length === 0) {
|
|
659402
659615
|
critique2 = this._buildVisualAdversaryCritique({
|
|
659403
659616
|
evidence: `${toolName} changed ${surface} state but did not return a structured evidence event.`,
|
|
659404
659617
|
hypothesis: "The agent may be acting from stale visual state after a click/type/submit/navigation action.",
|
|
659405
|
-
correctiveAction: surface === "browser" ? 'Run playwright_browser({action:"
|
|
659618
|
+
correctiveAction: surface === "browser" ? 'Run playwright_browser({action:"observe_window", observation_ms:5000, expect:"..."}) before claiming success. Use a fresh headed validate_lifecycle run when the claim concerns GUI, GPU, WebGL, WebGPU, canvas, or animation behavior.' : 'Run vision_action_loop({action:"observe", goal:"..."}) or desktop_describe before claiming success.'
|
|
659406
659619
|
});
|
|
659407
659620
|
}
|
|
659408
659621
|
if (critique2) {
|
|
@@ -678995,6 +679208,9 @@ Example: ${tool.name}(${JSON.stringify(meta.examples[0].args ?? {})})` : "";
|
|
|
678995
679208
|
"file_explore",
|
|
678996
679209
|
"web_search",
|
|
678997
679210
|
"web_fetch",
|
|
679211
|
+
// Browser evidence must be available without a lexical relevance guess.
|
|
679212
|
+
// Surfaces that do not register this tool do not expose it.
|
|
679213
|
+
"playwright_browser",
|
|
678998
679214
|
"memory_read",
|
|
678999
679215
|
"memory_write",
|
|
679000
679216
|
"working_notes",
|
|
@@ -679112,11 +679328,12 @@ Example: ${tool.name}(${JSON.stringify(meta.examples[0].args ?? {})})` : "";
|
|
|
679112
679328
|
const compressDesc = true;
|
|
679113
679329
|
const defs = dedupedInline.map((tool) => {
|
|
679114
679330
|
const desc = getDesc(tool);
|
|
679331
|
+
const modelFacingDescription = tool.modelFacingSummary?.trim();
|
|
679115
679332
|
return {
|
|
679116
679333
|
type: "function",
|
|
679117
679334
|
function: {
|
|
679118
679335
|
name: tool.name,
|
|
679119
|
-
description: compressDesc ? (desc.split(/\.\s/)[0]?.slice(0, 120) ?? desc.slice(0, 120)) + "." : desc,
|
|
679336
|
+
description: modelFacingDescription ? modelFacingDescription.slice(0, 420) : compressDesc ? (desc.split(/\.\s/)[0]?.slice(0, 120) ?? desc.slice(0, 120)) + "." : desc,
|
|
679120
679337
|
parameters: this._publicToolParameters(tool.parameters)
|
|
679121
679338
|
}
|
|
679122
679339
|
};
|
|
@@ -686617,11 +686834,11 @@ var init_workerSkillStandard = __esm({
|
|
|
686617
686834
|
{
|
|
686618
686835
|
stepNumber: 3,
|
|
686619
686836
|
title: "Validate every requested browser flow in one Playwright session",
|
|
686620
|
-
description: "Use playwright_browser
|
|
686837
|
+
description: "Use playwright_browser validate_lifecycle -> action -> state-based postcondition -> observe_window. Set a finite observation_ms so delayed errors can surface. For GUI, GPU, WebGL, WebGPU, canvas, or animation claims, use a fresh headed browser. A clean headless load is not headed rendering evidence. Prefer data-testid or role/name locators. A click receipt or screenshot alone is not a pass. Re-query after a detached-element error; record each requested interaction as passed, failed, blocked, not_applicable, or inconclusive with the concrete state and diagnostics.",
|
|
686621
686838
|
tools: ["playwright_browser"],
|
|
686622
686839
|
skills: ["browser-interaction-validation"],
|
|
686623
686840
|
output: "One claim-scoped browser evidence entry per requested interaction, separate from static test evidence",
|
|
686624
|
-
verification: "Every interaction has an observed postcondition or a precise failed/blocked/not-applicable outcome; page errors, console errors,
|
|
686841
|
+
verification: "Every interaction has an observed postcondition or a precise failed/blocked/not-applicable outcome; delayed page errors, console errors, failed network requests, DOM state, and screenshots are reviewed from the relevant observation window"
|
|
686625
686842
|
},
|
|
686626
686843
|
{
|
|
686627
686844
|
stepNumber: 4,
|
|
@@ -692429,10 +692646,12 @@ FOR SCREEN / DESKTOP UI (what is on this computer display, clicking, navigating)
|
|
|
692429
692646
|
desktop_click({ target: "element" }) - Click a UI element by description.
|
|
692430
692647
|
vision_action_loop({ goal: "task", action: "observe" }) - Persistent screenshot/OCR/point/action loop with previewable screenshots.
|
|
692431
692648
|
|
|
692432
|
-
FOR BROWSER PAGE / WEB GUI RENDERS
|
|
692649
|
+
FOR BROWSER PAGE / WEB GUI RENDERS:
|
|
692433
692650
|
browser_action({ action: "screenshot", width: 1280, height: 720, output_path: ".omnius/browser/page.png" }) - Render the current headless browser page and return an image input.
|
|
692434
692651
|
playwright_browser({ action: "viewport", text: "1280x720" }) then playwright_browser({ action: "screenshot", value: ".omnius/browser/page.png" }) - Playwright diagnostic browser capture.
|
|
692435
|
-
playwright_browser({ action: "
|
|
692652
|
+
playwright_browser({ action: "validate_lifecycle", url: "http://127.0.0.1:3000", headless: false, force_new: true, observation_ms: 8000, expect: "text=Ready" }) - Start diagnostics before navigation and hold a fresh GUI browser open for delayed rendering failures.
|
|
692653
|
+
playwright_browser({ action: "observe_window", observation_ms: 5000, expect: "text=Updated" }) - Keep the current page alive and return diagnostics emitted during the post-action window.
|
|
692654
|
+
playwright_browser({ action: "observe_bundle" }) - Capture current session diagnostics and page state when a timed window is not required.
|
|
692436
692655
|
playwright_browser({ action: "visual_click", target: "button or field", vision_model: "moondream" }) - Browser screenshot -> Moondream point -> DOM candidate -> click -> post-action screenshot.
|
|
692437
692656
|
|
|
692438
692657
|
RULES:
|
|
@@ -692441,6 +692660,7 @@ RULES:
|
|
|
692441
692660
|
- For seeing the screen, use screenshot, desktop_describe, or vision_action_loop, not camera_capture.
|
|
692442
692661
|
- For image files, use image_read or vision, not desktop_describe.
|
|
692443
692662
|
- For browser GUI action when selectors are unknown, use playwright_browser visual_click before desktop-level clicking.
|
|
692663
|
+
- Match the browser mode to the claim. A clean immediate or headless run does not verify delayed headed GPU/WebGL behavior.
|
|
692444
692664
|
- Do not claim you cannot see visual content until the relevant visual tool has failed.
|
|
692445
692665
|
</visual-and-sensor-tools>`;
|
|
692446
692666
|
}
|
|
@@ -701137,6 +701357,7 @@ function adaptExecutionTool(tool, options2 = {}) {
|
|
|
701137
701357
|
name: tool.name,
|
|
701138
701358
|
aliases: tool.aliases,
|
|
701139
701359
|
description: tool.description,
|
|
701360
|
+
modelFacingSummary: tool.modelFacingSummary,
|
|
701140
701361
|
parameters: tool.parameters,
|
|
701141
701362
|
inputSchema: tool.inputSchema,
|
|
701142
701363
|
maxResultSizeChars: tool.maxResultSizeChars,
|
|
@@ -781438,6 +781659,30 @@ function parseTelegramSilentReflectionNotes(text3) {
|
|
|
781438
781659
|
}
|
|
781439
781660
|
return null;
|
|
781440
781661
|
}
|
|
781662
|
+
function telegramInteractionDecisionResponseFormatForPacket(packet) {
|
|
781663
|
+
const format3 = structuredClone(
|
|
781664
|
+
TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT
|
|
781665
|
+
);
|
|
781666
|
+
const properties = format3.json_schema.schema.properties;
|
|
781667
|
+
properties.input_id = {
|
|
781668
|
+
type: "string",
|
|
781669
|
+
enum: [packet.inputId]
|
|
781670
|
+
};
|
|
781671
|
+
properties.addressed_actor_keys = {
|
|
781672
|
+
type: "array",
|
|
781673
|
+
items: { type: "string", enum: packet.actorKeys },
|
|
781674
|
+
maxItems: 12
|
|
781675
|
+
};
|
|
781676
|
+
properties.evidence_ids = {
|
|
781677
|
+
type: "array",
|
|
781678
|
+
items: {
|
|
781679
|
+
type: "string",
|
|
781680
|
+
enum: packet.evidence.map((entry) => entry.id)
|
|
781681
|
+
},
|
|
781682
|
+
maxItems: 16
|
|
781683
|
+
};
|
|
781684
|
+
return format3;
|
|
781685
|
+
}
|
|
781441
781686
|
function extractPartialTelegramReplyJson(buffer2) {
|
|
781442
781687
|
const stripped = stripTelegramHiddenThinking(buffer2).trimStart();
|
|
781443
781688
|
if (!stripped.startsWith("{")) {
|
|
@@ -786166,8 +786411,8 @@ ${context2}` : context2;
|
|
|
786166
786411
|
}
|
|
786167
786412
|
await this.transitionTelegramIntake(
|
|
786168
786413
|
intakeRecord,
|
|
786169
|
-
"consumed",
|
|
786170
|
-
"attention router retained active-runner input as context without reply authority",
|
|
786414
|
+
decision2.source === "inference-unavailable" ? "failed" : "consumed",
|
|
786415
|
+
decision2.source === "inference-unavailable" ? "attention router could not produce a valid input-bound decision" : "attention router retained active-runner input as context without reply authority",
|
|
786171
786416
|
{ runId: sameRunner ? currentSubAgent.runId : expectedSubAgent.runId }
|
|
786172
786417
|
);
|
|
786173
786418
|
return;
|
|
@@ -789246,6 +789491,8 @@ ${antecedents.join("\n")}` : "Immediate antecedents: none.",
|
|
|
789246
789491
|
scenarioConfidence: decision2.scenarioConfidence,
|
|
789247
789492
|
scenarioObjective: decision2.scenarioObjective,
|
|
789248
789493
|
scenarioStateLoop: decision2.scenarioStateLoop,
|
|
789494
|
+
diagnosticNote: decision2.diagnosticNote,
|
|
789495
|
+
validationIssueCodes: decision2.validationIssueCodes,
|
|
789249
789496
|
salienceSignals,
|
|
789250
789497
|
self: this.telegramSelfSocialActorInput(),
|
|
789251
789498
|
daydreamOpportunities
|
|
@@ -791646,10 +791893,7 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
791646
791893
|
id2,
|
|
791647
791894
|
`broker queue admission deadline expired for ${deadline.request_id}${queueSummary ? ` (${queueSummary})` : ""}; re-entering after ${(delayMs / 1e3).toFixed(1)}s, attempt ${brokerQueueRetryAttempt}`
|
|
791648
791895
|
);
|
|
791649
|
-
await this.waitForTelegramBrokerQueueRetry(
|
|
791650
|
-
delayMs,
|
|
791651
|
-
lifecycleSignal
|
|
791652
|
-
);
|
|
791896
|
+
await this.waitForTelegramBrokerQueueRetry(delayMs, lifecycleSignal);
|
|
791653
791897
|
}
|
|
791654
791898
|
}
|
|
791655
791899
|
const usage = result.usage;
|
|
@@ -792032,6 +792276,15 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792032
792276
|
getTelegramThinkingVisible() {
|
|
792033
792277
|
return this.telegramThinkingVisible;
|
|
792034
792278
|
}
|
|
792279
|
+
telegramMentionActorIsSelf(actor) {
|
|
792280
|
+
const selfUserId = this.currentTelegramBotUserId();
|
|
792281
|
+
if (selfUserId !== void 0 && actor.userId !== void 0 && actor.userId === selfUserId) {
|
|
792282
|
+
return true;
|
|
792283
|
+
}
|
|
792284
|
+
const selfUsername = this.state.botUsername.trim().replace(/^@/, "").toLowerCase();
|
|
792285
|
+
const actorUsername = actor.username?.trim().replace(/^@/, "").toLowerCase();
|
|
792286
|
+
return Boolean(selfUsername && actorUsername === selfUsername);
|
|
792287
|
+
}
|
|
792035
792288
|
buildTelegramInteractionEvidencePacket(msg) {
|
|
792036
792289
|
const sessionKey = this.sessionKeyForMessage(msg);
|
|
792037
792290
|
const selfActorKey = telegramSocialActorKey(
|
|
@@ -792057,7 +792310,7 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792057
792310
|
];
|
|
792058
792311
|
const mentionedActors = msg.mentionedActors ?? (msg.mentionedUsernames ?? []).map((username) => ({ username }));
|
|
792059
792312
|
mentionedActors.forEach((actor, index) => {
|
|
792060
|
-
const actorKey = telegramSocialActorKey(actor);
|
|
792313
|
+
const actorKey = this.telegramMentionActorIsSelf(actor) ? selfActorKey : telegramSocialActorKey(actor);
|
|
792061
792314
|
if (actorKey === "unknown") return;
|
|
792062
792315
|
actorKeys.add(actorKey);
|
|
792063
792316
|
evidence.push({
|
|
@@ -792097,33 +792350,103 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792097
792350
|
evidence
|
|
792098
792351
|
};
|
|
792099
792352
|
}
|
|
792100
|
-
|
|
792101
|
-
|
|
792102
|
-
if (!decision2.
|
|
792353
|
+
validateTelegramInteractionDecisionDetailed(decision2, packet) {
|
|
792354
|
+
const issues = [];
|
|
792355
|
+
if (!decision2.inputId) {
|
|
792356
|
+
issues.push({
|
|
792357
|
+
code: "missing_input_id",
|
|
792358
|
+
message: `input_id must be ${JSON.stringify(packet.inputId)}.`
|
|
792359
|
+
});
|
|
792360
|
+
} else if (decision2.inputId !== packet.inputId) {
|
|
792361
|
+
issues.push({
|
|
792362
|
+
code: "input_id_mismatch",
|
|
792363
|
+
message: `input_id must be ${JSON.stringify(packet.inputId)}.`
|
|
792364
|
+
});
|
|
792365
|
+
}
|
|
792366
|
+
if (!decision2.selfRole) {
|
|
792367
|
+
issues.push({
|
|
792368
|
+
code: "missing_self_role",
|
|
792369
|
+
message: "self_role is required."
|
|
792370
|
+
});
|
|
792371
|
+
}
|
|
792372
|
+
if (!decision2.replyBasis) {
|
|
792373
|
+
issues.push({
|
|
792374
|
+
code: "missing_reply_basis",
|
|
792375
|
+
message: "reply_basis is required."
|
|
792376
|
+
});
|
|
792377
|
+
}
|
|
792103
792378
|
const addressed = decision2.addressedActorKeys ?? [];
|
|
792104
792379
|
const evidenceIds = decision2.evidenceIds ?? [];
|
|
792105
792380
|
const allowedActors = new Set(packet.actorKeys);
|
|
792106
792381
|
const allowedEvidence = new Set(packet.evidence.map((entry) => entry.id));
|
|
792107
|
-
|
|
792108
|
-
if (
|
|
792382
|
+
const unknownActors = addressed.filter((key) => !allowedActors.has(key));
|
|
792383
|
+
if (unknownActors.length > 0) {
|
|
792384
|
+
issues.push({
|
|
792385
|
+
code: "unknown_addressed_actor",
|
|
792386
|
+
message: `addressed_actor_keys contains unknown values ${JSON.stringify(unknownActors)}. Allowed values: ${JSON.stringify(packet.actorKeys)}.`
|
|
792387
|
+
});
|
|
792388
|
+
}
|
|
792389
|
+
const unknownEvidence = evidenceIds.filter(
|
|
792390
|
+
(id2) => !allowedEvidence.has(id2)
|
|
792391
|
+
);
|
|
792392
|
+
if (unknownEvidence.length > 0) {
|
|
792393
|
+
issues.push({
|
|
792394
|
+
code: "unknown_evidence_id",
|
|
792395
|
+
message: `evidence_ids contains unknown values ${JSON.stringify(unknownEvidence)}. Allowed values: ${JSON.stringify([...allowedEvidence])}.`
|
|
792396
|
+
});
|
|
792397
|
+
}
|
|
792109
792398
|
if (decision2.selfRole === "addressee") {
|
|
792110
|
-
if (!addressed.includes(packet.selfActorKey))
|
|
792399
|
+
if (!addressed.includes(packet.selfActorKey)) {
|
|
792400
|
+
issues.push({
|
|
792401
|
+
code: "addressee_missing_self_actor",
|
|
792402
|
+
message: `self_role=addressee requires addressed_actor_keys to include ${JSON.stringify(packet.selfActorKey)}.`
|
|
792403
|
+
});
|
|
792404
|
+
}
|
|
792111
792405
|
} else if (decision2.selfRole === "observer") {
|
|
792112
|
-
if (addressed.includes(packet.selfActorKey))
|
|
792406
|
+
if (addressed.includes(packet.selfActorKey)) {
|
|
792407
|
+
issues.push({
|
|
792408
|
+
code: "observer_addresses_self",
|
|
792409
|
+
message: `self_role=observer cannot address ${JSON.stringify(packet.selfActorKey)}.`
|
|
792410
|
+
});
|
|
792411
|
+
}
|
|
792113
792412
|
}
|
|
792114
792413
|
if (decision2.shouldReply) {
|
|
792115
|
-
if (decision2.replyBasis === "none" || decision2.replyBasis === "uncertain"
|
|
792116
|
-
|
|
792414
|
+
if (decision2.replyBasis === "none" || decision2.replyBasis === "uncertain") {
|
|
792415
|
+
issues.push({
|
|
792416
|
+
code: "reply_basis_not_authorized",
|
|
792417
|
+
message: "should_reply=true requires reply_basis direct_turn, ongoing_self_task, or social_intervention."
|
|
792418
|
+
});
|
|
792117
792419
|
}
|
|
792118
|
-
if (
|
|
792119
|
-
|
|
792420
|
+
if (evidenceIds.length === 0) {
|
|
792421
|
+
issues.push({
|
|
792422
|
+
code: "reply_missing_evidence",
|
|
792423
|
+
message: "should_reply=true requires at least one evidence_id."
|
|
792424
|
+
});
|
|
792425
|
+
}
|
|
792426
|
+
if (decision2.replyBasis === "direct_turn") {
|
|
792427
|
+
if (decision2.selfRole !== "addressee") {
|
|
792428
|
+
issues.push({
|
|
792429
|
+
code: "direct_turn_self_not_addressee",
|
|
792430
|
+
message: "reply_basis=direct_turn requires self_role=addressee."
|
|
792431
|
+
});
|
|
792432
|
+
}
|
|
792433
|
+
if (!addressed.includes(packet.selfActorKey)) {
|
|
792434
|
+
issues.push({
|
|
792435
|
+
code: "direct_turn_missing_self_actor",
|
|
792436
|
+
message: `reply_basis=direct_turn requires addressed_actor_keys to include ${JSON.stringify(packet.selfActorKey)}.`
|
|
792437
|
+
});
|
|
792438
|
+
}
|
|
792120
792439
|
}
|
|
792121
792440
|
if (decision2.replyBasis === "ongoing_self_task" && !packet.evidence.some(
|
|
792122
792441
|
(entry) => entry.kind === "active_task" && evidenceIds.includes(entry.id)
|
|
792123
792442
|
)) {
|
|
792124
|
-
|
|
792443
|
+
issues.push({
|
|
792444
|
+
code: "ongoing_task_missing_active_task_evidence",
|
|
792445
|
+
message: "reply_basis=ongoing_self_task requires the active_task evidence ID."
|
|
792446
|
+
});
|
|
792125
792447
|
}
|
|
792126
792448
|
}
|
|
792449
|
+
if (issues.length > 0) return { decision: null, issues };
|
|
792127
792450
|
const decisionId = `tgdec-${createHash74("sha256").update(
|
|
792128
792451
|
JSON.stringify({
|
|
792129
792452
|
inputId: packet.inputId,
|
|
@@ -792135,7 +792458,30 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792135
792458
|
evidenceIds
|
|
792136
792459
|
})
|
|
792137
792460
|
).digest("hex").slice(0, 20)}`;
|
|
792138
|
-
return { ...decision2, decisionId };
|
|
792461
|
+
return { decision: { ...decision2, decisionId }, issues: [] };
|
|
792462
|
+
}
|
|
792463
|
+
validateTelegramInteractionDecision(decision2, packet) {
|
|
792464
|
+
return this.validateTelegramInteractionDecisionDetailed(decision2, packet).decision;
|
|
792465
|
+
}
|
|
792466
|
+
/**
|
|
792467
|
+
* Materialize fields that are logical consequences of the model's chosen
|
|
792468
|
+
* reply basis. The model still decides whether to reply and why. Once it
|
|
792469
|
+
* chooses direct_turn, however, asking it to repeat "self is an addressee"
|
|
792470
|
+
* in two additional fields creates three representations of one decision.
|
|
792471
|
+
* A disagreement between those copies must not spend another inference.
|
|
792472
|
+
*/
|
|
792473
|
+
normalizeTelegramInteractionDecisionImplications(decision2, packet) {
|
|
792474
|
+
if (decision2.replyBasis !== "direct_turn") return decision2;
|
|
792475
|
+
return {
|
|
792476
|
+
...decision2,
|
|
792477
|
+
addressedActorKeys: [
|
|
792478
|
+
.../* @__PURE__ */ new Set([
|
|
792479
|
+
...decision2.addressedActorKeys ?? [],
|
|
792480
|
+
packet.selfActorKey
|
|
792481
|
+
])
|
|
792482
|
+
],
|
|
792483
|
+
selfRole: "addressee"
|
|
792484
|
+
};
|
|
792139
792485
|
}
|
|
792140
792486
|
bindTrustedTelegramDecision(decision2, packet) {
|
|
792141
792487
|
const bound = {
|
|
@@ -792148,13 +792494,20 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792148
792494
|
};
|
|
792149
792495
|
return this.validateTelegramInteractionDecision(bound, packet) ?? bound;
|
|
792150
792496
|
}
|
|
792151
|
-
async retryTelegramInteractionDecisionStrict(backend, userPrompt, forcedRoute, timeoutMs, diagnostics, sessionKey = "__router__", evidencePacket) {
|
|
792497
|
+
async retryTelegramInteractionDecisionStrict(backend, userPrompt, forcedRoute, timeoutMs, diagnostics, sessionKey = "__router__", evidencePacket, validationIssues = []) {
|
|
792152
792498
|
const routeInstruction = forcedRoute ? `The operator selected Telegram mode "${forcedRoute}". The route field must be "${forcedRoute}", but should_reply must still be inferred from context.` : `Infer route live from context.`;
|
|
792153
792499
|
const retryPrompt = [
|
|
792154
792500
|
`A prior attempt failed the typed Telegram attention-decision contract and was discarded.`,
|
|
792155
792501
|
`Make a fresh model-derived attention decision from the complete clean context below.`,
|
|
792156
792502
|
`Return exactly one JSON object and no prose. No <think> tags. No commentary.`,
|
|
792157
792503
|
routeInstruction,
|
|
792504
|
+
...validationIssues.length > 0 ? [
|
|
792505
|
+
`The host rejected the prior semantic contract for these exact reasons:`,
|
|
792506
|
+
...validationIssues.map(
|
|
792507
|
+
(issue2) => `- ${issue2.code}: ${issue2.message}`
|
|
792508
|
+
),
|
|
792509
|
+
`Correct every listed issue. Do not repeat a rejected identifier.`
|
|
792510
|
+
] : [],
|
|
792158
792511
|
``,
|
|
792159
792512
|
`Required schema: ${TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA}`,
|
|
792160
792513
|
``,
|
|
@@ -792177,7 +792530,7 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792177
792530
|
maxTokens: 700,
|
|
792178
792531
|
timeoutMs: telegramRouterTimeoutMs(timeoutMs, 8e3, 15e3),
|
|
792179
792532
|
think: false,
|
|
792180
|
-
responseFormat: TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT
|
|
792533
|
+
responseFormat: evidencePacket ? telegramInteractionDecisionResponseFormatForPacket(evidencePacket) : TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT
|
|
792181
792534
|
},
|
|
792182
792535
|
diagnostics,
|
|
792183
792536
|
"router-strict-retry",
|
|
@@ -792193,11 +792546,23 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
|
|
|
792193
792546
|
defaultShouldReply: false,
|
|
792194
792547
|
requireShouldReply: true
|
|
792195
792548
|
});
|
|
792196
|
-
|
|
792549
|
+
if (parsed && evidencePacket) parsed.inputId = evidencePacket.inputId;
|
|
792550
|
+
const normalized4 = parsed && evidencePacket ? this.normalizeTelegramInteractionDecisionImplications(
|
|
792551
|
+
parsed,
|
|
792552
|
+
evidencePacket
|
|
792553
|
+
) : parsed;
|
|
792554
|
+
const validation = normalized4 && evidencePacket ? this.validateTelegramInteractionDecisionDetailed(
|
|
792555
|
+
normalized4,
|
|
792556
|
+
evidencePacket
|
|
792557
|
+
) : { decision: normalized4, issues: [] };
|
|
792558
|
+
const validated = validation.decision;
|
|
792197
792559
|
if (!validated) {
|
|
792198
792560
|
if (diagnostics) {
|
|
792199
792561
|
const cleaned = stripTelegramHiddenThinking(retryText).trim();
|
|
792200
|
-
diagnostics.strictRetryStatus = cleaned ? "unparseable" : "empty";
|
|
792562
|
+
diagnostics.strictRetryStatus = parsed && validation.issues.length > 0 ? "semantic-invalid" : cleaned ? "unparseable" : "empty";
|
|
792563
|
+
diagnostics.strictRetryValidationIssues = validation.issues.map(
|
|
792564
|
+
(issue2) => issue2.code
|
|
792565
|
+
);
|
|
792201
792566
|
}
|
|
792202
792567
|
return null;
|
|
792203
792568
|
}
|
|
@@ -792750,7 +793115,7 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792750
793115
|
maxTokens: 360,
|
|
792751
793116
|
timeoutMs: telegramRouterTimeoutMs(config.timeoutMs, 8e3, 3e4),
|
|
792752
793117
|
think: false,
|
|
792753
|
-
responseFormat:
|
|
793118
|
+
responseFormat: telegramInteractionDecisionResponseFormatForPacket(evidencePacket)
|
|
792754
793119
|
},
|
|
792755
793120
|
diagnostics,
|
|
792756
793121
|
"router",
|
|
@@ -792780,7 +793145,24 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792780
793145
|
defaultShouldReply: false,
|
|
792781
793146
|
requireShouldReply: true
|
|
792782
793147
|
});
|
|
792783
|
-
|
|
793148
|
+
if (parsed) parsed.inputId = evidencePacket.inputId;
|
|
793149
|
+
const normalized4 = parsed ? this.normalizeTelegramInteractionDecisionImplications(
|
|
793150
|
+
parsed,
|
|
793151
|
+
evidencePacket
|
|
793152
|
+
) : null;
|
|
793153
|
+
const initialValidation = normalized4 ? this.validateTelegramInteractionDecisionDetailed(
|
|
793154
|
+
normalized4,
|
|
793155
|
+
evidencePacket
|
|
793156
|
+
) : {
|
|
793157
|
+
decision: null,
|
|
793158
|
+
issues: []
|
|
793159
|
+
};
|
|
793160
|
+
if (diagnostics) {
|
|
793161
|
+
diagnostics.validationIssues = initialValidation.issues.map(
|
|
793162
|
+
(issue2) => issue2.code
|
|
793163
|
+
);
|
|
793164
|
+
}
|
|
793165
|
+
const validated = initialValidation.decision;
|
|
792784
793166
|
if (validated) {
|
|
792785
793167
|
return withRouterTelemetry(
|
|
792786
793168
|
this.applyTelegramSilentReflectionNotes(validated, reflectionNotes)
|
|
@@ -792812,7 +793194,8 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792812
793194
|
config.timeoutMs ?? 3e4,
|
|
792813
793195
|
diagnostics,
|
|
792814
793196
|
sessionKey,
|
|
792815
|
-
evidencePacket
|
|
793197
|
+
evidencePacket,
|
|
793198
|
+
initialValidation.issues
|
|
792816
793199
|
);
|
|
792817
793200
|
if (strictRetry) {
|
|
792818
793201
|
return withRouterTelemetry(
|
|
@@ -792826,20 +793209,26 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792826
793209
|
) || telegramRouterErrorLooksLikeBackendLiveness(
|
|
792827
793210
|
diagnostics.strictRetryError ?? ""
|
|
792828
793211
|
);
|
|
792829
|
-
const fallback =
|
|
792830
|
-
this.
|
|
792831
|
-
|
|
792832
|
-
|
|
792833
|
-
|
|
792834
|
-
|
|
792835
|
-
|
|
792836
|
-
|
|
792837
|
-
|
|
792838
|
-
|
|
792839
|
-
|
|
792840
|
-
|
|
792841
|
-
|
|
792842
|
-
|
|
793212
|
+
const fallback = {
|
|
793213
|
+
...this.applyTelegramSilentReflectionNotes(
|
|
793214
|
+
this.buildTelegramRouterUnavailableDecision(msg, toolContext, {
|
|
793215
|
+
reason: backendLivenessFailure ? "router recovery hit a backend liveness failure; no model-derived reply decision" : dualEmptyVisible ? "router returned no visible decision content in JSON or plain mode; no model-derived reply decision" : "router output failed the typed decision contract and the fresh retry; no model-derived reply decision",
|
|
793216
|
+
silentDisposition: reflectionNotes.silentDisposition,
|
|
793217
|
+
diagnosticNote: this.composeTelegramRouterDiagnosticNote(
|
|
793218
|
+
invalidRouterPreview,
|
|
793219
|
+
failureNarrative,
|
|
793220
|
+
backendLivenessFailure ? "router backend failed during attention-decision recovery; no usable router decision was available" : dualEmptyVisible ? "router returned no visible decision content in JSON or plain mode; fresh typed retry did not recover it" : invalidRouterPreview ? "router produced an invalid attention decision payload; the quarantined fresh retry did not recover it" : "router produced an empty attention decision payload; the fresh typed retry did not recover it",
|
|
793221
|
+
diagnostics
|
|
793222
|
+
),
|
|
793223
|
+
raw: text3
|
|
793224
|
+
}),
|
|
793225
|
+
reflectionNotes
|
|
793226
|
+
),
|
|
793227
|
+
validationIssueCodes: [
|
|
793228
|
+
...diagnostics.validationIssues ?? [],
|
|
793229
|
+
...diagnostics.strictRetryValidationIssues ?? []
|
|
793230
|
+
].filter((code8, index, all2) => all2.indexOf(code8) === index)
|
|
793231
|
+
};
|
|
792843
793232
|
return withRouterTelemetry(fallback);
|
|
792844
793233
|
} catch (err) {
|
|
792845
793234
|
if (err instanceof TelegramBridgeStoppedError) throw err;
|
|
@@ -792918,7 +793307,7 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792918
793307
|
`empty visible content after <think> strip during ${affected}`
|
|
792919
793308
|
);
|
|
792920
793309
|
}
|
|
792921
|
-
if (visibleAttempts.length > 0 && diag.strictRetryStatus !== "recovered") {
|
|
793310
|
+
if (visibleAttempts.length > 0 && (diag.validationIssues ?? []).length === 0 && diag.strictRetryStatus !== "recovered") {
|
|
792922
793311
|
parts.push(`visible router text remained unparseable`);
|
|
792923
793312
|
}
|
|
792924
793313
|
if (skippedAttempts.length > 0) {
|
|
@@ -792969,6 +793358,10 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792969
793358
|
detailParts.push(
|
|
792970
793359
|
`strict-retry: unparseable (preview="${diag.strictRetryPreview ?? ""}")`
|
|
792971
793360
|
);
|
|
793361
|
+
} else if (diag.strictRetryStatus === "semantic-invalid") {
|
|
793362
|
+
detailParts.push(
|
|
793363
|
+
`strict-retry: semantic-invalid (${(diag.strictRetryValidationIssues ?? []).join(", ") || "no issue codes"})`
|
|
793364
|
+
);
|
|
792972
793365
|
} else if (diag.strictRetryStatus === "threw") {
|
|
792973
793366
|
detailParts.push(
|
|
792974
793367
|
`strict-retry: threw (${diag.strictRetryError ?? "no detail"})`
|
|
@@ -792980,6 +793373,19 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
|
|
|
792980
793373
|
} else if (diag.strictRetryStatus === "recovered") {
|
|
792981
793374
|
detailParts.push(`strict-retry: recovered`);
|
|
792982
793375
|
}
|
|
793376
|
+
if ((diag.validationIssues ?? []).length > 0) {
|
|
793377
|
+
parts.push(
|
|
793378
|
+
`router semantic contract rejected (${diag.validationIssues.join(", ")})`
|
|
793379
|
+
);
|
|
793380
|
+
detailParts.push(
|
|
793381
|
+
`router-validation: ${diag.validationIssues.join(", ")}`
|
|
793382
|
+
);
|
|
793383
|
+
}
|
|
793384
|
+
if ((diag.strictRetryValidationIssues ?? []).length > 0) {
|
|
793385
|
+
detailParts.push(
|
|
793386
|
+
`strict-retry-validation: ${diag.strictRetryValidationIssues.join(", ")}`
|
|
793387
|
+
);
|
|
793388
|
+
}
|
|
792983
793389
|
let operatorHint;
|
|
792984
793390
|
if (networkErrorSeen) {
|
|
792985
793391
|
operatorHint = this.telegramRouterBackendLivenessHint(timeoutSeen);
|
|
@@ -795145,8 +795551,8 @@ Join: ${newUrl}`
|
|
|
795145
795551
|
work.intakeRecords.map(
|
|
795146
795552
|
(intake) => this.transitionTelegramIntake(
|
|
795147
795553
|
intake,
|
|
795148
|
-
"consumed",
|
|
795149
|
-
"Telegram attention router retained intake without visible reply"
|
|
795554
|
+
decision2.source === "inference-unavailable" ? "failed" : "consumed",
|
|
795555
|
+
decision2.source === "inference-unavailable" ? "Telegram attention router could not produce a valid input-bound decision" : "Telegram attention router retained intake without visible reply"
|
|
795150
795556
|
)
|
|
795151
795557
|
)
|
|
795152
795558
|
);
|
package/dist/update-worker.js
CHANGED
|
@@ -290365,7 +290365,6 @@ init_process_lifecycle();
|
|
|
290365
290365
|
import { dirname as dirname2, join as join2, resolve as resolve3 } from "node:path";
|
|
290366
290366
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
290367
290367
|
init_vision();
|
|
290368
|
-
var dynamicImport = new Function("mod", "return import(mod)");
|
|
290369
290368
|
var PLAYWRIGHT_RUNTIME_DIR = join2(homedir3(), ".omnius", "playwright-runtime");
|
|
290370
290369
|
var PLAYWRIGHT_BROWSERS_DIR = join2(PLAYWRIGHT_RUNTIME_DIR, "browsers");
|
|
290371
290370
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.666",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.666",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED