@quantiya/codevibe-core 2.0.50 → 2.0.51
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/dist/appsync/appsync-client.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +497 -491
- package/dist/orchestration-shell/attachments.d.ts +7 -0
- package/dist/orchestration-shell/cli.js +414 -51
- package/dist/orchestration-shell/index.d.ts +5 -4
- package/dist/orchestration-shell/web/extract.d.ts +12 -0
- package/dist/planner/client.d.ts +1 -0
- package/dist/planner/composite-advisory.d.ts +1 -0
- package/dist/planner/hosted-advisory.d.ts +4 -1
- package/dist/tool-activity/types.d.ts +12 -12
- package/package.json +1 -1
|
@@ -195,3 +195,10 @@ export declare function attachmentsToBase64(attachments: ImageAttachment[], opts
|
|
|
195
195
|
images: string[];
|
|
196
196
|
failed: ImageAttachment[];
|
|
197
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* Detects whether a clarifying question emitted on an image attachment turn is a blind deflection
|
|
200
|
+
* caused by a text-only classifier's inability to see/inspect images (e.g. asking the user to
|
|
201
|
+
* describe the screenshot or what to do with it, or generic rephrase requests), rather than a genuine
|
|
202
|
+
* domain clarification (e.g. "which specific region?").
|
|
203
|
+
*/
|
|
204
|
+
export declare function isBlindImageClarification(prompt: string, clarifyingQuestion?: string): boolean;
|
|
@@ -5756,6 +5756,23 @@ var AppSyncClient = class _AppSyncClient {
|
|
|
5756
5756
|
throw new Error("generatePlannerAdvisory: prompt ciphertext is required");
|
|
5757
5757
|
if (input.prompt.length > 2e5)
|
|
5758
5758
|
throw new Error(`generatePlannerAdvisory: prompt ciphertext exceeds 200,000 chars ceiling (${input.prompt.length})`);
|
|
5759
|
+
if (input.images !== void 0) {
|
|
5760
|
+
if (!Array.isArray(input.images))
|
|
5761
|
+
throw new Error("generatePlannerAdvisory: images must be an array of string ciphertexts");
|
|
5762
|
+
if (input.images.length > 5)
|
|
5763
|
+
throw new Error(`generatePlannerAdvisory: images count exceeds maximum of 5 (got ${input.images.length})`);
|
|
5764
|
+
let totalCiphertextLen = input.prompt.length;
|
|
5765
|
+
for (let i = 0; i < input.images.length; i++) {
|
|
5766
|
+
let imgCipher = input.images[i];
|
|
5767
|
+
if (typeof imgCipher != "string" || imgCipher.trim().length === 0)
|
|
5768
|
+
throw new Error(`generatePlannerAdvisory: image at index ${i} must be a non-empty string ciphertext`);
|
|
5769
|
+
if (imgCipher.length > 27e5)
|
|
5770
|
+
throw new Error(`generatePlannerAdvisory: image at index ${i} exceeds ciphertext limit of 2,700,000 chars (got ${imgCipher.length})`);
|
|
5771
|
+
totalCiphertextLen += imgCipher.length;
|
|
5772
|
+
}
|
|
5773
|
+
if (totalCiphertextLen > 45e5)
|
|
5774
|
+
throw new Error(`generatePlannerAdvisory: total request ciphertext exceeds 4,500,000 chars ceiling (${totalCiphertextLen})`);
|
|
5775
|
+
}
|
|
5759
5776
|
if (input.maxTokens !== void 0 && (input.maxTokens < 1 || input.maxTokens > 1536))
|
|
5760
5777
|
throw new Error(`generatePlannerAdvisory: maxTokens must be between 1 and 1536 (got ${input.maxTokens})`);
|
|
5761
5778
|
if (input.temperature !== void 0 && (input.temperature < 0 || input.temperature > 1))
|
|
@@ -17335,6 +17352,14 @@ function attachmentsToBase64(attachments, opts) {
|
|
|
17335
17352
|
}
|
|
17336
17353
|
return { images, failed };
|
|
17337
17354
|
}
|
|
17355
|
+
function isBlindImageClarification(prompt, clarifyingQuestion) {
|
|
17356
|
+
if (clarifyingQuestion && clarifyingQuestion.trim().length > 0) {
|
|
17357
|
+
let q = clarifyingQuestion.toLowerCase();
|
|
17358
|
+
return /what .*like me to do with the (screenshot|image)/i.test(q) || /what .*want me to do with the (screenshot|image)/i.test(q) || /how should i use (that|this) information/i.test(q) || /information from the (screenshot|image)/i.test(q) || /rephrase that as a specific command or request/i.test(q) || /cannot (see|view|read|inspect) (the )?(image|screenshot)/i.test(q) || /describe what you('d| would) like me to do with (the )?(screenshot|image)/i.test(q);
|
|
17359
|
+
}
|
|
17360
|
+
let p = prompt.toLowerCase();
|
|
17361
|
+
return /what('s| is| do you see) (in |on )?(the |this )?(screenshot|image|picture)/i.test(p) || /what does (the |this )?(screenshot|image|picture) (show|contain|depict)/i.test(p) || /what (shape|color|text) is (in |on )?(this |the )?(image|screenshot)/i.test(p);
|
|
17362
|
+
}
|
|
17338
17363
|
|
|
17339
17364
|
// src/orchestration-shell/slash-suggest.ts
|
|
17340
17365
|
function isSlashCommandInProgress(value) {
|
|
@@ -20992,6 +21017,310 @@ function assembleParagraphs(paragraphs, indices, maxChars) {
|
|
|
20992
21017
|
`);
|
|
20993
21018
|
return result.length > maxChars ? result.slice(0, maxChars) : result;
|
|
20994
21019
|
}
|
|
21020
|
+
var GENERIC_RELEVANCE_STOPWORDS = /* @__PURE__ */ new Set([
|
|
21021
|
+
// Basic query, auxiliary, and question words
|
|
21022
|
+
"what",
|
|
21023
|
+
"when",
|
|
21024
|
+
"where",
|
|
21025
|
+
"which",
|
|
21026
|
+
"who",
|
|
21027
|
+
"whom",
|
|
21028
|
+
"whose",
|
|
21029
|
+
"why",
|
|
21030
|
+
"how",
|
|
21031
|
+
"this",
|
|
21032
|
+
"that",
|
|
21033
|
+
"these",
|
|
21034
|
+
"those",
|
|
21035
|
+
"there",
|
|
21036
|
+
"their",
|
|
21037
|
+
"theirs",
|
|
21038
|
+
"here",
|
|
21039
|
+
"about",
|
|
21040
|
+
"above",
|
|
21041
|
+
"below",
|
|
21042
|
+
"from",
|
|
21043
|
+
"with",
|
|
21044
|
+
"within",
|
|
21045
|
+
"without",
|
|
21046
|
+
"under",
|
|
21047
|
+
"over",
|
|
21048
|
+
"have",
|
|
21049
|
+
"having",
|
|
21050
|
+
"has",
|
|
21051
|
+
"had",
|
|
21052
|
+
"been",
|
|
21053
|
+
"would",
|
|
21054
|
+
"could",
|
|
21055
|
+
"should",
|
|
21056
|
+
"might",
|
|
21057
|
+
"must",
|
|
21058
|
+
"more",
|
|
21059
|
+
"most",
|
|
21060
|
+
"some",
|
|
21061
|
+
"many",
|
|
21062
|
+
"much",
|
|
21063
|
+
"also",
|
|
21064
|
+
"just",
|
|
21065
|
+
"only",
|
|
21066
|
+
"other",
|
|
21067
|
+
"such",
|
|
21068
|
+
"does",
|
|
21069
|
+
"did",
|
|
21070
|
+
"doing",
|
|
21071
|
+
"done",
|
|
21072
|
+
"will",
|
|
21073
|
+
"shall",
|
|
21074
|
+
"can",
|
|
21075
|
+
"cant",
|
|
21076
|
+
"cannot",
|
|
21077
|
+
"into",
|
|
21078
|
+
"onto",
|
|
21079
|
+
"upon",
|
|
21080
|
+
"than",
|
|
21081
|
+
"then",
|
|
21082
|
+
"them",
|
|
21083
|
+
"they",
|
|
21084
|
+
"your",
|
|
21085
|
+
"yours",
|
|
21086
|
+
// Conversational verbs and common nouns
|
|
21087
|
+
"explain",
|
|
21088
|
+
"explanation",
|
|
21089
|
+
"algorithm",
|
|
21090
|
+
"algorithms",
|
|
21091
|
+
"code",
|
|
21092
|
+
"coding",
|
|
21093
|
+
"function",
|
|
21094
|
+
"functions",
|
|
21095
|
+
"write",
|
|
21096
|
+
"writing",
|
|
21097
|
+
"create",
|
|
21098
|
+
"build",
|
|
21099
|
+
"make",
|
|
21100
|
+
"implement",
|
|
21101
|
+
"implementation",
|
|
21102
|
+
"test",
|
|
21103
|
+
"tests",
|
|
21104
|
+
"testing",
|
|
21105
|
+
"file",
|
|
21106
|
+
"files",
|
|
21107
|
+
"error",
|
|
21108
|
+
"errors",
|
|
21109
|
+
"run",
|
|
21110
|
+
"running",
|
|
21111
|
+
"use",
|
|
21112
|
+
"using",
|
|
21113
|
+
"work",
|
|
21114
|
+
"works",
|
|
21115
|
+
"working",
|
|
21116
|
+
"difference",
|
|
21117
|
+
"between",
|
|
21118
|
+
"better",
|
|
21119
|
+
"best",
|
|
21120
|
+
"example",
|
|
21121
|
+
"examples",
|
|
21122
|
+
"help",
|
|
21123
|
+
"please",
|
|
21124
|
+
"know",
|
|
21125
|
+
"want",
|
|
21126
|
+
"need",
|
|
21127
|
+
"like",
|
|
21128
|
+
"good",
|
|
21129
|
+
"bad",
|
|
21130
|
+
"worse",
|
|
21131
|
+
"worst",
|
|
21132
|
+
"mean",
|
|
21133
|
+
"means",
|
|
21134
|
+
"problem",
|
|
21135
|
+
"problems",
|
|
21136
|
+
"issue",
|
|
21137
|
+
"issues",
|
|
21138
|
+
"question",
|
|
21139
|
+
"questions",
|
|
21140
|
+
"answer",
|
|
21141
|
+
"answers",
|
|
21142
|
+
"search",
|
|
21143
|
+
"searching",
|
|
21144
|
+
"read",
|
|
21145
|
+
"reading",
|
|
21146
|
+
"view",
|
|
21147
|
+
"look",
|
|
21148
|
+
"looks",
|
|
21149
|
+
"looking",
|
|
21150
|
+
"show",
|
|
21151
|
+
"find",
|
|
21152
|
+
"get",
|
|
21153
|
+
"set",
|
|
21154
|
+
"data",
|
|
21155
|
+
"type",
|
|
21156
|
+
"types",
|
|
21157
|
+
"system",
|
|
21158
|
+
"method",
|
|
21159
|
+
"methods",
|
|
21160
|
+
"class",
|
|
21161
|
+
"classes",
|
|
21162
|
+
"object",
|
|
21163
|
+
"objects",
|
|
21164
|
+
"program",
|
|
21165
|
+
"programs",
|
|
21166
|
+
"language",
|
|
21167
|
+
"languages",
|
|
21168
|
+
"value",
|
|
21169
|
+
"values",
|
|
21170
|
+
"script",
|
|
21171
|
+
"prompt",
|
|
21172
|
+
"model",
|
|
21173
|
+
"query",
|
|
21174
|
+
"input",
|
|
21175
|
+
"output",
|
|
21176
|
+
"state",
|
|
21177
|
+
"process",
|
|
21178
|
+
"node",
|
|
21179
|
+
"call",
|
|
21180
|
+
// Conversational follow-ups, speaking, evaluation & opinions
|
|
21181
|
+
"say",
|
|
21182
|
+
"says",
|
|
21183
|
+
"said",
|
|
21184
|
+
"saying",
|
|
21185
|
+
"tell",
|
|
21186
|
+
"tells",
|
|
21187
|
+
"told",
|
|
21188
|
+
"sound",
|
|
21189
|
+
"sounds",
|
|
21190
|
+
"sounding",
|
|
21191
|
+
"think",
|
|
21192
|
+
"thinks",
|
|
21193
|
+
"thinking",
|
|
21194
|
+
"thought",
|
|
21195
|
+
"thoughts",
|
|
21196
|
+
"opinion",
|
|
21197
|
+
"opinions",
|
|
21198
|
+
"take",
|
|
21199
|
+
"takes",
|
|
21200
|
+
"critique",
|
|
21201
|
+
"critiques",
|
|
21202
|
+
"perspective",
|
|
21203
|
+
"perspectives",
|
|
21204
|
+
"viewpoint",
|
|
21205
|
+
"viewpoints",
|
|
21206
|
+
"summary",
|
|
21207
|
+
"summarize",
|
|
21208
|
+
"summarizes",
|
|
21209
|
+
"summarizing",
|
|
21210
|
+
"takeaway",
|
|
21211
|
+
"takeaways",
|
|
21212
|
+
"key",
|
|
21213
|
+
"keys",
|
|
21214
|
+
"pros",
|
|
21215
|
+
"cons",
|
|
21216
|
+
"pro",
|
|
21217
|
+
"con",
|
|
21218
|
+
"detail",
|
|
21219
|
+
"details",
|
|
21220
|
+
"information",
|
|
21221
|
+
"info",
|
|
21222
|
+
// Shopping, consumer evaluation, and general follow-up adjectives
|
|
21223
|
+
"worth",
|
|
21224
|
+
"buy",
|
|
21225
|
+
"buys",
|
|
21226
|
+
"buying",
|
|
21227
|
+
"bought",
|
|
21228
|
+
"purchase",
|
|
21229
|
+
"purchasing",
|
|
21230
|
+
"purchases",
|
|
21231
|
+
"cost",
|
|
21232
|
+
"costs",
|
|
21233
|
+
"costing",
|
|
21234
|
+
"price",
|
|
21235
|
+
"prices",
|
|
21236
|
+
"pricing",
|
|
21237
|
+
"expensive",
|
|
21238
|
+
"cheap",
|
|
21239
|
+
"recommend",
|
|
21240
|
+
"recommends",
|
|
21241
|
+
"recommended",
|
|
21242
|
+
"recommendation",
|
|
21243
|
+
"recommendations",
|
|
21244
|
+
"scratches",
|
|
21245
|
+
"scratch",
|
|
21246
|
+
"scratching",
|
|
21247
|
+
"easily",
|
|
21248
|
+
"easy",
|
|
21249
|
+
"hard",
|
|
21250
|
+
"completely",
|
|
21251
|
+
"thing",
|
|
21252
|
+
"things",
|
|
21253
|
+
"item",
|
|
21254
|
+
"items",
|
|
21255
|
+
"stuff",
|
|
21256
|
+
"possible",
|
|
21257
|
+
"possibility",
|
|
21258
|
+
"reverse",
|
|
21259
|
+
"reversing",
|
|
21260
|
+
"place",
|
|
21261
|
+
"places",
|
|
21262
|
+
// Page / Document references and meta-terms
|
|
21263
|
+
"page",
|
|
21264
|
+
"pages",
|
|
21265
|
+
"article",
|
|
21266
|
+
"articles",
|
|
21267
|
+
"site",
|
|
21268
|
+
"sites",
|
|
21269
|
+
"website",
|
|
21270
|
+
"websites",
|
|
21271
|
+
"url",
|
|
21272
|
+
"urls",
|
|
21273
|
+
"webpage",
|
|
21274
|
+
"webpages",
|
|
21275
|
+
"document",
|
|
21276
|
+
"documents",
|
|
21277
|
+
"post",
|
|
21278
|
+
"posts",
|
|
21279
|
+
"blog",
|
|
21280
|
+
"blogs",
|
|
21281
|
+
"review",
|
|
21282
|
+
"reviews",
|
|
21283
|
+
"author",
|
|
21284
|
+
"writer",
|
|
21285
|
+
"writers",
|
|
21286
|
+
"wrote",
|
|
21287
|
+
"source",
|
|
21288
|
+
"sources",
|
|
21289
|
+
"results",
|
|
21290
|
+
"result",
|
|
21291
|
+
"findings",
|
|
21292
|
+
"finding"
|
|
21293
|
+
]);
|
|
21294
|
+
function isPromptRelevantToRetainedPage(prompt, retainedPage) {
|
|
21295
|
+
if (!retainedPage || !retainedPage.text || retainedPage.text.trim().length === 0)
|
|
21296
|
+
return !1;
|
|
21297
|
+
let cleanPrompt = (prompt || "").trim();
|
|
21298
|
+
if (!cleanPrompt) return !1;
|
|
21299
|
+
let pageTitle = (retainedPage.title || "").toLowerCase(), pageUrl = (retainedPage.url || "").toLowerCase(), DEICTIC_PHRASE_REGEX = /\b(this|that|the|current)\s+(?:web\s+)?(page|article|site|website|url|link|post|webpage|document|blog|review)\b/i, PREPOSITIONAL_PAGE_REGEX = /\b(from|on|in)\s+(the|this|that)\s+(?:web\s+)?(page|article|site|website|post|document|link|webpage)\b/i, AUTHOR_REF_REGEX = /\b(author|who wrote|who is the author)\b/i, CJK_DEICTIC_REGEX = /(这篇文章|该文章|这个网页|该网页|这个页面|该页面|这个网站|该网站|原文|作者|出处)/, CJK_EVALUATIVE_FOLLOWUP_REGEX = /(总结|概括|看法|观点|优缺点|评价|详细说说|你怎么看)/;
|
|
21300
|
+
if (DEICTIC_PHRASE_REGEX.test(cleanPrompt) || PREPOSITIONAL_PAGE_REGEX.test(cleanPrompt) || AUTHOR_REF_REGEX.test(cleanPrompt) || CJK_DEICTIC_REGEX.test(cleanPrompt) || CJK_EVALUATIVE_FOLLOWUP_REGEX.test(cleanPrompt))
|
|
21301
|
+
return !0;
|
|
21302
|
+
function tokenMatchesWordStart(token, text2) {
|
|
21303
|
+
if (!text2) return !1;
|
|
21304
|
+
if (/[\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]/.test(token))
|
|
21305
|
+
return text2.includes(token);
|
|
21306
|
+
let escaped = escapeRegex2(token);
|
|
21307
|
+
return /^[a-zA-Z0-9_]+$/.test(token) ? new RegExp(`\\b${escaped}`, "i").test(text2) : new RegExp(`(?<=^|[\\s\\p{P}])${escaped}`, "gui").test(text2);
|
|
21308
|
+
}
|
|
21309
|
+
let distinctiveTokens = extractQueryTokens(cleanPrompt).filter(
|
|
21310
|
+
(t) => t.length >= 3 && !GENERIC_RELEVANCE_STOPWORDS.has(t.toLowerCase())
|
|
21311
|
+
), matchingTokens = distinctiveTokens.filter(
|
|
21312
|
+
(token) => tokenMatchesWordStart(token, pageTitle) || tokenMatchesWordStart(token, pageUrl) || tokenMatchesWordStart(token, retainedPage.text || "")
|
|
21313
|
+
);
|
|
21314
|
+
if (distinctiveTokens.length > 0 && matchingTokens.length === 0)
|
|
21315
|
+
return !1;
|
|
21316
|
+
let SUMMARY_FOLLOWUP_REGEX = /\b(summarize|summary|takeaways?|tl;?dr)\b|\b(pros\s+and\s+cons|pros|cons)(\s*\?|\s*$|\s+(of|about)\s+(it|this|that|them|the\s+(page|article|site|website|post|document|device|product|phone|display)))/i, OPINION_FOLLOWUP_REGEX = /\b(your\s+(opinion|thoughts?|take|critique|perspective))\b/i, THINK_FOLLOWUP_REGEX = /\bwhat do you think(\?|$|\s+(about|of)\s+(it|this|that|them|the\s+(page|article|site|website|post|document|device|product|phone|display)))/i, PRONOUN_FOLLOWUP_REGEX = /\b(is|does|can|will|should|would)\s+it\b/i, ABOUT_IT_REGEX = /\b(about|of)\s+(it|this|them)\b/i, TELL_ME_MORE_REGEX = /\b(tell me more|more details)\b/i;
|
|
21317
|
+
if ((SUMMARY_FOLLOWUP_REGEX.test(cleanPrompt) || OPINION_FOLLOWUP_REGEX.test(cleanPrompt) || THINK_FOLLOWUP_REGEX.test(cleanPrompt) || PRONOUN_FOLLOWUP_REGEX.test(cleanPrompt) || ABOUT_IT_REGEX.test(cleanPrompt) || TELL_ME_MORE_REGEX.test(cleanPrompt)) && (distinctiveTokens.length === 0 || matchingTokens.length >= 2 || matchingTokens.some((t) => t.length >= 6) || matchingTokens.length >= 1 && matchingTokens.length / distinctiveTokens.length >= 0.5))
|
|
21318
|
+
return !0;
|
|
21319
|
+
for (let token of distinctiveTokens)
|
|
21320
|
+
if (pageTitle.length > 0 && tokenMatchesWordStart(token, pageTitle) || pageUrl.length > 0 && tokenMatchesWordStart(token, pageUrl))
|
|
21321
|
+
return !0;
|
|
21322
|
+
return distinctiveTokens.length === 0 ? !1 : matchingTokens.length >= 2 || matchingTokens.some((t) => t.length >= 6);
|
|
21323
|
+
}
|
|
20995
21324
|
|
|
20996
21325
|
// src/orchestration-shell/web/fetch.ts
|
|
20997
21326
|
var http2 = __toESM(require("node:http")), https3 = __toESM(require("node:https")), dns2 = __toESM(require("node:dns")), zlib = __toESM(require("node:zlib")), import_node_string_decoder = require("node:string_decoder");
|
|
@@ -71374,7 +71703,7 @@ async function routeReadOnlyAgentMention(args) {
|
|
|
71374
71703
|
localOnly: !0
|
|
71375
71704
|
});
|
|
71376
71705
|
}
|
|
71377
|
-
let
|
|
71706
|
+
let rawRetainedPage = args.retainedPage !== void 0 ? args.retainedPage : getFreshRetainedBrowsePage(retainedBrowsePages, sessionId), retainedPage = rawRetainedPage && (args.retainedPage !== void 0 || isPromptRelevantToRetainedPage(requestBrief, rawRetainedPage)) ? rawRetainedPage : null, hasRetainedPage = !!(retainedPage && retainedPage.text.trim().length > 0), preparedBrief = composeBrainstormPanelBrief({
|
|
71378
71707
|
priorContext,
|
|
71379
71708
|
requestBrief,
|
|
71380
71709
|
retainedPage
|
|
@@ -72340,14 +72669,6 @@ async function routeBrainstorm(deps) {
|
|
|
72340
72669
|
return;
|
|
72341
72670
|
}
|
|
72342
72671
|
let isHostedBrainstorm = args.localAdvisoryRunner.providerKind === "hosted";
|
|
72343
|
-
if (images && images.length > 0 && isHostedBrainstorm) {
|
|
72344
|
-
store.dispatch({
|
|
72345
|
-
type: "SHELL_ADVISORY",
|
|
72346
|
-
source: "shell",
|
|
72347
|
-
text: "The local CodeVibe model is required to analyze attached images during brainstorming. Enable it with `codevibe model install` from a Pro/Max account, then ask again. No hosted model was called and no code was changed."
|
|
72348
|
-
});
|
|
72349
|
-
return;
|
|
72350
|
-
}
|
|
72351
72672
|
store.dispatch({
|
|
72352
72673
|
type: "SHELL_ADVISORY",
|
|
72353
72674
|
source: "shell",
|
|
@@ -72428,18 +72749,10 @@ async function routeAdvisory(deps) {
|
|
|
72428
72749
|
return;
|
|
72429
72750
|
}
|
|
72430
72751
|
let isHostedAdvisory = args.localAdvisoryRunner.providerKind === "hosted";
|
|
72431
|
-
if (hasImages && isHostedAdvisory) {
|
|
72432
|
-
store.dispatch({
|
|
72433
|
-
type: "SHELL_ADVISORY",
|
|
72434
|
-
source: "shell",
|
|
72435
|
-
text: "The local CodeVibe model is required to analyze an attached image. Enable it with `codevibe model install` from a Pro/Max account, then ask again. No hosted model was called and no code was changed."
|
|
72436
|
-
});
|
|
72437
|
-
return;
|
|
72438
|
-
}
|
|
72439
72752
|
store.dispatch({
|
|
72440
72753
|
type: "SHELL_ADVISORY",
|
|
72441
72754
|
source: "shell",
|
|
72442
|
-
text: hasImages ? "Analyzing the attached image(s) with local Gemma\u2026" : isHostedAdvisory ? "Answering with hosted Gemma\u2026" : "Answering with local Gemma\u2026"
|
|
72755
|
+
text: hasImages ? isHostedAdvisory ? "Analyzing the attached image(s) with hosted Gemma\u2026" : "Analyzing the attached image(s) with local Gemma\u2026" : isHostedAdvisory ? "Answering with hosted Gemma\u2026" : "Answering with local Gemma\u2026"
|
|
72443
72756
|
});
|
|
72444
72757
|
let MAX_ADVISORY_CLARIFICATIONS = 4, MAX_ADVISORY_CLARIFICATION_QUESTION_CHARS = 400, MAX_ADVISORY_CLARIFICATION_ANSWER_CHARS = 1e3, MAX_ADVISORY_CANONICAL_CONTEXT_CHARS = 6e3, MAX_ADVISORY_USER_PROMPT_CHARS = 4e3, MAX_ADVISORY_PROMPT_CHARS = 42e3, MAX_ADVISORY_PAGE_CHARS = 24e3, MAX_ADVISORY_STATUS_CHARS = 1500, MAX_ADVISORY_PAGE_TOKENS = 6e3, MAX_ADVISORY_PROMPT_TOKENS = 13500, statusText = "";
|
|
72445
72758
|
try {
|
|
@@ -72449,7 +72762,7 @@ async function routeAdvisory(deps) {
|
|
|
72449
72762
|
statusText = "";
|
|
72450
72763
|
}
|
|
72451
72764
|
let retainedPage = deps.retainedPage, pageText = "";
|
|
72452
|
-
if (retainedPage && retainedPage.text.trim().length > 0) {
|
|
72765
|
+
if (retainedPage && retainedPage.text.trim().length > 0 && isPromptRelevantToRetainedPage(userPrompt, retainedPage)) {
|
|
72453
72766
|
let relevant = extractQueryRelevantSnippets(retainedPage.text, userPrompt, {
|
|
72454
72767
|
maxChars: MAX_ADVISORY_PAGE_CHARS - 100
|
|
72455
72768
|
});
|
|
@@ -72461,7 +72774,7 @@ async function routeAdvisory(deps) {
|
|
|
72461
72774
|
canonicalContextText = rawContext.length > MAX_ADVISORY_CANONICAL_CONTEXT_CHARS ? `[older context omitted]
|
|
72462
72775
|
` + rawContext.slice(-MAX_ADVISORY_CANONICAL_CONTEXT_CHARS) : rawContext;
|
|
72463
72776
|
}
|
|
72464
|
-
let sanitizedUserPrompt = redactAbsoluteLocalPaths(userPrompt.trim()),
|
|
72777
|
+
let sanitizedUserPrompt = redactAbsoluteLocalPaths(userPrompt.trim()), effectiveUserPrompt = hasImages && sanitizedUserPrompt.replace(/\[Image #\d+\]/g, "").trim().length === 0 ? "Describe what is shown in the attached image(s)." : sanitizedUserPrompt, boundedUserPrompt = effectiveUserPrompt.length > MAX_ADVISORY_USER_PROMPT_CHARS ? effectiveUserPrompt.slice(0, MAX_ADVISORY_USER_PROMPT_CHARS) + "\u2026" : effectiveUserPrompt, advisoryClarifications = [];
|
|
72465
72778
|
if (deps.clarifications && deps.clarifications.length > 0) {
|
|
72466
72779
|
let sanitized = deps.clarifications.map((c) => {
|
|
72467
72780
|
let q = redactAbsoluteLocalPaths(c.question.trim()), a = redactAbsoluteLocalPaths(c.answer.trim());
|
|
@@ -72549,7 +72862,7 @@ async function routeAdvisory(deps) {
|
|
|
72549
72862
|
chars: prompt.length
|
|
72550
72863
|
}), pageText = "", prompt = buildPrompt());
|
|
72551
72864
|
}
|
|
72552
|
-
let advisoryRunner = args.localAdvisoryRunner, generate2 = (p) => advisoryRunner.generateAdvisory(p, {
|
|
72865
|
+
let advisoryRunner = args.localAdvisoryRunner, beforeProviderKind = advisoryRunner.providerKind, generate2 = (p) => advisoryRunner.generateAdvisory(p, {
|
|
72553
72866
|
responseFormat: "text",
|
|
72554
72867
|
numPredict: 1400,
|
|
72555
72868
|
...images.length > 0 ? { images } : {}
|
|
@@ -72564,6 +72877,12 @@ async function routeAdvisory(deps) {
|
|
|
72564
72877
|
else
|
|
72565
72878
|
throw err;
|
|
72566
72879
|
}
|
|
72880
|
+
let afterProviderKind = advisoryRunner.providerKind;
|
|
72881
|
+
beforeProviderKind !== "hosted" && afterProviderKind === "hosted" && store.dispatch({
|
|
72882
|
+
type: "SHELL_ADVISORY",
|
|
72883
|
+
source: "shell",
|
|
72884
|
+
text: hasImages ? "Local model unavailable; falling back to hosted Gemma for image analysis. No code was changed." : "Local model unavailable; falling back to hosted Gemma. No code was changed."
|
|
72885
|
+
});
|
|
72567
72886
|
let answer = sanitizeForTerminal(raw.trim());
|
|
72568
72887
|
if (answer) {
|
|
72569
72888
|
store.dispatch({
|
|
@@ -72590,11 +72909,25 @@ async function routeAdvisory(deps) {
|
|
|
72590
72909
|
text: hasImages ? `${modelNoun} returned no answer for the attached image(s). ${trustLine}` : `${modelNoun} returned an empty answer. Try rephrasing with a bit more detail. ${trustLine}`
|
|
72591
72910
|
});
|
|
72592
72911
|
} catch (err) {
|
|
72593
|
-
|
|
72912
|
+
let afterProviderKind = args.localAdvisoryRunner.providerKind;
|
|
72913
|
+
beforeProviderKind !== "hosted" && afterProviderKind === "hosted" && store.dispatch({
|
|
72914
|
+
type: "SHELL_ADVISORY",
|
|
72915
|
+
source: "shell",
|
|
72916
|
+
text: hasImages ? "Local model unavailable; falling back to hosted Gemma for image analysis. No code was changed." : "Local model unavailable; falling back to hosted Gemma. No code was changed."
|
|
72917
|
+
}), logger.warn("[orchestration-shell] local advisory failed", {
|
|
72594
72918
|
error: err.message,
|
|
72595
72919
|
hasImages,
|
|
72596
72920
|
runtimeLabel: args.localAdvisoryRunner.runtimeLabel
|
|
72597
72921
|
});
|
|
72922
|
+
let errMsg = err?.message ?? "";
|
|
72923
|
+
if (hasImages && /exceeds size limit|image limit exceeded|maximum 5 images|exceeds backend limit|exceeds ciphertext limit|total request ciphertext/i.test(errMsg)) {
|
|
72924
|
+
store.dispatch({
|
|
72925
|
+
type: "SHELL_ADVISORY",
|
|
72926
|
+
source: "shell",
|
|
72927
|
+
text: `Unable to analyze image: ${errMsg} No code was changed.`
|
|
72928
|
+
});
|
|
72929
|
+
return;
|
|
72930
|
+
}
|
|
72598
72931
|
let fallback = deps.fallbackSummary?.trim(), effectiveIsHosted = args.localAdvisoryRunner.providerKind === "hosted", modelLabel = effectiveIsHosted ? "Hosted Gemma" : "Local Gemma", trustLine = effectiveIsHosted ? "No code was changed." : "No hosted model was called and no code was changed.", generationScope = effectiveIsHosted ? "hosted" : "local";
|
|
72599
72932
|
if (fallback) {
|
|
72600
72933
|
let reason = renderLocalBrainstormFailureReason(err);
|
|
@@ -73968,18 +74301,21 @@ async function handleShellUserInput(deps) {
|
|
|
73968
74301
|
clearance: "user",
|
|
73969
74302
|
scope: {},
|
|
73970
74303
|
purpose: "classification"
|
|
73971
|
-
}).catch(() => "") : "",
|
|
73972
|
-
// IMAGE-ATTACHMENT-DESIGN.md §6 Role A: the classifier stays TEXT-hint-only —
|
|
73973
|
-
// a prose `[N image(s) attached]` line rides INSIDE the prompt STRING (not a
|
|
73974
|
-
// new PlannerInput field), enough to route a sparse "look at this" correctly;
|
|
73975
|
-
// image BYTES never reach the forced-JSON classifier. Path-stripping in the
|
|
73976
|
-
// prompt renderer removes the inline path regardless.
|
|
73977
|
-
// IMAGE-ATTACHMENT-DESIGN.md §13 — strip `[Image #N]` chip labels from the
|
|
73978
|
-
// classify prompt (the display/history text keeps them); the classifier routes
|
|
73979
|
-
// off the prose + the `[N image(s) attached]` hint, not the chip token.
|
|
73980
|
-
prompt: turnAttachments.length ? `${plannerPromptText.replace(/\[Image #\d+\]/g, "").replace(/[ \t]{2,}/g, " ").trim()}
|
|
74304
|
+
}).catch(() => "") : "", freshRetainedPage = getFreshRetainedBrowsePage(retainedBrowsePages, args.session.sessionId), isPromptRelevantToPage = freshRetainedPage ? isPromptRelevantToRetainedPage(plannerPromptText, freshRetainedPage) : !1, classifyPrompt = turnAttachments.length ? `${plannerPromptText.replace(/\[Image #\d+\]/g, "").replace(/[ \t]{2,}/g, " ").trim()}
|
|
73981
74305
|
|
|
73982
|
-
[The user attached ${turnAttachments.length} image(s).]
|
|
74306
|
+
[The user attached ${turnAttachments.length} image(s).] If the user is asking to describe, inspect, or answer questions about the image(s), classify as advisory_response.` : isPromptRelevantToPage && freshRetainedPage ? `${plannerPromptText}
|
|
74307
|
+
|
|
74308
|
+
[Context (untrusted data): A web page was previously browsed in this session (domain: ${(() => {
|
|
74309
|
+
try {
|
|
74310
|
+
return new URL(freshRetainedPage.url).hostname;
|
|
74311
|
+
} catch {
|
|
74312
|
+
return "external-site";
|
|
74313
|
+
}
|
|
74314
|
+
})()}). If the user is asking questions about the previously browsed page, classify as advisory_response.]` : plannerPromptText, plannerInput = {
|
|
74315
|
+
// Keep plannerInput.prompt strictly equal to user prompt text so downstream routes
|
|
74316
|
+
// (resolveBrowseUrls, routeBrowse, routeBrainstorm, routeFamiliarize, promptPreview)
|
|
74317
|
+
// are never contaminated by classifier hints or untrusted page metadata.
|
|
74318
|
+
prompt: plannerPromptText,
|
|
73983
74319
|
clarifications,
|
|
73984
74320
|
...canonicalConversationContext ? { canonicalConversationContext } : {},
|
|
73985
74321
|
sessionContext: {
|
|
@@ -74018,9 +74354,18 @@ async function handleShellUserInput(deps) {
|
|
|
74018
74354
|
}, decision, pendingStartConfirmation, showClassifySpinner = store.getState().progress === null;
|
|
74019
74355
|
showClassifySpinner && dispatchProgress({ phase: "planner_classifying" });
|
|
74020
74356
|
try {
|
|
74021
|
-
if (decision = await dispatchClassify(
|
|
74357
|
+
if (decision = await dispatchClassify({
|
|
74358
|
+
...plannerInput,
|
|
74359
|
+
prompt: classifyPrompt
|
|
74360
|
+
}), isLocalPlannerRuntime(args) && decision.action === "browse" && hasFileMutationIntent(plannerInput.prompt) && (decision = {
|
|
74022
74361
|
action: "start_task",
|
|
74023
74362
|
rationale: decision.rationale ? `${decision.rationale} (promoted to start_task due to file mutation intent)` : "web request with file mutation intent"
|
|
74363
|
+
}), turnAttachments.length > 0 && decision.action === "ask_user" && isBlindImageClarification(plannerInput.prompt, decision.clarifying_question) && !hasFileMutationIntent(plannerInput.prompt) && !isDestructiveFileRequest(plannerInput.prompt) && (decision = {
|
|
74364
|
+
action: "advisory_response",
|
|
74365
|
+
rationale: decision.rationale || "analyze and answer inquiry about the attached image"
|
|
74366
|
+
}), freshRetainedPage && decision.action === "ask_user" && isPromptRelevantToPage && !hasFileMutationIntent(plannerInput.prompt) && !isDestructiveFileRequest(plannerInput.prompt) && (decision = {
|
|
74367
|
+
action: "advisory_response",
|
|
74368
|
+
rationale: decision.rationale || "answer inquiry using retained web page context"
|
|
74024
74369
|
}), isLocalPlannerRuntime(args) && decision.action === "start_task" && plannerInput.clarifications.length === 0 && isDestructiveFileRequest(plannerInput.prompt))
|
|
74025
74370
|
logger.warn(
|
|
74026
74371
|
"[orchestration-shell] P43 backstop: a destructive file request was classified start_task without a confirmation this turn; asking first",
|
|
@@ -75865,21 +76210,35 @@ var HostedGemmaAdvisoryRunner = class {
|
|
|
75865
76210
|
this.providerKind = "hosted";
|
|
75866
76211
|
}
|
|
75867
76212
|
async generateAdvisory(promptText, options) {
|
|
75868
|
-
if (options?.images && options.images.length > 0)
|
|
75869
|
-
throw new Error(
|
|
75870
|
-
"HostedGemmaAdvisoryRunner: image attachments are not supported by hosted Bedrock Gemma. A local vision model is required."
|
|
75871
|
-
);
|
|
75872
76213
|
let sessionId = this.deps.activeSessionIdHolder.value;
|
|
75873
76214
|
if (!sessionId)
|
|
75874
76215
|
throw new Error("Hosted Gemma advisory generation failed: no active session ID");
|
|
75875
76216
|
let sessionKey = await this.deps.sessionKeyResolver.getSessionKey(sessionId);
|
|
75876
76217
|
if (!sessionKey)
|
|
75877
76218
|
throw new Error(`Hosted Gemma advisory generation failed: session key unresolved for session ${sessionId}`);
|
|
75878
|
-
let encryptedPrompt = this.deps.crypto.encryptString(promptText, sessionKey),
|
|
76219
|
+
let encryptedPrompt = this.deps.crypto.encryptString(promptText, sessionKey), encryptedImages;
|
|
76220
|
+
if (options?.images && options.images.length > 0) {
|
|
76221
|
+
if (options.images.length > 5)
|
|
76222
|
+
throw new Error(
|
|
76223
|
+
`Hosted Gemma image limit exceeded: at most 5 images are supported (received ${options.images.length}).`
|
|
76224
|
+
);
|
|
76225
|
+
for (let i = 0; i < options.images.length; i++) {
|
|
76226
|
+
let img = options.images[i];
|
|
76227
|
+
if (typeof img != "string" || img.trim().length === 0)
|
|
76228
|
+
throw new Error(`Hosted Gemma image at index ${i} is empty or invalid.`);
|
|
76229
|
+
if (img.length > 2e6)
|
|
76230
|
+
throw new Error(
|
|
76231
|
+
`Hosted Gemma image at index ${i} exceeds size limit of 2,000,000 characters (~1.5 MB). Please provide a smaller or downscaled image.`
|
|
76232
|
+
);
|
|
76233
|
+
}
|
|
76234
|
+
encryptedImages = options.images.map((img) => this.deps.crypto.encryptString(img, sessionKey));
|
|
76235
|
+
}
|
|
76236
|
+
let maxTokens = options?.numPredict, temperature = options?.temperature, start = Date.now();
|
|
75879
76237
|
try {
|
|
75880
76238
|
let response = await this.deps.transport.generatePlannerAdvisory({
|
|
75881
76239
|
sessionId,
|
|
75882
76240
|
prompt: encryptedPrompt,
|
|
76241
|
+
...encryptedImages && encryptedImages.length > 0 ? { images: encryptedImages } : {},
|
|
75883
76242
|
...maxTokens !== void 0 ? { maxTokens } : {},
|
|
75884
76243
|
...temperature !== void 0 ? { temperature } : {}
|
|
75885
76244
|
});
|
|
@@ -75918,14 +76277,7 @@ var CompositeAdvisoryRunner = class {
|
|
|
75918
76277
|
if (this.opts.tier === "FREE") {
|
|
75919
76278
|
if (!this.opts.localRunner)
|
|
75920
76279
|
throw new Error(
|
|
75921
|
-
"LocalModelUnavailable: local Gemma is not installed or enabled. Free tier operates in local-only mode."
|
|
75922
|
-
);
|
|
75923
|
-
return this.opts.localRunner.generateAdvisory(promptText, options);
|
|
75924
|
-
}
|
|
75925
|
-
if (options?.images && options.images.length > 0) {
|
|
75926
|
-
if (!this.localHealthy || !this.opts.localRunner)
|
|
75927
|
-
throw new Error(
|
|
75928
|
-
"LocalModelUnavailable: local CodeVibe vision model is required to analyze attached images."
|
|
76280
|
+
options?.images && options.images.length > 0 ? "LocalModelUnavailable: local CodeVibe vision model is required to analyze attached images. Free tier operates in local-only mode." : "LocalModelUnavailable: local Gemma is not installed or enabled. Free tier operates in local-only mode."
|
|
75929
76281
|
);
|
|
75930
76282
|
return this.opts.localRunner.generateAdvisory(promptText, options);
|
|
75931
76283
|
}
|
|
@@ -75933,9 +76285,17 @@ var CompositeAdvisoryRunner = class {
|
|
|
75933
76285
|
try {
|
|
75934
76286
|
return await this.opts.localRunner.generateAdvisory(promptText, options);
|
|
75935
76287
|
} catch (err) {
|
|
76288
|
+
let hasImages = !!(options?.images && options.images.length > 0);
|
|
75936
76289
|
logger.warn("[composite-advisory] local advisory failed; falling back to hosted Bedrock Gemma", {
|
|
75937
|
-
error: err?.message
|
|
75938
|
-
|
|
76290
|
+
error: err?.message,
|
|
76291
|
+
hasImages
|
|
76292
|
+
}), this.localHealthy = !1, this.opts.onNotice && this.opts.onNotice(
|
|
76293
|
+
hasImages ? `
|
|
76294
|
+
Local vision model error. Falling back to hosted Gemma on AWS.
|
|
76295
|
+
` : `
|
|
76296
|
+
Local advisory error. Falling back to hosted Gemma on AWS.
|
|
76297
|
+
`
|
|
76298
|
+
), this.opts.onFallbackToHosted?.(err);
|
|
75939
76299
|
}
|
|
75940
76300
|
return this.opts.hostedRunner.generateAdvisory(promptText, options);
|
|
75941
76301
|
}
|
|
@@ -81580,12 +81940,15 @@ function resolvePlannerAdapter(args) {
|
|
|
81580
81940
|
localRuntimeLabel: args.localPlanner.runtimeLabel,
|
|
81581
81941
|
hostedHealth: hostedStack.health,
|
|
81582
81942
|
onNotice: (msg) => {
|
|
81583
|
-
|
|
81943
|
+
logger.info("[planner] " + msg);
|
|
81584
81944
|
}
|
|
81585
81945
|
}), compositeAdvisoryRunner = new CompositeAdvisoryRunner({
|
|
81586
81946
|
localRunner: args.localPlanner.advisoryRunner,
|
|
81587
81947
|
hostedRunner: hostedStack.hostedAdvisoryRunner,
|
|
81588
|
-
tier
|
|
81948
|
+
tier,
|
|
81949
|
+
onNotice: (msg) => {
|
|
81950
|
+
logger.info("[planner] " + msg);
|
|
81951
|
+
}
|
|
81589
81952
|
});
|
|
81590
81953
|
return {
|
|
81591
81954
|
adapter: compositeAdapter,
|
|
@@ -325,7 +325,7 @@ export { reducer } from './reducer';
|
|
|
325
325
|
export { createOrchestrationStore, type OrchestrationStore } from './store';
|
|
326
326
|
export { routeBrowse, RETAINED_PAGE_MAX_CHARS, type RouteBrowseDeps, type RetainedBrowsePage, } from './route-browse';
|
|
327
327
|
export { composeBrainstormPanelBrief, fitTextToBudget, MAX_BRAINSTORM_PAGE_CHARS, MAX_BRAINSTORM_PAGE_TOKENS, MAX_BRAINSTORM_PAGE_BYTES, } from './brainstorm-quorum';
|
|
328
|
-
export { extractQueryRelevantSnippets, htmlToText } from './web/extract';
|
|
328
|
+
export { extractQueryRelevantSnippets, isPromptRelevantToRetainedPage, htmlToText } from './web/extract';
|
|
329
329
|
export { validateAgyArgPrompt, AGY_ARG_PROMPT_MAX_UTF8_BYTES, } from '../agy-cli-contract';
|
|
330
330
|
export type { Mode, Tier, PlannerDecision, AgentKind, PlannerHealthState, RunningTaskState, ReviewerSeatState, GateState, ExecutionEventEntry, RefusalEventEntry, BypassEventEntry, MobileEventEntry, EventStreamEntry, ConversationEntry, QueuedTask, PendingClarification, OrchestrationState, OrchestrationAction, LastModeFile, TeamState, TeamTrackEntry, TeamTrackState, TeamMergeGateStatus, LiveProgress, } from './types';
|
|
331
331
|
export { formatElapsed, isSpinnerPhase, renderProgressLine, type TaskProgressEvent, type OnProgress, } from './task-progress';
|
|
@@ -925,9 +925,10 @@ export declare function routeAdvisory(deps: {
|
|
|
925
925
|
*/
|
|
926
926
|
attemptedImages?: number;
|
|
927
927
|
/**
|
|
928
|
-
* 2026-09-12 — the page the `browse` route read most recently in this session.
|
|
929
|
-
* Rendered as untrusted source material
|
|
930
|
-
*
|
|
928
|
+
* 2026-09-12 (updated 2026-09-23) — the page the `browse` route read most recently in this session.
|
|
929
|
+
* Rendered as untrusted source material injected ONLY when the shell determines via
|
|
930
|
+
* `isPromptRelevantToRetainedPage` that the request is relevant to that page (preventing
|
|
931
|
+
* over-grounding and false refusals on unrelated technical follow-ups like A* algorithm).
|
|
931
932
|
*/
|
|
932
933
|
retainedPage?: RetainedBrowsePage;
|
|
933
934
|
}): Promise<void>;
|
|
@@ -44,3 +44,15 @@ export declare function extractQueryTokens(query: string): string[];
|
|
|
44
44
|
* NEVER throws.
|
|
45
45
|
*/
|
|
46
46
|
export declare function extractQueryRelevantSnippets(fullText: string, query: string, options?: ExtractQuerySnippetsOptions): string;
|
|
47
|
+
/**
|
|
48
|
+
* Detect whether a user prompt in an advisory turn is relevant to the retained browse page.
|
|
49
|
+
*
|
|
50
|
+
* Prevents over-grounding where an unrelated technical question (e.g. "Can you explain A* algorithm to me?")
|
|
51
|
+
* after a web search (e.g. for "iPhone Duo availability") is flooded with 24,000 characters of unrelated web text
|
|
52
|
+
* and rigid "take facts ONLY from the page text" rules, causing false refusals.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isPromptRelevantToRetainedPage(prompt: string, retainedPage?: {
|
|
55
|
+
url?: string;
|
|
56
|
+
title?: string;
|
|
57
|
+
text?: string;
|
|
58
|
+
} | null): boolean;
|