@lunora/vue 1.0.0-alpha.273 → 1.0.0-alpha.274

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,5 +1,5 @@
1
1
  import { Component, Ref, InjectionKey, App, MaybeRefOrGetter, ComputedRef, DeepReadonly, ShallowRef } from 'vue';
2
- import { Preloaded, SubscriptionErrorCallback, LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, User, ConnectionStatus, LiveTopicOptions, LiveStreamSubscribeError, LiveTopicRef, MutationCallOptions, MutatorHandle, SubscriptionError } from '@lunora/client';
2
+ import { Preloaded, SubscriptionErrorCallback, LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, User, ConnectionStatus, LiveTopicOptions, LiveStreamSubscribeError, LiveTopicRef, MutationCallOptions, OnlineOnlyOption, MutatorHandle, SubscriptionError } from '@lunora/client';
3
3
  export type { ArgsOf, FunctionReference, LunoraClient, MutationCallOptions, MutatorHandle, MutatorTransaction, OptimisticLocalStore, OptimisticUpdate, Preloaded, ReturnOf, SubscriptionError, SubscriptionErrorCallback, Unsubscribe, User } from '@lunora/client';
4
4
  import { AuthStatus } from '@lunora/client/auth';
5
5
  import { PaginationStatus } from '@lunora/client/pagination';
@@ -262,8 +262,8 @@ interface AgentChatMessage {
262
262
  optimistic?: boolean;
263
263
  role: "assistant" | "system" | "tool" | "user";
264
264
  seq: number;
265
- /** Approval lifecycle marker on a human-in-the-loop tool message. */
266
- status?: "approved" | "awaiting_approval" | "rejected";
265
+ /** Approval or secret-request lifecycle marker on a human-in-the-loop tool message. */
266
+ status?: "approved" | "awaiting_approval" | "awaiting_secret" | "rejected";
267
267
  toolCallId?: string;
268
268
  toolCalls?: ReadonlyArray<{
269
269
  id: string;
@@ -317,7 +317,7 @@ type AgentMessagesReference$1 = FunctionReference<"query", {
317
317
  }, ReadonlyArray<Record<string, unknown>>>;
318
318
  /** The `agents:agentResolveApproval` reference — resolves a human-in-the-loop tool approval. */
319
319
  type AgentApprovalReference = FunctionReference<"mutation", {
320
- decision: "approve" | "reject";
320
+ decision: "approve" | "approve_for_thread" | "reject";
321
321
  instanceId: string;
322
322
  note?: string;
323
323
  threadKey: string;
@@ -325,10 +325,41 @@ type AgentApprovalReference = FunctionReference<"mutation", {
325
325
  }, {
326
326
  resolved: boolean;
327
327
  }>;
328
+ /** The `agents:agentSupplySecret` reference — stores a person's value for a paused `requestSecretTool` call. */
329
+ type AgentSupplySecretReference = FunctionReference<"mutation", {
330
+ secret: string;
331
+ threadKey: string;
332
+ toolCallId: string;
333
+ }, {
334
+ resolved: boolean;
335
+ }>;
336
+ /** The `agents:agentDeclineSecret` reference — refuses a paused `requestSecretTool` call. */
337
+ type AgentDeclineSecretReference = FunctionReference<"mutation", {
338
+ threadKey: string;
339
+ toolCallId: string;
340
+ }, {
341
+ resolved: boolean;
342
+ }>;
328
343
  /** The `agents:agentThread` reference — live thread status + in-flight `instanceId`. */
329
344
  type AgentThreadReference = FunctionReference<"query", {
330
345
  key: string;
331
346
  }, Record<string, unknown> | undefined>;
347
+ /** A tool approved for the rest of a thread, as `agents:agentApprovalGrants` lists it. */
348
+ interface AgentApprovalGrant {
349
+ createdAt: number;
350
+ toolName: string;
351
+ }
352
+ /** The `agents:agentApprovalGrants` reference — live thread-scoped approval grants. */
353
+ type AgentApprovalGrantsReference = FunctionReference<"query", {
354
+ key: string;
355
+ }, ReadonlyArray<AgentApprovalGrant>>;
356
+ /** The `agents:agentRevokeApprovalGrant` reference — removes a thread-scoped approval grant. */
357
+ type AgentRevokeApprovalGrantReference = FunctionReference<"mutation", {
358
+ threadKey: string;
359
+ toolName: string;
360
+ }, {
361
+ revoked: boolean;
362
+ }>;
332
363
  /**
333
364
  * An app stream reference that tees the agent's in-flight live events, keyed by
334
365
  * thread. Carries token deltas and — since `ctx.reportProgress` rides the same
@@ -344,8 +375,12 @@ type AgentTokenStreamReference = FunctionReference<"stream", {
344
375
  */
345
376
  interface UseAgentChatApi {
346
377
  agents: {
378
+ agentApprovalGrants: AgentApprovalGrantsReference;
379
+ agentDeclineSecret: AgentDeclineSecretReference;
347
380
  agentMessages: AgentMessagesReference$1;
348
381
  agentResolveApproval: AgentApprovalReference;
382
+ agentRevokeApprovalGrant: AgentRevokeApprovalGrantReference;
383
+ agentSupplySecret: AgentSupplySecretReference;
349
384
  agentThread: AgentThreadReference;
350
385
  };
351
386
  }
@@ -362,7 +397,7 @@ interface UseAgentChatOptions {
362
397
  /** History depth forwarded to `agents:agentMessages`. */
363
398
  limit?: number;
364
399
  /**
365
- * Called when the live history or thread subscription reports an error (a
400
+ * Called when the live history, thread, or grants subscription reports an error (a
366
401
  * session expiry, an RLS denial). Without it — and without reading `error` —
367
402
  * such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
368
403
  */
@@ -385,29 +420,47 @@ interface UseAgentChatOptions {
385
420
  threadKey: MaybeRefOrGetter<string>;
386
421
  }
387
422
  interface UseAgentChatResult {
423
+ /** The tools approved for the rest of this thread, live. Empty until the grants subscription answers. */
424
+ approvalGrants: ComputedRef<ReadonlyArray<AgentApprovalGrant>>;
388
425
  /** Approve a paused human-in-the-loop tool call (optionally with a note). */
389
426
  approve: (toolCallId: string, note?: string) => Promise<void>;
427
+ /**
428
+ * Approve a paused tool call and grant that tool for the rest of the thread, so
429
+ * later calls to it run without pausing. Undo with {@link UseAgentChatResult.revokeGrant}.
430
+ */
431
+ approveForThread: (toolCallId: string, note?: string) => Promise<void>;
390
432
  /**
391
433
  * Terminate the in-flight run and mark its thread `"cancelled"`. Resolves as a
392
434
  * no-op when no `cancel` mutation was supplied or no run is in flight.
393
435
  */
394
436
  cancel: () => Promise<void>;
395
- /** The history or thread subscription's last error, or `undefined`. */
437
+ /** Refuse a paused `requestSecretTool` call: the run resumes with a "declined" result. */
438
+ declineSecret: (toolCallId: string) => Promise<void>;
439
+ /** The history, thread, or grants subscription's last error, or `undefined`. */
396
440
  error: ComputedRef<Error | undefined>;
397
441
  /** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
398
442
  messages: ComputedRef<ReadonlyArray<AgentChatMessage>>;
399
443
  /** Reject a paused human-in-the-loop tool call (optionally with a reason). */
400
444
  reject: (toolCallId: string, note?: string) => Promise<void>;
445
+ /** Remove a thread-scoped approval grant so the tool's gate applies again to later calls. */
446
+ revokeGrant: (toolName: string) => Promise<void>;
401
447
  /** Start (or continue) a run with a user message; extra args merge over `sendArgs`. Appends an optimistic user turn. */
402
448
  send: (input: string, args?: Record<string, unknown>) => Promise<void>;
403
449
  /** The live thread status, or `undefined` before the thread exists. */
404
450
  status: ComputedRef<AgentThreadStatus | undefined>;
405
451
  /** The in-flight turn's streamed text — live-only, empty once the turn persists to `messages`. */
406
452
  streamingText: ComputedRef<string>;
453
+ /**
454
+ * Give a paused `requestSecretTool` call its value. Always sent online-only: the
455
+ * value is never queued, persisted or replayed, and the call rejects with
456
+ * `OFFLINE_NOT_QUEUED` while the connection is down. The composable keeps no copy;
457
+ * a failure rethrows the original error.
458
+ */
459
+ supplySecret: (toolCallId: string, secret: string) => Promise<void>;
407
460
  }
408
461
  /**
409
462
  * A first-class agent chat surface: live durable history + in-flight token
410
- * streaming + the send / approve / reject / cancel writes, keyed by `threadKey` —
463
+ * streaming + the send / approve / reject / secret / cancel writes, keyed by `threadKey` —
411
464
  * the Vue counterpart to React's `useAgentChat`, re-expressed with refs.
412
465
  *
413
466
  * It composes the existing primitives rather than adding transport:
@@ -503,7 +556,7 @@ interface UseAgentToolEventsOptions {
503
556
  * Optional live event stream — the same app stream function `useAgentChat`
504
557
  * uses. When supplied, ephemeral `ctx.reportProgress(...)` events for the
505
558
  * thread are surfaced as `{ type: "progress" }` entries; when omitted only the
506
- * durable lifecycle (call / result / awaiting-approval) is returned.
559
+ * durable lifecycle (call / result / awaiting-approval / awaiting-secret) is returned.
507
560
  */
508
561
  stream?: AgentLiveStreamReference;
509
562
  /** The thread whose tool activity to observe — may be a plain value, `ref`, or getter (a reactive source re-subscribes). */
@@ -511,7 +564,7 @@ interface UseAgentToolEventsOptions {
511
564
  }
512
565
  /**
513
566
  * A single tool-lifecycle event for a thread. The durable arms
514
- * (`call`/`result`/`awaiting-approval`) are derived from `agents:agentMessages`
567
+ * (`call`/`result`/`awaiting-approval`/`awaiting-secret`) are derived from `agents:agentMessages`
515
568
  * and carry the persisted `seq`; the ephemeral `progress` arm comes live off the
516
569
  * stream and has no `seq`. Discriminate on `type`.
517
570
  */
@@ -537,6 +590,11 @@ type AgentToolEvent = {
537
590
  toolCallId?: string;
538
591
  toolName?: string;
539
592
  type: "awaiting-approval";
593
+ } | {
594
+ seq: number;
595
+ toolCallId?: string;
596
+ toolName?: string;
597
+ type: "awaiting-secret";
540
598
  };
541
599
  interface UseAgentToolEventsResult {
542
600
  /**
@@ -698,7 +756,7 @@ interface MutationHandle<F extends FunctionReference> {
698
756
  /** The latest invocation's error, or `undefined`. */
699
757
  error: Ref<Error | undefined>;
700
758
  /** Invoke the mutation. Resolves with the server value; rejects on failure. */
701
- mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
759
+ mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
702
760
  /** `true` while ANY invocation from this handle is in flight (ref-counted, so overlapping calls compose). */
703
761
  pending: Ref<boolean>;
704
762
  /** Clear the latest `data`/`error` back to idle. */
@@ -1192,7 +1250,7 @@ interface UseVoiceAgentResult {
1192
1250
  * `createSocket`) so the composable is drivable outside a browser.
1193
1251
  */
1194
1252
  declare const useVoiceAgent: (options: UseVoiceAgentOptions) => UseVoiceAgentResult;
1195
- export { type ActionHandle, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type FlagValue, type HeartbeatReference,
1253
+ export { type ActionHandle, type AgentApprovalGrant, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type FlagValue, type HeartbeatReference,
1196
1254
  /**
1197
1255
  * `@lunora/vue` — the Vue adapter for Lunora.
1198
1256
  *
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Component, Ref, InjectionKey, App, MaybeRefOrGetter, ComputedRef, DeepReadonly, ShallowRef } from 'vue';
2
- import { Preloaded, SubscriptionErrorCallback, LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, User, ConnectionStatus, LiveTopicOptions, LiveStreamSubscribeError, LiveTopicRef, MutationCallOptions, MutatorHandle, SubscriptionError } from '@lunora/client';
2
+ import { Preloaded, SubscriptionErrorCallback, LunoraClient, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, User, ConnectionStatus, LiveTopicOptions, LiveStreamSubscribeError, LiveTopicRef, MutationCallOptions, OnlineOnlyOption, MutatorHandle, SubscriptionError } from '@lunora/client';
3
3
  export type { ArgsOf, FunctionReference, LunoraClient, MutationCallOptions, MutatorHandle, MutatorTransaction, OptimisticLocalStore, OptimisticUpdate, Preloaded, ReturnOf, SubscriptionError, SubscriptionErrorCallback, Unsubscribe, User } from '@lunora/client';
4
4
  import { AuthStatus } from '@lunora/client/auth';
5
5
  import { PaginationStatus } from '@lunora/client/pagination';
@@ -262,8 +262,8 @@ interface AgentChatMessage {
262
262
  optimistic?: boolean;
263
263
  role: "assistant" | "system" | "tool" | "user";
264
264
  seq: number;
265
- /** Approval lifecycle marker on a human-in-the-loop tool message. */
266
- status?: "approved" | "awaiting_approval" | "rejected";
265
+ /** Approval or secret-request lifecycle marker on a human-in-the-loop tool message. */
266
+ status?: "approved" | "awaiting_approval" | "awaiting_secret" | "rejected";
267
267
  toolCallId?: string;
268
268
  toolCalls?: ReadonlyArray<{
269
269
  id: string;
@@ -317,7 +317,7 @@ type AgentMessagesReference$1 = FunctionReference<"query", {
317
317
  }, ReadonlyArray<Record<string, unknown>>>;
318
318
  /** The `agents:agentResolveApproval` reference — resolves a human-in-the-loop tool approval. */
319
319
  type AgentApprovalReference = FunctionReference<"mutation", {
320
- decision: "approve" | "reject";
320
+ decision: "approve" | "approve_for_thread" | "reject";
321
321
  instanceId: string;
322
322
  note?: string;
323
323
  threadKey: string;
@@ -325,10 +325,41 @@ type AgentApprovalReference = FunctionReference<"mutation", {
325
325
  }, {
326
326
  resolved: boolean;
327
327
  }>;
328
+ /** The `agents:agentSupplySecret` reference — stores a person's value for a paused `requestSecretTool` call. */
329
+ type AgentSupplySecretReference = FunctionReference<"mutation", {
330
+ secret: string;
331
+ threadKey: string;
332
+ toolCallId: string;
333
+ }, {
334
+ resolved: boolean;
335
+ }>;
336
+ /** The `agents:agentDeclineSecret` reference — refuses a paused `requestSecretTool` call. */
337
+ type AgentDeclineSecretReference = FunctionReference<"mutation", {
338
+ threadKey: string;
339
+ toolCallId: string;
340
+ }, {
341
+ resolved: boolean;
342
+ }>;
328
343
  /** The `agents:agentThread` reference — live thread status + in-flight `instanceId`. */
329
344
  type AgentThreadReference = FunctionReference<"query", {
330
345
  key: string;
331
346
  }, Record<string, unknown> | undefined>;
347
+ /** A tool approved for the rest of a thread, as `agents:agentApprovalGrants` lists it. */
348
+ interface AgentApprovalGrant {
349
+ createdAt: number;
350
+ toolName: string;
351
+ }
352
+ /** The `agents:agentApprovalGrants` reference — live thread-scoped approval grants. */
353
+ type AgentApprovalGrantsReference = FunctionReference<"query", {
354
+ key: string;
355
+ }, ReadonlyArray<AgentApprovalGrant>>;
356
+ /** The `agents:agentRevokeApprovalGrant` reference — removes a thread-scoped approval grant. */
357
+ type AgentRevokeApprovalGrantReference = FunctionReference<"mutation", {
358
+ threadKey: string;
359
+ toolName: string;
360
+ }, {
361
+ revoked: boolean;
362
+ }>;
332
363
  /**
333
364
  * An app stream reference that tees the agent's in-flight live events, keyed by
334
365
  * thread. Carries token deltas and — since `ctx.reportProgress` rides the same
@@ -344,8 +375,12 @@ type AgentTokenStreamReference = FunctionReference<"stream", {
344
375
  */
345
376
  interface UseAgentChatApi {
346
377
  agents: {
378
+ agentApprovalGrants: AgentApprovalGrantsReference;
379
+ agentDeclineSecret: AgentDeclineSecretReference;
347
380
  agentMessages: AgentMessagesReference$1;
348
381
  agentResolveApproval: AgentApprovalReference;
382
+ agentRevokeApprovalGrant: AgentRevokeApprovalGrantReference;
383
+ agentSupplySecret: AgentSupplySecretReference;
349
384
  agentThread: AgentThreadReference;
350
385
  };
351
386
  }
@@ -362,7 +397,7 @@ interface UseAgentChatOptions {
362
397
  /** History depth forwarded to `agents:agentMessages`. */
363
398
  limit?: number;
364
399
  /**
365
- * Called when the live history or thread subscription reports an error (a
400
+ * Called when the live history, thread, or grants subscription reports an error (a
366
401
  * session expiry, an RLS denial). Without it — and without reading `error` —
367
402
  * such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
368
403
  */
@@ -385,29 +420,47 @@ interface UseAgentChatOptions {
385
420
  threadKey: MaybeRefOrGetter<string>;
386
421
  }
387
422
  interface UseAgentChatResult {
423
+ /** The tools approved for the rest of this thread, live. Empty until the grants subscription answers. */
424
+ approvalGrants: ComputedRef<ReadonlyArray<AgentApprovalGrant>>;
388
425
  /** Approve a paused human-in-the-loop tool call (optionally with a note). */
389
426
  approve: (toolCallId: string, note?: string) => Promise<void>;
427
+ /**
428
+ * Approve a paused tool call and grant that tool for the rest of the thread, so
429
+ * later calls to it run without pausing. Undo with {@link UseAgentChatResult.revokeGrant}.
430
+ */
431
+ approveForThread: (toolCallId: string, note?: string) => Promise<void>;
390
432
  /**
391
433
  * Terminate the in-flight run and mark its thread `"cancelled"`. Resolves as a
392
434
  * no-op when no `cancel` mutation was supplied or no run is in flight.
393
435
  */
394
436
  cancel: () => Promise<void>;
395
- /** The history or thread subscription's last error, or `undefined`. */
437
+ /** Refuse a paused `requestSecretTool` call: the run resumes with a "declined" result. */
438
+ declineSecret: (toolCallId: string) => Promise<void>;
439
+ /** The history, thread, or grants subscription's last error, or `undefined`. */
396
440
  error: ComputedRef<Error | undefined>;
397
441
  /** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
398
442
  messages: ComputedRef<ReadonlyArray<AgentChatMessage>>;
399
443
  /** Reject a paused human-in-the-loop tool call (optionally with a reason). */
400
444
  reject: (toolCallId: string, note?: string) => Promise<void>;
445
+ /** Remove a thread-scoped approval grant so the tool's gate applies again to later calls. */
446
+ revokeGrant: (toolName: string) => Promise<void>;
401
447
  /** Start (or continue) a run with a user message; extra args merge over `sendArgs`. Appends an optimistic user turn. */
402
448
  send: (input: string, args?: Record<string, unknown>) => Promise<void>;
403
449
  /** The live thread status, or `undefined` before the thread exists. */
404
450
  status: ComputedRef<AgentThreadStatus | undefined>;
405
451
  /** The in-flight turn's streamed text — live-only, empty once the turn persists to `messages`. */
406
452
  streamingText: ComputedRef<string>;
453
+ /**
454
+ * Give a paused `requestSecretTool` call its value. Always sent online-only: the
455
+ * value is never queued, persisted or replayed, and the call rejects with
456
+ * `OFFLINE_NOT_QUEUED` while the connection is down. The composable keeps no copy;
457
+ * a failure rethrows the original error.
458
+ */
459
+ supplySecret: (toolCallId: string, secret: string) => Promise<void>;
407
460
  }
408
461
  /**
409
462
  * A first-class agent chat surface: live durable history + in-flight token
410
- * streaming + the send / approve / reject / cancel writes, keyed by `threadKey` —
463
+ * streaming + the send / approve / reject / secret / cancel writes, keyed by `threadKey` —
411
464
  * the Vue counterpart to React's `useAgentChat`, re-expressed with refs.
412
465
  *
413
466
  * It composes the existing primitives rather than adding transport:
@@ -503,7 +556,7 @@ interface UseAgentToolEventsOptions {
503
556
  * Optional live event stream — the same app stream function `useAgentChat`
504
557
  * uses. When supplied, ephemeral `ctx.reportProgress(...)` events for the
505
558
  * thread are surfaced as `{ type: "progress" }` entries; when omitted only the
506
- * durable lifecycle (call / result / awaiting-approval) is returned.
559
+ * durable lifecycle (call / result / awaiting-approval / awaiting-secret) is returned.
507
560
  */
508
561
  stream?: AgentLiveStreamReference;
509
562
  /** The thread whose tool activity to observe — may be a plain value, `ref`, or getter (a reactive source re-subscribes). */
@@ -511,7 +564,7 @@ interface UseAgentToolEventsOptions {
511
564
  }
512
565
  /**
513
566
  * A single tool-lifecycle event for a thread. The durable arms
514
- * (`call`/`result`/`awaiting-approval`) are derived from `agents:agentMessages`
567
+ * (`call`/`result`/`awaiting-approval`/`awaiting-secret`) are derived from `agents:agentMessages`
515
568
  * and carry the persisted `seq`; the ephemeral `progress` arm comes live off the
516
569
  * stream and has no `seq`. Discriminate on `type`.
517
570
  */
@@ -537,6 +590,11 @@ type AgentToolEvent = {
537
590
  toolCallId?: string;
538
591
  toolName?: string;
539
592
  type: "awaiting-approval";
593
+ } | {
594
+ seq: number;
595
+ toolCallId?: string;
596
+ toolName?: string;
597
+ type: "awaiting-secret";
540
598
  };
541
599
  interface UseAgentToolEventsResult {
542
600
  /**
@@ -698,7 +756,7 @@ interface MutationHandle<F extends FunctionReference> {
698
756
  /** The latest invocation's error, or `undefined`. */
699
757
  error: Ref<Error | undefined>;
700
758
  /** Invoke the mutation. Resolves with the server value; rejects on failure. */
701
- mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
759
+ mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
702
760
  /** `true` while ANY invocation from this handle is in flight (ref-counted, so overlapping calls compose). */
703
761
  pending: Ref<boolean>;
704
762
  /** Clear the latest `data`/`error` back to idle. */
@@ -1192,7 +1250,7 @@ interface UseVoiceAgentResult {
1192
1250
  * `createSocket`) so the composable is drivable outside a browser.
1193
1251
  */
1194
1252
  declare const useVoiceAgent: (options: UseVoiceAgentOptions) => UseVoiceAgentResult;
1195
- export { type ActionHandle, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type FlagValue, type HeartbeatReference,
1253
+ export { type ActionHandle, type AgentApprovalGrant, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, Authenticated, type FlagValue, type HeartbeatReference,
1196
1254
  /**
1197
1255
  * `@lunora/vue` — the Vue adapter for Lunora.
1198
1256
  *
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{AuthLoading as r,Authenticated as t,Unauthenticated as u}from"./packem_shared/AuthLoading-ZXVgXos1.mjs";import{hydratePreloaded as p}from"./packem_shared/hydratePreloaded-DicHNxhB.mjs";import{LUNORA_INJECTION_KEY as f,createLunora as m,provideLunora as n,useLunora as x}from"./packem_shared/LUNORA_INJECTION_KEY-Bct9tKCj.mjs";import{useAction as c}from"./packem_shared/useAction-C4VLsh4M.mjs";import{useAgent as d}from"./packem_shared/useAgent-Bp5UEoEp.mjs";import{useAgentChat as L}from"./packem_shared/useAgentChat-CNBm2vp1.mjs";import{useAgentState as l}from"./packem_shared/useAgentState-DpFm2lH0.mjs";import{useAgentToolEvents as Q}from"./packem_shared/useAgentToolEvents-CFGnBjKS.mjs";import{useAuth as T}from"./packem_shared/useAuth-QDllAwZL.mjs";import{default as v}from"./packem_shared/useConnectionStatus-CCUbKnj2.mjs";import{useFlag as E,useFlags as I}from"./packem_shared/useFlag-xVfWC_c6.mjs";import{useLiveTopic as P}from"./packem_shared/useLiveTopic-B0HA04MY.mjs";import{useMutation as M}from"./packem_shared/useMutation-D6PkaNaE.mjs";import{useMutator as R}from"./packem_shared/useMutator-CO7nXlRf.mjs";import{useInfiniteQuery as _,usePaginatedQuery as J}from"./packem_shared/useInfiniteQuery-Clqt_MYU.mjs";import{usePresence as V}from"./packem_shared/usePresence-Dpnb4kjv.mjs";import{subscribeToQuery as j,useQuery as k}from"./packem_shared/subscribeToQuery-BvnA8ErG.mjs";import{useRateLimit as w}from"./packem_shared/useRateLimit-zoPsflSG.mjs";import{useStream as B}from"./packem_shared/useStream-COVzNdKq.mjs";import{useSubscription as G}from"./packem_shared/useSubscription-cTKyOIAv.mjs";import{useVoiceAgent as W}from"./packem_shared/useVoiceAgent-BEGHhbmX.mjs";export{r as AuthLoading,t as Authenticated,f as LUNORA_INJECTION_KEY,u as Unauthenticated,m as createLunora,p as hydratePreloaded,n as provideLunora,j as subscribeToQuery,c as useAction,d as useAgent,L as useAgentChat,l as useAgentState,Q as useAgentToolEvents,T as useAuth,v as useConnectionStatus,E as useFlag,I as useFlags,_ as useInfiniteQuery,P as useLiveTopic,x as useLunora,M as useMutation,R as useMutator,J as usePaginatedQuery,V as usePresence,k as useQuery,w as useRateLimit,B as useStream,G as useSubscription,W as useVoiceAgent};
1
+ import{AuthLoading as r,Authenticated as t,Unauthenticated as u}from"./packem_shared/AuthLoading-ZXVgXos1.mjs";import{hydratePreloaded as p}from"./packem_shared/hydratePreloaded-DicHNxhB.mjs";import{LUNORA_INJECTION_KEY as f,createLunora as m,provideLunora as n,useLunora as x}from"./packem_shared/LUNORA_INJECTION_KEY-Bct9tKCj.mjs";import{useAction as c}from"./packem_shared/useAction-C4VLsh4M.mjs";import{useAgent as d}from"./packem_shared/useAgent-Bp5UEoEp.mjs";import{useAgentChat as L}from"./packem_shared/useAgentChat-CVgX8Z-J.mjs";import{useAgentState as l}from"./packem_shared/useAgentState-DpFm2lH0.mjs";import{useAgentToolEvents as Q}from"./packem_shared/useAgentToolEvents-CWHORsCT.mjs";import{useAuth as T}from"./packem_shared/useAuth-QDllAwZL.mjs";import{default as v}from"./packem_shared/useConnectionStatus-CCUbKnj2.mjs";import{useFlag as E,useFlags as I}from"./packem_shared/useFlag-xVfWC_c6.mjs";import{useLiveTopic as P}from"./packem_shared/useLiveTopic-B0HA04MY.mjs";import{useMutation as M}from"./packem_shared/useMutation-D6PkaNaE.mjs";import{useMutator as R}from"./packem_shared/useMutator-CO7nXlRf.mjs";import{useInfiniteQuery as _,usePaginatedQuery as J}from"./packem_shared/useInfiniteQuery-Clqt_MYU.mjs";import{usePresence as V}from"./packem_shared/usePresence-Dpnb4kjv.mjs";import{subscribeToQuery as j,useQuery as k}from"./packem_shared/subscribeToQuery-BvnA8ErG.mjs";import{useRateLimit as w}from"./packem_shared/useRateLimit-zoPsflSG.mjs";import{useStream as B}from"./packem_shared/useStream-COVzNdKq.mjs";import{useSubscription as G}from"./packem_shared/useSubscription-cTKyOIAv.mjs";import{useVoiceAgent as W}from"./packem_shared/useVoiceAgent-Dz1t4xgi.mjs";export{r as AuthLoading,t as Authenticated,f as LUNORA_INJECTION_KEY,u as Unauthenticated,m as createLunora,p as hydratePreloaded,n as provideLunora,j as subscribeToQuery,c as useAction,d as useAgent,L as useAgentChat,l as useAgentState,Q as useAgentToolEvents,T as useAuth,v as useConnectionStatus,E as useFlag,I as useFlags,_ as useInfiniteQuery,P as useLiveTopic,x as useLunora,M as useMutation,R as useMutator,J as usePaginatedQuery,V as usePresence,k as useQuery,w as useRateLimit,B as useStream,G as useSubscription,W as useVoiceAgent};
@@ -0,0 +1 @@
1
+ import{reconcileOptimistic as A,maxSeq as k}from"@lunora/client";import{computed as s,ref as X,watch as Z,toValue as n}from"vue";import{NO_MUTATION_REF as tt}from"./useAgent-Bp5UEoEp.mjs";import{useMutation as u}from"./useMutation-D6PkaNaE.mjs";import{useStream as et}from"./useStream-COVzNdKq.mjs";import{useSubscription as y}from"./useSubscription-cTKyOIAv.mjs";const at={__lunoraRef:""},rt=[],lt=w=>{const{api:o,cancel:h,limit:g,onError:p,send:M,sendArgs:E,stream:f,threadKey:r}=w,{data:R,error:_}=y(o.agents.agentMessages,()=>{const t=n(r);return g===void 0?{key:t}:{key:t,limit:g}},{onError:p}),{data:K,error:T}=y(o.agents.agentThread,()=>({key:n(r)}),{onError:p}),{data:x,error:I}=y(o.agents.agentApprovalGrants,()=>({key:n(r)}),{onError:p}),b=s(()=>_.value??T.value??I.value),D=f===void 0?"skip":()=>({key:n(r)}),{chunks:G}=et(f??at,D),O=u(M),q=u(h??tt),N=u(o.agents.agentResolveApproval),j=u(o.agents.agentRevokeApprovalGrant),C=u(o.agents.agentSupplySecret),F=u(o.agents.agentDeclineSecret),c=X([]);let S=0;Z(()=>n(r),()=>{c.value=[]});const d=s(()=>K.value),P=s(()=>d.value?.status),l=s(()=>R.value??[]),U=s(()=>{const t=l.value,e=A(c.value,t);if(e.length===0)return t;const a=k(t);return[...t,...e.map((i,m)=>({content:i.content,optimistic:!0,role:"user",seq:a+1+m}))]}),V=s(()=>{const t=n(r),e=l.value.filter(a=>a.role==="assistant").length;return G.value.filter(a=>a.kind!=="progress"&&a.threadKey===t&&a.turn>=e).map(a=>a.text).join("")}),Y=async(t,e)=>{const a=S;S+=1;const i=k(l.value);c.value=[...A(c.value,l.value),{content:t,id:a,maxDurableSeqAtSend:i}];try{await O.mutate({input:t,threadKey:n(r),...E,...e})}catch(m){throw c.value=c.value.filter(W=>W.id!==a),m}},v=async(t,e,a)=>{const i=d.value?.instanceId;if(i===void 0)throw new Error(`useAgentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await N.mutate({decision:t,instanceId:i,threadKey:n(r),toolCallId:e,...a===void 0?{}:{note:a}})},$=async(t,e)=>v("approve",t,e),z=async(t,e)=>v("approve_for_thread",t,e),B=async(t,e)=>v("reject",t,e),H=async t=>{await j.mutate({threadKey:n(r),toolName:t})},J=async(t,e)=>{await C.mutate({secret:e,threadKey:n(r),toolCallId:t},{onlineOnly:!0})},L=async t=>{await F.mutate({threadKey:n(r),toolCallId:t})},Q=async()=>{const t=d.value?.instanceId;h===void 0||t===void 0||await q.mutate({instanceId:t,threadKey:n(r)})};return{approvalGrants:s(()=>x.value??rt),approve:$,approveForThread:z,cancel:Q,declineSecret:L,error:b,messages:U,reject:B,revokeGrant:H,send:Y,status:P,streamingText:V,supplySecret:J}};export{lt as useAgentChat};
@@ -0,0 +1 @@
1
+ import{computed as v,toValue as a}from"vue";import{useStream as f}from"./useStream-COVzNdKq.mjs";import{useSubscription as E}from"./useSubscription-cTKyOIAv.mjs";const C={__lunoraRef:""},y=[],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}}]},M=t=>{const{api:o,limit:r,stream:i,threadKey:e}=t,d=()=>{const l=a(e);return r===void 0?{key:l}:{key:l,limit:r}},{data:s}=E(o.agents.agentMessages,d),p=i===void 0?"skip":()=>({key:a(e)}),{chunks:c}=f(i??C,p);return{events:v(()=>{const l=a(e),u=(s.value??y).flatMap(n=>_(n)??[]);for(const n of c.value)n.kind==="progress"&&n.threadKey===l&&u.push({data:n.data,toolCallId:n.toolCallId,type:"progress"});return u})}};export{M as useAgentToolEvents};
@@ -0,0 +1 @@
1
+ import{ref as y,onScopeDispose as N,toValue as O}from"vue";import{useLunora as P}from"./LUNORA_INJECTION_KEY-Bct9tKCj.mjs";const M="/_lunora/ws",H="/_lunora/voice/",$=4001,I=e=>e.startsWith("https://")?`wss://${e.slice(8)}`:e.startsWith("http://")?`ws://${e.slice(7)}`:e,B=e=>{const r=e.startsWith("agents:")?e.slice(7):e;return r.endsWith("Voice")?r.slice(0,-5):r},K=(e,r)=>{if(r===void 0||r==="")return I(e);if(r.endsWith(M))return r.slice(0,-M.length);try{return new URL(r).origin}catch{return I(e)}},q=e=>{const r=K(e.httpUrl,e.wsUrl),s=r.endsWith("/")?r.slice(0,-1):r,i=new URLSearchParams({threadKey:e.threadKey});return`${s}${H}${encodeURIComponent(e.agent)}?${i.toString()}`},J=(e,r)=>{if(r?.code===$)return new Error(`${e}: authentication token expired — refresh the credential and start a new call`)},G=(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`))})},X=16e3,j=e=>{if(e.length===0)return 0;let r=0;for(const s of e)r+=s*s;return Math.sqrt(r/e.length)},z=(e,r)=>{const s=r/X,i=s>1?Math.floor(e.length/s):e.length,g=new ArrayBuffer(i*2),p=new DataView(g);for(let l=0;l<i;l+=1){const k=e[Math.floor(l*s)]??0,v=Math.max(-1,Math.min(1,k));p.setInt16(l*2,v<0?v*32768:v*32767,!0)}return new Uint8Array(g)},Q=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("useVoiceAgent: microphone capture requires getUserMedia + AudioContext (no browser audio available)");const g=await s({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),p=new i,l=p.createMediaStreamSource(g),k=p.createScriptProcessor(4096,1,1);let v=!1,w=!1,c=0,o=0;return k.onaudioprocess=u=>{const d=u.inputBuffer.getChannelData(0),h=v?0:j(d);if(e.onLevel(h),v)return;if(e.onAudio(z(d,p.sampleRate)),e.isTurnActive()){o=h>=e.interruptThreshold?o+1:0,o>=e.interruptChunks&&(o=0,e.onInterrupt());return}o=0;const S=d.length/p.sampleRate*1e3;if(h>=e.silenceThreshold){w=!0,c=0;return}w&&(c+=S,c>=e.silenceDurationMs&&(w=!1,c=0,e.onSilence()))},l.connect(k),k.connect(p.destination),{setMuted:u=>{v=u},stop:()=>{k.disconnect(),l.disconnect();for(const u of g.getTracks())u.stop();p.close()}}},Y=()=>{const e=globalThis,r=e.AudioContext??e.webkitAudioContext;if(!r)throw new Error("useVoiceAgent: audio playback requires AudioContext (no browser audio available)");const s=new r,i=new Set;let g=0,p=Promise.resolve(),l=0;const k=async(c,o)=>{if(o!==l)return;let u;try{u=await s.decodeAudioData(c.buffer)}catch{return}if(o!==l)return;const d=s.createBufferSource();d.buffer=u,d.connect(s.destination);const h=Math.max(s.currentTime,g);d.start(h),g=h+u.duration,i.add(d),d.onended=()=>{i.delete(d)}},v=c=>{const o=Uint8Array.from(c),u=l;p=p.then(()=>k(o,u))},w=()=>{l+=1;for(const c of i)try{c.stop()}catch{}i.clear(),g=s.currentTime};return{enqueue:v,interrupt:w,stop:()=>{w(),s.close()}}},U=1,Z=.01,ee=1200,te=.15,ne=3,ae=e=>{const{createMicrophone:r=Q,createSpeaker:s=Y,createSocket:i,interruptChunks:g=ne,interruptThreshold:p=te,silenceDurationMs:l=ee,silenceThreshold:k=Z,threadKey:v,voice:w}=e,c=P(),o=y("idle"),u=y(!1),d=y(""),h=y(""),S=y(0),b=y(!1),m=y(void 0);let a,C=!1;const _=n=>{const t=a?.socket;return t?.readyState===U?(t.send(JSON.stringify(n)),!0):!1},T=()=>{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,u.value=!1,o.value="idle",S.value=0},R=T,D=n=>{const t=a;switch(n.type){case"assistant_delta":{t&&(t.speaking=!0),o.value="speaking",h.value+=n.text;break}case"assistant_discarded":{t&&(t.suppressAudio=!0),t?.speaker?.interrupt(),h.value="";break}case"assistant_done":{t&&(t.awaitingTurn=!1,t.speaking=!1),h.value=n.text,o.value="listening";break}case"error":{t&&(t.awaitingTurn=!1,t.speaking=!1),m.value=new Error(n.message),o.value="listening";break}case"interrupted":{t&&(t.awaitingTurn=!1,t.speaking=!1,t.suppressAudio=!1),t?.speaker?.interrupt(),o.value="listening";break}case"ready":{t&&(t.audioFormat=n.audioFormat,t.suppressAudio=!1),u.value=!0,o.value="listening";break}case"user_transcript":{t&&(t.suppressAudio=!1),d.value=n.text,h.value="",o.value="thinking";break}}},L=n=>{const t=a;!t||t.suppressAudio||(t.speaker??=s({audioFormat:t.audioFormat}),t.speaking=!0,o.value="speaking",t.speaker.enqueue(n))},V=async()=>{if(a||C)return;C=!0,m.value=void 0,d.value="",h.value="";let n;try{const t=q({agent:B(w.__lunoraRef),httpUrl:c.url,threadKey:O(v),wsUrl:c.wsUrl}),A=(i??(f=>{const E=c.getWebSocketImpl();if(!E)throw new Error("useVoiceAgent: no WebSocket implementation available (pass createSocket explicitly)");return new E(f)}))(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=G(c,"useVoiceAgent",f=>{a===n&&(m.value=f,T())}),A.onmessage=f=>{if(typeof f.data=="string"){try{D(JSON.parse(f.data))}catch{}return}L(new Uint8Array(f.data))},A.onerror=()=>{m.value=new Error("useVoiceAgent: voice socket error")},A.onclose=f=>{if(a!==n)return;const E=J("useVoiceAgent",f);E&&(m.value=E),T()};const x=await r({interruptChunks:g,interruptThreshold:p,isTurnActive:()=>(a?.speaking??!1)||(a?.awaitingTurn??!1),onAudio:f=>{A.readyState===U&&A.send(f)},onInterrupt:()=>{_({type:"interrupt"}),a?.speaker?.interrupt(),a&&(a.awaitingTurn=!1,a.speaking=!1,a.suppressAudio=!0),o.value="listening"},onLevel:f=>{S.value=f},onSilence:()=>{_({type:"commit"}),a&&(a.awaitingTurn=!0),o.value="thinking"},silenceDurationMs:l,silenceThreshold:k});a===n?(n.microphone=x,b.value=!1,n.speaking||(o.value="listening")):x.stop()}catch(t){a===n&&(m.value=t instanceof Error?t:new Error(String(t)),T())}finally{C=!1}},F=()=>{const n=!b.value;return a?.microphone?.setMuted(n),b.value=n,n},W=n=>{_({text:n,type:"text"})&&(a&&(a.awaitingTurn=!0),o.value="thinking")};return N(T),{audioLevel:S,connected:u,endCall:R,error:m,interimTranscript:h,isMuted:b,sendText:W,startCall:V,status:o,toggleMute:F,transcript:d}};export{ae as useVoiceAgent};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/vue",
3
- "version": "1.0.0-alpha.273",
3
+ "version": "1.0.0-alpha.274",
4
4
  "description": "Vue adapter for Lunora — live composables, 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.233",
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.155",
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 A,maxSeq as w}from"@lunora/client";import{computed as c,ref as V,watch as $,toValue as a}from"vue";import{NO_MUTATION_REF as z}from"./useAgent-Bp5UEoEp.mjs";import{useMutation as m}from"./useMutation-D6PkaNaE.mjs";import{useStream as B}from"./useStream-COVzNdKq.mjs";import{useSubscription as E}from"./useSubscription-cTKyOIAv.mjs";const G={__lunoraRef:""},tt=R=>{const{api:u,cancel:v,limit:p,onError:h,send:k,sendArgs:x,stream:f,threadKey:n}=R,{data:I,error:M}=E(u.agents.agentMessages,()=>{const t=a(n);return p===void 0?{key:t}:{key:t,limit:p}},{onError:h}),{data:S,error:b}=E(u.agents.agentThread,()=>({key:a(n)}),{onError:h}),_=c(()=>M.value??b.value),K=f===void 0?"skip":()=>({key:a(n)}),{chunks:T}=B(f??G,K),j=m(k),q=m(v??z),O=m(u.agents.agentResolveApproval),o=V([]);let g=0;$(()=>a(n),()=>{o.value=[]});const l=c(()=>S.value),C=c(()=>l.value?.status),i=c(()=>I.value??[]),D=c(()=>{const t=i.value,r=A(o.value,t);if(r.length===0)return t;const e=w(t);return[...t,...r.map((s,d)=>({content:s.content,optimistic:!0,role:"user",seq:e+1+d}))]}),N=c(()=>{const t=a(n),r=i.value.filter(e=>e.role==="assistant").length;return T.value.filter(e=>e.kind!=="progress"&&e.threadKey===t&&e.turn>=r).map(e=>e.text).join("")}),F=async(t,r)=>{const e=g;g+=1;const s=w(i.value);o.value=[...A(o.value,i.value),{content:t,id:e,maxDurableSeqAtSend:s}];try{await j.mutate({input:t,threadKey:a(n),...x,...r})}catch(d){throw o.value=o.value.filter(U=>U.id!==e),d}},y=async(t,r,e)=>{const s=l.value?.instanceId;if(s===void 0)throw new Error(`useAgentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await O.mutate({decision:t,instanceId:s,threadKey:a(n),toolCallId:r,...e===void 0?{}:{note:e}})};return{approve:async(t,r)=>y("approve",t,r),cancel:async()=>{const t=l.value?.instanceId;v===void 0||t===void 0||await q.mutate({instanceId:t,threadKey:a(n)})},error:_,messages:D,reject:async(t,r)=>y("reject",t,r),send:F,status:C,streamingText:N}};export{tt as useAgentChat};
@@ -1 +0,0 @@
1
- import{computed as v,toValue as e}from"vue";import{useStream as f}from"./useStream-COVzNdKq.mjs";import{useSubscription as C}from"./useSubscription-cTKyOIAv.mjs";const y={__lunoraRef:""},I=[],N=t=>{if(t.role==="assistant"&&t.toolCalls)return t.toolCalls.map(l=>({input:l.input,seq:t.seq,toolCallId:l.id,toolName:l.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}}]},h=t=>{const{api:l,limit:a,stream:u,threadKey:n}=t,d=()=>{const r=e(n);return a===void 0?{key:r}:{key:r,limit:a}},{data:p}=C(l.agents.agentMessages,d),s=u===void 0?"skip":()=>({key:e(n)}),{chunks:c}=f(u??y,s);return{events:v(()=>{const r=e(n),i=(p.value??I).flatMap(o=>N(o)??[]);for(const o of c.value)o.kind==="progress"&&o.threadKey===r&&i.push({data:o.data,toolCallId:o.toolCallId,type:"progress"});return i})}};export{h as useAgentToolEvents};
@@ -1 +0,0 @@
1
- import{ref as y,onScopeDispose as N,toValue as O}from"vue";import{useLunora as P}from"./LUNORA_INJECTION_KEY-Bct9tKCj.mjs";const M="/_lunora/ws",H="/_lunora/voice/",$=4001,I=e=>e.startsWith("https://")?`wss://${e.slice(8)}`:e.startsWith("http://")?`ws://${e.slice(7)}`:e,B=e=>{const r=e.startsWith("agents:")?e.slice(7):e;return r.endsWith("Voice")?r.slice(0,-5):r},K=(e,r)=>{if(r===void 0||r==="")return I(e);if(r.endsWith(M))return r.slice(0,-M.length);try{return new URL(r).origin}catch{return I(e)}},q=e=>{const r=K(e.httpUrl,e.wsUrl),s=r.endsWith("/")?r.slice(0,-1):r,i=new URLSearchParams({threadKey:e.threadKey});return`${s}${H}${encodeURIComponent(e.agent)}?${i.toString()}`},J=(e,r)=>{if(r?.code===$)return new Error(`${e}: authentication token expired — refresh the credential and start a new call`)},G=(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`))})},X=16e3,j=e=>{if(e.length===0)return 0;let r=0;for(const s of e)r+=s*s;return Math.sqrt(r/e.length)},z=(e,r)=>{const s=r/X,i=s>1?Math.floor(e.length/s):e.length,g=new ArrayBuffer(i*2),p=new DataView(g);for(let l=0;l<i;l+=1){const k=e[Math.floor(l*s)]??0,v=Math.max(-1,Math.min(1,k));p.setInt16(l*2,v<0?v*32768:v*32767,!0)}return new Uint8Array(g)},Q=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("useVoiceAgent: microphone capture requires getUserMedia + AudioContext (no browser audio available)");const g=await s({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),p=new i,l=p.createMediaStreamSource(g),k=p.createScriptProcessor(4096,1,1);let v=!1,w=!1,c=0,o=0;return k.onaudioprocess=u=>{const d=u.inputBuffer.getChannelData(0),f=v?0:j(d);if(e.onLevel(f),v)return;if(e.onAudio(z(d,p.sampleRate)),e.isTurnActive()){o=f>=e.interruptThreshold?o+1:0,o>=e.interruptChunks&&(o=0,e.onInterrupt());return}o=0;const S=d.length/p.sampleRate*1e3;if(f>=e.silenceThreshold){w=!0,c=0;return}w&&(c+=S,c>=e.silenceDurationMs&&(w=!1,c=0,e.onSilence()))},l.connect(k),k.connect(p.destination),{setMuted:u=>{v=u},stop:()=>{k.disconnect(),l.disconnect();for(const u of g.getTracks())u.stop();p.close()}}},Y=()=>{const e=globalThis,r=e.AudioContext??e.webkitAudioContext;if(!r)throw new Error("useVoiceAgent: audio playback requires AudioContext (no browser audio available)");const s=new r,i=new Set;let g=0,p=Promise.resolve(),l=0;const k=async(c,o)=>{if(o!==l)return;let u;try{u=await s.decodeAudioData(c.buffer)}catch{return}if(o!==l)return;const d=s.createBufferSource();d.buffer=u,d.connect(s.destination);const f=Math.max(s.currentTime,g);d.start(f),g=f+u.duration,i.add(d),d.onended=()=>{i.delete(d)}},v=c=>{const o=Uint8Array.from(c),u=l;p=p.then(()=>k(o,u))},w=()=>{l+=1;for(const c of i)try{c.stop()}catch{}i.clear(),g=s.currentTime};return{enqueue:v,interrupt:w,stop:()=>{w(),s.close()}}},U=1,Z=.01,ee=1200,te=.15,ne=3,ae=e=>{const{createMicrophone:r=Q,createSpeaker:s=Y,createSocket:i,interruptChunks:g=ne,interruptThreshold:p=te,silenceDurationMs:l=ee,silenceThreshold:k=Z,threadKey:v,voice:w}=e,c=P(),o=y("idle"),u=y(!1),d=y(""),f=y(""),S=y(0),C=y(!1),m=y(void 0);let a,b=!1;const _=t=>{const n=a?.socket;return n?.readyState===U?(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{}}b=!1,u.value=!1,o.value="idle",S.value=0},R=T,D=t=>{const n=a;switch(t.type){case"assistant_delta":{n&&(n.speaking=!0),o.value="speaking",f.value+=t.text;break}case"assistant_done":{n&&(n.awaitingTurn=!1,n.speaking=!1),f.value=t.text,o.value="listening";break}case"error":{n&&(n.awaitingTurn=!1,n.speaking=!1),m.value=new Error(t.message),o.value="listening";break}case"interrupted":{n&&(n.awaitingTurn=!1,n.speaking=!1,n.suppressAudio=!1),n?.speaker?.interrupt(),o.value="listening";break}case"ready":{n&&(n.audioFormat=t.audioFormat,n.suppressAudio=!1),u.value=!0,o.value="listening";break}case"user_transcript":{n&&(n.suppressAudio=!1),d.value=t.text,f.value="",o.value="thinking";break}}},L=t=>{const n=a;!n||n.suppressAudio||(n.speaker??=s({audioFormat:n.audioFormat}),n.speaking=!0,o.value="speaking",n.speaker.enqueue(t))},V=async()=>{if(a||b)return;b=!0,m.value=void 0,d.value="",f.value="";let t;try{const n=q({agent:B(w.__lunoraRef),httpUrl:c.url,threadKey:O(v),wsUrl:c.wsUrl}),A=(i??(h=>{const E=c.getWebSocketImpl();if(!E)throw new Error("useVoiceAgent: no WebSocket implementation available (pass createSocket explicitly)");return new E(h)}))(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=G(c,"useVoiceAgent",h=>{a===t&&(m.value=h,T())}),A.onmessage=h=>{if(typeof h.data=="string"){try{D(JSON.parse(h.data))}catch{}return}L(new Uint8Array(h.data))},A.onerror=()=>{m.value=new Error("useVoiceAgent: voice socket error")},A.onclose=h=>{if(a!==t)return;const E=J("useVoiceAgent",h);E&&(m.value=E),T()};const x=await r({interruptChunks:g,interruptThreshold:p,isTurnActive:()=>(a?.speaking??!1)||(a?.awaitingTurn??!1),onAudio:h=>{A.readyState===U&&A.send(h)},onInterrupt:()=>{_({type:"interrupt"}),a?.speaker?.interrupt(),a&&(a.awaitingTurn=!1,a.speaking=!1,a.suppressAudio=!0),o.value="listening"},onLevel:h=>{S.value=h},onSilence:()=>{_({type:"commit"}),a&&(a.awaitingTurn=!0),o.value="thinking"},silenceDurationMs:l,silenceThreshold:k});a===t?(t.microphone=x,C.value=!1,t.speaking||(o.value="listening")):x.stop()}catch(n){a===t&&(m.value=n instanceof Error?n:new Error(String(n)),T())}finally{b=!1}},F=()=>{const t=!C.value;return a?.microphone?.setMuted(t),C.value=t,t},W=t=>{_({text:t,type:"text"})&&(a&&(a.awaitingTurn=!0),o.value="thinking")};return N(T),{audioLevel:S,connected:u,endCall:R,error:m,interimTranscript:f,isMuted:C,sendText:W,startCall:V,status:o,toggleMute:F,transcript:d}};export{ae as useVoiceAgent};