@gajae-code/coding-agent 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -1
- package/dist/types/config/model-registry.d.ts +8 -0
- package/dist/types/config/model-resolver.d.ts +4 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +26 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +44 -0
- package/dist/types/goals/tools/goal-tool.d.ts +4 -4
- package/dist/types/hooks/skill-state.d.ts +3 -0
- package/dist/types/modes/components/model-selector.d.ts +5 -7
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -4
- package/dist/types/session/agent-session.d.ts +3 -9
- package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +28 -0
- package/package.json +13 -9
- package/src/config/model-registry.ts +45 -0
- package/src/config/model-resolver.ts +5 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +30 -30
- package/src/defaults/gjc/skills/team/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +51 -21
- package/src/gjc-runtime/team-runtime.ts +80 -1
- package/src/gjc-runtime/ultragoal-guard.ts +239 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +318 -4
- package/src/goals/tools/goal-tool.ts +10 -4
- package/src/hooks/native-skill-hook.ts +26 -0
- package/src/hooks/skill-state.ts +59 -0
- package/src/main.ts +2 -17
- package/src/modes/components/model-selector.ts +225 -33
- package/src/modes/controllers/selector-controller.ts +16 -3
- package/src/modes/interactive-mode.ts +34 -22
- package/src/modes/prompt-action-autocomplete.ts +40 -15
- package/src/sdk.ts +3 -1
- package/src/session/agent-session.ts +40 -4
- package/src/setup/model-onboarding-guidance.ts +5 -3
- package/src/skill-state/deep-interview-mutation-guard.ts +303 -0
- package/src/slash-commands/builtin-registry.ts +130 -11
- package/src/tools/ask.ts +55 -17
- package/src/tools/ast-edit.ts +7 -0
- package/src/tools/bash.ts +2 -1
- package/src/tools/gh.ts +37 -9
- package/src/tools/image-gen.ts +19 -10
- package/src/tools/path-utils.ts +1 -0
|
@@ -121,9 +121,14 @@ const HINT_SHIMMER_PALETTE: ShimmerPalette = {
|
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
function configureDefaultComposerChrome(editor: CustomEditor): void {
|
|
124
|
-
editor.setBorderVisible(
|
|
125
|
-
editor.
|
|
124
|
+
editor.setBorderVisible(true);
|
|
125
|
+
editor.setBorderStyle("sharp");
|
|
126
|
+
editor.setClosedBorderBox(true);
|
|
127
|
+
editor.setPromptGutter(undefined);
|
|
128
|
+
editor.setInputPrefix(`${theme.fg("accent", ">")} `);
|
|
129
|
+
editor.setPlaceholder("Type your message...");
|
|
126
130
|
editor.setPaddingX(1);
|
|
131
|
+
editor.setTopBorder(undefined);
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
interface WorkingMessageAccent {
|
|
@@ -376,7 +381,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
376
381
|
this.#syncEditorMaxHeight();
|
|
377
382
|
this.#resizeHandler = () => {
|
|
378
383
|
this.#syncEditorMaxHeight();
|
|
379
|
-
this.
|
|
384
|
+
this.updateEditorChrome();
|
|
380
385
|
};
|
|
381
386
|
process.stdout.on("resize", this.#resizeHandler);
|
|
382
387
|
try {
|
|
@@ -500,7 +505,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
500
505
|
this.ui.addChild(this.statusContainer);
|
|
501
506
|
this.ui.addChild(this.todoContainer);
|
|
502
507
|
this.ui.addChild(this.btwContainer);
|
|
503
|
-
this.ui.addChild(this.statusLine); // Main status rail + hook statuses; composer
|
|
508
|
+
this.ui.addChild(this.statusLine); // Main status rail + hook statuses; composer chrome is rendered by the editor.
|
|
504
509
|
this.ui.addChild(this.hookWidgetContainerAbove);
|
|
505
510
|
this.ui.addChild(this.editorContainer);
|
|
506
511
|
this.ui.addChild(this.hookWidgetContainerBelow);
|
|
@@ -526,7 +531,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
526
531
|
this.ui.start();
|
|
527
532
|
pushTerminalTitle();
|
|
528
533
|
setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
|
|
529
|
-
this.
|
|
534
|
+
this.updateEditorChrome();
|
|
530
535
|
this.#syncEditorMaxHeight();
|
|
531
536
|
this.isInitialized = true;
|
|
532
537
|
this.ui.requestRender(true);
|
|
@@ -544,7 +549,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
544
549
|
const draft = await this.sessionManager.consumeDraft();
|
|
545
550
|
if (draft && !this.editor.getText()) {
|
|
546
551
|
this.editor.setText(draft);
|
|
547
|
-
this.
|
|
552
|
+
this.updateEditorChrome();
|
|
548
553
|
this.ui.requestRender();
|
|
549
554
|
}
|
|
550
555
|
} catch (err) {
|
|
@@ -564,7 +569,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
564
569
|
clearRenderCache();
|
|
565
570
|
configureDefaultComposerChrome(this.editor);
|
|
566
571
|
this.ui.invalidate();
|
|
567
|
-
this.
|
|
572
|
+
this.updateEditorChrome();
|
|
568
573
|
this.ui.requestRender();
|
|
569
574
|
});
|
|
570
575
|
|
|
@@ -577,12 +582,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
577
582
|
|
|
578
583
|
// Set up git branch watcher
|
|
579
584
|
this.statusLine.watchBranch(() => {
|
|
580
|
-
this.
|
|
585
|
+
this.updateEditorChrome();
|
|
581
586
|
this.ui.requestRender();
|
|
582
587
|
});
|
|
583
588
|
|
|
584
589
|
// Initial top border update
|
|
585
|
-
this.
|
|
590
|
+
this.updateEditorChrome();
|
|
586
591
|
}
|
|
587
592
|
|
|
588
593
|
/** Reload slash commands and autocomplete for the provided working directory. */
|
|
@@ -749,7 +754,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
749
754
|
this.loopLimit = undefined;
|
|
750
755
|
this.#cancelLoopAutoSubmit();
|
|
751
756
|
this.statusLine.setLoopModeStatus(undefined);
|
|
752
|
-
this.
|
|
757
|
+
this.updateEditorChrome();
|
|
753
758
|
this.ui.requestRender();
|
|
754
759
|
if (wasEnabled) {
|
|
755
760
|
this.showStatus(message);
|
|
@@ -780,7 +785,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
780
785
|
this.loopPrompt = undefined;
|
|
781
786
|
this.loopLimit = createLoopLimitRuntime(parsedLimit);
|
|
782
787
|
this.statusLine.setLoopModeStatus({ enabled: true });
|
|
783
|
-
this.
|
|
788
|
+
this.updateEditorChrome();
|
|
784
789
|
this.ui.requestRender();
|
|
785
790
|
const limitSuffix = parsedLimit ? ` Limited to ${describeLoopLimit(parsedLimit)}.` : "";
|
|
786
791
|
const remainingSuffix = this.loopLimit ? ` ${describeLoopLimitRuntime(this.loopLimit)}.` : "";
|
|
@@ -874,7 +879,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
874
879
|
this.rebuildChatFromMessages();
|
|
875
880
|
this.editor.setText(submission.text);
|
|
876
881
|
}
|
|
877
|
-
this.
|
|
882
|
+
this.updateEditorChrome();
|
|
878
883
|
this.ui.requestRender();
|
|
879
884
|
return true;
|
|
880
885
|
}
|
|
@@ -921,7 +926,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
921
926
|
this.editor.setMaxHeight(this.#computeEditorMaxHeight());
|
|
922
927
|
}
|
|
923
928
|
|
|
924
|
-
|
|
929
|
+
updateEditorChrome(): void {
|
|
925
930
|
if (this.isBashMode) {
|
|
926
931
|
this.editor.borderColor = theme.getBashModeBorderColor();
|
|
927
932
|
} else if (this.isPythonMode) {
|
|
@@ -938,13 +943,21 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
938
943
|
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
939
944
|
}
|
|
940
945
|
}
|
|
941
|
-
this
|
|
946
|
+
this.#setComposerTopBorder();
|
|
942
947
|
this.ui.requestRender();
|
|
943
948
|
}
|
|
944
949
|
|
|
950
|
+
updateEditorBorderColor(): void {
|
|
951
|
+
this.updateEditorChrome();
|
|
952
|
+
}
|
|
953
|
+
|
|
945
954
|
updateEditorTopBorder(): void {
|
|
946
|
-
|
|
947
|
-
|
|
955
|
+
this.#setComposerTopBorder();
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
#setComposerTopBorder(): void {
|
|
959
|
+
// Keep the composer as a plain closed input rectangle; status-line
|
|
960
|
+
// rendering stays outside the input area.
|
|
948
961
|
this.editor.setTopBorder(undefined);
|
|
949
962
|
}
|
|
950
963
|
|
|
@@ -1048,7 +1061,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1048
1061
|
}
|
|
1049
1062
|
: undefined;
|
|
1050
1063
|
this.statusLine.setPlanModeStatus(status);
|
|
1051
|
-
this.
|
|
1064
|
+
this.updateEditorChrome();
|
|
1052
1065
|
this.ui.requestRender();
|
|
1053
1066
|
}
|
|
1054
1067
|
|
|
@@ -1058,7 +1071,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1058
1071
|
? { enabled: this.goalModeEnabled, paused: this.goalModePaused }
|
|
1059
1072
|
: undefined;
|
|
1060
1073
|
this.statusLine.setGoalModeStatus(status);
|
|
1061
|
-
this.
|
|
1074
|
+
this.updateEditorChrome();
|
|
1062
1075
|
this.ui.requestRender();
|
|
1063
1076
|
}
|
|
1064
1077
|
|
|
@@ -1650,7 +1663,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1650
1663
|
const applied = await this.sessionManager.setSessionName(seededName, "auto");
|
|
1651
1664
|
if (applied) {
|
|
1652
1665
|
setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
|
|
1653
|
-
this.
|
|
1666
|
+
this.updateEditorChrome();
|
|
1654
1667
|
}
|
|
1655
1668
|
}
|
|
1656
1669
|
|
|
@@ -2121,8 +2134,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2121
2134
|
logger.warn("Failed to refresh slash command state for custom editor", { error: String(error) });
|
|
2122
2135
|
});
|
|
2123
2136
|
|
|
2124
|
-
this.
|
|
2125
|
-
this.updateEditorTopBorder();
|
|
2137
|
+
this.updateEditorChrome();
|
|
2126
2138
|
this.ui.requestRender();
|
|
2127
2139
|
}
|
|
2128
2140
|
|
|
@@ -2417,7 +2429,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2417
2429
|
} else {
|
|
2418
2430
|
this.#cleanupMicAnimation();
|
|
2419
2431
|
}
|
|
2420
|
-
this.
|
|
2432
|
+
this.updateEditorChrome();
|
|
2421
2433
|
this.ui.requestRender();
|
|
2422
2434
|
},
|
|
2423
2435
|
});
|
|
@@ -84,6 +84,34 @@ function isSkillCommandAutocompleteItem(item: AutocompleteItem): item is SkillCo
|
|
|
84
84
|
return "normalizedSkillCommand" in item && item.normalizedSkillCommand === true;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
function mergeAutocompleteSuggestions(
|
|
88
|
+
primary: { items: AutocompleteItem[]; prefix: string } | null,
|
|
89
|
+
secondary: { items: AutocompleteItem[]; prefix: string } | null,
|
|
90
|
+
): { items: AutocompleteItem[]; prefix: string } | null {
|
|
91
|
+
if (!primary) return secondary;
|
|
92
|
+
if (!secondary) return primary;
|
|
93
|
+
if (primary.prefix !== secondary.prefix) return primary;
|
|
94
|
+
|
|
95
|
+
const seen = new Set<string>();
|
|
96
|
+
const items: AutocompleteItem[] = [];
|
|
97
|
+
for (const item of [...primary.items, ...secondary.items]) {
|
|
98
|
+
const key = `${item.value}\0${item.label}`;
|
|
99
|
+
if (seen.has(key)) continue;
|
|
100
|
+
seen.add(key);
|
|
101
|
+
items.push(item);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { items, prefix: primary.prefix };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function withoutSkillCommandSuggestions(
|
|
108
|
+
suggestions: { items: AutocompleteItem[]; prefix: string } | null,
|
|
109
|
+
): { items: AutocompleteItem[]; prefix: string } | null {
|
|
110
|
+
if (!suggestions) return null;
|
|
111
|
+
const items = suggestions.items.filter(item => !item.value.startsWith("skill:"));
|
|
112
|
+
return items.length > 0 ? { ...suggestions, items } : null;
|
|
113
|
+
}
|
|
114
|
+
|
|
87
115
|
function getPromptActionPrefix(textBeforeCursor: string): string | null {
|
|
88
116
|
const hashIndex = textBeforeCursor.lastIndexOf("#");
|
|
89
117
|
if (hashIndex === -1) return null;
|
|
@@ -148,8 +176,14 @@ export class PromptActionAutocompleteProvider implements AutocompleteProvider {
|
|
|
148
176
|
}
|
|
149
177
|
}
|
|
150
178
|
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
179
|
+
const slashPrefix = getSlashTokenPrefix(textBeforeCursor);
|
|
180
|
+
if (slashPrefix) {
|
|
181
|
+
const baseSuggestions = withoutSkillCommandSuggestions(
|
|
182
|
+
await this.#baseProvider.getSuggestions(lines, cursorLine, cursorCol),
|
|
183
|
+
);
|
|
184
|
+
const skillCommandSuggestions = this.#getSkillCommandSuggestions(textBeforeCursor);
|
|
185
|
+
return mergeAutocompleteSuggestions(baseSuggestions, skillCommandSuggestions);
|
|
186
|
+
}
|
|
153
187
|
|
|
154
188
|
if (!isSettingsInitialized() || settings.get("emojiAutocomplete")) {
|
|
155
189
|
const emojiSuggestions = getEmojiSuggestions(textBeforeCursor);
|
|
@@ -215,9 +249,11 @@ export class PromptActionAutocompleteProvider implements AutocompleteProvider {
|
|
|
215
249
|
return this.#baseProvider.getInlineHint?.(lines, cursorLine, cursorCol) ?? null;
|
|
216
250
|
}
|
|
217
251
|
trySyncSlashCompletion(textBeforeCursor: string): { items: AutocompleteItem[]; prefix: string } | null {
|
|
252
|
+
const baseSuggestions = withoutSkillCommandSuggestions(
|
|
253
|
+
this.#baseProvider.trySyncSlashCompletion?.(textBeforeCursor) ?? null,
|
|
254
|
+
);
|
|
218
255
|
const skillCommandSuggestions = this.#getSkillCommandSuggestions(textBeforeCursor);
|
|
219
|
-
|
|
220
|
-
return this.#baseProvider.trySyncSlashCompletion?.(textBeforeCursor) ?? null;
|
|
256
|
+
return mergeAutocompleteSuggestions(baseSuggestions, skillCommandSuggestions);
|
|
221
257
|
}
|
|
222
258
|
trySyncInlineReplace(textBeforeCursor: string): { replaceLen: number; insert: string } | null {
|
|
223
259
|
if (isSettingsInitialized() && !settings.get("emojiAutocomplete")) return null;
|
|
@@ -233,17 +269,6 @@ export class PromptActionAutocompleteProvider implements AutocompleteProvider {
|
|
|
233
269
|
const exactNonSkillCommand = this.#commands.some(
|
|
234
270
|
command => command.name === query && !command.name.startsWith("skill:"),
|
|
235
271
|
);
|
|
236
|
-
if (exactNonSkillCommand) {
|
|
237
|
-
const command = this.#commands.find(
|
|
238
|
-
candidate => candidate.name === query && !candidate.name.startsWith("skill:"),
|
|
239
|
-
);
|
|
240
|
-
if (command) {
|
|
241
|
-
return {
|
|
242
|
-
items: [{ value: command.name, label: command.name, description: command.description }],
|
|
243
|
-
prefix,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
272
|
const items = this.#commands
|
|
248
273
|
.filter(command => command.name.startsWith("skill:"))
|
|
249
274
|
.map(command => {
|
package/src/sdk.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
parseModelString,
|
|
41
41
|
resolveAllowedModels,
|
|
42
42
|
resolveModelRoleValue,
|
|
43
|
+
type ScopedModelSelection,
|
|
43
44
|
} from "./config/model-resolver";
|
|
44
45
|
import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
|
|
45
46
|
import { Settings, type SkillsSettings } from "./config/settings";
|
|
@@ -230,7 +231,7 @@ export interface CreateAgentSessionOptions {
|
|
|
230
231
|
/** Thinking selector. Default: from settings, else unset */
|
|
231
232
|
thinkingLevel?: ThinkingLevel;
|
|
232
233
|
/** Models available for cycling (Ctrl+P in interactive mode) */
|
|
233
|
-
scopedModels?:
|
|
234
|
+
scopedModels?: ScopedModelSelection[];
|
|
234
235
|
|
|
235
236
|
/** System prompt blocks. Array replaces default, function receives default blocks and returns final blocks. */
|
|
236
237
|
systemPrompt?: string[] | ((defaultPrompt: string[]) => string[]);
|
|
@@ -1760,6 +1761,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1760
1761
|
}
|
|
1761
1762
|
return key;
|
|
1762
1763
|
},
|
|
1764
|
+
getAuthCredentialType: provider => modelRegistry.getSessionCredentialType(provider, agent.sessionId),
|
|
1763
1765
|
streamFn: (streamModel, context, streamOptions) =>
|
|
1764
1766
|
streamSimple(streamModel, context, {
|
|
1765
1767
|
...streamOptions,
|
|
@@ -95,6 +95,7 @@ import {
|
|
|
95
95
|
parseModelString,
|
|
96
96
|
type ResolvedModelRoleValue,
|
|
97
97
|
resolveModelRoleValue,
|
|
98
|
+
type ScopedModelSelection,
|
|
98
99
|
} from "../config/model-resolver";
|
|
99
100
|
import { expandPromptTemplate, type PromptTemplate } from "../config/prompt-templates";
|
|
100
101
|
import type { Settings, SkillsSettings } from "../config/settings";
|
|
@@ -167,6 +168,7 @@ import {
|
|
|
167
168
|
import { deobfuscateSessionContext, type SecretObfuscator } from "../secrets/obfuscator";
|
|
168
169
|
import { formatNoCredentialOnboardingError, formatNoModelOnboardingError } from "../setup/model-onboarding-guidance";
|
|
169
170
|
import { isCanonicalGjcWorkflowSkill, syncSkillActiveState } from "../skill-state/active-state";
|
|
171
|
+
import { assertDeepInterviewMutationAllowed } from "../skill-state/deep-interview-mutation-guard";
|
|
170
172
|
import { invalidateHostMetadata } from "../ssh/connection-manager";
|
|
171
173
|
import { resolveThinkingLevelForModel, toReasoningEffort } from "../thinking";
|
|
172
174
|
import {
|
|
@@ -257,7 +259,7 @@ export interface AgentSessionConfig {
|
|
|
257
259
|
sessionManager: SessionManager;
|
|
258
260
|
settings: Settings;
|
|
259
261
|
/** Models to cycle through with Ctrl+P (from --models flag) */
|
|
260
|
-
scopedModels?:
|
|
262
|
+
scopedModels?: ScopedModelSelection[];
|
|
261
263
|
/** Initial session thinking selector. */
|
|
262
264
|
thinkingLevel?: ThinkingLevel;
|
|
263
265
|
/** Prompt templates for expansion */
|
|
@@ -747,7 +749,7 @@ export class AgentSession {
|
|
|
747
749
|
|
|
748
750
|
readonly configWarnings: string[] = [];
|
|
749
751
|
|
|
750
|
-
#scopedModels:
|
|
752
|
+
#scopedModels: ScopedModelSelection[];
|
|
751
753
|
#thinkingLevel: ThinkingLevel | undefined;
|
|
752
754
|
#promptTemplates: PromptTemplate[];
|
|
753
755
|
#slashCommands: FileSlashCommand[];
|
|
@@ -3273,6 +3275,35 @@ export class AgentSession {
|
|
|
3273
3275
|
}) as T;
|
|
3274
3276
|
}
|
|
3275
3277
|
|
|
3278
|
+
/**
|
|
3279
|
+
* Wrap a tool with the deep-interview mutation guard. This guard is intentionally
|
|
3280
|
+
* outermost so active interviews reject product-code mutation before ACP permission
|
|
3281
|
+
* prompts or tool execution can run.
|
|
3282
|
+
*/
|
|
3283
|
+
#wrapToolForDeepInterviewMutationGuard<T extends AgentTool>(tool: T): T {
|
|
3284
|
+
if (!["edit", "write", "ast_edit"].includes(tool.name)) return tool;
|
|
3285
|
+
return new Proxy(tool, {
|
|
3286
|
+
get: (target, prop) => {
|
|
3287
|
+
if (prop !== "execute") return Reflect.get(target, prop, target);
|
|
3288
|
+
return async (
|
|
3289
|
+
toolCallId: string,
|
|
3290
|
+
args: unknown,
|
|
3291
|
+
signal: AbortSignal | undefined,
|
|
3292
|
+
onUpdate: never,
|
|
3293
|
+
ctx: never,
|
|
3294
|
+
) => {
|
|
3295
|
+
await assertDeepInterviewMutationAllowed({
|
|
3296
|
+
cwd: this.sessionManager.getCwd(),
|
|
3297
|
+
sessionId: this.sessionManager.getSessionId(),
|
|
3298
|
+
tool: target,
|
|
3299
|
+
args,
|
|
3300
|
+
});
|
|
3301
|
+
return await target.execute(toolCallId, args as never, signal, onUpdate, ctx);
|
|
3302
|
+
};
|
|
3303
|
+
},
|
|
3304
|
+
}) as T;
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3276
3307
|
async #applyActiveToolsByName(
|
|
3277
3308
|
toolNames: string[],
|
|
3278
3309
|
options?: { persistMCPSelection?: boolean; previousSelectedMCPToolNames?: string[] },
|
|
@@ -3284,7 +3315,7 @@ export class AgentSession {
|
|
|
3284
3315
|
for (const name of toolNames) {
|
|
3285
3316
|
const tool = this.#toolRegistry.get(name);
|
|
3286
3317
|
if (tool) {
|
|
3287
|
-
tools.push(this.#wrapToolForAcpPermission(tool));
|
|
3318
|
+
tools.push(this.#wrapToolForDeepInterviewMutationGuard(this.#wrapToolForAcpPermission(tool)));
|
|
3288
3319
|
validToolNames.push(name);
|
|
3289
3320
|
}
|
|
3290
3321
|
}
|
|
@@ -3719,7 +3750,7 @@ export class AgentSession {
|
|
|
3719
3750
|
}
|
|
3720
3751
|
|
|
3721
3752
|
/** Scoped models for cycling (from --models flag) */
|
|
3722
|
-
get scopedModels(): ReadonlyArray<
|
|
3753
|
+
get scopedModels(): ReadonlyArray<ScopedModelSelection> {
|
|
3723
3754
|
return this.#scopedModels;
|
|
3724
3755
|
}
|
|
3725
3756
|
|
|
@@ -6415,6 +6446,7 @@ export class AgentSession {
|
|
|
6415
6446
|
metadata: this.agent.metadataForProvider(candidate.provider),
|
|
6416
6447
|
convertToLlm,
|
|
6417
6448
|
telemetry,
|
|
6449
|
+
authCredentialType: this.#modelRegistry.getSessionCredentialType(candidate.provider, this.sessionId),
|
|
6418
6450
|
});
|
|
6419
6451
|
} catch (error) {
|
|
6420
6452
|
if (!this.#isCompactionAuthFailure(error)) {
|
|
@@ -6670,6 +6702,10 @@ export class AgentSession {
|
|
|
6670
6702
|
initiatorOverride: "agent",
|
|
6671
6703
|
convertToLlm,
|
|
6672
6704
|
telemetry,
|
|
6705
|
+
authCredentialType: this.#modelRegistry.getSessionCredentialType(
|
|
6706
|
+
candidate.provider,
|
|
6707
|
+
this.sessionId,
|
|
6708
|
+
),
|
|
6673
6709
|
});
|
|
6674
6710
|
break;
|
|
6675
6711
|
} catch (error) {
|
|
@@ -7,14 +7,16 @@ export const MODEL_ONBOARDING_OAUTH_COMMAND = "/provider login [provider-id] or
|
|
|
7
7
|
export function formatModelOnboardingGuidance(): string {
|
|
8
8
|
return [
|
|
9
9
|
"Model selection only shows configured providers.",
|
|
10
|
+
"Assignment targets are DEFAULT plus the GJC role agents: EXECUTOR, ARCHITECT, PLANNER, and CRITIC.",
|
|
11
|
+
"Legacy model-role aliases are compatibility-only and are not shown as assignment targets.",
|
|
10
12
|
`API-compatible providers: ${MODEL_ONBOARDING_API_PROVIDER_COMMAND} (or ${MODEL_ONBOARDING_SETUP_COMMAND}).`,
|
|
11
13
|
`OAuth/subscription providers: ${MODEL_ONBOARDING_OAUTH_COMMAND}.`,
|
|
12
|
-
"Then run /model to select a configured model.",
|
|
14
|
+
"Then run /model to select a configured model or assign it to a target.",
|
|
13
15
|
].join("\n");
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export function formatModelOnboardingInlineHint(): string {
|
|
17
|
-
return `Add API-compatible providers with ${MODEL_ONBOARDING_API_PROVIDER_COMMAND} (or ${MODEL_ONBOARDING_SETUP_COMMAND}); OAuth/subscription with ${MODEL_ONBOARDING_OAUTH_COMMAND}; then run /model.`;
|
|
19
|
+
return `Add API-compatible providers with ${MODEL_ONBOARDING_API_PROVIDER_COMMAND} (or ${MODEL_ONBOARDING_SETUP_COMMAND}); OAuth/subscription with ${MODEL_ONBOARDING_OAUTH_COMMAND}; then run /model for DEFAULT, EXECUTOR, ARCHITECT, PLANNER, and CRITIC.`;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function formatNoModelOnboardingError(): string {
|
|
@@ -27,7 +29,7 @@ export function formatNoCredentialOnboardingError(providerId: string): string {
|
|
|
27
29
|
"",
|
|
28
30
|
`For API-compatible providers, configure credentials with ${MODEL_ONBOARDING_API_PROVIDER_COMMAND} (or ${MODEL_ONBOARDING_SETUP_COMMAND}).`,
|
|
29
31
|
`For OAuth/subscription providers, use ${MODEL_ONBOARDING_OAUTH_COMMAND}.`,
|
|
30
|
-
"Then run /model to select a configured model.",
|
|
32
|
+
"Then run /model to select a configured model or assign it to DEFAULT, EXECUTOR, ARCHITECT, PLANNER, or CRITIC.",
|
|
31
33
|
].join("\n");
|
|
32
34
|
}
|
|
33
35
|
|