@quantiya/codevibe-claude-plugin 2.0.73 → 2.0.75
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/.claude-plugin/plugin.json +1 -1
- package/dist/server.js +18 -18
- package/node_modules/@quantiya/codevibe-core/dist/appsync/appsync-client.d.ts +62 -24
- package/node_modules/@quantiya/codevibe-core/dist/appsync/queries.d.ts +8 -12
- package/node_modules/@quantiya/codevibe-core/dist/appsync/sync-event-client.d.ts +3 -3
- package/node_modules/@quantiya/codevibe-core/dist/appsync/sync-inbound-journal.d.ts +2 -0
- package/node_modules/@quantiya/codevibe-core/dist/appsync/sync-live-connection.d.ts +6 -1
- package/node_modules/@quantiya/codevibe-core/dist/appsync/sync-operation-journal.d.ts +5 -0
- package/node_modules/@quantiya/codevibe-core/dist/appsync/sync-workspace-outcome.d.ts +5 -3
- package/node_modules/@quantiya/codevibe-core/dist/index.d.ts +1 -1
- package/node_modules/@quantiya/codevibe-core/dist/index.js +594 -595
- package/node_modules/@quantiya/codevibe-core/dist/local-model/ollama-gemma-runner.d.ts +18 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-model/ollama.d.ts +26 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/attachments.d.ts +8 -14
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.d.ts +50 -64
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +2787 -2797
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/components/OrchestrationApp.d.ts +3 -1
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/decision-attempt-recovery.d.ts +2 -2
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/gate-decision-submit.d.ts +2 -2
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/git-status-summary.d.ts +5 -10
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/index.d.ts +29 -46
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/route-browse.d.ts +4 -4
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/runtime-labels.d.ts +63 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/task-progress-relay.d.ts +9 -1
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/task-progress.d.ts +7 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/cache.d.ts +7 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/gemma-errors.d.ts +61 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/gemma-pipeline.d.ts +219 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/gemma-runner.d.ts +66 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/hosted-gemma-runner.d.ts +83 -0
- package/node_modules/@quantiya/codevibe-core/dist/planner/index.d.ts +5 -3
- package/node_modules/@quantiya/codevibe-core/dist/planner/local-advisory.d.ts +3 -6
- package/node_modules/@quantiya/codevibe-core/dist/planner/local-gemma.d.ts +82 -21
- package/node_modules/@quantiya/codevibe-core/dist/planner/types.d.ts +4 -4
- package/node_modules/@quantiya/codevibe-core/dist/reviewer/verdict-classifier.d.ts +18 -5
- package/node_modules/@quantiya/codevibe-core/dist/tool-activity/consolidator.d.ts +5 -1
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/package.json +2 -2
- package/node_modules/@quantiya/codevibe-core/dist/planner/composite-adapter.d.ts +0 -39
- package/node_modules/@quantiya/codevibe-core/dist/planner/composite-advisory.d.ts +0 -26
- package/node_modules/@quantiya/codevibe-core/dist/planner/hosted-advisory.d.ts +0 -40
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { GemmaCallError, GemmaEmptyOutputError, type GemmaRuntime } from './gemma-errors';
|
|
2
|
+
import { type GemmaRunner, type ImageFormat, type RunnerImage, type RunnerImageCapability } from './gemma-runner';
|
|
3
|
+
/** §3.3 — every rendered prompt, both runtimes, before any runner call (= the server caps). */
|
|
4
|
+
export declare const GEMMA_PROMPT_BYTE_BOUND = 100000;
|
|
5
|
+
/** §3.3 — output budgets are capped at the hosted server ceiling on both runtimes. */
|
|
6
|
+
export declare const GEMMA_MAX_OUTPUT_TOKENS = 1536;
|
|
7
|
+
/**
|
|
8
|
+
* §3.3 / §4 — a classify call's budget is capped at the rendered-classify contract's ceiling
|
|
9
|
+
* (`maxOutputTokens: Int! # 1..1024`), on both runtimes, so no caller can send hosted a request
|
|
10
|
+
* the server refuses while local accepts it (Stage 1 R1-F7).
|
|
11
|
+
*/
|
|
12
|
+
export declare const GEMMA_CLASSIFY_MAX_OUTPUT_TOKENS = 1024;
|
|
13
|
+
/** Marker appended to a text answer that ended early (moved here from `ollama.ts`, §3.3). */
|
|
14
|
+
export declare const PIPELINE_CUT_OFF_MARKER = " [\u2026]";
|
|
15
|
+
/** Composite recovery probe interval (unchanged from the composite adapter). */
|
|
16
|
+
export declare const RECOVERY_PROBE_INTERVAL_MS = 30000;
|
|
17
|
+
/**
|
|
18
|
+
* The runtimes attempted by ONE admitted natural-language turn. Each turn owns its scope;
|
|
19
|
+
* nothing can reset or replace another turn's record. Implemented with AsyncLocalStorage:
|
|
20
|
+
* every pipeline call made inside the turn's async context records into it, including the
|
|
21
|
+
* classify (the adapter never handles runtime facts) — and a slash command, which runs
|
|
22
|
+
* outside that context (it bypasses the submission queue), never touches it.
|
|
23
|
+
*
|
|
24
|
+
* Inheritance (Stage 1 N7): AsyncLocalStorage follows every async continuation, timers and
|
|
25
|
+
* un-awaited promises included, so background work a turn STARTS inherits its scope. Every
|
|
26
|
+
* pipeline call the shell makes for a turn is awaited inside it (classify, the answer, the
|
|
27
|
+
* brainstorm, the browse readers, the git-status intent). The one background caller — the
|
|
28
|
+
* verdict classifier, running inside a task the turn started — opts out with
|
|
29
|
+
* {@link GemmaCallPipeline.runOutsideTurn}; a new background entry point must do the same.
|
|
30
|
+
*/
|
|
31
|
+
export declare class TurnScope {
|
|
32
|
+
private readonly attempted;
|
|
33
|
+
/** Recorded when an attempt STARTS, before dispatch, so a pending hosted call counts. */
|
|
34
|
+
record(runtime: GemmaRuntime): void;
|
|
35
|
+
attemptedRuntimes(): GemmaRuntime[];
|
|
36
|
+
}
|
|
37
|
+
export interface RunnerSource {
|
|
38
|
+
current(): GemmaRunner;
|
|
39
|
+
/**
|
|
40
|
+
* True when a transport failure of `failed` (the runner THIS attempt used) can be retried
|
|
41
|
+
* on another runner. Decided by the failed runner, never by the source's current state:
|
|
42
|
+
* one source serves every concurrent call, so another call or the recovery probe may have
|
|
43
|
+
* moved it meanwhile (§3.2: failover is local → hosted only; §3.4: never hosted → local).
|
|
44
|
+
*/
|
|
45
|
+
canFailOver(failed: GemmaRunner): boolean;
|
|
46
|
+
/** Switch to the fallback runner (a no-op switch when already there) and return it. */
|
|
47
|
+
failOver(failed: GemmaRunner, reason: GemmaCallError): GemmaRunner;
|
|
48
|
+
onSourceChange(listener: (runtime: GemmaRuntime) => void): () => void;
|
|
49
|
+
runners(): GemmaRunner[];
|
|
50
|
+
dispose(): void;
|
|
51
|
+
/** Sources that switch runtimes post a notice per switch (§3.4). */
|
|
52
|
+
bindNotice?(sink: (text: string) => void): void;
|
|
53
|
+
}
|
|
54
|
+
export declare class SingleRunnerSource implements RunnerSource {
|
|
55
|
+
private readonly runner;
|
|
56
|
+
constructor(runner: GemmaRunner);
|
|
57
|
+
current(): GemmaRunner;
|
|
58
|
+
canFailOver(_failed: GemmaRunner): boolean;
|
|
59
|
+
failOver(_failed: GemmaRunner, _reason: GemmaCallError): GemmaRunner;
|
|
60
|
+
onSourceChange(): () => void;
|
|
61
|
+
runners(): GemmaRunner[];
|
|
62
|
+
dispose(): void;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Pro/Max with a local model: local first, hosted on a TRANSPORT failure, back to local when
|
|
66
|
+
* the 30 s probe succeeds. One instance per session serves classify, advisory, git-status and
|
|
67
|
+
* the verdict classifier, so every consumer sees the same runtime at the same moment.
|
|
68
|
+
*/
|
|
69
|
+
export declare class CompositeRunnerSource implements RunnerSource {
|
|
70
|
+
private readonly local;
|
|
71
|
+
private readonly hosted;
|
|
72
|
+
private readonly notice;
|
|
73
|
+
private readonly probeIntervalMs;
|
|
74
|
+
private source;
|
|
75
|
+
private probeTimer;
|
|
76
|
+
private probing;
|
|
77
|
+
private readonly listeners;
|
|
78
|
+
private disposed;
|
|
79
|
+
private boundNotice;
|
|
80
|
+
constructor(local: GemmaRunner, hosted: GemmaRunner, notice?: (text: string) => void, probeIntervalMs?: number);
|
|
81
|
+
/** The pipeline binds its notice sink here, so the shell's advisory line gets the switch notices. */
|
|
82
|
+
bindNotice(sink: (text: string) => void): void;
|
|
83
|
+
private say;
|
|
84
|
+
current(): GemmaRunner;
|
|
85
|
+
canFailOver(failed: GemmaRunner): boolean;
|
|
86
|
+
failOver(_failed: GemmaRunner, reason: GemmaCallError): GemmaRunner;
|
|
87
|
+
onSourceChange(listener: (runtime: GemmaRuntime) => void): () => void;
|
|
88
|
+
runners(): GemmaRunner[];
|
|
89
|
+
dispose(): void;
|
|
90
|
+
private emit;
|
|
91
|
+
private startProbe;
|
|
92
|
+
/** Test seam + timer body. */
|
|
93
|
+
tick(): Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
export interface PipelineImage {
|
|
96
|
+
/** Position in the user's attachment order (stable across attempts). */
|
|
97
|
+
index: number;
|
|
98
|
+
/** Reads the bytes (fd-safe in the shell). May throw: the image is then "unreadable". */
|
|
99
|
+
read(): {
|
|
100
|
+
buf: Buffer;
|
|
101
|
+
mime: string;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export type OmittedReason = 'over-limit' | 'format' | 'unreadable';
|
|
105
|
+
export interface OmittedImage {
|
|
106
|
+
index: number;
|
|
107
|
+
reason: OmittedReason;
|
|
108
|
+
/** For a `format` omission of a known format (the note names it, e.g. WEBP on local). */
|
|
109
|
+
format?: ImageFormat;
|
|
110
|
+
}
|
|
111
|
+
export interface LoadedImage {
|
|
112
|
+
index: number;
|
|
113
|
+
image?: RunnerImage;
|
|
114
|
+
unreadable?: boolean;
|
|
115
|
+
/** The bytes are not one of the five image formats any runtime reads. */
|
|
116
|
+
unknownFormat?: boolean;
|
|
117
|
+
}
|
|
118
|
+
/** First-N-under-cap in attachment order (today's local rule, `attachments.ts:953-976`), per capability. */
|
|
119
|
+
export declare function selectImagesForCapability(loaded: LoadedImage[], cap: RunnerImageCapability): {
|
|
120
|
+
selected: Array<{
|
|
121
|
+
index: number;
|
|
122
|
+
image: RunnerImage;
|
|
123
|
+
}>;
|
|
124
|
+
omitted: OmittedImage[];
|
|
125
|
+
};
|
|
126
|
+
/** Read each image once per call; selection is redone per attempt from these (§3.7). */
|
|
127
|
+
export declare function loadPipelineImages(images: PipelineImage[]): LoadedImage[];
|
|
128
|
+
export interface PipelineResult {
|
|
129
|
+
text: string;
|
|
130
|
+
finishReason: 'stop' | 'length';
|
|
131
|
+
runtime: GemmaRuntime;
|
|
132
|
+
attemptedRuntimes: GemmaRuntime[];
|
|
133
|
+
images: {
|
|
134
|
+
included: number[];
|
|
135
|
+
omitted: OmittedImage[];
|
|
136
|
+
};
|
|
137
|
+
callId: number;
|
|
138
|
+
}
|
|
139
|
+
export interface PipelineClassifyRequest {
|
|
140
|
+
prompt: string;
|
|
141
|
+
/** Absent → JSON-object mode (the verdict classifier). */
|
|
142
|
+
jsonSchema?: object;
|
|
143
|
+
maxOutputTokens: number;
|
|
144
|
+
timeoutMs?: number;
|
|
145
|
+
signal?: AbortSignal;
|
|
146
|
+
}
|
|
147
|
+
export interface PipelineAdviseRequest {
|
|
148
|
+
/** Rendered per attempt, with the number of images that attempt includes (§3.7). */
|
|
149
|
+
buildPrompt: (ctx: {
|
|
150
|
+
includedImageCount: number;
|
|
151
|
+
}) => string;
|
|
152
|
+
images?: PipelineImage[];
|
|
153
|
+
responseFormat?: 'json' | 'text';
|
|
154
|
+
numPredict?: number;
|
|
155
|
+
timeoutMs?: number;
|
|
156
|
+
signal?: AbortSignal;
|
|
157
|
+
numCtx?: number;
|
|
158
|
+
think?: boolean;
|
|
159
|
+
}
|
|
160
|
+
/** The shape today's text-only callers use (`AdvisoryOptions`), minus runtime facts. */
|
|
161
|
+
export interface PipelineAdvisoryOptions {
|
|
162
|
+
responseFormat?: 'json' | 'text';
|
|
163
|
+
numPredict?: number;
|
|
164
|
+
timeoutMs?: number;
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
numCtx?: number;
|
|
167
|
+
think?: boolean;
|
|
168
|
+
/** Ignored (§3.3: temperature is always 0). */
|
|
169
|
+
temperature?: number;
|
|
170
|
+
/** Raw base64 images (legacy shape). Image callers should use `advise()` instead. */
|
|
171
|
+
images?: string[];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* A caller that rejects a returned answer as empty (after its own sanitization) reports it as the
|
|
175
|
+
* empty answer of the call that produced it: the error carries that call's attempted runtimes and
|
|
176
|
+
* image selection, so trust lines and notes stay truthful (§3.2). Runtime facts stay in the
|
|
177
|
+
* pipeline (core Stage 1 R1-F1).
|
|
178
|
+
*/
|
|
179
|
+
export declare function emptyOutputErrorFor(result: PipelineResult, message?: string): GemmaEmptyOutputError;
|
|
180
|
+
export declare class GemmaCallPipeline {
|
|
181
|
+
private readonly source;
|
|
182
|
+
private callSeq;
|
|
183
|
+
private readonly turnAttemptListeners;
|
|
184
|
+
private noticeSink;
|
|
185
|
+
constructor(source: RunnerSource);
|
|
186
|
+
/** The shell's advisory line for the source's switch notices (§3.4); null detaches it. */
|
|
187
|
+
setNoticeSink(sink: ((text: string) => void) | null): void;
|
|
188
|
+
notify(text: string): void;
|
|
189
|
+
currentRuntime(): GemmaRuntime;
|
|
190
|
+
onSourceChange(listener: (runtime: GemmaRuntime) => void): () => void;
|
|
191
|
+
/**
|
|
192
|
+
* Progress re-labelling (§3.5, Codex R2-F4): while subscribed, `listener` hears the runtime
|
|
193
|
+
* of every attempt that STARTS in the caller's turn (outside a turn: every attempt), so an
|
|
194
|
+
* active progress phase re-labels when a hosted retry starts. Calls outside the turn (the
|
|
195
|
+
* verdict classifier) never re-label a turn's phase.
|
|
196
|
+
*/
|
|
197
|
+
onTurnAttemptStart(listener: (runtime: GemmaRuntime) => void): () => void;
|
|
198
|
+
openTurn(): TurnScope;
|
|
199
|
+
runInTurn<T>(scope: TurnScope, fn: () => Promise<T>): Promise<T>;
|
|
200
|
+
/** Calls that are not part of the user's turn (the verdict classifier) never record into it. */
|
|
201
|
+
runOutsideTurn<T>(fn: () => Promise<T>): Promise<T>;
|
|
202
|
+
currentTurn(): TurnScope | undefined;
|
|
203
|
+
setActiveSession(sessionId: string | null): void;
|
|
204
|
+
warm(): Promise<boolean>;
|
|
205
|
+
unload(): Promise<boolean>;
|
|
206
|
+
dispose(): void;
|
|
207
|
+
/** Classify-mode call: the planner (via the adapter) and the verdict classifier. */
|
|
208
|
+
classify(req: PipelineClassifyRequest): Promise<PipelineResult>;
|
|
209
|
+
/** Advisory-mode call with per-attempt image selection and prompt rendering (§3.4, §3.7). */
|
|
210
|
+
advise(req: PipelineAdviseRequest): Promise<PipelineResult>;
|
|
211
|
+
/** Text-only callers' shape (browse readers, git-status intent). Returns the text. */
|
|
212
|
+
generateAdvisory(promptText: string, options?: PipelineAdvisoryOptions): Promise<string>;
|
|
213
|
+
private assertPromptBound;
|
|
214
|
+
/** §3.3 — the same rules on both runtimes. */
|
|
215
|
+
private postProcessAdvisory;
|
|
216
|
+
/** The attempt loop: failover on transport errors only, never after the caller aborted. */
|
|
217
|
+
private run;
|
|
218
|
+
private tag;
|
|
219
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { GemmaRuntime } from './gemma-errors';
|
|
2
|
+
export type ImageFormat = 'png' | 'jpeg' | 'gif' | 'bmp' | 'webp';
|
|
3
|
+
export interface RunnerImageCapability {
|
|
4
|
+
maxCount: number;
|
|
5
|
+
/** Sum of raw image bytes per call. */
|
|
6
|
+
maxTotalRawBytes: number;
|
|
7
|
+
maxImageRawBytes: number;
|
|
8
|
+
formats: readonly ImageFormat[];
|
|
9
|
+
/**
|
|
10
|
+
* Hosted only (§3.3): the exact serialized provider body must not exceed this, so a
|
|
11
|
+
* JSON-escaping-heavy prompt leaves room for fewer images.
|
|
12
|
+
*/
|
|
13
|
+
maxProviderBodyBytes?: number;
|
|
14
|
+
/** Hosted only: the AppSync/Lambda leg's total ciphertext ceiling (planner-proxy, unchanged). */
|
|
15
|
+
maxTotalCiphertextBytes?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface RunnerCapabilities {
|
|
18
|
+
images: RunnerImageCapability;
|
|
19
|
+
}
|
|
20
|
+
export interface RunnerResult {
|
|
21
|
+
text: string;
|
|
22
|
+
finishReason: 'stop' | 'length';
|
|
23
|
+
}
|
|
24
|
+
export interface RunnerClassifyOptions {
|
|
25
|
+
/** Absent → JSON-object mode (Ollama `format:"json"`, Mantle `json_object`). */
|
|
26
|
+
jsonSchema?: object;
|
|
27
|
+
maxOutputTokens: number;
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}
|
|
31
|
+
export interface RunnerImage {
|
|
32
|
+
/** Raw base64, no `data:` prefix. */
|
|
33
|
+
base64: string;
|
|
34
|
+
format: ImageFormat;
|
|
35
|
+
rawBytes: number;
|
|
36
|
+
}
|
|
37
|
+
export interface RunnerAdvisoryOptions {
|
|
38
|
+
responseFormat: 'json' | 'text';
|
|
39
|
+
maxOutputTokens: number;
|
|
40
|
+
/** Already selected for THIS runner by the pipeline (§3.7). */
|
|
41
|
+
images: RunnerImage[];
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
/** Ollama transport knobs (§3.3); hosted ignores them. */
|
|
45
|
+
numCtx?: number;
|
|
46
|
+
think?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface GemmaRunner {
|
|
49
|
+
readonly runtime: GemmaRuntime;
|
|
50
|
+
/** Display only: never read for behaviour. */
|
|
51
|
+
readonly label: string;
|
|
52
|
+
readonly capabilities: RunnerCapabilities;
|
|
53
|
+
classify(prompt: string, opts: RunnerClassifyOptions): Promise<RunnerResult>;
|
|
54
|
+
generateAdvisory(prompt: string, opts: RunnerAdvisoryOptions): Promise<RunnerResult>;
|
|
55
|
+
/** Liveness probe for the composite's recovery timer; never throws. */
|
|
56
|
+
probe(): Promise<boolean>;
|
|
57
|
+
/** Session binding (hosted needs the active session and its key; local ignores it). */
|
|
58
|
+
setActiveSession?(sessionId: string | null): void;
|
|
59
|
+
/** Fire-and-forget model pre-warm / release (local only); never throw. */
|
|
60
|
+
warm?(): Promise<boolean>;
|
|
61
|
+
unload?(): Promise<boolean>;
|
|
62
|
+
}
|
|
63
|
+
export declare const LOCAL_IMAGE_CAPABILITY: RunnerImageCapability;
|
|
64
|
+
export declare const HOSTED_IMAGE_CAPABILITY: RunnerImageCapability;
|
|
65
|
+
export declare function imageFormatFromMime(mime: string): ImageFormat | null;
|
|
66
|
+
export declare function mimeFromImageFormat(format: ImageFormat): string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { GemmaCallError } from './gemma-errors';
|
|
2
|
+
import { type GemmaRunner, type RunnerAdvisoryOptions, type RunnerCapabilities, type RunnerClassifyOptions, type RunnerImage, type RunnerResult } from './gemma-runner';
|
|
3
|
+
export interface HostedRenderedTransport {
|
|
4
|
+
classifyRenderedPlannerPrompt(input: {
|
|
5
|
+
sessionId: string;
|
|
6
|
+
encryptedPrompt: string;
|
|
7
|
+
responseSchema?: string;
|
|
8
|
+
maxOutputTokens: number;
|
|
9
|
+
}, signal?: AbortSignal): Promise<{
|
|
10
|
+
encryptedOutput: string;
|
|
11
|
+
finishReason: 'STOP' | 'LENGTH' | null;
|
|
12
|
+
}>;
|
|
13
|
+
generatePlannerAdvisoryRendered(input: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
prompt: string;
|
|
16
|
+
images?: string[];
|
|
17
|
+
maxTokens: number;
|
|
18
|
+
temperature: number;
|
|
19
|
+
responseFormat: 'TEXT' | 'JSON_OBJECT';
|
|
20
|
+
}, signal?: AbortSignal): Promise<{
|
|
21
|
+
advisoryText: string;
|
|
22
|
+
finishReason: 'STOP' | 'LENGTH' | null;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
export interface HostedRunnerCrypto {
|
|
26
|
+
encryptString(plaintext: string, sessionKeyB64: string): string;
|
|
27
|
+
decryptString(ciphertextB64: string, sessionKeyB64: string): string;
|
|
28
|
+
}
|
|
29
|
+
export interface HostedSessionKeyResolver {
|
|
30
|
+
getSessionKey(sessionId: string): Promise<string | null>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The model id the server's body uses (planner-proxy `DEFAULT_BEDROCK_MODEL_ID`). The client's
|
|
34
|
+
* 3,400,000 B body limit sits 100 KB under the server's 3,500,000 B check, which absorbs any
|
|
35
|
+
* difference in the model id the server is configured with.
|
|
36
|
+
*/
|
|
37
|
+
export declare const HOSTED_BODY_MODEL_ID = "google.gemma-4-26b-a4b";
|
|
38
|
+
/**
|
|
39
|
+
* Mirror of planner-proxy `renderedChatBody` + `invokeMantle` (§4.2): the exact JSON body the
|
|
40
|
+
* server sends for a client-rendered call, so the pipeline can select images against the
|
|
41
|
+
* provider-body limit BEFORE sending (§3.3, §3.4 step 5). Field order is part of the contract;
|
|
42
|
+
* a cross-repo golden fixture pins it on both sides.
|
|
43
|
+
*/
|
|
44
|
+
export declare function hostedRenderedBody(req: {
|
|
45
|
+
promptText: string;
|
|
46
|
+
images?: Array<{
|
|
47
|
+
mime: string;
|
|
48
|
+
base64: string;
|
|
49
|
+
}>;
|
|
50
|
+
maxOutputTokens: number;
|
|
51
|
+
temperature: number;
|
|
52
|
+
responseFormat?: unknown;
|
|
53
|
+
}): string;
|
|
54
|
+
export declare function hostedRenderedBodyBytes(req: Parameters<typeof hostedRenderedBody>[0]): number;
|
|
55
|
+
/** base64(AES-GCM(utf-8 plaintext)) length for a plaintext of `plaintextBytes` (nonce 12 + tag 16). */
|
|
56
|
+
export declare function sessionCiphertextLength(plaintextBytes: number): number;
|
|
57
|
+
/** Map any failure of a hosted call to the typed set (§3.2). Reads the server's verbatim message. */
|
|
58
|
+
export declare function toHostedGemmaError(err: unknown, signal?: AbortSignal): GemmaCallError;
|
|
59
|
+
export declare class HostedGemmaRunner implements GemmaRunner {
|
|
60
|
+
private readonly deps;
|
|
61
|
+
readonly runtime: "hosted";
|
|
62
|
+
readonly label = "Hosted Gemma (AWS Bedrock)";
|
|
63
|
+
readonly capabilities: RunnerCapabilities;
|
|
64
|
+
private activeSessionId;
|
|
65
|
+
constructor(deps: {
|
|
66
|
+
transport: HostedRenderedTransport;
|
|
67
|
+
crypto: HostedRunnerCrypto;
|
|
68
|
+
sessionKeyResolver: HostedSessionKeyResolver;
|
|
69
|
+
});
|
|
70
|
+
setActiveSession(sessionId: string | null): void;
|
|
71
|
+
private sessionAndKey;
|
|
72
|
+
private finish;
|
|
73
|
+
private withTimeout;
|
|
74
|
+
classify(prompt: string, opts: RunnerClassifyOptions): Promise<RunnerResult>;
|
|
75
|
+
generateAdvisory(prompt: string, opts: RunnerAdvisoryOptions): Promise<RunnerResult>;
|
|
76
|
+
/** Hosted is the composite's fallback; it is never probed for recovery. */
|
|
77
|
+
probe(): Promise<boolean>;
|
|
78
|
+
}
|
|
79
|
+
/** Data-URI image parts as the server will build them (for the body-size mirror). */
|
|
80
|
+
export declare function hostedBodyImages(images: RunnerImage[]): Array<{
|
|
81
|
+
mime: string;
|
|
82
|
+
base64: string;
|
|
83
|
+
}>;
|
|
@@ -5,6 +5,8 @@ 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
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
|
-
export {
|
|
9
|
-
export
|
|
10
|
-
export
|
|
8
|
+
export { GemmaPlannerAdapter, applyMaxTierGate, renderGemmaPlannerPrompt, parseGemmaPlannerDecision, type GemmaClassifyPort, } from './local-gemma';
|
|
9
|
+
export * from './gemma-errors';
|
|
10
|
+
export * from './gemma-runner';
|
|
11
|
+
export * from './gemma-pipeline';
|
|
12
|
+
export * from './hosted-gemma-runner';
|
|
@@ -13,7 +13,6 @@ export interface AdvisoryRunner {
|
|
|
13
13
|
*/
|
|
14
14
|
unload?(): Promise<boolean>;
|
|
15
15
|
runtimeLabel: string;
|
|
16
|
-
readonly providerKind?: 'local' | 'hosted';
|
|
17
16
|
}
|
|
18
17
|
export type AdvisoryResponseFormat = 'json' | 'text';
|
|
19
18
|
export interface AdvisoryOptions {
|
|
@@ -21,11 +20,9 @@ export interface AdvisoryOptions {
|
|
|
21
20
|
numPredict?: number;
|
|
22
21
|
/**
|
|
23
22
|
* RAW base64 images (NO `data:` prefix) for the MULTIMODAL local answerer
|
|
24
|
-
* (IMAGE-ATTACHMENT-DESIGN.md §6)
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* has no image channel and IGNORES them (documented no-op, §6 Role B). NEVER set
|
|
28
|
-
* on the classifier (forced-JSON) or on `browse`/`familiarize`.
|
|
23
|
+
* (IMAGE-ATTACHMENT-DESIGN.md §6) on this legacy runner shape. The Ollama runtime
|
|
24
|
+
* forwards these to `/api/generate images[]`. The orchestration shell's image
|
|
25
|
+
* callers go through the Gemma pipeline's `advise()` (planner parity §3.7).
|
|
29
26
|
*/
|
|
30
27
|
images?: string[];
|
|
31
28
|
/**
|
|
@@ -21,7 +21,6 @@ export interface LocalGemmaPlannerRunner {
|
|
|
21
21
|
*/
|
|
22
22
|
unload?(): Promise<boolean>;
|
|
23
23
|
runtimeLabel: string;
|
|
24
|
-
readonly providerKind?: 'local' | 'hosted';
|
|
25
24
|
}
|
|
26
25
|
/**
|
|
27
26
|
* A1a P0 (R3 — design §7 "the conductor must NEVER hard-fail"): thrown when the
|
|
@@ -67,7 +66,7 @@ export declare class PlannerOutputUnparseableError extends Error {
|
|
|
67
66
|
degradeTo?: PlannerOutputUnparseableError['degradeTo'];
|
|
68
67
|
});
|
|
69
68
|
}
|
|
70
|
-
export declare function localGemmaAllowedActions(
|
|
69
|
+
export declare function localGemmaAllowedActions(): ReadonlySet<PlannerDecision['action']>;
|
|
71
70
|
interface LocalGemmaDecisionJsonSchema {
|
|
72
71
|
type: 'object';
|
|
73
72
|
properties: {
|
|
@@ -75,19 +74,19 @@ interface LocalGemmaDecisionJsonSchema {
|
|
|
75
74
|
type: 'string';
|
|
76
75
|
};
|
|
77
76
|
clarifying_question: {
|
|
78
|
-
type: 'string';
|
|
77
|
+
type: ['string', 'null'];
|
|
79
78
|
};
|
|
80
79
|
advisory_summary: {
|
|
81
|
-
type: 'string';
|
|
80
|
+
type: ['string', 'null'];
|
|
82
81
|
};
|
|
83
82
|
browseUrls: {
|
|
84
|
-
type: 'array';
|
|
83
|
+
type: ['array', 'null'];
|
|
85
84
|
items: {
|
|
86
85
|
type: 'string';
|
|
87
86
|
};
|
|
88
87
|
};
|
|
89
88
|
browseQuery: {
|
|
90
|
-
type: 'string';
|
|
89
|
+
type: ['string', 'null'];
|
|
91
90
|
};
|
|
92
91
|
action: {
|
|
93
92
|
type: 'string';
|
|
@@ -97,30 +96,92 @@ interface LocalGemmaDecisionJsonSchema {
|
|
|
97
96
|
required: string[];
|
|
98
97
|
additionalProperties: boolean;
|
|
99
98
|
}
|
|
100
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* The ONE planner decision schema (both runtimes). Its canonical SHA-256 is allow-listed by
|
|
101
|
+
* planner-proxy (`lambda/planner-proxy/schemas.ts`); a change here needs the backend
|
|
102
|
+
* allow-list updated first (design §4.1, §10) or hosted decoding degrades to JSON-object mode.
|
|
103
|
+
*/
|
|
101
104
|
export declare const LOCAL_GEMMA_DECISION_JSON_SCHEMA: LocalGemmaDecisionJsonSchema;
|
|
102
|
-
|
|
103
|
-
export declare const LOCAL_GEMMA_SUBPROCESS_DECISION_JSON_SCHEMA: LocalGemmaDecisionJsonSchema;
|
|
105
|
+
export declare const GEMMA_DECISION_JSON_SCHEMA: LocalGemmaDecisionJsonSchema;
|
|
104
106
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
+
* The shape the planner prompt was rendered with — sizes and counts only, never text (Stage 2
|
|
108
|
+
* codex S2-codex-F4: the evidence that a maximum input reached the model as rendered).
|
|
107
109
|
*/
|
|
108
|
-
export
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
export interface PlannerPromptShape {
|
|
111
|
+
/**
|
|
112
|
+
* The input after the per-field caps (prompt 4,000; clarifications compacted to 4, questions
|
|
113
|
+
* 300 / answers 900; context 6,000) and BEFORE fitting to the rendered-prompt cap. A maximum
|
|
114
|
+
* input (the design's S9 shape) shows every field at its cap here.
|
|
115
|
+
*/
|
|
116
|
+
capped: {
|
|
117
|
+
userPromptChars: number;
|
|
118
|
+
clarifications: number;
|
|
119
|
+
clarificationQuestionChars: number[];
|
|
120
|
+
clarificationAnswerChars: number[];
|
|
121
|
+
contextChars: number;
|
|
122
|
+
};
|
|
123
|
+
/** What was rendered after fitting (oldest clarifications go first, then context, then prompt). */
|
|
124
|
+
userPromptChars: number;
|
|
125
|
+
clarifications: number;
|
|
126
|
+
clarificationQuestionChars: number[];
|
|
127
|
+
clarificationAnswerChars: number[];
|
|
128
|
+
contextChars: number;
|
|
129
|
+
examplesKept: number;
|
|
130
|
+
renderedChars: number;
|
|
131
|
+
renderedBytes: number;
|
|
132
|
+
}
|
|
133
|
+
export declare function renderLocalGemmaPlannerPrompt(input: PlannerInput): string;
|
|
134
|
+
/** {@link renderLocalGemmaPlannerPrompt} plus the rendered shape (sizes and counts only). */
|
|
135
|
+
export declare function renderLocalGemmaPlannerPromptWithShape(input: PlannerInput): {
|
|
136
|
+
prompt: string;
|
|
137
|
+
shape: PlannerPromptShape;
|
|
138
|
+
};
|
|
111
139
|
/** Characters of raw model output retained on {@link PlannerOutputUnparseableError.rawOutputHead}. */
|
|
112
140
|
export declare const RAW_OUTPUT_HEAD_CHARS = 500;
|
|
113
141
|
/** Terminal-control-free, bounded head of a raw model output for the warn log. */
|
|
114
142
|
export declare function summarizeRawOutputForLog(raw: string): string;
|
|
115
|
-
export declare function parseLocalGemmaPlannerDecision(raw: string
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
export declare function parseLocalGemmaPlannerDecision(raw: string): PlannerDecision;
|
|
144
|
+
/**
|
|
145
|
+
* The adapter's view of the shared pipeline (`gemma-pipeline.ts`): a classify call that
|
|
146
|
+
* returns the raw model text. The adapter never sees which runtime answered (§3.2).
|
|
147
|
+
*/
|
|
148
|
+
export interface GemmaClassifyPort {
|
|
149
|
+
classify(req: {
|
|
150
|
+
prompt: string;
|
|
151
|
+
jsonSchema?: object;
|
|
152
|
+
maxOutputTokens: number;
|
|
153
|
+
}): Promise<{
|
|
154
|
+
text: string;
|
|
155
|
+
}>;
|
|
156
|
+
setActiveSession?(sessionId: string | null): void;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Planner parity D-4 (codevibe-backend docs/2.0/PLANNER-RUNTIME-PARITY-DESIGN.md §3.3): the
|
|
160
|
+
* Max-tier gate on `team_decompose`, on BOTH runtimes, exactly the server's former rule
|
|
161
|
+
* (planner-proxy `applyDeterministicMaxGate`). It runs post-parse, so a converted `start_task`
|
|
162
|
+
* still passes the shell's P43 destructive backstop and `confirmBeforeStart`.
|
|
163
|
+
*/
|
|
164
|
+
export declare function applyMaxTierGate(decision: PlannerDecision, tier: PlannerInput['sessionContext']['tier']): PlannerDecision;
|
|
165
|
+
/**
|
|
166
|
+
* The ONE planner implementation for both runtimes (§3.1): render the shared prompt, classify
|
|
167
|
+
* through the pipeline (which owns failover and the runtime), parse with the shared parser,
|
|
168
|
+
* apply the Max gate. Identical logic whichever runtime answered.
|
|
169
|
+
*/
|
|
170
|
+
export declare class GemmaPlannerAdapter implements PlannerAdapter {
|
|
171
|
+
private readonly port;
|
|
172
|
+
constructor(port: GemmaClassifyPort);
|
|
122
173
|
classify(input: PlannerInput): Promise<PlannerDecision>;
|
|
123
174
|
probe(): Promise<PlannerProbeResult>;
|
|
124
175
|
setActiveSession(sessionId: string | null): void;
|
|
125
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Compatibility alias (§3.1: "the old name stays as an alias"): wraps a legacy text runner
|
|
179
|
+
* (`classify(prompt, { jsonSchema, numPredict }) → string`) as the classify port. Used by
|
|
180
|
+
* tests and spikes; production builds `GemmaPlannerAdapter` over the pipeline.
|
|
181
|
+
*/
|
|
182
|
+
export declare class LocalGemmaPlannerAdapter extends GemmaPlannerAdapter {
|
|
183
|
+
constructor(runner: LocalGemmaPlannerRunner);
|
|
184
|
+
}
|
|
185
|
+
export declare const renderGemmaPlannerPrompt: typeof renderLocalGemmaPlannerPrompt;
|
|
186
|
+
export declare const parseGemmaPlannerDecision: typeof parseLocalGemmaPlannerDecision;
|
|
126
187
|
export {};
|
|
@@ -64,10 +64,10 @@ export interface PlannerInput {
|
|
|
64
64
|
sessionContext: SessionContext;
|
|
65
65
|
budgetHint: BudgetHint;
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
67
|
+
* Role-filtered rendering of the canonical ContextItems session history, given to
|
|
68
|
+
* the planner on BOTH runtimes (planner parity D-2: one rendered prompt for local and
|
|
69
|
+
* hosted). It lets the planner resolve ordinary multi-turn references without relying
|
|
70
|
+
* on shell text heuristics or a model-private conversation cache.
|
|
71
71
|
*/
|
|
72
72
|
canonicalConversationContext?: string;
|
|
73
73
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { LocalGemmaPlannerRunner } from '../planner/local-gemma';
|
|
2
1
|
import type { AgentKind, ReviewerRole, VerdictKind } from './types';
|
|
3
2
|
/** Per-verdict context (seat/role/agent) — carried for observability; the Gemma
|
|
4
3
|
* classification itself is context-free (deterministic on `rawText`). */
|
|
@@ -22,6 +21,20 @@ export type VerdictClassifier = (rawText: string, ctx: VerdictClassifierContext)
|
|
|
22
21
|
export declare const VERDICT_CLASSIFIER_UNCERTAIN = "verdict_classifier_uncertain";
|
|
23
22
|
export declare const VERDICT_CLASSIFIER_CONFLICT = "verdict_classifier_conflict";
|
|
24
23
|
export declare const VERDICT_CLASSIFIER_UNAVAILABLE = "verdict_classifier_unavailable";
|
|
24
|
+
/**
|
|
25
|
+
* The slice of `GemmaCallPipeline` the classifier uses (structural, so tests inject a
|
|
26
|
+
* fake). Absent `jsonSchema` → JSON-object mode on both runtimes.
|
|
27
|
+
*/
|
|
28
|
+
export interface VerdictGemmaPort {
|
|
29
|
+
classify(req: {
|
|
30
|
+
prompt: string;
|
|
31
|
+
maxOutputTokens: number;
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
text: string;
|
|
35
|
+
}>;
|
|
36
|
+
runOutsideTurn<T>(fn: () => Promise<T>): Promise<T>;
|
|
37
|
+
}
|
|
25
38
|
/**
|
|
26
39
|
* Build a fail-closed Gemma verdict classifier. Order:
|
|
27
40
|
* (1) empty `rawText.trim()===''` → ESCALATE (no `classify` call);
|
|
@@ -33,14 +46,14 @@ export declare const VERDICT_CLASSIFIER_UNAVAILABLE = "verdict_classifier_unavai
|
|
|
33
46
|
* A genuine non-ESCALATE verdict (and a genuine reviewer ESCALATE) returns NO
|
|
34
47
|
* `reason` so the provider keeps the reviewer's own reasoning.
|
|
35
48
|
*/
|
|
36
|
-
export declare function makeGemmaVerdictClassifier(
|
|
49
|
+
export declare function makeGemmaVerdictClassifier(port: VerdictGemmaPort, opts?: {
|
|
37
50
|
timeoutMs?: number;
|
|
38
51
|
}): VerdictClassifier;
|
|
39
52
|
/**
|
|
40
53
|
* A trivial classifier that returns ESCALATE (with a closed `reason` label) for
|
|
41
|
-
* every input, with no
|
|
42
|
-
*
|
|
43
|
-
*
|
|
54
|
+
* every input, with no model call. Installed by the wiring when flag=`gemma` but the
|
|
55
|
+
* session has no Gemma source at boot — so `gemma` mode NEVER silently degrades to
|
|
56
|
+
* the regex parser (agy-MED-1).
|
|
44
57
|
*/
|
|
45
58
|
export declare function alwaysEscalateClassifier(reason: string): VerdictClassifier;
|
|
46
59
|
/**
|
|
@@ -42,6 +42,10 @@ export interface ToolActivityTransport {
|
|
|
42
42
|
send(sessionId: string, envelope: ToolActivityOutboxEnvelope): Promise<void | DurableSyncResult>;
|
|
43
43
|
/** Required for SYNC_V2: idempotent cleanup after durable source settlement. */
|
|
44
44
|
settled?(sessionId: string, envelope: ToolActivityOutboxEnvelope): Promise<void>;
|
|
45
|
+
/** Finite request-format compatibility for already sealed legacy windows.
|
|
46
|
+
* New windows still use this transport's generation-bound format. Both
|
|
47
|
+
* delegates call the existing createEvent API, never alternate metering. */
|
|
48
|
+
sendRetainedLegacy?(sessionId: string, envelope: ToolActivityOutboxEnvelope): Promise<void>;
|
|
45
49
|
}
|
|
46
50
|
/**
|
|
47
51
|
* True when a failed TOOL_ACTIVITY `createEvent` is the backend's TYPED
|
|
@@ -70,7 +74,7 @@ export interface ToolActivityConsolidatorOptions {
|
|
|
70
74
|
outbox: ToolActivityOutbox;
|
|
71
75
|
ledger: ToolActivityLedger;
|
|
72
76
|
transport: ToolActivityTransport;
|
|
73
|
-
/** Seal
|
|
77
|
+
/** Seal after this much wall-clock or logical occurrence span (default 3000ms). */
|
|
74
78
|
windowMs?: number;
|
|
75
79
|
/** Seal (with `continues`) once the open window reaches this many occurrences (default 50). */
|
|
76
80
|
maxOccurrences?: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantiya/codevibe-claude-plugin",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.75",
|
|
4
4
|
"description": "Control Claude Code from your iPhone and Android — real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"codevibe": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node": ">=22.0.0"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@quantiya/codevibe-core": "^2.0.
|
|
51
|
+
"@quantiya/codevibe-core": "^2.0.70",
|
|
52
52
|
"@quantiya/quorum-core": "^1.0.1",
|
|
53
53
|
"dotenv": "^16.6.1",
|
|
54
54
|
"express": "^5.1.0",
|