/** * PainSignalRuntimeFactory — creates PainSignalBridge for a given workspace. * * M8 direction: both openclaw-plugin (after_tool_call hook) and pd-cli * use the same PainSignalBridge to enter the Runtime v2 pain chain. * pd-cli can call this factory without importing openclaw-plugin private code. * * Usage: * import { createPainSignalBridge } from '@principles/core/runtime-v2'; * const bridge = await createPainSignalBridge({ workspaceDir, stateDir, ledgerAdapter }); * await bridge.onPainDetected(data); */ import { PainSignalBridge, type DiagnosticianRunnerLike } from './pain-signal-bridge.js'; import type { RunnerResult } from './runner/runner-result.js'; import { type CandidateIntakeServiceOptions } from './candidate-intake-service.js'; import type { TrajectoryTurnReader } from './store/context/trajectory-turn-reader.js'; import type { TelemetryEvent } from '../telemetry-event.js'; import type { RuntimeKind } from './runtime-protocol.js'; import type { LedgerAdapter } from './candidate-intake.js'; import type { IntentDocReader } from './intent/intent-doc-reader-port.js'; import type { EffectivePdConfig, InternalAgentName } from './config/pd-config-types.js'; export interface PainSignalRuntimeFactoryOptions { workspaceDir: string; stateDir: string; ledgerAdapter: LedgerAdapter; owner?: string; autoIntakeEnabled?: boolean; /** PRI-306: Effective PD config for config-driven runtime binding. * When provided, takes precedence over WorkflowFunnelLoader. */ effectiveConfig?: EffectivePdConfig; /** PRI-306: Env var accessor for readiness checks. Defaults to process.env. */ getEnvVar?: (name: string) => string | undefined; /** * PRI-468: Optional INTENT.md reader for Stage A intent tension check. * * Provided by the plugin layer (which owns filesystem I/O). When present * AND `intent_engineering` flag is on, Stage A reads INTENT.md and * injects it into the prompt. When absent, intent_engineering degrades * silently to off (telemetry emitted by the runner). * * Core never performs filesystem I/O — it only consumes the port. */ intentDocReader?: IntentDocReader; trajectoryTurnReader?: TrajectoryTurnReader; /** * PRI-939 Option A: optional workspace-scoped telemetry sink (host-runtime * WorkspaceTelemetryEmitter) for short-lived CLI processes. Bridge telemetry * mapped by createBridgeTelemetryEventEmitter forwards here instead of the * unsubscribed storeEmitter singleton, so allowlisted events * (reuse_gate_triggered / reuse_evaluation_unavailable) persist to * critical-events.jsonl. Absent = pre-Option-A behavior (singleton). */ telemetrySink?: { emitTelemetry: (event: TelemetryEvent) => void; }; } /** Total timeout for the 3-stage split pipeline (3 × 20 min = 60 min). * Local GPU inference (e.g. qwen3.6-27b-mtp with 200K context) needs * 10-18 min per stage; 20 min per stage provides headroom. * Shared with pd-cli diagnose command. */ export declare const SPLIT_PIPELINE_TOTAL_TIMEOUT_MS = 3600000; /** Resolved runtime configuration from funnel policy. */ export interface RuntimeConfig { runtimeKind: RuntimeKind; openclawMode?: 'local' | 'gateway'; timeoutMs: number; agentId: string; provider?: string; model?: string; apiKeyEnv?: string; maxRetries?: number; /** Max output tokens (max_tokens) for pi-ai LLM calls. */ maxTokens?: number; /** Optional reasoning level (flows from profile to PiAiRuntimeAdapter; PRI-758). */ reasoning?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | false; /** Custom base URL for OpenAI-compatible providers not in pi-ai's built-in registry. */ baseUrl?: string; /** Optional system prompt (flows from profile to PiAiRuntimeAdapter). */ systemPrompt?: string; /** * PRI-719: the runtimeProfile id this config was resolved FROM (absent on * legacy/CLI-override resolutions). Lets run evidence answer * "which declared profile actually executed" without a second lookup. */ runtimeProfileId?: string; } export interface RuntimeConfigError { ok: false; reason: string; message: string; nextAction: string; } export type RuntimeConfigResult = RuntimeConfig | RuntimeConfigError; export declare function isRuntimeConfigError(result: RuntimeConfigResult): result is RuntimeConfigError; export interface ResolveRuntimeConfigOptions { openclawLocal?: boolean; openclawGateway?: boolean; requestedRuntimeKind?: string; } /** * Resolve runtime configuration from the pd-runtime-v2-diagnosis funnel policy. * Falls back to defaults if no funnel is found. * * @deprecated PRI-393: This function reads .state/workflows.yaml and MUST NOT be * called by production execution paths (probe, run-once, diagnose, pain-retry). * Use resolveRuntimeConfigFromPdConfig() with loadPdConfig() instead. * Retained only for legacy warning / migration detection. * * When `requestedRuntimeKind === 'openclaw-cli'` or policy `runtimeKind === 'openclaw-cli'`: * - CLI flag or file config must provide exactly one mode (local or gateway). * - Both provided: fail loud (conflicting mode). * - Neither provided: fail loud (missing mode). * * When `requestedRuntimeKind === 'config'` (explicit config): * - Config load failure, missing config, or schema error must fail loud. * - Only non-explicit config compatibility paths allow fallback. */ export declare function resolveRuntimeConfig(stateDir: string, explicitConfig?: ResolveRuntimeConfigOptions): RuntimeConfigResult; /** * Validate runtime configuration before adapter creation (D-02). * Throws plain Error (not PDRuntimeError) for config issues (D-06). * Includes migration guidance for D-05 breaking change. */ export declare function validateRuntimeConfig(config: RuntimeConfig): void; /** * PRI-719: taskKind → internalAgents.agents key for the consumer/run-once * peer stages. `rollout_reviewer` maps to the camelCase agent name * `rolloutReviewer` (INTERNAL_AGENT_NAMES); diagnostic stages are NOT here — * they run through the pain-signal bridge, which owns the diagnostician * binding. */ export declare const AGENT_NAME_FOR_TASK_KIND: Readonly>; export interface ResolveRuntimeConfigForAgentOptions { /** Env var accessor for readiness checks. */ readonly getEnvVar: (name: string) => string | undefined; /** * PRI-719: resolve the binding even when the agent is disabled. The * consumer's per-stage scope is governed by the internalization_full_chain * FLAG, not by internalAgents.agents[kind].enabled — the shipped default * config disables philosopher/evaluator/rolloutReviewer yet the full-chain * consumer runs them. `enabled` gates the pain-signal bridge * (diagnostician). Lifts only the gate, through the SAME binding * authority, via a read-only re-enabled view of the config. */ readonly ignoreAgentEnabled?: boolean; } export declare function resolveRuntimeConfigForAgent(effectiveConfig: EffectivePdConfig, agentName: InternalAgentName, options: ResolveRuntimeConfigForAgentOptions): RuntimeConfigResult; /** * Resolve runtime configuration from a NAMED profile id rather than an agent * binding (PRI-917 v0.3.2 §8 — the Semantic Reuse Evaluation Capability is a * dedicated config section, NOT an internal agent, so it must not acquire an * `internalAgents.agents[*]` entry in order to reach a profile). * * Fail-closed: an unknown profile id is a config error, never a silent * fallback onto some other profile's LLM. */ export declare function resolveRuntimeConfigForProfile(effectiveConfig: EffectivePdConfig, profileId: string, getEnvVar: (name: string) => string | undefined): RuntimeConfigResult; /** * PRI-917 v0.3.3 (OD-PRI917-05) — build the auto-path Reuse Review Gate * recommendation hook from the `reuseEvaluation` config section. * * Single implementation shared by all three automatic intake construction * sites (this factory + `pd diagnose` + `pd pain-retry`). Returns `undefined` * when the capability is disabled or no effective config was supplied — the * caller then injects nothing and intake behaves EXACTLY as before v0.3.3 * (SPEC T11: the rollback switch). The returned hook NEVER throws and NEVER * returns a decision: every failure degrades to `{ status: 'unavailable' }` * so CREATE proceeds (Rule 4). It reads the ledger read-only * (readReusablePrinciples) to assemble the proposal texts — the same data the * `pd candidate review` surface shows the Owner. */ export declare function createReuseRecommendationHook(args: { effectiveConfig?: EffectivePdConfig; workspaceDir: string; stateDir: string; getEnvVar?: (name: string) => string | undefined; }): CandidateIntakeServiceOptions['reuseRecommendation']; /** * PRI-306: Resolve runtime configuration from EffectivePdConfig. * * Uses resolveAgentRuntimeBinding() to determine which profile the diagnostician * should use, then checks readiness and produces adapter config. * * This is the new config-driven path that replaces WorkflowFunnelLoader. * When effectiveConfig is provided, this path takes precedence. */ export declare function resolveRuntimeConfigFromPdConfig(effectiveConfig: EffectivePdConfig, getEnvVar: (name: string) => string | undefined): RuntimeConfigResult; export interface DisabledDiagnosticianRunnerOptions { /** Human-readable reason. Defaults to the canonical Owner-disable message. */ readonly failureReason?: string; /** Recovery action surfaced to the Owner / CLI operator. */ readonly nextAction?: string; } export declare const DIAGNOSTICIAN_DISABLED_FAILURE_REASON = "Diagnostician capability is disabled by Owner configuration (internalAgents.agents.diagnostician.enabled=false)"; export declare const DIAGNOSTICIAN_DISABLED_NEXT_ACTION = "Enable internalAgents.agents.diagnostician.enabled in .pd/config.yaml (or Console \u2192 Control Center), then retry."; /** * DisabledDiagnosticianRunner — the single representation of "Diagnostician is * not available" (PRI-638). * * Before PRI-638 this class was selected by the `diagnostician_split_pipeline` * feature flag, which made a rollout flag act as a second kill switch. The * Owner capability authority (`internalAgents.agents.diagnostician.enabled`) is * now the only thing that produces this runner. * * Contract (identical for every entrypoint): * - status: 'failed' * - errorCategory: 'capability_missing' (existing PDErrorCategory — reuse, do * not invent a new enum) * - zero provider/LLM calls: the runner never touches an adapter * - attemptCount stays informational; the task is not marked failed by this * runner, so no LLM retry budget is consumed (see PainSignalBridge) */ export declare class DisabledDiagnosticianRunner implements DiagnosticianRunnerLike { private readonly failureReason; private readonly nextAction; constructor(opts?: DisabledDiagnosticianRunnerOptions); run(taskId: string): Promise; } export declare function mapBridgeTelemetryToStoreEvent(event: { eventType: string; traceId: string; timestamp: string; payload: Record; }): TelemetryEvent | null; /** * The single bridge→store telemetry emitter, shared by the factory and the * CLI diagnosis paths (PRI-935). Call sites must not re-implement the mapping * rule: only persistence-degradation events reach the store emitter, so * rc-9 observability stays identical wherever the bridge runs. */ export declare function createBridgeTelemetryEventEmitter(sink?: { emitTelemetry: (event: TelemetryEvent) => void; }): { emitTelemetry: (event: Parameters[0]) => void; }; /** * PRI-624: dispose + drop every cached bridge for a workspace, releasing * their SQLite handles. Per-cycle workers (Companion workspace worker) call * this after execution; long-lived hosts that reuse the cached bridge do not. */ export declare function disposePainSignalBridgesForWorkspace(workspaceDir: string): Promise; export declare function createPainSignalBridge(opts: PainSignalRuntimeFactoryOptions): Promise; /** * PRI-638: bridge for the "Owner disabled the Diagnostician" state. * * Deliberately built WITHOUT a runtime adapter — there is nothing to call, and * constructing one is what previously forced a hard throw. Everything the * durable Pain path needs (state manager + intake) is still wired, so pains * keep landing and can be diagnosed after the Owner re-enables the agent. */ export declare function invalidatePainSignalBridge(workspaceDir: string, runtimeKind?: string): void; //# sourceMappingURL=pain-signal-runtime-factory.d.ts.map