pi-subagents 0.54.0 → 0.55.0
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 +35 -1
- package/agents/reviewer.md +12 -2
- package/docs/agents.md +4 -4
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +14 -4
- package/docs/models.md +24 -3
- package/docs/observability.md +14 -3
- package/docs/tool-reference.md +21 -6
- package/docs/workflows.md +7 -1
- package/package.json +1 -1
- package/prompts/council.md +9 -0
- package/prompts/parallel-review.md +5 -1
- package/prompts/review-loop.md +9 -5
- package/skills/council-mode/SKILL.md +33 -10
- package/skills/pi-subagents/references/constraints-and-recipes.md +16 -1
- package/skills/pi-subagents/references/execution-controls.md +11 -4
- package/skills/pi-subagents/references/multi-lane-orchestration.md +3 -3
- package/skills/pi-subagents/references/prompting-and-roles.md +8 -8
- package/src/agents/agent-management.ts +30 -9
- package/src/agents/agent-serializer.ts +2 -2
- package/src/agents/agents.ts +146 -41
- package/src/api/external-job-provider.ts +10 -1
- package/src/api/preflight.ts +26 -17
- package/src/api/project-panes.ts +2 -0
- package/src/extension/index.ts +20 -1
- package/src/extension/public-execution.ts +12 -9
- package/src/extension/rpc.ts +77 -3
- package/src/extension/schemas.ts +2 -1
- package/src/extension/tool-description.ts +9 -6
- package/src/inspectors/herdr/focus.ts +55 -0
- package/src/inspectors/herdr/project-panes.ts +228 -44
- package/src/integrations/herdr-status.ts +26 -4
- package/src/runs/background/async-execution.ts +103 -9
- package/src/runs/background/async-job-tracker.ts +33 -14
- package/src/runs/background/async-resume.ts +20 -2
- package/src/runs/background/async-status.ts +10 -0
- package/src/runs/background/control-channel.ts +98 -10
- package/src/runs/background/notify.ts +62 -1
- package/src/runs/background/run-status.ts +15 -1
- package/src/runs/background/subagent-runner.ts +226 -37
- package/src/runs/foreground/async-stop-action.ts +23 -2
- package/src/runs/foreground/execution.ts +81 -7
- package/src/runs/foreground/subagent-executor.ts +348 -40
- package/src/runs/foreground/workflow-detach-reconcile.ts +3 -0
- package/src/runs/shared/acceptance.ts +1 -0
- package/src/runs/shared/child-identity.ts +36 -0
- package/src/runs/shared/completion-guard.ts +50 -1
- package/src/runs/shared/external-job-bridge.ts +53 -37
- package/src/runs/shared/external-job-runner.ts +126 -23
- package/src/runs/shared/model-fallback.ts +10 -0
- package/src/runs/shared/orca-progress-tabs.ts +71 -9
- package/src/runs/shared/parallel-utils.ts +12 -0
- package/src/runs/shared/pi-args.ts +9 -12
- package/src/runs/shared/subagent-prompt-runtime.ts +3 -1
- package/src/runs/shared/tool-availability.ts +1 -3
- package/src/shared/launch-contract.ts +6 -5
- package/src/shared/thinking-ceiling.ts +52 -0
- package/src/shared/types.ts +59 -2
- package/src/tui/fleet-status.ts +66 -13
- package/src/tui/render.ts +5 -4
- package/src/workflows/scripted-workflow.ts +107 -10
package/src/agents/agents.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { parseMemoryFrontmatter } from "./agent-memory.ts";
|
|
|
22
22
|
import { resolveTurnBudgetConfig } from "../runs/shared/turn-budget.ts";
|
|
23
23
|
import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
24
24
|
import { validatePermissionRules, type PermissionRules } from "../runs/shared/permissions.ts";
|
|
25
|
+
import { parseThinkingLevel, type ThinkingLevel } from "../shared/thinking-ceiling.ts";
|
|
25
26
|
|
|
26
27
|
export type AgentScope = "user" | "project" | "both";
|
|
27
28
|
|
|
@@ -50,8 +51,11 @@ export function defaultInheritSkills(): boolean {
|
|
|
50
51
|
|
|
51
52
|
export interface BuiltinAgentOverrideBase {
|
|
52
53
|
description?: string;
|
|
54
|
+
output?: string;
|
|
53
55
|
outputMode?: OutputMode;
|
|
56
|
+
defaultReads?: string[];
|
|
54
57
|
model?: string;
|
|
58
|
+
modelProvider?: string;
|
|
55
59
|
fallbackModels?: string[];
|
|
56
60
|
thinking?: string | false;
|
|
57
61
|
systemPromptMode: SystemPromptMode;
|
|
@@ -73,8 +77,11 @@ export interface BuiltinAgentOverrideBase {
|
|
|
73
77
|
|
|
74
78
|
interface BuiltinAgentOverrideConfig {
|
|
75
79
|
description?: string;
|
|
80
|
+
output?: string | false;
|
|
76
81
|
outputMode?: OutputMode;
|
|
82
|
+
defaultReads?: string[] | false;
|
|
77
83
|
model?: string | false;
|
|
84
|
+
defaultProvider?: string | false;
|
|
78
85
|
fallbackModels?: string[] | false;
|
|
79
86
|
thinking?: string | false;
|
|
80
87
|
systemPromptMode?: SystemPromptMode;
|
|
@@ -103,6 +110,7 @@ export interface AgentModelSourceInfo {
|
|
|
103
110
|
scope: "user" | "project";
|
|
104
111
|
path: string;
|
|
105
112
|
model: string;
|
|
113
|
+
defaultProvider?: string;
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
export interface AgentConfig {
|
|
@@ -118,6 +126,7 @@ export interface AgentConfig {
|
|
|
118
126
|
tools?: string[];
|
|
119
127
|
mcpDirectTools?: string[];
|
|
120
128
|
model?: string;
|
|
129
|
+
modelProvider?: string;
|
|
121
130
|
fallbackModels?: string[];
|
|
122
131
|
thinking?: string | false;
|
|
123
132
|
systemPromptMode: SystemPromptMode;
|
|
@@ -153,6 +162,7 @@ export interface AgentConfig {
|
|
|
153
162
|
extraFields?: Record<string, string>;
|
|
154
163
|
override?: BuiltinAgentOverrideInfo;
|
|
155
164
|
modelSource?: AgentModelSourceInfo;
|
|
165
|
+
maxThinking?: ThinkingLevel;
|
|
156
166
|
}
|
|
157
167
|
|
|
158
168
|
type ProjectRootResolution = "nearest" | "git-root";
|
|
@@ -160,7 +170,9 @@ type ProjectRootResolution = "nearest" | "git-root";
|
|
|
160
170
|
interface SubagentSettings {
|
|
161
171
|
overrides: Record<string, BuiltinAgentOverrideConfig>;
|
|
162
172
|
defaultModel?: string;
|
|
173
|
+
defaultProvider?: string;
|
|
163
174
|
defaultThinking?: string;
|
|
175
|
+
maxThinking?: ThinkingLevel;
|
|
164
176
|
defaultExtensions?: string[];
|
|
165
177
|
disableBuiltins?: boolean;
|
|
166
178
|
disableThinking?: boolean;
|
|
@@ -252,6 +264,7 @@ interface AgentDiscoveryResult {
|
|
|
252
264
|
agentDiagnostics?: AgentDiscoveryDiagnostic[];
|
|
253
265
|
projectAgentsDir: string | null;
|
|
254
266
|
modelScope?: ModelScopeConfig;
|
|
267
|
+
maxThinking?: ThinkingLevel;
|
|
255
268
|
}
|
|
256
269
|
|
|
257
270
|
function getUserChainDir(): string {
|
|
@@ -621,8 +634,11 @@ function arraysEqual(a: string[] | undefined, b: string[] | undefined): boolean
|
|
|
621
634
|
function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
622
635
|
return {
|
|
623
636
|
description: agent.description,
|
|
637
|
+
...(agent.output !== undefined ? { output: agent.output } : {}),
|
|
624
638
|
...(agent.outputMode !== undefined ? { outputMode: agent.outputMode } : {}),
|
|
639
|
+
...(agent.defaultReads !== undefined ? { defaultReads: [...agent.defaultReads] } : {}),
|
|
625
640
|
...(agent.model !== undefined ? { model: agent.model } : {}),
|
|
641
|
+
...(agent.modelProvider !== undefined ? { modelProvider: agent.modelProvider } : {}),
|
|
626
642
|
...(agent.fallbackModels ? { fallbackModels: [...agent.fallbackModels] } : {}),
|
|
627
643
|
...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
|
|
628
644
|
systemPromptMode: agent.systemPromptMode,
|
|
@@ -646,8 +662,11 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
646
662
|
function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentOverrideConfig {
|
|
647
663
|
return {
|
|
648
664
|
...(override.description !== undefined ? { description: override.description } : {}),
|
|
665
|
+
...(override.output !== undefined ? { output: override.output } : {}),
|
|
649
666
|
...(override.outputMode !== undefined ? { outputMode: override.outputMode } : {}),
|
|
667
|
+
...(override.defaultReads !== undefined ? { defaultReads: override.defaultReads === false ? false : [...override.defaultReads] } : {}),
|
|
650
668
|
...(override.model !== undefined ? { model: override.model } : {}),
|
|
669
|
+
...(override.defaultProvider !== undefined ? { defaultProvider: override.defaultProvider } : {}),
|
|
651
670
|
...(override.fallbackModels !== undefined
|
|
652
671
|
? { fallbackModels: override.fallbackModels === false ? false : [...override.fallbackModels] }
|
|
653
672
|
: {}),
|
|
@@ -827,6 +846,11 @@ function parseBuiltinOverrideEntry(
|
|
|
827
846
|
}
|
|
828
847
|
}
|
|
829
848
|
|
|
849
|
+
if ("output" in input) {
|
|
850
|
+
if ((typeof input.output === "string" && input.output.trim()) || input.output === false) override.output = input.output;
|
|
851
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'output'; expected a non-empty string or false.`);
|
|
852
|
+
}
|
|
853
|
+
|
|
830
854
|
if ("outputMode" in input) {
|
|
831
855
|
if (input.outputMode === "inline" || input.outputMode === "file-only") {
|
|
832
856
|
override.outputMode = input.outputMode;
|
|
@@ -916,9 +940,18 @@ function parseBuiltinOverrideEntry(
|
|
|
916
940
|
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPrompt'; expected a string.`);
|
|
917
941
|
}
|
|
918
942
|
|
|
943
|
+
const defaultReads = parseOverrideStringArrayOrFalse(input.defaultReads, { filePath, name, field: "defaultReads" });
|
|
944
|
+
if (defaultReads !== undefined) override.defaultReads = defaultReads;
|
|
945
|
+
|
|
919
946
|
const fallbackModels = parseOverrideStringArrayOrFalse(input.fallbackModels, { filePath, name, field: "fallbackModels" });
|
|
920
947
|
if (fallbackModels !== undefined) override.fallbackModels = fallbackModels;
|
|
921
948
|
|
|
949
|
+
if ("defaultProvider" in input) {
|
|
950
|
+
if (input.defaultProvider === false) override.defaultProvider = false;
|
|
951
|
+
else if (typeof input.defaultProvider === "string" && input.defaultProvider.trim()) override.defaultProvider = input.defaultProvider.trim();
|
|
952
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'defaultProvider'; expected a non-empty string or false.`);
|
|
953
|
+
}
|
|
954
|
+
|
|
922
955
|
const skills = parseOverrideStringArrayOrFalse(input.skills, { filePath, name, field: "skills" });
|
|
923
956
|
if (skills !== undefined) override.skills = skills;
|
|
924
957
|
|
|
@@ -965,6 +998,14 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
965
998
|
throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultModel'; expected a non-empty string.`);
|
|
966
999
|
}
|
|
967
1000
|
}
|
|
1001
|
+
let defaultProvider: string | undefined;
|
|
1002
|
+
if ("defaultProvider" in subagentsObject) {
|
|
1003
|
+
if (typeof subagentsObject.defaultProvider === "string" && subagentsObject.defaultProvider.trim()) {
|
|
1004
|
+
defaultProvider = subagentsObject.defaultProvider.trim();
|
|
1005
|
+
} else {
|
|
1006
|
+
throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultProvider'; expected a non-empty string.`);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
968
1009
|
let defaultThinking: string | undefined;
|
|
969
1010
|
if ("defaultThinking" in subagentsObject) {
|
|
970
1011
|
if (typeof subagentsObject.defaultThinking === "string" && subagentsObject.defaultThinking.trim()) {
|
|
@@ -973,6 +1014,14 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
973
1014
|
throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultThinking'; expected a non-empty string.`);
|
|
974
1015
|
}
|
|
975
1016
|
}
|
|
1017
|
+
let maxThinking: ThinkingLevel | undefined;
|
|
1018
|
+
if ("maxThinking" in subagentsObject) {
|
|
1019
|
+
try {
|
|
1020
|
+
maxThinking = parseThinkingLevel(subagentsObject.maxThinking, `'${filePath}' subagents.maxThinking`);
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
throw new Error(`Subagent settings in '${filePath}' have invalid 'maxThinking'; expected one of off, minimal, low, medium, high, xhigh, or max.`, { cause: error instanceof Error ? error : undefined });
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
976
1025
|
let defaultExtensions: string[] | undefined;
|
|
977
1026
|
if ("defaultExtensions" in subagentsObject) {
|
|
978
1027
|
if (!Array.isArray(subagentsObject.defaultExtensions)
|
|
@@ -988,7 +1037,9 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
988
1037
|
const parsedSettings: SubagentSettings = {
|
|
989
1038
|
overrides: parsed,
|
|
990
1039
|
...(defaultModel !== undefined ? { defaultModel } : {}),
|
|
1040
|
+
...(defaultProvider !== undefined ? { defaultProvider } : {}),
|
|
991
1041
|
...(defaultThinking !== undefined ? { defaultThinking } : {}),
|
|
1042
|
+
...(maxThinking !== undefined ? { maxThinking } : {}),
|
|
992
1043
|
...(defaultExtensions !== undefined ? { defaultExtensions } : {}),
|
|
993
1044
|
...(disableBuiltins !== undefined ? { disableBuiltins } : {}),
|
|
994
1045
|
...(disableThinking !== undefined ? { disableThinking } : {}),
|
|
@@ -1004,25 +1055,39 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
1004
1055
|
return parsedSettings;
|
|
1005
1056
|
}
|
|
1006
1057
|
|
|
1058
|
+
function resolveSubagentDefaultProvider(
|
|
1059
|
+
userSettings: SubagentSettings,
|
|
1060
|
+
projectSettings: SubagentSettings,
|
|
1061
|
+
projectSettingsPath: string | null,
|
|
1062
|
+
): string | undefined {
|
|
1063
|
+
if (projectSettingsPath && projectSettings.defaultProvider !== undefined) return projectSettings.defaultProvider;
|
|
1064
|
+
return userSettings.defaultProvider;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1007
1067
|
function resolveSubagentDefaultModel(
|
|
1008
1068
|
userSettings: SubagentSettings,
|
|
1009
1069
|
projectSettings: SubagentSettings,
|
|
1010
1070
|
userSettingsPath: string,
|
|
1011
1071
|
projectSettingsPath: string | null,
|
|
1072
|
+
defaultProvider: string | undefined,
|
|
1012
1073
|
): AgentModelSourceInfo | undefined {
|
|
1013
1074
|
if (projectSettingsPath && projectSettings.defaultModel !== undefined) {
|
|
1014
|
-
return { type: "subagents.defaultModel", scope: "project", path: projectSettingsPath, model: projectSettings.defaultModel };
|
|
1075
|
+
return { type: "subagents.defaultModel", scope: "project", path: projectSettingsPath, model: projectSettings.defaultModel, ...(defaultProvider ? { defaultProvider } : {}) };
|
|
1015
1076
|
}
|
|
1016
1077
|
return userSettings.defaultModel !== undefined
|
|
1017
|
-
? { type: "subagents.defaultModel", scope: "user", path: userSettingsPath, model: userSettings.defaultModel }
|
|
1078
|
+
? { type: "subagents.defaultModel", scope: "user", path: userSettingsPath, model: userSettings.defaultModel, ...(defaultProvider ? { defaultProvider } : {}) }
|
|
1018
1079
|
: undefined;
|
|
1019
1080
|
}
|
|
1020
1081
|
|
|
1021
|
-
function applySubagentDefaultModel(agents: AgentConfig[], defaultModel: AgentModelSourceInfo | undefined): AgentConfig[] {
|
|
1022
|
-
if (!defaultModel) return agents;
|
|
1082
|
+
function applySubagentDefaultModel(agents: AgentConfig[], defaultModel: AgentModelSourceInfo | undefined, defaultProvider: string | undefined): AgentConfig[] {
|
|
1083
|
+
if (!defaultModel && !defaultProvider) return agents;
|
|
1023
1084
|
return agents.map((agent) => {
|
|
1024
|
-
if (agent.model !== undefined) return agent;
|
|
1025
|
-
const next = {
|
|
1085
|
+
if (agent.model !== undefined && (agent.modelProvider !== undefined || !defaultProvider)) return agent;
|
|
1086
|
+
const next = {
|
|
1087
|
+
...agent,
|
|
1088
|
+
...(agent.model === undefined && defaultModel ? { model: defaultModel.model, modelSource: defaultModel } : {}),
|
|
1089
|
+
...(defaultProvider ? { modelProvider: defaultProvider } : {}),
|
|
1090
|
+
};
|
|
1026
1091
|
const frontmatterFields = agentFrontmatterFields.get(agent);
|
|
1027
1092
|
if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
|
|
1028
1093
|
return next;
|
|
@@ -1049,6 +1114,20 @@ function applySubagentDefaultThinking(agents: AgentConfig[], defaultThinking: st
|
|
|
1049
1114
|
});
|
|
1050
1115
|
}
|
|
1051
1116
|
|
|
1117
|
+
function resolveSubagentMaxThinking(
|
|
1118
|
+
userSettings: SubagentSettings,
|
|
1119
|
+
projectSettings: SubagentSettings,
|
|
1120
|
+
projectSettingsPath: string | null,
|
|
1121
|
+
): ThinkingLevel | undefined {
|
|
1122
|
+
if (projectSettingsPath && projectSettings.maxThinking !== undefined) return projectSettings.maxThinking;
|
|
1123
|
+
return userSettings.maxThinking;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
function applySubagentMaxThinking(agents: AgentConfig[], maxThinking: ThinkingLevel | undefined): AgentConfig[] {
|
|
1127
|
+
if (maxThinking === undefined) return agents;
|
|
1128
|
+
return agents.map((agent) => agent.maxThinking === maxThinking ? agent : { ...agent, maxThinking });
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1052
1131
|
function resolveSubagentDefaultExtensions(
|
|
1053
1132
|
userSettings: SubagentSettings,
|
|
1054
1133
|
projectSettings: SubagentSettings,
|
|
@@ -1072,11 +1151,12 @@ function applySubagentDefaultExtensions(agents: AgentConfig[], defaultExtensions
|
|
|
1072
1151
|
function applySubagentDefaults(
|
|
1073
1152
|
agents: AgentConfig[],
|
|
1074
1153
|
defaultModel: AgentModelSourceInfo | undefined,
|
|
1154
|
+
defaultProvider: string | undefined,
|
|
1075
1155
|
defaultThinking: string | undefined,
|
|
1076
1156
|
defaultExtensions: string[] | undefined,
|
|
1077
1157
|
): AgentConfig[] {
|
|
1078
1158
|
return applySubagentDefaultExtensions(
|
|
1079
|
-
applySubagentDefaultThinking(applySubagentDefaultModel(agents, defaultModel), defaultThinking),
|
|
1159
|
+
applySubagentDefaultThinking(applySubagentDefaultModel(agents, defaultModel, defaultProvider), defaultThinking),
|
|
1080
1160
|
defaultExtensions,
|
|
1081
1161
|
);
|
|
1082
1162
|
}
|
|
@@ -1103,11 +1183,17 @@ function applyBuiltinOverride(
|
|
|
1103
1183
|
};
|
|
1104
1184
|
|
|
1105
1185
|
if (override.description !== undefined) next.description = override.description;
|
|
1186
|
+
if (override.output !== undefined) { if (override.output === false) delete next.output; else next.output = override.output; }
|
|
1106
1187
|
if (override.outputMode !== undefined) next.outputMode = override.outputMode;
|
|
1188
|
+
if (override.defaultReads !== undefined) { if (override.defaultReads === false) delete next.defaultReads; else next.defaultReads = [...override.defaultReads]; }
|
|
1107
1189
|
if (override.model !== undefined) {
|
|
1108
1190
|
if (override.model === false) delete next.model; else next.model = override.model;
|
|
1109
1191
|
delete next.modelSource;
|
|
1110
1192
|
}
|
|
1193
|
+
if (override.defaultProvider !== undefined) {
|
|
1194
|
+
if (override.defaultProvider === false) delete next.modelProvider;
|
|
1195
|
+
else next.modelProvider = override.defaultProvider;
|
|
1196
|
+
}
|
|
1111
1197
|
if (override.fallbackModels !== undefined) { if (override.fallbackModels === false) delete next.fallbackModels; else next.fallbackModels = [...override.fallbackModels]; }
|
|
1112
1198
|
if (override.thinking !== undefined) { if (override.thinking === false) delete next.thinking; else next.thinking = override.thinking; }
|
|
1113
1199
|
if (override.systemPromptMode !== undefined) next.systemPromptMode = override.systemPromptMode;
|
|
@@ -1221,15 +1307,24 @@ function applyCustomAgentOverride(
|
|
|
1221
1307
|
mutable().description = override.description;
|
|
1222
1308
|
anyFilled = true;
|
|
1223
1309
|
}
|
|
1310
|
+
if (override.output !== undefined) {
|
|
1311
|
+
fill("output", ["output"], override.output === false ? undefined : override.output);
|
|
1312
|
+
}
|
|
1224
1313
|
if (override.outputMode !== undefined) {
|
|
1225
1314
|
fill("outputMode", ["outputMode"], override.outputMode);
|
|
1226
1315
|
}
|
|
1316
|
+
if (override.defaultReads !== undefined) {
|
|
1317
|
+
fill("defaultReads", ["defaultReads"], override.defaultReads === false ? undefined : [...override.defaultReads]);
|
|
1318
|
+
}
|
|
1227
1319
|
if (override.model !== undefined && !agentHasFrontmatterField(agent, "model")) {
|
|
1228
1320
|
const target = mutable();
|
|
1229
1321
|
if (override.model === false) delete target.model; else target.model = override.model;
|
|
1230
1322
|
delete target.modelSource;
|
|
1231
1323
|
anyFilled = true;
|
|
1232
1324
|
}
|
|
1325
|
+
if (override.defaultProvider !== undefined) {
|
|
1326
|
+
fill("modelProvider", ["modelProvider", "defaultProvider"], override.defaultProvider === false ? undefined : override.defaultProvider);
|
|
1327
|
+
}
|
|
1233
1328
|
if (override.fallbackModels !== undefined) {
|
|
1234
1329
|
fill(
|
|
1235
1330
|
"fallbackModels",
|
|
@@ -1256,17 +1351,7 @@ function applyCustomAgentOverride(
|
|
|
1256
1351
|
fill("acceptanceRole", ["acceptanceRole"], override.acceptanceRole === false ? undefined : override.acceptanceRole);
|
|
1257
1352
|
}
|
|
1258
1353
|
if (override.disabled !== undefined) {
|
|
1259
|
-
//
|
|
1260
|
-
// frontmatter concept of `disabled` to protect (unlike model/thinking/
|
|
1261
|
-
// etc., which use `fill()` + agentHasFrontmatterField to defer to the
|
|
1262
|
-
// agent's own file). A guard here previously read `agent.disabled ===
|
|
1263
|
-
// undefined`, which was a no-op before user+project layering existed
|
|
1264
|
-
// (this function only ever ran once, against the pristine base agent,
|
|
1265
|
-
// whose `.disabled` is always undefined for custom agents) but became a
|
|
1266
|
-
// real bug once a user-scope override could run first: the guard then
|
|
1267
|
-
// silently blocked a later project-scope override from ever changing
|
|
1268
|
-
// `disabled`, breaking this PR's own "project wins" precedence for this
|
|
1269
|
-
// one field.
|
|
1354
|
+
// Custom agent files cannot set `disabled`, so project overrides replace user overrides.
|
|
1270
1355
|
mutable().disabled = override.disabled;
|
|
1271
1356
|
anyFilled = true;
|
|
1272
1357
|
}
|
|
@@ -1295,7 +1380,7 @@ function applyCustomAgentOverride(
|
|
|
1295
1380
|
}
|
|
1296
1381
|
|
|
1297
1382
|
if (!anyFilled || !next) return agent;
|
|
1298
|
-
next.override = { ...meta, base: cloneOverrideBase(agent) };
|
|
1383
|
+
next.override = { ...meta, base: agent.override?.base ?? cloneOverrideBase(agent) };
|
|
1299
1384
|
const frontmatterFields = agentFrontmatterFields.get(agent);
|
|
1300
1385
|
if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
|
|
1301
1386
|
return next;
|
|
@@ -1308,13 +1393,7 @@ function applyCustomAgentOverrides(
|
|
|
1308
1393
|
userSettingsPath: string,
|
|
1309
1394
|
projectSettingsPath: string | null,
|
|
1310
1395
|
): AgentConfig[] {
|
|
1311
|
-
//
|
|
1312
|
-
// only sets a subset of fields (e.g. just `extensions`) layers on top of the
|
|
1313
|
-
// user's override instead of silently discarding it (#1341 / issue writeup:
|
|
1314
|
-
// "agentOverrides project override drops user-only fields for custom agents").
|
|
1315
|
-
// Per-field precedence still favors project over user: applyCustomAgentOverride
|
|
1316
|
-
// only fills fields present in the override it's given, and project is applied
|
|
1317
|
-
// last, so any field set at both scopes ends up with the project's value.
|
|
1396
|
+
// Apply user then project so project fields win without dropping user-only fields.
|
|
1318
1397
|
return agents.map((agent) => {
|
|
1319
1398
|
const userOverride = userSettings.overrides[agent.name];
|
|
1320
1399
|
const withUserOverride = userOverride
|
|
@@ -1332,7 +1411,7 @@ function applyCustomAgentOverrides(
|
|
|
1332
1411
|
|
|
1333
1412
|
export function buildBuiltinOverrideConfig(
|
|
1334
1413
|
base: BuiltinAgentOverrideBase,
|
|
1335
|
-
draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "outputMode">>,
|
|
1414
|
+
draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
|
|
1336
1415
|
): BuiltinAgentOverrideConfig | undefined {
|
|
1337
1416
|
const override: BuiltinAgentOverrideConfig = {};
|
|
1338
1417
|
|
|
@@ -1340,8 +1419,11 @@ export function buildBuiltinOverrideConfig(
|
|
|
1340
1419
|
const description = draft.description.trim();
|
|
1341
1420
|
if (description && description !== base.description) override.description = description;
|
|
1342
1421
|
}
|
|
1422
|
+
if (draft.output !== base.output) override.output = draft.output ?? false;
|
|
1343
1423
|
if (draft.outputMode !== undefined && draft.outputMode !== base.outputMode) override.outputMode = draft.outputMode;
|
|
1424
|
+
if (!arraysEqual(draft.defaultReads, base.defaultReads)) override.defaultReads = draft.defaultReads ? [...draft.defaultReads] : false;
|
|
1344
1425
|
if (draft.model !== base.model) override.model = draft.model ?? false;
|
|
1426
|
+
if (draft.modelProvider !== base.modelProvider) override.defaultProvider = draft.modelProvider ?? false;
|
|
1345
1427
|
if (!arraysEqual(draft.fallbackModels, base.fallbackModels)) override.fallbackModels = draft.fallbackModels ? [...draft.fallbackModels] : false;
|
|
1346
1428
|
if (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;
|
|
1347
1429
|
if (draft.systemPromptMode !== base.systemPromptMode) override.systemPromptMode = draft.systemPromptMode;
|
|
@@ -1931,8 +2013,10 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1931
2013
|
const projectSettingsPath = getProjectAgentSettingsPath(cwd);
|
|
1932
2014
|
const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
|
|
1933
2015
|
const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
|
|
1934
|
-
const
|
|
2016
|
+
const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath);
|
|
2017
|
+
const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath, defaultProvider);
|
|
1935
2018
|
const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
|
|
2019
|
+
const maxThinking = resolveSubagentMaxThinking(userSettings, projectSettings, projectSettingsPath);
|
|
1936
2020
|
const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
|
|
1937
2021
|
const modelScope = projectSettings.modelScope ?? userSettings.modelScope;
|
|
1938
2022
|
const packageSubagentPaths = collectPackageSubagentPaths(cwd, {
|
|
@@ -1942,7 +2026,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1942
2026
|
|
|
1943
2027
|
const builtinLoaded = loadAgentsFromDefinitionFiles(BUILTIN_AGENT_DEFINITION_FILES, "builtin");
|
|
1944
2028
|
const builtinAgents = applyBuiltinOverrides(
|
|
1945
|
-
applySubagentDefaults(builtinLoaded.agents, defaultModel, defaultThinking, defaultExtensions),
|
|
2029
|
+
applySubagentDefaults(builtinLoaded.agents, defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
1946
2030
|
userSettings,
|
|
1947
2031
|
projectSettings,
|
|
1948
2032
|
userSettingsPath,
|
|
@@ -1952,7 +2036,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1952
2036
|
const userLoaded = scope === "project" ? [] : [...extraUserAgentDirs(), userDirOld, userDirNew]
|
|
1953
2037
|
.map((dir, discoveryPriority) => loadAgentsFromDir(dir, "user", discoveryPriority));
|
|
1954
2038
|
const userAgents = applyCustomAgentOverrides(
|
|
1955
|
-
applySubagentDefaults(userLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultThinking, defaultExtensions),
|
|
2039
|
+
applySubagentDefaults(userLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
1956
2040
|
userSettings,
|
|
1957
2041
|
projectSettings,
|
|
1958
2042
|
userSettingsPath,
|
|
@@ -1961,7 +2045,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1961
2045
|
|
|
1962
2046
|
const projectLoaded = scope === "user" ? [] : projectAgentDirs.map((dir) => loadAgentsFromDir(dir, "project", dir === projectAgentsDir ? 1 : 0));
|
|
1963
2047
|
const projectAgents = applyCustomAgentOverrides(
|
|
1964
|
-
applySubagentDefaults(projectLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultThinking, defaultExtensions),
|
|
2048
|
+
applySubagentDefaults(projectLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
1965
2049
|
userSettings,
|
|
1966
2050
|
projectSettings,
|
|
1967
2051
|
userSettingsPath,
|
|
@@ -1975,14 +2059,17 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1975
2059
|
}
|
|
1976
2060
|
}
|
|
1977
2061
|
const packageAgents = applyCustomAgentOverrides(
|
|
1978
|
-
applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultThinking, defaultExtensions),
|
|
2062
|
+
applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
1979
2063
|
userSettings,
|
|
1980
2064
|
projectSettings,
|
|
1981
2065
|
userSettingsPath,
|
|
1982
2066
|
projectSettingsPath,
|
|
1983
2067
|
);
|
|
1984
|
-
const agents =
|
|
1985
|
-
|
|
2068
|
+
const agents = applySubagentMaxThinking(
|
|
2069
|
+
mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents)
|
|
2070
|
+
.filter((agent) => agent.disabled !== true),
|
|
2071
|
+
maxThinking,
|
|
2072
|
+
);
|
|
1986
2073
|
|
|
1987
2074
|
const agentDiagnostics = [
|
|
1988
2075
|
...builtinLoaded.diagnostics,
|
|
@@ -1990,7 +2077,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1990
2077
|
...projectLoaded.flatMap((loaded) => loaded.diagnostics),
|
|
1991
2078
|
...packageLoaded.flatMap((loaded) => loaded.diagnostics),
|
|
1992
2079
|
];
|
|
1993
|
-
return { agents, agentDiagnostics, projectAgentsDir, ...(modelScope !== undefined ? { modelScope } : {}) };
|
|
2080
|
+
return { agents, agentDiagnostics, projectAgentsDir, ...(modelScope !== undefined ? { modelScope } : {}), ...(maxThinking !== undefined ? { maxThinking } : {}) };
|
|
1994
2081
|
}
|
|
1995
2082
|
|
|
1996
2083
|
export function discoverAgentsAll(cwd: string): {
|
|
@@ -2007,6 +2094,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2007
2094
|
projectChainDir: string | null;
|
|
2008
2095
|
userSettingsPath: string;
|
|
2009
2096
|
projectSettingsPath: string | null;
|
|
2097
|
+
maxThinking?: ThinkingLevel;
|
|
2010
2098
|
} {
|
|
2011
2099
|
const userDirOld = path.join(getAgentDir(), "agents");
|
|
2012
2100
|
const userDirNew = path.join(os.homedir(), ".agents");
|
|
@@ -2017,14 +2105,16 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2017
2105
|
const projectSettingsPath = getProjectAgentSettingsPath(cwd);
|
|
2018
2106
|
const userSettings = readSubagentSettings(userSettingsPath);
|
|
2019
2107
|
const projectSettings = readSubagentSettings(projectSettingsPath);
|
|
2020
|
-
const
|
|
2108
|
+
const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath);
|
|
2109
|
+
const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath, defaultProvider);
|
|
2021
2110
|
const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
|
|
2111
|
+
const maxThinking = resolveSubagentMaxThinking(userSettings, projectSettings, projectSettingsPath);
|
|
2022
2112
|
const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
|
|
2023
2113
|
const packageSubagentPaths = collectPackageSubagentPaths(cwd);
|
|
2024
2114
|
|
|
2025
2115
|
const builtinLoaded = loadAgentsFromDefinitionFiles(BUILTIN_AGENT_DEFINITION_FILES, "builtin");
|
|
2026
2116
|
const builtin = applyBuiltinOverrides(
|
|
2027
|
-
applySubagentDefaults(builtinLoaded.agents, defaultModel, defaultThinking, defaultExtensions),
|
|
2117
|
+
applySubagentDefaults(builtinLoaded.agents, defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
2028
2118
|
userSettings,
|
|
2029
2119
|
projectSettings,
|
|
2030
2120
|
userSettingsPath,
|
|
@@ -2033,7 +2123,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2033
2123
|
const userLoaded = [...extraUserAgentDirs(), userDirOld, userDirNew]
|
|
2034
2124
|
.map((dir, discoveryPriority) => loadAgentsFromDir(dir, "user", discoveryPriority));
|
|
2035
2125
|
const user = applyCustomAgentOverrides(
|
|
2036
|
-
applySubagentDefaults(userLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultThinking, defaultExtensions),
|
|
2126
|
+
applySubagentDefaults(userLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
2037
2127
|
userSettings,
|
|
2038
2128
|
projectSettings,
|
|
2039
2129
|
userSettingsPath,
|
|
@@ -2049,7 +2139,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2049
2139
|
}
|
|
2050
2140
|
}
|
|
2051
2141
|
const packageAgents = applyCustomAgentOverrides(
|
|
2052
|
-
applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultThinking, defaultExtensions),
|
|
2142
|
+
applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
2053
2143
|
userSettings,
|
|
2054
2144
|
projectSettings,
|
|
2055
2145
|
userSettingsPath,
|
|
@@ -2065,7 +2155,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2065
2155
|
}
|
|
2066
2156
|
}
|
|
2067
2157
|
const project = applyCustomAgentOverrides(
|
|
2068
|
-
applySubagentDefaults(Array.from(projectMap.values()), defaultModel, defaultThinking, defaultExtensions),
|
|
2158
|
+
applySubagentDefaults(Array.from(projectMap.values()), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
|
|
2069
2159
|
userSettings,
|
|
2070
2160
|
projectSettings,
|
|
2071
2161
|
userSettingsPath,
|
|
@@ -2110,5 +2200,20 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2110
2200
|
|
|
2111
2201
|
const userDir = process.env.PI_CODING_AGENT_DIR ? userDirOld : fs.existsSync(userDirNew) ? userDirNew : userDirOld;
|
|
2112
2202
|
|
|
2113
|
-
return {
|
|
2203
|
+
return {
|
|
2204
|
+
builtin: applySubagentMaxThinking(builtin, maxThinking),
|
|
2205
|
+
package: applySubagentMaxThinking(packageAgents, maxThinking),
|
|
2206
|
+
user: applySubagentMaxThinking(user, maxThinking),
|
|
2207
|
+
project: applySubagentMaxThinking(project, maxThinking),
|
|
2208
|
+
agentDiagnostics,
|
|
2209
|
+
chains,
|
|
2210
|
+
chainDiagnostics,
|
|
2211
|
+
userDir,
|
|
2212
|
+
projectDir,
|
|
2213
|
+
userChainDir,
|
|
2214
|
+
projectChainDir,
|
|
2215
|
+
userSettingsPath,
|
|
2216
|
+
projectSettingsPath,
|
|
2217
|
+
...(maxThinking !== undefined ? { maxThinking } : {}),
|
|
2218
|
+
};
|
|
2114
2219
|
}
|
|
@@ -9,7 +9,7 @@ const MAX_FAILURE_MESSAGE_LENGTH = 4_096;
|
|
|
9
9
|
const MAX_URL_LENGTH = 4_096;
|
|
10
10
|
|
|
11
11
|
export type ExternalJobState = "queued" | "running" | "completed" | "failed" | "stopped" | "blocked";
|
|
12
|
-
export type ExternalJobOperation = "start" | "status" | "result" | "reattach";
|
|
12
|
+
export type ExternalJobOperation = "start" | "follow-up" | "status" | "result" | "reattach";
|
|
13
13
|
|
|
14
14
|
export type ExternalJobOptions = Record<string, unknown>;
|
|
15
15
|
|
|
@@ -24,6 +24,14 @@ export interface ExternalJobStartInput {
|
|
|
24
24
|
sessionId?: string;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export interface ExternalJobFollowUpInput extends ExternalJobStartInput {
|
|
28
|
+
sourceRunId: string;
|
|
29
|
+
sourceStepIndex: number;
|
|
30
|
+
parentProviderJobId: string;
|
|
31
|
+
requestId: string;
|
|
32
|
+
requestDigest: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
export interface ExternalJobHandle {
|
|
28
36
|
providerJobId: string;
|
|
29
37
|
state: ExternalJobState;
|
|
@@ -42,6 +50,7 @@ export interface ExternalJobResult extends ExternalJobHandle {
|
|
|
42
50
|
export interface ExternalJobProvider {
|
|
43
51
|
name: string;
|
|
44
52
|
start(input: ExternalJobStartInput): Promise<ExternalJobHandle> | ExternalJobHandle;
|
|
53
|
+
followUp?(input: ExternalJobFollowUpInput): Promise<ExternalJobHandle> | ExternalJobHandle;
|
|
45
54
|
status(providerJobId: string): Promise<ExternalJobHandle> | ExternalJobHandle;
|
|
46
55
|
result(providerJobId: string): Promise<ExternalJobResult> | ExternalJobResult;
|
|
47
56
|
reattach(providerJobId: string): Promise<ExternalJobHandle> | ExternalJobHandle;
|
package/src/api/preflight.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import * as fs from "node:fs";
|
|
3
2
|
import * as path from "node:path";
|
|
4
3
|
import { fileURLToPath } from "node:url";
|
|
@@ -12,6 +11,7 @@ import { applyThinkingSuffix, resolvePiLaunchToolPlan, type PiLaunchToolPlan } f
|
|
|
12
11
|
import { injectOutputPathSystemPrompt, normalizeSingleOutputOverride, resolveSingleOutputPath } from "../runs/shared/single-output.ts";
|
|
13
12
|
import { getArtifactPaths, getArtifactsDir } from "../shared/artifacts.ts";
|
|
14
13
|
import { resolveEffectiveThinking } from "../shared/model-info.ts";
|
|
14
|
+
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV, type ThinkingLevel } from "../shared/thinking-ceiling.ts";
|
|
15
15
|
import { SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, type ArtifactDirPreference, type ArtifactPaths, type JsonSchemaObject, type OutputMode } from "../shared/types.ts";
|
|
16
16
|
import { capabilityCeilingAgentRestrictionMessage, intersectSubagentCapabilityCeilings, type ResolvedSubagentCapabilityCeiling, type SubagentCapabilityAudit } from "../runs/shared/capability-ceiling.ts";
|
|
17
17
|
import { appendTurnBudgetSystemPrompt } from "../runs/shared/turn-budget.ts";
|
|
@@ -21,7 +21,7 @@ import type { ResolvedMcpDirectToolSelection } from "../runs/shared/mcp-direct-t
|
|
|
21
21
|
import { resolveStepBehavior } from "../shared/settings.ts";
|
|
22
22
|
import { canPreferForkFromSnapshot, resolveSubagentLaunchContext } from "../shared/fork-context.ts";
|
|
23
23
|
import { loadConfig } from "../extension/config.ts";
|
|
24
|
-
import { agentDefinitionDigest, AGENT_DEFINITION_PROJECTION_VERSION, launchBindingDigest } from "../shared/launch-contract.ts";
|
|
24
|
+
import { agentDefinitionDigest, AGENT_DEFINITION_PROJECTION_VERSION, launchBindingDigest, stableJsonDigest } from "../shared/launch-contract.ts";
|
|
25
25
|
import { DIRS, TEMP_ROOT_DIR } from "../shared/types.ts";
|
|
26
26
|
import { processTerminalCandidatePath, processTerminalPath } from "../runs/background/process-terminal.ts";
|
|
27
27
|
import { resultFilePath } from "../runs/background/result-files.ts";
|
|
@@ -37,7 +37,8 @@ export type SubagentLaunchContractReasonCode =
|
|
|
37
37
|
| "invalid_artifact_dir"
|
|
38
38
|
| "invalid_cwd"
|
|
39
39
|
| "unsupported_mode"
|
|
40
|
-
| "restricted_agent"
|
|
40
|
+
| "restricted_agent"
|
|
41
|
+
| "thinking_ceiling";
|
|
41
42
|
|
|
42
43
|
export interface SubagentLaunchContractDiagnostic {
|
|
43
44
|
code: SubagentLaunchContractReasonCode | "host_required" | "snapshot_warning";
|
|
@@ -53,6 +54,8 @@ export interface SubagentLaunchContractInput {
|
|
|
53
54
|
context?: "fresh" | "fork";
|
|
54
55
|
model?: string;
|
|
55
56
|
thinking?: string | false;
|
|
57
|
+
thinkingCeiling?: ThinkingLevel;
|
|
58
|
+
inheritedThinkingCeiling?: ThinkingLevel;
|
|
56
59
|
parentModel?: ParentModel;
|
|
57
60
|
availableModels?: ReadonlyArray<AvailableModelInfo | { provider: string; id: string; fullId?: string; reasoning?: boolean }>;
|
|
58
61
|
preferredProvider?: string;
|
|
@@ -147,6 +150,7 @@ export interface SubagentLaunchContract {
|
|
|
147
150
|
model?: string;
|
|
148
151
|
modelCandidates: string[];
|
|
149
152
|
thinking?: string;
|
|
153
|
+
thinkingCeiling?: ThinkingLevel;
|
|
150
154
|
systemPromptMode: AgentConfig["systemPromptMode"];
|
|
151
155
|
inheritProjectContext: boolean;
|
|
152
156
|
inheritSkills: boolean;
|
|
@@ -176,20 +180,8 @@ function packageVersion(): string {
|
|
|
176
180
|
return parsed.version;
|
|
177
181
|
}
|
|
178
182
|
|
|
179
|
-
function stableJson(value: unknown): string {
|
|
180
|
-
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
181
|
-
if (value && typeof value === "object") {
|
|
182
|
-
return `{${Object.entries(value as Record<string, unknown>)
|
|
183
|
-
.filter(([, entry]) => entry !== undefined)
|
|
184
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
185
|
-
.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
|
|
186
|
-
.join(",")}}`;
|
|
187
|
-
}
|
|
188
|
-
return JSON.stringify(value);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
183
|
function digestContract(contract: Omit<SubagentLaunchContract, "digest">): string {
|
|
192
|
-
return
|
|
184
|
+
return stableJsonDigest(contract);
|
|
193
185
|
}
|
|
194
186
|
|
|
195
187
|
function normalizeAvailableModels(models: SubagentLaunchContractInput["availableModels"]): AvailableModelInfo[] {
|
|
@@ -289,12 +281,18 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
289
281
|
|
|
290
282
|
const externalRunner = agent.runner?.type === "external-cli" || agent.runner?.type === "external-job";
|
|
291
283
|
const availableModels = normalizeAvailableModels(input.availableModels);
|
|
292
|
-
const preferredProvider = input.preferredProvider ?? input.parentModel?.provider;
|
|
284
|
+
const preferredProvider = agent.modelProvider ?? input.preferredProvider ?? input.parentModel?.provider;
|
|
293
285
|
const modelScopes = resolveModelScopesForAgent(discovered.modelScope, agent.name, input.parentModel);
|
|
294
286
|
const primaryModel = externalRunner
|
|
295
287
|
? undefined
|
|
296
288
|
: resolveEffectiveSubagentModel(input.model, agent.model, input.parentModel, availableModels, preferredProvider, { scope: modelScopes });
|
|
297
289
|
const effectiveThinkingConfig = input.thinking !== undefined ? input.thinking : agent.thinking;
|
|
290
|
+
const thinkingCeiling = externalRunner ? undefined : intersectThinkingCeilings(
|
|
291
|
+
discovered.maxThinking,
|
|
292
|
+
input.thinkingCeiling,
|
|
293
|
+
input.inheritedThinkingCeiling,
|
|
294
|
+
decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]),
|
|
295
|
+
);
|
|
298
296
|
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinkingConfig, input.thinking !== undefined);
|
|
299
297
|
const modelCandidates = externalRunner
|
|
300
298
|
? []
|
|
@@ -303,6 +301,16 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
303
301
|
primaryModelFromParent: inheritsParentModel(input.model, agent.model, input.parentModel),
|
|
304
302
|
})
|
|
305
303
|
.map((candidate) => applyThinkingSuffix(candidate, effectiveThinkingConfig, input.thinking !== undefined) ?? candidate);
|
|
304
|
+
if (!externalRunner) {
|
|
305
|
+
try {
|
|
306
|
+
assertThinkingWithinCeiling({ model, configThinking: effectiveThinkingConfig, ceiling: thinkingCeiling, agent: agent.name, runId });
|
|
307
|
+
for (const candidate of modelCandidates) assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinkingConfig, ceiling: thinkingCeiling, agent: agent.name, runId });
|
|
308
|
+
} catch (error) {
|
|
309
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
310
|
+
diagnostics.push({ code: "thinking_ceiling", severity: "error", message });
|
|
311
|
+
return { ok: false, code: "thinking_ceiling", message, diagnostics };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
306
314
|
let toolPlan: PiLaunchToolPlan;
|
|
307
315
|
const permissionRules = resolvePermissionRules(loadConfig().permissions, agent.permissions);
|
|
308
316
|
try {
|
|
@@ -372,6 +380,7 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
372
380
|
...(model ? { model } : {}),
|
|
373
381
|
modelCandidates,
|
|
374
382
|
...(resolveEffectiveThinking(model, effectiveThinkingConfig) ? { thinking: resolveEffectiveThinking(model, effectiveThinkingConfig) } : {}),
|
|
383
|
+
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
375
384
|
systemPromptMode: agent.systemPromptMode,
|
|
376
385
|
inheritProjectContext: agent.inheritProjectContext,
|
|
377
386
|
inheritSkills: agent.inheritSkills,
|
package/src/api/project-panes.ts
CHANGED
|
@@ -10,6 +10,7 @@ export {
|
|
|
10
10
|
createProjectPaneManager,
|
|
11
11
|
openProjectPane,
|
|
12
12
|
getProjectPaneStatus,
|
|
13
|
+
focusProjectPane,
|
|
13
14
|
closeProjectPane,
|
|
14
15
|
readProjectPaneBinding,
|
|
15
16
|
projectPaneBindingPath,
|
|
@@ -21,6 +22,7 @@ export {
|
|
|
21
22
|
type CloseProjectPaneOptions,
|
|
22
23
|
type OpenProjectPaneData,
|
|
23
24
|
type ProjectPaneStatusData,
|
|
25
|
+
type FocusProjectPaneData,
|
|
24
26
|
type CloseProjectPaneData,
|
|
25
27
|
type ProjectPaneRuntime,
|
|
26
28
|
type ProjectPaneError,
|