mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-19 09:44:07 +00:00
fix(server): wire CLAUDE_SYSTEM_PROMPT (dead since APPEND_SYSTEM_PROMPT retirement) (#175)
* fix(server): wire CLAUDE_SYSTEM_PROMPT into the composed system prompt (was dead since APPEND_SYSTEM_PROMPT retirement) The var was read (SYSTEM_PROMPT, server.mjs), documented in the file header as "appended to all requests", and echoed on /health.systemPrompt — but nothing on the request path consumed it: extractSystemPrompt() composed only the wrapper + client system messages. The wiring was lost when APPEND_SYSTEM_PROMPT was retired, leaving the header comment and the buildCliArgs comment describing behavior that did not exist (caught by the PR #170 independent reviewer). Wire, not delete, because: - the /health `systemPrompt` field is part of the grandfathered B.2 contract (ADR 0006, frozen at v3.16.4) — removal would need an ADR; wiring keeps the shape and makes the field honest; - fleet check: no deployment sets the var (Mac prod plist, Oracle systemd unit, PI231 /etc/ocp/ocp.env all clean), so wiring changes behavior for NOBODY today; - with the var unset, appendOperatorPrompt returns its input string unchanged — the default path is byte-for-byte identical. Mechanics: new pure lib/prompt.mjs `appendOperatorPrompt(base, operatorAppend)` (trimmed; whitespace-only treated as unset so a stray space in a service unit cannot inject "\n\n " into every request), applied as the LAST segment in both extractSystemPrompt branches — an operator-wide directive reads as the final instruction, after client system messages. TUI-mode is untouched (panes keep the interactive CLI's own system prompt); documented in the README row. ALIGNMENT.md Rule 2: no cli.js citation applies. No endpoint, header, or wire field is added or altered; the change affects only the CONTENT OCP passes to the already-established `--system-prompt` flag (file header § verified v2.1.104), i.e. OCP-owned prompt composition. /health shape unchanged. Tests: +3, doubly mutation-proven (unconditional-base revert → 2 failures; trim removal → 2 failures). Suite 341 passed / 0 failed. Co-Authored-By: Claude <claude-opus-4-8> <noreply@anthropic.com> * docs(readme): cache-staleness caveat on CLAUDE_SYSTEM_PROMPT row (reviewer advisory) --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude <claude-opus-4-8> <noreply@anthropic.com>
This commit is contained in:
+7
-4
@@ -49,6 +49,7 @@ import { TuiSemaphore, SemaphoreAbortError, recordTuiEntrypoint, buildTuiHealthB
|
||||
import { TuiPanePool, resolvePoolSize, POOL_MAX_SIZE } from "./lib/tui/pool.mjs";
|
||||
import { TuiDeltaAssembler, DEFAULT_HOLDBACK_CHARS, resolveStreamHoldback } from "./lib/tui/stream.mjs";
|
||||
import { createSerialMutex, createTtlCache, isTokenExpiring, orderLabelsLastGoodFirst } from "./lib/spawn-auth.mjs";
|
||||
import { appendOperatorPrompt } from "./lib/prompt.mjs";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const _pkg = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8"));
|
||||
@@ -195,17 +196,19 @@ function resolveClaude() {
|
||||
const OCP_SYSTEM_PROMPT_WRAPPER = `You are accessed via the OCP HTTP proxy. You do NOT have access to any local filesystem, working directory, shell, git status, or machine environment. Do not infer or invent such information from any context you observe. Respond only based on the conversation provided.`;
|
||||
|
||||
// Build the full system-prompt string: OCP_SYSTEM_PROMPT_WRAPPER prepended,
|
||||
// then any system-role messages from the request appended (separated by blank line).
|
||||
// ADR 0009 Amendment 1 analogue § "OLP system prompt wrapper".
|
||||
// then any system-role messages from the request appended (separated by blank line),
|
||||
// then the operator-wide CLAUDE_SYSTEM_PROMPT appended LAST (lib/prompt.mjs — a
|
||||
// no-op returning the same string when the var is unset, so the default path is
|
||||
// byte-for-byte unchanged). ADR 0009 Amendment 1 analogue § "OLP system prompt wrapper".
|
||||
function extractSystemPrompt(messages) {
|
||||
const systemMessages = (messages ?? []).filter(m => m.role === "system");
|
||||
if (systemMessages.length === 0) {
|
||||
return OCP_SYSTEM_PROMPT_WRAPPER;
|
||||
return appendOperatorPrompt(OCP_SYSTEM_PROMPT_WRAPPER, SYSTEM_PROMPT);
|
||||
}
|
||||
const clientContent = systemMessages.map(m =>
|
||||
contentToText(m.content)
|
||||
).join("\n\n");
|
||||
return `${OCP_SYSTEM_PROMPT_WRAPPER}\n\n${clientContent}`;
|
||||
return appendOperatorPrompt(`${OCP_SYSTEM_PROMPT_WRAPPER}\n\n${clientContent}`, SYSTEM_PROMPT);
|
||||
}
|
||||
|
||||
// ── NDJSON line buffer parser (Phase 6c port) ─────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user