Skip to content

Commit 583c427

Browse files
committed
feat(agent-core-v2): add the permission mode reminder env switch
Set PYTHINKER_CODE_PERMISSION_MODE_REMINDER to a false value to stop injecting the auto permission-mode reminder into the model context.
1 parent 6a1181a commit 583c427

5 files changed

Lines changed: 74 additions & 6 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pymodel/pythinker-code": patch
3+
---
4+
5+
Add the `PYTHINKER_CODE_PERMISSION_MODE_REMINDER` environment variable: set it to a false value to stop injecting the auto permission-mode reminders into the model context.

docs/configuration/env-vars.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ Switches that control the behavior of subsystems such as telemetry, background t
142142
| `PYTHINKER_CODE_TUI_FULL_SCREEN` | Control the fullscreen TUI with a fixed prompt dock, scrollable transcript, mouse text selection, clickable links, transcript search, and a clickable jump-to-bottom control. Fullscreen is enabled by default | `0` restores the legacy inline UI; unset or any other value keeps fullscreen enabled |
143143
| `PYTHINKER_CODE_EXPERIMENTAL_SECONDARY_MODEL` | Control the [subagent model pool](./config-files.md#subagent-model-pool) in every launch mode, including the interactive TUI. It is enabled by default; set this variable to a false value to disable it | Truthy: `1`/`true`/`yes`/`on`; falsy: `0`/`false`/`no`/`off` |
144144
| `PYTHINKER_CODE_DANGEROUS_COMMAND_GUARD` | Override [`[permission].dangerous_command_guard`](./config-files.md#permission). The guard asks before dangerous or unanalyzable `Bash` commands in interactive modes and blocks them in Auto mode | `true` or `false`; default `true` |
145+
| `PYTHINKER_CODE_PERMISSION_MODE_REMINDER` | Stop injecting the automatic permission-mode reminder (the context note that explains Auto mode) into the model context; set to a false value to disable | Truthy keeps the reminder enabled; falsy: `0`/`false`/`no`/`off` disables it |
145146
| `PYTHINKER_CODE_EXPERIMENTAL_SUBAGENT_FORK` | Enable the experimental `fork` parameter on the `Agent` and `AgentDynamicWorkflow` tools, letting the model start a subagent with a snapshot of the calling agent's conversation history instead of an empty context; the master `PYTHINKER_CODE_EXPERIMENTAL_FLAG=1` also enables it | Truthy: `1`/`true`/`yes`/`on`; falsy: `0`/`false`/`no`/`off` |
146147
| `PYTHINKER_CODE_EXPERIMENTAL_TOWER` | Enable the experimental [`/tower`](../reference/slash-commands.md#modes--run-control) command for workspace-wide subagent coordination; the master `PYTHINKER_CODE_EXPERIMENTAL_FLAG=1` also enables it | Truthy: `1`/`true`/`yes`/`on`; falsy: `0`/`false`/`no`/`off` |
147148
| `PYTHINKER_MCP_STARTUP_TIMEOUT_MS` | Global default connection timeout (ms) for all MCP servers; takes higher priority than `[mcp] startup_timeout_ms` in `config.toml`, but a per-server `startupTimeoutMs` in `mcp.json` still wins (default `30000`) | Integer from `1` to `2147483647`; invalid values are ignored |

packages/agent-core-v2/src/agent/permissionMode/permissionModeService.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { PermissionMode } from '#/agent/permissionPolicy/types';
22
import { Service } from '#/_base/di/service';
3+
import { parseBooleanEnv } from '#/_base/utils/env';
4+
import { IBootstrapService } from '#/app/bootstrap/bootstrap';
35
import { LifecycleScope } from '#/app/scopes';
46
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
57
import { Emitter, type Event } from '#/_base/event';
@@ -20,6 +22,8 @@ import {
2022
PermissionSetMode,
2123
} from './permissionModeOps';
2224

25+
export const PERMISSION_MODE_REMINDER_ENV = 'PYTHINKER_CODE_PERMISSION_MODE_REMINDER';
26+
2327
export class AgentPermissionModeService extends Service implements IAgentPermissionModeService {
2428
declare readonly _serviceBrand: undefined;
2529

@@ -32,15 +36,18 @@ export class AgentPermissionModeService extends Service implements IAgentPermiss
3236
@IAgentLifecycleService private readonly agentLifecycle: IAgentLifecycleService,
3337
@ITelemetryService private readonly telemetry: ITelemetryService,
3438
@IAgentStateService private readonly agentState: IAgentStateService,
39+
@IBootstrapService bootstrap: IBootstrapService,
3540
) {
3641
super();
3742
this.agentState.contributeState(permissionModeKey);
3843
this.agentState.contributeState(permissionModeConfiguredKey);
39-
this._register(
40-
activateReminderWhenReady(this.agentLifecycle, this.scopeContext, (reminder) =>
41-
new PermissionModeInjection(this, reminder, this.agentState),
42-
),
43-
);
44+
if (parseBooleanEnv(bootstrap.getEnv(PERMISSION_MODE_REMINDER_ENV)) !== false) {
45+
this._register(
46+
activateReminderWhenReady(this.agentLifecycle, this.scopeContext, (reminder) =>
47+
new PermissionModeInjection(this, reminder, this.agentState),
48+
),
49+
);
50+
}
4451
}
4552

4653
get mode(): PermissionMode {

packages/agent-core-v2/test/agent/permissionMode/permissionMode.test.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ import type { ReminderRuntime } from '#/features/reminder/reminderAgentRuntime';
77
import type { ContextInjectionProvider } from '#/features/reminder/types';
88
import { IAgentLifecycleService } from '#/session/agentLifecycle/agentLifecycle';
99
import { lifecycleWithReminder } from '../../features/reminder/stubs';
10+
import { IBootstrapService } from '#/app/bootstrap/bootstrap';
11+
import { stubBootstrap } from '../../app/bootstrap/stubs';
1012
import { IAgentPermissionModeService } from '#/agent/permissionMode/permissionMode';
1113
import { PermissionModeInjection } from '#/agent/permissionMode/injection/permissionModeInjection';
12-
import { AgentPermissionModeService } from '#/agent/permissionMode/permissionModeService';
14+
import {
15+
AgentPermissionModeService,
16+
PERMISSION_MODE_REMINDER_ENV,
17+
} from '#/agent/permissionMode/permissionModeService';
1318
import { permissionModeKey } from '#/agent/permissionMode/permissionModeOps';
1419
import type { PermissionMode } from '#/agent/permissionPolicy/types';
1520
import { IAgentStateService } from '#/agent/state/agentState';
@@ -57,15 +62,18 @@ let log: IAppendLogStore;
5762
let dispatcher: IEventDispatcher;
5863
let svc: IAgentPermissionModeService;
5964
let reminderLive = false;
65+
let bootstrapEnv: NodeJS.ProcessEnv;
6066

6167
beforeEach(() => {
6268
registeredInjection = undefined;
6369
reminderLive = false;
70+
bootstrapEnv = {};
6471
disposables = new DisposableStore();
6572
ix = disposables.add(new TestInstantiationService());
6673
ix.stub(IFileSystemStorageService, new InMemoryStorageService());
6774
ix.set(IAppendLogStore, new SyncDescriptor(AppendLogStore));
6875
ix.stub(IAgentLifecycleService, lifecycleWithReminder(injectorStub));
76+
ix.stub(IBootstrapService, stubBootstrap('/tmp/pythinker-home', bootstrapEnv));
6977
ix.set(IAgentStateService, new AgentStateService());
7078
ix.set(IAgentPermissionModeService, new SyncDescriptor(AgentPermissionModeService));
7179
log = ix.get(IAppendLogStore);
@@ -243,4 +251,50 @@ describe('AgentPermissionModeService (wire-backed)', () => {
243251
expect(written[0]).toMatchObject({ type: 'metadata' });
244252
expect(written.slice(1)).toEqual([{ type: 'permission.set_mode', mode: 'auto' }]);
245253
});
254+
it('skips the auto-mode reminder injection when the reminder env is disabled', () => {
255+
registeredInjection = undefined;
256+
const ix2 = disposables.add(new TestInstantiationService());
257+
ix2.stub(IFileSystemStorageService, new InMemoryStorageService());
258+
ix2.set(IAppendLogStore, new SyncDescriptor(AppendLogStore));
259+
ix2.stub(IAgentLifecycleService, lifecycleWithReminder(injectorStub));
260+
ix2.stub(
261+
IBootstrapService,
262+
stubBootstrap('/tmp/pythinker-home', { [PERMISSION_MODE_REMINDER_ENV]: '0' }),
263+
);
264+
ix2.set(IAgentStateService, new AgentStateService());
265+
ix2.set(IAgentPermissionModeService, new SyncDescriptor(AgentPermissionModeService));
266+
registerTestAgentWire(ix2, testWireScope(SCOPE, 'permission-mode-no-reminder'), {
267+
log: ix2.get(IAppendLogStore),
268+
});
269+
registerTestEventDispatcher(ix2);
270+
271+
const svc2 = ix2.get(IAgentPermissionModeService);
272+
273+
expect(registeredInjection).toBeUndefined();
274+
svc2.setMode('auto');
275+
expect(svc2.mode).toBe('auto');
276+
expect(registeredInjection).toBeUndefined();
277+
});
278+
279+
it('keeps the auto-mode reminder injection when the env override enables it explicitly', () => {
280+
registeredInjection = undefined;
281+
const ix2 = disposables.add(new TestInstantiationService());
282+
ix2.stub(IFileSystemStorageService, new InMemoryStorageService());
283+
ix2.set(IAppendLogStore, new SyncDescriptor(AppendLogStore));
284+
ix2.stub(IAgentLifecycleService, lifecycleWithReminder(injectorStub));
285+
ix2.stub(
286+
IBootstrapService,
287+
stubBootstrap('/tmp/pythinker-home', { [PERMISSION_MODE_REMINDER_ENV]: '1' }),
288+
);
289+
ix2.set(IAgentStateService, new AgentStateService());
290+
ix2.set(IAgentPermissionModeService, new SyncDescriptor(AgentPermissionModeService));
291+
registerTestAgentWire(ix2, testWireScope(SCOPE, 'permission-mode-reminder-on'), {
292+
log: ix2.get(IAppendLogStore),
293+
});
294+
registerTestEventDispatcher(ix2);
295+
296+
ix2.get(IAgentPermissionModeService);
297+
298+
expect((registeredInjection as { readonly name: string } | undefined)?.name).toBe('permission_mode');
299+
});
246300
});

packages/agent-core-v2/test/session/agentLifecycle/agentLifecycle.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ describe('AgentLifecycleService', () => {
265265
_serviceBrand: undefined,
266266
homeDir: '/tmp/pythinker-agentLifecycle-home',
267267
cwd: '/tmp/pythinker-agentLifecycle-home',
268+
getEnv: () => undefined,
268269
} as unknown as IBootstrapService);
269270
ix.stub(ISessionWorkspaceContext, {
270271
_serviceBrand: undefined,

0 commit comments

Comments
 (0)