@rtrvr-ai/rover 1.3.1 → 1.3.3
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 +49 -13
- package/dist/embed.js +37 -18
- package/dist/index.d.ts +48 -9
- package/dist/rover.js +4997 -760
- package/dist/worker/rover-worker.js +2002 -435
- package/package.json +1 -1
|
@@ -113,6 +113,8 @@ var PLANNER_FUNCTION_CALLS;
|
|
|
113
113
|
PLANNER_FUNCTION_CALLS2["GOOGLE_SLIDES_GENERATOR"] = "google_slides_generator";
|
|
114
114
|
PLANNER_FUNCTION_CALLS2["PROCESS_TEXT"] = "process_text";
|
|
115
115
|
PLANNER_FUNCTION_CALLS2["CREATE_SHEET_FROM_DATA"] = "create_sheet_from_data";
|
|
116
|
+
PLANNER_FUNCTION_CALLS2["ROVER_EXTERNAL_READ_CONTEXT"] = "rover_external_read_context";
|
|
117
|
+
PLANNER_FUNCTION_CALLS2["ROVER_EXTERNAL_ACT_CONTEXT"] = "rover_external_act_context";
|
|
116
118
|
PLANNER_FUNCTION_CALLS2["CONFIGURE_API_KEY"] = "configure_api_key";
|
|
117
119
|
PLANNER_FUNCTION_CALLS2["TASK_COMPLETE"] = "task_complete";
|
|
118
120
|
PLANNER_FUNCTION_CALLS2["ASK_USER"] = "ask_user";
|
|
@@ -135,6 +137,8 @@ var FUNCTION_CALLS;
|
|
|
135
137
|
FUNCTION_CALLS2["GOOGLE_SLIDES_GENERATOR"] = "Google Slides Generator";
|
|
136
138
|
FUNCTION_CALLS2["PROCESS_TEXT"] = "Process Text";
|
|
137
139
|
FUNCTION_CALLS2["CREATE_SHEET_FROM_DATA"] = "Create Sheet From Data";
|
|
140
|
+
FUNCTION_CALLS2["ROVER_EXTERNAL_READ_CONTEXT"] = "Rover External Read Context";
|
|
141
|
+
FUNCTION_CALLS2["ROVER_EXTERNAL_ACT_CONTEXT"] = "Rover External Act Context";
|
|
138
142
|
FUNCTION_CALLS2["EXECUTE_MULTIPLE_TOOLS"] = "Execute Multiple User Tools";
|
|
139
143
|
FUNCTION_CALLS2["CONFIGURE_API_KEY"] = "Configure Gemini API Key";
|
|
140
144
|
FUNCTION_CALLS2["QUERY_RTRVR_AI_DOCUMENTATION"] = "query_rtrvr_ai_documentation";
|
|
@@ -152,6 +156,8 @@ var plannerFunctionCallValueToFunctionCallValueMap = {
|
|
|
152
156
|
[PLANNER_FUNCTION_CALLS.GOOGLE_SLIDES_GENERATOR]: FUNCTION_CALLS.GOOGLE_SLIDES_GENERATOR,
|
|
153
157
|
[PLANNER_FUNCTION_CALLS.PROCESS_TEXT]: FUNCTION_CALLS.PROCESS_TEXT,
|
|
154
158
|
[PLANNER_FUNCTION_CALLS.CREATE_SHEET_FROM_DATA]: FUNCTION_CALLS.CREATE_SHEET_FROM_DATA,
|
|
159
|
+
[PLANNER_FUNCTION_CALLS.ROVER_EXTERNAL_READ_CONTEXT]: FUNCTION_CALLS.ROVER_EXTERNAL_READ_CONTEXT,
|
|
160
|
+
[PLANNER_FUNCTION_CALLS.ROVER_EXTERNAL_ACT_CONTEXT]: FUNCTION_CALLS.ROVER_EXTERNAL_ACT_CONTEXT,
|
|
155
161
|
[PLANNER_FUNCTION_CALLS.EXECUTE_MULTIPLE_TOOLS]: FUNCTION_CALLS.EXECUTE_MULTIPLE_TOOLS,
|
|
156
162
|
[PLANNER_FUNCTION_CALLS.CONFIGURE_API_KEY]: FUNCTION_CALLS.CONFIGURE_API_KEY,
|
|
157
163
|
[PLANNER_FUNCTION_CALLS.QUERY_RTRVR_AI_DOCUMENTATION]: FUNCTION_CALLS.QUERY_RTRVR_AI_DOCUMENTATION
|
|
@@ -161,27 +167,6 @@ var DEFAULT_GEMINI_MODEL = GEMINI_MODEL.FLASH;
|
|
|
161
167
|
var PLANNER = FUNCTION_CALLS.PLANNER;
|
|
162
168
|
var maxFileSizeInBytes = 20 * 1024 * 1024;
|
|
163
169
|
|
|
164
|
-
// ../shared/dist/lib/types/agent-types.js
|
|
165
|
-
var SUB_AGENTS;
|
|
166
|
-
(function(SUB_AGENTS2) {
|
|
167
|
-
SUB_AGENTS2["enhance"] = "enhance";
|
|
168
|
-
SUB_AGENTS2["plan"] = "plan";
|
|
169
|
-
SUB_AGENTS2["actOnTabs"] = "actOnTabs";
|
|
170
|
-
SUB_AGENTS2["extract"] = "extract";
|
|
171
|
-
SUB_AGENTS2["infer"] = "infer";
|
|
172
|
-
SUB_AGENTS2["processTabWorkflows"] = "processTabWorkflows";
|
|
173
|
-
SUB_AGENTS2["processText"] = "processText";
|
|
174
|
-
SUB_AGENTS2["createSheetFromData"] = "createSheetFromData";
|
|
175
|
-
SUB_AGENTS2["queryRtrvrDocs"] = "queryRtrvrDocs";
|
|
176
|
-
SUB_AGENTS2["googleDocGenerator"] = "googleDocGenerator";
|
|
177
|
-
SUB_AGENTS2["googleSlidesGenerator"] = "googleSlidesGenerator";
|
|
178
|
-
SUB_AGENTS2["webpageGenerator"] = "webpageGenerator";
|
|
179
|
-
SUB_AGENTS2["pdfFiller"] = "pdfFiller";
|
|
180
|
-
SUB_AGENTS2["customToolGenerator"] = "customToolGenerator";
|
|
181
|
-
SUB_AGENTS2["getPageData"] = "getPageData";
|
|
182
|
-
SUB_AGENTS2["roverExternalPageData"] = "roverExternalPageData";
|
|
183
|
-
})(SUB_AGENTS || (SUB_AGENTS = {}));
|
|
184
|
-
|
|
185
170
|
// dist/tabular-memory/tabular-store.js
|
|
186
171
|
var makeId = () => {
|
|
187
172
|
if (typeof crypto !== "undefined" && "randomUUID" in crypto)
|
|
@@ -607,6 +592,18 @@ var isMemorySheetId = (sheetId) => {
|
|
|
607
592
|
// dist/agent/errors.js
|
|
608
593
|
function inferErrorCode(message) {
|
|
609
594
|
const text = String(message || "").toLowerCase();
|
|
595
|
+
if (text.includes("stale_seq") || text.includes("stale seq"))
|
|
596
|
+
return "STALE_SEQ";
|
|
597
|
+
if (text.includes("stale_epoch") || text.includes("stale epoch"))
|
|
598
|
+
return "STALE_EPOCH";
|
|
599
|
+
if (text.includes("session token") && text.includes("expired"))
|
|
600
|
+
return "SESSION_TOKEN_EXPIRED";
|
|
601
|
+
if (text.includes("session token") && text.includes("invalid"))
|
|
602
|
+
return "SESSION_TOKEN_INVALID";
|
|
603
|
+
if (text.includes("bootstrap") && text.includes("required"))
|
|
604
|
+
return "BOOTSTRAP_REQUIRED";
|
|
605
|
+
if (text.includes("navigation handoff"))
|
|
606
|
+
return "NAVIGATION_HANDOFF_PENDING";
|
|
610
607
|
if ((text.includes("auth token") || text.includes("authentication token")) && (text.includes("missing") || text.includes("required"))) {
|
|
611
608
|
return "MISSING_AUTH_TOKEN";
|
|
612
609
|
}
|
|
@@ -630,31 +627,78 @@ function inferErrorCode(message) {
|
|
|
630
627
|
}
|
|
631
628
|
function defaultNextActionForCode(code) {
|
|
632
629
|
if (code === "MISSING_AUTH" || code === "MISSING_AUTH_TOKEN") {
|
|
633
|
-
return "Provide
|
|
630
|
+
return "Provide a valid rvrsess_* sessionToken from /v1/rover/session/start in rover.boot(...).";
|
|
634
631
|
}
|
|
635
632
|
if (code === "MISSING_API_KEY") {
|
|
636
|
-
return "
|
|
633
|
+
return "Use a Rover session token (rvrsess_*) from /v1/rover/session/start.";
|
|
637
634
|
}
|
|
638
635
|
if (code === "INVALID_API_KEY") {
|
|
639
|
-
return "Use a valid active
|
|
636
|
+
return "Use a valid active Rover session token or rotate your site public key.";
|
|
637
|
+
}
|
|
638
|
+
if (code === "STALE_SEQ") {
|
|
639
|
+
return "Sync session projection and retry with latest seq.";
|
|
640
|
+
}
|
|
641
|
+
if (code === "STALE_EPOCH") {
|
|
642
|
+
return "Refresh session token/projection and retry with latest epoch.";
|
|
643
|
+
}
|
|
644
|
+
if (code === "SESSION_TOKEN_EXPIRED") {
|
|
645
|
+
return "Refresh session via /v1/rover/session/start using bootstrap public key (pk_site_*), then retry.";
|
|
646
|
+
}
|
|
647
|
+
if (code === "SESSION_TOKEN_INVALID") {
|
|
648
|
+
return "Initialize a fresh session token via /v1/rover/session/start and retry.";
|
|
649
|
+
}
|
|
650
|
+
if (code === "BOOTSTRAP_REQUIRED") {
|
|
651
|
+
return "Provide a valid pk_site_* key in bootstrapToken/publicKey and retry session start.";
|
|
652
|
+
}
|
|
653
|
+
if (code === "NAVIGATION_HANDOFF_PENDING") {
|
|
654
|
+
return "Wait for post-navigation hydration/projection sync and retry.";
|
|
640
655
|
}
|
|
641
656
|
return void 0;
|
|
642
657
|
}
|
|
643
658
|
function toRoverErrorEnvelope(err, fallbackMessage = "Operation failed") {
|
|
659
|
+
const rawErrorCode = String(err?.error || "").trim().toLowerCase();
|
|
660
|
+
if (rawErrorCode === "stale_seq" || rawErrorCode === "stale_epoch" || rawErrorCode === "session_token_expired" || rawErrorCode === "session_token_invalid" || rawErrorCode === "bootstrap_required") {
|
|
661
|
+
const code2 = rawErrorCode === "stale_epoch" ? "STALE_EPOCH" : rawErrorCode === "session_token_expired" ? "SESSION_TOKEN_EXPIRED" : rawErrorCode === "session_token_invalid" ? "SESSION_TOKEN_INVALID" : rawErrorCode === "bootstrap_required" ? "BOOTSTRAP_REQUIRED" : "STALE_SEQ";
|
|
662
|
+
const data = err?.data && typeof err.data === "object" ? err.data : {};
|
|
663
|
+
const message2 = typeof data?.reason === "string" ? data.reason : rawErrorCode === "stale_epoch" ? "Session epoch is stale." : rawErrorCode === "session_token_expired" ? "Session token expired." : rawErrorCode === "session_token_invalid" ? "Session token invalid." : rawErrorCode === "bootstrap_required" ? "Bootstrap token required." : "Run sequence is stale.";
|
|
664
|
+
return {
|
|
665
|
+
code: code2,
|
|
666
|
+
message: message2,
|
|
667
|
+
next_action: defaultNextActionForCode(code2),
|
|
668
|
+
retryable: code2 === "STALE_SEQ" || code2 === "STALE_EPOCH" || code2 === "SESSION_TOKEN_EXPIRED",
|
|
669
|
+
details: err
|
|
670
|
+
};
|
|
671
|
+
}
|
|
644
672
|
const directCandidate = err && typeof err === "object" && typeof err.code === "string" && typeof err.message === "string" ? err : void 0;
|
|
645
673
|
const candidate = err?.roverError || err?.errorDetails || (typeof err?.error === "object" ? err.error : void 0) || directCandidate;
|
|
646
674
|
if (candidate && typeof candidate === "object" && candidate.code && candidate.message) {
|
|
675
|
+
const candidateCodeRaw = String(candidate.code || "").trim();
|
|
676
|
+
const normalizedCandidateCode = candidateCodeRaw === "stale_seq" ? "STALE_SEQ" : candidateCodeRaw === "stale_epoch" ? "STALE_EPOCH" : candidateCodeRaw === "session_token_expired" ? "SESSION_TOKEN_EXPIRED" : candidateCodeRaw === "session_token_invalid" ? "SESSION_TOKEN_INVALID" : candidateCodeRaw === "bootstrap_required" ? "BOOTSTRAP_REQUIRED" : candidateCodeRaw === "navigation_handoff_pending" ? "NAVIGATION_HANDOFF_PENDING" : candidateCodeRaw;
|
|
677
|
+
const normalizedCode = normalizedCandidateCode;
|
|
678
|
+
const retryable = typeof candidate.retryable === "boolean" ? candidate.retryable : normalizedCode === "STALE_SEQ" || normalizedCode === "STALE_EPOCH" || normalizedCode === "SESSION_TOKEN_EXPIRED" || normalizedCode === "NAVIGATION_HANDOFF_PENDING";
|
|
647
679
|
return {
|
|
648
|
-
code:
|
|
680
|
+
code: normalizedCode,
|
|
649
681
|
message: candidate.message,
|
|
650
682
|
requires_api_key: !!candidate.requires_api_key,
|
|
651
683
|
missing: Array.isArray(candidate.missing) ? candidate.missing : void 0,
|
|
652
|
-
next_action: candidate.next_action,
|
|
653
|
-
retryable
|
|
684
|
+
next_action: candidate.next_action || defaultNextActionForCode(normalizedCode),
|
|
685
|
+
retryable,
|
|
654
686
|
degraded: candidate.degraded,
|
|
655
687
|
details: candidate.details
|
|
656
688
|
};
|
|
657
689
|
}
|
|
690
|
+
if (typeof err === "string") {
|
|
691
|
+
const message2 = err || fallbackMessage;
|
|
692
|
+
const code2 = inferErrorCode(message2);
|
|
693
|
+
return {
|
|
694
|
+
code: code2,
|
|
695
|
+
message: message2,
|
|
696
|
+
requires_api_key: code2 === "MISSING_API_KEY" || code2 === "INVALID_API_KEY",
|
|
697
|
+
missing: code2 === "MISSING_AUTH" || code2 === "MISSING_AUTH_TOKEN" ? ["authToken"] : void 0,
|
|
698
|
+
next_action: defaultNextActionForCode(code2),
|
|
699
|
+
retryable: code2 === "NETWORK_ERROR" || code2 === "STALE_SEQ" || code2 === "STALE_EPOCH" || code2 === "SESSION_TOKEN_EXPIRED" || code2 === "NAVIGATION_HANDOFF_PENDING"
|
|
700
|
+
};
|
|
701
|
+
}
|
|
658
702
|
const message = String(err?.message || err?.error || fallbackMessage);
|
|
659
703
|
const code = inferErrorCode(message);
|
|
660
704
|
const requiresApiKey = code === "MISSING_API_KEY" || code === "INVALID_API_KEY";
|
|
@@ -662,9 +706,9 @@ function toRoverErrorEnvelope(err, fallbackMessage = "Operation failed") {
|
|
|
662
706
|
code,
|
|
663
707
|
message,
|
|
664
708
|
requires_api_key: requiresApiKey,
|
|
665
|
-
missing: requiresApiKey ? ["
|
|
709
|
+
missing: requiresApiKey ? ["publicKey"] : code === "MISSING_AUTH" || code === "MISSING_AUTH_TOKEN" ? ["authToken"] : void 0,
|
|
666
710
|
next_action: defaultNextActionForCode(code),
|
|
667
|
-
retryable: code === "NETWORK_ERROR",
|
|
711
|
+
retryable: code === "NETWORK_ERROR" || code === "STALE_SEQ" || code === "STALE_EPOCH" || code === "SESSION_TOKEN_EXPIRED" || code === "NAVIGATION_HANDOFF_PENDING",
|
|
668
712
|
details: err
|
|
669
713
|
};
|
|
670
714
|
}
|
|
@@ -788,6 +832,30 @@ function normalizeRuntimeExternalTabs(input) {
|
|
|
788
832
|
}
|
|
789
833
|
return Array.from(deduped.values());
|
|
790
834
|
}
|
|
835
|
+
function selectExternalIntent(requestedIntent, message) {
|
|
836
|
+
if (requestedIntent === "act")
|
|
837
|
+
return "act";
|
|
838
|
+
if (requestedIntent === "read_context")
|
|
839
|
+
return "read_context";
|
|
840
|
+
if (requestedIntent === "open_only")
|
|
841
|
+
return "open_only";
|
|
842
|
+
const normalized = String(message || "").toLowerCase();
|
|
843
|
+
if (!normalized.trim())
|
|
844
|
+
return "read_context";
|
|
845
|
+
const mutationSignals = /\b(fill|submit|book|buy|purchase|apply|sign up|signup|log in|login|register|delete|update|create|post|send|checkout|pay)\b/i;
|
|
846
|
+
const navigationSignals = /\b(open|navigate|go to|visit|take me to|bring me to)\b/i;
|
|
847
|
+
const readSignals = /\b(read|summarize|extract|inspect|analyze|check|find|lookup|list|show|compare|review)\b/i;
|
|
848
|
+
if (mutationSignals.test(normalized) && !/\b(do not|don't)\b/i.test(normalized)) {
|
|
849
|
+
return "act";
|
|
850
|
+
}
|
|
851
|
+
if (navigationSignals.test(normalized) && !readSignals.test(normalized)) {
|
|
852
|
+
return "read_context";
|
|
853
|
+
}
|
|
854
|
+
if (readSignals.test(normalized)) {
|
|
855
|
+
return "read_context";
|
|
856
|
+
}
|
|
857
|
+
return "read_context";
|
|
858
|
+
}
|
|
791
859
|
function resolveExtensionRouterEndpoint(apiBase) {
|
|
792
860
|
const fallback = DEFAULT_EXTENSION_ROUTER_BASE;
|
|
793
861
|
const base = String(apiBase || fallback).trim().replace(/\/+$/, "");
|
|
@@ -806,6 +874,24 @@ function resolveExtensionRouterEndpoint(apiBase) {
|
|
|
806
874
|
}
|
|
807
875
|
return `${base}/extensionRouter`;
|
|
808
876
|
}
|
|
877
|
+
function resolveRoverV1Endpoint(apiBase) {
|
|
878
|
+
const fallback = DEFAULT_EXTENSION_ROUTER_BASE;
|
|
879
|
+
const base = String(apiBase || fallback).trim().replace(/\/+$/, "");
|
|
880
|
+
if (!base)
|
|
881
|
+
return `${fallback}/v1/rover`;
|
|
882
|
+
if (base.endsWith("/extensionRouter")) {
|
|
883
|
+
return `${base.slice(0, -"/extensionRouter".length)}/v1/rover`;
|
|
884
|
+
}
|
|
885
|
+
if (base.endsWith("/v1/rover"))
|
|
886
|
+
return base;
|
|
887
|
+
return `${base}/v1/rover`;
|
|
888
|
+
}
|
|
889
|
+
function createRequestNonce() {
|
|
890
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
891
|
+
return crypto.randomUUID();
|
|
892
|
+
}
|
|
893
|
+
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
894
|
+
}
|
|
809
895
|
function buildRoverRuntimeContext(config2) {
|
|
810
896
|
const runtimeContext = config2.runtimeContext;
|
|
811
897
|
if (!runtimeContext || runtimeContext.mode !== "rover_embed")
|
|
@@ -854,7 +940,7 @@ function getUserFriendlyTimestamp() {
|
|
|
854
940
|
}
|
|
855
941
|
function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
856
942
|
const userTimestamp = getUserFriendlyTimestamp();
|
|
857
|
-
const apiMode = typeof config2.apiMode === "boolean" ? config2.apiMode : !!config2.
|
|
943
|
+
const apiMode = typeof config2.apiMode === "boolean" ? config2.apiMode : !!String(config2.sessionToken || config2.authToken || "").trim();
|
|
858
944
|
const llmIntegration = {
|
|
859
945
|
model: config2.llmIntegration?.model || config2.model || DEFAULT_GEMINI_MODEL
|
|
860
946
|
};
|
|
@@ -870,6 +956,7 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
870
956
|
llmIntegration.enableGoogleAiStudioApiKey = true;
|
|
871
957
|
}
|
|
872
958
|
const endpoint = resolveExtensionRouterEndpoint(config2.apiBase);
|
|
959
|
+
const roverV1Endpoint = resolveRoverV1Endpoint(config2.apiBase);
|
|
873
960
|
const runtimeContext = buildRoverRuntimeContext(config2);
|
|
874
961
|
const externalWebConfig = normalizeExternalWebConfig(config2.tools?.web);
|
|
875
962
|
const externalPageDataCache = /* @__PURE__ */ new Map();
|
|
@@ -882,13 +969,21 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
882
969
|
const ACTIVE_TAB_CACHE_TTL_MS = 250;
|
|
883
970
|
const EXTERNAL_PAGE_CACHE_TTL_MS = 45e3;
|
|
884
971
|
const callExtensionRouter = async (action, data) => {
|
|
885
|
-
|
|
886
|
-
if (!
|
|
972
|
+
let sessionToken = String(config2.sessionToken || config2.authToken || "").trim();
|
|
973
|
+
if (!sessionToken || !sessionToken.startsWith("rvrsess_")) {
|
|
974
|
+
for (let wait = 0; wait < 3; wait++) {
|
|
975
|
+
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
976
|
+
sessionToken = String(config2.sessionToken || config2.authToken || "").trim();
|
|
977
|
+
if (sessionToken && sessionToken.startsWith("rvrsess_"))
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
if (!sessionToken || !sessionToken.startsWith("rvrsess_")) {
|
|
887
982
|
throw createRoverError({
|
|
888
|
-
code: "
|
|
889
|
-
message: "Rover
|
|
890
|
-
requires_api_key:
|
|
891
|
-
next_action: "
|
|
983
|
+
code: "MISSING_AUTH_TOKEN",
|
|
984
|
+
message: "Rover session token is required to call backend action routes.",
|
|
985
|
+
requires_api_key: false,
|
|
986
|
+
next_action: "Initialize Rover session via /v1/rover/session/start and pass sessionToken to rover.boot(...).",
|
|
892
987
|
retryable: false
|
|
893
988
|
});
|
|
894
989
|
}
|
|
@@ -900,15 +995,24 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
900
995
|
const response = await fetch(endpoint, {
|
|
901
996
|
method: "POST",
|
|
902
997
|
headers: {
|
|
903
|
-
Authorization: `Bearer ${token}`,
|
|
904
998
|
"Content-Type": "application/json"
|
|
905
999
|
},
|
|
906
1000
|
body: JSON.stringify({
|
|
907
1001
|
action,
|
|
908
1002
|
data: data && typeof data === "object" ? {
|
|
909
1003
|
...data,
|
|
1004
|
+
sessionToken,
|
|
1005
|
+
sessionId: String(config2.sessionId || "").trim() || void 0,
|
|
1006
|
+
runId: String(config2.activeRunId || "").trim() || void 0,
|
|
1007
|
+
requestNonce: createRequestNonce(),
|
|
910
1008
|
...!data.runtimeContext && runtimeContext ? { runtimeContext } : {}
|
|
911
|
-
} :
|
|
1009
|
+
} : {
|
|
1010
|
+
payload: data,
|
|
1011
|
+
sessionToken,
|
|
1012
|
+
sessionId: String(config2.sessionId || "").trim() || void 0,
|
|
1013
|
+
runId: String(config2.activeRunId || "").trim() || void 0,
|
|
1014
|
+
requestNonce: createRequestNonce()
|
|
1015
|
+
}
|
|
912
1016
|
}),
|
|
913
1017
|
signal: config2.signal
|
|
914
1018
|
});
|
|
@@ -967,7 +1071,9 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
967
1071
|
if (!normalizedUrl)
|
|
968
1072
|
throw new Error("external page data requires url");
|
|
969
1073
|
const cacheTabId = Number(options?.tabId) || 0;
|
|
970
|
-
const
|
|
1074
|
+
const source = options?.source || "direct_url";
|
|
1075
|
+
const intent = options?.intent === "act" ? "act" : options?.intent === "open_only" ? "open_only" : "read_context";
|
|
1076
|
+
const cacheKey = `${cacheTabId}:${intent}:${source}:${normalizedUrl}`;
|
|
971
1077
|
const nowMs = Date.now();
|
|
972
1078
|
const cachedData = externalPageDataCache.get(cacheKey);
|
|
973
1079
|
if (cachedData && nowMs - cachedData.ts <= EXTERNAL_PAGE_CACHE_TTL_MS) {
|
|
@@ -982,19 +1088,49 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
982
1088
|
if (externalPageDataDisabledReason) {
|
|
983
1089
|
throw new Error(externalPageDataDisabledReason);
|
|
984
1090
|
}
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
};
|
|
1091
|
+
const sessionToken = String(config2.sessionToken || "").trim();
|
|
1092
|
+
if (!sessionToken.startsWith("rvrsess_")) {
|
|
1093
|
+
throw createRoverError({
|
|
1094
|
+
code: "MISSING_AUTH_TOKEN",
|
|
1095
|
+
message: "External context requires a Rover session token.",
|
|
1096
|
+
next_action: "Initialize Rover v1 session/start before requesting external context.",
|
|
1097
|
+
retryable: false
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
995
1100
|
try {
|
|
996
|
-
const
|
|
997
|
-
|
|
1101
|
+
const v1Resp = await fetch(`${roverV1Endpoint}/context/external`, {
|
|
1102
|
+
method: "POST",
|
|
1103
|
+
headers: {
|
|
1104
|
+
"Content-Type": "application/json"
|
|
1105
|
+
},
|
|
1106
|
+
body: JSON.stringify({
|
|
1107
|
+
requestNonce: createRequestNonce(),
|
|
1108
|
+
sessionToken,
|
|
1109
|
+
sessionId: String(config2.sessionId || "").trim() || void 0,
|
|
1110
|
+
runId: String(options?.runId || config2.activeRunId || "").trim() || void 0,
|
|
1111
|
+
expectedEpoch: Number.isFinite(Number(config2.sessionEpoch)) ? Number(config2.sessionEpoch) : void 0,
|
|
1112
|
+
expectedSeq: Number.isFinite(Number(config2.sessionSeq)) ? Number(config2.sessionSeq) : void 0,
|
|
1113
|
+
logicalTabId: Number(options?.tabId) > 0 ? String(Math.trunc(Number(options?.tabId))) : void 0,
|
|
1114
|
+
intent,
|
|
1115
|
+
url: normalizedUrl,
|
|
1116
|
+
source,
|
|
1117
|
+
message: options?.message
|
|
1118
|
+
}),
|
|
1119
|
+
signal: config2.signal
|
|
1120
|
+
});
|
|
1121
|
+
const payload = await v1Resp.json().catch(() => void 0);
|
|
1122
|
+
if (!v1Resp.ok || payload?.success === false) {
|
|
1123
|
+
const envelope = toRoverErrorEnvelope(payload, payload?.error || `external context request failed (${v1Resp.status})`);
|
|
1124
|
+
throw createRoverError({
|
|
1125
|
+
...envelope,
|
|
1126
|
+
details: {
|
|
1127
|
+
endpoint: `${roverV1Endpoint}/context/external`,
|
|
1128
|
+
status: v1Resp.status,
|
|
1129
|
+
response: payload
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
const pageData = payload?.data?.pageData || payload?.data;
|
|
998
1134
|
externalPageDataCache.set(cacheKey, { data: pageData, ts: nowMs });
|
|
999
1135
|
return pageData;
|
|
1000
1136
|
} catch (error) {
|
|
@@ -1028,7 +1164,10 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
1028
1164
|
const numericTabId = Number(tabId);
|
|
1029
1165
|
const rawOptions = options && typeof options === "object" ? options : void 0;
|
|
1030
1166
|
const allowExternalFetch = rawOptions?.__roverAllowExternalFetch === true;
|
|
1031
|
-
const
|
|
1167
|
+
const requestedExternalIntent = rawOptions?.__roverExternalIntent === "act" || rawOptions?.__roverExternalIntent === "open_only" || rawOptions?.__roverExternalIntent === "read_context" || rawOptions?.__roverExternalIntent === "auto" ? rawOptions.__roverExternalIntent : "auto";
|
|
1168
|
+
const externalMessage = typeof rawOptions?.__roverExternalMessage === "string" ? String(rawOptions.__roverExternalMessage) : void 0;
|
|
1169
|
+
const externalIntent = selectExternalIntent(requestedExternalIntent, externalMessage);
|
|
1170
|
+
const pageConfig = rawOptions && typeof rawOptions === "object" ? Object.fromEntries(Object.entries(rawOptions).filter(([key]) => key !== "__roverAllowExternalFetch" && key !== "__roverExternalIntent" && key !== "__roverExternalMessage")) : void 0;
|
|
1032
1171
|
const hasPageConfig = !!pageConfig && Object.keys(pageConfig).length > 0;
|
|
1033
1172
|
const localPageData = rawOptions ? await bridgeRpc2("getPageData", hasPageConfig ? { pageConfig, tabId: numericTabId } : { tabId: numericTabId }) : await bridgeRpc2("getPageData", { tabId: numericTabId });
|
|
1034
1173
|
const metadata = localPageData?.metadata || {};
|
|
@@ -1070,8 +1209,13 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
1070
1209
|
try {
|
|
1071
1210
|
const cloudData = await getExternalPageData(pageUrl, {
|
|
1072
1211
|
tabId: numericTabId,
|
|
1073
|
-
source: pageUrl.includes("google.com/search") ? "google_search" : "direct_url"
|
|
1212
|
+
source: pageUrl.includes("google.com/search") ? "google_search" : "direct_url",
|
|
1213
|
+
intent: externalIntent,
|
|
1214
|
+
message: externalMessage
|
|
1074
1215
|
});
|
|
1216
|
+
if (externalIntent === "open_only") {
|
|
1217
|
+
return localPageData;
|
|
1218
|
+
}
|
|
1075
1219
|
if (cloudData && typeof cloudData === "object") {
|
|
1076
1220
|
return {
|
|
1077
1221
|
...cloudData,
|
|
@@ -1315,6 +1459,27 @@ var GeminiModel;
|
|
|
1315
1459
|
GeminiModel2["PRO"] = "Gemini Pro";
|
|
1316
1460
|
})(GeminiModel || (GeminiModel = {}));
|
|
1317
1461
|
|
|
1462
|
+
// ../shared/dist/lib/types/agent-types.js
|
|
1463
|
+
var SUB_AGENTS;
|
|
1464
|
+
(function(SUB_AGENTS2) {
|
|
1465
|
+
SUB_AGENTS2["enhance"] = "enhance";
|
|
1466
|
+
SUB_AGENTS2["plan"] = "plan";
|
|
1467
|
+
SUB_AGENTS2["actOnTabs"] = "actOnTabs";
|
|
1468
|
+
SUB_AGENTS2["extract"] = "extract";
|
|
1469
|
+
SUB_AGENTS2["infer"] = "infer";
|
|
1470
|
+
SUB_AGENTS2["processTabWorkflows"] = "processTabWorkflows";
|
|
1471
|
+
SUB_AGENTS2["processText"] = "processText";
|
|
1472
|
+
SUB_AGENTS2["createSheetFromData"] = "createSheetFromData";
|
|
1473
|
+
SUB_AGENTS2["queryRtrvrDocs"] = "queryRtrvrDocs";
|
|
1474
|
+
SUB_AGENTS2["googleDocGenerator"] = "googleDocGenerator";
|
|
1475
|
+
SUB_AGENTS2["googleSlidesGenerator"] = "googleSlidesGenerator";
|
|
1476
|
+
SUB_AGENTS2["webpageGenerator"] = "webpageGenerator";
|
|
1477
|
+
SUB_AGENTS2["pdfFiller"] = "pdfFiller";
|
|
1478
|
+
SUB_AGENTS2["customToolGenerator"] = "customToolGenerator";
|
|
1479
|
+
SUB_AGENTS2["getPageData"] = "getPageData";
|
|
1480
|
+
SUB_AGENTS2["roverExternalPageData"] = "roverExternalPageData";
|
|
1481
|
+
})(SUB_AGENTS || (SUB_AGENTS = {}));
|
|
1482
|
+
|
|
1318
1483
|
// ../shared/dist/lib/system-tools/tools.js
|
|
1319
1484
|
var SystemToolNames;
|
|
1320
1485
|
(function(SystemToolNames2) {
|
|
@@ -1350,6 +1515,8 @@ var SystemToolNames;
|
|
|
1350
1515
|
SystemToolNames2["describe_images"] = "describe_images";
|
|
1351
1516
|
SystemToolNames2["google_search"] = "google_search";
|
|
1352
1517
|
SystemToolNames2["network_run_recipe"] = "network_run_recipe";
|
|
1518
|
+
SystemToolNames2["rover_external_read_context"] = "rover_external_read_context";
|
|
1519
|
+
SystemToolNames2["rover_external_act_context"] = "rover_external_act_context";
|
|
1353
1520
|
SystemToolNames2["copy_text"] = "copy_text";
|
|
1354
1521
|
SystemToolNames2["paste_text"] = "paste_text";
|
|
1355
1522
|
SystemToolNames2["wait_action"] = "wait_action";
|
|
@@ -1367,6 +1534,7 @@ var NAVIGATION_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1367
1534
|
SystemToolNames.go_back,
|
|
1368
1535
|
SystemToolNames.go_forward,
|
|
1369
1536
|
SystemToolNames.refresh_page,
|
|
1537
|
+
SystemToolNames.open_new_tab,
|
|
1370
1538
|
SystemToolNames.switch_tab,
|
|
1371
1539
|
SystemToolNames.close_tab
|
|
1372
1540
|
]);
|
|
@@ -1381,12 +1549,26 @@ var VIEWPORT_SENSITIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1381
1549
|
SystemToolNames.focus_element
|
|
1382
1550
|
]);
|
|
1383
1551
|
var ACTION_DELAY_MS = 600;
|
|
1384
|
-
|
|
1552
|
+
var NAVIGATION_OUTCOMES = /* @__PURE__ */ new Set([
|
|
1553
|
+
"same_tab_scheduled",
|
|
1554
|
+
"new_tab_opened",
|
|
1555
|
+
"blocked",
|
|
1556
|
+
"switch_tab"
|
|
1557
|
+
]);
|
|
1558
|
+
function throwIfCancelled(isCancelled) {
|
|
1559
|
+
if (!isCancelled?.())
|
|
1560
|
+
return;
|
|
1561
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
1562
|
+
}
|
|
1563
|
+
async function executeSystemToolCallsSequentially({ calls, bridgeRpc: bridgeRpc2, isCancelled }) {
|
|
1385
1564
|
const results = [];
|
|
1386
1565
|
let sawViewportSensitiveToolSuccess = false;
|
|
1387
1566
|
let navigationOccurred = false;
|
|
1388
1567
|
let navigationTool;
|
|
1568
|
+
let navigationOutcome;
|
|
1569
|
+
let logicalTabId;
|
|
1389
1570
|
for (const call of calls) {
|
|
1571
|
+
throwIfCancelled(isCancelled);
|
|
1390
1572
|
const name = call.name;
|
|
1391
1573
|
const args = call.args || {};
|
|
1392
1574
|
if (navigationOccurred) {
|
|
@@ -1405,8 +1587,10 @@ async function executeSystemToolCallsSequentially({ calls, bridgeRpc: bridgeRpc2
|
|
|
1405
1587
|
}
|
|
1406
1588
|
let response;
|
|
1407
1589
|
try {
|
|
1590
|
+
throwIfCancelled(isCancelled);
|
|
1408
1591
|
response = await bridgeRpc2("executeTool", { call });
|
|
1409
1592
|
} catch (err) {
|
|
1593
|
+
throwIfCancelled(isCancelled);
|
|
1410
1594
|
response = { success: false, error: err?.message || String(err), allowFallback: true };
|
|
1411
1595
|
}
|
|
1412
1596
|
const llmResponse = {
|
|
@@ -1418,20 +1602,51 @@ async function executeSystemToolCallsSequentially({ calls, bridgeRpc: bridgeRpc2
|
|
|
1418
1602
|
const resolvedResult = { name: name || "unknown", args, response: llmResponse };
|
|
1419
1603
|
results.push(resolvedResult);
|
|
1420
1604
|
if (response?.success) {
|
|
1421
|
-
|
|
1605
|
+
const output = response?.output && typeof response.output === "object" ? response.output : void 0;
|
|
1606
|
+
const outputNavigationOutcomeRaw = String(output?.navigationOutcome || "").trim().toLowerCase();
|
|
1607
|
+
const outputNavigationOutcome = NAVIGATION_OUTCOMES.has(outputNavigationOutcomeRaw) ? outputNavigationOutcomeRaw : void 0;
|
|
1608
|
+
const outputNavigationPending = output?.navigationPending === true;
|
|
1609
|
+
const outputOpenedInNewTab = output?.openedInNewTab === true;
|
|
1610
|
+
const inferredNavigation = !!outputNavigationOutcome || outputNavigationPending || outputOpenedInNewTab;
|
|
1611
|
+
if (NAVIGATION_TOOLS.has(name) || inferredNavigation) {
|
|
1422
1612
|
navigationOccurred = true;
|
|
1423
1613
|
navigationTool = name;
|
|
1424
1614
|
sawViewportSensitiveToolSuccess = false;
|
|
1615
|
+
if (outputNavigationOutcome) {
|
|
1616
|
+
navigationOutcome = outputNavigationOutcome;
|
|
1617
|
+
} else if (outputOpenedInNewTab) {
|
|
1618
|
+
navigationOutcome = "new_tab_opened";
|
|
1619
|
+
} else if (name === SystemToolNames.switch_tab) {
|
|
1620
|
+
navigationOutcome = "switch_tab";
|
|
1621
|
+
} else if (name === SystemToolNames.open_new_tab) {
|
|
1622
|
+
navigationOutcome = "new_tab_opened";
|
|
1623
|
+
} else if (outputNavigationPending) {
|
|
1624
|
+
navigationOutcome = "same_tab_scheduled";
|
|
1625
|
+
} else {
|
|
1626
|
+
navigationOutcome = "same_tab_scheduled";
|
|
1627
|
+
}
|
|
1628
|
+
const outputLogicalTabId = Number(output?.logicalTabId ?? output?.logical_tab_id ?? output?.tabId ?? output?.tab_id ?? args?.logical_tab_id ?? args?.tab_id);
|
|
1629
|
+
if (Number.isFinite(outputLogicalTabId) && outputLogicalTabId > 0) {
|
|
1630
|
+
logicalTabId = outputLogicalTabId;
|
|
1631
|
+
}
|
|
1425
1632
|
} else if (VIEWPORT_SENSITIVE_TOOLS.has(name)) {
|
|
1426
1633
|
sawViewportSensitiveToolSuccess = true;
|
|
1427
1634
|
}
|
|
1428
1635
|
}
|
|
1429
1636
|
if (ACTION_DELAY_MS > 0) {
|
|
1430
1637
|
await new Promise((resolve) => setTimeout(resolve, ACTION_DELAY_MS));
|
|
1638
|
+
throwIfCancelled(isCancelled);
|
|
1431
1639
|
}
|
|
1432
1640
|
}
|
|
1433
1641
|
const disableAutoScroll = sawViewportSensitiveToolSuccess && !navigationOccurred;
|
|
1434
|
-
return {
|
|
1642
|
+
return {
|
|
1643
|
+
results,
|
|
1644
|
+
disableAutoScroll,
|
|
1645
|
+
navigationOccurred,
|
|
1646
|
+
navigationTool,
|
|
1647
|
+
navigationOutcome,
|
|
1648
|
+
logicalTabId
|
|
1649
|
+
};
|
|
1435
1650
|
}
|
|
1436
1651
|
|
|
1437
1652
|
// dist/agent/utils.js
|
|
@@ -1445,7 +1660,22 @@ async function waitWhilePaused(executionRef) {
|
|
|
1445
1660
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1446
1661
|
}
|
|
1447
1662
|
}
|
|
1448
|
-
|
|
1663
|
+
function buildWorkerStopSignal(params) {
|
|
1664
|
+
if (params.isCancelled) {
|
|
1665
|
+
return {
|
|
1666
|
+
state: "cancel_requested",
|
|
1667
|
+
reason: params.reason || "worker_cancelled"
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
return { state: "continue" };
|
|
1671
|
+
}
|
|
1672
|
+
async function processActionResponse({ request, response, tabId, prevSteps, thought, bridgeRpc: bridgeRpc2, isCancelled, userFunctionDeclarations, onStatusUpdate, onPrevStepsUpdate }) {
|
|
1673
|
+
const throwIfCancelled2 = () => {
|
|
1674
|
+
if (!isCancelled?.())
|
|
1675
|
+
return;
|
|
1676
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
1677
|
+
};
|
|
1678
|
+
throwIfCancelled2();
|
|
1449
1679
|
const { functionCalls, modelParts, data, accTreeId } = response || {};
|
|
1450
1680
|
let disableAutoScroll = false;
|
|
1451
1681
|
if (data && Array.isArray(data) && data.length > 0) {
|
|
@@ -1548,6 +1778,7 @@ async function processActionResponse({ request, response, tabId, prevSteps, thou
|
|
|
1548
1778
|
}
|
|
1549
1779
|
}
|
|
1550
1780
|
if (externalCalls.length > 0) {
|
|
1781
|
+
throwIfCancelled2();
|
|
1551
1782
|
if (userFunctionDeclarations?.length) {
|
|
1552
1783
|
for (const funcCall of externalCalls) {
|
|
1553
1784
|
const found = userFunctionDeclarations.find((decl) => decl.name === funcCall.name);
|
|
@@ -1575,6 +1806,7 @@ async function processActionResponse({ request, response, tabId, prevSteps, thou
|
|
|
1575
1806
|
return { needsRetry: false, functionCalls: externalCalls };
|
|
1576
1807
|
}
|
|
1577
1808
|
if (systemCalls.length > 0) {
|
|
1809
|
+
throwIfCancelled2();
|
|
1578
1810
|
onStatusUpdate?.(`Executing browser actions: ${systemCalls.map((c) => c.name).join(", ")}`, thought, "execute");
|
|
1579
1811
|
prevSteps.push({
|
|
1580
1812
|
accTreeId,
|
|
@@ -1589,11 +1821,13 @@ async function processActionResponse({ request, response, tabId, prevSteps, thou
|
|
|
1589
1821
|
limitPrevSteps(prevSteps);
|
|
1590
1822
|
onPrevStepsUpdate?.(prevSteps);
|
|
1591
1823
|
const stepIndex = prevSteps.length - 1;
|
|
1592
|
-
const { results, disableAutoScroll: isScroll } = await executeSystemToolCallsSequentially({
|
|
1824
|
+
const { results, disableAutoScroll: isScroll, navigationOccurred, navigationTool, navigationOutcome, logicalTabId } = await executeSystemToolCallsSequentially({
|
|
1593
1825
|
calls: systemCalls,
|
|
1594
|
-
bridgeRpc: bridgeRpc2
|
|
1826
|
+
bridgeRpc: bridgeRpc2,
|
|
1827
|
+
isCancelled
|
|
1595
1828
|
});
|
|
1596
1829
|
disableAutoScroll = isScroll;
|
|
1830
|
+
throwIfCancelled2();
|
|
1597
1831
|
if (stepIndex >= 0 && stepIndex < prevSteps.length) {
|
|
1598
1832
|
prevSteps[stepIndex].functions = results;
|
|
1599
1833
|
const failedCount = results.filter((r) => r.response.status === "Failure").length;
|
|
@@ -1603,7 +1837,14 @@ async function processActionResponse({ request, response, tabId, prevSteps, thou
|
|
|
1603
1837
|
}
|
|
1604
1838
|
limitPrevSteps(prevSteps);
|
|
1605
1839
|
onPrevStepsUpdate?.(prevSteps);
|
|
1606
|
-
return {
|
|
1840
|
+
return {
|
|
1841
|
+
needsRetry: false,
|
|
1842
|
+
disableAutoScroll,
|
|
1843
|
+
navigationOccurred,
|
|
1844
|
+
navigationTool,
|
|
1845
|
+
navigationOutcome,
|
|
1846
|
+
logicalTabId
|
|
1847
|
+
};
|
|
1607
1848
|
}
|
|
1608
1849
|
}
|
|
1609
1850
|
prevSteps.push({ accTreeId, thought, modelParts, fail: "Empty or unusable response" });
|
|
@@ -1757,81 +1998,192 @@ function normalizeListedTabs(input) {
|
|
|
1757
1998
|
};
|
|
1758
1999
|
}).filter((tab) => !!tab);
|
|
1759
2000
|
}
|
|
2001
|
+
function preferScopedOrder(scopedOrder, activeTabId, maxContextTabs) {
|
|
2002
|
+
const deduped = dedupePositiveTabIds(scopedOrder);
|
|
2003
|
+
if (!deduped.length)
|
|
2004
|
+
return [];
|
|
2005
|
+
const activeInScope = deduped.includes(activeTabId);
|
|
2006
|
+
const resolvedActive = activeInScope ? activeTabId : deduped[0];
|
|
2007
|
+
const ordered = [
|
|
2008
|
+
resolvedActive,
|
|
2009
|
+
...deduped.filter((tabId) => tabId !== resolvedActive)
|
|
2010
|
+
];
|
|
2011
|
+
return ordered.slice(0, maxContextTabs);
|
|
2012
|
+
}
|
|
2013
|
+
function filterTabIdsToScope(tabIds, scopedTabIds2) {
|
|
2014
|
+
if (!scopedTabIds2.length)
|
|
2015
|
+
return dedupePositiveTabIds(tabIds);
|
|
2016
|
+
const scoped = new Set(scopedTabIds2);
|
|
2017
|
+
return dedupePositiveTabIds(tabIds).filter((tabId) => scoped.has(tabId));
|
|
2018
|
+
}
|
|
1760
2019
|
async function resolveRuntimeTabs(bridgeRpc2, fallbackTabs, options) {
|
|
1761
2020
|
const maxContextTabs = Math.max(1, Number(options?.maxContextTabs) || DEFAULT_MAX_CONTEXT_TABS);
|
|
1762
2021
|
const detachedExternalTabMaxAgeMs = Math.max(5e3, Number(options?.detachedExternalTabMaxAgeMs) || DEFAULT_DETACHED_EXTERNAL_TAB_MAX_AGE_MS);
|
|
1763
2022
|
const staleRuntimeTabMaxAgeMs = Math.max(1e4, Number(options?.staleRuntimeTabMaxAgeMs) || DEFAULT_STALE_RUNTIME_TAB_MAX_AGE_MS);
|
|
2023
|
+
const scopedTabIds2 = dedupePositiveTabIds(options?.scopedTabIds || []);
|
|
2024
|
+
const hasExplicitScope = scopedTabIds2.length > 0;
|
|
2025
|
+
const scopedOrder = [...scopedTabIds2];
|
|
2026
|
+
const scopedTabSet = new Set(scopedOrder);
|
|
1764
2027
|
const fallbackSnapshots = normalizeFallbackTabs(fallbackTabs);
|
|
1765
|
-
const fallbackTabIds = dedupePositiveTabIds(fallbackSnapshots.map((tab) => tab.id));
|
|
2028
|
+
const fallbackTabIds = dedupePositiveTabIds((scopedTabIds2.length > 0 ? fallbackSnapshots.filter((tab) => scopedTabIds2.includes(tab.id)) : fallbackSnapshots).map((tab) => tab.id));
|
|
1766
2029
|
let tabIds = [...fallbackTabIds];
|
|
1767
2030
|
let listedTabs = [];
|
|
2031
|
+
let listedTabIds = [];
|
|
2032
|
+
const isTabInScope = (tabId) => {
|
|
2033
|
+
if (!hasExplicitScope)
|
|
2034
|
+
return true;
|
|
2035
|
+
return scopedTabSet.has(tabId);
|
|
2036
|
+
};
|
|
1768
2037
|
if (bridgeRpc2) {
|
|
1769
2038
|
try {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
2039
|
+
const listed = await bridgeRpc2("listSessionTabs");
|
|
2040
|
+
listedTabs = normalizeListedTabs(Array.isArray(listed) ? listed : []);
|
|
2041
|
+
listedTabIds = dedupePositiveTabIds(listedTabs.map((tab) => tab.id));
|
|
2042
|
+
if (listedTabIds.length > 0) {
|
|
2043
|
+
tabIds = hasExplicitScope ? filterTabIdsToScope(listedTabIds, scopedOrder) : listedTabIds;
|
|
2044
|
+
} else if (hasExplicitScope) {
|
|
2045
|
+
tabIds = [...scopedOrder];
|
|
1774
2046
|
}
|
|
1775
2047
|
} catch {
|
|
1776
2048
|
}
|
|
1777
2049
|
}
|
|
1778
|
-
|
|
2050
|
+
if (hasExplicitScope) {
|
|
2051
|
+
tabIds = dedupePositiveTabIds(tabIds).filter((tabId) => isTabInScope(tabId));
|
|
2052
|
+
if (!tabIds.length && scopedOrder.length) {
|
|
2053
|
+
tabIds = [...scopedOrder];
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
let activeTabId = Number(options?.seedTabId) > 0 ? Number(options?.seedTabId) : tabIds[0] || fallbackTabIds[0] || 1;
|
|
1779
2057
|
if (bridgeRpc2) {
|
|
1780
2058
|
try {
|
|
1781
2059
|
const context = await bridgeRpc2("getTabContext");
|
|
1782
2060
|
const candidate = Number(context?.activeLogicalTabId || context?.logicalTabId || context?.id);
|
|
1783
|
-
if (Number.isFinite(candidate) && candidate > 0) {
|
|
2061
|
+
if (Number.isFinite(candidate) && candidate > 0 && isTabInScope(candidate)) {
|
|
1784
2062
|
activeTabId = candidate;
|
|
1785
2063
|
}
|
|
1786
2064
|
} catch {
|
|
1787
2065
|
}
|
|
1788
2066
|
}
|
|
1789
|
-
if (!
|
|
1790
|
-
|
|
1791
|
-
} else if (!tabIds.includes(activeTabId)) {
|
|
1792
|
-
tabIds = [activeTabId, ...tabIds];
|
|
2067
|
+
if (hasExplicitScope && !isTabInScope(activeTabId) && scopedOrder.length > 0) {
|
|
2068
|
+
activeTabId = scopedOrder[0];
|
|
1793
2069
|
}
|
|
1794
2070
|
const nowMs = Date.now();
|
|
1795
2071
|
const listedById = /* @__PURE__ */ new Map();
|
|
1796
2072
|
for (const tab of listedTabs)
|
|
1797
2073
|
listedById.set(tab.id, tab);
|
|
1798
|
-
const
|
|
2074
|
+
const freshRuntimeListedIds = listedTabs.filter((tab) => !!tab.runtimeId && nowMs - (tab.updatedAt || 0) <= staleRuntimeTabMaxAgeMs).map((tab) => tab.id);
|
|
2075
|
+
if (freshRuntimeListedIds.length > 0 && !freshRuntimeListedIds.includes(activeTabId)) {
|
|
2076
|
+
const freshestRuntimeTabId = [...freshRuntimeListedIds].sort((a, b) => Number(listedById.get(b)?.updatedAt || 0) - Number(listedById.get(a)?.updatedAt || 0))[0];
|
|
2077
|
+
if (Number.isFinite(freshestRuntimeTabId) && freshestRuntimeTabId > 0 && isTabInScope(freshestRuntimeTabId)) {
|
|
2078
|
+
activeTabId = freshestRuntimeTabId;
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
if (!tabIds.length) {
|
|
2082
|
+
tabIds = hasExplicitScope ? scopedOrder.length > 0 ? [...scopedOrder] : [activeTabId] : [activeTabId];
|
|
2083
|
+
} else if (!tabIds.includes(activeTabId)) {
|
|
2084
|
+
if (hasExplicitScope) {
|
|
2085
|
+
tabIds = scopedOrder.length > 0 ? [...scopedOrder] : tabIds;
|
|
2086
|
+
} else if (listedTabs.length > 0) {
|
|
2087
|
+
activeTabId = tabIds[0];
|
|
2088
|
+
} else {
|
|
2089
|
+
tabIds = [activeTabId, ...tabIds];
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
const baseOrder = hasExplicitScope ? [...scopedOrder] : listedTabs.length > 0 ? dedupePositiveTabIds(listedTabs.map((tab) => tab.id)) : [...tabIds];
|
|
2093
|
+
const prioritized = baseOrder.filter((tabId) => {
|
|
1799
2094
|
if (tabId === activeTabId)
|
|
1800
2095
|
return true;
|
|
1801
2096
|
const listed = listedById.get(tabId);
|
|
1802
|
-
if (!listed)
|
|
1803
|
-
return
|
|
2097
|
+
if (!listed) {
|
|
2098
|
+
return hasExplicitScope;
|
|
2099
|
+
}
|
|
1804
2100
|
if (listed.runtimeId) {
|
|
1805
2101
|
return nowMs - (listed.updatedAt || 0) <= staleRuntimeTabMaxAgeMs;
|
|
1806
2102
|
}
|
|
1807
|
-
if (
|
|
1808
|
-
return
|
|
1809
|
-
|
|
2103
|
+
if (listed.external) {
|
|
2104
|
+
return nowMs - (listed.updatedAt || 0) <= detachedExternalTabMaxAgeMs;
|
|
2105
|
+
}
|
|
2106
|
+
return nowMs - (listed.updatedAt || 0) <= staleRuntimeTabMaxAgeMs;
|
|
1810
2107
|
});
|
|
1811
|
-
let tabOrder = (prioritized.length ? prioritized :
|
|
1812
|
-
if (!
|
|
1813
|
-
|
|
2108
|
+
let tabOrder = hasExplicitScope ? preferScopedOrder(scopedOrder, activeTabId, maxContextTabs) : [...new Set(prioritized.length ? prioritized : baseOrder.length ? baseOrder : tabIds)];
|
|
2109
|
+
if (!hasExplicitScope) {
|
|
2110
|
+
if (tabOrder.includes(activeTabId)) {
|
|
2111
|
+
tabOrder = [activeTabId, ...tabOrder.filter((tabId) => tabId !== activeTabId)];
|
|
2112
|
+
} else {
|
|
2113
|
+
tabOrder = [activeTabId, ...tabOrder];
|
|
2114
|
+
}
|
|
2115
|
+
tabOrder = tabOrder.slice(0, maxContextTabs);
|
|
1814
2116
|
}
|
|
1815
2117
|
if (!tabOrder.length) {
|
|
1816
|
-
tabOrder = [activeTabId || 1];
|
|
2118
|
+
tabOrder = hasExplicitScope ? scopedOrder.length > 0 ? preferScopedOrder(scopedOrder, activeTabId || scopedOrder[0], maxContextTabs) : [activeTabId || 1] : [activeTabId || 1];
|
|
1817
2119
|
}
|
|
1818
2120
|
const tabMetaById = {};
|
|
1819
2121
|
for (const tab of fallbackSnapshots)
|
|
1820
2122
|
tabMetaById[tab.id] = tab;
|
|
1821
2123
|
for (const tab of listedTabs)
|
|
1822
2124
|
tabMetaById[tab.id] = { ...tabMetaById[tab.id] || {}, ...tab };
|
|
2125
|
+
for (const tabId of scopedOrder) {
|
|
2126
|
+
if (!tabMetaById[tabId]) {
|
|
2127
|
+
tabMetaById[tabId] = {
|
|
2128
|
+
id: tabId,
|
|
2129
|
+
accessMode: "live_dom",
|
|
2130
|
+
inaccessibleReason: "detached_runtime_placeholder"
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
1823
2134
|
for (const tabId of tabOrder) {
|
|
1824
|
-
if (!tabMetaById[tabId])
|
|
1825
|
-
tabMetaById[tabId] = {
|
|
2135
|
+
if (!tabMetaById[tabId]) {
|
|
2136
|
+
tabMetaById[tabId] = {
|
|
2137
|
+
id: tabId,
|
|
2138
|
+
accessMode: "live_dom",
|
|
2139
|
+
inaccessibleReason: "detached_runtime_placeholder"
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
const diagnostics = {
|
|
2144
|
+
hasExplicitScope,
|
|
2145
|
+
scopedTabIdsInput: scopedTabIds2,
|
|
2146
|
+
listedTabIds,
|
|
2147
|
+
keptScopedTabIds: scopedOrder,
|
|
2148
|
+
resolvedTabOrder: tabOrder
|
|
2149
|
+
};
|
|
2150
|
+
if (hasExplicitScope) {
|
|
2151
|
+
if (scopedOrder.length && !scopedTabSet.has(activeTabId)) {
|
|
2152
|
+
activeTabId = scopedOrder[0];
|
|
2153
|
+
}
|
|
2154
|
+
tabOrder = preferScopedOrder(scopedOrder, activeTabId, maxContextTabs);
|
|
2155
|
+
const scopedMeta = {};
|
|
2156
|
+
for (const tabId of scopedOrder) {
|
|
2157
|
+
scopedMeta[tabId] = tabMetaById[tabId] || { id: tabId };
|
|
2158
|
+
}
|
|
2159
|
+
options?.onDiagnostics?.({
|
|
2160
|
+
...diagnostics,
|
|
2161
|
+
resolvedTabOrder: tabOrder
|
|
2162
|
+
});
|
|
2163
|
+
return { tabOrder, activeTabId, tabMetaById: scopedMeta };
|
|
1826
2164
|
}
|
|
2165
|
+
options?.onDiagnostics?.(diagnostics);
|
|
1827
2166
|
return { tabOrder, activeTabId, tabMetaById };
|
|
1828
2167
|
}
|
|
1829
2168
|
|
|
1830
2169
|
// dist/agent/actAgent.js
|
|
1831
2170
|
var MAX_RETRIES = 3;
|
|
1832
|
-
|
|
2171
|
+
function dedupePositiveTabIds2(input) {
|
|
2172
|
+
if (!Array.isArray(input))
|
|
2173
|
+
return [];
|
|
2174
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2175
|
+
const out = [];
|
|
2176
|
+
for (const value of input) {
|
|
2177
|
+
const tabId = Number(value);
|
|
2178
|
+
if (!Number.isFinite(tabId) || tabId <= 0 || seen.has(tabId))
|
|
2179
|
+
continue;
|
|
2180
|
+
seen.add(tabId);
|
|
2181
|
+
out.push(tabId);
|
|
2182
|
+
}
|
|
2183
|
+
return out;
|
|
2184
|
+
}
|
|
1833
2185
|
async function executeAgenticSeek(options) {
|
|
1834
|
-
const { tabOrder, userInput, schema, previousSteps = [], plannerPrevSteps = [], files = [], chatLog = [], recordingContext, trajectoryId
|
|
2186
|
+
const { tabOrder, scopedTabIds: scopedTabIds2, seedTabId, onScopedTabIdsTouched, userInput, schema, previousSteps = [], plannerPrevSteps = [], files = [], chatLog = [], recordingContext, trajectoryId, onStatusUpdate, functionDeclarations, bridgeRpc: bridgeRpc2, ctx, onPrevStepsUpdate } = options;
|
|
1835
2187
|
if (!tabOrder?.length) {
|
|
1836
2188
|
return { error: "No tabs available for processing", warnings: ["No active tab found"] };
|
|
1837
2189
|
}
|
|
@@ -1839,26 +2191,48 @@ async function executeAgenticSeek(options) {
|
|
|
1839
2191
|
const allWarnings = [];
|
|
1840
2192
|
const accumulatedPrevSteps = Array.isArray(previousSteps) ? previousSteps : [];
|
|
1841
2193
|
const fallbackTabs = tabOrder.map((id) => ({ id }));
|
|
2194
|
+
let runtimeScopedTabIds = dedupePositiveTabIds2(scopedTabIds2 || []);
|
|
2195
|
+
if (Number(seedTabId) > 0 && !runtimeScopedTabIds.includes(Number(seedTabId))) {
|
|
2196
|
+
runtimeScopedTabIds.unshift(Number(seedTabId));
|
|
2197
|
+
}
|
|
2198
|
+
const touchScopedTabIds = (tabIds) => {
|
|
2199
|
+
const touched = dedupePositiveTabIds2(tabIds);
|
|
2200
|
+
if (!touched.length)
|
|
2201
|
+
return;
|
|
2202
|
+
const nextScoped = dedupePositiveTabIds2([...runtimeScopedTabIds, ...touched]);
|
|
2203
|
+
if (nextScoped.length === runtimeScopedTabIds.length && nextScoped.every((id, index) => id === runtimeScopedTabIds[index])) {
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
runtimeScopedTabIds = nextScoped;
|
|
2207
|
+
onScopedTabIdsTouched?.(nextScoped);
|
|
2208
|
+
};
|
|
1842
2209
|
let retry = 0;
|
|
1843
|
-
let iterations = 0;
|
|
1844
2210
|
let pageDataOptions;
|
|
1845
2211
|
while (retry < MAX_RETRIES) {
|
|
1846
|
-
if (iterations++ >= MAX_ITERATIONS) {
|
|
1847
|
-
return { error: "Max action iterations reached", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
1848
|
-
}
|
|
1849
2212
|
if (ctx.isCancelled?.()) {
|
|
1850
2213
|
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
1851
2214
|
}
|
|
1852
2215
|
try {
|
|
1853
2216
|
await waitWhilePaused(void 0);
|
|
2217
|
+
if (ctx.isCancelled?.()) {
|
|
2218
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2219
|
+
}
|
|
1854
2220
|
onStatusUpdate?.("Analyzing page content...", "Calling seek workflow", "analyze");
|
|
1855
|
-
const { tabOrder: runtimeTabOrder, activeTabId } = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs
|
|
2221
|
+
const { tabOrder: runtimeTabOrder, activeTabId } = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs, {
|
|
2222
|
+
scopedTabIds: runtimeScopedTabIds,
|
|
2223
|
+
seedTabId
|
|
2224
|
+
});
|
|
2225
|
+
if (ctx.isCancelled?.()) {
|
|
2226
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2227
|
+
}
|
|
1856
2228
|
const scopedTabOrder = runtimeTabOrder.length ? runtimeTabOrder : tabOrder;
|
|
1857
2229
|
const webPageMap = {};
|
|
1858
2230
|
try {
|
|
1859
2231
|
webPageMap[activeTabId] = await ctx.getPageData(activeTabId, {
|
|
1860
2232
|
...pageDataOptions || {},
|
|
1861
|
-
__roverAllowExternalFetch: true
|
|
2233
|
+
__roverAllowExternalFetch: true,
|
|
2234
|
+
__roverExternalIntent: "auto",
|
|
2235
|
+
__roverExternalMessage: userInput
|
|
1862
2236
|
});
|
|
1863
2237
|
} catch {
|
|
1864
2238
|
retry++;
|
|
@@ -1873,6 +2247,9 @@ async function executeAgenticSeek(options) {
|
|
|
1873
2247
|
return { tabId: currentTabId, pageData: void 0 };
|
|
1874
2248
|
}
|
|
1875
2249
|
}));
|
|
2250
|
+
if (ctx.isCancelled?.()) {
|
|
2251
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2252
|
+
}
|
|
1876
2253
|
for (const result of backgroundResults) {
|
|
1877
2254
|
if (result.pageData) {
|
|
1878
2255
|
webPageMap[result.tabId] = result.pageData;
|
|
@@ -1902,12 +2279,22 @@ async function executeAgenticSeek(options) {
|
|
|
1902
2279
|
functionDeclarations,
|
|
1903
2280
|
authToken: void 0,
|
|
1904
2281
|
timestamp: ctx.userTimestamp,
|
|
1905
|
-
trajectoryId
|
|
1906
|
-
userProfile: ctx.userProfile
|
|
2282
|
+
trajectoryId,
|
|
2283
|
+
userProfile: ctx.userProfile,
|
|
2284
|
+
stop: buildWorkerStopSignal({
|
|
2285
|
+
isCancelled: !!ctx.isCancelled?.()
|
|
2286
|
+
})
|
|
1907
2287
|
};
|
|
1908
2288
|
const response = await ctx.callExtensionRouter(SUB_AGENTS.processTabWorkflows, request);
|
|
2289
|
+
if (ctx.isCancelled?.()) {
|
|
2290
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2291
|
+
}
|
|
1909
2292
|
if (!response?.success) {
|
|
1910
|
-
return {
|
|
2293
|
+
return {
|
|
2294
|
+
error: response?.error || "Failed to process tab workflows",
|
|
2295
|
+
errorDetails: response?.errorDetails || void 0,
|
|
2296
|
+
creditsUsed: totalCreditsUsed
|
|
2297
|
+
};
|
|
1911
2298
|
}
|
|
1912
2299
|
const data = response.data;
|
|
1913
2300
|
totalCreditsUsed += data?.creditsUsed || 0;
|
|
@@ -1918,6 +2305,10 @@ async function executeAgenticSeek(options) {
|
|
|
1918
2305
|
}
|
|
1919
2306
|
if (tabResponse?.warnings?.length)
|
|
1920
2307
|
allWarnings.push(...tabResponse.warnings);
|
|
2308
|
+
if (tabResponse?.stopState && tabResponse.stopState !== "continue") {
|
|
2309
|
+
const stopReason = String(tabResponse.stopReason || tabResponse.error || "").trim() || `Execution stopped (${tabResponse.stopState})`;
|
|
2310
|
+
return { error: stopReason, prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed, warnings: allWarnings };
|
|
2311
|
+
}
|
|
1921
2312
|
if (tabResponse?.error) {
|
|
1922
2313
|
retry++;
|
|
1923
2314
|
continue;
|
|
@@ -1929,15 +2320,58 @@ async function executeAgenticSeek(options) {
|
|
|
1929
2320
|
prevSteps: accumulatedPrevSteps,
|
|
1930
2321
|
thought: tabResponse.thought,
|
|
1931
2322
|
bridgeRpc: bridgeRpc2,
|
|
2323
|
+
isCancelled: ctx.isCancelled,
|
|
1932
2324
|
userFunctionDeclarations: functionDeclarations,
|
|
1933
2325
|
onStatusUpdate,
|
|
1934
2326
|
onPrevStepsUpdate
|
|
1935
2327
|
});
|
|
2328
|
+
if (ctx.isCancelled?.()) {
|
|
2329
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2330
|
+
}
|
|
1936
2331
|
if (processResult.needsRetry) {
|
|
1937
2332
|
pageDataOptions = processResult.disableAutoScroll ? { disableAutoScroll: true } : void 0;
|
|
1938
2333
|
retry++;
|
|
1939
2334
|
continue;
|
|
1940
2335
|
}
|
|
2336
|
+
if (processResult.navigationOccurred) {
|
|
2337
|
+
const navigationOutcome = processResult.navigationOutcome;
|
|
2338
|
+
const logicalTabId = Number(processResult.logicalTabId);
|
|
2339
|
+
if (Number.isFinite(logicalTabId) && logicalTabId > 0) {
|
|
2340
|
+
touchScopedTabIds([logicalTabId]);
|
|
2341
|
+
}
|
|
2342
|
+
if (navigationOutcome === "new_tab_opened" || navigationOutcome === "switch_tab") {
|
|
2343
|
+
if (Number.isFinite(logicalTabId) && logicalTabId > 0) {
|
|
2344
|
+
try {
|
|
2345
|
+
await bridgeRpc2("executeTool", {
|
|
2346
|
+
call: {
|
|
2347
|
+
name: "switch_tab",
|
|
2348
|
+
args: {
|
|
2349
|
+
logical_tab_id: logicalTabId,
|
|
2350
|
+
tab_id: logicalTabId
|
|
2351
|
+
}
|
|
2352
|
+
},
|
|
2353
|
+
payload: {
|
|
2354
|
+
reason: "act_loop_navigation_continue"
|
|
2355
|
+
}
|
|
2356
|
+
});
|
|
2357
|
+
} catch {
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
pageDataOptions = processResult.disableAutoScroll ? { disableAutoScroll: true } : void 0;
|
|
2361
|
+
continue;
|
|
2362
|
+
}
|
|
2363
|
+
managePrevStepsSize(accumulatedPrevSteps);
|
|
2364
|
+
onPrevStepsUpdate?.(accumulatedPrevSteps);
|
|
2365
|
+
return {
|
|
2366
|
+
prevSteps: accumulatedPrevSteps,
|
|
2367
|
+
creditsUsed: totalCreditsUsed,
|
|
2368
|
+
warnings: allWarnings,
|
|
2369
|
+
navigationPending: true,
|
|
2370
|
+
navigationTool: processResult.navigationTool,
|
|
2371
|
+
navigationOutcome: processResult.navigationOutcome,
|
|
2372
|
+
logicalTabId: processResult.logicalTabId
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
1941
2375
|
if (processResult.data) {
|
|
1942
2376
|
managePrevStepsSize(accumulatedPrevSteps);
|
|
1943
2377
|
onPrevStepsUpdate?.(accumulatedPrevSteps);
|
|
@@ -1966,10 +2400,19 @@ async function executeAgenticSeek(options) {
|
|
|
1966
2400
|
}));
|
|
1967
2401
|
const functionResults = {};
|
|
1968
2402
|
for (const fc of functionCallsWithIds) {
|
|
2403
|
+
if (ctx.isCancelled?.()) {
|
|
2404
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2405
|
+
}
|
|
1969
2406
|
try {
|
|
1970
2407
|
const result = await bridgeRpc2("executeClientTool", { name: fc.name, args: fc.args });
|
|
2408
|
+
if (ctx.isCancelled?.()) {
|
|
2409
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2410
|
+
}
|
|
1971
2411
|
functionResults[fc.callId] = { success: true, result };
|
|
1972
2412
|
} catch (error) {
|
|
2413
|
+
if (ctx.isCancelled?.()) {
|
|
2414
|
+
return { error: "Run cancelled", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
2415
|
+
}
|
|
1973
2416
|
functionResults[fc.callId] = { success: false, error: { message: error?.message || String(error) } };
|
|
1974
2417
|
}
|
|
1975
2418
|
}
|
|
@@ -1984,7 +2427,12 @@ async function executeAgenticSeek(options) {
|
|
|
1984
2427
|
}
|
|
1985
2428
|
retry++;
|
|
1986
2429
|
if (retry >= MAX_RETRIES) {
|
|
1987
|
-
return {
|
|
2430
|
+
return {
|
|
2431
|
+
error: error?.message || "Agentic seek failed",
|
|
2432
|
+
errorDetails: error?.roverError || void 0,
|
|
2433
|
+
prevSteps: accumulatedPrevSteps,
|
|
2434
|
+
creditsUsed: totalCreditsUsed
|
|
2435
|
+
};
|
|
1988
2436
|
}
|
|
1989
2437
|
await new Promise((resolve) => setTimeout(resolve, 500 * retry));
|
|
1990
2438
|
}
|
|
@@ -1994,19 +2442,57 @@ async function executeAgenticSeek(options) {
|
|
|
1994
2442
|
|
|
1995
2443
|
// dist/agent/extractAgent.js
|
|
1996
2444
|
var MAX_RETRIES2 = 3;
|
|
2445
|
+
function dedupePositiveTabIds3(input) {
|
|
2446
|
+
if (!Array.isArray(input))
|
|
2447
|
+
return [];
|
|
2448
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2449
|
+
const out = [];
|
|
2450
|
+
for (const value of input) {
|
|
2451
|
+
const tabId = Number(value);
|
|
2452
|
+
if (!Number.isFinite(tabId) || tabId <= 0 || seen.has(tabId))
|
|
2453
|
+
continue;
|
|
2454
|
+
seen.add(tabId);
|
|
2455
|
+
out.push(tabId);
|
|
2456
|
+
}
|
|
2457
|
+
return out;
|
|
2458
|
+
}
|
|
1997
2459
|
async function executeExtract(options) {
|
|
1998
|
-
const { tabOrder, userInput, schema, outputDestination, trajectoryId
|
|
2460
|
+
const { tabOrder, scopedTabIds: scopedTabIds2, seedTabId, onScopedTabIdsTouched, userInput, schema, outputDestination, trajectoryId, recordingContext, plannerPrevSteps = [], files = [], onStatusUpdate, schemaHeaderSheetInfo, returnDataOnly, previousSteps = [], bridgeRpc: bridgeRpc2, ctx, onPrevStepsUpdate } = options;
|
|
1999
2461
|
if (!tabOrder?.length) {
|
|
2000
2462
|
return { error: "No tabs available for extraction", warnings: ["No active tab found"] };
|
|
2001
2463
|
}
|
|
2002
2464
|
let totalCreditsUsed = 0;
|
|
2003
2465
|
const warnings = [];
|
|
2004
2466
|
const fallbackTabs = tabOrder.map((id) => ({ id }));
|
|
2467
|
+
let runtimeScopedTabIds = dedupePositiveTabIds3(scopedTabIds2 || []);
|
|
2468
|
+
if (Number(seedTabId) > 0 && !runtimeScopedTabIds.includes(Number(seedTabId))) {
|
|
2469
|
+
runtimeScopedTabIds.unshift(Number(seedTabId));
|
|
2470
|
+
}
|
|
2471
|
+
const touchScopedTabIds = (tabIds) => {
|
|
2472
|
+
const touched = dedupePositiveTabIds3(tabIds);
|
|
2473
|
+
if (!touched.length)
|
|
2474
|
+
return;
|
|
2475
|
+
const nextScoped = dedupePositiveTabIds3([...runtimeScopedTabIds, ...touched]);
|
|
2476
|
+
if (nextScoped.length === runtimeScopedTabIds.length && nextScoped.every((id, index) => id === runtimeScopedTabIds[index])) {
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2479
|
+
runtimeScopedTabIds = nextScoped;
|
|
2480
|
+
onScopedTabIdsTouched?.(nextScoped);
|
|
2481
|
+
};
|
|
2005
2482
|
const prevSteps = Array.isArray(previousSteps) ? previousSteps : [];
|
|
2006
2483
|
let pageDataOptions;
|
|
2007
2484
|
for (let retry = 0; retry < MAX_RETRIES2; retry++) {
|
|
2008
2485
|
await waitWhilePaused(void 0);
|
|
2009
|
-
|
|
2486
|
+
if (ctx.isCancelled?.()) {
|
|
2487
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2488
|
+
}
|
|
2489
|
+
const { activeTabId } = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs, {
|
|
2490
|
+
scopedTabIds: runtimeScopedTabIds,
|
|
2491
|
+
seedTabId
|
|
2492
|
+
});
|
|
2493
|
+
if (ctx.isCancelled?.()) {
|
|
2494
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2495
|
+
}
|
|
2010
2496
|
const tabId = activeTabId;
|
|
2011
2497
|
let pageData;
|
|
2012
2498
|
try {
|
|
@@ -2029,14 +2515,20 @@ async function executeExtract(options) {
|
|
|
2029
2515
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
2030
2516
|
authToken: void 0,
|
|
2031
2517
|
timestamp: ctx.userTimestamp,
|
|
2032
|
-
trajectoryId
|
|
2518
|
+
trajectoryId,
|
|
2033
2519
|
userProfile: ctx.userProfile,
|
|
2034
2520
|
recordingContext,
|
|
2035
2521
|
files,
|
|
2036
|
-
returnDataOnly
|
|
2522
|
+
returnDataOnly,
|
|
2523
|
+
stop: buildWorkerStopSignal({
|
|
2524
|
+
isCancelled: !!ctx.isCancelled?.()
|
|
2525
|
+
})
|
|
2037
2526
|
};
|
|
2038
2527
|
onStatusUpdate?.("Extracting data...", "Calling extract sub-agent", "execute");
|
|
2039
2528
|
const response = await ctx.callExtensionRouter(SUB_AGENTS.extract, request);
|
|
2529
|
+
if (ctx.isCancelled?.()) {
|
|
2530
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2531
|
+
}
|
|
2040
2532
|
if (!response?.success) {
|
|
2041
2533
|
return { error: response?.error || "Extract request failed", creditsUsed: totalCreditsUsed };
|
|
2042
2534
|
}
|
|
@@ -2055,6 +2547,10 @@ async function executeExtract(options) {
|
|
|
2055
2547
|
}
|
|
2056
2548
|
const tabResponse = data?.tabResponses?.[activeTabId];
|
|
2057
2549
|
if (tabResponse) {
|
|
2550
|
+
if (tabResponse?.stopState && tabResponse.stopState !== "continue") {
|
|
2551
|
+
const stopReason = String(tabResponse.stopReason || tabResponse.error || "").trim() || `Execution stopped (${tabResponse.stopState})`;
|
|
2552
|
+
return { error: stopReason, prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2553
|
+
}
|
|
2058
2554
|
const processResult = await processActionResponse({
|
|
2059
2555
|
request,
|
|
2060
2556
|
response: tabResponse,
|
|
@@ -2062,12 +2558,22 @@ async function executeExtract(options) {
|
|
|
2062
2558
|
prevSteps,
|
|
2063
2559
|
thought: tabResponse.thought,
|
|
2064
2560
|
bridgeRpc: bridgeRpc2,
|
|
2561
|
+
isCancelled: ctx.isCancelled,
|
|
2065
2562
|
onPrevStepsUpdate
|
|
2066
2563
|
});
|
|
2564
|
+
if (ctx.isCancelled?.()) {
|
|
2565
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2566
|
+
}
|
|
2067
2567
|
if (processResult.needsRetry) {
|
|
2068
2568
|
pageDataOptions = processResult.disableAutoScroll ? { disableAutoScroll: true } : void 0;
|
|
2069
2569
|
continue;
|
|
2070
2570
|
}
|
|
2571
|
+
if (processResult.navigationOccurred) {
|
|
2572
|
+
const logicalTabId = Number(processResult.logicalTabId);
|
|
2573
|
+
if (Number.isFinite(logicalTabId) && logicalTabId > 0) {
|
|
2574
|
+
touchScopedTabIds([logicalTabId]);
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2071
2577
|
pageDataOptions = processResult.disableAutoScroll ? { disableAutoScroll: true } : void 0;
|
|
2072
2578
|
if (processResult.data) {
|
|
2073
2579
|
return {
|
|
@@ -2080,9 +2586,18 @@ async function executeExtract(options) {
|
|
|
2080
2586
|
}
|
|
2081
2587
|
if (processResult.functionCalls?.length) {
|
|
2082
2588
|
for (const fc of processResult.functionCalls) {
|
|
2589
|
+
if (ctx.isCancelled?.()) {
|
|
2590
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2591
|
+
}
|
|
2083
2592
|
try {
|
|
2084
2593
|
await bridgeRpc2("executeClientTool", { name: fc.name, args: fc.args });
|
|
2594
|
+
if (ctx.isCancelled?.()) {
|
|
2595
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2596
|
+
}
|
|
2085
2597
|
} catch {
|
|
2598
|
+
if (ctx.isCancelled?.()) {
|
|
2599
|
+
return { error: "Run cancelled", prevSteps, creditsUsed: totalCreditsUsed, warnings };
|
|
2600
|
+
}
|
|
2086
2601
|
}
|
|
2087
2602
|
}
|
|
2088
2603
|
}
|
|
@@ -2258,8 +2773,14 @@ function attachSheetData(store, sheetInfo) {
|
|
|
2258
2773
|
|
|
2259
2774
|
// dist/agent/sheetsWorkflowAgent.js
|
|
2260
2775
|
async function executeSheetsWorkflow(options) {
|
|
2261
|
-
const { workflow, userInput, trajectoryId
|
|
2776
|
+
const { workflow, userInput, trajectoryId, plannerPrevSteps, agentLog, files, onStatusUpdate, ctx, bridgeRpc: bridgeRpc2, driveAuthToken } = options;
|
|
2777
|
+
const throwIfCancelled2 = () => {
|
|
2778
|
+
if (!ctx.isCancelled?.())
|
|
2779
|
+
return;
|
|
2780
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
2781
|
+
};
|
|
2262
2782
|
try {
|
|
2783
|
+
throwIfCancelled2();
|
|
2263
2784
|
const sourceSheetInfo = workflow.sourceSheetFromHistory ? resolveHistorySheetInfo(workflow.sourceSheetFromHistory, plannerPrevSteps) : void 0;
|
|
2264
2785
|
let sheetId = sourceSheetInfo?.sheetId || workflow.sheetId;
|
|
2265
2786
|
let sheetTabTitle = sourceSheetInfo?.sheetTab || workflow.sheetTabTitle;
|
|
@@ -2293,6 +2814,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2293
2814
|
if (!sheetTabTitle) {
|
|
2294
2815
|
return { error: "Could not resolve sheet tab title for workflow." };
|
|
2295
2816
|
}
|
|
2817
|
+
throwIfCancelled2();
|
|
2296
2818
|
onStatusUpdate?.("Loading sheet rows...", sheetTabTitle, "analyze");
|
|
2297
2819
|
grid = await fetchWorkflowSheetTabDataSmart(sheetId, sheetTabTitle, getAuthToken) || [];
|
|
2298
2820
|
}
|
|
@@ -2311,6 +2833,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2311
2833
|
const outputRows = [];
|
|
2312
2834
|
const newTabOutputs = {};
|
|
2313
2835
|
for (let rowIdx = startRow; rowIdx < endRow; rowIdx++) {
|
|
2836
|
+
throwIfCancelled2();
|
|
2314
2837
|
const row = dataRows[rowIdx] || [];
|
|
2315
2838
|
const rowData = buildRowData(header, row);
|
|
2316
2839
|
const context = buildContextData(header, row, contextIndices);
|
|
@@ -2323,11 +2846,13 @@ async function executeSheetsWorkflow(options) {
|
|
|
2323
2846
|
const stepOutputs = {};
|
|
2324
2847
|
const rowOutputValues = [];
|
|
2325
2848
|
for (const step of workflow.workflowSteps) {
|
|
2849
|
+
throwIfCancelled2();
|
|
2326
2850
|
const stepName = step.stepName || step.tool;
|
|
2327
2851
|
const resolvedUserInput = resolveTemplate(step.userInputTemplate || userInput, rowContext, stepOutputs);
|
|
2328
2852
|
if (step.tabManagement?.urlTemplate) {
|
|
2329
2853
|
const targetUrl = resolveTemplate(step.tabManagement.urlTemplate, rowContext, stepOutputs);
|
|
2330
2854
|
if (targetUrl) {
|
|
2855
|
+
throwIfCancelled2();
|
|
2331
2856
|
await bridgeRpc2("executeTool", { call: { name: "goto_url", args: { tab_id: 0, url: targetUrl } } });
|
|
2332
2857
|
}
|
|
2333
2858
|
}
|
|
@@ -2335,7 +2860,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2335
2860
|
const stepResult = await executeWorkflowStep({
|
|
2336
2861
|
step,
|
|
2337
2862
|
userInput: resolvedUserInput,
|
|
2338
|
-
trajectoryId
|
|
2863
|
+
trajectoryId,
|
|
2339
2864
|
plannerPrevSteps,
|
|
2340
2865
|
agentLog,
|
|
2341
2866
|
files,
|
|
@@ -2346,6 +2871,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2346
2871
|
toolArgs: resolvedToolArgs
|
|
2347
2872
|
});
|
|
2348
2873
|
stepOutputs[stepName] = stepResult;
|
|
2874
|
+
throwIfCancelled2();
|
|
2349
2875
|
if (step.outputMapping === SheetOutputFormat.CONTEXT) {
|
|
2350
2876
|
continue;
|
|
2351
2877
|
}
|
|
@@ -2364,6 +2890,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2364
2890
|
outputRows.push(rowOutputValues);
|
|
2365
2891
|
}
|
|
2366
2892
|
if (useMemory) {
|
|
2893
|
+
throwIfCancelled2();
|
|
2367
2894
|
const store = ctx.tabularStore;
|
|
2368
2895
|
const baseTab = sheetTabId !== void 0 ? store.getTab(sheetId, sheetTabId) : store.getTabByTitle(sheetId, sheetTabTitle) || store.getTab(sheetId, 0);
|
|
2369
2896
|
if (outputColumnHeaders.length) {
|
|
@@ -2402,6 +2929,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2402
2929
|
};
|
|
2403
2930
|
}
|
|
2404
2931
|
if (outputColumnHeaders.length) {
|
|
2932
|
+
throwIfCancelled2();
|
|
2405
2933
|
await appendColumnsToSheet({
|
|
2406
2934
|
sheetId,
|
|
2407
2935
|
sheetTabTitle,
|
|
@@ -2413,6 +2941,7 @@ async function executeSheetsWorkflow(options) {
|
|
|
2413
2941
|
});
|
|
2414
2942
|
}
|
|
2415
2943
|
for (const [stepName, rows] of Object.entries(newTabOutputs)) {
|
|
2944
|
+
throwIfCancelled2();
|
|
2416
2945
|
const title = truncateTabTitle(stepName);
|
|
2417
2946
|
const newTitle = await createSheetTab(sheetId, title, getAuthToken);
|
|
2418
2947
|
const headerRowValues = buildNewTabHeader(rows);
|
|
@@ -2443,7 +2972,10 @@ async function executeSheetsWorkflow(options) {
|
|
|
2443
2972
|
return { error: error?.message || String(error) };
|
|
2444
2973
|
}
|
|
2445
2974
|
}
|
|
2446
|
-
async function executeWorkflowStep({ step, userInput, trajectoryId
|
|
2975
|
+
async function executeWorkflowStep({ step, userInput, trajectoryId, plannerPrevSteps, agentLog, files, onStatusUpdate, ctx, bridgeRpc: bridgeRpc2, driveAuthToken, toolArgs }) {
|
|
2976
|
+
if (ctx.isCancelled?.()) {
|
|
2977
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
2978
|
+
}
|
|
2447
2979
|
const toolName = step.tool;
|
|
2448
2980
|
if (toolName === PLANNER_FUNCTION_CALLS.PROCESS_TEXT) {
|
|
2449
2981
|
const result = await executeToolFromPlan({
|
|
@@ -2455,7 +2987,7 @@ async function executeWorkflowStep({ step, userInput, trajectoryId: trajectoryId
|
|
|
2455
2987
|
},
|
|
2456
2988
|
userInput,
|
|
2457
2989
|
tabs: [{ id: 1 }],
|
|
2458
|
-
trajectoryId
|
|
2990
|
+
trajectoryId,
|
|
2459
2991
|
plannerPrevSteps,
|
|
2460
2992
|
agentLog,
|
|
2461
2993
|
files,
|
|
@@ -2480,7 +3012,7 @@ async function executeWorkflowStep({ step, userInput, trajectoryId: trajectoryId
|
|
|
2480
3012
|
},
|
|
2481
3013
|
userInput,
|
|
2482
3014
|
tabs: [{ id: 1 }],
|
|
2483
|
-
trajectoryId
|
|
3015
|
+
trajectoryId,
|
|
2484
3016
|
plannerPrevSteps,
|
|
2485
3017
|
agentLog,
|
|
2486
3018
|
files,
|
|
@@ -2495,7 +3027,13 @@ async function executeWorkflowStep({ step, userInput, trajectoryId: trajectoryId
|
|
|
2495
3027
|
return result.output ?? result;
|
|
2496
3028
|
}
|
|
2497
3029
|
if (toolArgs || step.toolArgs || typeof toolName === "string") {
|
|
3030
|
+
if (ctx.isCancelled?.()) {
|
|
3031
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
3032
|
+
}
|
|
2498
3033
|
const result = await bridgeRpc2("executeClientTool", { name: toolName, args: toolArgs || step.toolArgs || {} });
|
|
3034
|
+
if (ctx.isCancelled?.()) {
|
|
3035
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
3036
|
+
}
|
|
2499
3037
|
return result;
|
|
2500
3038
|
}
|
|
2501
3039
|
return { error: `Unsupported step tool: ${toolName}` };
|
|
@@ -2757,28 +3295,98 @@ function normalizeAgentLog(agentLog) {
|
|
|
2757
3295
|
continue;
|
|
2758
3296
|
dedupedChatLog.push(entry);
|
|
2759
3297
|
}
|
|
2760
|
-
|
|
2761
|
-
const
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
3298
|
+
let chatLog = dedupedChatLog.slice(-MAX_AGENT_CHATLOG_ENTRIES);
|
|
3299
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3300
|
+
const compactedReverse = [];
|
|
3301
|
+
for (let i = chatLog.length - 1; i >= 0; i -= 1) {
|
|
3302
|
+
const entry = chatLog[i];
|
|
3303
|
+
const key = `${entry.role}::${entry.message.toLowerCase()}`;
|
|
3304
|
+
if (seen.has(key))
|
|
3305
|
+
continue;
|
|
3306
|
+
seen.add(key);
|
|
3307
|
+
compactedReverse.push(entry);
|
|
2768
3308
|
}
|
|
3309
|
+
chatLog = compactedReverse.reverse();
|
|
2769
3310
|
if (chatLog.length > MAX_AGENT_CHATLOG_ENTRIES) {
|
|
2770
3311
|
chatLog = chatLog.slice(-MAX_AGENT_CHATLOG_ENTRIES);
|
|
2771
3312
|
}
|
|
2772
3313
|
return { prevSteps, chatLog };
|
|
2773
3314
|
}
|
|
3315
|
+
function isExecutionCancelled(ctx) {
|
|
3316
|
+
if (!ctx?.isCancelled)
|
|
3317
|
+
return false;
|
|
3318
|
+
try {
|
|
3319
|
+
return !!ctx.isCancelled();
|
|
3320
|
+
} catch {
|
|
3321
|
+
return false;
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
function throwIfExecutionCancelled(ctx) {
|
|
3325
|
+
if (!isExecutionCancelled(ctx))
|
|
3326
|
+
return;
|
|
3327
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
3328
|
+
}
|
|
3329
|
+
function cancelledToolResult() {
|
|
3330
|
+
return { error: "Run cancelled" };
|
|
3331
|
+
}
|
|
3332
|
+
async function executeRoverExternalContextPlannerTool(params) {
|
|
3333
|
+
const bridge = params.bridgeRpc;
|
|
3334
|
+
if (!bridge) {
|
|
3335
|
+
return { error: `Bridge RPC unavailable for ${params.toolName}` };
|
|
3336
|
+
}
|
|
3337
|
+
const message = String(params.toolArgs?.message || params.toolArgs?.user_input || params.toolArgs?.task_instruction || params.userInput || "").trim();
|
|
3338
|
+
params.onStatusUpdate?.(params.toolName === PLANNER_FUNCTION_CALLS.ROVER_EXTERNAL_ACT_CONTEXT ? "Fetching external action context..." : "Fetching external context...", `Calling ${params.toolName}`, "execute");
|
|
3339
|
+
const routedResponse = await bridge("executeTool", {
|
|
3340
|
+
call: {
|
|
3341
|
+
name: params.toolName,
|
|
3342
|
+
args: {
|
|
3343
|
+
...params.toolArgs,
|
|
3344
|
+
...message ? { message } : {}
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
});
|
|
3348
|
+
const success = routedResponse?.success === true;
|
|
3349
|
+
if (!success) {
|
|
3350
|
+
const errorMessage = String(routedResponse?.output?.error?.message || routedResponse?.error || `${params.toolName} failed`);
|
|
3351
|
+
return {
|
|
3352
|
+
error: errorMessage,
|
|
3353
|
+
output: routedResponse?.output,
|
|
3354
|
+
warnings: errorMessage ? [errorMessage] : void 0
|
|
3355
|
+
};
|
|
3356
|
+
}
|
|
3357
|
+
return {
|
|
3358
|
+
output: routedResponse?.output,
|
|
3359
|
+
warnings: Array.isArray(routedResponse?.output?.warnings) ? routedResponse.output.warnings : void 0
|
|
3360
|
+
};
|
|
3361
|
+
}
|
|
3362
|
+
async function callExtensionRouterWithCancel(ctx, action, request) {
|
|
3363
|
+
throwIfExecutionCancelled(ctx);
|
|
3364
|
+
const response = await ctx.callExtensionRouter(action, request);
|
|
3365
|
+
throwIfExecutionCancelled(ctx);
|
|
3366
|
+
return response;
|
|
3367
|
+
}
|
|
2774
3368
|
async function executeToolFromPlan(context) {
|
|
2775
|
-
const { toolName, toolArgs, userInput, tabs,
|
|
3369
|
+
const { toolName, toolArgs, userInput, tabs, scopedTabIds: scopedTabIds2, seedTabId, getScopedTabRuntimeContext, onScopedTabIdsTouched, trajectoryId, plannerPrevSteps, files, onStatusUpdate, recordingContext, toolFunctions, bridgeRpc: bridgeRpc2, ctx, functionDeclarations, driveAuthToken, agentLog, onPrevStepsUpdate } = context;
|
|
2776
3370
|
const effectiveCtx = ctx;
|
|
2777
3371
|
if (!effectiveCtx) {
|
|
2778
3372
|
return { error: "Agent context unavailable" };
|
|
2779
3373
|
}
|
|
3374
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3375
|
+
return cancelledToolResult();
|
|
3376
|
+
}
|
|
2780
3377
|
const fallbackTabs = Array.isArray(tabs) && tabs.length ? tabs : [{ id: 1 }];
|
|
2781
|
-
const
|
|
3378
|
+
const runtimeScope = getScopedTabRuntimeContext?.() || {};
|
|
3379
|
+
const scopedTabIdsInput = runtimeScope.scopedTabIds ?? scopedTabIds2;
|
|
3380
|
+
const seedTabIdInput = runtimeScope.seedTabId ?? seedTabId;
|
|
3381
|
+
const resolvedScopedTabIds = Array.isArray(scopedTabIdsInput) && scopedTabIdsInput.length ? Array.from(new Set(scopedTabIdsInput.map((tabId) => Number(tabId)).filter((tabId) => Number.isFinite(tabId) && tabId > 0))) : Array.from(new Set(fallbackTabs.map((tab) => Number(tab?.id)).filter((tabId) => Number.isFinite(tabId) && tabId > 0)));
|
|
3382
|
+
const resolvedSeedTabId = Number(seedTabIdInput) > 0 ? Number(seedTabIdInput) : resolvedScopedTabIds[0];
|
|
3383
|
+
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs, {
|
|
3384
|
+
scopedTabIds: resolvedScopedTabIds,
|
|
3385
|
+
seedTabId: resolvedSeedTabId
|
|
3386
|
+
});
|
|
3387
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3388
|
+
return cancelledToolResult();
|
|
3389
|
+
}
|
|
2782
3390
|
const tabOrder = resolvedTabs.tabOrder.length ? resolvedTabs.tabOrder : fallbackTabs.map((tab) => tab.id);
|
|
2783
3391
|
const effectiveAgentLog = normalizeAgentLog(agentLog);
|
|
2784
3392
|
try {
|
|
@@ -2787,6 +3395,9 @@ async function executeToolFromPlan(context) {
|
|
|
2787
3395
|
const prompt = toolArgs?.user_input || toolArgs?.prompt || toolArgs?.task_instruction || userInput;
|
|
2788
3396
|
const actResult = await executeAgenticSeek({
|
|
2789
3397
|
tabOrder,
|
|
3398
|
+
scopedTabIds: resolvedScopedTabIds,
|
|
3399
|
+
seedTabId: resolvedSeedTabId,
|
|
3400
|
+
onScopedTabIdsTouched,
|
|
2790
3401
|
userInput: prompt,
|
|
2791
3402
|
schema: toolArgs?.schema,
|
|
2792
3403
|
previousSteps: effectiveAgentLog.prevSteps,
|
|
@@ -2794,7 +3405,7 @@ async function executeToolFromPlan(context) {
|
|
|
2794
3405
|
files,
|
|
2795
3406
|
chatLog: effectiveAgentLog.chatLog,
|
|
2796
3407
|
recordingContext,
|
|
2797
|
-
trajectoryId
|
|
3408
|
+
trajectoryId,
|
|
2798
3409
|
onStatusUpdate,
|
|
2799
3410
|
functionDeclarations,
|
|
2800
3411
|
bridgeRpc: bridgeRpc2,
|
|
@@ -2805,6 +3416,13 @@ async function executeToolFromPlan(context) {
|
|
|
2805
3416
|
status: "waiting_input",
|
|
2806
3417
|
needsUserInput: true,
|
|
2807
3418
|
questions: Array.isArray(actResult.questions) ? actResult.questions : []
|
|
3419
|
+
} : actResult.navigationPending ? {
|
|
3420
|
+
status: "in_progress",
|
|
3421
|
+
taskStatus: "in_progress",
|
|
3422
|
+
navigationPending: true,
|
|
3423
|
+
navigationTool: actResult.navigationTool,
|
|
3424
|
+
navigationOutcome: actResult.navigationOutcome,
|
|
3425
|
+
logicalTabId: actResult.logicalTabId
|
|
2808
3426
|
} : void 0);
|
|
2809
3427
|
return { ...actResult, output: actOutput };
|
|
2810
3428
|
}
|
|
@@ -2816,6 +3434,9 @@ async function executeToolFromPlan(context) {
|
|
|
2816
3434
|
const returnDataOnly = toolArgs?.return_data_only ?? toolArgs?.returnDataOnly ?? shouldMemory;
|
|
2817
3435
|
const extractResult = await executeExtract({
|
|
2818
3436
|
tabOrder,
|
|
3437
|
+
scopedTabIds: resolvedScopedTabIds,
|
|
3438
|
+
seedTabId: resolvedSeedTabId,
|
|
3439
|
+
onScopedTabIdsTouched,
|
|
2819
3440
|
userInput: prompt,
|
|
2820
3441
|
schema: toolArgs?.schema,
|
|
2821
3442
|
outputDestination,
|
|
@@ -2824,7 +3445,7 @@ async function executeToolFromPlan(context) {
|
|
|
2824
3445
|
files,
|
|
2825
3446
|
recordingContext,
|
|
2826
3447
|
previousSteps: effectiveAgentLog.prevSteps,
|
|
2827
|
-
trajectoryId
|
|
3448
|
+
trajectoryId,
|
|
2828
3449
|
returnDataOnly,
|
|
2829
3450
|
onStatusUpdate,
|
|
2830
3451
|
bridgeRpc: bridgeRpc2,
|
|
@@ -2871,7 +3492,7 @@ async function executeToolFromPlan(context) {
|
|
|
2871
3492
|
files,
|
|
2872
3493
|
recordingContext,
|
|
2873
3494
|
previousSteps: effectiveAgentLog.prevSteps,
|
|
2874
|
-
trajectoryId
|
|
3495
|
+
trajectoryId,
|
|
2875
3496
|
onStatusUpdate,
|
|
2876
3497
|
returnDataOnly,
|
|
2877
3498
|
bridgeRpc: bridgeRpc2,
|
|
@@ -2913,13 +3534,23 @@ async function executeToolFromPlan(context) {
|
|
|
2913
3534
|
schema: toolArgs?.schema,
|
|
2914
3535
|
plannerPrevSteps,
|
|
2915
3536
|
files,
|
|
2916
|
-
trajectoryId
|
|
3537
|
+
trajectoryId,
|
|
2917
3538
|
onStatusUpdate,
|
|
2918
3539
|
agentLog: effectiveAgentLog,
|
|
2919
3540
|
ctx: effectiveCtx,
|
|
2920
3541
|
driveAuthToken: toolArgs?.authToken || toolArgs?.driveAuthToken || driveAuthToken
|
|
2921
3542
|
});
|
|
2922
3543
|
}
|
|
3544
|
+
case PLANNER_FUNCTION_CALLS.ROVER_EXTERNAL_READ_CONTEXT:
|
|
3545
|
+
case PLANNER_FUNCTION_CALLS.ROVER_EXTERNAL_ACT_CONTEXT: {
|
|
3546
|
+
return executeRoverExternalContextPlannerTool({
|
|
3547
|
+
toolName,
|
|
3548
|
+
toolArgs: toolArgs || {},
|
|
3549
|
+
userInput,
|
|
3550
|
+
bridgeRpc: bridgeRpc2,
|
|
3551
|
+
onStatusUpdate
|
|
3552
|
+
});
|
|
3553
|
+
}
|
|
2923
3554
|
case PLANNER_FUNCTION_CALLS.CREATE_SHEET_FROM_DATA: {
|
|
2924
3555
|
const dataInputs = toolArgs?.data_inputs || toolArgs?.dataInputs || [];
|
|
2925
3556
|
const taskInstruction = toolArgs?.task_instruction || toolArgs?.taskInstruction || userInput;
|
|
@@ -2930,7 +3561,7 @@ async function executeToolFromPlan(context) {
|
|
|
2930
3561
|
outputSheetParameters: toolArgs?.output_sheet_parameters || toolArgs?.outputSheetParameters,
|
|
2931
3562
|
plannerPrevSteps,
|
|
2932
3563
|
files,
|
|
2933
|
-
trajectoryId
|
|
3564
|
+
trajectoryId,
|
|
2934
3565
|
onStatusUpdate,
|
|
2935
3566
|
agentLog: effectiveAgentLog,
|
|
2936
3567
|
ctx: effectiveCtx,
|
|
@@ -2942,7 +3573,7 @@ async function executeToolFromPlan(context) {
|
|
|
2942
3573
|
toolArgs,
|
|
2943
3574
|
plannerPrevSteps,
|
|
2944
3575
|
files,
|
|
2945
|
-
trajectoryId
|
|
3576
|
+
trajectoryId,
|
|
2946
3577
|
onStatusUpdate,
|
|
2947
3578
|
agentLog: effectiveAgentLog,
|
|
2948
3579
|
ctx: effectiveCtx,
|
|
@@ -2951,7 +3582,7 @@ async function executeToolFromPlan(context) {
|
|
|
2951
3582
|
}
|
|
2952
3583
|
case PLANNER_FUNCTION_CALLS.QUERY_RTRVR_AI_DOCUMENTATION: {
|
|
2953
3584
|
const userQuestion = toolArgs?.user_question || toolArgs?.userQuestion || userInput;
|
|
2954
|
-
return executeQueryDocs({ userQuestion, trajectoryId
|
|
3585
|
+
return executeQueryDocs({ userQuestion, trajectoryId, plannerPrevSteps, onStatusUpdate, agentLog: effectiveAgentLog, ctx: effectiveCtx });
|
|
2955
3586
|
}
|
|
2956
3587
|
case PLANNER_FUNCTION_CALLS.GOOGLE_DOC_GENERATOR: {
|
|
2957
3588
|
const prompt = toolArgs?.user_input || toolArgs?.prompt || toolArgs?.task_instruction || userInput;
|
|
@@ -2961,7 +3592,7 @@ async function executeToolFromPlan(context) {
|
|
|
2961
3592
|
tabOrder,
|
|
2962
3593
|
plannerPrevSteps,
|
|
2963
3594
|
files,
|
|
2964
|
-
trajectoryId
|
|
3595
|
+
trajectoryId,
|
|
2965
3596
|
onStatusUpdate,
|
|
2966
3597
|
agentLog: effectiveAgentLog,
|
|
2967
3598
|
ctx: effectiveCtx,
|
|
@@ -2976,7 +3607,7 @@ async function executeToolFromPlan(context) {
|
|
|
2976
3607
|
tabOrder,
|
|
2977
3608
|
plannerPrevSteps,
|
|
2978
3609
|
files,
|
|
2979
|
-
trajectoryId
|
|
3610
|
+
trajectoryId,
|
|
2980
3611
|
onStatusUpdate,
|
|
2981
3612
|
agentLog: effectiveAgentLog,
|
|
2982
3613
|
ctx: effectiveCtx,
|
|
@@ -2991,7 +3622,7 @@ async function executeToolFromPlan(context) {
|
|
|
2991
3622
|
tabOrder,
|
|
2992
3623
|
plannerPrevSteps,
|
|
2993
3624
|
files,
|
|
2994
|
-
trajectoryId
|
|
3625
|
+
trajectoryId,
|
|
2995
3626
|
onStatusUpdate,
|
|
2996
3627
|
agentLog: effectiveAgentLog,
|
|
2997
3628
|
ctx: effectiveCtx
|
|
@@ -3005,7 +3636,7 @@ async function executeToolFromPlan(context) {
|
|
|
3005
3636
|
tabOrder,
|
|
3006
3637
|
plannerPrevSteps,
|
|
3007
3638
|
files,
|
|
3008
|
-
trajectoryId
|
|
3639
|
+
trajectoryId,
|
|
3009
3640
|
onStatusUpdate,
|
|
3010
3641
|
agentLog: effectiveAgentLog,
|
|
3011
3642
|
ctx: effectiveCtx,
|
|
@@ -3018,7 +3649,7 @@ async function executeToolFromPlan(context) {
|
|
|
3018
3649
|
userInput: prompt,
|
|
3019
3650
|
plannerPrevSteps,
|
|
3020
3651
|
files,
|
|
3021
|
-
trajectoryId
|
|
3652
|
+
trajectoryId,
|
|
3022
3653
|
onStatusUpdate,
|
|
3023
3654
|
agentLog: effectiveAgentLog,
|
|
3024
3655
|
ctx: effectiveCtx
|
|
@@ -3029,7 +3660,7 @@ async function executeToolFromPlan(context) {
|
|
|
3029
3660
|
return executeSheetsWorkflow({
|
|
3030
3661
|
workflow,
|
|
3031
3662
|
userInput,
|
|
3032
|
-
trajectoryId
|
|
3663
|
+
trajectoryId,
|
|
3033
3664
|
plannerPrevSteps,
|
|
3034
3665
|
files,
|
|
3035
3666
|
onStatusUpdate,
|
|
@@ -3047,6 +3678,9 @@ async function executeToolFromPlan(context) {
|
|
|
3047
3678
|
const results = [];
|
|
3048
3679
|
if (Array.isArray(toolCalls)) {
|
|
3049
3680
|
for (const call of toolCalls) {
|
|
3681
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3682
|
+
return { error: "Run cancelled", output: results };
|
|
3683
|
+
}
|
|
3050
3684
|
const name = call.tool_name || call.name;
|
|
3051
3685
|
const args = call.tool_args || call.args || {};
|
|
3052
3686
|
try {
|
|
@@ -3056,8 +3690,14 @@ async function executeToolFromPlan(context) {
|
|
|
3056
3690
|
} else {
|
|
3057
3691
|
res = await bridgeRpc2?.("executeClientTool", { name, args });
|
|
3058
3692
|
}
|
|
3693
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3694
|
+
return { error: "Run cancelled", output: results };
|
|
3695
|
+
}
|
|
3059
3696
|
results.push({ name, result: res, success: true });
|
|
3060
3697
|
} catch (error) {
|
|
3698
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3699
|
+
return { error: "Run cancelled", output: results };
|
|
3700
|
+
}
|
|
3061
3701
|
results.push({ name, error: error?.message || String(error), success: false });
|
|
3062
3702
|
}
|
|
3063
3703
|
}
|
|
@@ -3065,12 +3705,18 @@ async function executeToolFromPlan(context) {
|
|
|
3065
3705
|
return { output: results };
|
|
3066
3706
|
}
|
|
3067
3707
|
case PLANNER_FUNCTION_CALLS.CONFIGURE_API_KEY: {
|
|
3068
|
-
return unsupportedToolResult(PLANNER_FUNCTION_CALLS.CONFIGURE_API_KEY, "configure_api_key is not supported in rover embed mode. Provide
|
|
3708
|
+
return unsupportedToolResult(PLANNER_FUNCTION_CALLS.CONFIGURE_API_KEY, "configure_api_key is not supported in rover embed mode. Provide publicKey (pk_site_*) via rover.boot(...) or an rvrsess_* sessionToken.");
|
|
3069
3709
|
}
|
|
3070
3710
|
default: {
|
|
3071
3711
|
if (toolFunctions && toolFunctions[toolName]) {
|
|
3072
3712
|
try {
|
|
3713
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3714
|
+
return cancelledToolResult();
|
|
3715
|
+
}
|
|
3073
3716
|
const result = await bridgeRpc2?.("executeClientTool", { name: toolName, args: toolArgs });
|
|
3717
|
+
if (isExecutionCancelled(effectiveCtx)) {
|
|
3718
|
+
return cancelledToolResult();
|
|
3719
|
+
}
|
|
3074
3720
|
return { output: result };
|
|
3075
3721
|
} catch (error) {
|
|
3076
3722
|
return { error: error?.message || String(error) };
|
|
@@ -3091,7 +3737,7 @@ async function executeToolFromPlan(context) {
|
|
|
3091
3737
|
};
|
|
3092
3738
|
}
|
|
3093
3739
|
}
|
|
3094
|
-
async function executeProcessText({ textInputs, taskInstruction, schema, plannerPrevSteps, files, trajectoryId
|
|
3740
|
+
async function executeProcessText({ textInputs, taskInstruction, schema, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx, driveAuthToken }) {
|
|
3095
3741
|
onStatusUpdate?.("Processing text...", "Calling process_text", "execute");
|
|
3096
3742
|
const request = {
|
|
3097
3743
|
siteId: ctx.siteId,
|
|
@@ -3108,11 +3754,11 @@ async function executeProcessText({ textInputs, taskInstruction, schema, planner
|
|
|
3108
3754
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3109
3755
|
authToken: driveAuthToken || "",
|
|
3110
3756
|
timestamp: ctx.userTimestamp,
|
|
3111
|
-
trajectoryId
|
|
3757
|
+
trajectoryId,
|
|
3112
3758
|
userProfile: ctx.userProfile,
|
|
3113
3759
|
files
|
|
3114
3760
|
};
|
|
3115
|
-
const response = await ctx
|
|
3761
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.processText, request);
|
|
3116
3762
|
if (!response?.success)
|
|
3117
3763
|
return { error: response?.error || "process_text failed" };
|
|
3118
3764
|
return {
|
|
@@ -3123,7 +3769,7 @@ async function executeProcessText({ textInputs, taskInstruction, schema, planner
|
|
|
3123
3769
|
warnings: response.data?.warnings
|
|
3124
3770
|
};
|
|
3125
3771
|
}
|
|
3126
|
-
async function executeCreateSheetFromData({ dataInputs, taskInstruction, schema, outputSheetParameters, plannerPrevSteps, files, trajectoryId
|
|
3772
|
+
async function executeCreateSheetFromData({ dataInputs, taskInstruction, schema, outputSheetParameters, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx, driveAuthToken }) {
|
|
3127
3773
|
onStatusUpdate?.("Creating sheet...", "Calling create_sheet_from_data", "execute");
|
|
3128
3774
|
const memoryTarget = resolveMemoryTarget(outputSheetParameters, plannerPrevSteps);
|
|
3129
3775
|
const useMemory = ctx.apiMode || !driveAuthToken || memoryTarget.sheetId && isMemorySheetId(memoryTarget.sheetId);
|
|
@@ -3143,12 +3789,12 @@ async function executeCreateSheetFromData({ dataInputs, taskInstruction, schema,
|
|
|
3143
3789
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3144
3790
|
authToken: driveAuthToken || "",
|
|
3145
3791
|
timestamp: ctx.userTimestamp,
|
|
3146
|
-
trajectoryId
|
|
3792
|
+
trajectoryId,
|
|
3147
3793
|
userProfile: ctx.userProfile,
|
|
3148
3794
|
files,
|
|
3149
3795
|
returnDataOnly: useMemory
|
|
3150
3796
|
};
|
|
3151
|
-
const response = await ctx
|
|
3797
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.createSheetFromData, request);
|
|
3152
3798
|
if (!response?.success)
|
|
3153
3799
|
return { error: response?.error || "create_sheet_from_data failed" };
|
|
3154
3800
|
if (useMemory) {
|
|
@@ -3189,7 +3835,7 @@ async function executeCreateSheetFromData({ dataInputs, taskInstruction, schema,
|
|
|
3189
3835
|
schemaHeaderSheetInfo: response.data?.schemaHeaderSheetInfo
|
|
3190
3836
|
};
|
|
3191
3837
|
}
|
|
3192
|
-
async function executeInferSheetData({ toolArgs, plannerPrevSteps, files, trajectoryId
|
|
3838
|
+
async function executeInferSheetData({ toolArgs, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx, driveAuthToken }) {
|
|
3193
3839
|
onStatusUpdate?.("Inferring sheet data...", "Calling infer_sheet_data", "execute");
|
|
3194
3840
|
const sourceSheetRef = toolArgs?.source_sheet_from_history || toolArgs?.sourceSheetFromHistory;
|
|
3195
3841
|
const resolvedSheetInfo = sourceSheetRef ? resolveHistorySheetInfo(sourceSheetRef, plannerPrevSteps) : void 0;
|
|
@@ -3224,11 +3870,11 @@ async function executeInferSheetData({ toolArgs, plannerPrevSteps, files, trajec
|
|
|
3224
3870
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3225
3871
|
authToken: driveAuthToken || "",
|
|
3226
3872
|
timestamp: ctx.userTimestamp,
|
|
3227
|
-
trajectoryId
|
|
3873
|
+
trajectoryId,
|
|
3228
3874
|
userProfile: ctx.userProfile,
|
|
3229
3875
|
files
|
|
3230
3876
|
};
|
|
3231
|
-
const response = await ctx
|
|
3877
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.infer, request);
|
|
3232
3878
|
if (!response?.success)
|
|
3233
3879
|
return { error: response?.error || "infer_sheet_data failed" };
|
|
3234
3880
|
const inferredItems = Array.isArray(response.data?.data) ? response.data.data : [];
|
|
@@ -3307,7 +3953,7 @@ async function executeInferSheetData({ toolArgs, plannerPrevSteps, files, trajec
|
|
|
3307
3953
|
warnings: response.data?.warnings
|
|
3308
3954
|
};
|
|
3309
3955
|
}
|
|
3310
|
-
async function executeQueryDocs({ userQuestion, trajectoryId
|
|
3956
|
+
async function executeQueryDocs({ userQuestion, trajectoryId, plannerPrevSteps, onStatusUpdate, agentLog, ctx }) {
|
|
3311
3957
|
onStatusUpdate?.("Querying docs...", "Calling query_rtrvr_docs", "execute");
|
|
3312
3958
|
const request = {
|
|
3313
3959
|
siteId: ctx.siteId,
|
|
@@ -3322,10 +3968,10 @@ async function executeQueryDocs({ userQuestion, trajectoryId: trajectoryId2, pla
|
|
|
3322
3968
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3323
3969
|
authToken: "",
|
|
3324
3970
|
timestamp: ctx.userTimestamp,
|
|
3325
|
-
trajectoryId
|
|
3971
|
+
trajectoryId,
|
|
3326
3972
|
userProfile: ctx.userProfile
|
|
3327
3973
|
};
|
|
3328
|
-
const response = await ctx
|
|
3974
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.queryRtrvrDocs, request);
|
|
3329
3975
|
if (!response?.success)
|
|
3330
3976
|
return { error: response?.error || "query_rtrvr_docs failed" };
|
|
3331
3977
|
return {
|
|
@@ -3382,7 +4028,7 @@ Slide 3: Summary`;
|
|
|
3382
4028
|
warnings: [warning]
|
|
3383
4029
|
};
|
|
3384
4030
|
}
|
|
3385
|
-
async function executeDocGenerator({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId
|
|
4031
|
+
async function executeDocGenerator({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx, driveAuthToken }) {
|
|
3386
4032
|
onStatusUpdate?.("Generating doc...", "Calling google_doc_generator", "execute");
|
|
3387
4033
|
if (!driveAuthToken) {
|
|
3388
4034
|
return buildMissingAuthToolResult("google_doc_generator", ["authToken"]);
|
|
@@ -3404,13 +4050,13 @@ async function executeDocGenerator({ userInput, toolArgs, tabOrder, plannerPrevS
|
|
|
3404
4050
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3405
4051
|
authToken: driveAuthToken || "",
|
|
3406
4052
|
timestamp: ctx.userTimestamp,
|
|
3407
|
-
trajectoryId
|
|
4053
|
+
trajectoryId,
|
|
3408
4054
|
userProfile: ctx.userProfile,
|
|
3409
4055
|
files
|
|
3410
4056
|
};
|
|
3411
4057
|
let response;
|
|
3412
4058
|
try {
|
|
3413
|
-
response = await ctx
|
|
4059
|
+
response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.googleDocGenerator, request);
|
|
3414
4060
|
} catch (err) {
|
|
3415
4061
|
if (shouldFallbackToMemoryArtifact(err)) {
|
|
3416
4062
|
const envelope2 = toRoverErrorEnvelope(err);
|
|
@@ -3433,7 +4079,7 @@ async function executeDocGenerator({ userInput, toolArgs, tabOrder, plannerPrevS
|
|
|
3433
4079
|
warnings: response.data?.warnings
|
|
3434
4080
|
};
|
|
3435
4081
|
}
|
|
3436
|
-
async function executeSlidesGenerator({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId
|
|
4082
|
+
async function executeSlidesGenerator({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx, driveAuthToken }) {
|
|
3437
4083
|
onStatusUpdate?.("Generating slides...", "Calling google_slides_generator", "execute");
|
|
3438
4084
|
if (!driveAuthToken) {
|
|
3439
4085
|
return buildMissingAuthToolResult("google_slides_generator", ["authToken"]);
|
|
@@ -3455,13 +4101,13 @@ async function executeSlidesGenerator({ userInput, toolArgs, tabOrder, plannerPr
|
|
|
3455
4101
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3456
4102
|
authToken: driveAuthToken || "",
|
|
3457
4103
|
timestamp: ctx.userTimestamp,
|
|
3458
|
-
trajectoryId
|
|
4104
|
+
trajectoryId,
|
|
3459
4105
|
userProfile: ctx.userProfile,
|
|
3460
4106
|
files
|
|
3461
4107
|
};
|
|
3462
4108
|
let response;
|
|
3463
4109
|
try {
|
|
3464
|
-
response = await ctx
|
|
4110
|
+
response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.googleSlidesGenerator, request);
|
|
3465
4111
|
} catch (err) {
|
|
3466
4112
|
if (shouldFallbackToMemoryArtifact(err)) {
|
|
3467
4113
|
const envelope2 = toRoverErrorEnvelope(err);
|
|
@@ -3484,7 +4130,7 @@ async function executeSlidesGenerator({ userInput, toolArgs, tabOrder, plannerPr
|
|
|
3484
4130
|
warnings: response.data?.warnings
|
|
3485
4131
|
};
|
|
3486
4132
|
}
|
|
3487
|
-
async function executeWebpageGenerator({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId
|
|
4133
|
+
async function executeWebpageGenerator({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx }) {
|
|
3488
4134
|
onStatusUpdate?.("Generating webpage...", "Calling webpage_generator", "execute");
|
|
3489
4135
|
const pageData = await ctx.getPageData(tabOrder[0]);
|
|
3490
4136
|
const request = {
|
|
@@ -3502,12 +4148,12 @@ async function executeWebpageGenerator({ userInput, toolArgs, tabOrder, plannerP
|
|
|
3502
4148
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3503
4149
|
authToken: "",
|
|
3504
4150
|
timestamp: ctx.userTimestamp,
|
|
3505
|
-
trajectoryId
|
|
4151
|
+
trajectoryId,
|
|
3506
4152
|
userProfile: ctx.userProfile,
|
|
3507
4153
|
files,
|
|
3508
4154
|
outputDestination: toolArgs?.output_destination || toolArgs?.outputDestination
|
|
3509
4155
|
};
|
|
3510
|
-
const response = await ctx
|
|
4156
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.webpageGenerator, request);
|
|
3511
4157
|
if (!response?.success)
|
|
3512
4158
|
return { error: response?.error || "webpage_generator failed" };
|
|
3513
4159
|
return {
|
|
@@ -3519,7 +4165,7 @@ async function executeWebpageGenerator({ userInput, toolArgs, tabOrder, plannerP
|
|
|
3519
4165
|
warnings: response.data?.warnings
|
|
3520
4166
|
};
|
|
3521
4167
|
}
|
|
3522
|
-
async function executePdfFiller({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId
|
|
4168
|
+
async function executePdfFiller({ userInput, toolArgs, tabOrder, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx, driveAuthToken }) {
|
|
3523
4169
|
onStatusUpdate?.("Filling PDF...", "Calling pdf_filler", "execute");
|
|
3524
4170
|
if (!driveAuthToken) {
|
|
3525
4171
|
return buildMissingAuthToolResult("pdf_filler", ["authToken"]);
|
|
@@ -3540,12 +4186,12 @@ async function executePdfFiller({ userInput, toolArgs, tabOrder, plannerPrevStep
|
|
|
3540
4186
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3541
4187
|
authToken: driveAuthToken || "",
|
|
3542
4188
|
timestamp: ctx.userTimestamp,
|
|
3543
|
-
trajectoryId
|
|
4189
|
+
trajectoryId,
|
|
3544
4190
|
userProfile: ctx.userProfile,
|
|
3545
4191
|
files,
|
|
3546
4192
|
outputDestination: toolArgs?.output_destination || toolArgs?.outputDestination
|
|
3547
4193
|
};
|
|
3548
|
-
const response = await ctx
|
|
4194
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.pdfFiller, request);
|
|
3549
4195
|
if (!response?.success)
|
|
3550
4196
|
return { error: response?.error || "pdf_filler failed" };
|
|
3551
4197
|
return {
|
|
@@ -3557,7 +4203,7 @@ async function executePdfFiller({ userInput, toolArgs, tabOrder, plannerPrevStep
|
|
|
3557
4203
|
warnings: response.data?.warnings
|
|
3558
4204
|
};
|
|
3559
4205
|
}
|
|
3560
|
-
async function executeCustomToolGenerator({ userInput, plannerPrevSteps, files, trajectoryId
|
|
4206
|
+
async function executeCustomToolGenerator({ userInput, plannerPrevSteps, files, trajectoryId, onStatusUpdate, agentLog, ctx }) {
|
|
3561
4207
|
onStatusUpdate?.("Generating custom tool...", "Calling custom_tool_generator", "execute");
|
|
3562
4208
|
const request = {
|
|
3563
4209
|
siteId: ctx.siteId,
|
|
@@ -3572,11 +4218,11 @@ async function executeCustomToolGenerator({ userInput, plannerPrevSteps, files,
|
|
|
3572
4218
|
apiToolsConfig: ctx.apiToolsConfig,
|
|
3573
4219
|
authToken: "",
|
|
3574
4220
|
timestamp: ctx.userTimestamp,
|
|
3575
|
-
trajectoryId
|
|
4221
|
+
trajectoryId,
|
|
3576
4222
|
userProfile: ctx.userProfile,
|
|
3577
4223
|
files
|
|
3578
4224
|
};
|
|
3579
|
-
const response = await ctx
|
|
4225
|
+
const response = await callExtensionRouterWithCancel(ctx, SUB_AGENTS.customToolGenerator, request);
|
|
3580
4226
|
if (!response?.success)
|
|
3581
4227
|
return { error: response?.error || "custom_tool_generator failed" };
|
|
3582
4228
|
return {
|
|
@@ -3606,24 +4252,33 @@ function normalizeChatLog(entries) {
|
|
|
3606
4252
|
continue;
|
|
3607
4253
|
deduped.push(entry);
|
|
3608
4254
|
}
|
|
3609
|
-
|
|
3610
|
-
const
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
const
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
4255
|
+
let selected = deduped.slice(-MAX_CHATLOG_ENTRIES);
|
|
4256
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4257
|
+
const compactedReverse = [];
|
|
4258
|
+
for (let i = selected.length - 1; i >= 0; i -= 1) {
|
|
4259
|
+
const entry = selected[i];
|
|
4260
|
+
const key = `${entry.role}::${entry.message.toLowerCase()}`;
|
|
4261
|
+
if (seen.has(key))
|
|
4262
|
+
continue;
|
|
4263
|
+
seen.add(key);
|
|
4264
|
+
compactedReverse.push(entry);
|
|
3617
4265
|
}
|
|
4266
|
+
selected = compactedReverse.reverse();
|
|
3618
4267
|
if (selected.length > MAX_CHATLOG_ENTRIES) {
|
|
3619
4268
|
selected = selected.slice(-MAX_CHATLOG_ENTRIES);
|
|
3620
4269
|
}
|
|
3621
4270
|
return selected;
|
|
3622
4271
|
}
|
|
3623
4272
|
async function executePlanner(options) {
|
|
3624
|
-
const { userInput, tabs, previousMessages = [], trajectoryId
|
|
4273
|
+
const { userInput, tabs, scopedTabIds: scopedTabIds2, seedTabId, getScopedTabRuntimeContext, previousMessages = [], trajectoryId, previousSteps = [], files, continuePlanning = false, recordingContext, driveAuthToken, agentLog, lastToolPreviousSteps, ctx, bridgeRpc: bridgeRpc2, functionDeclarations } = options;
|
|
4274
|
+
const runtimeScope = getScopedTabRuntimeContext?.() || {};
|
|
4275
|
+
const scopedTabIdsInput = runtimeScope.scopedTabIds ?? scopedTabIds2;
|
|
4276
|
+
const seedTabIdInput = runtimeScope.seedTabId ?? seedTabId;
|
|
3625
4277
|
const fallbackTabs = Array.isArray(tabs) && tabs.length ? tabs : [{ id: 1 }];
|
|
3626
|
-
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs
|
|
4278
|
+
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs, {
|
|
4279
|
+
scopedTabIds: scopedTabIdsInput,
|
|
4280
|
+
seedTabId: seedTabIdInput
|
|
4281
|
+
});
|
|
3627
4282
|
const tabOrder = resolvedTabs.tabOrder.length ? resolvedTabs.tabOrder : fallbackTabs.map((tab) => tab.id);
|
|
3628
4283
|
const activeTabId = resolvedTabs.activeTabId;
|
|
3629
4284
|
const tabMetaById = resolvedTabs.tabMetaById;
|
|
@@ -3632,7 +4287,9 @@ async function executePlanner(options) {
|
|
|
3632
4287
|
try {
|
|
3633
4288
|
return await ctx.getPageData(tabId, {
|
|
3634
4289
|
onlyTextContent: false,
|
|
3635
|
-
...options2?.allowExternalFetch ? { __roverAllowExternalFetch: true } : {}
|
|
4290
|
+
...options2?.allowExternalFetch ? { __roverAllowExternalFetch: true } : {},
|
|
4291
|
+
...options2?.allowExternalFetch ? { __roverExternalIntent: "auto" } : {},
|
|
4292
|
+
...options2?.allowExternalFetch ? { __roverExternalMessage: userInput } : {}
|
|
3636
4293
|
});
|
|
3637
4294
|
} catch {
|
|
3638
4295
|
const tab = tabMetaById[tabId];
|
|
@@ -3668,7 +4325,7 @@ async function executePlanner(options) {
|
|
|
3668
4325
|
authToken: driveAuthToken || "",
|
|
3669
4326
|
timestamp: ctx.userTimestamp,
|
|
3670
4327
|
continuePlanning,
|
|
3671
|
-
trajectoryId
|
|
4328
|
+
trajectoryId,
|
|
3672
4329
|
userProfile: ctx.userProfile
|
|
3673
4330
|
};
|
|
3674
4331
|
const response = await ctx.callExtensionRouter(SUB_AGENTS.plan, request);
|
|
@@ -4087,55 +4744,130 @@ function convertParametersToTypes(parameters, functionDef) {
|
|
|
4087
4744
|
|
|
4088
4745
|
// dist/agent/messageOrchestrator.js
|
|
4089
4746
|
var COMPLEX_TASK_HINTS = [
|
|
4090
|
-
"plan",
|
|
4091
|
-
"research",
|
|
4092
|
-
"compare",
|
|
4093
|
-
"summarize",
|
|
4094
|
-
"table",
|
|
4095
|
-
"spreadsheet",
|
|
4096
|
-
"sheet",
|
|
4097
4747
|
"extract",
|
|
4098
|
-
"
|
|
4099
|
-
"
|
|
4748
|
+
"compare",
|
|
4749
|
+
"list",
|
|
4100
4750
|
"across",
|
|
4101
|
-
"multi",
|
|
4102
4751
|
"multiple",
|
|
4103
|
-
"
|
|
4104
|
-
"
|
|
4105
|
-
"finally",
|
|
4106
|
-
"slides",
|
|
4752
|
+
"many",
|
|
4753
|
+
"report",
|
|
4107
4754
|
"document",
|
|
4108
|
-
"
|
|
4109
|
-
"
|
|
4110
|
-
"
|
|
4755
|
+
"spreadsheet",
|
|
4756
|
+
"sheet",
|
|
4757
|
+
"table",
|
|
4758
|
+
"csv",
|
|
4759
|
+
"json",
|
|
4760
|
+
"pdf",
|
|
4761
|
+
"slides"
|
|
4111
4762
|
];
|
|
4763
|
+
var MULTI_LABEL_TLDS = /* @__PURE__ */ new Set([
|
|
4764
|
+
"co.uk",
|
|
4765
|
+
"org.uk",
|
|
4766
|
+
"gov.uk",
|
|
4767
|
+
"ac.uk",
|
|
4768
|
+
"com.au",
|
|
4769
|
+
"net.au",
|
|
4770
|
+
"org.au",
|
|
4771
|
+
"co.jp",
|
|
4772
|
+
"com.br",
|
|
4773
|
+
"com.mx",
|
|
4774
|
+
"com.sg",
|
|
4775
|
+
"co.in"
|
|
4776
|
+
]);
|
|
4777
|
+
function extractHostFromUrl(input) {
|
|
4778
|
+
const raw = String(input || "").trim();
|
|
4779
|
+
if (!raw)
|
|
4780
|
+
return "";
|
|
4781
|
+
try {
|
|
4782
|
+
return new URL(raw).hostname.toLowerCase();
|
|
4783
|
+
} catch {
|
|
4784
|
+
return "";
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
function registrableDomain(host) {
|
|
4788
|
+
const clean = String(host || "").trim().toLowerCase().replace(/^\.+/, "");
|
|
4789
|
+
if (!clean)
|
|
4790
|
+
return "";
|
|
4791
|
+
if (clean === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(clean))
|
|
4792
|
+
return clean;
|
|
4793
|
+
const parts = clean.split(".").filter(Boolean);
|
|
4794
|
+
if (parts.length < 2)
|
|
4795
|
+
return clean;
|
|
4796
|
+
const tail2 = `${parts[parts.length - 2]}.${parts[parts.length - 1]}`;
|
|
4797
|
+
if (parts.length >= 3 && MULTI_LABEL_TLDS.has(tail2)) {
|
|
4798
|
+
return `${parts[parts.length - 3]}.${tail2}`;
|
|
4799
|
+
}
|
|
4800
|
+
return tail2;
|
|
4801
|
+
}
|
|
4802
|
+
function hasCrossDomainPlanDependency(userInput, tabs) {
|
|
4803
|
+
const currentUrl = String(tabs?.find((tab) => typeof tab?.url === "string" && String(tab.url || "").trim())?.url || "");
|
|
4804
|
+
const currentDomain = registrableDomain(extractHostFromUrl(currentUrl));
|
|
4805
|
+
if (!currentDomain)
|
|
4806
|
+
return false;
|
|
4807
|
+
const urls = String(userInput || "").match(/https?:\/\/[^\s)]+/g) || [];
|
|
4808
|
+
if (!urls.length)
|
|
4809
|
+
return false;
|
|
4810
|
+
return urls.some((url) => {
|
|
4811
|
+
const targetDomain = registrableDomain(extractHostFromUrl(url));
|
|
4812
|
+
return !!targetDomain && targetDomain !== currentDomain;
|
|
4813
|
+
});
|
|
4814
|
+
}
|
|
4815
|
+
function countCrossDomainNavigationDependencies(userInput, tabs) {
|
|
4816
|
+
const currentUrl = String(tabs?.find((tab) => typeof tab?.url === "string" && String(tab.url || "").trim())?.url || "");
|
|
4817
|
+
const currentDomain = registrableDomain(extractHostFromUrl(currentUrl));
|
|
4818
|
+
const urls = String(userInput || "").match(/https?:\/\/[^\s)]+/g) || [];
|
|
4819
|
+
if (!urls.length || !currentDomain)
|
|
4820
|
+
return 0;
|
|
4821
|
+
const distinct = /* @__PURE__ */ new Set();
|
|
4822
|
+
for (const url of urls) {
|
|
4823
|
+
const targetDomain = registrableDomain(extractHostFromUrl(url));
|
|
4824
|
+
if (!targetDomain || targetDomain === currentDomain)
|
|
4825
|
+
continue;
|
|
4826
|
+
distinct.add(targetDomain);
|
|
4827
|
+
}
|
|
4828
|
+
return distinct.size;
|
|
4829
|
+
}
|
|
4830
|
+
function hasMultiStepDependencyMarkers(text) {
|
|
4831
|
+
const input = String(text || "").toLowerCase();
|
|
4832
|
+
if (!input)
|
|
4833
|
+
return false;
|
|
4834
|
+
const sequenceMarkers = (input.match(/\b(first|second|third|then|after that|next|finally)\b/g) || []).length;
|
|
4835
|
+
if (sequenceMarkers >= 2)
|
|
4836
|
+
return true;
|
|
4837
|
+
if ((input.match(/\bstep\s*[1-9]\b/g) || []).length >= 2)
|
|
4838
|
+
return true;
|
|
4839
|
+
if ((input.match(/\b\d+\.\s+/g) || []).length >= 2)
|
|
4840
|
+
return true;
|
|
4841
|
+
return false;
|
|
4842
|
+
}
|
|
4112
4843
|
function computeComplexityScore(text) {
|
|
4113
4844
|
const input = String(text || "").toLowerCase().trim();
|
|
4114
4845
|
if (!input)
|
|
4115
4846
|
return 0;
|
|
4116
4847
|
let score = 0;
|
|
4117
|
-
const
|
|
4118
|
-
if (
|
|
4119
|
-
score += 1;
|
|
4120
|
-
if (words.length >= 26)
|
|
4848
|
+
const actionVerbs = new Set((input.match(/\b(click|open|go|navigate|fill|type|submit|extract|find|search|compare|summarize|collect|download|upload|create|generate|report)\b/g) || []).map((v) => v.toLowerCase()));
|
|
4849
|
+
if (input.length > 120)
|
|
4121
4850
|
score += 1;
|
|
4122
|
-
if (
|
|
4123
|
-
score += 1;
|
|
4124
|
-
if ((input.match(/[;,]/g) || []).length >= 2)
|
|
4851
|
+
if (actionVerbs.size >= 2)
|
|
4125
4852
|
score += 1;
|
|
4853
|
+
if ((input.match(/\b(and then|then|after|next|finally|first|second|third)\b/g) || []).length >= 1)
|
|
4854
|
+
score += 2;
|
|
4855
|
+
if ((input.match(/\b(extract|compare|list|all|each|every|across|multiple|many)\b/g) || []).length >= 2)
|
|
4856
|
+
score += 2;
|
|
4126
4857
|
if (/https?:\/\/|www\./.test(input))
|
|
4127
|
-
score +=
|
|
4128
|
-
if (/\b(
|
|
4129
|
-
score +=
|
|
4858
|
+
score += 2;
|
|
4859
|
+
if ((input.match(/\b(report|document|doc|spreadsheet|sheet|table|csv|json|pdf|slides|summary)\b/g) || []).length >= 1)
|
|
4860
|
+
score += 2;
|
|
4130
4861
|
for (const hint of COMPLEX_TASK_HINTS) {
|
|
4131
4862
|
if (input.includes(hint)) {
|
|
4132
|
-
score +=
|
|
4863
|
+
score += 0.25;
|
|
4133
4864
|
}
|
|
4134
4865
|
}
|
|
4866
|
+
const words = input.split(/\s+/).filter(Boolean);
|
|
4135
4867
|
if (/^(click|type|fill|open|go to|scroll|press|select)\b/.test(input) && words.length <= 10) {
|
|
4136
4868
|
score = Math.max(0, score - 2);
|
|
4137
4869
|
}
|
|
4138
|
-
return score;
|
|
4870
|
+
return Math.max(0, Math.min(10, Math.round(score)));
|
|
4139
4871
|
}
|
|
4140
4872
|
function decideRouting(message, options) {
|
|
4141
4873
|
const mode = options.taskRouting?.mode || "act";
|
|
@@ -4145,21 +4877,97 @@ function decideRouting(message, options) {
|
|
|
4145
4877
|
if (mode === "act") {
|
|
4146
4878
|
return { mode: "act", reason: "Configured act mode" };
|
|
4147
4879
|
}
|
|
4148
|
-
const
|
|
4880
|
+
const hasAwaitingUserChain = Array.isArray(options.previousSteps) && options.previousSteps.some((step) => Array.isArray(step?.questionsAsked) && step.questionsAsked.length > 0 && !(step?.userAnswers && Object.keys(step.userAnswers).length > 0));
|
|
4881
|
+
if (hasAwaitingUserChain) {
|
|
4882
|
+
const score2 = computeComplexityScore(message);
|
|
4883
|
+
return {
|
|
4884
|
+
mode: "planner",
|
|
4885
|
+
score: score2,
|
|
4886
|
+
reason: "Forced planner due to awaiting_user continuation chain."
|
|
4887
|
+
};
|
|
4888
|
+
}
|
|
4889
|
+
if (hasMultiStepDependencyMarkers(message)) {
|
|
4890
|
+
const score2 = computeComplexityScore(message);
|
|
4891
|
+
return {
|
|
4892
|
+
mode: "planner",
|
|
4893
|
+
score: score2,
|
|
4894
|
+
reason: "Forced planner due to multi-step dependency markers in prompt."
|
|
4895
|
+
};
|
|
4896
|
+
}
|
|
4897
|
+
const crossDomainDependencies = countCrossDomainNavigationDependencies(message, options.tabs || []);
|
|
4898
|
+
if (crossDomainDependencies > 1) {
|
|
4899
|
+
const score2 = computeComplexityScore(message);
|
|
4900
|
+
return {
|
|
4901
|
+
mode: "planner",
|
|
4902
|
+
score: score2,
|
|
4903
|
+
reason: `Forced planner due to ${crossDomainDependencies} cross-domain dependencies.`
|
|
4904
|
+
};
|
|
4905
|
+
}
|
|
4149
4906
|
const score = computeComplexityScore(message);
|
|
4150
|
-
|
|
4907
|
+
const plannerThreshold = Math.max(3, Math.min(10, Number(options.taskRouting?.actHeuristicThreshold) || 7));
|
|
4908
|
+
if (score >= plannerThreshold) {
|
|
4151
4909
|
return {
|
|
4152
4910
|
mode: "planner",
|
|
4153
4911
|
score,
|
|
4154
|
-
reason: `Complexity score ${score} >=
|
|
4912
|
+
reason: `Complexity score ${score} >= ${plannerThreshold}`
|
|
4155
4913
|
};
|
|
4156
4914
|
}
|
|
4157
4915
|
return {
|
|
4158
4916
|
mode: "act",
|
|
4159
4917
|
score,
|
|
4160
|
-
reason: `Complexity score ${score} <
|
|
4918
|
+
reason: `Complexity score ${score} < ${plannerThreshold}`
|
|
4161
4919
|
};
|
|
4162
4920
|
}
|
|
4921
|
+
function hasUsableActOutcome(actResult) {
|
|
4922
|
+
if (!actResult || typeof actResult !== "object")
|
|
4923
|
+
return false;
|
|
4924
|
+
if (actResult.error)
|
|
4925
|
+
return false;
|
|
4926
|
+
const hasNonEmptyValue = (value) => {
|
|
4927
|
+
if (Array.isArray(value))
|
|
4928
|
+
return value.length > 0;
|
|
4929
|
+
if (value && typeof value === "object")
|
|
4930
|
+
return Object.keys(value).length > 0;
|
|
4931
|
+
if (typeof value === "string")
|
|
4932
|
+
return value.trim().length > 0;
|
|
4933
|
+
return value !== void 0 && value !== null;
|
|
4934
|
+
};
|
|
4935
|
+
if (hasNonEmptyValue(actResult.data))
|
|
4936
|
+
return true;
|
|
4937
|
+
if (actResult.navigationPending === true)
|
|
4938
|
+
return true;
|
|
4939
|
+
if (actResult.needsUserInput === true)
|
|
4940
|
+
return true;
|
|
4941
|
+
const output = actResult.output;
|
|
4942
|
+
if (!output)
|
|
4943
|
+
return false;
|
|
4944
|
+
if (typeof output === "string")
|
|
4945
|
+
return output.trim().length > 0;
|
|
4946
|
+
if (typeof output !== "object")
|
|
4947
|
+
return hasNonEmptyValue(output);
|
|
4948
|
+
if (output.success === false || output.error)
|
|
4949
|
+
return false;
|
|
4950
|
+
const navigationOutcome = String(output.navigationOutcome || "").trim().toLowerCase();
|
|
4951
|
+
if (navigationOutcome === "same_tab_scheduled" || navigationOutcome === "new_tab_opened")
|
|
4952
|
+
return true;
|
|
4953
|
+
if (output.navigationPending === true)
|
|
4954
|
+
return true;
|
|
4955
|
+
if (output.needsUserInput === true || output.waitingForUserInput === true)
|
|
4956
|
+
return true;
|
|
4957
|
+
if (Array.isArray(output.questions) && output.questions.length > 0)
|
|
4958
|
+
return true;
|
|
4959
|
+
if (String(output.taskStatus || "").trim().toLowerCase() === "in_progress")
|
|
4960
|
+
return true;
|
|
4961
|
+
if (output.taskComplete === true)
|
|
4962
|
+
return true;
|
|
4963
|
+
if (hasNonEmptyValue(output.data))
|
|
4964
|
+
return true;
|
|
4965
|
+
if (typeof output.response === "string" && String(output.response || "").trim())
|
|
4966
|
+
return true;
|
|
4967
|
+
if (hasNonEmptyValue(output))
|
|
4968
|
+
return true;
|
|
4969
|
+
return false;
|
|
4970
|
+
}
|
|
4163
4971
|
async function processMessageWithFunctions(options) {
|
|
4164
4972
|
const { message, toolFunctions } = options;
|
|
4165
4973
|
const parsed = parseMessage(message);
|
|
@@ -4255,6 +5063,7 @@ async function handleSendMessageWithFunctions(userInput, context) {
|
|
|
4255
5063
|
let routedAgentPrevSteps = context.agentLog?.prevSteps;
|
|
4256
5064
|
if (routing.mode === "act") {
|
|
4257
5065
|
context.onStatusUpdate?.("Executing action plan", "Using ACT tool loop", "execute");
|
|
5066
|
+
const actStartedAt = Date.now();
|
|
4258
5067
|
const actResult = await executeToolFromPlan({
|
|
4259
5068
|
...context,
|
|
4260
5069
|
toolName: PLANNER_FUNCTION_CALLS.ACT,
|
|
@@ -4273,7 +5082,17 @@ async function handleSendMessageWithFunctions(userInput, context) {
|
|
|
4273
5082
|
routedAgentPrevSteps = actResult.prevSteps;
|
|
4274
5083
|
context.onPrevStepsUpdate?.(routedAgentPrevSteps);
|
|
4275
5084
|
}
|
|
4276
|
-
const
|
|
5085
|
+
const actElapsedMs = Date.now() - actStartedAt;
|
|
5086
|
+
const actFunctionCount = Array.isArray(actResult.prevSteps?.[actResult.prevSteps.length - 1]?.functions) ? actResult.prevSteps[actResult.prevSteps.length - 1].functions.length : 0;
|
|
5087
|
+
const recoverableFailures = Array.isArray(actResult.prevSteps) ? actResult.prevSteps.reduce((count, step) => {
|
|
5088
|
+
const failures = Array.isArray(step.functions) ? step.functions.filter((fn) => fn?.response?.status === "Failure").length : 0;
|
|
5089
|
+
return count + failures;
|
|
5090
|
+
}, 0) : 0;
|
|
5091
|
+
const crossDomainPlanDependency = hasCrossDomainPlanDependency(userInput, context.tabs || []);
|
|
5092
|
+
const crossDomainDependencyCount = countCrossDomainNavigationDependencies(userInput, context.tabs || []);
|
|
5093
|
+
const multiStepDependency = hasMultiStepDependencyMarkers(userInput);
|
|
5094
|
+
const actProducedUsableOutcome = hasUsableActOutcome(actResult);
|
|
5095
|
+
const shouldEscalateToPlanner = !actProducedUsableOutcome && (!!actResult.error && (context.taskRouting?.plannerOnActError ?? true) && context.taskRouting?.mode !== "act" || actElapsedMs > 8e3 || actFunctionCount > 3 || recoverableFailures >= 2 || crossDomainDependencyCount > 1 || crossDomainPlanDependency || multiStepDependency);
|
|
4277
5096
|
if (!shouldEscalateToPlanner) {
|
|
4278
5097
|
return {
|
|
4279
5098
|
success: !actResult.error,
|
|
@@ -4311,6 +5130,19 @@ async function handleSendMessageWithFunctions(userInput, context) {
|
|
|
4311
5130
|
return { success: true, processedMessage: result.processedMessage };
|
|
4312
5131
|
}
|
|
4313
5132
|
|
|
5133
|
+
// dist/runHistoryGuards.js
|
|
5134
|
+
function shouldClearHistoryForRun(params) {
|
|
5135
|
+
return !params.resume && !params.preserveHistory;
|
|
5136
|
+
}
|
|
5137
|
+
function shouldBuildResumeCueChatLog(params) {
|
|
5138
|
+
return !!(params.resume || params.preserveHistory) && params.resumeFollowupMode === "deterministic_cues";
|
|
5139
|
+
}
|
|
5140
|
+
function shouldUseFollowupChatLog(params) {
|
|
5141
|
+
if (params.resume)
|
|
5142
|
+
return false;
|
|
5143
|
+
return Number(params.followupChatLogLength) > 0;
|
|
5144
|
+
}
|
|
5145
|
+
|
|
4314
5146
|
// dist/worker.js
|
|
4315
5147
|
var history = [];
|
|
4316
5148
|
var config = null;
|
|
@@ -4319,7 +5151,12 @@ var toolRegistry = new ToolRegistry();
|
|
|
4319
5151
|
var plannerHistory = [];
|
|
4320
5152
|
var agentPrevSteps = [];
|
|
4321
5153
|
var pendingAskUser;
|
|
4322
|
-
var
|
|
5154
|
+
var rootUserInput = "";
|
|
5155
|
+
var workerSessionId = "";
|
|
5156
|
+
var taskTrajectoryId = crypto.randomUUID();
|
|
5157
|
+
var taskBoundaryId = crypto.randomUUID();
|
|
5158
|
+
var scopedTabIds = [];
|
|
5159
|
+
var scopedSeedTabId;
|
|
4323
5160
|
var tabularStore = null;
|
|
4324
5161
|
var PLANNER_TOOL_NAME_SET = new Set(Object.values(PLANNER_FUNCTION_CALLS));
|
|
4325
5162
|
var activeRun = null;
|
|
@@ -4327,10 +5164,12 @@ var cancelledRunIds = /* @__PURE__ */ new Set();
|
|
|
4327
5164
|
var activeAbortController = null;
|
|
4328
5165
|
var lastStatusKey = "";
|
|
4329
5166
|
var seenStatusKeys = /* @__PURE__ */ new Set();
|
|
5167
|
+
var lastRuntimeTabsDiagnosticsKey = "";
|
|
4330
5168
|
var terminalRuns = /* @__PURE__ */ new Map();
|
|
4331
5169
|
var RPC_TIMEOUT_MS = 3e4;
|
|
4332
5170
|
var DETACHED_EXTERNAL_TAB_MAX_AGE_MS = 9e4;
|
|
4333
|
-
var
|
|
5171
|
+
var PENDING_ATTACH_TAB_MAX_AGE_MS = 2e4;
|
|
5172
|
+
var MAX_RESUME_CUE_TURNS = 2;
|
|
4334
5173
|
function resolveAgentName(config2) {
|
|
4335
5174
|
const raw = String(config2?.ui?.agent?.name || "").trim();
|
|
4336
5175
|
if (!raw)
|
|
@@ -4379,6 +5218,7 @@ function buildRoverRuntimeContext2(params) {
|
|
|
4379
5218
|
agentName: params.agentName,
|
|
4380
5219
|
externalNavigationPolicy: params.externalNavigationPolicy,
|
|
4381
5220
|
tabIdContract: "tree_index_mapped_by_tab_order",
|
|
5221
|
+
taskBoundaryId: params.taskBoundaryId,
|
|
4382
5222
|
...externalTabs.length ? { externalTabs } : {}
|
|
4383
5223
|
};
|
|
4384
5224
|
}
|
|
@@ -4483,6 +5323,8 @@ async function getKnownTabs() {
|
|
|
4483
5323
|
id,
|
|
4484
5324
|
runtimeId: typeof tab?.runtimeId === "string" ? tab.runtimeId : void 0,
|
|
4485
5325
|
updatedAt: Number(tab?.updatedAt) || 0,
|
|
5326
|
+
detachedAt: Number(tab?.detachedAt) || 0,
|
|
5327
|
+
detachedReason: typeof tab?.detachedReason === "string" ? tab.detachedReason : void 0,
|
|
4486
5328
|
url: typeof tab?.url === "string" ? tab.url : void 0,
|
|
4487
5329
|
title: typeof tab?.title === "string" ? tab.title : void 0,
|
|
4488
5330
|
external,
|
|
@@ -4490,9 +5332,15 @@ async function getKnownTabs() {
|
|
|
4490
5332
|
inaccessibleReason: typeof tab?.inaccessibleReason === "string" ? tab.inaccessibleReason : void 0
|
|
4491
5333
|
};
|
|
4492
5334
|
}).filter((tab) => Number.isFinite(tab.id) && tab.id > 0).filter((tab) => {
|
|
4493
|
-
|
|
5335
|
+
const freshness = Math.max(Number(tab.updatedAt) || 0, Number(tab.detachedAt) || 0);
|
|
5336
|
+
if (tab.runtimeId)
|
|
4494
5337
|
return true;
|
|
4495
|
-
|
|
5338
|
+
if (tab.external)
|
|
5339
|
+
return nowMs - freshness <= DETACHED_EXTERNAL_TAB_MAX_AGE_MS;
|
|
5340
|
+
if (tab.detachedReason === "opened_pending_attach") {
|
|
5341
|
+
return nowMs - freshness <= PENDING_ATTACH_TAB_MAX_AGE_MS;
|
|
5342
|
+
}
|
|
5343
|
+
return false;
|
|
4496
5344
|
}).map((tab) => ({
|
|
4497
5345
|
id: tab.id,
|
|
4498
5346
|
url: tab.url,
|
|
@@ -4534,6 +5382,8 @@ function postStatus(message, thought, stage) {
|
|
|
4534
5382
|
const resolvedStage = inferStatusStage(message, thought, stage);
|
|
4535
5383
|
const compact = compactThought(message, thought);
|
|
4536
5384
|
const runId = activeRun?.runId || "no-run";
|
|
5385
|
+
if (runId !== "no-run" && cancelledRunIds.has(runId))
|
|
5386
|
+
return;
|
|
4537
5387
|
const key = `${runId}|${resolvedStage}|${String(message || "").trim().toLowerCase()}|${compact.toLowerCase()}`;
|
|
4538
5388
|
if (key === lastStatusKey || seenStatusKeys.has(key))
|
|
4539
5389
|
return;
|
|
@@ -4546,6 +5396,27 @@ function postStatus(message, thought, stage) {
|
|
|
4546
5396
|
self.postMessage({ type: "status", message, thought, stage: resolvedStage, compactThought: compact, runId: activeRun?.runId });
|
|
4547
5397
|
postStateSnapshot();
|
|
4548
5398
|
}
|
|
5399
|
+
function postRuntimeTabsDiagnostics(payload) {
|
|
5400
|
+
const runId = activeRun?.runId || "no-run";
|
|
5401
|
+
if (runId !== "no-run" && cancelledRunIds.has(runId))
|
|
5402
|
+
return;
|
|
5403
|
+
const signature = [
|
|
5404
|
+
runId,
|
|
5405
|
+
payload.hasExplicitScope ? "1" : "0",
|
|
5406
|
+
payload.scopedTabIdsInput.join(","),
|
|
5407
|
+
payload.listedTabIds.join(","),
|
|
5408
|
+
payload.keptScopedTabIds.join(","),
|
|
5409
|
+
payload.resolvedTabOrder.join(",")
|
|
5410
|
+
].join("|");
|
|
5411
|
+
if (signature === lastRuntimeTabsDiagnosticsKey)
|
|
5412
|
+
return;
|
|
5413
|
+
lastRuntimeTabsDiagnosticsKey = signature;
|
|
5414
|
+
self.postMessage({
|
|
5415
|
+
type: "runtime_tabs_diagnostics",
|
|
5416
|
+
runId: activeRun?.runId,
|
|
5417
|
+
diagnostics: payload
|
|
5418
|
+
});
|
|
5419
|
+
}
|
|
4549
5420
|
function cloneUnknown(value) {
|
|
4550
5421
|
if (value == null)
|
|
4551
5422
|
return value;
|
|
@@ -4562,8 +5433,8 @@ function cloneUnknown(value) {
|
|
|
4562
5433
|
}
|
|
4563
5434
|
}
|
|
4564
5435
|
function sanitizeHistoryForPersist(input) {
|
|
4565
|
-
return input.slice(-
|
|
4566
|
-
|
|
5436
|
+
return input.filter((message) => message?.role === "user").slice(-20).map((message) => ({
|
|
5437
|
+
role: "user",
|
|
4567
5438
|
content: String(message?.content ?? "")
|
|
4568
5439
|
}));
|
|
4569
5440
|
}
|
|
@@ -4631,6 +5502,7 @@ function questionToDisplayText(question) {
|
|
|
4631
5502
|
function normalizeAskUserAnswerMeta(raw, questions, fallbackText) {
|
|
4632
5503
|
const validKeys = new Set(questions.map((question) => question.key));
|
|
4633
5504
|
const answersByKey = {};
|
|
5505
|
+
const submittedKeys = Array.isArray(raw?.keys) ? raw.keys.map((key) => String(key || "").trim()).filter((key) => !!key && validKeys.has(key)) : [];
|
|
4634
5506
|
if (raw?.answersByKey && typeof raw.answersByKey === "object") {
|
|
4635
5507
|
for (const [key, value] of Object.entries(raw.answersByKey)) {
|
|
4636
5508
|
if (!validKeys.has(key))
|
|
@@ -4660,8 +5532,14 @@ function normalizeAskUserAnswerMeta(raw, questions, fallbackText) {
|
|
|
4660
5532
|
}
|
|
4661
5533
|
}
|
|
4662
5534
|
const rawText = String(raw?.rawText || fallback || "").trim();
|
|
4663
|
-
if (!rawText && Object.keys(answersByKey).length === 0)
|
|
4664
|
-
|
|
5535
|
+
if (!rawText && Object.keys(answersByKey).length === 0) {
|
|
5536
|
+
if (!submittedKeys.length)
|
|
5537
|
+
return void 0;
|
|
5538
|
+
return {
|
|
5539
|
+
answersByKey,
|
|
5540
|
+
rawText: submittedKeys.map((key) => `${key}: (no answer provided)`).join("\n")
|
|
5541
|
+
};
|
|
5542
|
+
}
|
|
4665
5543
|
return { answersByKey, rawText };
|
|
4666
5544
|
}
|
|
4667
5545
|
function buildAskUserAnswerContext(questions, answers) {
|
|
@@ -4676,10 +5554,256 @@ function buildAskUserAnswerContext(questions, answers) {
|
|
|
4676
5554
|
}
|
|
4677
5555
|
return lines.join("\n");
|
|
4678
5556
|
}
|
|
5557
|
+
function normalizeRootUserInput(input) {
|
|
5558
|
+
const normalized = String(input || "").trim();
|
|
5559
|
+
return normalized || void 0;
|
|
5560
|
+
}
|
|
5561
|
+
function normalizeFollowupChatLog(input) {
|
|
5562
|
+
if (!Array.isArray(input))
|
|
5563
|
+
return [];
|
|
5564
|
+
const normalized = input.map((entry) => ({
|
|
5565
|
+
role: entry?.role === "user" ? "user" : "model",
|
|
5566
|
+
message: String(entry?.message || "").replace(/\s+/g, " ").trim()
|
|
5567
|
+
})).filter((entry) => !!entry.message);
|
|
5568
|
+
if (!normalized.length)
|
|
5569
|
+
return [];
|
|
5570
|
+
const deduped = [];
|
|
5571
|
+
for (const entry of normalized) {
|
|
5572
|
+
const previous = deduped[deduped.length - 1];
|
|
5573
|
+
if (previous && previous.role === entry.role && previous.message === entry.message)
|
|
5574
|
+
continue;
|
|
5575
|
+
deduped.push(entry);
|
|
5576
|
+
}
|
|
5577
|
+
return deduped.slice(-12);
|
|
5578
|
+
}
|
|
5579
|
+
function dedupePositiveTabIds4(input) {
|
|
5580
|
+
if (!Array.isArray(input))
|
|
5581
|
+
return [];
|
|
5582
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5583
|
+
const out = [];
|
|
5584
|
+
for (const value of input) {
|
|
5585
|
+
const tabId = Number(value);
|
|
5586
|
+
if (!Number.isFinite(tabId) || tabId <= 0 || seen.has(tabId))
|
|
5587
|
+
continue;
|
|
5588
|
+
seen.add(tabId);
|
|
5589
|
+
out.push(tabId);
|
|
5590
|
+
}
|
|
5591
|
+
return out;
|
|
5592
|
+
}
|
|
5593
|
+
function resolveScopedTabConfig(partial) {
|
|
5594
|
+
const directScoped = dedupePositiveTabIds4(partial?.scopedTabIds);
|
|
5595
|
+
const scope = partial?.taskTabScope;
|
|
5596
|
+
const scopedFromScope = dedupePositiveTabIds4(scope?.touchedTabIds);
|
|
5597
|
+
const seedCandidate = Number(scope?.seedTabId);
|
|
5598
|
+
const seedTabId = Number.isFinite(seedCandidate) && seedCandidate > 0 ? seedCandidate : void 0;
|
|
5599
|
+
const scoped = dedupePositiveTabIds4(directScoped.length > 0 ? directScoped : scopedFromScope.length > 0 ? scopedFromScope : seedTabId ? [seedTabId] : []);
|
|
5600
|
+
if (seedTabId && !scoped.includes(seedTabId)) {
|
|
5601
|
+
scoped.unshift(seedTabId);
|
|
5602
|
+
}
|
|
5603
|
+
return { scoped, seedTabId };
|
|
5604
|
+
}
|
|
5605
|
+
function applyScopedTabConfig(partial) {
|
|
5606
|
+
if (!partial || typeof partial !== "object")
|
|
5607
|
+
return;
|
|
5608
|
+
const hasScopedTabIds = Object.prototype.hasOwnProperty.call(partial, "scopedTabIds");
|
|
5609
|
+
const hasTaskTabScope = Object.prototype.hasOwnProperty.call(partial, "taskTabScope");
|
|
5610
|
+
if (!hasScopedTabIds && !hasTaskTabScope)
|
|
5611
|
+
return;
|
|
5612
|
+
const next = resolveScopedTabConfig(partial);
|
|
5613
|
+
scopedTabIds = next.scoped;
|
|
5614
|
+
scopedSeedTabId = next.seedTabId;
|
|
5615
|
+
}
|
|
5616
|
+
function touchRunScopedTabIds(tabIds) {
|
|
5617
|
+
const touched = dedupePositiveTabIds4(Array.isArray(tabIds) ? tabIds : [tabIds]);
|
|
5618
|
+
if (!touched.length)
|
|
5619
|
+
return scopedTabIds;
|
|
5620
|
+
const next = dedupePositiveTabIds4([
|
|
5621
|
+
...Number(scopedSeedTabId) > 0 ? [Number(scopedSeedTabId)] : [],
|
|
5622
|
+
...scopedTabIds,
|
|
5623
|
+
...touched
|
|
5624
|
+
]);
|
|
5625
|
+
if (next.length === scopedTabIds.length && next.every((tabId, index) => tabId === scopedTabIds[index])) {
|
|
5626
|
+
return scopedTabIds;
|
|
5627
|
+
}
|
|
5628
|
+
scopedTabIds = next;
|
|
5629
|
+
return scopedTabIds;
|
|
5630
|
+
}
|
|
5631
|
+
function getRootUserInputFallbackFromHistory() {
|
|
5632
|
+
for (const message of history) {
|
|
5633
|
+
if (message.role !== "user")
|
|
5634
|
+
continue;
|
|
5635
|
+
const content = normalizeRootUserInput(String(message.content || ""));
|
|
5636
|
+
if (content)
|
|
5637
|
+
return content;
|
|
5638
|
+
}
|
|
5639
|
+
return void 0;
|
|
5640
|
+
}
|
|
5641
|
+
function buildContinuePlanningInput(focus, lastToolName, lastToolOutput) {
|
|
5642
|
+
const safeToolName = String(lastToolName || "").trim();
|
|
5643
|
+
const safeFocus = String(focus || "").trim();
|
|
5644
|
+
const lines = [
|
|
5645
|
+
safeToolName ? `The tool \`${safeToolName}\` just finished executing.` : "No tool was issued previously.",
|
|
5646
|
+
`Please analyze the progress based on the complete history and determine the single next best step required to fulfill the overall request: ${safeFocus || "(none)"}.`,
|
|
5647
|
+
`If the request is complete, invoke tool \`${PLANNER_FUNCTION_CALLS.TASK_COMPLETE}\` via \`tool_code\`. If not, invoke the appropriate tool.`
|
|
5648
|
+
];
|
|
5649
|
+
const output = String(lastToolOutput || "").trim();
|
|
5650
|
+
if (output) {
|
|
5651
|
+
lines.push("[LAST_TOOL_OUTPUT]");
|
|
5652
|
+
lines.push(output);
|
|
5653
|
+
}
|
|
5654
|
+
return lines.join("\n");
|
|
5655
|
+
}
|
|
5656
|
+
function findLatestAskUserFunctionStep(steps) {
|
|
5657
|
+
if (!Array.isArray(steps) || steps.length === 0)
|
|
5658
|
+
return void 0;
|
|
5659
|
+
for (let stepIndex = steps.length - 1; stepIndex >= 0; stepIndex -= 1) {
|
|
5660
|
+
const step = steps[stepIndex];
|
|
5661
|
+
const functions = Array.isArray(step?.functions) ? step.functions : [];
|
|
5662
|
+
for (let functionIndex = functions.length - 1; functionIndex >= 0; functionIndex -= 1) {
|
|
5663
|
+
const fn = functions[functionIndex];
|
|
5664
|
+
if (String(fn?.name || "").trim().toLowerCase() === "ask_user") {
|
|
5665
|
+
return { stepIndex, functionIndex };
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
}
|
|
5669
|
+
return void 0;
|
|
5670
|
+
}
|
|
5671
|
+
function resolveAskUserStepRef(steps, prompt) {
|
|
5672
|
+
const explicit = prompt?.stepRef;
|
|
5673
|
+
if (explicit && prompt?.boundaryId && prompt.boundaryId === taskBoundaryId && Number.isFinite(explicit.stepIndex) && explicit.stepIndex >= 0 && Number.isFinite(explicit.functionIndex) && explicit.functionIndex >= 0 && explicit.stepIndex < steps.length) {
|
|
5674
|
+
const step = steps[explicit.stepIndex];
|
|
5675
|
+
const functions = Array.isArray(step?.functions) ? step.functions : [];
|
|
5676
|
+
const fn = functions[explicit.functionIndex];
|
|
5677
|
+
if (String(fn?.name || "").trim().toLowerCase() === "ask_user") {
|
|
5678
|
+
return {
|
|
5679
|
+
stepIndex: explicit.stepIndex,
|
|
5680
|
+
functionIndex: explicit.functionIndex
|
|
5681
|
+
};
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
const refs = [];
|
|
5685
|
+
for (let stepIndex = 0; stepIndex < steps.length; stepIndex += 1) {
|
|
5686
|
+
const step = steps[stepIndex];
|
|
5687
|
+
const functions = Array.isArray(step?.functions) ? step.functions : [];
|
|
5688
|
+
for (let functionIndex = 0; functionIndex < functions.length; functionIndex += 1) {
|
|
5689
|
+
const fn = functions[functionIndex];
|
|
5690
|
+
if (String(fn?.name || "").trim().toLowerCase() === "ask_user") {
|
|
5691
|
+
refs.push({ stepIndex, functionIndex });
|
|
5692
|
+
}
|
|
5693
|
+
}
|
|
5694
|
+
}
|
|
5695
|
+
if (refs.length === 1)
|
|
5696
|
+
return refs[0];
|
|
5697
|
+
if (refs.length > 1)
|
|
5698
|
+
return refs[refs.length - 1];
|
|
5699
|
+
return void 0;
|
|
5700
|
+
}
|
|
5701
|
+
function captureLatestAskUserStepRef(steps) {
|
|
5702
|
+
const ref = findLatestAskUserFunctionStep(steps);
|
|
5703
|
+
if (!ref)
|
|
5704
|
+
return void 0;
|
|
5705
|
+
const step = steps[ref.stepIndex];
|
|
5706
|
+
return {
|
|
5707
|
+
stepIndex: ref.stepIndex,
|
|
5708
|
+
functionIndex: ref.functionIndex,
|
|
5709
|
+
...typeof step?.accTreeId === "string" && String(step.accTreeId).trim() ? { accTreeId: String(step.accTreeId).trim() } : {}
|
|
5710
|
+
};
|
|
5711
|
+
}
|
|
5712
|
+
function buildPendingAskUserPrompt(source, questions) {
|
|
5713
|
+
const stepRef = captureLatestAskUserStepRef(agentPrevSteps);
|
|
5714
|
+
return {
|
|
5715
|
+
questions,
|
|
5716
|
+
source,
|
|
5717
|
+
askedAt: Date.now(),
|
|
5718
|
+
boundaryId: taskBoundaryId,
|
|
5719
|
+
...stepRef ? { stepRef } : {}
|
|
5720
|
+
};
|
|
5721
|
+
}
|
|
5722
|
+
function mergeAskUserAnswerIntoPrevSteps(inputSteps, prompt, answers) {
|
|
5723
|
+
const next = sanitizeAgentPrevStepsForPersist(Array.isArray(inputSteps) ? inputSteps : []);
|
|
5724
|
+
const questions = normalizePlannerQuestions(prompt?.questions);
|
|
5725
|
+
if (!questions.length)
|
|
5726
|
+
return next;
|
|
5727
|
+
const askUserRef = resolveAskUserStepRef(next, prompt);
|
|
5728
|
+
const questionPayload = normalizePlannerQuestions(questions).map((question) => ({
|
|
5729
|
+
key: question.key,
|
|
5730
|
+
query: question.query,
|
|
5731
|
+
...question.required === false ? { required: false } : {}
|
|
5732
|
+
}));
|
|
5733
|
+
const buildOutputPayload = (previousOutput2) => {
|
|
5734
|
+
const prev = previousOutput2 && typeof previousOutput2 === "object" && !Array.isArray(previousOutput2) ? previousOutput2 : {};
|
|
5735
|
+
const prevQuestions = normalizePlannerQuestions(prev.questions);
|
|
5736
|
+
const resolvedQuestions = prevQuestions.length ? prevQuestions : normalizePlannerQuestions(questions);
|
|
5737
|
+
return {
|
|
5738
|
+
...prev,
|
|
5739
|
+
status: "answered",
|
|
5740
|
+
needsUserInput: false,
|
|
5741
|
+
...resolvedQuestions.length ? { questions: resolvedQuestions } : {},
|
|
5742
|
+
ask_user_answers: { ...answers.answersByKey },
|
|
5743
|
+
...answers.rawText ? { raw_user_reply: answers.rawText } : {},
|
|
5744
|
+
answeredAt: Date.now()
|
|
5745
|
+
};
|
|
5746
|
+
};
|
|
5747
|
+
if (!askUserRef) {
|
|
5748
|
+
return next;
|
|
5749
|
+
}
|
|
5750
|
+
const step = next[askUserRef.stepIndex];
|
|
5751
|
+
if (!Array.isArray(step.functions))
|
|
5752
|
+
step.functions = [];
|
|
5753
|
+
const existingFn = step.functions[askUserRef.functionIndex];
|
|
5754
|
+
const previousOutput = existingFn?.response?.output;
|
|
5755
|
+
step.functions[askUserRef.functionIndex] = {
|
|
5756
|
+
name: "ask_user",
|
|
5757
|
+
args: {
|
|
5758
|
+
questions_to_ask: questionPayload
|
|
5759
|
+
},
|
|
5760
|
+
response: {
|
|
5761
|
+
status: "Success",
|
|
5762
|
+
output: buildOutputPayload(previousOutput)
|
|
5763
|
+
}
|
|
5764
|
+
};
|
|
5765
|
+
return next;
|
|
5766
|
+
}
|
|
5767
|
+
function mergeAskUserAnswersIntoPlannerHistory(input, questions, answersByKey) {
|
|
5768
|
+
const next = sanitizePlannerHistoryForPersist(Array.isArray(input) ? input : []);
|
|
5769
|
+
for (let i = next.length - 1; i >= 0; i -= 1) {
|
|
5770
|
+
const step = next[i];
|
|
5771
|
+
if (!step || typeof step !== "object")
|
|
5772
|
+
continue;
|
|
5773
|
+
const asked = normalizePlannerQuestions(step.questionsAsked);
|
|
5774
|
+
if (!asked.length)
|
|
5775
|
+
continue;
|
|
5776
|
+
const askedKeys = new Set(asked.map((question) => question.key.toLowerCase()));
|
|
5777
|
+
const overlaps = questions.some((question) => askedKeys.has(String(question.key || "").toLowerCase()));
|
|
5778
|
+
if (!overlaps)
|
|
5779
|
+
continue;
|
|
5780
|
+
const existingAnswers = step.userAnswers && typeof step.userAnswers === "object" && !Array.isArray(step.userAnswers) ? step.userAnswers : {};
|
|
5781
|
+
step.userAnswers = {
|
|
5782
|
+
...existingAnswers,
|
|
5783
|
+
...answersByKey
|
|
5784
|
+
};
|
|
5785
|
+
return sanitizePlannerHistoryForPersist(next);
|
|
5786
|
+
}
|
|
5787
|
+
next.push({
|
|
5788
|
+
thought: "User provided clarification answers.",
|
|
5789
|
+
questionsAsked: questions,
|
|
5790
|
+
userAnswers: answersByKey
|
|
5791
|
+
});
|
|
5792
|
+
return sanitizePlannerHistoryForPersist(next);
|
|
5793
|
+
}
|
|
4679
5794
|
function buildPersistedState() {
|
|
4680
5795
|
const safePrevSteps = sanitizeAgentPrevStepsForPersist(Array.isArray(agentPrevSteps) ? agentPrevSteps : []);
|
|
5796
|
+
const normalizedRootUserInput = normalizeRootUserInput(rootUserInput);
|
|
5797
|
+
const pendingStepRef = pendingAskUser?.stepRef;
|
|
5798
|
+
const safePendingStepRef = pendingStepRef && Number.isFinite(pendingStepRef.stepIndex) && pendingStepRef.stepIndex >= 0 && Number.isFinite(pendingStepRef.functionIndex) && pendingStepRef.functionIndex >= 0 ? {
|
|
5799
|
+
stepIndex: pendingStepRef.stepIndex,
|
|
5800
|
+
functionIndex: pendingStepRef.functionIndex,
|
|
5801
|
+
...typeof pendingStepRef.accTreeId === "string" && pendingStepRef.accTreeId.trim() ? { accTreeId: pendingStepRef.accTreeId.trim() } : {}
|
|
5802
|
+
} : void 0;
|
|
4681
5803
|
return {
|
|
4682
|
-
trajectoryId,
|
|
5804
|
+
trajectoryId: taskTrajectoryId,
|
|
5805
|
+
taskBoundaryId,
|
|
5806
|
+
...normalizedRootUserInput ? { rootUserInput: normalizedRootUserInput } : {},
|
|
4683
5807
|
history: sanitizeHistoryForPersist(history),
|
|
4684
5808
|
plannerHistory: sanitizePlannerHistoryForPersist(Array.isArray(plannerHistory) ? plannerHistory : []),
|
|
4685
5809
|
agentPrevSteps: safePrevSteps,
|
|
@@ -4687,7 +5811,9 @@ function buildPersistedState() {
|
|
|
4687
5811
|
pendingAskUser: pendingAskUser ? {
|
|
4688
5812
|
questions: normalizePlannerQuestions(pendingAskUser.questions),
|
|
4689
5813
|
source: pendingAskUser.source,
|
|
4690
|
-
askedAt: Number(pendingAskUser.askedAt) || Date.now()
|
|
5814
|
+
askedAt: Number(pendingAskUser.askedAt) || Date.now(),
|
|
5815
|
+
...typeof pendingAskUser.boundaryId === "string" && pendingAskUser.boundaryId.trim() ? { boundaryId: pendingAskUser.boundaryId.trim() } : {},
|
|
5816
|
+
...safePendingStepRef ? { stepRef: safePendingStepRef } : {}
|
|
4691
5817
|
} : void 0
|
|
4692
5818
|
};
|
|
4693
5819
|
}
|
|
@@ -4722,20 +5848,33 @@ function hydrateState(raw) {
|
|
|
4722
5848
|
agentPrevSteps = sanitizeAgentPrevStepsForPersist(snapshot.lastToolPreviousSteps);
|
|
4723
5849
|
}
|
|
4724
5850
|
const hydratedQuestions = normalizePlannerQuestions(snapshot.pendingAskUser?.questions);
|
|
5851
|
+
const hydratedStepRefRaw = snapshot.pendingAskUser?.stepRef;
|
|
5852
|
+
const hydratedStepRef = hydratedStepRefRaw && Number.isFinite(Number(hydratedStepRefRaw.stepIndex)) && Number(hydratedStepRefRaw.stepIndex) >= 0 && Number.isFinite(Number(hydratedStepRefRaw.functionIndex)) && Number(hydratedStepRefRaw.functionIndex) >= 0 ? {
|
|
5853
|
+
stepIndex: Number(hydratedStepRefRaw.stepIndex),
|
|
5854
|
+
functionIndex: Number(hydratedStepRefRaw.functionIndex),
|
|
5855
|
+
...typeof hydratedStepRefRaw.accTreeId === "string" && hydratedStepRefRaw.accTreeId.trim() ? { accTreeId: hydratedStepRefRaw.accTreeId.trim() } : {}
|
|
5856
|
+
} : void 0;
|
|
4725
5857
|
if (hydratedQuestions.length > 0) {
|
|
4726
5858
|
pendingAskUser = {
|
|
4727
5859
|
questions: hydratedQuestions,
|
|
4728
5860
|
source: snapshot.pendingAskUser?.source === "planner" ? "planner" : "act",
|
|
4729
|
-
askedAt: Number(snapshot.pendingAskUser?.askedAt) || Date.now()
|
|
5861
|
+
askedAt: Number(snapshot.pendingAskUser?.askedAt) || Date.now(),
|
|
5862
|
+
boundaryId: typeof snapshot.pendingAskUser?.boundaryId === "string" ? String(snapshot.pendingAskUser.boundaryId).trim() || void 0 : void 0,
|
|
5863
|
+
...hydratedStepRef ? { stepRef: hydratedStepRef } : {}
|
|
4730
5864
|
};
|
|
4731
5865
|
} else {
|
|
4732
5866
|
pendingAskUser = void 0;
|
|
4733
5867
|
}
|
|
4734
5868
|
if (typeof snapshot.trajectoryId === "string" && snapshot.trajectoryId.trim()) {
|
|
4735
|
-
|
|
5869
|
+
taskTrajectoryId = snapshot.trajectoryId.trim();
|
|
4736
5870
|
}
|
|
5871
|
+
if (typeof snapshot.taskBoundaryId === "string" && String(snapshot.taskBoundaryId).trim()) {
|
|
5872
|
+
taskBoundaryId = String(snapshot.taskBoundaryId).trim();
|
|
5873
|
+
}
|
|
5874
|
+
const hydratedRootUserInput = normalizeRootUserInput(snapshot.rootUserInput);
|
|
5875
|
+
rootUserInput = hydratedRootUserInput || normalizeRootUserInput(getRootUserInputFallbackFromHistory()) || "";
|
|
4737
5876
|
if (!tabularStore) {
|
|
4738
|
-
tabularStore = new TabularStore(`rover-${
|
|
5877
|
+
tabularStore = new TabularStore(`rover-${taskTrajectoryId}`);
|
|
4739
5878
|
}
|
|
4740
5879
|
postStateSnapshot();
|
|
4741
5880
|
}
|
|
@@ -4757,7 +5896,7 @@ function sanitizeAssistantBlocks(input) {
|
|
|
4757
5896
|
if (type === "tool_output" || type === "json") {
|
|
4758
5897
|
out.push({
|
|
4759
5898
|
type,
|
|
4760
|
-
data:
|
|
5899
|
+
data: normalizeRuntimeToolOutput(raw.data),
|
|
4761
5900
|
label: typeof raw.label === "string" ? raw.label : void 0,
|
|
4762
5901
|
toolName: typeof raw.toolName === "string" ? raw.toolName : void 0
|
|
4763
5902
|
});
|
|
@@ -4765,6 +5904,21 @@ function sanitizeAssistantBlocks(input) {
|
|
|
4765
5904
|
}
|
|
4766
5905
|
return out.length ? out : void 0;
|
|
4767
5906
|
}
|
|
5907
|
+
function normalizeRuntimeToolOutput(value) {
|
|
5908
|
+
const cloned = cloneUnknown(value);
|
|
5909
|
+
if (cloned == null)
|
|
5910
|
+
return null;
|
|
5911
|
+
if (typeof cloned === "string" || typeof cloned === "number" || typeof cloned === "boolean") {
|
|
5912
|
+
return cloned;
|
|
5913
|
+
}
|
|
5914
|
+
if (Array.isArray(cloned)) {
|
|
5915
|
+
return cloned;
|
|
5916
|
+
}
|
|
5917
|
+
if (typeof cloned === "object") {
|
|
5918
|
+
return cloned;
|
|
5919
|
+
}
|
|
5920
|
+
return String(cloned);
|
|
5921
|
+
}
|
|
4768
5922
|
function summarizeOutputText(output) {
|
|
4769
5923
|
if (output == null)
|
|
4770
5924
|
return void 0;
|
|
@@ -4786,7 +5940,7 @@ function summarizeOutputText(output) {
|
|
|
4786
5940
|
}
|
|
4787
5941
|
if (lines.length)
|
|
4788
5942
|
return lines.join("\n");
|
|
4789
|
-
return
|
|
5943
|
+
return void 0;
|
|
4790
5944
|
}
|
|
4791
5945
|
if (typeof output === "object") {
|
|
4792
5946
|
const preferredKeys = ["response", "message", "summary", "text", "content", "result", "description"];
|
|
@@ -4796,10 +5950,7 @@ function summarizeOutputText(output) {
|
|
|
4796
5950
|
return value.trim();
|
|
4797
5951
|
}
|
|
4798
5952
|
}
|
|
4799
|
-
|
|
4800
|
-
if (!keys.length)
|
|
4801
|
-
return void 0;
|
|
4802
|
-
return `Received ${keys.length} field(s).`;
|
|
5953
|
+
return void 0;
|
|
4803
5954
|
}
|
|
4804
5955
|
return void 0;
|
|
4805
5956
|
}
|
|
@@ -4844,14 +5995,14 @@ function shouldAttachStructuredBlock(output, summaryText) {
|
|
|
4844
5995
|
}
|
|
4845
5996
|
function buildAssistantPayloadFromToolOutput(output, options) {
|
|
4846
5997
|
const summaryText = summarizeOutputText(output);
|
|
4847
|
-
const text = summaryText || options?.fallbackText || "
|
|
5998
|
+
const text = summaryText || options?.fallbackText || "";
|
|
4848
5999
|
const blocks = [];
|
|
4849
6000
|
if (shouldAttachStructuredBlock(output, summaryText)) {
|
|
4850
6001
|
blocks.push({
|
|
4851
6002
|
type: "tool_output",
|
|
4852
6003
|
label: options?.label,
|
|
4853
6004
|
toolName: options?.toolName,
|
|
4854
|
-
data:
|
|
6005
|
+
data: normalizeRuntimeToolOutput(output)
|
|
4855
6006
|
});
|
|
4856
6007
|
}
|
|
4857
6008
|
return { text, blocks: blocks.length ? blocks : void 0 };
|
|
@@ -4861,8 +6012,15 @@ function postAssistantMessage(payload) {
|
|
|
4861
6012
|
const blocks = typeof payload === "string" ? void 0 : sanitizeAssistantBlocks(payload.blocks);
|
|
4862
6013
|
const firstTextBlock = blocks?.find((block) => block.type === "text");
|
|
4863
6014
|
const firstStructuredBlock = blocks?.find((block) => block.type === "tool_output" || block.type === "json");
|
|
4864
|
-
const resolvedText = text || firstTextBlock?.text || summarizeOutputText(firstStructuredBlock?.data) || "
|
|
4865
|
-
|
|
6015
|
+
const resolvedText = text || firstTextBlock?.text || summarizeOutputText(firstStructuredBlock?.data) || "";
|
|
6016
|
+
if (!resolvedText && (!blocks || blocks.length === 0)) {
|
|
6017
|
+
return "";
|
|
6018
|
+
}
|
|
6019
|
+
const runId = activeRun?.runId;
|
|
6020
|
+
if (runId && cancelledRunIds.has(runId)) {
|
|
6021
|
+
return resolvedText;
|
|
6022
|
+
}
|
|
6023
|
+
self.postMessage({ type: "assistant", text: resolvedText, blocks, runId });
|
|
4866
6024
|
return resolvedText;
|
|
4867
6025
|
}
|
|
4868
6026
|
function dedupeFunctionDeclarations(declarations) {
|
|
@@ -4880,9 +6038,20 @@ function removePlannerNameCollisions(declarations) {
|
|
|
4880
6038
|
return declarations.filter((decl) => !!decl?.name && !PLANNER_TOOL_NAME_SET.has(decl.name));
|
|
4881
6039
|
}
|
|
4882
6040
|
function postAuthRequired(err) {
|
|
6041
|
+
const runId = activeRun?.runId;
|
|
6042
|
+
if (runId && cancelledRunIds.has(runId))
|
|
6043
|
+
return;
|
|
4883
6044
|
const envelope = err && typeof err === "object" && err.code && err.message ? toRoverErrorEnvelope({ errorDetails: err }, "Rover API key is required.") : toRoverErrorEnvelope(err, "Rover API key is required.");
|
|
4884
|
-
self.postMessage({ type: "auth_required", error: envelope, runId
|
|
4885
|
-
}
|
|
6045
|
+
self.postMessage({ type: "auth_required", error: envelope, runId });
|
|
6046
|
+
}
|
|
6047
|
+
var NAVIGATION_TOOL_NAME_SET = /* @__PURE__ */ new Set([
|
|
6048
|
+
"goto_url",
|
|
6049
|
+
"google_search",
|
|
6050
|
+
"go_back",
|
|
6051
|
+
"go_forward",
|
|
6052
|
+
"refresh_page",
|
|
6053
|
+
"open_new_tab"
|
|
6054
|
+
]);
|
|
4886
6055
|
function toStructuredErrorPayload(err, fallbackMessage = "Operation failed") {
|
|
4887
6056
|
const envelope = toRoverErrorEnvelope(err, fallbackMessage);
|
|
4888
6057
|
const payload = {
|
|
@@ -4923,6 +6092,58 @@ function extractStructuredErrorFromToolResult(result) {
|
|
|
4923
6092
|
}
|
|
4924
6093
|
return void 0;
|
|
4925
6094
|
}
|
|
6095
|
+
function sawRecentSuccessfulNavigationStep(steps) {
|
|
6096
|
+
if (!Array.isArray(steps) || steps.length === 0)
|
|
6097
|
+
return false;
|
|
6098
|
+
let inspectedStepCount = 0;
|
|
6099
|
+
for (let stepIndex = steps.length - 1; stepIndex >= 0; stepIndex -= 1) {
|
|
6100
|
+
const step = steps[stepIndex];
|
|
6101
|
+
const functions = Array.isArray(step?.functions) ? step.functions : [];
|
|
6102
|
+
if (!functions.length)
|
|
6103
|
+
continue;
|
|
6104
|
+
inspectedStepCount += 1;
|
|
6105
|
+
for (let fnIndex = functions.length - 1; fnIndex >= 0; fnIndex -= 1) {
|
|
6106
|
+
const fn = functions[fnIndex];
|
|
6107
|
+
const toolName = String(fn?.name || fn?.toolName || fn?.functionName || "").trim();
|
|
6108
|
+
if (!toolName || !NAVIGATION_TOOL_NAME_SET.has(toolName))
|
|
6109
|
+
continue;
|
|
6110
|
+
const status = String(fn?.response?.status || fn?.status || "").trim().toLowerCase();
|
|
6111
|
+
if (status === "success") {
|
|
6112
|
+
return true;
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
if (inspectedStepCount >= 2)
|
|
6116
|
+
break;
|
|
6117
|
+
}
|
|
6118
|
+
return false;
|
|
6119
|
+
}
|
|
6120
|
+
var NAVIGATION_TRANSIENT_CODES = /* @__PURE__ */ new Set([
|
|
6121
|
+
"UNKNOWN_ERROR",
|
|
6122
|
+
"MISSING_AUTH_TOKEN",
|
|
6123
|
+
"MISSING_AUTH",
|
|
6124
|
+
"SESSION_TOKEN_EXPIRED",
|
|
6125
|
+
"SESSION_TOKEN_INVALID",
|
|
6126
|
+
"BOOTSTRAP_REQUIRED"
|
|
6127
|
+
]);
|
|
6128
|
+
function normalizeLifecycleHandoffError(payload, steps) {
|
|
6129
|
+
const code = String(payload?.error?.code || "").trim().toUpperCase();
|
|
6130
|
+
if (code && !NAVIGATION_TRANSIENT_CODES.has(code))
|
|
6131
|
+
return payload;
|
|
6132
|
+
if (!sawRecentSuccessfulNavigationStep(steps))
|
|
6133
|
+
return payload;
|
|
6134
|
+
return {
|
|
6135
|
+
...payload,
|
|
6136
|
+
error: {
|
|
6137
|
+
...payload.error,
|
|
6138
|
+
code: "NAVIGATION_HANDOFF_PENDING",
|
|
6139
|
+
message: payload.error?.message || "Navigation handoff is in progress.",
|
|
6140
|
+
retryable: true,
|
|
6141
|
+
next_action: "Wait for post-navigation resume and continue the task."
|
|
6142
|
+
},
|
|
6143
|
+
retryable: true,
|
|
6144
|
+
next_action: "Wait for post-navigation resume and continue the task."
|
|
6145
|
+
};
|
|
6146
|
+
}
|
|
4926
6147
|
function maybePostNavigationGuardrailFromToolResult(toolResult) {
|
|
4927
6148
|
if (!toolResult || typeof toolResult !== "object")
|
|
4928
6149
|
return;
|
|
@@ -4942,52 +6163,71 @@ function maybePostNavigationGuardrailFromToolResult(toolResult) {
|
|
|
4942
6163
|
allowedDomains: output?.allowed_domains || details?.details?.allowedDomains
|
|
4943
6164
|
});
|
|
4944
6165
|
}
|
|
4945
|
-
function
|
|
4946
|
-
const
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
const
|
|
6166
|
+
function assessAdversarialInput(rawText) {
|
|
6167
|
+
const text = String(rawText || "").toLowerCase();
|
|
6168
|
+
if (!text.trim())
|
|
6169
|
+
return { blocked: false, score: 0, reasons: [] };
|
|
6170
|
+
const signals = [
|
|
6171
|
+
{ reason: "prompt_injection", pattern: /\b(ignore|bypass|override)\b.{0,40}\b(instruction|policy|guardrail|system|developer)\b/i, weight: 2 },
|
|
6172
|
+
{ reason: "secret_exfiltration", pattern: /\b(token|cookie|password|secret|api key|session key)\b.{0,40}\b(extract|dump|reveal|steal|exfiltrat)/i, weight: 3 },
|
|
6173
|
+
{ reason: "credential_harvest", pattern: /\b(phish|credential|login prompt|social engineering)\b/i, weight: 3 },
|
|
6174
|
+
{ reason: "policy_evasion", pattern: /\b(do not tell|without asking|silently|hidden|covert)\b/i, weight: 1 }
|
|
6175
|
+
];
|
|
6176
|
+
const reasons = [];
|
|
6177
|
+
let score = 0;
|
|
6178
|
+
for (const signal of signals) {
|
|
6179
|
+
if (!signal.pattern.test(text))
|
|
6180
|
+
continue;
|
|
6181
|
+
reasons.push(signal.reason);
|
|
6182
|
+
score += signal.weight;
|
|
6183
|
+
}
|
|
6184
|
+
const blocked = score >= 3;
|
|
6185
|
+
return { blocked, score, reasons };
|
|
6186
|
+
}
|
|
6187
|
+
function buildChatLogFromHistory(input, currentUserInput, maxTurns = MAX_RESUME_CUE_TURNS) {
|
|
6188
|
+
const normalize = (value) => String(value || "").replace(/\s+/g, " ").trim();
|
|
6189
|
+
const normalizedCurrent = normalize(String(currentUserInput || ""));
|
|
6190
|
+
if (!normalizedCurrent)
|
|
6191
|
+
return [];
|
|
4950
6192
|
const entries = input.filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
|
|
4951
6193
|
role: message.role,
|
|
4952
|
-
content:
|
|
4953
|
-
})).filter((message) => !!message.content)
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
6194
|
+
content: normalize(String(message.content || ""))
|
|
6195
|
+
})).filter((message) => !!message.content).filter((message) => {
|
|
6196
|
+
const lowered = message.content.toLowerCase();
|
|
6197
|
+
if (lowered.includes("[ask_user_answers]"))
|
|
6198
|
+
return false;
|
|
6199
|
+
if (lowered.includes("[raw_user_reply]"))
|
|
6200
|
+
return false;
|
|
6201
|
+
if (lowered.includes("[continue_planning]"))
|
|
6202
|
+
return false;
|
|
6203
|
+
return true;
|
|
6204
|
+
});
|
|
6205
|
+
const turns = [];
|
|
4963
6206
|
for (const entry of entries) {
|
|
4964
|
-
|
|
4965
|
-
|
|
6207
|
+
if (entry.role === "user") {
|
|
6208
|
+
turns.push({ user: entry.content });
|
|
4966
6209
|
continue;
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
const hasAnchor = selected.some((message) => message.role === "user" && message.content === firstUser.content);
|
|
4974
|
-
if (!hasAnchor) {
|
|
4975
|
-
selected = [firstUser, ...selected];
|
|
6210
|
+
}
|
|
6211
|
+
if (!turns.length)
|
|
6212
|
+
continue;
|
|
6213
|
+
const latest = turns[turns.length - 1];
|
|
6214
|
+
if (!latest.assistant) {
|
|
6215
|
+
latest.assistant = entry.content;
|
|
4976
6216
|
}
|
|
4977
6217
|
}
|
|
4978
|
-
if (
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
if (
|
|
4984
|
-
|
|
6218
|
+
if (!turns.length)
|
|
6219
|
+
return [];
|
|
6220
|
+
const cappedTurns = turns.slice(-Math.max(1, Math.min(4, Math.floor(maxTurns))));
|
|
6221
|
+
const messages = [];
|
|
6222
|
+
for (const turn of cappedTurns) {
|
|
6223
|
+
if (turn.user && turn.user !== normalizedCurrent) {
|
|
6224
|
+
messages.push({ role: "user", message: turn.user });
|
|
6225
|
+
}
|
|
6226
|
+
if (turn.assistant) {
|
|
6227
|
+
messages.push({ role: "model", message: turn.assistant });
|
|
4985
6228
|
}
|
|
4986
6229
|
}
|
|
4987
|
-
return
|
|
4988
|
-
role: message.role === "user" ? "user" : "model",
|
|
4989
|
-
message: message.content
|
|
4990
|
-
}));
|
|
6230
|
+
return messages;
|
|
4991
6231
|
}
|
|
4992
6232
|
function applyAgentPrevSteps(next, options) {
|
|
4993
6233
|
if (!Array.isArray(next) || !next.length)
|
|
@@ -5049,14 +6289,14 @@ function buildPlannerToolResultBlocks(toolResults) {
|
|
|
5049
6289
|
type: "tool_output",
|
|
5050
6290
|
label: result.toolName ? `${stepLabel}: ${result.toolName}` : stepLabel,
|
|
5051
6291
|
toolName: typeof result.toolName === "string" ? result.toolName : void 0,
|
|
5052
|
-
data:
|
|
6292
|
+
data: normalizeRuntimeToolOutput(output)
|
|
5053
6293
|
});
|
|
5054
6294
|
}
|
|
5055
6295
|
if (result.error || result.errorDetails) {
|
|
5056
6296
|
blocks.push({
|
|
5057
6297
|
type: "json",
|
|
5058
6298
|
label: `${stepLabel} error`,
|
|
5059
|
-
data:
|
|
6299
|
+
data: normalizeRuntimeToolOutput({
|
|
5060
6300
|
error: result.error,
|
|
5061
6301
|
errorDetails: result.errorDetails
|
|
5062
6302
|
})
|
|
@@ -5142,6 +6382,24 @@ function detectOpenedTabFromToolResult(result) {
|
|
|
5142
6382
|
}
|
|
5143
6383
|
return void 0;
|
|
5144
6384
|
}
|
|
6385
|
+
function extractTouchedTabIdsFromToolResult(result) {
|
|
6386
|
+
if (!result || typeof result !== "object")
|
|
6387
|
+
return [];
|
|
6388
|
+
const output = result.output && typeof result.output === "object" ? result.output : void 0;
|
|
6389
|
+
const candidates = [
|
|
6390
|
+
Number(result.logicalTabId ?? result.logical_tab_id ?? result.tabId ?? result.tab_id),
|
|
6391
|
+
Number(output?.logicalTabId ?? output?.logical_tab_id ?? output?.tabId ?? output?.tab_id)
|
|
6392
|
+
];
|
|
6393
|
+
const unique = /* @__PURE__ */ new Set();
|
|
6394
|
+
const out = [];
|
|
6395
|
+
for (const value of candidates) {
|
|
6396
|
+
if (!Number.isFinite(value) || value <= 0 || unique.has(value))
|
|
6397
|
+
continue;
|
|
6398
|
+
unique.add(value);
|
|
6399
|
+
out.push(value);
|
|
6400
|
+
}
|
|
6401
|
+
return out;
|
|
6402
|
+
}
|
|
5145
6403
|
function extractQuestionsFromResult(result) {
|
|
5146
6404
|
if (!result || typeof result !== "object")
|
|
5147
6405
|
return void 0;
|
|
@@ -5149,7 +6407,7 @@ function extractQuestionsFromResult(result) {
|
|
|
5149
6407
|
if (topLevel.length)
|
|
5150
6408
|
return topLevel;
|
|
5151
6409
|
const output = result.output;
|
|
5152
|
-
const outputQuestions = normalizePlannerQuestions(output
|
|
6410
|
+
const outputQuestions = normalizePlannerQuestions(output && typeof output === "object" ? output.questions : void 0);
|
|
5153
6411
|
if (outputQuestions.length)
|
|
5154
6412
|
return outputQuestions;
|
|
5155
6413
|
return void 0;
|
|
@@ -5173,77 +6431,170 @@ function extractPlannerQuestionsFromToolResults(toolResults) {
|
|
|
5173
6431
|
}
|
|
5174
6432
|
return combined.slice(0, 6);
|
|
5175
6433
|
}
|
|
5176
|
-
function
|
|
5177
|
-
if (!
|
|
5178
|
-
return {
|
|
6434
|
+
function inferPlannerContinuation(toolResults) {
|
|
6435
|
+
if (!Array.isArray(toolResults) || toolResults.length === 0) {
|
|
6436
|
+
return {
|
|
6437
|
+
failed: false,
|
|
6438
|
+
needsUserInput: false,
|
|
6439
|
+
navigationPending: false,
|
|
6440
|
+
sameTabNavigationPending: false
|
|
6441
|
+
};
|
|
5179
6442
|
}
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
6443
|
+
let failed = false;
|
|
6444
|
+
let needsUserInput = false;
|
|
6445
|
+
let navigationPending = false;
|
|
6446
|
+
let sameTabNavigationPending = false;
|
|
6447
|
+
for (const result of toolResults) {
|
|
6448
|
+
if (!result || typeof result !== "object")
|
|
6449
|
+
continue;
|
|
6450
|
+
if (result.error || result.errorDetails) {
|
|
6451
|
+
failed = true;
|
|
6452
|
+
continue;
|
|
6453
|
+
}
|
|
6454
|
+
const output = result.output && typeof result.output === "object" ? result.output : void 0;
|
|
6455
|
+
if (!output)
|
|
6456
|
+
continue;
|
|
6457
|
+
const navigationOutcome = String(output.navigationOutcome || "").trim().toLowerCase();
|
|
6458
|
+
if (output.navigationPending === true || navigationOutcome === "same_tab_scheduled" || navigationOutcome === "new_tab_opened") {
|
|
6459
|
+
navigationPending = true;
|
|
6460
|
+
if (navigationOutcome === "same_tab_scheduled") {
|
|
6461
|
+
sameTabNavigationPending = true;
|
|
6462
|
+
}
|
|
6463
|
+
}
|
|
6464
|
+
const status = String(output.taskStatus || output.status || "").trim().toLowerCase();
|
|
6465
|
+
if (status === "failure" || status === "failed" || status === "error") {
|
|
6466
|
+
failed = true;
|
|
6467
|
+
}
|
|
6468
|
+
if (status === "waiting_input" || status === "needs_input" || status === "pending_user_input") {
|
|
6469
|
+
needsUserInput = true;
|
|
6470
|
+
}
|
|
6471
|
+
if (output.needsUserInput === true || output.waitingForUserInput === true) {
|
|
6472
|
+
needsUserInput = true;
|
|
6473
|
+
}
|
|
6474
|
+
const questions = normalizePlannerQuestions(output.questions);
|
|
6475
|
+
if (questions.length > 0) {
|
|
6476
|
+
needsUserInput = true;
|
|
6477
|
+
}
|
|
5184
6478
|
}
|
|
5185
|
-
|
|
5186
|
-
|
|
6479
|
+
return { failed, needsUserInput, navigationPending, sameTabNavigationPending };
|
|
6480
|
+
}
|
|
6481
|
+
function deriveDirectToolRunOutcome(result) {
|
|
6482
|
+
if (!result || typeof result !== "object") {
|
|
6483
|
+
return {
|
|
6484
|
+
taskComplete: true,
|
|
6485
|
+
terminalState: "completed",
|
|
6486
|
+
contextResetRecommended: true
|
|
6487
|
+
};
|
|
5187
6488
|
}
|
|
5188
|
-
|
|
5189
|
-
|
|
6489
|
+
const topLevelNavigationOutcome = String(result.navigationOutcome || "").trim().toLowerCase();
|
|
6490
|
+
if (result.navigationPending === true) {
|
|
6491
|
+
const isSameTabHandoff = topLevelNavigationOutcome === "same_tab_scheduled";
|
|
6492
|
+
return {
|
|
6493
|
+
taskComplete: false,
|
|
6494
|
+
terminalState: "in_progress",
|
|
6495
|
+
navigationPending: isSameTabHandoff,
|
|
6496
|
+
continuationReason: isSameTabHandoff ? "same_tab_navigation_handoff" : "loop_continue"
|
|
6497
|
+
};
|
|
5190
6498
|
}
|
|
6499
|
+
const questions = extractQuestionsFromResult(result);
|
|
6500
|
+
if (result.error)
|
|
6501
|
+
return { taskComplete: false, terminalState: "failed" };
|
|
5191
6502
|
const output = result.output;
|
|
5192
6503
|
if (output && typeof output === "object") {
|
|
5193
|
-
|
|
5194
|
-
|
|
6504
|
+
const outputRecord = output;
|
|
6505
|
+
const topLevelStatus = String(result.status || "").trim().toLowerCase();
|
|
6506
|
+
if (topLevelStatus === "failure" || topLevelStatus === "failed" || topLevelStatus === "error") {
|
|
6507
|
+
return { taskComplete: false, terminalState: "failed" };
|
|
5195
6508
|
}
|
|
5196
|
-
if (
|
|
5197
|
-
return {
|
|
6509
|
+
if (topLevelStatus === "waiting_input" || topLevelStatus === "needs_input" || topLevelStatus === "pending_user_input") {
|
|
6510
|
+
return {
|
|
6511
|
+
taskComplete: false,
|
|
6512
|
+
needsUserInput: true,
|
|
6513
|
+
questions,
|
|
6514
|
+
terminalState: "waiting_input",
|
|
6515
|
+
continuationReason: "awaiting_user"
|
|
6516
|
+
};
|
|
5198
6517
|
}
|
|
5199
|
-
|
|
5200
|
-
|
|
6518
|
+
const navigationOutcome = String(outputRecord.navigationOutcome || "").trim().toLowerCase();
|
|
6519
|
+
const navigationMode = String(outputRecord.navigation || "").trim().toLowerCase();
|
|
6520
|
+
if (outputRecord.navigationPending === true || navigationOutcome === "same_tab_scheduled" || navigationOutcome === "new_tab_opened" || navigationMode === "same_tab") {
|
|
6521
|
+
const sameTabHandoff = navigationOutcome === "same_tab_scheduled" || navigationMode === "same_tab";
|
|
6522
|
+
return {
|
|
6523
|
+
taskComplete: false,
|
|
6524
|
+
terminalState: "in_progress",
|
|
6525
|
+
navigationPending: sameTabHandoff,
|
|
6526
|
+
continuationReason: sameTabHandoff ? "same_tab_navigation_handoff" : "loop_continue",
|
|
6527
|
+
contextResetRecommended: false
|
|
6528
|
+
};
|
|
5201
6529
|
}
|
|
5202
|
-
if (
|
|
5203
|
-
return {
|
|
6530
|
+
if (outputRecord.needsUserInput === true || outputRecord.waitingForUserInput === true) {
|
|
6531
|
+
return {
|
|
6532
|
+
taskComplete: false,
|
|
6533
|
+
needsUserInput: true,
|
|
6534
|
+
questions,
|
|
6535
|
+
terminalState: "waiting_input",
|
|
6536
|
+
continuationReason: "awaiting_user"
|
|
6537
|
+
};
|
|
5204
6538
|
}
|
|
5205
|
-
if (
|
|
5206
|
-
return {
|
|
6539
|
+
if (Array.isArray(outputRecord.questions) && outputRecord.questions.length > 0) {
|
|
6540
|
+
return {
|
|
6541
|
+
taskComplete: false,
|
|
6542
|
+
needsUserInput: true,
|
|
6543
|
+
questions,
|
|
6544
|
+
terminalState: "waiting_input",
|
|
6545
|
+
continuationReason: "awaiting_user"
|
|
6546
|
+
};
|
|
5207
6547
|
}
|
|
5208
|
-
|
|
6548
|
+
if (outputRecord.error || outputRecord.success === false)
|
|
6549
|
+
return { taskComplete: false, terminalState: "failed" };
|
|
6550
|
+
const taskStatus = String(outputRecord.taskStatus || outputRecord.status || "").toLowerCase();
|
|
5209
6551
|
if (taskStatus) {
|
|
5210
6552
|
if (taskStatus === "waiting_input" || taskStatus === "needs_input" || taskStatus === "pending_user_input") {
|
|
5211
|
-
return {
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
return { taskComplete: true };
|
|
6553
|
+
return {
|
|
6554
|
+
taskComplete: false,
|
|
6555
|
+
needsUserInput: true,
|
|
6556
|
+
terminalState: "waiting_input",
|
|
6557
|
+
continuationReason: "awaiting_user"
|
|
6558
|
+
};
|
|
5218
6559
|
}
|
|
5219
6560
|
if (taskStatus === "failure" || taskStatus === "failed" || taskStatus === "error") {
|
|
5220
|
-
return { taskComplete: false };
|
|
6561
|
+
return { taskComplete: false, terminalState: "failed" };
|
|
5221
6562
|
}
|
|
5222
6563
|
}
|
|
5223
|
-
if (output.success === false) {
|
|
5224
|
-
return { taskComplete: false };
|
|
5225
|
-
}
|
|
5226
|
-
if (String(output.status || "").trim().toLowerCase() === "failure") {
|
|
5227
|
-
return { taskComplete: false };
|
|
5228
|
-
}
|
|
5229
|
-
}
|
|
5230
|
-
if (output != null) {
|
|
5231
|
-
return { taskComplete: true };
|
|
5232
6564
|
}
|
|
5233
|
-
return {
|
|
6565
|
+
return {
|
|
6566
|
+
taskComplete: true,
|
|
6567
|
+
terminalState: "completed",
|
|
6568
|
+
contextResetRecommended: true
|
|
6569
|
+
};
|
|
5234
6570
|
}
|
|
5235
6571
|
function normalizeRunOutcome(outcome) {
|
|
5236
6572
|
if (!outcome || typeof outcome !== "object") {
|
|
5237
|
-
return {
|
|
6573
|
+
return {
|
|
6574
|
+
taskComplete: true,
|
|
6575
|
+
needsUserInput: false,
|
|
6576
|
+
terminalState: "completed",
|
|
6577
|
+
continuationReason: void 0,
|
|
6578
|
+
contextResetRecommended: true
|
|
6579
|
+
};
|
|
5238
6580
|
}
|
|
5239
|
-
const
|
|
5240
|
-
const
|
|
6581
|
+
const inferredNeedsUserInput = outcome.needsUserInput === true;
|
|
6582
|
+
const incomingTerminalState = String(outcome.terminalState || "").trim().toLowerCase();
|
|
6583
|
+
const terminalState = incomingTerminalState === "waiting_input" || incomingTerminalState === "in_progress" || incomingTerminalState === "completed" || incomingTerminalState === "failed" ? incomingTerminalState : inferredNeedsUserInput ? "waiting_input" : outcome.taskComplete === true ? "completed" : outcome.taskComplete === false ? "in_progress" : "completed";
|
|
6584
|
+
const needsUserInput = terminalState === "waiting_input" || inferredNeedsUserInput;
|
|
6585
|
+
const taskComplete = terminalState === "completed" || outcome.taskComplete === true && !needsUserInput;
|
|
5241
6586
|
const questions = normalizePlannerQuestions(outcome.questions);
|
|
6587
|
+
const continuationCandidate = String(outcome.continuationReason || "").trim().toLowerCase();
|
|
6588
|
+
const continuationReason = continuationCandidate === "loop_continue" || continuationCandidate === "same_tab_navigation_handoff" || continuationCandidate === "awaiting_user" ? continuationCandidate : needsUserInput ? "awaiting_user" : outcome.navigationPending === true ? "same_tab_navigation_handoff" : terminalState === "in_progress" && !taskComplete ? "loop_continue" : void 0;
|
|
6589
|
+
const contextResetRecommended = outcome.contextResetRecommended === true || terminalState === "completed" || terminalState === "failed";
|
|
5242
6590
|
return {
|
|
5243
6591
|
route: outcome.route,
|
|
5244
6592
|
taskComplete,
|
|
5245
6593
|
needsUserInput,
|
|
5246
|
-
questions: questions.length ? questions : void 0
|
|
6594
|
+
questions: questions.length ? questions : void 0,
|
|
6595
|
+
terminalState,
|
|
6596
|
+
continuationReason,
|
|
6597
|
+
contextResetRecommended
|
|
5247
6598
|
};
|
|
5248
6599
|
}
|
|
5249
6600
|
function rememberTerminalRun(runId, result) {
|
|
@@ -5264,11 +6615,19 @@ function rememberCancelledRun(runId) {
|
|
|
5264
6615
|
cancelledRunIds.delete(oldest);
|
|
5265
6616
|
}
|
|
5266
6617
|
}
|
|
5267
|
-
function
|
|
6618
|
+
function throwIfCancelledRun(runId) {
|
|
6619
|
+
if (!runId)
|
|
6620
|
+
return;
|
|
6621
|
+
if (cancelledRunIds.has(runId)) {
|
|
6622
|
+
throw new DOMException("Run cancelled", "AbortError");
|
|
6623
|
+
}
|
|
6624
|
+
}
|
|
6625
|
+
function clearTaskScopedContextAfterBoundary(_reason) {
|
|
5268
6626
|
history.length = 0;
|
|
5269
6627
|
plannerHistory = [];
|
|
5270
6628
|
agentPrevSteps = [];
|
|
5271
6629
|
pendingAskUser = void 0;
|
|
6630
|
+
rootUserInput = "";
|
|
5272
6631
|
}
|
|
5273
6632
|
async function maybeWaitForNewTab(result) {
|
|
5274
6633
|
const openedTab = detectOpenedTabFromToolResult(result);
|
|
@@ -5284,52 +6643,66 @@ async function handleUserMessage(text, options) {
|
|
|
5284
6643
|
throw new Error("Worker not initialized");
|
|
5285
6644
|
if (!bridgeRpc)
|
|
5286
6645
|
throw new Error("Bridge RPC not initialized");
|
|
6646
|
+
const activeRunId = activeRun?.runId;
|
|
6647
|
+
throwIfCancelledRun(activeRunId);
|
|
5287
6648
|
postStatus("Analyzing request", text, "analyze");
|
|
5288
6649
|
const shouldSkipUserPush = options?.resume && history.length > 0 && history[history.length - 1]?.role === "user" && history[history.length - 1]?.content === text;
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
6650
|
+
const normalizedIncomingText = String(text || "").trim();
|
|
6651
|
+
if (config.external?.adversarialGate === "pre_tool_block") {
|
|
6652
|
+
const adversarial = assessAdversarialInput(normalizedIncomingText);
|
|
6653
|
+
if (adversarial.blocked) {
|
|
6654
|
+
const blockedMessage = "I can\u2019t run that request because it appears adversarial. Please rephrase with a safe, task-focused instruction.";
|
|
6655
|
+
postAssistantMessage(blockedMessage);
|
|
6656
|
+
postStatus("Blocked unsafe request", adversarial.reasons.join(", ") || "adversarial_input", "complete");
|
|
6657
|
+
postStateSnapshot();
|
|
6658
|
+
return {
|
|
6659
|
+
taskComplete: false,
|
|
6660
|
+
needsUserInput: false,
|
|
6661
|
+
terminalState: "failed",
|
|
6662
|
+
contextResetRecommended: true
|
|
6663
|
+
};
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
const pendingAskUserSnapshot = pendingAskUser && pendingAskUser.boundaryId && pendingAskUser.boundaryId !== taskBoundaryId ? void 0 : pendingAskUser;
|
|
6667
|
+
if (!pendingAskUserSnapshot && pendingAskUser) {
|
|
6668
|
+
pendingAskUser = void 0;
|
|
6669
|
+
}
|
|
6670
|
+
const fallbackRootInput = normalizeRootUserInput(getRootUserInputFallbackFromHistory());
|
|
6671
|
+
const existingRootInput = normalizeRootUserInput(rootUserInput) || fallbackRootInput;
|
|
6672
|
+
if (existingRootInput) {
|
|
6673
|
+
rootUserInput = existingRootInput;
|
|
6674
|
+
}
|
|
6675
|
+
if (!pendingAskUserSnapshot?.questions?.length && normalizedIncomingText && !options?.resume) {
|
|
6676
|
+
rootUserInput = normalizedIncomingText;
|
|
5292
6677
|
}
|
|
5293
6678
|
let effectiveUserInput = text;
|
|
5294
|
-
|
|
5295
|
-
|
|
6679
|
+
let chatLogCurrentInputForDedupe = text;
|
|
6680
|
+
let consumedAsAskUserAnswer = false;
|
|
6681
|
+
if (pendingAskUserSnapshot?.questions?.length) {
|
|
6682
|
+
const normalizedAnswers = normalizeAskUserAnswerMeta(options?.askUserAnswers, pendingAskUserSnapshot.questions, text);
|
|
5296
6683
|
if (normalizedAnswers) {
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
applyAgentPrevSteps(
|
|
5308
|
-
...agentPrevSteps,
|
|
5309
|
-
{
|
|
5310
|
-
functions: [{
|
|
5311
|
-
name: "ask_user",
|
|
5312
|
-
args: {
|
|
5313
|
-
questions_to_ask: pendingAskUser.questions.map((q) => ({
|
|
5314
|
-
key: q.key,
|
|
5315
|
-
query: q.query
|
|
5316
|
-
}))
|
|
5317
|
-
},
|
|
5318
|
-
response: {
|
|
5319
|
-
status: "Success",
|
|
5320
|
-
output: {
|
|
5321
|
-
ask_user_answers: normalizedAnswers.answersByKey,
|
|
5322
|
-
raw_user_reply: normalizedAnswers.rawText
|
|
5323
|
-
}
|
|
5324
|
-
}
|
|
5325
|
-
}]
|
|
5326
|
-
}
|
|
5327
|
-
], { snapshot: false });
|
|
6684
|
+
consumedAsAskUserAnswer = true;
|
|
6685
|
+
const answerContext = buildAskUserAnswerContext(pendingAskUserSnapshot.questions, normalizedAnswers);
|
|
6686
|
+
const focusInput = normalizeRootUserInput(rootUserInput) || normalizedIncomingText || fallbackRootInput || "";
|
|
6687
|
+
if (focusInput)
|
|
6688
|
+
rootUserInput = focusInput;
|
|
6689
|
+
effectiveUserInput = buildContinuePlanningInput(focusInput, "ask_user", answerContext);
|
|
6690
|
+
chatLogCurrentInputForDedupe = focusInput || text;
|
|
6691
|
+
if (pendingAskUserSnapshot.source === "planner") {
|
|
6692
|
+
plannerHistory = mergeAskUserAnswersIntoPlannerHistory(plannerHistory, pendingAskUserSnapshot.questions, normalizedAnswers.answersByKey);
|
|
6693
|
+
}
|
|
6694
|
+
applyAgentPrevSteps(mergeAskUserAnswerIntoPrevSteps(agentPrevSteps, pendingAskUserSnapshot, normalizedAnswers), { snapshot: false });
|
|
5328
6695
|
pendingAskUser = void 0;
|
|
5329
6696
|
postStateSnapshot();
|
|
5330
6697
|
}
|
|
5331
6698
|
}
|
|
6699
|
+
if (!shouldSkipUserPush && !consumedAsAskUserAnswer) {
|
|
6700
|
+
history.push({ role: "user", content: text });
|
|
6701
|
+
postStateSnapshot();
|
|
6702
|
+
}
|
|
6703
|
+
throwIfCancelledRun(activeRunId);
|
|
5332
6704
|
const tabs = await getKnownTabs();
|
|
6705
|
+
throwIfCancelledRun(activeRunId);
|
|
5333
6706
|
const fallbackTabs = tabs.length > 0 ? tabs : [
|
|
5334
6707
|
{
|
|
5335
6708
|
id: 1,
|
|
@@ -5337,7 +6710,14 @@ async function handleUserMessage(text, options) {
|
|
|
5337
6710
|
accessMode: "live_dom"
|
|
5338
6711
|
}
|
|
5339
6712
|
];
|
|
5340
|
-
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc, fallbackTabs
|
|
6713
|
+
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc, fallbackTabs, {
|
|
6714
|
+
scopedTabIds,
|
|
6715
|
+
seedTabId: scopedSeedTabId,
|
|
6716
|
+
onDiagnostics: (payload) => {
|
|
6717
|
+
postRuntimeTabsDiagnostics(payload);
|
|
6718
|
+
}
|
|
6719
|
+
});
|
|
6720
|
+
throwIfCancelledRun(activeRunId);
|
|
5341
6721
|
const tabsById = new Map(tabs.map((tab) => [tab.id, tab]));
|
|
5342
6722
|
const orderedTabs = resolvedTabs.tabOrder.map((tabId) => {
|
|
5343
6723
|
const knownTab = tabsById.get(tabId);
|
|
@@ -5357,28 +6737,42 @@ async function handleUserMessage(text, options) {
|
|
|
5357
6737
|
};
|
|
5358
6738
|
}).filter((tab) => Number.isFinite(tab.id) && tab.id > 0);
|
|
5359
6739
|
const tabsForRun = orderedTabs.length > 0 ? orderedTabs : fallbackTabs;
|
|
6740
|
+
if (orderedTabs.length === 0) {
|
|
6741
|
+
postStatus("Using fallback tab mapping", `active=${resolvedTabs.activeTabId}; order=${resolvedTabs.tabOrder.join(",") || "none"}`, "analyze");
|
|
6742
|
+
}
|
|
5360
6743
|
if (!tabularStore) {
|
|
5361
|
-
tabularStore = new TabularStore(`rover-${
|
|
6744
|
+
tabularStore = new TabularStore(`rover-${taskTrajectoryId}`);
|
|
5362
6745
|
}
|
|
5363
6746
|
const agentName = resolveAgentName(config);
|
|
5364
6747
|
const runtimeContext = buildRoverRuntimeContext2({
|
|
5365
6748
|
tabs: tabsForRun,
|
|
5366
6749
|
agentName,
|
|
5367
|
-
externalNavigationPolicy: resolveRuntimeExternalNavigationPolicy(config)
|
|
6750
|
+
externalNavigationPolicy: resolveRuntimeExternalNavigationPolicy(config),
|
|
6751
|
+
taskBoundaryId
|
|
5368
6752
|
});
|
|
5369
6753
|
const ctx = createAgentContext({
|
|
5370
6754
|
...config,
|
|
5371
6755
|
signal: activeAbortController?.signal,
|
|
6756
|
+
sessionId: workerSessionId || config.sessionId || taskTrajectoryId,
|
|
6757
|
+
activeRunId,
|
|
5372
6758
|
runtimeContext,
|
|
5373
6759
|
tools: {
|
|
5374
6760
|
web: extractWebToolsConfig(config)
|
|
5375
6761
|
}
|
|
5376
6762
|
}, bridgeRpc, tabularStore);
|
|
5377
|
-
|
|
5378
|
-
ctx.isCancelled = () => !!(currentRunId && cancelledRunIds.has(currentRunId));
|
|
6763
|
+
ctx.isCancelled = () => !!(activeRunId && cancelledRunIds.has(activeRunId));
|
|
5379
6764
|
const functionDeclarations = dedupeFunctionDeclarations(removePlannerNameCollisions(toolRegistry.getFunctionDeclarations()));
|
|
5380
6765
|
const toolFunctions = toolRegistry.getToolFunctions();
|
|
5381
|
-
const
|
|
6766
|
+
const resumeFollowupTurns = Math.max(1, Math.min(4, Math.floor(Number(config.chat?.resumeFollowup?.maxTurns) || MAX_RESUME_CUE_TURNS)));
|
|
6767
|
+
const normalizedFollowupChatLog = normalizeFollowupChatLog(options?.followupChatLog);
|
|
6768
|
+
const chatLog = shouldBuildResumeCueChatLog({
|
|
6769
|
+
resume: options?.resume,
|
|
6770
|
+
preserveHistory: options?.preserveHistory,
|
|
6771
|
+
resumeFollowupMode: config.chat?.resumeFollowup?.mode
|
|
6772
|
+
}) ? buildChatLogFromHistory(history, chatLogCurrentInputForDedupe, resumeFollowupTurns) : shouldUseFollowupChatLog({
|
|
6773
|
+
resume: options?.resume,
|
|
6774
|
+
followupChatLogLength: normalizedFollowupChatLog.length
|
|
6775
|
+
}) ? normalizedFollowupChatLog : [];
|
|
5382
6776
|
const onPrevStepsUpdate = (steps) => {
|
|
5383
6777
|
applyAgentPrevSteps(steps, { snapshot: true });
|
|
5384
6778
|
};
|
|
@@ -5386,10 +6780,22 @@ async function handleUserMessage(text, options) {
|
|
|
5386
6780
|
plannerHistory = sanitizePlannerHistoryForPersist(Array.isArray(steps) ? steps : []);
|
|
5387
6781
|
postStateSnapshot();
|
|
5388
6782
|
};
|
|
6783
|
+
const getScopedTabRuntimeContext = () => ({
|
|
6784
|
+
scopedTabIds: [...scopedTabIds],
|
|
6785
|
+
seedTabId: scopedSeedTabId
|
|
6786
|
+
});
|
|
6787
|
+
const onScopedTabIdsTouched = (tabIds) => {
|
|
6788
|
+
touchRunScopedTabIds(tabIds);
|
|
6789
|
+
};
|
|
6790
|
+
throwIfCancelledRun(activeRunId);
|
|
5389
6791
|
const result = await handleSendMessageWithFunctions(effectiveUserInput, {
|
|
5390
6792
|
tabs: tabsForRun,
|
|
6793
|
+
scopedTabIds,
|
|
6794
|
+
seedTabId: scopedSeedTabId,
|
|
6795
|
+
getScopedTabRuntimeContext,
|
|
6796
|
+
onScopedTabIdsTouched,
|
|
5391
6797
|
previousMessages: history,
|
|
5392
|
-
trajectoryId,
|
|
6798
|
+
trajectoryId: taskTrajectoryId,
|
|
5393
6799
|
files: [],
|
|
5394
6800
|
recordingContext: config.recordingContext,
|
|
5395
6801
|
previousSteps: plannerHistory,
|
|
@@ -5407,25 +6813,49 @@ async function handleUserMessage(text, options) {
|
|
|
5407
6813
|
onPrevStepsUpdate,
|
|
5408
6814
|
onPlannerHistoryUpdate
|
|
5409
6815
|
});
|
|
6816
|
+
throwIfCancelledRun(activeRunId);
|
|
6817
|
+
if (result.directToolResult) {
|
|
6818
|
+
touchRunScopedTabIds(extractTouchedTabIdsFromToolResult(result.directToolResult));
|
|
6819
|
+
}
|
|
6820
|
+
if (Array.isArray(result.executedFunctions) && result.executedFunctions.length > 0) {
|
|
6821
|
+
for (const executed of result.executedFunctions) {
|
|
6822
|
+
touchRunScopedTabIds(extractTouchedTabIdsFromToolResult(executed?.result));
|
|
6823
|
+
}
|
|
6824
|
+
}
|
|
5410
6825
|
if (!result.success) {
|
|
5411
|
-
const
|
|
6826
|
+
const rawErrorPayload = toStructuredErrorPayload(result.error, "Something went wrong.");
|
|
6827
|
+
const errorPayload = normalizeLifecycleHandoffError(rawErrorPayload, agentPrevSteps);
|
|
6828
|
+
const errorCode = String(errorPayload.error.code || "").trim().toUpperCase();
|
|
6829
|
+
const isRetryableLifecycleError = !!errorPayload.error.retryable || errorCode === "STALE_SEQ" || errorCode === "STALE_EPOCH" || errorCode === "SESSION_TOKEN_EXPIRED" || errorCode === "NAVIGATION_HANDOFF_PENDING";
|
|
6830
|
+
if (isRetryableLifecycleError) {
|
|
6831
|
+
const retryMessage = `${errorPayload.error.code}: ${errorPayload.error.message}`;
|
|
6832
|
+
postAssistantMessage(retryMessage);
|
|
6833
|
+
postStatus("Waiting for navigation/session sync", errorPayload.error.message, "verify");
|
|
6834
|
+
postStateSnapshot();
|
|
6835
|
+
return {
|
|
6836
|
+
route: result.route,
|
|
6837
|
+
taskComplete: false,
|
|
6838
|
+
terminalState: "in_progress",
|
|
6839
|
+
continuationReason: "loop_continue",
|
|
6840
|
+
contextResetRecommended: false
|
|
6841
|
+
};
|
|
6842
|
+
}
|
|
5412
6843
|
if (errorPayload.error.requires_api_key) {
|
|
5413
6844
|
postAuthRequired(errorPayload.error);
|
|
5414
6845
|
}
|
|
5415
|
-
|
|
6846
|
+
postAssistantMessage({
|
|
5416
6847
|
text: `${errorPayload.error.code}: ${errorPayload.error.message}`,
|
|
5417
6848
|
blocks: [
|
|
5418
6849
|
{
|
|
5419
6850
|
type: "json",
|
|
5420
6851
|
label: "Error details",
|
|
5421
|
-
data:
|
|
6852
|
+
data: normalizeRuntimeToolOutput(errorPayload)
|
|
5422
6853
|
}
|
|
5423
6854
|
]
|
|
5424
6855
|
});
|
|
5425
|
-
history.push({ role: "assistant", content: errorMsg });
|
|
5426
6856
|
postStatus("Execution failed", errorPayload.error.message, "complete");
|
|
5427
6857
|
postStateSnapshot();
|
|
5428
|
-
return { route: result.route, taskComplete: false };
|
|
6858
|
+
return { route: result.route, taskComplete: false, terminalState: "failed" };
|
|
5429
6859
|
}
|
|
5430
6860
|
if (result.executedFunctions?.length) {
|
|
5431
6861
|
for (const fn of result.executedFunctions) {
|
|
@@ -5433,6 +6863,12 @@ async function handleUserMessage(text, options) {
|
|
|
5433
6863
|
}
|
|
5434
6864
|
const blocks = [];
|
|
5435
6865
|
const lines = [];
|
|
6866
|
+
let inferredFailed = false;
|
|
6867
|
+
let inferredCompleted = false;
|
|
6868
|
+
let inferredNavigationPending = false;
|
|
6869
|
+
let inferredSameTabPending = false;
|
|
6870
|
+
let inferredNeedsUserInput = false;
|
|
6871
|
+
let inferredQuestions = [];
|
|
5436
6872
|
for (const fn of result.executedFunctions) {
|
|
5437
6873
|
const summary = summarizeOutputText(fn.result);
|
|
5438
6874
|
if (fn.result !== void 0 && shouldAttachStructuredBlock(fn.result, summary)) {
|
|
@@ -5440,28 +6876,100 @@ async function handleUserMessage(text, options) {
|
|
|
5440
6876
|
type: "tool_output",
|
|
5441
6877
|
toolName: fn.name,
|
|
5442
6878
|
label: `${fn.name} output`,
|
|
5443
|
-
data:
|
|
6879
|
+
data: normalizeRuntimeToolOutput(fn.result)
|
|
5444
6880
|
});
|
|
5445
6881
|
}
|
|
5446
6882
|
if (fn.error) {
|
|
5447
6883
|
blocks.push({
|
|
5448
6884
|
type: "json",
|
|
5449
6885
|
label: `${fn.name} error`,
|
|
5450
|
-
data:
|
|
6886
|
+
data: normalizeRuntimeToolOutput({ error: fn.error })
|
|
5451
6887
|
});
|
|
5452
6888
|
}
|
|
5453
6889
|
lines.push(summary ? `@${fn.name}: ${summary}` : `@${fn.name}: ${fn.error || "ok"}`);
|
|
6890
|
+
if (fn.error) {
|
|
6891
|
+
inferredFailed = true;
|
|
6892
|
+
continue;
|
|
6893
|
+
}
|
|
6894
|
+
const rawResult = fn.result;
|
|
6895
|
+
if (!rawResult || typeof rawResult !== "object")
|
|
6896
|
+
continue;
|
|
6897
|
+
const normalized = Array.isArray(rawResult) ? rawResult.find((item) => item && typeof item === "object") : rawResult;
|
|
6898
|
+
if (!normalized)
|
|
6899
|
+
continue;
|
|
6900
|
+
const taskComplete = normalized.taskComplete;
|
|
6901
|
+
if (typeof taskComplete === "boolean" && taskComplete) {
|
|
6902
|
+
inferredCompleted = true;
|
|
6903
|
+
}
|
|
6904
|
+
const navigationPending = normalized.navigationPending === true;
|
|
6905
|
+
const navigationOutcome = String(normalized.navigationOutcome || "").trim().toLowerCase();
|
|
6906
|
+
if (navigationPending || navigationOutcome === "same_tab_scheduled" || navigationOutcome === "new_tab_opened") {
|
|
6907
|
+
inferredNavigationPending = true;
|
|
6908
|
+
if (navigationOutcome === "same_tab_scheduled") {
|
|
6909
|
+
inferredSameTabPending = true;
|
|
6910
|
+
}
|
|
6911
|
+
}
|
|
6912
|
+
const statusRaw = String(normalized.taskStatus || normalized.status || "").trim().toLowerCase();
|
|
6913
|
+
if (statusRaw === "failed" || statusRaw === "error" || statusRaw === "failure") {
|
|
6914
|
+
inferredFailed = true;
|
|
6915
|
+
}
|
|
6916
|
+
if (statusRaw === "waiting_input" || statusRaw === "needs_input" || statusRaw === "pending_user_input") {
|
|
6917
|
+
inferredNeedsUserInput = true;
|
|
6918
|
+
}
|
|
6919
|
+
if (statusRaw === "completed" || statusRaw === "complete" || statusRaw === "done" || statusRaw === "success") {
|
|
6920
|
+
inferredCompleted = true;
|
|
6921
|
+
}
|
|
6922
|
+
if (normalized.needsUserInput === true || normalized.waitingForUserInput === true) {
|
|
6923
|
+
inferredNeedsUserInput = true;
|
|
6924
|
+
}
|
|
6925
|
+
const q = extractQuestionsFromResult(normalized);
|
|
6926
|
+
if (q?.length) {
|
|
6927
|
+
inferredNeedsUserInput = true;
|
|
6928
|
+
inferredQuestions = normalizePlannerQuestions([...inferredQuestions, ...q]);
|
|
6929
|
+
}
|
|
5454
6930
|
}
|
|
5455
|
-
|
|
5456
|
-
text: lines.join("\n")
|
|
6931
|
+
postAssistantMessage({
|
|
6932
|
+
text: lines.join("\n"),
|
|
5457
6933
|
blocks
|
|
5458
6934
|
});
|
|
5459
|
-
history.push({ role: "assistant", content: msg });
|
|
5460
6935
|
postStatus("Execution completed", "Function calls finished", "complete");
|
|
5461
6936
|
postStateSnapshot();
|
|
5462
|
-
|
|
6937
|
+
if (inferredFailed) {
|
|
6938
|
+
return {
|
|
6939
|
+
route: result.route,
|
|
6940
|
+
taskComplete: false,
|
|
6941
|
+
terminalState: "failed"
|
|
6942
|
+
};
|
|
6943
|
+
}
|
|
6944
|
+
if (inferredNavigationPending) {
|
|
6945
|
+
return {
|
|
6946
|
+
route: result.route,
|
|
6947
|
+
taskComplete: false,
|
|
6948
|
+
terminalState: "in_progress",
|
|
6949
|
+
continuationReason: inferredSameTabPending ? "same_tab_navigation_handoff" : "loop_continue",
|
|
6950
|
+
contextResetRecommended: false
|
|
6951
|
+
};
|
|
6952
|
+
}
|
|
6953
|
+
if (inferredNeedsUserInput) {
|
|
6954
|
+
return {
|
|
6955
|
+
route: result.route,
|
|
6956
|
+
taskComplete: false,
|
|
6957
|
+
needsUserInput: true,
|
|
6958
|
+
questions: inferredQuestions.length ? inferredQuestions : void 0,
|
|
6959
|
+
terminalState: "waiting_input",
|
|
6960
|
+
continuationReason: "awaiting_user"
|
|
6961
|
+
};
|
|
6962
|
+
}
|
|
6963
|
+
return {
|
|
6964
|
+
route: result.route,
|
|
6965
|
+
taskComplete: true,
|
|
6966
|
+
terminalState: "completed",
|
|
6967
|
+
continuationReason: void 0,
|
|
6968
|
+
contextResetRecommended: true
|
|
6969
|
+
};
|
|
5463
6970
|
}
|
|
5464
6971
|
if (result.directToolResult) {
|
|
6972
|
+
throwIfCancelledRun(activeRunId);
|
|
5465
6973
|
const newTabWait = await maybeWaitForNewTab(result.directToolResult);
|
|
5466
6974
|
if (newTabWait.openedTab && newTabWait.readyState && !newTabWait.readyState.ready && !newTabWait.readyState.external) {
|
|
5467
6975
|
const fallbackUrl = String(newTabWait.openedTab.url || "").trim();
|
|
@@ -5507,9 +7015,7 @@ async function handleUserMessage(text, options) {
|
|
|
5507
7015
|
const questions = normalizePlannerQuestions(outcome.questions);
|
|
5508
7016
|
if (outcome.needsUserInput && questions.length > 0) {
|
|
5509
7017
|
pendingAskUser = {
|
|
5510
|
-
questions
|
|
5511
|
-
source: "act",
|
|
5512
|
-
askedAt: Date.now()
|
|
7018
|
+
...buildPendingAskUserPrompt("act", questions)
|
|
5513
7019
|
};
|
|
5514
7020
|
plannerHistory = sanitizePlannerHistoryForPersist([
|
|
5515
7021
|
...plannerHistory,
|
|
@@ -5519,16 +7025,17 @@ async function handleUserMessage(text, options) {
|
|
|
5519
7025
|
}
|
|
5520
7026
|
]);
|
|
5521
7027
|
const qText = questions.map((question) => `- ${question.key}: ${questionToDisplayText(question)}`).join("\n");
|
|
5522
|
-
|
|
7028
|
+
postAssistantMessage(`I need a bit more info before continuing:
|
|
5523
7029
|
${qText}`);
|
|
5524
|
-
history.push({ role: "assistant", content: msg2 });
|
|
5525
7030
|
postStatus("Need more input to continue", void 0, "verify");
|
|
5526
7031
|
postStateSnapshot();
|
|
5527
7032
|
return {
|
|
5528
7033
|
route: result.route,
|
|
5529
7034
|
taskComplete: false,
|
|
5530
7035
|
needsUserInput: true,
|
|
5531
|
-
questions
|
|
7036
|
+
questions,
|
|
7037
|
+
terminalState: "waiting_input",
|
|
7038
|
+
continuationReason: "awaiting_user"
|
|
5532
7039
|
};
|
|
5533
7040
|
}
|
|
5534
7041
|
pendingAskUser = void 0;
|
|
@@ -5537,27 +7044,28 @@ ${qText}`);
|
|
|
5537
7044
|
if (structuredError?.error.requires_api_key) {
|
|
5538
7045
|
postAuthRequired(structuredError.error);
|
|
5539
7046
|
}
|
|
5540
|
-
|
|
7047
|
+
structuredError ? postAssistantMessage({
|
|
5541
7048
|
text: `${structuredError.error.code}: ${structuredError.error.message}`,
|
|
5542
7049
|
blocks: [
|
|
5543
7050
|
{
|
|
5544
7051
|
type: "json",
|
|
5545
7052
|
label: "Error details",
|
|
5546
|
-
data:
|
|
7053
|
+
data: normalizeRuntimeToolOutput(structuredError)
|
|
5547
7054
|
}
|
|
5548
7055
|
]
|
|
5549
7056
|
}) : postAssistantMessage(buildAssistantPayloadFromToolOutput(output, {
|
|
5550
|
-
label: "Tool output"
|
|
5551
|
-
fallbackText: "Done."
|
|
7057
|
+
label: "Tool output"
|
|
5552
7058
|
}));
|
|
5553
|
-
history.push({ role: "assistant", content: msg });
|
|
5554
7059
|
postStatus("Execution completed", structuredError?.error.message, "complete");
|
|
5555
7060
|
postStateSnapshot();
|
|
5556
7061
|
return {
|
|
5557
7062
|
route: result.route,
|
|
5558
7063
|
taskComplete: outcome.taskComplete,
|
|
5559
7064
|
needsUserInput: outcome.needsUserInput,
|
|
5560
|
-
questions: normalizePlannerQuestions(outcome.questions)
|
|
7065
|
+
questions: normalizePlannerQuestions(outcome.questions),
|
|
7066
|
+
terminalState: outcome.terminalState,
|
|
7067
|
+
continuationReason: outcome.continuationReason,
|
|
7068
|
+
contextResetRecommended: outcome.contextResetRecommended
|
|
5561
7069
|
};
|
|
5562
7070
|
}
|
|
5563
7071
|
if (result.plannerResponse) {
|
|
@@ -5575,23 +7083,19 @@ ${qText}`);
|
|
|
5575
7083
|
const plannerQuestions = responseQuestions.length ? responseQuestions : fallbackQuestions;
|
|
5576
7084
|
if (plannerQuestions.length) {
|
|
5577
7085
|
const questions = plannerQuestions;
|
|
5578
|
-
pendingAskUser = questions.length ?
|
|
5579
|
-
questions,
|
|
5580
|
-
source: "planner",
|
|
5581
|
-
askedAt: Date.now()
|
|
5582
|
-
} : void 0;
|
|
7086
|
+
pendingAskUser = questions.length ? buildPendingAskUserPrompt("planner", questions) : void 0;
|
|
5583
7087
|
const qText = questions.map((question) => `- ${question.key}: ${questionToDisplayText(question)}`).join("\n");
|
|
5584
|
-
|
|
5585
|
-
${qText}
|
|
5586
|
-
postAssistantMessage(msg2);
|
|
5587
|
-
history.push({ role: "assistant", content: msg2 });
|
|
7088
|
+
postAssistantMessage(`I need a bit more info:
|
|
7089
|
+
${qText}`);
|
|
5588
7090
|
postStatus("Planner needs user input", void 0, "verify");
|
|
5589
7091
|
postStateSnapshot();
|
|
5590
7092
|
return {
|
|
5591
7093
|
route: result.route,
|
|
5592
7094
|
taskComplete: false,
|
|
5593
7095
|
needsUserInput: true,
|
|
5594
|
-
questions
|
|
7096
|
+
questions,
|
|
7097
|
+
terminalState: "waiting_input",
|
|
7098
|
+
continuationReason: "awaiting_user"
|
|
5595
7099
|
};
|
|
5596
7100
|
}
|
|
5597
7101
|
pendingAskUser = void 0;
|
|
@@ -5601,37 +7105,44 @@ ${qText}`;
|
|
|
5601
7105
|
}
|
|
5602
7106
|
const toolBlocks = buildPlannerToolResultBlocks(toolResults);
|
|
5603
7107
|
const responseError = response.error || response.errorDetails ? toStructuredErrorPayload(response.errorDetails || { message: response.error }, "Planner failed") : void 0;
|
|
7108
|
+
const plannerContinuation = inferPlannerContinuation(toolResults);
|
|
5604
7109
|
if (responseError?.error.requires_api_key) {
|
|
5605
7110
|
postAuthRequired(responseError.error);
|
|
5606
7111
|
}
|
|
5607
|
-
|
|
7112
|
+
responseError ? postAssistantMessage({
|
|
5608
7113
|
text: `${responseError.error.code}: ${responseError.error.message}`,
|
|
5609
7114
|
blocks: [
|
|
5610
7115
|
{
|
|
5611
7116
|
type: "json",
|
|
5612
7117
|
label: "Planner error",
|
|
5613
|
-
data:
|
|
7118
|
+
data: normalizeRuntimeToolOutput(responseError)
|
|
5614
7119
|
},
|
|
5615
7120
|
...toolBlocks || []
|
|
5616
7121
|
]
|
|
5617
7122
|
}) : postAssistantMessage({
|
|
5618
|
-
text: String(response.overallThought || summarizePlannerToolResults(toolResults) || "
|
|
7123
|
+
text: String(response.overallThought || summarizePlannerToolResults(toolResults) || ""),
|
|
5619
7124
|
blocks: toolBlocks
|
|
5620
7125
|
});
|
|
5621
|
-
history.push({ role: "assistant", content: msg });
|
|
5622
7126
|
postStatus("Planner execution completed", response.overallThought, "complete");
|
|
5623
7127
|
postStateSnapshot();
|
|
7128
|
+
const plannerComplete = !!response.taskComplete && !responseError && !plannerContinuation.needsUserInput && !plannerContinuation.navigationPending;
|
|
5624
7129
|
return {
|
|
5625
7130
|
route: result.route,
|
|
5626
|
-
taskComplete:
|
|
5627
|
-
needsUserInput:
|
|
7131
|
+
taskComplete: plannerComplete,
|
|
7132
|
+
needsUserInput: plannerContinuation.needsUserInput,
|
|
7133
|
+
terminalState: responseError ? "failed" : plannerContinuation.needsUserInput ? "waiting_input" : plannerContinuation.navigationPending ? "in_progress" : "completed",
|
|
7134
|
+
continuationReason: responseError ? void 0 : plannerContinuation.needsUserInput ? "awaiting_user" : plannerContinuation.navigationPending ? plannerContinuation.sameTabNavigationPending ? "same_tab_navigation_handoff" : "loop_continue" : void 0,
|
|
7135
|
+
contextResetRecommended: !responseError && plannerComplete
|
|
5628
7136
|
};
|
|
5629
7137
|
}
|
|
5630
|
-
const doneMsg = postAssistantMessage("Done.");
|
|
5631
|
-
history.push({ role: "assistant", content: doneMsg });
|
|
5632
7138
|
postStatus("Completed", void 0, "complete");
|
|
5633
7139
|
postStateSnapshot();
|
|
5634
|
-
return {
|
|
7140
|
+
return {
|
|
7141
|
+
route: result.route,
|
|
7142
|
+
taskComplete: true,
|
|
7143
|
+
terminalState: "completed",
|
|
7144
|
+
contextResetRecommended: true
|
|
7145
|
+
};
|
|
5635
7146
|
}
|
|
5636
7147
|
async function runUserMessage(text, meta) {
|
|
5637
7148
|
const runId = meta?.runId || crypto.randomUUID();
|
|
@@ -5642,20 +7153,27 @@ async function runUserMessage(text, meta) {
|
|
|
5642
7153
|
self.postMessage({
|
|
5643
7154
|
type: "run_completed",
|
|
5644
7155
|
runId,
|
|
7156
|
+
taskBoundaryId: terminal.taskBoundaryId,
|
|
5645
7157
|
ok: true,
|
|
5646
7158
|
route: cachedOutcome.route,
|
|
5647
7159
|
taskComplete: cachedOutcome.taskComplete,
|
|
5648
7160
|
needsUserInput: cachedOutcome.needsUserInput,
|
|
5649
|
-
questions: cachedOutcome.questions
|
|
7161
|
+
questions: cachedOutcome.questions,
|
|
7162
|
+
terminalState: cachedOutcome.terminalState,
|
|
7163
|
+
continuationReason: cachedOutcome.continuationReason,
|
|
7164
|
+
contextResetRecommended: cachedOutcome.contextResetRecommended
|
|
5650
7165
|
});
|
|
5651
7166
|
} else {
|
|
5652
7167
|
self.postMessage({
|
|
5653
7168
|
type: "run_completed",
|
|
5654
7169
|
runId,
|
|
7170
|
+
taskBoundaryId: terminal.taskBoundaryId,
|
|
5655
7171
|
ok: false,
|
|
5656
7172
|
error: terminal.error,
|
|
5657
7173
|
taskComplete: false,
|
|
5658
|
-
needsUserInput: false
|
|
7174
|
+
needsUserInput: false,
|
|
7175
|
+
terminalState: "failed",
|
|
7176
|
+
contextResetRecommended: terminal.contextResetRecommended
|
|
5659
7177
|
});
|
|
5660
7178
|
}
|
|
5661
7179
|
return;
|
|
@@ -5664,32 +7182,58 @@ async function runUserMessage(text, meta) {
|
|
|
5664
7182
|
return;
|
|
5665
7183
|
}
|
|
5666
7184
|
const resume = !!meta?.resume;
|
|
7185
|
+
const preserveHistory = !!meta?.preserveHistory;
|
|
7186
|
+
const runTaskBoundaryId = taskBoundaryId;
|
|
5667
7187
|
lastStatusKey = "";
|
|
5668
7188
|
seenStatusKeys = /* @__PURE__ */ new Set();
|
|
7189
|
+
lastRuntimeTabsDiagnosticsKey = "";
|
|
5669
7190
|
cancelledRunIds.delete(runId);
|
|
5670
7191
|
activeAbortController = new AbortController();
|
|
5671
|
-
activeRun = { runId, text, startedAt: Date.now(), resume };
|
|
5672
|
-
self.postMessage({ type: "run_started", runId, text, resume });
|
|
7192
|
+
activeRun = { runId, text, startedAt: Date.now(), resume, preserveHistory };
|
|
7193
|
+
self.postMessage({ type: "run_started", runId, text, resume, taskBoundaryId: runTaskBoundaryId });
|
|
7194
|
+
if (shouldClearHistoryForRun({ resume, preserveHistory })) {
|
|
7195
|
+
history.length = 0;
|
|
7196
|
+
}
|
|
5673
7197
|
postStateSnapshot();
|
|
5674
7198
|
try {
|
|
5675
7199
|
const outcome = normalizeRunOutcome(await handleUserMessage(text, {
|
|
5676
7200
|
resume,
|
|
7201
|
+
preserveHistory,
|
|
7202
|
+
followupChatLog: normalizeFollowupChatLog(meta?.followupChatLog),
|
|
5677
7203
|
routing: meta?.routing,
|
|
5678
7204
|
askUserAnswers: meta?.askUserAnswers
|
|
5679
7205
|
}));
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
7206
|
+
const isTerminalOutcome = outcome.terminalState === "completed" || outcome.terminalState === "failed";
|
|
7207
|
+
if (isTerminalOutcome) {
|
|
7208
|
+
rememberTerminalRun(runId, { ok: true, outcome, taskBoundaryId: runTaskBoundaryId });
|
|
7209
|
+
self.postMessage({
|
|
7210
|
+
type: "run_completed",
|
|
7211
|
+
runId,
|
|
7212
|
+
taskBoundaryId: runTaskBoundaryId,
|
|
7213
|
+
ok: true,
|
|
7214
|
+
route: outcome.route,
|
|
7215
|
+
taskComplete: outcome.taskComplete,
|
|
7216
|
+
needsUserInput: outcome.needsUserInput,
|
|
7217
|
+
questions: outcome.questions,
|
|
7218
|
+
terminalState: outcome.terminalState,
|
|
7219
|
+
continuationReason: outcome.continuationReason,
|
|
7220
|
+
contextResetRecommended: outcome.contextResetRecommended
|
|
7221
|
+
});
|
|
7222
|
+
} else {
|
|
7223
|
+
terminalRuns.delete(runId);
|
|
7224
|
+
self.postMessage({
|
|
7225
|
+
type: "run_state_transition",
|
|
7226
|
+
runId,
|
|
7227
|
+
taskBoundaryId: runTaskBoundaryId,
|
|
7228
|
+
ok: true,
|
|
7229
|
+
route: outcome.route,
|
|
7230
|
+
taskComplete: outcome.taskComplete,
|
|
7231
|
+
needsUserInput: outcome.needsUserInput,
|
|
7232
|
+
questions: outcome.questions,
|
|
7233
|
+
terminalState: outcome.terminalState,
|
|
7234
|
+
continuationReason: outcome.continuationReason,
|
|
7235
|
+
contextResetRecommended: outcome.contextResetRecommended
|
|
7236
|
+
});
|
|
5693
7237
|
}
|
|
5694
7238
|
} catch (error) {
|
|
5695
7239
|
if (error?.name === "AbortError") {
|
|
@@ -5697,30 +7241,42 @@ async function runUserMessage(text, meta) {
|
|
|
5697
7241
|
ok: false,
|
|
5698
7242
|
error: "Run cancelled",
|
|
5699
7243
|
taskComplete: false,
|
|
5700
|
-
needsUserInput: false
|
|
7244
|
+
needsUserInput: false,
|
|
7245
|
+
terminalState: "failed",
|
|
7246
|
+
contextResetRecommended: false,
|
|
7247
|
+
taskBoundaryId: runTaskBoundaryId
|
|
5701
7248
|
});
|
|
5702
7249
|
self.postMessage({
|
|
5703
7250
|
type: "run_completed",
|
|
5704
7251
|
runId,
|
|
7252
|
+
taskBoundaryId: runTaskBoundaryId,
|
|
5705
7253
|
ok: false,
|
|
5706
7254
|
error: "Run cancelled",
|
|
5707
7255
|
taskComplete: false,
|
|
5708
|
-
needsUserInput: false
|
|
7256
|
+
needsUserInput: false,
|
|
7257
|
+
terminalState: "failed",
|
|
7258
|
+
contextResetRecommended: false
|
|
5709
7259
|
});
|
|
5710
7260
|
} else {
|
|
5711
7261
|
rememberTerminalRun(runId, {
|
|
5712
7262
|
ok: false,
|
|
5713
7263
|
error: error?.message || String(error),
|
|
5714
7264
|
taskComplete: false,
|
|
5715
|
-
needsUserInput: false
|
|
7265
|
+
needsUserInput: false,
|
|
7266
|
+
terminalState: "failed",
|
|
7267
|
+
contextResetRecommended: true,
|
|
7268
|
+
taskBoundaryId: runTaskBoundaryId
|
|
5716
7269
|
});
|
|
5717
7270
|
self.postMessage({
|
|
5718
7271
|
type: "run_completed",
|
|
5719
7272
|
runId,
|
|
7273
|
+
taskBoundaryId: runTaskBoundaryId,
|
|
5720
7274
|
ok: false,
|
|
5721
7275
|
error: error?.message || String(error),
|
|
5722
7276
|
taskComplete: false,
|
|
5723
|
-
needsUserInput: false
|
|
7277
|
+
needsUserInput: false,
|
|
7278
|
+
terminalState: "failed",
|
|
7279
|
+
contextResetRecommended: true
|
|
5724
7280
|
});
|
|
5725
7281
|
throw error;
|
|
5726
7282
|
}
|
|
@@ -5735,9 +7291,14 @@ self.onmessage = async (ev) => {
|
|
|
5735
7291
|
try {
|
|
5736
7292
|
if (data.type === "init") {
|
|
5737
7293
|
config = data.config;
|
|
5738
|
-
|
|
7294
|
+
workerSessionId = typeof config.sessionId === "string" && config.sessionId.trim() ? config.sessionId.trim() : workerSessionId || crypto.randomUUID();
|
|
7295
|
+
taskBoundaryId = typeof config.taskBoundaryId === "string" && config.taskBoundaryId.trim() ? config.taskBoundaryId.trim() : taskBoundaryId;
|
|
7296
|
+
applyScopedTabConfig(config);
|
|
7297
|
+
if (config?.timing?.actionTimeoutMs) {
|
|
7298
|
+
RPC_TIMEOUT_MS = Math.max(5e3, Math.min(12e4, Number(config.timing.actionTimeoutMs)));
|
|
7299
|
+
}
|
|
5739
7300
|
if (!tabularStore) {
|
|
5740
|
-
tabularStore = new TabularStore(`rover-${
|
|
7301
|
+
tabularStore = new TabularStore(`rover-${taskTrajectoryId}`);
|
|
5741
7302
|
}
|
|
5742
7303
|
if (data.port) {
|
|
5743
7304
|
bridgeRpc = createRpcClient(data.port);
|
|
@@ -5770,15 +7331,16 @@ self.onmessage = async (ev) => {
|
|
|
5770
7331
|
ui: mergeWorkerUi(config.ui, partial.ui),
|
|
5771
7332
|
tools: mergeWorkerTools(config.tools, partial.tools)
|
|
5772
7333
|
};
|
|
5773
|
-
if (typeof partial.sessionId === "string" && partial.sessionId.trim()
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
terminalRuns.clear();
|
|
5779
|
-
cancelledRunIds.clear();
|
|
5780
|
-
tabularStore = new TabularStore(`rover-${trajectoryId}`);
|
|
7334
|
+
if (typeof partial.sessionId === "string" && partial.sessionId.trim()) {
|
|
7335
|
+
workerSessionId = partial.sessionId.trim();
|
|
7336
|
+
}
|
|
7337
|
+
if (partial?.timing?.actionTimeoutMs) {
|
|
7338
|
+
RPC_TIMEOUT_MS = Math.max(5e3, Math.min(12e4, Number(partial.timing.actionTimeoutMs)));
|
|
5781
7339
|
}
|
|
7340
|
+
if (typeof partial.taskBoundaryId === "string" && partial.taskBoundaryId.trim()) {
|
|
7341
|
+
taskBoundaryId = partial.taskBoundaryId.trim();
|
|
7342
|
+
}
|
|
7343
|
+
applyScopedTabConfig(partial);
|
|
5782
7344
|
const tools = partial.tools;
|
|
5783
7345
|
if (Array.isArray(tools)) {
|
|
5784
7346
|
for (const def of tools)
|
|
@@ -5800,15 +7362,15 @@ self.onmessage = async (ev) => {
|
|
|
5800
7362
|
if (!config)
|
|
5801
7363
|
throw new Error("Worker not initialized");
|
|
5802
7364
|
const nextTaskId = typeof data.taskId === "string" && data.taskId.trim() ? data.taskId.trim() : crypto.randomUUID();
|
|
7365
|
+
const nextTaskBoundaryId = typeof data.taskBoundaryId === "string" && data.taskBoundaryId.trim() ? data.taskBoundaryId.trim() : crypto.randomUUID();
|
|
5803
7366
|
activeAbortController?.abort();
|
|
5804
|
-
|
|
5805
|
-
plannerHistory = [];
|
|
5806
|
-
agentPrevSteps = [];
|
|
5807
|
-
pendingAskUser = void 0;
|
|
7367
|
+
clearTaskScopedContextAfterBoundary("new_task");
|
|
5808
7368
|
terminalRuns.clear();
|
|
5809
7369
|
cancelledRunIds.clear();
|
|
5810
|
-
|
|
5811
|
-
|
|
7370
|
+
taskTrajectoryId = nextTaskId;
|
|
7371
|
+
taskBoundaryId = nextTaskBoundaryId;
|
|
7372
|
+
applyScopedTabConfig(data);
|
|
7373
|
+
tabularStore = new TabularStore(`rover-${taskTrajectoryId}`);
|
|
5812
7374
|
activeRun = null;
|
|
5813
7375
|
activeAbortController = null;
|
|
5814
7376
|
postStateSnapshot();
|
|
@@ -5820,14 +7382,17 @@ self.onmessage = async (ev) => {
|
|
|
5820
7382
|
rememberCancelledRun(data.runId);
|
|
5821
7383
|
activeAbortController?.abort();
|
|
5822
7384
|
}
|
|
5823
|
-
|
|
7385
|
+
clearTaskScopedContextAfterBoundary("cancel");
|
|
5824
7386
|
postStateSnapshot();
|
|
5825
7387
|
return;
|
|
5826
7388
|
}
|
|
5827
7389
|
if (data.type === "run") {
|
|
7390
|
+
applyScopedTabConfig(data);
|
|
5828
7391
|
await runUserMessage(String(data.text || ""), {
|
|
5829
7392
|
runId: data.runId,
|
|
5830
7393
|
resume: !!data.resume,
|
|
7394
|
+
preserveHistory: !!data.preserveHistory,
|
|
7395
|
+
followupChatLog: normalizeFollowupChatLog(data.followupChatLog),
|
|
5831
7396
|
routing: data.routing,
|
|
5832
7397
|
askUserAnswers: data.askUserAnswers
|
|
5833
7398
|
});
|
|
@@ -5837,6 +7402,8 @@ self.onmessage = async (ev) => {
|
|
|
5837
7402
|
await runUserMessage(String(data.text || ""), {
|
|
5838
7403
|
runId: data.runId,
|
|
5839
7404
|
resume: !!data.resume,
|
|
7405
|
+
preserveHistory: !!data.preserveHistory,
|
|
7406
|
+
followupChatLog: normalizeFollowupChatLog(data.followupChatLog),
|
|
5840
7407
|
askUserAnswers: data.askUserAnswers
|
|
5841
7408
|
});
|
|
5842
7409
|
return;
|