@muhkoo/connect 0.4.0-alpha.1 → 0.6.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/connect.d.ts CHANGED
@@ -1812,6 +1812,16 @@ interface AuthSuccess {
1812
1812
  token: string;
1813
1813
  username: string;
1814
1814
  }
1815
+ /** A vault factor record (M1.0). Wrap/iv are base64 AES-GCM; absent for phrase. */
1816
+ interface VaultFactor {
1817
+ id: string;
1818
+ type: "password" | "passkey" | "phrase-marker";
1819
+ wrap?: string;
1820
+ iv?: string;
1821
+ params?: Record<string, unknown>;
1822
+ label?: string;
1823
+ createdAt?: number;
1824
+ }
1815
1825
  interface AuthClientOptions {
1816
1826
  /** Absolute URL of the accelerator worker (no trailing slash required). */
1817
1827
  baseUrl: string;
@@ -1836,6 +1846,28 @@ declare class AuthClient {
1836
1846
  verify(token: string): Promise<{
1837
1847
  username: string;
1838
1848
  }>;
1849
+ /** Blinded OPRF evaluation — the server-gated half of a password/recovery wrap key. */
1850
+ oprfEvaluate(username: string, blinded: string): Promise<{
1851
+ evaluated: string;
1852
+ }>;
1853
+ /** Read a factor record for `username` (returns an indistinguishable decoy if absent). */
1854
+ vaultRead(username: string, factorType: VaultFactor["type"]): Promise<{
1855
+ factor: VaultFactor | null;
1856
+ }>;
1857
+ /** Add/replace a factor (session-authed; the seed is already wrapped client-side). */
1858
+ vaultPutFactor(token: string, factor: VaultFactor): Promise<{
1859
+ ok: boolean;
1860
+ id: string;
1861
+ }>;
1862
+ /** List the user's factor metadata (no ciphertext). Session-authed. */
1863
+ vaultFactors(token: string): Promise<{
1864
+ factors: VaultFactor[];
1865
+ migrated: boolean;
1866
+ }>;
1867
+ /** Remove a factor by id (can't remove the last one). Session-authed. */
1868
+ vaultDeleteFactor(token: string, id: string): Promise<{
1869
+ deleted: boolean;
1870
+ }>;
1839
1871
  private json;
1840
1872
  private parse;
1841
1873
  }
@@ -1882,6 +1914,23 @@ interface ZkIdentity {
1882
1914
  * devices.
1883
1915
  */
1884
1916
  declare function deriveIdentity(username: string, password: string): Promise<ZkIdentity>;
1917
+ /**
1918
+ * Legacy master-seed derivation: `PBKDF2(password, "muhkoo-zk-v1:"||username)`.
1919
+ *
1920
+ * This was the *only* path pre-vault, where the identity descended directly from
1921
+ * the password. It's kept so existing accounts still re-derive their seed (and
1922
+ * the vault can adopt that exact seed on migration, preserving the commitment).
1923
+ * New accounts use a random seed (`vault.randomSeed`) instead, so their identity
1924
+ * is no longer a function of the password.
1925
+ */
1926
+ declare function deriveMasterSeedFromPassword(username: string, password: string): Promise<Uint8Array>;
1927
+ /**
1928
+ * Derive the (unchanged) ZK identity from a 32-byte **master seed**. The seed is
1929
+ * HKDF-expanded into secret/salt + the P-256 ECDSA & ECDH keypairs exactly as
1930
+ * before — so the resulting commitment is byte-identical for a given seed. The
1931
+ * vault wraps THIS seed under each recovery factor.
1932
+ */
1933
+ declare function deriveIdentityFromSeed(seed: Uint8Array): Promise<ZkIdentity>;
1885
1934
 
1886
1935
  /**
1887
1936
  * Poseidon hash wrapper used by the ZK auth flow.
@@ -2083,6 +2132,10 @@ declare function defaultSessionStore(keyPrefix?: string): SessionStore;
2083
2132
  declare class SessionState {
2084
2133
  private session;
2085
2134
  private _identity;
2135
+ /** The 32-byte master seed, in-memory only (never persisted). Held after
2136
+ * login/register so additional recovery factors (passkey, phrase) can be
2137
+ * enrolled, and a password can be changed, without re-deriving. */
2138
+ private _seed;
2086
2139
  private readonly store;
2087
2140
  constructor(store?: SessionStore);
2088
2141
  /** True once a token-bearing session exists (regardless of identity). */
@@ -2099,6 +2152,10 @@ declare class SessionState {
2099
2152
  setSession(session: StoredSession): Promise<void>;
2100
2153
  /** Attach derived identity material to the current session. */
2101
2154
  setIdentity(identity: ZkIdentity): void;
2155
+ /** The in-memory master seed (or null when locked / not held). */
2156
+ get seed(): Uint8Array | null;
2157
+ /** Hold the master seed in memory (set on login/register when available). */
2158
+ setSeed(seed: Uint8Array | null): void;
2102
2159
  /** Load a persisted session (used by `restore()`); identity stays null. */
2103
2160
  loadPersisted(): Promise<StoredSession | null>;
2104
2161
  /** Drop all session + identity state and clear persistence. */
@@ -2122,6 +2179,17 @@ declare class SessionState {
2122
2179
  * at-rest encryption and the messaging ratchet without re-deriving.
2123
2180
  */
2124
2181
 
2182
+ /**
2183
+ * Thrown when the identity vault can't be reached to unlock the seed — a network
2184
+ * failure, a 5xx, or the per-user rate limit (429). This is distinct from a wrong
2185
+ * password, and is surfaced so `login`/`unlock` do NOT silently fall back to the
2186
+ * legacy password derivation (which, for a vault account, yields a misleading
2187
+ * "commitment mismatch"). Callers should ask the user to retry, not re-enter a
2188
+ * password.
2189
+ */
2190
+ declare class VaultUnavailableError extends Error {
2191
+ constructor(cause?: unknown);
2192
+ }
2125
2193
  /** What the auth methods resolve to — the stable, non-secret user facts. */
2126
2194
  interface AuthUser {
2127
2195
  username: string;
@@ -2152,17 +2220,26 @@ declare class ZkAuth {
2152
2220
  private readonly deps;
2153
2221
  constructor(deps: ZkAuthDeps);
2154
2222
  /**
2155
- * Register a new user, then (by default) sign them in. The identity is
2156
- * derived deterministically from `(username, password)` — the same inputs
2157
- * reproduce it on any device, so there's no key material to ship around.
2223
+ * Register a new user, then (by default) sign them in.
2224
+ *
2225
+ * M1.0: the identity now descends from a **random master seed** (not the
2226
+ * password), so it's recoverable + the password can be changed. We register
2227
+ * the commitment, sign in with the in-memory identity to get a token, then
2228
+ * enroll the OPRF-gated **password factor** (the seed wrapped under a key the
2229
+ * server can't derive offline). Future logins unlock the seed via that factor.
2158
2230
  */
2159
2231
  register(params: RegisterParams): Promise<AuthUser>;
2160
2232
  /**
2161
- * Sign in: re-derive the identity, prove knowledge of it against a fresh
2162
- * server challenge, and trade the proof for a session token. On success
2163
- * both the session and the identity are stored on the client.
2233
+ * Sign in. M1.0 is **vault-first**: read the password factor and OPRF-unwrap
2234
+ * the master seed → identity. If that fails (a pre-vault account, whose factor
2235
+ * is absent so the server returns a decoy, or a wrong password), fall back to
2236
+ * the legacy password-derived identity. Either way we then prove knowledge of
2237
+ * the identity and trade it for a session token.
2164
2238
  */
2165
2239
  login(username: string, password: string, opts?: LoginOptions): Promise<AuthUser>;
2240
+ /** Enroll the password factor for a legacy (pre-vault) account. Idempotent +
2241
+ * best-effort; failure just means we retry on the next login. */
2242
+ private migrateLegacyPasswordFactor;
2166
2243
  /**
2167
2244
  * Silently re-authenticate the current user without prompting for a
2168
2245
  * password. Only possible while the client is **unlocked** — i.e. the
@@ -2200,6 +2277,60 @@ declare class ZkAuth {
2200
2277
  * the password by checking the derived commitment matches the session's.
2201
2278
  */
2202
2279
  unlock(password: string): Promise<void>;
2280
+ /**
2281
+ * Generate a 24-word **recovery phrase** that encodes the master seed, and
2282
+ * record a marker in the vault so the UI knows one exists. Show the returned
2283
+ * phrase to the user ONCE — it's never stored server-side (the phrase *is* the
2284
+ * seed). Requires being signed in (the seed must be held in memory).
2285
+ */
2286
+ enrollRecoveryPhrase(): Promise<string>;
2287
+ /**
2288
+ * Recover an account with its recovery phrase (the "forgot password" path).
2289
+ * Decodes the phrase to the master seed → identity → session. After this,
2290
+ * call {@link changePassword} to set a new password. No server lookup needed.
2291
+ */
2292
+ recoverWithPhrase(username: string, mnemonic: string, opts?: LoginOptions): Promise<AuthUser>;
2293
+ /**
2294
+ * Change the password — re-wraps the (unchanged) master seed under the new
2295
+ * password's OPRF-gated key. The identity/commitment never moves. Requires
2296
+ * being signed in (or freshly recovered) so the seed is held.
2297
+ */
2298
+ changePassword(newPassword: string): Promise<void>;
2299
+ /** Whether this browser can use passkeys (WebAuthn) at all. */
2300
+ passkeyAvailable(): boolean;
2301
+ /**
2302
+ * Whether this browser's authenticator can do the **PRF extension** our
2303
+ * passkey factor requires. A browser may support passkeys generally but not
2304
+ * PRF — in which case enrolling one would fail. Resolves `true`/`false`, or
2305
+ * `null` when it can't be determined (no capabilities API). Use this to gate
2306
+ * the passkey UI so users don't hit a dead-end error.
2307
+ */
2308
+ passkeyPrfAvailable(): Promise<boolean | null>;
2309
+ /**
2310
+ * Add a **passkey** recovery factor. Creates a WebAuthn passkey with PRF,
2311
+ * wraps the master seed under its PRF output, and stores the factor. The
2312
+ * passkey (synced via the platform's keychain) then unlocks the account on
2313
+ * any device — no password. Requires being signed in (seed held in memory).
2314
+ */
2315
+ enrollPasskey(opts?: {
2316
+ rpId?: string;
2317
+ rpName?: string;
2318
+ label?: string;
2319
+ }): Promise<void>;
2320
+ /**
2321
+ * Sign in with a passkey (no password). Reads the passkey factor, evaluates
2322
+ * its PRF, unwraps the master seed → identity → session.
2323
+ */
2324
+ loginWithPasskey(username: string, opts?: LoginOptions): Promise<AuthUser>;
2325
+ /** List the user's enrolled login methods (metadata only). Session-authed. */
2326
+ listFactors(): Promise<Array<{
2327
+ id: string;
2328
+ type: string;
2329
+ label?: string;
2330
+ createdAt?: number;
2331
+ }>>;
2332
+ /** Remove a login method by id (can't remove your only one). Session-authed. */
2333
+ removeFactor(id: string): Promise<void>;
2203
2334
  /** Sign out: clears the session, identity, and persisted token. */
2204
2335
  logout(): Promise<void>;
2205
2336
  /** The signed-in user, or `null`. Synchronous read of current state. */
@@ -2213,8 +2344,43 @@ declare class ZkAuth {
2213
2344
  get identity(): ZkIdentity | null;
2214
2345
  /** The current session token, or `null` when signed out. */
2215
2346
  get token(): string | null;
2347
+ /**
2348
+ * The master seed as base64, or `null` when locked. The host app uses this to
2349
+ * wrap app-level data (e.g. chat ratchet keys) to the **seed** instead of the
2350
+ * password — so that data survives password changes and can be unlocked by a
2351
+ * passwordless (passkey) login, both of which recover the same seed.
2352
+ */
2353
+ get seedBase64(): string | null;
2216
2354
  /** Poseidon commitment for an identity — the value the server stores. */
2217
2355
  private commitmentFor;
2356
+ /**
2357
+ * Derive the OPRF-gated wrap key for the password factor: `scrypt(password)`
2358
+ * is blinded, evaluated by the server's secret OPRF key (so it can't be
2359
+ * derived offline), unblinded, then HKDF'd into an AES-GCM key.
2360
+ */
2361
+ private passwordWrapKey;
2362
+ /**
2363
+ * Try to recover the master seed from the password factor.
2364
+ *
2365
+ * Returns `null` only when the vault read SUCCEEDS but the seed can't be
2366
+ * unwrapped — i.e. there's no real factor (a pre-vault/legacy account, whose
2367
+ * read returns a decoy that won't unwrap) or the password is wrong. The caller
2368
+ * then legitimately falls back to the legacy password-derived identity.
2369
+ *
2370
+ * Throws {@link VaultUnavailableError} when the vault itself can't be reached
2371
+ * (network / 5xx / rate-limit) — so a *transient* failure is NOT silently
2372
+ * turned into a legacy fallback (which would surface as "commitment mismatch").
2373
+ */
2374
+ private tryUnlockSeed;
2375
+ /**
2376
+ * Enroll/replace the password factor for `username` — wraps `seed` under the
2377
+ * OPRF-gated key and stores it (needs a session `token`).
2378
+ *
2379
+ * Retries: this is the step that persists the (otherwise in-memory-only)
2380
+ * master seed. If it fails after a fresh registration the account would be
2381
+ * unrecoverable, so we retry a few times before surfacing the error.
2382
+ */
2383
+ private enrollPasswordFactor;
2218
2384
  }
2219
2385
  /** `client.auth` — the auth namespace. Strategies hang off here. */
2220
2386
  declare class AuthNamespace {
@@ -2373,6 +2539,101 @@ declare class KvNamespace {
2373
2539
  private getCipher;
2374
2540
  }
2375
2541
 
2542
+ /**
2543
+ * `client.db` — the app's scalable database. A developer defines tables in the
2544
+ * Muhkoo portal (columns + indexes); each table is backed by its own Durable
2545
+ * Object SQLite instance and reachable through a sanitized REST gateway. This
2546
+ * namespace wraps that gateway:
2547
+ *
2548
+ * const todos = client.db.table('todos');
2549
+ * const { id } = await todos.insert({ title: 'Buy milk', done: false });
2550
+ * const one = await todos.get(id);
2551
+ * const { rows, nextCursor } = await todos.query({
2552
+ * where: [{ column: 'done', op: 'eq', value: false }],
2553
+ * orderBy: { column: 'rank', dir: 'asc' },
2554
+ * limit: 50,
2555
+ * });
2556
+ * await todos.update(id, { done: true });
2557
+ * await todos.delete(id);
2558
+ *
2559
+ * Authorization is the **app key** ({@link HttpClient} stamps it on every
2560
+ * request); the appId + environment are resolved server-side from the key, so a
2561
+ * key can only ever reach its own app's tables. The front end never touches the
2562
+ * database directly — this REST surface is the only gateway, and all input is
2563
+ * validated against the table's schema (parameterized statements, column +
2564
+ * operator allowlists). There is no raw-SQL passthrough.
2565
+ *
2566
+ * Schema is authored in the portal, not here (the SDK reads + writes rows, it
2567
+ * doesn't create tables). Pagination is keyset-based: pass the `nextCursor` from
2568
+ * a previous `query()` back as `cursor` to fetch the next page.
2569
+ */
2570
+
2571
+ interface DbNamespaceDeps {
2572
+ http: HttpClient;
2573
+ }
2574
+ /** Comparison operators allowed in a {@link DbQuery} `where` clause. */
2575
+ type DbFilterOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "likeStartsWith" | "likeContains";
2576
+ interface DbWhereCondition {
2577
+ column: string;
2578
+ op: DbFilterOp;
2579
+ /** Scalar for most ops; an array for `in`; a string for the `like` family. */
2580
+ value: unknown;
2581
+ }
2582
+ interface DbQuery {
2583
+ /** Columns to return; omit for all columns. */
2584
+ select?: string[];
2585
+ /** Conditions AND-combined. */
2586
+ where?: DbWhereCondition[];
2587
+ /** Sort by a column (defaults to the primary key, ascending). */
2588
+ orderBy?: {
2589
+ column: string;
2590
+ dir?: "asc" | "desc";
2591
+ };
2592
+ /** Page size, clamped server-side to 100. */
2593
+ limit?: number;
2594
+ /** Opaque keyset cursor from a previous query's `nextCursor`. */
2595
+ cursor?: string;
2596
+ }
2597
+ interface DbQueryResult<T = Record<string, unknown>> {
2598
+ rows: T[];
2599
+ /** Cursor for the next page, or `null` when the last page was returned. */
2600
+ nextCursor: string | null;
2601
+ }
2602
+ /** A handle to one table — the ergonomic surface for row operations. */
2603
+ declare class DbTable<T extends Record<string, unknown> = Record<string, unknown>> {
2604
+ private readonly http;
2605
+ private readonly name;
2606
+ constructor(http: HttpClient, name: string);
2607
+ private base;
2608
+ /** Insert a row. Returns the created row and its primary-key value. */
2609
+ insert(values: Partial<T>): Promise<{
2610
+ row: T;
2611
+ id: unknown;
2612
+ }>;
2613
+ /** Fetch a row by primary key, or `null` if it doesn't exist. */
2614
+ get(id: string | number): Promise<T | null>;
2615
+ /** Query rows with filters, ordering, and keyset pagination. */
2616
+ query(query?: DbQuery): Promise<DbQueryResult<T>>;
2617
+ /** Update a row by primary key. Returns the updated row. */
2618
+ update(id: string | number, values: Partial<T>): Promise<{
2619
+ row: T;
2620
+ }>;
2621
+ /** Delete a row by primary key. Returns the number of rows removed (0 or 1). */
2622
+ delete(id: string | number): Promise<number>;
2623
+ }
2624
+ declare class DbNamespace {
2625
+ private readonly deps;
2626
+ constructor(deps: DbNamespaceDeps);
2627
+ /**
2628
+ * A handle to a table defined in the portal. The optional type parameter
2629
+ * gives row operations a typed shape:
2630
+ *
2631
+ * interface Todo { _id: number; title: string; done: boolean }
2632
+ * const todos = client.db.table<Todo>('todos');
2633
+ */
2634
+ table<T extends Record<string, unknown> = Record<string, unknown>>(name: string): DbTable<T>;
2635
+ }
2636
+
2376
2637
  /**
2377
2638
  * `client.storage` — file storage. Hides the `FileStorage` / `ShardClient` /
2378
2639
  * `SharedSpaceClient` primitives behind the unified client.
@@ -3228,11 +3489,41 @@ declare class SpaceNamespace {
3228
3489
  * (viewers can read). Authorization rides the user session token; non-owner
3229
3490
  * editors pass their management Space via `opts.space`.
3230
3491
  *
3231
- * v1 is "prompts + persona": a system prompt, a model, named prompt `skills`,
3232
- * and `triggers` that decide when the agent speaks. No tools, no code.
3492
+ * An agent is "prompts + persona": a system prompt, a model, named prompt
3493
+ * `skills`, and `triggers` that decide when it speaks — plus optional `tools`
3494
+ * that let it act on the app (query/write its database, call its functions,
3495
+ * resolve its channels) via a server-side function-calling loop. See
3496
+ * {@link AgentToolsConfig}. Pair with the `@MuhkooAgent`/`@MuhkooSpace`/
3497
+ * `@MuhkooDB`/`@MuhkooFunction` decorators + `ejectAgentPrompt`/`ejectAgentTools`
3498
+ * to generate `systemPrompt` and `tools` straight from your app's surface.
3233
3499
  */
3234
3500
 
3235
3501
  type AgentTriggerType = "mention" | "keyword" | "regex" | "always";
3502
+ /** How much database access the agent's tool-use has. */
3503
+ type AgentDbToolMode = "off" | "read" | "write";
3504
+ /**
3505
+ * Tool-use config — lets the agent act on the app through a function-calling
3506
+ * loop. Opt-in and conservatively gated server-side: a fresh agent has tools
3507
+ * off, the DB is read-only and per-table allowlisted, functions are per-name
3508
+ * allowlisted, and channels are off. **Enabling tools requires a
3509
+ * function-calling `model` in the same create/update payload** (the server
3510
+ * rejects `enabled: true` otherwise). `ejectAgentTools` produces this shape.
3511
+ */
3512
+ interface AgentToolsConfig {
3513
+ enabled: boolean;
3514
+ db: {
3515
+ /** `off` = no DB tools; `read` = query/get; `write` = + insert/update/delete. */
3516
+ mode: AgentDbToolMode;
3517
+ /** Allowlisted table names the agent may touch. */
3518
+ tables: string[];
3519
+ };
3520
+ /** Allowlisted serverless-function names the agent may call. */
3521
+ functions: string[];
3522
+ /** Whether the agent may resolve the app's PUBLIC channels. */
3523
+ channels: boolean;
3524
+ /** Max tool-call rounds per reply (1..6). */
3525
+ maxIterations: number;
3526
+ }
3236
3527
  interface AgentTrigger {
3237
3528
  type: AgentTriggerType;
3238
3529
  /** Required for `keyword` (case-insensitive substring) and `regex`. */
@@ -3258,6 +3549,8 @@ interface AgentConfig {
3258
3549
  caps: {
3259
3550
  dailyTokenBudget: number;
3260
3551
  };
3552
+ /** Tool-use config (absent / `enabled: false` = prompt-only). */
3553
+ tools?: AgentToolsConfig;
3261
3554
  createdAt: number;
3262
3555
  updatedAt: number;
3263
3556
  }
@@ -3272,6 +3565,8 @@ interface AgentCreateInput {
3272
3565
  caps?: {
3273
3566
  dailyTokenBudget: number;
3274
3567
  };
3568
+ /** Grant tool-use. Requires `model` to be a function-calling model. */
3569
+ tools?: AgentToolsConfig;
3275
3570
  }
3276
3571
  type AgentUpdateInput = Partial<AgentCreateInput>;
3277
3572
  /** Create/get response — the config plus the agent's published identity keys. */
@@ -3481,6 +3776,8 @@ declare class Client {
3481
3776
  readonly auth: AuthNamespace;
3482
3777
  /** Per-user key/value storage — `client.kv.set(...)`, etc. */
3483
3778
  readonly kv: KvNamespace;
3779
+ /** App scalable database — `client.db.table('todos').query(...)`, etc. */
3780
+ readonly db: DbNamespace;
3484
3781
  /** File storage — `client.storage.writeFile(...)`, etc. */
3485
3782
  readonly storage: StorageNamespace;
3486
3783
  /** Realtime messaging — `client.message.subscribe(...)`, etc. */
@@ -3523,6 +3820,134 @@ declare class Client {
3523
3820
  recoverSession(): Promise<boolean>;
3524
3821
  }
3525
3822
 
3823
+ /**
3824
+ * Muhkoo app decorators — declare your app's agent-facing surface in code, then
3825
+ * "eject" a system prompt you hand to a Programmable Agent.
3826
+ *
3827
+ * You annotate a plain class with `@MuhkooAgent` (the app's identity + how the
3828
+ * agent should behave) plus per-surface decorators — `@MuhkooSpace`,
3829
+ * `@MuhkooDB`, `@MuhkooFunction` — that describe what each channel, table, and
3830
+ * function is *for*. {@link ejectAgentPrompt} reads those annotations and
3831
+ * produces a `systemPrompt` string:
3832
+ *
3833
+ * ```ts
3834
+ * @MuhkooAgent({
3835
+ * name: "Chat Assistant",
3836
+ * purpose: "A helpful assistant inside a real-time team chat.",
3837
+ * guidance: ["Keep replies short.", "Only chime in when relevant."],
3838
+ * })
3839
+ * class ChatAssistant {
3840
+ * @MuhkooSpace({ description: "Main team discussion." }) general!: string;
3841
+ * @MuhkooDB({ access: "read", description: "Chat message history." }) messages!: unknown;
3842
+ * @MuhkooFunction({ description: "Open a support ticket." }) openTicket!: () => void;
3843
+ * }
3844
+ *
3845
+ * const systemPrompt = ejectAgentPrompt(ChatAssistant);
3846
+ * await client.agents.create({ handle: "assistant", displayName: "Assistant", systemPrompt });
3847
+ * ```
3848
+ *
3849
+ * The ejected prompt owns the **semantic** layer — what the app is, how to act,
3850
+ * and what each surface means. The Muhkoo runtime separately appends the
3851
+ * **authoritative** roster (exact columns, function parameters, and the closed
3852
+ * list of callable tools), so the prompt here never needs to restate schema and
3853
+ * can't drift from it. Decorators only describe; they never change runtime
3854
+ * behavior, so they're safe to apply to a throwaway descriptor class.
3855
+ *
3856
+ * Requires `experimentalDecorators` (already enabled in this package). Metadata
3857
+ * is captured in a per-class registry — no `reflect-metadata` dependency.
3858
+ */
3859
+
3860
+ /** Whether the agent may only read a table, or read and write it. */
3861
+ type MuhkooDBAccess = "read" | "write";
3862
+ /** App-level identity + behavioral guidance — the heart of the ejected prompt. */
3863
+ interface MuhkooAgentMeta {
3864
+ /** The agent persona's name (e.g. "Chat Assistant"). */
3865
+ name: string;
3866
+ /** What the app is and the agent's role in it. One or two sentences. */
3867
+ purpose: string;
3868
+ /** Short behavioral rules, rendered as a bulleted list. */
3869
+ guidance?: string[];
3870
+ /** Optional free-form instructions appended verbatim after the surface. */
3871
+ instructions?: string;
3872
+ }
3873
+ /** A channel/Space the agent can resolve and post into. */
3874
+ interface MuhkooSpaceMeta {
3875
+ /** Channel name. Defaults to the decorated member's name. */
3876
+ name?: string;
3877
+ description: string;
3878
+ }
3879
+ /** An app database table the agent can query (and optionally mutate). */
3880
+ interface MuhkooDBMeta {
3881
+ /** Table name. Defaults to the decorated member's name. */
3882
+ table?: string;
3883
+ /** Read-only by default. */
3884
+ access?: MuhkooDBAccess;
3885
+ description: string;
3886
+ }
3887
+ /** A serverless function the agent can invoke via `call_function`. */
3888
+ interface MuhkooFunctionMeta {
3889
+ /** Function name. Defaults to the decorated member's name. */
3890
+ name?: string;
3891
+ description: string;
3892
+ }
3893
+ interface SpaceEntry {
3894
+ name: string;
3895
+ description: string;
3896
+ }
3897
+ interface TableEntry {
3898
+ table: string;
3899
+ access: MuhkooDBAccess;
3900
+ description: string;
3901
+ }
3902
+ interface FunctionEntry {
3903
+ name: string;
3904
+ description: string;
3905
+ }
3906
+ /** The full annotated surface gathered from one decorated class. */
3907
+ interface MuhkooAppDescriptor {
3908
+ agent?: MuhkooAgentMeta;
3909
+ spaces: SpaceEntry[];
3910
+ tables: TableEntry[];
3911
+ functions: FunctionEntry[];
3912
+ }
3913
+ /**
3914
+ * Class decorator. Declares the app's agent identity, purpose, and behavioral
3915
+ * guidance. Apply it to the class whose members carry the surface decorators.
3916
+ */
3917
+ declare function MuhkooAgent(meta: MuhkooAgentMeta): ClassDecorator;
3918
+ /** Member decorator. Marks a channel/Space the agent can resolve and post to. */
3919
+ declare function MuhkooSpace(meta: MuhkooSpaceMeta): PropertyDecorator & MethodDecorator;
3920
+ /** Member decorator. Marks an app database table the agent can query/mutate. */
3921
+ declare function MuhkooDB(meta: MuhkooDBMeta): PropertyDecorator & MethodDecorator;
3922
+ /** Member decorator. Marks a serverless function the agent can call. */
3923
+ declare function MuhkooFunction(meta: MuhkooFunctionMeta): PropertyDecorator & MethodDecorator;
3924
+ /** Read back the raw descriptor a class accumulated (for tooling/tests). */
3925
+ declare function getMuhkooAppDescriptor(appClass: Function): MuhkooAppDescriptor | undefined;
3926
+ /**
3927
+ * Compose the agent system prompt from a `@MuhkooAgent`-decorated class. Throws
3928
+ * if the class isn't decorated. The result is the semantic layer only — the
3929
+ * runtime appends exact schema + the closed tool list at invocation time.
3930
+ */
3931
+ declare function ejectAgentPrompt(appClass: Function): string;
3932
+ /**
3933
+ * The tools-config shape the Muhkoo platform uses to gate an agent. Alias of
3934
+ * `client.agents`' {@link AgentToolsConfig} so {@link ejectAgentTools} output
3935
+ * drops straight into `client.agents.create({ tools })`.
3936
+ */
3937
+ type MuhkooAgentToolsConfig = AgentToolsConfig;
3938
+ /**
3939
+ * Derive a suggested tools allowlist from a decorated class — the db tables
3940
+ * (and whether any are writable), the callable functions, and whether channels
3941
+ * are in play. Pair with {@link ejectAgentPrompt} when configuring the agent.
3942
+ *
3943
+ * If any tables/functions are present the result has `enabled: true`; to
3944
+ * actually grant tools you must also pass a function-calling `model` in the same
3945
+ * `client.agents.create`/`update` call (the server enforces this).
3946
+ */
3947
+ declare function ejectAgentTools(appClass: Function, opts?: {
3948
+ maxIterations?: number;
3949
+ }): AgentToolsConfig;
3950
+
3526
3951
  /**
3527
3952
  * KeyringClient — HTTP implementation of {@link KeyringTransport} against the
3528
3953
  * accelerator's per-space keyring endpoints. All blobs are opaque to the
@@ -3583,5 +4008,5 @@ declare class KeyringClient implements KeyringTransport {
3583
4008
  fetchMetadata(): Promise<SpaceMetadata | null>;
3584
4009
  }
3585
4010
 
3586
- export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, DEFAULT_BASE_URL, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HashKnowledge, HttpClient, HttpError, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvNamespace, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardClient, SharedSpaceClient, Space, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, WSTransport, ZkAuth, buildCommitment, compilePrograms, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, generateAuthProof, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, manifestToStat, poseidonHash, quickVerify, randomBytes, shardHash, signMessage, toField, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase };
3587
- export type { ACL, ACLEntry, AgentConfig, AgentCreateInput, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, DehydratedKeypair, DehydratedKeys, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EphemeralEvent, EpochKeyProvider, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvNamespaceDeps, LoginOptions, MessageBody, MessageDeletedEvent, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOptions, MessageSubscription, MuhkooMessageEvent, OAuthProvider, PacketCipher, PacketHeaders, PacketOptions, Participant, Permission, PermissionCheckRequest, PermissionCheckResult, PersonalSpaceClientOptions, PublicKeyJWK, RatchetState, ReceiveResult, RegisterParams, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardClientOptions, SharedSpaceClientOptions, SnarkProof, SpaceChannelLike, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, StorageChangeEvent, StoredSession, Subscription, UserIdentity, VerificationKey, WSMessage, WSMessageType, WSTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };
4011
+ export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, DEFAULT_BASE_URL, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HashKnowledge, HttpClient, HttpError, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvNamespace, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardClient, SharedSpaceClient, Space, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, VaultUnavailableError, WSTransport, ZkAuth, buildCommitment, compilePrograms, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, ejectAgentPrompt, ejectAgentTools, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, generateAuthProof, getMuhkooAppDescriptor, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, manifestToStat, poseidonHash, quickVerify, randomBytes, shardHash, signMessage, toField, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase };
4012
+ export type { ACL, ACLEntry, AgentConfig, AgentCreateInput, AgentDbToolMode, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentToolsConfig, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, DehydratedKeypair, DehydratedKeys, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EphemeralEvent, EpochKeyProvider, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvNamespaceDeps, LoginOptions, MessageBody, MessageDeletedEvent, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOptions, MessageSubscription, MuhkooAgentMeta, MuhkooAgentToolsConfig, MuhkooAppDescriptor, MuhkooDBAccess, MuhkooDBMeta, MuhkooFunctionMeta, MuhkooMessageEvent, MuhkooSpaceMeta, OAuthProvider, PacketCipher, PacketHeaders, PacketOptions, Participant, Permission, PermissionCheckRequest, PermissionCheckResult, PersonalSpaceClientOptions, PublicKeyJWK, RatchetState, ReceiveResult, RegisterParams, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardClientOptions, SharedSpaceClientOptions, SnarkProof, SpaceChannelLike, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, StorageChangeEvent, StoredSession, Subscription, UserIdentity, VaultFactor, VerificationKey, WSMessage, WSMessageType, WSTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };