@oh-my-pi/pi-coding-agent 15.10.11 → 15.10.12
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 +44 -0
- package/dist/cli.js +5349 -5328
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/api-key-resolver.d.ts +3 -0
- package/dist/types/config/model-registry.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +18 -0
- package/dist/types/config/settings-schema.d.ts +29 -1
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/eval/py/executor.d.ts +5 -0
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -2
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +66 -1
- package/dist/types/modes/index.d.ts +3 -3
- package/dist/types/modes/interactive-mode.d.ts +7 -2
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
- package/dist/types/modes/setup-wizard/index.d.ts +5 -1
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +8 -2
- package/dist/types/session/agent-session.d.ts +14 -2
- package/dist/types/session/streaming-output.d.ts +23 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
- package/dist/types/slash-commands/types.d.ts +1 -1
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/index.d.ts +2 -2
- package/dist/types/task/types.d.ts +8 -0
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +11 -0
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/index.d.ts +6 -0
- package/dist/types/utils/git.d.ts +15 -2
- package/dist/types/utils/title-generator.d.ts +3 -2
- package/package.json +10 -10
- package/src/auto-thinking/classifier.ts +1 -0
- package/src/cli/args.ts +3 -0
- package/src/cli-commands.ts +29 -0
- package/src/cli.ts +8 -9
- package/src/commands/launch.ts +4 -0
- package/src/commit/model-selection.ts +3 -2
- package/src/config/api-key-resolver.ts +8 -6
- package/src/config/model-registry.ts +97 -30
- package/src/config/model-resolver.ts +60 -0
- package/src/config/settings-schema.ts +43 -15
- package/src/config/settings.ts +61 -3
- package/src/edit/hashline/execute.ts +39 -2
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/eval/completion-bridge.ts +1 -0
- package/src/eval/py/executor.ts +29 -7
- package/src/eval/py/index.ts +6 -1
- package/src/eval/py/kernel.ts +31 -11
- package/src/eval/py/runtime.ts +37 -0
- package/src/exec/bash-executor.ts +82 -3
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/runner.ts +6 -1
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/hindsight/bank.ts +17 -2
- package/src/internal-urls/docs-index.generated.ts +3 -3
- package/src/main.ts +18 -6
- package/src/memories/index.ts +2 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/local-backend.ts +9 -0
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +81 -1
- package/src/mnemopi/backend.ts +151 -4
- package/src/modes/acp/acp-agent.ts +119 -11
- package/src/modes/components/assistant-message.ts +19 -21
- package/src/modes/components/footer.ts +3 -1
- package/src/modes/components/status-line/component.ts +118 -34
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/input-controller.ts +1 -0
- package/src/modes/controllers/mcp-command-controller.ts +38 -3
- package/src/modes/index.ts +3 -21
- package/src/modes/interactive-mode.ts +39 -9
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +154 -3
- package/src/modes/rpc/rpc-mode.ts +97 -12
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +81 -1
- package/src/modes/setup-wizard/index.ts +12 -2
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/types.ts +2 -0
- package/src/sdk.ts +8 -1
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +39 -18
- package/src/session/agent-session.ts +179 -54
- package/src/session/streaming-output.ts +166 -10
- package/src/slash-commands/acp-builtins.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/slash-commands/types.ts +1 -1
- package/src/system-prompt.ts +14 -0
- package/src/task/executor.ts +13 -12
- package/src/task/index.ts +9 -8
- package/src/task/render.ts +18 -3
- package/src/task/types.ts +9 -0
- package/src/thinking.ts +7 -0
- package/src/tiny/title-client.ts +34 -5
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +6 -4
- package/src/tools/bash.ts +46 -5
- package/src/tools/image-gen.ts +11 -4
- package/src/tools/index.ts +13 -1
- package/src/tools/inspect-image.ts +1 -0
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/git.ts +267 -13
- package/src/utils/title-generator.ts +24 -5
|
@@ -108,6 +108,7 @@ import { shouldEnableAppendOnlyContext } from "../config/append-only-context-mod
|
|
|
108
108
|
import type { ModelRegistry } from "../config/model-registry";
|
|
109
109
|
import {
|
|
110
110
|
extractExplicitThinkingSelector,
|
|
111
|
+
filterAvailableModelsByEnabledPatterns,
|
|
111
112
|
formatModelSelectorValue,
|
|
112
113
|
formatModelString,
|
|
113
114
|
getModelMatchPreferences,
|
|
@@ -184,7 +185,12 @@ import planModeToolDecisionReminderPrompt from "../prompts/system/plan-mode-tool
|
|
|
184
185
|
import ttsrInterruptTemplate from "../prompts/system/ttsr-interrupt.md" with { type: "text" };
|
|
185
186
|
import ttsrToolReminderTemplate from "../prompts/system/ttsr-tool-reminder.md" with { type: "text" };
|
|
186
187
|
import { type AgentRegistry, MAIN_AGENT_ID } from "../registry/agent-registry";
|
|
187
|
-
import {
|
|
188
|
+
import {
|
|
189
|
+
deobfuscateSessionContext,
|
|
190
|
+
obfuscateProviderContext,
|
|
191
|
+
obfuscateProviderTools,
|
|
192
|
+
type SecretObfuscator,
|
|
193
|
+
} from "../secrets/obfuscator";
|
|
188
194
|
import { invalidateHostMetadata } from "../ssh/connection-manager";
|
|
189
195
|
import {
|
|
190
196
|
AUTO_THINKING,
|
|
@@ -192,6 +198,7 @@ import {
|
|
|
192
198
|
clampAutoThinkingEffort,
|
|
193
199
|
resolveProvisionalAutoLevel,
|
|
194
200
|
resolveThinkingLevelForModel,
|
|
201
|
+
shouldDisableReasoning,
|
|
195
202
|
toReasoningEffort,
|
|
196
203
|
} from "../thinking";
|
|
197
204
|
import { shutdownTinyTitleClient } from "../tiny/title-client";
|
|
@@ -324,6 +331,8 @@ export interface AgentSessionConfig {
|
|
|
324
331
|
agent: Agent;
|
|
325
332
|
sessionManager: SessionManager;
|
|
326
333
|
settings: Settings;
|
|
334
|
+
/** Whether the caller explicitly requested yolo/auto-approve behavior for this session. */
|
|
335
|
+
autoApprove?: boolean;
|
|
327
336
|
/** Models to cycle through with Ctrl+P (from --models flag) */
|
|
328
337
|
scopedModels?: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
|
|
329
338
|
/** Initial session thinking selector. */
|
|
@@ -839,6 +848,7 @@ export class AgentSession {
|
|
|
839
848
|
readonly settings: Settings;
|
|
840
849
|
readonly yieldQueue: YieldQueue;
|
|
841
850
|
fileSnapshotStore?: InMemorySnapshotStore;
|
|
851
|
+
#autoApprove: boolean;
|
|
842
852
|
|
|
843
853
|
#powerAssertion: MacOSPowerAssertion | undefined;
|
|
844
854
|
|
|
@@ -1118,6 +1128,7 @@ export class AgentSession {
|
|
|
1118
1128
|
this.agent = config.agent;
|
|
1119
1129
|
this.sessionManager = config.sessionManager;
|
|
1120
1130
|
this.settings = config.settings;
|
|
1131
|
+
this.#autoApprove = config.autoApprove === true;
|
|
1121
1132
|
// Power assertions are taken per turn (see #beginInFlight); nothing acquired here.
|
|
1122
1133
|
this.#evalKernelOwnerId = config.evalKernelOwnerId ?? `agent-session:${Snowflake.next()}`;
|
|
1123
1134
|
this.#parentEvalSessionId = config.parentEvalSessionId;
|
|
@@ -1133,6 +1144,7 @@ export class AgentSession {
|
|
|
1133
1144
|
} else {
|
|
1134
1145
|
this.#thinkingLevel = config.thinkingLevel;
|
|
1135
1146
|
}
|
|
1147
|
+
this.#applyThinkingLevelToAgent(this.#thinkingLevel);
|
|
1136
1148
|
this.#promptTemplates = config.promptTemplates ?? [];
|
|
1137
1149
|
this.#slashCommands = config.slashCommands ?? [];
|
|
1138
1150
|
this.#extensionRunner = config.extensionRunner;
|
|
@@ -3529,12 +3541,26 @@ export class AgentSession {
|
|
|
3529
3541
|
* Wrap a tool with a permission-gate proxy when an ACP client is connected.
|
|
3530
3542
|
* Only wraps tools whose name is in PERMISSION_REQUIRED_TOOLS and only when
|
|
3531
3543
|
* the bridge exposes `requestPermission`. No-ops for all other cases.
|
|
3544
|
+
*
|
|
3545
|
+
* When the user has explicitly opted into `yolo` / auto-approve behavior (via
|
|
3546
|
+
* the SDK/CLI `autoApprove` flag or a configured `tools.approvalMode: yolo`),
|
|
3547
|
+
* skips the gate unless the per-tool policy explicitly requires a prompt or
|
|
3548
|
+
* deny. The schema default is also `yolo`, so an explicit configuration or
|
|
3549
|
+
* explicit session flag is required: default-config ACP sessions keep the
|
|
3550
|
+
* client-side permission gate.
|
|
3532
3551
|
*/
|
|
3533
3552
|
#wrapToolForAcpPermission<T extends AgentTool>(tool: T): T {
|
|
3534
3553
|
const bridge = this.#clientBridge;
|
|
3535
3554
|
// Match the capability+method gating pattern used by read/write/bash.
|
|
3536
3555
|
if (!bridge?.capabilities.requestPermission || !bridge.requestPermission) return tool;
|
|
3537
3556
|
if (!PERMISSION_REQUIRED_TOOLS.has(tool.name)) return tool;
|
|
3557
|
+
// Skip the gate only on explicit yolo opt-in; honour per-tool policies
|
|
3558
|
+
// that require a prompt or deny (matching the normal approval wrapper).
|
|
3559
|
+
if (this.#isExplicitAutoApproveMode()) {
|
|
3560
|
+
const userPolicies = (this.settings.get("tools.approval") ?? {}) as Record<string, unknown>;
|
|
3561
|
+
const toolPolicy = userPolicies[tool.name];
|
|
3562
|
+
if (!toolPolicy || toolPolicy === "allow") return tool;
|
|
3563
|
+
}
|
|
3538
3564
|
return new Proxy(tool, {
|
|
3539
3565
|
get: (target, prop) => {
|
|
3540
3566
|
if (prop !== "execute") return Reflect.get(target, prop, target);
|
|
@@ -3622,6 +3648,13 @@ export class AgentSession {
|
|
|
3622
3648
|
}) as T;
|
|
3623
3649
|
}
|
|
3624
3650
|
|
|
3651
|
+
#isExplicitAutoApproveMode(): boolean {
|
|
3652
|
+
return (
|
|
3653
|
+
this.#autoApprove ||
|
|
3654
|
+
(this.settings.isConfigured("tools.approvalMode") && this.settings.get("tools.approvalMode") === "yolo")
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3625
3658
|
async #applyActiveToolsByName(
|
|
3626
3659
|
toolNames: string[],
|
|
3627
3660
|
options?: { persistMCPSelection?: boolean; previousSelectedMCPToolNames?: string[] },
|
|
@@ -3999,6 +4032,47 @@ export class AgentSession {
|
|
|
3999
4032
|
return deobfuscateSessionContext(this.sessionManager.buildSessionContext(), this.#obfuscator);
|
|
4000
4033
|
}
|
|
4001
4034
|
|
|
4035
|
+
#obfuscateForProvider<T>(value: T): T {
|
|
4036
|
+
if (!this.#obfuscator?.hasSecrets()) return value;
|
|
4037
|
+
return this.#obfuscator.obfuscateObject(value);
|
|
4038
|
+
}
|
|
4039
|
+
|
|
4040
|
+
#obfuscateTextForProvider(text: string | undefined): string | undefined {
|
|
4041
|
+
if (!text || !this.#obfuscator?.hasSecrets()) return text;
|
|
4042
|
+
return this.#obfuscator.obfuscate(text);
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
#obfuscatePreparationForProvider(preparation: CompactionPreparation): CompactionPreparation {
|
|
4046
|
+
if (!this.#obfuscator?.hasSecrets()) return preparation;
|
|
4047
|
+
if (!preparation.previousSummary && !preparation.previousPreserveData) return preparation;
|
|
4048
|
+
return {
|
|
4049
|
+
...preparation,
|
|
4050
|
+
previousSummary: preparation.previousSummary
|
|
4051
|
+
? this.#obfuscator.obfuscate(preparation.previousSummary)
|
|
4052
|
+
: preparation.previousSummary,
|
|
4053
|
+
previousPreserveData: preparation.previousPreserveData
|
|
4054
|
+
? this.#obfuscator.obfuscateObject(preparation.previousPreserveData)
|
|
4055
|
+
: preparation.previousPreserveData,
|
|
4056
|
+
};
|
|
4057
|
+
}
|
|
4058
|
+
|
|
4059
|
+
#deobfuscateFromProvider(text: string): string {
|
|
4060
|
+
if (!this.#obfuscator?.hasSecrets()) return text;
|
|
4061
|
+
return this.#obfuscator.deobfuscate(text);
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
#deobfuscatedProviderTextReadyForDelta(text: string): string {
|
|
4065
|
+
const deobfuscated = this.#deobfuscateFromProvider(text);
|
|
4066
|
+
if (!this.#obfuscator?.hasSecrets()) return deobfuscated;
|
|
4067
|
+
const pendingPlaceholderStart = deobfuscated.match(/#[A-Z0-9]{0,4}$/);
|
|
4068
|
+
if (pendingPlaceholderStart?.index === undefined) return deobfuscated;
|
|
4069
|
+
return deobfuscated.slice(0, pendingPlaceholderStart.index);
|
|
4070
|
+
}
|
|
4071
|
+
|
|
4072
|
+
#convertToLlmForSideRequest(messages: AgentMessage[]): Message[] {
|
|
4073
|
+
return this.#obfuscateForProvider(convertToLlm(messages));
|
|
4074
|
+
}
|
|
4075
|
+
|
|
4002
4076
|
/** Convert session messages using the same pre-LLM pipeline as the active session. */
|
|
4003
4077
|
async convertMessagesToLlm(messages: AgentMessage[], signal?: AbortSignal): Promise<Message[]> {
|
|
4004
4078
|
const transformedMessages = await this.#transformContext(messages, signal);
|
|
@@ -4398,21 +4472,28 @@ export class AgentSession {
|
|
|
4398
4472
|
* @throws Error if streaming and no streamingBehavior specified
|
|
4399
4473
|
* @throws Error if no model selected or no API key available (when not streaming)
|
|
4400
4474
|
*/
|
|
4401
|
-
|
|
4475
|
+
/**
|
|
4476
|
+
* Returns `false` when the command was fully handled locally (extension or
|
|
4477
|
+
* custom-TS command consumed without calling the LLM). Returns `true` when
|
|
4478
|
+
* the prompt was forwarded to the agent — either directly or queued as a
|
|
4479
|
+
* steer/follow-up. Callers that render a UI or manage turn lifecycle (e.g.
|
|
4480
|
+
* the ACP agent) use this to know whether to expect an `agent_end` event.
|
|
4481
|
+
*/
|
|
4482
|
+
async prompt(text: string, options?: PromptOptions): Promise<boolean> {
|
|
4402
4483
|
const expandPromptTemplates = options?.expandPromptTemplates ?? true;
|
|
4403
4484
|
|
|
4404
4485
|
// Handle extension commands first (execute immediately, even during streaming)
|
|
4405
4486
|
if (expandPromptTemplates && text.startsWith("/")) {
|
|
4406
4487
|
const handled = await this.#tryExecuteExtensionCommand(text);
|
|
4407
4488
|
if (handled) {
|
|
4408
|
-
return;
|
|
4489
|
+
return false;
|
|
4409
4490
|
}
|
|
4410
4491
|
|
|
4411
4492
|
// Try custom commands (TypeScript slash commands)
|
|
4412
4493
|
const customResult = await this.#tryExecuteCustomCommand(text);
|
|
4413
4494
|
if (customResult !== null) {
|
|
4414
4495
|
if (customResult === "") {
|
|
4415
|
-
return;
|
|
4496
|
+
return false;
|
|
4416
4497
|
}
|
|
4417
4498
|
text = customResult;
|
|
4418
4499
|
}
|
|
@@ -4446,7 +4527,7 @@ export class AgentSession {
|
|
|
4446
4527
|
for (const notice of keywordNotices) {
|
|
4447
4528
|
await this.sendCustomMessage(notice, { deliverAs: options.streamingBehavior });
|
|
4448
4529
|
}
|
|
4449
|
-
return;
|
|
4530
|
+
return true;
|
|
4450
4531
|
}
|
|
4451
4532
|
|
|
4452
4533
|
// Skip eager todo prelude when the user has already queued a directive
|
|
@@ -4486,6 +4567,7 @@ export class AgentSession {
|
|
|
4486
4567
|
if (!options?.synthetic) {
|
|
4487
4568
|
await this.#enforcePlanModeToolDecision();
|
|
4488
4569
|
}
|
|
4570
|
+
return true;
|
|
4489
4571
|
}
|
|
4490
4572
|
|
|
4491
4573
|
async promptCustomMessage<T = unknown>(
|
|
@@ -5694,16 +5776,25 @@ export class AgentSession {
|
|
|
5694
5776
|
}
|
|
5695
5777
|
|
|
5696
5778
|
/**
|
|
5697
|
-
* Get all available models with valid API keys.
|
|
5779
|
+
* Get all available models with valid API keys, filtered by `enabledModels` when configured.
|
|
5780
|
+
* See {@link filterAvailableModelsByEnabledPatterns} for supported pattern forms and limitations.
|
|
5698
5781
|
*/
|
|
5699
5782
|
getAvailableModels(): Model[] {
|
|
5700
|
-
|
|
5783
|
+
const all = this.#modelRegistry.getAvailable();
|
|
5784
|
+
const patterns = this.settings.get("enabledModels");
|
|
5785
|
+
if (!patterns || patterns.length === 0) return all;
|
|
5786
|
+
return filterAvailableModelsByEnabledPatterns(all, patterns, this.#modelRegistry);
|
|
5701
5787
|
}
|
|
5702
5788
|
|
|
5703
5789
|
// =========================================================================
|
|
5704
5790
|
// Thinking Level Management
|
|
5705
5791
|
// =========================================================================
|
|
5706
5792
|
|
|
5793
|
+
#applyThinkingLevelToAgent(level: ThinkingLevel | undefined): void {
|
|
5794
|
+
this.agent.setThinkingLevel(toReasoningEffort(level));
|
|
5795
|
+
this.agent.setDisableReasoning(shouldDisableReasoning(level));
|
|
5796
|
+
}
|
|
5797
|
+
|
|
5707
5798
|
/**
|
|
5708
5799
|
* Set the thinking level. `auto` enables per-turn classification; the selector
|
|
5709
5800
|
* itself is never written to the session log, but resolved concrete levels are
|
|
@@ -5717,7 +5808,7 @@ export class AgentSession {
|
|
|
5717
5808
|
this.#autoThinking = true;
|
|
5718
5809
|
this.#autoResolvedLevel = undefined;
|
|
5719
5810
|
this.#thinkingLevel = provisional;
|
|
5720
|
-
this
|
|
5811
|
+
this.#applyThinkingLevelToAgent(provisional);
|
|
5721
5812
|
if (persist) {
|
|
5722
5813
|
this.settings.set("defaultThinkingLevel", AUTO_THINKING);
|
|
5723
5814
|
}
|
|
@@ -5733,7 +5824,7 @@ export class AgentSession {
|
|
|
5733
5824
|
const isChanging = effectiveLevel !== this.#thinkingLevel;
|
|
5734
5825
|
|
|
5735
5826
|
this.#thinkingLevel = effectiveLevel;
|
|
5736
|
-
this
|
|
5827
|
+
this.#applyThinkingLevelToAgent(effectiveLevel);
|
|
5737
5828
|
|
|
5738
5829
|
if (isChanging) {
|
|
5739
5830
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
@@ -5823,7 +5914,7 @@ export class AgentSession {
|
|
|
5823
5914
|
const shouldPersistResolution = this.#autoResolvedLevel !== effort;
|
|
5824
5915
|
this.#autoResolvedLevel = effort;
|
|
5825
5916
|
this.#thinkingLevel = effort;
|
|
5826
|
-
this
|
|
5917
|
+
this.#applyThinkingLevelToAgent(effort);
|
|
5827
5918
|
if (shouldPersistResolution) {
|
|
5828
5919
|
this.sessionManager.appendThinkingLevelChange(effort);
|
|
5829
5920
|
}
|
|
@@ -6177,10 +6268,10 @@ export class AgentSession {
|
|
|
6177
6268
|
customInstructions,
|
|
6178
6269
|
compactionAbortController.signal,
|
|
6179
6270
|
{
|
|
6180
|
-
promptOverride: compactionPrep.hookPrompt,
|
|
6181
|
-
extraContext: compactionPrep.hookContext,
|
|
6182
|
-
remoteInstructions: this.#baseSystemPrompt.join("\n\n"),
|
|
6183
|
-
convertToLlm,
|
|
6271
|
+
promptOverride: this.#obfuscateTextForProvider(compactionPrep.hookPrompt),
|
|
6272
|
+
extraContext: this.#obfuscateForProvider(compactionPrep.hookContext),
|
|
6273
|
+
remoteInstructions: this.#obfuscateForProvider(this.#baseSystemPrompt.join("\n\n")),
|
|
6274
|
+
convertToLlm: messages => this.#convertToLlmForSideRequest(messages),
|
|
6184
6275
|
},
|
|
6185
6276
|
);
|
|
6186
6277
|
summary = result.summary;
|
|
@@ -6363,15 +6454,15 @@ export class AgentSession {
|
|
|
6363
6454
|
throw new Error(`No API key for ${model.provider}`);
|
|
6364
6455
|
}
|
|
6365
6456
|
|
|
6366
|
-
const
|
|
6457
|
+
const rawHandoffText = await generateHandoff(
|
|
6367
6458
|
this.agent.state.messages,
|
|
6368
6459
|
model,
|
|
6369
6460
|
apiKey,
|
|
6370
6461
|
{
|
|
6371
|
-
systemPrompt: this.#baseSystemPrompt,
|
|
6372
|
-
tools: this.agent.state.tools,
|
|
6373
|
-
customInstructions,
|
|
6374
|
-
convertToLlm,
|
|
6462
|
+
systemPrompt: this.#obfuscateForProvider(this.#baseSystemPrompt),
|
|
6463
|
+
tools: obfuscateProviderTools(this.#obfuscator, this.agent.state.tools),
|
|
6464
|
+
customInstructions: this.#obfuscateTextForProvider(customInstructions),
|
|
6465
|
+
convertToLlm: messages => this.#convertToLlmForSideRequest(messages),
|
|
6375
6466
|
initiatorOverride: "agent",
|
|
6376
6467
|
metadata: this.agent.metadataForProvider(model.provider),
|
|
6377
6468
|
telemetry: resolveTelemetry(this.agent.telemetry, this.sessionId),
|
|
@@ -6383,6 +6474,7 @@ export class AgentSession {
|
|
|
6383
6474
|
},
|
|
6384
6475
|
handoffSignal,
|
|
6385
6476
|
);
|
|
6477
|
+
const handoffText = this.#deobfuscateFromProvider(rawHandoffText);
|
|
6386
6478
|
|
|
6387
6479
|
if (handoffSignal.aborted) {
|
|
6388
6480
|
throw new Error("Handoff cancelled");
|
|
@@ -7344,17 +7436,24 @@ export class AgentSession {
|
|
|
7344
7436
|
if (!apiKey) continue;
|
|
7345
7437
|
|
|
7346
7438
|
try {
|
|
7347
|
-
return await compact(
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7439
|
+
return await compact(
|
|
7440
|
+
this.#obfuscatePreparationForProvider(preparation),
|
|
7441
|
+
candidate,
|
|
7442
|
+
apiKey,
|
|
7443
|
+
this.#obfuscateTextForProvider(customInstructions),
|
|
7444
|
+
signal,
|
|
7445
|
+
{
|
|
7446
|
+
...options,
|
|
7447
|
+
metadata: this.agent.metadataForProvider(candidate.provider),
|
|
7448
|
+
convertToLlm: messages => this.#convertToLlmForSideRequest(messages),
|
|
7449
|
+
telemetry,
|
|
7450
|
+
// Honor the user's /model thinking selection (incl. `off`) on
|
|
7451
|
+
// the manual `/compact` path. Clamped per-model inside compact()
|
|
7452
|
+
// via resolveCompactionEffort so unsupported-effort models
|
|
7453
|
+
// (xai-oauth/grok-build) don't trip requireSupportedEffort.
|
|
7454
|
+
thinkingLevel: this.thinkingLevel,
|
|
7455
|
+
},
|
|
7456
|
+
);
|
|
7358
7457
|
} catch (error) {
|
|
7359
7458
|
if (!this.#isCompactionAuthFailure(error)) {
|
|
7360
7459
|
throw error;
|
|
@@ -7634,20 +7733,27 @@ export class AgentSession {
|
|
|
7634
7733
|
let attempt = 0;
|
|
7635
7734
|
while (true) {
|
|
7636
7735
|
try {
|
|
7637
|
-
compactResult = await compact(
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7736
|
+
compactResult = await compact(
|
|
7737
|
+
this.#obfuscatePreparationForProvider(preparation),
|
|
7738
|
+
candidate,
|
|
7739
|
+
apiKey,
|
|
7740
|
+
undefined,
|
|
7741
|
+
autoCompactionSignal,
|
|
7742
|
+
{
|
|
7743
|
+
promptOverride: this.#obfuscateTextForProvider(compactionPrep.hookPrompt),
|
|
7744
|
+
extraContext: this.#obfuscateForProvider(compactionPrep.hookContext),
|
|
7745
|
+
remoteInstructions: this.#obfuscateForProvider(this.#baseSystemPrompt.join("\n\n")),
|
|
7746
|
+
metadata: this.agent.metadataForProvider(candidate.provider),
|
|
7747
|
+
initiatorOverride: "agent",
|
|
7748
|
+
convertToLlm: messages => this.#convertToLlmForSideRequest(messages),
|
|
7749
|
+
telemetry,
|
|
7750
|
+
// Honor the user's /model thinking selection on the
|
|
7751
|
+
// auto-compaction path — the most-fired compaction
|
|
7752
|
+
// site. Clamped per-model inside compact() via
|
|
7753
|
+
// resolveCompactionEffort.
|
|
7754
|
+
thinkingLevel: this.thinkingLevel,
|
|
7755
|
+
},
|
|
7756
|
+
);
|
|
7651
7757
|
break;
|
|
7652
7758
|
} catch (error) {
|
|
7653
7759
|
if (autoCompactionSignal.aborted) {
|
|
@@ -8337,6 +8443,7 @@ export class AgentSession {
|
|
|
8337
8443
|
{
|
|
8338
8444
|
retryAfterMs,
|
|
8339
8445
|
baseUrl: this.model.baseUrl,
|
|
8446
|
+
modelId: this.model.id,
|
|
8340
8447
|
},
|
|
8341
8448
|
);
|
|
8342
8449
|
if (outcome.switched) {
|
|
@@ -8533,11 +8640,12 @@ export class AgentSession {
|
|
|
8533
8640
|
* @param command The bash command to execute
|
|
8534
8641
|
* @param onChunk Optional streaming callback for output
|
|
8535
8642
|
* @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)
|
|
8643
|
+
* @param options.useUserShell If true, allow caller to request configured user-shell routing
|
|
8536
8644
|
*/
|
|
8537
8645
|
async executeBash(
|
|
8538
8646
|
command: string,
|
|
8539
8647
|
onChunk?: (chunk: string) => void,
|
|
8540
|
-
options?: { excludeFromContext?: boolean },
|
|
8648
|
+
options?: { excludeFromContext?: boolean; useUserShell?: boolean },
|
|
8541
8649
|
): Promise<BashResult> {
|
|
8542
8650
|
const excludeFromContext = options?.excludeFromContext === true;
|
|
8543
8651
|
const cwd = this.sessionManager.getCwd();
|
|
@@ -8565,6 +8673,7 @@ export class AgentSession {
|
|
|
8565
8673
|
sessionKey: this.sessionId,
|
|
8566
8674
|
timeout: clampTimeout("bash") * 1000,
|
|
8567
8675
|
onMinimizedSave: originalText => this.#saveBashOriginalArtifact(originalText),
|
|
8676
|
+
useUserShell: options?.useUserShell,
|
|
8568
8677
|
});
|
|
8569
8678
|
|
|
8570
8679
|
this.recordBashResult(command, result, options);
|
|
@@ -8690,6 +8799,7 @@ export class AgentSession {
|
|
|
8690
8799
|
sessionId: namespacePythonSessionId(sessionId),
|
|
8691
8800
|
kernelOwnerId: this.#evalKernelOwnerId,
|
|
8692
8801
|
kernelMode: this.settings.get("python.kernelMode"),
|
|
8802
|
+
interpreter: this.settings.get("python.interpreter")?.trim() || undefined,
|
|
8693
8803
|
onChunk,
|
|
8694
8804
|
signal: abortController.signal,
|
|
8695
8805
|
});
|
|
@@ -8982,6 +9092,7 @@ export class AgentSession {
|
|
|
8982
9092
|
promptCacheKey: cacheSessionId,
|
|
8983
9093
|
preferWebsockets: false,
|
|
8984
9094
|
reasoning: toReasoningEffort(this.thinkingLevel),
|
|
9095
|
+
disableReasoning: shouldDisableReasoning(this.thinkingLevel),
|
|
8985
9096
|
hideThinkingSummary: this.agent.hideThinkingSummary,
|
|
8986
9097
|
serviceTier: this.serviceTier,
|
|
8987
9098
|
signal: args.signal,
|
|
@@ -8990,17 +9101,27 @@ export class AgentSession {
|
|
|
8990
9101
|
model.provider,
|
|
8991
9102
|
);
|
|
8992
9103
|
|
|
8993
|
-
let
|
|
9104
|
+
let providerReplyText = "";
|
|
9105
|
+
let emittedReplyText = "";
|
|
8994
9106
|
let assistantMessage: AssistantMessage | undefined;
|
|
8995
|
-
const stream = streamSimple(model, context, options);
|
|
9107
|
+
const stream = streamSimple(model, obfuscateProviderContext(this.#obfuscator, context), options);
|
|
8996
9108
|
for await (const event of stream) {
|
|
8997
9109
|
if (event.type === "text_delta") {
|
|
8998
|
-
|
|
8999
|
-
if (args.onTextDelta)
|
|
9110
|
+
providerReplyText += event.delta;
|
|
9111
|
+
if (args.onTextDelta) {
|
|
9112
|
+
const readyText = this.#deobfuscatedProviderTextReadyForDelta(providerReplyText);
|
|
9113
|
+
if (readyText.length > emittedReplyText.length) {
|
|
9114
|
+
const delta = readyText.slice(emittedReplyText.length);
|
|
9115
|
+
emittedReplyText = readyText;
|
|
9116
|
+
args.onTextDelta(delta);
|
|
9117
|
+
}
|
|
9118
|
+
}
|
|
9000
9119
|
continue;
|
|
9001
9120
|
}
|
|
9002
9121
|
if (event.type === "done") {
|
|
9003
|
-
assistantMessage =
|
|
9122
|
+
assistantMessage = this.#obfuscator?.hasSecrets()
|
|
9123
|
+
? { ...event.message, content: this.#obfuscator.deobfuscateObject(event.message.content) }
|
|
9124
|
+
: event.message;
|
|
9004
9125
|
break;
|
|
9005
9126
|
}
|
|
9006
9127
|
if (event.type === "error") {
|
|
@@ -9011,6 +9132,10 @@ export class AgentSession {
|
|
|
9011
9132
|
if (!assistantMessage) {
|
|
9012
9133
|
throw new Error("Ephemeral turn ended without a final message");
|
|
9013
9134
|
}
|
|
9135
|
+
const replyText = this.#deobfuscateFromProvider(providerReplyText);
|
|
9136
|
+
if (args.onTextDelta && replyText.length > emittedReplyText.length) {
|
|
9137
|
+
args.onTextDelta(replyText.slice(emittedReplyText.length));
|
|
9138
|
+
}
|
|
9014
9139
|
return {
|
|
9015
9140
|
replyText: args.dedupeReply === false ? replyText.trim() : dedupeIrcReply(replyText.trim()),
|
|
9016
9141
|
assistantMessage,
|
|
@@ -9270,7 +9395,7 @@ export class AgentSession {
|
|
|
9270
9395
|
this.#autoResolvedLevel = undefined;
|
|
9271
9396
|
this.#thinkingLevel = resolveThinkingLevelForModel(this.model, restoredThinkingLevel);
|
|
9272
9397
|
}
|
|
9273
|
-
this
|
|
9398
|
+
this.#applyThinkingLevelToAgent(this.#thinkingLevel);
|
|
9274
9399
|
this.agent.serviceTier = hasServiceTierEntry
|
|
9275
9400
|
? sessionContext.serviceTier
|
|
9276
9401
|
: configuredServiceTier === "none"
|
|
@@ -9327,7 +9452,7 @@ export class AgentSession {
|
|
|
9327
9452
|
this.#thinkingLevel = previousThinkingLevel;
|
|
9328
9453
|
this.#autoThinking = previousAutoThinking;
|
|
9329
9454
|
this.#autoResolvedLevel = previousAutoResolvedLevel;
|
|
9330
|
-
this
|
|
9455
|
+
this.#applyThinkingLevelToAgent(previousThinkingLevel);
|
|
9331
9456
|
this.agent.serviceTier = previousServiceTier;
|
|
9332
9457
|
this.#syncTodoPhasesFromBranch();
|
|
9333
9458
|
this.#reconnectToAgent();
|
|
@@ -9511,10 +9636,10 @@ export class AgentSession {
|
|
|
9511
9636
|
model,
|
|
9512
9637
|
apiKey,
|
|
9513
9638
|
signal: this.#branchSummaryAbortController.signal,
|
|
9514
|
-
customInstructions: options.customInstructions,
|
|
9639
|
+
customInstructions: this.#obfuscateTextForProvider(options.customInstructions),
|
|
9515
9640
|
reserveTokens: branchSummarySettings.reserveTokens,
|
|
9516
9641
|
metadata: this.agent.metadataForProvider(model.provider),
|
|
9517
|
-
convertToLlm,
|
|
9642
|
+
convertToLlm: messages => this.#convertToLlmForSideRequest(messages),
|
|
9518
9643
|
telemetry: resolveTelemetry(this.agent.telemetry, this.sessionId),
|
|
9519
9644
|
});
|
|
9520
9645
|
this.#branchSummaryAbortController = undefined;
|