mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
effective(session) = findLast(the session own knob events)?.value ?? the composition-config default. One log-only event per knob, owned by its domain (bash/sandbox-mode in dsh-bash, approval/policy in dsh-approval), each exporting the same three-piece kit: the event declaration, a pure fold, and THE write path — a switch IS its event; no owner service, no facts map. Restart immunity and multi-session isolation fall out of the log replay by construction. Execution follows the fold on both sides: the bash tool stamps escalation grant > session override > executor default, and the approval seam prepends the never-gate that auto-rejects before any interactive answerer. Visibility is two layers per knob: a per-agent prompt section states the effective value on every request (logged through request/header*, so what-the-model-was-told replays from the log), and an agent/pre-step narrator injects at most one coalesced delta notice with positional attribution (user switch vs operator/config drift). The ACP bridge advertises one capability-gated select per composable knob with currentValue folded per session, validates set_config_option against the closed vocabularies, and anchors idle switches at the next turn prompt-submit under the turn-enclosure contract.
66 lines
3.2 KiB
TypeScript
66 lines
3.2 KiB
TypeScript
/**
|
|
* Per-session sandbox-mode override: the session log as the store. A runtime
|
|
* switch (an ACP `session/set_config_option`, a test scenario) is recorded as
|
|
* one `bash/sandbox-mode` event on the session it applies to;
|
|
* `effective = fold(events) ?? the executor's configured default`, so an
|
|
* override survives restart by replay, two sessions can never see each
|
|
* other's state, and there is no external config store. The event is
|
|
* log-only (the `approval/*` precedent): the model learns the mode from the
|
|
* prompt section and the boundary notices in `@deepseek-ai/dsh-tool-bash`,
|
|
* never from the event itself. EXECUTION honors the fold in the tool layer —
|
|
* it stamps the effective mode onto each call's `BashExecRequest.sandboxMode`
|
|
* (weakest-precedence: an escalation grant for the call outranks it) — the
|
|
* executor itself stays a config-fixed default plus per-call overrides.
|
|
*
|
|
* @module dsh-bash/session-mode
|
|
*/
|
|
|
|
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'
|
|
import type { SandboxMode } from '@deepseek-ai/dsh-sandbox'
|
|
|
|
declare module '@deepseek-ai/dsh-session' {
|
|
interface SessionEventMap {
|
|
/**
|
|
* The session's sandbox mode was switched — log-only (like `approval/*`;
|
|
* NOT a surface event, carries no `surfaceOp`): durable and replayable,
|
|
* never in the model transcript. The LAST such event is the session's
|
|
* override ({@link effectiveSandboxMode}); who asked for it is derivable
|
|
* from position (an event after the log's last `request/header*` was a
|
|
* runtime switch by the user; see the tool layer's narrator).
|
|
*/
|
|
'bash/sandbox-mode': { mode: SandboxMode }
|
|
}
|
|
}
|
|
|
|
/** Every {@link SandboxMode}, for option advertisement and runtime validation of untrusted mode strings. */
|
|
export const SANDBOX_MODES: readonly SandboxMode[] = ['read-only', 'workspace-write', 'danger-full-access']
|
|
|
|
/**
|
|
* The session's sandbox-mode override: the last `bash/sandbox-mode` event in
|
|
* the log, or undefined when the session never switched (callers apply the
|
|
* executor's configured default). The pure fold — resume needs no catch-up
|
|
* machinery because replaying the log IS the state.
|
|
* @param events - session events in log order (other event types are skipped).
|
|
* @returns the mode of the last switch event, or undefined without one.
|
|
*/
|
|
export function effectiveSandboxMode(events: readonly SessionEvent[]): SandboxMode | undefined {
|
|
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
const event = events[index] as SessionEvent
|
|
if (event.type === 'bash/sandbox-mode') return event.data.mode
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
/**
|
|
* THE write path for a session's sandbox-mode override: appends exactly one
|
|
* `bash/sandbox-mode` event — the switch IS its event; nothing mutates mode
|
|
* state out of band. Takes effect on the session's next bash call and next
|
|
* prompt assembly (the consumers fold on every read).
|
|
* @param session - the session the override belongs to.
|
|
* @param mode - the mode every subsequent bash call in this session runs
|
|
* under (until the next switch).
|
|
*/
|
|
export function setSandboxMode(session: Session, mode: SandboxMode): void {
|
|
session.append('bash/sandbox-mode', { mode })
|
|
}
|