diff --git a/packages/adapter-utils/src/server-utils.test.ts b/packages/adapter-utils/src/server-utils.test.ts index 6467973ab0..2dd38ccdf4 100644 --- a/packages/adapter-utils/src/server-utils.test.ts +++ b/packages/adapter-utils/src/server-utils.test.ts @@ -742,6 +742,37 @@ describe("renderPaperclipWakePrompt", () => { ); }); + it("renders the simplified-english interaction directive only when the payload enables it", () => { + const payload = { + reason: "issue_commented", + issue: { + id: "issue-1", + identifier: "PAP-15936", + title: "Interaction language", + description: null, + descriptionTruncated: false, + status: "in_progress", + }, + commentWindow: { requestedCount: 0, includedCount: 0, missingCount: 0 }, + comments: [], + fallbackFetchNeeded: false, + }; + + expect(renderPaperclipWakePrompt(payload)).not.toContain("ASD-STE100"); + + const enabled = { ...payload, simplifiedEnglishInteractions: true }; + const fresh = renderPaperclipWakePrompt(enabled); + expect(fresh).toContain("ASD-STE100 Simplified Technical English"); + expect(fresh).toContain("what happens for each choice"); + // Resume deltas carry the directive too: the setting can change between wakes. + expect(renderPaperclipWakePrompt(enabled, { resumedSession: true })).toContain( + "ASD-STE100 Simplified Technical English", + ); + expect(JSON.parse(stringifyPaperclipWakePayload(enabled) ?? "{}")).toMatchObject({ + simplifiedEnglishInteractions: true, + }); + }); + it("suppresses the issue description when the prompt already carries the task-context markdown", () => { const payload = { reason: "issue_assigned", diff --git a/packages/adapter-utils/src/server-utils.ts b/packages/adapter-utils/src/server-utils.ts index 401ae2c27e..6c51a3cd32 100644 --- a/packages/adapter-utils/src/server-utils.ts +++ b/packages/adapter-utils/src/server-utils.ts @@ -666,6 +666,9 @@ type PaperclipWakePayload = { recovery: PaperclipWakeRecovery | null; issue: PaperclipWakeIssue | null; checkedOutByHarness: boolean; + // Experimental: write user-interaction content in ASD-STE100 Simplified + // Technical English with brief decision context. + simplifiedEnglishInteractions: boolean; dependencyBlockedInteraction: boolean; treeHoldInteraction: boolean; activeTreeHold: PaperclipWakeTreeHoldSummary | null; @@ -1317,6 +1320,7 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl recovery, issue: normalizePaperclipWakeIssue(payload.issue), checkedOutByHarness: asBoolean(payload.checkedOutByHarness, false), + simplifiedEnglishInteractions: asBoolean(payload.simplifiedEnglishInteractions, false), dependencyBlockedInteraction: asBoolean(payload.dependencyBlockedInteraction, false), treeHoldInteraction: asBoolean(payload.treeHoldInteraction, false), activeTreeHold, @@ -1624,6 +1628,11 @@ export function renderPaperclipWakePrompt( `- execution workspace branch: you are running in an execution workspace on branch ${markdownInlineCode(normalized.executionWorkspace.branchName)}. Do not switch, rename, or re-point this branch; keep all commits on it.`, ); } + if (normalized.simplifiedEnglishInteractions) { + lines.push( + "- interaction language (experimental): write every user interaction you post (request_confirmation, ask_user_questions, suggest_tasks, checkbox prompts and options, and any other content rendered inside an interaction block) in ASD-STE100 Simplified Technical English. In each interaction, briefly tell the user what information they need to make the decision and what happens for each choice. This applies only to interaction content — write your thinking, comments, documents, and other responses in your usual style.", + ); + } if (normalized.dependencyBlockedInteraction) { lines.push("- dependency-blocked interaction: yes"); lines.push("- execution scope: respond or triage the human comment; do not treat blocker-dependent deliverable work as unblocked"); diff --git a/packages/shared/src/feature-catalog.ts b/packages/shared/src/feature-catalog.ts index 5b0837e17e..9916d916f6 100644 --- a/packages/shared/src/feature-catalog.ts +++ b/packages/shared/src/feature-catalog.ts @@ -189,6 +189,14 @@ export const INSTANCE_FEATURE_CATALOG: Record { enableDecisions: false, enableGoalsSidebarLink: true, enableServerInfoDebugView: true, + enableSimplifiedEnglishInteractions: false, autoRestartDevServerWhenIdle: true, enableIssueGraphLivenessAutoRecovery: true, enableWorkspaceBranchReconcileForward: true, @@ -71,6 +72,19 @@ describe("instance settings service", () => { ).toBe(false); }); + it("defaults enableSimplifiedEnglishInteractions to false for empty and legacy stored settings", () => { + expect(normalizeExperimentalSettings(undefined).enableSimplifiedEnglishInteractions).toBe(false); + expect(normalizeExperimentalSettings({}).enableSimplifiedEnglishInteractions).toBe(false); + expect( + normalizeExperimentalSettings({ enableStreamlinedLeftNavigation: true }) + .enableSimplifiedEnglishInteractions, + ).toBe(false); + expect( + normalizeExperimentalSettings({ enableSimplifiedEnglishInteractions: true }) + .enableSimplifiedEnglishInteractions, + ).toBe(true); + }); + it("defaults enableTaskWatchdogs to false for empty and legacy stored settings", () => { expect(normalizeExperimentalSettings(undefined).enableTaskWatchdogs).toBe(false); expect(normalizeExperimentalSettings({}).enableTaskWatchdogs).toBe(false); diff --git a/server/src/services/heartbeat.ts b/server/src/services/heartbeat.ts index 91c3668539..6941b33ba8 100644 --- a/server/src/services/heartbeat.ts +++ b/server/src/services/heartbeat.ts @@ -5464,6 +5464,9 @@ export async function buildPaperclipWakePayload(input: { } | null; exposeLowTrustRaw?: boolean; + // Experimental: agents write user-interaction content in ASD-STE100 + // Simplified Technical English (rendered as a prompt directive downstream). + simplifiedEnglishInteractions?: boolean; }) { const executionStage = parseObject(input.contextSnapshot.executionStage); const commentIds = extractWakeCommentIds(input.contextSnapshot); @@ -5739,6 +5742,7 @@ export async function buildPaperclipWakePayload(input: { interactionStatus, checkboxSelection: Object.keys(checkboxSelection).length > 0 ? checkboxSelection : null, checkedOutByHarness: input.contextSnapshot[PAPERCLIP_HARNESS_CHECKOUT_KEY] === true, + simplifiedEnglishInteractions: input.simplifiedEnglishInteractions === true, dependencyBlockedInteraction: input.contextSnapshot.dependencyBlockedInteraction === true, treeHoldInteraction: input.contextSnapshot.treeHoldInteraction === true, activeTreeHold: parseObject(input.contextSnapshot.activeTreeHold), @@ -13576,7 +13580,8 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {}) issueContext.assigneeAdapterOverrides, ) : null; - const isolatedWorkspacesEnabled = (await instanceSettings.getExperimental()).enableIsolatedWorkspaces; + const experimentalInstanceSettings = await instanceSettings.getExperimental(); + const isolatedWorkspacesEnabled = experimentalInstanceSettings.enableIsolatedWorkspaces; const parsedIssueExecutionWorkspaceSettings = parseIssueExecutionWorkspaceSettings( issueContext?.executionWorkspaceSettings, ); @@ -13778,6 +13783,7 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {}) } : null, exposeLowTrustRaw, + simplifiedEnglishInteractions: experimentalInstanceSettings.enableSimplifiedEnglishInteractions === true, }); if (paperclipWakePayload) { context[PAPERCLIP_WAKE_PAYLOAD_KEY] = paperclipWakePayload; diff --git a/server/src/services/instance-settings.ts b/server/src/services/instance-settings.ts index f7a017c5c9..9be8b2e1a0 100644 --- a/server/src/services/instance-settings.ts +++ b/server/src/services/instance-settings.ts @@ -227,6 +227,7 @@ export function normalizeExperimentalSettings(raw: unknown): InstanceExperimenta enableDecisions: parsed.data.enableDecisions ?? false, enableGoalsSidebarLink: parsed.data.enableGoalsSidebarLink ?? false, enableServerInfoDebugView: parsed.data.enableServerInfoDebugView ?? false, + enableSimplifiedEnglishInteractions: parsed.data.enableSimplifiedEnglishInteractions ?? false, autoRestartDevServerWhenIdle: parsed.data.autoRestartDevServerWhenIdle ?? false, enableIssueGraphLivenessAutoRecovery: parsed.data.enableIssueGraphLivenessAutoRecovery ?? false, enableWorkspaceBranchReconcileForward: parsed.data.enableWorkspaceBranchReconcileForward ?? true, @@ -262,6 +263,7 @@ export function normalizeExperimentalSettings(raw: unknown): InstanceExperimenta enableDecisions: false, enableGoalsSidebarLink: false, enableServerInfoDebugView: false, + enableSimplifiedEnglishInteractions: false, autoRestartDevServerWhenIdle: false, enableIssueGraphLivenessAutoRecovery: false, enableWorkspaceBranchReconcileForward: true, diff --git a/ui/src/pages/InstanceExperimentalSettings.test.tsx b/ui/src/pages/InstanceExperimentalSettings.test.tsx index 3e6ae06160..04dc76705c 100644 --- a/ui/src/pages/InstanceExperimentalSettings.test.tsx +++ b/ui/src/pages/InstanceExperimentalSettings.test.tsx @@ -90,6 +90,7 @@ function defaultExperimentalSettings(): InstanceExperimentalSettingsPayload { enableGoalsSidebarLink: false, enableTaskWatchdogs: false, enableServerInfoDebugView: false, + enableSimplifiedEnglishInteractions: false, enableSmokeLab: false, autoRestartDevServerWhenIdle: false, enableIssueGraphLivenessAutoRecovery: false, diff --git a/ui/src/pages/InstanceExperimentalSettings.tsx b/ui/src/pages/InstanceExperimentalSettings.tsx index 40a2a40359..1be545941c 100644 --- a/ui/src/pages/InstanceExperimentalSettings.tsx +++ b/ui/src/pages/InstanceExperimentalSettings.tsx @@ -379,6 +379,8 @@ export function InstanceExperimentalSettings() { const enableGoalsSidebarLink = experimentalQuery.data?.enableGoalsSidebarLink === true; const enableCases = experimentalQuery.data?.enableCases === true; const enableServerInfoDebugView = experimentalQuery.data?.enableServerInfoDebugView === true; + const enableSimplifiedEnglishInteractions = + experimentalQuery.data?.enableSimplifiedEnglishInteractions === true; const enableSmokeLab = experimentalQuery.data?.enableSmokeLab === true; const autoRestartDevServerWhenIdle = experimentalQuery.data?.autoRestartDevServerWhenIdle === true; const enableIssueGraphLivenessAutoRecovery = @@ -748,6 +750,18 @@ export function InstanceExperimentalSettings() { ariaLabel="Toggle server info debug view experimental setting" /> + + toggleMutation.mutate({ enableSimplifiedEnglishInteractions: checked }) + } + disabled={toggleMutation.isPending} + managed={managedKeys.enableSimplifiedEnglishInteractions} + ariaLabel="Toggle simplified english interactions experimental setting" + /> +