import { b0 as WSClientOptions, L as GranularQuotaProgress, T as ToolWithHandler, f as PublishToolsResult, aE as Job, g as ToolHandler, I as InstanceToolHandler, aG as ConversationMessageInput, aH as ConversationAppendResult, ar as EffectInfo, P as Prompt, aq as ToolInfo, at as EffectsChangedEvent, as as ToolsChangedEvent, D as DomainState, q as GranularOptions, br as EnvironmentImporter, u as RecordUserOptions, U as User, w as OpenEnvironmentOptions, a5 as EnvironmentData, a2 as BuildPolicy, bp as EnvironmentSetupSummary, y as ConversationSessionInfo, x as CreateSessionOptions, ba as RecordObjectOptions, bb as RecordObjectResult, bd as RecordObjectsOptions, bk as RecordImport, bg as RecordImportStatus, bl as EnvironmentRecordImportSummary, aC as EnvironmentFeedbackRecord, c as SessionHeapSnapshot, aW as SessionDocumentResult, aX as SessionCollectionListOptions, aZ as SessionCollectionListResult, aI as SessionConversationMessage, aJ as SessionTimelineEvent, aY as SessionJobListOptions, aP as SessionJobRecord, aN as SessionFileRecord, aO as SessionFileUploadOptions, S as SessionHeapEntry, b as SessionHeapList, aS as SessionHeapVariable, d as SessionTranscriptEntry, bN as GraphQLResult, aU as RecordSearchOptions, aT as RecordSearchResult, aV as RecordMentionInput, b9 as DefineRelationshipOptions, b8 as RelationshipInfo, b7 as ModelRef, bM as ManifestContent, bf as RecordImportOptions, C as ConnectOptions, bn as RunEnvironmentImporterOptions, l as OpenAIUsageSpendEvent, G as GranularSpendContext, o as RecordOpenAIUsageSpendResult, X as SandboxListResponse, V as Sandbox, W as CreateSandboxData, bP as DeleteResponse, Z as PermissionProfile, _ as CreatePermissionProfileData, a6 as CreateEnvironmentData, bQ as StreamEvent, bR as StreamSubscription, bS as StreamStats, v as Subject, a1 as AssignmentListResponse } from './spend-tAz2a16I.js';
import * as Automerge from '@automerge/automerge';
import { Doc } from '@automerge/automerge/slim';

declare class WSClient {
    private ws;
    private url;
    private sessionId;
    private token;
    private messageQueue;
    private syncHandlers;
    private rpcHandlers;
    private eventHandlers;
    private nextRpcId;
    doc: Automerge.Doc<Record<string, unknown>>;
    private syncState;
    private reconnectTimer;
    private tokenRefreshTimer;
    private isExplicitlyDisconnected;
    private options;
    constructor(options: WSClientOptions);
    get currentSessionId(): string;
    private clearTokenRefreshTimer;
    private decodeBase64Url;
    private getTokenExpiryMs;
    private scheduleTokenRefresh;
    private refreshTokenInBackground;
    private resolveTokenForConnect;
    /**
     * Connect to the WebSocket server
     * @returns {Promise<void>} Resolves when connection is open
     */
    connect(): Promise<void>;
    private normalizeReason;
    private rejectPending;
    private buildDisconnectError;
    private handleDisconnect;
    private handleMessage;
    /**
     * Make an RPC call to the server
     * @param {string} method - RPC method name
     * @param {unknown} params - Request parameters
     * @returns {Promise<unknown>} Response result
     * @throws {Error} If connection is closed or timeout occurs
     */
    call(method: string, params: unknown): Promise<unknown>;
    private handleIncomingRpc;
    /**
     * Subscribe to client events
     * @param {string} event - Event name
     * @param {Function} handler - Event handler
     */
    on(event: string, handler: (params: unknown) => void): void;
    /**
     * Register an RPC handler for incoming server requests
     * @param {string} method - RPC method name
     * @param {Function} handler - Handler function
     */
    registerRpcHandler(method: string, handler: (params: unknown) => Promise<unknown>): void;
    /**
     * Unsubscribe from client events
     * @param {string} event - Event name
     * @param {Function} handler - Handler to remove
     */
    off(event: string, handler: (params: unknown) => void): void;
    /**
     * Emit an event locally
     * @param {string} event - Event name
     * @param params - Event data
     */
    emit(event: string, params: unknown): void;
    /**
     * Disconnect the WebSocket and clear state
     */
    disconnect(): void;
}

declare class Session {
    protected client: WSClient;
    private clientId;
    private initialQuota;
    private jobsMap;
    private pendingAgentMessagesByJobId;
    private eventListeners;
    private toolHandlers;
    /** Tracks which tools are instance methods (className set, not static) */
    private instanceTools;
    private currentDomainRevision;
    /** Local effect registry: name → full ToolWithHandler */
    private effects;
    /** Last known tools for diffing */
    private lastKnownTools;
    /** Last seen live prompts, keyed by prompt id, for answer normalization */
    private promptCache;
    /** Prompt ids locally answered before the document sync catches up. */
    private hiddenPromptIds;
    constructor(client: WSClient, clientId?: string, options?: {
        initialQuota?: GranularQuotaProgress | null;
    });
    private extractDomainRevisionFromDoc;
    private buildLegacyEffectContext;
    private stringifyConversationValue;
    get document(): Doc<Record<string, unknown>>;
    get quota(): GranularQuotaProgress | null;
    getQuota(): GranularQuotaProgress | null;
    get sessionId(): string;
    get domainRevision(): string | null;
    /**
     * Make a raw RPC call to the session's Durable Object.
     *
     * Use this when you need to call an RPC method that doesn't have a
     * dedicated wrapper method on the Session/Environment class.
     *
     * @param method - RPC method name (e.g. 'domain.fetchPackagePart')
     * @param params - Request parameters
     * @returns The raw RPC response
     *
     * @example
     * ```typescript
     * const result = await env.rpc('domain.fetchPackagePart', {
     *   moduleSpecifier: '@sandbox/domain',
     *   part: 'types',
     * });
     * ```
     */
    rpc<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T>;
    /**
     * Send client hello to establish the session
     */
    hello(): Promise<{
        ok: boolean;
        environmentId?: string;
        docId?: string;
        graphContainerStatus?: {
            lastKeepAliveAt: number;
            status: "warming" | "hot" | "unknown";
        };
    }>;
    publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
    publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
    publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
    unpublishEffect(name: string): Promise<PublishToolsResult>;
    unpublishAllEffects(): Promise<PublishToolsResult>;
    /**
     * Submit a job to execute code in the sandbox.
     *
     * The code can import typed classes from `./sandbox-tools`:
     * ```typescript
     * import { Author, Book, global_search } from './sandbox-tools';
     *
     * const totalAuthors = await Author.count();
     * const firstAuthorsPage = await Author.page({ page: 1, perPage: 10, saveAs: 'recent_authors' });
     * const authors = firstAuthorsPage.items;
     * const tolkien = await Author.get({ path: 'author_tolkien' });
     * const bio = await tolkien.get_bio({ detailed: true });
     * const books = await tolkien.get_books();
     * for await (const author of Author.iterate({ perPage: 100, maxItems: 500 })) {
     *   console.log(author.id);
     * }
     * ```
     *
     * Effect calls (instance methods, static methods, global functions) trigger
     * `effect.invoke` RPC back to the sandbox effect host, where the registered handlers
     * execute locally and return the result to the sandbox.
     */
    submitJob(code: string, domainRevisionOrOptions?: string | {
        domainRevision?: string;
        metadata?: Record<string, unknown>;
        agent?: Record<string, unknown>;
    }): Promise<Job>;
    /**
     * Register a handler for a specific tool.
     * @param isInstance - If true, handler will receive (id, params) for instance method dispatch.
     */
    registerToolHandler(name: string, handler: ToolHandler | InstanceToolHandler, isInstance?: boolean): void;
    /**
     * Respond to a prompt request from the sandbox
     */
    answerPrompt(promptId: string, answer: unknown): Promise<void>;
    appendConversationMessage(input: ConversationMessageInput): Promise<ConversationAppendResult>;
    /**
     * Get the current list of available effects.
     * Consolidates effect declarations and live availability for the session.
     */
    getEffects(): EffectInfo[];
    /**
     * Return the currently open prompt payloads known to this session.
     *
     * These come from live `prompt` / `prompt.request` websocket events and
     * preserve the exact shape used by `answerPrompt(...)`.
     */
    getPrompts(): Prompt[];
    getHiddenPromptIds(): string[];
    /**
     * Backwards-compatible alias for `getEffects()`.
     */
    getTools(): ToolInfo[];
    /**
     * Subscribe to effect changes (added, removed, updated).
     * @param callback - Function called with change events
     * @returns Unsubscribe function
     */
    onEffectsChanged(callback: (event: EffectsChangedEvent) => void): () => void;
    /**
     * Backwards-compatible alias for `onEffectsChanged()`.
     */
    onToolsChanged(callback: (event: ToolsChangedEvent) => void): () => void;
    /**
     * Get the current domain state and available tools
     */
    getDomain(): Promise<DomainState>;
    /**
     * Fetch a domain package part from the backend (no fallback).
     */
    private fetchDomainPart;
    /**
     * Get TypeScript class declarations for the current domain (for LLM/code gen).
     */
    getDomainTypes(): Promise<string>;
    /**
     * Get Markdown documentation for the current domain (human-readable).
     */
    getDomainDocs(): Promise<string>;
    /**
     * Get domain documentation for LLMs. Returns types (preferred) or fallback.
     */
    getDomainDocumentation(): Promise<string>;
    /**
     * Generate markdown documentation from the domain summary.
     * Class-aware: groups tools by class with property/relationship info.
     */
    private generateFallbackDocs;
    /**
     * Close the session and disconnect from the sandbox
     */
    disconnect(): Promise<void>;
    /**
     * Subscribe to session events
     */
    on(event: string, handler: (data: unknown) => void): () => void;
    /**
     * Unsubscribe from session events
     */
    off(event: string, handler: (data: unknown) => void): void;
    private setupToolInvokeHandler;
    private setupEventHandlers;
    protected emit(event: string, data: unknown): void;
    /**
     * Check for changes in the effect catalog and emit change events if needed.
     */
    private checkForToolChanges;
}

type SessionFileUploadBody = Blob | ArrayBuffer | Uint8Array | string;
type EnvironmentImporterHandler = (importer: EnvironmentImporter) => Promise<void> | void;
/**
 * Environment is the sessionless handle for one resolved ontology environment.
 *
 * Use it to query or mutate environment data directly, or to open live runtime
 * sessions through `environment.sessions.*` when you need jobs, prompts, or a
 * synced Automerge document.
 */
declare class Environment {
    private granular;
    private envData;
    private _apiKey;
    private _apiEndpoint;
    constructor(granular: Granular, envData: EnvironmentData, apiKey: string, apiEndpoint: string);
    /** The environment ID */
    get environmentId(): string;
    /** The sandbox ID */
    get sandboxId(): string;
    /** The ontology ID */
    get ontologyId(): string;
    /** The subject ID */
    get subjectId(): string;
    /** The named environment slot, such as dev or prod */
    get envName(): string;
    /** The named environment slot, such as dev or prod */
    get environment(): string;
    /** The resolved ontology version backing this environment */
    get versionId(): string;
    /** Internal Granular user identifier for this environment */
    get granularId(): string;
    /** The permission profile ID */
    get permissionProfileId(): string;
    /** The current build policy backing this environment */
    get buildPolicy(): BuildPolicy;
    /** The current update state relative to the followed tag */
    get updateState(): EnvironmentData["updateState"];
    /** The latest setup/import run summary for this environment, when available. */
    get setup(): EnvironmentSetupSummary | null;
    /** Convenience flag for whether this environment trails the current tag target */
    get isOutdated(): boolean;
    /** The followed tag name when this environment is tag-tracked */
    get tag(): string | null;
    /** The GraphQL API endpoint URL */
    get apiEndpoint(): string;
    /** Internal auth token used for control-plane and runtime fallback requests */
    get authToken(): string;
    /** Base runtime URL derived from the GraphQL endpoint */
    get runtimeBaseUrl(): string;
    syncEnvironmentData(envData: EnvironmentData): void;
    get sessions(): {
        list: (options?: {
            status?: "active" | "closed" | "all";
        }) => Promise<ConversationSessionInfo[]>;
        create: (options?: CreateSessionOptions) => Promise<EnvironmentSession>;
        connect: (sessionId: string, options?: {
            clientId?: string;
        }) => Promise<EnvironmentSession>;
        reopen: (sessionId: string, options?: {
            clientId?: string;
        }) => Promise<EnvironmentSession>;
        close: (sessionId: string, session?: EnvironmentSession | null) => Promise<void>;
    };
    get data(): {
        record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
        recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
        import: (records: RecordObjectOptions[], options?: {
            batchSize?: number;
        }) => Promise<RecordImport>;
        listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
        getImport: (importId: string) => Promise<RecordImport>;
        getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
        cancelImport: (importId: string) => Promise<RecordImport>;
        getAwaitingCount: () => Promise<number>;
    };
    get feedback(): {
        list: () => Promise<EnvironmentFeedbackRecord[]>;
    };
    /**
     * Sessionless environments do not own a live transport, so disconnecting the
     * environment handle itself is a no-op. This keeps the public surface
     * symmetric with `EnvironmentSession.disconnect()` and lets callers always
     * clean up safely without tracking whether they currently hold an environment
     * or a session.
     */
    disconnect(): Promise<void>;
    listSessions(status?: "active" | "closed" | "all"): Promise<ConversationSessionInfo[]>;
    createSession(options?: CreateSessionOptions): Promise<EnvironmentSession>;
    connectSession(sessionId: string, options?: {
        clientId?: string;
    }): Promise<EnvironmentSession>;
    reopenSession(sessionId: string, options?: {
        clientId?: string;
    }): Promise<EnvironmentSession>;
    closeSession(sessionId: string, session?: EnvironmentSession | null): Promise<void>;
    listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
    private getRuntimeBaseUrl;
    private controlPlaneRequest;
    private static normalizeGraphPathSegment;
    /**
     * Convert a class name + application record ID into Granular's graph path.
     *
     * This mirrors the record-write path normalization used by the control plane.
     * Keep the original customer/system ID in `real_id`; graph paths are stable
     * internal addresses, not the source of truth for business identity.
     */
    static toGraphPath(className: string, id: string): string;
    /**
     * Best-effort extraction of an ID-like suffix from a graph path.
     *
     * Prefer the record's `real_id` field whenever exact customer/system IDs
     * matter, because graph path normalization is intentionally lossy.
     */
    static extractIdFromGraphPath(graphPath: string, className: string): string;
    /**
     * Execute a GraphQL query against the environment's graph.
     *
     * The query uses the Granular graph query language (based on Cypher/GraphQL).
     * Authentication is handled automatically using the SDK's API key.
     *
     * @param query - The GraphQL query string
     * @param variables - Optional variables for the query
     * @returns The query result data
     *
     * @example
     * ```typescript
     * // Read the workspace
     * const result = await env.graphql(
     *   `query { model(path: "workspace") { path label submodels { path label } } }`
     * );
     * console.log(result.data);
     *
     * // Create a model
     * const created = await env.graphql(
     *   `mutation { at(path: "workspace") { create_submodel(subpath: "my_node", label: "My Node", prototype: "Model") { model { path label } } } }`
     * );
     * ```
     */
    graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
    searchRecords(query: string, options?: RecordSearchOptions): Promise<RecordSearchResult[]>;
    /**
     * Define a relationship between two model types.
     *
     * Creates both submodels (if they don't exist) and links them with
     * a RelationshipDef node that encodes cardinality.
     *
     * @example
     * ```typescript
     * // Author has many Books, Book has one Author
     * const rel = await env.defineRelationship({
     *   model: 'author',
     *   localSubmodel: 'books',
     *   localIsMany: true,
     *   foreignModel: 'book',
     *   foreignSubmodel: 'author',
     *   foreignIsMany: false,
     * });
     * console.log(rel.relationship_kind); // "one_to_many"
     * ```
     */
    defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
    /**
     * Get all relationships for a model type.
     *
     * @param modelPath - The model type path (e.g., "author")
     * @returns Array of relationships from this model's perspective
     *
     * @example
     * ```typescript
     * const rels = await env.getRelationships('author');
     * for (const rel of rels) {
     *   console.log(`${rel.local_submodel.path} -> ${rel.foreign_model.path} (${rel.relationship_kind})`);
     * }
     * ```
     */
    getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
    /**
     * Attach a target model to a relationship submodel.
     *
     * Handles cardinality automatically:
     * - "One" side: sets/replaces the reference
     * - "Many" side: adds the target to the collection
     *
     * If the target model doesn't exist, it's created as an instance of the foreign type.
     * Bidirectional sync is automatic.
     *
     * @param modelPath - The model instance path (e.g., "tolkien")
     * @param submodelPath - The relationship submodel (e.g., "books")
     * @param targetPath - The target model to attach (e.g., "lord_of_the_rings")
     *
     * @example
     * ```typescript
     * // Attach a book to an author (many side)
     * await env.attach('tolkien', 'books', 'lord_of_the_rings');
     * // This also automatically sets lord_of_the_rings:author -> tolkien
     * ```
     */
    attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
    /**
     * Detach a target model from a relationship submodel.
     *
     * Handles bidirectional cleanup automatically.
     *
     * @param modelPath - The model instance path
     * @param submodelPath - The relationship submodel
     * @param targetPath - The target to detach (optional for "one" side; omit on "many" side to detach all)
     *
     * @example
     * ```typescript
     * // Detach a specific book
     * await env.detach('tolkien', 'books', 'lord_of_the_rings');
     *
     * // Detach all books
     * await env.detach('tolkien', 'books');
     * ```
     */
    detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
    /**
     * List all related models through a relationship submodel.
     *
     * @param modelPath - The model instance path
     * @param submodelPath - The relationship submodel
     * @returns Array of related model references
     *
     * @example
     * ```typescript
     * const books = await env.listRelated('tolkien', 'books');
     * console.log(books); // [{ path: "lord_of_the_rings", label: "Lord of the Rings" }, ...]
     * ```
     */
    listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
    /**
     * Apply a manifest to the current environment's graph.
     *
     * Translates each manifest operation into GraphQL mutations and executes them
     * in order. This is the core mechanism for creating classes, fields, and
     * relationships from a declarative manifest.
     *
     * @param manifest - The manifest content to apply
     * @returns Summary of applied operations
     *
     * @example
     * ```typescript
     * await environment.applyManifest({
     *   schemaVersion: 2,
     *   name: 'my-app',
     *   volumes: [{
     *     name: 'schema',
     *     scope: 'sandbox',
     *     operations: [
     *       { create: 'author', extends: 'class', has: { name: { type: 'string' } } },
     *       { create: 'book', extends: 'class', has: { title: { type: 'string' } } },
     *       { defineRelationship: {
     *         left: 'author', right: 'book',
     *         leftSubmodel: 'books', rightSubmodel: 'author',
     *         leftIsMany: true, rightIsMany: false,
     *       }},
     *     ],
     *   }],
     * });
     * ```
     */
    applyManifest(manifest: ManifestContent): Promise<{
        applied: number;
        errors: string[];
    }>;
    /**
     * Resolve an alias reference like "@std/class" → "class"
     * Strips the alias prefix, returning the bare model path.
     */
    private _resolveAlias;
    private _runGraphql;
    private _applyFieldMetamodels;
    private _applyModelMetamodels;
    private _ensureWorkspaceToolsRoot;
    private _storeEffectSchemas;
    private _applyEffectMetamodels;
    private _ensureWorkspaceStreamsRoot;
    private _applyEventStreamDeclaration;
    private _applyEffectDeclaration;
    /**
     * Apply a single manifest operation via GraphQL
     */
    private _applyOperation;
    /**
     * Apply field definitions (has) to a model via GraphQL
     */
    private _applyFields;
    /**
     * Create or update an instance of a class in the graph.
     *
     * Uses `instantiate` under the hood, which has find-or-create semantics:
     * if an instance with the given `id` already exists for the class it is
     * returned; otherwise a new instance is created.  Fields are then set
     * (overwriting previous values) and relationships are attached.
     *
     * The graph path is derived as `{className}_{id}` to ensure uniqueness
     * across classes (two objects of different classes may share the same
     * real-world ID).  Relationship targets are also resolved automatically
     * using the foreign class from the relationship definition.
     *
     * @param options - The object specification
     * @returns The graph path, real-world ID, and creation status
     *
     * @example
     * ```typescript
     * // Create an author with fields
     * const result = await env.recordObject({
     *   className: 'author',
     *   id: 'tolkien',
     *   label: 'J.R.R. Tolkien',
     *   fields: { name: 'J.R.R. Tolkien', birth_year: 1892 },
     *   relationships: { books: ['lotr', 'silmarillion'] },
     * });
     * // result.path → 'author_tolkien'  (internal graph path)
     * // result.id   → 'tolkien'         (real-world ID)
     * // result.created → true
     * ```
     */
    recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
    /**
     * Batch version of `recordObject()`.
     *
     * Sends rows through the control-plane **`/records/batch`** endpoint in **chunks** (default
     * **100** records per HTTP request) so individual requests stay bounded and gateway timeouts are
     * unlikely. Each chunk is retried on transient network / worker errors.
     *
     * Use the optional second argument to:
     * - **`batchSize`** — rows per POST (smaller = more progress events; larger = fewer round trips).
     * - **`concurrency`** — run up to N chunk POSTs in parallel (capped at 16) when you want lower wall time.
     * - **`onChunkComplete`** — hook for UIs after each chunk succeeds (row order in the returned array
     *   always matches `records`; chunk **completion** order may differ when `concurrency > 1`).
     *
     * For **asynchronous** ingestion with worker-side batching and aggregate counters (`queued`,
     * `completed`, …), use **`enqueueRecordImport`** and poll **`getRecordImport`** /
     * **`getRecordImportSummary`** — best for very large fire-and-forget loads when immediate
     * synchronous commit of every row is not required.
     */
    recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
    private executeRecordObjectsChunk;
    /**
     * Queue a background record import for this environment (async worker pipeline).
     *
     * **vs `recordObjects`:** this path accepts the full payload in one request, returns an
     * **`importId`**, and processes rows in the background — use **`getRecordImport`** /
     * **`getRecordImportSummary`** for progress. Choose it for large bulk loads where you do not
     * need every row committed before the HTTP call returns. Use **`recordObjects`** when you need
     * synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
     */
    enqueueRecordImport(records: RecordObjectOptions[], options?: RecordImportOptions): Promise<RecordImport>;
    /**
     * List queued or completed record imports for this environment.
     */
    listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
    /**
     * Fetch the latest aggregate import counters for this environment.
     */
    getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
    /**
     * Convenience helper returning queued + processing records for this environment.
     */
    getAwaitingRecordCount(): Promise<number>;
    /**
     * Fetch a single record import by id.
     */
    getRecordImport(importId: string): Promise<RecordImport>;
    /**
     * Cancel a queued/background record import.
     */
    cancelRecordImport(importId: string): Promise<RecordImport>;
}
/**
 * Live runtime session attached to one opened environment.
 *
 * This is the object returned by `environment.sessions.create()` and friends.
 * It owns websocket state, prompts, job execution, and the synced Automerge
 * document while delegating environment-level data APIs back to
 * `session.environment`.
 */
declare class EnvironmentSession extends Session {
    readonly environment: Environment;
    private readonly sessionDataRoutePrefix;
    /** The last known graph container status, updated by checkReadiness() or on heartbeat */
    graphContainerStatus: {
        lastKeepAliveAt: number;
        status: "warming" | "hot" | "unknown";
    } | null;
    constructor(client: WSClient, environment: Environment, clientId: string, options?: {
        sessionDataRoutePrefix?: string;
        initialQuota?: GranularQuotaProgress | null;
    });
    get environmentId(): string;
    get sandboxId(): string;
    get ontologyId(): string;
    get subjectId(): string;
    get envName(): string;
    get tag(): string | null;
    get versionId(): string;
    get granularId(): string;
    get permissionProfileId(): string;
    get apiEndpoint(): string;
    get data(): {
        record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
        recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
        import: (records: RecordObjectOptions[], options?: {
            batchSize?: number;
        } | undefined) => Promise<RecordImport>;
        listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
        getImport: (importId: string) => Promise<RecordImport>;
        getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
        cancelImport: (importId: string) => Promise<RecordImport>;
        getAwaitingCount: () => Promise<number>;
    };
    get feedback(): {
        list: () => Promise<EnvironmentFeedbackRecord[]>;
    };
    /**
     * Return a plain JS copy of the synced session heap.
     */
    getHeap(): SessionHeapSnapshot;
    private buildSessionDataUrl;
    private sessionDataFetch;
    private sessionDataRequest;
    private collectAllSessionItems;
    /**
     * Fetch the live session document from the runtime DO.
     *
     * For history and saved artifacts, prefer the collection APIs on
     * `messages`, `timeline`, `jobs`, and `heap`.
     */
    getDocument(): Promise<SessionDocumentResult>;
    get messages(): {
        list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionConversationMessage>>;
    };
    get timeline(): {
        list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionTimelineEvent>>;
    };
    get jobs(): {
        list: (options?: SessionJobListOptions) => Promise<SessionCollectionListResult<SessionJobRecord>>;
        get: (jobId: string) => Promise<SessionJobRecord>;
    };
    get files(): {
        list: (options?: SessionCollectionListOptions & {
            status?: string | null;
            source?: string | null;
        }) => Promise<SessionCollectionListResult<SessionFileRecord>>;
        get: (fileId: string) => Promise<SessionFileRecord>;
        upload: (body: SessionFileUploadBody, options?: SessionFileUploadOptions) => Promise<SessionFileRecord>;
        download: (fileId: string) => Promise<ArrayBuffer>;
        delete: (fileId: string) => Promise<{
            deleted: boolean;
            fileId: string;
        }>;
    };
    get heap(): {
        entries: {
            list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapEntry>>;
            get: (path: string) => Promise<SessionHeapEntry>;
        };
        lists: {
            list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapList>>;
            get: (name: string) => Promise<SessionHeapList>;
        };
        variables: {
            list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapVariable>>;
            get: (name: string) => Promise<SessionHeapVariable>;
            delete: (name: string) => Promise<{
                deleted: boolean;
                name: string;
            }>;
        };
    };
    get transcript(): {
        list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionTranscriptEntry>>;
    };
    graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
    searchRecords(query: string, options?: RecordSearchOptions): Promise<RecordSearchResult[]>;
    mentionRecord(input: RecordMentionInput): Promise<SessionHeapEntry>;
    defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
    getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
    attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
    detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
    listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
    applyManifest(manifest: ManifestContent): Promise<{
        applied: number;
        errors: string[];
    }>;
    recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
    recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
    enqueueRecordImport(records: RecordObjectOptions[], options?: RecordImportOptions): Promise<RecordImport>;
    listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
    getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
    getAwaitingRecordCount(): Promise<number>;
    getRecordImport(importId: string): Promise<RecordImport>;
    cancelRecordImport(importId: string): Promise<RecordImport>;
    listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
    /**
     * Close the session and disconnect from the sandbox.
     *
     * Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
     * to the runtime goodbye endpoint if no definitive WS-side runtime notify
     * acknowledgement was observed.
     */
    disconnect(): Promise<void>;
    /**
     * Close only the socket transport without sending `client.goodbye`.
     */
    disconnectTransport(): void;
    /**
     * Backwards-compatible alias for `disconnect()`.
     */
    close(): Promise<void>;
    /**
     * Check if the graph container is ready and warm.
     */
    checkReadiness(): Promise<{
        lastKeepAliveAt: number;
        status: "warming" | "hot" | "unknown";
    }>;
}
declare class OntologyHandle {
    private granular;
    private ontologyNameOrId;
    constructor(granular: Granular, ontologyNameOrId: string);
    get effects(): {
        register: (effect: ToolWithHandler) => Promise<void>;
        registerMany: (effects: ToolWithHandler[]) => Promise<void>;
        unregister: (name: string) => Promise<void>;
        clear: () => Promise<void>;
        disconnect: () => Promise<void>;
    };
    get importer(): {
        onEnvironmentCreate: (handler: EnvironmentImporterHandler) => void;
        clear: () => void;
    };
}
declare class Granular {
    private apiKey;
    private apiUrl;
    private httpUrl;
    private tokenProvider?;
    private WebSocketCtor?;
    private onUnexpectedClose?;
    private onReconnectError?;
    private effectHostUrl?;
    private debugHttp;
    /** Sandbox-level effect registry: sandboxId → (effectKey@selector → ToolWithHandler) */
    private sandboxEffects;
    /** Live sandbox-scoped effect hosts keyed by sandboxId */
    private sandboxEffectHosts;
    /** In-flight host connection promises to avoid duplicate concurrent connects */
    private sandboxEffectHostPromises;
    /** Ontology-bound environment importer hooks keyed by the caller's ontology identifier. */
    private ontologyImporters;
    /** Resolved importer hooks keyed by sandboxId for fast lookups during openEnvironment(). */
    private sandboxImporters;
    /**
     * Create a new Granular client
     * @param options - Client configuration
     */
    constructor(options: GranularOptions);
    /**
     * Return an ontology-scoped handle for effects and other ontology-level APIs.
     */
    ontology(ontologyNameOrId: string): OntologyHandle;
    registerEnvironmentImporter(ontologyNameOrId: string, handler: EnvironmentImporterHandler): void;
    clearEnvironmentImporter(ontologyNameOrId: string): void;
    /**
     * Records/upserts a user and prepares them for sandbox connections
     *
     * @param options - User options
     * @returns The recorded user with both `userId` and `granularId`
     *
     * @example
     * ```typescript
     * const user = await granular.recordUser({
     *   userId: 'user_123',
     *   name: 'John Doe',
     *   permissions: ['agent'],
     * });
     * ```
     */
    recordUser(options: RecordUserOptions): Promise<User>;
    /**
     * Alias for `recordUser()` with user-facing naming that matches upsert semantics.
     */
    upsertUser(options: RecordUserOptions): Promise<User>;
    private resolveConnectUser;
    /**
     * Open or resolve an ontology environment for one user without opening a session.
     *
     * @example
     * ```typescript
     * const environment = await granular.openEnvironment({
     *   ontology: 'my-ontology',
     *   tag: 'dev',
     *   userId: 'user_123',
     *   permissions: ['agent'],
     * });
     *
     * await environment.data.record({
     *   className: 'customer',
     *   id: 'acme',
     *   fields: { name: 'Acme' },
     * });
     *
     * const session = await environment.sessions.create();
     * const job = await session.submitJob(`return "hello";`);
     * console.log(await job.result);
     * ```
     */
    openEnvironment(options: OpenEnvironmentOptions): Promise<Environment>;
    /**
     * Deprecated compatibility alias for `openEnvironment()`.
     *
     * `connect()` no longer opens a runtime session automatically.
     */
    connect(options: ConnectOptions): Promise<Environment>;
    /**
     * Run a registered environment importer against an environment that was
     * opened outside this SDK instance, for example by a delegated browser flow.
     *
     * This uses the same setup-run and queued record-import plumbing as
     * `openEnvironment()`: importer stages, expected object counts, and queued
     * import counters remain visible through `environment.setup` and
     * `getRecordImportSummary()`.
     */
    runEnvironmentImporterForEnvironment(environmentId: string, options?: RunEnvironmentImporterOptions): Promise<EnvironmentSetupSummary | null>;
    private resolveRequestedTag;
    private buildManagedEnvironmentName;
    private matchesTagTrackedEnvironment;
    private sortEnvironmentsByRecency;
    private resolveOpenEnvironmentData;
    /**
     * List active (open) sessions for an environment — each session is one agent conversation thread.
     */
    listOpenSessions(filters: {
        environmentId: string;
    }): Promise<ConversationSessionInfo[]>;
    /**
     * List closed sessions for an environment (conversations that have disconnected).
     */
    listClosedSessions(filters: {
        environmentId: string;
    }): Promise<ConversationSessionInfo[]>;
    private listSessionsForEnvironment;
    private normalizeConversationSession;
    private static coerceIsoDate;
    /**
     * Create a new session (conversation) for an existing environment and connect to it.
     * The runtime graph is shared across all sessions for the same environment.
     */
    createSession(options: {
        environmentId: string;
        clientId?: string;
        initialHeap?: CreateSessionOptions["initialHeap"];
    }): Promise<EnvironmentSession>;
    /**
     * Connect to an existing open session (same conversation thread) using a freshly minted WebSocket token.
     */
    connectSession(options: {
        sessionId: string;
        clientId?: string;
    }): Promise<EnvironmentSession>;
    recordOpenAIUsageSpend(usage: OpenAIUsageSpendEvent, context?: GranularSpendContext | null, options?: {
        metadata?: Record<string, unknown> | null;
    }): Promise<RecordOpenAIUsageSpendResult>;
    /**
     * Mark a session closed in the control plane. If `environment` is the connected handle for that
     * `sessionId`, disconnects the WebSocket so the runtime tears down cleanly.
     */
    closeSession(sessionId: string, environment?: EnvironmentSession | null): Promise<void>;
    /**
     * Re-open a closed session in the index and connect to its existing runtime document.
     */
    reopenSession(sessionId: string, options?: {
        clientId?: string;
    }): Promise<EnvironmentSession>;
    private resolveEnvironmentImporter;
    private maybeRunEnvironmentImporter;
    private runEnvironmentImporter;
    private bindEnvironmentHandle;
    private bindWebSocketEnvironmentSession;
    private activateEnvironment;
    private getSandboxEffectMap;
    private serializeEffect;
    private publishSandboxEffectCatalog;
    private syncSandboxEffectCatalog;
    private recoverEffectHost;
    private startEffectHostHeartbeat;
    private stopEffectHostHeartbeat;
    private synchronizeEffectHost;
    private ensureSandboxEffectHost;
    private disconnectSandboxEffectHost;
    /**
     * Register an effect (tool) for a specific sandbox.
     *
     * @param sandboxNameOrId - The name or ID of the sandbox
     * @param effect - The tool definition and handler
     */
    registerEffect(sandboxNameOrId: string, effect: ToolWithHandler): Promise<void>;
    /**
     * Register multiple effects (tools) for a specific sandbox.
     *
     * batch version of `registerEffect`.
     */
    registerEffects(sandboxNameOrId: string, effects: ToolWithHandler[]): Promise<void>;
    /**
     * Unregister an effect from a sandbox.
     *
     * Removes it from the local sandbox registry and updates the
     * sandbox-scoped live catalog.
     */
    unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
    /**
     * Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
     *
     * This is primarily useful for long-lived helper processes such as generated
     * `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
     */
    disconnectEffects(sandboxNameOrId?: string): Promise<void>;
    /**
     * Unregister all effects for a sandbox.
     */
    unregisterAllEffects(sandboxNameOrId: string): Promise<void>;
    /**
     * Find a sandbox by name or create it if it doesn't exist
     */
    private findOrCreateSandbox;
    /**
     * Ensure a permission profile exists for a sandbox, creating it if needed.
     * If profileName matches an existing profile name, returns its ID.
     * Otherwise, creates a v1 source-profile file shape with an allow default.
     */
    private ensurePermissionProfile;
    /**
     * Ensure an assignment exists for a subject in a sandbox with a permission profile
     */
    private ensureAssignment;
    /**
     * Sandbox management API
     */
    get sandboxes(): {
        list: () => Promise<SandboxListResponse>;
        get: (id: string) => Promise<Sandbox>;
        create: (data: CreateSandboxData) => Promise<Sandbox>;
        update: (id: string, data: Partial<CreateSandboxData>) => Promise<Sandbox>;
        delete: (id: string) => Promise<DeleteResponse>;
    };
    /**
     * Permission Profile management for sandboxes
     */
    get permissionProfiles(): {
        list: (sandboxId: string) => Promise<PermissionProfile[]>;
        get: (sandboxId: string, profileId: string) => Promise<PermissionProfile>;
        create: (sandboxId: string, data: CreatePermissionProfileData) => Promise<PermissionProfile>;
        delete: (_sandboxId: string, _profileId: string) => Promise<DeleteResponse>;
    };
    /**
     * Environment management
     */
    get environments(): {
        list: (sandboxId: string) => Promise<EnvironmentData[]>;
        get: (environmentId: string) => Promise<EnvironmentData>;
        create: (sandboxId: string, data: CreateEnvironmentData) => Promise<EnvironmentData>;
        delete: (environmentId: string) => Promise<DeleteResponse>;
    };
    /**
     * Event stream operations: query, subscribe, and acknowledge stream events
     */
    get streams(): {
        getEvents: (params: {
            ontology: string;
            stream: string;
            environment?: string;
            session?: string;
            eventTypes?: string[];
            since?: Date;
            until?: Date;
            isAcked?: boolean;
            limit?: number;
            offset?: number;
        }) => Promise<StreamEvent[]>;
        subscribe: (params: {
            ontology: string;
            stream: string;
            environment?: string;
            session?: string;
            eventTypes?: string[];
            since?: Date;
            onEvent: (event: StreamEvent) => void;
            onError?: (err: Error) => void;
            pollIntervalMs?: number;
        }) => StreamSubscription;
        ack: (eventId: string) => Promise<void>;
        ackBatch: (eventIds: string[]) => Promise<void>;
        getStats: (params: {
            ontology: string;
            environment?: string;
        }) => Promise<StreamStats[]>;
    };
    /**
     * Subject management
     */
    get subjects(): {
        get: (subjectId: string) => Promise<Subject>;
        listAssignments: (subjectId: string) => Promise<AssignmentListResponse>;
    };
    /**
     * @deprecated Use recordUser() instead
     */
    get users(): {
        create: (data: {
            id: string;
            name?: string;
            email?: string;
        }) => Promise<Subject>;
        get: (id: string) => Promise<Subject>;
    };
    private _resolveSandboxId;
    /**
     * Make an authenticated API request
     */
    private request;
}

export { Environment as E, Granular as G, OntologyHandle as O, Session as S, WSClient as W, EnvironmentSession as a };
