@lunora/angular 1.0.0-alpha.219 → 1.0.0-alpha.220
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 +69 -11
- package/dist/index.d.ts +69 -11
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/agentChat-CQ3TWlc5.mjs +1 -0
- package/dist/packem_shared/agentToolEvents-CFnjzw3X.mjs +1 -0
- package/dist/packem_shared/mutate-Dg5AiM8y.mjs +1 -0
- package/dist/packem_shared/voiceAgent-DppK8OxH.mjs +1 -0
- package/package.json +3 -3
- package/dist/packem_shared/agentChat-DyJrje49.mjs +0 -1
- package/dist/packem_shared/agentToolEvents-VuBRpS6v.mjs +0 -1
- package/dist/packem_shared/mutate-BZvLQLyu.mjs +0 -1
- package/dist/packem_shared/voiceAgent-CH--tRWP.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DestroyRef, Signal, InjectionToken, EnvironmentProviders, Injector } from '@angular/core';
|
|
2
|
-
import { FunctionReference, LunoraClient, SubscriptionErrorCallback, SubscriptionError, User, LunoraClientOptions, ConnectionStatus, Preloaded, ArgsOf, ReturnOf, LiveTopicOptions as LiveTopicOptions$1, LiveTopicRef, LiveStreamSubscribeError, MutationCallOptions, MutatorHandle, ActionCallOptions } from '@lunora/client';
|
|
2
|
+
import { FunctionReference, LunoraClient, SubscriptionErrorCallback, SubscriptionError, User, LunoraClientOptions, ConnectionStatus, Preloaded, ArgsOf, ReturnOf, LiveTopicOptions as LiveTopicOptions$1, LiveTopicRef, LiveStreamSubscribeError, MutationCallOptions, OnlineOnlyOption, MutatorHandle, ActionCallOptions } from '@lunora/client';
|
|
3
3
|
export type { ArgsOf, ConnectionStatus, FunctionReference, LunoraClient, LunoraClientOptions, MutationCallOptions, Preloaded, ReturnOf, SubscriptionError, Unsubscribe } from '@lunora/client';
|
|
4
4
|
import { AuthStatus } from '@lunora/client/auth';
|
|
5
5
|
import { PaginationStatus } from '@lunora/client/pagination';
|
|
@@ -56,8 +56,8 @@ interface AgentChatMessage {
|
|
|
56
56
|
optimistic?: boolean;
|
|
57
57
|
role: "assistant" | "system" | "tool" | "user";
|
|
58
58
|
seq: number;
|
|
59
|
-
/** Approval lifecycle marker on a human-in-the-loop tool message. */
|
|
60
|
-
status?: "approved" | "awaiting_approval" | "rejected";
|
|
59
|
+
/** Approval or secret-request lifecycle marker on a human-in-the-loop tool message. */
|
|
60
|
+
status?: "approved" | "awaiting_approval" | "awaiting_secret" | "rejected";
|
|
61
61
|
toolCallId?: string;
|
|
62
62
|
toolCalls?: ReadonlyArray<{
|
|
63
63
|
id: string;
|
|
@@ -202,7 +202,7 @@ type AgentMessagesReference$1 = FunctionReference<"query", {
|
|
|
202
202
|
}, ReadonlyArray<Record<string, unknown>>>;
|
|
203
203
|
/** The `agents:agentResolveApproval` reference — resolves a human-in-the-loop tool approval. */
|
|
204
204
|
type AgentApprovalReference = FunctionReference<"mutation", {
|
|
205
|
-
decision: "approve" | "reject";
|
|
205
|
+
decision: "approve" | "approve_for_thread" | "reject";
|
|
206
206
|
instanceId: string;
|
|
207
207
|
note?: string;
|
|
208
208
|
threadKey: string;
|
|
@@ -210,10 +210,41 @@ type AgentApprovalReference = FunctionReference<"mutation", {
|
|
|
210
210
|
}, {
|
|
211
211
|
resolved: boolean;
|
|
212
212
|
}>;
|
|
213
|
+
/** The `agents:agentSupplySecret` reference — stores a person's value for a paused `requestSecretTool` call. */
|
|
214
|
+
type AgentSupplySecretReference = FunctionReference<"mutation", {
|
|
215
|
+
secret: string;
|
|
216
|
+
threadKey: string;
|
|
217
|
+
toolCallId: string;
|
|
218
|
+
}, {
|
|
219
|
+
resolved: boolean;
|
|
220
|
+
}>;
|
|
221
|
+
/** The `agents:agentDeclineSecret` reference — refuses a paused `requestSecretTool` call. */
|
|
222
|
+
type AgentDeclineSecretReference = FunctionReference<"mutation", {
|
|
223
|
+
threadKey: string;
|
|
224
|
+
toolCallId: string;
|
|
225
|
+
}, {
|
|
226
|
+
resolved: boolean;
|
|
227
|
+
}>;
|
|
213
228
|
/** The `agents:agentThread` reference — live thread status + in-flight `instanceId`. */
|
|
214
229
|
type AgentThreadReference = FunctionReference<"query", {
|
|
215
230
|
key: string;
|
|
216
231
|
}, Record<string, unknown> | undefined>;
|
|
232
|
+
/** A tool approved for the rest of a thread, as `agents:agentApprovalGrants` lists it. */
|
|
233
|
+
interface AgentApprovalGrant {
|
|
234
|
+
createdAt: number;
|
|
235
|
+
toolName: string;
|
|
236
|
+
}
|
|
237
|
+
/** The `agents:agentApprovalGrants` reference — live thread-scoped approval grants. */
|
|
238
|
+
type AgentApprovalGrantsReference = FunctionReference<"query", {
|
|
239
|
+
key: string;
|
|
240
|
+
}, ReadonlyArray<AgentApprovalGrant>>;
|
|
241
|
+
/** The `agents:agentRevokeApprovalGrant` reference — removes a thread-scoped approval grant. */
|
|
242
|
+
type AgentRevokeApprovalGrantReference = FunctionReference<"mutation", {
|
|
243
|
+
threadKey: string;
|
|
244
|
+
toolName: string;
|
|
245
|
+
}, {
|
|
246
|
+
revoked: boolean;
|
|
247
|
+
}>;
|
|
217
248
|
/**
|
|
218
249
|
* An app stream reference that tees the agent's in-flight live events, keyed by
|
|
219
250
|
* thread. Carries token deltas and — since `ctx.reportProgress` rides the same
|
|
@@ -231,8 +262,12 @@ type AgentTokenStreamReference = FunctionReference<"stream", {
|
|
|
231
262
|
*/
|
|
232
263
|
interface AgentChatApi {
|
|
233
264
|
agents: {
|
|
265
|
+
agentApprovalGrants: AgentApprovalGrantsReference;
|
|
266
|
+
agentDeclineSecret: AgentDeclineSecretReference;
|
|
234
267
|
agentMessages: AgentMessagesReference$1;
|
|
235
268
|
agentResolveApproval: AgentApprovalReference;
|
|
269
|
+
agentRevokeApprovalGrant: AgentRevokeApprovalGrantReference;
|
|
270
|
+
agentSupplySecret: AgentSupplySecretReference;
|
|
236
271
|
agentThread: AgentThreadReference;
|
|
237
272
|
};
|
|
238
273
|
}
|
|
@@ -260,7 +295,7 @@ interface AgentChatOptions {
|
|
|
260
295
|
/** History depth forwarded to `agents:agentMessages`. */
|
|
261
296
|
limit?: number;
|
|
262
297
|
/**
|
|
263
|
-
* Called when the live history or
|
|
298
|
+
* Called when the live history, thread, or grants subscription reports an error (a
|
|
264
299
|
* session expiry, an RLS denial). Without it — and without reading `error` —
|
|
265
300
|
* such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
|
|
266
301
|
*/
|
|
@@ -287,29 +322,47 @@ interface AgentChatOptions {
|
|
|
287
322
|
* @experimental
|
|
288
323
|
*/
|
|
289
324
|
interface AgentChatResult {
|
|
325
|
+
/** The tools approved for the rest of this thread, live. Empty until the grants subscription answers. */
|
|
326
|
+
approvalGrants: Signal<ReadonlyArray<AgentApprovalGrant>>;
|
|
290
327
|
/** Approve a paused human-in-the-loop tool call (optionally with a note). */
|
|
291
328
|
approve: (toolCallId: string, note?: string) => Promise<void>;
|
|
329
|
+
/**
|
|
330
|
+
* Approve a paused tool call and grant that tool for the rest of the thread, so
|
|
331
|
+
* later calls to it run without pausing. Undo with {@link AgentChatResult.revokeGrant}.
|
|
332
|
+
*/
|
|
333
|
+
approveForThread: (toolCallId: string, note?: string) => Promise<void>;
|
|
292
334
|
/**
|
|
293
335
|
* Terminate the in-flight run and mark its thread `"cancelled"`. Resolves as a
|
|
294
336
|
* no-op when no `cancel` mutation was supplied or no run is in flight.
|
|
295
337
|
*/
|
|
296
338
|
cancel: () => Promise<void>;
|
|
297
|
-
/**
|
|
339
|
+
/** Refuse a paused `requestSecretTool` call: the run resumes with a "declined" result. */
|
|
340
|
+
declineSecret: (toolCallId: string) => Promise<void>;
|
|
341
|
+
/** The history, thread, or grants subscription's last error, or `undefined`. */
|
|
298
342
|
error: Signal<SubscriptionError | undefined>;
|
|
299
343
|
/** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
|
|
300
344
|
messages: Signal<ReadonlyArray<AgentChatMessage>>;
|
|
301
345
|
/** Reject a paused human-in-the-loop tool call (optionally with a reason). */
|
|
302
346
|
reject: (toolCallId: string, note?: string) => Promise<void>;
|
|
347
|
+
/** Remove a thread-scoped approval grant so the tool's gate applies again to later calls. */
|
|
348
|
+
revokeGrant: (toolName: string) => Promise<void>;
|
|
303
349
|
/** Start (or continue) a run with a user message; extra args merge over `sendArgs`. Appends an optimistic user turn. */
|
|
304
350
|
send: (input: string, args?: Record<string, unknown>) => Promise<void>;
|
|
305
351
|
/** The live thread status, or `undefined` before the thread exists. */
|
|
306
352
|
status: Signal<AgentThreadStatus | undefined>;
|
|
307
353
|
/** The in-flight turn's streamed text — live-only, empty once the turn persists to `messages`. */
|
|
308
354
|
streamingText: Signal<string>;
|
|
355
|
+
/**
|
|
356
|
+
* Give a paused `requestSecretTool` call its value. Always sent online-only: the
|
|
357
|
+
* value is never queued, persisted or replayed, and the call rejects with
|
|
358
|
+
* `OFFLINE_NOT_QUEUED` while the connection is down. The service keeps no copy;
|
|
359
|
+
* a failure rethrows the original error.
|
|
360
|
+
*/
|
|
361
|
+
supplySecret: (toolCallId: string, secret: string) => Promise<void>;
|
|
309
362
|
}
|
|
310
363
|
/**
|
|
311
364
|
* A first-class agent chat surface: live durable history + in-flight token
|
|
312
|
-
* streaming + the send / approve / reject / cancel writes, keyed by `threadKey` —
|
|
365
|
+
* streaming + the send / approve / reject / secret / cancel writes, keyed by `threadKey` —
|
|
313
366
|
* the Angular counterpart to React's `useAgentChat`, re-expressed with signals.
|
|
314
367
|
*
|
|
315
368
|
* It composes the existing primitives rather than adding transport:
|
|
@@ -439,7 +492,7 @@ interface AgentToolEventsOptions {
|
|
|
439
492
|
* Optional live event stream — the same app stream function `agentChat` uses.
|
|
440
493
|
* When supplied, ephemeral `ctx.reportProgress(...)` events for the thread are
|
|
441
494
|
* surfaced as `{ type: "progress" }` entries; when omitted only the durable
|
|
442
|
-
* lifecycle (call / result / awaiting-approval) is returned.
|
|
495
|
+
* lifecycle (call / result / awaiting-approval / awaiting-secret) is returned.
|
|
443
496
|
*/
|
|
444
497
|
stream?: AgentLiveStreamReference;
|
|
445
498
|
/** The thread whose tool activity to observe. */
|
|
@@ -447,7 +500,7 @@ interface AgentToolEventsOptions {
|
|
|
447
500
|
}
|
|
448
501
|
/**
|
|
449
502
|
* A single tool-lifecycle event for a thread. The durable arms
|
|
450
|
-
* (`call`/`result`/`awaiting-approval`) are derived from `agents:agentMessages`
|
|
503
|
+
* (`call`/`result`/`awaiting-approval`/`awaiting-secret`) are derived from `agents:agentMessages`
|
|
451
504
|
* and carry the persisted `seq`; the ephemeral `progress` arm comes live off the
|
|
452
505
|
* stream and has no `seq`. Discriminate on `type`.
|
|
453
506
|
* @experimental
|
|
@@ -474,6 +527,11 @@ type AgentToolEvent = {
|
|
|
474
527
|
toolCallId?: string;
|
|
475
528
|
toolName?: string;
|
|
476
529
|
type: "awaiting-approval";
|
|
530
|
+
} | {
|
|
531
|
+
seq: number;
|
|
532
|
+
toolCallId?: string;
|
|
533
|
+
toolName?: string;
|
|
534
|
+
type: "awaiting-secret";
|
|
477
535
|
};
|
|
478
536
|
/**
|
|
479
537
|
* `AgentToolEventsResult` is part of the experimental `@lunora/angular` API and may change without a major version bump.
|
|
@@ -933,7 +991,7 @@ interface MutateOptions<F extends FunctionReference> extends MutationCallOptions
|
|
|
933
991
|
* resolve from the injector.
|
|
934
992
|
* @experimental
|
|
935
993
|
*/
|
|
936
|
-
declare const mutate: <F extends FunctionReference>(reference: F, args: ArgsOf<F>, options?: MutateOptions<F>) => Promise<ReturnOf<F>>;
|
|
994
|
+
declare const mutate: <F extends FunctionReference>(reference: F, args: ArgsOf<F>, options?: MutateOptions<F> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
|
|
937
995
|
/**
|
|
938
996
|
* `MutatorResult` is part of the experimental `@lunora/angular` API and may change without a major version bump.
|
|
939
997
|
* @experimental
|
|
@@ -1560,7 +1618,7 @@ interface VoiceAgentResult {
|
|
|
1560
1618
|
* @experimental
|
|
1561
1619
|
*/
|
|
1562
1620
|
declare const voiceAgent: (options: VoiceAgentOptions) => VoiceAgentResult;
|
|
1563
|
-
export { type AgentApi, type AgentChatApi, type AgentChatMessage, type AgentChatOptions, type AgentChatResult, type AgentLiveEvent, type AgentOptions, type AgentProgressEvent, type AgentResult, type AgentStateApi, type AgentStateOptions, type AgentStateResult, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentTokenStreamReference, type AgentToolEvent, type AgentToolEventsApi, type AgentToolEventsOptions, type AgentToolEventsResult, type AuthGateResult, type AuthOptions, type AuthResult, type ConnectionStatusOptions, type FlagOptions, type FlagValue, type FlagsOptions, type HeartbeatReference, type HydratePreloadedOptions, type HydratePreloadedResult, type InfiniteQueryResult, LUNORA_CLIENT, type ListPresentReference, type LiveQueryOptions, type LiveTopicOptions, type MutateOptions, type MutatorResult, type PaginatedQueryOptions, type PaginatedQueryResult, type PresenceOptions, type PresenceResult,
|
|
1621
|
+
export { type AgentApi, type AgentApprovalGrant, type AgentChatApi, type AgentChatMessage, type AgentChatOptions, type AgentChatResult, type AgentLiveEvent, type AgentOptions, type AgentProgressEvent, type AgentResult, type AgentStateApi, type AgentStateOptions, type AgentStateResult, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentTokenStreamReference, type AgentToolEvent, type AgentToolEventsApi, type AgentToolEventsOptions, type AgentToolEventsResult, type AuthGateResult, type AuthOptions, type AuthResult, type ConnectionStatusOptions, type FlagOptions, type FlagValue, type FlagsOptions, type HeartbeatReference, type HydratePreloadedOptions, type HydratePreloadedResult, type InfiniteQueryResult, LUNORA_CLIENT, type ListPresentReference, type LiveQueryOptions, type LiveTopicOptions, type MutateOptions, type MutatorResult, type PaginatedQueryOptions, type PaginatedQueryResult, type PresenceOptions, type PresenceResult,
|
|
1564
1622
|
/**
|
|
1565
1623
|
* The Angular adapter for Lunora.
|
|
1566
1624
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DestroyRef, Signal, InjectionToken, EnvironmentProviders, Injector } from '@angular/core';
|
|
2
|
-
import { FunctionReference, LunoraClient, SubscriptionErrorCallback, SubscriptionError, User, LunoraClientOptions, ConnectionStatus, Preloaded, ArgsOf, ReturnOf, LiveTopicOptions as LiveTopicOptions$1, LiveTopicRef, LiveStreamSubscribeError, MutationCallOptions, MutatorHandle, ActionCallOptions } from '@lunora/client';
|
|
2
|
+
import { FunctionReference, LunoraClient, SubscriptionErrorCallback, SubscriptionError, User, LunoraClientOptions, ConnectionStatus, Preloaded, ArgsOf, ReturnOf, LiveTopicOptions as LiveTopicOptions$1, LiveTopicRef, LiveStreamSubscribeError, MutationCallOptions, OnlineOnlyOption, MutatorHandle, ActionCallOptions } from '@lunora/client';
|
|
3
3
|
export type { ArgsOf, ConnectionStatus, FunctionReference, LunoraClient, LunoraClientOptions, MutationCallOptions, Preloaded, ReturnOf, SubscriptionError, Unsubscribe } from '@lunora/client';
|
|
4
4
|
import { AuthStatus } from '@lunora/client/auth';
|
|
5
5
|
import { PaginationStatus } from '@lunora/client/pagination';
|
|
@@ -56,8 +56,8 @@ interface AgentChatMessage {
|
|
|
56
56
|
optimistic?: boolean;
|
|
57
57
|
role: "assistant" | "system" | "tool" | "user";
|
|
58
58
|
seq: number;
|
|
59
|
-
/** Approval lifecycle marker on a human-in-the-loop tool message. */
|
|
60
|
-
status?: "approved" | "awaiting_approval" | "rejected";
|
|
59
|
+
/** Approval or secret-request lifecycle marker on a human-in-the-loop tool message. */
|
|
60
|
+
status?: "approved" | "awaiting_approval" | "awaiting_secret" | "rejected";
|
|
61
61
|
toolCallId?: string;
|
|
62
62
|
toolCalls?: ReadonlyArray<{
|
|
63
63
|
id: string;
|
|
@@ -202,7 +202,7 @@ type AgentMessagesReference$1 = FunctionReference<"query", {
|
|
|
202
202
|
}, ReadonlyArray<Record<string, unknown>>>;
|
|
203
203
|
/** The `agents:agentResolveApproval` reference — resolves a human-in-the-loop tool approval. */
|
|
204
204
|
type AgentApprovalReference = FunctionReference<"mutation", {
|
|
205
|
-
decision: "approve" | "reject";
|
|
205
|
+
decision: "approve" | "approve_for_thread" | "reject";
|
|
206
206
|
instanceId: string;
|
|
207
207
|
note?: string;
|
|
208
208
|
threadKey: string;
|
|
@@ -210,10 +210,41 @@ type AgentApprovalReference = FunctionReference<"mutation", {
|
|
|
210
210
|
}, {
|
|
211
211
|
resolved: boolean;
|
|
212
212
|
}>;
|
|
213
|
+
/** The `agents:agentSupplySecret` reference — stores a person's value for a paused `requestSecretTool` call. */
|
|
214
|
+
type AgentSupplySecretReference = FunctionReference<"mutation", {
|
|
215
|
+
secret: string;
|
|
216
|
+
threadKey: string;
|
|
217
|
+
toolCallId: string;
|
|
218
|
+
}, {
|
|
219
|
+
resolved: boolean;
|
|
220
|
+
}>;
|
|
221
|
+
/** The `agents:agentDeclineSecret` reference — refuses a paused `requestSecretTool` call. */
|
|
222
|
+
type AgentDeclineSecretReference = FunctionReference<"mutation", {
|
|
223
|
+
threadKey: string;
|
|
224
|
+
toolCallId: string;
|
|
225
|
+
}, {
|
|
226
|
+
resolved: boolean;
|
|
227
|
+
}>;
|
|
213
228
|
/** The `agents:agentThread` reference — live thread status + in-flight `instanceId`. */
|
|
214
229
|
type AgentThreadReference = FunctionReference<"query", {
|
|
215
230
|
key: string;
|
|
216
231
|
}, Record<string, unknown> | undefined>;
|
|
232
|
+
/** A tool approved for the rest of a thread, as `agents:agentApprovalGrants` lists it. */
|
|
233
|
+
interface AgentApprovalGrant {
|
|
234
|
+
createdAt: number;
|
|
235
|
+
toolName: string;
|
|
236
|
+
}
|
|
237
|
+
/** The `agents:agentApprovalGrants` reference — live thread-scoped approval grants. */
|
|
238
|
+
type AgentApprovalGrantsReference = FunctionReference<"query", {
|
|
239
|
+
key: string;
|
|
240
|
+
}, ReadonlyArray<AgentApprovalGrant>>;
|
|
241
|
+
/** The `agents:agentRevokeApprovalGrant` reference — removes a thread-scoped approval grant. */
|
|
242
|
+
type AgentRevokeApprovalGrantReference = FunctionReference<"mutation", {
|
|
243
|
+
threadKey: string;
|
|
244
|
+
toolName: string;
|
|
245
|
+
}, {
|
|
246
|
+
revoked: boolean;
|
|
247
|
+
}>;
|
|
217
248
|
/**
|
|
218
249
|
* An app stream reference that tees the agent's in-flight live events, keyed by
|
|
219
250
|
* thread. Carries token deltas and — since `ctx.reportProgress` rides the same
|
|
@@ -231,8 +262,12 @@ type AgentTokenStreamReference = FunctionReference<"stream", {
|
|
|
231
262
|
*/
|
|
232
263
|
interface AgentChatApi {
|
|
233
264
|
agents: {
|
|
265
|
+
agentApprovalGrants: AgentApprovalGrantsReference;
|
|
266
|
+
agentDeclineSecret: AgentDeclineSecretReference;
|
|
234
267
|
agentMessages: AgentMessagesReference$1;
|
|
235
268
|
agentResolveApproval: AgentApprovalReference;
|
|
269
|
+
agentRevokeApprovalGrant: AgentRevokeApprovalGrantReference;
|
|
270
|
+
agentSupplySecret: AgentSupplySecretReference;
|
|
236
271
|
agentThread: AgentThreadReference;
|
|
237
272
|
};
|
|
238
273
|
}
|
|
@@ -260,7 +295,7 @@ interface AgentChatOptions {
|
|
|
260
295
|
/** History depth forwarded to `agents:agentMessages`. */
|
|
261
296
|
limit?: number;
|
|
262
297
|
/**
|
|
263
|
-
* Called when the live history or
|
|
298
|
+
* Called when the live history, thread, or grants subscription reports an error (a
|
|
264
299
|
* session expiry, an RLS denial). Without it — and without reading `error` —
|
|
265
300
|
* such a failure is invisible and `messages` / `status` are cleared until a later frame arrives.
|
|
266
301
|
*/
|
|
@@ -287,29 +322,47 @@ interface AgentChatOptions {
|
|
|
287
322
|
* @experimental
|
|
288
323
|
*/
|
|
289
324
|
interface AgentChatResult {
|
|
325
|
+
/** The tools approved for the rest of this thread, live. Empty until the grants subscription answers. */
|
|
326
|
+
approvalGrants: Signal<ReadonlyArray<AgentApprovalGrant>>;
|
|
290
327
|
/** Approve a paused human-in-the-loop tool call (optionally with a note). */
|
|
291
328
|
approve: (toolCallId: string, note?: string) => Promise<void>;
|
|
329
|
+
/**
|
|
330
|
+
* Approve a paused tool call and grant that tool for the rest of the thread, so
|
|
331
|
+
* later calls to it run without pausing. Undo with {@link AgentChatResult.revokeGrant}.
|
|
332
|
+
*/
|
|
333
|
+
approveForThread: (toolCallId: string, note?: string) => Promise<void>;
|
|
292
334
|
/**
|
|
293
335
|
* Terminate the in-flight run and mark its thread `"cancelled"`. Resolves as a
|
|
294
336
|
* no-op when no `cancel` mutation was supplied or no run is in flight.
|
|
295
337
|
*/
|
|
296
338
|
cancel: () => Promise<void>;
|
|
297
|
-
/**
|
|
339
|
+
/** Refuse a paused `requestSecretTool` call: the run resumes with a "declined" result. */
|
|
340
|
+
declineSecret: (toolCallId: string) => Promise<void>;
|
|
341
|
+
/** The history, thread, or grants subscription's last error, or `undefined`. */
|
|
298
342
|
error: Signal<SubscriptionError | undefined>;
|
|
299
343
|
/** Durable thread history (oldest first) plus any un-acknowledged optimistic user turns. */
|
|
300
344
|
messages: Signal<ReadonlyArray<AgentChatMessage>>;
|
|
301
345
|
/** Reject a paused human-in-the-loop tool call (optionally with a reason). */
|
|
302
346
|
reject: (toolCallId: string, note?: string) => Promise<void>;
|
|
347
|
+
/** Remove a thread-scoped approval grant so the tool's gate applies again to later calls. */
|
|
348
|
+
revokeGrant: (toolName: string) => Promise<void>;
|
|
303
349
|
/** Start (or continue) a run with a user message; extra args merge over `sendArgs`. Appends an optimistic user turn. */
|
|
304
350
|
send: (input: string, args?: Record<string, unknown>) => Promise<void>;
|
|
305
351
|
/** The live thread status, or `undefined` before the thread exists. */
|
|
306
352
|
status: Signal<AgentThreadStatus | undefined>;
|
|
307
353
|
/** The in-flight turn's streamed text — live-only, empty once the turn persists to `messages`. */
|
|
308
354
|
streamingText: Signal<string>;
|
|
355
|
+
/**
|
|
356
|
+
* Give a paused `requestSecretTool` call its value. Always sent online-only: the
|
|
357
|
+
* value is never queued, persisted or replayed, and the call rejects with
|
|
358
|
+
* `OFFLINE_NOT_QUEUED` while the connection is down. The service keeps no copy;
|
|
359
|
+
* a failure rethrows the original error.
|
|
360
|
+
*/
|
|
361
|
+
supplySecret: (toolCallId: string, secret: string) => Promise<void>;
|
|
309
362
|
}
|
|
310
363
|
/**
|
|
311
364
|
* A first-class agent chat surface: live durable history + in-flight token
|
|
312
|
-
* streaming + the send / approve / reject / cancel writes, keyed by `threadKey` —
|
|
365
|
+
* streaming + the send / approve / reject / secret / cancel writes, keyed by `threadKey` —
|
|
313
366
|
* the Angular counterpart to React's `useAgentChat`, re-expressed with signals.
|
|
314
367
|
*
|
|
315
368
|
* It composes the existing primitives rather than adding transport:
|
|
@@ -439,7 +492,7 @@ interface AgentToolEventsOptions {
|
|
|
439
492
|
* Optional live event stream — the same app stream function `agentChat` uses.
|
|
440
493
|
* When supplied, ephemeral `ctx.reportProgress(...)` events for the thread are
|
|
441
494
|
* surfaced as `{ type: "progress" }` entries; when omitted only the durable
|
|
442
|
-
* lifecycle (call / result / awaiting-approval) is returned.
|
|
495
|
+
* lifecycle (call / result / awaiting-approval / awaiting-secret) is returned.
|
|
443
496
|
*/
|
|
444
497
|
stream?: AgentLiveStreamReference;
|
|
445
498
|
/** The thread whose tool activity to observe. */
|
|
@@ -447,7 +500,7 @@ interface AgentToolEventsOptions {
|
|
|
447
500
|
}
|
|
448
501
|
/**
|
|
449
502
|
* A single tool-lifecycle event for a thread. The durable arms
|
|
450
|
-
* (`call`/`result`/`awaiting-approval`) are derived from `agents:agentMessages`
|
|
503
|
+
* (`call`/`result`/`awaiting-approval`/`awaiting-secret`) are derived from `agents:agentMessages`
|
|
451
504
|
* and carry the persisted `seq`; the ephemeral `progress` arm comes live off the
|
|
452
505
|
* stream and has no `seq`. Discriminate on `type`.
|
|
453
506
|
* @experimental
|
|
@@ -474,6 +527,11 @@ type AgentToolEvent = {
|
|
|
474
527
|
toolCallId?: string;
|
|
475
528
|
toolName?: string;
|
|
476
529
|
type: "awaiting-approval";
|
|
530
|
+
} | {
|
|
531
|
+
seq: number;
|
|
532
|
+
toolCallId?: string;
|
|
533
|
+
toolName?: string;
|
|
534
|
+
type: "awaiting-secret";
|
|
477
535
|
};
|
|
478
536
|
/**
|
|
479
537
|
* `AgentToolEventsResult` is part of the experimental `@lunora/angular` API and may change without a major version bump.
|
|
@@ -933,7 +991,7 @@ interface MutateOptions<F extends FunctionReference> extends MutationCallOptions
|
|
|
933
991
|
* resolve from the injector.
|
|
934
992
|
* @experimental
|
|
935
993
|
*/
|
|
936
|
-
declare const mutate: <F extends FunctionReference>(reference: F, args: ArgsOf<F>, options?: MutateOptions<F>) => Promise<ReturnOf<F>>;
|
|
994
|
+
declare const mutate: <F extends FunctionReference>(reference: F, args: ArgsOf<F>, options?: MutateOptions<F> & OnlineOnlyOption<F>) => Promise<ReturnOf<F>>;
|
|
937
995
|
/**
|
|
938
996
|
* `MutatorResult` is part of the experimental `@lunora/angular` API and may change without a major version bump.
|
|
939
997
|
* @experimental
|
|
@@ -1560,7 +1618,7 @@ interface VoiceAgentResult {
|
|
|
1560
1618
|
* @experimental
|
|
1561
1619
|
*/
|
|
1562
1620
|
declare const voiceAgent: (options: VoiceAgentOptions) => VoiceAgentResult;
|
|
1563
|
-
export { type AgentApi, type AgentChatApi, type AgentChatMessage, type AgentChatOptions, type AgentChatResult, type AgentLiveEvent, type AgentOptions, type AgentProgressEvent, type AgentResult, type AgentStateApi, type AgentStateOptions, type AgentStateResult, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentTokenStreamReference, type AgentToolEvent, type AgentToolEventsApi, type AgentToolEventsOptions, type AgentToolEventsResult, type AuthGateResult, type AuthOptions, type AuthResult, type ConnectionStatusOptions, type FlagOptions, type FlagValue, type FlagsOptions, type HeartbeatReference, type HydratePreloadedOptions, type HydratePreloadedResult, type InfiniteQueryResult, LUNORA_CLIENT, type ListPresentReference, type LiveQueryOptions, type LiveTopicOptions, type MutateOptions, type MutatorResult, type PaginatedQueryOptions, type PaginatedQueryResult, type PresenceOptions, type PresenceResult,
|
|
1621
|
+
export { type AgentApi, type AgentApprovalGrant, type AgentChatApi, type AgentChatMessage, type AgentChatOptions, type AgentChatResult, type AgentLiveEvent, type AgentOptions, type AgentProgressEvent, type AgentResult, type AgentStateApi, type AgentStateOptions, type AgentStateResult, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentTokenStreamReference, type AgentToolEvent, type AgentToolEventsApi, type AgentToolEventsOptions, type AgentToolEventsResult, type AuthGateResult, type AuthOptions, type AuthResult, type ConnectionStatusOptions, type FlagOptions, type FlagValue, type FlagsOptions, type HeartbeatReference, type HydratePreloadedOptions, type HydratePreloadedResult, type InfiniteQueryResult, LUNORA_CLIENT, type ListPresentReference, type LiveQueryOptions, type LiveTopicOptions, type MutateOptions, type MutatorResult, type PaginatedQueryOptions, type PaginatedQueryResult, type PresenceOptions, type PresenceResult,
|
|
1564
1622
|
/**
|
|
1565
1623
|
* The Angular adapter for Lunora.
|
|
1566
1624
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{agent as e}from"./packem_shared/agent-DjMQf-yE.mjs";import{agentChat as p}from"./packem_shared/agentChat-
|
|
1
|
+
import{agent as e}from"./packem_shared/agent-DjMQf-yE.mjs";import{agentChat as p}from"./packem_shared/agentChat-CQ3TWlc5.mjs";import{agentState as f}from"./packem_shared/agentState-Bjqf9q2f.mjs";import{agentToolEvents as x}from"./packem_shared/agentToolEvents-CFnjzw3X.mjs";import{auth as i,authGate as u}from"./packem_shared/auth-C3dB8sYS.mjs";import{LUNORA_CLIENT as g,injectLunoraClient as l,provideLunora as s}from"./packem_shared/LUNORA_CLIENT-B0toApHY.mjs";import{connectionStatus as v}from"./packem_shared/connectionStatus-UhmuwzMa.mjs";import{flag as h,flags as y}from"./packem_shared/flag-BDKBQGos.mjs";import{hydratePreloaded as C}from"./packem_shared/hydratePreloaded-QPAo50Am.mjs";import{liveQuery as S}from"./packem_shared/liveQuery-eE9zMaxo.mjs";import{liveTopic as E}from"./packem_shared/liveTopic-Cz1BDkMP.mjs";import{mutate as N}from"./packem_shared/mutate-Dg5AiM8y.mjs";import{mutator as b}from"./packem_shared/mutator-DjG1yGk8.mjs";import{infiniteQuery as G,paginatedQuery as K}from"./packem_shared/infiniteQuery-DGYdgFHW.mjs";import{presence as R}from"./packem_shared/presence-1T4-U8ij.mjs";import{rateLimit as _}from"./packem_shared/rateLimit-B3h9qzh-.mjs";import{runAction as q}from"./packem_shared/runAction-BfiPq4Xz.mjs";import{stream as z}from"./packem_shared/stream-BuhiwhIH.mjs";import{subscription as D}from"./packem_shared/subscription-zJv48q6C.mjs";import{voiceAgent as H}from"./packem_shared/voiceAgent-DppK8OxH.mjs";import{SKIP as M}from"@lunora/client/query";export{g as LUNORA_CLIENT,M as SKIP,e as agent,p as agentChat,f as agentState,x as agentToolEvents,i as auth,u as authGate,v as connectionStatus,h as flag,y as flags,C as hydratePreloaded,G as infiniteQuery,l as injectLunoraClient,S as liveQuery,E as liveTopic,N as mutate,b as mutator,K as paginatedQuery,R as presence,s as provideLunora,_ as rateLimit,q as runAction,z as stream,D as subscription,H as voiceAgent};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{computed as o,signal as J}from"@angular/core";import{reconcileOptimistic as w,maxSeq as A}from"@lunora/client";import{resolveLunoraClient as Q}from"./LUNORA_CLIENT-B0toApHY.mjs";import{stream as U}from"./stream-BuhiwhIH.mjs";import{subscription as h}from"./subscription-zJv48q6C.mjs";const V={__lunoraRef:""},W=[],rt=d=>{const{api:a,cancel:v,limit:f,onError:m,send:R,sendArgs:E,stream:S,threadKey:n}=d,r=Q(d.client),{destroyRef:l}=d,x=f===void 0?{key:n}:{key:n,limit:f},{data:_,error:b}=h(a.agents.agentMessages,x,{client:r,destroyRef:l,onError:m}),{data:I,error:T}=h(a.agents.agentThread,{key:n},{client:r,destroyRef:l,onError:m}),{data:D,error:G}=h(a.agents.agentApprovalGrants,{key:n},{client:r,destroyRef:l,onError:m}),q=o(()=>b()??T()??G()),C=S===void 0?"skip":{key:n},{chunks:j}=U(S??V,C,{client:r,destroyRef:l}),i=J([]);let k=0;const u=o(()=>I()),M=o(()=>u()?.status),p=o(()=>_()??[]),O=o(()=>{const t=p(),e=w(i(),t);if(e.length===0)return t;const s=A(t);return[...t,...e.map((c,y)=>({content:c.content,optimistic:!0,role:"user",seq:s+1+y}))]}),F=o(()=>{const t=p().filter(e=>e.role==="assistant").length;return j().filter(e=>e.kind!=="progress"&&e.threadKey===n&&e.turn>=t).map(e=>e.text).join("")}),K=async(t,e)=>{const s=k;k+=1;const c=A(p());i.set([...w(i(),p()),{content:t,id:s,maxDurableSeqAtSend:c}]);try{await r.mutation(R,{input:t,threadKey:n,...E,...e})}catch(y){throw i.set(i().filter(H=>H.id!==s)),y}},g=async(t,e,s)=>{const c=u()?.instanceId;if(c===void 0)throw new Error(`agentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await r.mutation(a.agents.agentResolveApproval,{decision:t,instanceId:c,threadKey:n,toolCallId:e,...s===void 0?{}:{note:s}})},N=async(t,e)=>g("approve",t,e),L=async(t,e)=>g("approve_for_thread",t,e),P=async(t,e)=>g("reject",t,e),Y=async t=>{await r.mutation(a.agents.agentRevokeApprovalGrant,{threadKey:n,toolName:t})},$=async(t,e)=>{await r.mutation(a.agents.agentSupplySecret,{secret:e,threadKey:n,toolCallId:t},{onlineOnly:!0})},z=async t=>{await r.mutation(a.agents.agentDeclineSecret,{threadKey:n,toolCallId:t})},B=async()=>{const t=u()?.instanceId;v===void 0||t===void 0||await r.mutation(v,{instanceId:t,threadKey:n})};return{approvalGrants:o(()=>D()??W),approve:N,approveForThread:L,cancel:B,declineSecret:z,error:q,messages:O,reject:P,revokeGrant:Y,send:K,status:M,streamingText:F,supplySecret:$}};export{rt as agentChat};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{computed as v}from"@angular/core";import{resolveLunoraClient as f}from"./LUNORA_CLIENT-B0toApHY.mjs";import{stream as C}from"./stream-BuhiwhIH.mjs";import{subscription as E}from"./subscription-zJv48q6C.mjs";const y={__lunoraRef:""},I=[],N={awaiting_approval:"awaiting-approval",awaiting_secret:"awaiting-secret"},_=t=>{const o=t.status===void 0?void 0:N[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}}},k=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=_(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}}]},R=t=>{const{api:o,limit:r,stream:e,threadKey:l}=t,a=f(t.client),{destroyRef:i}=t,s=r===void 0?{key:l}:{key:l,limit:r},{data:u}=E(o.agents.agentMessages,s,{client:a,destroyRef:i}),c=e===void 0?"skip":{key:l},{chunks:p}=C(e??y,c,{client:a,destroyRef:i});return{events:v(()=>{const d=(u()??I).flatMap(n=>k(n)??[]);for(const n of p())n.kind==="progress"&&n.threadKey===l&&d.push({data:n.data,toolCallId:n.toolCallId,type:"progress"});return d})}};export{R as agentToolEvents};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{resolveLunoraClient as c}from"./LUNORA_CLIENT-B0toApHY.mjs";const l=(t,o,n={})=>{const{client:e,...r}=n,s=r;return c(e).mutation(t,o,s)};export{l as mutate};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{inject as B,DestroyRef as K,signal as T}from"@angular/core";import{resolveLunoraClient as V}from"./LUNORA_CLIENT-B0toApHY.mjs";import{o as q}from"./platform-DGTu4Ucl.mjs";const D="/_lunora/ws",j="/_lunora/voice/",J=4001,L=e=>e.startsWith("https://")?`wss://${e.slice(8)}`:e.startsWith("http://")?`ws://${e.slice(7)}`:e,G=e=>{const s=e.startsWith("agents:")?e.slice(7):e;return s.endsWith("Voice")?s.slice(0,-5):s},X=(e,s)=>{if(s===void 0||s==="")return L(e);if(s.endsWith(D))return s.slice(0,-D.length);try{return new URL(s).origin}catch{return L(e)}},z=e=>{const s=X(e.httpUrl,e.wsUrl),r=s.endsWith("/")?s.slice(0,-1):s,i=new URLSearchParams({threadKey:e.threadKey});return`${r}${j}${encodeURIComponent(e.agent)}?${i.toString()}`},Q=(e,s)=>{if(s?.code===J)return new Error(`${e}: authentication token expired — refresh the credential and start a new call`)},Y=(e,s,r)=>{const i=e.currentIdentity();return e.onAuthTokenChange(()=>{e.currentIdentity()!==i&&r(new Error(`${s}: the signed-in identity changed during the call — the session was ended; start a new call`))})},Z=16e3,ee=e=>{if(e.length===0)return 0;let s=0;for(const r of e)s+=r*r;return Math.sqrt(s/e.length)},te=(e,s)=>{const r=s/Z,i=r>1?Math.floor(e.length/r):e.length,k=new ArrayBuffer(i*2),l=new DataView(k);for(let u=0;u<i;u+=1){const y=e[Math.floor(u*r)]??0,d=Math.max(-1,Math.min(1,y));l.setInt16(u*2,d<0?d*32768:d*32767,!0)}return new Uint8Array(k)},ne=async e=>{const s=globalThis,r=s.navigator?.mediaDevices?.getUserMedia.bind(s.navigator.mediaDevices),i=s.AudioContext??s.webkitAudioContext;if(!r||!i)throw new Error("voiceAgent: microphone capture requires getUserMedia + AudioContext (no browser audio available)");const k=await r({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),l=new i,u=l.createMediaStreamSource(k),y=l.createScriptProcessor(4096,1,1);let d=!1,m=!1,c=0,g=0;return y.onaudioprocess=p=>{const f=p.inputBuffer.getChannelData(0),a=d?0:ee(f);if(e.onLevel(a),d)return;if(e.onAudio(te(f,l.sampleRate)),e.isTurnActive()){g=a>=e.interruptThreshold?g+1:0,g>=e.interruptChunks&&(g=0,e.onInterrupt());return}g=0;const S=f.length/l.sampleRate*1e3;if(a>=e.silenceThreshold){m=!0,c=0;return}m&&(c+=S,c>=e.silenceDurationMs&&(m=!1,c=0,e.onSilence()))},u.connect(y),y.connect(l.destination),{setMuted:p=>{d=p},stop:()=>{y.disconnect(),u.disconnect();for(const p of k.getTracks())p.stop();l.close()}}},se=()=>{const e=globalThis,s=e.AudioContext??e.webkitAudioContext;if(!s)throw new Error("voiceAgent: audio playback requires AudioContext (no browser audio available)");const r=new s,i=new Set;let k=0,l=Promise.resolve(),u=0;const y=async(c,g)=>{if(g!==u)return;let p;try{p=await r.decodeAudioData(c.buffer)}catch{return}if(g!==u)return;const f=r.createBufferSource();f.buffer=p,f.connect(r.destination);const a=Math.max(r.currentTime,k);f.start(a),k=a+p.duration,i.add(f),f.onended=()=>{i.delete(f)}},d=c=>{const g=Uint8Array.from(c),p=u;l=l.then(()=>y(g,p))},m=()=>{u+=1;for(const c of i)try{c.stop()}catch{}i.clear(),k=r.currentTime};return{enqueue:d,interrupt:m,stop:()=>{m(),r.close()}}},F=1,re=.01,oe=1200,ae=.15,ie=3,de=e=>{const{createMicrophone:s=ne,createSpeaker:r=se,createSocket:i,interruptChunks:k=ie,interruptThreshold:l=ae,silenceDurationMs:u=oe,silenceThreshold:y=re,threadKey:d,voice:m}=e,c=V(e.client),g=e.destroyRef===void 0,p=e.destroyRef??B(K),f=q(g),a=T("idle"),S=T(!1),_=T(""),v=T(""),x=T(0),R=T(!1),w=T(void 0);let o,b=!1;const M=n=>{const t=o?.socket;return t?.readyState===F?(t.send(JSON.stringify(n)),!0):!1},E=()=>{const n=o;if(o=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{}}b=!1,S.set(!1),a.set("idle"),x.set(0)},W=E,N=n=>{const t=o;switch(n.type){case"assistant_delta":{t&&(t.speaking=!0),a.set("speaking"),v.update(I=>I+n.text);break}case"assistant_discarded":{t&&(t.suppressAudio=!0),t?.speaker?.interrupt(),v.set("");break}case"assistant_done":{t&&(t.awaitingTurn=!1,t.speaking=!1),v.set(n.text),a.set("listening");break}case"error":{t&&(t.awaitingTurn=!1,t.speaking=!1),w.set(new Error(n.message)),a.set("listening");break}case"interrupted":{t&&(t.awaitingTurn=!1,t.speaking=!1,t.suppressAudio=!1),t?.speaker?.interrupt(),a.set("listening");break}case"ready":{t&&(t.audioFormat=n.audioFormat,t.suppressAudio=!1),S.set(!0),a.set("listening");break}case"user_transcript":{t&&(t.suppressAudio=!1),_.set(n.text),v.set(""),a.set("thinking");break}}},O=n=>{const t=o;!t||t.suppressAudio||(t.speaker??=r({audioFormat:t.audioFormat}),t.speaking=!0,a.set("speaking"),t.speaker.enqueue(n))},P=async()=>{if(o||b)return;b=!0,w.set(void 0),_.set(""),v.set("");let n;try{const t=z({agent:G(m.__lunoraRef),httpUrl:c.url,threadKey:typeof d=="function"?d():d,wsUrl:c.wsUrl}),I=i??(h=>{const C=c.getWebSocketImpl();if(!C)throw new Error("voiceAgent: no WebSocket implementation available (pass createSocket explicitly)");return new C(h)}),A=f(()=>I(t));A.binaryType="arraybuffer",n={audioFormat:"mp3",microphone:void 0,socket:A,speaker:void 0,speaking:!1,awaitingTurn:!1,suppressAudio:!1,unwatchIdentity:void 0},o=n,n.unwatchIdentity=Y(c,"voiceAgent",h=>{o===n&&(w.set(h),E())}),A.onmessage=h=>{if(typeof h.data=="string"){try{N(JSON.parse(h.data))}catch{}return}O(new Uint8Array(h.data))},A.onerror=()=>{w.set(new Error("voiceAgent: voice socket error"))},A.onclose=h=>{if(o!==n)return;const C=Q("voiceAgent",h);C&&w.set(C),E()};const U=await f(async()=>s({interruptChunks:k,interruptThreshold:l,isTurnActive:()=>(o?.speaking??!1)||(o?.awaitingTurn??!1),onAudio:h=>{A.readyState===F&&A.send(h)},onInterrupt:()=>{M({type:"interrupt"}),o?.speaker?.interrupt(),o&&(o.awaitingTurn=!1,o.speaking=!1,o.suppressAudio=!0),a.set("listening")},onLevel:h=>{x.set(h)},onSilence:()=>{M({type:"commit"}),o&&(o.awaitingTurn=!0),a.set("thinking")},silenceDurationMs:u,silenceThreshold:y}));o===n?(n.microphone=U,R.set(!1),n.speaking||a.set("listening")):U.stop()}catch(t){o===n&&(w.set(t instanceof Error?t:new Error(String(t))),E())}finally{b=!1}},H=()=>{const n=!R();return o?.microphone?.setMuted(n),R.set(n),n},$=n=>{M({text:n,type:"text"})&&(o&&(o.awaitingTurn=!0),a.set("thinking"))};return p.onDestroy(E),{audioLevel:x.asReadonly(),connected:S.asReadonly(),endCall:W,error:w.asReadonly(),interimTranscript:v.asReadonly(),isMuted:R.asReadonly(),sendText:$,startCall:P,status:a.asReadonly(),toggleMute:H,transcript:_.asReadonly()}};export{de as voiceAgent};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/angular",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.220",
|
|
4
4
|
"description": "Angular reactive adapter for Lunora — signal-based live queries and mutations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@lunora/client": "1.0.0-alpha.
|
|
57
|
-
"@lunora/ratelimit": "1.0.0-alpha.
|
|
56
|
+
"@lunora/client": "1.0.0-alpha.234",
|
|
57
|
+
"@lunora/ratelimit": "1.0.0-alpha.156",
|
|
58
58
|
"@lunora/wire": "1.0.0-alpha.1",
|
|
59
59
|
"@visulima/storage-client": "1.0.9"
|
|
60
60
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{computed as a,signal as L}from"@angular/core";import{reconcileOptimistic as k,maxSeq as w}from"@lunora/client";import{resolveLunoraClient as N}from"./LUNORA_CLIENT-B0toApHY.mjs";import{stream as $}from"./stream-BuhiwhIH.mjs";import{subscription as x}from"./subscription-zJv48q6C.mjs";const z={__lunoraRef:""},W=m=>{const{api:d,cancel:g,limit:h,onError:f,send:A,sendArgs:E,stream:y,threadKey:r}=m,s=N(m.client),{destroyRef:l}=m,b=h===void 0?{key:r}:{key:r,limit:h},{data:I,error:S}=x(d.agents.agentMessages,b,{client:s,destroyRef:l,onError:f}),{data:j,error:q}=x(d.agents.agentThread,{key:r},{client:s,destroyRef:l,onError:f}),C=a(()=>S()??q()),_=y===void 0?"skip":{key:r},{chunks:D}=$(y??z,_,{client:s,destroyRef:l}),c=L([]);let v=0;const u=a(()=>j()),T=a(()=>u()?.status),i=a(()=>I()??[]),K=a(()=>{const t=i(),e=k(c(),t);if(e.length===0)return t;const n=w(t);return[...t,...e.map((o,p)=>({content:o.content,optimistic:!0,role:"user",seq:n+1+p}))]}),M=a(()=>{const t=i().filter(e=>e.role==="assistant").length;return D().filter(e=>e.kind!=="progress"&&e.threadKey===r&&e.turn>=t).map(e=>e.text).join("")}),O=async(t,e)=>{const n=v;v+=1;const o=w(i());c.set([...k(c(),i()),{content:t,id:n,maxDurableSeqAtSend:o}]);try{await s.mutation(A,{input:t,threadKey:r,...E,...e})}catch(p){throw c.set(c().filter(F=>F.id!==n)),p}},R=async(t,e,n)=>{const o=u()?.instanceId;if(o===void 0)throw new Error(`agentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await s.mutation(d.agents.agentResolveApproval,{decision:t,instanceId:o,threadKey:r,toolCallId:e,...n===void 0?{}:{note:n}})};return{approve:async(t,e)=>R("approve",t,e),cancel:async()=>{const t=u()?.instanceId;g===void 0||t===void 0||await s.mutation(g,{instanceId:t,threadKey:r})},error:C,messages:K,reject:async(t,e)=>R("reject",t,e),send:O,status:T,streamingText:M}};export{W as agentChat};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{computed as v}from"@angular/core";import{resolveLunoraClient as f}from"./LUNORA_CLIENT-B0toApHY.mjs";import{stream as C}from"./stream-BuhiwhIH.mjs";import{subscription as y}from"./subscription-zJv48q6C.mjs";const I={__lunoraRef:""},N=[],m=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}}]},R=t=>{const{api:l,limit:n,stream:e,threadKey:r}=t,a=f(t.client),{destroyRef:i}=t,u=n===void 0?{key:r}:{key:r,limit:n},{data:p}=y(l.agents.agentMessages,u,{client:a,destroyRef:i}),s=e===void 0?"skip":{key:r},{chunks:c}=C(e??I,s,{client:a,destroyRef:i});return{events:v(()=>{const d=(p()??N).flatMap(o=>m(o)??[]);for(const o of c())o.kind==="progress"&&o.threadKey===r&&d.push({data:o.data,toolCallId:o.toolCallId,type:"progress"});return d})}};export{R as agentToolEvents};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{resolveLunoraClient as i}from"./LUNORA_CLIENT-B0toApHY.mjs";const a=(t,o,n={})=>{const{client:e,...r}=n;return i(e).mutation(t,o,r)};export{a as mutate};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{inject as B,DestroyRef as K,signal as T}from"@angular/core";import{resolveLunoraClient as V}from"./LUNORA_CLIENT-B0toApHY.mjs";import{o as q}from"./platform-DGTu4Ucl.mjs";const D="/_lunora/ws",j="/_lunora/voice/",J=4001,L=e=>e.startsWith("https://")?`wss://${e.slice(8)}`:e.startsWith("http://")?`ws://${e.slice(7)}`:e,G=e=>{const r=e.startsWith("agents:")?e.slice(7):e;return r.endsWith("Voice")?r.slice(0,-5):r},X=(e,r)=>{if(r===void 0||r==="")return L(e);if(r.endsWith(D))return r.slice(0,-D.length);try{return new URL(r).origin}catch{return L(e)}},z=e=>{const r=X(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()}`},Q=(e,r)=>{if(r?.code===J)return new Error(`${e}: authentication token expired — refresh the credential and start a new call`)},Y=(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`))})},Z=16e3,ee=e=>{if(e.length===0)return 0;let r=0;for(const s of e)r+=s*s;return Math.sqrt(r/e.length)},te=(e,r)=>{const s=r/Z,i=s>1?Math.floor(e.length/s):e.length,k=new ArrayBuffer(i*2),l=new DataView(k);for(let u=0;u<i;u+=1){const y=e[Math.floor(u*s)]??0,d=Math.max(-1,Math.min(1,y));l.setInt16(u*2,d<0?d*32768:d*32767,!0)}return new Uint8Array(k)},ne=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("voiceAgent: microphone capture requires getUserMedia + AudioContext (no browser audio available)");const k=await s({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),l=new i,u=l.createMediaStreamSource(k),y=l.createScriptProcessor(4096,1,1);let d=!1,m=!1,c=0,g=0;return y.onaudioprocess=p=>{const h=p.inputBuffer.getChannelData(0),a=d?0:ee(h);if(e.onLevel(a),d)return;if(e.onAudio(te(h,l.sampleRate)),e.isTurnActive()){g=a>=e.interruptThreshold?g+1:0,g>=e.interruptChunks&&(g=0,e.onInterrupt());return}g=0;const v=h.length/l.sampleRate*1e3;if(a>=e.silenceThreshold){m=!0,c=0;return}m&&(c+=v,c>=e.silenceDurationMs&&(m=!1,c=0,e.onSilence()))},u.connect(y),y.connect(l.destination),{setMuted:p=>{d=p},stop:()=>{y.disconnect(),u.disconnect();for(const p of k.getTracks())p.stop();l.close()}}},re=()=>{const e=globalThis,r=e.AudioContext??e.webkitAudioContext;if(!r)throw new Error("voiceAgent: audio playback requires AudioContext (no browser audio available)");const s=new r,i=new Set;let k=0,l=Promise.resolve(),u=0;const y=async(c,g)=>{if(g!==u)return;let p;try{p=await s.decodeAudioData(c.buffer)}catch{return}if(g!==u)return;const h=s.createBufferSource();h.buffer=p,h.connect(s.destination);const a=Math.max(s.currentTime,k);h.start(a),k=a+p.duration,i.add(h),h.onended=()=>{i.delete(h)}},d=c=>{const g=Uint8Array.from(c),p=u;l=l.then(()=>y(g,p))},m=()=>{u+=1;for(const c of i)try{c.stop()}catch{}i.clear(),k=s.currentTime};return{enqueue:d,interrupt:m,stop:()=>{m(),s.close()}}},F=1,se=.01,oe=1200,ae=.15,ie=3,de=e=>{const{createMicrophone:r=ne,createSpeaker:s=re,createSocket:i,interruptChunks:k=ie,interruptThreshold:l=ae,silenceDurationMs:u=oe,silenceThreshold:y=se,threadKey:d,voice:m}=e,c=V(e.client),g=e.destroyRef===void 0,p=e.destroyRef??B(K),h=q(g),a=T("idle"),v=T(!1),_=T(""),S=T(""),x=T(0),R=T(!1),w=T(void 0);let o,b=!1;const M=t=>{const n=o?.socket;return n?.readyState===F?(n.send(JSON.stringify(t)),!0):!1},E=()=>{const t=o;if(o=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,v.set(!1),a.set("idle"),x.set(0)},W=E,N=t=>{const n=o;switch(t.type){case"assistant_delta":{n&&(n.speaking=!0),a.set("speaking"),S.update(I=>I+t.text);break}case"assistant_done":{n&&(n.awaitingTurn=!1,n.speaking=!1),S.set(t.text),a.set("listening");break}case"error":{n&&(n.awaitingTurn=!1,n.speaking=!1),w.set(new Error(t.message)),a.set("listening");break}case"interrupted":{n&&(n.awaitingTurn=!1,n.speaking=!1,n.suppressAudio=!1),n?.speaker?.interrupt(),a.set("listening");break}case"ready":{n&&(n.audioFormat=t.audioFormat,n.suppressAudio=!1),v.set(!0),a.set("listening");break}case"user_transcript":{n&&(n.suppressAudio=!1),_.set(t.text),S.set(""),a.set("thinking");break}}},O=t=>{const n=o;!n||n.suppressAudio||(n.speaker??=s({audioFormat:n.audioFormat}),n.speaking=!0,a.set("speaking"),n.speaker.enqueue(t))},P=async()=>{if(o||b)return;b=!0,w.set(void 0),_.set(""),S.set("");let t;try{const n=z({agent:G(m.__lunoraRef),httpUrl:c.url,threadKey:typeof d=="function"?d():d,wsUrl:c.wsUrl}),I=i??(f=>{const C=c.getWebSocketImpl();if(!C)throw new Error("voiceAgent: no WebSocket implementation available (pass createSocket explicitly)");return new C(f)}),A=h(()=>I(n));A.binaryType="arraybuffer",t={audioFormat:"mp3",microphone:void 0,socket:A,speaker:void 0,speaking:!1,awaitingTurn:!1,suppressAudio:!1,unwatchIdentity:void 0},o=t,t.unwatchIdentity=Y(c,"voiceAgent",f=>{o===t&&(w.set(f),E())}),A.onmessage=f=>{if(typeof f.data=="string"){try{N(JSON.parse(f.data))}catch{}return}O(new Uint8Array(f.data))},A.onerror=()=>{w.set(new Error("voiceAgent: voice socket error"))},A.onclose=f=>{if(o!==t)return;const C=Q("voiceAgent",f);C&&w.set(C),E()};const U=await h(async()=>r({interruptChunks:k,interruptThreshold:l,isTurnActive:()=>(o?.speaking??!1)||(o?.awaitingTurn??!1),onAudio:f=>{A.readyState===F&&A.send(f)},onInterrupt:()=>{M({type:"interrupt"}),o?.speaker?.interrupt(),o&&(o.awaitingTurn=!1,o.speaking=!1,o.suppressAudio=!0),a.set("listening")},onLevel:f=>{x.set(f)},onSilence:()=>{M({type:"commit"}),o&&(o.awaitingTurn=!0),a.set("thinking")},silenceDurationMs:u,silenceThreshold:y}));o===t?(t.microphone=U,R.set(!1),t.speaking||a.set("listening")):U.stop()}catch(n){o===t&&(w.set(n instanceof Error?n:new Error(String(n))),E())}finally{b=!1}},H=()=>{const t=!R();return o?.microphone?.setMuted(t),R.set(t),t},$=t=>{M({text:t,type:"text"})&&(o&&(o.awaitingTurn=!0),a.set("thinking"))};return p.onDestroy(E),{audioLevel:x.asReadonly(),connected:v.asReadonly(),endCall:W,error:w.asReadonly(),interimTranscript:S.asReadonly(),isMuted:R.asReadonly(),sendText:$,startCall:P,status:a.asReadonly(),toggleMute:H,transcript:_.asReadonly()}};export{de as voiceAgent};
|