/** * Conversational "not configured" response — every metric tool calls * this when the MCP has no real env configured for the call. Returns * a structured markdown message that names the supported backend * kinds, lists what info each needs, and tells the agent to drive the * user through `log10x_configure_env`. * * The MCP doesn't ask the user directly — agents do, by reading this * response and turning it into a conversation. Same pattern * `signin_start` already uses for the log10x backend's Auth0 device * flow. * * Demo-mode gate: surface when `envs.isDemoMode && !envs.demoFallbackReason` * (pure-demo state means nothing was configured and we silently * landed on the demo backend). Phase 7 makes the unconfigured state * explicit — no more silent demo. */ import type { Environments } from './environments.js'; import { type StructuredOutput, type Action } from './output-types.js'; import { type ChassisEnvelope } from './chassis-envelope.js'; export interface NotConfiguredOptions { /** The tool that's reporting the not-configured state, for context. */ callingTool: string; /** * Whether `log10x_configure_env` is callable in the current boot state. * It is not when the MCP is attached to the shared public demo dataset: * DEMO_FALLBACK_DENYLIST keeps every mutator off the shared account, so * configure_env is never registered there. Telling the agent to call an * unregistered tool is how the demo walkthrough dead-ended. Defaults to * true, which is the state every non-demo caller is in. */ configureEnvRegistered?: boolean; } /** * Build the structured `not_configured` response. Returns a markdown * string that the calling tool returns directly. */ export declare function renderNotConfigured(opts: NotConfiguredOptions): string; /** * Returns the `not_configured` markdown if the MCP is in pure-demo * state (no user configuration, silently landed on the demo backend); * returns undefined otherwise. * * Demo-mode gate: tools check this at the top of their execute() and * return the response immediately if defined. */ export declare function notConfiguredMessageIfNeeded(envs: Environments, callingTool: string): string | undefined; /** Which precondition is missing. Drives the default remediation copy. */ export type NotConfiguredKind = 'metrics_backend' | 'customer_metrics' | 'retriever' | 'siem' | 'gitops' | 'generic'; /** * Throw this from a tool when a precondition is missing and you want the * loud-failure path (the throw is caught at the `wrap()` chokepoint and * converted to a structured `not_configured` envelope). Carries the kind, * a remediation markdown block, and optional next-step actions so the * chokepoint can build a rich envelope without re-deriving them. */ export declare class NotConfiguredError extends Error { /** Stable discriminator read by `isNotConfiguredError` (survives bundling). */ readonly code: "not_configured"; readonly kind: NotConfiguredKind; readonly remediation?: string; readonly actions?: Action[]; constructor(kind: NotConfiguredKind, opts?: { message?: string; remediation?: string; actions?: Action[]; }); } /** * Recognise a "not configured" error at the `wrap()` chokepoint: * precisely, by discriminator, NOT by fuzzy message matching (a stray * "...is not configured" in some unrelated error must not be hijacked). * Matches: our own `NotConfiguredError` (by `code`), and the engine's * `CustomerMetricsNotConfiguredError` (by `name`). Matching by name keeps * this base module dependency-free: it must not import customer-metrics.ts * (this is a low-level module many tools import; pulling the heavy * customer-metrics graph in here would bloat the import surface and risk a * future cycle). */ export declare function isNotConfiguredError(e: unknown): boolean; /** * Build a structured `not_configured` envelope. `remediation` is the * markdown the agent should surface; `actions` are the next-step tool * calls that fix it. The headline tells the agent this is an expected * state to branch on, not a failure to retry. * * Returns a ChassisEnvelope (which extends StructuredOutput) so every * caller gets invocation_id, performance, and a valid ChassisData shape. * The existing precondition + remediation fields are preserved in * data.payload so agents that already read data.payload.status / * data.payload.precondition / data.payload.remediation continue to work. * * Chassis wire-up: status=error, error_type=config_missing, * retryable=false — the clean, branchable signal that the chassis * verifier expects. NOT isError on the MCP transport; not_configured is * an expected state. */ export declare function buildNotConfiguredEnvelope(args: { tool: string; kind?: NotConfiguredKind; remediation: string; actions?: Action[]; diagnostic?: string; }): ChassisEnvelope; /** * Default remediation actions per kind, so the agent has a concrete next step. * * `configureEnvRegistered: false` swaps the metrics_backend action for * `log10x_signin_start`. An action naming a tool the session did not register * is not a next step; it is a dead end the agent cannot detect until it calls * and gets "no such tool". */ export declare function defaultActionsForKind(kind: NotConfiguredKind, opts?: { configureEnvRegistered?: boolean; }): Action[]; /** * Convert a thrown error into a structured `not_configured` envelope. * Used by the `wrap()` chokepoint so a deliberate throw (the loud * human-escape-hatch path) still reaches the agent as a branchable, * chain-safe result. Falls back to a generic envelope carrying the raw * message when the throw isn't a recognised kind. */ export declare function notConfiguredEnvelopeFromError(tool: string, e: unknown): StructuredOutput; /** * Validate + shape a `not_configured` envelope into the MCP tool-result * form (text channel carries the JSON; structured channel ships the * typed envelope). Mirrors the success path in `wrap()`; kept here so the * chokepoint stays a one-liner and the not-configured contract lives in * one place. NOT `isError`: `not_configured` is an expected state. */ export declare function notConfiguredToolResult(env: StructuredOutput): { content: Array<{ type: 'text'; text: string; }>; structuredContent: Record; };