iosm-cli 0.2.2 → 0.2.4
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 +33 -0
- package/README.md +32 -5
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-profiles.d.ts +1 -1
- package/dist/core/agent-profiles.d.ts.map +1 -1
- package/dist/core/agent-profiles.js +9 -0
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +58 -13
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/orchestration-limits.d.ts +6 -0
- package/dist/core/orchestration-limits.d.ts.map +1 -0
- package/dist/core/orchestration-limits.js +6 -0
- package/dist/core/orchestration-limits.js.map +1 -0
- package/dist/core/sdk.d.ts +6 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +96 -6
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/subagents.d.ts.map +1 -1
- package/dist/core/subagents.js +21 -7
- package/dist/core/subagents.js.map +1 -1
- package/dist/core/tools/edit.d.ts +8 -4
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +18 -3
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/index.d.ts +9 -7
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/task.d.ts +10 -3
- package/dist/core/tools/task.d.ts.map +1 -1
- package/dist/core/tools/task.js +404 -149
- package/dist/core/tools/task.js.map +1 -1
- package/dist/core/tools/todo.d.ts +10 -10
- package/dist/core/tools/todo.d.ts.map +1 -1
- package/dist/core/tools/todo.js +135 -17
- package/dist/core/tools/todo.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +243 -15
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/cli-reference.md +4 -0
- package/docs/configuration.md +5 -1
- package/docs/interactive-mode.md +5 -1
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ import { parseSkillBlock } from "../../core/agent-session.js";
|
|
|
15
15
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
16
16
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
17
17
|
import { createCompactionSummaryMessage, INTERNAL_UI_META_CUSTOM_TYPE, isInternalUiMetaDetails, } from "../../core/messages.js";
|
|
18
|
+
import { MAX_ORCHESTRATION_AGENTS, MAX_ORCHESTRATION_PARALLEL, MAX_SUBAGENT_DELEGATE_PARALLEL, } from "../../core/orchestration-limits.js";
|
|
18
19
|
import { loadModelsDevProviderCatalog, } from "../../core/models-dev-provider-catalog.js";
|
|
19
20
|
import { ModelRegistry } from "../../core/model-registry.js";
|
|
20
21
|
import { MODELS_DEV_PROVIDERS } from "../../core/models-dev-providers.js";
|
|
@@ -75,6 +76,152 @@ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMar
|
|
|
75
76
|
function isExpandable(obj) {
|
|
76
77
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
77
78
|
}
|
|
79
|
+
export function resolveStreamingSubmissionMode(input) {
|
|
80
|
+
if (input.configuredMode === "meta" &&
|
|
81
|
+
input.activeProfileName === "meta" &&
|
|
82
|
+
(input.activeSubagentCount > 0 || input.activeAssistantOrchestrationContext)) {
|
|
83
|
+
return "followUp";
|
|
84
|
+
}
|
|
85
|
+
return input.configuredMode;
|
|
86
|
+
}
|
|
87
|
+
function parseRequestedParallelAgentCount(text) {
|
|
88
|
+
const patterns = [
|
|
89
|
+
/(\d+)\s+(?:parallel|concurrent)\s+agents?/i,
|
|
90
|
+
/(\d+)\s+agents?/i,
|
|
91
|
+
/(\d+)\s+паралл\w*\s+агент\w*/i,
|
|
92
|
+
/(\d+)\s+агент\w*/i,
|
|
93
|
+
];
|
|
94
|
+
for (const pattern of patterns) {
|
|
95
|
+
const match = text.match(pattern);
|
|
96
|
+
const parsed = match?.[1] ? Number.parseInt(match[1], 10) : Number.NaN;
|
|
97
|
+
if (Number.isInteger(parsed) && parsed >= 1) {
|
|
98
|
+
return Math.max(1, Math.min(MAX_ORCHESTRATION_AGENTS, parsed));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
function deriveMetaRequiredTopLevelTaskCalls(userInput, taskPlanSnapshot) {
|
|
104
|
+
const requested = parseRequestedParallelAgentCount(userInput);
|
|
105
|
+
if (requested)
|
|
106
|
+
return requested;
|
|
107
|
+
if (!taskPlanSnapshot)
|
|
108
|
+
return undefined;
|
|
109
|
+
return Math.max(2, Math.min(3, taskPlanSnapshot.totalSteps));
|
|
110
|
+
}
|
|
111
|
+
function extractTaskToolErrorText(result) {
|
|
112
|
+
if (!result || typeof result !== "object")
|
|
113
|
+
return undefined;
|
|
114
|
+
const candidate = result;
|
|
115
|
+
if (typeof candidate.error === "string" && candidate.error.trim())
|
|
116
|
+
return candidate.error.trim();
|
|
117
|
+
if (typeof candidate.output === "string" && candidate.output.trim())
|
|
118
|
+
return candidate.output.trim();
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
function buildMetaParallelismCorrection(input) {
|
|
122
|
+
const validationFailure = input.taskToolError && /Validation failed for tool "task"/i.test(input.taskToolError)
|
|
123
|
+
? input.taskToolError.split("\n").slice(0, 3).join("\n")
|
|
124
|
+
: undefined;
|
|
125
|
+
return [
|
|
126
|
+
"[META_PARALLELISM_CORRECTION]",
|
|
127
|
+
`Meta runtime correction: this run currently has ${input.launchedTopLevelTasks} top-level task call(s), but it should have at least ${input.requiredTopLevelTasks}.`,
|
|
128
|
+
"Stop manual sequential execution in the main agent and convert the execution graph into parallel task calls now.",
|
|
129
|
+
"Emit the missing top-level task calls in the same assistant response when branches are independent.",
|
|
130
|
+
"Each task tool call MUST include description and prompt.",
|
|
131
|
+
'If you want a custom subagent, pass it via agent="name"; keep profile set to the capability profile, not the custom subagent name.',
|
|
132
|
+
input.rawRootDelegateBlocks && input.rawRootDelegateBlocks > 0
|
|
133
|
+
? `You emitted ${input.rawRootDelegateBlocks} raw root-level <delegate_task> block(s). Those are not executed automatically in the parent session. Convert each one into an actual top-level task tool call now.`
|
|
134
|
+
: undefined,
|
|
135
|
+
"If a child workstream is still broad, require nested <delegate_task> fan-out instead of letting one child do everything alone.",
|
|
136
|
+
input.taskPlanSnapshot
|
|
137
|
+
? `You already produced a complex plan with ${input.taskPlanSnapshot.totalSteps} steps. Turn that plan into parallel execution now.`
|
|
138
|
+
: undefined,
|
|
139
|
+
validationFailure ? `Previous task validation failure:\n${validationFailure}` : undefined,
|
|
140
|
+
"If you truly cannot split safely, output exactly one line: DELEGATION_IMPOSSIBLE: <precise reason>.",
|
|
141
|
+
"[/META_PARALLELISM_CORRECTION]",
|
|
142
|
+
]
|
|
143
|
+
.filter((line) => typeof line === "string" && line.trim().length > 0)
|
|
144
|
+
.join("\n");
|
|
145
|
+
}
|
|
146
|
+
async function promptMetaWithParallelismGuard(input) {
|
|
147
|
+
let taskToolCalls = 0;
|
|
148
|
+
let nonTaskToolCalls = 0;
|
|
149
|
+
let taskPlanSnapshot;
|
|
150
|
+
let taskToolError;
|
|
151
|
+
let rawRootDelegateBlocks = 0;
|
|
152
|
+
let delegationImpossibleDeclared = false;
|
|
153
|
+
let correctionText;
|
|
154
|
+
const maybeScheduleCorrection = () => {
|
|
155
|
+
const requiredTopLevelTasks = deriveMetaRequiredTopLevelTaskCalls(input.userInput, taskPlanSnapshot);
|
|
156
|
+
if (!requiredTopLevelTasks || taskToolCalls >= requiredTopLevelTasks || delegationImpossibleDeclared) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const hasComplexPlan = !!taskPlanSnapshot;
|
|
160
|
+
const hasTaskFailure = !!taskToolError;
|
|
161
|
+
const hasRawRootDelegates = rawRootDelegateBlocks > 0;
|
|
162
|
+
if (!hasTaskFailure && !hasRawRootDelegates && nonTaskToolCalls < 1) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!hasComplexPlan && !hasTaskFailure && !hasRawRootDelegates && nonTaskToolCalls < 2) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
correctionText = buildMetaParallelismCorrection({
|
|
169
|
+
requiredTopLevelTasks,
|
|
170
|
+
launchedTopLevelTasks: taskToolCalls,
|
|
171
|
+
taskPlanSnapshot,
|
|
172
|
+
taskToolError,
|
|
173
|
+
rawRootDelegateBlocks,
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
const unsubscribe = input.session.subscribe((event) => {
|
|
177
|
+
if (event.type === "message_end" && event.message.role === "custom") {
|
|
178
|
+
if (event.message.customType === TASK_PLAN_CUSTOM_TYPE && isTaskPlanSnapshot(event.message.details)) {
|
|
179
|
+
taskPlanSnapshot = event.message.details;
|
|
180
|
+
maybeScheduleCorrection();
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (event.type === "message_end" && event.message.role === "assistant") {
|
|
185
|
+
const rawText = extractAssistantText(event.message);
|
|
186
|
+
rawRootDelegateBlocks += (rawText.match(/<delegate_task\b/gi) ?? []).length;
|
|
187
|
+
delegationImpossibleDeclared =
|
|
188
|
+
delegationImpossibleDeclared || /^\s*DELEGATION_IMPOSSIBLE\s*:/im.test(rawText);
|
|
189
|
+
maybeScheduleCorrection();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (event.type === "tool_execution_start") {
|
|
193
|
+
if (event.toolName === "task") {
|
|
194
|
+
taskToolCalls += 1;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
nonTaskToolCalls += 1;
|
|
198
|
+
}
|
|
199
|
+
maybeScheduleCorrection();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (event.type === "tool_execution_end" && event.toolName === "task" && event.isError) {
|
|
203
|
+
taskToolError = extractTaskToolErrorText(event.result) ?? taskToolError;
|
|
204
|
+
maybeScheduleCorrection();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
try {
|
|
208
|
+
await input.session.prompt(input.userInput);
|
|
209
|
+
const requiredTopLevelTasks = deriveMetaRequiredTopLevelTaskCalls(input.userInput, taskPlanSnapshot);
|
|
210
|
+
if (correctionText &&
|
|
211
|
+
requiredTopLevelTasks &&
|
|
212
|
+
taskToolCalls < requiredTopLevelTasks &&
|
|
213
|
+
!delegationImpossibleDeclared) {
|
|
214
|
+
await input.session.prompt(correctionText, {
|
|
215
|
+
expandPromptTemplates: false,
|
|
216
|
+
skipOrchestrationDirective: true,
|
|
217
|
+
source: "interactive",
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
unsubscribe();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
78
225
|
const IOSM_PROFILE_ONLY_COMMANDS = new Set(["iosm", "cycle-list", "cycle-plan", "cycle-status", "cycle-report"]);
|
|
79
226
|
const CHECKPOINT_LABEL_PREFIX = "checkpoint:";
|
|
80
227
|
const INTERRUPT_ABORT_TIMEOUT_MS = 8_000;
|
|
@@ -411,6 +558,7 @@ export class InteractiveMode {
|
|
|
411
558
|
// Streaming message tracking
|
|
412
559
|
this.streamingComponent = undefined;
|
|
413
560
|
this.streamingMessage = undefined;
|
|
561
|
+
this.currentTurnSawAssistantMessage = false;
|
|
414
562
|
// Tool execution tracking: toolCallId -> component
|
|
415
563
|
this.pendingTools = new Map();
|
|
416
564
|
// Subagent execution tracking with live progress/metadata for task tool calls.
|
|
@@ -1245,6 +1393,8 @@ export class InteractiveMode {
|
|
|
1245
1393
|
// Both are needed: fd for autocomplete, rg for grep tool and bash commands
|
|
1246
1394
|
const [fdPath] = await Promise.all([ensureTool("fd"), ensureTool("rg")]);
|
|
1247
1395
|
this.fdPath = fdPath;
|
|
1396
|
+
// Restore saved default model early so startup header/session are consistent after restart.
|
|
1397
|
+
await this.restoreSavedModelSelectionOnStartup();
|
|
1248
1398
|
// Add header container as first child
|
|
1249
1399
|
this.ui.addChild(this.headerContainer);
|
|
1250
1400
|
// Add header with keybindings from config (unless silenced)
|
|
@@ -1481,7 +1631,10 @@ export class InteractiveMode {
|
|
|
1481
1631
|
this.showError(`models.json error: ${modelsJsonError}`);
|
|
1482
1632
|
}
|
|
1483
1633
|
if (modelFallbackMessage) {
|
|
1484
|
-
this.
|
|
1634
|
+
const staleNoModelsWarning = this.session.model && modelFallbackMessage.startsWith("No models available.");
|
|
1635
|
+
if (!staleNoModelsWarning) {
|
|
1636
|
+
this.showWarning(modelFallbackMessage);
|
|
1637
|
+
}
|
|
1485
1638
|
}
|
|
1486
1639
|
if (!this.session.model) {
|
|
1487
1640
|
this.showWarning("No model selected. Choose a model to start.");
|
|
@@ -2912,9 +3065,18 @@ export class InteractiveMode {
|
|
|
2912
3065
|
// If streaming, use configured stream input mode (meta/followUp/steer)
|
|
2913
3066
|
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
2914
3067
|
if (this.session.isStreaming) {
|
|
3068
|
+
const streamingBehavior = resolveStreamingSubmissionMode({
|
|
3069
|
+
configuredMode: this.session.streamInputMode,
|
|
3070
|
+
activeProfileName: this.activeProfileName,
|
|
3071
|
+
activeSubagentCount: this.subagentComponents.size,
|
|
3072
|
+
activeAssistantOrchestrationContext: this.activeAssistantOrchestrationContext,
|
|
3073
|
+
});
|
|
2915
3074
|
this.editor.addToHistory?.(text);
|
|
2916
3075
|
this.editor.setText("");
|
|
2917
|
-
await this.session.prompt(text, { streamingBehavior
|
|
3076
|
+
await this.session.prompt(text, { streamingBehavior });
|
|
3077
|
+
if (streamingBehavior !== this.session.streamInputMode) {
|
|
3078
|
+
this.showStatus("Queued follow-up until meta orchestration completes");
|
|
3079
|
+
}
|
|
2918
3080
|
this.updatePendingMessagesDisplay();
|
|
2919
3081
|
this.ui.requestRender();
|
|
2920
3082
|
return;
|
|
@@ -2993,6 +3155,7 @@ export class InteractiveMode {
|
|
|
2993
3155
|
this.footer.invalidate();
|
|
2994
3156
|
switch (event.type) {
|
|
2995
3157
|
case "agent_start":
|
|
3158
|
+
this.currentTurnSawAssistantMessage = false;
|
|
2996
3159
|
// Restore main escape handler if retry handler is still active
|
|
2997
3160
|
// (retry success event fires later, but we need main handler now)
|
|
2998
3161
|
if (this.retryEscapeHandler) {
|
|
@@ -3029,6 +3192,7 @@ export class InteractiveMode {
|
|
|
3029
3192
|
this.ui.requestRender();
|
|
3030
3193
|
}
|
|
3031
3194
|
else if (event.message.role === "assistant") {
|
|
3195
|
+
this.currentTurnSawAssistantMessage = true;
|
|
3032
3196
|
this.activeAssistantOrchestrationContext = this.pendingAssistantOrchestrationContexts > 0;
|
|
3033
3197
|
if (this.activeAssistantOrchestrationContext) {
|
|
3034
3198
|
this.pendingAssistantOrchestrationContexts -= 1;
|
|
@@ -3079,6 +3243,7 @@ export class InteractiveMode {
|
|
|
3079
3243
|
if (this.streamingComponent && event.message.role === "assistant") {
|
|
3080
3244
|
this.streamingMessage = event.message;
|
|
3081
3245
|
let errorMessage;
|
|
3246
|
+
let interruptedStopReason;
|
|
3082
3247
|
if (this.streamingMessage.stopReason === "aborted") {
|
|
3083
3248
|
const retryAttempt = this.session.retryAttempt;
|
|
3084
3249
|
errorMessage =
|
|
@@ -3086,9 +3251,13 @@ export class InteractiveMode {
|
|
|
3086
3251
|
? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`
|
|
3087
3252
|
: "Operation aborted";
|
|
3088
3253
|
this.streamingMessage.errorMessage = errorMessage;
|
|
3254
|
+
interruptedStopReason = "aborted";
|
|
3089
3255
|
}
|
|
3090
3256
|
this.streamingComponent.updateContent(this.sanitizeAssistantDisplayMessage(this.streamingMessage));
|
|
3091
3257
|
if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
|
|
3258
|
+
if (this.streamingMessage.stopReason === "error") {
|
|
3259
|
+
interruptedStopReason = "error";
|
|
3260
|
+
}
|
|
3092
3261
|
if (!errorMessage) {
|
|
3093
3262
|
errorMessage = this.streamingMessage.errorMessage || "Error";
|
|
3094
3263
|
}
|
|
@@ -3106,6 +3275,9 @@ export class InteractiveMode {
|
|
|
3106
3275
|
component.setArgsComplete();
|
|
3107
3276
|
}
|
|
3108
3277
|
}
|
|
3278
|
+
if (interruptedStopReason) {
|
|
3279
|
+
this.showMetaModeInterruptionHint(interruptedStopReason);
|
|
3280
|
+
}
|
|
3109
3281
|
this.streamingComponent = undefined;
|
|
3110
3282
|
this.streamingMessage = undefined;
|
|
3111
3283
|
this.activeAssistantOrchestrationContext = false;
|
|
@@ -3325,6 +3497,9 @@ export class InteractiveMode {
|
|
|
3325
3497
|
break;
|
|
3326
3498
|
}
|
|
3327
3499
|
case "agent_end":
|
|
3500
|
+
if (this.activeProfileName === "meta" && !this.currentTurnSawAssistantMessage) {
|
|
3501
|
+
this.showMetaModeInterruptionHint("error");
|
|
3502
|
+
}
|
|
3328
3503
|
if (this.loadingAnimation) {
|
|
3329
3504
|
this.loadingAnimation.stop();
|
|
3330
3505
|
this.loadingAnimation = undefined;
|
|
@@ -3338,6 +3513,7 @@ export class InteractiveMode {
|
|
|
3338
3513
|
this.pendingTools.clear();
|
|
3339
3514
|
this.subagentComponents.clear();
|
|
3340
3515
|
this.clearSubagentElapsedTimer();
|
|
3516
|
+
this.currentTurnSawAssistantMessage = false;
|
|
3341
3517
|
await this.checkShutdownRequested();
|
|
3342
3518
|
this.ui.requestRender();
|
|
3343
3519
|
break;
|
|
@@ -3454,7 +3630,12 @@ export class InteractiveMode {
|
|
|
3454
3630
|
return;
|
|
3455
3631
|
if (message.details.kind !== "orchestration_context")
|
|
3456
3632
|
return;
|
|
3457
|
-
|
|
3633
|
+
// Hide assistant prose only for explicit legacy orchestration contracts.
|
|
3634
|
+
// META profile guidance should not suppress normal chat/task responses.
|
|
3635
|
+
const rawPrompt = message.details.rawPrompt ?? "";
|
|
3636
|
+
if (rawPrompt.includes("[ORCHESTRATION_DIRECTIVE]")) {
|
|
3637
|
+
this.pendingAssistantOrchestrationContexts += 1;
|
|
3638
|
+
}
|
|
3458
3639
|
if (message.details.rawPrompt && message.details.displayText) {
|
|
3459
3640
|
this.pendingInternalUserDisplayAliases.push({
|
|
3460
3641
|
rawPrompt: message.details.rawPrompt,
|
|
@@ -3485,6 +3666,21 @@ export class InteractiveMode {
|
|
|
3485
3666
|
this.lastStatusText = text;
|
|
3486
3667
|
this.ui.requestRender();
|
|
3487
3668
|
}
|
|
3669
|
+
showMetaModeInterruptionHint(reason) {
|
|
3670
|
+
if (this.activeProfileName !== "meta")
|
|
3671
|
+
return;
|
|
3672
|
+
const reasonText = reason === "error" ? "response failed unexpectedly" : "response was interrupted";
|
|
3673
|
+
this.showWarning(`META mode ${reasonText}. ` +
|
|
3674
|
+
"Please repeat your request following META profile rules: concrete repository task (goal + scope + constraints + expected output). " +
|
|
3675
|
+
"For conversational chat, switch profile to `full` (Shift+Tab).");
|
|
3676
|
+
}
|
|
3677
|
+
showMetaModeProfileHint() {
|
|
3678
|
+
if (this.activeProfileName !== "meta")
|
|
3679
|
+
return;
|
|
3680
|
+
this.showWarning("META mode is orchestration-first. " +
|
|
3681
|
+
"Send concrete repository tasks (goal + scope + constraints + expected output). " +
|
|
3682
|
+
"For conversational chat, switch profile to `full` (Shift+Tab).");
|
|
3683
|
+
}
|
|
3488
3684
|
showProgressLine(message) {
|
|
3489
3685
|
this.chatContainer.addChild(new Spacer(1));
|
|
3490
3686
|
this.chatContainer.addChild(new Text(theme.fg("dim", message), 1, 0));
|
|
@@ -3885,6 +4081,7 @@ export class InteractiveMode {
|
|
|
3885
4081
|
const nextActiveTools = this.getProfileToolNames(profile.name);
|
|
3886
4082
|
this.session.setActiveToolsByName(nextActiveTools);
|
|
3887
4083
|
this.session.setThinkingLevel(profile.thinkingLevel);
|
|
4084
|
+
this.session.setProfileName(profile.name);
|
|
3888
4085
|
this.profilePromptSuffix = profile.systemPromptAppend || undefined;
|
|
3889
4086
|
this.syncRuntimePromptSuffix();
|
|
3890
4087
|
this.session.setIosmAutopilotEnabled(profile.name === "iosm");
|
|
@@ -3896,6 +4093,7 @@ export class InteractiveMode {
|
|
|
3896
4093
|
this.updateEditorBorderColor();
|
|
3897
4094
|
this.refreshBuiltInHeader();
|
|
3898
4095
|
this.showStatus(`Profile: ${profile.name}`);
|
|
4096
|
+
this.showMetaModeProfileHint();
|
|
3899
4097
|
}
|
|
3900
4098
|
cycleProfile(direction) {
|
|
3901
4099
|
if (this.session.isStreaming || this.session.isCompacting || this.iosmAutomationRun || this.iosmVerificationSession) {
|
|
@@ -5533,6 +5731,29 @@ export class InteractiveMode {
|
|
|
5533
5731
|
await this.hydrateProviderModelsFromModelsDev(providerId);
|
|
5534
5732
|
}
|
|
5535
5733
|
}
|
|
5734
|
+
async restoreSavedModelSelectionOnStartup() {
|
|
5735
|
+
if (this.session.model)
|
|
5736
|
+
return;
|
|
5737
|
+
const defaultProvider = this.settingsManager.getDefaultProvider();
|
|
5738
|
+
const defaultModelId = this.settingsManager.getDefaultModel();
|
|
5739
|
+
if (!defaultProvider || !defaultModelId)
|
|
5740
|
+
return;
|
|
5741
|
+
if (!this.hasRegisteredProviderModels(defaultProvider)) {
|
|
5742
|
+
await this.hydrateProviderModelsFromModelsDev(defaultProvider);
|
|
5743
|
+
}
|
|
5744
|
+
const model = this.session.modelRegistry.find(defaultProvider, defaultModelId);
|
|
5745
|
+
if (!model)
|
|
5746
|
+
return;
|
|
5747
|
+
try {
|
|
5748
|
+
const apiKey = await this.session.modelRegistry.getApiKey(model);
|
|
5749
|
+
if (!apiKey)
|
|
5750
|
+
return;
|
|
5751
|
+
}
|
|
5752
|
+
catch {
|
|
5753
|
+
return;
|
|
5754
|
+
}
|
|
5755
|
+
this.session.agent.setModel(model);
|
|
5756
|
+
}
|
|
5536
5757
|
getApiKeyLoginProviders(modelsDevProviders) {
|
|
5537
5758
|
const providerNames = new Map();
|
|
5538
5759
|
this.apiKeyProviderDisplayNames.clear();
|
|
@@ -8627,7 +8848,7 @@ export class InteractiveMode {
|
|
|
8627
8848
|
const mentionTask = cleaned.length > 0 ? cleaned : userInput;
|
|
8628
8849
|
const orchestrationAwareAgent = /orchestrator/i.test(mentionedAgent);
|
|
8629
8850
|
const mentionMode = orchestrationAwareAgent ? "parallel" : "sequential";
|
|
8630
|
-
const mentionMaxParallel = orchestrationAwareAgent ?
|
|
8851
|
+
const mentionMaxParallel = orchestrationAwareAgent ? MAX_ORCHESTRATION_PARALLEL : undefined;
|
|
8631
8852
|
const mentionPrompt = [
|
|
8632
8853
|
`<orchestrate mode="${mentionMode}" agents="1"${mentionMaxParallel ? ` max_parallel="${mentionMaxParallel}"` : ""}>`,
|
|
8633
8854
|
`- agent 1: profile=${this.activeProfileName} cwd=${this.sessionManager.getCwd()} agent=${mentionedAgent}`,
|
|
@@ -8638,8 +8859,8 @@ export class InteractiveMode {
|
|
|
8638
8859
|
...(orchestrationAwareAgent
|
|
8639
8860
|
? [
|
|
8640
8861
|
"- Include delegate_parallel_hint in the task call.",
|
|
8641
|
-
|
|
8642
|
-
|
|
8862
|
+
`- If user explicitly requested an agent count, set delegate_parallel_hint to that count (clamp 1..${MAX_SUBAGENT_DELEGATE_PARALLEL}).`,
|
|
8863
|
+
`- Otherwise set delegate_parallel_hint based on complexity: simple=1, medium=3-6, complex/risky=7-${MAX_SUBAGENT_DELEGATE_PARALLEL}.`,
|
|
8643
8864
|
"- For non-trivial tasks, prefer delegate_parallel_hint >= 2 and split into independent <delegate_task> workstreams.",
|
|
8644
8865
|
'- Prefer existing custom agents for delegated work when suitable (use <delegate_task agent="name" ...>).',
|
|
8645
8866
|
"- If no existing custom agent fits, create focused delegate streams via profile-based <delegate_task> blocks.",
|
|
@@ -8654,6 +8875,13 @@ export class InteractiveMode {
|
|
|
8654
8875
|
});
|
|
8655
8876
|
return;
|
|
8656
8877
|
}
|
|
8878
|
+
if (this.activeProfileName === "meta") {
|
|
8879
|
+
await promptMetaWithParallelismGuard({
|
|
8880
|
+
session: this.session,
|
|
8881
|
+
userInput,
|
|
8882
|
+
});
|
|
8883
|
+
return;
|
|
8884
|
+
}
|
|
8657
8885
|
await this.session.prompt(userInput);
|
|
8658
8886
|
}
|
|
8659
8887
|
createIosmVerificationEventBridge(options) {
|
|
@@ -9109,8 +9337,8 @@ export class InteractiveMode {
|
|
|
9109
9337
|
if (token === "--max-parallel") {
|
|
9110
9338
|
const next = rest[index + 1];
|
|
9111
9339
|
const parsed = next ? Number.parseInt(next, 10) : Number.NaN;
|
|
9112
|
-
if (!Number.isInteger(parsed) || parsed < 1 || parsed >
|
|
9113
|
-
this.showWarning(
|
|
9340
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_ORCHESTRATION_PARALLEL) {
|
|
9341
|
+
this.showWarning(`Invalid --max-parallel value (expected 1..${MAX_ORCHESTRATION_PARALLEL}).`);
|
|
9114
9342
|
return undefined;
|
|
9115
9343
|
}
|
|
9116
9344
|
maxParallel = parsed;
|
|
@@ -9627,7 +9855,7 @@ export class InteractiveMode {
|
|
|
9627
9855
|
index: indexInfo.index,
|
|
9628
9856
|
});
|
|
9629
9857
|
const runId = `swarm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
9630
|
-
const maxParallel = Math.max(1, Math.min(
|
|
9858
|
+
const maxParallel = Math.max(1, Math.min(MAX_ORCHESTRATION_PARALLEL, options.maxParallel ?? 3));
|
|
9631
9859
|
const meta = this.buildSwarmRunMeta({
|
|
9632
9860
|
runId,
|
|
9633
9861
|
source: "plain",
|
|
@@ -9671,7 +9899,7 @@ export class InteractiveMode {
|
|
|
9671
9899
|
index: indexInfo.index,
|
|
9672
9900
|
});
|
|
9673
9901
|
const runId = `swarm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
9674
|
-
const maxParallel = Math.max(1, Math.min(
|
|
9902
|
+
const maxParallel = Math.max(1, Math.min(MAX_ORCHESTRATION_PARALLEL, input.maxParallel ?? 3));
|
|
9675
9903
|
const meta = this.buildSwarmRunMeta({
|
|
9676
9904
|
runId,
|
|
9677
9905
|
source: "singular",
|
|
@@ -9941,8 +10169,8 @@ export class InteractiveMode {
|
|
|
9941
10169
|
if (arg === "--agents") {
|
|
9942
10170
|
const value = args[index + 1];
|
|
9943
10171
|
const parsed = value ? Number.parseInt(value, 10) : Number.NaN;
|
|
9944
|
-
if (!Number.isInteger(parsed) || parsed < 1 || parsed >
|
|
9945
|
-
this.showWarning(
|
|
10172
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_ORCHESTRATION_AGENTS) {
|
|
10173
|
+
this.showWarning(`Invalid --agents value (expected 1..${MAX_ORCHESTRATION_AGENTS}).`);
|
|
9946
10174
|
return undefined;
|
|
9947
10175
|
}
|
|
9948
10176
|
agents = parsed;
|
|
@@ -9952,8 +10180,8 @@ export class InteractiveMode {
|
|
|
9952
10180
|
if (arg === "--max-parallel") {
|
|
9953
10181
|
const value = args[index + 1];
|
|
9954
10182
|
const parsed = value ? Number.parseInt(value, 10) : Number.NaN;
|
|
9955
|
-
if (!Number.isInteger(parsed) || parsed < 1 || parsed >
|
|
9956
|
-
this.showWarning(
|
|
10183
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_ORCHESTRATION_PARALLEL) {
|
|
10184
|
+
this.showWarning(`Invalid --max-parallel value (expected 1..${MAX_ORCHESTRATION_PARALLEL}).`);
|
|
9957
10185
|
return undefined;
|
|
9958
10186
|
}
|
|
9959
10187
|
maxParallel = parsed;
|
|
@@ -10484,7 +10712,7 @@ export class InteractiveMode {
|
|
|
10484
10712
|
"You are generating a custom IOSM subagent specification.",
|
|
10485
10713
|
"Return ONLY a single JSON object and no additional text.",
|
|
10486
10714
|
'Allowed JSON keys: name, description, profile, tools, disallowed_tools, system_prompt, cwd, background, instructions.',
|
|
10487
|
-
'profile must be one of: full, plan, iosm, explore, iosm_analyst, iosm_verifier, cycle_planner.',
|
|
10715
|
+
'profile must be one of: full, plan, iosm, meta, explore, iosm_analyst, iosm_verifier, cycle_planner.',
|
|
10488
10716
|
"name must be short snake/kebab case, suitable for @mention.",
|
|
10489
10717
|
"tools/disallowed_tools must be arrays of tool names when present.",
|
|
10490
10718
|
"instructions must be a concise markdown body for the agent file.",
|