import { Tool } from 'ai'; /** * Error base + taxonomy primitives for @ar-agents/*. * * Every package SHOULD extend `ArAgentsError` for its own typed * errors so callers can rely on: * * - `code: string` — machine-readable identifier * - `retryable: boolean` — whether the caller should backoff + retry * - `context: Record` — structured ctx for logs * * Use the helper subclasses when the situation matches; subclass them * for jurisdiction/service-specific cases. */ interface ArAgentsErrorInit { code: string; /** Retry after backoff? Defaults to false. */ retryable?: boolean; /** Structured context attached to the error. Never include secrets. */ context?: Record; /** Underlying cause. */ cause?: unknown; } declare class ArAgentsError extends Error { readonly code: string; readonly retryable: boolean; readonly context: Record; constructor(message: string, init: ArAgentsErrorInit); } /** Caller passed bad input. Do NOT retry. */ declare class ArAgentsValidationError extends ArAgentsError { readonly field: string; constructor(field: string, message: string, context?: Record); } /** * Upstream returned a 2xx body whose SHAPE failed the response schema. * * This is the single most important error in the SDK's live-integration * story: it is what turns a malformed / partial / silently-changed API * response into a LOUD failure instead of letting `?? 0 / ?? [] / ?? false` * defaults fabricate a clean, creditworthy, zero-debt, invoiced, or canceled * result. Distinct from {@link ArAgentsValidationError} (bad *caller* input) so * a caller can tell "I sent garbage" apart from "the State/bank sent garbage." * * NOT retryable: a contract mismatch does not fix itself on backoff. Surface it * — a human needs to look at whether the upstream shape drifted. */ declare class ArAgentsResponseValidationError extends ArAgentsError { readonly field: string; constructor(field: string, message: string, context?: Record); } /** Adapter not wired. Surface to the operator. */ declare class ArAgentsUnconfiguredError extends ArAgentsError { constructor(operation: string, label?: string, context?: Record); } /** Auth rejected (token missing / expired / wrong scope). Don't retry blindly. */ declare class ArAgentsAuthError extends ArAgentsError { constructor(message: string, context?: Record); } /** Rate limit hit. Honors `retryAfterMs` for the caller's backoff loop. */ declare class ArAgentsRateLimitError extends ArAgentsError { readonly retryAfterMs: number; constructor(retryAfterMs: number, context?: Record); } /** Network / HTTP / upstream-service-down. Generally safe to retry. */ declare class ArAgentsProtocolError extends ArAgentsError { readonly status: number | null; constructor(message: string, init?: { status?: number | null; context?: Record; cause?: unknown; }); } /** * Type guard for any `@ar-agents/*` error. Use in switch logic: * * try { ... } catch (e) { * if (isArAgentsError(e) && e.retryable) backoffAndRetry(); * else throw e; * } */ declare function isArAgentsError(value: unknown): value is ArAgentsError; interface HttpRetryOptions { /** Max attempts (including the first). Default 4. */ maxAttempts?: number; /** Base delay in ms before the first retry. Default 200. */ baseDelayMs?: number; /** Max delay between retries in ms. Default 8000. */ maxDelayMs?: number; /** Jitter factor 0..1. Default 0.3 (±30%). */ jitter?: number; /** Fired before each retry (attempt is 1-based, pre-increment). */ onRetry?: (attempt: number, lastError: unknown) => void; } interface RetryDecision { shouldRetry: boolean; /** Override delay (e.g. from a `Retry-After` header), in ms. */ delayMsOverride?: number; } interface RetryContext { /** HTTP method of the request, uppercase. Default "GET". */ method?: string; /** Attempt number (1-based). */ attempt?: number; /** * Explicit override of method-based idempotency. When set it wins: pass * `true` for a POST that is safe to retry (idempotent endpoint or an * Idempotency-Key header), `false` to forbid retrying an otherwise-idempotent * method. Undefined → derive from {@link IDEMPOTENT_METHODS}. */ idempotent?: boolean; } /** A function that decides whether a thrown error / response is retryable. */ type RetryClassifier = (error: unknown, response: Response | null, ctx?: RetryContext) => RetryDecision; /** HTTP methods safe to retry by default (RFC 9110 idempotent set). */ declare const IDEMPOTENT_METHODS: ReadonlySet; /** Parse a `Retry-After` header value: integer seconds OR HTTP-date → ms. */ declare function parseRetryAfter(value: string): number | null; /** * Default classifier — retry on 5xx, 429, and network/timeout errors, but only * for idempotent requests (see {@link RetryContext.idempotent}). * * - **429**: retryable only if idempotent — honors `Retry-After`. A * non-idempotent money POST is NOT retried on a 429 (double-spend risk). * - **5xx**: retry only if idempotent — a gateway can persist a write after a * 5xx (split-brain), so retrying a POST risks a duplicate. * - **network error**: retry if idempotent. * - **our own timeout** (`TimeoutError` from `AbortSignal.timeout`): retry if * idempotent — the attempt was abandoned before a response. * - **caller cancellation** (`AbortError`): never retry — the caller asked to * stop. */ declare const defaultRetryClassifier: RetryClassifier; /** * Run an async op with exponential backoff. The op receives the 1-based attempt * number and either resolves or throws; the classifier decides on retry. For * HTTP prefer {@link fetchWithRetry}, which composes this with response * inspection. */ declare function runWithRetry(op: (attempt: number) => Promise, classifier?: RetryClassifier, options?: HttpRetryOptions, ctx?: RetryContext): Promise; /** * `runWithRetry` specialized for `fetch`. The wrapped call MUST return the * `Response` (not throw on 4xx/5xx) — this helper inspects the status itself and * synthesizes a retry-carrying error when the classifier says so. Network * errors (fetch throwing) propagate to the classifier as-is. */ declare function fetchWithRetry(url: string, init: RequestInit, options?: HttpRetryOptions, classifier?: RetryClassifier, fetchImpl?: typeof fetch, ctx?: RetryContext): Promise; declare function sleep(ms: number): Promise; /** One validation issue — the structural subset we read from zod's error. */ interface SchemaIssue { /** Path to the offending field. `join(".")`-able (zod gives `PropertyKey[]`). */ path?: ReadonlyArray; message: string; } type SafeParseResult = { success: true; data: T; } | { success: false; error: { issues: ReadonlyArray; }; }; /** * The structural contract a response schema must satisfy. Any Zod schema * (`z.object({...})`, `z.array(...)`, …) already does, with no cast — pass it * straight in. Custom validators can implement `safeParse` too. */ interface ResponseSchema { safeParse(value: unknown): SafeParseResult; } /** * Validate `value` against `schema`, returning the typed data or throwing * {@link ArAgentsResponseValidationError}. Use at every network boundary that * touches money or the State so a malformed body fails loud. * * @param context optional `{ url, status }` merged into the error's structured * context for logs — never put PII in the message; keep it here. */ declare function parseOrThrow(schema: ResponseSchema, value: unknown, context?: Record): T; type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD"; type QueryParams = Record; /** * Supplies the `Authorization` header value (the FULL value, e.g. * `"Bearer abc"`). A function is called per request so token refresh is * transparent; return `null` for an unauthenticated request. */ type AuthProvider = string | (() => string | null | Promise); interface HttpClientOptions { /** Base URL; every request path is resolved against it. */ baseUrl: string; /** Override fetch (tests / msw). Defaults to `globalThis.fetch`. */ fetch?: typeof fetch; /** Per-request timeout in ms. Default 30_000. */ timeoutMs?: number; /** Retry policy forwarded to {@link fetchWithRetry}. */ retry?: HttpRetryOptions; /** Custom retry classifier. Default: idempotency-aware 5xx/429/network. */ retryClassifier?: RetryClassifier; /** `User-Agent` sent on every request. */ userAgent?: string; /** Headers merged into every request (request-level headers win). */ defaultHeaders?: Record; /** Provides the `Authorization` header value; see {@link AuthProvider}. */ auth?: AuthProvider; } interface HttpRequest { method?: HttpMethod; /** Path relative to `baseUrl` (must start with `/`). Absolute URLs rejected. */ path: string; query?: QueryParams; /** Request body. Objects are JSON-serialized; strings are sent as-is. */ body?: unknown; /** Per-request headers (override `defaultHeaders`). */ headers?: Record; /** * Schema validated against the 2xx JSON body. STRONGLY recommended on * money/State paths: without it the raw parsed JSON is returned and the old * blind-cast footgun is back. With it, a malformed body throws * `ArAgentsResponseValidationError`. */ schema?: ResponseSchema; /** Caller AbortSignal, composed with the per-request timeout. */ signal?: AbortSignal; /** Per-request timeout override (ms). */ timeoutMs?: number; /** * Mark a non-idempotent method (POST/PATCH) as safe to retry — e.g. the * endpoint is idempotent or you set an Idempotency-Key header. Default: * method-based (GET/PUT/DELETE/HEAD retried, POST/PATCH not). */ idempotent?: boolean; /** Per-request retry override, or `false` to disable retry entirely. */ retry?: HttpRetryOptions | false; /** `Accept` header. Default `application/json`. */ accept?: string; } declare class HttpClient { readonly baseUrl: string; private readonly fetchImpl; private readonly timeoutMs; private readonly retry; private readonly retryClassifier; private readonly userAgent; private readonly defaultHeaders; private readonly auth; constructor(options: HttpClientOptions); /** Make a request and return the parsed (and, if `schema` given, validated) body. */ request(req: HttpRequest): Promise; /** * Make a request and return the raw `Response` (for binary bodies: PDFs, ZPL * labels, SOAP XML). Still runs the full auth + timeout + retry pipeline and * still throws a typed error on status >= 400 — the caller only owns body * decoding. */ requestRaw(req: HttpRequest): Promise; /** Shared pipeline. Returns a < 400 Response; throws a typed error otherwise. */ private execute; private resolveAuth; /** Map a >= 400 Response to the right typed error, attaching a body snippet. */ private toHttpError; /** Map a thrown network/timeout error. Caller-cancellation is re-raised as-is. */ private toNetworkError; private buildUrl; private hostOf; } /** * Telemetry hook contract. * * A single `TelemetryHook` interface that every middleware in this * package speaks. Plug in an OpenTelemetry adapter, a Datadog * shipper, a console logger, or your own — the middleware doesn't * care. * * # Why we don't depend on `@opentelemetry/api` directly * * @opentelemetry/api is heavy (≈30KB), version-volatile, and not * everyone uses OTel. By staying behind a tiny interface we let the * consumer choose their observability stack without pulling code we * don't need. * * # Convention * * Each tool invocation produces one ToolEvent. Fields: * - name tool name (e.g. "uala_create_payment_link") * - durationMs latency from `execute` start to settle * - ok whether `execute` resolved (true) or threw (false) * - errorCode iff ok=false and the error is an ArAgentsError * - attrs free-form structured attributes (avoid PII) */ interface ToolEvent { name: string; durationMs: number; ok: boolean; errorCode?: string; errorRetryable?: boolean; attrs?: Record; } interface TelemetryHook { onToolEvent(event: ToolEvent): void; } /** * A no-op hook. Use as a default so middleware never crashes when no * hook was wired. */ declare const noopTelemetryHook: TelemetryHook; /** * Combine multiple hooks into one. Each event is delivered to all * hooks in order; a throwing hook does NOT block the others — its * exception is swallowed (observability must never crash the request). */ declare function combineHooks(...hooks: TelemetryHook[]): TelemetryHook; /** * A console-backed hook. Useful for local dev + CI. Emits JSON lines * to stdout so log shippers can pick them up. */ declare function consoleTelemetryHook(opts?: { prefix?: string; }): TelemetryHook; /** * Tool middleware — composable wrappers around Vercel AI SDK 6 tools. * * Every middleware is a `Tool → Tool` function. They wrap the * `execute` callback (the network/IO/state-mutating part) with a * cross-cutting concern (metrics, retry, timeout, HITL gate) WITHOUT * modifying the tool's input schema, description, or output type. * * # Composition order * * Middleware applies innermost-first when called via `compose()`: * * compose(A, B, C)(tool) ≡ A(B(C(tool))) * * Execution order at runtime is THE OPPOSITE (outermost first): * request → A → B → C → tool.execute → C → B → A → response * * Recommended ordering (outermost first): * withApproval — gate the call BEFORE we burn time on it * withRetry — surround the real work * withTimeout — cap the real work * withMetrics — closest to execute, sees the real timing */ type AnyTool = Tool; type ToolMiddleware = (tool: T) => T; /** * Combine multiple middleware into one. Innermost-first composition: * * compose(A, B, C)(tool) ≡ A(B(C(tool))) * * At call time the runtime order is reversed: A wraps B wraps C wraps tool. */ declare function compose(...middlewares: ToolMiddleware[]): ToolMiddleware; /** * Apply one middleware (or composition) to every tool in a record * (the shape Vercel AI SDK 6 expects for the `tools` option). Each * tool gets the same middleware stack; tool name is passed to the * underlying middleware via the closure so middleware can label its * telemetry by the tool name. * * const wrapped = applyToAllTools(tools, (name) => * compose(withMetrics(name, { telemetry }), withTimeout(name, 10_000)), * ); */ declare function applyToAllTools>(tools: T, middlewareForName: (name: string) => ToolMiddleware): T; interface WithMetricsOptions { telemetry?: TelemetryHook; /** Static attributes attached to every event. */ attrs?: Record; } /** * Emit one ToolEvent per invocation to the configured telemetry hook. * Captures latency + success/error + ArAgentsError code & retryable * fields when available. */ declare function withMetrics(toolName: string, opts?: WithMetricsOptions): ToolMiddleware; /** * Cap execute() at `timeoutMs`. On timeout, throws a NON-retryable * ArAgentsError(code="timeout"). The middleware does NOT cancel the underlying * call (no AbortController is plumbed through here — that's tool-internal); it * merely returns control promptly so the caller's response budget is honored. * * SECURITY: the timeout error is `retryable: false` ON PURPOSE. Because the * original execute() keeps running after a timeout, marking it retryable let * withRetry re-invoke a still-running side-effectful tool — turning one approved * money/fiscal/irreversible action into several (double-spend). A timeout is only * safe to retry once execution is genuinely cancelled (AbortSignal) or the tool * is protected by a deterministic idempotency key; until then, do not retry it. */ declare function withTimeout(toolName: string, timeoutMs: number): ToolMiddleware; interface WithRetryOptions { /** Max attempts INCLUDING the first. Default 3. */ maxAttempts?: number; /** Base backoff in ms (exponential). Default 250. */ baseMs?: number; /** Max backoff in ms. Default 5_000. */ maxMs?: number; /** Predicate that decides whether THIS error is retryable. Default: * `ArAgentsError.retryable === true`. */ shouldRetry?: (err: unknown, attempt: number) => boolean; /** Jitter ratio (0..1). Default 0.2. */ jitter?: number; } /** * Retry transient failures (network blips, rate-limits, 5xx) with * exponential backoff + jitter. Bails immediately on non-retryable * errors (e.g. validation, auth). * * For ArAgentsRateLimitError, honors the error's `retryAfterMs` over * the computed backoff so the caller respects server signals. */ declare function withRetry(opts?: WithRetryOptions): ToolMiddleware; interface WithApprovalOptions { /** * Called BEFORE execute. Return true to proceed, false (or throw) * to refuse. This is the real runtime enforcement of the * `requiresConfirmation` flag in tools.manifest.json (which is * merely a hint to clients). */ approve: (toolName: string, args: unknown) => Promise | boolean; /** Optional reason emitted in the error when refused. */ refusedMessage?: string; } /** * Human-in-the-loop gate. Use on side-effectful tools (money moves, * tax returns, irreversible writes). The `approve` callback is the * host's hook to ask the user / call a policy engine / consult an * allowlist. */ declare function withApproval(toolName: string, opts: WithApprovalOptions): ToolMiddleware; /** Risk tiers, lowest to highest stakes. */ type RiskLevel = "read" | "create" | "money" | "fiscal" | "legal" | "irreversible" | "unknown"; /** Whether a given risk level demands human approval before the tool runs. */ declare function levelRequiresApproval(level: RiskLevel): boolean; interface ToolRiskInput { name: string; description?: string | undefined; /** The `sideEffects` value from a package's tools.manifest.json, if present. */ sideEffects?: string | undefined; } /** Classify a tool into a {@link RiskLevel}. Positive signals win; unknown fails closed. */ declare function classifyTool(input: ToolRiskInput): RiskLevel; /** Whether a tool needs a human approval before it may run. */ declare function requiresApproval(input: ToolRiskInput): boolean; interface EnforceRiskPolicyOptions { /** * The HITL hook, called BEFORE an approval-level tool runs. Return true to * proceed; false (or throw) refuses. This is where the host asks the human * administrator, consults a policy engine, or checks an approval token. */ approve: (toolName: string, args: unknown) => Promise | boolean; /** Supply a tool's manifest `sideEffects` by name to sharpen classification. */ sideEffectsFor?: (toolName: string) => string | undefined; refusedMessage?: string; /** * Kill-switch. When provided and it returns true, EVERY tool refuses (the * society is suspended), regardless of risk level — checked before the risk * gate. The art. 102 supervision duty made operational: a human can halt the * whole society, enforced centrally here rather than trusted to each agent. * Fails closed (see {@link withHalt}). */ isHalted?: (toolName: string, args: unknown) => Promise | boolean; } /** * Gate every approval-level tool in a ToolSet behind the `approve` callback; * read/create tools pass through untouched. This is the central art. 102 * enforcement: a caller cannot invoke a money/fiscal/legal/irreversible tool * (or an unclassified one) without a human approval, no matter which agent or * transport made the call. */ declare function enforceRiskPolicy>(tools: T, opts: EnforceRiskPolicyOptions): T; /** * The subset of the AI SDK 7 `toolApproval` generic-function argument this * helper reads. Declared structurally so `@ar-agents/core` does not depend on * `ai` at the type level; the returned function is assignable to the SDK's * `ToolApprovalConfiguration` generic-function form. */ interface ToolApprovalCallInfo { toolCall: { toolName: string; input?: unknown; }; } /** * The AI SDK 7 approval statuses this helper returns. `'user-approval'` defers * to a human; `'not-applicable'` lets the tool run without approval. (The SDK * also accepts `'approved'` / `'denied'`; we never auto-approve or auto-deny a * classified-risky tool here — that decision belongs to the human gate.) */ type RiskToolApprovalStatus = "user-approval" | "not-applicable"; interface ToolApprovalFromRiskOptions { /** Supply a tool's manifest `sideEffects` by name to sharpen classification. */ sideEffectsFor?: (toolName: string) => string | undefined; /** * Supply a tool's description by name so the `**IRREVERSIBLE**` flag is seen. * Optional: when the tools are passed to the SDK they carry their own * descriptions, but the approval callback only receives the tool NAME, so the * host can thread descriptions through here for parity with enforceRiskPolicy. */ descriptionFor?: (toolName: string) => string | undefined; } /** * Build an AI SDK 7 `toolApproval` generic function from the risk manifest. * * @example * ```ts * import { toolApprovalFromRisk } from "@ar-agents/core"; * const result = await agent.generate({ * prompt, * toolApproval: toolApprovalFromRisk({ sideEffectsFor }), * experimental_toolApprovalSecret: process.env.TOOL_APPROVAL_SECRET, // HMAC-signs requests * }); * ``` */ declare function toolApprovalFromRisk(opts?: ToolApprovalFromRiskOptions): (info: ToolApprovalCallInfo) => RiskToolApprovalStatus; /** ISO 3166-1 alpha-2 country code, optionally with a subdivision (ISO 3166-2). AR is jurisdiction #1, not the only one. */ type CountryCode = string; /** ISO 3166-2 subdivision code — an optional refinement of a country. */ type SubdivisionCode = string; /** ISO 4217 currency code the jurisdiction settles fiat in. */ type CurrencyCode = string; /** A legal jurisdiction in which an autonomous company can be in good standing. The composition root that ties a Registry, its FiatRail(s) and TaxRule(s) together. */ interface Jurisdiction { /** ISO 3166-1 alpha-2. */ readonly country: CountryCode; /** Optional subdivision (e.g. "US-WY" Wyoming, "AR-C" CABA). */ readonly subdivision?: SubdivisionCode | undefined; /** Human label, e.g. "Argentina", "Wyoming DAO LLC". */ readonly name: string; /** Default settlement currency. Rails (FiatRail.currency) and tax (TaxOwed.currency) carry their own; this is only the jurisdiction's primary. */ readonly defaultCurrency: CurrencyCode; /** The registry-of-record for good-standing in this jurisdiction. */ readonly registry: Registry; /** Fiat off/on-ramps available here (first = preferred). May be empty pre-integration. */ readonly fiatRails: ReadonlyArray; /** Tax rules that apply to an entity's acts here. */ readonly taxRules: ReadonlyArray; /** Whether this jurisdiction's autonomous-company regime is enacted law or proposed. Drives the LAW_STATUS pre/live switch on the site. */ readonly status: "operational" | "proposal"; } /** A fiat settlement rail (off-ramp / on-ramp), jurisdiction-agnostic generalization of treasury's OffRampAdapter. Crypto<->fiat. Async, idempotent, gateable. */ interface FiatRail { /** Stable id, e.g. "manteca", "bitso", "bridge-us". */ readonly id: string; /** Country this rail settles into. */ readonly country: CountryCode; /** Fiat currency this rail pays out. */ readonly currency: CurrencyCode; /** Direction(s) supported. */ readonly direction: "off-ramp" | "on-ramp" | "both"; /** Quote a crypto->fiat (or fiat->crypto) conversion. No side effects. amount in the SOURCE asset's minor-agnostic units. */ quote(input: { amount: number; fromAsset: string; toAsset: string; }): Promise; /** * Execute the conversion + payout. IRREVERSIBLE: callers MUST gate behind the art.102 approval (enforceRiskPolicy / toolApprovalFromRisk). * externalId is a REQUIRED idempotency key (same key on retry => same receipt, never double-spend). */ settle(input: { amount: number; fromAsset: string; toAsset: string; externalId: string; }): Promise; /** Poll async settlement. Optional (in-memory rails settle instantly). */ getStatus?(txId: string): Promise; } interface FiatRailQuote { amount: number; out: number; rate: number; spread: number; } interface FiatRailReceipt { amount: number; received: number; rate: number; txId: string; depositAddress?: string | undefined; } type FiatRailStatus = "PENDING" | "PROCESSING" | "COMPLETED" | "FAILED" | "UNKNOWN"; interface FiatRailStatusReport { txId: string; status: FiatRailStatus; settled?: number | undefined; raw?: string | undefined; } /** The registry-of-record / good-standing ORACLE for a jurisdiction. The moat surface: trust-minimized, publicly verifiable (no ar-agents key required to verify). Sprint 2 makes the AR impl writable+queryable; this interface is the contract counterparties consult. */ interface Registry { /** Stable id, e.g. "ar-igj", "us-wy-sos". */ readonly id: string; readonly country: CountryCode; /** Human label, e.g. "IGJ (Argentina)". */ readonly name: string; /** Look up a company's good-standing by its registry id. Read-only; what a bank/marketplace/agent-framework calls before transacting (the demand side, CAPTURE-TRANSFORMATION.md:66-73). Returns null if unknown. */ lookup(entityId: string): Promise; /** Verify a signed attestation WITHOUT trusting any ar-agents private key, by checking the public anchor (transparency log / L2 / OpenTimestamps). A conformant impl MUST set trustMinimized:true ONLY when the verdict was reached solely via the PublicAnchor, never via an operator-held key (thesis #2). */ verifyAttestation(attestation: GoodStandingAttestation): Promise; } interface GoodStandingRecord { /** Registry-native entity id. */ readonly entityId: string; readonly jurisdiction: CountryCode; /** Legal name on record. */ readonly name: string; /** Current standing. "suspended" = good-standing administratively paused by the registry (in AR, the art.102 kill-switch state). */ readonly status: "good-standing" | "suspended" | "revoked" | "unknown"; /** ISO-8601 of last status change. */ readonly asOf: string; } interface GoodStandingAttestation { readonly record: GoodStandingRecord; /** Signature of convenience (NOT the root of trust per thesis #2). */ readonly signature?: string | undefined; /** Public anchor proving the record was committed at a point in time without trusting our key (e.g. OpenTimestamps proof, L2 tx hash, CT entry). */ readonly anchor?: PublicAnchor | undefined; } interface PublicAnchor { readonly type: "opentimestamps" | "l2-tx" | "ct-log" | string; readonly proof: string; readonly anchoredAt?: string | undefined; } interface AttestationVerification { readonly valid: boolean; /** True ONLY if `valid` was established without any operator-held key, i.e. solely from the PublicAnchor. A black-box (key-only) verdict MUST set this false. */ readonly trustMinimized: boolean; readonly reason?: string | undefined; } /** A tax/fiscal rule for a jurisdiction: a PURE calculator of what is owed. Jurisdiction-neutral by design — it carries NO risk taxonomy, so a non-AR jurisdiction is never forced into Argentina's art.102 vocabulary. Each jurisdiction maps its own filings onto its own approval regime; AR refines this as `ArTaxRule` (with a RiskLevel) in ./jurisdictions/ar. Generalizes AR's cedular/monotributo/IIBB so non-AR jurisdictions slot in. */ interface TaxRule { /** Stable id, e.g. "ar-cedular", "ar-monotributo", "us-wy-annual". */ readonly id: string; readonly country: CountryCode; /** Human label. */ readonly label: string; /** Pure calculator: tax owed for a taxable event. No side effects. */ computeOwed(event: TaxableEvent): TaxOwed; } interface TaxableEvent { readonly kind: string; readonly amount: number; readonly currency: CurrencyCode; readonly meta?: Record | undefined; } interface TaxOwed { readonly amount: number; readonly currency: CurrencyCode; readonly ruleId: string; } /** Registry of installed jurisdictions, keyed by CountryCode (+optional subdivision). Pure, no I/O. Lets a host resolve "AR" -> the AR Jurisdiction, and later "US-WY" etc. */ interface JurisdictionRegistry { get(country: CountryCode, subdivision?: SubdivisionCode): Jurisdiction | undefined; list(): ReadonlyArray; } /** Build a pure {@link JurisdictionRegistry}. No I/O. Each jurisdiction is keyed by `${country}` and, when it has a subdivision, ALSO by `${country}/${subdivision}` so callers can resolve either granularity. */ declare function createJurisdictionRegistry(jurisdictions: ReadonlyArray): JurisdictionRegistry; /** * An AR tax rule: a neutral {@link TaxRule} plus the art.102 risk tier the AR * regime assigns to acting on it (a pure calculator is "read"; a filing/payment * is "fiscal"). This refinement is what keeps RiskLevel OUT of the * jurisdiction-neutral core contract — a non-AR jurisdiction is never forced * into Argentina's risk vocabulary. */ interface ArTaxRule extends TaxRule { readonly riskLevel: RiskLevel; } /** * AR cedular tax on a crypto disposal, as a pure {@link TaxRule}. * * The {@link TaxableEvent}: * - `kind`: "crypto-disposal" * - `amount`: units of crypto disposed (the USD/USDC amount, like treasury's `amountUsd`) * - `currency`: "ARS" (the tax is denominated/paid in pesos) * - `meta.fxRate`: ARS per USD (required) * - `meta.costBasisPerUsd`: average USD cost basis per unit (default 1, like USDC) * - `meta.denomination`: "ARS" (5%) | "FOREIGN" (15%) — default "ARS" * * riskLevel "read": this is a pure calculator with NO side effect (the actual * filing is a separate fiscal act). Mirrors how risk-manifest classifies tax * CALCULATORS as read and tax ACTS as fiscal. */ declare const AR_CEDULAR: ArTaxRule; /** * AR monotributo monthly cuota, as a fiscal {@link TaxRule}. Reproduces * treasury monotributoCuota: throws on an unknown category and on a * services taxpayer requesting a bienes-only (I/J/K) category. */ declare const AR_MONOTRIBUTO: ArTaxRule; /** All AR tax rules wired into the AR Jurisdiction. */ declare const AR_TAX_RULES: ReadonlyArray; /** * Build the AR {@link Jurisdiction}. `registry` and `fiatRails` are INJECTED — * the host wires the real IGJ good-standing lookup and the treasury off-ramp * (as a FiatRail) — so core carries no AFIP/Manteca runtime dependency. */ declare function createArJurisdiction(opts: { registry: Registry; fiatRails?: ReadonlyArray; }): Jurisdiction; interface FxRate { /** Units of `to` per 1 unit of `from` (e.g. ARS per USD). */ rate: number; from: CurrencyCode; to: CurrencyCode; /** ISO-8601 of the quote. */ at: string; /** Where the rate came from, e.g. "mock", "bcra", "criptoya". */ source: string; } /** Pluggable FX oracle. The host injects a real feed; {@link mockFxOracle} is for tests. */ interface FxOracle { rate(from: CurrencyCode, to: CurrencyCode, at?: string): Promise; } /** * The secondary valuation attached to a USD-denominated movement. `local` is the * local-currency equivalent at `at` (== execution time), for invoicing, tax, and * registry scoring. */ interface AccountingPayload { /** The USD-denominated amount that moved (for OUSD/USDC, 1 unit == 1 USD). */ usd: number; /** Local-currency equivalent at execution time. */ local: number; /** Local currency code (e.g. "ARS"). */ localCurrency: CurrencyCode; /** FX rate used: local per USD. */ fxRate: number; /** Provenance of the rate (never "mock" in production valuation). */ fxSource: string; /** ISO-8601 of the valuation, equal to the execution timestamp. */ at: string; /** Asset ticker, e.g. "OUSD", "USDC". */ asset: string; } /** * Build the accounting payload for a USD-denominated movement. `at` is REQUIRED and * MUST be the execution timestamp (the valuation is point-in-time, per the rule). * Pure: the only external call is the injected FxOracle. */ declare function buildAccountingPayload(input: { usd: number; asset: string; fx: FxOracle; at: string; /** Defaults to "ARS". */ localCurrency?: CurrencyCode; }): Promise; /** * A deterministic mock FX oracle for tests + pre-launch dev. `source: "mock"` so a * downstream tax/invoicing module can REFUSE a mock-sourced valuation in production. */ declare function mockFxOracle(rate?: number): FxOracle; /** Lifecycle of the OUSD asset. Flip to "live" once OUSD is issued + a provider lists it. */ type OpenUsdStatus = "pre-launch" | "live"; /** Static facts about Open USD. `status` gates any real integration (MOCK until "live"). */ declare const OPEN_USD: { readonly asset: "OUSD"; readonly issuer: string; readonly chains: readonly string[]; readonly status: OpenUsdStatus; }; /** * The on/off-chain settlement backend for OUSD, injected by the host. The default * is a deterministic MOCK (no chain deps). A real backend (Open Standard SDK / * Fireblocks / a chain client) is wired ONLY once OUSD is live + legally cleared. */ interface OpenUsdSettlementBackend { /** Move `amount` OUSD off-ramp, idempotent by externalId (same key => same txId). */ transfer(input: { amount: number; toAsset: string; externalId: string; }): Promise<{ txId: string; depositAddress?: string; }>; getStatus?(txId: string): Promise; } /** Deterministic mock backend: txId derived from externalId (idempotent), no I/O. */ declare function mockOpenUsdBackend(): OpenUsdSettlementBackend; interface OpenUsdRailOptions { /** Local off-ramp fiat (default "ARS"). */ currency?: CurrencyCode; /** Settlement country (default "AR"). */ country?: CountryCode; /** FX feed for accounting + off-ramp valuation (injected). */ fx: FxOracle; /** On/off-chain backend (default: deterministic mock). */ backend?: OpenUsdSettlementBackend; /** Fractional spread charged on the off-ramp quote (0..1, default 0). */ spread?: number; } /** OpenUsdRail also exposes {@link accountingFor} to value a raw OUSD movement (no off-ramp). */ interface OpenUsdRail extends FiatRail { readonly asset: "OUSD"; /** The accounting_payload for a bare OUSD movement of `amount` at `at` (execution time). */ accountingFor(input: { amount: number; at: string; }): Promise; } /** * Build the OUSD FiatRail. MOCK by default (pass a real `backend` + `fx` when OUSD * is live). `settle` is IRREVERSIBLE — callers MUST gate it behind the art.102 * approval + spending guardrails, exactly like any other FiatRail. */ declare function createOpenUsdRail(opts: OpenUsdRailOptions): OpenUsdRail; export { AR_CEDULAR, AR_MONOTRIBUTO, AR_TAX_RULES, type AccountingPayload, type AnyTool, ArAgentsAuthError, ArAgentsError, type ArAgentsErrorInit, ArAgentsProtocolError, ArAgentsRateLimitError, ArAgentsResponseValidationError, ArAgentsUnconfiguredError, ArAgentsValidationError, type ArTaxRule, type AttestationVerification, type AuthProvider, type CountryCode, type CurrencyCode, type EnforceRiskPolicyOptions, type FiatRail, type FiatRailQuote, type FiatRailReceipt, type FiatRailStatus, type FiatRailStatusReport, type FxOracle, type FxRate, type GoodStandingAttestation, type GoodStandingRecord, HttpClient, type HttpClientOptions, type HttpMethod, type HttpRequest, type HttpRetryOptions, IDEMPOTENT_METHODS, type Jurisdiction, type JurisdictionRegistry, OPEN_USD, type OpenUsdRail, type OpenUsdRailOptions, type OpenUsdSettlementBackend, type OpenUsdStatus, type PublicAnchor, type QueryParams, type Registry, type ResponseSchema, type RetryClassifier, type RetryContext, type RetryDecision, type RiskLevel, type RiskToolApprovalStatus, type SafeParseResult, type SchemaIssue, type SubdivisionCode, type TaxOwed, type TaxRule, type TaxableEvent, type TelemetryHook, type ToolApprovalCallInfo, type ToolApprovalFromRiskOptions, type ToolEvent, type ToolMiddleware, type ToolRiskInput, type WithApprovalOptions, type WithMetricsOptions, type WithRetryOptions, applyToAllTools, buildAccountingPayload, classifyTool, combineHooks, compose, consoleTelemetryHook, createArJurisdiction, createJurisdictionRegistry, createOpenUsdRail, defaultRetryClassifier, enforceRiskPolicy, fetchWithRetry, isArAgentsError, levelRequiresApproval, mockFxOracle, mockOpenUsdBackend, noopTelemetryHook, parseOrThrow, parseRetryAfter, requiresApproval, runWithRetry, sleep, toolApprovalFromRisk, withApproval, withMetrics, withRetry, withTimeout };