@lunora/solid 1.0.0-alpha.241 → 1.0.0-alpha.243

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/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, SubscriptionErrorCallback, User, ConnectionStatus, LiveStreamSubscribeError, LiveTopicRef, LiveTopicOptions, MutationCallOptions, MutatorHandle, SubscriptionError, Preloaded } from '@lunora/client';
1
+ import { LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, SubscriptionErrorCallback, User, ConnectionStatus, LiveStreamSubscribeError, LiveTopicRef, LiveTopicOptions, MutationCallOptions, OnlineOnlyOption, MutatorHandle, SubscriptionError, Preloaded } from '@lunora/client';
2
2
  export type { ArgsOf, FunctionReference, MutatorHandle, MutatorTransaction, OptimisticUpdate, Preloaded, ReturnOf, SubscriptionError, SubscriptionErrorCallback, Unsubscribe } from '@lunora/client';
3
3
  import { Context, Accessor } from 'solid-js';
4
4
  import { AuthStatus } from '@lunora/client/auth';
@@ -190,8 +190,8 @@ interface AgentChatMessage {
190
190
  optimistic?: boolean;
191
191
  role: "assistant" | "system" | "tool" | "user";
192
192
  seq: number;
193
- /** Approval lifecycle marker on a human-in-the-loop tool message. */
194
- status?: "approved" | "awaiting_approval" | "rejected";
193
+ /** Approval or secret-request lifecycle marker on a human-in-the-loop tool message. */
194
+ status?: "approved" | "awaiting_approval" | "awaiting_secret" | "rejected";
195
195
  toolCallId?: string;
196
196
  toolCalls?: ReadonlyArray<{
197
197
  id: string;
@@ -245,7 +245,7 @@ type AgentMessagesReference$1 = FunctionReference<"query", {
245
245
  }, ReadonlyArray<Record<string, unknown>>>;
246
246
  /** The `agents:agentResolveApproval` reference — resolves a human-in-the-loop tool approval. */
247
247
  type AgentApprovalReference = FunctionReference<"mutation", {
248
- decision: "approve" | "reject";
248
+ decision: "approve" | "approve_for_thread" | "reject";
249
249
  instanceId: string;
250
250
  note?: string;
251
251
  threadKey: string;
@@ -253,10 +253,41 @@ type AgentApprovalReference = FunctionReference<"mutation", {
253
253
  }, {
254
254
  resolved: boolean;
255
255
  }>;
256
+ /** The `agents:agentSupplySecret` reference — stores a person's value for a paused `requestSecretTool` call. */
257
+ type AgentSupplySecretReference = FunctionReference<"mutation", {
258
+ secret: string;
259
+ threadKey: string;
260
+ toolCallId: string;
261
+ }, {
262
+ resolved: boolean;
263
+ }>;
264
+ /** The `agents:agentDeclineSecret` reference — refuses a paused `requestSecretTool` call. */
265
+ type AgentDeclineSecretReference = FunctionReference<"mutation", {
266
+ threadKey: string;
267
+ toolCallId: string;
268
+ }, {
269
+ resolved: boolean;
270
+ }>;
256
271
  /** The `agents:agentThread` reference — live thread status + in-flight `instanceId`. */
257
272
  type AgentThreadReference = FunctionReference<"query", {
258
273
  key: string;
259
274
  }, Record<string, unknown> | undefined>;
275
+ /** A tool approved for the rest of a thread, as `agents:agentApprovalGrants` lists it. */
276
+ interface AgentApprovalGrant {
277
+ createdAt: number;
278
+ toolName: string;
279
+ }
280
+ /** The `agents:agentApprovalGrants` reference — live thread-scoped approval grants. */
281
+ type AgentApprovalGrantsReference = FunctionReference<"query", {
282
+ key: string;
283
+ }, ReadonlyArray<AgentApprovalGrant>>;
284
+ /** The `agents:agentRevokeApprovalGrant` reference — removes a thread-scoped approval grant. */
285
+ type AgentRevokeApprovalGrantReference = FunctionReference<"mutation", {
286
+ threadKey: string;
287
+ toolName: string;
288
+ }, {
289
+ revoked: boolean;
290
+ }>;
260
291
  /**
261
292
  * An app stream reference that tees the agent's in-flight live events, keyed by
262
293
  * thread. Carries token deltas and — since `ctx.reportProgress` rides the same
@@ -272,8 +303,12 @@ type AgentTokenStreamReference = FunctionReference<"stream", {
272
303
  */
273
304
  interface CreateAgentChatApi {
274
305
  agents: {
306
+ agentApprovalGrants: AgentApprovalGrantsReference;
307
+ agentDeclineSecret: AgentDeclineSecretReference;
275
308
  agentMessages: AgentMessagesReference$1;
276
309
  agentResolveApproval: AgentApprovalReference;
310
+ agentRevokeApprovalGrant: AgentRevokeApprovalGrantReference;
311
+ agentSupplySecret: AgentSupplySecretReference;
277
312
  agentThread: AgentThreadReference;
278
313
  };
279
314
  }
@@ -290,7 +325,7 @@ interface CreateAgentChatOptions {
290
325
  /** History depth forwarded to `agents:agentMessages`. */
291
326
  limit?: number;
292
327
  /**
293
- * Called when the live history or thread subscription reports an error (a
328
+ * Called when the live history, thread, or grants subscription reports an error (a
294
329
  * session expiry, an RLS denial). Without it — and without reading `error` —
295
330
  * such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
296
331
  */
@@ -313,29 +348,47 @@ interface CreateAgentChatOptions {
313
348
  threadKey: MaybeAccessor<string>;
314
349
  }
315
350
  interface CreateAgentChatResult {
351
+ /** The tools approved for the rest of this thread, live. Empty until the grants subscription answers. */
352
+ approvalGrants: Accessor<ReadonlyArray<AgentApprovalGrant>>;
316
353
  /** Approve a paused human-in-the-loop tool call (optionally with a note). */
317
354
  approve: (toolCallId: string, note?: string) => Promise<void>;
355
+ /**
356
+ * Approve a paused tool call and grant that tool for the rest of the thread, so
357
+ * later calls to it run without pausing. Undo with {@link CreateAgentChatResult.revokeGrant}.
358
+ */
359
+ approveForThread: (toolCallId: string, note?: string) => Promise<void>;
318
360
  /**
319
361
  * Terminate the in-flight run and mark its thread `"cancelled"`. Resolves as a
320
362
  * no-op when no `cancel` mutation was supplied or no run is in flight.
321
363
  */
322
364
  cancel: () => Promise<void>;
323
- /** The history or thread subscription's last error, or `undefined`. */
365
+ /** Refuse a paused `requestSecretTool` call: the run resumes with a "declined" result. */
366
+ declineSecret: (toolCallId: string) => Promise<void>;
367
+ /** The history, thread, or grants subscription's last error, or `undefined`. */
324
368
  error: Accessor<Error | undefined>;
325
369
  /** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
326
370
  messages: Accessor<ReadonlyArray<AgentChatMessage>>;
327
371
  /** Reject a paused human-in-the-loop tool call (optionally with a reason). */
328
372
  reject: (toolCallId: string, note?: string) => Promise<void>;
373
+ /** Remove a thread-scoped approval grant so the tool's gate applies again to later calls. */
374
+ revokeGrant: (toolName: string) => Promise<void>;
329
375
  /** Start (or continue) a run with a user message; extra args merge over `sendArgs`. Appends an optimistic user turn. */
330
376
  send: (input: string, args?: Record<string, unknown>) => Promise<void>;
331
377
  /** The live thread status, or `undefined` before the thread exists. */
332
378
  status: Accessor<AgentThreadStatus | undefined>;
333
379
  /** The in-flight turn's streamed text — live-only, empty once the turn persists to `messages`. */
334
380
  streamingText: Accessor<string>;
381
+ /**
382
+ * Give a paused `requestSecretTool` call its value. Always sent online-only: the
383
+ * value is never queued, persisted or replayed, and the call rejects with
384
+ * `OFFLINE_NOT_QUEUED` while the connection is down. The primitive keeps no copy;
385
+ * a failure rethrows the original error.
386
+ */
387
+ supplySecret: (toolCallId: string, secret: string) => Promise<void>;
335
388
  }
336
389
  /**
337
390
  * A first-class agent chat surface: live durable history + in-flight token
338
- * streaming + the send / approve / reject / cancel writes, keyed by `threadKey` —
391
+ * streaming + the send / approve / reject / secret / cancel writes, keyed by `threadKey` —
339
392
  * the Solid counterpart to React's `useAgentChat`, re-expressed with signals.
340
393
  *
341
394
  * It composes the existing primitives rather than adding transport:
@@ -429,7 +482,7 @@ interface CreateAgentToolEventsOptions {
429
482
  * Optional live event stream — the same app stream function `createAgentChat`
430
483
  * uses. When supplied, ephemeral `ctx.reportProgress(...)` events for the
431
484
  * thread are surfaced as `{ type: "progress" }` entries; when omitted only the
432
- * durable lifecycle (call / result / awaiting-approval) is returned.
485
+ * durable lifecycle (call / result / awaiting-approval / awaiting-secret) is returned.
433
486
  */
434
487
  stream?: AgentLiveStreamReference;
435
488
  /** The thread whose tool activity to observe — a plain value or accessor (an accessor re-subscribes on change). */
@@ -437,7 +490,7 @@ interface CreateAgentToolEventsOptions {
437
490
  }
438
491
  /**
439
492
  * A single tool-lifecycle event for a thread. The durable arms
440
- * (`call`/`result`/`awaiting-approval`) are derived from `agents:agentMessages`
493
+ * (`call`/`result`/`awaiting-approval`/`awaiting-secret`) are derived from `agents:agentMessages`
441
494
  * and carry the persisted `seq`; the ephemeral `progress` arm comes live off the
442
495
  * stream and has no `seq`. Discriminate on `type`.
443
496
  */
@@ -463,6 +516,11 @@ type AgentToolEvent = {
463
516
  toolCallId?: string;
464
517
  toolName?: string;
465
518
  type: "awaiting-approval";
519
+ } | {
520
+ seq: number;
521
+ toolCallId?: string;
522
+ toolName?: string;
523
+ type: "awaiting-secret";
466
524
  };
467
525
  interface CreateAgentToolEventsResult {
468
526
  /**
@@ -643,7 +701,7 @@ interface MutationHandle<F extends FunctionReference> {
643
701
  /** The latest invocation's error, or `undefined`. */
644
702
  error: Accessor<Error | undefined>;
645
703
  /** Invoke the mutation. Resolves with the server result; rejects on failure. */
646
- mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
704
+ mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
647
705
  /** `true` while any invocation from this handle is in flight (ref-counted, so overlapping calls compose). */
648
706
  pending: Accessor<boolean>;
649
707
  /** Clear `data`/`error` back to idle. */
@@ -655,7 +713,7 @@ interface MutationHandle<F extends FunctionReference> {
655
713
  * in tests without constructing a full `LunoraClient`.
656
714
  */
657
715
  interface MutationClient<F extends FunctionReference> {
658
- mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
716
+ mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
659
717
  }
660
718
  /**
661
719
  * Build a mutation handle bound to an explicit client. Internal seam used by the
@@ -1213,7 +1271,7 @@ interface LunoraProviderProps {
1213
1271
  * itself is resolved per-major by {@link providerOf}.
1214
1272
  */
1215
1273
  declare const LunoraProvider: (props: LunoraProviderProps) => SolidElement;
1216
- export { type ActionClient, type ActionHandle, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type CreateAgentApi, type CreateAgentChatApi, type CreateAgentChatOptions, type CreateAgentChatResult, type CreateAgentOptions, type CreateAgentResult, type CreateAgentStateApi, type CreateAgentStateOptions, type CreateAgentStateResult, type CreateAgentToolEventsApi, type CreateAgentToolEventsOptions, type CreateAgentToolEventsResult, type CreateInfiniteQueryOptions, type CreateInfiniteQueryResult, type CreateLiveTopicResult, type CreatePaginatedQueryOptions, type CreatePaginatedQueryResult, type CreatePresenceOptions, type CreatePresenceResult, type CreateQueryOptions, type CreateRateLimitOptions, type CreateRateLimitResult, type CreateStreamOptions, type CreateStreamResult, type CreateStreamStatus, type CreateSubscriptionResult, type CreateVoiceAgentOptions, type CreateVoiceAgentResult, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraContext, LunoraProvider,
1274
+ export { type ActionClient, type ActionHandle, type AgentApprovalGrant, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type CreateAgentApi, type CreateAgentChatApi, type CreateAgentChatOptions, type CreateAgentChatResult, type CreateAgentOptions, type CreateAgentResult, type CreateAgentStateApi, type CreateAgentStateOptions, type CreateAgentStateResult, type CreateAgentToolEventsApi, type CreateAgentToolEventsOptions, type CreateAgentToolEventsResult, type CreateInfiniteQueryOptions, type CreateInfiniteQueryResult, type CreateLiveTopicResult, type CreatePaginatedQueryOptions, type CreatePaginatedQueryResult, type CreatePresenceOptions, type CreatePresenceResult, type CreateQueryOptions, type CreateRateLimitOptions, type CreateRateLimitResult, type CreateStreamOptions, type CreateStreamResult, type CreateStreamStatus, type CreateSubscriptionResult, type CreateVoiceAgentOptions, type CreateVoiceAgentResult, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraContext, LunoraProvider,
1217
1275
  /**
1218
1276
  * SolidJS adapter for Lunora.
1219
1277
  *
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, SubscriptionErrorCallback, User, ConnectionStatus, LiveStreamSubscribeError, LiveTopicRef, LiveTopicOptions, MutationCallOptions, MutatorHandle, SubscriptionError, Preloaded } from '@lunora/client';
1
+ import { LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, SubscriptionErrorCallback, User, ConnectionStatus, LiveStreamSubscribeError, LiveTopicRef, LiveTopicOptions, MutationCallOptions, OnlineOnlyOption, MutatorHandle, SubscriptionError, Preloaded } from '@lunora/client';
2
2
  export type { ArgsOf, FunctionReference, MutatorHandle, MutatorTransaction, OptimisticUpdate, Preloaded, ReturnOf, SubscriptionError, SubscriptionErrorCallback, Unsubscribe } from '@lunora/client';
3
3
  import { Context, Accessor } from 'solid-js';
4
4
  import { AuthStatus } from '@lunora/client/auth';
@@ -190,8 +190,8 @@ interface AgentChatMessage {
190
190
  optimistic?: boolean;
191
191
  role: "assistant" | "system" | "tool" | "user";
192
192
  seq: number;
193
- /** Approval lifecycle marker on a human-in-the-loop tool message. */
194
- status?: "approved" | "awaiting_approval" | "rejected";
193
+ /** Approval or secret-request lifecycle marker on a human-in-the-loop tool message. */
194
+ status?: "approved" | "awaiting_approval" | "awaiting_secret" | "rejected";
195
195
  toolCallId?: string;
196
196
  toolCalls?: ReadonlyArray<{
197
197
  id: string;
@@ -245,7 +245,7 @@ type AgentMessagesReference$1 = FunctionReference<"query", {
245
245
  }, ReadonlyArray<Record<string, unknown>>>;
246
246
  /** The `agents:agentResolveApproval` reference — resolves a human-in-the-loop tool approval. */
247
247
  type AgentApprovalReference = FunctionReference<"mutation", {
248
- decision: "approve" | "reject";
248
+ decision: "approve" | "approve_for_thread" | "reject";
249
249
  instanceId: string;
250
250
  note?: string;
251
251
  threadKey: string;
@@ -253,10 +253,41 @@ type AgentApprovalReference = FunctionReference<"mutation", {
253
253
  }, {
254
254
  resolved: boolean;
255
255
  }>;
256
+ /** The `agents:agentSupplySecret` reference — stores a person's value for a paused `requestSecretTool` call. */
257
+ type AgentSupplySecretReference = FunctionReference<"mutation", {
258
+ secret: string;
259
+ threadKey: string;
260
+ toolCallId: string;
261
+ }, {
262
+ resolved: boolean;
263
+ }>;
264
+ /** The `agents:agentDeclineSecret` reference — refuses a paused `requestSecretTool` call. */
265
+ type AgentDeclineSecretReference = FunctionReference<"mutation", {
266
+ threadKey: string;
267
+ toolCallId: string;
268
+ }, {
269
+ resolved: boolean;
270
+ }>;
256
271
  /** The `agents:agentThread` reference — live thread status + in-flight `instanceId`. */
257
272
  type AgentThreadReference = FunctionReference<"query", {
258
273
  key: string;
259
274
  }, Record<string, unknown> | undefined>;
275
+ /** A tool approved for the rest of a thread, as `agents:agentApprovalGrants` lists it. */
276
+ interface AgentApprovalGrant {
277
+ createdAt: number;
278
+ toolName: string;
279
+ }
280
+ /** The `agents:agentApprovalGrants` reference — live thread-scoped approval grants. */
281
+ type AgentApprovalGrantsReference = FunctionReference<"query", {
282
+ key: string;
283
+ }, ReadonlyArray<AgentApprovalGrant>>;
284
+ /** The `agents:agentRevokeApprovalGrant` reference — removes a thread-scoped approval grant. */
285
+ type AgentRevokeApprovalGrantReference = FunctionReference<"mutation", {
286
+ threadKey: string;
287
+ toolName: string;
288
+ }, {
289
+ revoked: boolean;
290
+ }>;
260
291
  /**
261
292
  * An app stream reference that tees the agent's in-flight live events, keyed by
262
293
  * thread. Carries token deltas and — since `ctx.reportProgress` rides the same
@@ -272,8 +303,12 @@ type AgentTokenStreamReference = FunctionReference<"stream", {
272
303
  */
273
304
  interface CreateAgentChatApi {
274
305
  agents: {
306
+ agentApprovalGrants: AgentApprovalGrantsReference;
307
+ agentDeclineSecret: AgentDeclineSecretReference;
275
308
  agentMessages: AgentMessagesReference$1;
276
309
  agentResolveApproval: AgentApprovalReference;
310
+ agentRevokeApprovalGrant: AgentRevokeApprovalGrantReference;
311
+ agentSupplySecret: AgentSupplySecretReference;
277
312
  agentThread: AgentThreadReference;
278
313
  };
279
314
  }
@@ -290,7 +325,7 @@ interface CreateAgentChatOptions {
290
325
  /** History depth forwarded to `agents:agentMessages`. */
291
326
  limit?: number;
292
327
  /**
293
- * Called when the live history or thread subscription reports an error (a
328
+ * Called when the live history, thread, or grants subscription reports an error (a
294
329
  * session expiry, an RLS denial). Without it — and without reading `error` —
295
330
  * such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
296
331
  */
@@ -313,29 +348,47 @@ interface CreateAgentChatOptions {
313
348
  threadKey: MaybeAccessor<string>;
314
349
  }
315
350
  interface CreateAgentChatResult {
351
+ /** The tools approved for the rest of this thread, live. Empty until the grants subscription answers. */
352
+ approvalGrants: Accessor<ReadonlyArray<AgentApprovalGrant>>;
316
353
  /** Approve a paused human-in-the-loop tool call (optionally with a note). */
317
354
  approve: (toolCallId: string, note?: string) => Promise<void>;
355
+ /**
356
+ * Approve a paused tool call and grant that tool for the rest of the thread, so
357
+ * later calls to it run without pausing. Undo with {@link CreateAgentChatResult.revokeGrant}.
358
+ */
359
+ approveForThread: (toolCallId: string, note?: string) => Promise<void>;
318
360
  /**
319
361
  * Terminate the in-flight run and mark its thread `"cancelled"`. Resolves as a
320
362
  * no-op when no `cancel` mutation was supplied or no run is in flight.
321
363
  */
322
364
  cancel: () => Promise<void>;
323
- /** The history or thread subscription's last error, or `undefined`. */
365
+ /** Refuse a paused `requestSecretTool` call: the run resumes with a "declined" result. */
366
+ declineSecret: (toolCallId: string) => Promise<void>;
367
+ /** The history, thread, or grants subscription's last error, or `undefined`. */
324
368
  error: Accessor<Error | undefined>;
325
369
  /** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
326
370
  messages: Accessor<ReadonlyArray<AgentChatMessage>>;
327
371
  /** Reject a paused human-in-the-loop tool call (optionally with a reason). */
328
372
  reject: (toolCallId: string, note?: string) => Promise<void>;
373
+ /** Remove a thread-scoped approval grant so the tool's gate applies again to later calls. */
374
+ revokeGrant: (toolName: string) => Promise<void>;
329
375
  /** Start (or continue) a run with a user message; extra args merge over `sendArgs`. Appends an optimistic user turn. */
330
376
  send: (input: string, args?: Record<string, unknown>) => Promise<void>;
331
377
  /** The live thread status, or `undefined` before the thread exists. */
332
378
  status: Accessor<AgentThreadStatus | undefined>;
333
379
  /** The in-flight turn's streamed text — live-only, empty once the turn persists to `messages`. */
334
380
  streamingText: Accessor<string>;
381
+ /**
382
+ * Give a paused `requestSecretTool` call its value. Always sent online-only: the
383
+ * value is never queued, persisted or replayed, and the call rejects with
384
+ * `OFFLINE_NOT_QUEUED` while the connection is down. The primitive keeps no copy;
385
+ * a failure rethrows the original error.
386
+ */
387
+ supplySecret: (toolCallId: string, secret: string) => Promise<void>;
335
388
  }
336
389
  /**
337
390
  * A first-class agent chat surface: live durable history + in-flight token
338
- * streaming + the send / approve / reject / cancel writes, keyed by `threadKey` —
391
+ * streaming + the send / approve / reject / secret / cancel writes, keyed by `threadKey` —
339
392
  * the Solid counterpart to React's `useAgentChat`, re-expressed with signals.
340
393
  *
341
394
  * It composes the existing primitives rather than adding transport:
@@ -429,7 +482,7 @@ interface CreateAgentToolEventsOptions {
429
482
  * Optional live event stream — the same app stream function `createAgentChat`
430
483
  * uses. When supplied, ephemeral `ctx.reportProgress(...)` events for the
431
484
  * thread are surfaced as `{ type: "progress" }` entries; when omitted only the
432
- * durable lifecycle (call / result / awaiting-approval) is returned.
485
+ * durable lifecycle (call / result / awaiting-approval / awaiting-secret) is returned.
433
486
  */
434
487
  stream?: AgentLiveStreamReference;
435
488
  /** The thread whose tool activity to observe — a plain value or accessor (an accessor re-subscribes on change). */
@@ -437,7 +490,7 @@ interface CreateAgentToolEventsOptions {
437
490
  }
438
491
  /**
439
492
  * A single tool-lifecycle event for a thread. The durable arms
440
- * (`call`/`result`/`awaiting-approval`) are derived from `agents:agentMessages`
493
+ * (`call`/`result`/`awaiting-approval`/`awaiting-secret`) are derived from `agents:agentMessages`
441
494
  * and carry the persisted `seq`; the ephemeral `progress` arm comes live off the
442
495
  * stream and has no `seq`. Discriminate on `type`.
443
496
  */
@@ -463,6 +516,11 @@ type AgentToolEvent = {
463
516
  toolCallId?: string;
464
517
  toolName?: string;
465
518
  type: "awaiting-approval";
519
+ } | {
520
+ seq: number;
521
+ toolCallId?: string;
522
+ toolName?: string;
523
+ type: "awaiting-secret";
466
524
  };
467
525
  interface CreateAgentToolEventsResult {
468
526
  /**
@@ -643,7 +701,7 @@ interface MutationHandle<F extends FunctionReference> {
643
701
  /** The latest invocation's error, or `undefined`. */
644
702
  error: Accessor<Error | undefined>;
645
703
  /** Invoke the mutation. Resolves with the server result; rejects on failure. */
646
- mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
704
+ mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
647
705
  /** `true` while any invocation from this handle is in flight (ref-counted, so overlapping calls compose). */
648
706
  pending: Accessor<boolean>;
649
707
  /** Clear `data`/`error` back to idle. */
@@ -655,7 +713,7 @@ interface MutationHandle<F extends FunctionReference> {
655
713
  * in tests without constructing a full `LunoraClient`.
656
714
  */
657
715
  interface MutationClient<F extends FunctionReference> {
658
- mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
716
+ mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
659
717
  }
660
718
  /**
661
719
  * Build a mutation handle bound to an explicit client. Internal seam used by the
@@ -1213,7 +1271,7 @@ interface LunoraProviderProps {
1213
1271
  * itself is resolved per-major by {@link providerOf}.
1214
1272
  */
1215
1273
  declare const LunoraProvider: (props: LunoraProviderProps) => SolidElement;
1216
- export { type ActionClient, type ActionHandle, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type CreateAgentApi, type CreateAgentChatApi, type CreateAgentChatOptions, type CreateAgentChatResult, type CreateAgentOptions, type CreateAgentResult, type CreateAgentStateApi, type CreateAgentStateOptions, type CreateAgentStateResult, type CreateAgentToolEventsApi, type CreateAgentToolEventsOptions, type CreateAgentToolEventsResult, type CreateInfiniteQueryOptions, type CreateInfiniteQueryResult, type CreateLiveTopicResult, type CreatePaginatedQueryOptions, type CreatePaginatedQueryResult, type CreatePresenceOptions, type CreatePresenceResult, type CreateQueryOptions, type CreateRateLimitOptions, type CreateRateLimitResult, type CreateStreamOptions, type CreateStreamResult, type CreateStreamStatus, type CreateSubscriptionResult, type CreateVoiceAgentOptions, type CreateVoiceAgentResult, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraContext, LunoraProvider,
1274
+ export { type ActionClient, type ActionHandle, type AgentApprovalGrant, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type CreateAgentApi, type CreateAgentChatApi, type CreateAgentChatOptions, type CreateAgentChatResult, type CreateAgentOptions, type CreateAgentResult, type CreateAgentStateApi, type CreateAgentStateOptions, type CreateAgentStateResult, type CreateAgentToolEventsApi, type CreateAgentToolEventsOptions, type CreateAgentToolEventsResult, type CreateInfiniteQueryOptions, type CreateInfiniteQueryResult, type CreateLiveTopicResult, type CreatePaginatedQueryOptions, type CreatePaginatedQueryResult, type CreatePresenceOptions, type CreatePresenceResult, type CreateQueryOptions, type CreateRateLimitOptions, type CreateRateLimitResult, type CreateStreamOptions, type CreateStreamResult, type CreateStreamStatus, type CreateSubscriptionResult, type CreateVoiceAgentOptions, type CreateVoiceAgentResult, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraContext, LunoraProvider,
1217
1275
  /**
1218
1276
  * SolidJS adapter for Lunora.
1219
1277
  *
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{LunoraContext as r,useLunora as o}from"./packem_shared/LunoraContext-BWsj_3CK.mjs";import{createAction as c,createActionForClient as n}from"./packem_shared/createAction-BZkayM2R.mjs";import{createAgent as m}from"./packem_shared/createAgent-CWckPY7u.mjs";import{createAgentChat as x}from"./packem_shared/createAgentChat-jPhnwbdQ.mjs";import{createAgentState as u}from"./packem_shared/createAgentState-BPo1e_ih.mjs";import{createAgentToolEvents as A}from"./packem_shared/createAgentToolEvents-WUQRSY8o.mjs";import{AuthLoading as l,Authenticated as s,Unauthenticated as h,createAuth as L}from"./packem_shared/AuthLoading-DjUnIaP5.mjs";import{default as y}from"./packem_shared/createConnectionStatus-D8bC05Jn.mjs";import{createFlag as P,createFlags as S}from"./packem_shared/createFlag-BwBkDAcT.mjs";import{createLiveTopic as M}from"./packem_shared/createLiveTopic-CgkjI8l8.mjs";import{createMutation as T,createMutationForClient as b}from"./packem_shared/createMutation-DM2mXpq3.mjs";import{createMutator as I}from"./packem_shared/createMutator-q9cMjGKv.mjs";import{createInfiniteQuery as U,createPaginatedQuery as V}from"./packem_shared/createInfiniteQuery-CwGPFeuc.mjs";import{createPresence as k}from"./packem_shared/createPresence-DkTotieP.mjs";import{createQuery as w}from"./packem_shared/createQuery-oNQqVGjE.mjs";import{createRateLimit as B}from"./packem_shared/createRateLimit-CIVWrD5H.mjs";import{createStream as G}from"./packem_shared/createStream-CCAOb9q1.mjs";import{createSubscription as J}from"./packem_shared/createSubscription-CF_00S2O.mjs";import{createVoiceAgent as N}from"./packem_shared/createVoiceAgent-CEuW4ux5.mjs";import{default as W}from"./packem_shared/hydratePreloaded-DCi296oW.mjs";import{LunoraProvider as Y}from"./packem_shared/LunoraProvider-DMhpuxvx.mjs";export{l as AuthLoading,s as Authenticated,r as LunoraContext,Y as LunoraProvider,h as Unauthenticated,c as createAction,n as createActionForClient,m as createAgent,x as createAgentChat,u as createAgentState,A as createAgentToolEvents,L as createAuth,y as createConnectionStatus,P as createFlag,S as createFlags,U as createInfiniteQuery,M as createLiveTopic,T as createMutation,b as createMutationForClient,I as createMutator,V as createPaginatedQuery,k as createPresence,w as createQuery,B as createRateLimit,G as createStream,J as createSubscription,N as createVoiceAgent,W as hydratePreloaded,o as useLunora};
1
+ import{LunoraContext as r,useLunora as o}from"./packem_shared/LunoraContext-BWsj_3CK.mjs";import{createAction as c,createActionForClient as n}from"./packem_shared/createAction-BZkayM2R.mjs";import{createAgent as m}from"./packem_shared/createAgent-CWckPY7u.mjs";import{createAgentChat as x}from"./packem_shared/createAgentChat-CS3PI19y.mjs";import{createAgentState as u}from"./packem_shared/createAgentState-BPo1e_ih.mjs";import{createAgentToolEvents as A}from"./packem_shared/createAgentToolEvents-Sjkq8qXp.mjs";import{AuthLoading as l,Authenticated as s,Unauthenticated as h,createAuth as L}from"./packem_shared/AuthLoading-DjUnIaP5.mjs";import{default as y}from"./packem_shared/createConnectionStatus-D8bC05Jn.mjs";import{createFlag as P,createFlags as S}from"./packem_shared/createFlag-BwBkDAcT.mjs";import{createLiveTopic as M}from"./packem_shared/createLiveTopic-CgkjI8l8.mjs";import{createMutation as T,createMutationForClient as b}from"./packem_shared/createMutation-DM2mXpq3.mjs";import{createMutator as I}from"./packem_shared/createMutator-q9cMjGKv.mjs";import{createInfiniteQuery as U,createPaginatedQuery as V}from"./packem_shared/createInfiniteQuery-CwGPFeuc.mjs";import{createPresence as k}from"./packem_shared/createPresence-DkTotieP.mjs";import{createQuery as w}from"./packem_shared/createQuery-oNQqVGjE.mjs";import{createRateLimit as B}from"./packem_shared/createRateLimit-CIVWrD5H.mjs";import{createStream as G}from"./packem_shared/createStream-CCAOb9q1.mjs";import{createSubscription as J}from"./packem_shared/createSubscription-CF_00S2O.mjs";import{createVoiceAgent as N}from"./packem_shared/createVoiceAgent-D42ylvG0.mjs";import{default as W}from"./packem_shared/hydratePreloaded-DCi296oW.mjs";import{LunoraProvider as Y}from"./packem_shared/LunoraProvider-DMhpuxvx.mjs";export{l as AuthLoading,s as Authenticated,r as LunoraContext,Y as LunoraProvider,h as Unauthenticated,c as createAction,n as createActionForClient,m as createAgent,x as createAgentChat,u as createAgentState,A as createAgentToolEvents,L as createAuth,y as createConnectionStatus,P as createFlag,S as createFlags,U as createInfiniteQuery,M as createLiveTopic,T as createMutation,b as createMutationForClient,I as createMutator,V as createPaginatedQuery,k as createPresence,w as createQuery,B as createRateLimit,G as createStream,J as createSubscription,N as createVoiceAgent,W as hydratePreloaded,o as useLunora};
@@ -0,0 +1 @@
1
+ import{reconcileOptimistic as M,maxSeq as A}from"@lunora/client";import{createMemo as c,createSignal as J}from"solid-js";import{resolveMaybe as a,NO_MUTATION_REF as L}from"./createAgent-CWckPY7u.mjs";import{createMutation as i}from"./createMutation-DM2mXpq3.mjs";import{createStream as Q}from"./createStream-CCAOb9q1.mjs";import{createSubscription as g}from"./createSubscription-CF_00S2O.mjs";import{t as V}from"./solid-compat-ByG5HD_F.mjs";const W={__lunoraRef:""},X=[],mt=E=>{const{api:o,cancel:h,limit:v,onError:l,send:w,sendArgs:R,stream:f,threadKey:n}=E,{data:T,error:_}=g(o.agents.agentMessages,()=>{const t=a(n);return v===void 0?{key:t}:{key:t,limit:v}},{onError:l}),{data:K,error:b}=g(o.agents.agentThread,()=>({key:a(n)}),{onError:l}),{data:x,error:I}=g(o.agents.agentApprovalGrants,()=>({key:a(n)}),{onError:l}),G=c(()=>_()??b()??I()),O=f===void 0?"skip":()=>({key:a(n)}),{chunks:D}=Q(f??W,O),j=i(w),q=i(h??L),F=i(o.agents.agentResolveApproval),N=i(o.agents.agentRevokeApprovalGrant),C=i(o.agents.agentSupplySecret),P=i(o.agents.agentDeclineSecret),[S,u]=J([]);let k=0;V(()=>a(n),()=>{S().length>0&&u([])});const m=c(()=>K()),U=c(()=>m()?.status),d=c(()=>T()??[]),Y=c(()=>{const t=d(),e=M(S(),t);if(e.length===0)return t;const r=A(t);return[...t,...e.map((s,p)=>({content:s.content,optimistic:!0,role:"user",seq:r+1+p}))]}),$=c(()=>{const t=a(n),e=d().filter(r=>r.role==="assistant").length;return D().filter(r=>r.kind!=="progress"&&r.threadKey===t&&r.turn>=e).map(r=>r.text).join("")}),z=async(t,e)=>{const r=k;k+=1;const s=A(d());u(p=>[...M(p,d()),{content:t,id:r,maxDurableSeqAtSend:s}]);try{await j.mutate({input:t,threadKey:a(n),...R,...e})}catch(p){throw u(B=>B.filter(H=>H.id!==r)),p}},y=async(t,e,r)=>{const s=m()?.instanceId;if(s===void 0)throw new Error(`createAgentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await F.mutate({decision:t,instanceId:s,threadKey:a(n),toolCallId:e,...r===void 0?{}:{note:r}})};return{approvalGrants:()=>x()??X,approve:async(t,e)=>y("approve",t,e),approveForThread:async(t,e)=>y("approve_for_thread",t,e),cancel:async()=>{const t=m()?.instanceId;h===void 0||t===void 0||await q.mutate({instanceId:t,threadKey:a(n)})},declineSecret:async t=>{await P.mutate({threadKey:a(n),toolCallId:t})},error:G,messages:Y,reject:async(t,e)=>y("reject",t,e),revokeGrant:async t=>{await N.mutate({threadKey:a(n),toolName:t})},send:z,status:U,streamingText:$,supplySecret:async(t,e)=>{await C.mutate({secret:e,threadKey:a(n),toolCallId:t},{onlineOnly:!0})}}};export{mt as createAgentChat};
@@ -0,0 +1 @@
1
+ import{createMemo as v}from"solid-js";import{resolveMaybe as a}from"./createAgent-CWckPY7u.mjs";import{createStream as f}from"./createStream-CCAOb9q1.mjs";import{createSubscription as E}from"./createSubscription-CF_00S2O.mjs";const y={__lunoraRef:""},C=[],I={awaiting_approval:"awaiting-approval",awaiting_secret:"awaiting-secret"},N=t=>{const o=t.status===void 0?void 0:I[t.status];if(o!==void 0)return{seq:t.seq,type:o,...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolName===void 0?{}:{toolName:t.toolName}}},_=t=>{if(t.role==="assistant"&&t.toolCalls)return t.toolCalls.map(r=>({input:r.input,seq:t.seq,toolCallId:r.id,toolName:r.name,type:"call"}));if(t.role!=="tool")return;const o=N(t);return o!==void 0?[o]:[{output:t.content,seq:t.seq,type:"result",...t.status==="approved"||t.status==="rejected"?{status:t.status}:{},...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolName===void 0?{}:{toolName:t.toolName}}]},b=t=>{const{api:o,limit:r,stream:i,threadKey:l}=t,u=()=>{const n=a(l);return r===void 0?{key:n}:{key:n,limit:r}},{data:s}=E(o.agents.agentMessages,u),c=i===void 0?"skip":()=>({key:a(l)}),{chunks:p}=f(i??y,c);return{events:v(()=>{const n=a(l),d=(s()??C).flatMap(e=>_(e)??[]);for(const e of p())e.kind==="progress"&&e.threadKey===n&&d.push({data:e.data,toolCallId:e.toolCallId,type:"progress"});return d})}};export{b as createAgentToolEvents};
@@ -1 +1 @@
1
- import{createSignal as y,onCleanup as J}from"solid-js";import{useLunora as G}from"./LunoraContext-BWsj_3CK.mjs";import{resolveMaybe as X}from"./createAgent-CWckPY7u.mjs";const D="/_lunora/ws",j="/_lunora/voice/",z=4001,F=e=>e.startsWith("https://")?`wss://${e.slice(8)}`:e.startsWith("http://")?`ws://${e.slice(7)}`:e,Q=e=>{const r=e.startsWith("agents:")?e.slice(7):e;return r.endsWith("Voice")?r.slice(0,-5):r},Y=(e,r)=>{if(r===void 0||r==="")return F(e);if(r.endsWith(D))return r.slice(0,-D.length);try{return new URL(r).origin}catch{return F(e)}},Z=e=>{const r=Y(e.httpUrl,e.wsUrl),s=r.endsWith("/")?r.slice(0,-1):r,i=new URLSearchParams({threadKey:e.threadKey});return`${s}${j}${encodeURIComponent(e.agent)}?${i.toString()}`},ee=(e,r)=>{if(r?.code===z)return new Error(`${e}: authentication token expired — refresh the credential and start a new call`)},te=(e,r,s)=>{const i=e.currentIdentity();return e.onAuthTokenChange(()=>{e.currentIdentity()!==i&&s(new Error(`${r}: the signed-in identity changed during the call — the session was ended; start a new call`))})},ne=16e3,re=e=>{if(e.length===0)return 0;let r=0;for(const s of e)r+=s*s;return Math.sqrt(r/e.length)},oe=(e,r)=>{const s=r/ne,i=s>1?Math.floor(e.length/s):e.length,f=new ArrayBuffer(i*2),l=new DataView(f);for(let u=0;u<i;u+=1){const k=e[Math.floor(u*s)]??0,g=Math.max(-1,Math.min(1,k));l.setInt16(u*2,g<0?g*32768:g*32767,!0)}return new Uint8Array(f)},se=async e=>{const r=globalThis,s=r.navigator?.mediaDevices?.getUserMedia.bind(r.navigator.mediaDevices),i=r.AudioContext??r.webkitAudioContext;if(!s||!i)throw new Error("createVoiceAgent: microphone capture requires getUserMedia + AudioContext (no browser audio available)");const f=await s({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),l=new i,u=l.createMediaStreamSource(f),k=l.createScriptProcessor(4096,1,1);let g=!1,w=!1,c=0,p=0;return k.onaudioprocess=o=>{const h=o.inputBuffer.getChannelData(0),m=g?0:re(h);if(e.onLevel(m),g)return;if(e.onAudio(oe(h,l.sampleRate)),e.isTurnActive()){p=m>=e.interruptThreshold?p+1:0,p>=e.interruptChunks&&(p=0,e.onInterrupt());return}p=0;const b=h.length/l.sampleRate*1e3;if(m>=e.silenceThreshold){w=!0,c=0;return}w&&(c+=b,c>=e.silenceDurationMs&&(w=!1,c=0,e.onSilence()))},u.connect(k),k.connect(l.destination),{setMuted:o=>{g=o},stop:()=>{k.disconnect(),u.disconnect();for(const o of f.getTracks())o.stop();l.close()}}},ae=()=>{const e=globalThis,r=e.AudioContext??e.webkitAudioContext;if(!r)throw new Error("createVoiceAgent: audio playback requires AudioContext (no browser audio available)");const s=new r,i=new Set;let f=0,l=Promise.resolve(),u=0;const k=async(c,p)=>{if(p!==u)return;let o;try{o=await s.decodeAudioData(c.buffer)}catch{return}if(p!==u)return;const h=s.createBufferSource();h.buffer=o,h.connect(s.destination);const m=Math.max(s.currentTime,f);h.start(m),f=m+o.duration,i.add(h),h.onended=()=>{i.delete(h)}},g=c=>{const p=Uint8Array.from(c),o=u;l=l.then(()=>k(p,o))},w=()=>{u+=1;for(const c of i)try{c.stop()}catch{}i.clear(),f=s.currentTime};return{enqueue:g,interrupt:w,stop:()=>{w(),s.close()}}},V=1,ie=.01,ce=1200,ue=.15,le=3,fe=e=>{const{createMicrophone:r=se,createSpeaker:s=ae,createSocket:i,interruptChunks:f=le,interruptThreshold:l=ue,silenceDurationMs:u=ce,silenceThreshold:k=ie,threadKey:g,voice:w}=e,c=G(),[p,o]=y("idle"),[h,m]=y(!1),[b,M]=y(""),[W,v]=y(""),[N,x]=y(0),[I,U]=y(!1),[O,S]=y(void 0);let a,C=!1;const _=t=>{const n=a?.socket;return n?.readyState===V?(n.send(JSON.stringify(t)),!0):!1},T=()=>{const t=a;if(a=void 0,t){t.unwatchIdentity?.(),t.microphone?.stop(),t.speaker?.stop(),t.socket.onmessage=null,t.socket.onerror=null,t.socket.onclose=null;try{t.socket.close()}catch{}}C=!1,m(!1),o("idle"),x(0)},P=T,H=t=>{const n=a;switch(t.type){case"assistant_delta":{n&&(n.speaking=!0),o("speaking"),v(R=>R+t.text);break}case"assistant_done":{n&&(n.awaitingTurn=!1,n.speaking=!1),v(t.text),o("listening");break}case"error":{n&&(n.awaitingTurn=!1,n.speaking=!1),S(new Error(t.message)),o("listening");break}case"interrupted":{n&&(n.awaitingTurn=!1,n.speaking=!1,n.suppressAudio=!1),n?.speaker?.interrupt(),o("listening");break}case"ready":{n&&(n.audioFormat=t.audioFormat,n.suppressAudio=!1),m(!0),o("listening");break}case"user_transcript":{n&&(n.suppressAudio=!1),M(t.text),v(""),o("thinking");break}}},$=t=>{const n=a;!n||n.suppressAudio||(n.speaker??=s({audioFormat:n.audioFormat}),n.speaking=!0,o("speaking"),n.speaker.enqueue(t))},B=async()=>{if(a||C)return;C=!0,S(void 0),M(""),v("");let t;try{const n=Z({agent:Q(w.__lunoraRef),httpUrl:c.url,threadKey:X(g),wsUrl:c.wsUrl}),A=(i??(d=>{const E=c.getWebSocketImpl();if(!E)throw new Error("createVoiceAgent: no WebSocket implementation available (pass createSocket explicitly)");return new E(d)}))(n);A.binaryType="arraybuffer",t={audioFormat:"mp3",microphone:void 0,socket:A,speaker:void 0,speaking:!1,awaitingTurn:!1,suppressAudio:!1,unwatchIdentity:void 0},a=t,t.unwatchIdentity=te(c,"createVoiceAgent",d=>{a===t&&(S(d),T())}),A.onmessage=d=>{if(typeof d.data=="string"){try{H(JSON.parse(d.data))}catch{}return}$(new Uint8Array(d.data))},A.onerror=()=>{S(new Error("createVoiceAgent: voice socket error"))},A.onclose=d=>{if(a!==t)return;const E=ee("createVoiceAgent",d);E&&S(E),T()};const L=await r({interruptChunks:f,interruptThreshold:l,isTurnActive:()=>(a?.speaking??!1)||(a?.awaitingTurn??!1),onAudio:d=>{A.readyState===V&&A.send(d)},onInterrupt:()=>{_({type:"interrupt"}),a?.speaker?.interrupt(),a&&(a.awaitingTurn=!1,a.speaking=!1,a.suppressAudio=!0),o("listening")},onLevel:d=>{x(d)},onSilence:()=>{_({type:"commit"}),a&&(a.awaitingTurn=!0),o("thinking")},silenceDurationMs:u,silenceThreshold:k});a===t?(t.microphone=L,U(!1),t.speaking||o("listening")):L.stop()}catch(n){a===t&&(S(n instanceof Error?n:new Error(String(n))),T())}finally{C=!1}},K=()=>{const t=!I();return a?.microphone?.setMuted(t),U(t),t},q=t=>{_({text:t,type:"text"})&&(a&&(a.awaitingTurn=!0),o("thinking"))};return J(T),{audioLevel:N,connected:h,endCall:P,error:O,interimTranscript:W,isMuted:I,sendText:q,startCall:B,status:p,toggleMute:K,transcript:b}};export{fe as createVoiceAgent};
1
+ import{createSignal as y,onCleanup as J}from"solid-js";import{useLunora as G}from"./LunoraContext-BWsj_3CK.mjs";import{resolveMaybe as X}from"./createAgent-CWckPY7u.mjs";const D="/_lunora/ws",j="/_lunora/voice/",z=4001,F=e=>e.startsWith("https://")?`wss://${e.slice(8)}`:e.startsWith("http://")?`ws://${e.slice(7)}`:e,Q=e=>{const r=e.startsWith("agents:")?e.slice(7):e;return r.endsWith("Voice")?r.slice(0,-5):r},Y=(e,r)=>{if(r===void 0||r==="")return F(e);if(r.endsWith(D))return r.slice(0,-D.length);try{return new URL(r).origin}catch{return F(e)}},Z=e=>{const r=Y(e.httpUrl,e.wsUrl),s=r.endsWith("/")?r.slice(0,-1):r,i=new URLSearchParams({threadKey:e.threadKey});return`${s}${j}${encodeURIComponent(e.agent)}?${i.toString()}`},ee=(e,r)=>{if(r?.code===z)return new Error(`${e}: authentication token expired — refresh the credential and start a new call`)},te=(e,r,s)=>{const i=e.currentIdentity();return e.onAuthTokenChange(()=>{e.currentIdentity()!==i&&s(new Error(`${r}: the signed-in identity changed during the call — the session was ended; start a new call`))})},ne=16e3,re=e=>{if(e.length===0)return 0;let r=0;for(const s of e)r+=s*s;return Math.sqrt(r/e.length)},oe=(e,r)=>{const s=r/ne,i=s>1?Math.floor(e.length/s):e.length,f=new ArrayBuffer(i*2),l=new DataView(f);for(let u=0;u<i;u+=1){const k=e[Math.floor(u*s)]??0,g=Math.max(-1,Math.min(1,k));l.setInt16(u*2,g<0?g*32768:g*32767,!0)}return new Uint8Array(f)},se=async e=>{const r=globalThis,s=r.navigator?.mediaDevices?.getUserMedia.bind(r.navigator.mediaDevices),i=r.AudioContext??r.webkitAudioContext;if(!s||!i)throw new Error("createVoiceAgent: microphone capture requires getUserMedia + AudioContext (no browser audio available)");const f=await s({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),l=new i,u=l.createMediaStreamSource(f),k=l.createScriptProcessor(4096,1,1);let g=!1,w=!1,c=0,p=0;return k.onaudioprocess=o=>{const h=o.inputBuffer.getChannelData(0),m=g?0:re(h);if(e.onLevel(m),g)return;if(e.onAudio(oe(h,l.sampleRate)),e.isTurnActive()){p=m>=e.interruptThreshold?p+1:0,p>=e.interruptChunks&&(p=0,e.onInterrupt());return}p=0;const b=h.length/l.sampleRate*1e3;if(m>=e.silenceThreshold){w=!0,c=0;return}w&&(c+=b,c>=e.silenceDurationMs&&(w=!1,c=0,e.onSilence()))},u.connect(k),k.connect(l.destination),{setMuted:o=>{g=o},stop:()=>{k.disconnect(),u.disconnect();for(const o of f.getTracks())o.stop();l.close()}}},ae=()=>{const e=globalThis,r=e.AudioContext??e.webkitAudioContext;if(!r)throw new Error("createVoiceAgent: audio playback requires AudioContext (no browser audio available)");const s=new r,i=new Set;let f=0,l=Promise.resolve(),u=0;const k=async(c,p)=>{if(p!==u)return;let o;try{o=await s.decodeAudioData(c.buffer)}catch{return}if(p!==u)return;const h=s.createBufferSource();h.buffer=o,h.connect(s.destination);const m=Math.max(s.currentTime,f);h.start(m),f=m+o.duration,i.add(h),h.onended=()=>{i.delete(h)}},g=c=>{const p=Uint8Array.from(c),o=u;l=l.then(()=>k(p,o))},w=()=>{u+=1;for(const c of i)try{c.stop()}catch{}i.clear(),f=s.currentTime};return{enqueue:g,interrupt:w,stop:()=>{w(),s.close()}}},V=1,ie=.01,ce=1200,ue=.15,le=3,fe=e=>{const{createMicrophone:r=se,createSpeaker:s=ae,createSocket:i,interruptChunks:f=le,interruptThreshold:l=ue,silenceDurationMs:u=ce,silenceThreshold:k=ie,threadKey:g,voice:w}=e,c=G(),[p,o]=y("idle"),[h,m]=y(!1),[b,M]=y(""),[W,T]=y(""),[N,x]=y(0),[I,U]=y(!1),[O,S]=y(void 0);let a,C=!1;const _=n=>{const t=a?.socket;return t?.readyState===V?(t.send(JSON.stringify(n)),!0):!1},E=()=>{const n=a;if(a=void 0,n){n.unwatchIdentity?.(),n.microphone?.stop(),n.speaker?.stop(),n.socket.onmessage=null,n.socket.onerror=null,n.socket.onclose=null;try{n.socket.close()}catch{}}C=!1,m(!1),o("idle"),x(0)},P=E,H=n=>{const t=a;switch(n.type){case"assistant_delta":{t&&(t.speaking=!0),o("speaking"),T(R=>R+n.text);break}case"assistant_discarded":{t&&(t.suppressAudio=!0),t?.speaker?.interrupt(),T("");break}case"assistant_done":{t&&(t.awaitingTurn=!1,t.speaking=!1),T(n.text),o("listening");break}case"error":{t&&(t.awaitingTurn=!1,t.speaking=!1),S(new Error(n.message)),o("listening");break}case"interrupted":{t&&(t.awaitingTurn=!1,t.speaking=!1,t.suppressAudio=!1),t?.speaker?.interrupt(),o("listening");break}case"ready":{t&&(t.audioFormat=n.audioFormat,t.suppressAudio=!1),m(!0),o("listening");break}case"user_transcript":{t&&(t.suppressAudio=!1),M(n.text),T(""),o("thinking");break}}},$=n=>{const t=a;!t||t.suppressAudio||(t.speaker??=s({audioFormat:t.audioFormat}),t.speaking=!0,o("speaking"),t.speaker.enqueue(n))},B=async()=>{if(a||C)return;C=!0,S(void 0),M(""),T("");let n;try{const t=Z({agent:Q(w.__lunoraRef),httpUrl:c.url,threadKey:X(g),wsUrl:c.wsUrl}),A=(i??(d=>{const v=c.getWebSocketImpl();if(!v)throw new Error("createVoiceAgent: no WebSocket implementation available (pass createSocket explicitly)");return new v(d)}))(t);A.binaryType="arraybuffer",n={audioFormat:"mp3",microphone:void 0,socket:A,speaker:void 0,speaking:!1,awaitingTurn:!1,suppressAudio:!1,unwatchIdentity:void 0},a=n,n.unwatchIdentity=te(c,"createVoiceAgent",d=>{a===n&&(S(d),E())}),A.onmessage=d=>{if(typeof d.data=="string"){try{H(JSON.parse(d.data))}catch{}return}$(new Uint8Array(d.data))},A.onerror=()=>{S(new Error("createVoiceAgent: voice socket error"))},A.onclose=d=>{if(a!==n)return;const v=ee("createVoiceAgent",d);v&&S(v),E()};const L=await r({interruptChunks:f,interruptThreshold:l,isTurnActive:()=>(a?.speaking??!1)||(a?.awaitingTurn??!1),onAudio:d=>{A.readyState===V&&A.send(d)},onInterrupt:()=>{_({type:"interrupt"}),a?.speaker?.interrupt(),a&&(a.awaitingTurn=!1,a.speaking=!1,a.suppressAudio=!0),o("listening")},onLevel:d=>{x(d)},onSilence:()=>{_({type:"commit"}),a&&(a.awaitingTurn=!0),o("thinking")},silenceDurationMs:u,silenceThreshold:k});a===n?(n.microphone=L,U(!1),n.speaking||o("listening")):L.stop()}catch(t){a===n&&(S(t instanceof Error?t:new Error(String(t))),E())}finally{C=!1}},K=()=>{const n=!I();return a?.microphone?.setMuted(n),U(n),n},q=n=>{_({text:n,type:"text"})&&(a&&(a.awaitingTurn=!0),o("thinking"))};return J(E),{audioLevel:N,connected:h,endCall:P,error:O,interimTranscript:W,isMuted:I,sendText:q,startCall:B,status:p,toggleMute:K,transcript:b}};export{fe as createVoiceAgent};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/solid",
3
- "version": "1.0.0-alpha.241",
3
+ "version": "1.0.0-alpha.243",
4
4
  "description": "SolidJS adapter for Lunora — live queries, optimistic mutations, and reactive loaders",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -54,9 +54,9 @@
54
54
  "access": "public"
55
55
  },
56
56
  "dependencies": {
57
- "@lunora/client": "1.0.0-alpha.232",
57
+ "@lunora/client": "1.0.0-alpha.234",
58
58
  "@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
59
- "@lunora/ratelimit": "1.0.0-alpha.154",
59
+ "@lunora/ratelimit": "1.0.0-alpha.156",
60
60
  "@lunora/wire": "1.0.0-alpha.1",
61
61
  "@visulima/storage-client": "1.0.9"
62
62
  },
@@ -1 +0,0 @@
1
- import{reconcileOptimistic as E,maxSeq as M}from"@lunora/client";import{createMemo as s,createSignal as B}from"solid-js";import{resolveMaybe as o,NO_MUTATION_REF as G}from"./createAgent-CWckPY7u.mjs";import{createMutation as u}from"./createMutation-DM2mXpq3.mjs";import{createStream as H}from"./createStream-CCAOb9q1.mjs";import{createSubscription as k}from"./createSubscription-CF_00S2O.mjs";import{t as J}from"./solid-compat-ByG5HD_F.mjs";const L={__lunoraRef:""},nt=R=>{const{api:m,cancel:l,limit:h,onError:f,send:S,sendArgs:b,stream:g,threadKey:n}=R,{data:w,error:x}=k(m.agents.agentMessages,()=>{const t=o(n);return h===void 0?{key:t}:{key:t,limit:h}},{onError:f}),{data:I,error:_}=k(m.agents.agentThread,()=>({key:o(n)}),{onError:f}),K=s(()=>x()??_()),O=g===void 0?"skip":()=>({key:o(n)}),{chunks:T}=H(g??L,O),j=u(S),q=u(l??G),C=u(m.agents.agentResolveApproval),[y,d]=B([]);let v=0;J(()=>o(n),()=>{y().length>0&&d([])});const p=s(()=>I()),D=s(()=>p()?.status),i=s(()=>w()??[]),N=s(()=>{const t=i(),r=E(y(),t);if(r.length===0)return t;const e=M(t);return[...t,...r.map((a,c)=>({content:a.content,optimistic:!0,role:"user",seq:e+1+c}))]}),F=s(()=>{const t=o(n),r=i().filter(e=>e.role==="assistant").length;return T().filter(e=>e.kind!=="progress"&&e.threadKey===t&&e.turn>=r).map(e=>e.text).join("")}),U=async(t,r)=>{const e=v;v+=1;const a=M(i());d(c=>[...E(c,i()),{content:t,id:e,maxDurableSeqAtSend:a}]);try{await j.mutate({input:t,threadKey:o(n),...b,...r})}catch(c){throw d($=>$.filter(z=>z.id!==e)),c}},A=async(t,r,e)=>{const a=p()?.instanceId;if(a===void 0)throw new Error(`createAgentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await C.mutate({decision:t,instanceId:a,threadKey:o(n),toolCallId:r,...e===void 0?{}:{note:e}})};return{approve:async(t,r)=>A("approve",t,r),cancel:async()=>{const t=p()?.instanceId;l===void 0||t===void 0||await q.mutate({instanceId:t,threadKey:o(n)})},error:K,messages:N,reject:async(t,r)=>A("reject",t,r),send:U,status:D,streamingText:F}};export{nt as createAgentChat};
@@ -1 +0,0 @@
1
- import{createMemo as v}from"solid-js";import{resolveMaybe as n}from"./createAgent-CWckPY7u.mjs";import{createStream as f}from"./createStream-CCAOb9q1.mjs";import{createSubscription as y}from"./createSubscription-CF_00S2O.mjs";const C={__lunoraRef:""},I=[],N=t=>{if(t.role==="assistant"&&t.toolCalls)return t.toolCalls.map(r=>({input:r.input,seq:t.seq,toolCallId:r.id,toolName:r.name,type:"call"}));if(t.role==="tool")return t.status==="awaiting_approval"?[{seq:t.seq,type:"awaiting-approval",...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolName===void 0?{}:{toolName:t.toolName}}]:[{output:t.content,seq:t.seq,type:"result",...t.status==="approved"||t.status==="rejected"?{status:t.status}:{},...t.toolCallId===void 0?{}:{toolCallId:t.toolCallId},...t.toolName===void 0?{}:{toolName:t.toolName}}]},_=t=>{const{api:r,limit:a,stream:i,threadKey:e}=t,u=()=>{const l=n(e);return a===void 0?{key:l}:{key:l,limit:a}},{data:p}=y(r.agents.agentMessages,u),s=i===void 0?"skip":()=>({key:n(e)}),{chunks:c}=f(i??C,s);return{events:v(()=>{const l=n(e),d=(p()??I).flatMap(o=>N(o)??[]);for(const o of c())o.kind==="progress"&&o.threadKey===l&&d.push({data:o.data,toolCallId:o.toolCallId,type:"progress"});return d})}};export{_ as createAgentToolEvents};