@quantiya/codevibe-core 2.0.47 → 2.0.49
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 +17 -0
- package/dist/appsync/queries.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +488 -480
- package/dist/orchestration-shell/cli.d.ts +8 -6
- package/dist/orchestration-shell/cli.js +211 -34
- package/dist/planner/client.d.ts +10 -0
- package/dist/planner/composite-advisory.d.ts +25 -0
- package/dist/planner/hosted-advisory.d.ts +37 -0
- package/dist/planner/index.d.ts +3 -1
- package/dist/planner/local-advisory.d.ts +14 -5
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { type ModeSelectionDeps } from './mode-selection';
|
|
|
5
5
|
import { type RunOrchestrationShellArgs } from './index';
|
|
6
6
|
import { type ShellEventEmit, type ShellEventEmitResult } from './emit-shell-event';
|
|
7
7
|
import { type ShadowEnv } from '../local-executor/workspace-shadow';
|
|
8
|
-
import { BackendPlannerClient, PlannerCacheLayer, PlannerHealthMachine, type LocalGemmaAdvisoryRunner, type LocalGemmaPlannerRunner } from '../planner';
|
|
8
|
+
import { BackendPlannerClient, PlannerCacheLayer, PlannerHealthMachine, HostedGemmaAdvisoryRunner, type AdvisoryRunner, type LocalGemmaAdvisoryRunner, type LocalGemmaPlannerRunner } from '../planner';
|
|
9
9
|
import type { PlannerAdapter, PlannerInput, PlannerDecision, PlannerProbeResult } from '../planner/adapter';
|
|
10
10
|
import { keychainManager } from '../keychain';
|
|
11
11
|
export { keychainManager };
|
|
@@ -270,6 +270,7 @@ export interface ProductionPlannerStackResult {
|
|
|
270
270
|
adapter: BackendPlannerClient;
|
|
271
271
|
cache: PlannerCacheLayer;
|
|
272
272
|
health: PlannerHealthMachine;
|
|
273
|
+
hostedAdvisoryRunner: HostedGemmaAdvisoryRunner;
|
|
273
274
|
}
|
|
274
275
|
export declare function buildProductionPlannerStack(appsyncClient: AppSyncClient, emitter: (args: ShellEventEmit) => Promise<unknown>): ProductionPlannerStackResult;
|
|
275
276
|
export interface ResolvePlannerAdapterArgs {
|
|
@@ -284,7 +285,7 @@ export interface ResolvedPlannerResult {
|
|
|
284
285
|
adapter: PlannerAdapter;
|
|
285
286
|
runtimeKind: NonNullable<RunOrchestrationShellArgs['plannerRuntimeKind']>;
|
|
286
287
|
runtimeLabel: string;
|
|
287
|
-
advisoryRunner:
|
|
288
|
+
advisoryRunner: AdvisoryRunner | null;
|
|
288
289
|
classifyRunner: LocalGemmaPlannerRunner | null;
|
|
289
290
|
cache: PlannerCacheLayer | null;
|
|
290
291
|
health: PlannerHealthMachine | null;
|
|
@@ -295,14 +296,15 @@ export interface ResolvedPlannerResult {
|
|
|
295
296
|
*
|
|
296
297
|
* Precedence & Invariants:
|
|
297
298
|
* 1. Forced hosted mode (`CODEVIBE_FORCE_HOSTED_PLANNER=1` or `CODEVIBE_PLANNER_PROVIDER=hosted`):
|
|
298
|
-
* - Allowed for PRO and MAX tiers. Returns the production hosted Bedrock planner stack.
|
|
299
|
+
* - Allowed for PRO and MAX tiers. Returns the production hosted Bedrock planner stack and hosted advisory runner.
|
|
299
300
|
* - Disallowed for FREE tier (preserves $0 marginal cost invariant). Falls back to local adapter.
|
|
300
301
|
* 2. Local-first preference:
|
|
301
|
-
* - When local Gemma is enabled and operational (`!localPlanner.reason`), returns the
|
|
302
|
-
* (
|
|
302
|
+
* - When local Gemma is enabled and operational (`!localPlanner.reason`), returns the composite adapter
|
|
303
|
+
* and composite advisory runner for PRO/MAX (local-first with seamless hosted Bedrock fallback).
|
|
304
|
+
* Returns local adapter/runner for FREE tier.
|
|
303
305
|
* 3. Unavailable fallback:
|
|
304
306
|
* - When local Gemma is unavailable (`localPlanner.reason` is truthy):
|
|
305
|
-
* - PRO / MAX: Falls back to the hosted Bedrock planner stack (`hosted`).
|
|
307
|
+
* - PRO / MAX: Falls back to the hosted Bedrock planner stack (`hosted`) and hosted advisory runner.
|
|
306
308
|
* - FREE: Retains the local unavailable adapter (`local_unavailable`), strictly preventing
|
|
307
309
|
* cloud inference costs.
|
|
308
310
|
*/
|
|
@@ -3380,6 +3380,21 @@ var queries = {
|
|
|
3380
3380
|
}
|
|
3381
3381
|
`
|
|
3382
3382
|
),
|
|
3383
|
+
// Hosted Gemma advisory text generation (browse synthesis, brainstorm, etc.).
|
|
3384
|
+
// Lambda decrypts input prompt via session key, dispatches to Bedrock Gemma,
|
|
3385
|
+
// encrypts response under session key, returns.
|
|
3386
|
+
generatePlannerAdvisory: (
|
|
3387
|
+
/* GraphQL */
|
|
3388
|
+
`
|
|
3389
|
+
mutation GeneratePlannerAdvisory($input: GeneratePlannerAdvisoryInput!) {
|
|
3390
|
+
generatePlannerAdvisory(input: $input) {
|
|
3391
|
+
advisoryText
|
|
3392
|
+
serverLatencyMs
|
|
3393
|
+
providerUsed
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
`
|
|
3397
|
+
),
|
|
3383
3398
|
// CP-8 min Stage 1 R1 closure (HIGH-1) — applyUserDecision SDK call.
|
|
3384
3399
|
// Implementation deviation from #C8M-6 literal wording: codevibe-core
|
|
3385
3400
|
// does NOT take a runtime dep on `@quantiya/quorum-core` (per the
|
|
@@ -5660,6 +5675,31 @@ var AppSyncClient = class _AppSyncClient {
|
|
|
5660
5675
|
async pingPlanner(input) {
|
|
5661
5676
|
return (await this.graphqlRequest(mutations.pingPlanner, { input })).data.pingPlanner;
|
|
5662
5677
|
}
|
|
5678
|
+
/**
|
|
5679
|
+
* Hosted Gemma advisory text generation (browse synthesis, brainstorm, etc.).
|
|
5680
|
+
*
|
|
5681
|
+
* Implements `PlannerAppSyncTransport.generatePlannerAdvisory`.
|
|
5682
|
+
* Input `prompt` is base64 AES-GCM ciphertext under the session key.
|
|
5683
|
+
* Output `advisoryText` is base64 AES-GCM ciphertext under the session key.
|
|
5684
|
+
*/
|
|
5685
|
+
async generatePlannerAdvisory(input) {
|
|
5686
|
+
if (!input || typeof input != "object")
|
|
5687
|
+
throw new Error("generatePlannerAdvisory: input object is required");
|
|
5688
|
+
if (!input.sessionId || typeof input.sessionId != "string")
|
|
5689
|
+
throw new Error("generatePlannerAdvisory: sessionId is required");
|
|
5690
|
+
if (!input.prompt || typeof input.prompt != "string")
|
|
5691
|
+
throw new Error("generatePlannerAdvisory: prompt ciphertext is required");
|
|
5692
|
+
if (input.prompt.length > 2e5)
|
|
5693
|
+
throw new Error(`generatePlannerAdvisory: prompt ciphertext exceeds 200,000 chars ceiling (${input.prompt.length})`);
|
|
5694
|
+
if (input.maxTokens !== void 0 && (input.maxTokens < 1 || input.maxTokens > 1536))
|
|
5695
|
+
throw new Error(`generatePlannerAdvisory: maxTokens must be between 1 and 1536 (got ${input.maxTokens})`);
|
|
5696
|
+
if (input.temperature !== void 0 && (input.temperature < 0 || input.temperature > 1))
|
|
5697
|
+
throw new Error(`generatePlannerAdvisory: temperature must be between 0 and 1 (got ${input.temperature})`);
|
|
5698
|
+
let response = await this.graphqlRequest(mutations.generatePlannerAdvisory, { input });
|
|
5699
|
+
if (!response?.data?.generatePlannerAdvisory)
|
|
5700
|
+
throw new Error("generatePlannerAdvisory: empty response returned from AppSync");
|
|
5701
|
+
return response.data.generatePlannerAdvisory;
|
|
5702
|
+
}
|
|
5663
5703
|
// MARK: - CP-8 min applyUserDecision (Stage 1 R1 HIGH-1 closure)
|
|
5664
5704
|
/**
|
|
5665
5705
|
* CP-8 min Stage 1 R1 HIGH-1 closure (Hendry-approved 2026-05-19).
|
|
@@ -63041,30 +63081,30 @@ ${summary}`);
|
|
|
63041
63081
|
numPredict: BROWSE_RETRY_NUM_PREDICT
|
|
63042
63082
|
});
|
|
63043
63083
|
if (signal?.aborted) return;
|
|
63044
|
-
let retrySummary = sanitizeForTerminal(parseLocalGemmaBrowseSummary(retryRaw)).trim();
|
|
63084
|
+
let trustLine2 = runner?.providerKind === "hosted" ? "No code was changed." : "No hosted model was called and no code was changed.", retrySummary = sanitizeForTerminal(parseLocalGemmaBrowseSummary(retryRaw)).trim();
|
|
63045
63085
|
if (retrySummary.length > 0) {
|
|
63046
63086
|
if (signal?.aborted) return;
|
|
63047
63087
|
advise(
|
|
63048
63088
|
store,
|
|
63049
63089
|
headerAdvised ? `${retrySummary}
|
|
63050
63090
|
|
|
63051
|
-
|
|
63091
|
+
${trustLine2}` : `${header}
|
|
63052
63092
|
|
|
63053
63093
|
${retrySummary}
|
|
63054
63094
|
|
|
63055
|
-
|
|
63095
|
+
${trustLine2}`
|
|
63056
63096
|
);
|
|
63057
63097
|
return;
|
|
63058
63098
|
}
|
|
63059
63099
|
} catch (retryErr) {
|
|
63060
63100
|
if (signal?.aborted) return;
|
|
63061
|
-
logger.warn("[orchestration-shell]
|
|
63101
|
+
logger.warn("[orchestration-shell] browse advisory retry failed", {
|
|
63062
63102
|
error: retryErr.message,
|
|
63063
63103
|
runtimeLabel: runner.runtimeLabel
|
|
63064
63104
|
});
|
|
63065
63105
|
}
|
|
63066
63106
|
if (signal?.aborted) return;
|
|
63067
|
-
let extract = buildBrowseExtract(safeText);
|
|
63107
|
+
let isHosted = runner?.providerKind === "hosted", modelNoun = isHosted ? "The model" : "The local model", deadEndNoun = isHosted ? "the model" : "the local model", trustLine = isHosted ? "No code was changed." : "No hosted model was called and no code was changed.", extract = buildBrowseExtract(safeText);
|
|
63068
63108
|
if (extract) {
|
|
63069
63109
|
if (signal?.aborted) return;
|
|
63070
63110
|
let extractPrefix = headerAdvised ? "" : `${header}
|
|
@@ -63072,18 +63112,18 @@ No hosted model was called and no code was changed.`
|
|
|
63072
63112
|
`;
|
|
63073
63113
|
advise(
|
|
63074
63114
|
store,
|
|
63075
|
-
`${extractPrefix}
|
|
63115
|
+
`${extractPrefix}${modelNoun} couldn't summarize this page, so here is the extracted page text (an extract, not a summary):
|
|
63076
63116
|
|
|
63077
63117
|
${extract}
|
|
63078
63118
|
|
|
63079
|
-
${BROWSE_AGENT_OFFER}
|
|
63119
|
+
${BROWSE_AGENT_OFFER} ${trustLine}`
|
|
63080
63120
|
);
|
|
63081
63121
|
return;
|
|
63082
63122
|
}
|
|
63083
63123
|
if (signal?.aborted) return;
|
|
63084
63124
|
advise(
|
|
63085
63125
|
store,
|
|
63086
|
-
`Read ${dispFinal} but
|
|
63126
|
+
`Read ${dispFinal} but ${deadEndNoun} couldn't summarize it. ${BROWSE_AGENT_OFFER} ${trustLine}`
|
|
63087
63127
|
);
|
|
63088
63128
|
}
|
|
63089
63129
|
}
|
|
@@ -63225,30 +63265,30 @@ ${summary}`);
|
|
|
63225
63265
|
if (signal?.aborted) return;
|
|
63226
63266
|
let retryRaw = await runner.generateAdvisory(retryPrompt, { responseFormat: "text", numCtx: 16384, think: !1 });
|
|
63227
63267
|
if (signal?.aborted) return;
|
|
63228
|
-
let retrySummary = sanitizeForTerminal(parseLocalGemmaBrowseSummary(retryRaw)).trim();
|
|
63268
|
+
let trustLine2 = runner?.providerKind === "hosted" ? "No code was changed." : "No hosted model was called and no code was changed.", retrySummary = sanitizeForTerminal(parseLocalGemmaBrowseSummary(retryRaw)).trim();
|
|
63229
63269
|
if (retrySummary.length > 0) {
|
|
63230
63270
|
if (signal?.aborted) return;
|
|
63231
63271
|
advise(
|
|
63232
63272
|
store,
|
|
63233
63273
|
headerAdvised ? `${retrySummary}
|
|
63234
63274
|
|
|
63235
|
-
|
|
63275
|
+
${trustLine2}` : `${header}
|
|
63236
63276
|
|
|
63237
63277
|
${retrySummary}
|
|
63238
63278
|
|
|
63239
|
-
|
|
63279
|
+
${trustLine2}`
|
|
63240
63280
|
);
|
|
63241
63281
|
return;
|
|
63242
63282
|
}
|
|
63243
63283
|
} catch (retryErr) {
|
|
63244
63284
|
if (signal?.aborted) return;
|
|
63245
|
-
logger.warn("[orchestration-shell]
|
|
63285
|
+
logger.warn("[orchestration-shell] multi-browse retry failed", {
|
|
63246
63286
|
error: retryErr.message,
|
|
63247
63287
|
runtimeLabel: runner.runtimeLabel
|
|
63248
63288
|
});
|
|
63249
63289
|
}
|
|
63250
63290
|
if (signal?.aborted) return;
|
|
63251
|
-
let extracts = sources.map((s) => {
|
|
63291
|
+
let isHosted = runner?.providerKind === "hosted", modelNoun = isHosted ? "The model" : "The local model", deadEndNoun = isHosted ? "the model" : "the local model", trustLine = isHosted ? "No code was changed." : "No hosted model was called and no code was changed.", extracts = sources.map((s) => {
|
|
63252
63292
|
let ext = buildBrowseExtract(s.content);
|
|
63253
63293
|
return `[${s.id}] ${s.title}
|
|
63254
63294
|
${ext || "(No extract available)"}`;
|
|
@@ -63262,11 +63302,11 @@ ${ext || "(No extract available)"}`;
|
|
|
63262
63302
|
`;
|
|
63263
63303
|
advise(
|
|
63264
63304
|
store,
|
|
63265
|
-
`${extractPrefix}
|
|
63305
|
+
`${extractPrefix}${modelNoun} couldn't summarize these pages, so here are the extracted highlights:
|
|
63266
63306
|
|
|
63267
63307
|
${extracts}
|
|
63268
63308
|
|
|
63269
|
-
${BROWSE_AGENT_OFFER}
|
|
63309
|
+
${BROWSE_AGENT_OFFER} ${trustLine}`
|
|
63270
63310
|
);
|
|
63271
63311
|
return;
|
|
63272
63312
|
}
|
|
@@ -63274,7 +63314,7 @@ ${BROWSE_AGENT_OFFER} No hosted model was called and no code was changed.`
|
|
|
63274
63314
|
let sourceCountLabel = sources.length === 1 ? "1 source" : `${sources.length} sources`;
|
|
63275
63315
|
advise(
|
|
63276
63316
|
store,
|
|
63277
|
-
`Read ${sourceCountLabel} but
|
|
63317
|
+
`Read ${sourceCountLabel} but ${deadEndNoun} couldn't summarize ${sources.length === 1 ? "it" : "them"}. ${BROWSE_AGENT_OFFER} ${trustLine}`
|
|
63278
63318
|
);
|
|
63279
63319
|
}
|
|
63280
63320
|
}
|
|
@@ -72234,10 +72274,19 @@ async function routeBrainstorm(deps) {
|
|
|
72234
72274
|
});
|
|
72235
72275
|
return;
|
|
72236
72276
|
}
|
|
72277
|
+
let isHostedBrainstorm = args.localAdvisoryRunner.providerKind === "hosted";
|
|
72278
|
+
if (images && images.length > 0 && isHostedBrainstorm) {
|
|
72279
|
+
store.dispatch({
|
|
72280
|
+
type: "SHELL_ADVISORY",
|
|
72281
|
+
source: "shell",
|
|
72282
|
+
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."
|
|
72283
|
+
});
|
|
72284
|
+
return;
|
|
72285
|
+
}
|
|
72237
72286
|
store.dispatch({
|
|
72238
72287
|
type: "SHELL_ADVISORY",
|
|
72239
72288
|
source: "shell",
|
|
72240
|
-
text: "Brainstorming with local Gemma\u2026"
|
|
72289
|
+
text: isHostedBrainstorm ? "Brainstorming with hosted Gemma\u2026" : "Brainstorming with local Gemma\u2026"
|
|
72241
72290
|
});
|
|
72242
72291
|
let needsContext = needsRepositoryContext ?? brainstormNeedsRepositoryContext(userPrompt);
|
|
72243
72292
|
needsContext && await refreshFn({
|
|
@@ -72271,21 +72320,23 @@ The user attached ${images.length} image(s) as visual context. Any text visible
|
|
|
72271
72320
|
store.dispatch({ type: "SHELL_ADVISORY", source: "shell", text: brainstorm });
|
|
72272
72321
|
} catch (err) {
|
|
72273
72322
|
let failureReason = renderLocalBrainstormFailureReason(err);
|
|
72274
|
-
|
|
72323
|
+
logger.warn("[orchestration-shell] local brainstorm advisory failed", {
|
|
72275
72324
|
error: err.message,
|
|
72276
72325
|
runtimeLabel: args.localAdvisoryRunner.runtimeLabel
|
|
72277
|
-
})
|
|
72326
|
+
});
|
|
72327
|
+
let isHosted = args.localAdvisoryRunner.providerKind === "hosted", modelLabel = isHosted ? "Hosted Gemma" : "Local Gemma", trustLine = isHosted ? "No code was changed." : "No hosted model was called and no code was changed.";
|
|
72328
|
+
if (brainstormPromptRequestsCommandGuidance(userPrompt) && failureReason.includes("command-like JSON keys")) {
|
|
72278
72329
|
store.dispatch({
|
|
72279
72330
|
type: "SHELL_ADVISORY",
|
|
72280
72331
|
source: "shell",
|
|
72281
|
-
text:
|
|
72332
|
+
text: `I can brainstorm approaches, but I cannot include shell commands in read-only brainstorm mode. Ask me to implement the recommended option when you are ready, or ask for a command-free design/checklist. ${trustLine}`
|
|
72282
72333
|
});
|
|
72283
72334
|
return;
|
|
72284
72335
|
}
|
|
72285
72336
|
store.dispatch({
|
|
72286
72337
|
type: "SHELL_ADVISORY",
|
|
72287
72338
|
source: "shell",
|
|
72288
|
-
text:
|
|
72339
|
+
text: `${modelLabel} could not produce the brainstorm. Reason: ${failureReason}. ${trustLine} Try again with a narrower question or run \`codevibe model health-check\` to verify the model.`
|
|
72289
72340
|
});
|
|
72290
72341
|
}
|
|
72291
72342
|
} finally {
|
|
@@ -72311,10 +72362,19 @@ async function routeAdvisory(deps) {
|
|
|
72311
72362
|
});
|
|
72312
72363
|
return;
|
|
72313
72364
|
}
|
|
72365
|
+
let isHostedAdvisory = args.localAdvisoryRunner.providerKind === "hosted";
|
|
72366
|
+
if (hasImages && isHostedAdvisory) {
|
|
72367
|
+
store.dispatch({
|
|
72368
|
+
type: "SHELL_ADVISORY",
|
|
72369
|
+
source: "shell",
|
|
72370
|
+
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."
|
|
72371
|
+
});
|
|
72372
|
+
return;
|
|
72373
|
+
}
|
|
72314
72374
|
store.dispatch({
|
|
72315
72375
|
type: "SHELL_ADVISORY",
|
|
72316
72376
|
source: "shell",
|
|
72317
|
-
text: hasImages ? "Analyzing the attached image(s) with local Gemma\u2026" : "Answering with local Gemma\u2026"
|
|
72377
|
+
text: hasImages ? "Analyzing the attached image(s) with local Gemma\u2026" : isHostedAdvisory ? "Answering with hosted Gemma\u2026" : "Answering with local Gemma\u2026"
|
|
72318
72378
|
});
|
|
72319
72379
|
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 = "";
|
|
72320
72380
|
try {
|
|
@@ -72448,21 +72508,21 @@ async function routeAdvisory(deps) {
|
|
|
72448
72508
|
});
|
|
72449
72509
|
return;
|
|
72450
72510
|
}
|
|
72451
|
-
let fallback = deps.fallbackSummary?.trim();
|
|
72511
|
+
let fallback = deps.fallbackSummary?.trim(), effectiveIsHosted = args.localAdvisoryRunner.providerKind === "hosted", modelNoun = effectiveIsHosted ? "The model" : "The local model", 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";
|
|
72452
72512
|
if (fallback) {
|
|
72453
72513
|
store.dispatch({
|
|
72454
72514
|
type: "SHELL_ADVISORY",
|
|
72455
72515
|
source: "shell",
|
|
72456
72516
|
text: sanitizeForTerminal(`${fallback}
|
|
72457
72517
|
|
|
72458
|
-
(Note: detailed
|
|
72518
|
+
(Note: detailed ${generationScope} generation returned an empty answer; showing concise answer.)`)
|
|
72459
72519
|
});
|
|
72460
72520
|
return;
|
|
72461
72521
|
}
|
|
72462
72522
|
store.dispatch({
|
|
72463
72523
|
type: "SHELL_ADVISORY",
|
|
72464
72524
|
source: "shell",
|
|
72465
|
-
text: hasImages ?
|
|
72525
|
+
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}`
|
|
72466
72526
|
});
|
|
72467
72527
|
} catch (err) {
|
|
72468
72528
|
logger.warn("[orchestration-shell] local advisory failed", {
|
|
@@ -72470,7 +72530,7 @@ async function routeAdvisory(deps) {
|
|
|
72470
72530
|
hasImages,
|
|
72471
72531
|
runtimeLabel: args.localAdvisoryRunner.runtimeLabel
|
|
72472
72532
|
});
|
|
72473
|
-
let fallback = deps.fallbackSummary?.trim();
|
|
72533
|
+
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";
|
|
72474
72534
|
if (fallback) {
|
|
72475
72535
|
let reason = renderLocalBrainstormFailureReason(err);
|
|
72476
72536
|
store.dispatch({
|
|
@@ -72478,14 +72538,14 @@ async function routeAdvisory(deps) {
|
|
|
72478
72538
|
source: "shell",
|
|
72479
72539
|
text: sanitizeForTerminal(`${fallback}
|
|
72480
72540
|
|
|
72481
|
-
(Note: detailed
|
|
72541
|
+
(Note: detailed ${generationScope} generation was unavailable: ${reason}. Showing concise answer.)`)
|
|
72482
72542
|
});
|
|
72483
72543
|
return;
|
|
72484
72544
|
}
|
|
72485
72545
|
store.dispatch({
|
|
72486
72546
|
type: "SHELL_ADVISORY",
|
|
72487
72547
|
source: "shell",
|
|
72488
|
-
text: hasImages ?
|
|
72548
|
+
text: hasImages ? `${modelLabel} could not analyze the attached image(s). Reason: ${renderLocalBrainstormFailureReason(err)}. ${trustLine}` : `${modelLabel} could not answer. Reason: ${renderLocalBrainstormFailureReason(err)}. ${trustLine}`
|
|
72489
72549
|
});
|
|
72490
72550
|
}
|
|
72491
72551
|
}
|
|
@@ -75731,6 +75791,109 @@ Local planner error. Falling back to hosted Gemma planner on AWS.
|
|
|
75731
75791
|
}
|
|
75732
75792
|
};
|
|
75733
75793
|
|
|
75794
|
+
// src/planner/hosted-advisory.ts
|
|
75795
|
+
init_logger2();
|
|
75796
|
+
var HostedGemmaAdvisoryRunner = class {
|
|
75797
|
+
constructor(deps) {
|
|
75798
|
+
this.deps = deps;
|
|
75799
|
+
this.runtimeLabel = "Hosted Gemma (AWS Bedrock)";
|
|
75800
|
+
this.providerKind = "hosted";
|
|
75801
|
+
}
|
|
75802
|
+
async generateAdvisory(promptText, options) {
|
|
75803
|
+
if (options?.images && options.images.length > 0)
|
|
75804
|
+
throw new Error(
|
|
75805
|
+
"HostedGemmaAdvisoryRunner: image attachments are not supported by hosted Bedrock Gemma. A local vision model is required."
|
|
75806
|
+
);
|
|
75807
|
+
let sessionId = this.deps.activeSessionIdHolder.value;
|
|
75808
|
+
if (!sessionId)
|
|
75809
|
+
throw new Error("Hosted Gemma advisory generation failed: no active session ID");
|
|
75810
|
+
let sessionKey = await this.deps.sessionKeyResolver.getSessionKey(sessionId);
|
|
75811
|
+
if (!sessionKey)
|
|
75812
|
+
throw new Error(`Hosted Gemma advisory generation failed: session key unresolved for session ${sessionId}`);
|
|
75813
|
+
let encryptedPrompt = this.deps.crypto.encryptString(promptText, sessionKey), maxTokens = options?.numPredict, temperature = options?.temperature, start = Date.now();
|
|
75814
|
+
try {
|
|
75815
|
+
let response = await this.deps.transport.generatePlannerAdvisory({
|
|
75816
|
+
sessionId,
|
|
75817
|
+
prompt: encryptedPrompt,
|
|
75818
|
+
...maxTokens !== void 0 ? { maxTokens } : {},
|
|
75819
|
+
...temperature !== void 0 ? { temperature } : {}
|
|
75820
|
+
});
|
|
75821
|
+
return this.deps.crypto.decryptString(response.advisoryText, sessionKey);
|
|
75822
|
+
} catch (err) {
|
|
75823
|
+
let elapsedMs = Date.now() - start;
|
|
75824
|
+
throw logger.warn("[hosted-advisory] generatePlannerAdvisory failed", {
|
|
75825
|
+
sessionId,
|
|
75826
|
+
elapsedMs,
|
|
75827
|
+
error: err?.message
|
|
75828
|
+
}), err;
|
|
75829
|
+
}
|
|
75830
|
+
}
|
|
75831
|
+
async warm() {
|
|
75832
|
+
return !0;
|
|
75833
|
+
}
|
|
75834
|
+
async unload() {
|
|
75835
|
+
return !0;
|
|
75836
|
+
}
|
|
75837
|
+
};
|
|
75838
|
+
|
|
75839
|
+
// src/planner/composite-advisory.ts
|
|
75840
|
+
init_logger2();
|
|
75841
|
+
var CompositeAdvisoryRunner = class {
|
|
75842
|
+
constructor(opts) {
|
|
75843
|
+
this.opts = opts;
|
|
75844
|
+
this.localHealthy = !!opts.localRunner;
|
|
75845
|
+
}
|
|
75846
|
+
get runtimeLabel() {
|
|
75847
|
+
return this.opts.tier === "FREE" || this.localHealthy ? this.opts.localRunner?.runtimeLabel ?? "Local Gemma" : this.opts.hostedRunner.runtimeLabel;
|
|
75848
|
+
}
|
|
75849
|
+
get providerKind() {
|
|
75850
|
+
return this.opts.tier === "FREE" || this.localHealthy ? "local" : "hosted";
|
|
75851
|
+
}
|
|
75852
|
+
async generateAdvisory(promptText, options) {
|
|
75853
|
+
if (this.opts.tier === "FREE") {
|
|
75854
|
+
if (!this.opts.localRunner)
|
|
75855
|
+
throw new Error(
|
|
75856
|
+
"LocalModelUnavailable: local Gemma is not installed or enabled. Free tier operates in local-only mode."
|
|
75857
|
+
);
|
|
75858
|
+
return this.opts.localRunner.generateAdvisory(promptText, options);
|
|
75859
|
+
}
|
|
75860
|
+
if (options?.images && options.images.length > 0) {
|
|
75861
|
+
if (!this.localHealthy || !this.opts.localRunner)
|
|
75862
|
+
throw new Error(
|
|
75863
|
+
"LocalModelUnavailable: local CodeVibe vision model is required to analyze attached images."
|
|
75864
|
+
);
|
|
75865
|
+
return this.opts.localRunner.generateAdvisory(promptText, options);
|
|
75866
|
+
}
|
|
75867
|
+
if (this.localHealthy && this.opts.localRunner)
|
|
75868
|
+
try {
|
|
75869
|
+
return await this.opts.localRunner.generateAdvisory(promptText, options);
|
|
75870
|
+
} catch (err) {
|
|
75871
|
+
logger.warn("[composite-advisory] local advisory failed; falling back to hosted Bedrock Gemma", {
|
|
75872
|
+
error: err?.message
|
|
75873
|
+
}), this.localHealthy = !1, this.opts.onFallbackToHosted?.(err);
|
|
75874
|
+
}
|
|
75875
|
+
return this.opts.hostedRunner.generateAdvisory(promptText, options);
|
|
75876
|
+
}
|
|
75877
|
+
async warm() {
|
|
75878
|
+
if (this.opts.localRunner?.warm)
|
|
75879
|
+
try {
|
|
75880
|
+
return await this.opts.localRunner.warm();
|
|
75881
|
+
} catch {
|
|
75882
|
+
return !1;
|
|
75883
|
+
}
|
|
75884
|
+
return !0;
|
|
75885
|
+
}
|
|
75886
|
+
async unload() {
|
|
75887
|
+
if (this.opts.localRunner?.unload)
|
|
75888
|
+
try {
|
|
75889
|
+
return await this.opts.localRunner.unload();
|
|
75890
|
+
} catch {
|
|
75891
|
+
return !1;
|
|
75892
|
+
}
|
|
75893
|
+
return !0;
|
|
75894
|
+
}
|
|
75895
|
+
};
|
|
75896
|
+
|
|
75734
75897
|
// src/session/session-rekey.ts
|
|
75735
75898
|
init_logger2();
|
|
75736
75899
|
|
|
@@ -81250,7 +81413,8 @@ ${err.message}
|
|
|
81250
81413
|
function buildProductionPlannerStack(appsyncClient, emitter) {
|
|
81251
81414
|
let transport = {
|
|
81252
81415
|
classifyPlannerPrompt: (input) => appsyncClient.classifyPlannerPrompt(input),
|
|
81253
|
-
pingPlanner: (input) => appsyncClient.pingPlanner(input)
|
|
81416
|
+
pingPlanner: (input) => appsyncClient.pingPlanner(input),
|
|
81417
|
+
generatePlannerAdvisory: (input) => appsyncClient.generatePlannerAdvisory(input)
|
|
81254
81418
|
}, cache = new PlannerCacheLayer(), adaptedEmitter = async (e) => {
|
|
81255
81419
|
await emitter({
|
|
81256
81420
|
sessionId: e.sessionId,
|
|
@@ -81291,9 +81455,18 @@ function buildProductionPlannerStack(appsyncClient, emitter) {
|
|
|
81291
81455
|
sessionKeyResolver,
|
|
81292
81456
|
adaptedEmitter
|
|
81293
81457
|
), realSetActiveSession = adapter.setActiveSession.bind(adapter);
|
|
81294
|
-
|
|
81458
|
+
adapter.setActiveSession = (sessionId) => {
|
|
81295
81459
|
activeSessionIdHolder.value = sessionId, realSetActiveSession(sessionId);
|
|
81296
|
-
}
|
|
81460
|
+
};
|
|
81461
|
+
let hostedAdvisoryRunner = new HostedGemmaAdvisoryRunner({
|
|
81462
|
+
transport: {
|
|
81463
|
+
generatePlannerAdvisory: (input) => appsyncClient.generatePlannerAdvisory(input)
|
|
81464
|
+
},
|
|
81465
|
+
crypto: crypto33,
|
|
81466
|
+
sessionKeyResolver,
|
|
81467
|
+
activeSessionIdHolder
|
|
81468
|
+
});
|
|
81469
|
+
return { adapter, cache, health, hostedAdvisoryRunner };
|
|
81297
81470
|
}
|
|
81298
81471
|
function resolvePlannerAdapter(args) {
|
|
81299
81472
|
let env = args.env ?? process.env, forceHosted = env.CODEVIBE_FORCE_HOSTED_PLANNER === "1" || env.CODEVIBE_PLANNER_PROVIDER === "hosted", tier = args.tier, isPaidTier = tier === "PRO" || tier === "MAX";
|
|
@@ -81304,7 +81477,7 @@ function resolvePlannerAdapter(args) {
|
|
|
81304
81477
|
adapter: hostedStack.adapter,
|
|
81305
81478
|
runtimeKind: "hosted",
|
|
81306
81479
|
runtimeLabel: "Hosted Gemma (AWS Bedrock)",
|
|
81307
|
-
advisoryRunner:
|
|
81480
|
+
advisoryRunner: hostedStack.hostedAdvisoryRunner,
|
|
81308
81481
|
classifyRunner: args.localPlanner.classifyRunner,
|
|
81309
81482
|
cache: hostedStack.cache,
|
|
81310
81483
|
health: hostedStack.health,
|
|
@@ -81336,6 +81509,10 @@ function resolvePlannerAdapter(args) {
|
|
|
81336
81509
|
onNotice: (msg) => {
|
|
81337
81510
|
process.stdout.write(msg);
|
|
81338
81511
|
}
|
|
81512
|
+
}), compositeAdvisoryRunner = new CompositeAdvisoryRunner({
|
|
81513
|
+
localRunner: args.localPlanner.advisoryRunner,
|
|
81514
|
+
hostedRunner: hostedStack.hostedAdvisoryRunner,
|
|
81515
|
+
tier
|
|
81339
81516
|
});
|
|
81340
81517
|
return {
|
|
81341
81518
|
adapter: compositeAdapter,
|
|
@@ -81345,7 +81522,7 @@ function resolvePlannerAdapter(args) {
|
|
|
81345
81522
|
get runtimeLabel() {
|
|
81346
81523
|
return compositeAdapter.runtimeLabel;
|
|
81347
81524
|
},
|
|
81348
|
-
advisoryRunner:
|
|
81525
|
+
advisoryRunner: compositeAdvisoryRunner,
|
|
81349
81526
|
classifyRunner: args.localPlanner.classifyRunner,
|
|
81350
81527
|
cache: hostedStack.cache,
|
|
81351
81528
|
health: hostedStack.health,
|
|
@@ -81378,7 +81555,7 @@ function resolvePlannerAdapter(args) {
|
|
|
81378
81555
|
adapter: hostedStack.adapter,
|
|
81379
81556
|
runtimeKind: "hosted",
|
|
81380
81557
|
runtimeLabel: "Hosted Gemma (AWS Bedrock)",
|
|
81381
|
-
advisoryRunner:
|
|
81558
|
+
advisoryRunner: hostedStack.hostedAdvisoryRunner,
|
|
81382
81559
|
classifyRunner: args.localPlanner.classifyRunner,
|
|
81383
81560
|
cache: hostedStack.cache,
|
|
81384
81561
|
health: hostedStack.health,
|
package/dist/planner/client.d.ts
CHANGED
|
@@ -26,6 +26,16 @@ export interface PlannerAppSyncTransport {
|
|
|
26
26
|
ok: boolean;
|
|
27
27
|
ms: number;
|
|
28
28
|
}>;
|
|
29
|
+
generatePlannerAdvisory?(input: {
|
|
30
|
+
sessionId: string;
|
|
31
|
+
prompt: string;
|
|
32
|
+
maxTokens?: number;
|
|
33
|
+
temperature?: number;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
advisoryText: string;
|
|
36
|
+
serverLatencyMs: number;
|
|
37
|
+
providerUsed: string;
|
|
38
|
+
}>;
|
|
29
39
|
}
|
|
30
40
|
/**
|
|
31
41
|
* Crypto bridge — `encryptString` + `encryptJson` + `decryptJson`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Tier } from '../orchestration-shell/types';
|
|
2
|
+
import type { AdvisoryOptions, AdvisoryRunner } from './local-advisory';
|
|
3
|
+
export interface CompositeAdvisoryRunnerOptions {
|
|
4
|
+
localRunner?: AdvisoryRunner | null;
|
|
5
|
+
hostedRunner: AdvisoryRunner;
|
|
6
|
+
tier: Tier;
|
|
7
|
+
onFallbackToHosted?: (error: Error) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* CompositeAdvisoryRunner coordinates local and hosted advisory execution:
|
|
11
|
+
* - Free Tier Invariant: strictly isolates Free tier from cloud inference ($0 marginal cost).
|
|
12
|
+
* - Local-First Preference: routes natural language turns / browse to local Gemma when healthy.
|
|
13
|
+
* - Dynamic Failover: if local Gemma fails (Ollama down, crash, OOM), seamlessly falls back
|
|
14
|
+
* to hosted Bedrock Gemma for Pro/Max users without interrupting the session.
|
|
15
|
+
*/
|
|
16
|
+
export declare class CompositeAdvisoryRunner implements AdvisoryRunner {
|
|
17
|
+
private readonly opts;
|
|
18
|
+
private localHealthy;
|
|
19
|
+
constructor(opts: CompositeAdvisoryRunnerOptions);
|
|
20
|
+
get runtimeLabel(): string;
|
|
21
|
+
get providerKind(): 'local' | 'hosted';
|
|
22
|
+
generateAdvisory(promptText: string, options?: AdvisoryOptions): Promise<string>;
|
|
23
|
+
warm(): Promise<boolean>;
|
|
24
|
+
unload(): Promise<boolean>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AdvisoryOptions, AdvisoryRunner } from './local-advisory';
|
|
2
|
+
import type { PlannerCryptoBridge, SessionKeyResolver } from './client';
|
|
3
|
+
export interface HostedAdvisoryTransport {
|
|
4
|
+
generatePlannerAdvisory(input: {
|
|
5
|
+
sessionId: string;
|
|
6
|
+
prompt: string;
|
|
7
|
+
maxTokens?: number;
|
|
8
|
+
temperature?: number;
|
|
9
|
+
}): Promise<{
|
|
10
|
+
advisoryText: string;
|
|
11
|
+
serverLatencyMs: number;
|
|
12
|
+
providerUsed: string;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
export interface HostedGemmaAdvisoryRunnerDeps {
|
|
16
|
+
transport: HostedAdvisoryTransport;
|
|
17
|
+
crypto: PlannerCryptoBridge;
|
|
18
|
+
sessionKeyResolver: SessionKeyResolver;
|
|
19
|
+
activeSessionIdHolder: {
|
|
20
|
+
value: string | null;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* HostedGemmaAdvisoryRunner executes advisory text generation (browse synthesis,
|
|
25
|
+
* brainstorm, etc.) against Google Gemma 3 12B on AWS Bedrock via AppSync planner proxy.
|
|
26
|
+
*
|
|
27
|
+
* Wire payload is encrypted end-to-end with AES-256-GCM under the session key.
|
|
28
|
+
*/
|
|
29
|
+
export declare class HostedGemmaAdvisoryRunner implements AdvisoryRunner {
|
|
30
|
+
private readonly deps;
|
|
31
|
+
readonly runtimeLabel = "Hosted Gemma (AWS Bedrock)";
|
|
32
|
+
readonly providerKind: "hosted";
|
|
33
|
+
constructor(deps: HostedGemmaAdvisoryRunnerDeps);
|
|
34
|
+
generateAdvisory(promptText: string, options?: AdvisoryOptions): Promise<string>;
|
|
35
|
+
warm(): Promise<boolean>;
|
|
36
|
+
unload(): Promise<boolean>;
|
|
37
|
+
}
|
package/dist/planner/index.d.ts
CHANGED
|
@@ -4,5 +4,7 @@ export { PlannerCacheLayer } from './cache';
|
|
|
4
4
|
export { PlannerHealthMachine } from './health-state';
|
|
5
5
|
export { BackendPlannerClient, PlannerBudgetExceededError, PlannerTierGateRejectedError, type PlannerAppSyncTransport, type PlannerCryptoBridge, type SessionKeyResolver, type ShellEventEmit, type EmitShellEventFn, } from './client';
|
|
6
6
|
export { LocalGemmaPlannerAdapter, parseLocalGemmaPlannerDecision, PlannerOutputUnparseableError, renderLocalGemmaPlannerPrompt, type LocalGemmaPlannerRunner, } from './local-gemma';
|
|
7
|
-
export { parseLocalGemmaAdvisorySummary, renderLocalGemmaFamiliarizePrompt, renderLocalGemmaMultiBrowsePrompt, renderLocalGemmaBrowsePrompt, MAX_BROWSE_CONTENT_CHARS, MAX_MULTI_BROWSE_TOTAL_CONTENT_CHARS, MAX_MULTI_BROWSE_RENDERED_PROMPT_CHARS, type LocalGemmaAdvisoryRunner, } from './local-advisory';
|
|
7
|
+
export { parseLocalGemmaAdvisorySummary, renderLocalGemmaFamiliarizePrompt, renderLocalGemmaMultiBrowsePrompt, renderLocalGemmaBrowsePrompt, MAX_BROWSE_CONTENT_CHARS, MAX_MULTI_BROWSE_TOTAL_CONTENT_CHARS, MAX_MULTI_BROWSE_RENDERED_PROMPT_CHARS, type AdvisoryRunner, type AdvisoryOptions, type AdvisoryResponseFormat, type LocalGemmaAdvisoryRunner, type LocalGemmaAdvisoryOptions, type LocalGemmaAdvisoryResponseFormat, } from './local-advisory';
|
|
8
8
|
export { CompositePlannerAdapter, type CompositePlannerAdapterOptions, } from './composite-adapter';
|
|
9
|
+
export { HostedGemmaAdvisoryRunner, type HostedGemmaAdvisoryRunnerDeps, type HostedAdvisoryTransport, } from './hosted-advisory';
|
|
10
|
+
export { CompositeAdvisoryRunner, type CompositeAdvisoryRunnerOptions, } from './composite-advisory';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StructuralSummary } from '../structural-summary/types';
|
|
2
|
-
export interface
|
|
3
|
-
generateAdvisory(promptText: string, options?:
|
|
2
|
+
export interface AdvisoryRunner {
|
|
3
|
+
generateAdvisory(promptText: string, options?: AdvisoryOptions): Promise<string>;
|
|
4
4
|
/**
|
|
5
5
|
* Dogfood #618 — optional fire-and-forget model pre-warm (load + keep_alive).
|
|
6
6
|
* Never throws; resolves false on failure. Called once at shell startup.
|
|
@@ -13,10 +13,11 @@ export interface LocalGemmaAdvisoryRunner {
|
|
|
13
13
|
*/
|
|
14
14
|
unload?(): Promise<boolean>;
|
|
15
15
|
runtimeLabel: string;
|
|
16
|
+
readonly providerKind?: 'local' | 'hosted';
|
|
16
17
|
}
|
|
17
|
-
export type
|
|
18
|
-
export interface
|
|
19
|
-
responseFormat?:
|
|
18
|
+
export type AdvisoryResponseFormat = 'json' | 'text';
|
|
19
|
+
export interface AdvisoryOptions {
|
|
20
|
+
responseFormat?: AdvisoryResponseFormat;
|
|
20
21
|
numPredict?: number;
|
|
21
22
|
/**
|
|
22
23
|
* RAW base64 images (NO `data:` prefix) for the MULTIMODAL local answerer
|
|
@@ -38,7 +39,15 @@ export interface LocalGemmaAdvisoryOptions {
|
|
|
38
39
|
* Omitted unless set; browse callers pass false (R8-F2, R9-F4).
|
|
39
40
|
*/
|
|
40
41
|
think?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Temperature hint for advisory generation.
|
|
44
|
+
*/
|
|
45
|
+
temperature?: number;
|
|
41
46
|
}
|
|
47
|
+
/** Backward-compatibility aliases for local runner consumers */
|
|
48
|
+
export type LocalGemmaAdvisoryRunner = AdvisoryRunner;
|
|
49
|
+
export type LocalGemmaAdvisoryResponseFormat = AdvisoryResponseFormat;
|
|
50
|
+
export type LocalGemmaAdvisoryOptions = AdvisoryOptions;
|
|
42
51
|
export declare const MAX_RENDERED_PROMPT_CHARS = 30000;
|
|
43
52
|
export declare const MAX_RENDERED_PROMPT_TOKENS = 7500;
|
|
44
53
|
export declare function redactAbsoluteLocalPaths(text: string): string;
|
package/package.json
CHANGED