/**
 * flowchartAsTool — wrap a footprintjs `FlowChart` as an Agent `Tool`.
 *
 * NOTE (9.76.0): for NEW procedures prefer `runbookAsTool` (core/runbook/) —
 * the standard bridge whose every answer carries the honesty envelope
 * (coverage, provenance, rule version, the recorded walk). This thin wrapper
 * stays for compatibility; `resultMapper` users stay put and nothing here
 * changes.
 *
 * The Block A7 piece. footprintjs is the substrate; agentfootprint is
 * the agent layer above it. When a multi-step procedure is already
 * expressed as a footprintjs flowchart (intake validation, refund
 * processing, claim adjudication — anything with branches, loops, or
 * decision evidence), let the LLM call it as ONE tool. The flowchart's
 * step-by-step recorders, narrative, and pause/resume continue to work
 * exactly as they do outside the agent.
 *
 * Why this matters:
 *
 *   1. **Composition over re-write.** A team with a non-trivial
 *      footprintjs flowchart shouldn't have to flatten it into N
 *      separate tools to expose it to an agent. Wrap it once.
 *
 *   2. **Observability stays free.** Every flowchart stage emits typed
 *      events. The Agent's recorders see the wrapping tool call;
 *      footprintjs's recorders see everything inside. Two layers,
 *      one observation tree. The `recorders` option bridges them:
 *      attach agent-layer observers (the causal-evidence bridge,
 *      `otel.decisionEvidenceRecorder()`, your own CombinedRecorder)
 *      to the tool's INTERNAL executor so decide()/select() evidence
 *      inside the flowchart reaches them too.
 *
 *   3. **The record can go THROUGH the boundary.** `keepRecord: true`
 *      retains each invocation's inner record under the `toolCallId` that
 *      named the call, so a `.selfExplain()` agent asked "why did you say
 *      it will rain?" does not stop at *"⚠ what happened inside the tool
 *      is not traced"* — it descends with `inspect_tool_run` and cites the
 *      inner stage and the field that decided it. Off by default: a
 *      retained record is retained memory (bounded LRU, default 20
 *      invocations, `keepRecordLimit` to change it).
 *
 *   4. **Pause/resume composes.** A pausable handler inside the
 *      flowchart pauses the inner executor; the outer agent treats
 *      the pause as an unfinished tool call. Resume the agent and the
 *      inner flowchart resumes from its checkpoint. (Today: surfaces
 *      the pause as a thrown error with the checkpoint attached;
 *      polished agent-side pause integration in v2.6.)
 *
 * Pattern: Adapter (GoF) over `FlowChartExecutor.run()`. Translates
 *          `Tool.execute(args, ctx)` into `executor.run({ input: args,
 *          env: { signal: ctx.signal } })` and the result back to a
 *          string via `resultMapper` (or a default JSON stringify).
 *
 * Role:    Layer-6 (Agent) → Layer-1 (footprintjs) bridge. Pure
 *          interop; no new abstraction in either layer.
 *
 * @example  Single-stage flowchart as a tool
 *   import { flowChart } from 'footprintjs';
 *   import { Agent, flowchartAsTool } from 'agentfootprint';
 *
 *   const refundChart = flowChart<{ refundId: string }>(
 *     'RefundFlow',
 *     async (scope) => {
 *       const args = scope.$getArgs<{ orderId: string; reason: string }>();
 *       scope.refundId = await refundService.process(args.orderId);
 *     },
 *     'refund-flow',
 *   ).build();
 *
 *   const refundTool = flowchartAsTool({
 *     name: 'process_refund',
 *     description: 'Process a refund for an order. Returns refundId on success.',
 *     inputSchema: {
 *       type: 'object',
 *       properties: {
 *         orderId: { type: 'string' },
 *         reason: { type: 'string' },
 *       },
 *       required: ['orderId', 'reason'],
 *     },
 *     flowchart: refundChart,
 *     resultMapper: (snapshot) =>
 *       JSON.stringify({ refundId: snapshot.values.refundId, status: 'processed' }),
 *   });
 *
 *   const agent = Agent.create({ provider }).tool(refundTool).build();
 *
 * @example  Multi-stage flowchart with decide() + recorders
 *   const triageChart = flowChart<TriageState>('Triage', validateInput, 'validate')
 *     .addDeciderFunction('Classify', classifyDecider, 'classify')
 *       .addFunctionBranch('high', 'Escalate', escalate)
 *       .addFunctionBranch('low', 'Auto-handle', autoHandle)
 *       .end()
 *     .build();
 *
 *   // decide() evidence inside the chart fires `onDecision` on each
 *   // attached recorder — wire the agent's evidence consumers straight
 *   // into the tool instead of hand-mounting the chart.
 *   const evidence = causalEvidenceRecorder();
 *
 *   const triageTool = flowchartAsTool({
 *     name: 'triage_request',
 *     description: 'Triage an incoming request and return the decision.',
 *     inputSchema: { ... },
 *     flowchart: triageChart,
 *     recorders: [evidence],
 *   });
 *
 * @example  A tool whose inner run the agent can explain later
 *   const adviceTool = flowchartAsTool({
 *     name: 'weather_advice',
 *     description: 'Fetch tomorrow’s forecast and advise on biking.',
 *     inputSchema: { ... },
 *     flowchart: adviceChart,
 *     keepRecord: true,               // keep each invocation's inner record
 *     keepRecordLimit: 20,            // …bounded (default; LRU)
 *     redact: { keys: ['apiKey'] },   // …one rule: the log, the result, the kept record
 *   });
 *
 *   const agent = Agent.create({ provider })
 *     .tool(adviceTool)
 *     .selfExplain()   // inspect_tool_call now teaches inspect_tool_run
 *     .build();
 */
import { type CombinedRecorder, type FlowChart, type RedactionPolicy } from 'footprintjs';
import type { Tool } from '../tools/tools.js';
/**
 * Pruned snapshot view passed to `resultMapper`. We keep this minimal
 * (the values bag + the chart's narrative entries) to avoid leaking
 * internal scope plumbing. Consumers needing the full snapshot can
 * pass a `passthrough` resultMapper that ignores the prune.
 */
export interface FlowchartToolSnapshot {
    /**
     * Final scope state — the merged result of every stage's writes, as the
     * tool may SHOW it: `executor.getSnapshot().sharedState` without a
     * `redact` policy, the redacted mirror with one (`servableSnapshot`).
     */
    readonly values: Readonly<Record<string, unknown>>;
    /**
     * The flowchart's combined narrative entries (flow + data).
     * Useful for resultMappers that want to extract specific commit
     * artifacts or audit a decision path.
     */
    readonly narrative: readonly {
        readonly type?: string;
        readonly text?: string;
    }[];
}
/**
 * Optional result mapper. Receives the flowchart's final snapshot
 * (pruned to `FlowchartToolSnapshot`) and returns the string the LLM
 * sees as the tool result.
 *
 * If omitted, the default behavior is `JSON.stringify(snapshot.values)`.
 *
 * Errors thrown from the mapper become the tool result with a
 * `[mapper-error: ...]` prefix so the LLM sees a useful diagnostic.
 */
export type FlowchartResultMapper = (snapshot: FlowchartToolSnapshot) => string;
/**
 * Options for `flowchartAsTool`.
 */
export interface FlowchartAsToolOptions {
    /** Tool name the LLM dispatches by. Must be unique across the agent's tools. */
    readonly name: string;
    /** Tool description shown to the LLM. */
    readonly description: string;
    /**
     * JSON Schema describing the input args the LLM must produce.
     * Becomes `flowchart.run({ input: args })`. Default: `{ type: 'object', properties: {} }`.
     */
    readonly inputSchema?: Readonly<Record<string, unknown>>;
    /**
     * The footprintjs flowchart to mount as the tool's body.
     * The chart's stages receive args via `scope.$getArgs()`.
     */
    readonly flowchart: FlowChart;
    /**
     * Optional shaping function. Default: `JSON.stringify(snapshot.values)`.
     * Errors throw into the tool's `[mapper-error: ...]` envelope.
     */
    readonly resultMapper?: FlowchartResultMapper;
    /**
     * Observers to attach to the tool's INTERNAL `FlowChartExecutor`
     * before each run. This is the hook that lets decide()/select()
     * evidence (and every other footprintjs event) inside a tool-mounted
     * flowchart reach agent-layer evidence consumers — e.g. the causal
     * `causalEvidenceRecorder()` bridge or `otel.decisionEvidenceRecorder()`.
     * Without it, the internal executor is unobservable from outside.
     *
     * Each entry is a footprintjs `CombinedRecorder`, attached via
     * `executor.attachCombinedRecorder` and routed by runtime
     * method-shape detection — so ONE array covers all three observer
     * channels (scope data-flow `onRead`/`onWrite`/`onCommit`/…,
     * control-flow `onDecision`/`onSelected`/`onLoop`/…, and emit
     * `onEmit`). Implement only the hooks you care about.
     *
     * **Per-invocation semantics:** the tool builds a FRESH executor per
     * call (flowchart state never leaks between invocations) and attaches
     * every recorder in this array to EACH invocation's executor before
     * `run()`. The recorder INSTANCES are yours and are shared across
     * invocations — a stateful recorder therefore accumulates events from
     * EVERY invocation of the tool. Each invocation is a distinct run
     * with a fresh `runId`; recorders needing per-invocation bookkeeping
     * detect the boundary via `event.traversalContext.runId !== lastRunId`
     * (Convention 4) rather than assuming one run per recorder lifetime.
     */
    readonly recorders?: ReadonlyArray<CombinedRecorder>;
    /**
     * KEEP the inner run's record, so the agent's trace can go THROUGH this
     * tool boundary instead of stopping at it.
     *
     * Off by default, and the default is the honest one: a retained record
     * is a retained snapshot, and a tool called every turn would pin one per
     * call forever. Turning it on is the caller agreeing to that memory.
     *
     * With it on, each invocation's record is filed under the `toolCallId`
     * the outer run already uses to name the call — so `inspect_tool_call`
     * gains a line teaching the descent, and `inspect_tool_run` opens the
     * inner chart with the same drill vocabulary (overview → step → value →
     * why). Records are bounded: the last {@link keepRecordLimit}
     * invocations, least-recently-used dropped first, and a session that
     * dropped some says so rather than answering "not found".
     *
     * What it costs when ON: one `controlDepRecorder()` attached per
     * invocation (so inner slices carry the `[control: rule]` edges a
     * serialized recording can never carry back), and the invocation's
     * snapshot held by reference until it ages out.
     *
     * What it costs when OFF: nothing. No store, no extra recorder, no
     * capture — the byte-identical path this tool had before the option
     * existed.
     *
     * **One store per `flowchartAsTool(...)` call**, held on the returned
     * tool — the same scoping as the `recorders` array above. Mount that one
     * tool object on two agents and they share it, which is usually what you
     * want (the id is the agent's own tool-call id) but is worth knowing if
     * the two agents can mint the same id: build the tool twice instead.
     */
    readonly keepRecord?: boolean;
    /**
     * How many invocations `keepRecord` retains. Default
     * {@link DEFAULT_INNER_RUN_LIMIT} (20) — a debugging window, not an
     * archive. Only meaningful with `keepRecord: true`; passing it alone is
     * refused rather than silently ignored.
     */
    readonly keepRecordLimit?: number;
    /**
     * Redaction policy for the INNER run, applied before every invocation
     * (`executor.setRedactionPolicy`).
     *
     * footprintjs scrubs at COMMIT time, so a redacted key never reaches the
     * inner COMMIT LOG at all — through every path, since footprintjs 9.19.0
     * (see 3 below). Same mechanism, same placeholders, and the same
     * `(redacted by policy)` flag as the outer run; the trace tools pass
     * placeholders through verbatim and never reconstruct around them.
     *
     * ONE RULE FOR EVERYTHING THE TOOL SHOWS (9.89.1). With a policy set, every
     * state-bearing thing this tool hands outward is footprintjs's REDACTED
     * view — `getSnapshot({ redact: true })`, the mirror the engine maintains
     * beside the raw heap for exactly this — taken through one owner,
     * `servableSnapshot`:
     *
     * - the string this tool RETURNS: `resultMapper` is handed `snapshot.values`
     *   from that view (`'REDACTED'` where the log says so), so the default
     *   `JSON.stringify` and a custom mapper see the same thing the log holds;
     * - a kept record's `sharedState`, `commitLog` and every subflow's final
     *   state (`subflowResults[*].treeContext.globalContext` — the subflow's
     *   own redacted mirror, served by footprintjs itself since 9.20.0);
     * - on every exit — ok, error, paused — the record is filed from that view.
     *
     * Independent of `keepRecord` — a chart handling secrets should carry a
     * policy whether or not anyone keeps its record. Without this option the
     * raw snapshot is served, byte for byte as before.
     *
     * JOINED WITH THE CALLER'S. The inner run is nested in the agent run that
     * called the tool, and a run's policy covers the runs nested in it — so the
     * policy that run is covered by (`ctx.redact`, the agent's own `redact`) is
     * joined with this one for the inner run, its result and its kept record.
     * Either alone is enough to keep a name out; neither can remove one the
     * other selects. With neither, the tool behaves exactly as before.
     *
     * WHAT IT DOES NOT GOVERN — said here so nobody has to rediscover it:
     *
     * 1. The run's fold base. The redacted view OMITS `initialState`
     *    (footprintjs `ExecutionRuntime.getSnapshot`: the raw pre-run seed
     *    never passed a policy, so it is dropped rather than served). A fold of
     *    a kept record therefore reports `basis: 'log-only'` — partial, and
     *    saying so. A subflow's `treeContext.initialState` travels as
     *    footprintjs serves it: its seed is a commit of its own (`history[0]`),
     *    so that base is the nested runtime's pre-seed state.
     * 2. The resume checkpoint. A paused run throws with `err.checkpoint`,
     *    which holds real values because resumption must replay against them;
     *    it goes to the agent loop, never to a model.
     * 3. What the LOG itself carries — footprintjs's law, not this option's,
     *    and since footprintjs 9.19.0 (this package's floor from 9.89.2) that
     *    law is one rule: a policy covers everything the run retains or serves
     *    — the log in both encodings, the mirror, `stageReads`/`stageWrites`,
     *    the narrative, a subflow's `inputMapper` seed (its `history[0]` and
     *    its `Input:` line), its `outputMapper` merge-back, `fields` dot-paths
     *    — and never the live heap or the checkpoint. The five places 9.18
     *    left plaintext in the record (dot-path fields, merge-back, seed, seed
     *    narrative, tracked reads) are closed at the root, and each is asserted
     *    closed in `test/core/flowchartAsTool.redact.test.ts` §6 (red on 9.18).
     *    So "every field" means every field, and the log agrees. The last
     *    limit — `subflowResults[*].treeContext.globalContext` and its `#n`
     *    twin were the subflow's own heap, since only the run-level runtime
     *    kept a mirror, which `servableSnapshot` refolded from the scrubbed
     *    `history` — is closed by footprintjs 9.20.0 (this package's floor
     *    from 9.89.3): a subflow keeps its own mirror whenever the run does,
     *    and the redacted view serves it, one object under both keys. Nothing
     *    left the log carries that the served view does not scrub; the
     *    checkpoint is not a served view. `servableSnapshot` is now that view
     *    exactly as the substrate serves it, and §7 of the same file pins both
     *    the placeholder in footprintjs's own view (red on 9.19.x) and the
     *    identity.
     */
    readonly redact?: RedactionPolicy;
}
/**
 * Wrap a footprintjs `FlowChart` as a `Tool` the Agent's LLM can call.
 *
 * On execute:
 *   1. Constructs a fresh `FlowChartExecutor(flowchart)` per call (so
 *      consecutive invocations don't share state).
 *   2. Attaches each `opts.recorders` entry via
 *      `executor.attachCombinedRecorder` — the SAME recorder instances
 *      attach to every invocation's fresh executor (see the option's
 *      JSDoc for the shared-state / runId implications).
 *   3. Calls `executor.run({ input: args, env: { signal } })` with the
 *      LLM-supplied args + the agent's abort signal.
 *   4. If the run paused, throws an Error with the checkpoint attached
 *      (`error.checkpoint`) so the agent loop can surface it. Polished
 *      agent-side pause integration is v2.6 work.
 *   5. If the run completed, calls `resultMapper(snapshot)` (or the
 *      default JSON.stringify) and returns the string. The snapshot is
 *      the SERVED view (`servableSnapshot`): redacted when `redact` is
 *      set, raw otherwise — the same view the kept record holds.
 *   6. If the run threw, the error propagates — the Agent's
 *      tool-call handler converts it to a synthetic error string for
 *      the LLM to see + recover from.
 *   7. With `keepRecord: true`, files the inner record under
 *      `ctx.toolCallId` on ALL THREE exits (ok / error / paused) —
 *      "why did it fail?" is the question most likely to come next.
 */
export declare function flowchartAsTool(opts: FlowchartAsToolOptions): Tool;
