@rtrvr-ai/rover 1.0.3 → 1.1.1
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 +40 -8
- package/dist/embed.js +16 -16
- package/dist/index.d.ts +36 -2
- package/dist/rover.js +739 -127
- package/dist/worker/rover-worker.js +853 -76
- package/package.json +1 -1
|
@@ -161,6 +161,27 @@ var DEFAULT_GEMINI_MODEL = GEMINI_MODEL.FLASH;
|
|
|
161
161
|
var PLANNER = FUNCTION_CALLS.PLANNER;
|
|
162
162
|
var maxFileSizeInBytes = 20 * 1024 * 1024;
|
|
163
163
|
|
|
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
|
+
|
|
164
185
|
// dist/tabular-memory/tabular-store.js
|
|
165
186
|
var makeId = () => {
|
|
166
187
|
if (typeof crypto !== "undefined" && "randomUUID" in crypto)
|
|
@@ -620,7 +641,8 @@ function defaultNextActionForCode(code) {
|
|
|
620
641
|
return void 0;
|
|
621
642
|
}
|
|
622
643
|
function toRoverErrorEnvelope(err, fallbackMessage = "Operation failed") {
|
|
623
|
-
const
|
|
644
|
+
const directCandidate = err && typeof err === "object" && typeof err.code === "string" && typeof err.message === "string" ? err : void 0;
|
|
645
|
+
const candidate = err?.roverError || err?.errorDetails || (typeof err?.error === "object" ? err.error : void 0) || directCandidate;
|
|
624
646
|
if (candidate && typeof candidate === "object" && candidate.code && candidate.message) {
|
|
625
647
|
return {
|
|
626
648
|
code: candidate.code,
|
|
@@ -664,6 +686,10 @@ var LEGACY_ADDITIONAL_TOOL_ALIASES = {
|
|
|
664
686
|
pdf_filling: "generate_docs",
|
|
665
687
|
generate_web_pages: "generate_websites"
|
|
666
688
|
};
|
|
689
|
+
var DEFAULT_EXTERNAL_WEB_CONFIG = {
|
|
690
|
+
enableExternalWebContext: false,
|
|
691
|
+
scrapeMode: "off"
|
|
692
|
+
};
|
|
667
693
|
function normalizeApiToolsConfig(input) {
|
|
668
694
|
if (!input)
|
|
669
695
|
return void 0;
|
|
@@ -680,6 +706,121 @@ function normalizeApiToolsConfig(input) {
|
|
|
680
706
|
enableAdditionalTools: normalizedAdditional
|
|
681
707
|
};
|
|
682
708
|
}
|
|
709
|
+
function normalizeDomainRules(input) {
|
|
710
|
+
if (!Array.isArray(input))
|
|
711
|
+
return [];
|
|
712
|
+
const seen = /* @__PURE__ */ new Set();
|
|
713
|
+
const out = [];
|
|
714
|
+
for (const raw of input) {
|
|
715
|
+
const next = String(raw || "").trim().toLowerCase().replace(/^\./, "");
|
|
716
|
+
if (!next || seen.has(next))
|
|
717
|
+
continue;
|
|
718
|
+
seen.add(next);
|
|
719
|
+
out.push(next);
|
|
720
|
+
}
|
|
721
|
+
return out;
|
|
722
|
+
}
|
|
723
|
+
function normalizeAgentName(input) {
|
|
724
|
+
const normalized = String(input || "").trim();
|
|
725
|
+
if (!normalized)
|
|
726
|
+
return void 0;
|
|
727
|
+
return normalized.slice(0, 64);
|
|
728
|
+
}
|
|
729
|
+
function hostFromUrl(url) {
|
|
730
|
+
try {
|
|
731
|
+
return new URL(String(url || "")).hostname.toLowerCase();
|
|
732
|
+
} catch {
|
|
733
|
+
return void 0;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
function matchesDomainRule(host, rule) {
|
|
737
|
+
const clean = String(rule || "").trim().toLowerCase();
|
|
738
|
+
if (!clean)
|
|
739
|
+
return false;
|
|
740
|
+
if (clean === "*")
|
|
741
|
+
return true;
|
|
742
|
+
if (clean.startsWith("*.")) {
|
|
743
|
+
const base = clean.slice(2);
|
|
744
|
+
return !!base && (host === base || host.endsWith(`.${base}`));
|
|
745
|
+
}
|
|
746
|
+
return host === clean || host.endsWith(`.${clean}`);
|
|
747
|
+
}
|
|
748
|
+
function normalizeExternalWebConfig(input) {
|
|
749
|
+
return {
|
|
750
|
+
enableExternalWebContext: input?.enableExternalWebContext ?? DEFAULT_EXTERNAL_WEB_CONFIG.enableExternalWebContext,
|
|
751
|
+
scrapeMode: input?.scrapeMode === "on_demand" ? "on_demand" : DEFAULT_EXTERNAL_WEB_CONFIG.scrapeMode,
|
|
752
|
+
allowDomains: normalizeDomainRules(input?.allowDomains),
|
|
753
|
+
denyDomains: normalizeDomainRules(input?.denyDomains)
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
function isAllowedByRules(url, rules) {
|
|
757
|
+
const host = hostFromUrl(url);
|
|
758
|
+
if (!host)
|
|
759
|
+
return { allowed: false, reason: "invalid_url" };
|
|
760
|
+
if (rules.denyDomains.some((rule) => matchesDomainRule(host, rule))) {
|
|
761
|
+
return { allowed: false, reason: `deny_rule:${host}` };
|
|
762
|
+
}
|
|
763
|
+
if (!rules.allowDomains.length)
|
|
764
|
+
return { allowed: true };
|
|
765
|
+
if (rules.allowDomains.some((rule) => matchesDomainRule(host, rule)))
|
|
766
|
+
return { allowed: true };
|
|
767
|
+
return { allowed: false, reason: `not_in_allowlist:${host}` };
|
|
768
|
+
}
|
|
769
|
+
function normalizeRuntimeExternalTabs(input) {
|
|
770
|
+
if (!Array.isArray(input))
|
|
771
|
+
return [];
|
|
772
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
773
|
+
for (const tab of input) {
|
|
774
|
+
const tabId = Number(tab?.tabId);
|
|
775
|
+
if (!Number.isFinite(tabId))
|
|
776
|
+
continue;
|
|
777
|
+
const accessMode = tab?.accessMode === "external_scraped" ? "external_scraped" : "external_placeholder";
|
|
778
|
+
const host = String(tab?.host || "").trim() || void 0;
|
|
779
|
+
const title = String(tab?.title || "").trim() || void 0;
|
|
780
|
+
const reason = String(tab?.reason || "").trim() || void 0;
|
|
781
|
+
deduped.set(tabId, {
|
|
782
|
+
tabId,
|
|
783
|
+
accessMode,
|
|
784
|
+
host,
|
|
785
|
+
title,
|
|
786
|
+
reason
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
return Array.from(deduped.values());
|
|
790
|
+
}
|
|
791
|
+
function buildRoverRuntimeContext(config2) {
|
|
792
|
+
const runtimeContext = config2.runtimeContext;
|
|
793
|
+
if (!runtimeContext || runtimeContext.mode !== "rover_embed")
|
|
794
|
+
return void 0;
|
|
795
|
+
const compactExternalTabs = normalizeRuntimeExternalTabs(runtimeContext.externalTabs).slice(0, 8);
|
|
796
|
+
return {
|
|
797
|
+
mode: "rover_embed",
|
|
798
|
+
agentName: normalizeAgentName(runtimeContext.agentName) || "Rover",
|
|
799
|
+
externalNavigationPolicy: runtimeContext.externalNavigationPolicy || config2.externalNavigationPolicy,
|
|
800
|
+
tabIdContract: runtimeContext.tabIdContract || "tree_index_mapped_by_tab_order",
|
|
801
|
+
...compactExternalTabs.length ? { externalTabs: compactExternalTabs } : {}
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
function buildExternalPlaceholderPageData(params) {
|
|
805
|
+
const agentName = normalizeAgentName(params.agentName) || "Rover";
|
|
806
|
+
const reason = params.reason || "external_domain_inaccessible";
|
|
807
|
+
const title = params.title || "External Tab (Inaccessible)";
|
|
808
|
+
const url = params.url || "";
|
|
809
|
+
const reasonLine = reason ? ` Reason: ${reason}.` : "";
|
|
810
|
+
return {
|
|
811
|
+
url,
|
|
812
|
+
title,
|
|
813
|
+
contentType: "text/html",
|
|
814
|
+
content: `${agentName} is running in virtual external-tab mode. Live DOM control and accessibility-tree access are unavailable here.${reasonLine}`,
|
|
815
|
+
metadata: {
|
|
816
|
+
inaccessible: true,
|
|
817
|
+
external: true,
|
|
818
|
+
accessMode: "external_placeholder",
|
|
819
|
+
reason,
|
|
820
|
+
logicalTabId: params.tabId
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
}
|
|
683
824
|
function getUserFriendlyTimestamp() {
|
|
684
825
|
const now = /* @__PURE__ */ new Date();
|
|
685
826
|
const year = now.getFullYear();
|
|
@@ -712,10 +853,19 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
712
853
|
}
|
|
713
854
|
const base = (config2.apiBase || DEFAULT_CLOUD_FUNCTIONS_BASE).replace(/\/$/, "");
|
|
714
855
|
const endpoint = base.endsWith("/extensionRouter") ? base : `${base}/extensionRouter`;
|
|
856
|
+
const runtimeContext = buildRoverRuntimeContext(config2);
|
|
857
|
+
const externalWebConfig = normalizeExternalWebConfig(config2.tools?.web);
|
|
858
|
+
const externalPageDataCache = /* @__PURE__ */ new Map();
|
|
859
|
+
const externalPageDataErrorCache = /* @__PURE__ */ new Map();
|
|
860
|
+
let externalPageDataDisabledReason;
|
|
861
|
+
let cachedActiveTabId = 0;
|
|
862
|
+
let cachedActiveTabTs = 0;
|
|
715
863
|
const RETRY_DELAYS = [1e3, 3e3];
|
|
716
864
|
const MAX_RETRIES3 = RETRY_DELAYS.length;
|
|
865
|
+
const ACTIVE_TAB_CACHE_TTL_MS = 250;
|
|
866
|
+
const EXTERNAL_PAGE_CACHE_TTL_MS = 45e3;
|
|
717
867
|
const callExtensionRouter = async (action, data) => {
|
|
718
|
-
const token = config2.
|
|
868
|
+
const token = config2.authToken || config2.apiKey;
|
|
719
869
|
if (!token) {
|
|
720
870
|
throw createRoverError({
|
|
721
871
|
code: "MISSING_API_KEY",
|
|
@@ -736,7 +886,13 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
736
886
|
Authorization: `Bearer ${token}`,
|
|
737
887
|
"Content-Type": "application/json"
|
|
738
888
|
},
|
|
739
|
-
body: JSON.stringify({
|
|
889
|
+
body: JSON.stringify({
|
|
890
|
+
action,
|
|
891
|
+
data: data && typeof data === "object" ? {
|
|
892
|
+
...data,
|
|
893
|
+
...!data.runtimeContext && runtimeContext ? { runtimeContext } : {}
|
|
894
|
+
} : data
|
|
895
|
+
}),
|
|
740
896
|
signal: config2.signal
|
|
741
897
|
});
|
|
742
898
|
if (!response.ok) {
|
|
@@ -789,11 +945,138 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
789
945
|
}
|
|
790
946
|
throw lastError || new Error("callExtensionRouter: unexpected retry exhaustion");
|
|
791
947
|
};
|
|
948
|
+
const getExternalPageData = async (url, options) => {
|
|
949
|
+
const normalizedUrl = String(url || "").trim();
|
|
950
|
+
if (!normalizedUrl)
|
|
951
|
+
throw new Error("external page data requires url");
|
|
952
|
+
const cacheTabId = Number(options?.tabId) || 0;
|
|
953
|
+
const cacheKey = `${cacheTabId}:${normalizedUrl}`;
|
|
954
|
+
const nowMs = Date.now();
|
|
955
|
+
const cachedData = externalPageDataCache.get(cacheKey);
|
|
956
|
+
if (cachedData && nowMs - cachedData.ts <= EXTERNAL_PAGE_CACHE_TTL_MS) {
|
|
957
|
+
return cachedData.data;
|
|
958
|
+
}
|
|
959
|
+
externalPageDataCache.delete(cacheKey);
|
|
960
|
+
const cachedError = externalPageDataErrorCache.get(cacheKey);
|
|
961
|
+
if (cachedError && nowMs - cachedError.ts <= EXTERNAL_PAGE_CACHE_TTL_MS) {
|
|
962
|
+
throw new Error(cachedError.message || "external page data fetch failed");
|
|
963
|
+
}
|
|
964
|
+
externalPageDataErrorCache.delete(cacheKey);
|
|
965
|
+
if (externalPageDataDisabledReason) {
|
|
966
|
+
throw new Error(externalPageDataDisabledReason);
|
|
967
|
+
}
|
|
968
|
+
const source = options?.source || "direct_url";
|
|
969
|
+
const payload = {
|
|
970
|
+
url: normalizedUrl,
|
|
971
|
+
source,
|
|
972
|
+
siteId: config2.siteId,
|
|
973
|
+
roverPolicy: {
|
|
974
|
+
allowDomains: externalWebConfig.allowDomains,
|
|
975
|
+
denyDomains: externalWebConfig.denyDomains
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
try {
|
|
979
|
+
const response = await callExtensionRouter(SUB_AGENTS.roverExternalPageData, payload);
|
|
980
|
+
const pageData = response?.data || response;
|
|
981
|
+
externalPageDataCache.set(cacheKey, { data: pageData, ts: nowMs });
|
|
982
|
+
return pageData;
|
|
983
|
+
} catch (error) {
|
|
984
|
+
const envelope = toRoverErrorEnvelope(error, "external page data fetch failed");
|
|
985
|
+
const normalizedMessage = envelope?.message || "external page data fetch failed";
|
|
986
|
+
externalPageDataErrorCache.set(cacheKey, { message: normalizedMessage, ts: nowMs });
|
|
987
|
+
if (envelope.code === "PERMISSION_DENIED" || envelope.code === "MISSING_API_KEY" || envelope.code === "INVALID_API_KEY") {
|
|
988
|
+
externalPageDataDisabledReason = `${envelope.code}: ${normalizedMessage}`;
|
|
989
|
+
}
|
|
990
|
+
throw error;
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
const getActiveLogicalTabId = async () => {
|
|
994
|
+
const nowMs = Date.now();
|
|
995
|
+
if (cachedActiveTabId > 0 && nowMs - cachedActiveTabTs <= ACTIVE_TAB_CACHE_TTL_MS) {
|
|
996
|
+
return cachedActiveTabId;
|
|
997
|
+
}
|
|
998
|
+
try {
|
|
999
|
+
const context = await bridgeRpc2("getTabContext");
|
|
1000
|
+
const active = Number(context?.activeLogicalTabId || context?.logicalTabId || context?.id);
|
|
1001
|
+
if (Number.isFinite(active) && active > 0) {
|
|
1002
|
+
cachedActiveTabId = active;
|
|
1003
|
+
cachedActiveTabTs = nowMs;
|
|
1004
|
+
return active;
|
|
1005
|
+
}
|
|
1006
|
+
} catch {
|
|
1007
|
+
}
|
|
1008
|
+
return void 0;
|
|
1009
|
+
};
|
|
792
1010
|
const getPageData = async (tabId, options) => {
|
|
793
|
-
|
|
794
|
-
|
|
1011
|
+
const numericTabId = Number(tabId);
|
|
1012
|
+
const rawOptions = options && typeof options === "object" ? options : void 0;
|
|
1013
|
+
const allowExternalFetch = rawOptions?.__roverAllowExternalFetch === true;
|
|
1014
|
+
const pageConfig = rawOptions && typeof rawOptions === "object" ? Object.fromEntries(Object.entries(rawOptions).filter(([key]) => key !== "__roverAllowExternalFetch")) : void 0;
|
|
1015
|
+
const hasPageConfig = !!pageConfig && Object.keys(pageConfig).length > 0;
|
|
1016
|
+
const localPageData = rawOptions ? await bridgeRpc2("getPageData", hasPageConfig ? { pageConfig, tabId: numericTabId } : { tabId: numericTabId }) : await bridgeRpc2("getPageData", { tabId: numericTabId });
|
|
1017
|
+
const metadata = localPageData?.metadata || {};
|
|
1018
|
+
const isExternal = !!metadata?.external || metadata?.accessMode === "external_placeholder" || metadata?.accessMode === "external_scraped";
|
|
1019
|
+
if (!isExternal) {
|
|
1020
|
+
return localPageData;
|
|
1021
|
+
}
|
|
1022
|
+
const pageUrl = typeof localPageData?.url === "string" ? localPageData.url.trim() : "";
|
|
1023
|
+
if (!externalWebConfig.enableExternalWebContext || externalWebConfig.scrapeMode === "off" || !pageUrl) {
|
|
1024
|
+
return localPageData;
|
|
1025
|
+
}
|
|
1026
|
+
if (externalPageDataDisabledReason) {
|
|
1027
|
+
return buildExternalPlaceholderPageData({
|
|
1028
|
+
tabId: numericTabId,
|
|
1029
|
+
url: pageUrl,
|
|
1030
|
+
title: localPageData?.title,
|
|
1031
|
+
agentName: runtimeContext?.agentName,
|
|
1032
|
+
reason: `cloud_fetch_disabled:${externalPageDataDisabledReason}`
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
const ruleCheck = isAllowedByRules(pageUrl, {
|
|
1036
|
+
allowDomains: externalWebConfig.allowDomains,
|
|
1037
|
+
denyDomains: externalWebConfig.denyDomains
|
|
1038
|
+
});
|
|
1039
|
+
if (!ruleCheck.allowed) {
|
|
1040
|
+
return buildExternalPlaceholderPageData({
|
|
1041
|
+
tabId: numericTabId,
|
|
1042
|
+
url: pageUrl,
|
|
1043
|
+
title: localPageData?.title,
|
|
1044
|
+
agentName: runtimeContext?.agentName,
|
|
1045
|
+
reason: `policy_blocked:${ruleCheck.reason || "blocked"}`
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
const activeTabId = await getActiveLogicalTabId();
|
|
1049
|
+
const shouldFetchExternalContext = allowExternalFetch || (activeTabId ? activeTabId === numericTabId : false);
|
|
1050
|
+
if (!shouldFetchExternalContext) {
|
|
1051
|
+
return localPageData;
|
|
1052
|
+
}
|
|
1053
|
+
try {
|
|
1054
|
+
const cloudData = await getExternalPageData(pageUrl, {
|
|
1055
|
+
tabId: numericTabId,
|
|
1056
|
+
source: pageUrl.includes("google.com/search") ? "google_search" : "direct_url"
|
|
1057
|
+
});
|
|
1058
|
+
if (cloudData && typeof cloudData === "object") {
|
|
1059
|
+
return {
|
|
1060
|
+
...cloudData,
|
|
1061
|
+
metadata: {
|
|
1062
|
+
...cloudData.metadata || {},
|
|
1063
|
+
external: true,
|
|
1064
|
+
accessMode: "external_scraped",
|
|
1065
|
+
logicalTabId: numericTabId
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
return localPageData;
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
const envelope = toRoverErrorEnvelope(error, "external page data fetch failed");
|
|
1072
|
+
return buildExternalPlaceholderPageData({
|
|
1073
|
+
tabId: numericTabId,
|
|
1074
|
+
url: pageUrl,
|
|
1075
|
+
title: localPageData?.title,
|
|
1076
|
+
agentName: runtimeContext?.agentName,
|
|
1077
|
+
reason: `cloud_fetch_failed:${envelope?.code || "unknown"}`
|
|
1078
|
+
});
|
|
795
1079
|
}
|
|
796
|
-
return bridgeRpc2("getPageData", { tabId });
|
|
797
1080
|
};
|
|
798
1081
|
const userProfile = config2.userProfile || (config2.userContext ? { userContext: config2.userContext } : void 0);
|
|
799
1082
|
const defaultApiToolsConfig = apiMode ? {
|
|
@@ -806,6 +1089,7 @@ function createAgentContext(config2, bridgeRpc2, tabularStore2) {
|
|
|
806
1089
|
llmIntegration,
|
|
807
1090
|
userProfile,
|
|
808
1091
|
getPageData,
|
|
1092
|
+
getExternalPageData,
|
|
809
1093
|
callExtensionRouter,
|
|
810
1094
|
apiMode,
|
|
811
1095
|
apiToolsConfig: normalizeApiToolsConfig(config2.apiToolsConfig ?? defaultApiToolsConfig),
|
|
@@ -1014,26 +1298,6 @@ var GeminiModel;
|
|
|
1014
1298
|
GeminiModel2["PRO"] = "Gemini Pro";
|
|
1015
1299
|
})(GeminiModel || (GeminiModel = {}));
|
|
1016
1300
|
|
|
1017
|
-
// ../shared/dist/lib/types/agent-types.js
|
|
1018
|
-
var SUB_AGENTS;
|
|
1019
|
-
(function(SUB_AGENTS2) {
|
|
1020
|
-
SUB_AGENTS2["enhance"] = "enhance";
|
|
1021
|
-
SUB_AGENTS2["plan"] = "plan";
|
|
1022
|
-
SUB_AGENTS2["actOnTabs"] = "actOnTabs";
|
|
1023
|
-
SUB_AGENTS2["extract"] = "extract";
|
|
1024
|
-
SUB_AGENTS2["infer"] = "infer";
|
|
1025
|
-
SUB_AGENTS2["processTabWorkflows"] = "processTabWorkflows";
|
|
1026
|
-
SUB_AGENTS2["processText"] = "processText";
|
|
1027
|
-
SUB_AGENTS2["createSheetFromData"] = "createSheetFromData";
|
|
1028
|
-
SUB_AGENTS2["queryRtrvrDocs"] = "queryRtrvrDocs";
|
|
1029
|
-
SUB_AGENTS2["googleDocGenerator"] = "googleDocGenerator";
|
|
1030
|
-
SUB_AGENTS2["googleSlidesGenerator"] = "googleSlidesGenerator";
|
|
1031
|
-
SUB_AGENTS2["webpageGenerator"] = "webpageGenerator";
|
|
1032
|
-
SUB_AGENTS2["pdfFiller"] = "pdfFiller";
|
|
1033
|
-
SUB_AGENTS2["customToolGenerator"] = "customToolGenerator";
|
|
1034
|
-
SUB_AGENTS2["getPageData"] = "getPageData";
|
|
1035
|
-
})(SUB_AGENTS || (SUB_AGENTS = {}));
|
|
1036
|
-
|
|
1037
1301
|
// ../shared/dist/lib/system-tools/tools.js
|
|
1038
1302
|
var SystemToolNames;
|
|
1039
1303
|
(function(SystemToolNames2) {
|
|
@@ -1315,6 +1579,127 @@ function formatFunctionResultsIntoPrevSteps(results, functionCalls) {
|
|
|
1315
1579
|
return steps;
|
|
1316
1580
|
}
|
|
1317
1581
|
|
|
1582
|
+
// dist/agent/runtimeTabs.js
|
|
1583
|
+
var DEFAULT_MAX_CONTEXT_TABS = 8;
|
|
1584
|
+
var DEFAULT_DETACHED_EXTERNAL_TAB_MAX_AGE_MS = 9e4;
|
|
1585
|
+
var DEFAULT_STALE_RUNTIME_TAB_MAX_AGE_MS = 45e3;
|
|
1586
|
+
function dedupePositiveTabIds(input) {
|
|
1587
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1588
|
+
const out = [];
|
|
1589
|
+
for (const value of input) {
|
|
1590
|
+
const next = Number(value);
|
|
1591
|
+
if (!Number.isFinite(next) || next <= 0 || seen.has(next))
|
|
1592
|
+
continue;
|
|
1593
|
+
seen.add(next);
|
|
1594
|
+
out.push(next);
|
|
1595
|
+
}
|
|
1596
|
+
return out;
|
|
1597
|
+
}
|
|
1598
|
+
function normalizeAccessMode(value, external) {
|
|
1599
|
+
if (value === "external_scraped" || value === "external_placeholder" || value === "live_dom")
|
|
1600
|
+
return value;
|
|
1601
|
+
return external ? "external_placeholder" : "live_dom";
|
|
1602
|
+
}
|
|
1603
|
+
function normalizeFallbackTabs(input) {
|
|
1604
|
+
return input.map((tab) => ({
|
|
1605
|
+
id: Number(tab?.id),
|
|
1606
|
+
url: typeof tab?.url === "string" ? tab.url : void 0,
|
|
1607
|
+
title: typeof tab?.title === "string" ? tab.title : void 0,
|
|
1608
|
+
external: !!tab?.external,
|
|
1609
|
+
accessMode: normalizeAccessMode(tab?.accessMode, !!tab?.external),
|
|
1610
|
+
inaccessibleReason: typeof tab?.inaccessibleReason === "string" ? tab.inaccessibleReason : void 0
|
|
1611
|
+
})).filter((tab) => Number.isFinite(tab.id) && tab.id > 0);
|
|
1612
|
+
}
|
|
1613
|
+
function normalizeListedTabs(input) {
|
|
1614
|
+
if (!Array.isArray(input))
|
|
1615
|
+
return [];
|
|
1616
|
+
return input.map((tab) => {
|
|
1617
|
+
const id = Number(tab?.logicalTabId || tab?.id);
|
|
1618
|
+
if (!Number.isFinite(id) || id <= 0)
|
|
1619
|
+
return void 0;
|
|
1620
|
+
const external = !!tab?.external;
|
|
1621
|
+
return {
|
|
1622
|
+
id,
|
|
1623
|
+
runtimeId: typeof tab?.runtimeId === "string" ? tab.runtimeId : void 0,
|
|
1624
|
+
url: typeof tab?.url === "string" ? tab.url : void 0,
|
|
1625
|
+
title: typeof tab?.title === "string" ? tab.title : void 0,
|
|
1626
|
+
external,
|
|
1627
|
+
accessMode: normalizeAccessMode(tab?.accessMode, external),
|
|
1628
|
+
inaccessibleReason: typeof tab?.inaccessibleReason === "string" ? tab.inaccessibleReason : void 0,
|
|
1629
|
+
updatedAt: Number(tab?.updatedAt) || 0
|
|
1630
|
+
};
|
|
1631
|
+
}).filter((tab) => !!tab);
|
|
1632
|
+
}
|
|
1633
|
+
async function resolveRuntimeTabs(bridgeRpc2, fallbackTabs, options) {
|
|
1634
|
+
const maxContextTabs = Math.max(1, Number(options?.maxContextTabs) || DEFAULT_MAX_CONTEXT_TABS);
|
|
1635
|
+
const detachedExternalTabMaxAgeMs = Math.max(5e3, Number(options?.detachedExternalTabMaxAgeMs) || DEFAULT_DETACHED_EXTERNAL_TAB_MAX_AGE_MS);
|
|
1636
|
+
const staleRuntimeTabMaxAgeMs = Math.max(1e4, Number(options?.staleRuntimeTabMaxAgeMs) || DEFAULT_STALE_RUNTIME_TAB_MAX_AGE_MS);
|
|
1637
|
+
const fallbackSnapshots = normalizeFallbackTabs(fallbackTabs);
|
|
1638
|
+
const fallbackTabIds = dedupePositiveTabIds(fallbackSnapshots.map((tab) => tab.id));
|
|
1639
|
+
let tabIds = [...fallbackTabIds];
|
|
1640
|
+
let listedTabs = [];
|
|
1641
|
+
if (bridgeRpc2) {
|
|
1642
|
+
try {
|
|
1643
|
+
listedTabs = normalizeListedTabs(await bridgeRpc2("listSessionTabs"));
|
|
1644
|
+
const listedIds = dedupePositiveTabIds(listedTabs.map((tab) => tab.id));
|
|
1645
|
+
if (listedIds.length > 0) {
|
|
1646
|
+
tabIds = listedIds;
|
|
1647
|
+
}
|
|
1648
|
+
} catch {
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
let activeTabId = tabIds[0] || fallbackTabIds[0] || 1;
|
|
1652
|
+
if (bridgeRpc2) {
|
|
1653
|
+
try {
|
|
1654
|
+
const context = await bridgeRpc2("getTabContext");
|
|
1655
|
+
const candidate = Number(context?.activeLogicalTabId || context?.logicalTabId || context?.id);
|
|
1656
|
+
if (Number.isFinite(candidate) && candidate > 0) {
|
|
1657
|
+
activeTabId = candidate;
|
|
1658
|
+
}
|
|
1659
|
+
} catch {
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
if (!tabIds.length) {
|
|
1663
|
+
tabIds = [activeTabId];
|
|
1664
|
+
} else if (!tabIds.includes(activeTabId)) {
|
|
1665
|
+
tabIds = [activeTabId, ...tabIds];
|
|
1666
|
+
}
|
|
1667
|
+
const nowMs = Date.now();
|
|
1668
|
+
const listedById = /* @__PURE__ */ new Map();
|
|
1669
|
+
for (const tab of listedTabs)
|
|
1670
|
+
listedById.set(tab.id, tab);
|
|
1671
|
+
const prioritized = tabIds.filter((tabId) => {
|
|
1672
|
+
if (tabId === activeTabId)
|
|
1673
|
+
return true;
|
|
1674
|
+
const listed = listedById.get(tabId);
|
|
1675
|
+
if (!listed)
|
|
1676
|
+
return true;
|
|
1677
|
+
if (listed.runtimeId) {
|
|
1678
|
+
return nowMs - (listed.updatedAt || 0) <= staleRuntimeTabMaxAgeMs;
|
|
1679
|
+
}
|
|
1680
|
+
if (!listed.external)
|
|
1681
|
+
return true;
|
|
1682
|
+
return nowMs - (listed.updatedAt || 0) <= detachedExternalTabMaxAgeMs;
|
|
1683
|
+
});
|
|
1684
|
+
let tabOrder = (prioritized.length ? prioritized : tabIds).slice(0, maxContextTabs);
|
|
1685
|
+
if (!tabOrder.includes(activeTabId)) {
|
|
1686
|
+
tabOrder = [activeTabId, ...tabOrder].slice(0, maxContextTabs);
|
|
1687
|
+
}
|
|
1688
|
+
if (!tabOrder.length) {
|
|
1689
|
+
tabOrder = [activeTabId || 1];
|
|
1690
|
+
}
|
|
1691
|
+
const tabMetaById = {};
|
|
1692
|
+
for (const tab of fallbackSnapshots)
|
|
1693
|
+
tabMetaById[tab.id] = tab;
|
|
1694
|
+
for (const tab of listedTabs)
|
|
1695
|
+
tabMetaById[tab.id] = { ...tabMetaById[tab.id] || {}, ...tab };
|
|
1696
|
+
for (const tabId of tabOrder) {
|
|
1697
|
+
if (!tabMetaById[tabId])
|
|
1698
|
+
tabMetaById[tabId] = { id: tabId };
|
|
1699
|
+
}
|
|
1700
|
+
return { tabOrder, activeTabId, tabMetaById };
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1318
1703
|
// dist/agent/actAgent.js
|
|
1319
1704
|
var MAX_RETRIES = 3;
|
|
1320
1705
|
var MAX_ITERATIONS = 25;
|
|
@@ -1326,10 +1711,10 @@ async function executeAgenticSeek(options) {
|
|
|
1326
1711
|
let totalCreditsUsed = 0;
|
|
1327
1712
|
const allWarnings = [];
|
|
1328
1713
|
const accumulatedPrevSteps = Array.isArray(previousSteps) ? previousSteps : [];
|
|
1714
|
+
const fallbackTabs = tabOrder.map((id) => ({ id }));
|
|
1329
1715
|
let retry = 0;
|
|
1330
1716
|
let iterations = 0;
|
|
1331
1717
|
let pageDataOptions;
|
|
1332
|
-
const tabId = tabOrder[0];
|
|
1333
1718
|
while (retry < MAX_RETRIES) {
|
|
1334
1719
|
if (iterations++ >= MAX_ITERATIONS) {
|
|
1335
1720
|
return { error: "Max action iterations reached", prevSteps: accumulatedPrevSteps, creditsUsed: totalCreditsUsed };
|
|
@@ -1340,13 +1725,44 @@ async function executeAgenticSeek(options) {
|
|
|
1340
1725
|
try {
|
|
1341
1726
|
await waitWhilePaused(void 0);
|
|
1342
1727
|
onStatusUpdate?.("Analyzing page content...", "Calling seek workflow", "analyze");
|
|
1343
|
-
const
|
|
1728
|
+
const { tabOrder: runtimeTabOrder, activeTabId } = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs);
|
|
1729
|
+
const scopedTabOrder = runtimeTabOrder.length ? runtimeTabOrder : tabOrder;
|
|
1730
|
+
const webPageMap = {};
|
|
1731
|
+
try {
|
|
1732
|
+
webPageMap[activeTabId] = await ctx.getPageData(activeTabId, {
|
|
1733
|
+
...pageDataOptions || {},
|
|
1734
|
+
__roverAllowExternalFetch: true
|
|
1735
|
+
});
|
|
1736
|
+
} catch {
|
|
1737
|
+
retry++;
|
|
1738
|
+
continue;
|
|
1739
|
+
}
|
|
1740
|
+
const backgroundTabIds = scopedTabOrder.filter((currentTabId) => currentTabId !== activeTabId);
|
|
1741
|
+
const backgroundResults = await Promise.all(backgroundTabIds.map(async (currentTabId) => {
|
|
1742
|
+
try {
|
|
1743
|
+
const pageData = await ctx.getPageData(currentTabId);
|
|
1744
|
+
return { tabId: currentTabId, pageData };
|
|
1745
|
+
} catch {
|
|
1746
|
+
return { tabId: currentTabId, pageData: void 0 };
|
|
1747
|
+
}
|
|
1748
|
+
}));
|
|
1749
|
+
for (const result of backgroundResults) {
|
|
1750
|
+
if (result.pageData) {
|
|
1751
|
+
webPageMap[result.tabId] = result.pageData;
|
|
1752
|
+
} else {
|
|
1753
|
+
allWarnings.push(`Could not load page data for tab ${result.tabId}; continuing with remaining tabs.`);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
if (!webPageMap[activeTabId]) {
|
|
1757
|
+
retry++;
|
|
1758
|
+
continue;
|
|
1759
|
+
}
|
|
1344
1760
|
const request = {
|
|
1345
1761
|
siteId: ctx.siteId,
|
|
1346
1762
|
customTabWorkflow: "Seek",
|
|
1347
|
-
webPageMap
|
|
1348
|
-
tabOrder:
|
|
1349
|
-
activeTabId
|
|
1763
|
+
webPageMap,
|
|
1764
|
+
tabOrder: scopedTabOrder,
|
|
1765
|
+
activeTabId,
|
|
1350
1766
|
userInput,
|
|
1351
1767
|
dataJsonSchema: schema,
|
|
1352
1768
|
files,
|
|
@@ -1368,7 +1784,7 @@ async function executeAgenticSeek(options) {
|
|
|
1368
1784
|
}
|
|
1369
1785
|
const data = response.data;
|
|
1370
1786
|
totalCreditsUsed += data?.creditsUsed || 0;
|
|
1371
|
-
const tabResponse = data?.tabResponses?.[
|
|
1787
|
+
const tabResponse = data?.tabResponses?.[activeTabId];
|
|
1372
1788
|
if (!tabResponse) {
|
|
1373
1789
|
retry++;
|
|
1374
1790
|
continue;
|
|
@@ -1382,7 +1798,7 @@ async function executeAgenticSeek(options) {
|
|
|
1382
1798
|
const processResult = await processActionResponse({
|
|
1383
1799
|
request,
|
|
1384
1800
|
response: tabResponse,
|
|
1385
|
-
tabId,
|
|
1801
|
+
tabId: activeTabId,
|
|
1386
1802
|
prevSteps: accumulatedPrevSteps,
|
|
1387
1803
|
thought: tabResponse.thought,
|
|
1388
1804
|
bridgeRpc: bridgeRpc2,
|
|
@@ -1447,20 +1863,28 @@ async function executeExtract(options) {
|
|
|
1447
1863
|
}
|
|
1448
1864
|
let totalCreditsUsed = 0;
|
|
1449
1865
|
const warnings = [];
|
|
1450
|
-
const
|
|
1866
|
+
const fallbackTabs = tabOrder.map((id) => ({ id }));
|
|
1451
1867
|
const prevSteps = Array.isArray(previousSteps) ? previousSteps : [];
|
|
1452
1868
|
let pageDataOptions;
|
|
1453
1869
|
for (let retry = 0; retry < MAX_RETRIES2; retry++) {
|
|
1454
1870
|
await waitWhilePaused(void 0);
|
|
1455
|
-
const
|
|
1871
|
+
const { activeTabId } = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs);
|
|
1872
|
+
const tabId = activeTabId;
|
|
1873
|
+
let pageData;
|
|
1874
|
+
try {
|
|
1875
|
+
pageData = await ctx.getPageData(tabId, pageDataOptions);
|
|
1876
|
+
} catch {
|
|
1877
|
+
warnings.push(`Could not load page data for tab ${tabId}; retrying.`);
|
|
1878
|
+
continue;
|
|
1879
|
+
}
|
|
1456
1880
|
const request = {
|
|
1457
1881
|
siteId: ctx.siteId,
|
|
1458
1882
|
userInput,
|
|
1459
1883
|
schema,
|
|
1460
1884
|
outputDestination,
|
|
1461
1885
|
schemaHeaderSheetInfo,
|
|
1462
|
-
webPageMap: { [
|
|
1463
|
-
tabOrder: [
|
|
1886
|
+
webPageMap: { [activeTabId]: pageData },
|
|
1887
|
+
tabOrder: [activeTabId],
|
|
1464
1888
|
plannerPrevSteps,
|
|
1465
1889
|
llmIntegration: ctx.llmIntegration,
|
|
1466
1890
|
apiMode: ctx.apiMode,
|
|
@@ -1491,12 +1915,12 @@ async function executeExtract(options) {
|
|
|
1491
1915
|
warnings
|
|
1492
1916
|
};
|
|
1493
1917
|
}
|
|
1494
|
-
const tabResponse = data?.tabResponses?.[
|
|
1918
|
+
const tabResponse = data?.tabResponses?.[activeTabId];
|
|
1495
1919
|
if (tabResponse) {
|
|
1496
1920
|
const processResult = await processActionResponse({
|
|
1497
1921
|
request,
|
|
1498
1922
|
response: tabResponse,
|
|
1499
|
-
tabId,
|
|
1923
|
+
tabId: activeTabId,
|
|
1500
1924
|
prevSteps,
|
|
1501
1925
|
thought: tabResponse.thought,
|
|
1502
1926
|
bridgeRpc: bridgeRpc2,
|
|
@@ -2151,6 +2575,8 @@ function resolvePath(obj, path) {
|
|
|
2151
2575
|
}
|
|
2152
2576
|
|
|
2153
2577
|
// dist/agent/toolExecutor.js
|
|
2578
|
+
var MAX_AGENT_CHATLOG_ENTRIES = 24;
|
|
2579
|
+
var MAX_AGENT_CHATLOG_MESSAGE_CHARS = 1e3;
|
|
2154
2580
|
function unsupportedToolResult(toolName, message) {
|
|
2155
2581
|
return {
|
|
2156
2582
|
error: message,
|
|
@@ -2180,10 +2606,18 @@ function buildStructuredErrorOutput(envelope) {
|
|
|
2180
2606
|
}
|
|
2181
2607
|
function normalizeAgentLog(agentLog) {
|
|
2182
2608
|
const prevSteps = Array.isArray(agentLog?.prevSteps) ? agentLog.prevSteps : [];
|
|
2609
|
+
const sanitizeMessage = (value) => {
|
|
2610
|
+
const normalized = String(value || "").replace(/\s+/g, " ").trim();
|
|
2611
|
+
if (!normalized)
|
|
2612
|
+
return "";
|
|
2613
|
+
if (normalized.length <= MAX_AGENT_CHATLOG_MESSAGE_CHARS)
|
|
2614
|
+
return normalized;
|
|
2615
|
+
return `${normalized.slice(0, MAX_AGENT_CHATLOG_MESSAGE_CHARS - 1)}\u2026`;
|
|
2616
|
+
};
|
|
2183
2617
|
const chatLog = Array.isArray(agentLog?.chatLog) ? agentLog.chatLog.map((entry) => ({
|
|
2184
2618
|
role: entry?.role === "user" ? "user" : "model",
|
|
2185
|
-
message: typeof entry?.message === "string" ? entry.message : ""
|
|
2186
|
-
})).filter((entry) => !!entry.message) : [];
|
|
2619
|
+
message: typeof entry?.message === "string" ? sanitizeMessage(entry.message) : ""
|
|
2620
|
+
})).filter((entry) => !!entry.message).slice(-MAX_AGENT_CHATLOG_ENTRIES) : [];
|
|
2187
2621
|
return { prevSteps, chatLog };
|
|
2188
2622
|
}
|
|
2189
2623
|
async function executeToolFromPlan(context) {
|
|
@@ -2192,7 +2626,9 @@ async function executeToolFromPlan(context) {
|
|
|
2192
2626
|
if (!effectiveCtx) {
|
|
2193
2627
|
return { error: "Agent context unavailable" };
|
|
2194
2628
|
}
|
|
2195
|
-
const
|
|
2629
|
+
const fallbackTabs = Array.isArray(tabs) && tabs.length ? tabs : [{ id: 1 }];
|
|
2630
|
+
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs);
|
|
2631
|
+
const tabOrder = resolvedTabs.tabOrder.length ? resolvedTabs.tabOrder : fallbackTabs.map((tab) => tab.id);
|
|
2196
2632
|
const effectiveAgentLog = normalizeAgentLog(agentLog);
|
|
2197
2633
|
try {
|
|
2198
2634
|
switch (toolName) {
|
|
@@ -2999,18 +3435,50 @@ async function executeCustomToolGenerator({ userInput, plannerPrevSteps, files,
|
|
|
2999
3435
|
|
|
3000
3436
|
// dist/agent/plannerAgent.js
|
|
3001
3437
|
var MAX_PLANNER_DEPTH = 15;
|
|
3438
|
+
var MAX_CHATLOG_ENTRIES = 24;
|
|
3439
|
+
var MAX_CHATLOG_MESSAGE_CHARS = 1e3;
|
|
3440
|
+
function normalizeChatLog(entries) {
|
|
3441
|
+
if (!Array.isArray(entries) || !entries.length)
|
|
3442
|
+
return [];
|
|
3443
|
+
return entries.map((entry) => ({
|
|
3444
|
+
role: entry?.role === "user" ? "user" : "model",
|
|
3445
|
+
message: String(entry?.message || "").replace(/\s+/g, " ").trim()
|
|
3446
|
+
})).filter((entry) => !!entry.message).map((entry) => ({
|
|
3447
|
+
role: entry.role,
|
|
3448
|
+
message: entry.message.length > MAX_CHATLOG_MESSAGE_CHARS ? `${entry.message.slice(0, MAX_CHATLOG_MESSAGE_CHARS - 1)}\u2026` : entry.message
|
|
3449
|
+
})).slice(-MAX_CHATLOG_ENTRIES);
|
|
3450
|
+
}
|
|
3002
3451
|
async function executePlanner(options) {
|
|
3003
|
-
const { userInput, tabs, previousMessages = [], trajectoryId: trajectoryId2, previousSteps = [], files, continuePlanning = false, recordingContext, driveAuthToken, agentLog, lastToolPreviousSteps, ctx, functionDeclarations } = options;
|
|
3004
|
-
const
|
|
3452
|
+
const { userInput, tabs, previousMessages = [], trajectoryId: trajectoryId2, previousSteps = [], files, continuePlanning = false, recordingContext, driveAuthToken, agentLog, lastToolPreviousSteps, ctx, bridgeRpc: bridgeRpc2, functionDeclarations } = options;
|
|
3453
|
+
const fallbackTabs = Array.isArray(tabs) && tabs.length ? tabs : [{ id: 1 }];
|
|
3454
|
+
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc2, fallbackTabs);
|
|
3455
|
+
const tabOrder = resolvedTabs.tabOrder.length ? resolvedTabs.tabOrder : fallbackTabs.map((tab) => tab.id);
|
|
3456
|
+
const activeTabId = resolvedTabs.activeTabId;
|
|
3457
|
+
const tabMetaById = resolvedTabs.tabMetaById;
|
|
3005
3458
|
const webPageMap = {};
|
|
3006
|
-
|
|
3459
|
+
const loadPageData = async (tabId, options2) => {
|
|
3007
3460
|
try {
|
|
3008
|
-
|
|
3461
|
+
return await ctx.getPageData(tabId, {
|
|
3462
|
+
onlyTextContent: false,
|
|
3463
|
+
...options2?.allowExternalFetch ? { __roverAllowExternalFetch: true } : {}
|
|
3464
|
+
});
|
|
3009
3465
|
} catch {
|
|
3010
|
-
|
|
3466
|
+
const tab = tabMetaById[tabId];
|
|
3467
|
+
return {
|
|
3468
|
+
url: tab?.url || "",
|
|
3469
|
+
title: tab?.title || (tab?.external ? "External Tab (Inaccessible)" : ""),
|
|
3470
|
+
content: "",
|
|
3471
|
+
contentType: "text/html"
|
|
3472
|
+
};
|
|
3011
3473
|
}
|
|
3474
|
+
};
|
|
3475
|
+
webPageMap[activeTabId] = await loadPageData(activeTabId, { allowExternalFetch: true });
|
|
3476
|
+
const backgroundTabIds = tabOrder.filter((tabId) => tabId !== activeTabId);
|
|
3477
|
+
const backgroundResults = await Promise.all(backgroundTabIds.map(async (tabId) => ({ tabId, pageData: await loadPageData(tabId) })));
|
|
3478
|
+
for (const { tabId, pageData } of backgroundResults) {
|
|
3479
|
+
webPageMap[tabId] = pageData;
|
|
3012
3480
|
}
|
|
3013
|
-
const chatLog = agentLog?.chatLog?.length ? agentLog.chatLog : previousMessages.filter((m) => m.role === "user" || m.role === "assistant").map((m) => ({ role: m.role === "user" ? "user" : "model", message: m.content }));
|
|
3481
|
+
const chatLog = agentLog?.chatLog?.length ? normalizeChatLog(agentLog.chatLog) : normalizeChatLog(previousMessages.filter((m) => m.role === "user" || m.role === "assistant").map((m) => ({ role: m.role === "user" ? "user" : "model", message: m.content })));
|
|
3014
3482
|
const request = {
|
|
3015
3483
|
siteId: ctx.siteId,
|
|
3016
3484
|
userInput,
|
|
@@ -3687,7 +4155,98 @@ var activeAbortController = null;
|
|
|
3687
4155
|
var lastStatusKey = "";
|
|
3688
4156
|
var seenStatusKeys = /* @__PURE__ */ new Set();
|
|
3689
4157
|
var completedRunIds = /* @__PURE__ */ new Set();
|
|
4158
|
+
var completedRunOutcomes = /* @__PURE__ */ new Map();
|
|
3690
4159
|
var RPC_TIMEOUT_MS = 3e4;
|
|
4160
|
+
var DETACHED_EXTERNAL_TAB_MAX_AGE_MS = 9e4;
|
|
4161
|
+
var MAX_CHATLOG_ENTRIES2 = 24;
|
|
4162
|
+
var MAX_CHATLOG_MESSAGE_CHARS2 = 1e3;
|
|
4163
|
+
function resolveAgentName(config2) {
|
|
4164
|
+
const raw = String(config2?.ui?.agent?.name || "").trim();
|
|
4165
|
+
if (!raw)
|
|
4166
|
+
return "Rover";
|
|
4167
|
+
return raw.slice(0, 64);
|
|
4168
|
+
}
|
|
4169
|
+
function hostFromUrl2(url) {
|
|
4170
|
+
const raw = String(url || "").trim();
|
|
4171
|
+
if (!raw)
|
|
4172
|
+
return void 0;
|
|
4173
|
+
try {
|
|
4174
|
+
return new URL(raw).hostname.toLowerCase();
|
|
4175
|
+
} catch {
|
|
4176
|
+
return void 0;
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
function extractWebToolsConfig(config2) {
|
|
4180
|
+
if (!config2?.tools || Array.isArray(config2.tools))
|
|
4181
|
+
return void 0;
|
|
4182
|
+
return config2.tools.web;
|
|
4183
|
+
}
|
|
4184
|
+
function resolveRuntimeExternalNavigationPolicy(config2) {
|
|
4185
|
+
if (!config2)
|
|
4186
|
+
return void 0;
|
|
4187
|
+
if (config2.externalNavigationPolicy === "open_new_tab_notice" || config2.externalNavigationPolicy === "block" || config2.externalNavigationPolicy === "allow") {
|
|
4188
|
+
return config2.externalNavigationPolicy;
|
|
4189
|
+
}
|
|
4190
|
+
return void 0;
|
|
4191
|
+
}
|
|
4192
|
+
function buildRoverRuntimeContext2(params) {
|
|
4193
|
+
const externalTabs = params.tabs.map((tab, index) => {
|
|
4194
|
+
if (!tab.external && tab.accessMode !== "external_placeholder" && tab.accessMode !== "external_scraped") {
|
|
4195
|
+
return void 0;
|
|
4196
|
+
}
|
|
4197
|
+
const accessMode = tab.accessMode === "external_scraped" ? "external_scraped" : "external_placeholder";
|
|
4198
|
+
return {
|
|
4199
|
+
tabId: index,
|
|
4200
|
+
host: hostFromUrl2(tab.url),
|
|
4201
|
+
title: String(tab.title || "").trim() || void 0,
|
|
4202
|
+
accessMode,
|
|
4203
|
+
reason: String(tab.inaccessibleReason || "").trim() || void 0
|
|
4204
|
+
};
|
|
4205
|
+
}).filter((tab) => !!tab).slice(0, 8);
|
|
4206
|
+
return {
|
|
4207
|
+
mode: "rover_embed",
|
|
4208
|
+
agentName: params.agentName,
|
|
4209
|
+
externalNavigationPolicy: params.externalNavigationPolicy,
|
|
4210
|
+
tabIdContract: "tree_index_mapped_by_tab_order",
|
|
4211
|
+
...externalTabs.length ? { externalTabs } : {}
|
|
4212
|
+
};
|
|
4213
|
+
}
|
|
4214
|
+
function mergeWorkerTools(current, incoming) {
|
|
4215
|
+
if (incoming === void 0)
|
|
4216
|
+
return current;
|
|
4217
|
+
if (Array.isArray(incoming))
|
|
4218
|
+
return incoming;
|
|
4219
|
+
if (Array.isArray(current)) {
|
|
4220
|
+
return {
|
|
4221
|
+
...incoming,
|
|
4222
|
+
client: incoming.client ?? current,
|
|
4223
|
+
web: {
|
|
4224
|
+
...incoming.web || {}
|
|
4225
|
+
}
|
|
4226
|
+
};
|
|
4227
|
+
}
|
|
4228
|
+
return {
|
|
4229
|
+
...current,
|
|
4230
|
+
...incoming,
|
|
4231
|
+
client: incoming.client ?? current?.client,
|
|
4232
|
+
web: {
|
|
4233
|
+
...current?.web || {},
|
|
4234
|
+
...incoming.web || {}
|
|
4235
|
+
}
|
|
4236
|
+
};
|
|
4237
|
+
}
|
|
4238
|
+
function mergeWorkerUi(current, incoming) {
|
|
4239
|
+
if (!incoming)
|
|
4240
|
+
return current;
|
|
4241
|
+
return {
|
|
4242
|
+
...current,
|
|
4243
|
+
...incoming,
|
|
4244
|
+
agent: {
|
|
4245
|
+
...current?.agent || {},
|
|
4246
|
+
...incoming.agent || {}
|
|
4247
|
+
}
|
|
4248
|
+
};
|
|
4249
|
+
}
|
|
3691
4250
|
function createRpcClient(port) {
|
|
3692
4251
|
const pending = /* @__PURE__ */ new Map();
|
|
3693
4252
|
port.onmessage = (ev) => {
|
|
@@ -3725,16 +4284,18 @@ async function getCurrentTab() {
|
|
|
3725
4284
|
return {
|
|
3726
4285
|
id: Number(tabContext.logicalTabId || tabContext.id || 1),
|
|
3727
4286
|
url: tabContext.url,
|
|
3728
|
-
title: tabContext.title
|
|
4287
|
+
title: tabContext.title,
|
|
4288
|
+
external: false,
|
|
4289
|
+
accessMode: "live_dom"
|
|
3729
4290
|
};
|
|
3730
4291
|
}
|
|
3731
4292
|
} catch {
|
|
3732
4293
|
}
|
|
3733
4294
|
try {
|
|
3734
4295
|
const pageData = await bridgeRpc("getPageData");
|
|
3735
|
-
return { id: 1, url: pageData?.url, title: pageData?.title };
|
|
4296
|
+
return { id: 1, url: pageData?.url, title: pageData?.title, external: false, accessMode: "live_dom" };
|
|
3736
4297
|
} catch {
|
|
3737
|
-
return { id: 1 };
|
|
4298
|
+
return { id: 1, external: false, accessMode: "live_dom" };
|
|
3738
4299
|
}
|
|
3739
4300
|
}
|
|
3740
4301
|
async function getKnownTabs() {
|
|
@@ -3743,11 +4304,32 @@ async function getKnownTabs() {
|
|
|
3743
4304
|
try {
|
|
3744
4305
|
const listed = await bridgeRpc("listSessionTabs");
|
|
3745
4306
|
if (Array.isArray(listed) && listed.length > 0) {
|
|
3746
|
-
const
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
4307
|
+
const nowMs = Date.now();
|
|
4308
|
+
const mapped = listed.map((tab) => {
|
|
4309
|
+
const id = Number(tab?.logicalTabId || tab?.id || 0);
|
|
4310
|
+
const external = !!tab?.external;
|
|
4311
|
+
return {
|
|
4312
|
+
id,
|
|
4313
|
+
runtimeId: typeof tab?.runtimeId === "string" ? tab.runtimeId : void 0,
|
|
4314
|
+
updatedAt: Number(tab?.updatedAt) || 0,
|
|
4315
|
+
url: typeof tab?.url === "string" ? tab.url : void 0,
|
|
4316
|
+
title: typeof tab?.title === "string" ? tab.title : void 0,
|
|
4317
|
+
external,
|
|
4318
|
+
accessMode: tab?.accessMode === "external_scraped" || tab?.accessMode === "external_placeholder" ? tab.accessMode : external ? "external_placeholder" : "live_dom",
|
|
4319
|
+
inaccessibleReason: typeof tab?.inaccessibleReason === "string" ? tab.inaccessibleReason : void 0
|
|
4320
|
+
};
|
|
4321
|
+
}).filter((tab) => Number.isFinite(tab.id) && tab.id > 0).filter((tab) => {
|
|
4322
|
+
if (!tab.external || tab.runtimeId)
|
|
4323
|
+
return true;
|
|
4324
|
+
return nowMs - (tab.updatedAt || 0) <= DETACHED_EXTERNAL_TAB_MAX_AGE_MS;
|
|
4325
|
+
}).map((tab) => ({
|
|
4326
|
+
id: tab.id,
|
|
4327
|
+
url: tab.url,
|
|
4328
|
+
title: tab.title,
|
|
4329
|
+
external: tab.external,
|
|
4330
|
+
accessMode: tab.accessMode,
|
|
4331
|
+
inaccessibleReason: tab.inaccessibleReason
|
|
4332
|
+
}));
|
|
3751
4333
|
if (mapped.length)
|
|
3752
4334
|
return mapped;
|
|
3753
4335
|
}
|
|
@@ -4112,19 +4694,46 @@ function maybePostNavigationGuardrailFromToolResult(toolResult) {
|
|
|
4112
4694
|
});
|
|
4113
4695
|
}
|
|
4114
4696
|
function buildChatLogFromHistory(input, currentUserInput) {
|
|
4697
|
+
const sanitizeChatText = (raw, role) => {
|
|
4698
|
+
let text = String(raw || "").replace(/\s+/g, " ").trim();
|
|
4699
|
+
if (!text)
|
|
4700
|
+
return "";
|
|
4701
|
+
if (role === "assistant") {
|
|
4702
|
+
if (/^\w[\w_]*:\s*\{/.test(text) || /^\[error\]/i.test(text) || /"success":\s*false/.test(text)) {
|
|
4703
|
+
const firstSentence = text.split(/(?<=\.)\s+/)[0] || text;
|
|
4704
|
+
text = firstSentence.trim();
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
if (text.length > MAX_CHATLOG_MESSAGE_CHARS2) {
|
|
4708
|
+
text = `${text.slice(0, MAX_CHATLOG_MESSAGE_CHARS2 - 1)}\u2026`;
|
|
4709
|
+
}
|
|
4710
|
+
return text;
|
|
4711
|
+
};
|
|
4712
|
+
const normalizedCurrentUserInput = currentUserInput ? sanitizeChatText(currentUserInput, "user") : "";
|
|
4115
4713
|
const entries = input.filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
|
|
4116
4714
|
role: message.role,
|
|
4117
|
-
content: String(message.content || "")
|
|
4118
|
-
}));
|
|
4119
|
-
if (
|
|
4715
|
+
content: sanitizeChatText(String(message.content || ""), message.role)
|
|
4716
|
+
})).filter((message) => !!message.content);
|
|
4717
|
+
if (normalizedCurrentUserInput) {
|
|
4120
4718
|
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
4121
|
-
if (entries[i].role === "user" && entries[i].content ===
|
|
4719
|
+
if (entries[i].role === "user" && entries[i].content === normalizedCurrentUserInput) {
|
|
4122
4720
|
entries.splice(i, 1);
|
|
4123
4721
|
break;
|
|
4124
4722
|
}
|
|
4125
4723
|
}
|
|
4126
4724
|
}
|
|
4127
|
-
|
|
4725
|
+
const deduped = [];
|
|
4726
|
+
for (const entry of entries) {
|
|
4727
|
+
const previous = deduped[deduped.length - 1];
|
|
4728
|
+
if (previous && previous.role === entry.role && previous.content === entry.content)
|
|
4729
|
+
continue;
|
|
4730
|
+
deduped.push(entry);
|
|
4731
|
+
}
|
|
4732
|
+
const tail = deduped.slice(-MAX_CHATLOG_ENTRIES2);
|
|
4733
|
+
while (tail.length > 1 && tail[0]?.role !== "user") {
|
|
4734
|
+
tail.shift();
|
|
4735
|
+
}
|
|
4736
|
+
return tail.map((message) => ({
|
|
4128
4737
|
role: message.role === "user" ? "user" : "model",
|
|
4129
4738
|
message: message.content
|
|
4130
4739
|
}));
|
|
@@ -4222,6 +4831,9 @@ async function waitForNewTabReady(logicalTabId, timeoutMs = 1e4) {
|
|
|
4222
4831
|
const tabs = await bridgeRpc("listSessionTabs");
|
|
4223
4832
|
if (Array.isArray(tabs)) {
|
|
4224
4833
|
const target = tabs.find((t) => Number(t?.logicalTabId) === logicalTabId);
|
|
4834
|
+
if (target?.external) {
|
|
4835
|
+
return true;
|
|
4836
|
+
}
|
|
4225
4837
|
if (target?.runtimeId) {
|
|
4226
4838
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
4227
4839
|
return true;
|
|
@@ -4242,6 +4854,81 @@ function detectOpenedTabFromToolResult(result) {
|
|
|
4242
4854
|
}
|
|
4243
4855
|
return void 0;
|
|
4244
4856
|
}
|
|
4857
|
+
function deriveDirectToolRunOutcome(result) {
|
|
4858
|
+
if (!result || typeof result !== "object") {
|
|
4859
|
+
return { taskComplete: false };
|
|
4860
|
+
}
|
|
4861
|
+
const topLevelStatus = String(result.status || "").trim().toLowerCase();
|
|
4862
|
+
if (topLevelStatus === "failure" || topLevelStatus === "failed" || topLevelStatus === "error") {
|
|
4863
|
+
return { taskComplete: false };
|
|
4864
|
+
}
|
|
4865
|
+
if (topLevelStatus === "waiting_input" || topLevelStatus === "needs_input" || topLevelStatus === "pending_user_input") {
|
|
4866
|
+
return { taskComplete: false, needsUserInput: true };
|
|
4867
|
+
}
|
|
4868
|
+
if (result.error) {
|
|
4869
|
+
return { taskComplete: false };
|
|
4870
|
+
}
|
|
4871
|
+
const output = result.output;
|
|
4872
|
+
if (output && typeof output === "object") {
|
|
4873
|
+
if (Array.isArray(output)) {
|
|
4874
|
+
return { taskComplete: true };
|
|
4875
|
+
}
|
|
4876
|
+
if (output.needsUserInput === true || output.waitingForUserInput === true) {
|
|
4877
|
+
return { taskComplete: false, needsUserInput: true };
|
|
4878
|
+
}
|
|
4879
|
+
if (Array.isArray(output.questions) && output.questions.length > 0) {
|
|
4880
|
+
return { taskComplete: false, needsUserInput: true };
|
|
4881
|
+
}
|
|
4882
|
+
if (output.error) {
|
|
4883
|
+
return { taskComplete: false };
|
|
4884
|
+
}
|
|
4885
|
+
if (typeof output.taskComplete === "boolean") {
|
|
4886
|
+
return { taskComplete: !!output.taskComplete };
|
|
4887
|
+
}
|
|
4888
|
+
const taskStatus = String(output.taskStatus || output.status || "").toLowerCase();
|
|
4889
|
+
if (taskStatus) {
|
|
4890
|
+
if (taskStatus === "waiting_input" || taskStatus === "needs_input" || taskStatus === "pending_user_input") {
|
|
4891
|
+
return { taskComplete: false, needsUserInput: true };
|
|
4892
|
+
}
|
|
4893
|
+
if (taskStatus === "running" || taskStatus === "in_progress" || taskStatus === "pending") {
|
|
4894
|
+
return { taskComplete: false };
|
|
4895
|
+
}
|
|
4896
|
+
if (taskStatus === "completed" || taskStatus === "complete" || taskStatus === "done" || taskStatus === "success") {
|
|
4897
|
+
return { taskComplete: true };
|
|
4898
|
+
}
|
|
4899
|
+
if (taskStatus === "failure" || taskStatus === "failed" || taskStatus === "error") {
|
|
4900
|
+
return { taskComplete: false };
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4903
|
+
if (output.success === false) {
|
|
4904
|
+
return { taskComplete: false };
|
|
4905
|
+
}
|
|
4906
|
+
if (String(output.status || "").trim().toLowerCase() === "failure") {
|
|
4907
|
+
return { taskComplete: false };
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
if (output != null) {
|
|
4911
|
+
return { taskComplete: true };
|
|
4912
|
+
}
|
|
4913
|
+
return { taskComplete: false };
|
|
4914
|
+
}
|
|
4915
|
+
function normalizeRunOutcome(outcome) {
|
|
4916
|
+
if (!outcome || typeof outcome !== "object") {
|
|
4917
|
+
return { taskComplete: false, needsUserInput: false };
|
|
4918
|
+
}
|
|
4919
|
+
const needsUserInput = outcome.needsUserInput === true;
|
|
4920
|
+
const taskComplete = outcome.taskComplete === true && !needsUserInput;
|
|
4921
|
+
return {
|
|
4922
|
+
route: outcome.route,
|
|
4923
|
+
taskComplete,
|
|
4924
|
+
needsUserInput
|
|
4925
|
+
};
|
|
4926
|
+
}
|
|
4927
|
+
function clearTaskScopedContextAfterCompletion() {
|
|
4928
|
+
history.length = 0;
|
|
4929
|
+
plannerHistory = [];
|
|
4930
|
+
agentPrevSteps = [];
|
|
4931
|
+
}
|
|
4245
4932
|
async function maybeWaitForNewTab(result) {
|
|
4246
4933
|
const logicalTabId = detectOpenedTabFromToolResult(result);
|
|
4247
4934
|
if (logicalTabId) {
|
|
@@ -4261,10 +4948,50 @@ async function handleUserMessage(text, options) {
|
|
|
4261
4948
|
postStateSnapshot();
|
|
4262
4949
|
}
|
|
4263
4950
|
const tabs = await getKnownTabs();
|
|
4951
|
+
const fallbackTabs = tabs.length > 0 ? tabs : [
|
|
4952
|
+
{
|
|
4953
|
+
id: 1,
|
|
4954
|
+
external: false,
|
|
4955
|
+
accessMode: "live_dom"
|
|
4956
|
+
}
|
|
4957
|
+
];
|
|
4958
|
+
const resolvedTabs = await resolveRuntimeTabs(bridgeRpc, fallbackTabs);
|
|
4959
|
+
const tabsById = new Map(tabs.map((tab) => [tab.id, tab]));
|
|
4960
|
+
const orderedTabs = resolvedTabs.tabOrder.map((tabId) => {
|
|
4961
|
+
const knownTab = tabsById.get(tabId);
|
|
4962
|
+
if (knownTab)
|
|
4963
|
+
return knownTab;
|
|
4964
|
+
const tabMeta = resolvedTabs.tabMetaById[tabId];
|
|
4965
|
+
if (!tabMeta)
|
|
4966
|
+
return { id: tabId };
|
|
4967
|
+
const external = !!tabMeta.external;
|
|
4968
|
+
return {
|
|
4969
|
+
id: tabId,
|
|
4970
|
+
url: tabMeta.url,
|
|
4971
|
+
title: tabMeta.title,
|
|
4972
|
+
external,
|
|
4973
|
+
accessMode: tabMeta.accessMode || (external ? "external_placeholder" : "live_dom"),
|
|
4974
|
+
inaccessibleReason: tabMeta.inaccessibleReason
|
|
4975
|
+
};
|
|
4976
|
+
}).filter((tab) => Number.isFinite(tab.id) && tab.id > 0);
|
|
4977
|
+
const tabsForRun = orderedTabs.length > 0 ? orderedTabs : fallbackTabs;
|
|
4264
4978
|
if (!tabularStore) {
|
|
4265
4979
|
tabularStore = new TabularStore(`rover-${trajectoryId}`);
|
|
4266
4980
|
}
|
|
4267
|
-
const
|
|
4981
|
+
const agentName = resolveAgentName(config);
|
|
4982
|
+
const runtimeContext = buildRoverRuntimeContext2({
|
|
4983
|
+
tabs: tabsForRun,
|
|
4984
|
+
agentName,
|
|
4985
|
+
externalNavigationPolicy: resolveRuntimeExternalNavigationPolicy(config)
|
|
4986
|
+
});
|
|
4987
|
+
const ctx = createAgentContext({
|
|
4988
|
+
...config,
|
|
4989
|
+
signal: activeAbortController?.signal,
|
|
4990
|
+
runtimeContext,
|
|
4991
|
+
tools: {
|
|
4992
|
+
web: extractWebToolsConfig(config)
|
|
4993
|
+
}
|
|
4994
|
+
}, bridgeRpc, tabularStore);
|
|
4268
4995
|
const currentRunId = activeRun?.runId;
|
|
4269
4996
|
ctx.isCancelled = () => cancelledRunId === currentRunId;
|
|
4270
4997
|
const functionDeclarations = dedupeFunctionDeclarations(removePlannerNameCollisions(toolRegistry.getFunctionDeclarations()));
|
|
@@ -4278,7 +5005,7 @@ async function handleUserMessage(text, options) {
|
|
|
4278
5005
|
postStateSnapshot();
|
|
4279
5006
|
};
|
|
4280
5007
|
const result = await handleSendMessageWithFunctions(text, {
|
|
4281
|
-
tabs,
|
|
5008
|
+
tabs: tabsForRun,
|
|
4282
5009
|
previousMessages: history,
|
|
4283
5010
|
trajectoryId,
|
|
4284
5011
|
files: [],
|
|
@@ -4308,7 +5035,7 @@ async function handleUserMessage(text, options) {
|
|
|
4308
5035
|
history.push({ role: "assistant", content: errorMsg });
|
|
4309
5036
|
postStatus("Execution failed", errorPayload.error.message, "complete");
|
|
4310
5037
|
postStateSnapshot();
|
|
4311
|
-
return result.route;
|
|
5038
|
+
return { route: result.route, taskComplete: false };
|
|
4312
5039
|
}
|
|
4313
5040
|
if (result.executedFunctions?.length) {
|
|
4314
5041
|
for (const fn of result.executedFunctions) {
|
|
@@ -4323,7 +5050,7 @@ async function handleUserMessage(text, options) {
|
|
|
4323
5050
|
history.push({ role: "assistant", content: msg });
|
|
4324
5051
|
postStatus("Execution completed", "Function calls finished", "complete");
|
|
4325
5052
|
postStateSnapshot();
|
|
4326
|
-
return result.route;
|
|
5053
|
+
return { route: result.route, taskComplete: true };
|
|
4327
5054
|
}
|
|
4328
5055
|
if (result.directToolResult) {
|
|
4329
5056
|
await maybeWaitForNewTab(result.directToolResult);
|
|
@@ -4341,7 +5068,12 @@ async function handleUserMessage(text, options) {
|
|
|
4341
5068
|
history.push({ role: "assistant", content: msg });
|
|
4342
5069
|
postStatus("Execution completed", structuredError?.error.message, "complete");
|
|
4343
5070
|
postStateSnapshot();
|
|
4344
|
-
|
|
5071
|
+
const outcome = deriveDirectToolRunOutcome(result.directToolResult);
|
|
5072
|
+
return {
|
|
5073
|
+
route: result.route,
|
|
5074
|
+
taskComplete: outcome.taskComplete,
|
|
5075
|
+
needsUserInput: outcome.needsUserInput
|
|
5076
|
+
};
|
|
4345
5077
|
}
|
|
4346
5078
|
if (result.plannerResponse) {
|
|
4347
5079
|
postStatus("Verifying planner output", void 0, "verify");
|
|
@@ -4360,7 +5092,7 @@ ${qText}`;
|
|
|
4360
5092
|
history.push({ role: "assistant", content: msg2 });
|
|
4361
5093
|
postStatus("Planner needs user input", void 0, "verify");
|
|
4362
5094
|
postStateSnapshot();
|
|
4363
|
-
return result.route;
|
|
5095
|
+
return { route: result.route, taskComplete: false, needsUserInput: true };
|
|
4364
5096
|
}
|
|
4365
5097
|
const toolResults = result.plannerResponse.toolResults || [];
|
|
4366
5098
|
for (const toolResult of toolResults) {
|
|
@@ -4377,18 +5109,30 @@ ${qText}`;
|
|
|
4377
5109
|
history.push({ role: "assistant", content: msg });
|
|
4378
5110
|
postStatus("Planner execution completed", response.overallThought, "complete");
|
|
4379
5111
|
postStateSnapshot();
|
|
4380
|
-
return
|
|
5112
|
+
return {
|
|
5113
|
+
route: result.route,
|
|
5114
|
+
taskComplete: !!response.taskComplete && !responseError,
|
|
5115
|
+
needsUserInput: false
|
|
5116
|
+
};
|
|
4381
5117
|
}
|
|
4382
5118
|
postAssistantMessage("Done.");
|
|
4383
5119
|
history.push({ role: "assistant", content: "Done." });
|
|
4384
5120
|
postStatus("Completed", void 0, "complete");
|
|
4385
5121
|
postStateSnapshot();
|
|
4386
|
-
return result.route;
|
|
5122
|
+
return { route: result.route, taskComplete: true };
|
|
4387
5123
|
}
|
|
4388
5124
|
async function runUserMessage(text, meta) {
|
|
4389
5125
|
const runId = meta?.runId || crypto.randomUUID();
|
|
4390
5126
|
if (completedRunIds.has(runId)) {
|
|
4391
|
-
|
|
5127
|
+
const cachedOutcome = normalizeRunOutcome(completedRunOutcomes.get(runId));
|
|
5128
|
+
self.postMessage({
|
|
5129
|
+
type: "run_completed",
|
|
5130
|
+
runId,
|
|
5131
|
+
ok: true,
|
|
5132
|
+
route: cachedOutcome.route,
|
|
5133
|
+
taskComplete: cachedOutcome.taskComplete,
|
|
5134
|
+
needsUserInput: cachedOutcome.needsUserInput
|
|
5135
|
+
});
|
|
4392
5136
|
return;
|
|
4393
5137
|
}
|
|
4394
5138
|
if (activeRun && activeRun.runId === runId) {
|
|
@@ -4402,13 +5146,39 @@ async function runUserMessage(text, meta) {
|
|
|
4402
5146
|
self.postMessage({ type: "run_started", runId, text, resume });
|
|
4403
5147
|
postStateSnapshot();
|
|
4404
5148
|
try {
|
|
4405
|
-
const
|
|
4406
|
-
|
|
5149
|
+
const outcome = normalizeRunOutcome(await handleUserMessage(text, { resume }));
|
|
5150
|
+
completedRunOutcomes.set(runId, outcome);
|
|
5151
|
+
self.postMessage({
|
|
5152
|
+
type: "run_completed",
|
|
5153
|
+
runId,
|
|
5154
|
+
ok: true,
|
|
5155
|
+
route: outcome.route,
|
|
5156
|
+
taskComplete: outcome.taskComplete,
|
|
5157
|
+
needsUserInput: outcome.needsUserInput
|
|
5158
|
+
});
|
|
5159
|
+
if (outcome.taskComplete && !outcome.needsUserInput) {
|
|
5160
|
+
clearTaskScopedContextAfterCompletion();
|
|
5161
|
+
postStateSnapshot();
|
|
5162
|
+
}
|
|
4407
5163
|
} catch (error) {
|
|
4408
5164
|
if (error?.name === "AbortError") {
|
|
4409
|
-
self.postMessage({
|
|
5165
|
+
self.postMessage({
|
|
5166
|
+
type: "run_completed",
|
|
5167
|
+
runId,
|
|
5168
|
+
ok: false,
|
|
5169
|
+
error: "Run cancelled",
|
|
5170
|
+
taskComplete: false,
|
|
5171
|
+
needsUserInput: false
|
|
5172
|
+
});
|
|
4410
5173
|
} else {
|
|
4411
|
-
self.postMessage({
|
|
5174
|
+
self.postMessage({
|
|
5175
|
+
type: "run_completed",
|
|
5176
|
+
runId,
|
|
5177
|
+
ok: false,
|
|
5178
|
+
error: error?.message || String(error),
|
|
5179
|
+
taskComplete: false,
|
|
5180
|
+
needsUserInput: false
|
|
5181
|
+
});
|
|
4412
5182
|
throw error;
|
|
4413
5183
|
}
|
|
4414
5184
|
} finally {
|
|
@@ -4417,8 +5187,10 @@ async function runUserMessage(text, meta) {
|
|
|
4417
5187
|
completedRunIds.add(runId);
|
|
4418
5188
|
if (completedRunIds.size > 50) {
|
|
4419
5189
|
const oldest = completedRunIds.values().next().value;
|
|
4420
|
-
if (oldest)
|
|
5190
|
+
if (oldest) {
|
|
4421
5191
|
completedRunIds.delete(oldest);
|
|
5192
|
+
completedRunOutcomes.delete(oldest);
|
|
5193
|
+
}
|
|
4422
5194
|
}
|
|
4423
5195
|
postStateSnapshot();
|
|
4424
5196
|
}
|
|
@@ -4457,7 +5229,12 @@ self.onmessage = async (ev) => {
|
|
|
4457
5229
|
if (!config)
|
|
4458
5230
|
throw new Error("Worker not initialized");
|
|
4459
5231
|
const partial = data.config || {};
|
|
4460
|
-
config = {
|
|
5232
|
+
config = {
|
|
5233
|
+
...config,
|
|
5234
|
+
...partial,
|
|
5235
|
+
ui: mergeWorkerUi(config.ui, partial.ui),
|
|
5236
|
+
tools: mergeWorkerTools(config.tools, partial.tools)
|
|
5237
|
+
};
|
|
4461
5238
|
if (typeof partial.sessionId === "string" && partial.sessionId.trim() && partial.sessionId.trim() !== trajectoryId) {
|
|
4462
5239
|
trajectoryId = partial.sessionId.trim();
|
|
4463
5240
|
plannerHistory = [];
|